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