From 9beac096fc08b5df6f9e5d51c2a04750cd2bfe35 Mon Sep 17 00:00:00 2001 From: Fedor Ivanov Date: Thu, 7 Mar 2024 11:53:42 +0000 Subject: [PATCH 1/3] Fix parsing tuples --- lib/abi/function_selector.ex | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/lib/abi/function_selector.ex b/lib/abi/function_selector.ex index 04d1d5d..6af9db2 100644 --- a/lib/abi/function_selector.ex +++ b/lib/abi/function_selector.ex @@ -311,34 +311,25 @@ defmodule ABI.FunctionSelector do end end - @doc false - def parse_specification_type(%{"type" => "tuple", "components" => components}) do - sub_types = for component <- components, do: parse_specification_type(component) - {:tuple, sub_types} + def replace_tuple({:array, inner}, sub_types) do + {:array, replace_tuple(inner, sub_types)} end - def parse_specification_type(%{"type" => "tuple[]", "components" => components}) do - sub_types = for component <- components, do: parse_specification_type(component) - {:array, {:tuple, sub_types}} + def replace_tuple({:array, inner, size}, sub_types) do + {:array, replace_tuple(inner, sub_types), size} end - def parse_specification_type(%{"type" => "tuple[][]", "components" => components}) do - sub_types = for component <- components, do: parse_specification_type(component) - {:array, {:array, {:tuple, sub_types}}} + def replace_tuple(:tuple, sub_types) do + {:tuple, sub_types} end - def parse_specification_type(%{ - "type" => "tuple[" <> tail, - "components" => components - }) do - sub_types = for component <- components, do: parse_specification_type(component) - - size = - tail - |> String.replace("]", "") - |> String.to_integer() + def replace_tuple(other, _) do + other + end - {:array, {:tuple, sub_types}, size} + def parse_specification_type(%{"type" => "tuple" <> _ = type, "components" => components}) do + sub_types = for component <- components, do: parse_specification_type(component) + decode_type(type) |> replace_tuple(sub_types) end def parse_specification_type(%{"type" => type}), do: decode_type(type) From 319a7950e877410d9e10ceebad7b160bdf0205a1 Mon Sep 17 00:00:00 2001 From: Fedor Ivanov Date: Thu, 7 Mar 2024 14:33:00 +0000 Subject: [PATCH 2/3] Add regression test for `tuple` parsing --- test/abi/function_selector_test.exs | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/abi/function_selector_test.exs b/test/abi/function_selector_test.exs index f0f40f2..9a9cb71 100644 --- a/test/abi/function_selector_test.exs +++ b/test/abi/function_selector_test.exs @@ -345,6 +345,38 @@ defmodule ABI.FunctionSelectorTest do assert expected_type == selector.types end + test "parses fixed 2D array of tuples" do + function = %{ + "inputs" => [], + "name" => "createTupleArray", + "outputs" => [ + %{ + "components" => [ + %{ + "internalType" => "uint256", + "name" => "element1", + "type" => "uint256" + }, + %{"internalType" => "bool", "name" => "element2", "type" => "bool"} + ], + "internalType" => "struct StorageB.MyTuple[2][]", + "name" => "", + "type" => "tuple[2][]" + } + ], + "stateMutability" => "pure", + "type" => "function" + } + + expected = [ + array: {:array, {:tuple, [{:uint, 256}, :bool]}, 2} + ] + + selector = FunctionSelector.parse_specification_item(function) + + assert expected == selector.returns + end + test "with stateMutability set" do ~w(pure view nonpayable payable) |> Enum.zip(~w(pure view non_payable payable)a) From f47f7b81e8537d3679984362523ca4f35202a123 Mon Sep 17 00:00:00 2001 From: Fedor Ivanov Date: Tue, 12 Mar 2024 11:43:51 +0000 Subject: [PATCH 3/3] Apply suggestions --- lib/abi/function_selector.ex | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/abi/function_selector.ex b/lib/abi/function_selector.ex index 6af9db2..fa6ae37 100644 --- a/lib/abi/function_selector.ex +++ b/lib/abi/function_selector.ex @@ -311,25 +311,28 @@ defmodule ABI.FunctionSelector do end end - def replace_tuple({:array, inner}, sub_types) do + defp replace_tuple({:array, inner}, sub_types) do {:array, replace_tuple(inner, sub_types)} end - def replace_tuple({:array, inner, size}, sub_types) do + defp replace_tuple({:array, inner, size}, sub_types) do {:array, replace_tuple(inner, sub_types), size} end - def replace_tuple(:tuple, sub_types) do + defp replace_tuple(:tuple, sub_types) do {:tuple, sub_types} end - def replace_tuple(other, _) do + defp replace_tuple(other, _) do other end def parse_specification_type(%{"type" => "tuple" <> _ = type, "components" => components}) do sub_types = for component <- components, do: parse_specification_type(component) - decode_type(type) |> replace_tuple(sub_types) + + type + |> decode_type() + |> replace_tuple(sub_types) end def parse_specification_type(%{"type" => type}), do: decode_type(type)