@@ -390,6 +390,166 @@ func NewTypeAsString(t string, internalType string, components []ArgumentMarshal
390390 return
391391}
392392
393+ // NewTypeAsString creates a new reflection type of abi type given in t.
394+ func NewTypeAsString (t string , internalType string , components []ArgumentMarshaling ) (typ Type , err error ) {
395+ // check that array brackets are equal if they exist
396+ if strings .Count (t , "[" ) != strings .Count (t , "]" ) {
397+ return Type {}, errors .New ("invalid arg type in abi" )
398+ }
399+ typ .stringKind = t
400+
401+ // if there are brackets, get ready to go into slice/array mode and
402+ // recursively create the type
403+ if strings .Count (t , "[" ) != 0 {
404+ // Note internalType can be empty here.
405+ subInternal := internalType
406+ if i := strings .LastIndex (internalType , "[" ); i != - 1 {
407+ subInternal = subInternal [:i ]
408+ }
409+ // recursively embed the type
410+ i := strings .LastIndex (t , "[" )
411+ embeddedType , err := NewTypeAsString (t [:i ], subInternal , components )
412+ if err != nil {
413+ return Type {}, err
414+ }
415+ // grab the last cell and create a type from there
416+ sliced := t [i :]
417+ // grab the slice size with regexp
418+ re := regexp .MustCompile ("[0-9]+" )
419+ intz := re .FindAllString (sliced , - 1 )
420+
421+ if len (intz ) == 0 {
422+ // is a slice
423+ typ .T = SliceTy
424+ typ .Elem = & embeddedType
425+ typ .stringKind = embeddedType .stringKind + sliced
426+ } else if len (intz ) == 1 {
427+ // is an array
428+ typ .T = ArrayTy
429+ typ .Elem = & embeddedType
430+ typ .Size , err = strconv .Atoi (intz [0 ])
431+ if err != nil {
432+ return Type {}, fmt .Errorf ("abi: error parsing variable size: %v" , err )
433+ }
434+ typ .stringKind = embeddedType .stringKind + sliced
435+ } else {
436+ return Type {}, errors .New ("invalid formatting of array type" )
437+ }
438+ return typ , err
439+ }
440+ // parse the type and size of the abi-type.
441+ matches := typeRegex .FindAllStringSubmatch (t , - 1 )
442+ if len (matches ) == 0 {
443+ return Type {}, fmt .Errorf ("invalid type '%v'" , t )
444+ }
445+ parsedType := matches [0 ]
446+
447+ // varSize is the size of the variable
448+ var varSize int
449+ if len (parsedType [3 ]) > 0 {
450+ var err error
451+ varSize , err = strconv .Atoi (parsedType [2 ])
452+ if err != nil {
453+ return Type {}, fmt .Errorf ("abi: error parsing variable size: %v" , err )
454+ }
455+ } else {
456+ if parsedType [0 ] == "uint" || parsedType [0 ] == "int" {
457+ // this should fail because it means that there's something wrong with
458+ // the abi type (the compiler should always format it to the size...always)
459+ return Type {}, fmt .Errorf ("unsupported arg type: %s" , t )
460+ }
461+ }
462+ // varType is the parsed abi type
463+ switch varType := parsedType [1 ]; varType {
464+ case "int" :
465+ typ .Size = varSize
466+ typ .T = IntTy
467+ case "uint" :
468+ typ .Size = varSize
469+ typ .T = UintTy
470+ case "bool" :
471+ typ .T = BoolTy
472+ case "address" :
473+ typ .Size = 20
474+ typ .T = AddressTy
475+ case "string" :
476+ typ .T = StringTy
477+ case "bytes" :
478+ if varSize == 0 {
479+ typ .T = BytesTy
480+ } else {
481+ if varSize > 32 {
482+ return Type {}, fmt .Errorf ("unsupported arg type: %s" , t )
483+ }
484+ typ .T = FixedBytesTy
485+ typ .Size = varSize
486+ }
487+ case "tuple" :
488+ var (
489+ fields []reflect.StructField
490+ elems []* Type
491+ names []string
492+ expression string // canonical parameter expression
493+ used = make (map [string ]bool )
494+ )
495+ expression += "("
496+ for idx , c := range components {
497+ cType , err := NewTypeAsString (c .Type , c .InternalType , c .Components )
498+ if err != nil {
499+ return Type {}, err
500+ }
501+ name := ToCamelCase (c .Name )
502+ if name == "" {
503+ return Type {}, errors .New ("abi: purely anonymous or underscored field is not supported" )
504+ }
505+ fieldName := ResolveNameConflict (name , func (s string ) bool { return used [s ] })
506+ if err != nil {
507+ return Type {}, err
508+ }
509+ used [fieldName ] = true
510+ if ! isValidFieldName (fieldName ) {
511+ return Type {}, fmt .Errorf ("field %d has invalid name" , idx )
512+ }
513+ fields = append (fields , reflect.StructField {
514+ Name : fieldName , // reflect.StructOf will panic for any exported field.
515+ Type : cType .GetTypeAsString (),
516+ Tag : reflect .StructTag ("json:\" " + c .Name + "\" " ),
517+ })
518+ elems = append (elems , & cType )
519+ names = append (names , c .Name )
520+ expression += cType .stringKind
521+ if idx != len (components )- 1 {
522+ expression += ","
523+ }
524+ }
525+ expression += ")"
526+
527+ typ .TupleType = reflect .StructOf (fields )
528+ typ .TupleElems = elems
529+ typ .TupleRawNames = names
530+ typ .T = TupleTy
531+ typ .stringKind = expression
532+
533+ const structPrefix = "struct "
534+ // After solidity 0.5.10, a new field of abi "internalType"
535+ // is introduced. From that we can obtain the struct name
536+ // user defined in the source code.
537+ if internalType != "" && strings .HasPrefix (internalType , structPrefix ) {
538+ // Foo.Bar type definition is not allowed in golang,
539+ // convert the format to FooBar
540+ typ .TupleRawName = strings .ReplaceAll (internalType [len (structPrefix ):], "." , "" )
541+ }
542+
543+ case "function" :
544+ typ .T = FunctionTy
545+ typ .Size = 24
546+ default :
547+ return Type {}, fmt .Errorf ("unsupported arg type: %s" , t )
548+ }
549+
550+ return
551+ }
552+
393553// GetType returns the reflection type of the ABI type.
394554func (t Type ) GetType () reflect.Type {
395555 switch t .T {
@@ -458,6 +618,42 @@ func (t Type) GetTypeAsString() reflect.Type {
458618 }
459619}
460620
621+ // GetTypeAsString returns the reflection type of the ABI type (always string).
622+ func (t Type ) GetTypeAsString () reflect.Type {
623+ switch t .T {
624+ case IntTy :
625+ return reflect .TypeOf ("" )
626+ case UintTy :
627+ return reflect .TypeOf ("" )
628+ case BoolTy :
629+ return reflect .TypeOf ("" )
630+ case StringTy :
631+ return reflect .TypeOf ("" )
632+ case SliceTy :
633+ return reflect .SliceOf (t .Elem .GetTypeAsString ())
634+ case ArrayTy :
635+ return reflect .ArrayOf (t .Size , t .Elem .GetTypeAsString ())
636+ case TupleTy :
637+ return t .TupleType
638+ case AddressTy :
639+ return reflect .TypeOf ("" )
640+ case FixedBytesTy :
641+ return reflect .TypeOf ("" )
642+ case BytesTy :
643+ return reflect .TypeOf ("" )
644+ case HashTy :
645+ // hashtype currently not used
646+ return reflect .TypeOf ("" )
647+ case FixedPointTy :
648+ // fixedpoint type currently not used
649+ return reflect .TypeOf ("" )
650+ case FunctionTy :
651+ return reflect .TypeOf ("" )
652+ default :
653+ panic ("Invalid type" )
654+ }
655+ }
656+
461657// String implements Stringer.
462658func (t Type ) String () (out string ) {
463659 return t .stringKind
0 commit comments