foundry_evm_fuzz/strategies/
calldata.rs1use crate::{
2 FuzzFixtures,
3 strategies::{EvmFuzzState, fuzz_param_from_state, fuzz_param_with_fixtures},
4};
5use alloy_dyn_abi::JsonAbiExt;
6use alloy_json_abi::Function;
7use alloy_primitives::{Bytes, U256};
8use proptest::prelude::Strategy;
9
10pub fn fuzz_calldata(
13 func: Function,
14 fuzz_fixtures: &FuzzFixtures,
15 max_fuzz_int: Option<U256>,
16) -> impl Strategy<Value = Bytes> + use<> {
17 let strats = func
20 .inputs
21 .iter()
22 .map(|input| {
23 fuzz_param_with_fixtures(
24 &input.selector_type().parse().unwrap(),
25 fuzz_fixtures.param_fixtures(&input.name),
26 &input.name,
27 max_fuzz_int,
28 )
29 })
30 .collect::<Vec<_>>();
31 strats.prop_map(move |values| {
32 func.abi_encode_input(&values)
33 .unwrap_or_else(|_| {
34 panic!(
35 "Fuzzer generated invalid arguments for function `{}` with inputs {:?}: {:?}",
36 func.name, func.inputs, values
37 )
38 })
39 .into()
40 })
41}
42
43pub fn fuzz_calldata_from_state(
46 func: Function,
47 state: &EvmFuzzState,
48 max_fuzz_int: Option<U256>,
49) -> impl Strategy<Value = Bytes> + use<> {
50 let strats = func
51 .inputs
52 .iter()
53 .map(|input| {
54 fuzz_param_from_state(&input.selector_type().parse().unwrap(), state, max_fuzz_int)
55 })
56 .collect::<Vec<_>>();
57 strats
58 .prop_map(move |values| {
59 func.abi_encode_input(&values)
60 .unwrap_or_else(|_| {
61 panic!(
62 "Fuzzer generated invalid arguments for function `{}` with inputs {:?}: {:?}",
63 func.name, func.inputs, values
64 )
65 })
66 .into()
67 })
68 .no_shrink()
69}
70
71#[cfg(test)]
72mod tests {
73 use crate::{FuzzFixtures, strategies::fuzz_calldata};
74 use alloy_dyn_abi::{DynSolValue, JsonAbiExt};
75 use alloy_json_abi::Function;
76 use alloy_primitives::{Address, map::HashMap};
77 use proptest::prelude::Strategy;
78
79 #[test]
80 fn can_fuzz_with_fixtures() {
81 let function = Function::parse("test_fuzzed_address(address addressFixture)").unwrap();
82
83 let address_fixture = DynSolValue::Address(Address::random());
84 let mut fixtures = HashMap::default();
85 fixtures.insert(
86 "addressFixture".to_string(),
87 DynSolValue::Array(vec![address_fixture.clone()]),
88 );
89
90 let expected = function.abi_encode_input(&[address_fixture]).unwrap();
91 let strategy = fuzz_calldata(function, &FuzzFixtures::new(fixtures), None);
92 let _ = strategy.prop_map(move |fuzzed| {
93 assert_eq!(expected, fuzzed);
94 });
95 }
96}