_borrower: address of the borrower, also the account which will be liquidated
_borrowedToken: address of the borrowed token
_collateralToken: address of the collateral token
Design Overview
By calling this function, the liquidator repays the borrower's loan if the borrower is liquidatable and also ends up buying the borrower's collateral at a 5% discounted price. This also resets the borrower's LTV back to what it was initially. The tokens that the liquidator uses to liquidate the borrower's account should be deposited in DeFiner.
By calling this function, the liquidator repays the borrower's loan if the borrower is liquidatable and also ends up buying the borrower's collateral at a 5% discounted price. This resets the borrower's LTV back to what it was initially. The tokens that the liquidator uses to liquidate the borrower's account should be deposited in DeFiner.
In order to be liquidatable, an account's LTV should be greater than 85%, since there is a high risk that this account will not repay it's debt once the LTV goes above 85%.
In order to be liquidatable, an account's LTV should be greater than 85%, since there is a high risk that this account will not repay it's debt once the LTV goes above 85%.
If all conditions are met, the liquidate function majorly executed the following operations:
Liquidator deposits collateral tokens equivalent to the payAmount calculated
Withdraws borrowed tokens equivalent to the repayAmount to the liquidator
Withdraws collateral tokens equivalent to the payAmount.
Repays the borrower's loan.
Please refer to the pseudocode given below for more details on how these calculations are performed.
Examples:
Terminology used:
CBB: Current borrow balance = principle + accrued interest
LDR: Liquidation Discount ratio: The discount ratio the liquidator will get when buying other's assets during the liquidation process.
CCV: Current Collateral Value = Collateral price * Collateral Amount
UAAL: User asset at Liquidation: The maximum collateral that can be liquidated or swapped.
BP: Borrow Power of borrower
ILTV: Initial LTV ratio of collateral token: 0.6 currently for most tokens
We have to make sure that:
Before liquidation:
(Assuming 1 DAI = 1 USDT = $1)
USDT Price drops by 65% after user deposits, setting LTV to 92%
Full liquidation
(Assuming 1 USDT = 1 DAI = $1)
Collateral price drops to 65% after User 1 borrows
User1:
Deposits: 100 USDT
Loans: 60 DAI
Collateral price drops to 65%, new collateral value = $65
LTV: 0.92, liquidatable
New borrow power = initial BP * %age price drop = 60 * 0.65 = 39
User2:
Deposits 200 DAI
It calls liquidate(user1, DAIAdress, USDTAddress)
Explanation
The maximum amount of DAI that user2 can transfer to user1 is 200 since it doesn't have any borrows.
Since DAI's price is 1, and 60 < 200, so user2 is able to pay the maximum value, which is 60 DAI. This is called full liquidation.
After Liquidation:
User 1:
Deposits: 5 USDT
Borrows: 0
User is not liquidatable
User 2:
Deposits: 95 USDT
2. Partial Liquidation
Before Liquidation:
User1:
Deposits: 100 USDT
Loans: 60 DAI
Collateral price drops to 65%, new collateral value = $65
LTV: 0.92, liquidatable
borrow power = initial BP * %age price drop = 60 * 0.65 = 39
User2:
Deposits 50 DAI
It calls liquidate(user1, DAIAdress, USDTAddress)
Explanation:
Here, UAAL is computed the same way as the previous example.
But here user2 only has 50DAI, which worth $50 and 50 < 60 so user2 can't be swapped to the maximum value UAAL. That way, user2 only pays 50 DAI and user1 will pay 50 / 0.95 = 52.6 USDC.
After liquidation
User 1:
Deposits: 100 - 50/0.95 = 47.4 USDT
Borrows: 60-50 = 10DAI
LTV: 10 / 47.4 = 0.21, not liquidatable
User 2:
Deposits: 50/0.95 = 52.6 USDC
Notice here although user2 doesn't fully liquidate user1, user1 is not liquidatable after liquidation. This is because there is a gap between the initial borrow LTV and the LTV to become liquidatable.
functionliquidate( address _liquidator, address _borrower, address _borrowedToken, address _collateralToken ) externalonlyAuthorizedreturns (uint256, uint256) {initCollateralFlag(_liquidator);initCollateralFlag(_borrower);require(isAccountLiquidatable(_borrower),"borrower is not liquidatable");// It is required that the liquidator doesn't exceed it's borrow power.// if liquidator has any borrows, then only check for borrowPower condition Account storage liquidateAcc = accounts[_liquidator];if (liquidateAcc.borrowBitmap >0) {require(getBorrowETH(_liquidator) <getBorrowPower(_liquidator),"No extra funds used for liquidation"); } LiquidationVars memory vars; ITokenRegistry tokenRegistry =globalConfig.tokenInfoRegistry();// _borrowedToken balance of the liquidator (deposit balance)vars.targetTokenBalance =getDepositBalanceCurrent(_borrowedToken, _liquidator);require(vars.targetTokenBalance >0,"amount must be > 0");// _borrowedToken balance of the borrower (borrow balance)vars.targetTokenBalanceBorrowed =getBorrowBalanceCurrent(_borrowedToken, _borrower);require(vars.targetTokenBalanceBorrowed >0,"borrower not own any debt token");// _borrowedToken available for liquidation uint256 borrowedTokenAmountForLiquidation =vars.targetTokenBalance.min(vars.targetTokenBalanceBorrowed);// _collateralToken balance of the borrower (deposit balance)vars.liquidateTokenBalance =getDepositBalanceCurrent(_collateralToken, _borrower); uint256 targetTokenDivisor; (, targetTokenDivisor,vars.targetTokenPrice,vars.borrowTokenLTV) =tokenRegistry.getTokenInfoFromAddress( _borrowedToken ); uint256 liquidateTokendivisor; uint256 collateralLTV; (, liquidateTokendivisor,vars.liquidateTokenPrice, collateralLTV) =tokenRegistry.getTokenInfoFromAddress( _collateralToken );// _collateralToken to purchase so that borrower's balance matches its borrow powervars.totalBorrow =getBorrowETH(_borrower);vars.borrowPower =getBorrowPower(_borrower);vars.liquidationDiscountRatio =globalConfig.liquidationDiscountRatio();vars.limitRepaymentValue =vars.totalBorrow.sub(vars.borrowPower).mul(100).div(vars.liquidationDiscountRatio.sub(collateralLTV) ); uint256 collateralTokenValueForLiquidation =vars.limitRepaymentValue.min(vars.liquidateTokenBalance.mul(vars.liquidateTokenPrice).div(liquidateTokendivisor) ); uint256 liquidationValue =collateralTokenValueForLiquidation.min(borrowedTokenAmountForLiquidation.mul(vars.targetTokenPrice).mul(100).div(targetTokenDivisor).div(vars.liquidationDiscountRatio ) );vars.repayAmount =liquidationValue.mul(vars.liquidationDiscountRatio).mul(targetTokenDivisor).div(100).div(vars.targetTokenPrice );vars.payAmount =vars.repayAmount.mul(liquidateTokendivisor).mul(100).mul(vars.targetTokenPrice);vars.payAmount =vars.payAmount.div(targetTokenDivisor).div(vars.liquidationDiscountRatio).div(vars.liquidateTokenPrice );deposit(_liquidator, _collateralToken,vars.payAmount);_withdrawLiquidate(_liquidator, _borrowedToken,vars.repayAmount);_withdrawLiquidate(_borrower, _collateralToken,vars.payAmount);repay(_borrower, _borrowedToken,vars.repayAmount);return (vars.repayAmount,vars.payAmount); }