Feat: liquidation cap and grace period timelock in recovery mode#6
Feat: liquidation cap and grace period timelock in recovery mode#6
Conversation
jasm1n33
commented
Mar 14, 2025
- Liquidation collateral amount would cap with 1.1 * debt in recovery mode.
- After getting into the recovery mode, a grace period is applied.
- Any position with MCR < ICR < CCR cannot be liquidated in grace period.
StillFantastic
left a comment
There was a problem hiding this comment.
Also need to update the grace period timestamp if necessary after the following operations:
- Liquidation
- Redemption
- Closing trove
| singleLiquidation = _tryLiquidateWithCap( | ||
| troveManager, account, debtInStabPool, troveManagerValues.MCR, troveManagerValues.price | ||
| ); |
There was a problem hiding this comment.
- If the intention is to cap the liquidation reward to 10%, then I think 110% should be used here instead of MCR.
_tryLiquidateWithCaponly liquidates a trove when SP can cover the debt (no redistribution). Consider if it is the expected behavior.
src/core/facets/LiquidationFacet.sol
Outdated
|
|
||
| uint256 TCR = SatoshiMath._computeCR(entireSystemColl, entireSystemDebt); | ||
| if (TCR >= Config.CCR || ICR >= TCR) break; | ||
| _checkRecoveryModeGracePeriod(); |
There was a problem hiding this comment.
_checkRecoveryModeGracePeriod should not throw an error here.
src/core/facets/LiquidationFacet.sol
Outdated
| debtInStabPool -= singleLiquidation.debtToOffset; | ||
| } else if (ICR < troveManagerValues.MCR) { | ||
| singleLiquidation = _tryLiquidateWithCap( | ||
| troveManager, account, debtInStabPool, troveManagerValues.MCR, troveManagerValues.price |
src/core/facets/LiquidationFacet.sol
Outdated
| uint256 TCR = SatoshiMath._computeCR(entireSystemColl, entireSystemDebt); | ||
| if (TCR >= Config.CCR || ICR >= TCR) continue; | ||
| // check the recovery mode grace period | ||
| _checkRecoveryModeGracePeriod(); |
| s.lastGracePeriodStartTimestamp = Config.UNSET_TIMESTAMP; | ||
| s.recoveryModeGracePeriodDuration = Config.MINIMUM_GRACE_PERIOD; |
There was a problem hiding this comment.
Besides this, I suggest adding another initialization function dedicated to these two variables. Otherwise, the state could be problematic after upgrading, e.g., unable to start a grace period countdown if already in recovery mode.
I'm thinking about adding an initv2 with a reinitializer modifier. Also have to make sure to to call initv2 inside the original init as well so that it becomes compatible for new chain deployment.
src/core/facets/LiquidationFacet.sol
Outdated
| _checkRecoveryModeGracePeriod(); | ||
|
|
||
| singleLiquidation = _tryLiquidateWithCap( | ||
| _troveManager, account, debtInStabPool, troveManagerValues.MCR, troveManagerValues.price |
src/core/facets/LiquidationFacet.sol
Outdated
| _liquidateNormalMode(s, troveManager, account, debtInStabPool, troveManagerValues.sunsetting); | ||
| } else if (ICR < troveManagerValues.MCR) { | ||
| singleLiquidation = _tryLiquidateWithCap( | ||
| troveManager, account, debtInStabPool, troveManagerValues.MCR, troveManagerValues.price |
src/core/facets/LiquidationFacet.sol
Outdated
| // check the recovery mode grace period | ||
| _checkRecoveryModeGracePeriod(); | ||
| singleLiquidation = _tryLiquidateWithCap( | ||
| troveManager, account, debtInStabPool, troveManagerValues.MCR, troveManagerValues.price |
There was a problem hiding this comment.
- LiquidationFacet.sol Line 104, 127, 222, 252
- Should include collateral surplus
- totalCollGasCompensation should be multiplied by price
I found two additional problems during the review. Currently, when a Trove gets liquidated, the order of some operations is as follows:
- Update
surplusBalancesfor borrower - Send collateral to SP and decrease
totalActiveCollateral - In
finalizeLiquidation,totalActiveCollateralwould be reduced for the amount in (1.) - Send collateral compensation to liquidator
First, in step 2, _exitCollFromStrategy could be triggered when the value of totalActiveCollateral hasn't been fully updated yet. Second, in step 3, _exitColl should be called (similar to _redeemCloseTrove) to ensure there is enough collateral in the contract for users to claim.
These 2 problems should have no effect as long as the retain percentage is 0%. We can consider to fix in another PR.
src/core/TroveManager.sol
Outdated
| { | ||
| _requireCallerIsSatoshiXapp(); | ||
|
|
||
| IBorrowerOperationsFacet(satoshiXApp).syncGracePeriod(); |
There was a problem hiding this comment.
This should be called at the end of the function, because here the total system collateral has not been updated yet.
src/core/facets/LiquidationFacet.sol
Outdated
| ); | ||
| } | ||
|
|
||
| syncGracePeriod(); |
There was a problem hiding this comment.
syncGracePeriod will be called in the finalizeLiquidation
src/core/TroveManager.sol
Outdated
|
|
||
| totals.collateralToSendToRedeemer = totals.totalCollateralDrawn - totals.collateralFee; | ||
|
|
||
| IBorrowerOperationsFacet(satoshiXApp).syncGracePeriod(); |
There was a problem hiding this comment.
Should be call at the end of redeemCollateral
StillFantastic
left a comment
There was a problem hiding this comment.
TroveManager.solalso needs to be upgraded.- Does
DeploySetup.s.solneed to be updated as well?
| function run() public { | ||
| vm.startBroadcast(OWNER_PRIVATE_KEY); | ||
|
|
||
| _upgradeBOFaucet(); |
| _upgradeBOFaucet(); | ||
| _upgradeLiquidationFacet(); | ||
| _upgradeInitializer(); |
There was a problem hiding this comment.
We better bundle these 3 txs into 1 to avoid the case of other txs from users getting in the middle.
|
|
||
| // initV2 | ||
| Initializer initializer = Initializer(SATOSHI_X_APP_ADDRESS); | ||
| initializer.initV2(); |
There was a problem hiding this comment.
Already called in _upgradeInitializer?
| }); | ||
|
|
||
| ISatoshiXApp XAPP = ISatoshiXApp(SATOSHI_X_APP_ADDRESS); | ||
| XAPP.diamondCut(facetCuts, address(0), data); |
There was a problem hiding this comment.
Does not work for initialize data
| selectors[18] = IBorrowerOperationsFacet.forceResetTM.selector; | ||
|
|
||
| bytes4[] memory newSelectors = new bytes4[](1); | ||
| newSelectors[0] = IBorrowerOperationsFacet.syncGracePeriod.selector; |
There was a problem hiding this comment.
There is also a syncGracePeriod in the LiquidationFacet, it causes selector collision.
StillFantastic
left a comment
There was a problem hiding this comment.
I think it's good to upgrade now.
For the new deployment, DeploySetup.s.sol has not been updated yet.