Core Contracts

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

Incorrect Collateralization Check in withdrawNFT Allows NFT Withdrawals Below Required Liquidation Threshold

Summary:

The withdrawNFT function in LendingPool implements a flawed collateralization check that incorrectly applies the liquidation threshold to the user's debt instead of calculating the required collateral value. This allows users to withdraw NFTs even when their remaining collateral would be insufficient to secure their outstanding debt.

Vulnerability Details:

In the withdrawNFT function:

function withdrawNFT(uint256 tokenId) external nonReentrant whenNotPaused {
// ... other checks ...
uint256 userDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex);
uint256 collateralValue = getUserCollateralValue(msg.sender);
uint256 nftValue = getNFTPrice(tokenId);
// Incorrect check
if (collateralValue - nftValue < userDebt.percentMul(liquidationThreshold)) {
revert WithdrawalWouldLeaveUserUnderCollateralized();
}
// ... rest of function
}

The vulnerability exists because:

  1. The check applies liquidationThreshold to debt (userDebt.percentMul(liquidationThreshold))

  2. Should instead calculate minimum required collateral (userDebt.percentDiv(liquidationThreshold))

Initial state:

  • userTotalDebt: 2000

  • collateralValue: 2500

  • nftValue: 700

  • liquidationThreshold: 75%

Current flawed check:

  • collateralValue - nftValue < (userDebt * liquidationThreshold)

  • 2500 - 700 < (2000 * 75%)

  • 1800 < 1500 (allows withdrawal)

Since 1800 is not less than 1500, the function allows withdrawal.

After withdrawal, remaining collateral would be insufficient:

  • collateralValue: 1800

  • userTotalDebt: 2000

This means the user’s remaining collateral is not enough to properly secure their debt.

Correct check should be:

  • Required collateral = userDebt / liquidationThreshold

  • Required collateral = 2000 / 0.75 = 2667

  • 1800 < 2667 (should revert)

Impact:

  • Users can withdraw NFTs leaving positions undercollateralized

  • Protocol's core safety mechanism is compromised

  • Potential for significant bad debt accumulation

  • Risk of protocol insolvency through systematic exploitation

Tools Used:

Manual code review

Recommendations:

  1. Implement correct collateralization check:

function withdrawNFT(uint256 tokenId) external nonReentrant whenNotPaused {
// ... existing checks ...
uint256 userDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex);
uint256 collateralValue = getUserCollateralValue(msg.sender);
uint256 nftValue = getNFTPrice(tokenId);
// Calculate minimum required collateral
uint256 requiredCollateral = userDebt.percentDiv(liquidationThreshold);
// Check if remaining collateral meets minimum requirement
if (collateralValue - nftValue < requiredCollateral) {
revert WithdrawalWouldLeaveUserUnderCollateralized();
}
// ... rest of function
}
Updates

Lead Judging Commences

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

LendingPool::borrow as well as withdrawNFT() reverses collateralization check, comparing collateral < debt*0.8 instead of collateral*0.8 > debt, allowing 125% borrowing vs intended 80%

Support

FAQs

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