Testing
StateZero:
(Vault has 10000 DAI)
testVaultHasDAI
User deposits WETH
Focus on testing the Vault, ignore the ERC20 mechanisms like testing transferring without approval and such
I.e. cannotWithdraw -> nothing to withdraw. no need to test, handled by token contract
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "lib/forge-std/src/Test.sol";
import "lib/forge-std/src/console2.sol";
import "src/Vault.sol";
import "test/Dai.sol";
import "test/WETH.sol";
import "test/MockV3Aggregator.sol";
abstract contract StateZero is Test {
Dai public dai;
WETH9 public weth;
MockV3Aggregator public priceFeed;
Vault public vault;
address user;
address deployer;
event Deposit(address indexed collateralAsset, address indexed user, uint collateralAmount);
event Borrow(address indexed debtAsset, address indexed user, uint debtAmount);
event Repay(address indexed debtAsset, address indexed user, uint debtAmount);
event Withdraw(address indexed collateralAsset, address indexed user, uint collateralAmount);
event Liquidation(address indexed collateralAsset, address indexed debtAsset, address indexed user, uint debtToCover, uint liquidatedCollateralAmount);
function setUp() public virtual {
//vm.chainId(4);
dai = new Dai(4);
vm.label(address(dai), "dai contract");
weth = new WETH9();
vm.label(address(weth), "weth contract");
priceFeed = new MockV3Aggregator(18, 386372840000000);
vm.label(address(priceFeed), "priceFeed contract");
deployer = 0xb4c79daB8f259C7Aee6E5b2Aa729821864227e84;
vm.label(deployer, "deployer");
user = address(1);
vm.label(user, "user");
//mint 100 DAI for Vault
vault = new Vault(address(dai), address(weth), address(priceFeed),8,10);
vm.label(address(vault), "vault contract");
dai.mint(address(vault), 10000*10**18);
}
}
contract StateZeroTest is StateZero {
function testVaultHasDAI() public {
console2.log("Check Vault has 100 DAI on deployment");
uint vaultDAI = dai.balanceOf(address(vault));
assertTrue(vaultDAI == 10000*10**18);
}
function testUserDepositsWETH () public {
vm.deal(user, 1 ether);
vm.startPrank(user);
weth.deposit{value: 1 ether}();
assertTrue(weth.balanceOf(user) == 1 ether);
vm.expectEmit(true, true, false, true);
emit Deposit(address(weth), user, 1 ether);
weth.approve(address(vault), 1 ether);
vault.deposit(1 ether);
assertTrue(vault.deposits(user) == 1 ether);
vm.stopPrank;
}
}setup()
setup users and token contracts and label them (vm.label).
labels are reflected in traces, very useful
pass decimals and initial price into MockV3Aggregator
mint 10000 DAI into vault
StateZeroTest()
use console2.log to give a high-level statement on the purpose of each test -> appears in traces
vm.deal(user, 1 ether) -> give 1 ether to user
user needs to change eth -> weth
how to add msg.value into function call:
StateDeposited
(Vault has 10000 DAI, 1 WETH) | (user deposited 1 WETH. can borrow, withdraw)
setUp()
testCannotWithdrawInExcess
Cannot withdraw in excess of deposited amount
testCannotBeLiquidatedWithoutDebt
Cannot be wrongly liquidated with no debt
testCannotBorrowInExcess
Cannot borrow in excess of collateral provided
testWithdraw
User can withdraw freely in absence of debt (fuzzing)
testBorrow
User can borrow against collateral provided (fuzzing)
StateBorrowed
user has borrowed half of maxDebt | actions:[borrow,repay,withdraw]
setUP()
testCannotBorrowExceedingMargin (fuzzing)
With existing debt, user should be unable to exceed margin limits
testCannotWithdrawExceedingMargin (fuzzing)
With existing debt, user should be unable to withdraw in excess of required collateral
testCannotBeLiquidatedAtSamePrice
testRepay (fuzzing)
StateLiquidation
(setup price to exceed)
update price
priceFeed.updateAnswer(386372840000000*10**5);
testLiquidationOnPriceAppreciation
DAI/WETH price appreciated significantly; user should be liquidated
testOnlyOwnerCanCallLiquidate
Only Owner of contract can call liquidate - onlyOwner modifier
Last updated