Skip to main content

foundry_cheatcodes/
utils.rs

1//! Implementations of [`Utilities`](spec::Group::Utilities) cheatcodes.
2
3use crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Result, Vm::*};
4use alloy_dyn_abi::{DynSolType, DynSolValue, Resolver, TypedData, eip712_parser::EncodeType};
5use alloy_ens::namehash;
6use alloy_primitives::{B64, Bytes, I256, U256, aliases::B32, keccak256, map::HashMap};
7use alloy_rlp::{Decodable, Encodable};
8use alloy_sol_types::SolValue;
9use foundry_common::{TYPE_BINDING_PREFIX, fs};
10use foundry_config::fs_permissions::FsAccessKind;
11use foundry_evm_core::constants::DEFAULT_CREATE2_DEPLOYER;
12use foundry_evm_fuzz::strategies::BoundMutator;
13use proptest::prelude::Strategy;
14use rand::{Rng, RngCore, seq::SliceRandom};
15use revm::{
16    context::{ContextTr, JournalTr},
17    inspector::JournalExt,
18};
19use std::path::PathBuf;
20
21/// Contains locations of traces ignored via cheatcodes.
22///
23/// The way we identify location in traces is by (node_idx, item_idx) tuple where node_idx is an
24/// index of a call trace node, and item_idx is a value between 0 and `node.ordering.len()` where i
25/// represents point after ith item, and 0 represents the beginning of the node trace.
26#[derive(Debug, Default, Clone)]
27pub struct IgnoredTraces {
28    /// Mapping from (start_node_idx, start_item_idx) to (end_node_idx, end_item_idx) representing
29    /// ranges of trace nodes to ignore.
30    pub ignored: HashMap<(usize, usize), (usize, usize)>,
31    /// Keeps track of (start_node_idx, start_item_idx) of the last `vm.pauseTracing` call.
32    pub last_pause_call: Option<(usize, usize)>,
33}
34
35impl Cheatcode for labelCall {
36    fn apply(&self, state: &mut Cheatcodes) -> Result {
37        let Self { account, newLabel } = self;
38        state.labels.insert(*account, newLabel.clone());
39        Ok(Default::default())
40    }
41}
42
43impl Cheatcode for getLabelCall {
44    fn apply(&self, state: &mut Cheatcodes) -> Result {
45        let Self { account } = self;
46        Ok(match state.labels.get(account) {
47            Some(label) => label.abi_encode(),
48            None => format!("unlabeled:{account}").abi_encode(),
49        })
50    }
51}
52
53impl Cheatcode for computeCreateAddressCall {
54    fn apply(&self, _state: &mut Cheatcodes) -> Result {
55        let Self { nonce, deployer } = self;
56        ensure!(*nonce <= U256::from(u64::MAX), "nonce must be less than 2^64");
57        Ok(deployer.create(nonce.to()).abi_encode())
58    }
59}
60
61impl Cheatcode for computeCreate2Address_0Call {
62    fn apply(&self, _state: &mut Cheatcodes) -> Result {
63        let Self { salt, initCodeHash, deployer } = self;
64        Ok(deployer.create2(salt, initCodeHash).abi_encode())
65    }
66}
67
68impl Cheatcode for computeCreate2Address_1Call {
69    fn apply(&self, _state: &mut Cheatcodes) -> Result {
70        let Self { salt, initCodeHash } = self;
71        Ok(DEFAULT_CREATE2_DEPLOYER.create2(salt, initCodeHash).abi_encode())
72    }
73}
74
75impl Cheatcode for ensNamehashCall {
76    fn apply(&self, _state: &mut Cheatcodes) -> Result {
77        let Self { name } = self;
78        Ok(namehash(name).abi_encode())
79    }
80}
81
82impl Cheatcode for bound_0Call {
83    fn apply(&self, state: &mut Cheatcodes) -> Result {
84        let Self { current, min, max } = *self;
85        let Some(mutated) = U256::bound(current, min, max, state.test_runner()) else {
86            bail!("cannot bound {current} in [{min}, {max}] range")
87        };
88        Ok(mutated.abi_encode())
89    }
90}
91
92impl Cheatcode for bound_1Call {
93    fn apply(&self, state: &mut Cheatcodes) -> Result {
94        let Self { current, min, max } = *self;
95        let Some(mutated) = I256::bound(current, min, max, state.test_runner()) else {
96            bail!("cannot bound {current} in [{min}, {max}] range")
97        };
98        Ok(mutated.abi_encode())
99    }
100}
101
102impl Cheatcode for randomUint_0Call {
103    fn apply(&self, state: &mut Cheatcodes) -> Result {
104        random_uint(state, None, None)
105    }
106}
107
108impl Cheatcode for randomUint_1Call {
109    fn apply(&self, state: &mut Cheatcodes) -> Result {
110        let Self { min, max } = *self;
111        random_uint(state, None, Some((min, max)))
112    }
113}
114
115impl Cheatcode for randomUint_2Call {
116    fn apply(&self, state: &mut Cheatcodes) -> Result {
117        let Self { bits } = *self;
118        random_uint(state, Some(bits), None)
119    }
120}
121
122impl Cheatcode for randomAddressCall {
123    fn apply(&self, state: &mut Cheatcodes) -> Result {
124        Ok(DynSolValue::type_strategy(&DynSolType::Address)
125            .new_tree(state.test_runner())
126            .unwrap()
127            .current()
128            .abi_encode())
129    }
130}
131
132impl Cheatcode for randomInt_0Call {
133    fn apply(&self, state: &mut Cheatcodes) -> Result {
134        random_int(state, None)
135    }
136}
137
138impl Cheatcode for randomInt_1Call {
139    fn apply(&self, state: &mut Cheatcodes) -> Result {
140        let Self { bits } = *self;
141        random_int(state, Some(bits))
142    }
143}
144
145impl Cheatcode for randomBoolCall {
146    fn apply(&self, state: &mut Cheatcodes) -> Result {
147        let rand_bool: bool = state.rng().random();
148        Ok(rand_bool.abi_encode())
149    }
150}
151
152impl Cheatcode for randomBytesCall {
153    fn apply(&self, state: &mut Cheatcodes) -> Result {
154        let Self { len } = *self;
155        ensure!(
156            len <= U256::from(usize::MAX),
157            format!("bytes length cannot exceed {}", usize::MAX)
158        );
159        let mut bytes = vec![0u8; len.to::<usize>()];
160        state.rng().fill_bytes(&mut bytes);
161        Ok(bytes.abi_encode())
162    }
163}
164
165impl Cheatcode for randomBytes4Call {
166    fn apply(&self, state: &mut Cheatcodes) -> Result {
167        let rand_u32 = state.rng().next_u32();
168        Ok(B32::from(rand_u32).abi_encode())
169    }
170}
171
172impl Cheatcode for randomBytes8Call {
173    fn apply(&self, state: &mut Cheatcodes) -> Result {
174        let rand_u64 = state.rng().next_u64();
175        Ok(B64::from(rand_u64).abi_encode())
176    }
177}
178
179impl Cheatcode for pauseTracingCall {
180    fn apply_full(
181        &self,
182        ccx: &mut crate::CheatsCtxt,
183        executor: &mut dyn CheatcodesExecutor,
184    ) -> Result {
185        let Some(tracer) = executor.tracing_inspector() else {
186            // No tracer -> nothing to pause
187            return Ok(Default::default());
188        };
189
190        // If paused earlier, ignore the call
191        if ccx.state.ignored_traces.last_pause_call.is_some() {
192            return Ok(Default::default());
193        }
194
195        let cur_node = &tracer.traces().nodes().last().expect("no trace nodes");
196        ccx.state.ignored_traces.last_pause_call = Some((cur_node.idx, cur_node.ordering.len()));
197
198        Ok(Default::default())
199    }
200}
201
202impl Cheatcode for resumeTracingCall {
203    fn apply_full(
204        &self,
205        ccx: &mut crate::CheatsCtxt,
206        executor: &mut dyn CheatcodesExecutor,
207    ) -> Result {
208        let Some(tracer) = executor.tracing_inspector() else {
209            // No tracer -> nothing to unpause
210            return Ok(Default::default());
211        };
212
213        let Some(start) = ccx.state.ignored_traces.last_pause_call.take() else {
214            // Nothing to unpause
215            return Ok(Default::default());
216        };
217
218        let node = &tracer.traces().nodes().last().expect("no trace nodes");
219        ccx.state.ignored_traces.ignored.insert(start, (node.idx, node.ordering.len()));
220
221        Ok(Default::default())
222    }
223}
224
225impl Cheatcode for interceptInitcodeCall {
226    fn apply(&self, state: &mut Cheatcodes) -> Result {
227        let Self {} = self;
228        if !state.intercept_next_create_call {
229            state.intercept_next_create_call = true;
230        } else {
231            bail!("vm.interceptInitcode() has already been called")
232        }
233        Ok(Default::default())
234    }
235}
236
237impl Cheatcode for setArbitraryStorage_0Call {
238    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
239        let Self { target } = self;
240        ccx.state.arbitrary_storage().mark_arbitrary(target, false);
241
242        Ok(Default::default())
243    }
244}
245
246impl Cheatcode for setArbitraryStorage_1Call {
247    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
248        let Self { target, overwrite } = self;
249        ccx.state.arbitrary_storage().mark_arbitrary(target, *overwrite);
250
251        Ok(Default::default())
252    }
253}
254
255impl Cheatcode for copyStorageCall {
256    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
257        let Self { from, to } = self;
258
259        ensure!(
260            !ccx.state.has_arbitrary_storage(to),
261            "target address cannot have arbitrary storage"
262        );
263
264        if let Ok(from_account) = ccx.ecx.journal_mut().load_account(*from) {
265            let from_storage = from_account.storage.clone();
266            if ccx.ecx.journal_mut().load_account(*to).is_ok() {
267                // SAFETY: We ensured the account was already loaded.
268                ccx.ecx.journal_mut().evm_state_mut().get_mut(to).unwrap().storage = from_storage;
269                if let Some(arbitrary_storage) = &mut ccx.state.arbitrary_storage {
270                    arbitrary_storage.mark_copy(from, to);
271                }
272            }
273        }
274
275        Ok(Default::default())
276    }
277}
278
279impl Cheatcode for sortCall {
280    fn apply(&self, _state: &mut Cheatcodes) -> Result {
281        let Self { array } = self;
282
283        let mut sorted_values = array.clone();
284        sorted_values.sort();
285
286        Ok(sorted_values.abi_encode())
287    }
288}
289
290impl Cheatcode for shuffleCall {
291    fn apply(&self, state: &mut Cheatcodes) -> Result {
292        let Self { array } = self;
293
294        let mut shuffled_values = array.clone();
295        let rng = state.rng();
296        shuffled_values.shuffle(rng);
297
298        Ok(shuffled_values.abi_encode())
299    }
300}
301
302impl Cheatcode for setSeedCall {
303    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
304        let Self { seed } = self;
305        ccx.state.set_seed(*seed);
306        Ok(Default::default())
307    }
308}
309
310/// Helper to generate a random `uint` value (with given bits or bounded if specified)
311/// from type strategy.
312fn random_uint(state: &mut Cheatcodes, bits: Option<U256>, bounds: Option<(U256, U256)>) -> Result {
313    if let Some(bits) = bits {
314        // Generate random with specified bits.
315        ensure!(bits <= U256::from(256), "number of bits cannot exceed 256");
316        return Ok(DynSolValue::type_strategy(&DynSolType::Uint(bits.to::<usize>()))
317            .new_tree(state.test_runner())
318            .unwrap()
319            .current()
320            .abi_encode());
321    }
322
323    if let Some((min, max)) = bounds {
324        ensure!(min <= max, "min must be less than or equal to max");
325        // Generate random between range min..=max
326        let exclusive_modulo = max - min;
327        let mut random_number: U256 = state.rng().random();
328        if exclusive_modulo != U256::MAX {
329            let inclusive_modulo = exclusive_modulo + U256::from(1);
330            random_number %= inclusive_modulo;
331        }
332        random_number += min;
333        return Ok(random_number.abi_encode());
334    }
335
336    // Generate random `uint256` value.
337    Ok(DynSolValue::type_strategy(&DynSolType::Uint(256))
338        .new_tree(state.test_runner())
339        .unwrap()
340        .current()
341        .abi_encode())
342}
343
344/// Helper to generate a random `int` value (with given bits if specified) from type strategy.
345fn random_int(state: &mut Cheatcodes, bits: Option<U256>) -> Result {
346    let no_bits = bits.unwrap_or(U256::from(256));
347    ensure!(no_bits <= U256::from(256), "number of bits cannot exceed 256");
348    Ok(DynSolValue::type_strategy(&DynSolType::Int(no_bits.to::<usize>()))
349        .new_tree(state.test_runner())
350        .unwrap()
351        .current()
352        .abi_encode())
353}
354
355impl Cheatcode for eip712HashType_0Call {
356    fn apply(&self, state: &mut Cheatcodes) -> Result {
357        let Self { typeNameOrDefinition } = self;
358
359        let type_def = get_canonical_type_def(typeNameOrDefinition, state, None)?;
360
361        Ok(keccak256(type_def.as_bytes()).to_vec())
362    }
363}
364
365impl Cheatcode for eip712HashType_1Call {
366    fn apply(&self, state: &mut Cheatcodes) -> Result {
367        let Self { bindingsPath, typeName } = self;
368
369        let path = state.config.ensure_path_allowed(bindingsPath, FsAccessKind::Read)?;
370        let type_def = get_type_def_from_bindings(typeName, path, &state.config.root)?;
371
372        Ok(keccak256(type_def.as_bytes()).to_vec())
373    }
374}
375
376impl Cheatcode for eip712HashStruct_0Call {
377    fn apply(&self, state: &mut Cheatcodes) -> Result {
378        let Self { typeNameOrDefinition, abiEncodedData } = self;
379
380        let type_def = get_canonical_type_def(typeNameOrDefinition, state, None)?;
381        let primary = &type_def[..type_def.find('(').unwrap_or(type_def.len())];
382
383        get_struct_hash(primary, &type_def, abiEncodedData)
384    }
385}
386
387impl Cheatcode for eip712HashStruct_1Call {
388    fn apply(&self, state: &mut Cheatcodes) -> Result {
389        let Self { bindingsPath, typeName, abiEncodedData } = self;
390
391        let path = state.config.ensure_path_allowed(bindingsPath, FsAccessKind::Read)?;
392        let type_def = get_type_def_from_bindings(typeName, path, &state.config.root)?;
393
394        get_struct_hash(typeName, &type_def, abiEncodedData)
395    }
396}
397
398impl Cheatcode for eip712HashTypedDataCall {
399    fn apply(&self, _state: &mut Cheatcodes) -> Result {
400        let Self { jsonData } = self;
401        let typed_data: TypedData = serde_json::from_str(jsonData)?;
402        let digest = typed_data.eip712_signing_hash()?;
403
404        Ok(digest.to_vec())
405    }
406}
407
408/// Returns EIP-712 canonical type definition from the provided string type representation or type
409/// name. If type name provided, then it looks up bindings from file generated by `forge bind-json`.
410fn get_canonical_type_def(
411    name_or_def: &String,
412    state: &mut Cheatcodes,
413    path: Option<PathBuf>,
414) -> Result<String> {
415    let type_def = if name_or_def.contains('(') {
416        // If the input contains '(', it must be the type definition.
417        EncodeType::parse(name_or_def).and_then(|parsed| parsed.canonicalize())?
418    } else {
419        // Otherwise, it must be the type name.
420        let path = path.as_ref().unwrap_or(&state.config.bind_json_path);
421        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;
422        get_type_def_from_bindings(name_or_def, path, &state.config.root)?
423    };
424
425    Ok(type_def)
426}
427
428/// Returns the EIP-712 type definition from the bindings in the provided path.
429/// Assumes that read validation for the path has already been checked.
430fn get_type_def_from_bindings(name: &String, path: PathBuf, root: &PathBuf) -> Result<String> {
431    let content = fs::read_to_string(&path)?;
432
433    let type_defs: HashMap<&str, &str> = content
434        .lines()
435        .filter_map(|line| {
436            let relevant = line.trim().strip_prefix(TYPE_BINDING_PREFIX)?;
437            let (name, def) = relevant.split_once('=')?;
438            Some((name.trim(), def.trim().strip_prefix('"')?.strip_suffix("\";")?))
439        })
440        .collect();
441
442    match type_defs.get(name.as_str()) {
443        Some(value) => Ok(value.to_string()),
444        None => {
445            let bindings =
446                type_defs.keys().map(|k| format!(" - {k}")).collect::<Vec<String>>().join("\n");
447
448            bail!(
449                "'{}' not found in '{}'.{}",
450                name,
451                path.strip_prefix(root).unwrap_or(&path).to_string_lossy(),
452                if bindings.is_empty() {
453                    String::new()
454                } else {
455                    format!("\nAvailable bindings:\n{bindings}\n")
456                }
457            );
458        }
459    }
460}
461
462/// Returns the EIP-712 struct hash for provided name, definition and ABI encoded data.
463fn get_struct_hash(primary: &str, type_def: &String, abi_encoded_data: &Bytes) -> Result {
464    let mut resolver = Resolver::default();
465
466    // Populate the resolver by ingesting the canonical type definition, and then get the
467    // corresponding `DynSolType` of the primary type.
468    resolver
469        .ingest_string(type_def)
470        .map_err(|e| fmt_err!("Resolver failed to ingest type definition: {e}"))?;
471
472    let resolved_sol_type = resolver
473        .resolve(primary)
474        .map_err(|e| fmt_err!("Failed to resolve EIP-712 primary type '{primary}': {e}"))?;
475
476    // ABI-decode the bytes into `DynSolValue::CustomStruct`.
477    let sol_value = resolved_sol_type.abi_decode(abi_encoded_data.as_ref()).map_err(|e| {
478        fmt_err!("Failed to ABI decode using resolved_sol_type directly for '{primary}': {e}.")
479    })?;
480
481    // Use the resolver to properly encode the data.
482    let encoded_data: Vec<u8> = resolver
483        .encode_data(&sol_value)
484        .map_err(|e| fmt_err!("Failed to EIP-712 encode data for struct '{primary}': {e}"))?
485        .ok_or_else(|| fmt_err!("EIP-712 data encoding returned 'None' for struct '{primary}'"))?;
486
487    // Compute the type hash of the primary type.
488    let type_hash = resolver
489        .type_hash(primary)
490        .map_err(|e| fmt_err!("Failed to compute typeHash for EIP712 type '{primary}': {e}"))?;
491
492    // Compute the struct hash of the concatenated type hash and encoded data.
493    let mut bytes_to_hash = Vec::with_capacity(32 + encoded_data.len());
494    bytes_to_hash.extend_from_slice(type_hash.as_slice());
495    bytes_to_hash.extend_from_slice(&encoded_data);
496
497    Ok(keccak256(&bytes_to_hash).to_vec())
498}
499
500impl Cheatcode for toRlpCall {
501    fn apply(&self, _state: &mut Cheatcodes) -> Result {
502        let Self { data } = self;
503
504        let mut buf = Vec::new();
505        data.encode(&mut buf);
506
507        Ok(Bytes::from(buf).abi_encode())
508    }
509}
510
511impl Cheatcode for fromRlpCall {
512    fn apply(&self, _state: &mut Cheatcodes) -> Result {
513        let Self { rlp } = self;
514
515        let decoded: Vec<Bytes> = Vec::<Bytes>::decode(&mut rlp.as_ref())
516            .map_err(|e| fmt_err!("Failed to decode RLP: {e}"))?;
517
518        Ok(decoded.abi_encode())
519    }
520}