Skip to content

Commit

Permalink
Merge pull request #166 from liquity/remove_RM
Browse files Browse the repository at this point in the history
feat: Remove Recovery Mode
  • Loading branch information
bingen authored May 10, 2024
2 parents 963df88 + 7c1dbb3 commit 234f761
Show file tree
Hide file tree
Showing 21 changed files with 423 additions and 4,640 deletions.
65 changes: 30 additions & 35 deletions contracts/src/BorrowerOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe

// --- Checks ---

bool isRecoveryMode = _checkRecoveryMode(vars.price);
_requireNotBelowCriticalThreshold(vars.price);

_requireValidAnnualInterestRate(_annualInterestRate);

Expand All @@ -183,13 +183,9 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe

vars.ICR = LiquityMath._computeCR(_ETHAmount, vars.compositeDebt, vars.price);

if (isRecoveryMode) {
_requireICRisAboveCCR(vars.ICR);
} else {
_requireICRisAboveMCR(vars.ICR);
uint256 newTCR = _getNewTCRFromTroveChange(_ETHAmount, true, vars.compositeDebt, true, vars.price); // bools: coll increase, debt increase
_requireNewTCRisAboveCCR(newTCR);
}
_requireICRisAboveMCR(vars.ICR);
uint256 newTCR = _getNewTCRFromTroveChange(_ETHAmount, true, vars.compositeDebt, true, vars.price); // bools: coll increase, debt increase
_requireNewTCRisAboveCCR(newTCR);

// --- Effects & interactions ---

Expand Down Expand Up @@ -335,7 +331,7 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe

// --- Checks ---

bool isRecoveryMode = _checkRecoveryMode(vars.price);
bool isBelowCriticalThreshold = _checkBelowCriticalThreshold(vars.price);

if (_isCollIncrease) {
_requireNonZeroCollChange(_collChange);
Expand Down Expand Up @@ -368,7 +364,7 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe

// Check the adjustment satisfies all conditions for the current system mode
_requireValidAdjustmentInCurrentMode(
isRecoveryMode, _collChange, _isCollIncrease, _boldChange, _isDebtIncrease, vars
isBelowCriticalThreshold, _collChange, _isCollIncrease, _boldChange, _isDebtIncrease, vars
);

// --- Effects and interactions ---
Expand Down Expand Up @@ -434,7 +430,6 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe
_requireCallerIsBorrower(contractsCache.troveManager, _troveId);
_requireTroveIsOpen(contractsCache.troveManager, _troveId);
uint256 price = priceFeed.fetchPrice();
_requireNotInRecoveryMode(price);

uint256 initialWeightedRecordedTroveDebt = contractsCache.troveManager.getTroveWeightedRecordedDebt(_troveId);
uint256 initialRecordedTroveDebt = contractsCache.troveManager.getTroveDebt(_troveId);
Expand Down Expand Up @@ -690,43 +685,38 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe
require(_boldChange > 0, "BorrowerOps: Debt increase requires non-zero debtChange");
}

function _requireNotInRecoveryMode(uint256 _price) internal view {
require(!_checkRecoveryMode(_price), "BorrowerOps: Operation not permitted during Recovery Mode");
function _requireNotBelowCriticalThreshold(uint256 _price) internal view {
require(!_checkBelowCriticalThreshold(_price), "BorrowerOps: Operation not permitted below CT");
}

function _requireNoCollWithdrawal(uint256 _collWithdrawal, bool _isCollIncrease) internal pure {
require(
_collWithdrawal == 0 || _isCollIncrease, "BorrowerOps: Collateral withdrawal not permitted Recovery Mode"
);
function _requireNoBorrowing(bool _isDebtIncrease) internal pure {
require(!_isDebtIncrease, "BorrowerOps: Borrowing not permitted below CT");
}

function _requireValidAdjustmentInCurrentMode(
bool _isRecoveryMode,
bool _isBelowCriticalThreshold,
uint256 _collChange,
bool _isCollIncrease,
uint256 _boldChange,
bool _isDebtIncrease,
LocalVariables_adjustTrove memory _vars
) internal view {
/*
*In Recovery Mode, only allow:
* Below Critical Threshold, it is not permitted:
*
* - Pure collateral top-up
* - Pure debt repayment
* - Collateral top-up with debt repayment
* - A debt increase combined with a collateral top-up which makes the ICR >= 150% and improves the ICR (and by extension improves the TCR).
* - Borrowing
* - Collateral withdrawal except accompanied by a debt repayment of at least the same value
*
* In Normal Mode, ensure:
*
* - The new ICR is above MCR
* - The adjustment won't pull the TCR below CCR
*/
if (_isRecoveryMode) {
_requireNoCollWithdrawal(_collChange, _isCollIncrease);
if (_isDebtIncrease) {
_requireICRisAboveCCR(_vars.newICR);
_requireNewICRisAboveOldICR(_vars.newICR, _vars.oldICR);
}
if (_isBelowCriticalThreshold) {
_requireNoBorrowing(_isDebtIncrease);
_requireDebtRepaymentGeCollWithdrawal(
_collChange, _isCollIncrease, _boldChange, _isDebtIncrease, _vars.price
);
} else {
// if Normal Mode
_requireICRisAboveMCR(_vars.newICR);
Expand All @@ -740,12 +730,17 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe
require(_newICR >= MCR, "BorrowerOps: An operation that would result in ICR < MCR is not permitted");
}

function _requireICRisAboveCCR(uint256 _newICR) internal pure {
require(_newICR >= CCR, "BorrowerOps: Operation must leave trove with ICR >= CCR");
}

function _requireNewICRisAboveOldICR(uint256 _newICR, uint256 _oldICR) internal pure {
require(_newICR >= _oldICR, "BorrowerOps: Cannot decrease your Trove's ICR in Recovery Mode");
function _requireDebtRepaymentGeCollWithdrawal(
uint256 _collChange,
bool _isCollIncrease,
uint256 _boldChange,
bool _isDebtIncrease,
uint256 _price
) internal pure {
require(
_isCollIncrease || (!_isDebtIncrease && _boldChange >= _collChange * _price / DECIMAL_PRECISION),
"BorrowerOps: below CT, repayment must be >= coll withdrawal"
);
}

function _requireNewTCRisAboveCCR(uint256 _newTCR) internal pure {
Expand Down
4 changes: 2 additions & 2 deletions contracts/src/Dependencies/LiquityBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ contract LiquityBase is BaseMath, ILiquityBase {
// Minimum collateral ratio for individual troves
uint256 public constant MCR = 1100000000000000000; // 110%

// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.
// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, some borrowing operation restrictions are applied
uint256 public constant CCR = 1500000000000000000; // 150%

// Amount of Bold to be locked in gas pool on opening troves
Expand Down Expand Up @@ -85,7 +85,7 @@ contract LiquityBase is BaseMath, ILiquityBase {
return TCR;
}

function _checkRecoveryMode(uint256 _price) internal view returns (bool) {
function _checkBelowCriticalThreshold(uint256 _price) internal view returns (bool) {
uint256 TCR = _getTCR(_price);

return TCR < CCR;
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/Interfaces/ITroveManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ interface ITroveManager is IERC721, ILiquityBase {

function getTCR(uint256 _price) external view returns (uint256);

function checkRecoveryMode(uint256 _price) external view returns (bool);
function checkBelowCriticalThreshold(uint256 _price) external view returns (bool);

function checkTroveIsOpen(uint256 _troveId) external view returns (bool);

Expand Down
15 changes: 8 additions & 7 deletions contracts/src/StabilityPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -333,26 +333,27 @@ contract StabilityPool is LiquityBase, Ownable, CheckContract, IStabilityPool {
assert(getDepositorETHGain(msg.sender) == 0);
}

function _stashOrSendETHGains(address _depositor, uint256 _currentETHGain, uint256 _boldLoss, bool _doClaim) internal {
function _stashOrSendETHGains(address _depositor, uint256 _currentETHGain, uint256 _boldLoss, bool _doClaim)
internal
{
if (_doClaim) {
// Get the total gain (stashed + current), zero the stashed balance, send total gain to depositor
uint ETHToSend = _getTotalETHGainAndZeroStash(_depositor, _currentETHGain);
uint256 ETHToSend = _getTotalETHGainAndZeroStash(_depositor, _currentETHGain);

emit ETHGainWithdrawn(msg.sender, ETHToSend, _boldLoss); // Bold Loss required for event log
_sendETHGainToDepositor(ETHToSend);

} else {
// Just stash the current gain
stashedETH[_depositor] += _currentETHGain;
}
}

function _getTotalETHGainAndZeroStash(address _depositor, uint256 _currentETHGain) internal returns (uint256) {
uint256 stashedETHGain = stashedETH[_depositor];
uint256 stashedETHGain = stashedETH[_depositor];
uint256 totalETHGain = stashedETHGain + _currentETHGain;

// TODO: Gas - saves gas when stashedETHGain == 0?
if (stashedETHGain > 0) {stashedETH[_depositor] = 0;}
if (stashedETHGain > 0) stashedETH[_depositor] = 0;

return totalETHGain;
}
Expand All @@ -368,15 +369,15 @@ contract StabilityPool is LiquityBase, Ownable, CheckContract, IStabilityPool {

// If they have a deposit, update it and update its snapshots
if (initialDeposit > 0) {
currentETHGain = getDepositorETHGain(msg.sender); // Only active deposits can have a current ETH gain
currentETHGain = getDepositorETHGain(msg.sender); // Only active deposits can have a current ETH gain

uint256 compoundedBoldDeposit = getCompoundedBoldDeposit(msg.sender);
boldLoss = initialDeposit - compoundedBoldDeposit; // Needed only for event log

_updateDepositAndSnapshots(msg.sender, compoundedBoldDeposit);
}

uint256 ETHToSend = _getTotalETHGainAndZeroStash(msg.sender, currentETHGain);
uint256 ETHToSend = _getTotalETHGainAndZeroStash(msg.sender, currentETHGain);

_sendETHGainToDepositor(ETHToSend);
assert(getDepositorETHGain(msg.sender) == 0);
Expand Down
Loading

0 comments on commit 234f761

Please sign in to comment.