Skip to main content

foundry_cheatcodes/
lib.rs

1//! # foundry-cheatcodes
2//!
3//! Foundry cheatcodes implementations.
4
5#![cfg_attr(not(test), warn(unused_crate_dependencies))]
6#![cfg_attr(docsrs, feature(doc_cfg))]
7#![allow(elided_lifetimes_in_paths)] // Cheats context uses 3 lifetimes
8
9#[macro_use]
10extern crate foundry_common;
11
12#[macro_use]
13pub extern crate foundry_cheatcodes_spec as spec;
14
15#[macro_use]
16extern crate tracing;
17
18use alloy_primitives::Address;
19use foundry_evm_core::{
20    backend::DatabaseExt,
21    evm::{FoundryContextFor, FoundryEvmNetwork},
22};
23use revm::context::{ContextTr, JournalTr};
24
25pub use Vm::ForgeContext;
26pub use config::CheatsConfig;
27pub use error::{Error, ErrorKind, Result};
28pub use foundry_evm_core::evm::NestedEvmClosureFor;
29pub use inspector::{
30    BroadcastableTransaction, BroadcastableTransactions, Cheatcodes, CheatcodesExecutor,
31};
32pub use spec::{CheatcodeDef, Vm};
33
34#[macro_use]
35mod error;
36
37mod base64;
38
39mod config;
40
41mod crypto;
42
43mod version;
44
45mod env;
46pub use env::{current_execution_context, set_execution_context};
47
48mod evm;
49
50mod external_storage;
51
52mod fs;
53
54mod inspector;
55pub use inspector::CheatcodeAnalysis;
56
57mod json;
58
59#[cfg(feature = "monad")]
60mod monad;
61
62mod script;
63pub use script::{Wallets, WalletsInner};
64
65mod string;
66
67mod tempo;
68
69mod test;
70pub use test::expect::ExpectedCallTracker;
71
72mod toml;
73
74mod utils;
75
76/// Cheatcode implementation.
77pub(crate) trait Cheatcode: CheatcodeDef {
78    /// Applies this cheatcode to the given state.
79    ///
80    /// Implement this function if you don't need access to the EVM data.
81    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
82        let _ = state;
83        unimplemented!("{}", Self::CHEATCODE.func.id)
84    }
85
86    /// Applies this cheatcode to the given context.
87    ///
88    /// Implement this function if you need access to the EVM data.
89    #[inline(always)]
90    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
91        self.apply(ccx.state)
92    }
93
94    /// Applies this cheatcode to the given context and executor.
95    ///
96    /// Implement this function if you need access to the executor.
97    #[inline(always)]
98    fn apply_full<FEN: FoundryEvmNetwork>(
99        &self,
100        ccx: &mut CheatsCtxt<'_, '_, FEN>,
101        executor: &mut dyn CheatcodesExecutor<FEN>,
102    ) -> Result {
103        let _ = executor;
104        self.apply_stateful(ccx)
105    }
106}
107
108/// The cheatcode context.
109pub struct CheatsCtxt<'a, 'db, FEN: FoundryEvmNetwork + 'db> {
110    /// The cheatcodes inspector state.
111    pub(crate) state: &'a mut Cheatcodes<FEN>,
112    /// The EVM context.
113    pub(crate) ecx: &'a mut FoundryContextFor<'db, FEN>,
114    /// The original `msg.sender`.
115    pub(crate) caller: Address,
116    /// Gas limit of the current cheatcode call.
117    pub(crate) gas_limit: u64,
118}
119
120impl<'a, 'db, FEN: FoundryEvmNetwork> std::ops::Deref for CheatsCtxt<'a, 'db, FEN> {
121    type Target = FoundryContextFor<'db, FEN>;
122
123    #[inline(always)]
124    fn deref(&self) -> &Self::Target {
125        self.ecx
126    }
127}
128
129impl<'db, FEN: FoundryEvmNetwork> std::ops::DerefMut for CheatsCtxt<'_, 'db, FEN> {
130    #[inline(always)]
131    fn deref_mut(&mut self) -> &mut Self::Target {
132        self.ecx
133    }
134}
135
136impl<FEN: FoundryEvmNetwork> CheatsCtxt<'_, '_, FEN> {
137    pub(crate) fn ensure_not_precompile(&self, address: &Address) -> Result<()> {
138        if self.is_precompile(address) { Err(precompile_error(address)) } else { Ok(()) }
139    }
140
141    pub(crate) fn is_precompile(&self, address: &Address) -> bool {
142        self.ecx.journal().precompile_addresses().contains(address)
143    }
144}
145
146#[cold]
147fn precompile_error(address: &Address) -> Error {
148    fmt_err!("cannot use precompile {address} as an argument")
149}