Force-feeding is an attack where an attacker forcefully sends Ether directly to a smart contract address without calling any of its functions. This action can disrupt the contract's internal accounting mechanisms, especially if the contract relies on strict equality checks on its balance for any logic or condition.
If a contract does not have a receive or fallback function to handle these transfers, the Ether will still be sent to the contract's balance, but the contract will not execute any code to account for it internally.
How smart contracts receive Ether
Unlike externally owned accounts (EOAs), smart contracts have more control over how they receive and handle funds. Typically, when Ether is sent to a smart contract, the Ethereum Virtual Machine (EVM) follows a specific order of operations to determine how to handle the incoming funds. The process involves checking for the presence of specific functions designed to handle Ether transfers:
Check for a receive Function:
If a contract has a receive function defined and is marked as payable, this function will be executed when the contract receives Ether without data.
If a contract does not have a receive or fallback function to handle these transfers, the Ether will still be sent to the contract's balance, but the contract will not execute any code to account for it internally.
How smart contracts receive Ether
Unlike externally owned accounts (EOAs), smart contracts have more control over how they receive and handle funds. Typically, when Ether is sent to a smart contract, the Ethereum Virtual Machine (EVM) follows a specific order of operations to determine how to handle the incoming funds. The process involves checking for the presence of specific functions designed to handle Ether transfers:
Check for a receive Function:
If a contract has a receive function defined and is marked as payable, this function will be executed when the contract receives Ether without data.
Check for a fallback Function:
If there is no receive function, or if Ether is sent with data, the contract will check for a fallback function. If this function is defined and marked as payable, it will be executed to handle the incoming Ether.
Revert:
If neither a receive nor a fallback function is defined (or if they are not marked as payable), the transaction will revert, meaning the transfer will fail, and the Ether will not be sent to the contract.
This is where force-feeding can come into play:
deliberately sending Ether to a smart contract address even when there are no mechanisms within the contract to handle incoming Ether. Force-feeding bypasses the normal behavior of smart contracts, where transfers would typically be reverted if the contract does not have appropriate receive or fallback functions.
Force Feeding Methods
1. Selfdestruct: Although Selfdestruct was deprecated during the Shanghai Ethereum upgrade, it is a method an attacker can use for force-feeding a contract address.
When a contract is destroyed using selfdestruct, its remaining Ether balance is transferred to a specified address. This transfer happens at the EVM level, bypassing Solidity-level mechanisms such as the receive and fallback functions.
Let's consider a simple smart contract, GameBet, that allows users to deposit exactly 1 ETH for a game bet and relies on address(this).balance for its internal accounting:
If now this contract has two bets and a malicious user force-feeds this contract with ETH, it will never be possible to finish the game.
2. Block Rewards and Coinbase
In proof-of-work, miners (or validators in a proof-of-stake system) receive block rewards for successfully adding a new block to the blockchain. These rewards are sent to a designated address known as the coinbase address. Normally, miners set their own wallet address as the coinbase address to collect these rewards. However, an attacker who is also a miner can set the coinbase address to the address of a target smart contract. This means that the block rewards for mining a new block will be sent directly to the smart contract's address.
The transfer of block rewards to the coinbase address is handled at the protocol level, bypassing any Solidity-level checks or functions such as receive and fallback. Consequently, the target contract will receive Ether directly as part of the block reward, regardless of any restrictions coded into the contract.
How to prevent Force Feeding
Refuse to Use the Contract's Balance Directly:
Instead of using address(this).balance for critical logic, rely exclusively on an internal balance tracking mechanism that can account for only valid deposits.
Immediate Funds Transfer:
Instead of holding funds within the contract, immediately transfer received Ether to a secure, off-contract storage or another smart contract that handles funds securely.
Event-based Balance Tracking:
Use events to track deposits and withdrawals, combined with off-chain validation to monitor and cross-check the contract's balance against its internal state.