Beatland Festival

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

`createMemorabiliaCollection()` creates dead-on-arrival collections – no way to toggle `isActive` later

Root + Impact

Description

Normal behaviour: The organiser can mint an empty memorabilia collection in “pre-launch” mode by passing activateNow = false, planning to open it later.
Issue: The struct field isActive is written once during creation and never exposed to any setter. A collection deployed as inactive can never be activated, so every call to redeemMemorabilia() reverts forever. This bricks the organiser’s inventory, blocks users from spending BEAT, and leaves project revenue/lore items inaccessible.

collections[collectionId] = MemorabiliaCollection({
name: name,
baseUri: baseUri,
priceInBeat: priceInBeat,
maxSupply: maxSupply,
currentItemId: 1, // Start item IDs at 1
isActive: activateNow // ← written once but never updated elsewhere
});

Risk

Likelihood:

  • Any organiser who deploys a collection with activateNow = false immediately hits the bug.

  • No user interaction is required; the revert is deterministic.

Impact:

  • Users are permanently unable to redeem memorabilia for that collection.

Proof of Concept

The PoC deploys a memorabilia collection with activateNow = false, then
immediately calls redeemMemorabilia(). Because isActive is never updatable,
the call reverts deterministically with “Collection not active”, proving that
the organiser has no way to launch the collection after creation.

function test_CollectionCannotBeActivated() public {
// 1. Deploy contracts and mint some BEAT to Alice …
vm.prank(organizer);
uint256 collectionId = festivalPass.createMemorabiliaCollection(
"2025 Limited Poster",
"ipfs://QmPoster/",
100 ether, // priceInBeat
1000, // maxSupply
false // <- keep inactive
);
// 2. user1 tries to redeem
vm.startPrank(user1);
beatToken.approve(address(festivalPass), type(uint256).max);
vm.expectRevert("Collection not active");
festivalPass.redeemMemorabilia(collectionId);
}

Recommended Mitigation

The diff introduces setCollectionActive(uint256 id, bool active) gated by
onlyOrganizer. This single function lets the organiser toggle isActive
post-deployment, unbricking pre-launch collections and allowing future pauses
for maintenance or sold-out status.

+ /// @notice Enable / disable a memorabilia collection
+ function setCollectionActive(uint256 collectionId, bool active)
+ external
+ onlyOrganizer
+ {
+ collections[collectionId].isActive = active;
+ }
Updates

Lead Judging Commences

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

createMemorabiliaCollection with isActive false for later usage - flow not properly implemented.

Low because an organizer can use it with active = true and organizer is trusted.

Support

FAQs

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