collectUsdcFromSelling() Authorizes Claims Using Mutable listing.seller, Blocking The Rightful Seller After ResaleThe intended flow is that after each successful sale, the account that just sold the NFT should be the one entitled to collect the sale proceeds for that sale.
In collectUsdcFromSelling(), access control is enforced with onlySeller(_listingId), which reads s_listings[_listingId].seller. However, listings are keyed by token ID and reused across future resales. After a buyer purchases an NFT and re-lists it, the same storage slot is reused for the new listing. This makes the authorization logic unreliable because entitlement to proceeds is derived from mutable listing state rather than from immutable sale records. In practice, this can leave the rightful seller unable to collect proceeds after a later resale, while another account associated with stale listing state can interfere with settlement.
Likelihood:
The issue occurs during normal secondary-market usage whenever the same token is sold and then re-listed, because the listing record for that token is overwritten and reused.
The protocol explicitly supports resale, so this stale-state path is part of the expected lifecycle rather than an edge case.
Impact:
The seller who should receive proceeds from a completed resale can be unable to claim them.
Settlement for secondary sales becomes unreliable because claim authorization is based on mutable listing storage instead of a dedicated sale payout record.
The following PoC can be used in test/NFTDealersTest.t.sol to demonstrate that the rightful seller cannot claim their proceeds after a resale:
Do not authorize claims from the mutable listing record. Instead, create dedicated sale-proceeds accounting at the moment of purchase and store the claimable amount in a double mapping keyed by listingId and seller address. This preserves each seller's entitlement even when the same NFT is re-listed and sold again before an earlier seller withdraws.
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.
The contest is complete and the rewards are being distributed.