Tickets can be entered after prizes for current round have partially been distributed
mediumLines of code
Vulnerability details
Impact
The ThrusterTreasure contract is designed to facilitate a lottery game where users can enter tickets to win prizes based on entropy. The contract includes mechanisms for entering tickets into rounds (enterTickets()), setting prizes for rounds (setPrize()), and claiming prizes (claimPrizesForRound()). A critical aspect of the game's integrity is ensuring each ticket has an equal chance to win every prize.
However, there is a significant flaw in enterTickets(). The function checks if winning tickets for the prize index 0 have been set by verifying that winningTickets[currentRound_][0].length == 0. This check is intended to prevent users from entering tickets after prizes have begun to be distributed, but it does not account for prizes with higher indices that may already have been distributed. As a result, users can still enter tickets after some prizes have been distributed, but these late-entered tickets will not have a chance to win the already distributed prizes:
ThrusterTreasure.sol#L83-L96
solidityfunction enterTickets(uint256 _amount, bytes32[] calldata _proof) external { ... require(winningTickets[currentRound_][0].length == 0, "ET"); ... }
Proof of Concept
- The contract owner sets up a new round with multiple prizes.
- User A enters tickets early in the round.
- The contract owner distributes prizes for index 1.
- User B enters tickets into the round.
- Due to the flawed logic in
enterTickets(), User B's tickets are accepted, even though the prizes for indices 1 and above have already been distributed. User B's tickets, therefore, have no chance of winning those prizes and are worth less than user A's, but the system incorrectly allows their participation for the undistributed prize at index 0.
Tools Used
Manual review
Recommended Mitigation Steps
Freeze ticket entry for the current round once any prize has been set.
Assessed type
Other
