Core Contracts

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

Incorrect Collateral Decimals in withdrawNFT() Function leads to deposited NFTs to get stuck in the protocol

Summary

The withdrawNFT() function in LendingPool.sol incorrectly compares collateral value (USD) with user debt (18-decimal precision). This mismatch in units leads to incorrect under collateralization checks, preventing users from withdrawing their NFTs even when they have sufficient collateral.

The issue arises because collateralValue and nftValue are represented in USD without decimals, whereas userDebt is in 18-decimal precision (DebtToken standard). This results in an incorrect comparison, marking users as undercollateralized when they are not.

Vulnerability Details

userDebt is in 18 decimals, calculated as:

uint256 userDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex);

rayMul() operates on 27-decimals * 18-decimals / 27-decimals, maintaining 18-dec precision.

collateralValue and nftValue are in raw USD (no decimals), retrieved via:

uint256 collateralValue = getUserCollateralValue(msg.sender);
uint256 nftValue = getNFTPrice(tokenId);

We can confirm from RAACHousePrices.sol that the prices are set in raw USD:

The values are not scaled, leading to a mismatch when compared to userDebt.
Incorrect collateral check:

if (collateralValue - nftValue < userDebt.percentMul(liquidationThreshold)) {
revert WithdrawalWouldLeaveUserUnderCollateralized();
}

Example: If collateralValue = $1,000,000 and userDebt = 1e18 (1 DebtToken), the user is incorrectly considered undercollateralized due to mismatched units.

Incorrect Behavior Flow

  1. User deposits NFT → Collateral value is stored in raw USD (150,000 instead of 150,000e18).

  2. User borrows → Debt is stored in 18-decimal precision (1e18 for 1 crvUSD).

  3. User attempts withdrawal:

    • Check compares raw USD (150,000) against 18-decimals (1e18), failing due to the large discrepancy.

    • Reverts WithdrawalWouldLeaveUserUnderCollateralized() even when collateral is sufficient.

Impact

Users will be permanently prevented from withdrawing NFTs, even with sufficient collateral.

Reduced Protocol Usability: Users will lose confidence in the borrowing system due to inability to withdraw their NFTs.

Tools Used

manual review

Recommendations

Scale collateralValue and nftValue to 18 Decimals.

Modify the calculation to match the precision of userDebt by multiplying collateral values by 1e18:

uint256 collateralValue = getUserCollateralValue(msg.sender) * 1e18;
uint256 nftValue = getNFTPrice(tokenId) * 1e18;

Now, both collateralValue and userDebt have the same precision.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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