Summary
If the owner wants to start the event again, previous participants will not be allowed to enter again.
Vulnerability Details
In MartenitsaEvent, owner starts an event. Users will join the event to become an temporary producer. In order to avoid repeatedly participating the event, _participants
is set to check whether msg.sender has participant the event. When we stop the event, _participants
is not deleted. It means when the owner wants to start another event, previous participants cannot participate again.
function joinEvent() external {
require(block.timestamp < eventEndTime, "Event has ended");
require(!_participants[msg.sender], "You have already joined the event");
require(!isProducer[msg.sender], "Producers are not allowed to participate");
require(_healthToken.balanceOf(msg.sender) >= healthTokenRequirement, "Insufficient HealthToken balance");
_participants[msg.sender] = true;
participants.push(msg.sender);
emit ParticipantJoined(msg.sender);
(bool success) = _healthToken.transferFrom(msg.sender, address(this), healthTokenRequirement);
require(success, "The transfer is not successful");
_addProducer(msg.sender);
}
function stopEvent() external onlyOwner {
require(block.timestamp >= eventEndTime, "Event is not ended");
for (uint256 i = 0; i < participants.length; i++) {
isProducer[participants[i]] = false;
}
}
Poc
function testSecondJoinEvent() public activeEvent eligibleForReward {
vm.startPrank(bob);
marketplace.collectReward();
healthToken.approve(address(martenitsaEvent), 10 ** 18);
martenitsaEvent.joinEvent();
vm.stopPrank();
vm.warp(2 days);
console.log("before stop event");
martenitsaEvent.stopEvent();
console.log("Test");
martenitsaEvent.startEvent(1 days);
vm.startPrank(bob);
healthToken.approve(address(martenitsaEvent), 10 ** 18);
martenitsaEvent.joinEvent();
}
The test case will be reverted because bob has already participant one event.
Impact
Previous participants cannot join another event.
Tools Used
Manual & Foundry
Recommendations
@@ -14,7 +14,7 @@ contract MartenitsaEvent is MartenitsaToken {
uint256 public healthTokenRequirement = 10 ** 18;
address[] public participants;
- mapping(address => bool) private _participants;
+ mapping(uint256 => mapping(address => bool)) private _participants;
event EventStarted(uint256 indexed startTime, uint256 indexed eventEndTime);
event ParticipantJoined(address indexed participant);
@@ -39,13 +39,15 @@ contract MartenitsaEvent is MartenitsaToken {
* @notice The event should be active and the caller should not be joined already.
* @notice Producers are not allowed to participate.
*/
function joinEvent() external {
require(block.timestamp < eventEndTime, "Event has ended");
- require(!_participants[msg.sender], "You have already joined the event");
+ require(!_participants[eventStartTime][msg.sender], "You have already joined the event");
require(!isProducer[msg.sender], "Producers are not allowed to participate");
require(_healthToken.balanceOf(msg.sender) >= healthTokenRequirement, "Insufficient HealthToken balance");
- _participants[msg.sender] = true;
+ _participants[eventStartTime][msg.sender] = true;
participants.push(msg.sender);
emit ParticipantJoined(msg.sender);
@@ -59,6 +61,8 @@ contract MartenitsaEvent is MartenitsaToken {
*/
function stopEvent() external onlyOwner {
require(block.timestamp >= eventEndTime, "Event is not ended");
for (uint256 i = 0; i < participants.length; i++) {
isProducer[participants[i]] = false;
}
@@ -68,7 +72,7 @@ contract MartenitsaEvent is MartenitsaToken {
* @notice Function to get information if a given address is a participant in the event.
*/
function getParticipant(address participant) external view returns (bool) {
- return _participants[participant];
+ return _participants[eventStartTime][participant];
}
/**