mirror of https://github.com/status-im/EIPs.git
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:
parent
d970b2385e
commit
9e4283608c
430
EIPS/eip-777.md
430
EIPS/eip-777.md
|
@ -18,21 +18,40 @@ This EIP defines standard interfaces and behaviors for token contracts.
|
|||
|
||||
This standard defines a new way to interact with a token contract while remaining backward compatible with [ERC20].
|
||||
|
||||
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 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 [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.
|
||||
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.
|
||||
|
||||
## Motivation
|
||||
|
||||
This standard tries to improve the widely used [ERC20] 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 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, unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this.
|
||||
5. The token holder can "authorize" and "revoke" operators which 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 `data` and `operatorData` bytes fields to be used freely to pass data from the token holder and the operator, respectively.
|
||||
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.
|
||||
|
||||
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,
|
||||
unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this.
|
||||
|
||||
5. The token holder can "authorize" and "revoke" operators which 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 `data` and `operatorData` bytes fields
|
||||
to be used freely to pass data from the token holder and the operator, respectively.
|
||||
|
||||
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
|
||||
|
||||
|
@ -93,7 +112,8 @@ the `keccak256` hash of `ERC777Token` as the interface hash and `0x0` as the imp
|
|||
|
||||
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.
|
||||
The display denomination—to display any amount to the end user—MUST be 10<sup>18</sup> of the internal denomination.
|
||||
The display denomination—to display any amount to the end user—MUST
|
||||
be 10<sup>18</sup> of the internal denomination.
|
||||
|
||||
In other words, the internal denomination is similar to a wei
|
||||
and the display denomination is similar to an ether.
|
||||
|
@ -105,7 +125,7 @@ the contract MUST be called with an amount of `300,000,000,000,000,000` (0.3&tim
|
|||
|
||||
User Interfaces which are generated programmatically from the ABI of the token contract
|
||||
MAY use and display the internal denomination.
|
||||
But this MUST be made clear, for example by displaying the `uint256` type.
|
||||
But this MUST be made clear, for example by displaying the `uint256` type.
|
||||
|
||||
#### **View Functions**
|
||||
|
||||
|
@ -139,10 +159,11 @@ function totalSupply() external view returns (uint256)
|
|||
|
||||
Get the total number of minted tokens.
|
||||
|
||||
*NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as returned by the `balanceOf` function.
|
||||
|
||||
*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.
|
||||
*NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as
|
||||
returned by the `balanceOf` function.
|
||||
|
||||
*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.
|
||||
|
||||
> <small>**returns:** Total supply of tokens currently in circulation.</small>
|
||||
|
||||
|
@ -169,55 +190,94 @@ function granularity() external view returns (uint256)
|
|||
|
||||
Get the smallest part of the token that's not divisible.
|
||||
|
||||
In other words, the granularity is the smallest number of tokens (in the basic unit) which MAY be minted, sent or burned at any time.
|
||||
In other words, the granularity is the smallest number of tokens (in the basic unit)
|
||||
which MAY be minted, sent or burned at any time.
|
||||
|
||||
The following rules MUST be applied regarding the *granularity*:
|
||||
|
||||
- The *granularity* value MUST be set at creation time.
|
||||
- The *granularity* value MUST NOT be changed ever.
|
||||
- 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 `revert`.
|
||||
|
||||
*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 fraction of the token.
|
||||
- The *granularity* value MUST NOT be changed ever.
|
||||
|
||||
- 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 `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.
|
||||
|
||||
> <small>**returns:** The smallest non-divisible part of the token.</small>
|
||||
|
||||
*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions, defined under the [operators] for consistency.
|
||||
*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions,
|
||||
defined under the [operators] for consistency.
|
||||
|
||||
*[ERC20] compatibility requirement*:
|
||||
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.)
|
||||
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.)
|
||||
|
||||
#### **Operators**
|
||||
|
||||
An `operator` is an address which is allowed to send and burn tokens on behalf of some *token holder*.
|
||||
|
||||
When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be emitted. The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively.
|
||||
When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be emitted.
|
||||
The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2)
|
||||
MUST be the addresses of the *operator* and the *token holder* respectively.
|
||||
|
||||
When a *token holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted. The `RevokedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively.
|
||||
When a *token holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted.
|
||||
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* MAY have multiple *operators* at the same time.
|
||||
|
||||
The token MAY define *default operators*. A *default operator* is an implicitly authorized *operator* for all *token holders*. `AuthorizedOperator` events MUST NOT be emitted when defining the *default operators*. The rules below apply to *default operators*:
|
||||
The token MAY define *default operators*.
|
||||
A *default operator* is an implicitly authorized *operator* for all *token holders*.
|
||||
`AuthorizedOperator` events MUST NOT be emitted 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 emitted when defining *default operators*.
|
||||
- A *token holder* MUST be allowed revoke a *default operator* (unless the *token holder* is the *default operator* in question).
|
||||
|
||||
- A *token holder* MUST be allowed revoke a *default operator*
|
||||
(unless the *token holder* is the *default operator* in question).
|
||||
|
||||
- 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 emitted.
|
||||
|
||||
- When a *default operator* is explicitly authorized or revoked for a specific *token holder*,
|
||||
an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be emitted.
|
||||
|
||||
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 token contract MUST emit an `AuthorizedOperator` event with the correct values when a *token holder* authorizes an address as its *operator* as defined in the [`AuthorizedOperator` Event][authorizedoperator].
|
||||
- The token contract MUST emit a `RevokedOperator` event with the correct values when a *token holder* revokes an address as its *operator* as defined in the [`RevokedOperator` Event][revokedoperator].
|
||||
|
||||
*NOTE*: A *token holder* MAY authorize an already authorized *operator*. An `AuthorizedOperator` MUST be emitted each time.
|
||||
- The token contract MUST emit an `AuthorizedOperator` event with the correct values
|
||||
when a *token holder* authorizes an address as its *operator* as defined in the
|
||||
[`AuthorizedOperator` Event][authorizedoperator].
|
||||
|
||||
*NOTE*: A *token holder* MAY revoke an already revoked *operator*. A `RevokedOperator` MUST be emitted each time.
|
||||
- The token contract MUST emit a `RevokedOperator` event with the correct values
|
||||
when a *token holder* revokes an address as its *operator* as defined in the
|
||||
[`RevokedOperator` Event][revokedoperator].
|
||||
|
||||
*NOTE*: A *token holder* MAY authorize an already authorized *operator*.
|
||||
An `AuthorizedOperator` MUST be emitted each time.
|
||||
|
||||
*NOTE*: A *token holder* MAY revoke an already revoked *operator*.
|
||||
A `RevokedOperator` MUST be emitted each time.
|
||||
|
||||
**`AuthorizedOperator` event** <a id="authorizedoperator"></a>
|
||||
|
||||
|
@ -233,7 +293,6 @@ Indicates the authorization of `operator` as an *operator* for `tokenHolder`.
|
|||
> <small>`operator`: Address which became an *operator* of `tokenHolder`.</small>
|
||||
> <small>`tokenHolder`: Address of a token holder which authorized the `operator` address as an *operator*.</small>
|
||||
|
||||
|
||||
**`RevokedOperator` event** <a id="revokedoperator"></a>
|
||||
|
||||
``` solidity
|
||||
|
@ -248,7 +307,8 @@ Indicates the revocation of `operator` as an *operator* for `tokenHolder`.
|
|||
> <small>`operator`: Address which was revoked as an *operator* of `tokenHolder`.</small>
|
||||
> <small>`tokenHolder`: Address of a token holder which revoked the `operator` address as an *operator*.</small>
|
||||
|
||||
The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below MUST be implemented to manage *operators*.
|
||||
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>
|
||||
|
@ -271,7 +331,10 @@ function authorizeOperator(address operator) external
|
|||
|
||||
Set a third party `operator` address as an *operator* of `msg.sender` to send and burn tokens on its behalf.
|
||||
|
||||
*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST `revert` if it is called to authorize the token holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`).
|
||||
*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself.
|
||||
This right SHALL NOT be revoked.
|
||||
Hence this function MUST `revert` if it is called to authorize the token holder (`msg.sender`)
|
||||
as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`).
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <small>`operator`: Address to set as an *operator* for `msg.sender`.</small>
|
||||
|
@ -284,7 +347,10 @@ function revokeOperator(address operator) external
|
|||
|
||||
Remove the right of the `operator` address to be an *operator* for `msg.sender` and to send and burn tokens on its behalf.
|
||||
|
||||
*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST `revert` 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`).
|
||||
*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself.
|
||||
This right SHALL NOT be revoked.
|
||||
Hence this function MUST `revert` 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`).
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <small>`operator`: Address to rescind as an *operator* for `msg.sender`.</small>
|
||||
|
@ -303,28 +369,48 @@ Indicate whether the `operator` address is an *operator* of the `tokenHolder` ad
|
|||
>
|
||||
> <small>**returns:** `true` if `operator` is an *operator* of `tokenHolder` and `false` otherwise.
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
#### **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:
|
||||
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:
|
||||
|
||||
- Any authorized *operator* MAY send tokens to any *recipient* (except to `0x0`).
|
||||
|
||||
- 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`—such that its resulting balance is greater or equal to zero (`0`) after the send.
|
||||
|
||||
- The balance of the *token holder* MUST be greater or equal to the `amount`—such
|
||||
that its resulting balance is greater or equal to zero (`0`) after the send.
|
||||
|
||||
- The token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent].
|
||||
|
||||
- The *operator* MAY include information in the `operatorData`.
|
||||
- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820].
|
||||
- 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.
|
||||
|
||||
- The token contract MUST call the `tokensToSend` hook of the *token holder*
|
||||
if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820].
|
||||
|
||||
- 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.
|
||||
|
||||
The token contract MUST `revert` when sending in any of the following cases:
|
||||
|
||||
- The *operator* address is not an authorized operator for the *token holder*.
|
||||
- The resulting *token holder* balance or *recipient* balance after the send is not a multiple of the *granularity* defined by the token contract.
|
||||
|
||||
- The resulting *token holder* balance or *recipient* balance after the send
|
||||
is not a multiple of the *granularity* defined by the token contract.
|
||||
|
||||
- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820].
|
||||
|
||||
- The address of the *token holder* or the *recipient* is `0x0`.
|
||||
|
||||
- Any of the resulting balances becomes negative, i.e. becomes less than zero (`0`).
|
||||
|
||||
The token contract MAY send tokens from many *token holders*, to many *recipients*, or both. In this case:
|
||||
|
@ -335,25 +421,35 @@ The token contract MAY send tokens from many *token holders*, to many *recipient
|
|||
- A `Sent` event MUST be emitted 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*.
|
||||
*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*.
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
*NOTE*: Sending an amount of zero (`0`) tokens is valid and MUST be treated as a regular send.
|
||||
|
||||
*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*. 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.
|
||||
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.
|
||||
|
||||
*NOTE*: The `data` field contains information provided by the token holder—similar
|
||||
to the data field in a regular ether send transaction.
|
||||
The `tokensToSend()` hook, the `tokensReceived()`, or both
|
||||
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*.
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
**`Sent` event** <a id="sent"></a>
|
||||
|
||||
|
@ -399,11 +495,18 @@ function operatorSend(address from, address to, uint256 amount, bytes calldata d
|
|||
|
||||
Send the `amount` of tokens on behalf of the address `from` to the address `to`.
|
||||
|
||||
The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the `from` (*token holder*) used for the send MUST be `msg.sender` (the `operator`).
|
||||
The *operator* MUST be `msg.sender`.
|
||||
The value of `from` MAY be `0x0`,
|
||||
then the `from` (*token holder*) used for the send MUST be `msg.sender` (the `operator`).
|
||||
|
||||
*Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the send process MUST `revert`.
|
||||
*Reminder*: If the *operator* address is not an authorized operator of the `from` address,
|
||||
then the send process MUST `revert`.
|
||||
|
||||
*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).
|
||||
*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 (or `0x0` to set `from` to `msg.sender`).</small>
|
||||
|
@ -414,17 +517,29 @@ The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the
|
|||
|
||||
#### **Minting Tokens**
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 emit 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* 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- The `data` field MUST be empty.
|
||||
|
||||
The token contract MUST `revert` when minting in any of the following cases:
|
||||
|
@ -433,10 +548,15 @@ The token contract MUST `revert` when minting in any of the following cases:
|
|||
- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820].
|
||||
- The address of the *recipient* is `0x0`.
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
*[ERC20] compatibility requirement*:
|
||||
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.
|
||||
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.
|
||||
|
||||
The token contract MAY mint tokens for multiple *recipients* at once. In this case:
|
||||
|
||||
|
@ -448,7 +568,7 @@ The token contract MAY mint tokens for multiple *recipients* at once. In this ca
|
|||
*NOTE*: Minting an amount of zero (`0`) tokens is valid and MUST be treated as a regular mint.
|
||||
|
||||
*NOTE*: The `operatorData` field contains information provided by the *operator*—similar
|
||||
to the data field in a regular ether send transaction.
|
||||
to the data field in a regular ether send transaction.
|
||||
The `tokensReceived()` hooks MAY use the information to decide if it wish to reject the transaction.
|
||||
|
||||
**`Minted` event** <a id="minted"></a>
|
||||
|
@ -470,27 +590,46 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator`
|
|||
|
||||
#### **Burning Tokens**
|
||||
|
||||
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. 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.
|
||||
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.
|
||||
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.
|
||||
|
||||
The rules below MUST be respected when burning the tokens of a *token holder*:
|
||||
|
||||
- Tokens MAY be burned from any *token holder* address.
|
||||
|
||||
- The total supply MUST be decreased by the amount of tokens burned.
|
||||
|
||||
- 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 emit 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* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820].
|
||||
- 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.
|
||||
|
||||
- The token contract MUST call the `tokensToSend` hook of the *token holder*
|
||||
if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820].
|
||||
|
||||
- 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.
|
||||
|
||||
The token contract MUST `revert` when burning in any of the following cases:
|
||||
|
||||
- The *operator* address is not an authorized operator for the *token holder*.
|
||||
- The resulting *token holder* balance after the burn is not a multiple of the *granularity* defined by the token contract.
|
||||
- The balance of *token holder* is inferior to the amount of tokens to burn (i.e., resulting in a negative balance for the *token holder*).
|
||||
|
||||
- The resulting *token holder* balance after the burn is not a multiple of the *granularity*
|
||||
defined by the token contract.
|
||||
|
||||
- The balance of *token holder* is inferior to the amount of tokens to burn
|
||||
(i.e., resulting in a negative balance for the *token holder*).
|
||||
|
||||
- The address of the *token holder* is `0x0`.
|
||||
|
||||
*[ERC20] compatibility requirement*:
|
||||
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.
|
||||
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.
|
||||
|
||||
The token contract MAY burn tokens for multiple *token holders* at once. In this case:
|
||||
|
||||
|
@ -550,9 +689,12 @@ function operatorBurn(address from, uint256 amount, bytes calldata data, bytes c
|
|||
|
||||
Burn the `amount` of tokens on behalf of the address `from`.
|
||||
|
||||
The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the `from` (*token holder*) used for the burn MUST be `msg.sender` (the `operator`).
|
||||
The *operator* MUST be `msg.sender`.
|
||||
The value of `from` MAY be `0x0`,
|
||||
then the `from` (*token holder*) used for the burn MUST be `msg.sender` (the `operator`).
|
||||
|
||||
*Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the burn process MUST `revert`.
|
||||
*Reminder*: If the *operator* address is not an authorized operator of the `from` address,
|
||||
then the burn process MUST `revert`.
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <small>`from`: Token holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`).</small>
|
||||
|
@ -560,13 +702,20 @@ The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the
|
|||
> <small>`data`: Information provided by the *token holder*.</small>
|
||||
> <small>`operatorData`: Information provided by the *operator*.</small>
|
||||
|
||||
*NOTE*: The *operator* MAY pass any information via `operatorData`. The `operatorData` MUST only be provided by the *operator*.
|
||||
*NOTE*: The *operator* MAY pass any information via `operatorData`.
|
||||
The `operatorData` MUST only be provided by the *operator*.
|
||||
|
||||
*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).
|
||||
*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).
|
||||
|
||||
#### **`ERC777TokensSender` And The `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 token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820].
|
||||
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 token debits from their address
|
||||
MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820].
|
||||
|
||||
``` solidity
|
||||
interface ERC777TokensSender {
|
||||
|
@ -581,7 +730,10 @@ interface ERC777TokensSender {
|
|||
}
|
||||
```
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
**`tokensToSend`**
|
||||
|
||||
|
@ -589,7 +741,8 @@ interface ERC777TokensSender {
|
|||
function tokensToSend(address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData) external
|
||||
```
|
||||
|
||||
Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` 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.
|
||||
|
||||
*NOTE*: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process.
|
||||
|
||||
|
@ -604,26 +757,44 @@ Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` addr
|
|||
The following rules apply when calling the `tokensToSend` hook:
|
||||
|
||||
- The `tokensToSend` hook MUST be called every time the balance is decremented.
|
||||
|
||||
- The `tokensToSend` hook MUST be called *before* the state is updated—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.
|
||||
|
||||
- `to` MUST be the address of the *recipient* whose balance is increased for a send.
|
||||
|
||||
- `to` MUST be `0x0` for a burn.
|
||||
|
||||
- `amount` MUST be the number of tokens the *token holder* balance is decreased by.
|
||||
|
||||
- `data` MUST contain the extra information provided by the *token holder* (if any) for a send.
|
||||
- `operatorData` MUST contain the extra information provided by the address which triggered the decrease of the balance (if any).
|
||||
- The *token holder* MAY block a decrease of its balance by `revert`ing. (I.e., reject the withdrawal of tokens from its account.)
|
||||
|
||||
- `operatorData` MUST contain the extra information provided by the address
|
||||
which triggered the decrease of the balance (if any).
|
||||
|
||||
- The *token holder* MAY block a decrease of its balance by `revert`ing.
|
||||
(I.e., reject the withdrawal of tokens from its account.)
|
||||
|
||||
*NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensSender`.
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
*[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.
|
||||
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 The `tokensReceived` Hook**
|
||||
|
||||
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].
|
||||
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].
|
||||
|
||||
``` solidity
|
||||
interface ERC777TokensRecipient {
|
||||
|
@ -638,12 +809,16 @@ interface ERC777TokensRecipient {
|
|||
}
|
||||
```
|
||||
|
||||
If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation; the token contract:
|
||||
If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation;
|
||||
then the token contract:
|
||||
|
||||
- MUST `revert` 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.
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
**`tokensReceived`**
|
||||
|
||||
|
@ -651,7 +826,8 @@ If the *recipient* is a contract, which has not registered an `ERC777TokensRecip
|
|||
function tokensReceived(address operator, address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external
|
||||
```
|
||||
|
||||
Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` 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.
|
||||
|
||||
*NOTE*: This function MUST NOT be called outside of a mint, send or [ERC20] transfer process.
|
||||
|
||||
|
@ -666,61 +842,92 @@ Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` ad
|
|||
The following rules apply when calling the `tokensReceived` hook:
|
||||
|
||||
- The `tokensReceived` hook MUST be called every time the balance is incremented.
|
||||
|
||||
- The `tokensReceived` hook MUST be called *after* the state is updated—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.
|
||||
|
||||
- `from` MUST be `0x0` for a mint.
|
||||
|
||||
- `to` MUST be the address of the *recipient* whose balance is increased.
|
||||
|
||||
- `amount` MUST be the number of tokens the *recipient* balance is increased by.
|
||||
|
||||
- `operatorData` MUST contain the extra information provided by the address which triggered the increase of the balance (if any).
|
||||
- `operatorData` MUST contain the extra information provided by the address
|
||||
which triggered the increase of the balance (if any).
|
||||
- The *token holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.)
|
||||
|
||||
*NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensRecipient`.
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
*[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.
|
||||
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.
|
||||
|
||||
#### **Note On Gas Consumption**
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
### Logo
|
||||
|
||||
| **Image** | ![beige logo] | ![white logo] | ![light grey logo] | ![dark grey logo] | ![black logo][black logo] |
|
||||
|----------:|:---------:|:---------:|:------------:|:-----------:|:---------:|
|
||||
| **Color** | beige | white | light grey | dark grey | black |
|
||||
| **Hex** | `#C99D66` | `#FFFFFF` | `#EBEFF0` | `#3C3C3D` | `#000000` |
|
||||
| **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` |
|
||||
|
||||
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 MAY be used, modified and adapted to promote valid [ERC777] token implementations
|
||||
and [ERC777] compliant technologies such as wallets and dapps.
|
||||
|
||||
[ERC777] token contract authors MAY 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—such as tokens—which is not [ERC777] compliant.
|
||||
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`][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`.
|
||||
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`.
|
||||
|
||||
## Rationale
|
||||
|
||||
This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. It avoids the problems and vulnerabilities of [EIP223].
|
||||
This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20].
|
||||
It avoids the problems and vulnerabilities of [EIP223].
|
||||
|
||||
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. Finally, it adds hooks to provide further control to *token holders* over their tokens. 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.
|
||||
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.
|
||||
Finally, it adds hooks to provide further control to *token holders* over their tokens.
|
||||
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.
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
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 confusion and mistakes when deciphering which token standard is being used.
|
||||
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 fully 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 MAY implement `decimals()` for backward compatibility with [ERC20]. If implemented, it MUST always return `18`.
|
||||
The token MAY implement `decimals()` for backward compatibility with [ERC20].
|
||||
If implemented, it MUST always return `18`.
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
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.
|
||||
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 [ERC1820].
|
||||
|
@ -734,10 +941,16 @@ Unregistering implies calling the `setInterfaceImplementer` with the token contr
|
|||
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.)
|
||||
|
||||
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.
|
||||
|
||||
The table below summarizes the different actions the token contract MUST take when sending, minting and transferring token via [ERC777] and [ERC20]:
|
||||
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.
|
||||
|
||||
The table below summarizes the different actions the token contract MUST take
|
||||
when sending, minting and transferring token via [ERC777] and [ERC20]:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -772,11 +985,23 @@ 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 only be canceled if another condition is not respected such as lack of funds or a `revert` in `tokensReceived` (if present).
|
||||
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).
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Test Cases
|
||||
|
||||
|
@ -784,7 +1009,8 @@ The [repository with the reference implementation][0xjac/ERC777] contains all th
|
|||
|
||||
## Implementation
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
## Copyright
|
||||
|
||||
|
|
Loading…
Reference in New Issue