function endGame(address player, bool playerWon) internal {
delete playersDeck[player].playersCards;
delete dealersDeck[player].dealersCards;
delete availableCards[player];
if (playerWon) {
@> payable(player).transfer(2 ether);
emit FeeWithdrawn(player, 2 ether);
}
}
## Impact
There is not 100% sure the recipient is an externally owned account (EOA) or a simple contract with no complex logic. It has limitations that make it unsuitable in more complex scenarios (for example, has a fixed 2,300 gas per transaction that in some cases might be not enough).
## Tools Used
Manual
## Recommendations
We recommend to use `call()` method instead of `transfer()`. Additionally, it is good option to add modifier `nonReentrant` to avoid possible reentrancy vulnerability from `@OpenZeppelin` library.
Here is a way how to mitigate it:
```diff
+ import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
- contract TwentyOne {
+ contract TwentyOne is ReentrancyGuard {
.
.
.
- function call() public {
+ function call() public nonReentrant {
.
.
.
function endGame(address player, bool playerWon) internal {
delete playersDeck[player].playersCards;
delete dealersDeck[player].dealersCards;
delete availableCards[player];
if (playerWon) {
- payable(player).transfer(2 ether);
- emit FeeWithdrawn(player, 2 ether);
+ require(address(this).balance >= 2 ether, "Contract has insufficient funds");
+ emit FeeWithdrawn(player, 2 ether);
+ (bool success, ) = payable(player).call{value: 2 ether}("");
+ require(success, "Transfer failed");
}
}