-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support contract address computing utils
- Loading branch information
1 parent
122c89b
commit 7da6d9d
Showing
4 changed files
with
131 additions
and
5 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
from typing import ( | ||
Union, | ||
overload, | ||
) | ||
|
||
import rlp | ||
from hexbytes import HexBytes | ||
from eth_utils import ( | ||
keccak, | ||
to_bytes, | ||
to_checksum_address, | ||
) | ||
|
||
from cfx_address import Base32Address | ||
from cfx_address.utils import ( | ||
normalize_to | ||
) | ||
from cfx_utils.types import ( | ||
ChecksumAddress, | ||
) | ||
|
||
def get_create_address(sender: Union[str, Base32Address], nonce: int, bytecode_hash: Union[bytes, str]) -> Union[ChecksumAddress, Base32Address]: | ||
""" | ||
Determine the resulting `CREATE` opcode contract address for a sender and a nonce. | ||
Typically, the sender is a wallet address and the nonce is the next nonce of the sender. | ||
NOTE: in Conflux, the contract address is computed differently from that in Ethereum | ||
where the bytecode hash is not accounted for in the address computation. | ||
:param sender: The address of the sender. Can be a hex string or a base32 address. | ||
:param nonce: The nonce of the sender. | ||
:param bytecode_hash: The keccak256 hash of the contract bytecode, whereas the "data" field of the transaction. Can be bytes or hex string. | ||
:return: The computed address as a hex string or base32 address, depending on the type of sender | ||
""" | ||
address_hex = normalize_to(sender, None) | ||
contract_address = "0x8" + keccak( | ||
b"\x00" | ||
+ to_bytes(hexstr=address_hex) | ||
+ nonce.to_bytes(32, "little") | ||
+ HexBytes(bytecode_hash) | ||
).hex()[-39:] | ||
if Base32Address.is_valid_base32(sender): | ||
return Base32Address(contract_address, network_id=Base32Address(sender).network_id) | ||
return to_checksum_address(contract_address) | ||
|
||
|
||
def get_create2_address( | ||
create2_factory_address: Union[str, Base32Address], salt: bytes, bytecode_hash: Union[bytes, str] | ||
) -> Union[ChecksumAddress, Base32Address]: | ||
""" | ||
Compute the address of a contract created using CREATE2. | ||
:param create2_factory_address: The address of the CREATE2 factory contract. On Conflux, it is deployed via `CIP-31 <https://github.com/Conflux-Chain/CIPs/blob/master/CIPs/cip-31.md>`_ | ||
:param salt: A 32-byte value used as salt. Should be bytes. | ||
:param bytecode_hash: The keccak256 hash of the contract bytecode. Can be bytes or hex string. | ||
:return: The computed address as a hex string or base32 address, depending on the type of create2_factory_address | ||
""" | ||
address_hex = normalize_to(create2_factory_address, None) | ||
contract_address = "0x8" + keccak( | ||
b"\xff" | ||
+ to_bytes(hexstr=address_hex) | ||
+ salt | ||
+ HexBytes(bytecode_hash) | ||
).hex()[-39:] | ||
if Base32Address.is_valid_base32(create2_factory_address): | ||
return Base32Address(contract_address, network_id=Base32Address(create2_factory_address).network_id) | ||
return to_checksum_address(contract_address) | ||
|
||
# def get_create2_address( | ||
# salt: bytes, | ||
# bytecode_hash: Union[bytes, str], | ||
# create2_factory_address: Union[str, Base32Address] | ||
# ) -> Union[str, Base32Address]: | ||
# """ | ||
# Compute the address of a contract created using CREATE2. | ||
|
||
# :param salt: A 32-byte value used as salt. Should be bytes. | ||
# :param bytecode_hash: The keccak256 hash of the contract bytecode. Can be bytes or hex string. | ||
# :param create2_factory_address: The address of the CREATE2 factory contract. On Conflux, it is deployed via `CIP-31 <https://github.com/Conflux-Chain/CIPs/blob/master/CIPs/cip-31.md>`_ | ||
# :return: The computed address as a hex string or base32 address, depending on the type of create2_factory_address | ||
# """ | ||
|
||
# # Ensure bytecode_hash is bytes32 | ||
# if isinstance(bytecode_hash, str): | ||
# bytecode_hash = bytes.fromhex(bytecode_hash.replace('0x', '')) | ||
# elif len(bytecode_hash) != 32: | ||
# raise ValueError("Bytecode hash must be 32 bytes long") | ||
|
||
# address_hex = to_bytes(hexstr=create2_factory_address.eth_checksum_address) if isinstance(create2_factory_address, Base32Address) else create2_factory_address | ||
|
||
# core_part = keccak( | ||
# ["bytes1", "address", "bytes32", "bytes32"], | ||
# ["0xff", create2_factory_address, salt, bytecode_hash], | ||
# ) | ||
# return "0x8" + core_part.hex()[-39:] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from conflux_web3 import Web3 | ||
from conflux_web3.types import Base32Address | ||
from cfx_address.utils import normalize_to | ||
from conflux_web3.utils.address import get_create_address, get_create2_address | ||
|
||
bytecode = "0x608060405234801561001057600080fd5b506101a1806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80637cf5dab014610030575b600080fd5b61004a600480360381019061004591906100b1565b610060565b60405161005791906100ed565b60405180910390f35b600060018261006f9190610137565b9050919050565b600080fd5b6000819050919050565b61008e8161007b565b811461009957600080fd5b50565b6000813590506100ab81610085565b92915050565b6000602082840312156100c7576100c6610076565b5b60006100d58482850161009c565b91505092915050565b6100e78161007b565b82525050565b600060208201905061010260008301846100de565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006101428261007b565b915061014d8361007b565b925082820190508082111561016557610164610108565b5b9291505056fea26469706673582212208eb410cb79fbf08652e19d496e31d076d04be7ed242c64a44aec4c5af0f2533b64736f6c63430008130033" | ||
|
||
def test_get_create_address(): | ||
address = "cfx:aamz08kfa8wsu69jhhcgrwkjkh69p85wj6222847yp" | ||
nonce = 1 | ||
bytecode_hash = Web3.solidity_keccak(["bytes"], [bytecode]) | ||
assert get_create_address(address, nonce, bytecode_hash) == Base32Address("0x837f77a1e8da5b860905a07bc1921e43fbfb04ef", 1029) | ||
assert get_create_address(Base32Address(address).hex_address, nonce, bytecode_hash) == normalize_to("0x837f77a1e8da5b860905a07bc1921e43fbfb04ef", None) | ||
|
||
def test_get_create2_address(): | ||
salt = (1111).to_bytes(32, 'big') | ||
bytecode_hash = Web3.solidity_keccak(["bytes"], [bytecode]) | ||
create2_factory_address = "0x8A3A92281Df6497105513B18543fd3B60c778E40" | ||
assert get_create2_address(create2_factory_address, salt, bytecode_hash) == normalize_to("0x80ac53cc16c0b58dc5bde5af47f5ef9e84693fe4", None) | ||
assert get_create2_address(Base32Address(create2_factory_address, 1029), salt, bytecode_hash) == normalize_to("0x80ac53cc16c0b58dc5bde5af47f5ef9e84693fe4", 1029) | ||
|