Rock Paper Scissors

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

Token Minting on Game Cancellation Increases Total Token Supply Unnecessarily

Summary

When a token-based game (game.bet == 0) is cancelled in the _cancelGame function, the contract mints new WinningToken tokens to the players instead of transferring the tokens they originally staked. This causes an unnecessary increase in the total supply of the WinningToken, which could lead to inflation over time.

Vulnerability Details

Function Affected: _cancelGame(uint256 _gameId)

  • Issue: When cancelling a game with tokens, the contract mints new tokens to the players instead of transferring the tokens that were previously staked. This increases the total supply of WinningToken unnecessarily.

  • Cause: The function uses winningToken.mint() to mint new tokens, instead of transferring the tokens that were originally staked by the players.

/**
* @dev Cancel game and refund
* @param _gameId ID of the game
*/
function _cancelGame(uint256 _gameId) internal {
Game storage game = games[_gameId];
game.state = GameState.Cancelled;
// Refund ETH to players
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");
}
}
// Return tokens for token games
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

  • Inflation of Token Supply: The total supply of the WinningToken increases without any backing value, leading to inflation over time.

Tools Used

  • Manual code review

Recommendations

Replace winningToken.mint() with a transfer mechanism to return the tokens that were originally staked by the players.

Ensure that the total supply of WinningToken is kept in check and that no new tokens are minted unnecessarily during cancellation.

/**
* @dev Cancel game and refund
* @param _gameId ID of the game
*/
function _cancelGame(uint256 _gameId) internal {
Game storage game = games[_gameId];
game.state = GameState.Cancelled;
// Refund ETH to players
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");
}
}
// Return tokens for token games
if (game.bet == 0) {
if (game.playerA != address(0)) {
winningToken.transferFrom(address(this), game.playerA, 1);
}
if (game.playerB != address(0)) {
winningToken.transferFrom(address(this), game.playerB, 1);
}
}
emit GameCancelled(_gameId);
}
Updates

Appeal created

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

Minting Instead of Transferring Staked Tokens

Mints new tokens upon game completion or cancellation for token-based games

Support

FAQs

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