Project #5: Collateralized Vault
Objective
Contract that acts as a collateralized debt engine.
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.
Tokens
Collateral: WETH
Underlying: DAI
Contract
Pull the contract code for both from Etherscan
Add a
mint()
function that allows you to obtain as much as you need for testing.
Workflow
Deposit: User deposit WETH into Vault. Vault records WETH deposited.
Borrow: User borrows DAI against their WETH deposit.
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 deposit
Vault transfers DAI to the users
Vault owner finances DAI to the Vault on deployment
Exchange rate: Chainlink Oracle [https://docs.chain.link/docs/ethereum-addresses]
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.
Process
Dependencies
IERC20 interface):
forge install yieldprotocol/yield-utils-v2
Ownable.sol:
forge install openZeppelin/openzeppelin-contracts
AggregatorV3 and MockV3Aggregator:
forge install smartcontractkit/chainlink
Pull contracts from Etherscan
Updating contracts to v0.8.0
WETH9.sol:
Added
emit
to all eventsLine 70:
uint(-1)
refactored totype(uint).max
DAI.sol:
removed inheritance of LibNote
line 78 & 79: removed note modifier from function reply and deny
line 112: removed
public
from constructor.line 190:
now
deprecated, changed toblock.timestamp
line 192:
uint(-1)
changed totype(uint).max
(also on 131, 147)
Pricing + Decimal scaling
Testing
Action: deposit, borrow, repay, withdraw. liquidated
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
Last updated