Summary
The _cancelGame function is missing else block to handle unexpected game.bet values.
Vulnerability Details
The function currently handles two cases:
If game.bet > 0: refund ETH to players
If game.bet == 0: gives tokens to the players
However, if game.bet is set to an unexpected or invalid non-zero value (e.g., due to a bug), neither condition is met, and the game is still marked as cancelled.
This results in:
No ETH refund
No tokens minting
No error or revert
function _cancelGame(uint256 _gameId) internal {
Game storage game = games[_gameId];
game.state = GameState.Cancelled;
if (game.bet > 0) {
(bool successA,) = game.playerA.call{value: game.bet}("");
require(successA, "Transfer to player A failed");
if (game.playerB != address(0)) {
(bool successB,) = game.playerB.call{value: game.bet}("");
require(successB, "Transfer to player B failed");
}
}
if (game.bet == 0) {
if (game.playerA != address(0)) {
winningToken.mint(game.playerA, 1);
}
if (game.playerB != address(0)) {
winningToken.mint(game.playerB, 1);
}
}
emit GameCancelled(_gameId);
}
Impact
Funds loss
Players might not get ETH or tokens
Tools Used
Manual review
Recommendations
Add an else block to explicitly handle invalid or unexpected game.bet values.
Fixed code
function _cancelGame(uint256 _gameId) internal {
Game storage game = games[_gameId];
game.state = GameState.Cancelled;
if (game.bet > 0) {
(bool successA,) = game.playerA.call{value: game.bet}("");
require(successA, "Transfer to player A failed");
if (game.playerB != address(0)) {
(bool successB,) = game.playerB.call{value: game.bet}("");
require(successB, "Transfer to player B failed");
}
}
if (game.bet == 0) {
if (game.playerA != address(0)) {
winningToken.mint(game.playerA, 1);
}
if (game.playerB != address(0)) {
winningToken.mint(game.playerB, 1);
}
} else {
revert("Invalid game state");
}
emit GameCancelled(_gameId);
}