Rock Paper Scissors

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

Unchecked Transfer Result in `joinGameWithToken()` Allows Silent Token Transfer Failures in `RockPaperScissors.sol`

🚨 Finding: Unchecked Transfer Result in joinGameWithToken() Allows Silent Token Transfer Failures

📊 Summary

The joinGameWithToken() function in the RockPaperScissors.sol contract performs a call to the transferFrom() function of the WinningToken contract to collect the required participation token from msg.sender. However, it fails to verify the return value of the call. This opens the door for silent failures, where the transfer does not succeed, yet the user is still allowed to participate in the game.


🔍 Vulnerable Code

File: RockPaperScissors.sol
Function: joinGameWithToken()

require(winningToken.balanceOf(msg.sender) >= 1, "Must have winning token");
// ⚠️ Unchecked transfer result
winningToken.transferFrom(msg.sender, address(this), 1);
game.playerB = msg.sender;
emit PlayerJoined(_gameId, msg.sender);
  • The transferFrom call returns a boolean indicating success.

  • The result is ignored, meaning failed transfers go unnoticed.

  • This allows the game state to proceed even if no token was transferred.


📈 Impact

  • Players could potentially join token-based games without actually transferring the required token.

  • Could be triggered accidentally (missing approval) or intentionally (using non-compliant ERC-20 tokens).

  • Corrupts game integrity and undermines trust in the token-based participation model.


🔧 Recommendation

Replace the transfer call with a checked version using require:

require(
winningToken.transferFrom(msg.sender, address(this), 1),
"Token transfer failed"
);

This ensures that if the token transfer fails, the transaction reverts and prevents the player from joining the game.


📄 Conclusion

Failing to validate ERC-20 token transfer results is a well-known source of logic bugs in smart contracts. This issue mirrors the same vulnerability previously identified in createGameWithToken() and should be addressed consistently across all token-related game entry points to uphold fairness and expected behavior.

📄 Tool Used

Solidity (Wake)
V1.18.0

Updates

Appeal created

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

Missing Check on External Call Return Value

ERC20 implementation typically reverts on transfer failures

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

Missing Check on External Call Return Value

ERC20 implementation typically reverts on transfer failures

Support

FAQs

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