feat(invariant): add Optimization mode to Invariant Testing similar to Echidna
Component
Forge
Describe the feature you would like
In Echidna, optimization mode is used to fuzz for the maximized return value of a given function.
Example:
function echidna_opt_price_difference() public view returns (int256) {
return maxPriceDifference;
}
It basically runs the fuzzer like normal, but instead of looking for broken invariants, it stores the highest value returned by the function being tested. I often use this to determine the max error due to rounding to determine if this is acceptable, but it has many uses.
Additional context
For more info see: https://secure-contracts.com/program-analysis/echidna/advanced/optimization_mode.html
@rappie from the echidna doc this seems to me like a stateless / regular fuzz test as per https://secure-contracts.com/program-analysis/echidna/advanced/optimization_mode.html#optimizing-with-echidna wonder if something like this should work:
function test_max_price(uint256 startPrice, uint256 endPrice, uint256 startTime, uint256 endTime)
public
view
returns (int256 maxPriceDifference)
{
if (endTime < (startTime + 900)) revert();
if (startPrice <= endPrice) revert();
uint256 numerator = (startPrice - endPrice) * (block.timestamp - startTime);
uint256 denominator = endTime - startTime;
uint256 stepDecrease = numerator / denominator;
uint256 currentAuctionPrice = startPrice - stepDecrease;
if (currentAuctionPrice < endPrice) {
maxPriceDifference = int256(endPrice - currentAuctionPrice);
}
if (currentAuctionPrice > startPrice) {
maxPriceDifference = int256(currentAuctionPrice - startPrice);
}
}
and we treat test* as optimization mode if returns int (or we could add a optimization = true config). Just want to make sure that I get this right and these can run as standalone stateless fuzz functions instead of invariant tests. Thank you!
Two things:
- You've got it right that having a view that returns an int256 is basically all we need to do optimization
- We do want to be able run this as invariant test. For example, you often have a sequence where you first deposit a certain amount of tokens, and then perform an action (transfer, swap, etc.) that has rounding errors. You then want to optimize for the maximum rounding error possible. These are usually 2-5 long sequences of transactions.