1

I'm learning solidity I got two methods for transferring ether

  1. <address payable>.send(1 ether)
  2. <address payable>.transfer(1 ether)

Both are used to transferring ether to the recipient address but what is the difference between them, and where should we use transfer or send.

Rob Hitchens
  • 55,151
  • 11
  • 89
  • 145
Rathore
  • 115
  • 1
  • 7

1 Answers1

4

Short answer

  • .send() returns a boolean result for success/failure.
  • .transfer() reverts on failure.

.send() is the original method. If the receiver is a contract, flow control will be transfered to the receiver's fallback function until it returns.

Long answer

They can fail if the receiver is a contract that doesn't want the money, and there are many good reasons why that might be the case. It is almost always best to revert if the send was unsuccessful.

Therefore, in old syntax, a good pattern was:

bool success = <address>.send(amount);
if(!success) throw; // revert() in newer compilers, possibly require instead of if()

Developers would not always remember (or know) to do that, so the contract might carry on assuming money has been sent when it wasn't ... bugs.

There are few occasions when it would be appropriate to transfer assets, update accounting or generally carry on if the transfer actually failed, but .send() provides a way to do that:

bool success = <address>.send(amount);
if(!success) {
  // deal with the failure case
} else {
  // deal with the success case
}

Reentrance

Reentrance was discovered with the DAO incident. "Checks, effects, interactions" is a defensive pattern, meaning:

  1. Validation
  2. Optimistic accounting
  3. send, transfer or call

So, you get something like:

balances[msg.sender] -= amount; // optimistic accounting
bool success = <address>.send(amount);
if(!success) {
  // failure case
  balances[msg.sender] += amount; // put it back
...

In most cases, one doesn't want to continue and one does want to revert the optimistic accounting, so:

balances[msg.sender] -= amount;
<address>.transfer(amount); // will revert on failure
// success, carry on

Hope it helps.

Rob Hitchens
  • 55,151
  • 11
  • 89
  • 145
  • Thanks, Rob for this descriptive answer. – Rathore Feb 18 '20 at 03:32
  • 1
    When you say "//will revert on failure" in your last code snippet do you mean that "balances[msg.sender] -=amount" will automatically be reversed? i.e. no need to code that explicitly like in the .send example? Thanks. – john blair Aug 19 '21 at 09:39
  • That is correct. – Rob Hitchens Aug 19 '21 at 14:18
  • Why would you want to .transfer(amount) and at the same time deduct amount from the balance? – sunwarr10r Dec 25 '21 at 15:38
  • In many cases, contracts have internal accounting concerns as well as the actual receipt and sending of funds. Consider a simple ATM. If Alice and Bob both deposit funds then the contract has a balance that is the sum of both deposits. The contract can transfer funds to Alice or Bob and its funds on hand will indeed adjust. However, it cannot know its liabilities to either user user - how much is owed to Alice? - unless it attends to accounting. This is what the balances mapping is doing in the example. – Rob Hitchens Dec 26 '21 at 08:40