-
-
Notifications
You must be signed in to change notification settings - Fork 56
/
create_address.vy
108 lines (96 loc) · 5.6 KB
/
create_address.vy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# pragma version ~=0.4.0
"""
@title `CREATE` EVM Opcode Utility Functions for Address Calculations
@custom:contract-name create_address
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions can be used to compute in advance the address
where a smart contract will be deployed if deployed via the
`CREATE` opcode. The implementation is inspired by my
implementation here:
https://github.com/pcaversaccio/create-util/blob/main/contracts/Create.sol.
"""
@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`.
"""
pass
@internal
@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 self._compute_address_rlp(self, nonce)
@internal
@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.
"""
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), "create_address: invalid nonce value"
# The integer zero is treated as an empty byte string and
# therefore has only one length prefix, 0x80, which is
# calculated via 0x80 + 0.
if (nonce == convert(0x00, uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xd6, length, convert(deployer, bytes20), 0x80)))
# A one-byte integer in the [0x00, 0x7f] range uses its own
# value as a length prefix, there is no additional "0x80 + length"
# prefix that precedes it.
elif (nonce <= convert(0x7f, uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xd6, length, convert(deployer, bytes20), convert(convert(nonce, uint8), bytes1))))
# In the case of `nonce > convert(0x7f, uint256)` and
# `nonce <= convert(max_value((uint8), uint256)`, we have the
# following encoding scheme (the same calculation can be carried
# over for higher nonce bytes):
# 0xda = 0xc0 (short RLP prefix) + 0x1a (= the bytes length of: 0x94 + address + 0x84 + nonce, in hex),
# 0x94 = 0x80 + 0x14 (= the bytes length of an address, 20 bytes, in hex),
# 0x84 = 0x80 + 0x04 (= the bytes length of the nonce, 4 bytes, in hex).
elif (nonce <= convert(max_value(uint8), uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xd7, length, convert(deployer, bytes20), 0x81, convert(convert(nonce, uint8), bytes1))))
elif (nonce <= convert(max_value(uint16), uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xd8, length, convert(deployer, bytes20), 0x82, convert(convert(nonce, uint16), bytes2))))
elif (nonce <= convert(max_value(uint24), uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xd9, length, convert(deployer, bytes20), 0x83, convert(convert(nonce, uint24), bytes3))))
elif (nonce <= convert(max_value(uint32), uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xda, length, convert(deployer, bytes20), 0x84, convert(convert(nonce, uint32), bytes4))))
elif (nonce <= convert(max_value(uint40), uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xdb, length, convert(deployer, bytes20), 0x85, convert(convert(nonce, uint40), bytes5))))
elif (nonce <= convert(max_value(uint48), uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xdc, length, convert(deployer, bytes20), 0x86, convert(convert(nonce, uint48), bytes6))))
elif (nonce <= convert(max_value(uint56), uint256)):
return self._convert_keccak256_2_address(keccak256(concat(0xdd, length, convert(deployer, bytes20), 0x87, convert(convert(nonce, uint56), bytes7))))
return self._convert_keccak256_2_address(keccak256(concat(0xde, length, convert(deployer, bytes20), 0x88, convert(convert(nonce, uint64), bytes8))))
@internal
@pure
def _convert_keccak256_2_address(digest: bytes32) -> address:
"""
@dev Converts a 32-byte keccak256 digest to an address.
@param digest The 32-byte keccak256 digest.
@return address The converted 20-byte address.
"""
return convert(convert(digest, uint256) & convert(max_value(uint160), uint256), address)