EIP-777: Token Standard Source

作者 Jacques Dafflon, Jordi Baylina, Thomas Shababi
讨论-To https://github.com/ethereum/EIPs/issues/777
状态 Final
类型 Standards Track
分类 ERC
创建日期 2017-11-20
依赖 1820
英文版 https://eips.ethereum.org/EIPS/eip-777

简述

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 ERC-20.

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 ERC-1820 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.

动机

This standard tries to improve upon the widely used ERC-20 token standard. The main advantages of this standard are:

  1. Uses the same philosophy as Ether in that tokens are sent with send(dest, value, data).

  2. Both contracts and regular addresses can control and reject which token they send by registering a tokensToSend hook. (Rejection is done by reverting 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 reverting in the hook function.)

  4. The tokensReceived hook allows to send tokens to a contract and notify it in a single transaction, unlike ERC-20 which requires a double call (approve/transferFrom) to achieve this.

  5. The 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 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.

规范

ERC777Token (Token Contract)

interface ERC777Token {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function totalSupply() external view returns (uint256);
    function balanceOf(address holder) external view returns (uint256);
    function granularity() external view returns (uint256);

    function defaultOperators() external view returns (address[] memory);
    function isOperatorFor(
        address operator,
        address holder
    ) external view returns (bool);
    function authorizeOperator(address operator) external;
    function revokeOperator(address operator) external;

    function send(address to, uint256 amount, bytes calldata data) external;
    function operatorSend(
        address from,
        address to,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    function burn(uint256 amount, bytes calldata data) external;
    function operatorBurn(
        address from,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    event Sent(
        address indexed operator,
        address indexed from,
        address indexed to,
        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 data,
        bytes operatorData
    );
    event AuthorizedOperator(
        address indexed operator,
        address indexed holder
    );
    event RevokedOperator(address indexed operator, address indexed holder);
}

The token contract MUST implement the above interface. The implementation MUST follow the specifications described below.

The token contract MUST register the ERC777Token interface with its own address via ERC-1820.

This is done by calling the setInterfaceImplementer function on the ERC-1820 registry with the token contract address as both the address and the implementer and the keccak256 hash of ERC777Token (0xac7fbab5f54a3ca8194167523c6753bfeb96a445279294b6125b68cce2177054) as the interface hash.

If the contract has a switch to enable or disable ERC777 functions, every time the switch is triggered, the token MUST register or unregister the ERC777Token interface for its own address accordingly via ERC1820. Unregistering implies calling the setInterfaceImplementer with the token contract address as the address, the keccak256 hash of ERC777Token as the interface hash and 0x0 as the implementer. (See Set An Interface For An Address in ERC-1820 for more details.)

When interacting with the token contract, all amounts and balances MUST be unsigned integers. I.e. internally, all values are stored as a denomination of 1E-18 of a token. The display denomination—to display any amount to the end user—MUST be 1018 of the internal denomination.

In other words, the internal denomination is similar to a wei and the display denomination is similar to an ether. It is equivalent to an ERC-20’s decimals function returning 18. E.g. if a token contract returns a balance of 500,000,000,000,000,000 (0.5×1018) for a user, the user interface MUST show 0.5 tokens to the user. If the user wishes to send 0.3 tokens, the contract MUST be called with an amount of 300,000,000,000,000,000 (0.3×1018).

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.

View Functions

The view functions detailed below MUST be implemented.

name function

function name() external view returns (string memory)

Get the name of the token, e.g., "MyToken".

identifier: 06fdde03 returns: Name of the token.

symbol function

function symbol() external view returns (string memory)

Get the symbol of the token, e.g., "MYT".

identifier: 95d89b41 returns: Symbol of the token.

totalSupply function

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.

identifier: 18160ddd returns: Total supply of tokens currently in circulation.

balanceOf function

function balanceOf(address holder) external view returns (uint256)

Get the balance of the account with address holder.

The balance MUST be zero (0) or higher.

identifier: 70a08231 parameters holder: Address for which the balance is returned.

returns: Amount of tokens held by holder in the token contract.

granularity function

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 amount of tokens (in the internal denomination) 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 than or equal to 1.

  • All balances MUST be a multiple of the granularity.

  • Any amount of tokens (in the internal denomination) minted, sent or burned 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 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.

identifier: 556f0dc7 returns: The smallest non-divisible part of the token.

NOTE: defaultOperators and isOperatorFor are also view functions, defined under the operators for consistency.

ERC-20 compatibility requirement: The decimals of the token MUST always be 18. For a pure ERC777 token the ERC-20 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 ERC-20 compatible token, the decimals function is REQUIRED and MUST return 18. (In ERC-20, 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 ERC-20 compatible tokens.)

Operators

An operator is an address which is allowed to send and burn tokens on behalf of some holder.

When an address becomes an operator for a holder, an AuthorizedOperator event MUST be emitted. The AuthorizedOperator’s operator (topic 1) and holder (topic 2) MUST be the addresses of the operator and the holder respectively.

When a holder revokes an operator, a RevokedOperator event MUST be emitted. The RevokedOperator’s operator (topic 1) and holder (topic 2) MUST be the addresses of the operator and the holder respectively.

NOTE: A 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 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 holder MUST be allowed to revoke a default operator (unless the holder is the default operator in question).

  • A holder MUST be allowed to re-authorize a previously revoked default operator.

  • When a default operator is explicitly authorized or revoked for a specific 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 holder, isOperatorFor MUST return true.

  • If an address is not an operator for a holder, isOperatorFor MUST return false.

  • The token contract MUST emit an AuthorizedOperator event with the correct values when a holder authorizes an address as its operator as defined in the AuthorizedOperator Event.

  • The token contract MUST emit a RevokedOperator event with the correct values when a holder revokes an address as its operator as defined in the RevokedOperator Event.

NOTE: A holder MAY authorize an already authorized operator. An AuthorizedOperator MUST be emitted each time.

NOTE: A holder MAY revoke an already revoked operator. A RevokedOperator MUST be emitted each time.

AuthorizedOperator event

event AuthorizedOperator(address indexed operator, address indexed holder)

Indicates the authorization of operator as an operator for holder.

NOTE: This event MUST NOT be emitted outside of an operator authorization process.

parameters operator: Address which became an operator of holder. holder: Address of a holder which authorized the operator address as an operator.

RevokedOperator event

event RevokedOperator(address indexed operator, address indexed holder)

Indicates the revocation of operator as an operator for holder.

NOTE: This event MUST NOT be emitted outside of an operator revocation process.

parameters operator: Address which was revoked as an operator of holder. holder: Address of a holder which revoked the operator address as an operator.

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

function defaultOperators() external view returns (address[] memory)

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.

identifier: 06e48538 returns: List of addresses of all the default operators.</p> </blockquote>

authorizeOperator function

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 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 holder (msg.sender) as an operator for itself (i.e. if operator is equal to msg.sender).

**identifier:** `959b8c3f`
**parameters**
`operator`: Address to set as an *operator* for `msg.sender`.

revokeOperator function

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 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 holder (msg.sender) as an operator for itself (i.e., if operator is equal to msg.sender).

**identifier:** `fad8b32a`
**parameters**
`operator`: Address to rescind as an *operator* for `msg.sender`.

isOperatorFor function

</p>

function isOperatorFor(
    address operator,
    address holder
) external view returns (bool)

Indicate whether the operator address is an operator of the holder address.

**identifier:** `d95b6371`
**parameters**
`operator`: Address which may be an *operator* of `holder`.
`holder`: Address of a *holder* which may have the `operator` address as an *operator*.

returns: true if operator is an operator of holder and false otherwise.</p> </blockquote>

NOTE: To know which addresses are operators for a given holder, one MUST call isOperatorFor with the holder for each default operator and parse the AuthorizedOperator, and RevokedOperator events for the holder in question.

Sending Tokens

When an operator sends an amount of tokens from a 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 holder MUST be decreased by the amount.

  • The balance of the recipient MUST be increased by the amount.

  • The balance of the 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.

  • The operator MAY include information in the operatorData.

  • The token contract MUST call the tokensToSend hook of the holder if the holder registers an ERC777TokensSender implementation via ERC-1820.

  • The token contract MUST call the tokensReceived hook of the recipient if the recipient registers an ERC777TokensRecipient implementation via ERC-1820.

  • 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 holder.

  • The resulting 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 ERC-1820.

  • The address of the holder or the recipient is 0x0.

  • Any of the resulting balances becomes negative, i.e. becomes less than zero (0).

  • The tokensToSend hook of the holder reverts.

  • The tokensReceived hook of the recipient reverts.

The token contract MAY send tokens from many holders, to many recipients, or both. In this case:

  • The previous send rules MUST apply to all the 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 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: Movements 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 field contains information provided by the holder—similar to the data field in a regular ether send transaction. The tokensToSend() hook, the tokensReceived(), or both MAY use the information to decide if they wish to reject the transaction.

NOTE: The operatorData field is analogous to the data field except it SHALL be provided by the operator.

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

</p>

<pre><code class="solidity">event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData ) </code></pre>

<p spaces-before="0">
  Indicate a send of <code>amount</code> of tokens from the <code>from</code> address to the <code>to</code> address by the <code>operator</code> address.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: This event MUST NOT be emitted outside of a send or an <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> transfer process.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**parameters**</small><br x-id="2" /> <small>`operator`: Address which triggered the send.</small><br x-id="2" /> <small>`from`: *Holder* whose tokens were sent.</small><br x-id="2" /> <small>`to`: Recipient of the tokens.</small><br x-id="2" /> <small>`amount`: Number of tokens sent.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small><br x-id="2" /> <small>`operatorData`: Information provided by the *operator*.</small>
  </p>
</blockquote>

<p spaces-before="0">
  The <code>send</code> and <code>operatorSend</code> functions described below MUST be implemented to send tokens. Token contracts MAY implement other functions to send tokens.
</p>

<p spaces-before="0">
  <strong x-id="1"><code>send</code> function</strong>
</p>

<pre><code class="solidity">function send(address to, uint256 amount, bytes calldata data) external </code></pre>

<p spaces-before="0">
  Send the <code>amount</code> of tokens from the address <code>msg.sender</code> to the address <code>to</code>.
</p>

<p spaces-before="0">
  The <em x-id="3">operator</em> and the <em x-id="3">holder</em> MUST both be the <code>msg.sender</code>.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**identifier:** `9bd9bbc6`</small><br x-id="2" /> <small>**parameters**</small><br x-id="2" /> <small>`to`: Recipient of the tokens.</small><br x-id="2" /> <small>`amount`: Number of tokens to send.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small>
  </p>
</blockquote>

<p spaces-before="0">
  <strong x-id="1"><code>operatorSend</code> function</strong>
</p>

<pre><code class="solidity">function operatorSend(
address from,
address to,
uint256 amount,
bytes calldata data,
bytes calldata operatorData ) external </code></pre>

<p spaces-before="0">
  Send the <code>amount</code> of tokens on behalf of the address <code>from</code> to the address <code>to</code>.
</p>

<p spaces-before="0">
  <em x-id="3">Reminder</em>: If the <em x-id="3">operator</em> address is not an authorized operator of the <code>from</code> address, then the send process MUST <code>revert</code>.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: <code>from</code> and <code>msg.sender</code> MAY be the same address. I.e., an address MAY call <code>operatorSend</code> for itself. This call MUST be equivalent to <code>send</code> with the addition that the <em x-id="3">operator</em> MAY specify an explicit value for <code>operatorData</code> (which cannot be done with the <code>send</code> function).
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**identifier:** `62ad1b83`</small><br x-id="2" /> <small>**parameters**</small><br x-id="2" /> <small>`from`: *Holder* whose tokens are being sent.</small><br x-id="2" /> <small>`to`: Recipient of the tokens.</small><br x-id="2" /> <small>`amount`: Number of tokens to send.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small><br x-id="2" /> <small>`operatorData`: Information provided by the *operator*.</small>
  </p>
</blockquote>

<h4 spaces-before="0">
  <strong x-id="1">Minting Tokens</strong>
</h4>

<p spaces-before="0">
  Minting tokens is the act of producing new tokens. <a href="./eip-777.md" fo="5">ERC-777</a> intentionally does not define specific functions to mint tokens. This intent comes from the wish not to limit the use of the <a href="./eip-777.md" fo="5">ERC-777</a> standard as the minting process is generally specific for every token.
</p>

<p spaces-before="0">
  Nonetheless, the rules below MUST be respected when minting for a <em x-id="3">recipient</em>:
</p>

<ul>
  <li>
    <p spaces-before="0">
      Tokens MAY be minted for any <em x-id="3">recipient</em> address (except <code>0x0</code>).
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The total supply MUST be increased by the amount of tokens minted.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The balance of <code>0x0</code> MUST NOT be decreased.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The balance of the <em x-id="3">recipient</em> MUST be increased by the amount of tokens minted.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The token contract MUST emit a <code>Minted</code> event with the correct values as defined in the <a href="#minted" f-id="minted" fo="23"><code>Minted</code> Event</a>.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The token contract MUST call the <code>tokensReceived</code> hook of the <em x-id="3">recipient</em> if the <em x-id="3">recipient</em> registers an <code>ERC777TokensRecipient</code> implementation via <a href="./eip-1820.md" fo="8">ERC-1820</a>.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The <code>data</code> and <code>operatorData</code> MUST be immutable during the entire mint process&mdash;hence the same <code>data</code> and <code>operatorData</code> MUST be used to call the <code>tokensReceived</code> hook and emit the <code>Minted</code> event.
    </p>
  </li>
</ul>

<p spaces-before="0">
  The token contract MUST <code>revert</code> when minting in any of the following cases:
</p>

<ul>
  <li>
    The resulting <em x-id="3">recipient</em> balance after the mint is not a multiple of the <em x-id="3">granularity</em> defined by the token contract.
  </li>
  <li>
    The <em x-id="3">recipient</em> is a contract, and it does not implement the <code>ERC777TokensRecipient</code> interface via <a href="./eip-1820.md" fo="8">ERC-1820</a>.
  </li>
  <li>
    The address of the <em x-id="3">recipient</em> is <code>0x0</code>.
  </li>
  <li>
    The <code>tokensReceived</code> hook of the <em x-id="3">recipient</em> <code>revert</code>s.
  </li>
</ul>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: 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 <code>Minted</code> events must be emitted and the <code>tokensReceived</code> hook of the recipient(s) MUST be called.
</p>

<p spaces-before="0">
  <em x-id="3"><a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> compatibility requirement</em>:<br x-id="2" /> While a <code>Sent</code> event MUST NOT be emitted when minting, if the token contract is <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> backward compatible, a <code>Transfer</code> event with the <code>from</code> parameter set to <code>0x0</code> SHOULD be emitted as defined in the <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> standard.
</p>

<p spaces-before="0">
  The token contract MAY mint tokens for multiple <em x-id="3">recipients</em> at once. In this case:
</p>

<ul>
  <li>
    The previous mint rules MUST apply to all the <em x-id="3">recipients</em>.
  </li>
  <li>
    The sum of all the balances incremented MUST be equal to the total minted amount.
  </li>
  <li>
    A <code>Minted</code> event MUST be emitted for every <em x-id="3">recipient</em> with the corresponding amount for each <em x-id="3">recipient</em>.
  </li>
  <li>
    The sum of all the amounts from the <code>Minted</code> event MUST be equal to the total minted <code>amount</code>.
  </li>
</ul>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: Minting an amount of zero (<code>0</code>) tokens is valid and MUST be treated as a regular mint.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: While during a send or a burn, the data is provided by the <em x-id="3">holder</em>, it is inapplicable for a mint. In this case the data MAY be provided by the token contract or the <em x-id="3">operator</em>, for example to ensure a successful minting to a <em x-id="3">holder</em> expecting specific data.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: The <code>operatorData</code> field contains information provided by the <em x-id="3">operator</em>&mdash;similar to the data field in a regular ether send transaction. The <code>tokensReceived()</code> hooks MAY use the information to decide if it wish to reject the transaction.
</p>

<p spaces-before="0">
  <strong x-id="1"><code>Minted</code> event</strong> <a id="minted"></a>
</p>

<pre><code class="solidity">event Minted(
address indexed operator,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData ) </code></pre>

<p spaces-before="0">
  Indicate the minting of <code>amount</code> of tokens to the <code>to</code> address by the <code>operator</code> address.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: This event MUST NOT be emitted outside of a mint process.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**parameters**</small><br x-id="2" /> <small>`operator`: Address which triggered the mint.</small><br x-id="2" /> <small>`to`: Recipient of the tokens.</small><br x-id="2" /> <small>`amount`: Number of tokens minted.</small><br x-id="2" /> <small>`data`: Information provided for the *recipient*.</small><br x-id="2" /> <small>`operatorData`: Information provided by the *operator*.</small>
  </p>
</blockquote>

<h4 spaces-before="0">
  <strong x-id="1">Burning Tokens</strong>
</h4>

<p spaces-before="0">
  Burning tokens is the act of destroying existing tokens. <a href="./eip-777.md" fo="5">ERC-777</a> explicitly defines two functions to burn tokens (<code>burn</code> and <code>operatorBurn</code>). These functions facilitate the integration of the burning process in wallets and dapps. However, the token contract MAY prevent some or all <em x-id="3">holders</em> from burning tokens for any reason. The token contract MAY also define other functions to burn tokens.
</p>

<p spaces-before="0">
  The rules below MUST be respected when burning the tokens of a <em x-id="3">holder</em>:
</p>

<ul>
  <li>
    <p spaces-before="0">
      Tokens MAY be burned from any <em x-id="3">holder</em> address (except <code>0x0</code>).
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The total supply MUST be decreased by the amount of tokens burned.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The balance of <code>0x0</code> MUST NOT be increased.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The balance of the <em x-id="3">holder</em> MUST be decreased by amount of tokens burned.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The token contract MUST emit a <code>Burned</code> event with the correct values as defined in the <a href="#burned" f-id="burned" fo="24"><code>Burned</code> Event</a>.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The token contract MUST call the <code>tokensToSend</code> hook of the <em x-id="3">holder</em> if the <em x-id="3">holder</em> registers an <code>ERC777TokensSender</code> implementation via <a href="./eip-1820.md" fo="8">ERC-1820</a>.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The <code>operatorData</code> MUST be immutable during the entire burn process&mdash;hence the same <code>operatorData</code> MUST be used to call the <code>tokensToSend</code> hook and emit the <code>Burned</code> event.
    </p>
  </li>
</ul>

<p spaces-before="0">
  The token contract MUST <code>revert</code> when burning in any of the following cases:
</p>

<ul>
  <li>
    <p spaces-before="0">
      The <em x-id="3">operator</em> address is not an authorized operator for the <em x-id="3">holder</em>.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The resulting <em x-id="3">holder</em> balance after the burn is not a multiple of the <em x-id="3">granularity</em> defined by the token contract.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The balance of <em x-id="3">holder</em> is inferior to the amount of tokens to burn (i.e., resulting in a negative balance for the <em x-id="3">holder</em>).
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The address of the <em x-id="3">holder</em> is <code>0x0</code>.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The <code>tokensToSend</code> hook of the <em x-id="3">holder</em> <code>revert</code>s.
    </p>
  </li>
</ul>

<p spaces-before="0">
  <em x-id="3"><a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> compatibility requirement</em>:<br x-id="2" /> While a <code>Sent</code> event MUST NOT be emitted when burning; if the token contract is <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> enabled, a <code>Transfer</code> event with the <code>to</code> parameter set to <code>0x0</code> SHOULD be emitted. The <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> standard does not define the concept of burning tokens, but this is a commonly accepted practice.
</p>

<p spaces-before="0">
  The token contract MAY burn tokens for multiple <em x-id="3">holders</em> at once. In this case:
</p>

<ul>
  <li>
    The previous burn rules MUST apply to each <em x-id="3">holders</em>.
  </li>
  <li>
    The sum of all the balances decremented MUST be equal to the total burned amount.
  </li>
  <li>
    A <code>Burned</code> event MUST be emitted for every <em x-id="3">holder</em> with the corresponding amount for each <em x-id="3">holder</em>.
  </li>
  <li>
    The sum of all the amounts from the <code>Burned</code> event MUST be equal to the total burned <code>amount</code>.
  </li>
</ul>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: Burning an amount of zero (<code>0</code>) tokens is valid and MUST be treated as a regular burn.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: The <code>data</code> field contains information provided by the holder&mdash;similar to the data field in a regular ether send transaction. The <code>tokensToSend()</code> hook, the <code>tokensReceived()</code>, or both MAY use the information to decide if they wish to reject the transaction.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: The <code>operatorData</code> field is analogous to the <code>data</code> field except it SHALL be provided by the <em x-id="3">operator</em>.
</p>

<p spaces-before="0">
  <strong x-id="1"><code>Burned</code> event</strong> <a id="burned"></a>
</p>

<pre><code class="solidity">event Burned(
ddress indexed operator,
address indexed from,
uint256 amount,
bytes data,
bytes operatorData ); </code></pre>

<p spaces-before="0">
  Indicate the burning of <code>amount</code> of tokens from the <code>from</code> address by the <code>operator</code> address.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: This event MUST NOT be emitted outside of a burn process.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**parameters**</small><br x-id="2" /> <small>`operator`: Address which triggered the burn.</small><br x-id="2" /> <small>`from`: *Holder* whose tokens were burned.</small><br x-id="2" /> <small>`amount`: Number of tokens burned.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small><br x-id="2" /> <small>`operatorData`: Information provided by the *operator*.</small>
  </p>
</blockquote>

<p spaces-before="0">
  The <code>burn</code> and <code>operatorBurn</code> functions described below MUST be implemented to burn tokens. Token contracts MAY implement other functions to burn tokens.
</p>

<p spaces-before="0">
  <strong x-id="1"><code>burn</code> function</strong>
</p>

<pre><code class="solidity">function burn(uint256 amount, bytes calldata data) external </code></pre>

<p spaces-before="0">
  Burn the <code>amount</code> of tokens from the address <code>msg.sender</code>.
</p>

<p spaces-before="0">
  The <em x-id="3">operator</em> and the <em x-id="3">holder</em> MUST both be the <code>msg.sender</code>.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**identifier:** `fe9d9303`</small><br x-id="2" /> <small>**parameters**</small><br x-id="2" /> <small>`amount`: Number of tokens to burn.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small>
  </p>
</blockquote>

<p spaces-before="0">
  <strong x-id="1"><code>operatorBurn</code> function</strong>
</p>

<pre><code class="solidity">function operatorBurn(
address from,
uint256 amount,
bytes calldata data,
bytes calldata operatorData ) external </code></pre>

<p spaces-before="0">
  Burn the <code>amount</code> of tokens on behalf of the address <code>from</code>.
</p>

<p spaces-before="0">
  <em x-id="3">Reminder</em>: If the <em x-id="3">operator</em> address is not an authorized operator of the <code>from</code> address, then the burn process MUST <code>revert</code>.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**identifier:** `fc673c4f`</small><br x-id="2" /> <small>**parameters**</small><br x-id="2" /> <small>`from`: *Holder* whose tokens will be burned.</small><br x-id="2" /> <small>`amount`: Number of tokens to burn.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small><br x-id="2" /> <small>`operatorData`: Information provided by the *operator*.</small>
  </p>
</blockquote>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: The <em x-id="3">operator</em> MAY pass any information via <code>operatorData</code>. The <code>operatorData</code> MUST only be provided by the <em x-id="3">operator</em>.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: <code>from</code> and <code>msg.sender</code> MAY be the same address. I.e., an address MAY call <code>operatorBurn</code> for itself. This call MUST be equivalent to <code>burn</code> with the addition that the <em x-id="3">operator</em> MAY specify an explicit value for <code>operatorData</code> (which cannot be done with the <code>burn</code> function).
</p>

<h4 spaces-before="0">
  <strong x-id="1"><code>ERC777TokensSender</code> And The <code>tokensToSend</code> Hook</strong>
</h4>

<p spaces-before="0">
  The <code>tokensToSend</code> hook notifies of any request to decrement the balance (send and burn) for a given <em x-id="3">holder</em>. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the <code>ERC777TokensSender</code> interface described below via <a href="./eip-1820.md" fo="8">ERC-1820</a>.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    This is done by calling the <code>setInterfaceImplementer</code> function on the <a href="./eip-1820.md" fo="8">ERC-1820</a> registry with the <em x-id="3">holder</em> address as the address, the <code>keccak256</code> hash of <code>ERC777TokensSender</code> (<code>0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895</code>) as the interface hash, and the address of the contract implementing the <code>ERC777TokensSender</code> as the implementer.
  </p>
</blockquote>

<pre><code class="solidity">interface ERC777TokensSender {
function tokensToSend(
    address operator,
    address from,
    address to,
    uint256 amount,
    bytes calldata userData,
    bytes calldata operatorData
) external; } </code></pre>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: A regular address MAY register a different address&mdash;the address of a contract&mdash;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.
</p>

<p spaces-before="0">
  <strong x-id="1"><code>tokensToSend</code></strong>
</p>

<pre><code class="solidity">function tokensToSend(
address operator,
address from,
address to,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData ) external </code></pre>

<p spaces-before="0">
  Notify a request to send or burn (if <code>to</code> is <code>0x0</code>) an <code>amount</code> tokens from the <code>from</code> address to the <code>to</code> address by the <code>operator</code> address.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: This function MUST NOT be called outside of a burn, send or <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> transfer process.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**identifier:** `75ab9782`</small><br x-id="2" /> <small>**parameters**</small><br x-id="2" /> <small>`operator`: Address which triggered the balance decrease (through sending or burning).</small><br x-id="2" /> <small>`from`: *Holder* whose tokens were sent.</small><br x-id="2" /> <small>`to`: Recipient of the tokens for a send (or `0x0` for a burn).</small><br x-id="2" /> <small>`amount`: Number of tokens the *holder* balance is decreased by.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small><br x-id="2" /> <small>`operatorData`: Information provided by the *operator*.</small>
  </p>
</blockquote>

<p spaces-before="0">
  The following rules apply when calling the <code>tokensToSend</code> hook:
</p>

<ul>
  <li>
    <p spaces-before="0">
      The <code>tokensToSend</code> hook MUST be called for every send and burn processes.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The <code>tokensToSend</code> hook MUST be called <em x-id="3">before</em> the state is updated&mdash;i.e. <em x-id="3">before</em> the balance is decremented.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>operator</code> MUST be the address which triggered the send or burn process.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>from</code> MUST be the address of the <em x-id="3">holder</em> whose tokens are sent or burned.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>to</code> MUST be the address of the <em x-id="3">recipient</em> which receives the tokens for a send.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>to</code> MUST be <code>0x0</code> for a burn.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>amount</code> MUST be the number of tokens the <em x-id="3">holder</em> sent or burned.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>data</code> MUST contain the extra information (if any) provided to the send or the burn process.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>operatorData</code> MUST contain the extra information provided by the address which triggered the decrease of the balance (if any).
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The <em x-id="3">holder</em> MAY block a send or burn process by <code>revert</code>ing. (I.e., reject the withdrawal of tokens from its account.)
    </p>
  </li>
</ul>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: Multiple <em x-id="3">holders</em> MAY use the same implementation of <code>ERC777TokensSender</code>.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: An address can register at most one implementation at any given time for all <a href="./eip-777.md" fo="5">ERC-777</a> tokens. Hence the <code>ERC777TokensSender</code> MUST expect to be called by different token contracts. The <code>msg.sender</code> of the <code>tokensToSend</code> call is expected to be the address of the token contract.
</p>

<p spaces-before="0">
  <em x-id="3"><a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> compatibility requirement</em>:<br x-id="2" /> This hook takes precedence over <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> and MUST be called (if registered) when calling <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>'s <code>transfer</code> and <code>transferFrom</code> event. When called from a <code>transfer</code>, <code>operator</code> MUST be the same value as the <code>from</code>. When called from a <code>transferFrom</code>, <code>operator</code> MUST be the address which issued the <code>transferFrom</code> call.
</p>

<h4 spaces-before="0">
  <strong x-id="1"><code>ERC777TokensRecipient</code> And The <code>tokensReceived</code> Hook</strong>
</h4>

<p spaces-before="0">
  The <code>tokensReceived</code> hook notifies of any increment of the balance (send and mint) for a given <em x-id="3">recipient</em>. Any address (regular or contract) wishing to be notified of token credits to their address MAY register the address of a contract implementing the <code>ERC777TokensRecipient</code> interface described below via <a href="./eip-1820.md" fo="8">ERC-1820</a>.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    This is done by calling the <code>setInterfaceImplementer</code> function on the <a href="./eip-1820.md" fo="8">ERC-1820</a> registry with the <em x-id="3">recipient</em> address as the address, the <code>keccak256</code> hash of <code>ERC777TokensRecipient</code> (<code>0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b</code>) as the interface hash, and the address of the contract implementing the <code>ERC777TokensRecipient</code> as the implementer.
  </p>
</blockquote>

<pre><code class="solidity">interface ERC777TokensRecipient {
function tokensReceived(
    address operator,
    address from,
    address to,
    uint256 amount,
    bytes calldata data,
    bytes calldata operatorData
) external; } </code></pre>

<p spaces-before="0">
  If the <em x-id="3">recipient</em> is a contract, which has not registered an <code>ERC777TokensRecipient</code> implementation; then the token contract:
</p>

<ul>
  <li>
    <p spaces-before="0">
      MUST <code>revert</code> if the <code>tokensReceived</code> hook is called from a mint or send call.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      SHOULD continue processing the transaction if the <code>tokensReceived</code> hook is called from an ERC20 <code>transfer</code> or <code>transferFrom</code> call.
    </p>
  </li>
</ul>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: A regular address MAY register a different address&mdash;the address of a contract&mdash;implementing the interface on its behalf. A contract MUST register either its address or the address of another contract but said address MUST implement the interface on its behalf.
</p>

<p spaces-before="0">
  <strong x-id="1"><code>tokensReceived</code></strong>
</p>

<pre><code class="solidity">function tokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes calldata data,
bytes calldata operatorData ) external </code></pre>

<p spaces-before="0">
  Notify a send or mint (if <code>from</code> is <code>0x0</code>) of <code>amount</code> tokens from the <code>from</code> address to the <code>to</code> address by the <code>operator</code> address.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: This function MUST NOT be called outside of a mint, send or <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> transfer process.
</p>

<blockquote spaces-before="0">
  <p spaces-before="0">
    <small>**identifier:** `0023de29`</small><br x-id="2" /> <small>**parameters**</small><br x-id="2" /> <small>`operator`: Address which triggered the balance increase (through sending or minting).</small><br x-id="2" /> <small>`from`: *Holder* whose tokens were sent (or `0x0` for a mint).</small><br x-id="2" /> <small>`to`: Recipient of the tokens.</small><br x-id="2" /> <small>`amount`: Number of tokens the *recipient* balance is increased by.</small><br x-id="2" /> <small>`data`: Information provided by the *holder*.</small><br x-id="2" /> <small>`operatorData`: Information provided by the *operator*.</small>
  </p>
</blockquote>

<p spaces-before="0">
  The following rules apply when calling the <code>tokensReceived</code> hook:
</p>

<ul>
  <li>
    <p spaces-before="0">
      The <code>tokensReceived</code> hook MUST be called for every send and mint processes.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The <code>tokensReceived</code> hook MUST be called <em x-id="3">after</em> the state is updated&mdash;i.e. <em x-id="3">after</em> the balance is incremented.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>operator</code> MUST be the address which triggered the send or mint process.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>from</code> MUST be the address of the <em x-id="3">holder</em> whose tokens are sent for a send.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>from</code> MUST be <code>0x0</code> for a mint.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>to</code> MUST be the address of the <em x-id="3">recipient</em> which receives the tokens.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>amount</code> MUST be the number of tokens the <em x-id="3">recipient</em> sent or minted.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>data</code> MUST contain the extra information (if any) provided to the send or the mint process.
    </p>
  </li>
  <li>
    <p spaces-before="0">
      <code>operatorData</code> MUST contain the extra information provided by the address which triggered the increase of the balance (if any).
    </p>
  </li>
  <li>
    <p spaces-before="0">
      The <em x-id="3">holder</em> MAY block a send or mint process by <code>revert</code>ing. (I.e., reject the reception of tokens.)
    </p>
  </li>
</ul>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: Multiple <em x-id="3">holders</em> MAY use the same implementation of <code>ERC777TokensRecipient</code>.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: An address can register at most one implementation at any given time for all <a href="./eip-777.md" fo="5">ERC-777</a> tokens. Hence the <code>ERC777TokensRecipient</code> MUST expect to be called by different token contracts. The <code>msg.sender</code> of the <code>tokensReceived</code> call is expected to be the address of the token contract.
</p>

<p spaces-before="0">
  <em x-id="3"><a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> compatibility requirement</em>:<br x-id="2" /> This hook takes precedence over <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> and MUST be called (if registered) when calling <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>'s <code>transfer</code> and <code>transferFrom</code> event. When called from a <code>transfer</code>, <code>operator</code> MUST be the same value as the <code>from</code>. When called from a <code>transferFrom</code>, <code>operator</code> MUST be the address which issued the <code>transferFrom</code> call.
</p>

<h4 spaces-before="0">
  <strong x-id="1">Note On Gas Consumption</strong>
</h4>

<p spaces-before="0">
  Dapps and wallets SHOULD first estimate the gas required when sending, minting, or burning tokens&mdash;using <a href="https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas" f-id="eth_estimateGas" fo="17"><code>eth_estimateGas</code></a>&mdash;to avoid running out of gas during the transaction.
</p>

<h3 spaces-before="0">
  Logo
</h3>
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
> 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 >
<p spaces-before="0">
  The logo MAY be used, modified and adapted to promote valid <a href="./eip-777.md" fo="5">ERC-777</a> token implementations and <a href="./eip-777.md" fo="5">ERC-777</a> compliant technologies such as wallets and dapps.
</p>

<p spaces-before="0">
  <a href="./eip-777.md" fo="5">ERC-777</a> token contract authors MAY create a specific logo for their token based on this logo.
</p>

<p spaces-before="0">
  The logo MUST NOT be used to advertise, promote or associate in any way technology&mdash;such as tokens&mdash;which is not <a href="./eip-777.md" fo="5">ERC-777</a> compliant.
</p>

<p spaces-before="0">
  The logo for the standard can be found in the <a href="https://github.com/ethereum/EIPs/tree/master/assets/eip-777/logo" f-id="logos" lbb="2" fo="25"><code>/assets/eip-777/logo</code></a> folder in <code>SVG</code> and <code>PNG</code> formats. The <code>PNG</code> version of the logo offers a few sizes in pixels. If needed, other sizes MAY be created by converting from <code>SVG</code> into <code>PNG</code>.
</p>

<h2 spaces-before="0">
  Rationale
</h2>

<p spaces-before="0">
  The principal intent for this standard is to solve some of the shortcomings of <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> while maintaining backward compatibility with <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>, and avoiding the problems and vulnerabilities of <a href="https://github.com/ethereum/EIPs/issues/223" fo="16">EIP-223</a>.
</p>

<p spaces-before="0">
  Below are the rationales for the decisions regarding the main aspects of the standards.
</p>

<p spaces-before="0">
  <em x-id="3">NOTE</em>: Jacques Dafflon (<a href="https://github.com/0xjac" fo="10">0xjac</a>), one of the authors of the standard, conjointly wrote his <a href="https://github.com/0xjac/master-thesis" fo="12">master thesis</a> on the standard, which goes in more details than could reasonably fit directly within the standard, and can provide further clarifications regarding certain aspects or decisions.
</p>

<h3 spaces-before="0">
  Lifecycle
</h3>

<p spaces-before="0">
  More than just sending tokens, <a href="./eip-777.md" fo="5">ERC-777</a> defines the entire lifecycle of a token, starting with the minting process, followed by the sending process and terminating with the burn process.
</p>

<p spaces-before="0">
  Having a lifecycle clearly defined is important for consistency and accuracy, especially when value is derived from scarcity. In contrast when looking at some <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> tokens, a discrepancy can be observed between the value returned by the <code>totalSupply</code> and the actual circulating supply, as the standard does not clearly define a process to create and destroy tokens.
</p>

<h3 spaces-before="0">
  Data
</h3>

<p spaces-before="0">
  The mint, send and burn processes can all make use of a <code>data</code> and <code>operatorData</code> fields which are passed to any movement (mint, send or burn). Those fields may be empty for simple use cases, or they may contain valuable information related to the movement of tokens, similar to information attached to a bank transfer by the sender or the bank itself.
</p>

<p spaces-before="0">
  The use of a <code>data</code> field is equally present in other standard proposals such as <a href="https://github.com/ethereum/EIPs/issues/223" fo="16">EIP-223</a>, and was requested by multiple members of the community who reviewed this standard.
</p>

<h3 spaces-before="0">
  Hooks
</h3>

<p spaces-before="0">
  In most cases, <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> requires two calls to safely transfer tokens to a contract without locking them. A call from the sender, using the <code>approve</code> function and a call from the recipient using <code>transferFrom</code>. Furthermore, this requires extra communication between the parties which is not clearly defined. Finally, holders can get confused between <code>transfer</code> and <code>approve</code>/<code>transferFrom</code>. Using the former to transfer tokens to a contract will most likely result in locked tokens.
</p>

<p spaces-before="0">
  Hooks allow streamlining of the sending process and offer a single way to send tokens to any recipient. Thanks to the <code>tokensReceived</code> hook, contracts are able to react and prevent locking tokens upon reception.
</p>

<h4 spaces-before="0">
  <strong x-id="1">Greater Control For Holders</strong>
</h4>

<p spaces-before="0">
  The <code>tokensReceived</code> hook also allows holders to reject the reception of some tokens. This gives greater control to holders who can accept or reject incoming tokens based on some parameters, for example located in the <code>data</code> or <code>operatorData</code> fields.
</p>

<p spaces-before="0">
  Following the same intentions and based on suggestions from the community, the <code>tokensToSend</code> hook was added to give control over and prevent the movement of outgoing tokens.
</p>

<h4 spaces-before="0">
  <strong x-id="1"><a href="./eip-1820.md" fo="8">ERC-1820</a> Registry</strong>
</h4>

<p spaces-before="0">
  The <a href="./eip-1820.md" fo="8">ERC-1820</a> Registry allows holders to register their hooks. Other alternatives were examined beforehand to link hooks and holders.
</p>

<p spaces-before="0">
  The first was for hooks to be defined at the sender's or recipient's address. This approach is similar to <a href="https://github.com/ethereum/EIPs/issues/223" fo="16">EIP-223</a> which proposes a <code>tokenFallback</code> function on recipient contracts to be called when receiving tokens, but improves on it by relying on <a href="./eip-165.md" fo="3">ERC-165</a> for interface detection. While straightforward to implement, this approach imposes several limitations. In particular, the sender and recipient must be contracts in order to provide their implementation of the hooks. Preventing externally owned addresses to benefit from hooks. Existing contracts have a strong probability not to be compatible, as they undoubtedly were unaware and do not define the new hooks. Consequently existing smart contract infrastructure such as multisig wallets which potentially hold large amounts of ether and tokens would need to be migrated to new updated contracts.
</p>

<p spaces-before="0">
  The second approach considered was to use <a href="https://github.com/ethereum/EIPs/issues/672" fo="4">ERC-672</a> which offered pseudo-introspection for addresses using reverse-ENS. However, this approach relied heavily on ENS, on top of which reverse lookup would need to be implemented. Analysis of this approach promptly revealed a certain degree of complexity and security concerns which would transcend the benefits of approach.
</p>

<p spaces-before="0">
  The third solution&mdash;used in this standard&mdash;is to rely on a unique registry where any address can register the addresses of contracts implementing the hooks on its behalf. This approach has the advantage that externally owned accounts and contracts can benefit from hooks, including existing contracts which can rely on hooks deployed on proxy contracts.
</p>

<p spaces-before="0">
  The decision was made to keep this registry in a separate EIP, as to not over complicate this standard. More importantly, the registry is designed in a flexible fashion, such that other EIPs and smart contract infrastructures can benefit from it for their own use cases, outside the realm of <a href="./eip-777.md" fo="5">ERC-777</a> and tokens. The first proposal for this registry was <a href="./eip-820.md" fo="6">ERC-820</a>. Unfortunately, issues emanating from upgrades in the Solidity language to versions 0.5 and above resulted in a bug in a separated part of the registry, which required changes. This was discovered right after the last call period. Attempts made to avoid creating a separate EIP, such as <a href="https://github.com/ethereum/EIPs/pull/1758" fo="7">ERC820a</a>, were rejected. Hence the standard for the registry used for <a href="./eip-777.md" fo="5">ERC-777</a> became <a href="./eip-1820.md" fo="8">ERC-1820</a>. <a href="./eip-1820.md" fo="8">ERC-1820</a> and <a href="./eip-820.md" fo="6">ERC-820</a> are functionally equivalent. <a href="./eip-1820.md" fo="8">ERC-1820</a> simply contains the fix for newer versions of Solidity.
</p>

<h3 spaces-before="0">
  Operators
</h3>

<p spaces-before="0">
  The standard defines the concept of operators as any address which moves tokens. While intuitively every address moves its own tokens, separating the concepts of holder and operator allows for greater flexibility. Primarily, this originates from the fact that the standard defines a mechanism for holders to let other addresses become their operators. Moreover, unlike the approve calls in <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> where the role of an approved address is not clearly defined, <a href="./eip-777.md" fo="5">ERC-777</a> details the intent of and interactions with operators, including an obligation for operators to be approved, and an irrevocable right for any holder to revoke operators.
</p>

<h4 spaces-before="0">
  <strong x-id="1">Default Operators</strong>
</h4>

<p spaces-before="0">
  Default operators were added based on community demand for pre-approved operators. That is operators which are approved for all holders by default. For obvious security reasons, the list of default operators is defined at the token contract creation time, and cannot be changed. Any holder still has the right to revoke default operators. One of the obvious advantages of default operators is to allow ether-less movements of tokens. Default operators offer other usability advantages, such as allowing token providers to offer functionality in a modular way, and to reduce the complexity for holders to use features provided through operators.
</p>

<h2 spaces-before="0">
  Backward Compatibility
</h2>

<p spaces-before="0">
  This EIP does not introduce backward incompatibilities and is backward compatible with the older <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> token standard.
</p>

<p spaces-before="0">
  This EIP does not use <code>transfer</code> and <code>transferFrom</code> and uses <code>send</code> and <code>operatorSend</code> to avoid confusion and mistakes when deciphering which token standard is being used.
</p>

<p spaces-before="0">
  This standard allows the implementation of <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> functions <code>transfer</code>, <code>transferFrom</code>, <code>approve</code> and <code>allowance</code> alongside to make a token fully compatible with <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>.
</p>

<p spaces-before="0">
  The token MAY implement <code>decimals()</code> for backward compatibility with <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>. If implemented, it MUST always return <code>18</code>.
</p>

<p spaces-before="0">
  Therefore a token contract MAY implement both <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> and <a href="./eip-777.md" fo="5">ERC-777</a> in parallel. The specification of the <code>view</code> functions (such as <code>name</code>, <code>symbol</code>, <code>balanceOf</code>, <code>totalSupply</code>) and internal data (such as the mapping of balances) overlap without problems. Note however that the following functions are mandatory in <a href="./eip-777.md" fo="5">ERC-777</a> and MUST be implemented: <code>name</code>, <code>symbol</code> <code>balanceOf</code> and <code>totalSupply</code> (<code>decimals</code> is not part of the <a href="./eip-777.md" fo="5">ERC-777</a> standard).
</p>

<p spaces-before="0">
  The state-modifying functions from both standards are decoupled and can operate independently from each other. Note that <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> functions SHOULD be limited to only being called from old contracts.
</p>

<p spaces-before="0">
  If the token implements <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>, it MUST register the <code>ERC20Token</code> interface with its own address via <a href="./eip-1820.md" fo="8">ERC-1820</a>. This is done by calling the <code>setInterfaceImplementer</code> function on the ERC1820 registry with the token contract address as both the address and the implementer and the <code>keccak256</code> hash of <code>ERC20Token</code> (<code>0xaea199e31a596269b42cdafd93407f14436db6e4cad65417994c2eb37381e05a</code>) as the interface hash.
</p>

<p spaces-before="0">
  If the contract has a switch to enable or disable ERC20 functions, every time the switch is triggered, the token MUST register or unregister the <code>ERC20Token</code> interface for its own address accordingly via ERC1820. Unregistering implies calling the <code>setInterfaceImplementer</code> with the token contract address as the address, the <code>keccak256</code> hash of <code>ERC20Token</code> as the interface hash and <code>0x0</code> as the implementer. (See <a href="./eip-1820.md#set-an-interface-for-an-address" f-id="erc1820-set" fo="9">Set An Interface For An Address</a> in <a href="./eip-1820.md" fo="8">ERC-1820</a> for more details.)
</p>

<p spaces-before="0">
  The difference for new contracts implementing <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> is that <code>tokensToSend</code> and <code>tokensReceived</code> hooks take precedence over <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>. Even with an <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> <code>transfer</code> and <code>transferFrom</code> call, the token contract MUST check via <a href="./eip-1820.md" fo="8">ERC-1820</a> if the <code>from</code> and the <code>to</code> address implement <code>tokensToSend</code> and <code>tokensReceived</code> hook respectively. If any hook is implemented, it MUST be called. Note that when calling <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> <code>transfer</code> on a contract, if the contract does not implement <code>tokensReceived</code>, the <code>transfer</code> call SHOULD still be accepted even if this means the tokens will probably be locked.
</p>

<p spaces-before="0">
  The table below summarizes the different actions the token contract MUST take when sending, minting and transferring token via <a href="./eip-777.md" fo="5">ERC-777</a> and <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>:
</p>
ERC1820 to address ERC777 Sending And Minting ERC20 transfer/transferFrom
ERC777TokensRecipient
registered
regular address MUST call tokensReceived
contract
ERC777TokensRecipient
not registered
regular address continue
contract MUST revert SHOULD continue1
<blockquote spaces-before="0">
  <p spaces-before="0">
    <a href="#continue-footnote-backlink"><small id="continue-footnote">1.</small></a>    <small>The transaction SHOULD continue for clarity as ERC20 is not aware of hooks.</small><br x-id="2" /> <small>However, this can result in accidentally locked tokens.</small> <small>If avoiding accidentally locked tokens is paramount, the transaction MAY <code>revert</code>.</small>
  </p>
</blockquote>

<p spaces-before="0">
  There is no particular action to take if <code>tokensToSend</code> is not implemented. The movement MUST proceed and only be canceled if another condition is not respected such as lack of funds or a <code>revert</code> in <code>tokensReceived</code> (if present).
</p>

<p spaces-before="0">
  During a send, mint and burn, the respective <code>Sent</code>, <code>Minted</code> and <code>Burned</code> events MUST be emitted. Furthermore, if the token contract declares that it implements <code>ERC20Token</code> via <a href="./eip-1820.md" fo="8">ERC-1820</a>, the token contract SHOULD emit a <code>Transfer</code> event for minting and burning and MUST emit a <code>Transfer</code> event for sending (as specified in the <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> standard). During an <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a>'s <code>transfer</code> or <code>transferFrom</code> functions, a valid <code>Sent</code> event MUST be emitted.
</p>

<p spaces-before="0">
  Hence for any movement of tokens, two events MAY be emitted: an <a href="./eip-20.md" lbb="2" fo="2">ERC-20</a> <code>Transfer</code> and an <a href="./eip-777.md" fo="5">ERC-777</a> <code>Sent</code>, <code>Minted</code> or <code>Burned</code> (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 <code>Transfer</code> event MUST be taken into account. If the application considers the token as an ERC777 token, then only the <code>Sent</code>, <code>Minted</code> and <code>Burned</code> events MUST be considered.
</p>

<h2 spaces-before="0">
  Test Cases
</h2>

<p spaces-before="0">
  The <a href="https://github.com/0xjac/ERC777" f-id="0xjac/ERC777" fo="11">repository with the reference implementation</a> contains all the <a href="https://github.com/0xjac/ERC777/blob/master/test/ReferenceToken.test.js" f-id="ref tests" fo="14">tests</a>.
</p>

<h2 spaces-before="0">
  Implementation
</h2>

<p spaces-before="0">
  The GitHub repository <a href="https://github.com/0xjac/ERC777" fo="11">0xjac/ERC777</a> contains the <a href="https://github.com/0xjac/ERC777/blob/master/contracts/examples/ReferenceToken.sol" fo="15">reference implementation</a>. The reference implementation is also available via <a href="https://www.npmjs.com/package/erc777" f-id="npm/erc777" fo="13">npm</a> and can be installed with <code>npm install erc777</code>.
</p>

<h2 spaces-before="0">
  Copyright
</h2>

<p spaces-before="0">
  Copyright and related rights waived via <a href="../LICENSE.md">CC0</a>.
</p>

参考文献

Please cite this document as:

Jacques Dafflon, Jordi Baylina, Thomas Shababi, "EIP-777: Token Standard," Ethereum Improvement Proposals, no. 777, November 2017. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-777.