Unchangeable MemorabiliaCollection.isActive
Prevents NFTs from Being Sold
Description
-
The createMemorabiliaCollection
function allows the organizer to set whether the NFT collection can be redeemed or not.
-
However, there is no way to change the isActive
property once the collection is created. If a collection is created with activateNow
set to false
, it becomes permanently unredeemable.
* @audit Below indicates that isActive is for setting the availability of redemption now
* @param isActive Whether redemption is currently enabled for this collection
*/
struct MemorabiliaCollection {
string name;
string baseUri;
uint256 priceInBeat;
uint256 maxSupply;
uint256 currentItemId;
@> bool isActive;
}
function createMemorabiliaCollection(
string memory name,
string memory baseUri,
uint256 priceInBeat,
uint256 maxSupply,
@> bool activateNow
) external onlyOrganizer returns (uint256) {
require(priceInBeat > 0, "Price must be greater than 0");
require(maxSupply > 0, "Supply must be at least 1");
require(bytes(name).length > 0, "Name required");
require(bytes(baseUri).length > 0, "URI required");
uint256 collectionId = nextCollectionId++;
collections[collectionId] = MemorabiliaCollection({
name: name,
baseUri: baseUri,
priceInBeat: priceInBeat,
maxSupply: maxSupply,
currentItemId: 1,
@> isActive: activateNow
});
emit CollectionCreated(collectionId, name, maxSupply);
return collectionId;
}
Risk
Likelihood:
Impact:
Proof of Concept
The following test shows the organizer creates a collection with an inactive state, and the redemption attempt is reverted. While this is the expected behavior given the isActive
state, there is no mechanism to activate the collection later, even if the initial setting was a mistake.
function test_Audit_UnchangeableIsActive() public {
vm.prank(organizer);
uint256 collectionId = festivalPass.createMemorabiliaCollection(
"Limited Shirts",
"ipfs://QmShirts",
50e18,
3,
false
);
vm.startPrank(address(festivalPass));
beatToken.mint(user1, 200e18);
vm.stopPrank();
vm.prank(user1);
vm.expectRevert("Collection not active");
festivalPass.redeemMemorabilia(collectionId);
}
Recommended Mitigation
Add a function to allow the organizer to toggle the isActive
status of a memorabilia collection.
+ event CollectionActiveUpdated(uint256 indexed collectionId, bool isActive);
+ function setMemorabiliaCollectionActive(uint256 _collectionId, bool _isActive) external onlyOrganizer {
+ MemorabiliaCollection storage collection = collections[_collectionId];
+ require(collection.priceInBeat > 0, "Collection does not exist");
+ collection.isActive = _isActive;
+ emit CollectionActiveUpdated(_collectionId, _isActive);
+ }