ERC-1363 Payable Token
Final · Tokens · created 2018-08-30
A standard that lets an ERC-20 token transfer or approval immediately run code in the receiving contract within the same transaction.
Why it is needed
With an ERC-20 token, there is no way for the receiving side to run any code after a transfer or an approve. So to pay for something with a token and trigger an action in response to that payment, you first have to send one transaction that sends the tokens and then send another transaction so that the receiving side notices it. Sending two transactions costs gas (GAS) fees twice, and the receiving side has to depend on a separate mechanism (a listener) that watches transfers. When you want to bundle a payment and the action that follows it into one step, such as selling a service for tokens, paying an invoice, or setting up a subscription, this process is cumbersome and costly.
What to implement
function transferAndCall(address to, uint256 value) external returns (bool);: Sends tokens to to, then calls onTransferReceived on the receiving contract.function transferAndCall(address to, uint256 value, bytes memory data) external returns (bool);: Sends tokens to to and calls onTransferReceived, passing additional data (data) along.function transferFromAndCall(address from, address to, uint256 value) external returns (bool);: Sends from's tokens to to, then calls onTransferReceived on the receiving contract.function transferFromAndCall(address from, address to, uint256 value, bytes memory data) external returns (bool);: Sends from's tokens to to and calls onTransferReceived, passing additional data along.function approveAndCall(address spender, uint256 value) external returns (bool);: Approves spender to use value, then calls onApprovalReceived on that contract.function approveAndCall(address spender, uint256 value, bytes memory data) external returns (bool);: Approves use and calls onApprovalReceived, passing additional data along.function onTransferReceived(address operator, address from, uint256 value, bytes memory data) external returns (bytes4);: The callback with which a contract that received tokens handles the transfer. It must return the specified magic value for the transfer to go through.function onApprovalReceived(address owner, uint256 value, bytes memory data) external returns (bytes4);: The callback with which a contract that was granted approval handles the approval. It must return the specified magic value for the approval to go through.
In depth
Interfaces to implement
A contract that implements ERC-1363 must implement the ERC-20 and ERC-165 interfaces along with the ERC-1363 interface. ERC-1363 adds callbacks to ERC-20 operations such as transfer, transferFrom and approve. It does not override the existing transfer and transferFrom, and adds separate functions instead. As a result, ERC-20 backward compatibility is preserved.
Transfer functions and onTransferReceived
transferAndCall and transferFromAndCall move tokens and then call onTransferReceived on the receiving address. transferAndCall sends from msg.sender to to, and transferFromAndCall sends from from to to. Each has a version without data and a version that also passes data, which is extra data with no fixed format that is forwarded with the call. Every function returns true unless it throws an exception. A contract that wants to receive token payments must implement the ERC1363Receiver interface.
Approval functions and onApprovalReceived
approveAndCall approves spender to use value tokens and then calls onApprovalReceived on spender. It has a version without data and a version that passes data. A contract that wants to receive approval payments must implement the ERC1363Spender interface. This design was inspired by the onERC721Received and ERC721TokenReceiver behavior in ERC-721.
Magic values and revert rules
onTransferReceived must return bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)")), and onApprovalReceived must return bytes4(keccak256("onApprovalReceived(address,uint256,bytes)")). If either returns any value other than this magic value, the transaction must revert. A callback can also reject a transfer or approval by throwing an exception. In both callbacks, the message sender (msg.sender) is always the token contract address. The operator, from and owner parameters distinguish the actual caller and the source of the tokens.
ERC-165 identifiers
The ERC-165 identifier of the ERC-1363 interface is 0xb0202a11, which is the XOR of the bytes4 keccak256 hashes of the six function signatures. The identifier of ERC1363Receiver is 0x88a7ca5c, and the identifier of ERC1363Spender is 0x7b04a2d0. By querying these identifiers with supportsInterface, you can check whether a token and a receiver support each interface.
Things to watch out for
- Approval race condition: approveAndCall and transferFromAndCall can have the same problem as ERC-20 approve and transferFrom. When the allowance is changed with approveAndCall, if transactions are ordered unfavorably, someone could use both the old and the new allowance. One way to mitigate this is to first reduce the spender's allowance to 0 and then set the desired value.