Unexpected Ether Transfers (Force Feeding)¶
Forcing a smart contract to hold an Ether balance can influence its internal accounting and security assumptions. There are multiple ways a smart contract can receive Ether. The hierarchy is as follows:
- Check whether a payable external
receivefunction is defined.
- If not, check whether a payable external
fallbackfunction is defined.
The precedence of each function is explained in this great graphic from the Solidity by Example article:
1 2 3 4 5 6 7 8 9 10 11 12 13
Consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12
The contract's logic seemingly disallows direct payments and prevents "something bad" from happening. However, calling
revert in both
receive cannot prevent the contract from receiving Ether. The following techniques can be used to force-feed Ether to a smart contract.
SELFDESTRUCT opcode is called, funds of the calling address are sent to the address on the stack, and execution is immediately halted. Since this opcode works on the EVM-level, Solidity-level functions that might block the receipt of Ether will not be executed.
Additionally, the target address of newly deployed smart contracts is generated deterministically. The address generation can be looked up in any EVM implementation, such as the py-evm reference implementation by the Ethereum Foundation:
An attacker can send funds to this address before the deployment has happened. This is also illustrated by this 2017 Underhanded Solidity Contest submission.
Block Rewards and Coinbase¶
Depending on the attacker's capabilities, they can also start proof-of-work mining. By setting the target address to their
coinbase, block rewards will be added to its balance. As this is yet another EVM-level capability, checks performed by Solidity are ineffective.
The above effects illustrate that relying on exact comparisons to the contract's Ether balance is unreliable. The smart contract's business logic must consider that the actual balance associated with it can be higher than the internal accounting's value.
Generally, using the contract's balance as a guard is not advisable.