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_primitives::{Address, B256, U256};
19use foundry_evm_core::{
20 FoundryTransaction,
21 backend::{DatabaseExt, LocalForkId},
22 env::FoundryContextExt,
23 evm::{FoundryContextFor, FoundryEvmNetwork, SpecFor},
24 fork::CreateFork,
25};
26use revm::{
27 context::{Block, Cfg, ContextTr, JournalTr, Transaction},
28 interpreter::Gas,
29};
30
31pub use Vm::ForgeContext;
32pub use config::CheatsConfig;
33pub use error::{Error, ErrorKind, Result};
34pub use foundry_evm_core::evm::NestedEvmClosureFor;
35pub use inspector::{
36 BroadcastableTransaction, BroadcastableTransactions, Cheatcodes, CheatcodesExecutor,
37};
38pub use spec::{CheatcodeDef, Vm};
39
40#[macro_use]
41mod error;
42
43mod base64;
44
45mod config;
46
47mod crypto;
48
49mod version;
50
51mod env;
52pub use env::{current_execution_context, set_execution_context};
53
54mod evm;
55
56mod expected_emit;
57
58mod external_storage;
59
60mod fs;
61
62mod inspector;
63pub use inspector::CheatcodeAnalysis;
64
65mod json;
66
67#[cfg(feature = "monad")]
68mod monad;
69
70mod script;
71pub use script::{Wallets, WalletsInner};
72
73mod state;
74pub use state::CheatcodesCore;
75
76mod string;
77
78mod tempo;
79
80mod test;
81pub use test::{
82 expect::ExpectedCallTracker,
83 revert_handlers::{DUMMY_CALL_OUTPUT, DUMMY_CREATE_ADDRESS},
84};
85
86mod toml;
87
88mod utils;
89
90pub(crate) trait Cheatcode: CheatcodeDef {
92 fn apply_context(&self, _state: &mut CheatcodesCore) -> Result {
96 self.apply_context_free()
97 }
98
99 #[inline(always)]
103 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
104 self.apply_context(&mut ccx.state.core)
105 }
106
107 #[inline(always)]
111 fn apply_full<FEN: FoundryEvmNetwork>(
112 &self,
113 ccx: &mut CheatsCtxt<'_, '_, FEN>,
114 executor: &mut dyn CheatcodesExecutor<FEN>,
115 ) -> Result {
116 let _ = executor;
117 self.apply_stateful(ccx)
118 }
119
120 fn apply_context_free(&self) -> Result {
124 unimplemented!("{}", Self::CHEATCODE.func.id)
125 }
126}
127
128pub struct CheatsCtxt<'a, 'db, FEN: FoundryEvmNetwork> {
130 pub(crate) state: &'a mut Cheatcodes<FEN>,
132 pub(crate) ecx: &'a mut FoundryContextFor<'db, FEN>,
134 pub(crate) caller: Address,
136 pub(crate) gas: &'a mut Gas,
138 pub(crate) is_static: bool,
140}
141
142impl<FEN: FoundryEvmNetwork> CheatsCtxt<'_, '_, FEN> {
143 pub(crate) fn ensure_not_precompile(&self, address: &Address) -> Result<()> {
144 if self.is_precompile(address) { Err(precompile_error(address)) } else { Ok(()) }
145 }
146
147 pub(crate) fn is_precompile(&self, address: &Address) -> bool {
148 self.ecx.journal().precompile_addresses().contains(address)
149 }
150
151 #[inline]
153 pub(crate) fn depth(&self) -> usize {
154 self.ecx.journal().depth()
155 }
156
157 #[inline]
159 pub(crate) fn spec(&self) -> SpecFor<FEN> {
160 self.ecx.cfg().spec()
161 }
162
163 #[inline]
165 pub(crate) fn chain_id(&self) -> u64 {
166 self.ecx.cfg().chain_id()
167 }
168
169 #[inline]
171 pub(crate) fn max_initcode_size(&self) -> usize {
172 self.ecx.cfg().max_initcode_size()
173 }
174
175 #[inline]
177 pub(crate) fn limit_contract_code_size(&self) -> Option<usize> {
178 self.ecx.cfg_env().limit_contract_code_size
179 }
180
181 #[inline]
183 pub(crate) fn block_number(&self) -> U256 {
184 self.ecx.block().number()
185 }
186
187 #[inline]
189 pub(crate) fn timestamp(&self) -> U256 {
190 self.ecx.block().timestamp()
191 }
192
193 #[inline]
195 pub(crate) fn basefee(&self) -> u64 {
196 self.ecx.block().basefee()
197 }
198
199 #[inline]
201 pub(crate) fn slot_num(&self) -> u64 {
202 self.ecx.block().slot_num()
203 }
204
205 #[inline]
207 pub(crate) fn blob_gasprice(&self) -> Option<u128> {
208 self.ecx.block().blob_gasprice()
209 }
210
211 #[inline]
213 pub(crate) fn tx_caller(&self) -> Address {
214 self.ecx.tx().caller()
215 }
216
217 #[inline]
219 pub(crate) fn tx_gas_price(&self) -> u128 {
220 self.ecx.tx().gas_price()
221 }
222
223 #[inline]
225 pub(crate) fn tx_type(&self) -> u8 {
226 self.ecx.tx().tx_type()
227 }
228
229 #[inline]
231 pub(crate) fn tx_blob_hashes(&self) -> &[B256] {
232 self.ecx.tx().blob_versioned_hashes()
233 }
234
235 #[inline]
237 pub(crate) fn tx_fee_token(&self) -> Option<Address> {
238 self.ecx.tx().fee_token()
239 }
240
241 #[inline]
243 pub(crate) fn active_fork_id(&self) -> Option<LocalForkId> {
244 self.ecx.db().active_fork_id()
245 }
246
247 #[inline]
249 pub(crate) fn active_fork_url(&self) -> Option<String> {
250 self.ecx.db().active_fork_url()
251 }
252
253 #[inline]
255 pub(crate) fn active_fork_block_number(&self) -> Option<u64> {
256 self.ecx.db().active_fork_block_number()
257 }
258
259 #[inline]
261 pub(crate) fn active_fork_options(&self) -> Option<CreateFork> {
262 self.ecx.db().active_fork_options()
263 }
264
265 #[inline]
267 pub(crate) fn is_forked_mode(&self) -> bool {
268 self.ecx.db().is_forked_mode()
269 }
270
271 #[inline]
273 pub(crate) fn is_persistent(&self, account: &Address) -> bool {
274 self.ecx.db().is_persistent(account)
275 }
276}
277
278#[cold]
279fn precompile_error(address: &Address) -> Error {
280 fmt_err!("cannot use precompile {address} as an argument")
281}