Core Contracts

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

The function getNFTPrice wrongly reverts when the price is at 0

Summary

The function getNFTPrice wrongly reverts when the price is at 0

Vulnerability Details

Observe the following code

/**
* @notice Gets the current price of an NFT from the oracle
* @param tokenId The token ID of the NFT
* @return The price of the NFT
*
* Checks if the price is stale
*/
function getNFTPrice(uint256 tokenId) public view returns (uint256) {
(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);
if (price == 0) revert InvalidNFTPrice();
return price;
}

The function getNFTPrice uses an oracle to fetch the price of the real estate NFT asset. Upon closer inspection you can see that the price is casted as an uint256. This can present a major issue as this NFT is representing a real world asset, not an ERC20 token.

This means that much like real estate, it is entirely pausible for the NFT to have a price at or even below 0. This can happen maliciously by taking out real world loans on the NFT or in a real estate market crash

[link](https://www.quickenloans.com/learn/negative-equity#:~:text=Negative equity is when your,home or missing mortgage payments.)

In such a case where the price of the NFT reaches 0, it will be impossible to liquidate the owner of that NFT shown here

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L556-L572

/**
* @notice Gets the total collateral value of a user
* @param userAddress The address of the user
* @return The total collateral value
*/
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;
}

Here we can see that the getNFTprice is called in the function getUserCollateralValue. This function is called during the function CalculateHealthfactor which is then called in the function initiateLiquidation

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L447-L463

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);
}

Impact

The protocol falsely assumes that the price of real estate will always remain positive and will not be able to liquidate NFT assets with negative or 0 value, and thus failing to liquidate bad debt.

Tools Used

Manual Review

Recommendations

allow the oracle to report negative and 0 prices so that negative value assets can be liquidated

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

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