Bid Beasts

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

Premature AuctionSettled Emission During placeBid()

Root + Impact

Description

  • The BidBeastsNFTMarket contract emits an AuctionSettled event inside the placeBid() function, even though the auction has not ended and the NFT has not been transferred to the winner.

emit AuctionSettled(tokenId, msg.sender, listing.seller, msg.value);

Risk

Likelihood: High

  • Every time placeBid() is called, the contract always emits AuctionSettled prematurely.

  • No conditions or access control prevent this — any bidder can trigger it.

  • Easy to reproduce on any listed NFT, making it highly likely to occur in practice.

Impact: Medium

  • Misleads off-chain services, UIs, and analytics about the auction state.

  • Could cause confusion for users about winners and final prices.

  • Does not directly allow theft of funds (the NFT and payout logic in _executeSale() remain intact), but damages trust and can lead to incorrect front-end behavior.

Proof of Concept

The test fails on the current contract because AuctionSettled is emitted during placeBid(), proving the bug exists.

function test_placeBid_DoesNotEmitAuctionSettledPrematurely() public {
_mintNFT();
_listNFT();
vm.startPrank(BIDDER_1);
// Record logs for this transaction
vm.recordLogs();
// Place the first bid (must be > min price)
uint256 firstBid = MIN_PRICE + 0.01 ether;
market.placeBid{value: firstBid}(TOKEN_ID);
// Get recorded logs
Vm.Log[] memory entries = vm.getRecordedLogs();
// Check that AuctionSettled is not emitted
bytes32 auctionSettledSig = keccak256("AuctionSettled(uint256,address,address,uint256)");
for (uint i = 0; i < entries.length; i++) {
if (entries[i].topics[0] == auctionSettledSig) {
require(false, "AuctionSettled should NOT be emitted during placeBid");
}
}
vm.stopPrank();
}

Recommended Mitigation

Remove the emit AuctionSettled line from placeBid().

  • Only emit AuctionSettled inside _executeSale(), after the NFT transfer and payout logic completes.

-emit AuctionSettled(tokenId, msg.sender, listing.seller, msg.value);
// Keep AuctionSettled in _executeSale() only
function _executeSale(uint256 tokenId) internal {
+ emit AuctionSettled(tokenId, bid.bidder, listing.seller, bid.amount);
}
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.