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(contracts);
20 let contracts_ref = contracts.clone();
21 proptest::prop_oneof![
22 80 => proptest::strategy::LazyJust::new(move || *target.read()),
23 20 => any::<prop::sample::Selector>()
24 .prop_map(move |selector| {
25 let (target, _) = selector.select(contracts_ref.iter());
26 *target
27 }),
28 ]
29 .prop_flat_map(move |target_address| {
30 let fuzz_state = fuzz_state.clone();
31 let fuzz_fixtures = fuzz_fixtures.clone();
32 let contracts = contracts.clone();
33
34 let (actual_target, func) = {
35 let (actual_target, fuzzed_functions) = contracts
40 .iter()
41 .find(|(address, _)| *address == target_address)
42 .map(|(address, functions)| (*address, functions.clone()))
43 .unwrap_or_else(|| {
44 let (address, functions) = contracts
45 .iter()
46 .choose(&mut rand::rng())
47 .expect("at least one target contract");
48 (*address, functions.clone())
49 });
50 (
51 actual_target,
52 any::<prop::sample::Index>()
53 .prop_map(move |index| index.get(&fuzzed_functions).clone()),
54 )
55 };
56
57 func.prop_flat_map(move |func| {
58 TxGenerator::call_strategy(
59 &fuzz_state,
60 &fuzz_fixtures,
61 actual_target,
62 func,
63 dictionary_weight,
64 payable_value_weight,
65 )
66 })
67 })
68}