In this section, we simulate a borrow->liquidation scenario:
Step 1: supply
Step 2: borrow max
Step 3: wait few blocks and let borrowed_balance > supplied_balance * collateral_factor -> leads to liquidation
Step 4: liquidate
Code:
Setup
Set Comptroller, borrowed token and borrowed cToken:
Comptroller public comptroller =Comptroller(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);IERC20 public tokenBorrow;CErc20 public cTokenBorrow;eventLog(string message, uint val);constructor(address_tokenBorrow,address_cTokenBorrow) { tokenBorrow =IERC20(_tokenBorrow); cTokenBorrow =CErc20(_cTokenBorrow);}
Close Factor
What is "close factor"? Quote from doc:
The percent, ranging from 0% to 100%, of a liquidatable account’s borrow that can be repaid in a single liquidate transaction. If a user has multiple borrowed assets, the closeFactor applies to any single borrowed asset, not the aggregated value of a user’s outstanding borrowing.
Close factor can be queried via comptroller.closeFactorMantissa():
// close factorfunctiongetCloseFactor() externalviewreturns (uint) {return comptroller.closeFactorMantissa();}
Liquidation Incentive
What is "liquidation incentive"? Quote from doc:
The additional collateral given to liquidators as an incentive to perform liquidation of underwater accounts. A portion of this is given to the collateral cToken reserves as determined by the seize share. The seize share is assumed to be 0 if the cToken does not have a protocolSeizeShareMantissa constant. For example, if the liquidation incentive is 1.08, and the collateral’s seize share is 1.028, liquidators receive an extra 5.2% of the borrower’s collateral for every unit they close, and the remaining 2.8% is added to the cToken’s reserves.
Liquidation incentive can be queried via comptroller.liquidationIncentiveMantissa():
To compute the amount of the collateral that we can liquidate, call comptroller .liquidateCalculateSeizeTokens():
// get amount of collateral to be liquidatedfunctiongetAmountToBeLiquidated(address_cTokenBorrowed,address_cTokenCollateral,uint_actualRepayAmount) externalviewreturns (uint) {/* * Get the exchange rate and calculate the number of collateral tokens to seize: * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral * seizeTokens = seizeAmount / exchangeRate * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) */ (uinterror,uint cTokenCollateralAmount) = comptroller .liquidateCalculateSeizeTokens( _cTokenBorrowed, _cTokenCollateral, _actualRepayAmount );require(error==0,"error");return cTokenCollateralAmount;}
Finally let's implement the high-level liquidate() function:
// liquidatefunctionliquidate(address_borrower,uint_repayAmount,address_cTokenCollateral) external {// Transfer the fund from user's wallet to this contract tokenBorrow.transferFrom(msg.sender,address(this), _repayAmount);// Approve the cTokenBorrow contract to spend this fund tokenBorrow.approve(address(cTokenBorrow), _repayAmount);// Call cTokenBorrow.liquidateBorrow() to liquidaterequire( cTokenBorrow.liquidateBorrow(_borrower, _repayAmount, _cTokenCollateral) ==0,"liquidate failed" );}