Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Invalid

No Allowance Check

Summary

The createGameWithToken function in the Rock Paper Scissors contract allows players to create a game using an ERC20 WinningToken. However, it performs a transferFrom call without verifying that the contract has sufficient allowance to transfer the token on behalf of the user. This omission can result in transaction reverts, degrading user experience and potentially exposing denial-of-service behavior.

Vulnerability Details

The vulnerable code is located in the createGameWithToken and in the joinGameWithToken function:

// Transfer token to contract
winningToken.transferFrom(msg.sender, address(this), 1);

This line attempts to transfer a token from the caller (msg.sender) to the contract without confirming that an allowance has been granted using approve.

While the function checks that the user has at least 1 token via:

require(winningToken.balanceOf(msg.sender) >= 1, "Must have winning token");

…it does not check if the WinningToken contract's allowance for the RPS contract is sufficient:

winningToken.allowance(msg.sender, address(this))

If the allowance is insufficient or not set, the transaction will revert with ERC20: insufficient allowance.

Impact

  • Denial of Service (DoS): Any user attempting to create a game without a prior approve() call will have their transaction reverted. This can confuse users and block gameplay.

  • Poor UX: No clear error message or guidance on setting the allowance, resulting in failed transactions that users may not understand.

  • Silent Failures: Without an allowance check, it becomes difficult to debug or anticipate errors.

Tools Used

Manual code review

Recommendations

Add a check for sufficient allowance before calling transferFrom:

require(winningToken.allowance(msg.sender, address(this)) >= 1,"Token allowance too low" );

Full fix:

//First Check the balance
require(winningToken.balanceOf(msg.sender) >= 1,"Must have winning token" );
//Then check the allowance
require(winningToken.allowance(msg.sender, address(this)) >= 1,"Token allowance too low" );
//Then the transfer is triggered
winningToken.transferFrom(msg.sender, address(this), 1);
Updates

Appeal created

m3dython Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Broken Token Game Creation

createGameWithToken and joinGameWithToken functions will revert because they attempt transferFrom without requiring the user to first approve

m3dython Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Broken Token Game Creation

createGameWithToken and joinGameWithToken functions will revert because they attempt transferFrom without requiring the user to first approve

Support

FAQs

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