TwentyOne

First Flight #29
Beginner FriendlyGameFiFoundrySolidity
100 EXP
View results
Submission Details
Severity: low
Invalid

The protocol's allows a player to wage at least one ether to start a game, but ends up repaying them only two ether in the case they win the game.

Summary

The TwentyOne.sol contract's README.md documentation contains conflicting information about wagering and payouts. One section claims that players can wager more than 1 ETH and double their wager upon winning, while another states that a player must deposit exactly 1 ETH to play, with a maximum payout capped at 2 ETH. The contract's implementation, specifically in the endGame() function, enforces the latter, potentially leading to mismatched user expectations.


Vulnerability Details

The discrepancy lies between these statements in the README.md:

  1. "Winning players double their wager, while losing players forfeit their initial bet."

  2. "A player must deposit 1 ETH to play, with a maximum payout of 2 ETH upon winning."

However, in the contract's implementation, the startGame() function enforces a minimum bet of 1 ETH, and the endGame() function pays a fixed amount of 2 ETH to winning players, regardless of the wager amount. This implementation does not allow players who wager more than 1 ETH to double their actual wager, which will be unfair to the players who wage more than 1 ETH and also contradicts the first statement.

function startGame() public payable returns (uint256) {
address player = msg.sender;
require(msg.value >= 1 ether, "not enough ether sent");
initializeDeck(player);
uint256 card1 = drawCard(player);
uint256 card2 = drawCard(player);
addCardForPlayer(player, card1);
addCardForPlayer(player, card2);
return playersHand(player);
}
function endGame(address player, bool playerWon) internal {
delete playersDeck[player].playersCards; // Clear the player's cards
delete dealersDeck[player].dealersCards; // Clear the dealer's cards
delete availableCards[player]; // Reset the deck
if (playerWon) {
payable(player).transfer(2 ether); // Transfer the prize to the player
emit FeeWithdrawn(player, 2 ether); // Emit the prize withdrawal event
}
}

Impact

  • Mismatched User Expectations: Players may incorrectly assume that they can wager more than 1 ETH and double their specific wager upon winning, which is not supported by the contract.


Tools Used

  • Manual Code Review and protocol's Readme.md


Recommendations

  • Implement that a player starts a game by waging only 1 ETH and if they win, they will be rewarded 2 ETH and update the README.md to clearly state that the wager is fixed at 1 ETH and the maximum payout is 2 ETH upon winning.

function startGame() public payable returns (uint256) {
address player = msg.sender;
require(msg.value = 1 ether, "Error, send 1ETH");
initializeDeck(player);
uint256 card1 = drawCard(player);
uint256 card2 = drawCard(player);
addCardForPlayer(player, card1);
addCardForPlayer(player, card2);
return playersHand(player);
}
function endGame(address player, bool playerWon) internal {
delete playersDeck[player].playersCards; // Clear the player's cards
delete dealersDeck[player].dealersCards; // Clear the dealer's cards
delete availableCards[player]; // Reset the deck
if (playerWon) {
payable(player).transfer(2 ether); // Transfer the prize to the player
emit FeeWithdrawn(player, 2 ether); // Emit the prize withdrawal event
}
}
  • Implement that a player starts a game by waging atleast 1 ETH and if they win, they will be rewarded twice their wager and update the README.md to state that the wager atleast 1 ETH and the payout is doubled upon winning.

Updates

Lead Judging Commences

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

[INVALID] User mistake, too much ETH sent

Support

FAQs

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