Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Off-by-One Error in redeemMemorabilia Prevents Full Supply from Being Minted

Root + Impact

Description

  • Each memorabilia collection is configured with a maxSupply. Users should be able to redeem items from that collection until the number of minted items reaches maxSupply.
    '''function redeemMemorabilia(uint256 collectionId) external { MemorabiliaCollection storage collection = collections[collectionId]; require(collection.priceInBeat > 0, "Collection does not exist"); require(collection.isActive, "Collection not active"); @> require(collection.currentItemId < collection.maxSupply, "Collection sold out"); @< // ← Off-by-one error'''

Risk

Likelihood:

  • The issue occurs every time a user attempts to redeem the final item in a collection.

  • All collections initialise with currentItemId = 1, which makes the off-by-one error inevitable and predictable.

Impact:

Only maxSupply - 1 items are ever minted, breaking user expectations.

  • For maxSupply == 1, redemptions are fully blocked.

  • NFT scarcity and distribution assumptions are violated, which may degrade platform credibility.

Proof of Concept

This test case demonstrates that even though a collection is configured to allow one item, that item can never be redeemed. currentItemId starts at 1, and the condition currentItemId < maxSupply fails when both equal 1. As a result, redemptions are blocked at the intended final supply.

function testOffByOneMintFail() public {
// Create a collection with a max supply of 1
festivalPass.createMemorabiliaCollection("Rare", "ipfs://uri", 1 ether, 1, true);
// First redemption attempt should succeed, but it fails
festivalPass.redeemMemorabilia(100); // Reverts with "Collection sold out"
}

Recommended Mitigation

Changing < to <= allows the redemption of the item where currentItemId == maxSupply, correctly enforcing the full supply limit. This off-by-one fix ensures collections deliver all intended items.

@@ function redeemMemorabilia(uint256 collectionId) external {
- require(collection.currentItemId < collection.maxSupply, "Collection sold out");
+ require(collection.currentItemId <= collection.maxSupply, "Collection sold out");
Updates

Lead Judging Commences

inallhonesty Lead Judge 26 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Off by one error in redeemMemorabilia

Support

FAQs

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