Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Inconsistent Auction Extension Mechanism

Summary

A design inconsistency exists in the auction extension mechanism where first bids and subsequent bids use different logic to extend auction end times. First bids correctly extend from the current timestamp, while subsequent bids incorrectly extend from the original end time, resulting in unpredictable and unfair extension durations.

Description

The placeBid function implements two different extension mechanisms:

For First Bids (no previous bid):

listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;

This correctly sets the auction to end 15 minutes from the current time.

For Subsequent Bids (with previous bid):

if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
}

This adds 15 minutes to the original end time, not the current time.

Example Scenario

Given: S_AUCTION_EXTENSION_DURATION = 15 minutes

  1. First bid at 4:30 PM

    • Auction end set to: 4:45 PM (4:30 + 15 min) ✓ Correct

  2. Second bid at 4:35 PM (10 minutes before original end)

    • Time left: 10 minutes

    • Since 10 < 15, extension triggers

    • New auction end: 5:00 PM (4:45 + 15 min)

    • Actual time given to bidder: 25 minutes (4:35 → 5:00)

  3. Third bid at 4:55 PM (5 minutes before current end)

    • Time left: 5 minutes

    • Since 5 < 15, extension triggers

    • New auction end: 5:15 PM (5:00 + 15 min)

    • Actual time given to bidder: 20 minutes (4:55 → 5:15)

ProofOfConcept

function test_inconsistentAuctionExtension() public {
_mintNFT();
_listNFT();
console.log("=== First Bid: Extension from current time ===");
uint256 firstBidTime = block.timestamp;
vm.prank(BIDDER_1);
market.placeBid{value: MIN_PRICE + 1}(TOKEN_ID);
uint256 auctionEndAfterFirstBid = market.getListing(TOKEN_ID).auctionEnd;
uint256 extensionFromFirstBid = auctionEndAfterFirstBid - firstBidTime;
console.log("First bid at:", firstBidTime);
console.log("Auction end:", auctionEndAfterFirstBid);
console.log("Extension duration:", extensionFromFirstBid / 60, "minutes");
assertEq(extensionFromFirstBid, market.S_AUCTION_EXTENSION_DURATION());
console.log("\n=== Second Bid: 10 minutes before end ===");
vm.warp(auctionEndAfterFirstBid - 10 minutes);
uint256 secondBidTime = block.timestamp;
uint256 secondBidAmount = (MIN_PRICE + 1) * 105 / 100; // 5% increase
vm.prank(BIDDER_2);
market.placeBid{value: secondBidAmount}(TOKEN_ID);
uint256 auctionEndAfterSecondBid = market.getListing(TOKEN_ID).auctionEnd;
uint256 extensionFromSecondBid = auctionEndAfterSecondBid - secondBidTime;
console.log("Second bid at:", secondBidTime);
console.log("Auction end:", auctionEndAfterSecondBid);
console.log("Extension duration:", extensionFromSecondBid / 60, "minutes");
console.log("\n=== Inconsistency Detected ===");
console.log("First bid extension:", extensionFromFirstBid / 60, "minutes");
console.log("Second bid extension:", extensionFromSecondBid / 60, "minutes");
console.log("Difference:", (extensionFromSecondBid - extensionFromFirstBid) / 60, "minutes");
// Second bid gets MORE time than the extension duration
assertGt(extensionFromSecondBid, market.S_AUCTION_EXTENSION_DURATION());
}
Logs:
=== First Bid: Extension from current time ===
First bid at: 1
Auction end: 901
Extension duration: 15 minutes
=== Second Bid: 10 minutes before end ===
Second bid at: 301
Auction end: 1801
Extension duration: 25 minutes
=== Inconsistency Detected ===
First bid extension: 15 minutes
Second bid extension: 25 minutes
Difference: 10 minutes

Impact

  • Unfair Advantage: Later bidders receive significantly more time than the intended 15-minute extension window

  • Inconsistent Behavior: First bid logic differs from subsequent bid logic, creating unpredictable auction behavior

Mitigation

  • Make the subsequent bid extension logic consistent with the first bid logic by extending from the current timestamp

Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeast Marketplace: Auction Duration Miscalculation

BidBeast marketplace contains a flaw in its auction timing mechanism. This causes the contract to miscalculate the actual end time of an auction, resulting in auctions that either conclude prematurely or run longer than specified.

Support

FAQs

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