Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

[L-1] Block Timestamp Manipulation in Auction Settlement

[L-1]Block Timestamp Manipulation in Auction Settlement

Description

  • The settleAuction function is designed to finalize NFT auctions after their designated end time has passed

  • The function relies on block.timestamp for timing validation, which can be manipulated by miners within a ±30 second window, potentially allowing unfair auction settlements

function settleAuction(uint256 tokenId) external isListed(tokenId) {
Listing storage listing = listings[tokenId];
require(listing.auctionEnd > 0, "Auction has not started (no bids)");
@> require(block.timestamp >= listing.auctionEnd, "Auction has not ended");
require(
bids[tokenId].amount >= listing.minPrice,
"Highest bid did not meet min price"
);
_executeSale(tokenId);
}

Risk

Likelihood: LOW

  • Miners can manipulate block timestamps by ±30 seconds on each block creation

  • Time manipulation becomes profitable during high-value auction settlements

Impact: LOW

  • Miners can front-run legitimate settlement transactions near auction end times

  • Early settlements could prevent last-moment legitimate bids from being placed

Proof of Concept

contract TimestampManipulationTest {
function demonstrateManipulation() public {
// Current block
uint256 currentTime = block.timestamp; // e.g. 1000
// Auction end time
uint256 auctionEnd = currentTime + 30; // 1030
// Miner can set next block's timestamp to:
// Previous block timestamp + 30s = 1030
// Making auction immediately settleable
// Other bidders expecting to have 30 seconds left
// will be unable to place their bids
}
}

Recommended Mitigation

contract BidBeastsNFTMarket {
struct Listing {
address seller;
uint256 minPrice;
uint256 buyNowPrice;
- uint256 auctionEnd;
+ uint256 endBlock; // Use block number instead of timestamp
bool listed;
}
function settleAuction(uint256 tokenId) external isListed(tokenId) {
Listing storage listing = listings[tokenId];
require(listing.endBlock > 0, "Auction has not started (no bids)");
- require(block.timestamp >= listing.auctionEnd, "Auction has not ended");
+ require(block.number >= listing.endBlock, "Auction has not ended");
require(
bids[tokenId].amount >= listing.minPrice,
"Highest bid did not meet min price"
);
_executeSale(tokenId);
}
}
Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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