Normal behavior: when a user deposits and then joins a country, the contract should record the user's current vault shares for that country and keep that country-level share record synchronized with any later deposits or burns so final winner distribution is correct.
Specific issue: the contract snapshots userSharesToCountry[msg.sender][countryId] at the time of joinEvent() but never updates that mapping on subsequent deposit() or _burn() calls. As a result the country-level snapshot becomes stale and does not reflect the user’s real holdings at payout time, causing incorrect reward distribution.
Likelihood:
A user deposits once, calls joinEvent(), and later deposits additional assets before the event ends — the stale snapshot will be present at settlement.
Users frequently top up or cancel participation before the event start (common UX), so the stale condition will occur in normal usage patterns.
Impact:
Final payout uses outdated per-country shares, causing winners to receive less than their fair share (denominator undervalued for some, overvalued for others), breaking fairness.
Accounting corruption persists on-chain (state variable userSharesToCountry remains wrong), undermining trust and potentially requiring manual off-chain reconciliation or contract migration.
Foundry test (PoC) that demonstrates the stale mapping: user deposits, joins, deposits again — balance increases but userSharesToCountry remains at old snapshot.
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.