Core Contracts

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

There is no logic checking for RAACNFT price staleness before minting it

[M-05] There is no logic checking for RAACNFT price staleness before minting it

Summary

The RAACNFT::mint function allows users to mint House NFTs using ERC20 tokens, but it fails to verify if the house prices are current before accepting payment. While the RAACHousePrices contract maintains a lastUpdateTimestamp that updates when prices are refreshed, the mint function doesn't check this timestamp. This oversight could lead to users minting NFTs at potentially outdated prices, as there's no mechanism to ensure price freshness before accepting payment.

Vulnerability Details

  1. Price Verification Flow:

    • Retrieves price from RAACHousePrices contract

    • Checks for zero price and sufficient funds

    • Transfers tokens without price freshness verification

    • No timestamp validation before accepting payment

  2. Current Implementation:

function mint(uint256 _tokenId, uint256 _amount) public override {
uint256 price = raac_hp.tokenToHousePrice(_tokenId);
if (price == 0) {
revert RAACNFT__HousePrice();
}
if (price > _amount) {
revert RAACNFT__InsufficientFundsMint();
}
//@audit, there is no check whether the price is stall or not,
// transfer erc20 from user to contract - requires pre-approval from user
token.safeTransferFrom(msg.sender, address(this), _amount);
// mint tokenId to user
_safeMint(msg.sender, _tokenId);
// If user approved more than necessary, refund the difference
if (_amount > price) {
uint256 refundAmount = _amount - price;
token.safeTransfer(msg.sender, refundAmount);
}
emit NFTMinted(msg.sender, _tokenId, price);
}

Missing Price Freshness Check:

  • No validation of RAACHousePrices.lastUpdateTimestamp

  • No consideration of price update intervals

  • No mechanism to prevent minting with stale prices

Impact

The lack of price staleness checking creates several critical issues:

  1. Economic Security Risks:

    • Users may mint NFTs at outdated prices

    • Potential for significant financial losses

    • Market manipulation opportunities

    • Inconsistent pricing across transactions

  2. User Protection Issues:

    • No way to verify price freshness

    • Users may unknowingly overpay

    • No mechanism to prevent stale price usage

    • Inadequate protection against price manipulation

  3. System Integrity Problems:

    • Inconsistent pricing mechanism

    • Potential for price arbitrage

    • Lack of price validation

    • Incomplete security measures

  4. Market Impact:

    • Could lead to market inefficiencies

    • May affect NFT pricing dynamics

    • Could create unfair market advantages

    • Potentially destabilizes the market

Tools Used

Manual Review

Recommendations

Implement Price Freshness Validation:

function mint(uint256 _tokenId, uint256 _amount) public override {
uint256 price = raac_hp.tokenToHousePrice(_tokenId);
uint256 lastUpdate = raac_hp.tokenLastUpdateTimestamp(_tokenId);
// Check price freshness
require(
block.timestamp - lastUpdate <= MAX_PRICE_STALENESS,
"RAACNFT__PriceTooStale"
);
if (price == 0) {
revert RAACNFT__HousePrice();
}
if (price > _amount) {
revert RAACNFT__InsufficientFundsMint();
}
token.safeTransferFrom(msg.sender, address(this), _amount);
_safeMint(msg.sender, _tokenId);
if (_amount > price) {
uint256 refundAmount = _amount - price;
token.safeTransfer(msg.sender, refundAmount);
}
emit NFTMinted(msg.sender, _tokenId, price);
}

Implement Price Freshness Configuration:

uint256 public constant MAX_PRICE_STALENESS = 24 hours; // Configurable
function setMaxPriceStaleness(uint256 _newMaxStaleness) public onlyOwner {
require(_newMaxStaleness > 0, "RAACNFT__InvalidStaleness");
MAX_PRICE_STALENESS = _newMaxStaleness;
}

Add Price Freshness View Function:

function getPriceFreshness(uint256 _tokenId)
public
view
returns (
uint256 price,
uint256 lastUpdate,
bool isFresh
) {
price = raac_hp.tokenToHousePrice(_tokenId);
lastUpdate = raac_hp.tokenLastUpdateTimestamp(_tokenId);
isFresh = block.timestamp - lastUpdate <= MAX_PRICE_STALENESS;
return (price, lastUpdate, isFresh);
}
Updates

Lead Judging Commences

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

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 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

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.

Give us feedback!