The intended behavior is that when an auction is finalized, the contract should:
Transfer the NFT to the winning bidder.
Deduct the marketplace fee.
Pay the seller their proceeds.
Only after successful settlement, clear out the stored bid data.
However, in the current implementation, the contract deletes the bids[tokenId] entry before performing the NFT transfer and payouts. This means that if the transfer reverts (for example, when the bidder is a contract that does not accept ERC721 tokens), the auction cannot be finalized and bid data is already lost. This leads to an inconsistent state where the highest bid has been erased but the NFT is not delivered.
Likelihood:
A bidder can be a smart contract that does not implement onERC721Received correctly or deliberately reverts on NFT transfers.
ERC721’s transferFrom will revert if address(this) is not the token owner (e.g., due to unexpected state changes).
Impact:
The auction enters an inconsistent state: the NFT remains locked in the marketplace, but the bid record is already deleted.
The auction cannot be correctly finalized, potentially leading to locked assets and disputes.
The test deploys a malicious bidder contract (RevertingReceiver) that always reverts on NFT transfers. When this contract places the highest bid and the auction ends, _executeSale deletes the bid record before attempting the NFT transfer. The transfer fails, leaving the auction in an inconsistent state: the NFT remains locked in the marketplace, but the bid data is already erased.
Move the deletion of bids[tokenId] to the end of the _executeSale function to ensure it only happens after a successful transfer and payouts.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.