Three methods to send ether by means of Solidity

Kirill Bulgakov
Daox
Published in
3 min readFeb 20, 2018

Solidity supports several methods of transferring ether between the contracts. This article takes a detailed look at three variants and the main differences between them. There will also be suggestions given as to the use of one or another method depending on a specific situation.

1. address.send(amount)

The first method which was introduced for transferring ether is send(). It has two details that should be considered.

First and the most important characteristic is providing 2300 gas limit for execution the fallback function of a contract receiving ether. By the way, this quantity will be sufficient only to create one event.

For instance, the code listed below works correctly:

contract Sender {
function send(address _receiver) payable {
_receiver.send(msg.value);
}
}
contract Receiver {
uint public balance = 0;
event Receive(uint value);

function () payable {
Receive(msg.value);
}
}

The second important aspect that should be paid attention to is as follows: unsuccessful execution of send(), for example out of gas error returns false, but does not throw an exception. Hence, each usage of send() should be inside of require. Otherwise you will pay for gas to proceed a transaction submission in the blockchain, but all the state changes will be undone.

For example, it only takes to change a bit the payable function in the Receiver contract:

function () payable {
Receive(msg.value);
balance += msg.value;
}

and your transaction will have a successful receipt, however the status will not change, as an out of gas error has occurred:

2. address.transfer(amount)

Let us consider a method that appeared in the later versions of solidity. It has two details worth mentioning as well.

First, this method has the same 2300 gas limit. However during the development process of these features the developers discussed an opportunity to add .gas() modifier, which redefines the limit of the provided gas.

Second, unlike send()method, transfer()throws exception when performed unsuccessfully. Thus, you get to know that your transaction is unsuccessful right at the execution attempt. Ethereum wallet or metamask will notify you about that:

3. address.call.value(amount)( )

The last and most customized method.

The given function still returns false in case an error occurs, that is why keep the usage of require() in mind.

Its principal difference from the two previous functions is an opportunity to set gas limit via .gas(gasLimit) modifier. It is necessary in case the payable function of the contract receiving ether performs a complex logic, that requires plenty of gas.

Let us take a look at the following example:

contract Sender {
function send(address _receiver) payable {
_receiver.call.value(msg.value).gas(20317)();
}
}
contract Receiver {
uint public balance = 0;

function () payable {
balance += msg.value;
}
}

Execution of the payable function in the Receiver contract costs more than 20 thousand gas. That is why, usage of send() or transfer() would cause an out of gas error. However thanks to gas() modifier the above-mentioned example works correctly.

Please notice that this method is not safe against reentrancy and impact on the contract could be worse than its potential flexibility. Check out this blogpost for more details.

Summary

Finally, let me share a chart which might guide you when choosing a suitable function according to the assigned task.

--

--