Skip to main content

libid_contracts/
factory.rs

1//! Bootstrap and use of the deterministic deployment factory.
2//!
3//! An environment's [`LibidFactory`] proxy lives at the same address on every
4//! EVM network because every byte that feeds its address is frozen but one:
5//! it is deployed through the canonical keyless CREATE2 deployer (Arachnid's
6//! deterministic-deployment proxy at [`CREATE2_DEPLOYER`]) with fixed salts
7//! and init codes whose only input is the genesis admin, the environment's
8//! deployer key ([`FactoryGenesis`]), baked in so that initialization happens
9//! atomically inside the deployment. Protocol proxies are then deployed
10//! *through* the factory via CREATE3, which makes their addresses a function
11//! of `(factory, name)` only — see `solidity/contracts/factory/README.md`.
12//!
13//! [`FactoryGenesis::ensure`] is the whole bootstrap: check → install the
14//! CREATE2 deployer if missing (via its well-known presigned transaction) →
15//! deploy the factory impl and proxy at their canonical addresses. There is
16//! deliberately no fallback deployment path: anything else would change the
17//! factory address and defeat the cross-network guarantee, so a chain that
18//! cannot take the presigned install transaction is a hard error.
19
20use alloy::{
21    hex,
22    network::TransactionBuilder,
23    primitives::{
24        address,
25        keccak256,
26        Address,
27        Bytes,
28        B256,
29        U256,
30    },
31    providers::Provider,
32    rpc::types::TransactionRequest,
33    sol_types::{
34        SolCall,
35        SolValue,
36    },
37};
38
39use crate::{
40    artifacts::Artifacts,
41    bindings::factory::LibidFactory,
42    deploy::deploy_via_create2,
43    error::{
44        Error,
45        Result,
46    },
47};
48
49/// Arachnid's deterministic-deployment proxy — deployed from a keyless
50/// one-time account, so it has this address on every chain that has it.
51/// Calldata format: 32-byte salt ++ init code.
52pub const CREATE2_DEPLOYER: Address =
53    address!("4e59b44847b379578588920cA78FbF26c0B4956C");
54
55/// The keyless one-time account the presigned install transaction spends
56/// from. It must hold the exact transaction cost (see
57/// [`CREATE2_DEPLOYER_FUNDING_WEI`]) before the broadcast.
58pub const CREATE2_DEPLOYER_SIGNER: Address =
59    address!("3fab184622dc19b6109349b94811493bf2a45362");
60
61/// What the install transaction costs: 100 gwei gas price × 100 000 gas
62/// limit = 0.01 ETH. The keyless account can never refund the surplus, so
63/// fund it with exactly this.
64pub const CREATE2_DEPLOYER_FUNDING_WEI: u128 = 10_000_000_000_000_000;
65
66/// The canonical presigned transaction that installs the CREATE2 deployer.
67///
68/// This is a pre-EIP-155 (no chain id, v = 27) legacy transaction whose
69/// signature was fixed *before any key existed* — r = s =
70/// 0x2222…22 — so nobody holds the sending key and the deployer lands at
71/// [`CREATE2_DEPLOYER`] on every chain that accepts it. Chains that enforce
72/// EIP-155 replay protection on all transactions reject it; per policy that
73/// is a hard error (see [`ensure_create2_deployer`]), not a cue for an
74/// alternate deployment path.
75pub const CREATE2_DEPLOYER_INSTALL_TX: &str = "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222";
76
77/// The 16-byte CREATE3 proxy init code (`Create3.PROXY_INITCODE`). Constant
78/// forever — its hash feeds every predicted address.
79pub const CREATE3_PROXY_INITCODE: [u8; 16] = [
80    0x67, 0x36, 0x3d, 0x3d, 0x37, 0x36, 0x3d, 0x34, 0xf0, 0x3d, 0x52, 0x60, 0x08, 0x60,
81    0x18, 0xf3,
82];
83
84/// Fixed salt of the factory implementation (`FactoryDeployer.IMPL_SALT`).
85pub fn factory_impl_salt() -> B256 {
86    keccak256("libid.factory.impl.v1")
87}
88
89/// Fixed salt of the factory proxy (`FactoryDeployer.PROXY_SALT`).
90pub fn factory_proxy_salt() -> B256 {
91    keccak256("libid.factory.v1")
92}
93
94/// The frozen implementation init code: LibidFactory's creation code, no
95/// constructor args.
96pub fn factory_impl_init_code(artifacts: &Artifacts) -> Result<Bytes> {
97    artifacts.bytecode("LibidFactory")
98}
99
100/// Where the factory implementation lands.
101pub fn predict_factory_impl_address(artifacts: &Artifacts) -> Result<Address> {
102    let init_code = factory_impl_init_code(artifacts)?;
103    Ok(CREATE2_DEPLOYER.create2(factory_impl_salt(), keccak256(&init_code)))
104}
105
106/// The factory of one environment, pinned by its genesis admin: the deployer
107/// key that owns the factory from its first block. The admin is the only
108/// varying input of the frozen proxy init code, so the factory's address, and
109/// every address deployed through it, follow from the admin and nothing
110/// else. Testnet and mainnet have their own.
111#[derive(Clone, Copy, Debug, PartialEq, Eq)]
112pub struct FactoryGenesis {
113    /// The deployer key: factory owner from genesis, `apply`'s signer.
114    pub admin: Address,
115}
116
117impl FactoryGenesis {
118    /// The frozen proxy init code: ERC1967Proxy creation code ++
119    /// abi.encode(implAddress, initialize(admin)). `FactoryDeployer.proxyInitCode(admin)`
120    /// produces the same bytes (asserted against the vendored artifacts by
121    /// the Solidity tests).
122    pub fn proxy_init_code(&self, artifacts: &Artifacts) -> Result<Bytes> {
123        let impl_addr = predict_factory_impl_address(artifacts)?;
124        let init_data = LibidFactory::initializeCall { owner_: self.admin }.abi_encode();
125        let mut code = artifacts.bytecode("ERC1967Proxy")?.to_vec();
126        code.extend_from_slice(&(impl_addr, Bytes::from(init_data)).abi_encode_params());
127        Ok(code.into())
128    }
129
130    /// The factory's address — the same on every EVM network the admin
131    /// deploys to.
132    pub fn address(&self, artifacts: &Artifacts) -> Result<Address> {
133        let init_code = self.proxy_init_code(artifacts)?;
134        Ok(CREATE2_DEPLOYER.create2(factory_proxy_salt(), keccak256(&init_code)))
135    }
136
137    /// Make sure the factory exists at [`Self::address`], bootstrapping
138    /// whatever is missing: the CREATE2 deployer (via the keyless presigned
139    /// transaction), the factory implementation, and the factory proxy —
140    /// each at its deterministic address. Idempotent: reruns are read-only
141    /// no-ops once the factory is up.
142    pub async fn ensure<P: Provider>(
143        &self,
144        provider: &P,
145        artifacts: &Artifacts,
146    ) -> Result<Address> {
147        let factory = self.address(artifacts)?;
148        let code = provider
149            .get_code_at(factory)
150            .await
151            .map_err(|e| Error::Rpc {
152                detail: format!("failed to read code at the factory address: {e}"),
153            })?;
154        if !code.is_empty() {
155            return Ok(factory);
156        }
157
158        ensure_create2_deployer(provider).await?;
159
160        let impl_addr = predict_factory_impl_address(artifacts)?;
161        let impl_code =
162            provider
163                .get_code_at(impl_addr)
164                .await
165                .map_err(|e| Error::Rpc {
166                    detail: format!(
167                        "failed to read code at the factory impl address: {e}"
168                    ),
169                })?;
170        if impl_code.is_empty() {
171            deploy_via_create2(
172                provider,
173                factory_impl_salt(),
174                &factory_impl_init_code(artifacts)?,
175                impl_addr,
176                "LibidFactory (impl)",
177                None,
178            )
179            .await?;
180        }
181
182        deploy_via_create2(
183            provider,
184            factory_proxy_salt(),
185            &self.proxy_init_code(artifacts)?,
186            factory,
187            "LibidFactory (proxy)",
188            None,
189        )
190        .await?;
191        Ok(factory)
192    }
193}
194
195/// The CREATE3 address `factory.deploy(name, ·)` lands on: the factory
196/// CREATE2-deploys the constant 16-byte proxy under `keccak256(name)`, and
197/// that proxy CREATE-deploys the target at its nonce 1. A pure function of
198/// `(factory, name)` — computable offline, before anything is deployed.
199pub fn predict_address(factory: Address, name: &str) -> Address {
200    let salt = keccak256(name.as_bytes());
201    let create3_proxy = factory.create2(salt, keccak256(CREATE3_PROXY_INITCODE));
202    create3_proxy.create(1)
203}
204
205/// Make sure the canonical CREATE2 deployer exists, installing it via the
206/// keyless presigned transaction if absent: fund the one-time signer with
207/// the exact transaction cost, then broadcast [`CREATE2_DEPLOYER_INSTALL_TX`].
208///
209/// Hard-errors on a chain that rejects the pre-EIP-155 transaction: there is
210/// no alternate deployment path (one would change the factory address), so
211/// such a network cannot host the deterministic factory.
212pub async fn ensure_create2_deployer<P: Provider>(provider: &P) -> Result<()> {
213    let code = provider
214        .get_code_at(CREATE2_DEPLOYER)
215        .await
216        .map_err(|e| Error::Rpc {
217            detail: format!("failed to read code at the CREATE2 deployer: {e}"),
218        })?;
219    if !code.is_empty() {
220        return Ok(());
221    }
222
223    // Fund the keyless one-time account up to the exact transaction cost.
224    let balance = provider
225        .get_balance(CREATE2_DEPLOYER_SIGNER)
226        .await
227        .map_err(|e| Error::Rpc {
228            detail: format!("failed to read the CREATE2 deployer signer balance: {e}"),
229        })?;
230    let needed = U256::from(CREATE2_DEPLOYER_FUNDING_WEI);
231    if balance < needed {
232        let tx = TransactionRequest::default()
233            .with_to(CREATE2_DEPLOYER_SIGNER)
234            .with_value(needed - balance);
235        let pending = provider
236            .send_transaction(tx)
237            .await
238            .map_err(|e| Error::Rpc {
239                detail: format!("failed to fund the CREATE2 deployer signer: {e}"),
240            })?;
241        pending.get_receipt().await.map_err(|e| Error::Rpc {
242            detail: format!("CREATE2 deployer funding confirmation failed: {e}"),
243        })?;
244    }
245
246    let raw = hex::decode(CREATE2_DEPLOYER_INSTALL_TX).map_err(|e| Error::Rpc {
247        detail: format!("bad CREATE2 deployer install tx constant: {e}"),
248    })?;
249    let pending = provider
250        .send_raw_transaction(&raw)
251        .await
252        .map_err(|e| Error::Rpc {
253            detail: format!(
254                "this chain rejected the keyless (pre-EIP-155) install transaction \
255                 for the canonical CREATE2 deployer: {e}. There is deliberately no \
256                 fallback deployment path — any other route would change the \
257                 factory address and defeat the cross-network guarantee — so this \
258                 network cannot host the deterministic factory and must be \
259                 reconsidered."
260            ),
261        })?;
262    pending.get_receipt().await.map_err(|e| Error::Rpc {
263        detail: format!("CREATE2 deployer install confirmation failed: {e}"),
264    })?;
265
266    let code = provider
267        .get_code_at(CREATE2_DEPLOYER)
268        .await
269        .map_err(|e| Error::Rpc {
270            detail: format!("failed to re-read code at the CREATE2 deployer: {e}"),
271        })?;
272    if code.is_empty() {
273        return Err(Error::Rpc {
274            detail: "the CREATE2 deployer install transaction landed but left no code"
275                .into(),
276        });
277    }
278    Ok(())
279}
280
281/// Deploy `creation_code` under `name` through the factory (the provider's
282/// wallet must be the factory owner). Returns the deployed address, which
283/// always equals [`predict_address`]`(factory, name)`.
284pub async fn factory_deploy<P: Provider>(
285    provider: &P,
286    factory: Address,
287    name: &str,
288    creation_code: Bytes,
289) -> Result<Address> {
290    // `deploy` is built as raw calldata: alloy's `sol!` reserves the `deploy`
291    // method name on generated contract instances, so the typed call struct
292    // is used directly instead.
293    let call = LibidFactory::deployCall {
294        name: name.to_string(),
295        creationCode: creation_code,
296    };
297    let tx = TransactionRequest::default()
298        .with_to(factory)
299        .with_input(Bytes::from(call.abi_encode()));
300    let pending = provider
301        .send_transaction(tx)
302        .await
303        .map_err(|e| Error::Rpc {
304            detail: format!("factory deploy of {name} send failed: {e}"),
305        })?;
306    pending.get_receipt().await.map_err(|e| Error::Rpc {
307        detail: format!("factory deploy of {name} confirmation failed: {e}"),
308    })?;
309
310    let contract = LibidFactory::new(factory, provider);
311    let addr = contract
312        .deployedAt(name.to_string())
313        .call()
314        .await
315        .map_err(|e| Error::Rpc {
316            detail: format!("factory deployedAt({name}) read failed: {e}"),
317        })?;
318    if addr == Address::ZERO {
319        return Err(Error::Rpc {
320            detail: format!("factory deploy of {name} landed no recorded address"),
321        });
322    }
323    Ok(addr)
324}