1#![no_std]
4#![cfg_attr(not(test), warn(unused_crate_dependencies))]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6#![allow(clippy::too_many_arguments)]
8
9#[cfg(test)]
10extern crate alloc;
11
12use alloy_primitives::{Address, B256, address, b256};
13
14pub const MULTICALL3_ADDRESS: Address = address!("0xcA11bde05977b3631167028862bE2a173976CA11");
16pub const CREATEX_ADDRESS: Address = address!("0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed");
17pub const SAFE_DEPLOYER_ADDRESS: Address = address!("0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7");
18pub const PERMIT2_ADDRESS: Address = address!("0x000000000022d473030f116ddee9f6b43ac78ba3");
19pub const PERMIT2_SALT: B256 =
20 b256!("0x0000000000000000000000000000000000000000d3af2663da51c10215000000");
21pub const ARACHNID_CREATE2_FACTORY_ADDRESS: Address =
22 address!("0x4e59b44847b379578588920cA78FbF26c0B4956C");
23
24macro_rules! sol {
26 ($($input:tt)*) => {
27 #[cfg(all(feature = "rpc", feature = "serde"))]
28 alloy_sol_types::sol! {
29 #[sol(rpc)]
30 #[derive(serde::Serialize, serde::Deserialize)]
31 $($input)*
32 }
33 #[cfg(all(feature = "rpc", not(feature = "serde")))]
34 alloy_sol_types::sol! {
35 #[sol(rpc)]
36 $($input)*
37 }
38 #[cfg(all(not(feature = "rpc"), feature = "serde"))]
39 alloy_sol_types::sol! {
40 #[derive(serde::Serialize, serde::Deserialize)]
41 $($input)*
42 }
43 #[cfg(all(not(feature = "rpc"), not(feature = "serde")))]
44 alloy_sol_types::sol! {
45 $($input)*
46 }
47 };
48}
49
50pub(crate) use sol;
51
52pub mod contracts {
53 use alloy_primitives::{B256, Bytes, b256, bytes};
54
55 sol!(
56 #[allow(missing_docs)]
57 CreateX,
58 "abi/CreateX.json",
59 );
60
61 pub const CREATEX_BYTECODE_HASH: B256 =
63 b256!("0xbd8a7ea8cfca7b4e5f5041d7d4b17bc317c5ce42cfbc42066a00cf26b43eb53f");
64
65 sol!(
66 #[allow(missing_docs)]
67 Permit2,
68 "abi/Permit2.json"
69 );
70
71 sol!(
72 #[allow(missing_docs)]
73 SafeDeployer,
74 "abi/SafeDeployer.json",
75 );
76
77 pub const ARACHNID_CREATE2_FACTORY_BYTECODE: Bytes = bytes!(
78 "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"
79 );
80
81 sol!(
82 #[allow(missing_docs)]
83 Multicall3,
84 "abi/Multicall3.json",
85 );
86
87 pub const MULTICALL3_DEPLOYED_BYTECODE_HASH: B256 =
89 b256!("0xd5c15df687b16f2ff992fc8d767b4216323184a2bbc6ee2f9c398c318e770891");
90}
91
92pub use contracts::{CreateX, Multicall3, Permit2, SafeDeployer};
93
94pub mod precompiles;
95
96#[cfg(test)]
97mod tests {
98 extern crate std;
112
113 use super::*;
114 use alloc::string::{String, ToString};
115 use alloy_primitives::{B256, keccak256};
116 use alloy_provider::{Provider, ProviderBuilder};
117
118 const DEFAULT_ETH_RPC_URL: &str = "https://eth.llamarpc.com";
120
121 fn get_rpc_url() -> String {
124 std::env::var("ETH_RPC_URL").unwrap_or_else(|_| DEFAULT_ETH_RPC_URL.to_string())
125 }
126
127 async fn get_mainnet_code_hash(address: Address) -> B256 {
129 let rpc_url = get_rpc_url();
130 let provider = ProviderBuilder::new().connect_http(rpc_url.parse().unwrap());
131
132 let code = provider
133 .get_code_at(address)
134 .await
135 .expect("Failed to fetch code from mainnet");
136 keccak256(&code)
137 }
138
139 #[tokio::test]
140 #[ignore = "requires mainnet RPC access - not needed after mainnet launch"]
141 async fn multicall3_bytecode_matches_mainnet() {
142 let computed_hash = keccak256(&Multicall3::DEPLOYED_BYTECODE);
144 let stored_hash = contracts::MULTICALL3_DEPLOYED_BYTECODE_HASH;
145 assert_eq!(
146 computed_hash, stored_hash,
147 "MULTICALL3_DEPLOYED_BYTECODE_HASH does not match the actual bytecode!\n\
148 Computed: {computed_hash}\n\
149 Stored: {stored_hash}"
150 );
151
152 let mainnet_hash = get_mainnet_code_hash(MULTICALL3_ADDRESS).await;
154 assert_eq!(
155 mainnet_hash, stored_hash,
156 "Multicall3 bytecode hash mismatch!\n\
157 Mainnet: {mainnet_hash}\n\
158 Ours: {stored_hash}\n\
159 This likely means we have the wrong bytecode for Multicall3."
160 );
161 }
162
163 #[tokio::test]
164 #[ignore = "requires mainnet RPC access - not needed after mainnet launch"]
165 async fn createx_bytecode_matches_mainnet() {
166 let computed_hash = keccak256(&CreateX::DEPLOYED_BYTECODE);
168 let stored_hash = contracts::CREATEX_BYTECODE_HASH;
169 assert_eq!(
170 computed_hash, stored_hash,
171 "CREATEX_BYTECODE_HASH does not match the actual bytecode!\n\
172 Computed: {computed_hash}\n\
173 Stored: {stored_hash}"
174 );
175
176 let mainnet_hash = get_mainnet_code_hash(CREATEX_ADDRESS).await;
178 assert_eq!(
179 mainnet_hash, stored_hash,
180 "CreateX bytecode hash mismatch!\n\
181 Mainnet: {mainnet_hash}\n\
182 Ours: {stored_hash}\n\
183 This likely means we have the wrong bytecode for CreateX."
184 );
185 }
186
187 #[tokio::test]
188 #[ignore = "requires mainnet RPC access - not needed after mainnet launch"]
189 async fn arachnid_create2_factory_bytecode_matches_mainnet() {
190 let mainnet_hash = get_mainnet_code_hash(ARACHNID_CREATE2_FACTORY_ADDRESS).await;
191 let our_hash = keccak256(&contracts::ARACHNID_CREATE2_FACTORY_BYTECODE);
192
193 assert_eq!(
194 mainnet_hash, our_hash,
195 "Arachnid CREATE2 factory bytecode hash mismatch!\n\
196 Mainnet: {mainnet_hash}\n\
197 Ours: {our_hash}\n\
198 This likely means we have the wrong bytecode for Arachnid CREATE2 factory."
199 );
200 }
201
202 #[tokio::test]
203 #[ignore = "requires mainnet RPC access - not needed after mainnet launch"]
204 async fn safe_deployer_bytecode_matches_mainnet() {
205 let mainnet_hash = get_mainnet_code_hash(SAFE_DEPLOYER_ADDRESS).await;
206 let our_hash = keccak256(&SafeDeployer::DEPLOYED_BYTECODE);
207
208 assert_eq!(
209 mainnet_hash, our_hash,
210 "SafeDeployer bytecode hash mismatch!\n\
211 Mainnet: {mainnet_hash}\n\
212 Ours: {our_hash}\n\
213 This likely means we have the wrong bytecode for SafeDeployer."
214 );
215 }
216}