Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Invalid

No early win mechanism

Summary

In the current game design, when a player wins early by coming on top for (turns / 2 + 1) turns, he still needs to play on to finish the game and get the prize, until:

  • all turns are completed or

  • commitMove + revealMove followed by calling timeoutReveal in order to finish the game and get the prize.

Vulnerability Details

Losing player can call timeoutReveal and cancel game, resulting in refunds for both players

Impact

Game is canceled, Prize is lost for the winner

Tools Used

Manual Code Review

Recommendations

Add an early winner check in _determineWinner

function _determineWinner(uint256 _gameId) internal {
Game storage game = games[_gameId];

function _determineWinner(uint256 _gameId) internal {
Game storage game = games[_gameId];
address turnWinner;
// Rock = 1, Paper = 2, Scissors = 3
if (game.moveA == game.moveB) {
// Tie, no points
turnWinner = address(0);
} else if (
(game.moveA == Move.Rock && game.moveB == Move.Scissors) ||
(game.moveA == Move.Paper && game.moveB == Move.Rock) ||
(game.moveA == Move.Scissors && game.moveB == Move.Paper)
) {
// Player A wins
game.scoreA++;
turnWinner = game.playerA;
} else {
// Player B wins
game.scoreB++;
turnWinner = game.playerB;
}
emit TurnCompleted(_gameId, turnWinner, game.currentTurn);
// ********** Early win check <- New code **********
uint8 currentWins = uint8(game.totalTurns / 2) + 1;
if (game.scoreA == currentWins) {
_finishGame(_gameId, game.playerA);
return;
} else if (game.scoreB == currentWins) {
_finishGame(_gameId, game.playerB);
return;
}
// Reset for next turn or end game
if (game.currentTurn < game.totalTurns) {
// Reset for next turn
game.currentTurn++;
game.commitA = bytes32(0);
game.commitB = bytes32(0);
game.moveA = Move.None;
game.moveB = Move.None;
game.state = GameState.Committed;
} else {
// End game
if (game.scoreA > game.scoreB) {
_finishGame(_gameId, game.playerA);
} else if (game.scoreB > game.scoreA) {
_finishGame(_gameId, game.playerB);
} else {
_handleTie(_gameId);
}
}
Updates

Appeal created

m3dython Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.