Omniscia Powercity Audit

TroveManager Manual Review Findings

TroveManager Manual Review Findings

TMR-01M: Incorrect Update of Aggregate Trackers in Recovery Mode

TypeSeverityLocation
Logical FaultTroveManager.sol:L602, L741

Description:

The TroveManager::_getTotalsFromLiquidateTrovesSequence_RecoveryMode and TroveManager::_getTotalFromBatchLiquidate_RecoveryMode functions will incorrectly update the system's aggregate collateral as the calculations will not factor in gas compensations nor surpluses.

Impact:

The system's recovery mode will assume that there is more collateral available to the system than in reality, causing it to improperly calculate incentives and thus aggravate the already-critical condition the system would be in recovery mode.

Example:

TroveManager.sol
704function _getTotalFromBatchLiquidate_RecoveryMode
705(
706 IActivePool _activePool,
707 IDefaultPool _defaultPool,
708 uint _price,
709 uint _LUSDInStabPool,
710 address[] memory _troveArray
711)
712 internal
713 returns(LiquidationTotals memory totals)
714{
715 LocalVariables_LiquidationSequence memory vars;
716 LiquidationValues memory singleLiquidation;
717
718 vars.remainingLUSDInStabPool = _LUSDInStabPool;
719 vars.backToNormalMode = false;
720 vars.entireSystemDebt = getEntireSystemDebt();
721 vars.entireSystemColl = getEntireSystemColl();
722
723 for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {
724 vars.user = _troveArray[vars.i];
725 // Skip non-active troves
726 if (Troves[vars.user].status != Status.active) { continue; }
727 vars.ICR = getCurrentICR(vars.user, _price);
728
729 if (!vars.backToNormalMode) {
730
731 // Skip this trove if ICR is greater than MCR and Stability Pool is empty
732 if (vars.ICR >= MCR && vars.remainingLUSDInStabPool == 0) { continue; }
733
734 uint TCR = LiquityMath._computeCR(vars.entireSystemColl, vars.entireSystemDebt, _price);
735
736 singleLiquidation = _liquidateRecoveryMode(_activePool, _defaultPool, vars.user, vars.ICR, vars.remainingLUSDInStabPool, TCR, _price);
737
738 // Update aggregate trackers
739 vars.remainingLUSDInStabPool = vars.remainingLUSDInStabPool.sub(singleLiquidation.debtToOffset);
740 vars.entireSystemDebt = vars.entireSystemDebt.sub(singleLiquidation.debtToOffset);
741 vars.entireSystemColl = vars.entireSystemColl.sub(singleLiquidation.collToSendToSP);
742
743 // Add liquidation values to their respective running totals
744 totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
745
746 vars.backToNormalMode = !_checkPotentialRecoveryMode(vars.entireSystemColl, vars.entireSystemDebt, _price);
747 }
748
749 else if (vars.backToNormalMode && vars.ICR < MCR) {
750 singleLiquidation = _liquidateNormalMode(_activePool, _defaultPool, vars.user, vars.remainingLUSDInStabPool);
751 vars.remainingLUSDInStabPool = vars.remainingLUSDInStabPool.sub(singleLiquidation.debtToOffset);
752
753 // Add liquidation values to their respective running totals
754 totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
755
756 } else continue; // In Normal Mode skip troves with ICR >= MCR
757 }
758}

Recommendation:

We advise them to be reverted to their original Liquity implementation as these adjustments can significantly affect the system's recovery mechanism, depicting it as having more collateral than actually available.

Alleviation (8bedd3b0df6387957e6b8f5d52507e776c1458b0):

The subtractions performed during recovery mode within the TroveManager have been corrected per the updated Liquity implementation and using the GHSA-xh2p-7p87-fhgh advisory as a guideline.

As such, we consider this exhibit properly alleviated.