Bid Beasts

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

Incorrect Event Emission During Bidding Process - AuctionSettled Event Emitted Prematurely in placeBid Function

Description

  • The BidBeastsNFTMarketPlace::AuctionSettled event should only be emitted when an auction is actually completed, which occurs in three legitimate scenarios: when a buyer purchases an NFT at the buy-now price, when an auction naturally ends and is settled via BidBeastsNFTMarketPlace::settleAuction function, or when a seller accepts the current highest bid via BidBeastsNFTMarketPlace::takeHighestBid function. In all these cases, the event is properly emitted from the BidBeastsNFTMarketPlace::_executeSale internal function after the NFT transfer and payment distribution have been completed.

  • The BidBeastsNFTMarketPlace::AuctionSettled event is incorrectly emitted on [line 143 in BidBeastsNFTMarketPlace.sol](https://github.com/CodeHawks-Contests/2025-09-bid-beasts/blob/449341c55a57d3f078d1250051a7b34625d3aa04/src/BidBeastsNFTMarketPlace.sol#L143) of the BidBeastsNFTMarketPlace::placeBid function during regular bidding operations, specifically when a bidder places a bid that exceeds the minimum bid increment. This creates a false signal that the auction has been completed when it is actually still ongoing, as the auction timer continues to run and other bidders can still place higher bids. The event is emitted with incorrect parameters (msg.sender as winner and msg.value as the final price) before any actual auction settlement logic has occurred.

function placeBid(uint256 tokenId) external payable isListed(tokenId) {
Listing storage listing = listings[tokenId];
address previousBidder = bids[tokenId].bidder;
uint256 previousBidAmount = bids[tokenId].amount;
require(listing.seller != msg.sender, "Seller cannot bid");
require(listing.auctionEnd == 0 || block.timestamp < listing.auctionEnd, "Auction ended");
// --- Buy Now Logic ---
if (listing.buyNowPrice > 0 && msg.value >= listing.buyNowPrice) {
uint256 salePrice = listing.buyNowPrice;
uint256 overpay = msg.value - salePrice;
bids[tokenId] = Bid(msg.sender, salePrice);
listing.listed = false;
if (previousBidder != address(0)) {
_payout(previousBidder, previousBidAmount);
}
_executeSale(tokenId);
if (overpay > 0) {
_payout(msg.sender, overpay);
}
return;
}
require(msg.sender != previousBidder, "Already highest bidder");
@> emit AuctionSettled(tokenId, msg.sender, listing.seller, msg.value);
// Regular Bidding Logic continued...
}

Risk

Likelihood:

  • This event emission occurs on every valid bid placement that exceeds the minimum bid increment percentage (5%), which happens frequently during active auctions as bidders compete for NFTs

Impact:

  • Frontend applications, monitoring systems, and event listeners will receive false BidBeastsNFTMarketPlace::AuctionSettled events during active bidding, leading to incorrect UI states, premature auction completion notifications, and potential automated system failures

  • Users monitoring auctions will receive misleading notifications suggesting auctions have ended when they are still ongoing, potentially causing them to stop bidding prematurely or miss opportunities to place higher bids

Proof of Concept

  1. Mint NFT

  2. List NFT

  3. Bidder 1 places first bid

  4. Set-up event test using vm.expectEmit and creating a BidBeastsNFTMarketPlace::AuctionSettled template.

  5. Place a second bid. If an event is emmitted in market.placeBid{value: secondBidAmount}(TOKEN_ID); that matches the event template then the vm.expectEmit test will not FAIL.

  6. Verify second bid is active and second bid executed

function test_AuctionSettledEventEmittedDuringBidding() public {
vm.startPrank(OWNER);
nft.mint(SELLER);
vm.stopPrank();
vm.startPrank(SELLER);
nft.approve(address(market), TOKEN_ID);
market.listNFT(TOKEN_ID, MIN_PRICE, BUY_NOW_PRICE);
vm.stopPrank();
uint256 firstBidAmount = MIN_PRICE + 0.1 ether;
vm.prank(BIDDER_1);
market.placeBid{value: firstBidAmount}(TOKEN_ID);
vm.stopPrank();
uint256 secondBidAmount = 1.2 ether;
vm.expectEmit(false, false, false, true, address(market));
emit AuctionSettled(
TOKEN_ID,
BIDDER_2,
SELLER,
secondBidAmount
);
vm.prank(BIDDER_2);
market.placeBid{value: secondBidAmount}(TOKEN_ID);
vm.stopPrank();
assertTrue(market.getListing(TOKEN_ID).listed, "Auction should NOT be settled (still listed)");
assertTrue(market.getListing(TOKEN_ID).auctionEnd > block.timestamp, "Auction should NOT be settled (has not ended)");
assertEq(market.getHighestBid(TOKEN_ID).bidder, BIDDER_2, "Bidder 2 should be the new highest bidder");
console.log("AuctionSettled event was INCORRECTLY emitted during active bidding!");
}

Recommended Mitigation

Removing the BidBeastsNFTMarketPlace::AuctionSettled event on line 143 eliminates the false event emissions while preserving all legitimate auction completion events.

function placeBid(uint256 tokenId) external payable isListed(tokenId) {
Listing storage listing = listings[tokenId];
address previousBidder = bids[tokenId].bidder;
uint256 previousBidAmount = bids[tokenId].amount;
require(listing.seller != msg.sender, "Seller cannot bid");
require(listing.auctionEnd == 0 || block.timestamp < listing.auctionEnd, "Auction ended");
// --- Buy Now Logic ---
if (listing.buyNowPrice > 0 && msg.value >= listing.buyNowPrice) {
uint256 salePrice = listing.buyNowPrice;
uint256 overpay = msg.value - salePrice;
bids[tokenId] = Bid(msg.sender, salePrice);
listing.listed = false;
if (previousBidder != address(0)) {
_payout(previousBidder, previousBidAmount);
}
_executeSale(tokenId);
if (overpay > 0) {
_payout(msg.sender, overpay);
}
return;
}
require(msg.sender != previousBidder, "Already highest bidder");
- emit AuctionSettled(tokenId, msg.sender, listing.seller, msg.value);
// Regular Bidding Logic continued...
}
Updates

Lead Judging Commences

cryptoghost Lead Judge 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeasts Marketplace: Incorrect Event Emission

placeBid emits AuctionSettled even though the auction hasn’t ended, causing misleading event logs.

Support

FAQs

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

Give us feedback!