selfdestruct Explained in Detail
selfdestruct is an EVM instruction that sends a contract's Ether balance to a target address. After EIP-6780, code and storage removal is limited in most cases, but forced Ether transfer remains important for audits.
Contracts cannot prevent Ether from arriving through selfdestruct.
selfdestruct is deprecated, so new usage should be treated as a design red flag unless there is a strong reason.
Smart contract example
A contract can force Ether into a target:
contract ForceSend {
constructor() payable {}
function boom(address payable target) external {
selfdestruct(target);
}
}
The target receives Ether even if it has no receive() function.
selfdestruct in Auditing
Forced Ether can break accounting that assumes address(this).balance only changes through deposits. It also matters when reviewing receive functions, vault solvency checks, upgrade flows, and emergency shutdown logic.
Red flags in code
-
Contract logic depends directly on
address(this).balance. -
Exact-balance checks such as
balance == totalDeposits. -
Privileged
selfdestructor shutdown function with weak access control. -
Assumptions that a contract cannot receive Ether without calling
deposit(). -
Old documentation or comments that rely on pre-EIP-6780 destruction behavior.
How to test or review it
-
Force-send Ether to the contract and check accounting invariants.
-
Review shutdown and rescue functions for authorization and ordering.
-
Avoid using raw contract balance as the only source of accounting truth.
-
Check whether external calls depend on exact Ether balances.
-
Confirm the codebase's threat model matches current EVM semantics.