The protocol defines three progressive fee tiers as its core economic mechanic: 1% for sale prices up to 1,000 USDC, 3% for prices up to 10,000 USDC, and 5% above 10,000 USDC. The Listing struct stores price as uint32, and list() accepts a uint32 _price parameter.
USDC has 6 decimals, so 1 USDC = 1,000,000 units. A uint32 holds a maximum value of 4,294,967,295 units, equivalent to approximately 4,294 USDC. The MID fee threshold is 10,000,000,000 units (10,000 USDC) and the HIGH threshold is anything above — both exceed uint32 maximum. Since the function parameter itself is uint32, any value above ~4,294 USDC cannot be passed by a caller. The 3% and 5% fee tiers are permanently dead code.
File: src/NFTDealers.sol
The root cause is a type mismatch between the fee threshold constants and the price storage type. The fee thresholds are defined as uint256 with values up to 10_000e6 (10 billion units), but Listing.price and both function parameters that write to it are declared as uint32, which saturates at 4,294,967,295 units (~4,294 USDC). The two halves of the fee system were designed independently without verifying that the price type can actually represent the values the thresholds require.
Likelihood:
Any user attempting to list an NFT for more than 4,294 USDC finds the call reverts at ABI encoding since the parameter type is uint32 and the value overflows.
The protocol operates at a perpetual 1% fee regardless of listing price for the entire lifetime of the deployment, as no value expressible in uint32 crosses either the MID or HIGH threshold.
Impact:
The 3% and 5% fee tiers are completely unreachable; the protocol collects only 1% fees on all transactions regardless of sale price, undermining its progressive fee design.
High-value NFT listings are hard-capped at approximately 4,294 USDC, severely limiting the protocol's utility for any valuable asset class.
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.