18

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?

0
21

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.

Case 1: 2300 gas

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?

Case 2: As much gas as it gets, watch out for security

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...

4
  • Is recipient.call.gas(2300).value(...) equivalent to recipient.call.gas(0).value(...)? Nov 15 '17 at 10:21
  • 1
    @K._ No, the former sends 2300 more gas.
    – eth
    Dec 5 '17 at 16:27
  • 2
    Important Update: as of May 2021, using send and transfer is no longer considered safe. Use call{value: amount}("") instead. Oct 13 at 8:14
  • @PaulRazvanBerg Thanks, added the Note to Case1 and also updated the Solidity syntax.
    – eth
    Oct 17 at 1:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.