Skip to main content

evm_fork_cache/
create3.rs

1//! CREATE3 deployment-address derivation.
2//!
3//! CREATE3 makes a contract's deployed address depend only on the deploying
4//! factory and a salt, independent of the contract's init code. This module
5//! reproduces that derivation off-chain: it computes the CREATE2 proxy address
6//! the factory would create from `(deployer, salt)`, then the CREATE address
7//! the proxy deploys to. This lets callers predict an address before a
8//! transaction is sent.
9
10use alloy_primitives::{Address, B256, address, b256, keccak256};
11
12/// Address of the widely deployed `CREATE3Factory` (the ZeframLou / Solmate-style
13/// implementation, deterministically deployed cross-chain — e.g. by LiFi).
14///
15/// This is the canonical cross-chain address at which this factory has been
16/// deployed on many EVM networks. Its derivation salts as
17/// `keccak256(abi.encodePacked(deployer, salt))` over the standard Solady/Solmate
18/// CREATE3 proxy init code whose hash is `CREATE3_PROXY_INITCODE_HASH`, which is
19/// what [`derive_universal_create3_address`] reproduces.
20///
21/// **This is not pcaversaccio's CreateX** (`0xba5Ed0...28ba5Ed`). CreateX applies
22/// a guarded-salt transformation (permissioned-deploy / cross-chain-redeploy
23/// protection, chain-ID mixing) that differs from the plain
24/// `keccak256(deployer, salt)` used here, so this module does **not** predict
25/// CreateX deployment addresses.
26///
27/// Callers must verify the factory is actually deployed at this address on
28/// their target chain before relying on a derived address: if the factory is
29/// absent (or a chain hosts a different factory implementation), the derived
30/// address will not correspond to any real deployment.
31pub const UNIVERSAL_CREATE3_FACTORY: Address = address!("93FEC2C00BfE902F733B57c5a6CeeD7CD1384AE1");
32
33// Standard Solady/Solmate CREATE3 proxy initcode used by this factory.
34// keccak256(0x67363d3d37363d34f03d5260086018f3)
35const CREATE3_PROXY_INITCODE_HASH: B256 =
36    b256!("21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f");
37
38/// Derive CREATE3 deployment address for the universal factory implementation.
39///
40/// CREATE3 deploys in two hops: the factory first `CREATE2`-deploys a tiny
41/// fixed proxy, then that proxy `CREATE`s the actual contract as its first
42/// (nonce-1) deployment. Because both hops use only the factory, the salt, and
43/// a fixed proxy init code, the final address depends solely on `factory`,
44/// `deployer`, and `salt` — it is **independent of the deployed contract's
45/// bytecode**. Two different contracts deployed with the same inputs land at
46/// the same address.
47///
48/// Formula:
49/// 1. `mixedSalt = keccak256(abi.encodePacked(deployer, salt))` — binds the
50///    salt to the logical deployer.
51/// 2. `proxy = create2(factory, mixedSalt, CREATE3_PROXY_INITCODE_HASH)` —
52///    the CREATE2 address of the proxy. `CREATE3_PROXY_INITCODE_HASH` is the
53///    keccak256 of the fixed proxy init code, so the proxy address is fully
54///    determined by the factory and mixed salt.
55/// 3. `deployed = address(keccak256(rlp([proxy, 1])))` — the CREATE address of
56///    the proxy's first deployment (nonce 1). The RLP framing bytes encode the
57///    short list `[proxy, 1]`: `0xd6` is the RLP list header for the 22-byte
58///    payload that follows, `0x94` introduces the 20-byte `proxy` address, and
59///    `0x01` is the RLP encoding of the proxy's nonce (1), since a fresh
60///    contract account's first `CREATE` uses nonce 1.
61///
62/// The address is returned as the low 20 bytes of each keccak256 hash, matching
63/// the EVM's address-from-hash convention.
64///
65/// `factory` lets you derive against a non-canonical factory deployment; for
66/// the canonical address use [`derive_universal_create3_address`].
67///
68/// ```
69/// use evm_fork_cache::create3::derive_create3_address;
70/// use alloy_primitives::{Address, B256, address, b256};
71///
72/// let factory: Address = address!("93FEC2C00BfE902F733B57c5a6CeeD7CD1384AE1");
73/// let deployer: Address = address!("00000000000000000000000000000000000000aa");
74/// let salt: B256 =
75///     b256!("1111111111111111111111111111111111111111111111111111111111111111");
76///
77/// // The derivation is a pure function of (factory, deployer, salt): identical
78/// // inputs always yield the same address.
79/// let a = derive_create3_address(factory, deployer, salt);
80/// let b = derive_create3_address(factory, deployer, salt);
81/// assert_eq!(a, b);
82///
83/// // Changing the salt changes the derived address.
84/// let other_salt: B256 =
85///     b256!("2222222222222222222222222222222222222222222222222222222222222222");
86/// assert_ne!(a, derive_create3_address(factory, deployer, other_salt));
87/// ```
88pub fn derive_create3_address(factory: Address, deployer: Address, salt: B256) -> Address {
89    let mut mixed_salt_input = [0u8; 52];
90    mixed_salt_input[..20].copy_from_slice(deployer.as_slice());
91    mixed_salt_input[20..].copy_from_slice(salt.as_slice());
92    let mixed_salt = keccak256(mixed_salt_input);
93
94    let mut create2_preimage = [0u8; 85];
95    create2_preimage[0] = 0xff;
96    create2_preimage[1..21].copy_from_slice(factory.as_slice());
97    create2_preimage[21..53].copy_from_slice(mixed_salt.as_slice());
98    create2_preimage[53..85].copy_from_slice(CREATE3_PROXY_INITCODE_HASH.as_slice());
99    let proxy_hash = keccak256(create2_preimage);
100    let proxy = Address::from_slice(&proxy_hash.as_slice()[12..]);
101
102    let mut create_preimage = [0u8; 23];
103    create_preimage[0] = 0xd6;
104    create_preimage[1] = 0x94;
105    create_preimage[2..22].copy_from_slice(proxy.as_slice());
106    create_preimage[22] = 0x01;
107    let deployed_hash = keccak256(create_preimage);
108
109    Address::from_slice(&deployed_hash.as_slice()[12..])
110}
111
112/// Derive CREATE3 deployment address via the universal factory.
113///
114/// Convenience wrapper around [`derive_create3_address`] that uses
115/// [`UNIVERSAL_CREATE3_FACTORY`] as the factory. As with the general form, the
116/// result depends only on `deployer` and `salt`, not on the deployed bytecode,
117/// and is only meaningful on chains where that factory is actually deployed.
118///
119/// ```
120/// use evm_fork_cache::create3::derive_universal_create3_address;
121/// use alloy_primitives::{Address, B256, address, b256};
122///
123/// let deployer: Address = address!("00000000000000000000000000000000000000aa");
124/// let salt: B256 =
125///     b256!("1111111111111111111111111111111111111111111111111111111111111111");
126///
127/// // Deterministic: the same (deployer, salt) always derive the same address.
128/// assert_eq!(
129///     derive_universal_create3_address(deployer, salt),
130///     derive_universal_create3_address(deployer, salt),
131/// );
132/// ```
133pub fn derive_universal_create3_address(deployer: Address, salt: B256) -> Address {
134    derive_create3_address(UNIVERSAL_CREATE3_FACTORY, deployer, salt)
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn test_derive_universal_create3_address_matches_factory_reference_vector() {
143        let deployer: Address = address!("C8bDb57Afa96E05DbE9d00a93Bf6863dfF634D59");
144        let salt: B256 = b256!("3e423a81e6ff85145e727e92fd89e4775e1fb188ed74b9f1f6e3679b7af66626");
145
146        let expected: Address = address!("eFef040ed447a25cF61277990DE61a429BF8F3e4");
147        let derived = derive_universal_create3_address(deployer, salt);
148
149        assert_eq!(derived, expected);
150    }
151
152    /// The derivation must be a pure function of its inputs: identical inputs
153    /// always yield the same address, and changing the salt changes the address.
154    #[test]
155    fn test_derive_is_deterministic_and_salt_sensitive() {
156        let deployer: Address = address!("00000000000000000000000000000000000000aa");
157        let salt_a: B256 =
158            b256!("1111111111111111111111111111111111111111111111111111111111111111");
159        let salt_b: B256 =
160            b256!("2222222222222222222222222222222222222222222222222222222222222222");
161
162        // Same inputs -> same output.
163        assert_eq!(
164            derive_universal_create3_address(deployer, salt_a),
165            derive_universal_create3_address(deployer, salt_a),
166        );
167
168        // Different salt -> different address.
169        assert_ne!(
170            derive_universal_create3_address(deployer, salt_a),
171            derive_universal_create3_address(deployer, salt_b),
172        );
173
174        // Different deployer (with the same salt) -> different address.
175        let other_deployer: Address = address!("00000000000000000000000000000000000000bb");
176        assert_ne!(
177            derive_universal_create3_address(deployer, salt_a),
178            derive_universal_create3_address(other_deployer, salt_a),
179        );
180    }
181}