The MartenitsaEvent contract currently from MartenitsaToken, which unnecessarily exposes token management functionalities. This leads to shared state variables that can result in synchronization and access control issues across the codebase. Such an inheritance structure contradicts the principle of separation of concerns between event management and token management.
MartenitsaEvent is supposed to contain event management functionalities, which is a completely separate concern from the NFT token management and producer management functionalities provided by MartenitsaToken.
However, MartenitsaEvent extends MartenitsaToken via inheritance, inappropriately merging two disparate concerns. This inheritance structure gives MartenitsaEvent unnecessary access to the internal mechanisms (e.g. NFT minting method) and state variables (e.g. producer lists) of MartenitsaToken.
This setup causes several problems, probably the biggest of which is that both contracts maintain separate and uncoordinated internal states regarding which addresses are recognized as producers. The test below demonstrates one such state inconcistency between the 2 contacts (one contract recognizes an address as producer, the other not).
State Confusion: both contracts will maintain separate and uncoordinated internal states regarding which addresses are recognized as producers. I.e. addresses denoted as producers by MartenitsaToken will not be recognized as producers by MartenitsaEvent and vice versa.
Access Control Issues: state confusion causes access control issues, e.g.
-- Addresses recognized as producers by MartenitsaToken are able to join an event via MartenitsaEvent::joinEvent, even though as producers they are not supposed to. This is because MartenitsaEvent::joinEvent only checks its own internal state regarding producer lists:
-- Addresses recognized as producers by MartenitsaEvent (during the duration of an event) are able to collect rewards via MartentisaMartkerplace::collectRewards even during an event, although they are not supposed to. This is because MartentisaMartkerplace::collectRewards checks only MartenitsaToken's internal state regarding producer lists:
-- Addresses recognized as producers by MartenitsaEvent (during the duration of an event) are not able to create Martinetsa NFTs via MartinetsaToken::createMartinetsa, only via MartinetsaEvent::createMartinetsa which creates further state inconsistencies and accounting issues.
Function Exposure: MartenitsaEvent gains access to NFT-specific functions that are irrelevant to its primary role of managing events. This not only adds unnecessary complexity to MartenitsaEvent but also increases the attack surface of the codebase.
Manual review, Foundry.
MartenitsaEvent should not inherit from MartenitsaToken. Instead, it should contain an instance of MartenitsaToken to allow explicit and controlled use of its functionalities. This change will limit MartenitsaEvent to necessary interactions with MartenitsaToken and prevent inadvertent exposure of token management features.
Consider the following modifications as a rough starting point for a fix. Note that the bug at hand is severe and fixing it requires rethinking the protocol design, thorough testing, and preferably another round of audit.
Note that a better, more elegant and simpler fix might be the following:
remove the inheritance
do not manipulate the state variables of MartenitsaMarketplace to grant producer privilages to event participants for the duration of an event, but instead:
-- completely separate participant and producer statuses, and use only the participants array and _participants mapping for participants (and producer state variables only for real producers set by MartenitsaMarketplace),
-- in all 5 contracts, whereever an action is gated for producers or non-producers, add a similar gate to the participants by referencing the particpants state variable of MartenitsaEvent. (For this to work, importing MartenitsaEventwill be needed in all affected contracts.)
This solution completely separates the handling of producers from participants. As such, it has the additional benefit that whenever an event ends, and the producer-like privilages of participants have to be revoked, it is enough to simply reset the participants array and _participants mapping.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.