libid_contracts/
factory.rs1use 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
49pub const CREATE2_DEPLOYER: Address =
53 address!("4e59b44847b379578588920cA78FbF26c0B4956C");
54
55pub const CREATE2_DEPLOYER_SIGNER: Address =
59 address!("3fab184622dc19b6109349b94811493bf2a45362");
60
61pub const CREATE2_DEPLOYER_FUNDING_WEI: u128 = 10_000_000_000_000_000;
65
66pub const CREATE2_DEPLOYER_INSTALL_TX: &str = "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222";
76
77pub const FACTORY_GENESIS_ADMIN: Address =
81 address!("5bb76B0f81F028de363150602cC6d0Ca929E3C31");
82
83pub const CREATE3_PROXY_INITCODE: [u8; 16] = [
86 0x67, 0x36, 0x3d, 0x3d, 0x37, 0x36, 0x3d, 0x34, 0xf0, 0x3d, 0x52, 0x60, 0x08, 0x60,
87 0x18, 0xf3,
88];
89
90pub fn factory_impl_salt() -> B256 {
92 keccak256("libid.factory.impl.v1")
93}
94
95pub fn factory_proxy_salt() -> B256 {
97 keccak256("libid.factory.v1")
98}
99
100pub fn factory_impl_init_code(artifacts: &Artifacts) -> Result<Bytes> {
103 artifacts.bytecode("LibidFactory")
104}
105
106pub fn predict_factory_impl_address(artifacts: &Artifacts) -> Result<Address> {
108 let init_code = factory_impl_init_code(artifacts)?;
109 Ok(CREATE2_DEPLOYER.create2(factory_impl_salt(), keccak256(&init_code)))
110}
111
112pub fn factory_proxy_init_code(artifacts: &Artifacts) -> Result<Bytes> {
117 let impl_addr = predict_factory_impl_address(artifacts)?;
118 let init_data = LibidFactory::initializeCall {
119 owner_: FACTORY_GENESIS_ADMIN,
120 }
121 .abi_encode();
122 let mut code = artifacts.bytecode("ERC1967Proxy")?.to_vec();
123 code.extend_from_slice(&(impl_addr, Bytes::from(init_data)).abi_encode_params());
124 Ok(code.into())
125}
126
127pub fn predict_factory_address(artifacts: &Artifacts) -> Result<Address> {
129 let init_code = factory_proxy_init_code(artifacts)?;
130 Ok(CREATE2_DEPLOYER.create2(factory_proxy_salt(), keccak256(&init_code)))
131}
132
133pub fn predict_address(factory: Address, name: &str) -> Address {
138 let salt = keccak256(name.as_bytes());
139 let create3_proxy = factory.create2(salt, keccak256(CREATE3_PROXY_INITCODE));
140 create3_proxy.create(1)
141}
142
143pub async fn ensure_create2_deployer<P: Provider>(provider: &P) -> Result<()> {
151 let code = provider
152 .get_code_at(CREATE2_DEPLOYER)
153 .await
154 .map_err(|e| Error::Rpc {
155 detail: format!("failed to read code at the CREATE2 deployer: {e}"),
156 })?;
157 if !code.is_empty() {
158 return Ok(());
159 }
160
161 let balance = provider
163 .get_balance(CREATE2_DEPLOYER_SIGNER)
164 .await
165 .map_err(|e| Error::Rpc {
166 detail: format!("failed to read the CREATE2 deployer signer balance: {e}"),
167 })?;
168 let needed = U256::from(CREATE2_DEPLOYER_FUNDING_WEI);
169 if balance < needed {
170 let tx = TransactionRequest::default()
171 .with_to(CREATE2_DEPLOYER_SIGNER)
172 .with_value(needed - balance);
173 let pending = provider
174 .send_transaction(tx)
175 .await
176 .map_err(|e| Error::Rpc {
177 detail: format!("failed to fund the CREATE2 deployer signer: {e}"),
178 })?;
179 pending.get_receipt().await.map_err(|e| Error::Rpc {
180 detail: format!("CREATE2 deployer funding confirmation failed: {e}"),
181 })?;
182 }
183
184 let raw = hex::decode(CREATE2_DEPLOYER_INSTALL_TX).map_err(|e| Error::Rpc {
185 detail: format!("bad CREATE2 deployer install tx constant: {e}"),
186 })?;
187 let pending = provider
188 .send_raw_transaction(&raw)
189 .await
190 .map_err(|e| Error::Rpc {
191 detail: format!(
192 "this chain rejected the keyless (pre-EIP-155) install transaction \
193 for the canonical CREATE2 deployer: {e}. There is deliberately no \
194 fallback deployment path — any other route would change the \
195 factory address and defeat the cross-network guarantee — so this \
196 network cannot host the deterministic factory and must be \
197 reconsidered."
198 ),
199 })?;
200 pending.get_receipt().await.map_err(|e| Error::Rpc {
201 detail: format!("CREATE2 deployer install confirmation failed: {e}"),
202 })?;
203
204 let code = provider
205 .get_code_at(CREATE2_DEPLOYER)
206 .await
207 .map_err(|e| Error::Rpc {
208 detail: format!("failed to re-read code at the CREATE2 deployer: {e}"),
209 })?;
210 if code.is_empty() {
211 return Err(Error::Rpc {
212 detail: "the CREATE2 deployer install transaction landed but left no code"
213 .into(),
214 });
215 }
216 Ok(())
217}
218
219pub async fn ensure_factory<P: Provider>(
225 provider: &P,
226 artifacts: &Artifacts,
227) -> Result<Address> {
228 let factory = predict_factory_address(artifacts)?;
229 let code = provider
230 .get_code_at(factory)
231 .await
232 .map_err(|e| Error::Rpc {
233 detail: format!("failed to read code at the factory address: {e}"),
234 })?;
235 if !code.is_empty() {
236 return Ok(factory);
237 }
238
239 ensure_create2_deployer(provider).await?;
240
241 let impl_addr = predict_factory_impl_address(artifacts)?;
242 let impl_code = provider
243 .get_code_at(impl_addr)
244 .await
245 .map_err(|e| Error::Rpc {
246 detail: format!("failed to read code at the factory impl address: {e}"),
247 })?;
248 if impl_code.is_empty() {
249 deploy_via_create2(
250 provider,
251 factory_impl_salt(),
252 &factory_impl_init_code(artifacts)?,
253 impl_addr,
254 "LibidFactory (impl)",
255 None,
256 )
257 .await?;
258 }
259
260 deploy_via_create2(
261 provider,
262 factory_proxy_salt(),
263 &factory_proxy_init_code(artifacts)?,
264 factory,
265 "LibidFactory (proxy)",
266 None,
267 )
268 .await?;
269 Ok(factory)
270}
271
272pub async fn factory_deploy<P: Provider>(
276 provider: &P,
277 factory: Address,
278 name: &str,
279 creation_code: Bytes,
280) -> Result<Address> {
281 let call = LibidFactory::deployCall {
285 name: name.to_string(),
286 creationCode: creation_code,
287 };
288 let tx = TransactionRequest::default()
289 .with_to(factory)
290 .with_input(Bytes::from(call.abi_encode()));
291 let pending = provider
292 .send_transaction(tx)
293 .await
294 .map_err(|e| Error::Rpc {
295 detail: format!("factory deploy of {name} send failed: {e}"),
296 })?;
297 pending.get_receipt().await.map_err(|e| Error::Rpc {
298 detail: format!("factory deploy of {name} confirmation failed: {e}"),
299 })?;
300
301 let contract = LibidFactory::new(factory, provider);
302 let addr = contract
303 .deployedAt(name.to_string())
304 .call()
305 .await
306 .map_err(|e| Error::Rpc {
307 detail: format!("factory deployedAt({name}) read failed: {e}"),
308 })?;
309 if addr == Address::ZERO {
310 return Err(Error::Rpc {
311 detail: format!("factory deploy of {name} landed no recorded address"),
312 });
313 }
314 Ok(addr)
315}