Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

Double Usage Index Multiplication in Stability Pool Liquidation Calculation

Summary

The liquidateBorrower function in the StabilityPool contract incorrectly scales user debt by multiplying it twice with the usage index, leading to inflated liquidation amounts.

Vulnerability Details

The bug occurs in two steps:

First multiplication in LendingPool.getUserDebt():

function getUserDebt(address userAddress) public view returns (uint256) {
UserData storage user = userData[userAddress];
return user.scaledDebtBalance.rayMul(reserve.usageIndex);
}

Second incorrect multiplication in StabilityPool.liquidateBorrower():

uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());
function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
uint256 userDebt = lendingPool.getUserDebt(userAddress); // First multiplication
uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt()); // Second multiplication
}

Impact

Incorrect Liquidation Condition

  • The contract checks if (crvUSDBalance < scaledUserDebt) revert InsufficientBalance();, but since scaledUserDebt is overestimated due to double multiplication, the required balance is higher than it should be.

  • This unnecessarily revert valid liquidations, preventing liquidation when it should be allowed.

  • At first the gap between the correct debt and inflated bebt is small, but as time goes by and usageIndex increment, the gap will grow larger and it will affect all liquidations.

Incorrect Event Emission

The function emits emit BorrowerLiquidated(userAddress, scaledUserDebt);, but since scaledUserDebt is inflated, external systems relying on this event will receive incorrect debt values.

  • This will affect off-chain analytics, monitoring services, or automated scripts that depend on accurate liquidation reporting.

  • For example, liquidators may miscalculate profits or losses, and historical liquidation data may become unreliable.

Tools Used

Manual Review

Recommendations

Remove the second multiplication in liquidateBorrower.

uint256 userDebt = lendingPool.getUserDebt(userAddress);
// remove this variable and use userDebt instead
uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

StabilityPool::liquidateBorrower double-scales debt by multiplying already-scaled userDebt with usage index again, causing liquidations to fail

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!