Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Receive and Fallback Functions in Solidity for Ether Handling

Tech May 10 3

Receive Function

A contract can declare at most one receive function.

receive() external payable {
    // Logic executed upon receiving Ether
}

Key Characteristics:

  • Declared without the function keyword.
  • Must be marked external payable.
  • Cannot have arguments or return values.
  • Is called on plain Ether transfers (e.g., via .send() or .transfer()).
  • It can use modifiers and perform arbitrary logic within gas limits.
  • If a contract needs to accept Ether and lacks a payable fallback function, it must implement a receive function.

Example Implementation:

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

contract ReceiverExample {
    event DepositReceived(address indexed from, uint256 amount);

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

Fallback Function

A contract can declare at most one fallback function.

// Minimal declaration
fallback() external [payable] {
    // Logic when no other function matches
}

// Declaration with data handling
fallback(bytes calldata inputData) external [payable] returns (bytes memory outputData) {
    // Logic with input/output data
}

Key Characteristics:

  • Declared without the function keyword.
  • Must be marked external; payable is optional.
  • Executed when a call to the contract does not match any funciton signature, or if no data is supplied (if receive is absent).
  • It can serve as a backup for receiving Ether if made payable.
  • Can use modifiers and perform complex operations.
  • The version with parameters allows inspection and response to arbitrary call data.

Example Contracts Demonstrating Behavior:

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

contract ContractA {
    uint256 public stateVar;
    // Non-payable fallback; contract rejects Ether transfers.
    fallback() external {
        stateVar = 100;
    }
}

contract ContractB {
    uint256 public valueX;
    uint256 public valueY;

    // Payable fallback for calls with unmatched signatures.
    fallback() external payable {
        valueX = 10;
        valueY = msg.value;
    }

    // Receive function for plain Ether transfers.
    receive() external payable {
        valueX = 20;
        valueY = msg.value;
    }
}

contract CallerExample {
    function interactWithContractA(ContractA targetContract) public returns (bool) {
        // Call a non-existent function, triggering fallback.
        (bool callSuccess, ) = address(targetContract).call(
            abi.encodeWithSignature("fakeFunction()")
        );
        require(callSuccess); // stateVar becomes 100.

        // Attempting to send Ether will fail.
        return payable(address(targetContract)).send(1 ether); // Returns false
    }

    function interactWithContractB(ContractB targetContract) public returns (bool) {
        // Call non-existent function without value.
        (bool success, ) = address(targetContract).call(
            abi.encodeWithSignature("fakeFunction()")
        );
        require(success); // valueX = 10, valueY = 0.

        // Call non-existent function with Ether value.
        (success, ) = address(targetContract).call{value: 1 ether}(
            abi.encodeWithSignature("fakeFunction()")
        );
        require(success); // valueX = 10, valueY = 1 ether.

        // Plain Ether transfer triggers receive().
        (success, ) = address(targetContract).call{value: 2 ether}("");
        require(success); // valueX = 20, valueY = 2 ether.

        return true;
    }
}

Execution Priority: For an incoming call with Ether:

  1. If the call data is empty, the receive() function is executed if it exists.
  2. If receive() does not exist, but a payable fallback() exists, fallback() is executed.
  3. If neither exists, the call reverts. For an incoming call without Ether but with unmatched call data, the fallback() function is executed if it exists.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.