TwentyOne

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

Inconsistent Logic when counting player's and dealer's card value

[H-2] Inconsistent Logic when counting player's and dealer's card value

Description: In the playersHand and dealersHand functions, the logic used to sum up the card value is not consistent.

function playersHand(address player) public view returns (uint256) {
uint256 playerTotal = 0;
for (uint256 i = 0; i < playersDeck[player].playersCards.length; i++) {
uint256 cardValue = playersDeck[player].playersCards[i] % 13;
if (cardValue == 0 || cardValue >= 10) {
playerTotal += 10;
} else {
playerTotal += cardValue;
}
}
return playerTotal;
}
function dealersHand(address player) public view returns (uint256) {
uint256 dealerTotal = 0;
for (uint256 i = 0; i < dealersDeck[player].dealersCards.length; i++) {
uint256 cardValue = dealersDeck[player].dealersCards[i] % 13;
// @audit med - drawing king +0 instead of +10
if (cardValue >= 10) {
dealerTotal += 10;
} else {
dealerTotal += cardValue;
}
}
return dealerTotal;
}

When counting the card value for the player's hand, cards 13, 26, 39, and 52 are treated to have a value of 10 for the player's hand, but a value of 0 for the dealer's hand.

Impact: This inconsistency results in the dealer having reduced chances of drawing cards that have a value of 10, which would result there being inconsistent odd of winning each game.

Proof of Code:

Insert the following in TwentyOne.t.sol

function test_UnfairLogicForDealerAndPlayer() public pure {
// We create the same hand for both the player and the dealer
uint256[] memory simulatedCards = new uint256[]();
simulatedCards[0] = 6;
simulatedCards[1] = 2;
simulatedCards[2] = 13;
simulatedCards[3] = 1; // This is where the logic will be different
// logic for counting player's total
uint256 playerTotal = 0;
for (uint256 i = 0; i < simulatedCards.length; i++) {
uint256 cardValue = simulatedCards[i] % 13;
if (cardValue == 0 || cardValue >= 10) {
playerTotal += 10;
} else {
playerTotal += cardValue;
}
}
// logic for counting dealer's total
uint256 dealerTotal = 0;
for (uint256 i = 0; i < simulatedCards.length; i++) {
uint256 cardValue = simulatedCards[i] % 13;
if (cardValue >= 10) {
dealerTotal += 10;
} else {
dealerTotal += cardValue;
}
}
// Check if the player and dealer have the same total card value
assert(playerTotal != dealerTotal);
}

Recommended Mitigation: Change the card value logic for the dealer to be consistent with the player, and with a standard deck of playing cards

function dealersHand(address player) public view returns (uint256) {
uint256 dealerTotal = 0;
for (uint256 i = 0; i < dealersDeck[player].dealersCards.length; i++) {
uint256 cardValue = dealersDeck[player].dealersCards[i] % 13;
- if (cardValue >= 10) {
+ if (cardValue == 0 || cardValue >= 10) {
dealerTotal += 10;
} else {
dealerTotal += cardValue;
}
}
return dealerTotal;
}
Updates

Lead Judging Commences

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

Asymmetric calculation of hands is rigged in the player`s favor.

Support

FAQs

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