Christmas Dinner

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

Multisig Wallets Cant Receive Refund Due to the Gas Constraint in .transfer() function, Which Leads to Loss of Funds to Users

Summary

The .transfer functions in Solidity impose a hardcoded gas limit of 2300 gas when sending ETH to a recipient. While this is sufficient for Externally Owned Accounts (EOAs), it may not be enough for smart contracts such as multisig wallets or complex contracts with additional fallback logic. This limitation can result in failed ETH transfers and potential loss of functionality. The recommended solution is to use the .call function, which provides flexibility by avoiding the gas limit issue and allowing developers to handle failures gracefully.


Vulnerabilities Detail

**Issue: Fixed Gas Limit in .transfer

  1. Gas Limit Restriction:

    • .transfer impose a fixed gas limit of 2300 gas for executing the recipient’s fallback or receive function.

    • While this is sufficient for EOAs (simple wallets), it is often inadequate for multisig wallets or other smart contracts with additional logic in their fallback function.

  2. Failure on Complex Contracts:

    • Contracts like multisig wallets typically require more than 2300 gas to perform operations like event logging or state updates in their fallback functions.

    • When these operations exceed the gas limit, the transfer fails, reverting the transaction.


Impact

  1. Failed Transfers to Complex Contracts:

    • ETH transfers to multisig wallets or other smart contracts may fail, breaking the intended functionality.

    • This could result in funds being locked or inaccessible if proper error handling is not implemented.


Recommendations

**1. Use .call Instead of .transfer **

  • Replace .transfer with .call for ETH transfers to avoid the fixed gas limit issue.

  • Example Implementation:

    function _refundETH(address payable _to) internal {
    uint256 refundValue = etherBalance[_to];
    etherBalance[_to] = 0; // Update state first to avoid reentrancy
    (bool success, ) = _to.call{value: refundValue}(""); // Use .call
    require(success, "ETH transfer failed");
    }

Updates

Lead Judging Commences

0xtimefliez Lead Judge 8 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.