Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support bytes array argument in solidity and vyper contracts #2255

19 changes: 17 additions & 2 deletions src/ape/managers/converters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import re
from collections.abc import Sequence
from collections.abc import Iterable, Sequence
from datetime import datetime, timedelta, timezone
from decimal import Decimal
from typing import Any, Union
Expand Down Expand Up @@ -70,6 +70,18 @@ def convert(self, value: Any) -> int:
return to_int(HexBytes(value))


class HexIterableConverter(ConverterAPI):
"""
Convert list of hex values to single concatenated ``HexBytes`` value.
"""

def is_convertible(self, value: Any) -> bool:
return isinstance(value, Iterable) and all(isinstance(v, bytes) or is_hex(v) for v in value)

def convert(self, value: Any) -> bytes:
return HexBytes(b"".join(HexBytes(v) for v in value))


class StringIntConverter(ConverterAPI):
def is_convertible(self, value: Any) -> bool:
return isinstance(value, str) and not is_0x_prefixed(value) and value.isnumeric()
Expand Down Expand Up @@ -263,7 +275,10 @@ def _converters(self) -> dict[type, list[ConverterAPI]]:
HexAddressConverter(),
IntAddressConverter(),
],
bytes: [HexConverter()],
bytes: [
HexConverter(),
HexIterableConverter(),
],
int: [
TimestampConverter(),
HexIntConverter(),
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions tests/functional/data/sources/SolidityContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ contract SolidityContract {

}

function functionWithCalldata(bytes calldata data) public {

}

function setStruct(MyStruct memory _my_struct) public pure {

}
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/data/sources/VyperContract.vy
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ def functionWithUniqueAmountOfArguments(
):
pass

@external
def functionWithCalldata(data: Bytes[1_024]=b""):
pass

@pure
@external
def setStruct(_my_struct: MyStruct):
Expand Down
35 changes: 33 additions & 2 deletions tests/functional/test_contract_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ def test_get_error_by_signature(error_contract):


def test_selector_identifiers(vyper_contract_instance):
assert len(vyper_contract_instance.selector_identifiers.keys()) == 52
assert len(vyper_contract_instance.selector_identifiers.keys()) == 54
assert vyper_contract_instance.selector_identifiers["balances(address)"] == "0x27e235e3"
assert vyper_contract_instance.selector_identifiers["owner()"] == "0x8da5cb5b"
assert (
Expand All @@ -829,7 +829,7 @@ def test_selector_identifiers(vyper_contract_instance):


def test_identifier_lookup(vyper_contract_instance):
assert len(vyper_contract_instance.identifier_lookup.keys()) == 52
assert len(vyper_contract_instance.identifier_lookup.keys()) == 54
assert vyper_contract_instance.identifier_lookup["0x27e235e3"].selector == "balances(address)"
assert vyper_contract_instance.identifier_lookup["0x8da5cb5b"].selector == "owner()"
assert (
Expand Down Expand Up @@ -990,3 +990,34 @@ def test_sending_funds_to_non_payable_constructor_by_accountDeploy(
def test_as_transaction(tx_type, vyper_contract_instance, owner, eth_tester_provider):
tx = vyper_contract_instance.setNumber.as_transaction(987, sender=owner, type=tx_type.value)
assert tx.gas_limit == eth_tester_provider.max_gas


@pytest.mark.parametrize(
"calldata,expected",
(
(
"0x123456",
"0x123456",
),
(
HexBytes("0x123456"),
"0x123456",
),
(
["0x123456", "0xabcd"],
"0x123456abcd",
),
(
[HexBytes("0x123456"), "0xabcd"],
"0x123456abcd",
),
(
("0x123456", "0xabcd"),
"0x123456abcd",
),
),
)
def test_calldata_arg(calldata, expected, contract_instance, owner):
tx = contract_instance.functionWithCalldata(calldata, sender=owner)
assert not tx.failed
antazoey marked this conversation as resolved.
Show resolved Hide resolved
assert HexBytes(expected) in tx.data
Loading