mirror of https://github.com/status-im/EIPs.git
545 lines
23 KiB
Markdown
545 lines
23 KiB
Markdown
|
---
|
|||
|
eip: 777
|
|||
|
title: A New Advanced Token Standard
|
|||
|
author: Jordi Baylina <jordi@baylina.cat>, Jacques Dafflon <jacques.dafflon@gmail.com>, Thomas Shababi <tom@truelevel.io>
|
|||
|
discussions-to: https://github.com/ethereum/EIPs/issues/777
|
|||
|
status: Draft
|
|||
|
type: Standards Track
|
|||
|
category: ERC
|
|||
|
created: 2017-11-20
|
|||
|
requires: 820
|
|||
|
---
|
|||
|
|
|||
|
## Simple Summary
|
|||
|
|
|||
|
This EIP defines a standard interface for token contracts.
|
|||
|
|
|||
|
*The repository for this standard containing the reference implementation can be found at [jacquesd/ERC777](https://github.com/jacquesd/ERC777) and installed via npm with: `npm install erc777`.*
|
|||
|
|
|||
|
## Abstract
|
|||
|
|
|||
|
This standard defines a new way to interact with a Token Contract.
|
|||
|
|
|||
|
It defines operators to send tokens on behalf of another address – contract or regular account. It takes advantage of [ERC820](https://github.com/ethereum/EIPs/issues/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.
|
|||
|
|
|||
|
## Motivation
|
|||
|
|
|||
|
This standard tries to improve the widely used [ERC20](https://github.com/ethereum/EIPs/issues/20) 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`).
|
|||
|
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 backwards compatible way with wallets that do not contain the `tokensReceived` function by deploying a proxy contract for the wallet.
|
|||
|
|
|||
|
## Specification
|
|||
|
|
|||
|
### ERC777Token (Token Contract)
|
|||
|
|
|||
|
``` 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) public;
|
|||
|
function send(address to, uint256 amount, bytes userData) public;
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
event Sent(
|
|||
|
address indexed operator,
|
|||
|
address indexed from,
|
|||
|
address indexed to,
|
|||
|
uint256 amount,
|
|||
|
bytes userData,
|
|||
|
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 AuthorizedOperator(address indexed operator, address indexed tokenHolder);
|
|||
|
event RevokedOperator(address indexed operator, address indexed tokenHolder);
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
The token-contract MUST register the `ERC777Token` interface via ERC820.
|
|||
|
|
|||
|
The basic unit token MUST be 10<sup>18</sup>.
|
|||
|
|
|||
|
#### Methods
|
|||
|
##### name
|
|||
|
|
|||
|
``` solidity
|
|||
|
function name() public constant returns (string)
|
|||
|
```
|
|||
|
|
|||
|
Returns the name of the token – e.g. `"MyToken"`.
|
|||
|
|
|||
|
> **returns:** Name of the token
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### symbol
|
|||
|
|
|||
|
``` solidity
|
|||
|
function symbol() public constant returns (string)
|
|||
|
```
|
|||
|
|
|||
|
Returns the symbol of the token – e.g. `"MYT"`.
|
|||
|
|
|||
|
> **returns:** Symbol of the token
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### granularity
|
|||
|
|
|||
|
``` 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)
|
|||
|
```
|
|||
|
|
|||
|
Get the total number of minted tokens.
|
|||
|
|
|||
|
> **returns:** Total supply of tokens currently in circulation.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### balanceOf
|
|||
|
|
|||
|
``` solidity
|
|||
|
function balanceOf(address tokenHolder) public constant returns (uint256)
|
|||
|
```
|
|||
|
|
|||
|
Get the balance of the account with address `tokenHolder`.
|
|||
|
> **parameters**
|
|||
|
> - `tokenHolder`: Address for which the balance is returned
|
|||
|
>
|
|||
|
> **returns:** Amount of token held by `tokenHolder` in the token contract.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### send
|
|||
|
|
|||
|
``` solidity
|
|||
|
function send(address to, uint256 amount) public
|
|||
|
function send(address to, uint256 amount, bytes userData) public
|
|||
|
```
|
|||
|
|
|||
|
Send `amount` of tokens to address `to`.
|
|||
|
|
|||
|
This call MUST:
|
|||
|
- call the `tokensToSend` method on the contract implementing `ERC777TokensSender` as returned by a 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 a ERC820 lookup on the `to` address – regardless if `to` is a regular address or a contract.
|
|||
|
- fire the `Sent` event.
|
|||
|
|
|||
|
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 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*: 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)
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### authorizeOperator
|
|||
|
|
|||
|
``` solidity
|
|||
|
function authorizeOperator(address operator) public
|
|||
|
```
|
|||
|
|
|||
|
Authorize a third party `operator` to send tokens on behalf of `msg.sender`.
|
|||
|
|
|||
|
A `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*: A token holder CAN authorize multiple operators at the same time.
|
|||
|
|
|||
|
> **parameters**
|
|||
|
> - `operator`: Address which will be granted rights to manage the tokens.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### revokeOperator
|
|||
|
|
|||
|
``` solidity
|
|||
|
function revokeOperator(address operator) public
|
|||
|
```
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
> **parameters**
|
|||
|
> - `operator`: Address which whose rights to manage the tokens will be revoked.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### isOperatorFor
|
|||
|
|
|||
|
``` solidity
|
|||
|
function isOperatorFor(address operator, address tokenHolder) public constant returns (bool)
|
|||
|
```
|
|||
|
|
|||
|
Check whether the `operator` address is allowed to send the tokens held by 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.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### operatorSend
|
|||
|
|
|||
|
``` solidity
|
|||
|
function operatorSend(address from, address to, uint256 amount, bytes userData, bytes operatorData) public
|
|||
|
```
|
|||
|
|
|||
|
Send `amount` of tokens on behalf of the address `from` to the address `to`.
|
|||
|
|
|||
|
`msg.sender` MUST be an authorized operator or the owner for the `from` address.
|
|||
|
|
|||
|
This call MUST:
|
|||
|
- call the `tokensToSend` method on the contract implementing `ERC777TokensSender` as returned by a ERC820 lookup on the `from` address
|
|||
|
- call the `tokensReceived` method on the contract implementing `ERC777TokensRecipient` as returned by a ERC820 lookup on the `to` address
|
|||
|
- fire the `Sent` event
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
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
|
|||
|
|
|||
|
``` solidity
|
|||
|
event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes userData, bytes operatorData)
|
|||
|
```
|
|||
|
|
|||
|
Indicate a transaction of `amount` of tokens from the `from` address to the `to` address.
|
|||
|
|
|||
|
This event MUST be fired on a successful call to `send` and `operatorSend`.
|
|||
|
|
|||
|
> **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
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### Minted
|
|||
|
|
|||
|
``` solidity
|
|||
|
event Minted(address indexed operator, address indexed to, uint256 amount, bytes operatorData)
|
|||
|
```
|
|||
|
|
|||
|
Indicate the minting of `amount` of tokens to the `to` 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.
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
> **parameters**
|
|||
|
> - `operator`: address which triggered the minting
|
|||
|
> - `to`: tokens recipient
|
|||
|
> - `amount`: number of tokens minted
|
|||
|
> - `operatorData`: information attached to the minting by the operator
|
|||
|
|
|||
|
###### `tokensReceived` for minting
|
|||
|
|
|||
|
Every mint MUST call `tokensReceived` on the address implementing `ERC777TokensRecipient` for the `to` address as returned by a ERC820 lookup.
|
|||
|
|
|||
|
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 `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.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### Burned
|
|||
|
|
|||
|
``` solidity
|
|||
|
event Burned(address indexed operator, address indexed from, uint256 amount, bytes userData, bytes operatorData)
|
|||
|
```
|
|||
|
|
|||
|
Indicate the burning of `amount` of tokens from the `from` address.
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
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 a 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
|
|||
|
|
|||
|
``` solidity
|
|||
|
event AuthorizedOperator(address indexed operator, address indexed tokenHolder)
|
|||
|
```
|
|||
|
|
|||
|
Indicate that the `operator` address is allowed to send the token of (i.e. is an operator for) the address `tokenHolder`.
|
|||
|
|
|||
|
This event MUST be fired on a successful call to `authorizeOperator`.
|
|||
|
|
|||
|
> **parameters**
|
|||
|
> - `operator`: Address which is granted rights to manage the tokens.
|
|||
|
> - `tokenHolder`: address which holds the tokens to be managed.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
##### RevokedOperator
|
|||
|
|
|||
|
``` solidity
|
|||
|
event RevokedOperator(address indexed operator, address indexed tokenHolder)
|
|||
|
```
|
|||
|
|
|||
|
Indicate that the `operator` address is denied the rights to send the token of (i.e. is not operator for) the address `tokenHolder`.
|
|||
|
|
|||
|
This event MUST be fired on a successful call to `revokeOperator`.
|
|||
|
|
|||
|
> **parameters**
|
|||
|
> - `operator`: Address which is denied the rights to manage the tokens.
|
|||
|
> - `tokenHolder`: address which holds the tokens to be managed.
|
|||
|
|
|||
|
<br/>
|
|||
|
|
|||
|
### ERC777TokensSender
|
|||
|
|
|||
|
Any address (contract or regular account) CAN register a contract (itself or an other) implementing the `ERC777TokensSender` interface via the ERC820 registry.
|
|||
|
|
|||
|
``` solidity
|
|||
|
interface ERC777TokensSender {
|
|||
|
function tokensToSend(
|
|||
|
address operator,
|
|||
|
address from,
|
|||
|
address to,
|
|||
|
uint value,
|
|||
|
bytes userData,
|
|||
|
bytes operatorData
|
|||
|
) public;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### Methods
|
|||
|
|
|||
|
##### tokensToSend
|
|||
|
|
|||
|
``` solidity
|
|||
|
function tokensToSend(address operator, address from, address to, uint value, bytes userData, bytes operatorData) public
|
|||
|
```
|
|||
|
|
|||
|
Notify the transmission of `amount` of tokens from the `from` 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
|
|||
|
|
|||
|
###### Burning Versus Sending
|
|||
|
|
|||
|
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
|
|||
|
|
|||
|
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`
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
|
|||
|
### ERC777TokensRecipient
|
|||
|
|
|||
|
Any address (contract or regular account) CAN register a contract (itself or an other) implementing the `ERC777TokensRecipient` interface via the ERC820 registry.
|
|||
|
|
|||
|
``` solidity
|
|||
|
interface ERC777TokensRecipient {
|
|||
|
function tokensReceived(address operator, address from, address to, uint amount, bytes userData, bytes operatorData) public;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### Methods
|
|||
|
|
|||
|
##### tokensReceived
|
|||
|
|
|||
|
``` solidity
|
|||
|
function tokensReceived(address operator, address from, address to, uint amount, bytes userData, bytes operatorData) public
|
|||
|
```
|
|||
|
|
|||
|
Notify the transmission of `amount` of tokens to the `to` 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
|
|||
|
|
|||
|
###### Minting Versus Sending
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
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`.
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
### Logo
|
|||
|
|
|||
|
| **Image** | ![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?raw=true)
|
|||
|
|----------:|:---------:|:---------:|:------------:|:-----------:|:---------:|
|
|||
|
| **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 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 pixel. 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.
|
|||
|
|
|||
|
## Rationale
|
|||
|
|
|||
|
This standard solves some of the problems of the [EIP223](https://github.com/ethereum/EIPs/issues/223) and goes an step further by allowing operators (generally contracts) that can manage the tokens in the same way that the ERC20 with infinite `approve` was allowed.
|
|||
|
|
|||
|
Also the usage of ERC820 allows backwards compatibility with wallets and proxy contracts without having to be redeployed.
|
|||
|
|
|||
|
## Backwards Compatibility (ERC20Token)
|
|||
|
|
|||
|
This EIP does not introduce backward incompatibilities and is compatible with the older ERC20 token standard.
|
|||
|
|
|||
|
This EIP does not uses `transfer` and `transferFrom` and uses `send` and `operatorSend` to avoid mistakes in knowing which interface you are using.
|
|||
|
|
|||
|
This standard allows the implementation of ERC20 functions `transfer`, `transferFrom`, `approve` and `allowance` alongside to make a token compatible with ERC20.
|
|||
|
|
|||
|
The token can implement `decimals()` for backwards compatibility. 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 problem. 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.
|
|||
|
|
|||
|
If the token implements ERC20, it MUST be register the `ERC20Token` interface 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 accordingly the `ERC20Token` interface via ERC820.
|
|||
|
|
|||
|
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 a 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 table below summarize the different actions the token contract must take when sending, minting and transferring token via ERC777 and ERC20:
|
|||
|
|
|||
|
<table>
|
|||
|
<tr>
|
|||
|
<th>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>
|
|||
|
</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>
|
|||
|
<td align="center">SHOULD accept</td>
|
|||
|
<td rowspan="2" align="center">SHOULD accept</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>contract</td>
|
|||
|
<td align="center">MUST throw</td>
|
|||
|
</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.
|
|||
|
|
|||
|
## 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).
|
|||
|
|
|||
|
## Implementation
|
|||
|
|
|||
|
The repository at [/jacquesd/ERC777](https://github.com/jacquesd/ERC777) contains the [reference implementation](https://github.com/jacquesd/ERC777/blob/master/contracts/ReferenceToken.sol).
|
|||
|
|
|||
|
## Copyright
|
|||
|
|
|||
|
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|