foundry_evm_fuzz/strategies/
invariants.rs1use super::TxGenerator;
2use crate::{CallDetails, FuzzFixtures, strategies::EvmFuzzState};
3use alloy_json_abi::Function;
4use alloy_primitives::Address;
5use parking_lot::RwLock;
6use proptest::prelude::*;
7use rand::seq::IteratorRandom;
8use std::sync::Arc;
9
10pub fn override_call_strat(
12 fuzz_state: EvmFuzzState,
13 contracts: Vec<(Address, Vec<Function>)>,
14 target: Arc<RwLock<Address>>,
15 fuzz_fixtures: FuzzFixtures,
16 dictionary_weight: u32,
17 payable_value_weight: u32,
18) -> impl Strategy<Value = CallDetails> + Send + Sync + 'static {
19 let contracts = Arc::new(
22 contracts
23 .into_iter()
24 .map(|(address, functions)| (address, Arc::new(functions)))
25 .collect::<Vec<_>>(),
26 );
27 let contracts_ref = contracts.clone();
28 proptest::prop_oneof![
29 80 => proptest::strategy::LazyJust::new(move || *target.read()),
30 20 => any::<prop::sample::Selector>()
31 .prop_map(move |selector| {
32 let (target, _) = selector.select(contracts_ref.iter());
33 *target
34 }),
35 ]
36 .prop_flat_map(move |target_address| {
37 let fuzz_state = fuzz_state.clone();
38 let fuzz_fixtures = fuzz_fixtures.clone();
39 let contracts = contracts.clone();
40
41 let (actual_target, func) = {
42 let (actual_target, fuzzed_functions) = contracts
47 .iter()
48 .find(|(address, _)| *address == target_address)
49 .map(|(address, functions)| (*address, functions.clone()))
50 .unwrap_or_else(|| {
51 let (address, functions) = contracts
52 .iter()
53 .choose(&mut rand::rng())
54 .expect("at least one target contract");
55 (*address, functions.clone())
56 });
57 (
58 actual_target,
59 any::<prop::sample::Index>()
60 .prop_map(move |index| index.get(&fuzzed_functions).clone()),
61 )
62 };
63
64 func.prop_flat_map(move |func| {
65 TxGenerator::call_strategy(
66 &fuzz_state,
67 &fuzz_fixtures,
68 actual_target,
69 func,
70 dictionary_weight,
71 payable_value_weight,
72 )
73 })
74 })
75}