Core Contracts

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

`StabilityPool.sol#liquidateBorrower()` does not interact.

Summary

StabilityPool.sol#liquidateBorrower() does not interact.

Vulnerability Details

StabilityPool.sol#liquidateBorrower() function is as follows.

function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
// 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();
...
emit BorrowerLiquidated(userAddress, scaledUserDebt);
}

The userDebt is value which has been already scaled up by usageIndex as follows.

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

But scaledUserDebt is calculated wrongly by scaling up with lendingPool.getNormalizedDebt() recursively.
This leads to bigger debt amount.

Impact

This vulnerability makes the protocol suffer from bigger funds than normal for liquidating.

Tools Used

Manual review

Recommendations

Modify StabilityPool.sol#liquidateBorrower() function as follows.

function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
// 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();
++ if (crvUSDBalance < userDebt) revert InsufficientBalance();
// Approve the LendingPool to transfer the debt amount
-- bool approveSuccess = crvUSDToken.approve(address(lendingPool), scaledUserDebt);
++ bool approveSuccess = crvUSDToken.approve(address(lendingPool), userDebt);
if (!approveSuccess) revert ApprovalFailed();
// Call finalizeLiquidation on LendingPool
lendingPool.finalizeLiquidation(userAddress);
-- emit BorrowerLiquidated(userAddress, scaledUserDebt);
++ emit BorrowerLiquidated(userAddress, userDebt);
}
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!