Collateralized Vault: contract that acts as a collateralized debt engine
For a full illustrated walkthrough, please see: https://calnix.gitbook.io/solidity-lr/yield-mentorship-2022/5-collateralized-vault
Contract allows users to deposit an asset they own (collateral), to borrow a different asset that the Vault owns (underlying). Exchange rate determined by oracle; - if value of collateral drops in underlying terms, the user will be liquidated.
Collateral: WETH Underlying: DAI
- Pull the contract code for both from Etherscan
- Add a mint() function that allows you to obtain as much as you need for testing.
-
Users deposit WETH into Vault,
- (WETH frm User to Vault. Vault recirds WETH deposited.)
-
Users borrow DAI against their WETH
- as long as the value DAI they borrow in WETH terms is less than the value of their WETH collateral
- DAI_value_in_WETH < WETH Collateral
- Vault sends DAI to the users.
- Vault owner finances DAI to the Vault on construction.
-
Exchange rate: Chainlink Oracle [https://docs.chain.link/docs/ethereum-addresses]
-
Users can repay debt in DAI
-
Withdrawal
- To withdraw WETH, the users must repay the DAI they borrowed.
-
Liquidation
- If ETH/DAI price changes such tt debt_value > collateral_value, Vault will erase user records from the contract -> cancelling the user debt, and at the same time stopping that user from withdrawing their collateral.
- forge install yieldprotocol/yield-utils-v2 (IERC20 interface)
- forge install openZeppelin/openzeppelin-contracts
(Ownable.sol) - forge install smartcontractkit/chainlink
(AggregatorV3 and MockV3Aggregator)
WETH9.sol: https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code DAI.sol: https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code
- added 'emit' to all events
- uint(-1) refactored to type(uint).max (line 70)
-> removed inheritance of LibNote -> removed note modifier from function reply and deny (line 78 & 79) -> line 112: removed public from constructor. -> line 190: now deprecated. changed to block.timestamp -> line 192: uint(-1) changed to type(uint).max (also on 131, 147)
StateZero:(Vault has 10000 DAI)
- testVaultHasDAI
- User deposits WETH
- cannotWithdraw -> nothing to withdraw. no need to test.
StateDeposited: (Vault has 10000 DAI, 1 WETH) | (user deposited 1 WETH. can borrow, withdraw)
- userCannotWithdrawExcess
- userCannotBeLiquidatedWithoutDebt
- userCannotBorrowInExcess
- User can withdraw freely in absence of debt (fuzzing)
- User can borrow against collateral provided
StateBorrowed: (user has borrowed half of maxDebt. actions:[borrow,repay,withdraw])
- userCannotBorrowExcessOfMargin
- userCannotWithdrawExcessOfMargin
- userCannotbeLiquidated - price unchanged.
- User Repays (Fuzzing)
StateLiquidation (setup price to exceed)
- userLiquidated
- testOnlyOwnerCanCallLiquidate
Node provider: Alchemy Target network: Ethereum-Goerli