TwentyOne

First Flight #29
Beginner FriendlyGameFiFoundrySolidity
100 EXP
View results
Submission Details
Severity: low
Invalid

[L-2] Using `transfer()` method instead of `call()`

Summary

TwentyOne::endGame function uses transfer method to withdraw a reward to a winner. The transfer method for sending Ether in Solidity is considered outdated and has a fixed 2,300 gas to the recipient.

Vulnerability Details

function endGame(address player, bool playerWon) internal {
delete playersDeck[player].playersCards; // Clear the player's cards
delete dealersDeck[player].dealersCards; // Clear the dealer's cards
delete availableCards[player]; // Reset the deck
if (playerWon) {
@> payable(player).transfer(2 ether); // Transfer the prize to the player
emit FeeWithdrawn(player, 2 ether); // Emit the prize withdrawal event
}
}
## 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; // Clear the player's cards
delete dealersDeck[player].dealersCards; // Clear the dealer's cards
delete availableCards[player]; // Reset the deck
if (playerWon) {
- payable(player).transfer(2 ether); // Transfer the prize to the player
- emit FeeWithdrawn(player, 2 ether); // Emit the prize withdrawal event
+ require(address(this).balance >= 2 ether, "Contract has insufficient funds");
+ emit FeeWithdrawn(player, 2 ether); // Emit the prize withdrawal event
+ (bool success, ) = payable(player).call{value: 2 ether}("");
+ require(success, "Transfer failed");
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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