Can somebody please explain the differences between using a send and call for contracts and when to use and not use these different methods?

For example :

   msg.sender.send(number);  
   msg.sender.call.value(number)();

I know that send uses 2300 gas and that using call does not use any gas.

Both call the fallback function, but with different amounts of gas "forwarded".

msg.sender.send(number);

is the same as:

msg.sender.call.gas(0).value(number)();

send is safer to use since by default it doesn't forward any gas, so the receiver's fallback function can only emit events. See How much computation can be done in a fallback function?


At the system level, both .send and .call use the CALL opcode of the EVM (there's no separate opcode for sending ether). The difference is that .send always passes 0 as the gas argument to the CALL opcode.

Additional information on the CALL opcode:

CALL has a multi-part gas cost:
* 700 base
* 9000 additional if the value is nonzero
* 25000 additional if the destination account does not yet exist (note: there is a difference between zero-balance and nonexistent!)
  • Thanks for the answer but I was also looking for more information about how these different methods work on the system level. For example, does the call method generate transactions on the blockchain? – Alex Darby Jun 23 '16 at 18:26
  • A .call does not create a transaction; just wrote this which has other details you may be looking for: ethereum.stackexchange.com/a/6477/42 – eth Jun 23 '16 at 18:54
  • 2
    I think send sends more than 0 gas, doesn't it? It sends 23000 – Tjaden Hess Jun 23 '16 at 23:42
  • 1
    send sends 0 gas, but there's an EVM rule that the receiver always gets a stipend of 2,300 gas (so that if it wants, it always has enough gas to log that it received something). – eth Jul 12 '16 at 3:33
  • Alex Darby is probably confusing .call from Javascript (no transaction) with .call in Solidity (already in a transaction). – Xavier Leprêtre B9lab Aug 23 '16 at 23:26

1 Send() does not forward gas anymore. It simply uses the hardcoded stipend (2300 gas) siphoned from the value transfer cost (minimum 9040). It's enough to send ether, but also enough to basically do one additional small logging operation (in a fallback function). The following operations will consume more gas than the stipend provided to a fallback function:

• Writing to storage

• Creating a contract

• Calling an external function which consumes a large amount of gas

• Sending Ether

2 If a send() call runs out of gas, it does not throw an error, it simply returns false.

from solidity Doc:

If a contract receives Ether (without a function being called), the fallback function is executed. The contract can only rely on the “gas stipend” (2300 gas) being available to it at that time. This stipend is not enough to access storage in any way. To be sure that your contract can receive Ether in that way, check the gas requirements of the fallback function (for example in the “details” section in browser-solidity).

• There is a way to forward more gas to the receiving contract using addr.call.value(x)(). This is essentially the same as addr.send(x), only that it forwards all remaining gas and opens up the ability for the recipient to perform more expensive actions. This might include calling back into the sending contract or other state changes you might not have though of. So it allows for great flexibility for honest users but also for malicious actors.

Warning: Contracts that receive Ether but do not define a fallback function throw an exception, sending back the Ether (this was different before Solidity v0.4.0). So if you want your contract to receive Ether, you have to implement a fallback function.

  • Good points. For clarity to readers, "does not throw an error, it simply returns false" also applies to .call(). And can't emphasize enough that .call() "allows for great flexibility for honest users but also for malicious actors." – eth Jan 17 '17 at 22:15

address.transfer()

  • throws on failure
  • forwards 2,300 gas stipend, safe against reentrancy
  • should be used in most cases as it's the safest way to send ether

address.send()

  • returns false on failure
  • forwards 2,300 gas stipend, safe against reentrancy
  • should be used in rare cases when you want to handle failure in the contract

address.call.value().gas()()

  • returns false on failure
  • forwards all available gas, allows specifying how much gas to forward
  • should be used when you need to control how much gas to forward when sending ether or to call a function of another contract

You can read more details here https://ethereum.stackexchange.com/a/38642/18932

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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