1

Quoting from here -

In such a context, there is usually very little gas available to the function call (to be precise, 2300 gas), so it is important to make fallback functions as cheap as possible. In particular, the following operations will consume more gas than the stipend provided to a fallback function (updating state variable a to 100):

Writing to storage Creating a contract Calling an external function which consumes a large amount of gas Sending Ether

When Using Transfer, Send or call method, 2300 gas is forwarded to the receiving contract, Is this valid for payable addresses also, If yes what can they do with it

1 Answer 1

1

We cannot foward custom gas when using .send(value) or .transfer(value). But we certainly can for .call{gas: anyGasYouWant, value: value}("") or while calling any payable function of a contract.

Take a look at the following example. The Receiving contract receives eth in 3 different ways, through the receive() external payable, fallback() external payable and the custom function receiveFunds() public payable function.

Notice how I'm updating a state variable counter inside each of these eth-receiving functions because reading and updating a state variable costs more than 20k gas, which will allow us to test if the gas we are forwarding to the contract allows us to do this operation. Also, I'm emitting an event that logs the gas left.

In the Sending contract, notice how while using .send and .transfer to send some eth, it fails due to an out-of-gas exception because we cannot forward more gas with these functions. But while using .call and calling a custom function, it works alright because we are able to forward custom gas this way.

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

contract Receiving {
    uint256 public counter;
    event Received(uint256 amount, uint256 gas);

    receive() external payable {
        uint256 gas = gasleft();
        emit Received(msg.value, gas);
        counter++;
    }

    fallback() external payable {
        uint256 gas = gasleft();
        emit Received(msg.value, gas);
        counter++;
    }

    function receiveFunds() public payable {
        uint256 gas = gasleft();
        emit Received(msg.value, gas);
        counter++;
    }

    function getBalance() public view returns(uint256) {
        return address(this).balance;
    }

}

contract Sending {

    event Sent(uint256 count, uint256 gas);

    // transact to Counter.sendFundsWithSend errored: Exceeds block gas limit
    function sendFundsWithSend(address payable receiving) public payable {
        
        // receiving.send{gas: 5000}(msg.value); // Not valid syntax

        emit Sent(1, gasleft());

        bool success = receiving.send(msg.value);
        require(success, "Error with .send");

        emit Sent(2, gasleft());

    }

    // transact to Counter.sendFundsWithTransfer errored: Exceeds block gas limit
    function sendFundsWithTransfer(address payable receiving) public payable {

         // receiving.transfer{gas: 5000}(msg.value); // Not valid syntax

        emit Sent(1, gasleft());

        receiving.transfer(msg.value);

        emit Sent(2, gasleft());

    }

    // Works alright
    function sendFundsWithCall(address payable receiving) public payable {

        emit Sent(1, gasleft());

        (bool success, ) = receiving.call{gas: gasleft(), value: msg.value}("");

        require(success, "Error with .call");

        emit Sent(2, gasleft());

    }

    // Works alright
    function sendFundsToFunction(address payable receiving) public payable {
        emit Sent(1, gasleft());
        Receiving(receiving).receiveFunds{gas: gasleft(), value: msg.value}();
        emit Sent(2, gasleft());
    }

    function getBalance() public view returns(uint256) {
        return address(this).balance;
    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.