Core Contracts

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

All NFTs deposited after one is marked for liquidation are lost

Summary

The current implementation allows users to deposit NFTs while under liquidation. Additionally, the liquidation process does not recalculate the user's health factor before finalizing liquidation, potentially resulting in asset loss.

Vulnerability Details

1.NFT deposit:

Users can deposit NFTs as collateral.

>> user.nftTokenIds.push(tokenId);
>> user.depositedNFTs[tokenId] = true;
>> raacNFT.safeTransferFrom(msg.sender, address(this), tokenId);

2.Borrowing:

When borrowing, users can use this collateral and receive DebtTokens, which represent their debt.

// @audit-info NFTs as collateral
>> uint256 collateralValue = getUserCollateralValue(msg.sender);
---SNIP---
// Fetch user's total debt after borrowing
uint256 userTotalDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex) + amount;
// Ensure the user has enough collateral to cover the new debt
if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}
---SNIP---
// Mint DebtTokens to the user (scaled amount)
>> (bool isFirstMint, uint256 amountMinted, uint256 newTotalSupply) = IDebtToken(reserve.reserveDebtTokenAddress).mint(msg.sender, msg.sender, amount, reserve.usageIndex);
// Transfer borrowed amount to user
>> IRToken(reserve.reserveRTokenAddress).transferAsset(msg.sender, amount);

3.Liquidation Trigger:

If the value of the collateral (NFTs) decreases, the initiateLiquidation() function can be called.

>> uint256 healthFactor = calculateHealthFactor(userAddress);
if (healthFactor >= healthFactorLiquidationThreshold) revert HealthFactorTooLow();
>> isUnderLiquidation[userAddress] = true;

This function checks the user's health factor, and if it falls below a certain threshold (healthFactorLiquidationThreshold), the user is marked for liquidation by setting isUnderLiquidation[userAddress] = true.

4.Depositing more NFTs:

Currently, there is no check in place to prevent users from depositing additional NFTs while they are under liquidation. This means that even if a user is in a precarious financial situation, they can still deposit an NFT

5.Finalizing Liquidation:

When the finalizeLiquidation() function is called, it transfers all of the user's NFTs (including any that were recently deposited) to the Stability Pool.

isUnderLiquidation[userAddress] = false;
liquidationStartTime[userAddress] = 0;
// Transfer NFTs to Stability Pool
>> for (uint256 i = 0; i < user.nftTokenIds.length; i++) {
uint256 tokenId = user.nftTokenIds[i];
user.depositedNFTs[tokenId] = false;
raacNFT.transferFrom(address(this), stabilityPool, tokenId);
}
>> delete user.nftTokenIds;
// Burn DebtTokens from the user
>> (uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) = IDebtToken(reserve.reserveDebtTokenAddress).burn(userAddress, userDebt, reserve.usageIndex);

The user's NFT array (user.nftTokenIds) is cleared, all entries in user.depositedNFTs are set to false, and his debt tokens burned.

Impact

This can lead to a situation where they lose all their NFTs, including those they may have deposited recently, without any opportunity to rectify their financial situation.

Tools Used

Manual Review

Recommendations

  1. Prevent NFT deposits during Liquidation

Updates

Lead Judging Commences

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

Users can deposit NFTs using LendingPool::depositNFT while under liquidation, leading to unfair liquidation of NFTs that weren't part of original position

Support

FAQs

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