1pub use crate::ic::*;
2use crate::{backend::DatabaseExt, constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH, InspectorExt};
3use alloy_consensus::BlockHeader;
4use alloy_json_abi::{Function, JsonAbi};
5use alloy_network::{AnyTxEnvelope, TransactionResponse};
6use alloy_primitives::{Address, Selector, TxKind, B256, U256};
7use alloy_provider::{network::BlockResponse, Network};
8use alloy_rpc_types::{Transaction, TransactionRequest};
9use foundry_common::is_impersonated_tx;
10use foundry_config::NamedChain;
11use foundry_fork_db::DatabaseError;
12use revm::{
13 handler::register::EvmHandler,
14 interpreter::{
15 return_ok, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome,
16 Gas, InstructionResult, InterpreterResult,
17 },
18 precompile::secp256r1::P256VERIFY,
19 primitives::{CreateScheme, EVMError, HandlerCfg, SpecId, KECCAK_EMPTY},
20 FrameOrResult, FrameResult,
21};
22use std::{cell::RefCell, rc::Rc, sync::Arc};
23
24pub use revm::primitives::EvmState as StateChangeset;
25
26pub fn apply_chain_and_block_specific_env_changes<N: Network>(
33 env: &mut revm::primitives::Env,
34 block: &N::BlockResponse,
35) {
36 use NamedChain::*;
37 if let Ok(chain) = NamedChain::try_from(env.cfg.chain_id) {
38 let block_number = block.header().number();
39
40 match chain {
41 Mainnet => {
42 if block_number >= 15_537_351u64 {
44 env.block.difficulty = env.block.prevrandao.unwrap_or_default().into();
45 }
46
47 return;
48 }
49 BinanceSmartChain | BinanceSmartChainTestnet => {
50 env.block.prevrandao = Some(env.block.difficulty.into());
57 return;
58 }
59 Moonbeam | Moonbase | Moonriver | MoonbeamDev => {
60 if env.block.prevrandao.is_none() {
61 env.block.prevrandao = Some(B256::random());
63 }
64 }
65 c if c.is_arbitrum() => {
66 if let Some(l1_block_number) = block
69 .other_fields()
70 .and_then(|other| other.get("l1BlockNumber").cloned())
71 .and_then(|l1_block_number| {
72 serde_json::from_value::<U256>(l1_block_number).ok()
73 })
74 {
75 env.block.number = l1_block_number;
76 }
77 }
78 _ => {}
79 }
80 }
81
82 if block.header().difficulty().is_zero() {
84 env.block.difficulty = env.block.prevrandao.unwrap_or_default().into();
85 }
86}
87
88pub fn get_function<'a>(
90 contract_name: &str,
91 selector: Selector,
92 abi: &'a JsonAbi,
93) -> eyre::Result<&'a Function> {
94 abi.functions()
95 .find(|func| func.selector() == selector)
96 .ok_or_else(|| eyre::eyre!("{contract_name} does not have the selector {selector}"))
97}
98
99pub fn configure_tx_env(env: &mut revm::primitives::Env, tx: &Transaction<AnyTxEnvelope>) {
102 let impersonated_from = is_impersonated_tx(&tx.inner).then_some(tx.from());
103 if let AnyTxEnvelope::Ethereum(tx) = &tx.inner.inner() {
104 configure_tx_req_env(env, &tx.clone().into(), impersonated_from).expect("cannot fail");
105 }
106}
107
108pub fn configure_tx_req_env(
112 env: &mut revm::primitives::Env,
113 tx: &TransactionRequest,
114 impersonated_from: Option<Address>,
115) -> eyre::Result<()> {
116 let TransactionRequest {
117 nonce,
118 from,
119 to,
120 value,
121 gas_price,
122 gas,
123 max_fee_per_gas,
124 max_priority_fee_per_gas,
125 max_fee_per_blob_gas,
126 ref input,
127 chain_id,
128 ref blob_versioned_hashes,
129 ref access_list,
130 transaction_type: _,
131 ref authorization_list,
132 sidecar: _,
133 } = *tx;
134
135 env.tx.transact_to = to.unwrap_or(TxKind::Create);
137 env.tx.caller =
140 impersonated_from.unwrap_or(from.ok_or_else(|| eyre::eyre!("missing `from` field"))?);
141 env.tx.gas_limit = gas.ok_or_else(|| eyre::eyre!("missing `gas` field"))?;
142 env.tx.nonce = nonce;
143 env.tx.value = value.unwrap_or_default();
144 env.tx.data = input.input().cloned().unwrap_or_default();
145 env.tx.chain_id = chain_id;
146
147 env.tx.access_list = access_list.clone().unwrap_or_default().0.into_iter().collect();
149
150 env.tx.gas_price = U256::from(gas_price.or(max_fee_per_gas).unwrap_or_default());
152 env.tx.gas_priority_fee = max_priority_fee_per_gas.map(U256::from);
153
154 env.tx.blob_hashes = blob_versioned_hashes.clone().unwrap_or_default();
156 env.tx.max_fee_per_blob_gas = max_fee_per_blob_gas.map(U256::from);
157
158 if let Some(authorization_list) = authorization_list {
160 env.tx.authorization_list =
161 Some(revm::primitives::AuthorizationList::Signed(authorization_list.clone()));
162 }
163
164 Ok(())
165}
166
167pub fn gas_used(spec: SpecId, spent: u64, refunded: u64) -> u64 {
169 let refund_quotient = if SpecId::enabled(spec, SpecId::LONDON) { 5 } else { 2 };
170 spent - (refunded).min(spent / refund_quotient)
171}
172
173fn get_create2_factory_call_inputs(
174 salt: U256,
175 inputs: CreateInputs,
176 deployer: Address,
177) -> CallInputs {
178 let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code[..]].concat();
179 CallInputs {
180 caller: inputs.caller,
181 bytecode_address: deployer,
182 target_address: deployer,
183 scheme: CallScheme::Call,
184 value: CallValue::Transfer(inputs.value),
185 input: calldata.into(),
186 gas_limit: inputs.gas_limit,
187 is_static: false,
188 return_memory_offset: 0..0,
189 is_eof: false,
190 }
191}
192
193pub fn create2_handler_register<I: InspectorExt>(
201 handler: &mut EvmHandler<'_, I, &mut dyn DatabaseExt>,
202) {
203 let create2_overrides = Rc::<RefCell<Vec<_>>>::new(RefCell::new(Vec::new()));
204
205 let create2_overrides_inner = create2_overrides.clone();
206 let old_handle = handler.execution.create.clone();
207 handler.execution.create =
208 Arc::new(move |ctx, mut inputs| -> Result<FrameOrResult, EVMError<DatabaseError>> {
209 let CreateScheme::Create2 { salt } = inputs.scheme else {
210 return old_handle(ctx, inputs);
211 };
212 if !ctx.external.should_use_create2_factory(&mut ctx.evm, &mut inputs) {
213 return old_handle(ctx, inputs);
214 }
215
216 let gas_limit = inputs.gas_limit;
217
218 let create2_deployer = ctx.external.create2_deployer();
220 let mut call_inputs = get_create2_factory_call_inputs(salt, *inputs, create2_deployer);
222
223 let outcome = ctx.external.call(&mut ctx.evm, &mut call_inputs);
225
226 create2_overrides_inner
228 .borrow_mut()
229 .push((ctx.evm.journaled_state.depth(), call_inputs.clone()));
230
231 let code_hash = ctx.evm.load_account(create2_deployer)?.info.code_hash;
233 if code_hash == KECCAK_EMPTY {
234 return Ok(FrameOrResult::Result(FrameResult::Call(CallOutcome {
235 result: InterpreterResult {
236 result: InstructionResult::Revert,
237 output: format!("missing CREATE2 deployer: {create2_deployer}").into(),
238 gas: Gas::new(gas_limit),
239 },
240 memory_offset: 0..0,
241 })))
242 } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
243 return Ok(FrameOrResult::Result(FrameResult::Call(CallOutcome {
244 result: InterpreterResult {
245 result: InstructionResult::Revert,
246 output: "invalid CREATE2 deployer bytecode".into(),
247 gas: Gas::new(gas_limit),
248 },
249 memory_offset: 0..0,
250 })))
251 }
252
253 if let Some(outcome) = outcome {
255 return Ok(FrameOrResult::Result(FrameResult::Call(outcome)));
256 }
257
258 let mut frame_or_result = ctx.evm.make_call_frame(&call_inputs);
260
261 if let Ok(FrameOrResult::Frame(frame)) = &mut frame_or_result {
262 ctx.external
263 .initialize_interp(&mut frame.frame_data_mut().interpreter, &mut ctx.evm)
264 }
265 frame_or_result
266 });
267
268 let create2_overrides_inner = create2_overrides;
269 let old_handle = handler.execution.insert_call_outcome.clone();
270 handler.execution.insert_call_outcome =
271 Arc::new(move |ctx, frame, shared_memory, mut outcome| {
272 if create2_overrides_inner
274 .borrow()
275 .last()
276 .is_some_and(|(depth, _)| *depth == ctx.evm.journaled_state.depth())
277 {
278 let (_, call_inputs) = create2_overrides_inner.borrow_mut().pop().unwrap();
279 outcome = ctx.external.call_end(&mut ctx.evm, &call_inputs, outcome);
280
281 let address = match outcome.instruction_result() {
283 return_ok!() => Address::try_from(outcome.output().as_ref())
284 .map_err(|_| {
285 outcome.result = InterpreterResult {
286 result: InstructionResult::Revert,
287 output: "invalid CREATE2 factory output".into(),
288 gas: Gas::new(call_inputs.gas_limit),
289 };
290 })
291 .ok(),
292 _ => None,
293 };
294 frame
295 .frame_data_mut()
296 .interpreter
297 .insert_create_outcome(CreateOutcome { address, result: outcome.result });
298
299 Ok(())
300 } else {
301 old_handle(ctx, frame, shared_memory, outcome)
302 }
303 });
304}
305
306pub fn odyssey_handler_register<EXT, DB: revm::Database>(handler: &mut EvmHandler<'_, EXT, DB>) {
308 let prev = handler.pre_execution.load_precompiles.clone();
309 handler.pre_execution.load_precompiles = Arc::new(move || {
310 let mut loaded_precompiles = prev();
311
312 loaded_precompiles.extend([P256VERIFY]);
313
314 loaded_precompiles
315 });
316}
317
318pub fn new_evm_with_inspector<'evm, 'i, 'db, I: InspectorExt + ?Sized>(
320 db: &'db mut dyn DatabaseExt,
321 env: revm::primitives::EnvWithHandlerCfg,
322 inspector: &'i mut I,
323) -> revm::Evm<'evm, &'i mut I, &'db mut dyn DatabaseExt> {
324 let revm::primitives::EnvWithHandlerCfg { env, handler_cfg } = env;
325
326 let mut handler = revm::Handler::new(handler_cfg);
340 handler.append_handler_register_plain(revm::inspector_handle_register);
341 if inspector.is_odyssey() {
342 handler.append_handler_register_plain(odyssey_handler_register);
343 }
344 handler.append_handler_register_plain(create2_handler_register);
345
346 let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector);
347
348 revm::Evm::new(context, handler)
349}
350
351pub fn new_evm_with_existing_context<'a>(
352 inner: revm::InnerEvmContext<&'a mut dyn DatabaseExt>,
353 inspector: &'a mut dyn InspectorExt,
354) -> revm::Evm<'a, &'a mut dyn InspectorExt, &'a mut dyn DatabaseExt> {
355 let handler_cfg = HandlerCfg::new(inner.spec_id());
356
357 let mut handler = revm::Handler::new(handler_cfg);
358 handler.append_handler_register_plain(revm::inspector_handle_register);
359 if inspector.is_odyssey() {
360 handler.append_handler_register_plain(odyssey_handler_register);
361 }
362 handler.append_handler_register_plain(create2_handler_register);
363
364 let context =
365 revm::Context::new(revm::EvmContext { inner, precompiles: Default::default() }, inspector);
366 revm::Evm::new(context, handler)
367}