@@ -226,6 +226,166 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
226
226
return
227
227
}
228
228
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
+
229
389
// GetType returns the reflection type of the ABI type.
230
390
func (t Type ) GetType () reflect.Type {
231
391
switch t .T {
@@ -262,6 +422,42 @@ func (t Type) GetType() reflect.Type {
262
422
}
263
423
}
264
424
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
+
265
461
// String implements Stringer.
266
462
func (t Type ) String () (out string ) {
267
463
return t .stringKind
0 commit comments