Skip to content

Commit 7e46e17

Browse files
authored
refactor(cheatcodes): extract fork env helper to reduce duplication (foundry-rs#13848)
Extract `fork_env_op` helper that handles the common pattern shared by all fork-switching cheatcodes: clone EVM/tx env → run db operation → write env back. Deduplicates 7 call sites (rollFork × 4, selectFork, createSelectFork × 2).
1 parent 8f17236 commit 7e46e17

1 file changed

Lines changed: 47 additions & 52 deletions

File tree

crates/cheatcodes/src/evm/fork.rs

Lines changed: 47 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ use alloy_provider::Provider;
1010
use alloy_rpc_types::Filter;
1111
use alloy_sol_types::SolValue;
1212
use foundry_common::provider::ProviderBuilder;
13-
use foundry_evm_core::{backend::FoundryJournalExt, fork::CreateFork};
14-
use revm::context::ContextTr;
13+
use foundry_evm_core::{
14+
backend::{FoundryJournalExt, JournaledState},
15+
fork::CreateFork,
16+
};
17+
use revm::context::{ContextTr, TxEnv};
1518

1619
impl Cheatcode for activeForkCall {
1720
fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(
@@ -73,55 +76,39 @@ impl Cheatcode for rollFork_0Call {
7376
fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {
7477
let Self { blockNumber } = self;
7578
persist_caller(ccx);
76-
let mut evm_env = ccx.ecx.evm_clone();
77-
let mut tx_env = ccx.ecx.tx_clone();
78-
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
79-
db.roll_fork(None, (*blockNumber).to(), &mut evm_env, &mut tx_env, inner)?;
80-
ccx.ecx.set_evm(evm_env);
81-
ccx.ecx.set_tx(tx_env);
82-
Ok(Default::default())
79+
fork_env_op(ccx, |db, evm_env, tx_env, inner| {
80+
db.roll_fork(None, (*blockNumber).to(), evm_env, tx_env, inner)
81+
})
8382
}
8483
}
8584

8685
impl Cheatcode for rollFork_1Call {
8786
fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {
8887
let Self { txHash } = self;
8988
persist_caller(ccx);
90-
let mut evm_env = ccx.ecx.evm_clone();
91-
let mut tx_env = ccx.ecx.tx_clone();
92-
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
93-
db.roll_fork_to_transaction(None, *txHash, &mut evm_env, &mut tx_env, inner)?;
94-
ccx.ecx.set_evm(evm_env);
95-
ccx.ecx.set_tx(tx_env);
96-
Ok(Default::default())
89+
fork_env_op(ccx, |db, evm_env, tx_env, inner| {
90+
db.roll_fork_to_transaction(None, *txHash, evm_env, tx_env, inner)
91+
})
9792
}
9893
}
9994

10095
impl Cheatcode for rollFork_2Call {
10196
fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {
10297
let Self { forkId, blockNumber } = self;
10398
persist_caller(ccx);
104-
let mut evm_env = ccx.ecx.evm_clone();
105-
let mut tx_env = ccx.ecx.tx_clone();
106-
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
107-
db.roll_fork(Some(*forkId), (*blockNumber).to(), &mut evm_env, &mut tx_env, inner)?;
108-
ccx.ecx.set_evm(evm_env);
109-
ccx.ecx.set_tx(tx_env);
110-
Ok(Default::default())
99+
fork_env_op(ccx, |db, evm_env, tx_env, inner| {
100+
db.roll_fork(Some(*forkId), (*blockNumber).to(), evm_env, tx_env, inner)
101+
})
111102
}
112103
}
113104

114105
impl Cheatcode for rollFork_3Call {
115106
fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {
116107
let Self { forkId, txHash } = self;
117108
persist_caller(ccx);
118-
let mut evm_env = ccx.ecx.evm_clone();
119-
let mut tx_env = ccx.ecx.tx_clone();
120-
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
121-
db.roll_fork_to_transaction(Some(*forkId), *txHash, &mut evm_env, &mut tx_env, inner)?;
122-
ccx.ecx.set_evm(evm_env);
123-
ccx.ecx.set_tx(tx_env);
124-
Ok(Default::default())
109+
fork_env_op(ccx, |db, evm_env, tx_env, inner| {
110+
db.roll_fork_to_transaction(Some(*forkId), *txHash, evm_env, tx_env, inner)
111+
})
125112
}
126113
}
127114

@@ -130,13 +117,9 @@ impl Cheatcode for selectForkCall {
130117
let Self { forkId } = self;
131118
persist_caller(ccx);
132119
check_broadcast(ccx.state)?;
133-
let mut evm_env = ccx.ecx.evm_clone();
134-
let mut tx_env = ccx.ecx.tx_clone();
135-
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
136-
db.select_fork(*forkId, &mut evm_env, &mut tx_env, inner)?;
137-
ccx.ecx.set_evm(evm_env);
138-
ccx.ecx.set_tx(tx_env);
139-
Ok(Default::default())
120+
fork_env_op(ccx, |db, evm_env, tx_env, inner| {
121+
db.select_fork(*forkId, evm_env, tx_env, inner)
122+
})
140123
}
141124
}
142125

@@ -355,13 +338,9 @@ fn create_select_fork<CTX: EthCheatCtx>(
355338
check_broadcast(ccx.state)?;
356339

357340
let fork = create_fork_request(ccx, url_or_alias, block)?;
358-
let mut evm_env = ccx.ecx.evm_clone();
359-
let mut tx_env = ccx.ecx.tx_clone();
360-
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
361-
let id = db.create_select_fork(fork, &mut evm_env, &mut tx_env, inner)?;
362-
ccx.ecx.set_evm(evm_env);
363-
ccx.ecx.set_tx(tx_env);
364-
Ok(id.abi_encode())
341+
fork_env_op(ccx, |db, evm_env, tx_env, inner| {
342+
db.create_select_fork(fork, evm_env, tx_env, inner)
343+
})
365344
}
366345

367346
/// Creates a new fork
@@ -384,14 +363,9 @@ fn create_select_fork_at_transaction<CTX: EthCheatCtx>(
384363
check_broadcast(ccx.state)?;
385364

386365
let fork = create_fork_request(ccx, url_or_alias, None)?;
387-
let mut evm_env = ccx.ecx.evm_clone();
388-
let mut tx_env = ccx.ecx.tx_clone();
389-
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
390-
let id =
391-
db.create_select_fork_at_transaction(fork, &mut evm_env, &mut tx_env, inner, *transaction)?;
392-
ccx.ecx.set_evm(evm_env);
393-
ccx.ecx.set_tx(tx_env);
394-
Ok(id.abi_encode())
366+
fork_env_op(ccx, |db, evm_env, tx_env, inner| {
367+
db.create_select_fork_at_transaction(fork, evm_env, tx_env, inner, *transaction)
368+
})
395369
}
396370

397371
/// Creates a new fork at the given transaction
@@ -435,6 +409,27 @@ fn create_fork_request<CTX: EthCheatCtx>(
435409
Ok(fork)
436410
}
437411

412+
/// Clones the EVM and tx environments, runs a fork operation that may modify them, then writes
413+
/// them back. This is the common pattern for all fork-switching cheatcodes (rollFork, selectFork,
414+
/// createSelectFork).
415+
fn fork_env_op<CTX: EthCheatCtx, T: SolValue>(
416+
ccx: &mut CheatsCtxt<'_, CTX>,
417+
f: impl FnOnce(
418+
&mut dyn DatabaseExt,
419+
&mut EvmEnv,
420+
&mut TxEnv,
421+
&mut JournaledState,
422+
) -> eyre::Result<T>,
423+
) -> Result {
424+
let mut evm_env = ccx.ecx.evm_clone();
425+
let mut tx_env = ccx.ecx.tx_clone();
426+
let (db, inner) = ccx.ecx.journal_mut().as_db_and_inner();
427+
let result = f(db, &mut evm_env, &mut tx_env, inner)?;
428+
ccx.ecx.set_evm(evm_env);
429+
ccx.ecx.set_tx(tx_env);
430+
Ok(result.abi_encode())
431+
}
432+
438433
fn check_broadcast(state: &Cheatcodes) -> Result<()> {
439434
if state.broadcast.is_none() {
440435
Ok(())

0 commit comments

Comments
 (0)