TwentyOne

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

Lack of Post-Game Dealer Hand Transparency in TwentyOne.sol

Summary

The TwentyOne contract fails to provide players with visibility into the dealer’s final hand at the end of the game. This issue arises because the dealer’s card array (dealersDeck) is reset during the endGame function, resulting in the getDealerCards function returning an empty array. This lack of transparency prevents players from verifying the fairness of the game outcomes.

Vulnerability Details

  • Data Deletion in endGame:

    • During the endGame function, the dealer’s cards are deleted in line delete dealersDeck[player].dealersCards; and as a result, the dealer’s final hand is no longer retrievable after the game ends.

      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
      // @-Audit should win twice the bet amount
      if (playerWon) {
      payable(player).transfer(2 ether); // Transfer the prize to the player
      emit FeeWithdrawn(player, 2 ether); // Emit the prize withdrawal event
      }
      }

Impact

  • Reputation Risk: The absence of transparency could lead to reputational damage for the contract and its creators.

  • Player Frustration: Honest players may feel cheated or lose confidence in the fairness of the system, leading to reduced engagement.

Tools Used

  • Manual Code Review

Recommendations

  • Emit the dealer’s and player’s final hands in an event at the end of each game: since events are logged on the blockchain and cannot be altered or deleted, events ensure an unchangeable and publicly verifiable record of the game outcome.

event GameResult(
address indexed player,
uint256[] playerCards,
uint256[] dealerCards,
uint256 playerHand,
uint256 dealerHand
);
function endGame(address player, bool playerWon) internal {
emit GameResult(
player,
playersDeck[player].playersCards,
dealersDeck[player].dealersCards,
playersHand(player),
dealersHand(player)
);
delete playersDeck[player].playersCards;
delete dealersDeck[player].dealersCards;
delete availableCards[player];
if (playerWon) {
payable(player).transfer(2 ether);
emit FeeWithdrawn(player, 2 ether);
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
11 months ago
inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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