mirror of
https://github.com/status-im/EIPs.git
synced 2025-03-03 08:00:51 +00:00
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
fc6d56f495
commit
b41669ede2
303
EIPS/eip-777.md
303
EIPS/eip-777.md
@ -1,7 +1,7 @@
|
||||
---
|
||||
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>
|
||||
author: Jacques Dafflon <jacques.dafflon@gmail.com>, Jordi Baylina <jordi@baylina.cat>, Thomas Shababi <tom@truelevel.io>
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/777
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
@ -14,8 +14,6 @@ requires: 820
|
||||
|
||||
This EIP defines standard interfaces and behaviors for token contracts.
|
||||
|
||||
*The repository containing the reference implementation for this standard can be found at [github.com/jacquesd/ERC777][jacquesd/ERC777] and installed via npm with `npm install erc777`.*
|
||||
|
||||
## Abstract
|
||||
|
||||
This standard defines a new way to interact with a token contract while remaining backward compatible with [ERC20].
|
||||
@ -29,11 +27,11 @@ It takes advantage of [ERC820] to find out whether and where to notify contracts
|
||||
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 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.
|
||||
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 a `data` bytes field and a similar `operatorData` to be used freely by the token holder and the operator respectively to pass data to the recipient.
|
||||
6. Every token transaction contains a `data` bytes field and a similar `operatorData` to be used freely 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
|
||||
@ -67,8 +65,8 @@ interface ERC777Token {
|
||||
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 data, bytes operatorData);
|
||||
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
|
||||
event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData);
|
||||
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
|
||||
event RevokedOperator(address indexed operator, address indexed tokenHolder);
|
||||
}
|
||||
@ -91,7 +89,7 @@ The `view` functions detailed below MUST be implemented.
|
||||
|
||||
Returns the name of the token, e.g., `"MyToken"`.
|
||||
|
||||
> <small>**returns:** Name of the token</small>
|
||||
> <small>**returns:** Name of the token.</small>
|
||||
|
||||
**`symbol` function**
|
||||
|
||||
@ -101,7 +99,7 @@ function symbol() public view returns (string)
|
||||
|
||||
Returns the symbol of the token, e.g., `"MYT"`.
|
||||
|
||||
> <small>**returns:** Symbol of the token</small>
|
||||
> <small>**returns:** Symbol of the token.</small>
|
||||
|
||||
**`totalSupply` function**
|
||||
|
||||
@ -113,6 +111,8 @@ Get the total number of minted tokens.
|
||||
|
||||
The total supply MUST be equal to the sum of the balances of all addresses—as returned by the `balanceOf` function.
|
||||
|
||||
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>
|
||||
|
||||
**`balanceOf` function**
|
||||
@ -126,7 +126,7 @@ Get the balance of the account with address `tokenHolder`.
|
||||
The balance MUST be zero (`0`) or higher.
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <small>`tokenHolder`: Address for which the balance is returned</small>
|
||||
> <small>`tokenHolder`: Address for which the balance is returned.</small>
|
||||
>
|
||||
> <small>**returns:** Amount of token held by `tokenHolder` in the token contract.</small>
|
||||
|
||||
@ -144,7 +144,7 @@ The following rules MUST be applied regarding the *granularity*:
|
||||
- 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 throw.
|
||||
- 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 partition of the token.
|
||||
|
||||
@ -182,9 +182,43 @@ 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 *operator* MUST pass the `data` from a *token holder* as is when sending and burning tokens. If the *token holder* does not provide any `data`, the operator MUST pass either an empty `data` field or MUST NOT pass any data (depending on whether the function requires the *token holder*'s `data` or not).
|
||||
- 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*: It is not expected for the token contract to validate the origin of the `data` field when the *operator* and *token holder* are different. However, the *operator* MUST not pass any information in the `data` field which does not originate from the *token holder*.
|
||||
*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.
|
||||
|
||||
*NOTE*: A token holder MAY have multiple *operators* at the same time.
|
||||
|
||||
**`AuthorizedOperator` event** <a id="authorizedoperator"></a>
|
||||
|
||||
``` solidity
|
||||
event AuthorizedOperator(address indexed operator, address indexed tokenHolder)
|
||||
```
|
||||
|
||||
Indicates the authorization of `operator` as an *operator* for `tokenHolder`.
|
||||
|
||||
*NOTE*: This event MUST NOT be emitted outside of an *operator* authorization process.
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <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
|
||||
event RevokedOperator(address indexed operator, address indexed tokenHolder)
|
||||
```
|
||||
|
||||
Indicates the revocation of `operator` as an *operator* for `tokenHolder`.
|
||||
|
||||
*NOTE*: This event MUST NOT be emitted outside of an *operator* revocation process.
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <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*.
|
||||
Token contracts MAY implement other functions to manage *operators*.
|
||||
@ -199,7 +233,7 @@ Get the list of *default operators* as defined by the token contract.
|
||||
|
||||
*NOTE*: If the token contract does not have any *default operators*, this function MUST return an empty list.
|
||||
|
||||
> <small>**returns:** List of addresses of all the *default operators*
|
||||
> <small>**returns:** List of addresses of all the *default operators*.
|
||||
|
||||
**`authorizeOperator` function**
|
||||
|
||||
@ -207,36 +241,26 @@ Get the list of *default operators* as defined by the token contract.
|
||||
function authorizeOperator(address operator) public
|
||||
```
|
||||
|
||||
Set a third party `operator` address as an *operator* of `msg.sender` to send, burn, and mint tokens on its behalf.
|
||||
Set a third party `operator` address as an *operator* of `msg.sender` to send and burn tokens on its behalf.
|
||||
|
||||
An `AuthorizedOperator` event MUST be emitted on a successful call to this function.
|
||||
|
||||
*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 authorize the token holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`).
|
||||
|
||||
*NOTE*: A token holder MAY authorize multiple *operators* at the same time.
|
||||
*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>
|
||||
|
||||
|
||||
**`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.
|
||||
Remove the right of the `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`.
|
||||
*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`).
|
||||
|
||||
A `RevokedOperator` event MUST be emitted on a successful call to this function.
|
||||
|
||||
*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`).
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <small>**parameters**</small>
|
||||
> <small>`operator`: Address to rescind as an *operator* for `msg.sender`.</small>
|
||||
|
||||
|
||||
**`isOperatorFor` function** <a id="isOperatorFor"></a>
|
||||
|
||||
``` solidity
|
||||
@ -247,7 +271,7 @@ Indicate whether the `operator` address is an *operator* of the `tokenHolder` ad
|
||||
|
||||
> <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>`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.
|
||||
|
||||
@ -262,29 +286,21 @@ When an *operator* sends an `amount` of tokens from a *token holder* to a *recip
|
||||
- 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 token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent].
|
||||
- The *token holder* MAY communicate any information in the `data`.
|
||||
- The *operator* MAY communicate any information in the `operatorData`.
|
||||
- The token contract MUST NOT modify the `data` nor the `operatorData`.
|
||||
- *Operators* MUST NOT modify the `data` provided by *token holders*.
|
||||
- The token contract MUST call the `tokensToSend` hook of the *token holder*, provided the *token holder* registers an `ERC777TokensRecipient` implementation via [ERC820].
|
||||
- The token contract MUST call the `tokensReceived` hook of the *recipient*, provided the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820].
|
||||
- When calling `tokensToSend`, `tokensReceived` or both:
|
||||
- `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*.
|
||||
- `operatorData` MUST be the data provided by the *operator*.
|
||||
- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensRecipient` implementation via [ERC820].
|
||||
- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820].
|
||||
- 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 throw when sending in any of the following cases:
|
||||
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 has a granularity smaller than the *granularity* defined by the token contract.
|
||||
- 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 address of the *token holder* or the *recipient* is `0x0`.
|
||||
- Any of the resulting balance becomes negative, i.e. becomes less than zero (`0`).
|
||||
- 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:
|
||||
The token contract MAY send tokens from many *token holders*, to many *recipients*, or both. In this case:
|
||||
|
||||
- The previous send rules MUST apply to all the *token holders* and all the *recipients*
|
||||
- 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 emitted for every *token holder* and *recipient* pair with the corresponding amount for each pair.
|
||||
@ -294,14 +310,14 @@ The token contract MAY send tokens from many *token holders* to many *recipients
|
||||
|
||||
*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.
|
||||
|
||||
|
||||
*NOTE*: The `data` and `operatorData` fields are free byte ranges provided by the *token holder* and the *operator* respectively. The `data` field is intended for the recipient. Typically, the recipient SHOULD indicate which data it expects to receive. (Similarly to the data field when sending ether.) The `operatorData` field 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`.
|
||||
|
||||
*NOTE*: The `data` field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically, `data` is used to describe the intent behind the send. 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>
|
||||
|
||||
@ -314,12 +330,12 @@ Indicate a send of `amount` of tokens from the `from` address to the `to` addres
|
||||
*NOTE*: This event MUST NOT be emitted outside of a send or an [ERC20] transfer process.
|
||||
|
||||
> <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 (`from`)</small>
|
||||
> <small>`operatorData`: information attached to the send by the `operator`</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, and intended for the recipient (`to`).</small>
|
||||
> <small>`operatorData`: Information attached to the send by the `operator`.</small>
|
||||
|
||||
The `send` and `operatorSend` functions described below MUST be implemented to send tokens.
|
||||
Token contracts MAY implement other functions to send tokens.
|
||||
@ -337,9 +353,9 @@ Send the `amount` of tokens from the address `msg.sender` to the address `to`.
|
||||
The *operator* and the *token holder* MUST both be the `msg.sender`.
|
||||
|
||||
> <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>
|
||||
> <small>`to`: Token recipient.</small>
|
||||
> <small>`amount`: Number of tokens to send.</small>
|
||||
> <small>`data`: Information attached to the send, and intended for the recipient (`to`).</small>
|
||||
|
||||
**`operatorSend` function**
|
||||
|
||||
@ -349,20 +365,18 @@ function operatorSend(address from, address to, uint256 amount, bytes data, byte
|
||||
|
||||
Send the `amount` of tokens on behalf of the address `from` to the address `to`.
|
||||
|
||||
The *operator* MUST be `msg.sender`.
|
||||
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 the send MUST throw.
|
||||
|
||||
*NOTE*: The *operator* MAY pass any information via `operatorData`. The *operator* MUST only pass data given to it by the *token holder* to the `data` parameter. The token holder MAY provide this data to the *operator* beforehand through another medium.
|
||||
*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).
|
||||
|
||||
> <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>
|
||||
> <small>`from`: Token holder (or `0x0` to set `from` to `msg.sender`).</small>
|
||||
> <small>`to`: Token recipient.</small>
|
||||
> <small>`amount`: Number of tokens to send.</small>
|
||||
> <small>`data`: Information attached to the send, and intended for the recipient (`to`).</small>
|
||||
> <small>`operatorData`: Information attached to the send by the `operator`.</small>
|
||||
|
||||
#### **Minting Tokens**
|
||||
|
||||
@ -375,17 +389,12 @@ Nonetheless, the rules below MUST be respected when minting for a *recipient*:
|
||||
- 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*, provided the *recipient* registers an `ERC777TokensRecipient` implementation 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, provided by the address which initiated the minting action (i.e., the *operator*).
|
||||
- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820].
|
||||
- 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 throw when minting in any of the following cases:
|
||||
The token contract MUST `revert` 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 resulting *recipient* balance after the mint 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 [ERC820].
|
||||
- The address of the *recipient* is `0x0`.
|
||||
|
||||
@ -399,10 +408,14 @@ The token contract MAY mint tokens for multiple *recipients* at once. In this ca
|
||||
- A `Minted` event MUST be emitted for every *recipient* with the corresponding amount for each *recipient*.
|
||||
- The sum of all the amounts from the `Minted` event MUST be equal to the total minted `amount`.
|
||||
|
||||
*NOTE*: Minting an amount of zero (`0`) tokens is valid and MUST be treated as a regular mint.
|
||||
|
||||
*NOTE*: The `data` field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically, `data` is used to describe the intent behind the mint. 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`.
|
||||
|
||||
**`Minted` event** <a id="minted"></a>
|
||||
|
||||
``` solidity
|
||||
event Minted(address indexed operator, address indexed to, uint256 amount, bytes operatorData)
|
||||
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData)
|
||||
```
|
||||
|
||||
Indicate the minting of `amount` of tokens to the `to` address by the `operator` address.
|
||||
@ -410,10 +423,11 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator`
|
||||
*NOTE*: This event MUST NOT be emitted outside of a mint process.
|
||||
|
||||
> <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>
|
||||
> <small>`operator`: Address which triggered the mint.</small>
|
||||
> <small>`to`: Token recipient.</small>
|
||||
> <small>`amount`: Number of tokens minted.</small>
|
||||
> <small>`data`: Information attached to the minting, and intended for the recipient (`to`).</small>
|
||||
> <small>`operatorData`: Information attached to the minting by the `operator`.</small>
|
||||
|
||||
#### **Burning Tokens**
|
||||
|
||||
@ -426,24 +440,19 @@ The rules below MUST be respected when burning the tokens of a *token holder*:
|
||||
- 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*, provided the *token holder* registers an `ERC777TokensSender` implementation via [ERC820].
|
||||
- When calling `tokensToSend`:
|
||||
- `operator` MUST be the address which initiated the burning action. (Generally the `msg.sender` of the burning function call.)
|
||||
- `from` MUST be the address of the *token holder*.
|
||||
- `to` MUST be `0x0`.
|
||||
- `data` MUST be the data provided by the *token holder*.
|
||||
- `operatorData` MUST contain data, provided by the address which initiated the burning action (i.e., the *operator*).
|
||||
- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC820].
|
||||
- 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 `data` field of the `tokensToSend` hook MUST be empty.
|
||||
|
||||
The token contract MUST throw when burning in any of the following cases:
|
||||
The token contract MUST `revert` when burning in any of the following cases:
|
||||
|
||||
- The address initiating the burn of tokens from a *token holder* MUST be an *operator* of the *token holder*.
|
||||
|
||||
- The resulting *token holder* balance after the burn has a granularity smaller than the *granularity* defined by the token contract.
|
||||
- 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 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` MUST be emitted as defined in the [ERC20] standard.
|
||||
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:
|
||||
|
||||
@ -452,10 +461,12 @@ The token contract MAY burn tokens for multiple *token holders* at once. In this
|
||||
- A `Burned` event MUST be emitted 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 burned `amount`.
|
||||
|
||||
*NOTE*: Burning an amount of zero (`0`) tokens is valid and MUST be treated as a regular burn.
|
||||
|
||||
**`Burned` event** <a id="burned"></a>
|
||||
|
||||
``` solidity
|
||||
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData)
|
||||
event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData)
|
||||
```
|
||||
|
||||
Indicate the burning of `amount` of tokens from the `from` address by the `operator` address.
|
||||
@ -463,11 +474,10 @@ Indicate the burning of `amount` of tokens from the `from` address by the `opera
|
||||
*NOTE*: This event MUST NOT be emitted outside of a burn process.
|
||||
|
||||
> <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>
|
||||
> <small>`operator`: Address which triggered the burn.</small>
|
||||
> <small>`from`: Token holder whose tokens are burned.</small>
|
||||
> <small>`amount`: Number of tokens burned.</small>
|
||||
> <small>`operatorData`: Information attached to the burn by the `operator`.</small>
|
||||
|
||||
The `burn` and `operatorBurn` functions described below MUST be implemented to burn tokens.
|
||||
Token contracts MAY implement other functions to burn tokens.
|
||||
@ -475,7 +485,7 @@ Token contracts MAY implement other functions to burn tokens.
|
||||
**`burn` function**
|
||||
|
||||
``` solidity
|
||||
function burn(uint256 amount, bytes data) public;
|
||||
function burn(uint256 amount) public;
|
||||
```
|
||||
|
||||
Burn the `amount` of tokens from the address `msg.sender`.
|
||||
@ -483,22 +493,26 @@ Burn the `amount` of tokens from the address `msg.sender`.
|
||||
The *operator* and the *token holder* MUST both be the `msg.sender`.
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <small>`amount`: number of tokens to burn</small>
|
||||
> <small>`data`: information attached to the burn by the token holder</small>
|
||||
> <small>`amount`: Number of tokens to burn.</small>
|
||||
|
||||
**`operatorBurn` function**
|
||||
|
||||
``` solidity
|
||||
function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public;
|
||||
function operatorBurn(address from, uint256 amount, bytes operatorData) public;
|
||||
```
|
||||
|
||||
Burn the `amount` of tokens on behalf of the address `from`.
|
||||
|
||||
The *operator* MUST be `msg.sender`.
|
||||
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 the burn MUST throw.
|
||||
*Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the burn process MUST `revert`.
|
||||
|
||||
*NOTE*: The *operator* MAY pass any information 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.
|
||||
> <small>**parameters**</small>
|
||||
> <small>`from`: Token holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`).</small>
|
||||
> <small>`amount`: Number of tokens to burn.</small>
|
||||
> <small>`operatorData`: Information attached to the burn by the *operator*.</small>
|
||||
|
||||
*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).
|
||||
|
||||
@ -512,7 +526,7 @@ interface ERC777TokensSender {
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint value,
|
||||
uint256 amount,
|
||||
bytes data,
|
||||
bytes operatorData
|
||||
) public;
|
||||
@ -524,7 +538,7 @@ interface ERC777TokensSender {
|
||||
**`tokensToSend`**
|
||||
|
||||
``` solidity
|
||||
function tokensToSend(address operator, address from, address to, uint value, bytes data, bytes operatorData) public
|
||||
function tokensToSend(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) public
|
||||
```
|
||||
|
||||
Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address.
|
||||
@ -532,14 +546,14 @@ Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` addr
|
||||
*NOTE*: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process.
|
||||
|
||||
> <small>**parameters**</small>
|
||||
> <small>`operator`: address which triggered the balance decrease (through sending or burning)</small>
|
||||
> <small>`from`: *token holder*</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*</small>
|
||||
> <small>`operatorData`: extra information provided by the address which triggered the balance decrease</small>
|
||||
> <small>`operator`: Address which triggered the balance decrease (through sending or burning).</small>
|
||||
> <small>`from`: *token holder*.</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*.</small>
|
||||
> <small>`operatorData`: Extra information provided by the address which triggered the balance decrease.</small>
|
||||
|
||||
The following rules apply to the `tokensToSend` hook:
|
||||
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.
|
||||
@ -547,9 +561,11 @@ The following rules apply to the `tokensToSend` hook:
|
||||
- `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.
|
||||
- `data` MUST contain the extra information provided by the *token holder* (if any) for a send or 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.
|
||||
- `data` MUST be empty for a burn.
|
||||
- `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 throwing. (I.e., reject the withdrawal of tokens from its account.)
|
||||
- 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`.
|
||||
|
||||
@ -560,7 +576,7 @@ This hook takes precedence over [ERC20] and MUST be called (if registered) when
|
||||
|
||||
#### **`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 debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC820].
|
||||
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 [ERC820].
|
||||
|
||||
``` solidity
|
||||
interface ERC777TokensRecipient {
|
||||
@ -568,7 +584,7 @@ interface ERC777TokensRecipient {
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint amount,
|
||||
uint256 amount,
|
||||
bytes data,
|
||||
bytes operatorData
|
||||
) public;
|
||||
@ -577,7 +593,7 @@ interface 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.
|
||||
- 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.
|
||||
@ -585,7 +601,7 @@ If the *recipient* is a contract, which has not registered an `ERC777TokensRecip
|
||||
**`tokensReceived`**
|
||||
|
||||
``` solidity
|
||||
function tokensReceived(address operator, address from, address to, uint amount, bytes data, bytes operatorData) public
|
||||
function tokensReceived(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) public
|
||||
```
|
||||
|
||||
Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address.
|
||||
@ -593,25 +609,25 @@ Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` ad
|
||||
*NOTE*: This function MUST NOT be called outside of a mint, send or [ERC20] transfer process.
|
||||
|
||||
> <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,</small>
|
||||
> <small>`operatorData`: extra information provided by the address which triggered the balance increase</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,.</small>
|
||||
> <small>`operatorData`: Extra information provided by the address which triggered the balance increase.</small>
|
||||
|
||||
The following rules apply to the `tokensToSend` hook:
|
||||
The following rules apply when calling the `tokensToSend` hook:
|
||||
|
||||
- The `tokensReceived` hook MUST be called every time the balance is incremented.
|
||||
- The `tokensReceived` hook MUST be called *after* the state is update—i.e. *after* 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.
|
||||
- `data` MUST contain the extra information provided by the *token holder* (if any) for a send.
|
||||
- `data` MUST be empty for a mint.
|
||||
- `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).
|
||||
- The *token holder* MAY block an increase of its balance by throwing. (I.e., reject the reception of tokens.)
|
||||
- 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`.
|
||||
|
||||
@ -640,7 +656,7 @@ The logo for the standard can be found in the [`/assets/eip-777/logo`][logos] fo
|
||||
|
||||
## Rationale
|
||||
|
||||
This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. It avoids the problems and vulnerabilities of he [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 [ERC820] provides backward compatibility with wallets and existing contracts without having to be redeployed thanks proxy contracts implementing the hooks.
|
||||
|
||||
@ -660,8 +676,7 @@ The state-modifying functions from both standards are decoupled and can operate
|
||||
|
||||
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 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 [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 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 [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]:
|
||||
|
||||
@ -695,13 +710,13 @@ The table below summarizes the different actions the token contract MUST take wh
|
||||
</tr>
|
||||
<tr>
|
||||
<td>contract</td>
|
||||
<td align="center">MUST throw</td>
|
||||
<td align="center">MUST <code>revert</code></td>
|
||||
</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 throw 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 [ERC820], the token contract SHOULD emit a `Transfer` event for minting and MUST emit a `Transfer` event for sending and burning (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 [ERC820], 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.
|
||||
|
||||
@ -711,7 +726,8 @@ The [repository with the reference implementation][jacquesd/ERC777] contains all
|
||||
|
||||
## Implementation
|
||||
|
||||
The GitHub repository [jacquesd/ERC777] contains the [reference implementation].
|
||||
The GitHub repository [jacquesd/ERC777] contains the [reference implementation]. The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`.
|
||||
|
||||
|
||||
## Copyright
|
||||
|
||||
@ -724,11 +740,14 @@ Copyright and related rights waived via [CC0].
|
||||
[ERC777]: https://eips.ethereum.org/EIPS/eip-777
|
||||
[ERC820]: https://eips.ethereum.org/EIPS/eip-820
|
||||
[jacquesd/ERC777]: https://github.com/jacquesd/ERC777
|
||||
[npm/erc777]: https://www.npmjs.com/package/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
|
||||
|
||||
[authorizedoperator]: #authorizedoperator
|
||||
[revokedoperator]: #revokedoperator
|
||||
[isOperatorFor]: #isOperatorFor
|
||||
[defaultOperators]: #defaultOperators
|
||||
[sent]: #sent
|
||||
|
Loading…
x
Reference in New Issue
Block a user