TwentyOne

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

The game can accept deposits exceeding 1 ether, but it only pays out a maximum of 2 ether. Players might not win the full amount they bet and could even incur a loss despite winning.

Description: In the TwentyOne:startGame function, the game accepts deposits exceeding 1 ether.

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);
}

However, the game only pays out a maximum of 2 ether. This means that players might not win the full amount they bet and could even incur a loss despite winning.

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:
This can breaks the game logic, players did not won the value they bet and players can lose money despite winning.

Proof of Concept:

  1. PLAYER deposits 3 ether.

  2. PLAYER wins the game.

Add the following code into TwentyOne.t.sol:

Proof of Code ```solidity modifier fundTwentyOne() { vm.deal(address(twentyOne), 100 ether); // Fund the contract with 10 ether _; } ... function test_player_send_more_than_required_eth() public fundTwentyOne { vm.startPrank(player1); uint256 initialPlayerBalance = player1.balance; twentyOne.startGame{value: 3 ether}();
vm.recordLogs();
twentyOne.call();
Vm.Log[] memory logs = vm.getRecordedLogs();
assertEq(logs[0].topics[0], keccak256("PlayerWonTheGame(string,uint256)"));
uint256 finalPlayerBalance = player1.balance;
assertEq(finalPlayerBalance, initialPlayerBalance - 1 ether); // Player sent 3 eth but only won 2 eth back
vm.stopPrank();
}
```

run forge test --mt test_player_send_more_than_required_eth and you will see the test pass (final player balance < initial player balance).

Recommended Mitigation:
Ensure that the game only accepts deposits of 1 ether in TwentyOne:startGame function.

function startGame() public payable returns (uint256) {
address player = msg.sender;
- require(msg.value >= 1 ether, "not enough ether sent");
+ require(msg.value == 1 ether, "only 1 ether allowed");
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.