Core Contracts

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

Incorrect Collateral Calculation in Liquidation Process

Summary

The initiateLiquidation function checks the user's health factor before initiating liquidation. However, the getUserCollateralValue function only considers NFTs as collateral, ignoring any deposits in the lending pool.

This leads to a scenario where a user with sufficient total collateral (NFTs + deposits) can still be liquidated because their deposits are not included in the calculation.

Vulnerability Details

function initiateLiquidation(address userAddress) external nonReentrant whenNotPaused {
if (isUnderLiquidation[userAddress]) revert UserAlreadyUnderLiquidation();
// update state
ReserveLibrary.updateReserveState(reserve, rateData);
UserData storage user = userData[userAddress];
uint256 healthFactor = calculateHealthFactor(userAddress);
if (healthFactor >= healthFactorLiquidationThreshold) revert HealthFactorTooLow();
isUnderLiquidation[userAddress] = true;
liquidationStartTime[userAddress] = block.timestamp;
emit LiquidationInitiated(msg.sender, userAddress);
}
function calculateHealthFactor(address userAddress) public view returns (uint256) {
uint256 collateralValue = getUserCollateralValue(userAddress);
uint256 userDebt = getUserDebt(userAddress);
if (userDebt < 1) return type(uint256).max;
uint256 collateralThreshold = collateralValue.percentMul(liquidationThreshold);
return (collateralThreshold * 1e18) / userDebt;
}
function getUserCollateralValue(address userAddress) public view returns (uint256) {
UserData storage user = userData[userAddress];
uint256 totalValue = 0;
for (uint256 i = 0; i < user.nftTokenIds.length; i++) {
uint256 tokenId = user.nftTokenIds[i];
uint256 price = getNFTPrice(tokenId);
totalValue += price;
}
return totalValue;
}

getUserCollateralValue() only sums up NFT values but ignores deposits made by the user in the lending pool.

When calculateHealthFactor() is called inside initiateLiquidation(), it gets an incomplete view of the user's collateral and might incorrectly determine that the user is undercollateralized.

This can trigger unnecessary liquidation for users who have enough deposits plus NFTs to cover their debt.

Impact

Users can be liquidated despite having sufficient total collateral.

Depositors may lose valuable NFTs unnecessarily.

POC

Step 1: User Deposits Assets

  • The user deposits $2,000 worth of stablecoins into the lending pool.

  • The user adds NFTs worth $10,000 as collateral.

  • The user borrows $5,000 worth of stablecoins from the protocol.

Step 2: Liquidation is Triggered

  • The market fluctuates slightly, causing NFT prices to drop to $3,000.

  • The user's total collateral is now:

    • NFTs: $3,000

    • Deposits: $2,000

    • Total Collateral: $5,000

  • However, getUserCollateralValue() only considers NFTs, so it calculates the user's collateral as just $3,000.

  • This results in a low health factor, even though the actual collateral (NFTs + deposits) is much higher.

  • The user is wrongly flagged for liquidation.

Step 3: Unjust Liquidation Occurs

  • The protocol sells the user's NFTs, even though they still had enough collateral in the lending pool to back their debt.

  • The user loses $3,000 worth of NFTs.

Tools Used

Manual Review

Recommendations

Modify getUserCollateralValue() to include deposits

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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