foundry_cheatcodes/
lib.rs1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
6#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_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;
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
65pub(crate) trait Cheatcode: CheatcodeDef + DynCheatcode {
67 fn apply(&self, state: &mut Cheatcodes) -> Result {
71 let _ = state;
72 unimplemented!("{}", Self::CHEATCODE.func.id)
73 }
74
75 #[inline(always)]
79 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
80 self.apply(ccx.state)
81 }
82
83 #[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 + std::fmt::Debug {
94 fn cheatcode(&self) -> &'static spec::Cheatcode<'static>;
95
96 fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result;
97}
98
99impl<T: Cheatcode> DynCheatcode for T {
100 fn cheatcode(&self) -> &'static spec::Cheatcode<'static> {
101 Self::CHEATCODE
102 }
103
104 fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result {
105 self.apply_full(ccx, executor)
106 }
107}
108
109impl dyn DynCheatcode {
110 pub(crate) fn name(&self) -> &'static str {
111 self.cheatcode().func.signature.split('(').next().unwrap()
112 }
113
114 pub(crate) fn id(&self) -> &'static str {
115 self.cheatcode().func.id
116 }
117
118 pub(crate) fn signature(&self) -> &'static str {
119 self.cheatcode().func.signature
120 }
121
122 pub(crate) fn status(&self) -> &Status<'static> {
123 &self.cheatcode().status
124 }
125}
126
127pub struct CheatsCtxt<'cheats, 'evm, 'db, 'db2> {
129 pub(crate) state: &'cheats mut Cheatcodes,
131 pub(crate) ecx: &'evm mut EthEvmContext<&'db mut (dyn DatabaseExt + 'db2)>,
133 pub(crate) caller: Address,
135 pub(crate) gas_limit: u64,
137}
138
139impl<'db, 'db2> std::ops::Deref for CheatsCtxt<'_, '_, 'db, 'db2> {
140 type Target = EthEvmContext<&'db mut (dyn DatabaseExt + 'db2)>;
141
142 #[inline(always)]
143 fn deref(&self) -> &Self::Target {
144 self.ecx
145 }
146}
147
148impl std::ops::DerefMut for CheatsCtxt<'_, '_, '_, '_> {
149 #[inline(always)]
150 fn deref_mut(&mut self) -> &mut Self::Target {
151 &mut *self.ecx
152 }
153}
154
155impl CheatsCtxt<'_, '_, '_, '_> {
156 pub(crate) fn ensure_not_precompile(&self, address: &Address) -> Result<()> {
157 if self.is_precompile(address) { Err(precompile_error(address)) } else { Ok(()) }
158 }
159
160 pub(crate) fn is_precompile(&self, address: &Address) -> bool {
161 self.ecx.journaled_state.warm_addresses.precompiles().contains(address)
162 }
163}
164
165#[cold]
166fn precompile_error(address: &Address) -> Error {
167 fmt_err!("cannot use precompile {address} as an argument")
168}