Skip to content

Commit

Permalink
♻️ Make CreateAddress Module-Friendly (#224)
Browse files Browse the repository at this point in the history
### 🕓 Changelog

This PR refactors the `CreateAddress` contract to make it
module-friendly and ready for the breaking `0.4.0` release.

---------

Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>
  • Loading branch information
pcaversaccio authored Apr 6, 2024
1 parent b26a9f3 commit 7207431
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 78 deletions.
82 changes: 41 additions & 41 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -67,47 +67,47 @@ Create2AddressTest:testComputeAddress() (gas: 550587)
Create2AddressTest:testComputeAddressSelf() (gas: 559245)
Create2AddressTest:testFuzzComputeAddress(bytes32,address) (runs: 257, μ: 551182, ~: 551182)
Create2AddressTest:testFuzzComputeAddressSelf(bytes32) (runs: 257, μ: 559266, ~: 559266)
CreateAddressTest:testComputeAddressNonce0x00() (gas: 16539)
CreateAddressTest:testComputeAddressNonce0x7f() (gas: 535256)
CreateAddressTest:testComputeAddressNonceUint16() (gas: 535308)
CreateAddressTest:testComputeAddressNonceUint24() (gas: 535403)
CreateAddressTest:testComputeAddressNonceUint32() (gas: 535365)
CreateAddressTest:testComputeAddressNonceUint40() (gas: 535437)
CreateAddressTest:testComputeAddressNonceUint48() (gas: 535465)
CreateAddressTest:testComputeAddressNonceUint56() (gas: 535493)
CreateAddressTest:testComputeAddressNonceUint64() (gas: 535630)
CreateAddressTest:testComputeAddressNonceUint8() (gas: 535348)
CreateAddressTest:testComputeAddressRevertTooHighNonce() (gas: 10704)
CreateAddressTest:testComputeAddressSelfNonce0x7f() (gas: 539488)
CreateAddressTest:testComputeAddressSelfNonceUint16() (gas: 539709)
CreateAddressTest:testComputeAddressSelfNonceUint24() (gas: 539738)
CreateAddressTest:testComputeAddressSelfNonceUint32() (gas: 539834)
CreateAddressTest:testComputeAddressSelfNonceUint40() (gas: 539863)
CreateAddressTest:testComputeAddressSelfNonceUint48() (gas: 539891)
CreateAddressTest:testComputeAddressSelfNonceUint56() (gas: 539920)
CreateAddressTest:testComputeAddressSelfNonceUint64() (gas: 540037)
CreateAddressTest:testComputeAddressSelfNonceUint8() (gas: 539643)
CreateAddressTest:testComputeAddressSelfRevertTooHighNonce() (gas: 8930)
CreateAddressTest:testFuzzComputeAddressNonce0x7f(uint64,address) (runs: 257, μ: 538245, ~: 538396)
CreateAddressTest:testFuzzComputeAddressNonceUint16(uint64,address) (runs: 257, μ: 537717, ~: 537861)
CreateAddressTest:testFuzzComputeAddressNonceUint24(uint64,address) (runs: 257, μ: 537870, ~: 537987)
CreateAddressTest:testFuzzComputeAddressNonceUint32(uint64,address) (runs: 257, μ: 537851, ~: 537994)
CreateAddressTest:testFuzzComputeAddressNonceUint40(uint64,address) (runs: 257, μ: 537982, ~: 538086)
CreateAddressTest:testFuzzComputeAddressNonceUint48(uint64,address) (runs: 257, μ: 537966, ~: 538070)
CreateAddressTest:testFuzzComputeAddressNonceUint56(uint64,address) (runs: 257, μ: 537987, ~: 538099)
CreateAddressTest:testFuzzComputeAddressNonceUint64(uint64,address) (runs: 257, μ: 537991, ~: 538203)
CreateAddressTest:testFuzzComputeAddressNonceUint8(uint64,address) (runs: 257, μ: 537762, ~: 537861)
CreateAddressTest:testFuzzComputeAddressRevertTooHighNonce(uint256,address) (runs: 257, μ: 12961, ~: 12936)
CreateAddressTest:testFuzzComputeAddressSelfNonce0x7f(uint64) (runs: 257, μ: 544478, ~: 544585)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint16(uint64) (runs: 257, μ: 543720, ~: 543874)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint24(uint64) (runs: 257, μ: 543979, ~: 544075)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint32(uint64) (runs: 257, μ: 544065, ~: 544171)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint40(uint64) (runs: 257, μ: 544074, ~: 544155)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint48(uint64) (runs: 257, μ: 544116, ~: 544229)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint56(uint64) (runs: 257, μ: 544208, ~: 544299)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint64(uint64) (runs: 257, μ: 544261, ~: 544429)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint8(uint64) (runs: 257, μ: 543793, ~: 543866)
CreateAddressTest:testFuzzComputeAddressSelfRevertTooHighNonce(uint256) (runs: 257, μ: 12809, ~: 12778)
CreateAddressTest:testComputeAddressNonce0x00() (gas: 16545)
CreateAddressTest:testComputeAddressNonce0x7f() (gas: 535262)
CreateAddressTest:testComputeAddressNonceUint16() (gas: 535314)
CreateAddressTest:testComputeAddressNonceUint24() (gas: 535409)
CreateAddressTest:testComputeAddressNonceUint32() (gas: 535371)
CreateAddressTest:testComputeAddressNonceUint40() (gas: 535443)
CreateAddressTest:testComputeAddressNonceUint48() (gas: 535471)
CreateAddressTest:testComputeAddressNonceUint56() (gas: 535499)
CreateAddressTest:testComputeAddressNonceUint64() (gas: 535636)
CreateAddressTest:testComputeAddressNonceUint8() (gas: 535354)
CreateAddressTest:testComputeAddressRevertTooHighNonce() (gas: 10928)
CreateAddressTest:testComputeAddressSelfNonce0x7f() (gas: 539553)
CreateAddressTest:testComputeAddressSelfNonceUint16() (gas: 539774)
CreateAddressTest:testComputeAddressSelfNonceUint24() (gas: 539803)
CreateAddressTest:testComputeAddressSelfNonceUint32() (gas: 539899)
CreateAddressTest:testComputeAddressSelfNonceUint40() (gas: 539928)
CreateAddressTest:testComputeAddressSelfNonceUint48() (gas: 539956)
CreateAddressTest:testComputeAddressSelfNonceUint56() (gas: 539985)
CreateAddressTest:testComputeAddressSelfNonceUint64() (gas: 540102)
CreateAddressTest:testComputeAddressSelfNonceUint8() (gas: 539708)
CreateAddressTest:testComputeAddressSelfRevertTooHighNonce() (gas: 9190)
CreateAddressTest:testFuzzComputeAddressNonce0x7f(uint64,address) (runs: 257, μ: 538246, ~: 538402)
CreateAddressTest:testFuzzComputeAddressNonceUint16(uint64,address) (runs: 257, μ: 537738, ~: 537867)
CreateAddressTest:testFuzzComputeAddressNonceUint24(uint64,address) (runs: 257, μ: 537888, ~: 537993)
CreateAddressTest:testFuzzComputeAddressNonceUint32(uint64,address) (runs: 257, μ: 537868, ~: 538000)
CreateAddressTest:testFuzzComputeAddressNonceUint40(uint64,address) (runs: 257, μ: 537993, ~: 538092)
CreateAddressTest:testFuzzComputeAddressNonceUint48(uint64,address) (runs: 257, μ: 537974, ~: 538076)
CreateAddressTest:testFuzzComputeAddressNonceUint56(uint64,address) (runs: 257, μ: 537990, ~: 538105)
CreateAddressTest:testFuzzComputeAddressNonceUint64(uint64,address) (runs: 257, μ: 538008, ~: 538209)
CreateAddressTest:testFuzzComputeAddressNonceUint8(uint64,address) (runs: 257, μ: 537769, ~: 537867)
CreateAddressTest:testFuzzComputeAddressRevertTooHighNonce(uint256,address) (runs: 257, μ: 13164, ~: 13139)
CreateAddressTest:testFuzzComputeAddressSelfNonce0x7f(uint64) (runs: 257, μ: 544547, ~: 544650)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint16(uint64) (runs: 257, μ: 543790, ~: 543939)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint24(uint64) (runs: 257, μ: 544045, ~: 544140)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint32(uint64) (runs: 257, μ: 544115, ~: 544236)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint40(uint64) (runs: 257, μ: 544138, ~: 544220)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint48(uint64) (runs: 257, μ: 544176, ~: 544294)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint56(uint64) (runs: 257, μ: 544275, ~: 544364)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint64(uint64) (runs: 257, μ: 544325, ~: 544494)
CreateAddressTest:testFuzzComputeAddressSelfNonceUint8(uint64) (runs: 257, μ: 543855, ~: 543931)
CreateAddressTest:testFuzzComputeAddressSelfRevertTooHighNonce(uint256) (runs: 257, μ: 13056, ~: 13014)
ECDSATest:testEthSignedMessageHash() (gas: 8735)
ECDSATest:testFuzzEthSignedMessageHash(string) (runs: 257, μ: 9321, ~: 9315)
ECDSATest:testFuzzRecoverWithInvalidSignature(bytes,string) (runs: 257, μ: 15522, ~: 15524)
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- **Utility Functions**
- [`Base64`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/Base64.vy): Make `Base64` module-friendly. ([#222](https://github.com/pcaversaccio/snekmate/pull/222))
- [`BatchDistributor`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/BatchDistributor.vy): Make `BatchDistributor` module-friendly. ([#223](https://github.com/pcaversaccio/snekmate/pull/223))
- [`CreateAddress`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/utils/CreateAddress.vy): Make `CreateAddress` module-friendly. ([#224](https://github.com/pcaversaccio/snekmate/pull/224))
- **Vyper Contract Deployer**
- [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/lib/utils/VyperDeployer.sol): Improve error message in the event of a Vyper compilation error. ([#219](https://github.com/pcaversaccio/snekmate/pull/219))

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ src
│ └── IERC5267 — "EIP-5267 Interface Definition"
└── mocks
├── Base64Mock — "Base64 Module Reference Implementation"
└── BatchDistributorMock — "BatchDistributor Module Reference Implementation"
├── BatchDistributorMock — "BatchDistributor Module Reference Implementation"
└── CreateAddressMock — "CreateAddress Module Reference Implementation"
```

## 🎛 Installation
Expand Down
38 changes: 7 additions & 31 deletions src/snekmate/utils/CreateAddress.vy
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,21 @@ def __init__():
pass


@external
@internal
@view
def compute_address_rlp_self(nonce: uint256) -> address:
def _compute_address_rlp_self(nonce: uint256) -> address:
"""
@dev Returns the address where a contract will be stored if
deployed via this contract using the `CREATE` opcode.
@param nonce The next 32-byte nonce of this contract.
@param nonce The 32-byte account nonce of this contract.
@return address The 20-byte address where a contract will be stored.
"""
return self._compute_address_rlp(self, nonce)


@external
@internal
@pure
def compute_address_rlp(deployer: address, nonce: uint256) -> address:
def _compute_address_rlp(deployer: address, nonce: uint256) -> address:
"""
@dev Returns the address where a contract will be stored
if deployed via `deployer` using the `CREATE` opcode.
Expand All @@ -53,38 +53,14 @@ def compute_address_rlp(deployer: address, nonce: uint256) -> address:
are initiated with `nonce = 1`. Thus, the first contract address
created by another contract is calculated with a non-zero nonce.
@param deployer The 20-byte deployer address.
@param nonce The next 32-byte nonce of the deployer address.
@return address The 20-byte address where a contract will be stored.
"""
return self._compute_address_rlp(deployer, nonce)


@internal
@pure
def _compute_address_rlp(deployer: address, nonce: uint256) -> address:
"""
@dev An `internal` helper function that returns the address where a
contract will be stored if deployed via `deployer` using the
`CREATE` opcode. For the specification of the Recursive Length
Prefix (RLP) encoding scheme, please refer to p. 19 of the Ethereum
Yellow Paper (https://ethereum.github.io/yellowpaper/paper.pdf)
and the Ethereum Wiki (https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp).
For further insights also, see the following issue:
https://github.com/transmissions11/solmate/issues/207.
Based on the EIP-161 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md)
specification, all contract accounts on the Ethereum mainnet
are initiated with `nonce = 1`. Thus, the first contract address
created by another contract is calculated with a non-zero nonce.
@param deployer The 20-byte deployer address.
@param nonce The next 32-byte nonce of the deployer address.
@param nonce The 32-byte account nonce of the deployer address.
@return address The 20-byte address where a contract will be stored.
"""
length: bytes1 = 0x94

# The theoretical allowed limit, based on EIP-2681, for an
# account nonce is 2**64-2: https://eips.ethereum.org/EIPS/eip-2681.
assert nonce < convert(max_value(uint64), uint256), "RLP: invalid nonce value"
assert nonce < convert(max_value(uint64), uint256), "CreateAddress: invalid nonce value"

# The integer zero is treated as an empty byte string and
# therefore has only one length prefix, 0x80, which is
Expand Down
59 changes: 59 additions & 0 deletions src/snekmate/utils/mocks/CreateAddressMock.vy
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# pragma version ~=0.4.0b5
"""
@title CreateAddress Module Reference Implementation
@custom:contract-name CreateAddressMock
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
"""


# @dev We import and initialise the `CreateAddress` module.
from .. import CreateAddress as ca
initializes: ca


@deploy
@payable
def __init__():
"""
@dev To omit the opcodes for checking the `msg.value`
in the creation-time EVM bytecode, the constructor
is declared as `payable`.
"""
ca.__init__()


@external
@view
def compute_address_rlp_self(nonce: uint256) -> address:
"""
@dev Returns the address where a contract will be stored if
deployed via this contract using the `CREATE` opcode.
@param nonce The 32-byte account nonce of this contract.
@return address The 20-byte address where a contract will be stored.
"""
return ca._compute_address_rlp_self(nonce)


@external
@pure
def compute_address_rlp(deployer: address, nonce: uint256) -> address:
"""
@dev Returns the address where a contract will be stored
if deployed via `deployer` using the `CREATE` opcode.
For the specification of the Recursive Length Prefix (RLP)
encoding scheme, please refer to p. 19 of the Ethereum
Yellow Paper (https://ethereum.github.io/yellowpaper/paper.pdf)
and the Ethereum Wiki (https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp).
For further insights also, see the following issue:
https://github.com/transmissions11/solmate/issues/207.
Based on the EIP-161 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md)
specification, all contract accounts on the Ethereum mainnet
are initiated with `nonce = 1`. Thus, the first contract address
created by another contract is calculated with a non-zero nonce.
@param deployer The 20-byte deployer address.
@param nonce The 32-byte account nonce of the deployer address.
@return address The 20-byte address where a contract will be stored.
"""
return ca._compute_address_rlp(deployer, nonce)
13 changes: 8 additions & 5 deletions test/utils/CreateAddress.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,23 @@ contract CreateAddressTest is Test {

function setUp() public {
createAddress = ICreateAddress(
vyperDeployer.deployContract("src/snekmate/utils/", "CreateAddress")
vyperDeployer.deployContract(
"src/snekmate/utils/mocks/",
"CreateAddressMock"
)
);
createAddressAddr = address(createAddress);
}

function testComputeAddressRevertTooHighNonce() public {
uint72 nonce = uint72(type(uint64).max);
vm.expectRevert(bytes("RLP: invalid nonce value"));
vm.expectRevert(bytes("CreateAddress: invalid nonce value"));
createAddress.compute_address_rlp(makeAddr("alice"), nonce);
}

function testComputeAddressSelfRevertTooHighNonce() public {
uint72 nonce = uint72(type(uint64).max);
vm.expectRevert(bytes("RLP: invalid nonce value"));
vm.expectRevert(bytes("CreateAddress: invalid nonce value"));
createAddress.compute_address_rlp_self(nonce);
}

Expand Down Expand Up @@ -485,7 +488,7 @@ contract CreateAddressTest is Test {
uint256(type(uint64).max),
uint256(type(uint256).max)
);
vm.expectRevert(bytes("RLP: invalid nonce value"));
vm.expectRevert(bytes("CreateAddress: invalid nonce value"));
createAddress.compute_address_rlp(deployer, nonce);
}

Expand All @@ -497,7 +500,7 @@ contract CreateAddressTest is Test {
uint256(type(uint64).max),
uint256(type(uint256).max)
);
vm.expectRevert(bytes("RLP: invalid nonce value"));
vm.expectRevert(bytes("CreateAddress: invalid nonce value"));
createAddress.compute_address_rlp_self(nonce);
}

Expand Down

0 comments on commit 7207431

Please sign in to comment.