Advanced Foundry Course: The issue with Invariant tests (FUZZ) #3546
-
Hi everyone. During the invariant tests, I encountered this issue. I think It is related to the foundry.toml (fail_on_revert = true (or false)). Every time when i run the invariant test Invariants.t.sol: // SPDX-License-Identifier: MIT
// Have our invariant aka (also known as) properties
// What are our invariants?
// 1. The total supply of DSC should be less than the total value of collateral
// 2. Getter view funtions should never revert <- evergreen invariant
pragma solidity ^0.8.0;
import {Test, console} from "forge-std/Test.sol";
import {StdInvariant} from "forge-std/StdInvariant.sol";
import {DeployDSC} from "script/DeployDSC.s.sol";
import {DSCEngine} from "src/DSCEngine.sol";
import {HelperConfig} from "script/HelperConfig.s.sol";
import {DecentralizedStableCoin} from "src/DecentralizedStableCoin.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {Handler} from "test/fuzz/Handler.t.sol";
contract InvariantsTest is StdInvariant, Test {
DeployDSC deployer;
DSCEngine dsce;
HelperConfig config;
DecentralizedStableCoin dsc;
address weth;
address wbtc;
Handler handler;
function setUp() external {
deployer = new DeployDSC();
(dsc, dsce, config) = deployer.run();
(,, weth, wbtc, ) = config.activeNetworkConfig();
handler = new Handler(dsce, dsc);
targetContract(address(handler));
// don't call redeemCollateral, unless there is collateral to redeem!
}
function invariant_protocolMustHaveMoreValueThanTotalSupply() public view {
// get the value of all the collateral in the protocol
// compare it to all the debt (dsc)
uint256 totalSupply = dsc.totalSupply();
uint256 totalWethDeposited = IERC20(weth).balanceOf(address(dsce));
uint256 totalBtcDeposited = IERC20(wbtc).balanceOf(address(dsce));
uint256 wethValue = dsce.getUsdValue(weth, totalWethDeposited);
uint256 wbtcValue = dsce.getUsdValue(weth, totalBtcDeposited);
console.log("Total Supply: ", totalSupply);
console.log("Weth Value: ", wethValue);
console.log("Wbtc Value: ", wbtcValue);
assert(wethValue + wbtcValue >= totalSupply);
}
} Handler.t.sol: // Handler is going to narrow down the way we call function
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Test} from "forge-std/Test.sol";
import {DecentralizedStableCoin} from "src/DecentralizedStableCoin.sol";
import {DSCEngine} from "src/DSCEngine.sol";
import {ERC20Mock} from "lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol";
contract Handler is Test {
DSCEngine dsce;
DecentralizedStableCoin dsc;
ERC20Mock weth;
ERC20Mock wbtc;
uint256 MAX_DEPOSIT_SIZE = type(uint96).max;
constructor(DSCEngine _dscEngine, DecentralizedStableCoin _dsc) {
dsce = _dscEngine;
dsc = _dsc;
address[] memory collateralTokens = dsce.getCollateralTokens();
weth = ERC20Mock(collateralTokens[0]);
wbtc = ERC20Mock(collateralTokens[1]);
}
// redeem collateral <-
/**
* We keep randomization in the depositCollateral function
*/
function depositCollateral(uint256 collateralSeed, uint256 amountCollateral) public {
ERC20Mock collateral = _getCollateralFromSeed(collateralSeed);
uint256 amountCollateral = bound(amountCollateral, 1, MAX_DEPOSIT_SIZE);
vm.startPrank(msg.sender);
collateral.mint(address(dsce), amountCollateral);
collateral.approve(address(dsce), amountCollateral);
dsce.depositCollateral(address(collateral), amountCollateral);
vm.stopPrank();
}
function redeemCollateral(uint256 collateralSeed, uint256 amountCollateral) public {
ERC20Mock collateral = _getCollateralFromSeed(collateralSeed);
uint256 maxCollateralToRedeem = dsce.getCollateralBalanceOfUser(address(collateral), msg.sender);
amountCollateral = bound(amountCollateral, 0, maxCollateralToRedeem);
if (amountCollateral == 0) {
return;
}
dsce.redeemCollateral(address(collateral), amountCollateral);
}
function _getCollateralFromSeed(uint256 collateralSeed) private view returns (ERC20Mock) {
if (collateralSeed % 2 == 0) {
return weth;
}
return wbtc;
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Fuzz testing is really dependent on some factors, such as |
Beta Was this translation helpful? Give feedback.
Fuzz testing is really dependent on some factors, such as
the number of runs
andthe seed used
, If you have any of this different from what Patrick has, I expect that you notice some little difference in the path taken or the number of runs undergone. If your Fuzz test works fine and correctly, I will urge you not to sweat over those little differences.