Core Contracts

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

Incorrect Debt Settlement Mechanism in finalizeLiquidation()

Summary

The finalizeLiquidation() function in LendingPool.sol is responsible for finalizing the liquidation process of undercollateralized users. It transfers the user’s NFTs to the StabilityPool and attempts to cover the user’s debt by pulling crvUSD (underlying asset) from the StabilityPool.

However, the StabilityPool does not hold or interact with crvUSD tokens, meaning the call to:

IERC20(reserve.reserveAssetAddress).safeTransferFrom(msg.sender, reserve.reserveRTokenAddress, amountScaled);

will always revert (msg.sender is the StabilityPool), as no crvUSD exists in the StabilityPool. This prevents any liquidation from being finalized, leaving bad debt in the system and undermining protocol security.

Vulnerability Details

Liquidation is initiated by marking the user as under liquidation.
After the grace period, finalizeLiquidation():

  1. Transfers the user's NFTs to the StabilityPool.

  2. Burns the user's debt tokens:

(uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) = IDebtToken(reserve.reserveDebtTokenAddress).burn(userAddress, userDebt, reserve.usageIndex);
  1. Attempts to cover the burned debt by pulling crvUSD from the StabilityPool:

IERC20(reserve.reserveAssetAddress).safeTransferFrom(msg.sender, reserve.reserveRTokenAddress, amountScaled);

StabilityPool does not hold crvUSD, meaning this transfer will always revert.
Liquidation never completes, leaving bad debt unaddressed.

Incorrect Behavior Flow

  1. User becomes undercollateralizedisUnderLiquidation[user] = true.

  2. After grace period, finalizeLiquidation() is called.

  3. NFTs are transferred to the StabilityPool.

  4. Debt tokens are burned.

  5. LendingPool tries to pull crvUSD from StabilityPool.

    • Fails because the StabilityPool never receives crvUSD.

  6. Transaction reverts.

  7. Liquidation is never finalized.

Impact

Undercollateralized users cannot be liquidated.

Bad debt remains on the protocol, leading to system insolvency.

Lenders and depositors face risks, as outstanding debt is never repaid.

Tools Used

manual review

Recommendations

In the liquidateBorrower() function in StabilityPool.sol call LendingPool.sol#withdraw(scaledUserDebt) to acquire the necessary crvUSD tokens.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

StabilityPool design flaw where liquidations will always fail as StabilityPool receives rTokens but LendingPool expects it to provide crvUSD

Support

FAQs

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