NFT Dealers

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

Price Floor Bypass in `updatePrice`

Author Revealed upon completion

Root + Impact

Description

  • Normal Behavior: The protocol establishes a global minimum price via the MIN_PRICE constant (1 USDC) to prevent "dust" listings, prevent certain types of griefing, or ensure fee generation is meaningful. This floor should be enforced for any price modification.


  • ** Specific Issue:** While the list function correctly enforces require(_price >= MIN_PRICE), the updatePrice function only checks if the new price is greater than zero. This allows a seller to bypass the protocol's price floor by listing an NFT at 1 USDC and then immediately updating the price to a sub-minimum value (e.g., 1 wei of USDC).

function updatePrice(uint256 _listingId, uint32 _newPrice) external onlySeller(_listingId) {
Listing memory listing = s_listings[_listingId];
uint256 oldPrice = listing.price;
if (!listing.isActive) revert ListingNotActive(_listingId);
// Only checks if price > 0, not price >= MIN_PRICE
require(_newPrice > 0, "Price must be greater than 0");
s_listings[_listingId].price = _newPrice;
emit NFT_Dealers_Price_Updated(_listingId, oldPrice, _newPrice);
}

Risk

Likelihood: High

  • Reason 1: Any seller can call this function at any time for an active listing.

  • Reason 2: There is a direct contradiction in the validation logic between two public functions.

**Impact: Medium **

  • Impact 1: Protocol Policy Bypass. The MIN_PRICE requirement becomes an "opt-in" rather than a hard rule.

Proof of Concept

function test_dustPriceUpadte() public {
uint256 tokenId = 1;
uint32 initialPrice = 10e6;
uint32 newPrice = 1e4; // 0.01 USDC, which is below the minimum price but we want to see if it can be set
mintAndListNFTForTesting(tokenId, initialPrice);
address randomUser = makeAddr("randomUser");
deal(address(usdc), randomUser, 100e6);
// Before user could buy, price gets updated
vm.prank(userWithCash);
nftDealers.updatePrice(tokenId, newPrice);
}

Recommended Mitigation

function updatePrice(uint256 _listingId, uint32 _newPrice) external onlySeller(_listingId) {
// ...
+ require(_newPrice >= MIN_PRICE, "Price must be at least 1 USDC");
- require(_newPrice > 0, "Price must be greater than 0");
// ...
}

Support

FAQs

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

Give us feedback!