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