How to Receive ETH in Solidity Smart Contracts

ยท

This chapter explains how smart contracts can receive Ether (ETH) in Solidity.


Smart contracts can store Ether (ETH) and receive ETH from external accounts. However, not all contracts inherently possess the ability to receive ETH.

For a smart contract to receive ETH, it must implement either a receive or fallback function.

Before learning about the receive function, it's essential to understand Ethereum's account types. If neither of these functions is defined, the contract cannot receive Ether.

According to Solidity's specifications, using the receive function is recommended because it's straightforward and purpose-specific, whereas the fallback function primarily handles calls to undefined functions.

1. The Receive Function

The receive function is defined as follows:

receive() external payable {
    // Custom logic (optional)
}

Key characteristics of the receive function:

  1. Does not require the function keyword
  2. Has no parameters
  3. Must have external visibility
  4. Must be payable

When ETH is sent to the contract's address, the receive function is triggered.

While custom logic can be added, it's common to leave the function body empty. If logic is necessary, keep it minimal since methods like send and transfer limit gas to 2300 to prevent reentrancy attacks, potentially causing transactions to revert if execution is too complex.

Example: Logging ETH Receipts

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract FuncReceive {
    event Received(address sender, uint amount);

    receive() external payable {
        emit Received(msg.sender, msg.value);
    }
}

After deploying this contract (e.g., using Remix), sending ETH (e.g., 100 wei) will:

2. The Fallback Function

In Solidity, fallback is a special function that handles:

  1. Calls to undefined functions
  2. ETH receipts (when no receive function exists)

Definition

fallback() external [payable] {
    // Custom logic (optional)
}

Key characteristics:

  1. No function keyword
  2. No parameters
  3. external visibility
  4. Optional payable modifier

2.1 When Fallback is Triggered

Scenario 1: Calling undefined functions

fallback() external {}

Scenario 2: Receiving ETH (no receive function)

fallback() external payable {}

๐Ÿ‘‰ Learn more about Solidity fallback patterns

2.2 Receive vs. Fallback Workflow

2.3 Testing Fallback Functions

a) Payable Fallback Only

contract FuncFallback {
    event Fallback();
    fallback() external payable {
        emit Fallback();
    }
}

Sending ETH triggers the Fallback event.

b) Both Receive and Fallback

contract FuncFallback {
    event Receive();
    event Fallback();
    
    receive() external payable {
        emit Receive();
    }
    
    fallback() external payable {
        emit Fallback();
    }
}

c) Calling Undefined Functions
Providing non-empty msg.data (e.g., via Remix's "CALLDATA") triggers the fallback.

2.4 Practical Use Cases

Preferred Approach: Use receive for ETH deposits and fallback for undefined function calls to maintain clarity.

Applications:

๐Ÿ‘‰ Explore real-world Solidity contract examples


FAQ

Q: Why can't some contracts receive ETH?
A: Contracts lacking both receive and payable fallback functions cannot process ETH transfers.

Q: What's the gas limit for receive/fallback?
A: Methods like transfer impose a 2300 gas limit, necessitating minimal logic in these functions.

Q: When should I use fallback instead of receive?
A: Only when handling undefined function calls. For pure ETH receipts, receive is clearer.

Q: Can fallback handle both ETH and function calls?
A: Yes, but separating concerns using receive for ETH is recommended.

Q: How do I debug failed ETH transfers?
A: Check if: