Normally, each participant should be recorded exactly once when they join the event; the contract should only count a user as a participant the first time they join and should not allow re-joining to double-count shares or participants.
The joinEvent function currently pushes msg.sender into usersAddress and increments numberOfParticipants / totalParticipantShares every time it's called, without checking whether the user already joined. This allows repeated joinEvent calls to create duplicate entries and inflate counters used in winner-share calculations.
Likelihood:
Occurs whenever a user calls joinEvent() more than once (either intentionally or by accident), because the function lacks any guard to prevent re-joining.
Occurs whenever the front-end or integrator doesn't block duplicate joins, since the smart contract itself does not enforce uniqueness.
Impact:
Impact 1: Duplicate entries inflate numberOfParticipants and totalParticipantShares, causing incorrect aggregate accounting and wrong proportions when computing winner payouts (e.g., _getWinnerShares() sums over usersAddress and will double-count).
Impact 2: A malicious participant can repeatedly call joinEvent to manipulate totalParticipantShares or totalWinnerShares calculations, degrading rewards for honest winners or breaking payout logic.
Observed effect: After demoJoinTwice, usersAddress contains the same address twice; numberOfParticipants increased by 2; totalParticipantShares increased by participantShares twice — causing downstream calculations to be incorrect.
Explanation: Ensure joinEvent only records a user once. Add a guard (hasJoined or check userToCountry) to prevent duplicate joins, and only increment participant counters and push to usersAddress on the first join. This preserves correct totals used in payout calculations.
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.