Normal behavior:
A user deposits tokens, receives vault shares, and calls joinEvent(countryId) once to register for their team.
After the event ends, the owner sets the winner, and the vault distributes funds proportionally to the shares of users who joined the winning team.
Specific issue:
joinEvent() doesn’t validate whether a user has already joined.
Each call pushes the same user again into usersAddress, increments numberOfParticipants, and adds to totalParticipantShares.
As a result, the same account can be counted multiple times and inflate its proportional rewards when _getWinnerShares() sums over usersAddress.
function joinEvent(uint256 countryId) public {
if (stakedAsset[msg.sender] == 0) { revert noDeposit(); }
if (countryId >= teams.length) { revert invalidCountry(); }
if (block.timestamp > eventStartDate) { revert eventStarted(); }
}
Likelihood:
Can be triggered by any user calling joinEvent() multiple times before eventStartDate.
No access control or boolean flag prevents rejoining.
Cheap and repeatable within the same transaction or block.
Impact:
Artificially inflates totalWinnerShares and totalParticipantShares, breaking reward fairness.
May cause gas bloat or DoS if usersAddress becomes excessively large.
Results in fund misallocation during payout calculation.
mapping(address => bool) private hasJoined;
function joinEvent(uint256 countryId) public {
if (stakedAsset[msg.sender] == 0) revert noDeposit();
if (countryId >= teams.length) revert invalidCountry();
if (block.timestamp > eventStartDate) revert eventStarted();
if (hasJoined[msg.sender]) {
}
userToCountry[msg.sender] = teams[countryId];
uint256 participantShares = balanceOf(msg.sender);
userSharesToCountry[msg.sender][countryId] = participantShares;
usersAddress.push(msg.sender);
numberOfParticipants++;
totalParticipantShares += participantShares;
hasJoined[msg.sender] = true;
emit joinedEvent(msg.sender, countryId);
}
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.