To determine the winner, the user has to call the call()
function, which reveals the dealer's cards. If the user wins, the contract attempts to transfer the prize using this logic:
However, if the transfer fails for any reason, the transaction is reverted. This means that the user would have to call call()
again to try to claim their prize. The problem is, this would lead to a different outcome because the dealer's cards could change each time the function is called, which might affect the result.
When the call()
function is used to determine the outcome of the game, the endGame()
function is called if the player wins, which handles transferring the funds to the user.
However, if the fund transfer fails for any reason, the entire transaction is reverted. This means the player would need to call call()
again to attempt claiming the prize. The issue is that calling call()
again could change the dealer’s cards, potentially altering the outcome of the game, causing the player to lose when they would have otherwise won.
The impact is high, as a user who has already won may lose the prize and the funds they wagered if they need to call the call()
function again. This can happen because the dealer's hand is recalculated, potentially altering the outcome and causing the user to lose after initially winning.
Manual Review.
Foundry.
Remix - Ethereum IDE.
To avoid the risk of altering the game outcome, the contract should ensure that the fund transfer is atomic and cannot be retried. One way to do this is by using a “claimable” status flag in the contract, which can be set to true
only once the game is complete and the funds have been successfully transferred. This way, the player can only claim their prize once, and any attempt to call the call()
function after the game has ended would be prevented.
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.