Rock Paper Scissors

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

Token Minting Instead of Transfer in Game Cancellation and Completion Leading to Infinite Inflation

Summary

The RockPaperScissors contract incorrectly mints new WinningToken tokens during game cancellation and completion instead of transferring the originally staked tokens. This flaw allows infinite token inflation, undermining the token's economic model.

Vulnerability Details

Root Cause:

  • In RockPaperScissors::_cancelGame and RockPaperScissors::_finishGame, the contract mints new tokens to players (e.g., winningToken.mint(game.playerA, 1)) rather than transferring the staked tokens held by the contract.

  • Players initially stake tokens via transferFrom, which are held by the contract. However, these tokens are never returned—instead, new ones are minted, leaving the original tokens locked in the contract.

Proof of Concept:

  1. Game Creation: Players stake tokens (e.g., 1 each via transferFrom), increasing the contract’s balance by 2.

  2. Game Resolution:

    • On cancellation: winningToken.mint is called for both players (2 new tokens minted).

    • On completion: winningToken.mint(_winner, 2) mints 2 new tokens to the winner.

  3. Result: The staked tokens remain in the contract, and the total supply increases by 2 per game.

https://github.com/CodeHawks-Contests/2025-04-rock-paper-scissors/blob/25cf9f29c3accd96a532e416eee6198808ba5271/src/RockPaperScissors.sol#L495-L504

https://github.com/CodeHawks-Contests/2025-04-rock-paper-scissors/blob/25cf9f29c3accd96a532e416eee6198808ba5271/src/RockPaperScissors.sol#L563-L571

Impact

  • Permanent Token Inflation: The WinningToken supply grows indefinitely as staked tokens are never burned or transferred.

  • Economic Model Breakage: The token’s scarcity is compromised, enabling arbitrary minting through repeated game creation/cancellation.

  • Funds Locked: Staked tokens accumulate in the contract without utility.

Tools Used

Recommendations

Replace minting with transfers of the staked tokens:

// In _cancelGame:
if (game.bet == 0) {
+ winningToken.transfer(game.playerA, 1);
+ winningToken.transfer(game.playerB, 1);
- winningToken.mint(game.playerA, 1);
- winningToken.mint(game.playerB, 1);
}
// In _finishGame for token games:
if (game.bet == 0) {
+ winningToken.transfer(_winner, 2); // Send the 2 staked tokens
- winningToken.mint(_winner, 2);
}
Updates

Appeal created

m3dython Lead Judge about 2 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

m3dython Lead Judge about 2 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.