Simply sending Ether to a contract, will run the contract's code. In Solidity, this code maps to what it calls the fallback function.
How much work can be done in a fallback function?
Ethereum Stack Exchange is a question and answer site for users of Ethereum, the decentralized application platform and smart contract enabled blockchain. It only takes a minute to sign up.
Sign up to join this communitySimply sending Ether to a contract, will run the contract's code. In Solidity, this code maps to what it calls the fallback function.
How much work can be done in a fallback function?
The fallback function can do as much computation as how much gas it gets.
There are 2 cases (basically recipient.send
and recipient.call{value:...}("")
) and case 2 has security implications and is a key part of how theDAO was attacked and exploited on June 17 2016.
A recipient
contract's fallback function only gets a 2300 gas stipend if it was invoked with recipient.transfer
or recipient.send
. This is the same as an external account paying recipient
with web3.eth.sendTransaction({to:recipient, gas:21000, ...})
.
The last part of an Ethereum blog post explains:
If you want your contract to receive Ether, you have to make its fallback function cheap. It can only use 2300 gas which neither allows any storage write nor function calls that send along Ether. Basically the only thing you should do inside the fallback function is log an event so that external processes can react on the fact.
Examples of an external process include web3.js filters and watches.
Note: Since Dec 2019, recipient.transfer
and recipient.send
are no longer recommended: Is transfer() still safe after the Istanbul update?
recipient.call{value:...}("")
(and using related functions like .callcode
, .delegatecall
) will provide the fallback function with virtually[1] as much gas as the caller has remaining.
To obtain the same effects (2300 gas stipend) and security as Case 1, callers must explicitly limit the gas to zero when invoking the recipient
by:
recipient.call{gas: 0, value: ...}("")
(theDAO did not limit the gas and suffered a reentrant attack on June 17 2016.)
Footnotes
[1] Explanation of why a fallback function gets almost all, but not all of the gas. chriseth (Solidity author) said:
This is one of the quirky places of the EVM. You cannot just say "send all my gas along with the call", you always have to give an explicit number. We do have the GAS opcode which gives us the amount of gas still available, but the problem is that performing the call itself also costs some gas, so we have to subtract the amount of gas the call costs from the value provided by GAS, and we also have to subtract the amount of gas it costs to perform the subtraction...
recipient.call.gas(2300).value(...)
equivalent to recipient.call.gas(0).value(...)
?
Nov 15, 2017 at 10:21
send
and transfer
is no longer considered safe. Use call{value: amount}("")
instead.
Oct 13, 2021 at 8:14