TwentyOne

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

Initial capital of the contract

Summary

When deploying TwentyOne contract remember to provide the initial capital to it.

Vulnerability Details

There is a chance that the TwentyOne contract will lose the first time (even several times at the beginning). Therefore, there must be ether in the contract that allows players to withdraw their winnings.

Impact

Failure to provide ETH to the contract may result in the contract functioning incorrectly, namely:

  1. A player who wins will never be able to get his winnings back

  2. Other players who win after the first player can win

Tools Used

Manual review. Below is an example of one scenario of how a contract might go wrong. The first player wins without any winnings, the second player wins and can withdraw his winnings

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Test, console2} from "forge-std/Test.sol";
import {TwentyOne} from "../src/TwentyOne.sol";
contract _21Test is Test {
TwentyOne twentyOne;
address player1 = address(0x123);
address player2 = address(0x4567);
function setUp() public {
twentyOne = new TwentyOne();
// not providing eth to the contract
// vm.deal(address(twentyOne), 10 ether);
vm.deal(player1, 10 ether);
vm.deal(player2, 10 ether);
//setting timestamp and prevrandao so to player 1 and player 2 win
vm.prevrandao(bytes32(0));
vm.warp(1);
}
function testNoETHInContract() public {
// -------------------------------- Player 1 playing --------------------------------
vm.startPrank(player1);
twentyOne.startGame{value: 1 ether}();
uint256 initialPlayerBalance = player1.balance; //should be 9 ether
vm.expectRevert(); // Player calls to compare hands but it'll revert due to out of funds in the contract
twentyOne.call();
uint256 finalPlayerBalance = player1.balance; //still 9 ether :-(
assertEq(finalPlayerBalance, initialPlayerBalance);
assertEq(finalPlayerBalance, 9 ether);
vm.stopPrank();
// -------------------------------- Player 2 playing --------------------------------
vm.startPrank(player2);
twentyOne.startGame{value: 1 ether}();
initialPlayerBalance = player2.balance; //should be 9 ether
assertEq(address(twentyOne).balance, 2 ether);
// Player calls to compare hands but it'll not revert
twentyOne.call();
finalPlayerBalance = player2.balance; //9+2 ether
assertEq(finalPlayerBalance, initialPlayerBalance + 2 ether);
assertEq(finalPlayerBalance, 11 ether);
vm.stopPrank();
}
}

Recommendations

Provide some initial aether during deployment. I assume you may be aware of this, but testing suggests otherwise.

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.