@@ -10,7 +10,7 @@ extern crate tracing;
1010
1111use alloy_dyn_abi:: { DynSolValue , JsonAbiExt } ;
1212use alloy_primitives:: {
13- Address , Bytes , Log ,
13+ Address , Bytes , Log , U256 ,
1414 map:: { AddressHashMap , HashMap } ,
1515} ;
1616use foundry_common:: { calc, contracts:: ContractsByAddress } ;
@@ -36,6 +36,10 @@ pub use inspector::Fuzzer;
3636/// Details of a transaction generated by fuzz strategy for fuzzing a target.
3737#[ derive( Clone , Debug , Serialize , Deserialize ) ]
3838pub struct BasicTxDetails {
39+ // Time (in seconds) to increase block timestamp before executing the tx.
40+ pub warp : Option < U256 > ,
41+ // Number to increase block number before executing the tx.
42+ pub roll : Option < U256 > ,
3943 // Transaction sender address.
4044 pub sender : Address ,
4145 // Transaction call details.
@@ -62,6 +66,10 @@ pub enum CounterExample {
6266
6367#[ derive( Clone , Debug , Serialize , Deserialize ) ]
6468pub struct BaseCounterExample {
69+ // Amount to increase block timestamp.
70+ pub warp : Option < U256 > ,
71+ // Amount to increase block number.
72+ pub roll : Option < U256 > ,
6573 /// Address which makes the call.
6674 pub sender : Option < Address > ,
6775 /// Address to which to call to.
@@ -89,21 +97,26 @@ pub struct BaseCounterExample {
8997impl BaseCounterExample {
9098 /// Creates counter example representing a step from invariant call sequence.
9199 pub fn from_invariant_call (
92- sender : Address ,
93- addr : Address ,
94- bytes : & Bytes ,
100+ tx : & BasicTxDetails ,
95101 contracts : & ContractsByAddress ,
96102 traces : Option < SparsedTraceArena > ,
97103 show_solidity : bool ,
98104 ) -> Self {
99- if let Some ( ( name, abi) ) = & contracts. get ( & addr)
105+ let sender = tx. sender ;
106+ let target = tx. call_details . target ;
107+ let bytes = & tx. call_details . calldata ;
108+ let warp = tx. warp ;
109+ let roll = tx. roll ;
110+ if let Some ( ( name, abi) ) = & contracts. get ( & target)
100111 && let Some ( func) = abi. functions ( ) . find ( |f| f. selector ( ) == bytes[ ..4 ] )
101112 {
102113 // skip the function selector when decoding
103114 if let Ok ( args) = func. abi_decode_input ( & bytes[ 4 ..] ) {
104115 return Self {
116+ warp,
117+ roll,
105118 sender : Some ( sender) ,
106- addr : Some ( addr ) ,
119+ addr : Some ( target ) ,
107120 calldata : bytes. clone ( ) ,
108121 contract_name : Some ( name. clone ( ) ) ,
109122 func_name : Some ( func. name . clone ( ) ) ,
@@ -119,8 +132,10 @@ impl BaseCounterExample {
119132 }
120133
121134 Self {
135+ warp,
136+ roll,
122137 sender : Some ( sender) ,
123- addr : Some ( addr ) ,
138+ addr : Some ( target ) ,
124139 calldata : bytes. clone ( ) ,
125140 contract_name : None ,
126141 func_name : None ,
@@ -139,6 +154,8 @@ impl BaseCounterExample {
139154 traces : Option < SparsedTraceArena > ,
140155 ) -> Self {
141156 Self {
157+ warp : None ,
158+ roll : None ,
142159 sender : None ,
143160 addr : None ,
144161 calldata : bytes,
@@ -160,6 +177,12 @@ impl fmt::Display for BaseCounterExample {
160177 && let ( Some ( sender) , Some ( contract) , Some ( address) , Some ( func_name) , Some ( args) ) =
161178 ( & self . sender , & self . contract_name , & self . addr , & self . func_name , & self . raw_args )
162179 {
180+ if let Some ( warp) = & self . warp {
181+ writeln ! ( f, "\t \t vm.warp(block.timestamp + {warp});" ) ?;
182+ }
183+ if let Some ( roll) = & self . roll {
184+ writeln ! ( f, "\t \t vm.roll(block.number + {roll});" ) ?;
185+ }
163186 writeln ! ( f, "\t \t vm.prank({sender});" ) ?;
164187 write ! (
165188 f,
@@ -186,6 +209,13 @@ impl fmt::Display for BaseCounterExample {
186209 write ! ( f, "{addr} " ) ?
187210 }
188211
212+ if let Some ( warp) = & self . warp {
213+ write ! ( f, "warp={warp} " ) ?;
214+ }
215+ if let Some ( roll) = & self . roll {
216+ write ! ( f, "roll={roll} " ) ?;
217+ }
218+
189219 if let Some ( sig) = & self . signature {
190220 write ! ( f, "calldata={sig}" ) ?
191221 } else {
0 commit comments