TwentyOne

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

Player is able to initiate with >1 ETH, but payout remains at 2 ETH

[M-1] Player is able to initiate with >1 ETH, but payout remains at 2 ETH

Description: From the README, it states that "A player must deposit 1 ETH to play, with a maximum payout of 2 ETH upon winning." However, the startGame function contains a check to ensure that >= 1 ETH is sent. Additionally, the endGame function fixes the payout at 2 ETH, meaning that

This means that a player could start the game by sending in > 1 ETH, and will only get 2 ETH upon winning.

Impact: This creates situations where the player can win, but still end up losing money, breaking the protocol functionality

Proof of Concept:

  1. The player bets 10 ETH, either by accident or assuming that the payout for winning will be 20 ETH.

  2. Player wins the game

  3. Player gets credited 2 ETH instead of the expected 20ETH, resulting in the player losing money despite winning

Proof of Code

Insert the following in TwentyOne.t.sol

function test_PlayerCanBetMoreThanOneEther() public {
vm.startPrank(player1); // Start acting as player1
uint256 initialPlayerBalance = player1.balance;
twentyOne.startGame{value: 10 ether}();
// Mock the dealer's behavior to ensure player wins
// Simulate dealer cards by manipulating state
vm.mockCall(
address(twentyOne),
abi.encodeWithSignature("dealersHand(address)", player1),
abi.encode(18) // Dealer's hand total is 18
);
// Player calls to compare hands
twentyOne.call();
uint256 finalPlayerBalance = player1.balance;
// Player's balance is expected to decrease despite winning
assert(finalPlayerBalance < initialPlayerBalance);
vm.stopPrank();
}

Recommended Mitigation: Include a check for bets that exceed 1 ETH

function startGame() public payable returns (uint256) {
address player = msg.sender;
- require(msg.value >= 1 ether, "not enough ether sent");
+ require(msg.value = 1 ether, "1 ETH to start game");
initializeDeck(player);
uint256 card1 = drawCard(player);
uint256 card2 = drawCard(player);
addCardForPlayer(player, card1);
addCardForPlayer(player, card2);
return playersHand(player);
}
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.