Solidity has a receive
keyword. What is it and how do I use it?
1 Answer
TL;DR
receive
is a new keyword in Solidity 0.6.x that is used as a fallback function that is only able to receive ether.
receive() external payable
— for empty calldata (and any value)fallback() external payable
— when no other function matches (not even the receive function). Optionallypayable
.
Long Answer
Solidity 0.6.x introduced the receive
keyword in order to make contracts more explicit when their fallback functions are called. The receive
method is used as a fallback function in a contract and is called when ether is sent to a contract with no calldata. If the receive
method does not exist, it will use the fallback
function.
From the docs:
A contract can have at most one
receive
function, declared usingreceive() external payable { ... }
(without thefunction
keyword). This function cannot have arguments, cannot return anything and must haveexternal
visibility andpayable
state mutability. It is executed on a call to the contract with empty calldata. This is the function that is executed on plain Ether transfers (e.g. via .send() or .transfer()). If no such function exists, but a payable fallback function exists, the fallback function will be called on a plain Ether transfer. If neither a receive Ether nor a payable fallback function is present, the contract cannot receive Ether through regular transactions and throws an exception.
To use it, you can include it in your contract in the following way:
pragma solidity ^0.6.0;
// This contract keeps all Ether sent to it with no way
// to get it back.
// This is example code. Do not use it in production.
contract Sink {
event Received(address, uint);
receive() external payable {
emit Received(msg.sender, msg.value);
}
}
When evaluating whether to use receive
or fallback
, consider the following:
This is why in version 0.6.x, the fallback function was split into two separate functions:
receive() external payable
— for empty calldata (and any value)fallback() external payable
— when no other function matches (not even the receive function). Optionallypayable
.
This separation provides an alternative to the fallback function for contracts that want to receive plain ether.
Edit based on Ismael's comment: The 2300 gas stipend required by .send()
and .transfer()
apply to receive()
in the same way that they apply to .transfer()
. Additionally, contracts compiled with pre-0.6.0 solc versions are able to interact with the receive()
function.
Additional information can be found in the Ethereum blog post here.
-
2Are these functions subject to gas stipend of 2300 gas? Are they compatible with previous versions of solidity? ie a contract compiled with an old version solc will be able to make a transfer to contracts compiled with 0.6?– Ismael ♦Mar 30, 2020 at 20:55
-
3The 2300 gas stipend is a limitation of
send
andtransfer
, not of the fallback function. With that said, the 2300 gas stipend behaves the same from the perspective of bothfallback()
andreceive()
. Mar 31, 2020 at 15:42 -
1And yes, older contracts (pre 0.6.x) can interact with new contracts that have the receive function. The following gist is what I used to test your questions: gist.github.com/shanefontaine/5bd2a40f6d967748710850d61ebf1bbf Mar 31, 2020 at 15:49
-
1It should be noted that if fallback() gets triggered because no receive() method exists, then in that case fallback() is restricted to 2300 gas, even if .call() was used to send ether.– erwamanApr 24, 2020 at 18:18
-
4