// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.0;import"lib/chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";import"lib/yield-utils-v2/contracts/token/IERC20.sol";import"lib/openzeppelin-contracts/contracts/access/Ownable.sol";contractVaultisOwnable {//vault records WETH DEPOSITSmapping (address=>uint) public deposits; //deposits in WETHmapping (address=>uint) public debts; //debt in DAI///@notice ERC20 interface specifying token contract functions ///@dev For constant variables, the value has to be fixed at compile-time, while for immutable, it can still be assigned at construction time.
IERC20 publicimmutable collateral; IERC20 publicimmutable debt; // DAi/WETH Pricefeed AggregatorV3Interface publicimmutable priceFeed; ///@dev Emitted on deposit()///@param collateralAsset The address of the collateral asset///@param user The address of the user calling deposit()///@param collateralAmount The amount of collateral asset depositedeventDeposit(addressindexed collateralAsset, addressindexed user, uint collateralAmount); ///@dev Emitted on borrow()///@param debtAsset The address of the debt asset///@param user The address of the user calling borrow()///@param debtAmount The amount of debt asset borrowedeventBorrow(addressindexed debtAsset, addressindexed user, uint debtAmount); ///@dev Emitted on repay()///@param debtAsset The address of the debt asset///@param user The address of the user calling repay()///@param debtAmount The amount of debt asset being repaideventRepay(addressindexed debtAsset, addressindexed user, uint debtAmount);///@dev Emitted on withdraw()///@param collateralAsset The address of the debt asset///@param user The address of the user calling withdraw()///@param collateralAmount The amount of collateral asset withdrawneventWithdraw(addressindexed collateralAsset, addressindexed user, uint collateralAmount); ///@dev Emitted on liquidation()///@param collateralAsset The address of the debt asset///@param debtAsset The address of the debt asset///@param user The address of the user calling withdraw()///@param debtToCover The amount of debt the liquidator wants to cover///@param liquidatedCollateralAmount The amount of collateral received by the liquidator event Liquidation(address indexed collateralAsset, address indexed debtAsset, address indexed user, uint debtToCover, uint liquidatedCollateralAmount);
///@dev To set collateralization level of debt engine///@notice To allow for margin call at defined level, preventing Vault from bearing risk in fast moving marketsuint bufferDenominator; uint bufferNumerator; constructor(address dai_, address weth_, address priceFeedAddress, uint bufferNumerator_, uint bufferDenominator_) {
collateral =IERC20(weth_); debt =IERC20(dai_); priceFeed =AggregatorV3Interface(priceFeedAddress);// collateralization level bufferNumerator = bufferNumerator_; bufferDenominator = bufferDenominator_; }///@dev Users deposit collateral asset into Vault///@param collateralAmount Amount of collateral to depositfunctiondeposit(uint collateralAmount) external { deposits[msg.sender] += collateralAmount;bool sent = collateral.transferFrom(msg.sender,address(this), collateralAmount);require(sent,"Deposit failed!"); emitDeposit(address(collateral), msg.sender, collateralAmount); }///@notice Users borrow debt asset calculated based on collateralization level and their deposits ///@dev See getMaxDebt() for colleteralization colculation///@param debtAmount Amount of debt asset to borrowfunctionborrow(uint debtAmount) external { uint maxDebt =getMaxDebt(msg.sender);require(debtAmount <= maxDebt,"Insufficient collateral!"); debts[msg.sender] += debtAmount;bool sent = debt.transfer(msg.sender, debtAmount);require(sent,"Borrow failed!"); emitBorrow(address(debt), msg.sender, debtAmount); }///@notice Get maximum debt asset borrowable, calculated based on collateralization level ///@dev Collateralization level: bufferNumerator/bufferDenominator (e.g. 8/10 -> 80%)///@param user User address to calculate maximum debt possible based on collateralization levelfunctiongetMaxDebt(address user) publicviewreturns(uint) {uint availableCollateral = (deposits[user]/bufferDenominator)*bufferNumerator;uint maxDebt = (availableCollateral*10**getDecimals() /get_daiETH_Price());return maxDebt; }///@notice Users repay their debt, in debt asset terms///@dev This covers partial and full repayment///@param debtAmount Amount of debt asset to repayfunctionrepay(uint debtAmount) external { debts[msg.sender] -= debtAmount;bool sent = debt.transferFrom(msg.sender,address(this), debtAmount);require(sent,"Repayment failed!"); emitRepay(address(debt), msg.sender, debtAmount); }///@notice Users withdraw their deposited collateral///@dev This covers partial and full withdrawal; checks for spare capacity before initiating withdrawal///@param collateralAmount Amount of collateral asset to withdrawfunctionwithdraw(uint collateralAmount) external { if (debts[msg.sender] >0){uint collateralRequired =getCollateralRequired(debts[msg.sender]);uint spareDeposit = deposits[msg.sender] - collateralRequired;require(collateralAmount < spareDeposit,"Collateral unavailable!"); } deposits[msg.sender] -= collateralAmount;bool sent = collateral.transfer(msg.sender, collateralAmount);require(sent,"Withdraw failed!");emitWithdraw(address(collateral), msg.sender, collateralAmount); }///@dev Calculates collateral required to support existing debt position at current market prices ///@param debtAmount Amount of debt asset to supportfunctiongetCollateralRequired(uint debtAmount) publicviewreturns(uint) {uint baseCollateralRequired = debtAmount*get_daiETH_Price() / (10**getDecimals());uint bufferCollateralRequired = (baseCollateralRequired/bufferNumerator)*bufferDenominator;return bufferCollateralRequired; }///@dev Can only be called by Vault owner; triggers liquidation check on supplied user address///@param user Address of user to trigger liquidation checkfunctionliquidation(address user) publiconlyOwner { uint collateralRequired =getCollateralRequired(debts[user]);if (collateralRequired > deposits[user]){emitLiquidation(address(collateral),address(debt), user, debts[user], deposits[user]); delete deposits[user];delete debts[user]; } }///@notice Price is returned as integer extending over its decimal places///@dev Get current market price of Collateral/Debt asset from Chainlinkfunctionget_daiETH_Price() publicviewreturns(uint) { (,int price,,,) = priceFeed.latestRoundData();returnuint(price); }///@notice Returns number of decimal places in price returned ///@dev Used to rebase price to account for decimal places (e.g. price = 386372840000000, decimals =18, actual_price = 0.00038637284)
functiongetDecimals() publicviewreturns(uint) {return priceFeed.decimals(); }}