Core Contracts

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

Permanent Token Lock in Auction Contract Due to Missing Withdrawal Mechanism

Summary

The Auction.sol contract lacks critical functionality to handle unsold ZENO tokens after an auction ends. When an auction concludes without selling all allocated tokens, the remaining ZENO tokens become permanently locked in the contract with no mechanism to withdraw or reallocate them.

Vulnerability Details

Let's examine how tokens become locked:

  1. The AuctionState state tracks remaining tokens but provides no withdrawal mechanism:

struct AuctionState {
uint256 endTime;
uint256 startTime;
uint256 startingPrice;
uint256 reservePrice;
uint256 totalAllocated;
uint256 totalRemaining; // @audit - These tokens can be locked forever
uint256 lastBidTime;
address lastBidder;
}
  1. Tokens can only be moved through the buy function:

function buy(uint256 amount) external whenActive {
require(amount <= state.totalRemaining, "Not enough ZENO remaining");
require(block.timestamp < state.endTime, "Auction ended");
uint256 price = getPrice();
uint256 total = amount * price;
state.totalRemaining -= amount;
// ... payment logic ...
}
  1. Once auction ends, tokens are frozen:

function checkAuctionEnded() external {
require(block.timestamp >= state.endTime, "Auction not ended");
emit AuctionEnded(getPrice());
// @audit - No mechanism to handle remaining tokens
// state.totalRemaining tokens are now locked forever
}

The locking occurs because:

  • Tokens can only move via buy()

  • buy() is blocked after endTime

  • No withdrawal function exists

  • No owner recovery mechanism

  • No way to start new auction with remaining tokens

Attack Path

  1. Auction starts with 1,000,000 ZENO tokens

  2. Only 600,000 tokens are sold

  3. Auction ends

  4. Remaining 400,000 tokens are permanently locked

  5. No function exists to recover these tokens

Impact

How the protocol gets affected?:

  1. Results in permanent loss of protocol assets (ZENO tokens)

  2. Affects every auction that doesn't sell out completely

  3. No recovery mechanism exists

  4. Impacts protocol's ability to efficiently allocate tokens

Tools Used

Manual review

Recommendations

Add withdrawal functionality for unsold tokens:

contract Auction {
function withdrawUnsoldTokens() external onlyOwner {
require(block.timestamp >= state.endTime, "Auction not ended");
require(state.totalRemaining > 0, "No tokens to withdraw");
uint256 remainingAmount = state.totalRemaining;
state.totalRemaining = 0;
// Transfer remaining tokens back to protocol treasury
ZENO.transfer(treasury, remainingAmount);
emit UnsoldTokensWithdrawn(remainingAmount);
}
}

The key focus should be on ensuring no tokens can become permanently locked in the contract, while maintaining the protocol's control over unsold tokens.

Updates

Lead Judging Commences

inallhonesty Lead Judge
5 months ago
inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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