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, doc_auto_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::{ContextPrecompiles, InnerEvmContext};
21use spec::Status;
22
23pub use config::CheatsConfig;
24pub use error::{Error, ErrorKind, Result};
25pub use inspector::{
26    BroadcastableTransaction, BroadcastableTransactions, Cheatcodes, CheatcodesExecutor, Context,
27};
28pub use spec::{CheatcodeDef, Vm};
29pub use Vm::ForgeContext;
30
31#[macro_use]
32mod error;
33
34mod base64;
35
36mod config;
37
38mod crypto;
39
40mod version;
41
42mod env;
43pub use env::set_execution_context;
44
45mod evm;
46
47mod fs;
48
49mod inspector;
50
51mod json;
52
53mod script;
54pub use script::{Wallets, WalletsInner};
55
56mod string;
57
58mod test;
59pub use test::expect::ExpectedCallTracker;
60
61mod toml;
62
63mod utils;
64
65/// Cheatcode implementation.
66pub(crate) trait Cheatcode: CheatcodeDef + DynCheatcode {
67    /// Applies this cheatcode to the given state.
68    ///
69    /// Implement this function if you don't need access to the EVM data.
70    fn apply(&self, state: &mut Cheatcodes) -> Result {
71        let _ = state;
72        unimplemented!("{}", Self::CHEATCODE.func.id)
73    }
74
75    /// Applies this cheatcode to the given context.
76    ///
77    /// Implement this function if you need access to the EVM data.
78    #[inline(always)]
79    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
80        self.apply(ccx.state)
81    }
82
83    /// Applies this cheatcode to the given context and executor.
84    ///
85    /// Implement this function if you need access to the executor.
86    #[inline(always)]
87    fn apply_full(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result {
88        let _ = executor;
89        self.apply_stateful(ccx)
90    }
91}
92
93pub(crate) trait DynCheatcode: 'static {
94    fn cheatcode(&self) -> &'static spec::Cheatcode<'static>;
95
96    fn as_debug(&self) -> &dyn std::fmt::Debug;
97
98    fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result;
99}
100
101impl<T: Cheatcode> DynCheatcode for T {
102    #[inline]
103    fn cheatcode(&self) -> &'static spec::Cheatcode<'static> {
104        Self::CHEATCODE
105    }
106
107    #[inline]
108    fn as_debug(&self) -> &dyn std::fmt::Debug {
109        self
110    }
111
112    #[inline]
113    fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result {
114        self.apply_full(ccx, executor)
115    }
116}
117
118impl dyn DynCheatcode {
119    pub(crate) fn name(&self) -> &'static str {
120        self.cheatcode().func.signature.split('(').next().unwrap()
121    }
122
123    pub(crate) fn id(&self) -> &'static str {
124        self.cheatcode().func.id
125    }
126
127    pub(crate) fn signature(&self) -> &'static str {
128        self.cheatcode().func.signature
129    }
130
131    pub(crate) fn status(&self) -> &Status<'static> {
132        &self.cheatcode().status
133    }
134}
135
136/// The cheatcode context, used in `Cheatcode`.
137pub struct CheatsCtxt<'cheats, 'evm, 'db, 'db2> {
138    /// The cheatcodes inspector state.
139    pub(crate) state: &'cheats mut Cheatcodes,
140    /// The EVM data.
141    pub(crate) ecx: &'evm mut InnerEvmContext<&'db mut (dyn DatabaseExt + 'db2)>,
142    /// The precompiles context.
143    pub(crate) precompiles: &'evm mut ContextPrecompiles<&'db mut (dyn DatabaseExt + 'db2)>,
144    /// The original `msg.sender`.
145    pub(crate) caller: Address,
146    /// Gas limit of the current cheatcode call.
147    pub(crate) gas_limit: u64,
148}
149
150impl<'db, 'db2> std::ops::Deref for CheatsCtxt<'_, '_, 'db, 'db2> {
151    type Target = InnerEvmContext<&'db mut (dyn DatabaseExt + 'db2)>;
152
153    #[inline(always)]
154    fn deref(&self) -> &Self::Target {
155        self.ecx
156    }
157}
158
159impl std::ops::DerefMut for CheatsCtxt<'_, '_, '_, '_> {
160    #[inline(always)]
161    fn deref_mut(&mut self) -> &mut Self::Target {
162        &mut *self.ecx
163    }
164}
165
166impl CheatsCtxt<'_, '_, '_, '_> {
167    #[inline]
168    pub(crate) fn is_precompile(&self, address: &Address) -> bool {
169        self.precompiles.contains(address)
170    }
171}