Beatland Festival

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

Off-by-One Error in Memorabilia Supply Check Prevents Minting Final Item

Root + Impact

Description

  • Normal Behavior:
    When a memorabilia collection is created with a given maxSupply, users should be able to redeem up to maxSupply unique memorabilia NFTs from that collection.

    Issue:
    The supply check in redeemMemorabilia uses a strict less-than comparison (<), which prevents the last item from ever being minted. As a result, only maxSupply - 1 items can be redeemed, not the intended 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 bug: should be <=
// ...existing code...
}

Risk

Likelihood:

  • This will always occur when a user attempts to redeem the last memorabilia item in any collection.

Impact:

  • Users are unable to mint the full advertised supply.

  • This can cause economic and reputational harm to the project.

Proof of Concept

The following test demonstrates the bug: after creating a memorabilia collection with a maxSupply of 3, a user is able to redeem only 2 items. Attempting to redeem the third (final) item fails with "Collection sold out", proving that the last item cannot be minted due to the off-by-one error.

function testCannotRedeemLastMemorabiliaWithLessThanCheck() public {
// Create a collection with maxSupply = 3
vm.startPrank(owner);
uint256 collectionId = festival.createMemorabiliaCollection(
"Test",
"ipfs://test",
1 ether,
3,
true
);
vm.stopPrank();
// User redeems 2 memorabilia (should succeed)
vm.startPrank(user);
festival.redeemMemorabilia(collectionId);
festival.redeemMemorabilia(collectionId);
// Third redemption (should fail with "<" bug)
vm.expectRevert("Collection sold out");
festival.redeemMemorabilia(collectionId);
vm.stopPrank();
}

Recommended Mitigation

To fix the bug, update the memorabilia supply check in redeemMemorabilia from a strict less-than (<) comparison to a less-than-or-equal-to (<=) comparison. This change allows users to redeem up to the intended maximum supply for each collection.

- require(collection.currentItemId < collection.maxSupply, "Collection sold out");
+ require(collection.currentItemId <= collection.maxSupply, "Collection sold out");
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months 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.