1use std::{
2 fmt::Debug,
3 ops::{Deref, DerefMut},
4};
5
6use crate::{
7 FoundryBlock, FoundryContextExt, FoundryInspectorExt, FoundryTransaction,
8 FromAnyRpcTransaction,
9 backend::{DatabaseExt, JournaledState},
10 constants::{CALLER, TEST_CONTRACT_ADDRESS},
11 tempo::{TEMPO_PRECOMPILE_ADDRESSES, TEMPO_TIP20_TOKENS, initialize_tempo_genesis_inner},
12};
13use alloy_consensus::{SignableTransaction, Signed, transaction::SignerRecoverable};
14use alloy_evm::{
15 EthEvmFactory, Evm, EvmEnv, EvmFactory, FromRecoveredTx, eth::EthEvmContext,
16 precompiles::PrecompilesMap,
17};
18use alloy_network::{Ethereum, Network};
19use alloy_op_evm::{OpEvmFactory, OpTx};
20use alloy_primitives::{Address, Bytes, Signature, U256};
21use alloy_rlp::Decodable;
22use foundry_common::{FoundryReceiptResponse, FoundryTransactionBuilder, fmt::UIfmt};
23use foundry_config::FromEvmVersion;
24use foundry_fork_db::{DatabaseError, ForkBlockEnv};
25use op_alloy_network::Optimism;
26use op_revm::{
27 L1BlockInfo, OpEvm, OpHaltReason, OpSpecId, OpTransaction, handler::OpHandler,
28 precompiles::OpPrecompiles, transaction::error::OpTransactionError,
29};
30use revm::{
31 Context, Database, Journal, MainContext,
32 context::{
33 BlockEnv, CfgEnv, ContextTr, Evm as RevmEvm, JournalTr, LocalContextTr, TxEnv,
34 result::{
35 EVMError, ExecResultAndState, ExecutionResult, HaltReason, InvalidTransaction,
36 ResultAndState,
37 },
38 },
39 handler::{
40 EthFrame, EvmTr, FrameResult, Handler, MainnetHandler, instructions::EthInstructions,
41 },
42 inspector::{InspectorEvmTr, InspectorHandler},
43 interpreter::{
44 CallInput, CallInputs, CallScheme, CallValue, CreateInputs, FrameInput, InstructionResult,
45 SharedMemory, interpreter::EthInterpreter, interpreter_action::FrameInit,
46 },
47 primitives::hardfork::SpecId,
48 state::Bytecode,
49};
50use serde::{Deserialize, Serialize};
51use tempo_alloy::TempoNetwork;
52use tempo_chainspec::hardfork::TempoHardfork;
53use tempo_evm::evm::TempoEvmFactory;
54use tempo_precompiles::storage::StorageCtx;
55use tempo_revm::{
56 TempoBlockEnv, TempoHaltReason, TempoInvalidTransaction, TempoTxEnv, evm::TempoContext,
57 gas_params::tempo_gas_params, handler::TempoEvmHandler,
58};
59
60pub type OpContext<DB> = Context<BlockEnv, OpTx, CfgEnv<OpSpecId>, DB, Journal<DB>, L1BlockInfo>;
62
63pub mod eth;
64pub mod op;
65pub mod tempo;
66
67pub use eth::*;
68pub use op::*;
69pub use tempo::*;
70
71pub trait FoundryEvmNetwork: Copy + Debug + Default + 'static {
73 type Network: Network<
74 TxEnvelope: Decodable
75 + SignerRecoverable
76 + From<Signed<<Self::Network as Network>::UnsignedTx>>
77 + for<'d> Deserialize<'d>
78 + Serialize
79 + UIfmt,
80 UnsignedTx: SignableTransaction<Signature>,
81 TransactionRequest: FoundryTransactionBuilder<Self::Network>
82 + for<'d> Deserialize<'d>
83 + Serialize,
84 ReceiptResponse: FoundryReceiptResponse,
85 >;
86 type EvmFactory: FoundryEvmFactory<Tx: FromRecoveredTx<<Self::Network as Network>::TxEnvelope>>;
87}
88
89#[derive(Clone, Copy, Debug, Default)]
90pub struct EthEvmNetwork;
91impl FoundryEvmNetwork for EthEvmNetwork {
92 type Network = Ethereum;
93 type EvmFactory = EthEvmFactory;
94}
95
96#[derive(Clone, Copy, Debug, Default)]
97pub struct TempoEvmNetwork;
98impl FoundryEvmNetwork for TempoEvmNetwork {
99 type Network = TempoNetwork;
100 type EvmFactory = TempoEvmFactory;
101}
102
103#[derive(Clone, Copy, Debug, Default)]
104pub struct OpEvmNetwork;
105impl FoundryEvmNetwork for OpEvmNetwork {
106 type Network = Optimism;
107 type EvmFactory = OpEvmFactory;
108}
109
110pub type EvmFactoryFor<FEN> = <FEN as FoundryEvmNetwork>::EvmFactory;
112pub type FoundryContextFor<'db, FEN> =
113 <EvmFactoryFor<FEN> as FoundryEvmFactory>::FoundryContext<'db>;
114pub type TxEnvFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Tx;
115pub type HaltReasonFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::HaltReason;
116pub type SpecFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Spec;
117pub type BlockEnvFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::BlockEnv;
118pub type PrecompilesFor<FEN> = <EvmFactoryFor<FEN> as EvmFactory>::Precompiles;
119pub type EvmEnvFor<FEN> = EvmEnv<SpecFor<FEN>, BlockEnvFor<FEN>>;
120
121pub type NetworkFor<FEN> = <FEN as FoundryEvmNetwork>::Network;
122pub type TxEnvelopeFor<FEN> = <NetworkFor<FEN> as Network>::TxEnvelope;
123pub type TransactionRequestFor<FEN> = <NetworkFor<FEN> as Network>::TransactionRequest;
124pub type TransactionResponseFor<FEN> = <NetworkFor<FEN> as Network>::TransactionResponse;
125pub type BlockResponseFor<FEN> = <NetworkFor<FEN> as Network>::BlockResponse;
126
127pub trait FoundryEvmFactory:
128 EvmFactory<
129 Spec: Into<SpecId> + FromEvmVersion + Default + Copy + Unpin + Send + 'static,
130 BlockEnv: FoundryBlock + ForkBlockEnv + Default + Unpin,
131 Tx: Clone + Debug + FoundryTransaction + FromAnyRpcTransaction + Default + Send + Sync,
132 HaltReason: IntoInstructionResult,
133 Precompiles = PrecompilesMap,
134 > + Clone
135 + Debug
136 + Default
137 + 'static
138{
139 type FoundryContext<'db>: FoundryContextExt<
141 Block = Self::BlockEnv,
142 Tx = Self::Tx,
143 Spec = Self::Spec,
144 Db: DatabaseExt<Self>,
145 >
146 where
147 Self: 'db;
148
149 type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>: Evm<
151 DB = &'db mut dyn DatabaseExt<Self>,
152 Tx = Self::Tx,
153 BlockEnv = Self::BlockEnv,
154 Spec = Self::Spec,
155 HaltReason = Self::HaltReason,
156 > + Deref<Target = Self::FoundryContext<'db>>
157 where
158 Self: 'db;
159
160 fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
162 &self,
163 db: &'db mut dyn DatabaseExt<Self>,
164 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
165 inspector: I,
166 ) -> Self::FoundryEvm<'db, I>;
167
168 fn create_foundry_nested_evm<'db>(
175 &self,
176 db: &'db mut dyn DatabaseExt<Self>,
177 evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
178 inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
179 ) -> Box<dyn NestedEvm<Spec = Self::Spec, Block = Self::BlockEnv, Tx = Self::Tx> + 'db>;
180}
181
182pub trait NestedEvm {
187 type Spec;
189 type Block;
191 type Tx;
193
194 fn journal_inner_mut(&mut self) -> &mut JournaledState;
196
197 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>>;
199
200 fn transact_raw(
202 &mut self,
203 tx: Self::Tx,
204 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>>;
205
206 fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block>;
207}
208
209pub type NestedEvmClosure<'a, Spec, Block, Tx> =
211 &'a mut dyn FnMut(
212 &mut dyn NestedEvm<Spec = Spec, Block = Block, Tx = Tx>,
213 ) -> Result<(), EVMError<DatabaseError>>;
214
215pub fn with_cloned_context<CTX: FoundryContextExt>(
220 ecx: &mut CTX,
221 f: impl FnOnce(
222 &mut CTX::Db,
223 EvmEnv<CTX::Spec, CTX::Block>,
224 JournaledState,
225 )
226 -> Result<(EvmEnv<CTX::Spec, CTX::Block>, JournaledState), EVMError<DatabaseError>>,
227) -> Result<(), EVMError<DatabaseError>> {
228 let evm_env = ecx.evm_clone();
229
230 let (db, journal_inner) = ecx.db_journal_inner_mut();
231 let journal_inner_clone = journal_inner.clone();
232
233 let (sub_evm_env, sub_inner) = f(db, evm_env, journal_inner_clone)?;
234
235 ecx.set_journal_inner(sub_inner);
237 ecx.set_evm(sub_evm_env);
238
239 Ok(())
240}
241
242pub fn get_create2_factory_call_inputs<T: JournalTr>(
244 salt: U256,
245 inputs: &CreateInputs,
246 deployer: Address,
247 journal: &mut T,
248) -> Result<CallInputs, <T::Database as Database>::Error> {
249 let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code()[..]].concat();
250 let account = journal.load_account_with_code(deployer)?;
251 Ok(CallInputs {
252 caller: inputs.caller(),
253 bytecode_address: deployer,
254 known_bytecode: (account.info.code_hash, account.info.code.clone().unwrap_or_default()),
255 target_address: deployer,
256 scheme: CallScheme::Call,
257 value: CallValue::Transfer(inputs.value()),
258 input: CallInput::Bytes(calldata.into()),
259 gas_limit: inputs.gas_limit(),
260 reservoir: inputs.reservoir(),
261 is_static: false,
262 return_memory_offset: 0..0,
263 })
264}
265
266pub trait IntoInstructionResult {
268 fn into_instruction_result(self) -> InstructionResult;
269}
270
271impl IntoInstructionResult for HaltReason {
272 fn into_instruction_result(self) -> InstructionResult {
273 self.into()
274 }
275}
276
277impl IntoInstructionResult for OpHaltReason {
278 fn into_instruction_result(self) -> InstructionResult {
279 match self {
280 Self::Base(eth) => eth.into(),
281 Self::FailedDeposit => InstructionResult::Stop,
282 }
283 }
284}
285
286impl IntoInstructionResult for TempoHaltReason {
287 fn into_instruction_result(self) -> InstructionResult {
288 match self {
289 Self::Ethereum(eth) => eth.into(),
290 _ => InstructionResult::PrecompileError,
291 }
292 }
293}