Sending Ether in Solidity
Overview
When sending ether to someone from our contract, the address of our contract is the sender address.
We can specify the receiver to be any payable
address
.
address payable to = 0x…;
When sending, we can define how much ether we want to send.
uint amount = 1 ether;
To send the ether we can choose between 3 functions available on the receiver address variable:
Send
to.send(amount);
Transfer
to.transfer(amount);
Call
to.call{value: amount}();
How to differentiate
All 3 functions: send
, transfer
and call
can be used to send a given amount of eher to a given address.
However, the functions work differently in the following aspects:
Gas
When we execute smart contracts, we need to pay for the execution.
We pay with gas.
When we send ether, we also want to forward gas.
This way the receiver can use the gas to process the incoming ether.
When looking at the different functions to send ether, there are some differences about:
- If we can define the amount of gas we want to forward
- And how much gas is forwarded
Error handling
When we try to send ether with our contracts, sending for some reason may fail.
And in solidity there are different ways to handle errors.
Comparing the different functions to send ether:
A function may already handle a possible failure and revert
the call.
Or the function does not handle failure internally. Instead it returns a bool
indicating success or failure. In this case we have to implement error handling by ourselves.
Transfer
address payable to;
to.transfer(amount);
Gas
Sending with transfer
will forward a fixed amount of 2300
gas.
We have no control on this, there is no way to forward a custom amount of gas to the receiver.
Error handling
Possible failure is automatically covered by transfer
, so we don’t have to implement it by ourselves.
When transfer
fails, it automatically revert
s and all changes on the current state are rolled back.
Send
address payable to;
bool success = to.send(amount);
Gas
send
’s behaviour in terms of gas is exactly the same as with transfer
:
It will forward a fixed amount of 2300
gas. We can not change this.
Error handling
Possible failure is not automatically covered by send
, we have to implement it by ourselves.
The status is returned as a bool
.
To handle failure we can make use of one of the multiple ways to handle errors in solidity.
require(success, "not send");
if (!success) {
revert("not send");
}
error FailedTransfer();
...
if (!success) {
revert FailedTransfer;
}
Call
(bool success,) = to.call{value: amount}("");
Gas
When we use call
to send ether, we can set a custom amount of gas we would like to forward:
(bool success,) = to.call{value: amount, gas: 10000 wei}("");
Error handling
As with send
, call
will not handle a failed transaction automatically for us.
The first return value we get back is a bool
that indicated success or failure.
Based on this we have to implement corresponding error handling.
What should we use?
The fixed amount of 2300 gas we get with transfer
and send
may not be enough for the recipient to process.
This especially is true, since gas prices can and may change.
Because of this it makes to use call
, where we can define a custom amount of gas that gets forwarded.