Skip to content

Commit e3dc19b

Browse files
authored
Fix parsing tuples (#164)
* Fix parsing tuples * Add regression test for `tuple` parsing * Apply suggestions
1 parent 5d63e8a commit e3dc19b

File tree

2 files changed

+46
-20
lines changed

2 files changed

+46
-20
lines changed

lib/abi/function_selector.ex

+14-20
Original file line numberDiff line numberDiff line change
@@ -311,34 +311,28 @@ defmodule ABI.FunctionSelector do
311311
end
312312
end
313313

314-
@doc false
315-
def parse_specification_type(%{"type" => "tuple", "components" => components}) do
316-
sub_types = for component <- components, do: parse_specification_type(component)
317-
{:tuple, sub_types}
314+
defp replace_tuple({:array, inner}, sub_types) do
315+
{:array, replace_tuple(inner, sub_types)}
318316
end
319317

320-
def parse_specification_type(%{"type" => "tuple[]", "components" => components}) do
321-
sub_types = for component <- components, do: parse_specification_type(component)
322-
{:array, {:tuple, sub_types}}
318+
defp replace_tuple({:array, inner, size}, sub_types) do
319+
{:array, replace_tuple(inner, sub_types), size}
323320
end
324321

325-
def parse_specification_type(%{"type" => "tuple[][]", "components" => components}) do
326-
sub_types = for component <- components, do: parse_specification_type(component)
327-
{:array, {:array, {:tuple, sub_types}}}
322+
defp replace_tuple(:tuple, sub_types) do
323+
{:tuple, sub_types}
328324
end
329325

330-
def parse_specification_type(%{
331-
"type" => "tuple[" <> tail,
332-
"components" => components
333-
}) do
334-
sub_types = for component <- components, do: parse_specification_type(component)
326+
defp replace_tuple(other, _) do
327+
other
328+
end
335329

336-
size =
337-
tail
338-
|> String.replace("]", "")
339-
|> String.to_integer()
330+
def parse_specification_type(%{"type" => "tuple" <> _ = type, "components" => components}) do
331+
sub_types = for component <- components, do: parse_specification_type(component)
340332

341-
{:array, {:tuple, sub_types}, size}
333+
type
334+
|> decode_type()
335+
|> replace_tuple(sub_types)
342336
end
343337

344338
def parse_specification_type(%{"type" => type}), do: decode_type(type)

test/abi/function_selector_test.exs

+32
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,38 @@ defmodule ABI.FunctionSelectorTest do
345345
assert expected_type == selector.types
346346
end
347347

348+
test "parses fixed 2D array of tuples" do
349+
function = %{
350+
"inputs" => [],
351+
"name" => "createTupleArray",
352+
"outputs" => [
353+
%{
354+
"components" => [
355+
%{
356+
"internalType" => "uint256",
357+
"name" => "element1",
358+
"type" => "uint256"
359+
},
360+
%{"internalType" => "bool", "name" => "element2", "type" => "bool"}
361+
],
362+
"internalType" => "struct StorageB.MyTuple[2][]",
363+
"name" => "",
364+
"type" => "tuple[2][]"
365+
}
366+
],
367+
"stateMutability" => "pure",
368+
"type" => "function"
369+
}
370+
371+
expected = [
372+
array: {:array, {:tuple, [{:uint, 256}, :bool]}, 2}
373+
]
374+
375+
selector = FunctionSelector.parse_specification_item(function)
376+
377+
assert expected == selector.returns
378+
end
379+
348380
test "with stateMutability set" do
349381
~w(pure view nonpayable payable)
350382
|> Enum.zip(~w(pure view non_payable payable)a)

0 commit comments

Comments
 (0)