Missing Duplicate Guard in joinEvent causing inflated Winner Shares and Misallocation of Funds
Normal behavior:
The joinEvent() function is intended to allow each legitimate participant to join an active event exactly once. The event logic later aggregates all participant shares to determine winner allocations, where each participant’s contribution should be counted only once and proportionally to their deposit amount.
Specific issue:
The contract does not enforce uniqueness in event participation. The same user can call joinEvent() multiple times, causing their address to be added repeatedly to the participant list. When winner shares are calculated, all entries including duplicates are counted, allowing a user to artificially inflate their weighting in the final share distribution without depositing additional funds. This causes unfair allocations and potential financial loss.
Likelihood:
Duplicate entries occur whenever the contract is deployed in its current state, because joinEvent() does not restrict how many times a participant can join.
Attackers are fully incentivized to exploit this since it requires zero extra cost (multiple calls cost minimal gas and no additional tokens), making abuse extremely accessible and predictable.
Impact:
A malicious participant can manipulate reward distribution, receiving disproportionately high winner shares compared to their actual deposited amount.
Honest users experience direct financial loss, as their rightful share is diluted resulting in incorrect payout calculations, unfair settlements, and potentially severe trust/reputation damage to the platform or project.
Test scenario with 2 users betting on same winning team
User1 exploits vulnerability by calling joinEvent() twice
Tournament concludes, winner is set
Internal _getWinnerShares() reveals inflated total due to duplicates
Expected shares: user1Shares + user2Shares
Actual shares: (user1Shares × 2) + user2Shares
100% inflation for User1's contribution
Direct proof of broken payout calculations
To demonstrate the vulnerability, a test function getWinnerSharesForTest() was added to expose the internal _getWinnerShares() calculation. This allows direct observation of how duplicate entries inflate the winner share total.
The root cause of this issue is the lack of a mechanism preventing duplicate event participation. The fix should focus on ensuring each user can only join once per event, unless multiple entries are explicitly part of the design.
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.