Skip to main content

foundry_evm_core/
evm.rs

1use std::{
2    fmt::Debug,
3    marker::PhantomData,
4    ops::{Deref, DerefMut},
5};
6
7use crate::{
8    FoundryBlock, FoundryContextExt, FoundryInspectorExt, FoundryTransaction,
9    FromAnyRpcTransaction,
10    backend::{DatabaseExt, JournaledState},
11    constants::{CALLER, DEFAULT_CREATE2_DEPLOYER_CODEHASH, TEST_CONTRACT_ADDRESS},
12    tempo::{TEMPO_PRECOMPILE_ADDRESSES, TEMPO_TIP20_TOKENS, initialize_tempo_genesis_inner},
13};
14use alloy_consensus::{
15    SignableTransaction, Signed, constants::KECCAK_EMPTY, transaction::SignerRecoverable,
16};
17use alloy_evm::{
18    EthEvmFactory, Evm, EvmEnv, EvmFactory, FromRecoveredTx, eth::EthEvmContext,
19    precompiles::PrecompilesMap,
20};
21use alloy_network::{Ethereum, Network};
22use alloy_op_evm::OpEvmFactory;
23use alloy_primitives::{Address, Bytes, Signature, U256};
24use alloy_rlp::Decodable;
25use foundry_common::{FoundryReceiptResponse, FoundryTransactionBuilder, fmt::UIfmt};
26use foundry_config::FromEvmVersion;
27use foundry_fork_db::{DatabaseError, ForkBlockEnv};
28use op_alloy_network::Optimism;
29use op_revm::{
30    DefaultOp, OpBuilder, OpContext, OpHaltReason, OpSpecId, OpTransaction, handler::OpHandler,
31    precompiles::OpPrecompiles, transaction::error::OpTransactionError,
32};
33use revm::{
34    Context,
35    context::{
36        BlockEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, LocalContextTr, TxEnv,
37        result::{EVMError, ExecResultAndState, ExecutionResult, HaltReason, ResultAndState},
38    },
39    handler::{
40        EthFrame, EvmTr, FrameResult, FrameTr, Handler, ItemOrResult, instructions::EthInstructions,
41    },
42    inspector::{InspectorEvmTr, InspectorHandler},
43    interpreter::{
44        CallInput, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome,
45        FrameInput, Gas, InstructionResult, InterpreterResult, SharedMemory,
46        interpreter::EthInterpreter, interpreter_action::FrameInit, return_ok,
47    },
48    primitives::hardfork::SpecId,
49    state::Bytecode,
50};
51use serde::{Deserialize, Serialize};
52use tempo_alloy::TempoNetwork;
53use tempo_chainspec::hardfork::TempoHardfork;
54use tempo_evm::evm::TempoEvmFactory;
55use tempo_precompiles::storage::StorageCtx;
56use tempo_revm::{
57    TempoBlockEnv, TempoHaltReason, TempoInvalidTransaction, TempoTxEnv, evm::TempoContext,
58    gas_params::tempo_gas_params, handler::TempoEvmHandler,
59};
60
61/// Converts a network-specific halt reason into an [`InstructionResult`].
62pub trait IntoInstructionResult {
63    fn into_instruction_result(self) -> InstructionResult;
64}
65
66impl IntoInstructionResult for HaltReason {
67    fn into_instruction_result(self) -> InstructionResult {
68        self.into()
69    }
70}
71
72impl IntoInstructionResult for OpHaltReason {
73    fn into_instruction_result(self) -> InstructionResult {
74        match self {
75            Self::Base(eth) => eth.into(),
76            Self::FailedDeposit => InstructionResult::Stop,
77        }
78    }
79}
80
81impl IntoInstructionResult for TempoHaltReason {
82    fn into_instruction_result(self) -> InstructionResult {
83        match self {
84            Self::Ethereum(eth) => eth.into(),
85            _ => InstructionResult::PrecompileError,
86        }
87    }
88}
89
90/// Foundry's supertrait associating [Network] with [FoundryEvmFactory]
91pub trait FoundryEvmNetwork: Copy + Debug + Default + 'static {
92    type Network: Network<
93            TxEnvelope: Decodable
94                            + SignerRecoverable
95                            + From<Signed<<Self::Network as Network>::UnsignedTx>>
96                            + for<'d> Deserialize<'d>
97                            + Serialize
98                            + UIfmt,
99            UnsignedTx: SignableTransaction<Signature>,
100            TransactionRequest: FoundryTransactionBuilder<Self::Network>
101                                    + for<'d> Deserialize<'d>
102                                    + Serialize,
103            ReceiptResponse: FoundryReceiptResponse,
104        >;
105    type EvmFactory: FoundryEvmFactory<Tx: FromRecoveredTx<<Self::Network as Network>::TxEnvelope>>;
106}
107
108#[derive(Clone, Copy, Debug, Default)]
109pub struct EthEvmNetwork;
110impl FoundryEvmNetwork for EthEvmNetwork {
111    type Network = Ethereum;
112    type EvmFactory = EthEvmFactory;
113}
114
115#[derive(Clone, Copy, Debug, Default)]
116pub struct TempoEvmNetwork;
117impl FoundryEvmNetwork for TempoEvmNetwork {
118    type Network = TempoNetwork;
119    type EvmFactory = TempoEvmFactory;
120}
121
122#[derive(Clone, Copy, Debug, Default)]
123pub struct OpEvmNetwork;
124impl FoundryEvmNetwork for OpEvmNetwork {
125    type Network = Optimism;
126    type EvmFactory = OpEvmFactory;
127}
128
129/// Convenience type aliases for accessing associated types through [`FoundryEvmNetwork`].
130pub type EvmFactoryFor<FEN> = <FEN as FoundryEvmNetwork>::EvmFactory;
131pub type FoundryContextFor<'db, FEN> =
132    <EvmFactoryFor<FEN> as FoundryEvmFactory>::FoundryContext<'db>;
133pub type TxEnvFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Tx;
134pub type HaltReasonFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::HaltReason;
135pub type SpecFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Spec;
136pub type BlockEnvFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::BlockEnv;
137pub type PrecompilesFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Precompiles;
138pub type EvmEnvFor<FEN> = EvmEnv<SpecFor<FEN>, BlockEnvFor<FEN>>;
139
140pub type NetworkFor<FEN> = <FEN as FoundryEvmNetwork>::Network;
141pub type TxEnvelopeFor<FEN> = <NetworkFor<FEN> as Network>::TxEnvelope;
142pub type TransactionRequestFor<FEN> = <NetworkFor<FEN> as Network>::TransactionRequest;
143pub type TransactionResponseFor<FEN> = <NetworkFor<FEN> as Network>::TransactionResponse;
144pub type BlockResponseFor<FEN> = <NetworkFor<FEN> as Network>::BlockResponse;
145
146pub trait FoundryEvmFactory:
147    EvmFactory<
148        Spec: Into<SpecId> + FromEvmVersion + Default + Copy + Unpin + Send + 'static,
149        BlockEnv: FoundryBlock + ForkBlockEnv + Default + Unpin,
150        Tx: Clone + Debug + FoundryTransaction + FromAnyRpcTransaction + Default + Send + Sync,
151        HaltReason: IntoInstructionResult,
152        Precompiles = PrecompilesMap,
153    > + Clone
154    + Debug
155    + Default
156    + 'static
157{
158    /// Foundry Context abstraction
159    type FoundryContext<'db>: FoundryContextExt<
160            Block = Self::BlockEnv,
161            Tx = Self::Tx,
162            Spec = Self::Spec,
163            Db: DatabaseExt<Self>,
164        >
165    where
166        Self: 'db;
167
168    /// The Foundry-wrapped EVM type produced by this factory.
169    type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>: Evm<
170            DB = &'db mut dyn DatabaseExt<Self>,
171            Tx = Self::Tx,
172            BlockEnv = Self::BlockEnv,
173            Spec = Self::Spec,
174            HaltReason = Self::HaltReason,
175        > + Deref<Target = Self::FoundryContext<'db>>
176        + IntoNestedEvm<Self::Spec, Self::BlockEnv, Self::Tx>
177    where
178        Self: 'db;
179
180    /// Creates a Foundry-wrapped EVM with the given inspector.
181    fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
182        &self,
183        db: &'db mut dyn DatabaseExt<Self>,
184        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
185        inspector: I,
186    ) -> Self::FoundryEvm<'db, I>;
187
188    /// Creates a Foundry-wrapped EVM with a dynamic inspector, returning a boxed [`NestedEvm`].
189    ///
190    /// This helper exists because `&mut dyn FoundryInspectorExt<FoundryContext>` cannot satisfy
191    /// the generic `I: FoundryInspectorExt<Self::FoundryContext<'db>>` bound when the context
192    /// type is only known through an associated type.  Each concrete factory implements this
193    /// directly, side-stepping the higher-kinded lifetime issue.
194    fn create_foundry_nested_evm<'db>(
195        &self,
196        db: &'db mut dyn DatabaseExt<Self>,
197        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
198        inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
199    ) -> Box<dyn NestedEvm<Spec = Self::Spec, Block = Self::BlockEnv, Tx = Self::Tx> + 'db>;
200}
201
202impl FoundryEvmFactory for EthEvmFactory {
203    type FoundryContext<'db> = EthEvmContext<&'db mut dyn DatabaseExt<Self>>;
204
205    type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> = EthFoundryEvm<'db, I>;
206
207    fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
208        &self,
209        db: &'db mut dyn DatabaseExt<Self>,
210        evm_env: EvmEnv,
211        inspector: I,
212    ) -> Self::FoundryEvm<'db, I> {
213        let eth_evm = Self::default().create_evm_with_inspector(db, evm_env, inspector);
214        let mut inner = eth_evm.into_inner();
215        inner.ctx.cfg.tx_chain_id_check = true;
216
217        let mut evm = EthFoundryEvm { inner };
218        evm.inspector().get_networks().inject_precompiles(evm.precompiles_mut());
219        evm
220    }
221
222    fn create_foundry_nested_evm<'db>(
223        &self,
224        db: &'db mut dyn DatabaseExt<Self>,
225        evm_env: EvmEnv,
226        inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
227    ) -> Box<dyn NestedEvm<Spec = SpecId, Block = BlockEnv, Tx = TxEnv> + 'db> {
228        Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).into_nested_evm())
229    }
230}
231
232/// Get the call inputs for the CREATE2 factory.
233fn get_create2_factory_call_inputs(
234    salt: U256,
235    inputs: &CreateInputs,
236    deployer: Address,
237) -> CallInputs {
238    let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code()[..]].concat();
239    CallInputs {
240        caller: inputs.caller(),
241        bytecode_address: deployer,
242        known_bytecode: None,
243        target_address: deployer,
244        scheme: CallScheme::Call,
245        value: CallValue::Transfer(inputs.value()),
246        input: CallInput::Bytes(calldata.into()),
247        gas_limit: inputs.gas_limit(),
248        is_static: false,
249        return_memory_offset: 0..0,
250    }
251}
252
253type EthRevmEvm<'db, I> = RevmEvm<
254    EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>,
255    I,
256    EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
257    PrecompilesMap,
258    EthFrame<EthInterpreter>,
259>;
260
261pub struct EthFoundryEvm<
262    'db,
263    I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
264> {
265    pub inner: EthRevmEvm<'db, I>,
266}
267
268impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Evm
269    for EthFoundryEvm<'db, I>
270{
271    type Precompiles = PrecompilesMap;
272    type Inspector = I;
273    type DB = &'db mut dyn DatabaseExt<EthEvmFactory>;
274    type Error = EVMError<DatabaseError>;
275    type HaltReason = HaltReason;
276    type Spec = SpecId;
277    type Tx = TxEnv;
278    type BlockEnv = BlockEnv;
279
280    fn block(&self) -> &BlockEnv {
281        &self.inner.block
282    }
283
284    fn chain_id(&self) -> u64 {
285        self.inner.ctx.cfg.chain_id
286    }
287
288    fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
289        (&self.inner.ctx.journaled_state.database, &self.inner.inspector, &self.inner.precompiles)
290    }
291
292    fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
293        (
294            &mut self.inner.ctx.journaled_state.database,
295            &mut self.inner.inspector,
296            &mut self.inner.precompiles,
297        )
298    }
299
300    fn set_inspector_enabled(&mut self, _enabled: bool) {
301        unimplemented!("FoundryEvm is always inspecting")
302    }
303
304    fn transact_raw(
305        &mut self,
306        tx: Self::Tx,
307    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
308        self.inner.set_tx(tx);
309
310        let mut handler = EthFoundryHandler::<I>::default();
311        let result = handler.inspect_run(&mut self.inner)?;
312
313        Ok(ResultAndState::new(result, self.inner.ctx.journaled_state.inner.state.clone()))
314    }
315
316    fn transact_system_call(
317        &mut self,
318        _caller: Address,
319        _contract: Address,
320        _data: Bytes,
321    ) -> Result<ExecResultAndState<ExecutionResult>, Self::Error> {
322        unimplemented!()
323    }
324
325    fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
326    where
327        Self: Sized,
328    {
329        let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx;
330
331        (journaled_state.database, EvmEnv { block_env, cfg_env })
332    }
333}
334
335impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Deref
336    for EthFoundryEvm<'db, I>
337{
338    type Target = EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>;
339
340    fn deref(&self) -> &Self::Target {
341        &self.inner.ctx
342    }
343}
344
345impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> DerefMut
346    for EthFoundryEvm<'db, I>
347{
348    fn deref_mut(&mut self) -> &mut Self::Target {
349        &mut self.inner.ctx
350    }
351}
352
353/// Trait for converting a Foundry EVM wrapper into its inner `NestedEvm` implementation.
354///
355/// Both [`EthFoundryEvm`] and [`TempoFoundryEvm`] wrap an inner revm EVM that implements
356/// [`NestedEvm`]. This trait provides a uniform way to unwrap them.
357pub trait IntoNestedEvm<SPEC, BLOCK, TX> {
358    /// The inner type that implements [`NestedEvm`].
359    type Inner: NestedEvm<Spec = SPEC, Block = BLOCK, Tx = TX>;
360
361    /// Consumes the wrapper, returning the inner revm EVM.
362    fn into_nested_evm(self) -> Self::Inner;
363}
364
365impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>>
366    IntoNestedEvm<SpecId, BlockEnv, TxEnv> for EthFoundryEvm<'db, I>
367{
368    type Inner = EthRevmEvm<'db, I>;
369
370    fn into_nested_evm(self) -> Self::Inner {
371        self.inner
372    }
373}
374
375/// Object-safe trait exposing the operations that cheatcode nested EVM closures need.
376///
377/// This abstracts over the concrete EVM type (`FoundryEvm`, future `TempoEvm`, etc.)
378/// so that cheatcode impls can build and run nested EVMs without knowing the concrete type.
379pub trait NestedEvm {
380    /// The spec type.
381    type Spec;
382    /// The block environment type.
383    type Block;
384    /// The transaction environment type.
385    type Tx;
386
387    /// Returns a mutable reference to the journal inner state (`JournaledState`).
388    fn journal_inner_mut(&mut self) -> &mut JournaledState;
389
390    /// Runs a single execution frame (create or call) through the EVM handler loop.
391    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>>;
392
393    /// Executes a full transaction with the given tx env.
394    fn transact_raw(
395        &mut self,
396        tx: Self::Tx,
397    ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>>;
398
399    fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block>;
400}
401
402impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> NestedEvm
403    for EthRevmEvm<'db, I>
404{
405    type Spec = SpecId;
406    type Block = BlockEnv;
407    type Tx = TxEnv;
408
409    fn journal_inner_mut(&mut self) -> &mut JournaledState {
410        &mut self.ctx_mut().journaled_state.inner
411    }
412
413    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
414        let mut handler = EthFoundryHandler::<I>::default();
415
416        // Create first frame
417        let memory =
418            SharedMemory::new_with_buffer(self.ctx().local().shared_memory_buffer().clone());
419        let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
420
421        // Run execution loop
422        let mut frame_result = handler.inspect_run_exec_loop(self, first_frame_input)?;
423
424        // Handle last frame result
425        handler.last_frame_result(self, &mut frame_result)?;
426
427        Ok(frame_result)
428    }
429
430    fn transact_raw(
431        &mut self,
432        tx: Self::Tx,
433    ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
434        self.set_tx(tx);
435
436        let mut handler = EthFoundryHandler::<I>::default();
437        let result = handler.inspect_run(self)?;
438
439        Ok(ResultAndState::new(result, self.ctx.journaled_state.inner.state.clone()))
440    }
441
442    fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
443        self.ctx_ref().evm_clone()
444    }
445}
446
447/// Closure type used by `CheatcodesExecutor` methods that run nested EVM operations.
448pub type NestedEvmClosure<'a, Spec, Block, Tx> =
449    &'a mut dyn FnMut(
450        &mut dyn NestedEvm<Spec = Spec, Block = Block, Tx = Tx>,
451    ) -> Result<(), EVMError<DatabaseError>>;
452
453/// Clones the current context (env + journal), passes the database, cloned env,
454/// and cloned journal inner to the callback. The callback builds whatever EVM it
455/// needs, runs its operations, and returns `(result, modified_env, modified_journal)`.
456/// Modified state is written back after the callback returns.
457pub fn with_cloned_context<CTX: FoundryContextExt>(
458    ecx: &mut CTX,
459    f: impl FnOnce(
460        &mut CTX::Db,
461        EvmEnv<CTX::Spec, CTX::Block>,
462        JournaledState,
463    )
464        -> Result<(EvmEnv<CTX::Spec, CTX::Block>, JournaledState), EVMError<DatabaseError>>,
465) -> Result<(), EVMError<DatabaseError>> {
466    let evm_env = ecx.evm_clone();
467
468    let (db, journal_inner) = ecx.db_journal_inner_mut();
469    let journal_inner_clone = journal_inner.clone();
470
471    let (sub_evm_env, sub_inner) = f(db, evm_env, journal_inner_clone)?;
472
473    // Write back modified state. The db borrow was released when f returned.
474    ecx.set_journal_inner(sub_inner);
475    ecx.set_evm(sub_evm_env);
476
477    Ok(())
478}
479
480pub struct EthFoundryHandler<
481    'db,
482    I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
483> {
484    create2_overrides: Vec<(usize, CallInputs)>,
485    _phantom: PhantomData<(&'db mut dyn DatabaseExt<EthEvmFactory>, I)>,
486}
487
488impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Default
489    for EthFoundryHandler<'db, I>
490{
491    fn default() -> Self {
492        Self { create2_overrides: Vec::new(), _phantom: PhantomData }
493    }
494}
495
496// Blanket Handler implementation for FoundryHandler, needed for implementing the InspectorHandler
497// trait.
498impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> Handler
499    for EthFoundryHandler<'db, I>
500{
501    type Evm = RevmEvm<
502        EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>,
503        I,
504        EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
505        PrecompilesMap,
506        EthFrame<EthInterpreter>,
507    >;
508    type Error = EVMError<DatabaseError>;
509    type HaltReason = HaltReason;
510}
511
512impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>>
513    EthFoundryHandler<'db, I>
514{
515    /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2
516    /// factory.
517    fn handle_create_frame(
518        &mut self,
519        evm: &mut <Self as Handler>::Evm,
520        init: &mut FrameInit,
521    ) -> Result<Option<FrameResult>, <Self as Handler>::Error> {
522        if let FrameInput::Create(inputs) = &init.frame_input
523            && let CreateScheme::Create2 { salt } = inputs.scheme()
524        {
525            let (ctx, inspector) = evm.ctx_inspector();
526
527            if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {
528                let gas_limit = inputs.gas_limit();
529
530                // Get CREATE2 deployer.
531                let create2_deployer = evm.inspector().create2_deployer();
532
533                // Generate call inputs for CREATE2 factory.
534                let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
535
536                // Push data about current override to the stack.
537                self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
538
539                // Sanity check that CREATE2 deployer exists.
540                let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
541                if code_hash == KECCAK_EMPTY {
542                    return Ok(Some(FrameResult::Call(CallOutcome {
543                        result: InterpreterResult {
544                            result: InstructionResult::Revert,
545                            output: Bytes::from(
546                                format!("missing CREATE2 deployer: {create2_deployer}")
547                                    .into_bytes(),
548                            ),
549                            gas: Gas::new(gas_limit),
550                        },
551                        memory_offset: 0..0,
552                        was_precompile_called: false,
553                        precompile_call_logs: vec![],
554                    })));
555                } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
556                    return Ok(Some(FrameResult::Call(CallOutcome {
557                        result: InterpreterResult {
558                            result: InstructionResult::Revert,
559                            output: "invalid CREATE2 deployer bytecode".into(),
560                            gas: Gas::new(gas_limit),
561                        },
562                        memory_offset: 0..0,
563                        was_precompile_called: false,
564                        precompile_call_logs: vec![],
565                    })));
566                }
567
568                // Rewrite the frame init
569                init.frame_input = FrameInput::Call(Box::new(call_inputs));
570            }
571        }
572        Ok(None)
573    }
574
575    /// Transforms CREATE2 factory call results back into CREATE outcomes.
576    fn handle_create2_override(
577        &mut self,
578        evm: &mut <Self as Handler>::Evm,
579        result: FrameResult,
580    ) -> FrameResult {
581        if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
582            let (_, call_inputs) = self.create2_overrides.pop().unwrap();
583            let FrameResult::Call(mut call) = result else {
584                unreachable!("create2 override should be a call frame");
585            };
586
587            // Decode address from output.
588            let address = match call.instruction_result() {
589                return_ok!() => Address::try_from(call.output().as_ref())
590                    .map_err(|_| {
591                        call.result = InterpreterResult {
592                            result: InstructionResult::Revert,
593                            output: "invalid CREATE2 factory output".into(),
594                            gas: Gas::new(call_inputs.gas_limit),
595                        };
596                    })
597                    .ok(),
598                _ => None,
599            };
600
601            FrameResult::Create(CreateOutcome { result: call.result, address })
602        } else {
603            result
604        }
605    }
606}
607
608impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>>
609    InspectorHandler for EthFoundryHandler<'db, I>
610{
611    type IT = EthInterpreter;
612
613    fn inspect_run_exec_loop(
614        &mut self,
615        evm: &mut Self::Evm,
616        first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
617    ) -> Result<FrameResult, Self::Error> {
618        let res = evm.inspect_frame_init(first_frame_input)?;
619
620        if let ItemOrResult::Result(frame_result) = res {
621            return Ok(frame_result);
622        }
623
624        loop {
625            let call_or_result = evm.inspect_frame_run()?;
626
627            let result = match call_or_result {
628                ItemOrResult::Item(mut init) => {
629                    // Handle CREATE/CREATE2 frame initialization
630                    if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? {
631                        return Ok(frame_result);
632                    }
633
634                    match evm.inspect_frame_init(init)? {
635                        ItemOrResult::Item(_) => continue,
636                        ItemOrResult::Result(result) => result,
637                    }
638                }
639                ItemOrResult::Result(result) => result,
640            };
641
642            // Handle CREATE2 override transformation if needed
643            let result = self.handle_create2_override(evm, result);
644
645            if let Some(result) = evm.frame_return_result(result)? {
646                return Ok(result);
647            }
648        }
649    }
650}
651
652type OpRevmEvm<'db, I> = op_revm::OpEvm<
653    OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>,
654    I,
655    EthInstructions<EthInterpreter, OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
656    PrecompilesMap,
657>;
658
659/// Optimism counterpart of [`EthFoundryEvm`]. Wraps `op_revm::OpEvm` and routes execution
660/// through [`OpFoundryHandler`] which composes [`OpHandler`] with CREATE2 factory redirect logic.
661pub struct OpFoundryEvm<
662    'db,
663    I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
664> {
665    pub inner: OpRevmEvm<'db, I>,
666}
667
668impl FoundryEvmFactory for OpEvmFactory {
669    type FoundryContext<'db> = OpContext<&'db mut dyn DatabaseExt<Self>>;
670
671    type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> = OpFoundryEvm<'db, I>;
672
673    fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
674        &self,
675        db: &'db mut dyn DatabaseExt<Self>,
676        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
677        inspector: I,
678    ) -> Self::FoundryEvm<'db, I> {
679        let spec_id = *evm_env.spec_id();
680        let mut inner = Context::op()
681            .with_db(db)
682            .with_block(evm_env.block_env)
683            .with_cfg(evm_env.cfg_env)
684            .build_op_with_inspector(inspector)
685            .with_precompiles(PrecompilesMap::from_static(
686                OpPrecompiles::new_with_spec(spec_id).precompiles(),
687            ));
688        inner.ctx().cfg.tx_chain_id_check = true;
689
690        let mut evm = OpFoundryEvm { inner };
691        let networks = Evm::inspector(&evm).get_networks();
692        networks.inject_precompiles(evm.precompiles_mut());
693        evm
694    }
695
696    fn create_foundry_nested_evm<'db>(
697        &self,
698        db: &'db mut dyn DatabaseExt<Self>,
699        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
700        inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
701    ) -> Box<dyn NestedEvm<Spec = OpSpecId, Block = BlockEnv, Tx = OpTransaction<TxEnv>> + 'db>
702    {
703        Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).into_nested_evm())
704    }
705}
706
707impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Evm
708    for OpFoundryEvm<'db, I>
709{
710    type Precompiles = PrecompilesMap;
711    type Inspector = I;
712    type DB = &'db mut dyn DatabaseExt<OpEvmFactory>;
713    type Error = EVMError<DatabaseError, OpTransactionError>;
714    type HaltReason = OpHaltReason;
715    type Spec = OpSpecId;
716    type Tx = OpTransaction<TxEnv>;
717    type BlockEnv = BlockEnv;
718
719    fn block(&self) -> &BlockEnv {
720        &self.inner.ctx_ref().block
721    }
722
723    fn chain_id(&self) -> u64 {
724        self.inner.ctx_ref().cfg.chain_id
725    }
726
727    fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
728        let (ctx, _, precompiles, _, inspector) = self.inner.all_inspector();
729        (&ctx.journaled_state.database, inspector, precompiles)
730    }
731
732    fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
733        let (ctx, _, precompiles, _, inspector) = self.inner.all_mut_inspector();
734        (&mut ctx.journaled_state.database, inspector, precompiles)
735    }
736
737    fn set_inspector_enabled(&mut self, _enabled: bool) {
738        unimplemented!("OpFoundryEvm is always inspecting")
739    }
740
741    fn transact_raw(
742        &mut self,
743        tx: Self::Tx,
744    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
745        self.inner.ctx().set_tx(tx);
746
747        let mut handler = OpFoundryHandler::<I>::default();
748        let result = handler.inspect_run(&mut self.inner)?;
749
750        Ok(ResultAndState::new(result, self.inner.ctx_ref().journaled_state.inner.state.clone()))
751    }
752
753    fn transact_system_call(
754        &mut self,
755        _caller: Address,
756        _contract: Address,
757        _data: Bytes,
758    ) -> Result<ExecResultAndState<ExecutionResult<Self::HaltReason>>, Self::Error> {
759        unimplemented!()
760    }
761
762    fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
763    where
764        Self: Sized,
765    {
766        let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx;
767        (journaled_state.database, EvmEnv { block_env, cfg_env })
768    }
769}
770
771impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Deref
772    for OpFoundryEvm<'db, I>
773{
774    type Target = OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>;
775
776    fn deref(&self) -> &Self::Target {
777        &self.inner.0.ctx
778    }
779}
780
781impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> DerefMut
782    for OpFoundryEvm<'db, I>
783{
784    fn deref_mut(&mut self) -> &mut Self::Target {
785        &mut self.inner.0.ctx
786    }
787}
788
789impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>>
790    IntoNestedEvm<OpSpecId, BlockEnv, OpTransaction<TxEnv>> for OpFoundryEvm<'db, I>
791{
792    type Inner = OpRevmEvm<'db, I>;
793
794    fn into_nested_evm(self) -> Self::Inner {
795        self.inner
796    }
797}
798
799/// Maps an OP [`EVMError`] to the common `EVMError<DatabaseError>` used by [`NestedEvm`].
800fn map_op_error(e: EVMError<DatabaseError, OpTransactionError>) -> EVMError<DatabaseError> {
801    match e {
802        EVMError::Database(db) => EVMError::Database(db),
803        EVMError::Header(h) => EVMError::Header(h),
804        EVMError::Custom(s) => EVMError::Custom(s),
805        EVMError::Transaction(t) => EVMError::Custom(format!("op transaction error: {t}")),
806    }
807}
808
809impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> NestedEvm
810    for OpRevmEvm<'db, I>
811{
812    type Spec = OpSpecId;
813    type Block = BlockEnv;
814    type Tx = OpTransaction<TxEnv>;
815
816    fn journal_inner_mut(&mut self) -> &mut JournaledState {
817        &mut self.ctx().journaled_state.inner
818    }
819
820    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
821        let mut handler = OpFoundryHandler::<I>::default();
822
823        let memory =
824            SharedMemory::new_with_buffer(self.ctx_ref().local.shared_memory_buffer().clone());
825        let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
826
827        let mut frame_result =
828            handler.inspect_run_exec_loop(self, first_frame_input).map_err(map_op_error)?;
829
830        handler.last_frame_result(self, &mut frame_result).map_err(map_op_error)?;
831
832        Ok(frame_result)
833    }
834
835    fn transact_raw(
836        &mut self,
837        tx: Self::Tx,
838    ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
839        self.ctx().set_tx(tx);
840
841        let mut handler = OpFoundryHandler::<I>::default();
842        let result = handler.inspect_run(self).map_err(map_op_error)?;
843
844        let result = result.map_haltreason(|h| match h {
845            OpHaltReason::Base(eth) => eth,
846            _ => HaltReason::PrecompileError,
847        });
848
849        Ok(ResultAndState::new(result, self.ctx_ref().journaled_state.inner.state.clone()))
850    }
851
852    fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
853        EvmEnv::new(self.ctx_ref().cfg.clone(), self.ctx_ref().block.clone())
854    }
855}
856
857/// Optimism handler that composes [`OpHandler`] with CREATE2 factory redirect logic.
858pub struct OpFoundryHandler<
859    'db,
860    I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
861> {
862    inner: OpHandler<
863        OpRevmEvm<'db, I>,
864        EVMError<DatabaseError, OpTransactionError>,
865        EthFrame<EthInterpreter>,
866    >,
867    create2_overrides: Vec<(usize, CallInputs)>,
868}
869
870impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Default
871    for OpFoundryHandler<'db, I>
872{
873    fn default() -> Self {
874        Self { inner: OpHandler::new(), create2_overrides: Vec::new() }
875    }
876}
877
878impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Handler
879    for OpFoundryHandler<'db, I>
880{
881    type Evm = OpRevmEvm<'db, I>;
882    type Error = EVMError<DatabaseError, OpTransactionError>;
883    type HaltReason = OpHaltReason;
884
885    #[inline]
886    fn run(
887        &mut self,
888        evm: &mut Self::Evm,
889    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
890        self.inner.run(evm)
891    }
892
893    #[inline]
894    fn execution(
895        &mut self,
896        evm: &mut Self::Evm,
897        init_and_floor_gas: &revm::interpreter::InitialAndFloorGas,
898    ) -> Result<FrameResult, Self::Error> {
899        self.inner.execution(evm, init_and_floor_gas)
900    }
901
902    #[inline]
903    fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
904        self.inner.validate_env(evm)
905    }
906
907    #[inline]
908    fn validate_against_state_and_deduct_caller(
909        &self,
910        evm: &mut Self::Evm,
911    ) -> Result<(), Self::Error> {
912        self.inner.validate_against_state_and_deduct_caller(evm)
913    }
914
915    #[inline]
916    fn reimburse_caller(
917        &self,
918        evm: &mut Self::Evm,
919        exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
920    ) -> Result<(), Self::Error> {
921        self.inner.reimburse_caller(evm, exec_result)
922    }
923
924    #[inline]
925    fn reward_beneficiary(
926        &self,
927        evm: &mut Self::Evm,
928        exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
929    ) -> Result<(), Self::Error> {
930        self.inner.reward_beneficiary(evm, exec_result)
931    }
932
933    #[inline]
934    fn validate_initial_tx_gas(
935        &self,
936        evm: &mut Self::Evm,
937    ) -> Result<revm::interpreter::InitialAndFloorGas, Self::Error> {
938        self.inner.validate_initial_tx_gas(evm)
939    }
940
941    #[inline]
942    fn execution_result(
943        &mut self,
944        evm: &mut Self::Evm,
945        result: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
946        result_gas: revm::context::result::ResultGas,
947    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
948        self.inner.execution_result(evm, result, result_gas)
949    }
950
951    #[inline]
952    fn catch_error(
953        &self,
954        evm: &mut Self::Evm,
955        error: Self::Error,
956    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
957        self.inner.catch_error(evm, error)
958    }
959}
960
961impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>>
962    InspectorHandler for OpFoundryHandler<'db, I>
963{
964    type IT = EthInterpreter;
965
966    fn inspect_run_exec_loop(
967        &mut self,
968        evm: &mut Self::Evm,
969        first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
970    ) -> Result<FrameResult, Self::Error> {
971        let res = evm.inspect_frame_init(first_frame_input)?;
972
973        if let ItemOrResult::Result(frame_result) = res {
974            return Ok(frame_result);
975        }
976
977        loop {
978            let call_or_result = evm.inspect_frame_run()?;
979
980            let result = match call_or_result {
981                ItemOrResult::Item(mut init) => {
982                    // Handle CREATE/CREATE2 frame initialization
983                    if let FrameInput::Create(inputs) = &init.frame_input
984                        && let CreateScheme::Create2 { salt } = inputs.scheme()
985                    {
986                        let (ctx, inspector) = evm.ctx_inspector();
987                        if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {
988                            let gas_limit = inputs.gas_limit();
989                            let create2_deployer = evm.inspector().create2_deployer();
990                            let call_inputs =
991                                get_create2_factory_call_inputs(salt, inputs, create2_deployer);
992
993                            self.create2_overrides
994                                .push((evm.ctx_ref().journal().depth(), call_inputs.clone()));
995
996                            let code_hash = evm
997                                .ctx()
998                                .journal_mut()
999                                .load_account(create2_deployer)?
1000                                .info
1001                                .code_hash;
1002                            if code_hash == KECCAK_EMPTY {
1003                                return Ok(FrameResult::Call(CallOutcome {
1004                                    result: InterpreterResult {
1005                                        result: InstructionResult::Revert,
1006                                        output: Bytes::from(
1007                                            format!("missing CREATE2 deployer: {create2_deployer}")
1008                                                .into_bytes(),
1009                                        ),
1010                                        gas: Gas::new(gas_limit),
1011                                    },
1012                                    memory_offset: 0..0,
1013                                    was_precompile_called: false,
1014                                    precompile_call_logs: vec![],
1015                                }));
1016                            } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
1017                                return Ok(FrameResult::Call(CallOutcome {
1018                                    result: InterpreterResult {
1019                                        result: InstructionResult::Revert,
1020                                        output: "invalid CREATE2 deployer bytecode".into(),
1021                                        gas: Gas::new(gas_limit),
1022                                    },
1023                                    memory_offset: 0..0,
1024                                    was_precompile_called: false,
1025                                    precompile_call_logs: vec![],
1026                                }));
1027                            }
1028
1029                            init.frame_input = FrameInput::Call(Box::new(call_inputs));
1030                        }
1031                    }
1032
1033                    match evm.inspect_frame_init(init)? {
1034                        ItemOrResult::Item(_) => continue,
1035                        ItemOrResult::Result(result) => result,
1036                    }
1037                }
1038                ItemOrResult::Result(result) => result,
1039            };
1040
1041            // Handle CREATE2 override transformation if needed
1042            let result = if self
1043                .create2_overrides
1044                .last()
1045                .is_some_and(|(depth, _)| *depth == evm.ctx_ref().journal().depth())
1046            {
1047                let (_, call_inputs) = self.create2_overrides.pop().unwrap();
1048                let FrameResult::Call(mut call) = result else {
1049                    unreachable!("create2 override should be a call frame");
1050                };
1051                let address = match call.instruction_result() {
1052                    return_ok!() => Address::try_from(call.output().as_ref())
1053                        .map_err(|_| {
1054                            call.result = InterpreterResult {
1055                                result: InstructionResult::Revert,
1056                                output: "invalid CREATE2 factory output".into(),
1057                                gas: Gas::new(call_inputs.gas_limit),
1058                            };
1059                        })
1060                        .ok(),
1061                    _ => None,
1062                };
1063                FrameResult::Create(CreateOutcome { result: call.result, address })
1064            } else {
1065                result
1066            };
1067
1068            if let Some(result) = evm.frame_return_result(result)? {
1069                return Ok(result);
1070            }
1071        }
1072    }
1073}
1074
1075// Will be removed when the next revm release includes bluealloy/revm#3518.
1076type TempoRevmEvm<'db, I> = tempo_revm::TempoEvm<&'db mut dyn DatabaseExt<TempoEvmFactory>, I>;
1077
1078/// Tempo counterpart of [`EthFoundryEvm`]. Wraps `tempo_revm::TempoEvm` and routes execution
1079/// through [`TempoFoundryHandler`] which composes [`TempoEvmHandler`] with CREATE2 factory
1080/// redirect logic.
1081///
1082/// Uses [`TempoEvmFactory`] for construction to reuse factory setup logic, then unwraps to the
1083/// raw revm EVM via `into_inner()` since the handler operates at the revm level.
1084pub struct TempoFoundryEvm<
1085    'db,
1086    I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1087> {
1088    pub inner: TempoRevmEvm<'db, I>,
1089}
1090
1091/// Initialize Tempo precompiles and contracts for a newly created [`TempoFoundryEvm`].
1092///
1093/// In non-fork mode, runs full genesis initialization (precompile sentinel bytecode,
1094/// TIP20 fee tokens, standard contracts) via [`StorageCtx::enter_evm`].
1095///
1096/// In fork mode, warms up precompile and TIP20 token addresses with sentinel bytecode
1097/// to prevent repeated RPC round-trips for addresses that are Rust-native precompiles
1098/// on Tempo nodes (no real EVM bytecode on-chain).
1099fn initialize_tempo_evm<
1100    'db,
1101    I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1102>(
1103    evm: &mut TempoFoundryEvm<'db, I>,
1104    is_forked: bool,
1105) {
1106    let ctx = &mut evm.inner.inner.ctx;
1107    StorageCtx::enter_evm(&mut ctx.journaled_state, &ctx.block, &ctx.cfg, &ctx.tx, || {
1108        if is_forked {
1109            // In fork mode, warm up precompile accounts to avoid repeated RPC fetches.
1110            let mut sctx = StorageCtx;
1111            let sentinel = Bytecode::new_legacy(Bytes::from_static(&[0xef]));
1112            for addr in TEMPO_PRECOMPILE_ADDRESSES.iter().chain(TEMPO_TIP20_TOKENS.iter()) {
1113                sctx.set_code(*addr, sentinel.clone())
1114                    .expect("failed to warm tempo precompile address");
1115            }
1116        } else {
1117            // In non-fork mode, run full genesis initialization.
1118            initialize_tempo_genesis_inner(TEST_CONTRACT_ADDRESS, CALLER)
1119                .expect("tempo genesis initialization failed");
1120        }
1121    });
1122}
1123
1124impl FoundryEvmFactory for TempoEvmFactory {
1125    type FoundryContext<'db> = TempoContext<&'db mut dyn DatabaseExt<Self>>;
1126
1127    type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> =
1128        TempoFoundryEvm<'db, I>;
1129
1130    fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
1131        &self,
1132        db: &'db mut dyn DatabaseExt<Self>,
1133        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
1134        inspector: I,
1135    ) -> Self::FoundryEvm<'db, I> {
1136        let is_forked = db.is_forked_mode();
1137        let spec = *evm_env.spec_id();
1138        let tempo_evm = Self::default().create_evm_with_inspector(db, evm_env, inspector);
1139        let mut inner = tempo_evm.into_inner();
1140        inner.ctx.cfg.gas_params = tempo_gas_params(spec);
1141        inner.ctx.cfg.tx_chain_id_check = true;
1142
1143        let mut evm = TempoFoundryEvm { inner };
1144        let networks = Evm::inspector(&evm).get_networks();
1145        networks.inject_precompiles(evm.precompiles_mut());
1146
1147        initialize_tempo_evm(&mut evm, is_forked);
1148        evm
1149    }
1150
1151    fn create_foundry_nested_evm<'db>(
1152        &self,
1153        db: &'db mut dyn DatabaseExt<Self>,
1154        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
1155        inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
1156    ) -> Box<dyn NestedEvm<Spec = TempoHardfork, Block = TempoBlockEnv, Tx = TempoTxEnv> + 'db>
1157    {
1158        Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).into_nested_evm())
1159    }
1160}
1161
1162impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Evm
1163    for TempoFoundryEvm<'db, I>
1164{
1165    type Precompiles = PrecompilesMap;
1166    type Inspector = I;
1167    type DB = &'db mut dyn DatabaseExt<TempoEvmFactory>;
1168    type Error = EVMError<DatabaseError, TempoInvalidTransaction>;
1169    type HaltReason = TempoHaltReason;
1170    type Spec = TempoHardfork;
1171    type Tx = TempoTxEnv;
1172    type BlockEnv = TempoBlockEnv;
1173
1174    fn block(&self) -> &TempoBlockEnv {
1175        &self.inner.block
1176    }
1177
1178    fn chain_id(&self) -> u64 {
1179        self.inner.ctx.cfg.chain_id
1180    }
1181
1182    fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
1183        let evm = &self.inner.inner;
1184        (&evm.ctx.journaled_state.database, &evm.inspector, &evm.precompiles)
1185    }
1186
1187    fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
1188        let evm = &mut self.inner.inner;
1189        (&mut evm.ctx.journaled_state.database, &mut evm.inspector, &mut evm.precompiles)
1190    }
1191
1192    fn set_inspector_enabled(&mut self, _enabled: bool) {
1193        unimplemented!("TempoFoundryEvm is always inspecting")
1194    }
1195
1196    fn transact_raw(
1197        &mut self,
1198        tx: Self::Tx,
1199    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
1200        self.inner.set_tx(tx);
1201
1202        let mut handler = TempoFoundryHandler::<I>::default();
1203        let result = handler.inspect_run(&mut self.inner)?;
1204
1205        Ok(ResultAndState::new(result, self.inner.inner.ctx.journaled_state.inner.state.clone()))
1206    }
1207
1208    fn transact_system_call(
1209        &mut self,
1210        _caller: Address,
1211        _contract: Address,
1212        _data: Bytes,
1213    ) -> Result<ExecResultAndState<ExecutionResult<Self::HaltReason>>, Self::Error> {
1214        unimplemented!()
1215    }
1216
1217    fn finish(self) -> (Self::DB, EvmEnv<Self::Spec, Self::BlockEnv>)
1218    where
1219        Self: Sized,
1220    {
1221        let revm_evm = self.inner.inner;
1222        let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = revm_evm.ctx;
1223        (journaled_state.database, EvmEnv { block_env, cfg_env })
1224    }
1225}
1226
1227impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Deref
1228    for TempoFoundryEvm<'db, I>
1229{
1230    type Target = TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>;
1231
1232    fn deref(&self) -> &Self::Target {
1233        &self.inner.ctx
1234    }
1235}
1236
1237impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> DerefMut
1238    for TempoFoundryEvm<'db, I>
1239{
1240    fn deref_mut(&mut self) -> &mut Self::Target {
1241        &mut self.inner.ctx
1242    }
1243}
1244
1245impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>>
1246    IntoNestedEvm<TempoHardfork, TempoBlockEnv, TempoTxEnv> for TempoFoundryEvm<'db, I>
1247{
1248    type Inner = TempoRevmEvm<'db, I>;
1249
1250    fn into_nested_evm(self) -> Self::Inner {
1251        self.inner
1252    }
1253}
1254
1255/// Maps a Tempo [`EVMError`] to the common `EVMError<DatabaseError>` used by [`NestedEvm`].
1256///
1257/// This exists because [`NestedEvm`] currently uses Eth-typed errors. When `NestedEvm` gains
1258/// an associated `Error` type, this mapping can be removed.
1259fn map_tempo_error(e: EVMError<DatabaseError, TempoInvalidTransaction>) -> EVMError<DatabaseError> {
1260    match e {
1261        EVMError::Database(db) => EVMError::Database(db),
1262        EVMError::Header(h) => EVMError::Header(h),
1263        EVMError::Custom(s) => EVMError::Custom(s),
1264        EVMError::Transaction(t) => match t {
1265            TempoInvalidTransaction::EthInvalidTransaction(eth) => EVMError::Transaction(eth),
1266            t => EVMError::Custom(format!("tempo transaction error: {t}")),
1267        },
1268    }
1269}
1270
1271impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> NestedEvm
1272    for TempoRevmEvm<'db, I>
1273{
1274    type Spec = TempoHardfork;
1275    type Block = TempoBlockEnv;
1276    type Tx = TempoTxEnv;
1277
1278    fn journal_inner_mut(&mut self) -> &mut JournaledState {
1279        &mut self.ctx_mut().journaled_state.inner
1280    }
1281
1282    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
1283        let mut handler = TempoFoundryHandler::<I>::default();
1284
1285        let memory =
1286            SharedMemory::new_with_buffer(self.ctx().local().shared_memory_buffer().clone());
1287        let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
1288
1289        let mut frame_result =
1290            handler.inspect_run_exec_loop(self, first_frame_input).map_err(map_tempo_error)?;
1291
1292        handler.last_frame_result(self, &mut frame_result).map_err(map_tempo_error)?;
1293
1294        Ok(frame_result)
1295    }
1296
1297    fn transact_raw(
1298        &mut self,
1299        tx: Self::Tx,
1300    ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
1301        self.set_tx(tx);
1302
1303        let mut handler = TempoFoundryHandler::<I>::default();
1304        let result = handler.inspect_run(self).map_err(map_tempo_error)?;
1305
1306        let result = result.map_haltreason(|h| match h {
1307            TempoHaltReason::Ethereum(eth) => eth,
1308            _ => HaltReason::PrecompileError,
1309        });
1310
1311        Ok(ResultAndState::new(result, self.ctx.journaled_state.inner.state.clone()))
1312    }
1313
1314    fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
1315        self.ctx_ref().evm_clone()
1316    }
1317}
1318
1319/// Tempo counterpart of [`EthFoundryHandler`]. Wraps [`TempoEvmHandler`] and injects CREATE2
1320/// factory redirect logic into the execution loop. Delegates all [`Handler`] methods to
1321/// [`TempoEvmHandler`] for proper Tempo validation, fee collection, AA dispatch, and gas
1322/// handling.
1323///
1324/// Will be removed when the next revm release includes bluealloy/revm#3518.
1325pub struct TempoFoundryHandler<
1326    'db,
1327    I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1328> {
1329    inner: TempoEvmHandler<&'db mut dyn DatabaseExt<TempoEvmFactory>, I>,
1330    create2_overrides: Vec<(usize, CallInputs)>,
1331}
1332
1333impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Default
1334    for TempoFoundryHandler<'db, I>
1335{
1336    fn default() -> Self {
1337        Self { inner: TempoEvmHandler::new(), create2_overrides: Vec::new() }
1338    }
1339}
1340
1341impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>> Handler
1342    for TempoFoundryHandler<'db, I>
1343{
1344    type Evm = TempoRevmEvm<'db, I>;
1345    type Error = EVMError<DatabaseError, TempoInvalidTransaction>;
1346    type HaltReason = TempoHaltReason;
1347
1348    #[inline]
1349    fn run(
1350        &mut self,
1351        evm: &mut Self::Evm,
1352    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1353        self.inner.run(evm)
1354    }
1355
1356    #[inline]
1357    fn execution(
1358        &mut self,
1359        evm: &mut Self::Evm,
1360        init_and_floor_gas: &revm::interpreter::InitialAndFloorGas,
1361    ) -> Result<FrameResult, Self::Error> {
1362        self.inner.execution(evm, init_and_floor_gas)
1363    }
1364
1365    #[inline]
1366    fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> {
1367        self.inner.validate_env(evm)
1368    }
1369
1370    #[inline]
1371    fn validate_against_state_and_deduct_caller(
1372        &self,
1373        evm: &mut Self::Evm,
1374    ) -> Result<(), Self::Error> {
1375        self.inner.validate_against_state_and_deduct_caller(evm)
1376    }
1377
1378    #[inline]
1379    fn reimburse_caller(
1380        &self,
1381        evm: &mut Self::Evm,
1382        exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
1383    ) -> Result<(), Self::Error> {
1384        self.inner.reimburse_caller(evm, exec_result)
1385    }
1386
1387    #[inline]
1388    fn reward_beneficiary(
1389        &self,
1390        evm: &mut Self::Evm,
1391        exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
1392    ) -> Result<(), Self::Error> {
1393        self.inner.reward_beneficiary(evm, exec_result)
1394    }
1395
1396    #[inline]
1397    fn validate_initial_tx_gas(
1398        &self,
1399        evm: &mut Self::Evm,
1400    ) -> Result<revm::interpreter::InitialAndFloorGas, Self::Error> {
1401        self.inner.validate_initial_tx_gas(evm)
1402    }
1403
1404    #[inline]
1405    fn execution_result(
1406        &mut self,
1407        evm: &mut Self::Evm,
1408        result: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
1409        result_gas: revm::context::result::ResultGas,
1410    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1411        self.inner.execution_result(evm, result, result_gas)
1412    }
1413
1414    #[inline]
1415    fn catch_error(
1416        &self,
1417        evm: &mut Self::Evm,
1418        error: Self::Error,
1419    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1420        self.inner.catch_error(evm, error)
1421    }
1422}
1423
1424/// CREATE2 factory redirect execution loop for Tempo.
1425fn create2_exec_loop<
1426    'db,
1427    I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1428>(
1429    create2_overrides: &mut Vec<(usize, CallInputs)>,
1430    evm: &mut TempoRevmEvm<'db, I>,
1431    first_frame_input: FrameInit,
1432) -> Result<FrameResult, EVMError<DatabaseError, TempoInvalidTransaction>> {
1433    let res = evm.inspect_frame_init(first_frame_input)?;
1434
1435    if let ItemOrResult::Result(frame_result) = res {
1436        return Ok(frame_result);
1437    }
1438
1439    loop {
1440        let call_or_result = evm.inspect_frame_run()?;
1441
1442        let result = match call_or_result {
1443            ItemOrResult::Item(mut init) => {
1444                if let Some(frame_result) = handle_create2_frame(create2_overrides, evm, &mut init)?
1445                {
1446                    return Ok(frame_result);
1447                }
1448
1449                match evm.inspect_frame_init(init)? {
1450                    ItemOrResult::Item(_) => continue,
1451                    ItemOrResult::Result(result) => result,
1452                }
1453            }
1454            ItemOrResult::Result(result) => result,
1455        };
1456
1457        let result = handle_create2_result(create2_overrides, evm, result);
1458
1459        if let Some(result) = evm.frame_return_result(result)? {
1460            return Ok(result);
1461        }
1462    }
1463}
1464
1465/// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2 factory.
1466fn handle_create2_frame<
1467    'db,
1468    I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1469>(
1470    create2_overrides: &mut Vec<(usize, CallInputs)>,
1471    evm: &mut TempoRevmEvm<'db, I>,
1472    init: &mut FrameInit,
1473) -> Result<Option<FrameResult>, EVMError<DatabaseError, TempoInvalidTransaction>> {
1474    if let FrameInput::Create(inputs) = &init.frame_input
1475        && let CreateScheme::Create2 { salt } = inputs.scheme()
1476    {
1477        let (ctx, inspector) = evm.ctx_inspector();
1478
1479        if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {
1480            let gas_limit = inputs.gas_limit();
1481            let create2_deployer = evm.inspector().create2_deployer();
1482            let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
1483
1484            create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
1485
1486            let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
1487            if code_hash == KECCAK_EMPTY {
1488                return Ok(Some(FrameResult::Call(CallOutcome {
1489                    result: InterpreterResult {
1490                        result: InstructionResult::Revert,
1491                        output: Bytes::from(
1492                            format!("missing CREATE2 deployer: {create2_deployer}").into_bytes(),
1493                        ),
1494                        gas: Gas::new(gas_limit),
1495                    },
1496                    memory_offset: 0..0,
1497                    was_precompile_called: false,
1498                    precompile_call_logs: vec![],
1499                })));
1500            } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
1501                return Ok(Some(FrameResult::Call(CallOutcome {
1502                    result: InterpreterResult {
1503                        result: InstructionResult::Revert,
1504                        output: "invalid CREATE2 deployer bytecode".into(),
1505                        gas: Gas::new(gas_limit),
1506                    },
1507                    memory_offset: 0..0,
1508                    was_precompile_called: false,
1509                    precompile_call_logs: vec![],
1510                })));
1511            }
1512
1513            init.frame_input = FrameInput::Call(Box::new(call_inputs));
1514        }
1515    }
1516    Ok(None)
1517}
1518
1519/// Transforms CREATE2 factory call results back into CREATE outcomes.
1520fn handle_create2_result<
1521    'db,
1522    I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>,
1523>(
1524    create2_overrides: &mut Vec<(usize, CallInputs)>,
1525    evm: &mut TempoRevmEvm<'db, I>,
1526    result: FrameResult,
1527) -> FrameResult {
1528    if create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
1529        let (_, call_inputs) = create2_overrides.pop().unwrap();
1530        let FrameResult::Call(mut call) = result else {
1531            unreachable!("create2 override should be a call frame");
1532        };
1533
1534        let address = match call.instruction_result() {
1535            return_ok!() => Address::try_from(call.output().as_ref())
1536                .map_err(|_| {
1537                    call.result = InterpreterResult {
1538                        result: InstructionResult::Revert,
1539                        output: "invalid CREATE2 factory output".into(),
1540                        gas: Gas::new(call_inputs.gas_limit),
1541                    };
1542                })
1543                .ok(),
1544            _ => None,
1545        };
1546
1547        FrameResult::Create(CreateOutcome { result: call.result, address })
1548    } else {
1549        result
1550    }
1551}
1552
1553impl<'db, I: FoundryInspectorExt<TempoContext<&'db mut dyn DatabaseExt<TempoEvmFactory>>>>
1554    InspectorHandler for TempoFoundryHandler<'db, I>
1555{
1556    type IT = EthInterpreter;
1557
1558    /// Overrides `inspect_run` to load Tempo fee fields before delegating to the default
1559    /// execution pipeline. This is necessary because the default `inspect_run` calls
1560    /// `validate` → `validate_against_state_and_deduct_caller` directly, bypassing
1561    /// `Handler::run` where `load_fee_fields` is normally invoked.
1562    fn inspect_run(
1563        &mut self,
1564        evm: &mut Self::Evm,
1565    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
1566        self.inner.load_fee_fields(evm)?;
1567
1568        match self.inspect_run_without_catch_error(evm) {
1569            Ok(output) => Ok(output),
1570            Err(e) => self.catch_error(evm, e),
1571        }
1572    }
1573
1574    /// Delegates to [`TempoEvmHandler::inspect_execution_with`], injecting the CREATE2 factory
1575    /// redirect exec loop. AA multi-call dispatch and gas adjustments are handled by the inner
1576    /// Tempo handler.
1577    #[inline]
1578    fn inspect_execution(
1579        &mut self,
1580        evm: &mut Self::Evm,
1581        init_and_floor_gas: &revm::interpreter::InitialAndFloorGas,
1582    ) -> Result<FrameResult, Self::Error> {
1583        let overrides = &mut self.create2_overrides;
1584        self.inner.inspect_execution_with(evm, init_and_floor_gas, |_handler, evm, init| {
1585            create2_exec_loop(overrides, evm, init)
1586        })
1587    }
1588
1589    fn inspect_run_exec_loop(
1590        &mut self,
1591        evm: &mut Self::Evm,
1592        first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
1593    ) -> Result<FrameResult, Self::Error> {
1594        create2_exec_loop(&mut self.create2_overrides, evm, first_frame_input)
1595    }
1596}