Platform: Code4rena
Start Date: 16/02/2023
Pot Size: $144,750 USDC
Total HM: 17
Participants: 154
Period: 19 days
Judge: Trust
Total Solo HM: 5
Id: 216
League: ETH
Rank: 15/154
Findings: 2
Award: $2,697.69
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: ltyu
Also found by: GalloDaSballo
2636.4342 USDC - $2,636.43
In redeemCollateral()
of RedemptionHelper.sol, the LUSD balanceOf
the redeemer is checked against the specific collateral recorded LUSD debt (both active and defaulted).
function redeemCollateral( address _collateral, address _redeemer, uint _LUSDamount, address _firstRedemptionHint, address _upperPartialRedemptionHint, address _lowerPartialRedemptionHint, uint _partialRedemptionHintNICR, uint _maxIterations, uint _maxFeePercentage ) external override { _requireCallerIsTroveManager(); _requireValidCollateralAddress(_collateral); RedemptionTotals memory totals; _requireValidMaxFeePercentage(_maxFeePercentage); _requireAfterBootstrapPeriod(); totals.price = priceFeed.fetchPrice(_collateral); ICollateralConfig collateralConfigCached = collateralConfig; totals.collDecimals = collateralConfigCached.getCollateralDecimals(_collateral); totals.collMCR = collateralConfigCached.getCollateralMCR(_collateral); _requireTCRoverMCR(_collateral, totals.price, totals.collDecimals, totals.collMCR); _requireAmountGreaterThanZero(_LUSDamount); _requireLUSDBalanceCoversRedemption(lusdToken, _redeemer, _LUSDamount); totals.totalLUSDSupplyAtStart = getEntireSystemDebt(_collateral); // Confirm redeemer's balance is less than total LUSD supply assert(lusdToken.balanceOf(_redeemer) <= totals.totalLUSDSupplyAtStart); ... }
This makes sense in a single collateral system such as Liquity, but is problematic in a multi-collateral one like Reserve. Since each collateral type tracks its own debt but mints the same LUSD token, LUSD supply (and thus balance) being less than the collateral debt is no longer an invariant. This can can result in:
Consider the cases when
- There are 2 Trove types (wBTC and wETH). - There is 10000 total LUSD debt in the wBTC Troves. - Stability Pool has 150 LUSD deposited i.e. full liquidity to offset debt. - There is 100 total LUSD debt in the wETH pool. - ETH prices crash and all Troves get liquidated except the last one.
A griefer can front-run the last Trove from redeeming by sending the user weth with the amount entireSystemDebt
+ 1.
In a similar case as above, any users that may borrow from multiple Troves types such that their LUSD balance is greater than the total collateral debt will be prevented from redeeming. However, this is not as problematic because they can just send their excess tokens out.
Manual Review
#0 - c4-judge
2023-03-09T19:04:55Z
trust1995 marked the issue as primary issue
#1 - c4-judge
2023-03-09T19:04:59Z
trust1995 marked the issue as satisfactory
#2 - tess3rac7
2023-03-15T02:06:50Z
dupe #549 leaving up to judge how to handle
#3 - c4-sponsor
2023-03-15T02:06:55Z
tess3rac7 requested judge review
#4 - c4-judge
2023-03-20T11:49:35Z
trust1995 marked the issue as duplicate of #549
#5 - c4-judge
2023-03-20T16:12:32Z
trust1995 marked the issue as selected for report