Normal Behavior: When a user calls the deposit() function, the stakedAsset[receiver] state variable should track the total amount of assets the user has deposited (minus participation fees). This mapping is used by cancelParticipation() to determine the refund amount.
Vulnerability: The deposit() function uses the assignment operator (=) instead of the accumulation operator (+=) at line 222, causing subsequent deposits to overwrite the previous stakedAsset[receiver] value rather than accumulating it. When a user deposits multiple times, only the most recent deposit amount is tracked, while shares are correctly minted for all deposits. This creates a critical mismatch between the user's actual share balance and their recorded staked amount.
Likelihood: HIGH
Reason 1: Users naturally deposit multiple times to increase their stake before the tournament starts, especially if they want to adjust their position based on odds or team performance during the deposit phase.
Reason 2: The protocol provides no warning or documentation that multiple deposits will cause fund loss, making this a silent failure that users cannot reasonably anticipate.
Impact: HIGH
Impact 1: Users lose their first deposit amount permanently when calling cancelParticipation(), receiving only the refund for their last deposit despite having shares for both deposits.
Impact 2: The stakedAsset mapping becomes desynchronized with actual share balances, breaking the protocol's accounting invariant that stakedAsset[user] should equal total deposited amount minus fees.
we get the output:
Change the assignment operator to accumulation operator:
Vault tracks only a single deposit slot per user and overwrites it on every call instead of accumulating the total.
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.