[VEN-3321]: Liquidation Threshold and repay Improvements in Core Pool on BNB#604
[VEN-3321]: Liquidation Threshold and repay Improvements in Core Pool on BNB#604Debugger022 wants to merge 122 commits intodevelopfrom
Conversation
| * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow (deprecated) | ||
| */ | ||
| uint256 public closeFactorMantissa; | ||
| uint256 public __oldCloseFactorMantissaSlot; |
There was a problem hiding this comment.
we could make it private then
| function getHypotheticalHealthSnapshot( | ||
| address account, | ||
| VToken vTokenModify, | ||
| uint256 redeemTokens, | ||
| uint256 borrowAmount, | ||
| WeightFunction weightingStrategy | ||
| ) external view returns (uint256 err, ComptrollerLensInterface.AccountSnapshot memory snapshot) { |
There was a problem hiding this comment.
We should move this external function to the policy facets to reduce the contract size across the other facets. The internal version can remain here in the FacetBase so it's still accessible to all facets that need it.
contracts/Lens/ComptrollerLens.sol
Outdated
| vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt( | ||
| vars.oraclePrice, | ||
| // borrow effect: oraclePrice * borrowAmount | ||
| snapshot.borrows = mul_ScalarTruncateAddUInt( |
There was a problem hiding this comment.
Not required, but we could call this totalBorrows to keep the naming consistent with totalCollateral.
| */ | ||
| function _finalizeSnapshot(AccountSnapshot memory snapshot) internal pure { | ||
| if (snapshot.totalCollateral > 0) { | ||
| snapshot.liquidationThresholdAvg = div_(snapshot.weightedCollateral * 1e18, snapshot.totalCollateral); |
There was a problem hiding this comment.
This value could represent either the LT or the CF, depending on the WeightFunction being applied right?
| * @param liquidationIncentiveMantissa The liquidation incentive to apply | ||
| * @return (errorCode, number of vTokenCollateral tokens to be seized in a liquidation) | ||
| */ | ||
| function liquidateCalculateSeizeTokens( | ||
| address borrower, | ||
| address vTokenBorrowed, | ||
| address vTokenCollateral, | ||
| uint256 actualRepayAmount | ||
| uint256 actualRepayAmount, | ||
| uint256 liquidationIncentiveMantissa | ||
| ) external view returns (uint256, uint256) { |
There was a problem hiding this comment.
This liquidateCalculateSeizeTokens variant (without the borrower parameter) is intentionally kept for vBNB, since vBNB is non-upgradeable and cannot adopt the updated signature. I missed adding the explanatory comment earlier, please avoid making changes to this version and add a note similar to the one in the corresponding ComptrollerLens function.
| * @param newMaxLiquidationIncentive The new max liquidation incentive, scaled by 1e18 | ||
| * @return uint256 0=success, otherwise reverted | ||
| */ | ||
| function __setMarketMaxLiquidationIncentive( |
There was a problem hiding this comment.
Please move the internal functions below the external ones to keep the function
contracts/Utils/ErrorReporter.sol
Outdated
| SET_COLLATERAL_FACTOR_NO_EXISTS, | ||
| SET_COLLATERAL_FACTOR_VALIDATION, | ||
| SET_COLLATERAL_FACTOR_WITHOUT_PRICE, | ||
| SET_COLLATERAL_FACTOR_VALIDATION_LIQUIDATION_THRESHOLD, |
There was a problem hiding this comment.
We could add the new error code at the end of the enum to avoid breaking existing error-code ordering.
| function liquidateBorrow( | ||
| address borrower, | ||
| uint repayAmount, | ||
| VTokenInterface vTokenCollateral | ||
| VTokenInterface vTokenCollateral, | ||
| ComptrollerLensInterface.AccountSnapshot memory snapshot |
There was a problem hiding this comment.
Why should the liquidator provide the snapshot? They could pass an invalid or manipulated snapshot.
There was a problem hiding this comment.
The liquidateBorrow function can only be called from the liquidator contract by the liquidator. In this function, we calculate the snapshot internally, preventing the liquidator from passing an invalid snapshot.
| * @param snapshot The account snapshot of the borrower | ||
| * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. | ||
| */ | ||
| function liquidateBorrowInternal( |
There was a problem hiding this comment.
why do we need two variants of this function ?
There was a problem hiding this comment.
One variant keeps vBNB compatibility, while the other implements the dynamic liquidation logic.
| } | ||
|
|
||
| // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to | ||
| return liquidateBorrowFresh(msg.sender, borrower, repayAmount, vTokenCollateral, snapshot); |
There was a problem hiding this comment.
why do we need two variants of this function ?
There was a problem hiding this comment.
One variant keeps vBNB compatibility, while the other implements the dynamic liquidation logic.
| * @param actualRepayAmount The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens | ||
| * @return (errorCode, number of vTokenCollateral tokens to be seized in a liquidation) | ||
| */ | ||
| function liquidateVAICalculateSeizeTokens( |
There was a problem hiding this comment.
Since this calculation is only needed by the VAIController, why do we maintain two variants of liquidateVAICalculateSeizeTokens?
| * @param healthFactor The health factor of the borrower | ||
| * @return incentive The dynamic liquidation incentive for the borrower, scaled by 1e18 | ||
| */ | ||
| function getDynamicLiquidationIncentive( |
There was a problem hiding this comment.
This variant of getDynamicLiquidationIncentive (the one that doesn’t take the borrower address) is currently used only in the Liquidator contract, but we need to account for eMode groups there as well. The only cases where eMode can safely be ignored are vBNB and VAI.
contracts/Lens/ComptrollerLens.sol
Outdated
|
|
||
| // Read the balances and exchange rate from the vToken | ||
| (oErr, vars.vTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot( | ||
| (vars.err, vars.vTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot( |
There was a problem hiding this comment.
We can use the returned errorCode directly instead of storing it in vars. In that case, we can remove err from AccountSnapshotLocal entirely.
|
|
||
| /* We calculate the number of collateral tokens that will be seized */ | ||
| (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens( | ||
| borrower, |
There was a problem hiding this comment.
Please consider avoiding changes to legacy contracts so we can preserve their ABI.
f8786ac to
d1378e1
Compare
|
| address borrower, | ||
| address vToken | ||
| ) external view returns (uint256 incentive) { | ||
| uint256 effectiveLiquidationIncentive = this.getEffectiveLiquidationIncentive(borrower, vToken); |
There was a problem hiding this comment.
We can make getEffectiveLiquidationIncentive an public function so that we can avoid the use of this. We don't follow this pattern in our contracts. Use of this is more expensive.
|
|
||
| /* The borrower must have shortfall in order to be liquidatable */ | ||
| (Error err, , uint256 shortfall) = getHypotheticalAccountLiquidityInternal( | ||
| (uint256 err, ComptrollerLensInterface.AccountSnapshot memory snapshot) = this.getHypotheticalHealthSnapshot( |
There was a problem hiding this comment.
Same here we can avoid the use of this
| * @dev Calculates incentive based on provided health factor and liquidation threshold average, | ||
| * without reading borrower's account state from storage | ||
| * @param vToken The address of the vToken to be seized | ||
| * @param borrower The address of the borrower |
There was a problem hiding this comment.
We can expand the comment to include why the borrower parameter is needed
Description
This PR implements the following features:-
[VEN-3321] - Add the concept of Liquidation Threshold to the core Pool on BNB.
[VEN-3322] - Dynamic Liquidation Incentive and Close Factor in core Pool on BNB.
[VEN-3323] - Define maximum Liquidation Incentive per seized asset in the core pool on BNB.
[VEN-233] - Repay logic improvisation
This pull request introduces significant enhancements and refactoring to the contracts, primarily to support dynamic liquidation incentives, improved health factor calculations, and integration with a new
LiquidationManagercontract. The changes include new interfaces and storage structures, updated function signatures, and expanded account health and liquidation logic.Liquidation and Account Health Enhancements
ComptrollerInterface.solto support dynamic liquidation incentives and close factor, health factor calculations, and detailed account snapshots, including overloaded methods for seize token calculations.LiquidationManager Integration
LiquidationManagercontract in both storage and interface files, and exposed its address via the Comptroller contract.Storage and Contract Refactoring
__oldCloseFactorMantissaSlot,maxLiquidationIncentiveMantissa) and moved toComptrollerV19Storage. Updated all relevant contract inheritance to use the new storage version. Also, removed the oldsetCloseFactorandsetLiquidationIncentivefunctions as they will now be calculated dynamically using theliquidationManager.Diamond Facet and Functionality Updates
FacetBaseandMarketFacetto use new health snapshot logic and ComptrollerLens integration, including new internal and external functions for health factor calculations and liquidation seize token calculations.Repay logic Improvisation
repayAmountcalculation in theVTokenfrom this to this:vars.repayAmount = repayAmount >= vars.accountBorrows ? vars.accountBorrows : repayAmount;