foundry_cheatcodes/
lib.rs1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
6#![cfg_attr(docsrs, feature(doc_cfg))]
7#![allow(elided_lifetimes_in_paths)] #[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};
26pub use inspector::{
27 BroadcastableTransaction, BroadcastableTransactions, Cheatcodes, CheatcodesExecutor,
28};
29pub use spec::{CheatcodeDef, Vm};
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;
50pub use inspector::CheatcodeAnalysis;
51
52mod json;
53
54mod script;
55pub use script::{Wallets, WalletsInner};
56
57mod string;
58
59mod test;
60pub use test::expect::ExpectedCallTracker;
61
62mod toml;
63
64mod utils;
65
66pub(crate) trait Cheatcode: CheatcodeDef + DynCheatcode {
68 fn apply(&self, state: &mut Cheatcodes) -> Result {
72 let _ = state;
73 unimplemented!("{}", Self::CHEATCODE.func.id)
74 }
75
76 #[inline(always)]
80 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
81 self.apply(ccx.state)
82 }
83
84 #[inline(always)]
88 fn apply_full(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result {
89 let _ = executor;
90 self.apply_stateful(ccx)
91 }
92}
93
94pub(crate) trait DynCheatcode: 'static + std::fmt::Debug {
95 fn cheatcode(&self) -> &'static spec::Cheatcode<'static>;
96
97 fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result;
98}
99
100impl<T: Cheatcode> DynCheatcode for T {
101 fn cheatcode(&self) -> &'static spec::Cheatcode<'static> {
102 Self::CHEATCODE
103 }
104
105 fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result {
106 self.apply_full(ccx, executor)
107 }
108}
109
110impl dyn DynCheatcode {
111 pub(crate) fn name(&self) -> &'static str {
112 self.cheatcode().func.signature.split('(').next().unwrap()
113 }
114
115 pub(crate) fn id(&self) -> &'static str {
116 self.cheatcode().func.id
117 }
118
119 pub(crate) fn signature(&self) -> &'static str {
120 self.cheatcode().func.signature
121 }
122
123 pub(crate) fn status(&self) -> &Status<'static> {
124 &self.cheatcode().status
125 }
126}
127
128pub struct CheatsCtxt<'cheats, 'evm, 'db, 'db2> {
130 pub(crate) state: &'cheats mut Cheatcodes,
132 pub(crate) ecx: &'evm mut EthEvmContext<&'db mut (dyn DatabaseExt + 'db2)>,
134 pub(crate) caller: Address,
136 pub(crate) gas_limit: u64,
138}
139
140impl<'db, 'db2> std::ops::Deref for CheatsCtxt<'_, '_, 'db, 'db2> {
141 type Target = EthEvmContext<&'db mut (dyn DatabaseExt + 'db2)>;
142
143 #[inline(always)]
144 fn deref(&self) -> &Self::Target {
145 self.ecx
146 }
147}
148
149impl std::ops::DerefMut for CheatsCtxt<'_, '_, '_, '_> {
150 #[inline(always)]
151 fn deref_mut(&mut self) -> &mut Self::Target {
152 &mut *self.ecx
153 }
154}
155
156impl CheatsCtxt<'_, '_, '_, '_> {
157 pub(crate) fn ensure_not_precompile(&self, address: &Address) -> Result<()> {
158 if self.is_precompile(address) { Err(precompile_error(address)) } else { Ok(()) }
159 }
160
161 pub(crate) fn is_precompile(&self, address: &Address) -> bool {
162 self.ecx.journaled_state.warm_addresses.precompiles().contains(address)
163 }
164}
165
166#[cold]
167fn precompile_error(address: &Address) -> Error {
168 fmt_err!("cannot use precompile {address} as an argument")
169}