diff --git a/lib/abi/type_decoder.ex b/lib/abi/type_decoder.ex index edbcaae..c78974a 100644 --- a/lib/abi/type_decoder.ex +++ b/lib/abi/type_decoder.ex @@ -253,7 +253,7 @@ defmodule ABI.TypeDecoder do end defp decode_type({:array, type, size}, data) do - types = List.duplicate(type, size) + types = Stream.duplicate(type, size) {tuple, bytes} = decode_type({:tuple, types}, data) {Tuple.to_list(tuple), bytes} @@ -298,9 +298,9 @@ defmodule ABI.TypeDecoder do defp decode_type({:array, type}, data, full_data) do {offset, rest_bytes} = decode_uint(data, 256) <<_padding::binary-size(offset), rest_data::binary>> = full_data - {count, bytes} = decode_uint(rest_data, 256) + {size, bytes} = decode_uint(rest_data, 256) - types = List.duplicate(type, count) + types = Stream.duplicate(type, size) {tuple, _bytes} = decode_type({:tuple, types}, bytes) {Tuple.to_list(tuple), rest_bytes} @@ -310,7 +310,7 @@ defmodule ABI.TypeDecoder do {offset, rest_bytes} = decode_uint(data, 256) <<_padding::binary-size(offset), rest_data::binary>> = full_data - types = List.duplicate(type, size) + types = Stream.duplicate(type, size) {tuple, _} = decode_type({:tuple, types}, rest_data) diff --git a/test/abi/type_decoder_test.exs b/test/abi/type_decoder_test.exs index 4a4f253..4bd7615 100644 --- a/test/abi/type_decoder_test.exs +++ b/test/abi/type_decoder_test.exs @@ -713,6 +713,50 @@ defmodule ABI.TypeDecoderTest do assert [0x123, "Hello, world!"] == TypeDecoder.decode(data, types) assert data == data |> TypeDecoder.decode(types) |> TypeEncoder.encode(types) end + + test "handles huge number of list items while ABI decoding" do + selector = %FunctionSelector{ + function: "swapExactTokensForTokens", + method_id: <<42, 68, 63, 174>>, + type: :function, + inputs_indexed: nil, + state_mutability: :non_payable, + input_names: ["amountIn", "amountOutMin", "path", "to", "deadline"], + types: [ + {:uint, 256}, + {:uint, 256}, + {:tuple, [array: {:uint, 256}, array: {:uint, 8}, array: :address]}, + :address, + {:uint, 256} + ], + returns: [uint: 256], + return_names: ["amountOut"] + } + + data = + <<42, 68, 63, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 71, 248, 212, 138, 1, 180, 77, + 243, 255, 243, 93, 37, 138, 16, 163, 174, 220, 17, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 212, 153, 236, 108, 99, 56, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 154, 114, 216, 245, 100, 121, 144, + 58, 227, 134, 132, 158, 41, 13, 73, 56, 158, 65, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 233, 25, 9, 44, 199, 203, 210, 9, 122, 227, 21, 143, 114, 218, 72, 74, 200, 19, 183, + 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 134, 203, 129, 146, 34, 242, 134, 159, 7, + 202, 92, 60, 237, 11, 130, 38, 218, 44, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, + 168, 239, 101, 138, 224, 219, 204, 165, 88, 224, 178, 219, 217, 229, 25, 37, 24, 13, 50, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 245>> + + assert_raise MatchError, fn -> + TypeDecoder.decode(data, selector) + end + end end describe "with examples from solidity docs" do