NFT Dealers

First Flight #58
Beginner FriendlyFoundry
100 EXP
Submission Details
Impact: medium
Likelihood: high

Listing.price is uint32 — Maximum Listing Price Capped at ~4,294 USDC, Higher Fee Tiers Unreachable

Author Revealed upon completion

Root + Impact

Listing.price is uint32 — Maximum Listing Price Capped at ~4,294 USDC, Higher Fee Tiers Unreachable

Description

  • The marketplace defines three fee tiers: LOW (1%) for prices ≤ 1,000 USDC, MID (3%) for 1,001–10,000 USDC, and HIGH (5%) for > 10,000 USDC. These thresholds are stored as uint256.

Listing.price and the _price parameter in list() are declared as uint32, whose maximum value is 4,294,967,295. With USDC's 6 decimals, this caps the effective price at ~4,294.97 USDC, making the HIGH fee tier completely unreachable and the MID tier only partially usable.

struct Listing {
address seller;
@> uint32 price; // max ~4,294 USDC with 6 decimals
address nft;
uint256 tokenId;
bool isActive;
}
@> function list(uint256 _tokenId, uint32 _price) external onlyWhitelisted { ... }
// Fee thresholds are uint256 — never reachable by uint32 price
@> uint256 public constant LOW_FEE_THRESHOLD = 1_000e6; // 1,000 USDC
@> uint256 public constant MID_FEE_THRESHOLD = 10_000e6; // 10,000 USDC — UNREACHABLE

Risk

Likelihood:

  • Every listing above ~4,294 USDC is affected — the Solidity compiler silently truncates any value exceeding uint32 max when passed as a function argument

The external calculateFees() view function accepts uint256 and returns correct results, masking this bug during testing

Impact:

  • HIGH fee tier (5%) is permanently unreachable — protocol loses significant fee revenue on high-value sales

NFTs worth more than ~4,294 USDC cannot be listed at their fair market value

  • Any attempt to list at a price > 4,294 USDC either silently truncates or reverts, depending on compiler settings

Proof of Concept

function test_NM004_Uint32PriceTruncation() public {
// uint32 max = 4,294,967,295 — in USDC terms (6 decimals) = ~4294.97 USDC
uint32 maxPrice = type(uint32).max;
assertEq(maxPrice, 4_294_967_295);
// This is below MID_FEE_THRESHOLD (10,000e6 = 10,000,000,000)
assertLt(uint256(maxPrice), 10_000e6);
// HIGH fee tier requires price > 10,000 USDC — impossible with uint32
// MID fee tier (1,001-10,000 USDC) only partially reachable (up to ~4,294 USDC)
// External calculateFees accepts uint256 — masks the bug
uint256 highFees = nftDealers.calculateFees(15_000e6); // works fine
// But list() cannot accept 15_000e6 as uint32
}

Recommended Mitigation

struct Listing {
address seller;
- uint32 price;
+ uint256 price;
address nft;
uint256 tokenId;
bool isActive;
}
- function list(uint256 _tokenId, uint32 _price) external onlyWhitelisted {
+ function list(uint256 _tokenId, uint256 _price) external onlyWhitelisted {
- function updatePrice(uint256 _listingId, uint32 _newPrice) external onlySeller(_listingId) {
+ function updatePrice(uint256 _listingId, uint256 _newPrice) external onlySeller(_listingId) {

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!