Core Contracts

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

Unchecked Auction Time Parameters

Summary

After reviewing Auction.sol, I confirm a critical vulnerability exists where lack of time parameter validation can lead to permanent auction failure through division by zero.

Vulnerable Code

constructor(
address _zenoAddress,
address _usdcAddress,
address _businessAddress,
uint256 _startTime,
uint256 _endTime, // No validation against _startTime
uint256 _startingPrice,
uint256 _reservePrice,
uint256 _totalAllocated,
address _initialOwner
) Ownable(_initialOwner) {
// ... initialization ...
}
function getPrice() public view returns (uint256) {
// ... timing checks ...
// VULNERABILITY: Division by zero if endTime == startTime
return state.startingPrice - (
(state.startingPrice - state.reservePrice) *
(block.timestamp - state.startTime) /
(state.endTime - state.startTime) // <- Potential division by zero
);
}

Impact

  1. Permanent Auction Failure

// Attack Scenario
function brickAuction() {
// Deploy with equal times
new Auction(
zenoAddr,
usdcAddr,
businessAddr,
block.timestamp, // startTime
block.timestamp, // endTime = startTime
1e6, // startingPrice
1e6, // reservePrice
1000e18, // totalAllocated
owner
);
// All price calculations will revert
auction.getPrice(); // reverts with division by zero
auction.buy(1); // reverts, making auction unusable
}
  1. Economic Impact

  • Locked ZENO allocation

  • Lost auction opportunity

  • Required redeployment and gas costs

Proof of Concept

contract AuctionTest is Test {
function testDivisionByZero() public {
uint256 currentTime = block.timestamp;
vm.expectRevert();
Auction auction = new Auction(
address(zeno),
address(usdc),
address(business),
currentTime, // startTime
currentTime, // endTime
100e6, // startingPrice
90e6, // reservePrice
1000e18, // totalAllocated
address(this)
);
// Try to get price
auction.getPrice(); // Reverts with division by zero
}
}

Recommended Mitigation

contract Auction is IAuction, Ownable {
// Add minimum auction duration
uint256 public constant MIN_AUCTION_DURATION = 1 hours;
constructor(
address _zenoAddress,
address _usdcAddress,
address _businessAddress,
uint256 _startTime,
uint256 _endTime,
uint256 _startingPrice,
uint256 _reservePrice,
uint256 _totalAllocated,
address _initialOwner
) Ownable(_initialOwner) {
// Validate time parameters
if (_startTime >= _endTime) revert InvalidAuctionTime();
if (_endTime - _startTime < MIN_AUCTION_DURATION) revert AuctionTooShort();
if (_startTime < block.timestamp) revert StartTimeInPast();
// Additional price validations
if (_startingPrice < _reservePrice) revert InvalidPrices();
if (_totalAllocated == 0) revert ZeroAllocation();
// Initialize state
state = AuctionState({
startTime: _startTime,
endTime: _endTime,
startingPrice: _startingPrice,
reservePrice: _reservePrice,
totalAllocated: _totalAllocated,
totalRemaining: _totalAllocated,
lastBidTime: 0,
lastBidder: address(0)
});
emit AuctionInitialized(
_startTime,
_endTime,
_startingPrice,
_reservePrice,
_totalAllocated
);
}
}

Additional Recommendations

  1. Add validation events:

event AuctionInitialized(
uint256 startTime,
uint256 endTime,
uint256 startingPrice,
uint256 reservePrice,
uint256 totalAllocated
);
  1. Implement emergency pause:

bool public paused;
modifier whenNotPaused() {
require(!paused, "Auction: paused");
_;
}
  1. Add safety checks in price calculation:

function getPrice() public view returns (uint256) {
if (block.timestamp < state.startTime) return state.startingPrice;
if (block.timestamp >= state.endTime) return state.reservePrice;
uint256 timeElapsed = block.timestamp - state.startTime;
uint256 duration = state.endTime - state.startTime;
assert(duration > 0); // Sanity check
return state.startingPrice - (
(state.startingPrice - state.reservePrice) *
timeElapsed /
duration
);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 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.

Give us feedback!