if (previousBidAmount == 0) {
requiredAmount = listing.minPrice;
require(msg.value > requiredAmount, "First bid must be > min price");
listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
} else {
requiredAmount = (previousBidAmount / 100) * (100 + S_MIN_BID_INCREMENT_PERCENTAGE);
require(msg.value >= requiredAmount, "Bid not high enough");
uint256 timeLeft = 0;
if (listing.auctionEnd > block.timestamp) {
timeLeft = listing.auctionEnd - block.timestamp;
}
if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
}
}
function test_auctionTimeExtensionUnfairness() public {
_mintNFT();
_listNFT();
vm.prank(BIDDER_1);
market.placeBid{value: MIN_PRICE}(TOKEN_ID);
uint256 firstAuctionEnd = market.getListing(TOKEN_ID).auctionEnd;
console.log("First auction end time:", firstAuctionEnd);
console.log("Current time:", block.timestamp);
console.log("Initial auction duration:", firstAuctionEnd - block.timestamp);
vm.warp(block.timestamp + 300);
uint256 secondBidAmount = MIN_PRICE * 120 / 100;
vm.prank(BIDDER_2);
market.placeBid{value: secondBidAmount}(TOKEN_ID);
uint256 secondAuctionEnd = market.getListing(TOKEN_ID).auctionEnd;
console.log("Second auction end time:", secondAuctionEnd);
console.log("Time after second bid:", block.timestamp);
console.log("Remaining time after second bid:", secondAuctionEnd - block.timestamp);
vm.warp(block.timestamp + 600);
uint256 thirdBidAmount = secondBidAmount * 120 / 100;
vm.prank(BIDDER_1);
market.placeBid{value: thirdBidAmount}(TOKEN_ID);
uint256 thirdAuctionEnd = market.getListing(TOKEN_ID).auctionEnd;
console.log("Third auction end time:", thirdAuctionEnd);
console.log("Time after third bid:", block.timestamp);
console.log("Remaining time after third bid:", thirdAuctionEnd - block.timestamp);
uint256 secondBidderDefenseTime = secondAuctionEnd - (block.timestamp - 600);
uint256 thirdBidderDefenseTime = thirdAuctionEnd - block.timestamp;
console.log("Second bidder defense time:", secondBidderDefenseTime);
console.log("Third bidder defense time:", thirdBidderDefenseTime);
assertTrue(secondBidderDefenseTime > thirdBidderDefenseTime,
"Earlier bidders should get longer defense time - this violates fairness!");
console.log("UNFAIRNESS PROVEN: Earlier bidders get longer total defense time");
}
if (previousBidAmount == 0) {
requiredAmount = listing.minPrice;
require(msg.value > requiredAmount, "First bid must be > min price");
listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
} else {
requiredAmount = (previousBidAmount / 100) * (100 + S_MIN_BID_INCREMENT_PERCENTAGE);
require(msg.value >= requiredAmount, "Bid not high enough");
uint256 timeLeft = 0;
if (listing.auctionEnd > block.timestamp) {
timeLeft = listing.auctionEnd - block.timestamp;
}
if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
// @Notice Whenever a bid is placed, the auction will be extended to the current time + 15 minutes.
listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
}
}