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.
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:
Destructed
contract with 1 ETHRecipient
contract without ETHDestructed
contract, effectively passing the 1 ETH to Recipient
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);
}
}
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.