@@ -86,7 +86,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
86
86
if input .Name == "" {
87
87
normalized .Inputs [j ].Name = fmt .Sprintf ("arg%d" , j )
88
88
}
89
- if _ , exist := structs [ input . Type . String ()]; input .Type . T == abi . TupleTy && ! exist {
89
+ if hasStruct ( input .Type ) {
90
90
bindStructType [lang ](input .Type , structs )
91
91
}
92
92
}
@@ -96,7 +96,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
96
96
if output .Name != "" {
97
97
normalized .Outputs [j ].Name = capitalise (output .Name )
98
98
}
99
- if _ , exist := structs [ output . Type . String ()]; output .Type . T == abi . TupleTy && ! exist {
99
+ if hasStruct ( output .Type ) {
100
100
bindStructType [lang ](output .Type , structs )
101
101
}
102
102
}
@@ -119,14 +119,11 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
119
119
normalized .Inputs = make ([]abi.Argument , len (original .Inputs ))
120
120
copy (normalized .Inputs , original .Inputs )
121
121
for j , input := range normalized .Inputs {
122
- // Indexed fields are input, non-indexed ones are outputs
123
- if input .Indexed {
124
- if input .Name == "" {
125
- normalized .Inputs [j ].Name = fmt .Sprintf ("arg%d" , j )
126
- }
127
- if _ , exist := structs [input .Type .String ()]; input .Type .T == abi .TupleTy && ! exist {
128
- bindStructType [lang ](input .Type , structs )
129
- }
122
+ if input .Name == "" {
123
+ normalized .Inputs [j ].Name = fmt .Sprintf ("arg%d" , j )
124
+ }
125
+ if hasStruct (input .Type ) {
126
+ bindStructType [lang ](input .Type , structs )
130
127
}
131
128
}
132
129
// Append the event to the accumulator list
@@ -244,7 +241,7 @@ func bindBasicTypeGo(kind abi.Type) string {
244
241
func bindTypeGo (kind abi.Type , structs map [string ]* tmplStruct ) string {
245
242
switch kind .T {
246
243
case abi .TupleTy :
247
- return structs [kind .String ()].Name
244
+ return structs [kind .TupleRawName + kind . String ()].Name
248
245
case abi .ArrayTy :
249
246
return fmt .Sprintf ("[%d]" , kind .Size ) + bindTypeGo (* kind .Elem , structs )
250
247
case abi .SliceTy :
@@ -321,7 +318,7 @@ func pluralizeJavaType(typ string) string {
321
318
func bindTypeJava (kind abi.Type , structs map [string ]* tmplStruct ) string {
322
319
switch kind .T {
323
320
case abi .TupleTy :
324
- return structs [kind .String ()].Name
321
+ return structs [kind .TupleRawName + kind . String ()].Name
325
322
case abi .ArrayTy , abi .SliceTy :
326
323
return pluralizeJavaType (bindTypeJava (* kind .Elem , structs ))
327
324
default :
@@ -340,6 +337,13 @@ var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct)
340
337
// funcionality as for simple types, but dynamic types get converted to hashes.
341
338
func bindTopicTypeGo (kind abi.Type , structs map [string ]* tmplStruct ) string {
342
339
bound := bindTypeGo (kind , structs )
340
+
341
+ // todo(rjl493456442) according solidity documentation, indexed event
342
+ // parameters that are not value types i.e. arrays and structs are not
343
+ // stored directly but instead a keccak256-hash of an encoding is stored.
344
+ //
345
+ // We only convert stringS and bytes to hash, still need to deal with
346
+ // array(both fixed-size and dynamic-size) and struct.
343
347
if bound == "string" || bound == "[]byte" {
344
348
bound = "common.Hash"
345
349
}
@@ -350,6 +354,13 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
350
354
// funcionality as for simple types, but dynamic types get converted to hashes.
351
355
func bindTopicTypeJava (kind abi.Type , structs map [string ]* tmplStruct ) string {
352
356
bound := bindTypeJava (kind , structs )
357
+
358
+ // todo(rjl493456442) according solidity documentation, indexed event
359
+ // parameters that are not value types i.e. arrays and structs are not
360
+ // stored directly but instead a keccak256-hash of an encoding is stored.
361
+ //
362
+ // We only convert stringS and bytes to hash, still need to deal with
363
+ // array(both fixed-size and dynamic-size) and struct.
353
364
if bound == "String" || bound == "byte[]" {
354
365
bound = "Hash"
355
366
}
@@ -369,16 +380,26 @@ var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct
369
380
func bindStructTypeGo (kind abi.Type , structs map [string ]* tmplStruct ) string {
370
381
switch kind .T {
371
382
case abi .TupleTy :
372
- if s , exist := structs [kind .String ()]; exist {
383
+ // We compose raw struct name and canonical parameter expression
384
+ // together here. The reason is before solidity v0.5.11, kind.TupleRawName
385
+ // is empty, so we use canonical parameter expression to distinguish
386
+ // different struct definition. From the consideration of backward
387
+ // compatibility, we concat these two together so that if kind.TupleRawName
388
+ // is not empty, it can have unique id.
389
+ id := kind .TupleRawName + kind .String ()
390
+ if s , exist := structs [id ]; exist {
373
391
return s .Name
374
392
}
375
393
var fields []* tmplField
376
394
for i , elem := range kind .TupleElems {
377
395
field := bindStructTypeGo (* elem , structs )
378
396
fields = append (fields , & tmplField {Type : field , Name : capitalise (kind .TupleRawNames [i ]), SolKind : * elem })
379
397
}
380
- name := fmt .Sprintf ("Struct%d" , len (structs ))
381
- structs [kind .String ()] = & tmplStruct {
398
+ name := kind .TupleRawName
399
+ if name == "" {
400
+ name = fmt .Sprintf ("Struct%d" , len (structs ))
401
+ }
402
+ structs [id ] = & tmplStruct {
382
403
Name : name ,
383
404
Fields : fields ,
384
405
}
@@ -398,16 +419,26 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
398
419
func bindStructTypeJava (kind abi.Type , structs map [string ]* tmplStruct ) string {
399
420
switch kind .T {
400
421
case abi .TupleTy :
401
- if s , exist := structs [kind .String ()]; exist {
422
+ // We compose raw struct name and canonical parameter expression
423
+ // together here. The reason is before solidity v0.5.11, kind.TupleRawName
424
+ // is empty, so we use canonical parameter expression to distinguish
425
+ // different struct definition. From the consideration of backward
426
+ // compatibility, we concat these two together so that if kind.TupleRawName
427
+ // is not empty, it can have unique id.
428
+ id := kind .TupleRawName + kind .String ()
429
+ if s , exist := structs [id ]; exist {
402
430
return s .Name
403
431
}
404
432
var fields []* tmplField
405
433
for i , elem := range kind .TupleElems {
406
434
field := bindStructTypeJava (* elem , structs )
407
435
fields = append (fields , & tmplField {Type : field , Name : decapitalise (kind .TupleRawNames [i ]), SolKind : * elem })
408
436
}
409
- name := fmt .Sprintf ("Class%d" , len (structs ))
410
- structs [kind .String ()] = & tmplStruct {
437
+ name := kind .TupleRawName
438
+ if name == "" {
439
+ name = fmt .Sprintf ("Class%d" , len (structs ))
440
+ }
441
+ structs [id ] = & tmplStruct {
411
442
Name : name ,
412
443
Fields : fields ,
413
444
}
@@ -497,6 +528,21 @@ func structured(args abi.Arguments) bool {
497
528
return true
498
529
}
499
530
531
+ // hasStruct returns an indicator whether the given type is struct, struct slice
532
+ // or struct array.
533
+ func hasStruct (t abi.Type ) bool {
534
+ switch t .T {
535
+ case abi .SliceTy :
536
+ return hasStruct (* t .Elem )
537
+ case abi .ArrayTy :
538
+ return hasStruct (* t .Elem )
539
+ case abi .TupleTy :
540
+ return true
541
+ default :
542
+ return false
543
+ }
544
+ }
545
+
500
546
// resolveArgName converts a raw argument representation into a user friendly format.
501
547
func resolveArgName (arg abi.Argument , structs map [string ]* tmplStruct ) string {
502
548
var (
@@ -512,7 +558,7 @@ loop:
512
558
case abi .ArrayTy :
513
559
prefix += fmt .Sprintf ("[%d]" , typ .Size )
514
560
default :
515
- embedded = typ .String ()
561
+ embedded = typ .TupleRawName + typ . String ()
516
562
break loop
517
563
}
518
564
typ = typ .Elem
0 commit comments