TwentyOne

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

[M-1] Out of Funds vulnerability in TwentyOne contract in endgame function

Summary

The contract risks failing to pay winners if its balance is insufficient, causing transaction reverts and denial of service. This medium-level vulnerability affects user trust and can be mitigated with balance checks and better fund management

Vulnerability Details

The contract assumes it will always have enough ether to pay out winners, specifically 2 ether per win. However, if the contract's balance is insufficient to cover these payouts, the transfer operation will fail, causing the entire transaction to revert. This can lead to a denial of service for players expecting a payout.

Impact

Players may not receive their winnings if the contract balance is too low, leading to transaction reverts.

This become evident after testing the following function in test script.

function test_Call_PlayerWins() public {
vm.startPrank(player1); // Start acting as player1
twentyOne.startGame{value: 1 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
);
uint256 initialPlayerBalance = player1.balance;
// Player calls to compare hands
twentyOne.call();
// Check if the player's balance increased (prize payout)
uint256 finalPlayerBalance = player1.balance;
assertGt(finalPlayerBalance, initialPlayerBalance);
vm.stopPrank();
}

Tools Used

Foundry Test



Recommendations

Add balance check in startGame function which will resolve the issue.

function startGame() public payable returns (uint256) {
address player = msg.sender;
require(msg.value >= 1 ether, "Not enough ether sent");
require(address(this).balance >= 2 ether, "Contract does not have enough balance to pay potential winnings");
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 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Insufficient balance for payouts / Lack of Contract Balance Check Before Starting Game

Support

FAQs

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