Bid Beasts

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

Missing AuctionSettled event emission on instant settlement (buyNowPrice reached) ,This means no AuctionSettled event is fired for instant-settled auctions, which can break off-chain indexers, dApps, or protocol features that depend on listening for

Root + Impact

Description

In the bidBeastMarketPlace:: placeBid() function, when a bidder submits a bid greater than or equal to bidBeastMarketPlace:: listing.buyNowPrice, the auction is immediately settled via bidBeastMarketPlace:: _executeSale(). However, the function performs a return statement before the bidBeastMarketPlace:: emit AuctionSettled(...) call, causing the event to never be emitted for instant-settled auctions.

This omission breaks the consistency of the event log:

Regular auctions emit AuctionSettled when they conclude.

Instant-settled auctions (via buyNowPrice) do not emit the event, making it harder for off-chain systems to track finalized auctions.

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");
// auctionEnd == 0 => no bids yet => allowed
// auctionEnd > 0 and block.timestamp >= auctionEnd => auction ended => block
require(listing.auctionEnd == 0 || block.timestamp < listing.auctionEnd, "Auction ended");
// --- Buy Now Logic ---
// i? if buyer pitched price higher that the buyPrice
// token is immediately transferred to the buyer and
// over pay trasnferred to the user back
// money is transferred to the seller
if (listing.buyNowPrice > 0 && msg.value >= listing.buyNowPrice) {
uint256 salePrice = listing.buyNowPrice;
uint256 overpay = msg.value - salePrice;
// EFFECT: set winner bid to exact sale price (keep consistent)
bids[tokenId] = Bid(msg.sender, salePrice);
listing.listed = false;
// q? previous bid details/struct should be deleted before creating new one
if (previousBidder != address(0)) {
_payout(previousBidder, previousBidAmount);
}
// NOTE: using internal finalize to do transfer/payouts. _executeSale will assume bids[tokenId] is the final winner.
_executeSale(tokenId);
// Refund overpay (if any) to buyer
if (overpay > 0) {
_payout(msg.sender, overpay);
}
return;
}
require(msg.sender != previousBidder, "Already highest bidder");
//q? why this emit , buying logic is still pending
// IF BUYING IS DONE OF IMMEDIAte price buy, then it will execute and return from there only
// only 1 logic is done , if buying price ? immediate sell price
// @audit , it is not making any sense here
emit AuctionSettled(tokenId, msg.sender, listing.seller, msg.value);
something something ....

Risk

Off-chain services (indexers, UIs, analytics, bots) depending on the AuctionSettled event will not detect instantly-settled auctions.

Protocol-integrated systems relying on this event for state updates, accounting, or triggers may malfunction.

Creates inconsistent protocol behavior, making instant settlements invisible in event logs.

Impact:

Off-chain services (indexers, UIs, analytics, bots) depending on the AuctionSettled event will not detect instantly-settled auctions.

Protocol-integrated systems relying on this event for state updates, accounting, or triggers may malfunction.

Creates inconsistent protocol behavior, making instant settlements invisible in event logs.

Proof of Concept

Alice lists an NFT with a buyNowPrice.

Bob submits a bid ≥ buyNowPrice.

The sale executes successfully (_executeSale() runs), and funds/NFT are transferred.

However, since the function returns early, the AuctionSettled event is not emitted.

Off-chain indexersdepending on emits wont get to know that whether the auction has happened or not .

Recommended Mitigation

Move the emit AuctionSettled(...) inside the if block handling the buyNowPrice case, before the return, to ensure consistent event emission for both instant-settled and regular auctions.

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);
}
// Emit before return
emit AuctionSettled(tokenId, msg.sender, listing.seller, salePrice);
return;
}
Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month 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.