Description: After the contract was deployed, it starts with a balance of 0 ETH. When a player begins a game and wins instantly, the balance may be insufficient to pay out, as the contract's only available balance is the original wager of 1 ETH. Additionally, due to variance, there are scenarios where the contract's balance can drop below 1 ETH, even when it is adequately funded.
To address this issue, I conducted a Monte Carlo simulation, which indicated that an initial funding of approximately 50 ETH is necessary to ensure the contract does not fall victim to variance in 99% of cases. Increasing the initial funding further can help reduce the likelihood of the contract's balance dropping below 1 ETH.
Impact: When the contracts balance is under 1 ETH, the contract fails to payout the player, therefore greatly impacting the contracts desired functionality.
Recommended Mitigations: Modify the constructor to require an initial msg.value
corresponding to the desired initial funding. Additionally, to further safeguard the contract against unlikely scenarios where the balance may be insufficient, include a check in the TwentyOne::startGame()
function to ensure that the contract's balance remains above 1 ETH.
TwentyOne::constructor()
example:
TwentyOne::startGame()
example:
PoC: The flaw is trivial to discover when running the test_Call_PlayerWins()
test, in which your team seemed to have overseen that the test fails.
To really make sure that the root cause of the failing test is an insufficient contract Balance. I added the following line to the tests set-up to fund the contract:
Now we can observe that the contract is not failing anymore but passes.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.