ERC 777
This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc777 |
This set of interfaces and contracts are all related to the [ERC777 token standard](https://eips.ethereum.org/EIPS/eip-777).
For an overview of ERC777 tokens and a walk through on how to create a token contract read our ERC777 guide. |
Additionally there are interfaces used to develop contracts that react to token movements: IERC777Sender
, IERC777Recipient
.
Core
IERC777
Interface of the ERC777Token standard as defined in the EIP.
This contract uses the
ERC1820 registry standard to let
token holders and recipients react to token movements by using setting implementers
for the associated interfaces in said registry. See IERC1820Registry
and
ERC1820Implementer
.
granularity() → uint256
external
Returns the smallest part of the token that is not divisible. This means all token operations (creation, movement and destruction) must have amounts that are a multiple of this number.
For most token contracts, this value will equal 1.
balanceOf(address owner) → uint256
external
Returns the amount of tokens owned by an account (owner
).
send(address recipient, uint256 amount, bytes data)
external
Moves amount
tokens from the caller’s account to recipient
.
If send or receive hooks are registered for the caller and recipient
,
the corresponding functions will be called with data
and empty
operatorData
. See IERC777Sender
and IERC777Recipient
.
Emits a Sent
event.
Requirements
-
the caller must have at least
amount
tokens. -
recipient
cannot be the zero address. -
if
recipient
is a contract, it must implement theIERC777Recipient
interface.
burn(uint256 amount, bytes data)
external
Destroys amount
tokens from the caller’s account, reducing the
total supply.
If a send hook is registered for the caller, the corresponding function
will be called with data
and empty operatorData
. See IERC777Sender
.
Emits a Burned
event.
Requirements
-
the caller must have at least
amount
tokens.
isOperatorFor(address operator, address tokenHolder) → bool
external
Returns true if an account is an operator of tokenHolder
.
Operators can send and burn tokens on behalf of their owners. All
accounts are their own operator.
See operatorSend
and operatorBurn
.
authorizeOperator(address operator)
external
Make an account an operator of the caller.
See isOperatorFor
.
Emits an AuthorizedOperator
event.
Requirements
-
operator
cannot be calling address.
revokeOperator(address operator)
external
Revoke an account’s operator status for the caller.
See isOperatorFor
and defaultOperators
.
Emits a RevokedOperator
event.
Requirements
-
operator
cannot be calling address.
defaultOperators() → address[]
external
Returns the list of default operators. These accounts are operators
for all token holders, even if authorizeOperator
was never called on
them.
This list is immutable, but individual holders may revoke these via
revokeOperator
, in which case isOperatorFor
will return false.
operatorSend(address sender, address recipient, uint256 amount, bytes data, bytes operatorData)
external
Moves amount
tokens from sender
to recipient
. The caller must
be an operator of sender
.
If send or receive hooks are registered for sender
and recipient
,
the corresponding functions will be called with data
and
operatorData
. See IERC777Sender
and IERC777Recipient
.
Emits a Sent
event.
Requirements
-
sender
cannot be the zero address. -
sender
must have at leastamount
tokens. -
the caller must be an operator for
sender
. -
recipient
cannot be the zero address. -
if
recipient
is a contract, it must implement theIERC777Recipient
interface.
operatorBurn(address account, uint256 amount, bytes data, bytes operatorData)
external
Destroys amount
tokens from account
, reducing the total supply.
The caller must be an operator of account
.
If a send hook is registered for account
, the corresponding function
will be called with data
and operatorData
. See IERC777Sender
.
Emits a Burned
event.
Requirements
-
account
cannot be the zero address. -
account
must have at leastamount
tokens. -
the caller must be an operator for
account
.
ERC777
Implementation of the IERC777
interface.
This implementation is agnostic to the way tokens are created. This means
that a supply mechanism has to be added in a derived contract using _mint
.
Support for ERC20 is included in this contract, as specified by the EIP: both
the ERC777 and ERC20 interfaces can be safely used when interacting with it.
Both IERC777.Sent
and IERC20.Transfer
events are emitted on token
movements.
Additionally, the IERC777.granularity
value is hard-coded to 1
, meaning that there
are no special restrictions in the amount of tokens that created, moved, or
destroyed. This makes integration with ERC20 applications seamless.
constructor(string name_, string symbol_, address[] defaultOperators_)
public
defaultOperators
may be an empty array.
name() → string
public
See IERC777.name
.
symbol() → string
public
See IERC777.symbol
.
decimals() → uint8
public
See ERC20.decimals
.
Always returns 18, as per the [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility).
totalSupply() → uint256
public
See IERC777.totalSupply
.
balanceOf(address tokenHolder) → uint256
public
Returns the amount of tokens owned by an account (tokenHolder
).
send(address recipient, uint256 amount, bytes data)
public
See IERC777.send
.
Also emits a IERC20.Transfer
event for ERC20 compatibility.
transfer(address recipient, uint256 amount) → bool
public
See IERC20.Transfer
.
Unlike send
, recipient
is not required to implement the IERC777Recipient
interface if it is a contract.
Also emits a Sent
event.
burn(uint256 amount, bytes data)
public
See IERC777.burn
.
Also emits a IERC20.Transfer
event for ERC20 compatibility.
operatorSend(address sender, address recipient, uint256 amount, bytes data, bytes operatorData)
public
See IERC777.operatorSend
.
Emits Sent
and IERC20.Transfer
events.
operatorBurn(address account, uint256 amount, bytes data, bytes operatorData)
public
See IERC777.operatorBurn
.
Emits Burned
and IERC20.Transfer
events.
allowance(address holder, address spender) → uint256
public
See IERC20.allowance
.
Note that operator and allowance concepts are orthogonal: operators may not have allowance, and accounts with allowance may not be operators themselves.
approve(address spender, uint256 value) → bool
public
See IERC20.approve
.
Note that accounts cannot have allowance issued by their operators.
transferFrom(address holder, address recipient, uint256 amount) → bool
public
See IERC20.transferFrom
.
Note that operator and allowance concepts are orthogonal: operators cannot
call transferFrom
(unless they have allowance), and accounts with
allowance cannot call operatorSend
(unless they are operators).
Emits Sent
, IERC20.Transfer
and IERC20.Approval
events.
_mint(address account, uint256 amount, bytes userData, bytes operatorData)
internal
Creates amount
tokens and assigns them to account
, increasing
the total supply.
If a send hook is registered for account
, the corresponding function
will be called with operator
, data
and operatorData
.
See IERC777Sender
and IERC777Recipient
.
Emits Minted
and IERC20.Transfer
events.
Requirements
-
account
cannot be the zero address. -
if
account
is a contract, it must implement theIERC777Recipient
interface.
_send(address from, address to, uint256 amount, bytes userData, bytes operatorData, bool requireReceptionAck)
internal
Send tokens
_approve(address holder, address spender, uint256 value)
internal
See ERC20._approve
.
Note that accounts cannot have allowance issued by their operators.
_beforeTokenTransfer(address operator, address from, address to, uint256 amount)
internal
Hook that is called before any token transfer. This includes
calls to send
, transfer
, operatorSend
, minting and burning.
Calling conditions:
-
when
from
andto
are both non-zero,amount
offrom
's tokens will be to transferred toto
. -
when
from
is zero,amount
tokens will be minted forto
. -
when
to
is zero,amount
offrom
's tokens will be burned. -
from
andto
are never both zero.
To learn more about hooks, head to Using Hooks.
Hooks
IERC777Sender
Interface of the ERC777TokensSender standard as defined in the EIP.
IERC777
Token holders can be notified of operations performed on their
tokens by having a contract implement this interface (contract holders can be
their own implementer) and registering it on the
ERC1820 global registry.
See IERC1820Registry
and ERC1820Implementer
.
tokensToSend(address operator, address from, address to, uint256 amount, bytes userData, bytes operatorData)
external
Called by an IERC777
token contract whenever a registered holder’s
(from
) tokens are about to be moved or destroyed. The type of operation
is conveyed by to
being the zero address or not.
This call occurs before the token contract’s state is updated, so
IERC777.balanceOf
, etc., can be used to query the pre-operation state.
This function may revert to prevent the operation from being executed.
IERC777Recipient
Interface of the ERC777TokensRecipient standard as defined in the EIP.
Accounts can be notified of IERC777
tokens being sent to them by having a
contract implement this interface (contract holders can be their own
implementer) and registering it on the
ERC1820 global registry.
See IERC1820Registry
and ERC1820Implementer
.
tokensReceived(address operator, address from, address to, uint256 amount, bytes userData, bytes operatorData)
external
Called by an IERC777
token contract whenever tokens are being
moved or created into a registered account (to
). The type of operation
is conveyed by from
being the zero address or not.
This call occurs after the token contract’s state is updated, so
IERC777.balanceOf
, etc., can be used to query the post-operation state.
This function may revert to prevent the operation from being executed.