Solidity Minimalist Guide #20: Sending ETH to Contracts

·

Solidity offers three primary methods for sending Ether (ETH) to other contracts: transfer(), send(), and call(). Among these, call() is the recommended approach due to its flexibility and lack of gas restrictions.


ReceiveETH Contract Example

First, let’s deploy a ReceiveETH contract capable of accepting ETH transfers. This contract includes:

contract ReceiveETH {
    event Log(uint amount, uint gas);
    
    receive() external payable {
        emit Log(msg.value, gasleft());
    }
    
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

After deployment, getBalance() will return 0 since no ETH has been sent yet.


SendETH Contract Implementation

We’ll create a SendETH contract with three methods to send ETH to ReceiveETH.

contract SendETH {
    constructor() payable {}
    receive() external payable {}
}

1. Using transfer()

function transferETH(address payable _to, uint256 amount) external payable {
    _to.transfer(amount);
}

Example:


2. Using send()

function sendETH(address payable _to, uint256 amount) external payable {
    bool success = _to.send(amount);
    if (!success) {
        revert SendFailed();
    }
}

Example:


3. Using call()

function callETH(address payable _to, uint256 amount) external payable {
    (bool success,) = _to.call{value: amount}("");
    if (!success) {
        revert CallFailed();
    }
}

Example:


Key Takeaways

  1. call()

    • ✅ No gas limits.
    • ✅ Most flexible (recommended).
    • ❌ Requires manual failure handling.
  2. transfer()

    • ✅ Auto-reverts on failure.
    • ❌ 2300 gas limit (use for simple transfers).
  3. send()

    • ❌ Rarely used due to manual handling and gas limits.

👉 Explore advanced Solidity techniques to deepen your understanding.


FAQs

Q1: Why is call() preferred over transfer()?

A: call() offers no gas restrictions and greater flexibility, making it suitable for contracts with complex receive() logic.

Q2: What happens if ETH transfer fails with transfer()?

A: The transaction automatically reverts, ensuring no partial state changes.

Q3: How can I check a contract’s ETH balance?

A: Use address(this).balance in a view function like getBalance().

Q4: Can I send ETH to non-payable functions?

A: No. The target contract must have a receive() or payable function.

Q5: What’s the gas cost for ETH transfers?

A: Fixed costs apply (e.g., 21k gas base + additional for logic).


For more Web3 insights, 👉 check out our developer resources.