Christmas Dinner

First Flight #31
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Use call instead of transfer in _refundETH function to prevent ETH stack in the contract

Summary
The _refundETH function in the ChristmasDinner contract uses the transfer method to send Ether. Using transfer is unsafe due to its fixed gas limit, which may not be sufficient to complete more complex operations in the receiving contract, potentially leading to failure and loss of funds. This function should be modified to use the call method instead.

Vulnerability Details

In the ChristmasDinner contract, the _refundETH function:

function _refundETH(address payable _to) internal {
uint256 refundValue = etherBalance[_to];
_to.transfer(refundValue);
etherBalance[_to] = 0;
}

uses the transfer method to send Ether to the recipient. The transfer function forwards only 2300 gas, which may not be enough to complete the transfer if the recipient's fallback function consumes more gas. This can lead to the contract’s Ether balance being permanently stuck. Furthermore, if the transfer fails, it throws an exception, which makes handling errors difficult.

Using transfer does not provide feedback about whether the operation was successful; it either succeeds or throws an error. This makes it harder to handle errors gracefully in the contract.

Impact

Using transfer in the _refundETH function can lead to the following issues:

  1. Potential loss of Ether: If the recipient’s contract consumes more gas than provided by transfer, the transaction fails, and the Ether is lost.

  2. Unreachable Ether: Ether can become permanently stuck in the contract, making it unavailable for withdrawals or refunds.

  3. Difficult error handling: In cases where the transfer fails, it throws an error without providing information about the failure, complicating debugging and recovery efforts.

Tools Used

  • Solidity compiler version 0.8.27

  • Etherscan for contract analysis

Recommendations
To prevent issues with the _refundETH function, it is recommended to use the call method instead of transfer. The call method allows specifying the gas limit, which provides more control over the transaction execution. Here’s how the function can be modified:

function _refundETH(address payable _to) internal {
uint256 refundValue = etherBalance[_to];
- _to.transfer(refundValue);
+ (bool success, ) = _to.call{value: refundValue}("");
+ require(success, "Failed to send Ether");
etherBalance[_to] = 0;
}

By using call, you can specify a gas limit (such as gasleft() or a fixed number like 5000) to ensure the recipient’s contract can handle the transaction. This approach also returns a boolean value indicating success or failure, making error handling simpler and more predictable.

Updates

Lead Judging Commences

0xtimefliez Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

transfer instead of call

0xtimefliez Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

transfer instead of call

Support

FAQs

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