Automatically merged updates to draft EIP(s) 777

Hi, I'm a bot! This change was automatically merged because:

 - It only modifies existing Draft or Last Call EIP(s)
 - The PR was approved or written by at least one author of each modified EIP
 - The build is passing
This commit is contained in:
Jacques Dafflon 2018-07-20 12:11:59 +02:00 committed by EIP Automerge Bot
parent a18c57c2ec
commit 861cec4369

View File

@ -14,25 +14,27 @@ requires: 820
This EIP defines a standard interface for token contracts.
*The repository containing the reference implementation for this standard can be found at [jacquesd/ERC777](https://github.com/jacquesd/ERC777) and installed via npm with: `npm install erc777`.*
*The repository containing the reference implementation for this standard can be found at [jacquesd/ERC777] and installed via npm with: `npm install erc777`.*
## Abstract
This standard defines a new way to interact with a Token Contract.
This standard defines a new way to interact with a token contract while remaining backward compatible with [ERC20].
It defines operators to send tokens on behalf of another address contract or regular account. It takes advantage of [ERC820](https://eips.ethereum.org/EIPS/eip-820) to find out whether and where to notify contracts and regular addresses when they receive tokens as well as to allow compatibility with old contracts.
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.
It takes advantage of [ERC820] 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.
## Motivation
This standard tries to improve the widely used [ERC20](https://eips.ethereum.org/EIPS/eip-20) token standard. The main advantages of this standard are:
This standard tries to improve the widely used [ERC20] token standard. The main advantages of this standard are:
1. Uses the same philosophy as Ether in that tokens are sent with `send(dest, value, data)`.
2. Both contracts and regular address can control and reject which token they send by registering a `tokensToSend` function rejection is done by throwing in the function.
3. Both contracts and regular addresses can control and reject which token they receive by registering a `tokensReceived` function rejection is done by throwing in the function.
4. The `tokensReceived` function also avoids the double call needed in the ERC20 standard (`approve` / `transferFrom`).
2. Both contracts and regular address can control and reject which token they send by registering a `tokensToSend` hook—rejection is done by throwing 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 throwing in the hook function.
4. The `tokensReceived` hook also avoids the double call needed in the [ERC20] standard (`approve` / `transferFrom`) to send tokens to a contract.
5. The token holder can "authorize" and "revoke" operators who can send tokens on their behalf. 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 a `userData` bytes field and a similar `operatorData` in case of an operator transaction to be used freely by the user (token holder) and the operator respectively to pass data to the recipient.
7. It is backward compatible with wallets that do not contain the `tokensReceived` function by deploying a proxy contract for the wallet.
6. Every token transaction contains a `data` bytes field and a similar `operatorData`—in case of an operator transaction—to be used freely by the token holder and the operator respectively to pass data to the recipient.
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.
## Specification
@ -40,332 +42,450 @@ This standard tries to improve the widely used [ERC20](https://eips.ethereum.org
``` solidity
interface ERC777Token {
function name() public constant returns (string);
function symbol() public constant returns (string);
function totalSupply() public constant returns (uint256);
function granularity() public constant returns (uint256);
function balanceOf(address owner) public constant returns (uint256);
function send(address to, uint256 amount, bytes userData) public;
function name() public view returns (string);
function symbol() public view returns (string);
function totalSupply() public view returns (uint256);
function balanceOf(address owner) public view returns (uint256);
function granularity() public view returns (uint256);
function defaultOperators() public view returns (address[]);
function authorizeOperator(address operator) public;
function revokeOperator(address operator) public;
function isOperatorFor(address operator, address tokenHolder) public constant returns (bool);
function operatorSend(address from, address to, uint256 amount, bytes userData, bytes operatorData) public;
function isOperatorFor(address operator, address tokenHolder) public view returns (bool);
function send(address to, uint256 amount, bytes data) public;
function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public;
function burn(uint256 amount, bytes data) public;
function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public;
event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes userData,
bytes data,
bytes operatorData
);
event Minted(address indexed operator, address indexed to, uint256 amount, bytes operatorData);
event Burned(address indexed operator, address indexed from, uint256 amount, bytes userData, bytes operatorData);
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
event RevokedOperator(address indexed operator, address indexed tokenHolder);
}
```
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 ERC820. If the contract has a switch to enable or disable ERC777 methods, every time the switch is triggered, the token MUST register or unregister its own address accordingly the `ERC777Token` interface via ERC820. (Unregistering implies setting the address to `0x0`.)
The token-contract MUST register the `ERC777Token` interface with its own address via [ERC820]. 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 [ERC820]. (Unregistering implies setting the address to `0x0`.)
The basic unit token MUST be 10<sup>18</sup>.
The basic unit token MUST be 10<sup>18</sup> (i.e. [ERC20]'s `decimals` MUST be `18`). All functions MUST consider any amount of tokens (such as balances and amount to send, mint, or burn) in the basic unit.
#### Methods
##### name
#### **View Functions**
The `view` functions detailed below MUST be implemented.
**`name` function**
``` solidity
function name() public constant returns (string)
function name() public view returns (string)
```
Returns the name of the token e.g. `"MyToken"`.
Returns the name of the token&mdash;e.g. `"MyToken"`.
> **returns:** Name of the token
> <small>**returns:** Name of the token</small>
<br/>
##### symbol
**`symbol` function**
``` solidity
function symbol() public constant returns (string)
function symbol() public view returns (string)
```
Returns the symbol of the token e.g. `"MYT"`.
Returns the symbol of the token&mdash;e.g. `"MYT"`.
> **returns:** Symbol of the token
> <small>**returns:** Symbol of the token</small>
<br/>
##### granularity
**`totalSupply` function**
``` solidity
function granularity() public constant returns (uint256)
```
Returns the smallest part of the token that's not divisible.
Any minting, transfer or burning of tokens MUST be a multiple of this value. Any operation that would result in a balance that's not a multiple of this value, MUST be considered invalid and the transaction MUST throw.
Most of the tokens SHOULD be fully partitionable, i.e. this function SHOULD return `1` unless there is a good reason for not allowing any partition of the token.
*NOTE*: `granularity` MUST be greater or equal to `1`.
> **returns:** The smallest non-divisible part of the token.
<br/>
##### totalSupply
``` solidity
function totalSupply() public constant returns (uint256)
function totalSupply() public view returns (uint256)
```
Get the total number of minted tokens.
> **returns:** Total supply of tokens currently in circulation.
The total supply MUST be equal to the sum of the balances as returned by `balanceOf` for all the addresses which appeared at least once in any of the `Sent`, `Minted` and `Burned` events.
<br/>
> <small>**returns:** Total supply of tokens currently in circulation.</small>
##### balanceOf
**`balanceOf` function**
``` solidity
function balanceOf(address tokenHolder) public constant returns (uint256)
function balanceOf(address tokenHolder) public view returns (uint256)
```
Get the balance of the account with address `tokenHolder`.
> **parameters**
> - `tokenHolder`: Address for which the balance is returned
The balance MUST be zero (`0`) or greater.
> <small>**parameters**</small>
> <small>`tokenHolder`: Address for which the balance is returned</small>
>
> **returns:** Amount of token held by `tokenHolder` in the token contract.
> <small>**returns:** Amount of token held by `tokenHolder` in the token contract.</small>
<br/>
##### send
**`granularity` function**
``` solidity
function send(address to, uint256 amount, bytes userData) public
function granularity() public view returns (uint256)
```
Send `amount` of tokens to address `to`.
Get the smallest part of the token that's not divisible.
This call MUST:
- call the `tokensToSend` method on the contract implementing `ERC777TokensSender` as returned by an ERC820 lookup on the `from` address regardless if `from` is a regular address or a contract.
- call the `tokensReceived` method on the address implementing `ERC777TokensRecipient` as returned by an ERC820 lookup on the `to` address regardless if `to` is a regular address or a contract.
- fire the `Sent` event.
The following rules MUST be applied with respect to the *granularity*:
If `to` is a contract which is not prepared to receive tokens. Specifically, it is a contract which does not register an address (its own or another) via ERC820 implementing the `ERC777TokensRecipient` interface. Then `send` MUST throw.
- The *granularity* value MUST NOT be changed.
- The *granularity* value MUST be greater or equal to `1`.
- Any minting, send or burning of tokens MUST be a multiple of the *granularity* value.
- 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 throw.
The function MUST `throw` if:
- `msg.sender` account balance does not have enough tokens to spend
- `to` is a contract which is not prepared to receive tokens.
*NOTE*: Most of the tokens SHOULD be fully partitionable, i.e. this function SHOULD return `1` unless there is a good reason for not allowing any partition of the token.
*NOTE*: Sending an amount of `0` is valid and MUST be treated as a regular send.
> **parameters**
> - `to`: tokens recipient
> - `amount`: number of tokens transferred
> - `userData`: information attached to the transaction by the user (sender)
> <small>**returns:** The smallest non-divisible part of the token.</small>
<br/>
*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions. They are defined under the [operators] for consistency.
##### authorizeOperator
*[ERC20] compatibility requirement*:
The decimals of the token MUST always be `18`. For a *pure* ERC777 token the [ERC20] `decimal` 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] enabled token, the `decimal` function is REQUIRED and MUST return `18`.
*[ERC20] compatibility requirement*:
The `name`, `symbol`, `totalSupply`, and `balanceOf` `view` functions MUST be backward compatible with [ERC20].
#### **Operators**
An `operator` is an address which is allowed to send and burn tokens on behalf of another address.
When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be fired. The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively.
When the *operator* of a *token holder* is revoked, a `RevokedOperator` event MUST be fired. The `RevokedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively.
*NOTE*: A *token holder* CAN have multiple *operators* at the same time.
In addition, the token MAY define *default operators*. A *default operator* is an *operator* which is implicitly authorized for all *token holders*. `AuthorizedOperator` events MUST NOT be fired when defining the *default operators*. The rules below apply to *default operators*:
- The token contract MUST define *default operators* at creation time.
- The *default operators* MUST be invariants. I.e. the token contract MUST NOT add or remove *default operators* ever.
- `AuthorizedOperator` events MUST NOT be fired when defining *default operators*.
- A *token holder* MUST be allowed revoke a *default operator* (unless the *token holder* is a *default operator*).
- A *token holder* MUST be allowed to re-authorize a previously revoked *default operator*
- When a *default operator* is explicitly authorized or revoked for a specific *token holder*, an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be fire.
The following rules apply to any *operator*:
- An address MUST always be an *operator* for itself. Hence an address MUST NOT ever be revoked as its own *operator*.
- If an address is an *operator* for a token holder `isOperatorFor` MUST return `true`.
- If an address is not an *operator* for a token holder `isOperatorFor` MUST return `false`.
The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below MUST be implemented to manage *operators*.
Token contracts MAY implement other functions to manage *operators*.
**`defaultOperators` function** <a id="defaultOperators"></a>
``` solidity
function defaultOperators() public view returns (address[])
```
Get the list of *default operators* as defined by the token contract
> <small>**returns:** List of addresses of all the *default operators*
**`authorizeOperator` function**
``` solidity
function authorizeOperator(address operator) public
```
Authorize a third party `operator` to send tokens on behalf of `msg.sender`.
Set a third party `operator` address as an *operator* of `msg.sender` to send, burn, and mint tokens on its behalf.
An `AuthorizedOperator` event MUST be fired on a successful call to this function.
*NOTE*: The token holder (`msg.sender`) is always an operator for himself. That is, he CAN call `operatorSend` on himself. This right cannot be revoked. Therefore if this function is called to set the token holder (`msg.sender`) as operator, then the function MUST throw.
*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST throw if it is called to set the token holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`).
*NOTE*: A token holder CAN authorize multiple operators at the same time.
*NOTE*: A token holder CAN authorize multiple *operators* at the same time.
> **parameters**
> - `operator`: Address which will be granted rights to manage the tokens.
> <small>**parameters**</small>
> <small>`operator`: Address to set as an *operator* for `msg.sender`.</small>
<br/>
##### revokeOperator
**`revokeOperator` function**
``` solidity
function revokeOperator(address operator) public
```
Remove the right of `operator` address to be an *operator* for `msg.sender` and to send and burn tokens on its behalf.
Revoke a third party `operator`'s rights to send tokens on behalf of `msg.sender`.
A `RevokedOperator` event MUST be fired on a successful call to this function.
*NOTE*: The token holder (`msg.sender`) is always an operator for himself. That is, he CAN call `operatorSend` on himself. This right cannot be revoked. Therefore if this function is called to set the token holder (`msg.sender`) as operator, then the function MUST throw.
*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST throw if it is called to revoke the token holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`).
> **parameters**
> - `operator`: Address which whose rights to manage the tokens will be revoked.
> <small>**parameters**</small>
> <small>`operator`: Address to rescind as an *operator* for `msg.sender`.</small>
<br/>
##### isOperatorFor
**`isOperatorFor` function** <a id="isOperatorFor"></a>
``` solidity
function isOperatorFor(address operator, address tokenHolder) public constant returns (bool)
function isOperatorFor(address operator, address tokenHolder) public view returns (bool)
```
Check whether the `operator` address is allowed to send the tokens held by the `tokenHolder` address.
Indicate whether the `operator` address is an *operator* of the `tokenHolder` address.
> **parameters**
> - `operator`: address to check if it has the right to manage the tokens.
> - `tokenHolder`: address which holds the tokens to be managed.
> <small>**parameters**</small>
> <small>`operator`: Address which may be an *operator* of `tokenHolder`.</small>
> <small>`tokenHolder`: Address of a token holder which may have the `operator` address as an `operator`.</small>
>
> <small>**returns:** `true` if `operator` is an *operator* of `tokenHolder` and `false` otherwise.
<br/>
*NOTE*: To know which addresses are *operators* for a given *token holder*, one MUST call `isOperatorFor` with the *token holder* for each *default operator* and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *token holder* in question.
##### operatorSend
#### **Sending Tokens**
When an *operator* sends an `amount` of tokens from a *token holder* to a *recipient* with the associated `data` and `operatorData`, the token contract MUST apply the following rules:
- Tokens MAY be sent from any *token holder* to any *recipient*.
- The balance of the *token holder* MUST be decreased by the `amount`.
- The balance of the *recipient* MUST be increased by the `amount`.
- The balance of the *token holder* MUST be greater or equal to the `amount`&mdash;such that its resulting balance is less than zero after the send.
- The token contract MUST fire a `Sent` event with the correct values as defined in the [`Sent` Event][sent].
- The *token holder* MAY communicate any data in the `data`.
- The *operator* MAY communicate any data in the `operatorData`.
- The contract MAY modify the `data` and `operatorData`
- The token contract MUST call the `tokensToSend` hook of the *token holder*, provided the *token holder* implements the `ERC777TokensRecipient` interface via [ERC820].
- The token contract MUST call the `tokensReceived` hook of the *recipient*, provided the *recipient* implements the `ERC777TokensRecipient` interface via [ERC820].
- When calling `tokensToSend` and/or `tokensReceived`:
- `operator` MUST be the address which initiated the send. (Generally the `msg.sender` of the send function call.)
- `from` MUST be the address of the *token holder*.
- `to` MUST be the address of the *recipient*.
- `data` MUST be the data provided by the *token holder* with the OPTIONAL modifications by the token contract.
- `operatorData` MUST be the data provided by the *operator* with the OPTIONAL modifications by the token contract.
The token contract MUST throw when sending in any of the following cases:
- The *operator* address is not an authorized operator for the *token holder*
- The resulting *token holder* and/or *recipient* balances after the send have a granularity smaller than the *granularity* defined by the token contract.
- The address of the *token holder* and/or the *recipient* are `0x0`.
The token contract MAY send tokens from many *token holders* and/or to many *recipients*. In this case:
- The previous send rules MUST apply to all the *token holders* and all the *recipients*
- 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`.
- A `Sent` event MUST be fired for every *token holder* and *recipient* pair with the corresponding amount for each pair.
- The sum of all the amounts from the `Sent` event MUST be equal to the total sent `amount`.
*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*.
*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.
I.e. `tokensToSend` MUST be called first, then the balances MUST be updated to reflect the send and finally `tokensReceived` MUST be called *afterward*. This means that 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.
*NOTE:* `data` and `operatorData` are fields of free bytes provided by the *token holder* and the *operator* respectively. `data` is intended for the recipient. Typically, the recipient SHOULD indicate which data it expects to receive. (Similarly to the data field when sending ether). `operatorData` is intended more for logging purposes and to very specific cases. (Examples include payment references, cheque numbers, counter signatures and more.) In most of the cases the recipient will just ignore the `operatorData` or at most it will log the `operatorData`.
**`Sent` event** <a id="sent"></a>
``` solidity
function operatorSend(address from, address to, uint256 amount, bytes userData, bytes operatorData) public
event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData)
```
Send `amount` of tokens on behalf of the address `from` to the address `to`.
Indicate a send of `amount` of tokens from the `from` address to the `to` address by the `operator` address.
`msg.sender` MUST be an authorized operator or the owner for the `from` address.
> <small>**parameters**</small>
> <small>`operator`: address which triggered the send</small>
> <small>`from`: token holder</small>
> <small>`to`: token recipient</small>
> <small>`amount`: number of tokens to send</small>
> <small>`data`: information attached to the send by the token holder</small>
> <small>`operatorData`: information attached to the send by the `operator`</small>
This call MUST:
- call the `tokensToSend` method on the contract implementing `ERC777TokensSender` as returned by an ERC820 lookup on the `from` address
- call the `tokensReceived` method on the contract implementing `ERC777TokensRecipient` as returned by an ERC820 lookup on the `to` address
- fire the `Sent` event
The `send` and `operatorSend` functions described below MUST be implemented to send tokens.
Token contracts MAY implement other functions to send tokens.
If `to` is a contract which is not prepared to receive tokens. Specifically, it is a contract which does not register an address (its own or another) via ERC820 implementing the `ERC777TokensRecipient` interface. Then `operatorSend` MUST throw.
*NOTE*: An address MAY send an amount of `0`. This is valid and MUST be treated as a regular send.
The method MUST throw if:
- `from` account balance does not have enough tokens to spend.
- `to` is a contract which does not register an address (its own or another) via ERC820 which implement the `ERC777TokensRecipient` interface.
- `to` is a contract which is not prepared to receive tokens.
- `msg.sender` is not an authorized operator for `from`.
> **parameters**
> - `from`: token holder (sender)
> - `to`: tokens recipient
> - `amount`: number of tokens transferred
> - `userData`: information attached to the transaction, previously provided by the sender (`from` address).
> - `operatorData`: information attached to the transaction by the operator
*NOTE*: The operator is free to pass any data via the `operatorData` parameter but the `userData` parameter is reserved for data provided by the user (token holder). The token holder SHOULD provide this data to the operator beforehand.
<br/>
#### Events
##### Sent
**`send` function**
``` solidity
event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes userData, bytes operatorData)
function send(address to, uint256 amount, bytes data) public
```
Indicate a transaction of `amount` of tokens from the `from` address to the `to` address.
Send the `amount` of tokens from the address `msg.sender` to the address `to`.
This event MUST be fired on a successful call to `send` and `operatorSend`.
The *operator* and the *token holder* MUST both be the `msg.sender`.
> **parameters**
> - `operator`: address which triggered the transfer, either the token holder for a direct send or an authorized operator for `operatorSend`
> - `from`: token holder
> - `to`: tokens recipient
> - `amount`: number of tokens sent
> - `userData`: information attached to the transaction by the token holder
> - `operatorData`: information attached to the transaction by the operator
> <small>**parameters**</small>
> <small>`to`: token recipient</small>
> <small>`amount`: number of tokens to send</small>
> <small>`data`: information attached to the send by the *token holder*</small>
<br/>
**`operatorSend` function**
##### Minted
``` solidity
function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public
```
Send the `amount` of tokens on behalf of the address `from` to the address `to`.
The *operator* MUST be `msg.sender`.
*Reminder*: If the *operator* address is not an authorized operator of the `from` address the send must throw.
*NOTE*: The *operator* MAY pass any data via `operatorData`. The *operator* MUST only pass to `data` data given to it by the *token holder*. The token holder MAY provide this data to the *operator* beforehand through another medium.
*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).
> <small>**parameters**</small>
> <small>`from`: token holder</small>
> <small>`to`: token recipient</small>
> <small>`amount`: number of tokens to send</small>
> <small>`data`: information attached to the send, previously provided by the *token holder*</small>
> <small>`operatorData`: information attached to the send by the `operator`</small>
#### **Minting Tokens**
Minting tokens is the act of producing new tokens. [ERC777] intentionally does not define explicit functions to mint tokens. This intent comes from the wish to not limit the use of the [ERC777] standard as the minting process is generally specific for every token.
Nonetheless, the rules below MUST be respected when minting for a *recipient*:
- Tokens MAY be minted for any *recipient* address.
- The total supply MUST be increased by the amount of tokens minted.
- The balance of `0x0` MUST NOT be decreased.
- The balance of the *recipient* MUST be increased by the amount of tokens minted.
- The token contract MUST fire a `Minted` event with the correct values as defined in the [`Minted` Event][minted].
- The token contract MUST call the `tokensReceived` hook of the *recipient*, provided the *recipient* implements the `ERC777TokensRecipient` interface via [ERC820].
- When calling `tokensReceived`:
- `operator` MUST be the address which initiated the minting action. (Generally the `msg.sender` of the minting function call.)
- `from` MUST be `0x0`.
- `to` MUST be the address of the *recipient*.
- `data` MUST be empty.
- `operatorData` MUST contain the data with the OPTIONAL modifications by the token contract, provided by the address which initiated the minting action.
The token contract MUST throw when minting in any of the following cases:
- The resulting *recipient* balance after the mint has a granularity smaller than the *granularity* defined by the token contract.
- The *recipient* is a contract and it does not implement the `ERC777TokensRecipient` interface via [ERC820].
- The address of the *recipient* is `0x0`.
*[ERC20] compatibility requirement*:
While a `Sent` event MUST NOT be fired when minting, if the token contract is [ERC20] backward compatible, a `Transfer` event with the `from` parameter set to `0x0` MUST be fired as defined in the [ERC20] standard.
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.
- A `Minted` event MUST be fired 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 sent `amount`.
**`Minted` event** <a id="minted"></a>
``` solidity
event Minted(address indexed operator, address indexed to, uint256 amount, bytes operatorData)
```
Indicate the minting of `amount` of tokens to the `to` address.
Indicate the minting of `amount` of tokens to the `to` address by the `operator` address.
This standard does not enforce a specific way to mint tokens as this can be done in various ways depending on the use case of the tokens.
> <small>**parameters**</small>
> <small>`operator`: address which triggered the mint</small>
> <small>`to`: token recipient</small>
> <small>`amount`: number of tokens minted</small>
> <small>`operatorData`: information attached to the minting by the `operator`</small>
However, this event MUST be fired every time tokens are minted and credited to a `to` recipient address. A `Sent` event (even with the `0x0` as `from` address) MUST NOT be fired to indicate minting.
#### **Burning Tokens**
> **parameters**
> - `operator`: address which triggered the minting
> - `to`: tokens recipient
> - `amount`: number of tokens minted
> - `operatorData`: information attached to the minting by the operator
Burning tokens is the act of destroying existing tokens. [ERC777] explicitly defines two functions to burn tokens (`burn` and `operatorBurn`). This makes it easier for wallets and dapps to let *token holders* burn tokens. However, the token contract MAY prevent some or all *token holders* from burning tokens for any reason. The token contract MAY also define other functions to burn tokens.
###### `tokensReceived` for minting
The rules below MUST be respected when burning the tokens of a *token holder*:
Every mint MUST call `tokensReceived` on the address implementing `ERC777TokensRecipient` for the `to` address as returned by an ERC820 lookup.
- Tokens MAY be burned from any *token holder* address.
- The total supply MUST be decreased by the amount of tokens minted.
- The balance of `0x0` MUST NOT be increased.
- The balance of the *token holder* MUST be decreased by amount of tokens burned.
- The token contract MUST fire a `Burned` event with the correct values as defined in the [`Burned` Event][burned].
- The token contract MUST call the `tokensToSend` hook of the *token holder*, provided the *token holder* implements the `ERC777TokensSender` interface via [ERC820].
- When calling `tokensToSend`:
- `operator` MUST be the address which initiated the minting action. (Generally the `msg.sender` of the minting function call.)
- `from` MUST be the address of the *token holder*.
- `to` MUST be `0x0`.
- `data` MUST be empty.
- `operatorData` MUST contain data with the OPTIONAL modifications by the token contract, provided by the address which initiated the burning action (i.e. the *operator*) and/or the token contract.
Minting MUST follow the same rules as `send`/`operatorSend` with the exception that `tokensToSend` MUST NOT be called in any case on any address. In addition, if `to` is a contract which is not prepared to receive tokens. Specifically, it is a contract which does not register an address (its own or another) via ERC820 implementing the `ERC777TokensRecipient` interface. Then the minting MUST throw.
The token contract MUST throw when burning in any of the following cases:
The `from` parameter of `tokensReceived` MUST be `0x0`. The operator MUST be `msg.sender`. The `userData` MUST be empty. `operatorData` MAY contain data related to the minting.
- The address initiating the burn of tokens from a *token holder* MUST be an *operator* of the *token holder*.
<br/>
- The resulting *token holder* balance after the burn has a granularity smaller than the *granularity* defined by the token contract.
- The balance of *token holder* is inferior to the amount of tokens being burnt (i.e. resulting in a negative balance for the *token holder*).
- The address of the *token holder* is `0x0`.
##### Burned
*[ERC20] compatibility requirement*:
While a `Sent` event MUST NOT be fired when burning, if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` MUST be fired as defined in the [ERC20] standard.
The token contract MAY burn tokens for multiple *token holders* at once. In this case:
- The previous burn rules MUST apply to each *token holders*.
- The sum of all the balances decremented MUST be equal to the total burned amount.
- A `Burned` event MUST be fired for every *token holder* with the corresponding amount for each *token holder*.
- The sum of all the amounts from the `Burned` event MUST be equal to the total sent `amount`
**`Burned` event** <a id="burned"></a>
``` solidity
event Burned(address indexed operator, address indexed from, uint256 amount, bytes userData, bytes operatorData)
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData)
```
Indicate the burning of `amount` of tokens from the `from` address.
The `burn` and `operatorBurn` functions described below MUST be implemented to burn tokens.
Token contracts MAY implement other functions to burn tokens.
This standard does not enforce a specific way to burn tokens as this can be done in various ways depending on the use case of the tokens.
Indicate the burning of `amount` of tokens from the `from` address by the `operator` address.
However, this event MUST be fired every time tokens are burned and taken from a `from` recipient address. A `Sent` event (even with the `0x0` as `to` address) MUST NOT be fired.
> **parameters**
> - `operator`: address which triggered the minting
> - `from`: token holder
> - `amount`: number of tokens burned
> - `userData`: information attached to the burn by the token holder
> - `operatorData`: information attached to the burn by the operator
###### `tokensToSend` for burning
Every burn MUST call `tokensToSend` on the address implementing `ERC777TokensSender` for the `from` address as returned by an ERC820 lookup.
Burning MUST follow the same rules as `send`/`operatorSend` with the exception that `tokensReceived` MUST NOT be called in any case on any address. But if the `from` address register an address via ERC820 implementing the `ERC777TokensSender` interface, `tokensToSend` MUST be called.
The `to` parameter of `tokensToSend` MUST be `0x0`. The operator MUST be `msg.sender`. The `userData` MUST be empty. `operatorData` MAY contain data related to the minting.
<br/>
##### AuthorizedOperator
> <small>**parameters**</small>
> <small>`operator`: address which triggered the burn</small>
> <small>`from`: token holder</small>
> <small>`amount`: number of tokens burned</small>
> <small>`data`: information attached to the burn by the token holder</small>
> <small>`operatorData`: information attached to the burn by the `operator`</small>
``` solidity
event AuthorizedOperator(address indexed operator, address indexed tokenHolder)
function burn(uint256 amount, bytes data) public;
```
Indicate that the `operator` address is allowed to send the token of (i.e. is an operator for) the address `tokenHolder`.
Burn the `amount` of tokens from the address `msg.sender`.
This event MUST be fired on a successful call to `authorizeOperator`.
The *operator* and the *token holder* MUST both be the `msg.sender`.
> **parameters**
> - `operator`: Address which is granted rights to manage the tokens.
> - `tokenHolder`: address which holds the tokens to be managed.
> <small>**parameters**</small>
> <small>`amount`: number of tokens to burn</small>
> <small>`data`: information attached to the transaction by the token holder</small>
<br/>
##### RevokedOperator
``` solidity
event RevokedOperator(address indexed operator, address indexed tokenHolder)
function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public;
```
Indicate that the `operator` address is denied the rights to send the token of (i.e. is not operator for) the address `tokenHolder`.
Burn the `amount` of tokens on behalf of the address `from`.
This event MUST be fired on a successful call to `revokeOperator`.
The *operator* MUST be `msg.sender`.
> **parameters**
> - `operator`: Address which is denied the rights to manage the tokens.
> - `tokenHolder`: address which holds the tokens to be managed.
*Reminder*: If the *operator* address is not an authorized operator of the `from` address the burn must throw.
<br/>
*NOTE*: The *operator* MAY pass any data via `operatorData`. The *operator* MUST only pass to `data` data given to it by the *token holder*. The token holder MAY provide this data to the *operator* beforehand through another medium.
### ERC777TokensSender
*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).
Any address (contract or regular account) CAN register a contract (itself or another) implementing the `ERC777TokensSender` interface via the ERC820 registry.
#### **`ERC777TokensSender` And `tokensToSend` Hook**
The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *token holder*. Any address (regular or contract) wishing to be notified of an debit of their tokens MUST register the address of a contract implementing the `ERC777TokensSender` interface below. A regular address can register a different address&mdash;the address of a contract&mdash; implementing the interface on its behalf. A contract can register either its address or the address of another contract, but said contract MUST implement the interface.
``` solidity
interface ERC777TokensSender {
@ -374,132 +494,162 @@ interface ERC777TokensSender {
address from,
address to,
uint value,
bytes userData,
bytes data,
bytes operatorData
) public;
}
```
#### Methods
##### tokensToSend
**`tokensToSend`**
``` solidity
function tokensToSend(address operator, address from, address to, uint value, bytes userData, bytes operatorData) public
function tokensToSend(address operator, address from, address to, uint value, bytes data, bytes operatorData) public
```
Notify the transmission of `amount` of tokens from the `from` address.
Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address.
> **parameters**
> - `operator`: address which triggered the transfer, either sender for a direct send or an authorized operator for `operatorSend`
> - `from`: token holder (sender)
> - `to`: tokens recipient (or `0x` for burning)
> - `amount`: number of tokens sent or burned
> - `userData`: information attached to the transaction by the sender
> - `operatorData`: information attached to the transaction by the operator
> <small>**parameters**</small>
> <small>`operator`: address which triggered the balance decrease (through sending or burning)</small>
> <small>`from`: *token holder* (sender)</small>
> <small>`to`: *token recipient* for a send and `0x` for a burn</small>
> <small>`amount`: number of tokens the *token holder* balance is decreased by</small>
> <small>`data`: extra information provided by the *token holder* with the OPTIONAL modifications by the token contract</small>
> <small>`operatorData`: extra information provided by the address which triggered the balance decrease with the OPTIONAL modifications by the token contract</small>
###### Burning Versus Sending
The following rules apply to the `tokensToSend` hook:
When tokens are sent as a result of burning:
- `to` MUST be `0x0`
- `userData` MUST be empty
- `operator` MUST be the address which initiated the burning
- `operatorData` MAY contain data
- The `tokensToSend` hook MUST be called every time the balance is decremented.
- The `tokensToSend` hook MUST be called *before* the state is update&mdash;i.e. *before* the balance is decremented.
- `operator` MUST be the address which triggered the decrease of the balance.
- `from` MUST be the address of the *token holder* whose balance is decreased for a send or burn.
- `from` MUST be `0x0` for a mint.
- `to` MUST be the address of the *recipient* whose balance is increased for a send or mint.
- `to` MUST be `0x0` for a burn.
- `data` MUST contain the extra information provided by the *token holder* (if any) with the OPTIONAL modifications by the token contract for a send.
- `data` MUST be empty for a mint.
- `operatorData` MUST contain the extra information provided by the address which triggered the decrease of the balance (if any) with the OPTIONAL modifications by the token contract.
- A *token holder* SHALL register its `tokensToSend` hook by registering the address implementing the hook via [ERC820] with the interface name `ERC777TokensSender`.
- A *token holder* CAN register any address (itself or any other) as the implementer of the `ERC777TokensSender` interface.
- A *token holder* MUST register at most one `ERC777TokensSender` implementation at any given time.
- The address claiming to implement the `ERC777TokensSender` interface MUST be a contract which implements the interface.
- The *token holder* MAY block a decrease of its balance by throwing. (I.e. reject the withdrawal of tokens from its account.)
- Any `ERC777TokensSender` implementation MAY be used by more than one *token holder*.
When tokens are sent as a result of sending (`send` or `operatorSend`):
- `to` MUST be the address to which the tokens will be sent
- `to` MUST NOT be `0x0`
*NOTE*: An address can (and MUST) register at most one implementation at a given time. 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.
If it is a direct `send` (i.e. not an `operatorSend`) the `operator` MUST be the address from which the tokens originate. That is the `from` and `operator` addresses MUST be equals.
*[ERC20] compatibility requirement*:
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.
#### **`ERC777TokensRecipient` And `tokensReceived` Hook**
### ERC777TokensRecipient
Any address (contract or regular account) CAN register a contract (itself or another) implementing the `ERC777TokensRecipient` interface via the ERC820 registry.
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 a reception of tokens MUST register the address of a contract implementing the `ERC777TokensRecipient` interface below. A regular address can register a different address&mdash;the address of a contract&mdash; implementing the interface on its behalf. A contract MUST register either its address or the address of another contract, but said contract MUST implement the interface.
``` solidity
interface ERC777TokensRecipient {
function tokensReceived(address operator, address from, address to, uint amount, bytes userData, bytes operatorData) public;
function tokensReceived(
address operator,
address from,
address to,
uint amount,
bytes data,
bytes operatorData
) public;
}
```
#### Methods
##### tokensReceived
**`tokensReceived`**
``` solidity
function tokensReceived(address operator, address from, address to, uint amount, bytes userData, bytes operatorData) public
function tokensReceived(address operator, address from, address to, uint amount, bytes data, bytes operatorData) public
```
Notify the transmission of `amount` of tokens to the `to` address.
Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address.
> **parameters**
> - `operator`: address which triggered the transfer, either sender for a direct send or an authorized operator for `operatorSend`
> - `from`: token holder (sender or `0x` for minting)
> - `to`: tokens recipient (or `0x` for burning)
> - `amount`: number of tokens sent, minted or burned
> - `userData`: information attached to the transaction by the sender
> - `operatorData`: information attached to the transaction by the operator
> <small>**parameters**</small>
> <small>`operator`: address which triggered the balance increase (through sending or minting)</small>
> <small>`from`: *token holder* for a send and `0x` for a mint</small>
> <small>`to`: *token recipient*</small>
> <small>`amount`: number of tokens the *recipient* balance is increased by</small>
> <small>`data`: extra information provided by the *token holder* for a send and nothing (empty bytes) for a mint, with the OPTIONAL modifications by the token contract</small>
> <small>`operatorData`: extra information provided by the address which triggered the balance increase with the OPTIONAL modifications by the token contract</small>
###### Minting Versus Sending
- The `tokensReceived` hook MUST be called every time the balance is incremented.
- The `tokensReceived` hook MUST be called *after* the state is update&mdash;i.e. *after* the balance is incremented.
- `operator` MUST be the address which triggered the increase of the balance.
- `from` MUST be the address of the *token holder* whose balance is decreased for a send or burn.
- `from` MUST be `0x0` for a mint.
- `to` MUST be the address of the *recipient* whose balance is increased for a send or mint.
- `to` MUST be `0x0` for a burn.
- `data` MUST contain the extra information provided by the *token holder* (if any) with the OPTIONAL modifications by the token contract for a send.
- `data` MUST be empty for a mint.
- `operatorData` MUST contain the extra information provided by the address which triggered the increase of the balance (if any) with the OPTIONAL modifications by the token contract.
- A *token holder* SHALL register its `tokensReceived` hook by registering the address implementing the hook via [ERC820] with the interface name `ERC777TokensRecipient`.
- If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation; the token contract:
- MUST throw if the `tokensReceived` hook is called from a mint or send call.
- SHOULD accept if the `tokensReceived` hook is called from an ERC20 `transfer` or `transferFrom` call.
- A *token holder* CAN register any address (itself or any other) as the implementer of the `ERC777TokensRecipient` interface.
- A *token holder* MUST register at most one `ERC777TokensRecipient` implementation at any given time.
- The address claiming to implement the `ERC777TokensRecipient` interface MUST be a contract which implements the interface.
- The *token holder* MAY block an increase of its balance by throwing. (I.e. reject the reception of tokens.)
- Any `ERC777TokensRecipient` implementation MAY be used by more than one *token holder*.
When tokens are received as a result of minting:
- `from` MUST be `0x0`
- `userData` MUST be empty
- `operator` MUST be the address which initiated the minting
- `operatorData` MAY contain data.
*NOTE*: An address can (and MUST) register at most one implementation at a given time. 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.
When tokens are received as a result of sending (`send` or `operatorSend`):
- `from` MUST be the one from which the tokens originate and
- `from` MUST NOT be `0x0`.
*[ERC20] compatibility requirement*:
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.
If it is a direct `send` (i.e. not an `operatorSend`) the `operator` MUST be the address from which the tokens originate. That is the `from` and `operator` addresses MUST be equals.
#### **Note On Gas Consumption**
Dapps and wallets SHOULD first estimate the gas required when sending, minting,or burning tokens&mdash;using [`eth_estimateGas`][eth_estimateGas]&mdash;to avoid running out of gas during the transaction.
### Logo
| **Image** | &nbsp;![beige logo](../assets/eip-777/logo/png/ERC-777-logo-beige-48px.png) | &nbsp;![white logo](../assets/eip-777/logo/png/ERC-777-logo-white-48px.png) | &nbsp;![light grey logo](../assets/eip-777/logo/png/ERC-777-logo-light_grey-48px.png) | &nbsp;![dark grey logo](../assets/eip-777/logo/png/ERC-777-logo-dark_grey-48px.png) | &nbsp;![black logo](../assets/eip-777/logo/png/ERC-777-logo-black-48px.png?raw=true)
| **Image** | &nbsp;![beige logo] | &nbsp;![white logo] | &nbsp;![light grey logo] | &nbsp;![dark grey logo] | &nbsp;![black logo][black logo] |
|----------:|:---------:|:---------:|:------------:|:-----------:|:---------:|
| **Color** | beige | white | light grey | dark grey | black |
| **Hex** | `#C99D66` | `#FFFFFF` | `#EBEFF0` | `#3C3C3D` | `#000000` |
The logo MUST NOT be used to advertise, promote or associate in any way technology such as tokens which is not ERC777 compliant.
The logo MAY be used, modified and adapted to promote valid [ERC777] token implementations and [ERC777] compliant technologies such as wallets and dapps.
The logo for the standard can be found in the `/assets/eip-777/logo` folder in `svg` and `png` formats. The `png` version of the logo offers a few sizes in pixels. If needed, other sizes CAN be created by converting from `svg` into `png`.
[ERC777] token contract authors CAN create a specific logo for their token based on this logo.
ERC777 token contract authors CAN create a specific logo for their token based on this logo.
The logo MUST NOT be used to advertise, promote or associate in any way technology&mdash;such as tokens&mdash;which is not [ERC777] compliant.
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 CAN be created by converting from `svg` into `png`.
## Rationale
This standard solves some of the problems of the [EIP223](https://github.com/ethereum/EIPs/issues/223) and goes a step further by allowing operators (generally contracts) that can manage the tokens in the same way that the ERC20 with infinite `approve` was allowed.
This standard solves some of the shortcomings of [ERC20]. It avoids the problems of the [EIP223]. It is backward compatible with [ERC20]. Lastly and 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 and hooks to give greater control to *token holders* over their tokens.
Also, the usage of ERC820 allows backward compatibility with wallets and proxy contracts without having to be redeployed.
Also, the usage of [ERC820] allows backward compatibility with wallets and existing contracts without having to be redeployed thanks proxy contracts implementing the hooks.
## Backward Compatibility (ERC20Token)
## Backward Compatibility
This EIP does not introduce backward incompatibilities and is compatible with the older ERC20 token standard.
This EIP does not introduce backward incompatibilities and is backward compatible with the older [ERC20] token standard.
This EIP does not use `transfer` and `transferFrom` and uses `send` and `operatorSend` to avoid mistakes in knowing which interface you are using.
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.
This standard allows the implementation of ERC20 functions `transfer`, `transferFrom`, `approve` and `allowance` alongside to make a token compatible with ERC20.
This standard allows the implementation of [ERC20] functions `transfer`, `transferFrom`, `approve` and `allowance` alongside to make a token fully compatible with [ERC20].
The token CAN implement `decimals()` for backward compatibility. If implemented, it MUST always return `18`.
The token CAN implement `decimals()` for backward compatibility with [ERC20]. If implemented, it MUST always return `18`.
Therefore a token contract CAN implement both ERC20 and ERC777 in parallel. Read-only 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` (`decimal` is not part of the ERC777 standard).
Therefore a token contract CAN 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` (`decimal` is not part of the [ERC777] standard).
The write methods 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.
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.
If the token implements ERC20, it MUST register the `ERC20Token` interface with its own address via ERC820. If the contract has a switch to enable or disable ERC20 methods, every time the switch is triggered, the token MUST register or unregister its own address accordingly the `ERC20Token` interface via ERC820. (Unregistering implies setting the address to `0x0`.)
If the token implements [ERC20], it MUST register the `ERC20Token` interface with its own address via [ERC820]. If the contract has a switch to enable or disable [ERC20] functions, every time the switch is triggered, the token MUST register or unregister its own address accordingly the `ERC20Token` interface via [ERC820]. (Unregistering implies setting the address to `0x0`.)
The only difference for new contracts implementing ERC20 is that registration of `ERC777TokensSender` and `ERC777TokensRecipient` via ERC820 takes precedence over ERC20. This means that even with an ERC20 `transfer` call, the token contract MUST check via ERC820 if the `from` / `to` address implements `tokensToSend` / `tokensReceived` and call it if available. 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.
The difference for new contracts implementing [ERC20] is that
`tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. This means that even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC820] 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.
The table below summarizes the different actions the token contract MUST take when sending, minting and transferring token via [ERC777] and [ERC20]:
The table below summarizes the different actions the token contract must take when sending, minting and transferring token via ERC777 and ERC20:
<table>
<tr>
<th>ERC820</th>
<th align="right">ERC820</th>
<th><code>to</code> address</th>
<th>ERC777 <code>send</code>/<code>operatorSend</code> and Minting</th>
<th>ERC20 <code>transfer</code></th>
<th align="center">ERC777 Sending And Minting</th>
<th align="center">ERC20 <code>transfer</code>/<code>transferFrom</code></th>
</tr>
<tr>
<td rowspan="2" align="right">
@ -527,16 +677,47 @@ The table below summarizes the different actions the token contract must take wh
</tr>
</table>
There is no particular action to take if `tokensToSend` is not implemented. The transfer MUST proceed and be canceled only if another condition is not respected such as lack of funds, a throw in `tokensReceived` (if present) or in some specific cases if `tokensReceived` is not implemented.
There is no particular action to take if `tokensToSend` is not implemented. The transfer MUST proceed and be canceled only if another condition is not respected such as lack of funds or a throw in `tokensReceived` (if present).
During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be fired. In addition, if the token contract declares that it implements `ERC20Token` via [ERC820], the token contract MUST fire a `Transfer` event (as specified in the [ERC20] standard). During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be fired.
This means that for any movement of tokens, two events MAY be fired: an [ERC20] `Transfer` and an [ERC777] `Sent`, `Minted` or `Burnt` (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 the token is considered by an application as an ERC20 token, then only the `Transfer` event MUST be considered. If the token is considered by an application as an ERC777 token, the only the `Sent`, `Minted` and `Burnt` events MUST be considered.
## Test Cases
The [repository with the reference implementation](https://github.com/jacquesd/ERC777) contains all the [tests](https://github.com/jacquesd/ERC777/blob/master/test/ReferenceToken.test.js).
The [repository with the reference implementation][jacquesd/ERC777] contains all the [tests][ref tests].
## Implementation
The repository at [jacquesd/ERC777](https://github.com/jacquesd/ERC777) contains the [reference implementation](https://github.com/jacquesd/ERC777/blob/master/contracts/examples/ReferenceToken.sol).
The repository at [jacquesd/ERC777] contains the [reference implementation].
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
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
[ERC820]: https://eips.ethereum.org/EIPS/eip-820
[jacquesd/ERC777]: https://github.com/jacquesd/ERC777
[ref tests]: https://github.com/jacquesd/ERC777/blob/master/test/ReferenceToken.test.js
[reference implementation]: https://github.com/jacquesd/ERC777/blob/master/contracts/examples/ReferenceToken.sol
[EIP223]: https://github.com/ethereum/EIPs/issues/223
[eth_estimateGas]: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas
[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/