Core Contracts

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

Double Normalization of User Debt in StabilityPool::liquidateBorrower

Summary

The liquidateBorrower function incorrectly calculates the scaledUserDebt by applying rayMul to userDebt, even though userDebt is already normalized when retrieved from the LendingPool. This results in double normalization, causing the debt amount to be artificially inflated, leading to excessive liquidations.

Vulnerability Details

LendingPool
/**
* @notice Gets the user's debt including interest
* @param userAddress The address of the user
* @return The user's total debt
*/
function getUserDebt(address userAddress) public view returns (uint256) {
UserData storage user = userData[userAddress];
return user.scaledDebtBalance.rayMul(reserve.usageIndex);
function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
_update();
// Get the user's debt from the LendingPool.
uint256 userDebt = lendingPool.getUserDebt(userAddress);
@> uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());
if (userDebt == 0) revert InvalidAmount();
uint256 crvUSDBalance = crvUSDToken.balanceOf(address(this));
if (crvUSDBalance < scaledUserDebt) revert InsufficientBalance();
// Approve the LendingPool to transfer the debt amount
bool approveSuccess = crvUSDToken.approve(address(lendingPool), scaledUserDebt);
if (!approveSuccess) revert ApprovalFailed();
// Update lending pool state before liquidation
lendingPool.updateState();
// Call finalizeLiquidation on LendingPool
lendingPool.finalizeLiquidation(userAddress);
emit BorrowerLiquidated(userAddress, scaledUserDebt);
}

userDebt is already normalized when retrieved from LendingPool.

  • Applying rayMul again with getNormalizedDebt() scales it a second time, inflating the debt amount.

  • The function then uses scaledUserDebt to approve transfers and emit liquidation events.

  • This leads to excessive liquidation requirements, making liquidations more expensive than they should be.

Impact

Users may lose more assets than necessary due to the overestimated debt amount.

Liquidators might receive excessive rewards

Tools Used

Manual Review

Recommendations

Use userDebt directly instead of scaledUserDebt.

Remove rayMul(userDebt, normalizedDebt), preventing double scaling.

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!