From 1a737cfb6326bdb16551f31f404ae2733e5a3f6b Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 24 Oct 2024 23:02:03 +0700 Subject: [PATCH 1/2] Support Tuple Deserialization into Arrays & Lists --- .../Thirdweb.Contracts.Tests.cs | 20 +++++++++++++++++++ .../Thirdweb.Contracts/ThirdwebContract.cs | 16 ++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index 2e88ce8b..b2c9293a 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -102,6 +102,26 @@ public async Task PrepareTest_NoSig() Assert.Contains("Method signature not found in contract ABI.", exception.Message); } + [Fact(Timeout = 120000)] + public async Task ReadTest_TupleIntoArray() + { + var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614); + var result = await contract.Read>("getReserves"); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.True(result.Count == 3); + } + + [Fact(Timeout = 120000)] + public async Task ReadTest_TupleIntoList() + { + var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614); + var result = await contract.Read>("getReserves"); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.True(result.Count == 3); + } + private sealed class AllowlistProof { public List Proof { get; set; } = new List(); diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 3f7a45eb..aae10476 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -1,6 +1,9 @@ using System.Numerics; +using Nethereum.ABI.FunctionEncoding; +using Nethereum.ABI.Model; using Nethereum.Contracts; using Nethereum.Hex.HexTypes; +using Newtonsoft.Json; namespace Thirdweb; @@ -119,7 +122,18 @@ public static async Task Read(ThirdwebContract contract, string method, pa var data = function.GetData(parameters); var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data }, "latest").ConfigureAwait(false); - return function.DecodeTypeOutput(resultData); + if ((typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(List<>)) || typeof(T).IsArray) + { + var functionAbi = contractRaw.ContractBuilder.ContractABI.FindFunctionABIFromInputData(data); + var outputList = new FunctionCallDecoder().DecodeDefaultData(resultData.HexToBytes(), functionAbi.OutputParameters); + var resultList = outputList.Select(x => x.Result).ToList(); + var json = JsonConvert.SerializeObject(resultList); + return JsonConvert.DeserializeObject(json); + } + else + { + return function.DecodeTypeOutput(resultData); + } } /// From 150f1164bdef80587d752b32a33b6e8eb3dc9fc8 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 25 Oct 2024 01:56:10 +0700 Subject: [PATCH 2/2] handle complex tuples (2 levels deep) --- .../Thirdweb.Contracts/ThirdwebContract.cs | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index aae10476..dfcff81d 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -125,10 +125,31 @@ public static async Task Read(ThirdwebContract contract, string method, pa if ((typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(List<>)) || typeof(T).IsArray) { var functionAbi = contractRaw.ContractBuilder.ContractABI.FindFunctionABIFromInputData(data); + var decoder = new FunctionCallDecoder(); var outputList = new FunctionCallDecoder().DecodeDefaultData(resultData.HexToBytes(), functionAbi.OutputParameters); var resultList = outputList.Select(x => x.Result).ToList(); - var json = JsonConvert.SerializeObject(resultList); - return JsonConvert.DeserializeObject(json); + + if (typeof(T) == typeof(List)) + { + return (T)(object)resultList; + } + + if (typeof(T) == typeof(object[])) + { + return (T)(object)resultList.ToArray(); + } + + try + { + var json = JsonConvert.SerializeObject(resultList); + return JsonConvert.DeserializeObject(json); + } + catch (Exception) + { + var dict = outputList.ConvertToObjectDictionary(); + var ser = JsonConvert.SerializeObject(dict.First().Value); + return JsonConvert.DeserializeObject(ser); + } } else {