Description: The _price parameter in list() and _newPrice in updatePrice() are typed as uint32, with a maximum value of 4,294,967,295 — equivalent to approximately 4,294 USDC (in 6-decimal USDC). However, the protocol defines fee thresholds of 10,000e6 and beyond, implying prices above 10,000 USDC are expected. The HIGH_FEE_BPS (5%) tier is therefore unreachable.
@> function list(uint256 _tokenId, uint32 _price) external onlyWhitelisted {
@> function updatePrice(uint256 _listingId, uint32 _newPrice) external onlySeller(_listingId) {
uint256 private constant MID_FEE_THRESHOLD = 10_000e6;
uint256 private constant HIGH_FEE_BPS = 500;
Impact: High-value NFTs cannot be listed or have their price updated above ~4,294 USDC. The progressive fee mechanism is partially broken.
Proof of Concept:
When a seller passes a price above uint32 max, it silently truncates to a wrong value with no revert or warning — the NFT ends up listed at a fraction of the intended price.
Run forge test --match-test test_poc_M3 -vvv to see the following output:
Logs:
Desired price (5000 USDC): 5000000000
Truncated uint32 price: 705032704
Actual listed price: 705032704
PoC Test Code
function test_poc_M3_uint32PriceCap() public {
vm.startPrank(owner);
nftDealers.revealCollection();
nftDealers.whitelistWallet(userWithCash);
vm.stopPrank();
vm.startPrank(userWithCash);
usdc.approve(address(nftDealers), 20e6);
nftDealers.mintNft();
vm.stopPrank();
uint256 desiredPrice = 5000e6;
uint32 truncatedPrice = uint32(desiredPrice);
console.log("Desired price (5000 USDC):", desiredPrice);
console.log("Truncated uint32 price: ", truncatedPrice);
vm.prank(userWithCash);
nftDealers.list(1, truncatedPrice);
(, uint32 listedPrice,,,) = nftDealers.s_listings(1);
console.log("Actual listed price: ", listedPrice);
assert(listedPrice != desiredPrice);
}
Recommended Mitigation: Change _price and _newPrice to uint256, and update the Listing.price field type accordingly.
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 onlyWhenRevealed {
-function updatePrice(uint256 _listingId, uint32 _newPrice) external onlySeller(_listingId) {
+function updatePrice(uint256 _listingId, uint256 _newPrice) external onlySeller(_listingId) {