TwentyOne

First Flight #29
Beginner FriendlyGameFiFoundrySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Insufficient Balance Check in startGame Allows Players to Participate Without Guarantee of Payout

Summary

The startGame function in the TwentyOne contract does not verify whether the contract has sufficient funds to cover potential payouts before allowing players to start a game. This leads to a scenario where a player deposits 1 ETH to play, but if they win, the contract might not have enough balance to pay the 2 ETH reward. This violates the principle of fairness and creates a negative user experience, as players might unknowingly enter unwinnable games.

Vulnerability Details

The startGame function currently validates that a player sends exactly 1 ETH to play. However, it does not check whether the contract's balance is sufficient to cover a potential 2 ETH payout upon the player's victory. As a result, the contract might allow players to participate even when it is underfunded, leading to failed payouts in the endGame function.

The following condition is missing in the startGame function:

require(address(this).balance >= 2 ether,
"Contract does not have sufficient funds to cover potential payout");

Example Scenario

Initial Setup:

  • The contract’s balance is 0.5 ETH.

  • A player sends 1 ETH to start the game, assuming a potential payout of 2 ETH if they win.

Execution:

  • The player calls startGame and successfully starts the game because there is no check for the contract’s balance.

Outcome:

  • If the player wins, the endGame function reverts due to insufficient funds for the 2 ETH payout.

  • The player loses their initial deposit and receives no winnings, resulting in dissatisfaction and a loss of trust in the platform.

Impact

  • Unfair Gameplay:

  • Players are unknowingly allowed to participate in games where the contract cannot honor payouts.

  • Negative User Experience:

    • Players lose their deposit without the possibility of winning, leading to frustration and distrust in the platform.

  • Reputation Risk:

    • Allowing underfunded games reduces confidence in the platform’s reliability and fairness.

Tools Used

Manual Review

Recommendations

Add a Balance Check in startGame:
Ensure the contract has sufficient funds to cover potential payouts before allowing the game to start. Update the startGame function as follows:

function startGame() public payable returns (uint256) {
address player = msg.sender;
// Ensure the player sends exactly 1 ETH
require(msg.value == 1 ether, "You must send exactly 1 ETH to play");
// Check if the contract has sufficient funds for payout
require(address(this).balance >= 2 ether, "Contract does not have sufficient funds to cover potential payout");
// Initialize the player's deck and deal cards
initializeDeck(player);
uint256 card1 = drawCard(player);
uint256 card2 = drawCard(player);
addCardForPlayer(player, card1);
addCardForPlayer(player, card2);
return playersHand(player);
}
  • Add a Balance Check in endGame:
    While the primary check belongs in startGame, an additional check in endGame ensures robustness:

    if (playerWon) {
    require(address(this).balance >= 2 ether, "Contract has insufficient funds for payout");
    payable(player).transfer(2 ether);
    emit FeeWithdrawn(player, 2 ether);
    }
  • Alert Players About Insufficient Funds:
    If the balance is insufficient, the player should be informed early to avoid frustration. The error message in the require statement achieves this.

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Insufficient balance for payouts / Lack of Contract Balance Check Before Starting Game

Support

FAQs

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