ethereumsolidityself-destruction

Does selfdestruct in Solidity provide enough gas to execute a receive function?


I'm trying to understand how the receive function behaves when it's triggered by a selfdestruct call in Solidity. I've read that selfdestruct only provides 5000 gas for executing any fallback or receive logic in the receiving contract.

However, I also know that 5000 gas might be just the minimum cost to execute the selfdestruct operation itself, not necessarily the amount forwarded to the recipient. This makes me wonder if the receive function can actually run with such limited gas and what kind of operations, if any, could be performed within this limit.

I looked into the gas costs for typical Ether transfers, like using send() or transfer(), which provide 2300 gas, and I understand these can be insufficient for anything beyond very simple logic. I also considered using call.value().gas() to forward a custom amount of gas. But when it comes to selfdestruct, I'm unsure whether the gas provided is really capped at 5000 or if it can vary depending on the remaining gas after execution.

I'm hoping to get clarification on whether the receive function can execute in these circumstances and what kind of logic might be feasible within the provided gas.


Solution

  • There is no limit for executing fallback() nor receive() from selfdestruct() because it does not invoke these functions on the recipient contract.

    It's possible that the 5,000 gas-related value that you read, was the cost (in gas units) of executing the selfdestruct opcode itself. But this represents just the cost of executing this specific operation - not how much gas is sent along to the recipient to process the incoming funds. See the yellowpaper, page 28.

    Calling selfdestruct() is actually one of the ways how to force send ETH to a contract that doesn't implement these functions and rejects all other incoming ETH transfers.

    See the example below:

    1. Deploy Destructed contract with 1 ETH
    2. Deploy Recipient contract without ETH
    3. Destruct Destructed contract, effectively passing the 1 ETH to Recipient
    4. Even though Recipient doesn't implement fallback() nor receive() functions, it was able to accept the incoming ETH.
    pragma solidity 0.8.26;
    
    contract Recipient {
        // doesn't implement `fallback()` nor `receive()`
    }
    
    contract Destructed {
        constructor() payable {}
    
        function destruct(address payable recipient) external {
            selfdestruct(recipient);
        }
    }
    

    Recipient contract received ETH


    Note from the docs page:

    From EVM >= Cancun onwards, selfdestruct will only send all Ether in the account to the given recipient and not destroy the contract.