@@ -86,7 +86,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
8686 if input .Name == "" {
8787 normalized .Inputs [j ].Name = fmt .Sprintf ("arg%d" , j )
8888 }
89- if _ , exist := structs [ input . Type . String ()]; input .Type . T == abi . TupleTy && ! exist {
89+ if hasStruct ( input .Type ) {
9090 bindStructType [lang ](input .Type , structs )
9191 }
9292 }
@@ -96,7 +96,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
9696 if output .Name != "" {
9797 normalized .Outputs [j ].Name = capitalise (output .Name )
9898 }
99- if _ , exist := structs [ output . Type . String ()]; output .Type . T == abi . TupleTy && ! exist {
99+ if hasStruct ( output .Type ) {
100100 bindStructType [lang ](output .Type , structs )
101101 }
102102 }
@@ -119,14 +119,11 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
119119 normalized .Inputs = make ([]abi.Argument , len (original .Inputs ))
120120 copy (normalized .Inputs , original .Inputs )
121121 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 )
130127 }
131128 }
132129 // Append the event to the accumulator list
@@ -244,7 +241,7 @@ func bindBasicTypeGo(kind abi.Type) string {
244241func bindTypeGo (kind abi.Type , structs map [string ]* tmplStruct ) string {
245242 switch kind .T {
246243 case abi .TupleTy :
247- return structs [kind .String ()].Name
244+ return structs [kind .TupleRawName + kind . String ()].Name
248245 case abi .ArrayTy :
249246 return fmt .Sprintf ("[%d]" , kind .Size ) + bindTypeGo (* kind .Elem , structs )
250247 case abi .SliceTy :
@@ -321,7 +318,7 @@ func pluralizeJavaType(typ string) string {
321318func bindTypeJava (kind abi.Type , structs map [string ]* tmplStruct ) string {
322319 switch kind .T {
323320 case abi .TupleTy :
324- return structs [kind .String ()].Name
321+ return structs [kind .TupleRawName + kind . String ()].Name
325322 case abi .ArrayTy , abi .SliceTy :
326323 return pluralizeJavaType (bindTypeJava (* kind .Elem , structs ))
327324 default :
@@ -340,6 +337,13 @@ var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct)
340337// funcionality as for simple types, but dynamic types get converted to hashes.
341338func bindTopicTypeGo (kind abi.Type , structs map [string ]* tmplStruct ) string {
342339 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.
343347 if bound == "string" || bound == "[]byte" {
344348 bound = "common.Hash"
345349 }
@@ -350,6 +354,13 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
350354// funcionality as for simple types, but dynamic types get converted to hashes.
351355func bindTopicTypeJava (kind abi.Type , structs map [string ]* tmplStruct ) string {
352356 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.
353364 if bound == "String" || bound == "byte[]" {
354365 bound = "Hash"
355366 }
@@ -369,16 +380,26 @@ var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct
369380func bindStructTypeGo (kind abi.Type , structs map [string ]* tmplStruct ) string {
370381 switch kind .T {
371382 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 {
373391 return s .Name
374392 }
375393 var fields []* tmplField
376394 for i , elem := range kind .TupleElems {
377395 field := bindStructTypeGo (* elem , structs )
378396 fields = append (fields , & tmplField {Type : field , Name : capitalise (kind .TupleRawNames [i ]), SolKind : * elem })
379397 }
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 {
382403 Name : name ,
383404 Fields : fields ,
384405 }
@@ -398,16 +419,26 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
398419func bindStructTypeJava (kind abi.Type , structs map [string ]* tmplStruct ) string {
399420 switch kind .T {
400421 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 {
402430 return s .Name
403431 }
404432 var fields []* tmplField
405433 for i , elem := range kind .TupleElems {
406434 field := bindStructTypeJava (* elem , structs )
407435 fields = append (fields , & tmplField {Type : field , Name : decapitalise (kind .TupleRawNames [i ]), SolKind : * elem })
408436 }
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 {
411442 Name : name ,
412443 Fields : fields ,
413444 }
@@ -497,6 +528,21 @@ func structured(args abi.Arguments) bool {
497528 return true
498529}
499530
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+
500546// resolveArgName converts a raw argument representation into a user friendly format.
501547func resolveArgName (arg abi.Argument , structs map [string ]* tmplStruct ) string {
502548 var (
@@ -512,7 +558,7 @@ loop:
512558 case abi .ArrayTy :
513559 prefix += fmt .Sprintf ("[%d]" , typ .Size )
514560 default :
515- embedded = typ .String ()
561+ embedded = typ .TupleRawName + typ . String ()
516562 break loop
517563 }
518564 typ = typ .Elem
0 commit comments