Rock Paper Scissors

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

Token Inflation via Improper Staking

Vulnerability Details

The smart contract incorrectly handles token staking during game cancellations. Instead of redistributing the tokens that players have already staked, the contract mints brand-new tokens and sends them to the players. This leads to uncontrolled inflation of the token supply over time.

Bug Description

When two players join a game using tokens, their tokens are successfully transferred into the contract. This part is correct:

// From createGameWithToken()
winningToken.transferFrom(msg.sender, address(this), 1);
// From joinGameWithToken()
winningToken.transferFrom(msg.sender, address(this), 1);

At this point, the contract holds 2 tokens.

However, when a game is canceled (or potentially ends), instead of sending the already-staked tokens back to the players, the contract mints new tokens:

// Inside _cancelGame()
if (game.bet == 0) {
winningToken.mint(game.playerA, 1);
winningToken.mint(game.playerB, 1);
}

This action increases the total token supply by 2, while the original 2 tokens remain locked in the contract forever.

Impact

  • Unlimited Token Inflation: Every time a game is canceled, two brand-new tokens are created. If this is done repeatedly, the token supply will grow exponentially.

  • Token Devaluation: As supply increases without control, each token becomes less valuable. This is bad for token holders and undermines trust in the ecosystem.

  • Contract as a Token Sink: The contract slowly accumulates more and more unused tokens, further disrupting the system’s economics.



    Recommended Mitigation Steps

Replace minting logic with logic that returns the original staked tokens. Instead of:

winningToken.mint(game.playerA, 1);
winningToken.mint(game.playerB, 1);

You should do:

winningToken.transfer(game.playerA, 1);
winningToken.transfer(game.playerB, 1);

This way, no new tokens are created, and the ones originally staked are properly returned to their owners.

Also, consider adding a unit test to check that the total supply does not increase when games are canceled.

Proof of Concept

  1. Start with 100 tokens in total supply.

  2. Player A and Player B each stake 1 token.

    • Contract receives 2 tokens → totalSupply = 100

  3. The game is canceled.

    • Contract mints 2 new tokens → totalSupply = 102

  4. The original 2 tokens are still inside the contract.

    • Tokens inside contract: 2

    • Tokens in circulation: 102

    • Real backing: Only 100 tokens were originally supposed to exist

Repeat this across hundreds or thousands of games, and the supply becomes meaningless.

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.