diff --git a/src/Nethereum.ABI/FunctionEncoding/ParameterDecoder.cs b/src/Nethereum.ABI/FunctionEncoding/ParameterDecoder.cs index 5f17a686d..c6c6fc128 100644 --- a/src/Nethereum.ABI/FunctionEncoding/ParameterDecoder.cs +++ b/src/Nethereum.ABI/FunctionEncoding/ParameterDecoder.cs @@ -138,18 +138,7 @@ public List GetParameterOutputsFromAttributes(PropertyI } else if (parameterAttribute.Parameter.ABIType is ArrayType arrayType) { - if (arrayType.ElementType is TupleType tupleTypeElement) - { -#if NETSTANDARD1_1 || PCL && !NET35 - var type = property.PropertyType.GenericTypeArguments.FirstOrDefault(); -#else - var type = property.PropertyType.GetGenericArguments().FirstOrDefault(); -#endif - if (type == null) throw new Exception("Tuple array has to decode to a IList: " + parameterAttribute.Parameter.Name); - - attributesToABIExtractor.InitTupleComponentsFromTypeAttributes(type, - tupleTypeElement); - } + InitTupleElementFromArray(property, parameterAttribute, arrayType); parameterAttribute.Parameter.DecodedType = property.PropertyType; } @@ -164,6 +153,41 @@ public List GetParameterOutputsFromAttributes(PropertyI return parameterObjects; } + private void InitTupleElementFromArray(PropertyInfo property, ParameterAttribute parameterAttribute, ArrayType arrayType, int depth = 1) + { + if (arrayType.ElementType is TupleType tupleTypeElement) + { + var type = GetListElementType(property.PropertyType, depth); + if (type == null) throw new Exception("Tuple array has to decode to a IList: " + parameterAttribute.Parameter.Name); + + attributesToABIExtractor.InitTupleComponentsFromTypeAttributes(type, + tupleTypeElement); + } + + if(arrayType.ElementType is ArrayType arrayElementType) + { + InitTupleElementFromArray(property, parameterAttribute, arrayElementType, depth + 1); + } + } + + private Type GetListElementType(Type startType, int depthOfLists) + { +#if NETSTANDARD1_1 || PCL && !NET35 + var type = startType.GenericTypeArguments.FirstOrDefault(); +#else + var type = startType.GetGenericArguments().FirstOrDefault(); +#endif + for(int i = 1; i < depthOfLists; i++) + { +#if NETSTANDARD1_1 || PCL && !NET35 + type = type.GenericTypeArguments.FirstOrDefault(); +#else + type = type.GetGenericArguments().FirstOrDefault(); +#endif + } + return type; + + } public List GetParameterOutputsFromAttributes(Type type) { diff --git a/tests/Nethereum.ABI.UnitTests/FunctionMultidimensionalStructNonDynamicArrayDecodingTests.cs b/tests/Nethereum.ABI.UnitTests/FunctionMultidimensionalStructNonDynamicArrayDecodingTests.cs new file mode 100644 index 000000000..5d3421c65 --- /dev/null +++ b/tests/Nethereum.ABI.UnitTests/FunctionMultidimensionalStructNonDynamicArrayDecodingTests.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using System.Numerics; +using Nethereum.ABI.FunctionEncoding; +using Nethereum.ABI.FunctionEncoding.Attributes; +using Xunit; + +namespace Nethereum.ABI.UnitTests +{ + public class FunctionMultidimensionalStructNonDynamicArrayDecodingTests + { + public partial class TestStruct : TestStructBase { } + + public class TestStructBase + { + [Parameter("uint256", "x", 1)] + public virtual BigInteger X { get; set; } + [Parameter("uint256", "y", 2)] + public virtual BigInteger Y { get; set; } + [Parameter("uint256", "z", 3)] + public virtual BigInteger Z { get; set; } + } + + public partial class GetTestStruct3dOutputDTO : GetTestStruct3dOutputDTOBase { } + + [FunctionOutput] + public class GetTestStruct3dOutputDTOBase : IFunctionOutputDTO + { + [Parameter("tuple[][][]", "testStructs", 1)] + public virtual List>> TestStructs { get; set; } + } + + /* + function getTestStruct3d() public view returns (TestStruct[][][] memory testStructs) { + uint256 maxX = 2; + uint256 maxY = 2; + + testStructs = new TestStruct[][][](maxX); + for (uint256 x; x < maxY; x++) { + + testStructs[x] = new TestStruct[][](maxY); + for (uint256 y; y < maxY; y++) { + testStructs[x][y] = getTestStruct(x, y, 2); + } + } + } + + struct TestStruct { + uint256 x; + uint256 y; + uint256 z; + } + + function getTestStruct(uint x ,uint256 y, uint256 z) public view returns (TestStruct[] memory testStruct) + { + testStruct = new TestStruct[](z); + for (uint256 a = 0; a < z; a++) { + + testStruct[a] = + TestStruct(x, + y, + a); + + } + } + */ + + + [Fact] + public void ShouldDecode3dArrayWithStructsAsNonDynamic() + { + var output = "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"; + var functionDecoder = new FunctionCallDecoder(); + var result = functionDecoder.DecodeFunctionOutput(output); + Assert.Equal(1, result.TestStructs[1][1][1].Y); + Assert.Equal(1, result.TestStructs[1][1][1].Z); + Assert.Equal(1, result.TestStructs[1][1][1].X); + + } + + + } +} \ No newline at end of file