diff --git a/cairo/ethereum/cancun/utils/address.cairo b/cairo/ethereum/cancun/utils/address.cairo index 0d36b6ed..3e071cad 100644 --- a/cairo/ethereum/cancun/utils/address.cairo +++ b/cairo/ethereum/cancun/utils/address.cairo @@ -4,11 +4,42 @@ from starkware.cairo.common.cairo_builtins import BitwiseBuiltin, KeccakBuiltin from starkware.cairo.common.math_cmp import is_nn, is_not_zero from ethereum_types.bytes import Bytes32, Bytes, BytesStruct -from ethereum_types.numeric import Uint +from ethereum_types.numeric import Uint, UnionUintU256 from ethereum.cancun.fork_types import Address from ethereum.crypto.hash import keccak256 from ethereum.utils.numeric import divmod -from src.utils.bytes import felt_to_bytes20_little, felt_to_bytes, uint256_to_bytes32_little + +from src.utils.bytes import ( + felt_to_bytes20_little, + bytes_to_felt, + felt_to_bytes, + uint256_to_bytes32_little, +) + +func to_address{range_check_ptr}(data: UnionUintU256) -> Address { + alloc_locals; + let (local bytes_data) = alloc(); + + if (cast(data.value.uint, felt) != 0) { + felt_to_bytes20_little(bytes_data, data.value.uint.value); + let res = bytes_to_felt(20, bytes_data); + tempvar address = Address(res); + return address; + } + + if (cast(data.value.u256.value, felt) != 0) { + uint256_to_bytes32_little(bytes_data, [data.value.u256.value]); + let res = bytes_to_felt(20, bytes_data); + tempvar address = Address(res); + return address; + } + + with_attr error_message("Type not valid") { + assert 0 = 1; + tempvar address = Address(0); + return address; + } +} func compute_contract_address{ range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* diff --git a/cairo/ethereum_types/numeric.cairo b/cairo/ethereum_types/numeric.cairo index eb3a1705..03d42ec9 100644 --- a/cairo/ethereum_types/numeric.cairo +++ b/cairo/ethereum_types/numeric.cairo @@ -20,6 +20,15 @@ struct U256 { value: U256Struct*, } +struct UnionUintU256Enum { + uint: Uint*, + u256: U256, +} + +struct UnionUintU256 { + value: UnionUintU256Enum*, +} + struct SetUintDictAccess { key: Uint, prev_value: bool, diff --git a/cairo/tests/ethereum/cancun/utils/test_address.py b/cairo/tests/ethereum/cancun/utils/test_address.py index 7fabc63a..9d151b0e 100644 --- a/cairo/tests/ethereum/cancun/utils/test_address.py +++ b/cairo/tests/ethereum/cancun/utils/test_address.py @@ -1,15 +1,23 @@ +from typing import Union + from ethereum_types.bytes import Bytes32 -from ethereum_types.numeric import Uint +from ethereum_types.numeric import U256, Uint from hypothesis import given from ethereum.cancun.fork_types import Address from ethereum.cancun.utils.address import ( compute_contract_address, compute_create2_contract_address, + to_address, ) class TestAddress: + + @given(data=...) + def test_to_address(self, cairo_run, data: Union[Uint, U256]): + assert to_address(data) == cairo_run("to_address", data) + @given(address=..., nonce=...) def test_compute_contract_address(self, cairo_run, address: Address, nonce: Uint): assert compute_contract_address(address, nonce) == cairo_run( diff --git a/cairo/tests/test_serde.py b/cairo/tests/test_serde.py index 70daecbc..e9651002 100644 --- a/cairo/tests/test_serde.py +++ b/cairo/tests/test_serde.py @@ -168,6 +168,7 @@ def test_type( Tuple[Mapping[Bytes, Bytes], ...], Set[Uint], Mapping[Address, Account], + Union[Uint, U256], Set[Address], ], ): diff --git a/cairo/tests/utils/args_gen.py b/cairo/tests/utils/args_gen.py index 76878eed..586b83cb 100644 --- a/cairo/tests/utils/args_gen.py +++ b/cairo/tests/utils/args_gen.py @@ -108,6 +108,7 @@ ("ethereum_types", "numeric", "Uint"): Uint, ("ethereum_types", "numeric", "U256"): U256, ("ethereum_types", "numeric", "SetUint"): Set[Uint], + ("ethereum_types", "numeric", "UnionUintU256"): Union[Uint, U256], ("ethereum_types", "bytes", "Bytes0"): Bytes0, ("ethereum_types", "bytes", "Bytes8"): Bytes8, ("ethereum_types", "bytes", "Bytes20"): Bytes20,