Core Contracts

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

Double scaling of debt amount in StabilityPool's liquidateBorrower function

Summary

The liquidateBorrower function in StabilityPool incorrectly scales the user's debt twice by multiplying an already-scaled debt amount by the normalized debt index.

Vulnerability Details

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/StabilityPool/StabilityPool.sol#L449

function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
uint256 userDebt = lendingPool.getUserDebt(userAddress);
// @audit userDebt is already multiplied by normalized debt from getUserDebt()
uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());

The getUserDebt() function in LendingPool already returns a debt amount that's scaled by the usage index:

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L579-L582

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

By multiplying this again with getNormalizedDebt(), the debt amount becomes incorrectly inflated by being scaled twice with the usage index.

Impact

High. The double scaling leads to:

  • Much higher debt amounts being calculated than actually owed

  • Liquidations requiring more crvUSD than necessary

  • Potential failed liquidations due to insufficient balance checks against inflated amounts

Recommended Mitigation

Remove the additional scaling and use the debt amount directly:

function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
uint256 userDebt = lendingPool.getUserDebt(userAddress);
// Remove the additional scaling
if (userDebt == 0) revert InvalidAmount();
uint256 crvUSDBalance = crvUSDToken.balanceOf(address(this));
if (crvUSDBalance < userDebt) revert InsufficientBalance();
...
}
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!