Premature AuctionSettled Emission Causing Frontend Delisting
Description
AuctionSettled event signals auction completion and NFT transfer to winner. In placeBid, it emits prematurely during regular bidding, misleading frontend to delist active auctions prematurely.
require(msg.sender != previousBidder, "Already highest bidder");
@>emit AuctionSettled(tokenId, msg.sender, listing.seller, msg.value);@>
uint256 requiredAmount;
Risk
Likelihood:
Impact:
-
Hides active NFTs from potential bidders, reducing participation.
-
Sellers lose visibility, potentially lowering final sale prices.
Proof of Concept
Lists NFT, places first bid expecting AuctionSettled event, checks listing still active and timer running to show wrong early signal.
event AuctionSettled(uint256 tokenId, address winner, address seller, uint256 price);
function testPrematureAuctionSettledEmission() public {
_mintNFT();
_listNFT();
vm.deal(BIDDER_1, MIN_PRICE + 0.01 ether);
vm.expectEmit(true, true, false, true);
emit BidBeastsNFTMarket.AuctionSettled(TOKEN_ID, BIDDER_1, SELLER, MIN_PRICE + 0.01 ether);
vm.prank(BIDDER_1);
market.placeBid{value: MIN_PRICE + 0.01 ether}(TOKEN_ID);
BidBeastsNFTMarket.Listing memory listing = market.getListing(TOKEN_ID);
assertTrue(listing.listed);
assertEq(listing.auctionEnd, block.timestamp + 15 minutes);
}
Recommended Mitigation
Cuts out early AuctionSettled emit in bidding; keeps only right BidPlaced event after update.
require(msg.sender != previousBidder, "Already highest bidder");
- emit AuctionSettled(tokenId, msg.sender, listing.seller, msg.value);
// --- Regular Bidding Logic ---
uint256 requiredAmount;
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);
}
}
// EFFECT: update highest bid
bids[tokenId] = Bid(msg.sender, msg.value);
if (previousBidder != address(0)) {
_payout(previousBidder, previousBidAmount);
}
emit BidPlaced(tokenId, msg.sender, msg.value);