Core Contracts

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

`Auction::checkAuctionEnded()` function fails to handle early auction completion when all ZENO tokens are sold, potentially blocking critical post-auction processes

Summary

The checkAuctionEnded() function only checks if the auction's end time has been reached, but fails to account for the case where all ZENO tokens have been sold before the end time, which is a valid auction completion condition according to the documentation.

Vulnerability Details

According to the ZENO Bond documentation, the auction can conclude in two ways:

  1. The total supply of ZENO is fully purchased

  2. The auction reaches its predetermined end time

However, the current implementation only checks for the second condition:

function checkAuctionEnded() external {
require(block.timestamp >= state.endTime, "Auction not ended");
emit AuctionEnded(getPrice());
}

This means that even if all ZENO tokens are sold (state.totalRemaining == 0), the function will still revert if called before endTime, preventing the proper signaling of auction completion.

Impact

This issue can:

  • Block critical post-auction processes that depend on the AuctionEnded event

  • Create confusion among participants about the auction's actual status

  • Delay or prevent the transition to post-auction phases

  • Emit the incorrect price in the AuctionEnded event

Tools Used

Manual review

Proof of Concept

Add the following test case to the test/Zeno/Integration.test.js file:

import { time } from "@nomicfoundation/hardhat-network-helpers";
// ... other code ...
it("fail to mark auction as ended even when all tokens are sold", async function () {
await time.setNextBlockTimestamp(auctionStartTime + 1);
await usdc.mint(addr1.address, ethers.parseUnits("10000000000", 6));
await usdc.connect(addr1).approve(auction1Address, ethers.parseUnits("10000000000", 6));
// Buy all available tokens
const beforeState = await auction1.state();
await auction1.connect(addr1).buy(beforeState.totalRemaining);
// Verify all tokens are sold
const afterState = await auction1.state();
expect(afterState.totalRemaining).to.equal(0);
// Try to finish auction - reverts even though all tokens are sold
await expect(
auction1.checkAuctionEnded()
).to.be.revertedWith("Auction not ended");
});

Recommendations

Update the checkAuctionEnded() function to account for both completion conditions:

function checkAuctionEnded() external {
- require(block.timestamp >= state.endTime, "Auction not ended");
+ require(block.timestamp >= state.endTime || state.totalRemaining == 0, "Auction not ended");
emit AuctionEnded(getPrice());
}
Updates

Lead Judging Commences

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

Auction.sol's checkAuctionEnded() only verifies time-based completion, ignoring sold-out condition, contradicting documentation and preventing early auction completion signaling

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

Auction.sol's checkAuctionEnded() only verifies time-based completion, ignoring sold-out condition, contradicting documentation and preventing early auction completion signaling

Support

FAQs

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