@@ -226,6 +226,166 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
226226 return
227227}
228228
229+ // NewTypeAsString creates a new reflection type of abi type given in t.
230+ func NewTypeAsString (t string , internalType string , components []ArgumentMarshaling ) (typ Type , err error ) {
231+ // check that array brackets are equal if they exist
232+ if strings .Count (t , "[" ) != strings .Count (t , "]" ) {
233+ return Type {}, errors .New ("invalid arg type in abi" )
234+ }
235+ typ .stringKind = t
236+
237+ // if there are brackets, get ready to go into slice/array mode and
238+ // recursively create the type
239+ if strings .Count (t , "[" ) != 0 {
240+ // Note internalType can be empty here.
241+ subInternal := internalType
242+ if i := strings .LastIndex (internalType , "[" ); i != - 1 {
243+ subInternal = subInternal [:i ]
244+ }
245+ // recursively embed the type
246+ i := strings .LastIndex (t , "[" )
247+ embeddedType , err := NewTypeAsString (t [:i ], subInternal , components )
248+ if err != nil {
249+ return Type {}, err
250+ }
251+ // grab the last cell and create a type from there
252+ sliced := t [i :]
253+ // grab the slice size with regexp
254+ re := regexp .MustCompile ("[0-9]+" )
255+ intz := re .FindAllString (sliced , - 1 )
256+
257+ if len (intz ) == 0 {
258+ // is a slice
259+ typ .T = SliceTy
260+ typ .Elem = & embeddedType
261+ typ .stringKind = embeddedType .stringKind + sliced
262+ } else if len (intz ) == 1 {
263+ // is an array
264+ typ .T = ArrayTy
265+ typ .Elem = & embeddedType
266+ typ .Size , err = strconv .Atoi (intz [0 ])
267+ if err != nil {
268+ return Type {}, fmt .Errorf ("abi: error parsing variable size: %v" , err )
269+ }
270+ typ .stringKind = embeddedType .stringKind + sliced
271+ } else {
272+ return Type {}, errors .New ("invalid formatting of array type" )
273+ }
274+ return typ , err
275+ }
276+ // parse the type and size of the abi-type.
277+ matches := typeRegex .FindAllStringSubmatch (t , - 1 )
278+ if len (matches ) == 0 {
279+ return Type {}, fmt .Errorf ("invalid type '%v'" , t )
280+ }
281+ parsedType := matches [0 ]
282+
283+ // varSize is the size of the variable
284+ var varSize int
285+ if len (parsedType [3 ]) > 0 {
286+ var err error
287+ varSize , err = strconv .Atoi (parsedType [2 ])
288+ if err != nil {
289+ return Type {}, fmt .Errorf ("abi: error parsing variable size: %v" , err )
290+ }
291+ } else {
292+ if parsedType [0 ] == "uint" || parsedType [0 ] == "int" {
293+ // this should fail because it means that there's something wrong with
294+ // the abi type (the compiler should always format it to the size...always)
295+ return Type {}, fmt .Errorf ("unsupported arg type: %s" , t )
296+ }
297+ }
298+ // varType is the parsed abi type
299+ switch varType := parsedType [1 ]; varType {
300+ case "int" :
301+ typ .Size = varSize
302+ typ .T = IntTy
303+ case "uint" :
304+ typ .Size = varSize
305+ typ .T = UintTy
306+ case "bool" :
307+ typ .T = BoolTy
308+ case "address" :
309+ typ .Size = 20
310+ typ .T = AddressTy
311+ case "string" :
312+ typ .T = StringTy
313+ case "bytes" :
314+ if varSize == 0 {
315+ typ .T = BytesTy
316+ } else {
317+ if varSize > 32 {
318+ return Type {}, fmt .Errorf ("unsupported arg type: %s" , t )
319+ }
320+ typ .T = FixedBytesTy
321+ typ .Size = varSize
322+ }
323+ case "tuple" :
324+ var (
325+ fields []reflect.StructField
326+ elems []* Type
327+ names []string
328+ expression string // canonical parameter expression
329+ used = make (map [string ]bool )
330+ )
331+ expression += "("
332+ for idx , c := range components {
333+ cType , err := NewTypeAsString (c .Type , c .InternalType , c .Components )
334+ if err != nil {
335+ return Type {}, err
336+ }
337+ name := ToCamelCase (c .Name )
338+ if name == "" {
339+ return Type {}, errors .New ("abi: purely anonymous or underscored field is not supported" )
340+ }
341+ fieldName := ResolveNameConflict (name , func (s string ) bool { return used [s ] })
342+ if err != nil {
343+ return Type {}, err
344+ }
345+ used [fieldName ] = true
346+ if ! isValidFieldName (fieldName ) {
347+ return Type {}, fmt .Errorf ("field %d has invalid name" , idx )
348+ }
349+ fields = append (fields , reflect.StructField {
350+ Name : fieldName , // reflect.StructOf will panic for any exported field.
351+ Type : cType .GetTypeAsString (),
352+ Tag : reflect .StructTag ("json:\" " + c .Name + "\" " ),
353+ })
354+ elems = append (elems , & cType )
355+ names = append (names , c .Name )
356+ expression += cType .stringKind
357+ if idx != len (components )- 1 {
358+ expression += ","
359+ }
360+ }
361+ expression += ")"
362+
363+ typ .TupleType = reflect .StructOf (fields )
364+ typ .TupleElems = elems
365+ typ .TupleRawNames = names
366+ typ .T = TupleTy
367+ typ .stringKind = expression
368+
369+ const structPrefix = "struct "
370+ // After solidity 0.5.10, a new field of abi "internalType"
371+ // is introduced. From that we can obtain the struct name
372+ // user defined in the source code.
373+ if internalType != "" && strings .HasPrefix (internalType , structPrefix ) {
374+ // Foo.Bar type definition is not allowed in golang,
375+ // convert the format to FooBar
376+ typ .TupleRawName = strings .ReplaceAll (internalType [len (structPrefix ):], "." , "" )
377+ }
378+
379+ case "function" :
380+ typ .T = FunctionTy
381+ typ .Size = 24
382+ default :
383+ return Type {}, fmt .Errorf ("unsupported arg type: %s" , t )
384+ }
385+
386+ return
387+ }
388+
229389// GetType returns the reflection type of the ABI type.
230390func (t Type ) GetType () reflect.Type {
231391 switch t .T {
@@ -262,6 +422,42 @@ func (t Type) GetType() reflect.Type {
262422 }
263423}
264424
425+ // GetTypeAsString returns the reflection type of the ABI type (always string).
426+ func (t Type ) GetTypeAsString () reflect.Type {
427+ switch t .T {
428+ case IntTy :
429+ return reflect .TypeOf ("" )
430+ case UintTy :
431+ return reflect .TypeOf ("" )
432+ case BoolTy :
433+ return reflect .TypeOf ("" )
434+ case StringTy :
435+ return reflect .TypeOf ("" )
436+ case SliceTy :
437+ return reflect .SliceOf (t .Elem .GetTypeAsString ())
438+ case ArrayTy :
439+ return reflect .ArrayOf (t .Size , t .Elem .GetTypeAsString ())
440+ case TupleTy :
441+ return t .TupleType
442+ case AddressTy :
443+ return reflect .TypeOf ("" )
444+ case FixedBytesTy :
445+ return reflect .TypeOf ("" )
446+ case BytesTy :
447+ return reflect .TypeOf ("" )
448+ case HashTy :
449+ // hashtype currently not used
450+ return reflect .TypeOf ("" )
451+ case FixedPointTy :
452+ // fixedpoint type currently not used
453+ return reflect .TypeOf ("" )
454+ case FunctionTy :
455+ return reflect .TypeOf ("" )
456+ default :
457+ panic ("Invalid type" )
458+ }
459+ }
460+
265461// String implements Stringer.
266462func (t Type ) String () (out string ) {
267463 return t .stringKind
0 commit comments