From 52f431bf1b3501174fbeee11668bfa896229fb64 Mon Sep 17 00:00:00 2001 From: antazoey Date: Wed, 31 Jan 2024 16:29:30 -0600 Subject: [PATCH] fix: array of structs or tuples when only 1 element would be weird (#1900) --- src/ape_ethereum/ecosystem.py | 16 +++++++++++- tests/functional/test_ecosystem.py | 41 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/ape_ethereum/ecosystem.py b/src/ape_ethereum/ecosystem.py index 497485f4e8..dc3d3b73ea 100644 --- a/src/ape_ethereum/ecosystem.py +++ b/src/ape_ethereum/ecosystem.py @@ -634,7 +634,21 @@ def decode_returndata(self, abi: MethodABI, raw_data: bytes) -> Tuple[Any, ...]: and isinstance(output_values, (list, tuple)) and len(output_values) == 1 ): - return ([o for o in output_values[0]],) + # Array of structs or tuples: don't convert to list + # Array of anything else: convert to single list + return ( + ( + [ + output_values[0], + ], + ) + if issubclass(type(output_values[0]), Struct) + else ([o for o in output_values[0]],) + ) + + elif returns_array(abi): + # Tuple with single item as the array. + return (output_values,) return tuple(output_values) diff --git a/tests/functional/test_ecosystem.py b/tests/functional/test_ecosystem.py index 28090ada8c..db35cb25b8 100644 --- a/tests/functional/test_ecosystem.py +++ b/tests/functional/test_ecosystem.py @@ -566,6 +566,47 @@ def test_decode_returndata_no_bytes_returns_zero(ethereum): assert actual == (0,) +def test_decode_returndata_list_with_1_struct(ethereum): + """ + Tests a condition where an array of a list with 1 struct + would be turned into a raw tuple instead of the Struct class. + """ + abi = MethodABI( + type="function", + name="getArrayOfStructs", + stateMutability="view", + inputs=[], + outputs=[ + ABIType( + name="", + type="tuple[]", + components=[ + ABIType(name="a", type="address", components=None, internal_type=None), + ABIType(name="b", type="bytes32", components=None, internal_type=None), + ], + internal_type=None, + ) + ], + ) + raw_data = HexBytes( + "0x000000000000000000000000000000000000000000000000000000000000002" + "00000000000000000000000000000000000000000000000000000000000000001" + "000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266f" + "d91dc47b758f65fd0f6fe511566770c0ae3f94ff9999ceb23bfec3ac9fdc168" + ) + actual = ethereum.decode_returndata(abi, raw_data) + + assert len(actual) == 1 + # The result should still be a list. + # There was also a bug where it was mistakenly a tuple! + assert isinstance(actual[0], list) + assert len(actual[0]) == 1 + assert actual[0][0].a == "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + assert actual[0][0].b == HexBytes( + "0xfd91dc47b758f65fd0f6fe511566770c0ae3f94ff9999ceb23bfec3ac9fdc168" + ) + + @pytest.mark.parametrize("tx_type", TransactionType) def test_create_transaction_uses_network_gas_limit(tx_type, ethereum, eth_tester_provider, owner): tx = ethereum.create_transaction(type=tx_type.value, sender=owner.address)