TwentyOne

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

hit() Function Allows Player to Hit After Achieving Blackjack

Summary

In the hit() function of the TwentyOne contract, players are allowed to draw another card even when their hand already totals 21 (a blackjack). This violates standard blackjack rules, where players should not hit after achieving a blackjack. The bug could lead to unnecessary actions and potentially unfair outcomes, as it allows players to risk busting (exceeding 21) even when they have already won the hand.

Vulnerability Details

The bug exists because there is no condition in the hit() function to check if the player's hand already totals 21. The absence of this check allows the player to call hit() regardless of their current hand total, as seen here:

function hit() public {
require(playersDeck[msg.sender].playersCards.length > 0, "Game not started");
uint256 handBefore = playersHand(msg.sender);
require(handBefore <= 21, "User is bust");
uint256 newCard = drawCard(msg.sender);
addCardForPlayer(msg.sender, newCard);
uint256 handAfter = playersHand(msg.sender);
if (handAfter > 21) {
emit PlayerLostTheGame("Player is bust", handAfter);
endGame(msg.sender, false);
}
}

This allows unnecessary card draws even when the player has already achieved 21, potentially causing them to lose the game by busting.

Impact

  1. Violation of Blackjack Rules:

    • Standard blackjack rules state that a player with a hand totaling 21 cannot hit. Allowing this action misaligns the game logic with accepted rules.

  2. Risk of Unnecessary Busting:

    • Players who hit after achieving 21 risk losing the game by exceeding 21, which creates unnecessary risks.

  3. Potential for Frustration:

    • Players might accidentally hit after achieving a blackjack and lose their winnings, leading to dissatisfaction and distrust in the platform.


Example Scenario:

Initial Setup:

  • The player starts the game and draws two cards: [10, 11], totaling 21 (a blackjack).

Execution:

  • The player calls hit(), which allows them to draw another card unnecessarily.

Outcome:

  • The player draws a card worth 5, making their hand [10, 11, 5], totaling 26. The player loses the game unnecessarily because they busted, even though they had already won with a blackjack.

Tools Used

Manual Review

Recommendations

Add a Check for Blackjack:
Update the hit() function to prevent players from drawing a card when their hand already totals 21.

Updated Code:

function hit() public {
require(playersDeck[msg.sender].playersCards.length > 0, "Game not started");
uint256 handBefore = playersHand(msg.sender);
// Prevent hitting if the player already has a blackjack
require(handBefore < 21, "Player already has a blackjack");
uint256 newCard = drawCard(msg.sender);
addCardForPlayer(msg.sender, newCard);
uint256 handAfter = playersHand(msg.sender);
if (handAfter > 21) {
emit PlayerLostTheGame("Player is bust", handAfter);
endGame(msg.sender, false);
}
}
Updates

Lead Judging Commences

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

Appeal created

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

Natural Blackjack not implemented

Naturals. If a player's first two cards are an ace and a "ten-card" (a picture card or 10), giving a count of 21 in two cards, this is a natural or "blackjack." If any player has a natural and the dealer does not, the dealer immediately pays that player one and a half times the amount of their bet.

Support

FAQs

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