-
Does anybody know with my problem, why are all the calls being reversed? not like Patrick did. Invariants.t.sol // SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test, console} from "forge-std/Test.sol";
import {StdInvariant} from "forge-std/StdInvariant.sol";
import {DecentralizedStableCoin} from "src/DecentralizedStableCoin.sol";
import {DSCEngine} from "src/DSCEngine.sol";
import {HelperConfig} from "script/HelperConfig.s.sol";
import {DeployDSC} from "script/DeployDSC.s.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Handler} from "test/fuzz/Handler.t.sol";
contract Invariants is StdInvariant, Test {
DeployDSC deployer;
DecentralizedStableCoin dsc;
DSCEngine engine;
HelperConfig config;
Handler handler;
address weth;
address wbtc;
function setUp() public {
deployer = new DeployDSC();
(dsc, engine, config) = deployer.run();
(,, weth, wbtc,) = config.activeNetworkConfig();
handler = new Handler(dsc, engine);
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 total debt (dsc)
uint256 totalSupply = dsc.totalSupply();
uint256 totalWethDeposited = IERC20(weth).balanceOf(address(engine));
uint256 totalWbtcDeposited = IERC20(wbtc).balanceOf(address(engine));
uint256 wethValue = engine.getUsdValue(weth, totalWethDeposited);
uint256 wbtcValue = engine.getUsdValue(wbtc, totalWbtcDeposited);
assert(wethValue + wbtcValue >= totalSupply);
}
} Handler.t.sol // SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test} from "forge-std/Test.sol";
import {DecentralizedStableCoin} from "src/DecentralizedStableCoin.sol";
import {DSCEngine} from "src/DSCEngine.sol";
import {ERC20Mock} from "@openzeppelin/contracts/mocks/ERC20Mock.sol";
contract Handler is Test {
DecentralizedStableCoin dsc;
DSCEngine engine;
ERC20Mock weth;
ERC20Mock wbtc;
constructor(DecentralizedStableCoin _dsc, DSCEngine _engine) {
dsc = _dsc;
engine = _engine;
address[] memory collateralAddresses = engine.getCollateralTokens();
weth = ERC20Mock(collateralAddresses[0]);
wbtc = ERC20Mock(collateralAddresses[1]);
}
// redeem collateral
function depositCollateral(uint256 collateralSeed, uint256 amountCollateral) public {
ERC20Mock collateral = _getCollateralFromSeed(collateralSeed);
engine.depositCollateral(address(collateral), amountCollateral);
}
// helper function
function _getCollateralFromSeed(uint256 collateralSeed) private view returns (ERC20Mock) {
if (collateralSeed % 2 == 0) {
return weth;
}
return wbtc;
}
} Terminal/console output: [⠊] Compiling...
[⠒] Compiling 4 files with Solc 0.8.28
[⠢] Solc 0.8.28 finished in 995.06ms
Compiler run successful!
Ran 1 test for test/fuzz/Invariants.t.sol:Invariants
[PASS] invariant_protocolMustHaveMoreValueThanTotalSupply() (runs: 128, calls: 16384, reverts: 16384)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 843.90ms (838.41ms CPU time)
Ran 1 test suite in 845.29ms (843.90ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 7 replies
-
Hello @Febri-An, It seems to me that your Handler contract is not versatile enough to handle some weird cases which will help you cut down on reverts. While I may be wrong, I will advice that you compare your // SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.23;
import {ERC20Mock} from "@openzeppelin/contracts/mocks/ERC20Mock.sol";
import {MockV3Aggregator} from "../Mocks/MockV3Aggregator.sol";
import {DSCEngine} from "../../src/DSCEngine.sol";
import {DecentralizedStableCoin} from "../../src/DecentralizedStableCoin.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {Test, console2} from "forge-std/Test.sol";
contract Handler is Test {
DSCEngine public dsc_engine;
DecentralizedStableCoin public decentralized_stable_coin;
MockV3Aggregator public eth_usd_price_feed;
MockV3Aggregator public btc_usd_price_feed;
ERC20Mock public weth;
ERC20Mock public wbtc;
uint96 public constant MAX_DEPOSIT_SIZE = type(uint96).max;
constructor(DSCEngine _dsc_engine, DecentralizedStableCoin _decentralized_stable_coin) {
dsc_engine = _dsc_engine;
decentralized_stable_coin = _decentralized_stable_coin;
address[] memory collateral_tokens = dsc_engine.get_collateral_tokens();
weth = ERC20Mock(collateral_tokens[0]);
wbtc = ERC20Mock(collateral_tokens[1]);
eth_usd_price_feed = MockV3Aggregator(dsc_engine.get_the_price_feed_address_for_token(address(weth)));
btc_usd_price_feed = MockV3Aggregator(dsc_engine.get_the_price_feed_address_for_token(address(wbtc)));
}
function mint_and_deposit_collateral(bool _pick_weth ,uint256 _amount_of_collateral) public {
_amount_of_collateral = bound(_amount_of_collateral, 1, MAX_DEPOSIT_SIZE);
ERC20Mock collateral = randomly_determine_token(_pick_weth);
vm.startPrank(msg.sender);
collateral.mint(msg.sender, _amount_of_collateral);
collateral.approve(address(dsc_engine), _amount_of_collateral);
dsc_engine.depositCollateral(address(collateral), _amount_of_collateral);
vm.stopPrank();
}
function redeem_collateral(bool _pick_weth, uint256 _amount_of_collateral) public {
// get the collateral for which we want to reedem
ERC20Mock collateral = randomly_determine_token(_pick_weth);
// set the maximum amount of the collateral we are going to be redeeming. Basically we make the maximum amount we can reedem be the amount the user have deposited in the dsc_engine initially
uint256 max_amount_of_collateral = dsc_engine.get_collateral_balance_of_user(address(collateral), msg.sender);
// we bound the amount we will reedem to between the maximum amount that we can reedeem and 0
_amount_of_collateral = bound(_amount_of_collateral, 0, max_amount_of_collateral);
// if the amount `_amount_of_collateral` turned out to be `0` meaning the user have not deposited any amount for the particular collateral initially then we return which would not throw any error but just end the process
if(_amount_of_collateral == 0) return;
vm.prank(msg.sender);
dsc_engine.redeemCollateral(address(collateral), _amount_of_collateral);
}
function burn_DSC(uint256 _amount_of_DSC) public {
uint256 max_amount_of_DSC = dsc_engine.get_amount_of_DSC_minted_by_user(msg.sender);
_amount_of_DSC = bound(_amount_of_DSC, 0, max_amount_of_DSC);
if(_amount_of_DSC == 0) return;
vm.startPrank(msg.sender);
DecentralizedStableCoin(address(decentralized_stable_coin)).approve(address(dsc_engine), _amount_of_DSC);
dsc_engine.burnDSC(_amount_of_DSC);
vm.stopPrank();
}
function mint_DSC(uint256 _amount_to_mint) public {
uint256 max_amount_to_mint = MAX_DEPOSIT_SIZE;
_amount_to_mint = bound(_amount_to_mint, 1, max_amount_to_mint);
uint256 total_weth_deposited_value = dsc_engine.get_account_collateral_value_in_USD(msg.sender);
uint256 total_wbtc_deposited_value = dsc_engine.get_account_collateral_value_in_USD(msg.sender);
uint256 total_weth_deposited_value_that_respect_health_factor = total_weth_deposited_value / 2;
uint256 total_wbtc_deposited_value_that_respect_health_factor = total_wbtc_deposited_value / 2;
uint256 health_factor_1 = total_weth_deposited_value_that_respect_health_factor / _amount_to_mint;
console2.log("health_factor_1 is: ", health_factor_1);
uint256 health_factor_2 = total_wbtc_deposited_value_that_respect_health_factor / _amount_to_mint;
console2.log("health_factor_2 is: ", health_factor_2);
bool health_factor_1_respect_health_factor = health_factor_1 >= 1000;
bool health_factor_2_respect_health_factor = health_factor_2 >= 1000;
if(!health_factor_1_respect_health_factor && !health_factor_2_respect_health_factor) return;
// vm.prank(decentralized_stable_coin.owner());
vm.prank(msg.sender);
dsc_engine.mintDSC(_amount_to_mint);
}
function randomly_determine_token(bool _pick_weth) public view returns(ERC20Mock) {
if(_pick_weth == true) {
return weth;
} else return wbtc;
}
} |
Beta Was this translation helpful? Give feedback.
Hello @Febri-An, It seems to me that your Handler contract is not versatile enough to handle some weird cases which will help you cut down on reverts. While I may be wrong, I will advice that you compare your
Handler
contract with Patrick'sHandler
contract on the official GitHub repo associated with the course. Also, below is my Hanlder contract, which works correctly.