-
Notifications
You must be signed in to change notification settings - Fork 197
[VEN-3321]: Liquidation Threshold and repay Improvements in Core Pool on BNB #604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could make it private then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not required, but we could call this totalBorrows to keep the naming consistent with totalCollateral.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| */ | ||
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This value could represent either the LT or the CF, depending on the WeightFunction being applied right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes !
| * @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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move the internal functions below the external ones to keep the function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add the new error code at the end of the enum to avoid breaking existing error-code ordering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| function liquidateBorrow( | ||
| address borrower, | ||
| uint repayAmount, | ||
| VTokenInterface vTokenCollateral | ||
| VTokenInterface vTokenCollateral, | ||
| ComptrollerLensInterface.AccountSnapshot memory snapshot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should the liquidator provide the snapshot? They could pass an invalid or manipulated snapshot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need two variants of this function ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need two variants of this function ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this calculation is only needed by the VAIController, why do we maintain two variants of liquidateVAICalculateSeizeTokens?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use the returned errorCode directly instead of storing it in vars. In that case, we can remove err from AccountSnapshotLocal entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| /* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please consider avoiding changes to legacy contracts so we can preserve their ABI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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;