2018-04-06 13:52:05 +00:00
|
|
|
---
|
|
|
|
eip: 777
|
|
|
|
title: A New Advanced Token Standard
|
2019-03-03 15:42:45 +00:00
|
|
|
author: Jacques Dafflon <mail@0xjac.com>, Jordi Baylina <jordi@baylina.cat>, Thomas Shababi <tom@truelevel.io>
|
2018-04-06 13:52:05 +00:00
|
|
|
discussions-to: https://github.com/ethereum/EIPs/issues/777
|
|
|
|
status: Draft
|
|
|
|
type: Standards Track
|
|
|
|
category: ERC
|
|
|
|
created: 2017-11-20
|
2019-03-08 11:54:37 +00:00
|
|
|
requires: 1820
|
2018-04-06 13:52:05 +00:00
|
|
|
---
|
|
|
|
|
|
|
|
## Simple Summary
|
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
This EIP defines standard interfaces and behaviors for token contracts.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
## Abstract
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
This standard defines a new way to interact with a token contract while remaining backward compatible with [ERC20].
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
It defines advanced features to interact with tokens.
|
|
|
|
Namely, *operators* to send tokens on behalf of another address—contract or regular account—and
|
|
|
|
send/receive *hooks* to offer token holders more control over their tokens.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
It takes advantage of [ERC1820] to find out whether and where to notify contracts and regular addresses
|
|
|
|
when they receive tokens as well as to allow compatibility with already-deployed contracts.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
## Motivation
|
|
|
|
|
2019-04-09 20:50:48 +00:00
|
|
|
This standard tries to improve upon the widely used [ERC20] token standard.
|
2019-03-26 00:21:07 +00:00
|
|
|
The main advantages of this standard are:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
1. Uses the same philosophy as Ether in that tokens are sent with `send(dest, value, data)`.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
|
|
|
2. Both contracts and regular addresses can control and reject which token they send
|
|
|
|
by registering a `tokensToSend` hook.
|
|
|
|
(Rejection is done by `revert`ing in the hook function.)
|
|
|
|
|
|
|
|
3. Both contracts and regular addresses can control and reject which token they receive
|
|
|
|
by registering a `tokensReceived` hook.
|
|
|
|
(Rejection is done by `revert`ing in the hook function.)
|
|
|
|
|
|
|
|
4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction,
|
2019-04-09 20:50:48 +00:00
|
|
|
unlike [ERC20] which requires a double call (`approve`/`transferFrom`) to achieve this.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
5. The holder can "authorize" and "revoke" operators which can send tokens on their behalf.
|
2019-03-26 00:21:07 +00:00
|
|
|
These operators are intended to be verified contracts
|
|
|
|
such as an exchange, a cheque processor or an automatic charging system.
|
|
|
|
|
|
|
|
6. Every token transaction contains `data` and `operatorData` bytes fields
|
2019-03-26 00:34:30 +00:00
|
|
|
to be used freely to pass data from the holder and the operator, respectively.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
|
|
|
7. It is backward compatible with wallets that do not contain the `tokensReceived` hook function
|
|
|
|
by deploying a proxy contract implementing the `tokensReceived` hook for the wallet.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
## Specification
|
|
|
|
|
|
|
|
### ERC777Token (Token Contract)
|
|
|
|
|
|
|
|
``` solidity
|
|
|
|
interface ERC777Token {
|
2019-03-25 00:12:29 +00:00
|
|
|
function name() external view returns (string memory);
|
|
|
|
function symbol() external view returns (string memory);
|
2019-03-04 01:12:53 +00:00
|
|
|
function totalSupply() external view returns (uint256);
|
2019-03-26 00:34:30 +00:00
|
|
|
function balanceOf(address holder) external view returns (uint256);
|
2019-03-04 01:12:53 +00:00
|
|
|
function granularity() external view returns (uint256);
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-25 00:12:29 +00:00
|
|
|
function defaultOperators() external view returns (address[] memory);
|
2019-03-26 00:34:30 +00:00
|
|
|
function isOperatorFor(address operator, address holder) external view returns (bool);
|
2019-03-04 01:12:53 +00:00
|
|
|
function authorizeOperator(address operator) external;
|
|
|
|
function revokeOperator(address operator) external;
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-25 00:12:29 +00:00
|
|
|
function send(address to, uint256 amount, bytes calldata data) external;
|
|
|
|
function operatorSend(
|
|
|
|
address from,
|
|
|
|
address to,
|
|
|
|
uint256 amount,
|
|
|
|
bytes calldata data,
|
|
|
|
bytes calldata operatorData
|
|
|
|
) external;
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-25 00:12:29 +00:00
|
|
|
function burn(uint256 amount, bytes calldata data) external;
|
|
|
|
function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external;
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
event Sent(
|
|
|
|
address indexed operator,
|
|
|
|
address indexed from,
|
|
|
|
address indexed to,
|
|
|
|
uint256 amount,
|
2018-07-20 10:11:59 +00:00
|
|
|
bytes data,
|
2018-04-06 13:52:05 +00:00
|
|
|
bytes operatorData
|
|
|
|
);
|
2018-07-31 15:35:49 +00:00
|
|
|
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
|
2019-03-04 00:45:51 +00:00
|
|
|
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);
|
2019-03-26 00:34:30 +00:00
|
|
|
event AuthorizedOperator(address indexed operator, address indexed holder);
|
|
|
|
event RevokedOperator(address indexed operator, address indexed holder);
|
2018-04-06 13:52:05 +00:00
|
|
|
}
|
|
|
|
```
|
2019-03-24 23:56:18 +00:00
|
|
|
The token contract MUST implement the above interface.
|
|
|
|
The implementation MUST follow the specifications described below.
|
|
|
|
|
|
|
|
The token contract MUST register the `ERC777Token` interface with its own address via [ERC1820].
|
|
|
|
This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry
|
|
|
|
with the token contract address as both the address and the implementer
|
|
|
|
and the `keccak256` hash of `ERC777Token` as the interface hash.
|
|
|
|
|
|
|
|
If the contract has a switch to enable or disable ERC777 functions, every time the switch is triggered,
|
|
|
|
the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via ERC1820.
|
|
|
|
Unregistering implies calling the `setInterfaceImplementer` with the token contract address as the address,
|
|
|
|
the `keccak256` hash of `ERC777Token` as the interface hash and `0x0` as the implementer.
|
|
|
|
(See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.)
|
|
|
|
|
|
|
|
When interacting with the token contract, all amounts and balances MUST be unsigned integers.
|
|
|
|
I.e. Internally, all values are stored as a denomination of 1E-18 of a token.
|
2019-03-26 00:21:07 +00:00
|
|
|
The display denomination—to display any amount to the end user—MUST
|
|
|
|
be 10<sup>18</sup> of the internal denomination.
|
2019-03-24 23:56:18 +00:00
|
|
|
|
|
|
|
In other words, the internal denomination is similar to a wei
|
|
|
|
and the display denomination is similar to an ether.
|
|
|
|
It is equivalent to an [ERC20]'s `decimals` function returning `18`.
|
|
|
|
E.g. if a token contract returns a balance of `500,000,000,000,000,000` (0.5×10<sup>18</sup>) for a user,
|
|
|
|
the user interface MUST show `0.5` tokens to the user.
|
|
|
|
If the user wishes to send `0.3` tokens,
|
|
|
|
the contract MUST be called with an amount of `300,000,000,000,000,000` (0.3×10<sup>18</sup>).
|
|
|
|
|
|
|
|
User Interfaces which are generated programmatically from the ABI of the token contract
|
|
|
|
MAY use and display the internal denomination.
|
2019-03-26 00:21:07 +00:00
|
|
|
But this MUST be made clear, for example by displaying the `uint256` type.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
#### **View Functions**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
The `view` functions detailed below MUST be implemented.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`name` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function name() external view returns (string memory)
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2019-03-24 23:56:18 +00:00
|
|
|
Get the name of the token, e.g., `"MyToken"`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `06fdde03`</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>**returns:** Name of the token.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`symbol` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function symbol() external view returns (string memory)
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2019-03-24 23:56:18 +00:00
|
|
|
Get the symbol of the token, e.g., `"MYT"`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `95d89b41`</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>**returns:** Symbol of the token.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`totalSupply` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-04 01:12:53 +00:00
|
|
|
function totalSupply() external view returns (uint256)
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Get the total number of minted tokens.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as
|
|
|
|
returned by the `balanceOf` function.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: The total supply MUST be equal to the sum of all the minted tokens
|
|
|
|
as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `18160ddd`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**returns:** Total supply of tokens currently in circulation.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`balanceOf` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
``` solidity
|
2019-03-26 00:34:30 +00:00
|
|
|
function balanceOf(address holder) external view returns (uint256)
|
2018-07-20 10:11:59 +00:00
|
|
|
```
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
Get the balance of the account with address `holder`.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
The balance MUST be zero (`0`) or higher.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `70a08231`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`holder`: Address for which the balance is returned.</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>**returns:** Amount of tokens held by `holder` in the token contract.</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
**`granularity` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-04 01:12:53 +00:00
|
|
|
function granularity() external view returns (uint256)
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Get the smallest part of the token that's not divisible.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 01:06:08 +00:00
|
|
|
In other words, the granularity is the smallest number of tokens (in the internal denomination)
|
2019-03-26 00:21:07 +00:00
|
|
|
which MAY be minted, sent or burned at any time.
|
2018-08-13 02:52:05 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
The following rules MUST be applied regarding the *granularity*:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-08-13 02:52:05 +00:00
|
|
|
- The *granularity* value MUST be set at creation time.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 01:06:08 +00:00
|
|
|
- The *granularity* value MUST NOT be changed, ever.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The *granularity* value MUST be greater or equal to `1`.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-04-09 20:50:48 +00:00
|
|
|
- Any amount of tokens (in the internal denomination) minted, sent or burned
|
2019-03-26 01:06:08 +00:00
|
|
|
MUST be a multiple of the *granularity* value.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
- Any operation that would result in a balance that's not a multiple of the *granularity* value
|
|
|
|
MUST be considered invalid, and the transaction MUST `revert`.
|
|
|
|
|
|
|
|
*NOTE*: Most of the tokens SHOULD be fully partition-able.
|
|
|
|
I.e., this function SHOULD return `1` unless there is a good reason for not allowing any fraction of the token.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `556f0dc7`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**returns:** The smallest non-divisible part of the token.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions,
|
|
|
|
defined under the [operators] for consistency.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
*[ERC20] compatibility requirement*:
|
2019-03-26 00:21:07 +00:00
|
|
|
The decimals of the token MUST always be `18`.
|
|
|
|
For a *pure* ERC777 token the [ERC20] `decimals` function is OPTIONAL,
|
|
|
|
and its existence SHALL NOT be relied upon when interacting with the token contract.
|
|
|
|
(The decimal value of `18` is implied.)
|
|
|
|
For an [ERC20] compatible token, the `decimals` function is REQUIRED and MUST return `18`.
|
|
|
|
(In [ERC20], the `decimals` function is OPTIONAL.
|
|
|
|
If the function is not present, the `decimals` value is not clearly defined and may be assumed to be `0`.
|
|
|
|
Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] compatible tokens.)
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
#### **Operators**
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
An `operator` is an address which is allowed to send and burn tokens on behalf of some *holder*.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
When an address becomes an *operator* for a *holder*, an `AuthorizedOperator` event MUST be emitted.
|
|
|
|
The `AuthorizedOperator`'s `operator` (topic 1) and `holder` (topic 2)
|
|
|
|
MUST be the addresses of the *operator* and the *holder* respectively.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
When a *holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted.
|
|
|
|
The `RevokedOperator`'s `operator` (topic 1) and `holder` (topic 2)
|
|
|
|
MUST be the addresses of the *operator* and the *holder* respectively.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: A *holder* MAY have multiple *operators* at the same time.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The token MAY define *default operators*.
|
2019-03-26 00:34:30 +00:00
|
|
|
A *default operator* is an implicitly authorized *operator* for all *holders*.
|
2019-03-26 00:21:07 +00:00
|
|
|
`AuthorizedOperator` events MUST NOT be emitted when defining the *default operators*.
|
|
|
|
The rules below apply to *default operators*:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The token contract MUST define *default operators* at creation time.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- The *default operators* MUST be invariants. I.e., the token contract MUST NOT add or remove *default operators* ever.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- `AuthorizedOperator` events MUST NOT be emitted when defining *default operators*.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- A *holder* MUST be allowed revoke a *default operator*
|
|
|
|
(unless the *holder* is the *default operator* in question).
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- A *holder* MUST be allowed to re-authorize a previously revoked *default operator*.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- When a *default operator* is explicitly authorized or revoked for a specific *holder*,
|
2019-03-26 00:21:07 +00:00
|
|
|
an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be emitted.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
The following rules apply to any *operator*:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- An address MUST always be an *operator* for itself. Hence an address MUST NOT ever be revoked as its own *operator*.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- If an address is an *operator* for a *holder*, `isOperatorFor` MUST return `true`.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- If an address is not an *operator* for a *holder*, `isOperatorFor` MUST return `false`.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
- The token contract MUST emit an `AuthorizedOperator` event with the correct values
|
2019-03-26 00:34:30 +00:00
|
|
|
when a *holder* authorizes an address as its *operator* as defined in the
|
2019-03-26 00:21:07 +00:00
|
|
|
[`AuthorizedOperator` Event][authorizedoperator].
|
|
|
|
|
|
|
|
- The token contract MUST emit a `RevokedOperator` event with the correct values
|
2019-03-26 00:34:30 +00:00
|
|
|
when a *holder* revokes an address as its *operator* as defined in the
|
2019-03-26 00:21:07 +00:00
|
|
|
[`RevokedOperator` Event][revokedoperator].
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: A *holder* MAY authorize an already authorized *operator*.
|
2019-03-26 00:21:07 +00:00
|
|
|
An `AuthorizedOperator` MUST be emitted each time.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: A *holder* MAY revoke an already revoked *operator*.
|
2019-03-26 00:21:07 +00:00
|
|
|
A `RevokedOperator` MUST be emitted each time.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
|
|
|
**`AuthorizedOperator` event** <a id="authorizedoperator"></a>
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
``` solidity
|
2019-03-26 00:34:30 +00:00
|
|
|
event AuthorizedOperator(address indexed operator, address indexed holder)
|
2018-07-31 15:35:49 +00:00
|
|
|
```
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
Indicates the authorization of `operator` as an *operator* for `holder`.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
|
|
|
*NOTE*: This event MUST NOT be emitted outside of an *operator* authorization process.
|
|
|
|
|
|
|
|
> <small>**parameters**</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`operator`: Address which became an *operator* of `holder`.</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`holder`: Address of a *holder* which authorized the `operator` address as an *operator*.</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
|
|
|
|
**`RevokedOperator` event** <a id="revokedoperator"></a>
|
|
|
|
|
|
|
|
``` solidity
|
2019-03-26 00:34:30 +00:00
|
|
|
event RevokedOperator(address indexed operator, address indexed holder)
|
2018-07-31 15:35:49 +00:00
|
|
|
```
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
Indicates the revocation of `operator` as an *operator* for `holder`.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
|
|
|
*NOTE*: This event MUST NOT be emitted outside of an *operator* revocation process.
|
|
|
|
|
|
|
|
> <small>**parameters**</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`operator`: Address which was revoked as an *operator* of `holder`.</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`holder`: Address of a *holder* which revoked the `operator` address as an *operator*.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below
|
|
|
|
MUST be implemented to manage *operators*.
|
2018-07-20 10:11:59 +00:00
|
|
|
Token contracts MAY implement other functions to manage *operators*.
|
|
|
|
|
|
|
|
**`defaultOperators` function** <a id="defaultOperators"></a>
|
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function defaultOperators() external view returns (address[] memory)
|
2018-07-20 10:11:59 +00:00
|
|
|
```
|
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
Get the list of *default operators* as defined by the token contract.
|
|
|
|
|
|
|
|
*NOTE*: If the token contract does not have any *default operators*, this function MUST return an empty list.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `06e48538`</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>**returns:** List of addresses of all the *default operators*.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
**`authorizeOperator` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-04 01:12:53 +00:00
|
|
|
function authorizeOperator(address operator) external
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
Set a third party `operator` address as an *operator* of `msg.sender` to send and burn tokens on its behalf.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: The *holder* (`msg.sender`) is always an *operator* for itself.
|
2019-03-26 00:21:07 +00:00
|
|
|
This right SHALL NOT be revoked.
|
2019-03-26 00:34:30 +00:00
|
|
|
Hence this function MUST `revert` if it is called to authorize the holder (`msg.sender`)
|
2019-03-26 00:21:07 +00:00
|
|
|
as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`).
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `959b8c3f`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
|
|
|
> <small>`operator`: Address to set as an *operator* for `msg.sender`.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`revokeOperator` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-04 01:12:53 +00:00
|
|
|
function revokeOperator(address operator) external
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
Remove the right of the `operator` address to be an *operator* for `msg.sender`
|
|
|
|
and to send and burn tokens on its behalf.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: The *holder* (`msg.sender`) is always an *operator* for itself.
|
2019-03-26 00:21:07 +00:00
|
|
|
This right SHALL NOT be revoked.
|
2019-03-26 00:34:30 +00:00
|
|
|
Hence this function MUST `revert` if it is called to revoke the holder (`msg.sender`)
|
2019-03-26 00:21:07 +00:00
|
|
|
as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`).
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `fad8b32a`</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>**parameters**</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>`operator`: Address to rescind as an *operator* for `msg.sender`.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`isOperatorFor` function** <a id="isOperatorFor"></a>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-26 00:34:30 +00:00
|
|
|
function isOperatorFor(address operator, address holder) external view returns (bool)
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
Indicate whether the `operator` address is an *operator* of the `holder` address.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `d95b6371`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`operator`: Address which may be an *operator* of `holder`.</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`holder`: Address of a *holder* which may have the `operator` address as an *operator*.</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>**returns:** `true` if `operator` is an *operator* of `holder` and `false` otherwise.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: To know which addresses are *operators* for a given *holder*,
|
|
|
|
one MUST call `isOperatorFor` with the *holder* for each *default operator*
|
|
|
|
and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *holder* in question.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
#### **Sending Tokens**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
When an *operator* sends an `amount` of tokens from a *holder* to a *recipient*
|
2019-03-26 00:21:07 +00:00
|
|
|
with the associated `data` and `operatorData`, the token contract MUST apply the following rules:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-24 23:56:18 +00:00
|
|
|
- Any authorized *operator* MAY send tokens to any *recipient* (except to `0x0`).
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The balance of the *holder* MUST be decreased by the `amount`.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The balance of the *recipient* MUST be increased by the `amount`.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The balance of the *holder* MUST be greater or equal to the `amount`—such
|
2019-03-26 00:21:07 +00:00
|
|
|
that its resulting balance is greater or equal to zero (`0`) after the send.
|
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- The token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent].
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-04 00:59:50 +00:00
|
|
|
- The *operator* MAY include information in the `operatorData`.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The token contract MUST call the `tokensToSend` hook of the *holder*
|
|
|
|
if the *holder* registers an `ERC777TokensSender` implementation via [ERC1820].
|
2019-03-26 00:21:07 +00:00
|
|
|
|
|
|
|
- The token contract MUST call the `tokensReceived` hook of the *recipient*
|
|
|
|
if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820].
|
|
|
|
|
|
|
|
- The `data` and `operatorData` MUST be immutable during the entire send process—hence
|
|
|
|
the same `data` and `operatorData` MUST be used to call both hooks and emit the `Sent` event.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
|
|
|
The token contract MUST `revert` when sending in any of the following cases:
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The *operator* address is not an authorized operator for the *holder*.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The resulting *holder* balance or *recipient* balance after the send
|
2019-03-26 00:21:07 +00:00
|
|
|
is not a multiple of the *granularity* defined by the token contract.
|
|
|
|
|
2019-03-24 23:56:18 +00:00
|
|
|
- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820].
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The address of the *holder* or the *recipient* is `0x0`.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
- Any of the resulting balances becomes negative, i.e. becomes less than zero (`0`).
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
The token contract MAY send tokens from many *holders*, to many *recipients*, or both. In this case:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The previous send rules MUST apply to all the *holders* and all the *recipients*.
|
2018-07-20 10:11:59 +00:00
|
|
|
- The sum of all the balances incremented MUST be equal to the total sent `amount`.
|
|
|
|
- The sum of all the balances decremented MUST be equal to the total sent `amount`.
|
2019-03-26 00:34:30 +00:00
|
|
|
- A `Sent` event MUST be emitted for every *holder* and *recipient* pair with the corresponding amount for each pair.
|
2018-07-20 10:11:59 +00:00
|
|
|
- The sum of all the amounts from the `Sent` event MUST be equal to the total sent `amount`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: Mechanisms such as applying a fee on a send is considered as a send to multiple *recipients*:
|
|
|
|
the intended *recipient* and the fee *recipient*.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: Transfer of tokens MAY be chained.
|
|
|
|
For example, if a contract upon receiving tokens sends them further to another address.
|
|
|
|
In this case, the previous send rules apply to each send, in order.
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
*NOTE*: Sending an amount of zero (`0`) tokens is valid and MUST be treated as a regular send.
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
*Implementation Requirement*:
|
|
|
|
- The token contract MUST call the `tokensToSend` hook *before* updating the state.
|
|
|
|
- The token contract MUST call the `tokensReceived` hook *after* updating the state.
|
2019-03-26 00:21:07 +00:00
|
|
|
I.e., `tokensToSend` MUST be called first,
|
|
|
|
then the balances MUST be updated to reflect the send,
|
|
|
|
and finally `tokensReceived` MUST be called *afterward*.
|
|
|
|
Thus a `balanceOf` call within `tokensToSend` returns the balance of the address *before* the send
|
|
|
|
and a `balanceOf` call within `tokensReceived` returns the balance of the address *after* the send.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: The `data` field contains information provided by the *holder*—similar
|
2019-03-04 00:59:50 +00:00
|
|
|
to the data field in a regular ether send transaction.
|
2019-03-26 00:21:07 +00:00
|
|
|
The `tokensToSend()` hook, the `tokensReceived()`, or both
|
2019-03-04 00:59:50 +00:00
|
|
|
MAY use the information to decide if they wish to reject the transaction.
|
|
|
|
|
|
|
|
*NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*.
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The `operatorData` MUST only be provided by the *operator*.
|
|
|
|
It is intended more for logging purposes and particular cases.
|
|
|
|
(Examples include payment references, cheque numbers, countersignatures and more.)
|
|
|
|
In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
**`Sent` event** <a id="sent"></a>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2018-07-20 10:11:59 +00:00
|
|
|
event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData)
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Indicate a send of `amount` of tokens from the `from` address to the `to` address by the `operator` address.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
*NOTE*: This event MUST NOT be emitted outside of a send or an [ERC20] transfer process.
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`operator`: Address which triggered the send.</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`from`: *Holder* whose tokens were sent.</small>
|
|
|
|
> <small>`to`: Recipient of the tokens.</small>
|
|
|
|
> <small>`amount`: Number of tokens sent.</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`operatorData`: Information provided by the *operator*.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
The `send` and `operatorSend` functions described below MUST be implemented to send tokens.
|
|
|
|
Token contracts MAY implement other functions to send tokens.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`send` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function send(address to, uint256 amount, bytes calldata data) external
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Send the `amount` of tokens from the address `msg.sender` to the address `to`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
The *operator* and the *holder* MUST both be the `msg.sender`.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `9bd9bbc6`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`to`: Recipient of the tokens.</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`amount`: Number of tokens to send.</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
**`operatorSend` function**
|
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function operatorSend(address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external
|
2018-07-20 10:11:59 +00:00
|
|
|
```
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Send the `amount` of tokens on behalf of the address `from` to the address `to`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*Reminder*: If the *operator* address is not an authorized operator of the `from` address,
|
|
|
|
then the send process MUST `revert`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: `from` and `msg.sender` MAY be the same address.
|
|
|
|
I.e., an address MAY call `operatorSend` for itself.
|
|
|
|
This call MUST be equivalent to `send` with the addition
|
|
|
|
that the *operator* MAY specify an explicit value for `operatorData`
|
|
|
|
(which cannot be done with the `send` function).
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `62ad1b83`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`from`: *Holder* whose tokens are being sent.</small>
|
|
|
|
> <small>`to`: Recipient of the tokens.</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`amount`: Number of tokens to send.</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`operatorData`: Information provided by the *operator*.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
#### **Minting Tokens**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
Minting tokens is the act of producing new tokens.
|
|
|
|
[ERC777] intentionally does not define specific functions to mint tokens.
|
|
|
|
This intent comes from the wish not to limit the use of the [ERC777] standard
|
|
|
|
as the minting process is generally specific for every token.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
Nonetheless, the rules below MUST be respected when minting for a *recipient*:
|
|
|
|
|
|
|
|
- Tokens MAY be minted for any *recipient* address.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The total supply MUST be increased by the amount of tokens minted.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The balance of `0x0` MUST NOT be decreased.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The balance of the *recipient* MUST be increased by the amount of tokens minted.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- The token contract MUST emit a `Minted` event with the correct values as defined in the [`Minted` Event][minted].
|
2019-03-26 00:21:07 +00:00
|
|
|
|
|
|
|
- The token contract MUST call the `tokensReceived` hook of the *recipient*
|
|
|
|
if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820].
|
|
|
|
|
|
|
|
- The `data` and `operatorData` MUST be immutable during the entire mint process—hence
|
|
|
|
the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event.
|
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
The token contract MUST `revert` when minting in any of the following cases:
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
- The resulting *recipient* balance after the mint is not a multiple of the *granularity* defined by the token contract.
|
2019-03-08 11:54:37 +00:00
|
|
|
- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820].
|
2018-07-20 10:11:59 +00:00
|
|
|
- The address of the *recipient* is `0x0`.
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: The initial token supply at the creation of the token contract MUST be considered as minting
|
|
|
|
for the amount of the initial supply to the address(es) receiving the initial supply.
|
|
|
|
This means one or more `Minted` events must be emitted
|
|
|
|
and the `tokensReceived` hook of the recipient(s) MUST be called.
|
2018-08-13 02:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
*[ERC20] compatibility requirement*:
|
2019-03-26 00:21:07 +00:00
|
|
|
While a `Sent` event MUST NOT be emitted when minting,
|
|
|
|
if the token contract is [ERC20] backward compatible,
|
|
|
|
a `Transfer` event with the `from` parameter set to `0x0` SHOULD be emitted as defined in the [ERC20] standard.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
The token contract MAY mint tokens for multiple *recipients* at once. In this case:
|
|
|
|
|
|
|
|
- The previous mint rules MUST apply to all the *recipients*.
|
|
|
|
- The sum of all the balances incremented MUST be equal to the total minted amount.
|
2018-07-30 20:29:38 +00:00
|
|
|
- A `Minted` event MUST be emitted for every *recipient* with the corresponding amount for each *recipient*.
|
|
|
|
- The sum of all the amounts from the `Minted` event MUST be equal to the total minted `amount`.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
*NOTE*: Minting an amount of zero (`0`) tokens is valid and MUST be treated as a regular mint.
|
|
|
|
|
2019-04-08 17:43:50 +00:00
|
|
|
*NOTE*: While during a send or a burn, the data is provided by the *holder*, it is inapplicable for a mint.
|
|
|
|
In this case the data MAY be provided by the token contract or the *operator*,
|
|
|
|
for example to ensure a successful minting to a *holder* expecting specific data.
|
|
|
|
|
2019-03-04 00:59:50 +00:00
|
|
|
*NOTE*: The `operatorData` field contains information provided by the *operator*—similar
|
2019-03-26 00:21:07 +00:00
|
|
|
to the data field in a regular ether send transaction.
|
2019-03-04 00:59:50 +00:00
|
|
|
The `tokensReceived()` hooks MAY use the information to decide if it wish to reject the transaction.
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`Minted` event** <a id="minted"></a>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2018-07-31 15:35:49 +00:00
|
|
|
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData)
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Indicate the minting of `amount` of tokens to the `to` address by the `operator` address.
|
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
*NOTE*: This event MUST NOT be emitted outside of a mint process.
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`operator`: Address which triggered the mint.</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`to`: Recipient of the tokens.</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`amount`: Number of tokens minted.</small>
|
2019-04-08 17:43:50 +00:00
|
|
|
> <small>`data`: Information provided for the *recipient*.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`operatorData`: Information provided by the *operator*.</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
#### **Burning Tokens**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
Burning tokens is the act of destroying existing tokens.
|
|
|
|
[ERC777] explicitly defines two functions to burn tokens (`burn` and `operatorBurn`).
|
|
|
|
These functions facilitate the integration of the burning process in wallets and dapps.
|
2019-03-26 00:34:30 +00:00
|
|
|
However, the token contract MAY prevent some or all *holders* from burning tokens for any reason.
|
2019-03-26 00:21:07 +00:00
|
|
|
The token contract MAY also define other functions to burn tokens.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
The rules below MUST be respected when burning the tokens of a *holder*:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- Tokens MAY be burned from any *holder* address.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- The total supply MUST be decreased by the amount of tokens burned.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The balance of `0x0` MUST NOT be increased.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The balance of the *holder* MUST be decreased by amount of tokens burned.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- The token contract MUST emit a `Burned` event with the correct values as defined in the [`Burned` Event][burned].
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The token contract MUST call the `tokensToSend` hook of the *holder*
|
|
|
|
if the *holder* registers an `ERC777TokensSender` implementation via [ERC1820].
|
2019-03-26 00:21:07 +00:00
|
|
|
|
|
|
|
- The `operatorData` MUST be immutable during the entire burn process—hence
|
|
|
|
the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
The token contract MUST `revert` when burning in any of the following cases:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The *operator* address is not an authorized operator for the *holder*.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The resulting *holder* balance after the burn is not a multiple of the *granularity*
|
2019-03-26 00:21:07 +00:00
|
|
|
defined by the token contract.
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The balance of *holder* is inferior to the amount of tokens to burn
|
|
|
|
(i.e., resulting in a negative balance for the *holder*).
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The address of the *holder* is `0x0`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
*[ERC20] compatibility requirement*:
|
2019-03-26 00:21:07 +00:00
|
|
|
While a `Sent` event MUST NOT be emitted when burning;
|
|
|
|
if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` SHOULD be emitted.
|
|
|
|
The [ERC20] standard does not define the concept of burning tokens, but this is a commonly accepted practice.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
The token contract MAY burn tokens for multiple *holders* at once. In this case:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The previous burn rules MUST apply to each *holders*.
|
2018-07-20 10:11:59 +00:00
|
|
|
- The sum of all the balances decremented MUST be equal to the total burned amount.
|
2019-03-26 00:34:30 +00:00
|
|
|
- A `Burned` event MUST be emitted for every *holder* with the corresponding amount for each *holder*.
|
2018-07-30 20:29:38 +00:00
|
|
|
- The sum of all the amounts from the `Burned` event MUST be equal to the total burned `amount`.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
*NOTE*: Burning an amount of zero (`0`) tokens is valid and MUST be treated as a regular burn.
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: The `data` field contains information provided by the holder—similar
|
2019-03-04 00:45:51 +00:00
|
|
|
to the data field in a regular ether send transaction.
|
|
|
|
The `tokensToSend()` hook, the `tokensReceived()`, or both
|
|
|
|
MAY use the information to decide if they wish to reject the transaction.
|
|
|
|
|
|
|
|
*NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*.
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`Burned` event** <a id="burned"></a>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-04 00:45:51 +00:00
|
|
|
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Indicate the burning of `amount` of tokens from the `from` address by the `operator` address.
|
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
*NOTE*: This event MUST NOT be emitted outside of a burn process.
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`operator`: Address which triggered the burn.</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`from`: *Holder* whose tokens were burned.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`amount`: Number of tokens burned.</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`operatorData`: Information provided by the *operator*.</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
The `burn` and `operatorBurn` functions described below MUST be implemented to burn tokens.
|
|
|
|
Token contracts MAY implement other functions to burn tokens.
|
|
|
|
|
|
|
|
**`burn` function**
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function burn(uint256 amount, bytes calldata data) external
|
2018-07-20 10:11:59 +00:00
|
|
|
```
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Burn the `amount` of tokens from the address `msg.sender`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
The *operator* and the *holder* MUST both be the `msg.sender`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `fe9d9303`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`amount`: Number of tokens to burn.</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
**`operatorBurn` function**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Burn the `amount` of tokens on behalf of the address `from`.
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*Reminder*: If the *operator* address is not an authorized operator of the `from` address,
|
|
|
|
then the burn process MUST `revert`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `fc673c4f`</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>**parameters**</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`from`: *Holder* whose tokens will be burned.</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`amount`: Number of tokens to burn.</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`operatorData`: Information provided by the *operator*.</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: The *operator* MAY pass any information via `operatorData`.
|
|
|
|
The `operatorData` MUST only be provided by the *operator*.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: `from` and `msg.sender` MAY be the same address.
|
|
|
|
I.e., an address MAY call `operatorBurn` for itself.
|
|
|
|
This call MUST be equivalent to `burn`
|
|
|
|
with the addition that the *operator* MAY specify an explicit value for `operatorData`
|
|
|
|
(which cannot be done with the `burn` function).
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
#### **`ERC777TokensSender` And The `tokensToSend` Hook**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 01:06:08 +00:00
|
|
|
The `tokensToSend` hook notifies of any request to decrement the balance (send and burn) for a given *holder*.
|
2019-03-26 00:21:07 +00:00
|
|
|
Any address (regular or contract) wishing to be notified of token debits from their address
|
|
|
|
MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820].
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
|
|
|
interface ERC777TokensSender {
|
|
|
|
function tokensToSend(
|
|
|
|
address operator,
|
|
|
|
address from,
|
|
|
|
address to,
|
2018-07-31 15:35:49 +00:00
|
|
|
uint256 amount,
|
2019-03-25 00:12:29 +00:00
|
|
|
bytes calldata userData,
|
|
|
|
bytes calldata operatorData
|
2019-03-04 01:21:09 +00:00
|
|
|
) external;
|
2018-04-06 13:52:05 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: A regular address MAY register a different address—the address of a contract—implementing
|
|
|
|
the interface on its behalf.
|
|
|
|
A contract MAY register either its address or the address of another contract
|
|
|
|
but said address MUST implement the interface on its behalf.
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`tokensToSend`**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function tokensToSend(address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData) external
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2019-03-26 01:06:08 +00:00
|
|
|
Notify a request to send or burn (if `to` is `0x0`) an `amount` tokens from the `from` address to the `to` address
|
2019-03-26 00:21:07 +00:00
|
|
|
by the `operator` address.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
*NOTE*: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process.
|
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `75ab9782`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`operator`: Address which triggered the balance decrease (through sending or burning).</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`from`: *Holder* whose tokens were sent.</small>
|
|
|
|
> <small>`to`: Recipient of the tokens for a send (or `0x0` for a burn).</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`amount`: Number of tokens the *holder* balance is decreased by.</small>
|
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`operatorData`: Information provided by the *operator*.</small>
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
The following rules apply when calling the `tokensToSend` hook:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- The `tokensToSend` hook MUST be called every time the balance is decremented.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- The `tokensToSend` hook MUST be called *before* the state is updated—i.e. *before* the balance is decremented.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- `operator` MUST be the address which triggered the decrease of the balance.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- `from` MUST be the address of the *holder* whose balance is decreased.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- `to` MUST be the address of the *recipient* whose balance is increased for a send.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- `to` MUST be `0x0` for a burn.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- `amount` MUST be the number of tokens the *holder* balance is decreased by.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- `data` MUST contain the extra information provided by the *holder* (if any) for a send.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
|
|
|
- `operatorData` MUST contain the extra information provided by the address
|
|
|
|
which triggered the decrease of the balance (if any).
|
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- The *holder* MAY block a decrease of its balance by `revert`ing.
|
2019-03-26 00:21:07 +00:00
|
|
|
(I.e., reject the withdrawal of tokens from its account.)
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensSender`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens.
|
|
|
|
Hence the `ERC777TokensSender` MUST expect to be called by different token contracts.
|
|
|
|
The `msg.sender` of the `tokensToSend` call is expected to be the address of the token contract.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
*[ERC20] compatibility requirement*:
|
2019-03-26 00:21:07 +00:00
|
|
|
This hook takes precedence over [ERC20] and MUST be called (if registered)
|
|
|
|
when calling [ERC20]'s `transfer` and `transferFrom` event.
|
|
|
|
When called from a `transfer`, `operator` MUST be the same value as the `from`.
|
|
|
|
When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
#### **`ERC777TokensRecipient` And The `tokensReceived` Hook**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The `tokensReceived` hook notifies of any increment of the balance (send and mint) for a given *recipient*.
|
|
|
|
Any address (regular or contract) wishing to be notified of token credits to their address
|
|
|
|
MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820].
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
|
|
|
interface ERC777TokensRecipient {
|
2018-07-20 10:11:59 +00:00
|
|
|
function tokensReceived(
|
|
|
|
address operator,
|
|
|
|
address from,
|
|
|
|
address to,
|
2018-07-31 15:35:49 +00:00
|
|
|
uint256 amount,
|
2019-03-25 00:12:29 +00:00
|
|
|
bytes calldata data,
|
|
|
|
bytes calldata operatorData
|
2019-03-04 01:21:09 +00:00
|
|
|
) external;
|
2018-04-06 13:52:05 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation;
|
|
|
|
then the token contract:
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
- MUST `revert` if the `tokensReceived` hook is called from a mint or send call.
|
2019-04-09 20:50:48 +00:00
|
|
|
|
|
|
|
- SHOULD continue processing the transaction
|
|
|
|
if the `tokensReceived` hook is called from an ERC20 `transfer` or `transferFrom` call.
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: A regular address MAY register a different address—the address of a contract—implementing
|
|
|
|
the interface on its behalf.
|
|
|
|
A contract MUST register either its address or the address of another contract
|
|
|
|
but said address MUST implement the interface on its behalf.
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
**`tokensReceived`**
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
``` solidity
|
2019-03-25 00:12:29 +00:00
|
|
|
function tokensReceived(address operator, address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external
|
2018-04-06 13:52:05 +00:00
|
|
|
```
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address
|
|
|
|
by the `operator` address.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
*NOTE*: This function MUST NOT be called outside of a mint, send or [ERC20] transfer process.
|
|
|
|
|
2019-04-06 22:07:05 +00:00
|
|
|
> <small>**identifier:** `0023de29`</small>
|
2018-07-20 10:11:59 +00:00
|
|
|
> <small>**parameters**</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`operator`: Address which triggered the balance increase (through sending or minting).</small>
|
2019-04-03 17:22:52 +00:00
|
|
|
> <small>`from`: *Holder* whose tokens were sent (or `0x0` for a mint).</small>
|
|
|
|
> <small>`to`: Recipient of the tokens.</small>
|
2018-07-31 15:35:49 +00:00
|
|
|
> <small>`amount`: Number of tokens the *recipient* balance is increased by.</small>
|
2019-03-26 00:34:30 +00:00
|
|
|
> <small>`data`: Information provided by the *holder*.</small>
|
2019-03-04 00:59:50 +00:00
|
|
|
> <small>`operatorData`: Information provided by the *operator*.</small>
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2019-03-04 00:31:32 +00:00
|
|
|
The following rules apply when calling the `tokensReceived` hook:
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
- The `tokensReceived` hook MUST be called every time the balance is incremented.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
- The `tokensReceived` hook MUST be called *after* the state is updated—i.e. *after* the balance is incremented.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- `operator` MUST be the address which triggered the increase of the balance.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
- `from` MUST be the address of the *holder* whose balance is decreased for a send.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
- `from` MUST be `0x0` for a mint.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
- `to` MUST be the address of the *recipient* whose balance is increased.
|
2019-03-26 00:21:07 +00:00
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
- `amount` MUST be the number of tokens the *recipient* balance is increased by.
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
- `operatorData` MUST contain the extra information provided by the address
|
|
|
|
which triggered the increase of the balance (if any).
|
2019-03-26 00:34:30 +00:00
|
|
|
- The *holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.)
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2019-03-26 00:34:30 +00:00
|
|
|
*NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensRecipient`.
|
2018-07-30 20:29:38 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens.
|
|
|
|
Hence the `ERC777TokensRecipient` MUST expect to be called by different token contracts.
|
|
|
|
The `msg.sender` of the `tokensReceived` call is expected to be the address of the token contract.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
*[ERC20] compatibility requirement*:
|
2019-03-26 00:21:07 +00:00
|
|
|
This hook takes precedence over [ERC20] and MUST be called (if registered)
|
|
|
|
when calling [ERC20]'s `transfer` and `transferFrom` event.
|
|
|
|
When called from a `transfer`, `operator` MUST be the same value as the `from`.
|
|
|
|
When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
|
|
|
#### **Note On Gas Consumption**
|
2019-03-24 23:56:18 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
Dapps and wallets SHOULD first estimate the gas required when sending, minting, or burning tokens—using
|
|
|
|
[`eth_estimateGas`][eth_estimateGas]—to avoid running out of gas during the transaction.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
### Logo
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
| **Image** | ![beige logo] | ![white logo] | ![light grey logo] | ![dark grey logo] | ![black logo] |
|
|
|
|
|----------:|:-------------:|:-------------:|:------------------:|:-----------------:|:-------------:|
|
|
|
|
| **Color** | beige | white | light grey | dark grey | black |
|
|
|
|
| **Hex** | `#C99D66` | `#FFFFFF` | `#EBEFF0` | `#3C3C3D` | `#000000` |
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The logo MAY be used, modified and adapted to promote valid [ERC777] token implementations
|
|
|
|
and [ERC777] compliant technologies such as wallets and dapps.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-30 20:29:38 +00:00
|
|
|
[ERC777] token contract authors MAY create a specific logo for their token based on this logo.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The logo MUST NOT be used to advertise, promote or associate in any way technology—such
|
|
|
|
as tokens—which is not [ERC777] compliant.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The logo for the standard can be found in the [`/assets/eip-777/logo`][logos] folder in `SVG` and `PNG` formats.
|
|
|
|
The `PNG` version of the logo offers a few sizes in pixels.
|
|
|
|
If needed, other sizes MAY be created by converting from `SVG` into `PNG`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
## Rationale
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20].
|
|
|
|
It avoids the problems and vulnerabilities of [EIP223].
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
It goes a step further by allowing *operators* (generally contracts)
|
|
|
|
which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed.
|
2019-03-26 00:34:30 +00:00
|
|
|
Finally, it adds hooks to provide further control to *holders* over their tokens.
|
2019-03-26 00:21:07 +00:00
|
|
|
Note that, the usage of [ERC1820] provides backward compatibility with wallets and existing contracts
|
|
|
|
without having to be redeployed thanks proxy contracts implementing the hooks.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
## Backward Compatibility
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
This EIP does not introduce backward incompatibilities and is backward compatible with the older [ERC20] token standard.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
This EIP does not use `transfer` and `transferFrom` and uses `send` and `operatorSend`
|
|
|
|
to avoid confusion and mistakes when deciphering which token standard is being used.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
This standard allows the implementation of [ERC20] functions `transfer`, `transferFrom`, `approve` and `allowance`
|
|
|
|
alongside to make a token fully compatible with [ERC20].
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The token MAY implement `decimals()` for backward compatibility with [ERC20].
|
|
|
|
If implemented, it MUST always return `18`.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel.
|
|
|
|
The specification of the `view` functions (such as `name`, `symbol`, `balanceOf`, `totalSupply`) and internal data
|
|
|
|
(such as the mapping of balances) overlap without problems.
|
|
|
|
Note however that the following functions are mandatory in [ERC777] and MUST be implemented:
|
|
|
|
`name`, `symbol` `balanceOf` and `totalSupply`
|
|
|
|
(`decimals` is not part of the [ERC777] standard).
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The state-modifying functions from both standards are decoupled and can operate independently from each other.
|
|
|
|
Note that [ERC20] functions SHOULD be limited to only being called from old contracts.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-24 23:56:18 +00:00
|
|
|
If the token implements [ERC20],
|
|
|
|
it MUST register the `ERC20Token` interface with its own address via [ERC1820].
|
|
|
|
This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry
|
|
|
|
with the token contract address as both the address and the implementer
|
|
|
|
and the `keccak256` hash of `ERC20Token` as the interface hash.
|
|
|
|
|
|
|
|
If the contract has a switch to enable or disable ERC20 functions, every time the switch is triggered,
|
|
|
|
the token MUST register or unregister the `ERC20Token` interface for its own address accordingly via ERC1820.
|
|
|
|
Unregistering implies calling the `setInterfaceImplementer` with the token contract address as the address,
|
|
|
|
the `keccak256` hash of `ERC20Token` as the interface hash and `0x0` as the implementer.
|
|
|
|
(See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.)
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The difference for new contracts implementing [ERC20] is that
|
|
|
|
`tokensToSend` and `tokensReceived` hooks take precedence over [ERC20].
|
|
|
|
Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC1820]
|
|
|
|
if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively.
|
|
|
|
If any hook is implemented, it MUST be called.
|
|
|
|
Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`,
|
|
|
|
the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The table below summarizes the different actions the token contract MUST take
|
|
|
|
when sending, minting and transferring token via [ERC777] and [ERC20]:
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
<table>
|
|
|
|
<tr>
|
2019-03-08 11:54:37 +00:00
|
|
|
<th align="right">ERC1820</th>
|
2018-04-06 13:52:05 +00:00
|
|
|
<th><code>to</code> address</th>
|
2018-07-20 10:11:59 +00:00
|
|
|
<th align="center">ERC777 Sending And Minting</th>
|
|
|
|
<th align="center">ERC20 <code>transfer</code>/<code>transferFrom</code></th>
|
2018-04-06 13:52:05 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td rowspan="2" align="right">
|
|
|
|
<code>ERC777TokensRecipient</code><br/>registered
|
|
|
|
</td>
|
|
|
|
<td>regular address</td>
|
|
|
|
<td colspan="2" rowspan="2" align="center">
|
|
|
|
MUST call <code>tokensReceived</code>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>contract</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td rowspan="2" align="right">
|
|
|
|
<code>ERC777TokensRecipient</code><br/>not registered
|
|
|
|
</td>
|
|
|
|
<td>regular address</td>
|
2019-04-09 20:50:48 +00:00
|
|
|
<td align="center">continue</td>
|
|
|
|
<td rowspan="2" align="center">continue</td>
|
2018-04-06 13:52:05 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>contract</td>
|
2018-07-31 15:35:49 +00:00
|
|
|
<td align="center">MUST <code>revert</code></td>
|
2018-04-06 13:52:05 +00:00
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
There is no particular action to take if `tokensToSend` is not implemented.
|
|
|
|
The transfer MUST proceed and only be canceled if another condition is not respected
|
|
|
|
such as lack of funds or a `revert` in `tokensReceived` (if present).
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted.
|
|
|
|
Furthermore, if the token contract declares that it implements `ERC20Token` via [ERC1820],
|
|
|
|
the token contract SHOULD emit a `Transfer` event for minting and burning
|
|
|
|
and MUST emit a `Transfer` event for sending (as specified in the [ERC20] standard).
|
|
|
|
During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be emitted.
|
2018-07-20 10:11:59 +00:00
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
Hence for any movement of tokens, two events MAY be emitted:
|
|
|
|
an [ERC20] `Transfer` and an [ERC777] `Sent`, `Minted` or `Burned` (depending on the type of movement).
|
|
|
|
Third-party developers MUST be careful not to consider both events as separate movements.
|
|
|
|
As a general rule, if an application considers the token as an ERC20 token,
|
|
|
|
then only the `Transfer` event MUST be taken into account.
|
|
|
|
If the application considers the token as an ERC777 token,
|
|
|
|
then only the `Sent`, `Minted` and `Burned` events MUST be considered.
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
## Test Cases
|
|
|
|
|
2019-03-08 11:54:37 +00:00
|
|
|
The [repository with the reference implementation][0xjac/ERC777] contains all the [tests][ref tests].
|
2018-04-06 13:52:05 +00:00
|
|
|
|
|
|
|
## Implementation
|
|
|
|
|
2019-03-26 00:21:07 +00:00
|
|
|
The GitHub repository [0xjac/ERC777] contains the [reference implementation].
|
|
|
|
The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`.
|
2018-07-31 15:35:49 +00:00
|
|
|
|
2018-04-06 13:52:05 +00:00
|
|
|
## Copyright
|
|
|
|
|
2018-07-20 10:11:59 +00:00
|
|
|
Copyright and related rights waived via [CC0].
|
|
|
|
|
|
|
|
[operators]: #operators
|
|
|
|
|
|
|
|
[ERC20]: https://eips.ethereum.org/EIPS/eip-20
|
|
|
|
[ERC777]: https://eips.ethereum.org/EIPS/eip-777
|
2019-03-08 11:54:37 +00:00
|
|
|
[ERC1820]: https://eips.ethereum.org/EIPS/eip-1820
|
2019-03-24 23:56:18 +00:00
|
|
|
[erc1820-set]: https://eips.ethereum.org/EIPS/eip-1820#set-an-interface-for-an-address
|
2019-03-08 11:54:37 +00:00
|
|
|
[0xjac/ERC777]: https://github.com/0xjac/ERC777
|
2018-07-31 15:35:49 +00:00
|
|
|
[npm/erc777]: https://www.npmjs.com/package/erc777
|
2019-03-08 11:54:37 +00:00
|
|
|
[ref tests]: https://github.com/0xjac/ERC777/blob/master/test/ReferenceToken.test.js
|
|
|
|
[reference implementation]: https://github.com/0xjac/ERC777/blob/master/contracts/examples/ReferenceToken.sol
|
2018-07-20 10:11:59 +00:00
|
|
|
[EIP223]: https://github.com/ethereum/EIPs/issues/223
|
|
|
|
[eth_estimateGas]: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas
|
|
|
|
|
2018-07-31 15:35:49 +00:00
|
|
|
[authorizedoperator]: #authorizedoperator
|
|
|
|
[revokedoperator]: #revokedoperator
|
2018-07-20 10:11:59 +00:00
|
|
|
[isOperatorFor]: #isOperatorFor
|
|
|
|
[defaultOperators]: #defaultOperators
|
|
|
|
[sent]: #sent
|
|
|
|
[minted]: #minted
|
|
|
|
[burned]: #burned
|
|
|
|
|
|
|
|
[logos]: https://github.com/ethereum/EIPs/tree/master/assets/eip-777/logo
|
|
|
|
[beige logo]: ../assets/eip-777/logo/png/ERC-777-logo-beige-48px.png
|
|
|
|
[white logo]: ../assets/eip-777/logo/png/ERC-777-logo-white-48px.png
|
|
|
|
[light grey logo]: ../assets/eip-777/logo/png/ERC-777-logo-light_grey-48px.png
|
|
|
|
[dark grey logo]: ../assets/eip-777/logo/png/ERC-777-logo-dark_grey-48px.png
|
|
|
|
[black logo]: ../assets/eip-777/logo/png/ERC-777-logo-black-48px.png
|
|
|
|
|
|
|
|
[CC0]: https://creativecommons.org/publicdomain/zero/1.0/
|