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