Core Contracts

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

Inconsistent Timestamp Management in `RAACHousePrices` Leading to Stale or Incorrect Price Data

Summary

The RAACHousePrices contract contains a vulnerability where the lastUpdateTimestamp variable is updated globally instead of being linked to individual token (house) IDs. This design flaw makes it impossible to determine when a specific token's price was last updated. Additionally, the LendingPool::getNFTPrice function does not perform any staleness check, which could lead to outdated price data being used in transactions.

Vulnerability Details

The RAACHousePrices contract maintains a single lastUpdateTimestamp variable that is updated whenever any token price is modified:

uint256 public lastUpdateTimestamp;
function setHousePrice(uint256 _tokenId, uint256 _amount) external onlyOracle {
tokenToHousePrice[_tokenId] = _amount;
@> lastUpdateTimestamp = block.timestamp;
emit PriceUpdated(_tokenId, _amount);
}

When retrieving a token's price, the function does not provide a token-specific timestamp:

function getLatestPrice(uint256 _tokenId) external view returns (uint256, uint256) {
@> return (tokenToHousePrice[_tokenId], lastUpdateTimestamp);
}

Since lastUpdateTimestamp is updated every time any token price is modified, it does not provide accurate information about when a particular token's price was last changed. As a result, users and other smart contracts may incorrectly assume that a token's price is more recent than it actually is.

Furthermore, the LendingPool::getNFTPrice function does not verify if the retrieved 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;
}

Without a mechanism to determine whether the price is outdated, users may unknowingly rely on old price data, leading to financial losses.

Impact

This vulnerability introduces two major risks:

  1. It is impossible to track the last update timestamp of an individual token, leading to incorrect assumptions about data freshness.

  2. Users and other contracts may rely on stale price data due to the lack of a staleness check in getNFTPrice, which could result in incorrect pricing decisions and financial exposure.

Tools Used

Manual review.

Recommendations

1. Store Timestamps per Token ID

Instead of using a global lastUpdateTimestamp, store timestamps individually for each token ID:

mapping(uint256 => uint256) public lastUpdateTimestamps;
function setHousePrice(uint256 _tokenId, uint256 _amount) external onlyOracle {
tokenToHousePrice[_tokenId] = _amount;
lastUpdateTimestamps[_tokenId] = block.timestamp;
emit PriceUpdated(_tokenId, _amount);
}
function getLatestPrice(uint256 _tokenId) external view returns (uint256, uint256) {
return (tokenToHousePrice[_tokenId], lastUpdateTimestamps[_tokenId]);
}

2. Implement a Staleness Check

Modify getNFTPrice to verify whether the price is still valid before returning it:

uint256 constant MAX_PRICE_AGE = 1 days;
function getNFTPrice(uint256 tokenId) public view returns (uint256) {
(uint256 price, uint256 updateTime) = priceOracle.getLatestPrice(tokenId);
if (price == 0) revert InvalidNFTPrice();
if (block.timestamp - updateTime > MAX_PRICE_AGE) revert StalePrice();
return price;
}
Updates

Lead Judging Commences

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

RAACHousePrices uses a single global lastUpdateTimestamp for all NFTs instead of per-token tracking, causing misleading price freshness data

LendingPool::getNFTPrice or getPrimeRate doesn't validate timestamp staleness despite claiming to, allowing users to exploit outdated collateral values during price drops

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

RAACHousePrices uses a single global lastUpdateTimestamp for all NFTs instead of per-token tracking, causing misleading price freshness data

LendingPool::getNFTPrice or getPrimeRate doesn't validate timestamp staleness despite claiming to, allowing users to exploit outdated collateral values during price drops

Support

FAQs

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