Beatland Festival

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

Single-item memorabilia collections can never be redeemed and every collection silently loses its last item

Description

createMemorabiliaCollection() seeds every new collection with currentItemId = 1, whileredeemMemorabilia() allows minting only when the current counter is strictly less thanmaxSupply. For a 1-of-1 drop (maxSupply = 1) the condition 1 < 1 fails on the very first call, so redemption always reverts and the unique item can never be minted.

// creation
collections[collectionId] = MemorabiliaCollection({
…,
maxSupply: maxSupply,
currentItemId: 1, // ← starts at 1
isActive: activateNow
});
// redemption guard
require(
collection.currentItemId < collection.maxSupply,
"Collection sold out"
);

Result: functional DoS for any collection configured with maxSupply = 1.

Risk

Likelihood:

  • Organisers often release exclusive 1-of-1 items; every such collection fails deterministically.

Impact:

  • Functional DoS – users cannot mint the intended item; organiser reputation hit. No funds lost, but business logic broken.

  • Off-by-one shortage and reputation damage for every other collection (N-1 minted instead of N).

Proof of Concept

The PoC deploys a 1-of-1 collection, tops up a user with BEAT, and shows that
the first redemption reverts because of the off-by-one.

function test_OneOfOneFails() public {
// 1-of-1 collection
vm.prank(organizer);
uint256 cid = festivalPass.createMemorabiliaCollection(
"VIP Golden Ticket",
"ipfs://uri/",
50 ether,
1, // maxSupply = 1
true
);
vm.expectRevert("Collection sold out"); // off-by-one hit
vm.prank(user1);
festivalPass.redeemMemorabilia(cid);
}

Recommended Mitigation

Allow “<=” in the check. Diff for the simple comparator fix:

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

This lets the first (and only) item in a 1-unit collection be minted
successfully; subsequent calls revert once currentItemId exceeds maxSupply.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 2 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.