41
41
import org .web3j .abi .datatypes .NumericType ;
42
42
import org .web3j .abi .datatypes .StaticArray ;
43
43
import org .web3j .abi .datatypes .StaticStruct ;
44
+ import org .web3j .abi .datatypes .StructType ;
44
45
import org .web3j .abi .datatypes .Type ;
45
46
import org .web3j .abi .datatypes .Ufixed ;
46
47
import org .web3j .abi .datatypes .Uint ;
50
51
import org .web3j .abi .datatypes .primitive .Float ;
51
52
import org .web3j .utils .Numeric ;
52
53
54
+ import static org .web3j .abi .DefaultFunctionReturnDecoder .getDataOffset ;
53
55
import static org .web3j .abi .TypeReference .makeTypeReference ;
56
+ import static org .web3j .abi .Utils .getSimpleTypeName ;
57
+ import static org .web3j .abi .Utils .staticStructNestedPublicFieldsFlatList ;
54
58
55
59
/**
56
60
* Ethereum Contract Application Binary Interface (ABI) decoding for types. Decoding is not
@@ -252,13 +256,16 @@ static Type instantiateAtomicType(Class<?> referenceClass, Object value)
252
256
return (Type ) cons .newInstance (constructorArg );
253
257
}
254
258
259
+ @ SuppressWarnings ("unchecked" )
255
260
static <T extends Type > int getSingleElementLength (String input , int offset , Class <T > type ) {
256
261
if (input .length () == offset ) {
257
262
return 0 ;
258
263
} else if (DynamicBytes .class .isAssignableFrom (type )
259
264
|| Utf8String .class .isAssignableFrom (type )) {
260
265
// length field + data value
261
266
return (decodeUintAsInt (input , offset ) / Type .MAX_BYTE_LENGTH ) + 2 ;
267
+ } else if (StaticStruct .class .isAssignableFrom (type )) {
268
+ return staticStructNestedPublicFieldsFlatList ((Class <Type >) type ).size ();
262
269
} else {
263
270
return 1 ;
264
271
}
@@ -331,7 +338,7 @@ static <T extends Type> T decodeStaticArray(
331
338
throw new UnsupportedOperationException (
332
339
"Zero length fixed array is invalid type" );
333
340
} else {
334
- return instantiateStaticArray (typeReference , elements , length );
341
+ return instantiateStaticArray (elements , length );
335
342
}
336
343
};
337
344
@@ -353,6 +360,7 @@ public static <T extends Type> T decodeStaticStruct(
353
360
return decodeStaticStructElement (input , offset , typeReference , function );
354
361
}
355
362
363
+ @ SuppressWarnings ("unchecked" )
356
364
private static <T extends Type > T decodeStaticStructElement (
357
365
final String input ,
358
366
final int offset ,
@@ -374,11 +382,10 @@ private static <T extends Type> T decodeStaticStructElement(
374
382
final int length = constructor .getParameterCount ();
375
383
List <T > elements = new ArrayList <>(length );
376
384
377
- for (int i = 0 , currOffset = 0 ; i < length ; i ++) {
385
+ for (int i = 0 , currOffset = offset ; i < length ; i ++) {
378
386
T value ;
379
387
final Class <T > declaredField = (Class <T >) constructor .getParameterTypes ()[i ];
380
388
381
- System .out .println (currOffset );
382
389
if (StaticStruct .class .isAssignableFrom (declaredField )) {
383
390
final int nestedStructLength =
384
391
classType
@@ -401,7 +408,7 @@ private static <T extends Type> T decodeStaticStructElement(
401
408
elements .add (value );
402
409
}
403
410
404
- String typeName = Utils . getSimpleTypeName (classType );
411
+ String typeName = getSimpleTypeName (classType );
405
412
406
413
return consumer .apply (elements , typeName );
407
414
} catch (ClassNotFoundException e ) {
@@ -411,6 +418,7 @@ private static <T extends Type> T decodeStaticStructElement(
411
418
}
412
419
}
413
420
421
+ @ SuppressWarnings ("unchecked" )
414
422
private static <T extends Type > T instantiateStruct (
415
423
final TypeReference <T > typeReference , final List <T > parameters ) {
416
424
try {
@@ -464,6 +472,7 @@ static <T extends Type> T decodeDynamicStruct(
464
472
return decodeDynamicStructElements (input , offset , typeReference , function );
465
473
}
466
474
475
+ @ SuppressWarnings ("unchecked" )
467
476
private static <T extends Type > T decodeDynamicStructElements (
468
477
final String input ,
469
478
final int offset ,
@@ -495,8 +504,9 @@ private static <T extends Type> T decodeDynamicStructElements(
495
504
final int parameterOffset =
496
505
isOnlyParameterInStruct
497
506
? offset
498
- : decodeDynamicStructDynamicParameterOffset (
499
- input .substring (beginIndex , beginIndex + 64 ));
507
+ : (decodeDynamicStructDynamicParameterOffset (
508
+ input .substring (beginIndex , beginIndex + 64 )))
509
+ + offset ;
500
510
parameterOffsets .add (parameterOffset );
501
511
staticOffset += 64 ;
502
512
} else {
@@ -506,11 +516,15 @@ private static <T extends Type> T decodeDynamicStructElements(
506
516
input .substring (beginIndex ),
507
517
0 ,
508
518
TypeReference .create (declaredField ));
519
+ staticOffset +=
520
+ staticStructNestedPublicFieldsFlatList ((Class <Type >) classType )
521
+ .size ()
522
+ * MAX_BYTE_LENGTH_FOR_HEX_STRING ;
509
523
} else {
510
524
value = decode (input .substring (beginIndex ), 0 , declaredField );
525
+ staticOffset += value .bytes32PaddedLength () * 2 ;
511
526
}
512
527
parameters .put (i , value );
513
- staticOffset += value .bytes32PaddedLength () * 2 ;
514
528
}
515
529
}
516
530
int dynamicParametersProcessed = 0 ;
@@ -538,7 +552,7 @@ private static <T extends Type> T decodeDynamicStructElements(
538
552
}
539
553
}
540
554
541
- String typeName = Utils . getSimpleTypeName (classType );
555
+ String typeName = getSimpleTypeName (classType );
542
556
543
557
final List <T > elements = new ArrayList <>();
544
558
for (int i = 0 ; i < length ; ++i ) {
@@ -579,7 +593,7 @@ private static <T extends Type> T decodeDynamicParameterFromStruct(
579
593
}
580
594
581
595
private static int decodeDynamicStructDynamicParameterOffset (final String input ) {
582
- return (decodeUintAsInt (input , 0 ) * 2 ) + 64 ;
596
+ return (decodeUintAsInt (input , 0 ) * 2 );
583
597
}
584
598
585
599
static <T extends Type > boolean isDynamic (Class <T > parameter ) {
@@ -618,13 +632,11 @@ static List arrayToList(Object array) {
618
632
}
619
633
620
634
@ SuppressWarnings ("unchecked" )
621
- private static <T extends Type > T instantiateStaticArray (
622
- TypeReference <T > typeReference , List <T > elements , int length ) {
635
+ private static <T extends Type > T instantiateStaticArray (List <T > elements , int length ) {
623
636
try {
624
637
Class <? extends StaticArray > arrayClass =
625
638
(Class <? extends StaticArray >)
626
639
Class .forName ("org.web3j.abi.datatypes.generated.StaticArray" + length );
627
-
628
640
return (T ) arrayClass .getConstructor (List .class ).newInstance (elements );
629
641
} catch (ReflectiveOperationException e ) {
630
642
throw new UnsupportedOperationException (e );
@@ -640,24 +652,55 @@ private static <T extends Type> T decodeArrayElements(
640
652
641
653
try {
642
654
Class <T > cls = Utils .getParameterizedTypeFromArray (typeReference );
643
- if (Array .class .isAssignableFrom (cls )) {
644
- throw new UnsupportedOperationException (
645
- "Arrays of arrays are not currently supported for external functions, see"
646
- + "http://solidity.readthedocs.io/en/develop/types.html#members" );
647
- } else {
655
+ if (StructType .class .isAssignableFrom (cls )) {
648
656
List <T > elements = new ArrayList <>(length );
649
-
650
657
for (int i = 0 , currOffset = offset ;
651
658
i < length ;
652
659
i ++,
653
660
currOffset +=
654
661
getSingleElementLength (input , currOffset , cls )
655
662
* MAX_BYTE_LENGTH_FOR_HEX_STRING ) {
656
- T value = decode (input , currOffset , cls );
663
+ T value ;
664
+ if (DynamicStruct .class .isAssignableFrom (cls )) {
665
+ value =
666
+ TypeDecoder .decodeDynamicStruct (
667
+ input ,
668
+ offset + getDataOffset (input , currOffset , typeReference ),
669
+ TypeReference .create (cls ));
670
+ } else {
671
+ value =
672
+ TypeDecoder .decodeStaticStruct (
673
+ input , currOffset , TypeReference .create (cls ));
674
+ }
675
+ elements .add (value );
676
+ }
677
+
678
+ String typeName = getSimpleTypeName (cls );
679
+
680
+ return consumer .apply (elements , typeName );
681
+ } else if (Array .class .isAssignableFrom (cls )) {
682
+ throw new UnsupportedOperationException (
683
+ "Arrays of arrays are not currently supported for external functions, see"
684
+ + "http://solidity.readthedocs.io/en/develop/types.html#members" );
685
+ } else {
686
+ List <T > elements = new ArrayList <>(length );
687
+ int currOffset = offset ;
688
+ for (int i = 0 ; i < length ; i ++) {
689
+ T value ;
690
+ if (isDynamic (cls )) {
691
+ int hexStringDataOffset = getDataOffset (input , currOffset , typeReference );
692
+ value = decode (input , offset + hexStringDataOffset , cls );
693
+ currOffset += MAX_BYTE_LENGTH_FOR_HEX_STRING ;
694
+ } else {
695
+ value = decode (input , currOffset , cls );
696
+ currOffset +=
697
+ getSingleElementLength (input , currOffset , cls )
698
+ * MAX_BYTE_LENGTH_FOR_HEX_STRING ;
699
+ }
657
700
elements .add (value );
658
701
}
659
702
660
- String typeName = Utils . getSimpleTypeName (cls );
703
+ String typeName = getSimpleTypeName (cls );
661
704
662
705
return consumer .apply (elements , typeName );
663
706
}
0 commit comments