NORMAL BEHAVIOUR:
When a user deposits assets into the vault, the same address should both be credited internally (e.g., stakedAsset[address]) and receive the minted vault shares. Invariant: ownerOfShares == ownerOfStakedAsset.
PROBLEM :
deposit() stores the deposited amount under stakedAsset[receiver] but mints the ERC20 vault shares to msg.sender. This creates a divergence between who is credited in the contract state and who actually holds the shares, breaking assumptions used by joinEvent, withdraw, cancelParticipation and payout logic.
Likelihood:
Any caller can deliberately pass a different receiver than msg.sender — the mismatch is trivial to trigger.
No checks exist to enforce that receiver == msg.sender or that stakedAsset owner and minted share owner are the same.
Impact:
An attacker can deposit tokens for victimAddress (crediting stakedAsset[victim]) while minting shares to themselves — attacker gets economic rights (shares) while victim is credited for stake (can cause refund confusion).
joinEvent / winner eligibility uses stakedAsset and userToCountry while payouts use balanceOf (shares). Divergence allows attacker to withdraw or deny rightful payouts to others.
Refund logic (cancelParticipation) can refund to a user who does not own shares or assets, enabling theft or grief.
Ensure the same address receives both the internal credit and minted shares. Either remove receiver parameter altogether, or if depositing on behalf is intended, mint to receiver and record stakedAsset[receiver]. Additionally, use actualReceived when computing shares (to prevent other separate share-inflation issues).
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.