foundry_config/
invariant.rs

1//! Configuration for invariant testing
2
3use crate::fuzz::{FuzzCorpusConfig, FuzzDictionaryConfig};
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7/// Contains for invariant testing
8#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
9pub struct InvariantConfig {
10    /// The number of runs that must execute for each invariant test group.
11    pub runs: u32,
12    /// The number of calls executed to attempt to break invariants in one run.
13    pub depth: u32,
14    /// Fails the invariant fuzzing if a revert occurs
15    pub fail_on_revert: bool,
16    /// Allows overriding an unsafe external call when running invariant tests. eg. reentrancy
17    /// checks
18    pub call_override: bool,
19    /// The fuzz dictionary configuration
20    #[serde(flatten)]
21    pub dictionary: FuzzDictionaryConfig,
22    /// The maximum number of attempts to shrink the sequence
23    pub shrink_run_limit: u32,
24    /// The maximum number of rejects via `vm.assume` which can be encountered during a single
25    /// invariant run.
26    pub max_assume_rejects: u32,
27    /// Number of runs to execute and include in the gas report.
28    pub gas_report_samples: u32,
29    /// The fuzz corpus configuration.
30    #[serde(flatten)]
31    pub corpus: FuzzCorpusConfig,
32    /// Path where invariant failures are recorded and replayed.
33    pub failure_persist_dir: Option<PathBuf>,
34    /// Whether to collect and display fuzzed selectors metrics.
35    pub show_metrics: bool,
36    /// Optional timeout (in seconds) for each invariant test.
37    pub timeout: Option<u32>,
38    /// Display counterexample as solidity calls.
39    pub show_solidity: bool,
40    /// Maximum time (in seconds) between generated txs.
41    pub max_time_delay: Option<u32>,
42    /// Maximum number of blocks elapsed between generated txs.
43    pub max_block_delay: Option<u32>,
44    /// Number of calls to execute between invariant assertions.
45    ///
46    /// - `0`: Only assert on the last call of each run (fastest, but may miss exact breaking call)
47    /// - `1` (default): Assert after every call (current behavior, most precise)
48    /// - `N`: Assert every N calls AND always on the last call
49    ///
50    /// Example: `check_interval = 10` means assert after calls 10, 20, 30, ... and the last call.
51    pub check_interval: u32,
52}
53
54impl Default for InvariantConfig {
55    fn default() -> Self {
56        Self {
57            runs: 256,
58            depth: 500,
59            fail_on_revert: false,
60            call_override: false,
61            dictionary: FuzzDictionaryConfig { dictionary_weight: 80, ..Default::default() },
62            shrink_run_limit: 5000,
63            max_assume_rejects: 65536,
64            gas_report_samples: 256,
65            corpus: FuzzCorpusConfig::default(),
66            failure_persist_dir: None,
67            show_metrics: true,
68            timeout: None,
69            show_solidity: false,
70            max_time_delay: None,
71            max_block_delay: None,
72            check_interval: 1,
73        }
74    }
75}
76
77impl InvariantConfig {
78    /// Creates invariant configuration to write failures in `{PROJECT_ROOT}/cache/fuzz` dir.
79    pub fn new(cache_dir: PathBuf) -> Self {
80        Self { failure_persist_dir: Some(cache_dir), ..Default::default() }
81    }
82}