5/5
_Follow along the course with this video._ --- ### Redeem Collateral Now that we've the means to depositCollateral in our tests, let's write the function to do the opposite, redeemCollateral. We're going to set this up similarly to our depositCollateral function within `Handler.t.sol`. ```solidity function redeemCollateral(uint256 collateralSeed, uint256 amountCollateral) public { ERC20Mock collateral = _getCollateralFromSeed(collateralSeed); } ``` Just like we bound the amountCollateral in our depositCollateral function, we'll need to do so here as well, but this time, the amount needs to be bound to the amount of collateral a user actually has! I added another getter function we can use for this. ```solidity function redeemCollateral(uint256 collateralSeed, uint256 amountCollateral) public { ERC20Mock collateral = _getCollateralFromSeed(collateralSeed); uint256 maxCollateralToRedeem = dsce.getCollateralBalanceOfUser(address(collateral), msg.sender); amountCollateral = bound(amountCollateral, 1, maxCollateralToRedeem); dsce.redeemCollateral(address(collateral), amountCollateral); } ``` Let's run it! ```bash forge test --mt invariant_ProtocolTotalSupplyLessThanCollateralValue -vvvv ``` ::image{src='/foundry-defi/21-defi-handler-redeem-collateral/defi-handler-redeem-collateral1.png' style='width: 100%; height: auto;'} Uh oh, it looks like we're running into an issue when the maxCollateralToRedeem is 0. We can fix this with a small adjustment to our function. We'll set the lower bounds of our `bound` function to `0`, additionally we'll add a conditional which will return if the `maxCollateralToRedeem == 0`. ```solidity 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); } ``` ::image{src='/foundry-defi/21-defi-handler-redeem-collateral/defi-handler-redeem-collateral2.png' style='width: 100%; height: auto;'} Woo, nailed it again! Our handler now allows us to test both the depositCollateral and redeemCollateral functionality of our protocol. Through the use of our handler, we've ensured that all the calls to deposit and redeem are going to be valid as well, avoiding reverts and wasted fuzz runs. Something to keep in mind at this point is that `fail_on_revert` flag, however. While writing this test, you can see we've restricted the functionality such that a user is only going to attempt to redeem the collateral that they have. Were there a bug, which allowed users to redeem _more_ than they had, our test wouldn't catch the vulnerability! ### Wrap Up We're crushing these stateful fuzz tests! We've written Handler functions for both our deposit and redeem functionalities within DecentralizedStableCoin.sol. In our testing, we've learnt the pros and cons of the `fail_on_revert` flag and how to be conscious of the false sense of security some of our test configurations may give us. In the next lesson we're hittin the mintDsc function, can't wait!
A focused lesson on Extending Invariant Tests: Adding a Mint Function Handler - Improve invariant test coverage by adding a `mintDsc` function handler in Foundry. Understand how to implement both loose and strict input narrowing strategies based on `fail_on_revert`.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
Advanced smart contract development
How to develop a stablecoin
How to develop a DeFi protocol
How to develop a DAO
Advanced smart contracts testing
Fuzz testing
Manual verification
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Web3 engineer, educator, and Cyfrin co-founder. Patrick's smart contract development and security courses have helped hundreds of thousands of engineers kickstarting their careers into web3.
Guest lecturers:
Last updated on June 10, 2025
Duration: 36min
Duration: 3h 06min
Duration: 5h 02min
Duration: 6h 02min
Duration: 2h 47min
Duration: 1h 23min
Duration: 4h 28min
Duration: 1h 19min
Duration: 1h 10min
Course Overview
About the course
Advanced smart contract development
How to develop a stablecoin
How to develop a DeFi protocol
How to develop a DAO
Advanced smart contracts testing
Fuzz testing
Manual verification
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Web3 engineer, educator, and Cyfrin co-founder. Patrick's smart contract development and security courses have helped hundreds of thousands of engineers kickstarting their careers into web3.
Guest lecturers:
Last updated on June 10, 2025