Users deposit assets and call joinEvent(countryId) to select a team from the teams[] array. The contract records their choice by storing the team name as a string in userToCountry[msg.sender]. When the owner calls setWinner(countryIndex), the winner variable is set to the current value of teams[countryIndex]. Withdrawal eligibility is verified by comparing these two strings using keccak256.
The issue arises because setCountry() can be called at any time by the owner, modifying teams[] after users have already joined. This causes userToCountry to hold an outdated team name, while winner reflects the updated name. The string comparison in withdraw() fails even when the user selected the correct team index.
Likelihood:
Owner updates team names after users join // occurs during typo fixes, branding changes, or localization
Any change to teams[] after joinEvent calls // happens in normal admin workflows
Impact:
Legitimate winners are permanently denied withdrawal // funds remain locked in vault
All prior participants lose access to rewards // even with correct prediction
A user joins when team[0] is "Brazil", then the owner updates it to "Brasil". After setWinner(0), the user’s stored country ("Brazil") no longer matches winner ("Brasil"), so withdraw() reverts with didNotWin() despite selecting the correct index. 1000 tokens remain permanently locked in the vault.
Stop using team names. Use team numbers (indexes)
This is owner action.
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.