Core Contracts

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

getPrice() Function Can Return Zero or Unexpected Values

Summary

The getPrice() function in the auction contract does not properly account for cases where integer rounding or misconfiguration may cause the price to return zero or unexpected values. This can result in users being able to buy tokens for free or auction dynamics behaving incorrectly.

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/zeno/Auction.sol#L69

Vulnerability Details

function getPrice() public view returns (uint256) {
if (block.timestamp < state.startTime) return state.startingPrice;
if (block.timestamp >= state.endTime) return state.reservePrice;
return state.startingPrice - (
(state.startingPrice - state.reservePrice) *
(block.timestamp - state.startTime) /
(state.endTime - state.startTime)
);
}

Integer Division Can Cause Rounding to Zero

  • Solidity rounds down in integer division, which may result in unexpected zero values in price calculation.

  • If startingPrice - reservePrice is small and time calculations do not distribute evenly, price adjustments may become zero, causing getPrice() to return startingPrice or lower values earlier than expected.

  • Misconfiguration Can Cause Unexpected Behavior

    • If startingPrice == reservePrice, price calculation is always zero, making the auction ineffective.

    • If reservePrice > startingPrice, subtraction results in negative overflow (though Solidity prevents negative unsigned integers, this will return an unintended price).

    • Impact

Tools Used

manual review

Recommendations

Modify the function to ensure the price never drops below reservePrice:

function getPrice() public view returns (uint256) {
if (block.timestamp < state.startTime) return state.startingPrice;
if (block.timestamp >= state.endTime) return state.reservePrice;
uint256 priceDrop = (state.startingPrice - state.reservePrice) *
(block.timestamp - state.startTime) /
(state.endTime - state.startTime);
return state.startingPrice > priceDrop
? state.startingPrice - priceDrop
: state.reservePrice; // Ensure price never falls below reserve
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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