ERC777
Smart contract ERC777 utilities and implementations
Outdated Version
🔥 CAUTION
As of v4.9, OpenZeppelin’s implementation of ERC-777 is deprecated and will be removed in the next major release.
This set of interfaces and contracts are all related to the ERC777 token standard.
For an overview of ERC777 tokens and a walk through on how to create a token contract read our ERC777 guide.
The token behavior itself is implemented in the core contracts: IERC777, ERC777.
Additionally there are interfaces used to develop contracts that react to token movements: IERC777Sender, IERC777Recipient.
Core
Hooks
Presets
These contracts are preconfigured combinations of features. They can be used through inheritance or as models to copy and paste their source code.
import "@openzeppelin/contracts/token/ERC777/ERC777.sol";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 ERC1155._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.
CAUTION: This file is deprecated as of v4.9 and will be removed in the next major release.
Functions
- constructor(name_, symbol_, defaultOperators_)
- name()
- symbol()
- decimals()
- granularity()
- totalSupply()
- balanceOf(tokenHolder)
- send(recipient, amount, data)
- transfer(recipient, amount)
- burn(amount, data)
- isOperatorFor(operator, tokenHolder)
- authorizeOperator(operator)
- revokeOperator(operator)
- defaultOperators()
- operatorSend(sender, recipient, amount, data, operatorData)
- operatorBurn(account, amount, data, operatorData)
- allowance(holder, spender)
- approve(spender, value)
- transferFrom(holder, recipient, amount)
- _mint(account, amount, userData, operatorData)
- _mint(account, amount, userData, operatorData, requireReceptionAck)
- _send(from, to, amount, userData, operatorData, requireReceptionAck)
- _burn(from, amount, data, operatorData)
- _approve(holder, spender, value)
- _spendAllowance(owner, spender, amount)
- _beforeTokenTransfer(operator, from, to, amount)
IERC20
IERC777
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.
granularity() → uint256
public
#See IERC777.granularity.
This implementation always returns 1.
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 IERC777.Sent event.
burn(uint256 amount, bytes data)
public
#See IERC777.burn.
Also emits a IERC20.Transfer event for ERC20 compatibility.
isOperatorFor(address operator, address tokenHolder) → bool
public
#authorizeOperator(address operator)
public
#revokeOperator(address operator)
public
#defaultOperators() → address[]
public
#operatorSend(address sender, address recipient, uint256 amount, bytes data, bytes operatorData)
public
#See IERC777.operatorSend.
Emits IERC777.Sent and IERC20.Transfer events.
operatorBurn(address account, uint256 amount, bytes data, bytes operatorData)
public
#See IERC777.operatorBurn.
Emits IERC777.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: If value is the maximum uint256, the allowance is not updated on
transferFrom. This is semantically equivalent to an infinite approval.
Note that accounts cannot have allowance issued by their operators.
transferFrom(address holder, address recipient, uint256 amount) → bool
public
#See IERC20.transferFrom.
NOTE: Does not update the allowance if the current allowance
is the maximum uint256.
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 IERC777.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 the caller address as the operator and with
userData and operatorData.
See IERC777Sender and IERC777Recipient.
Emits IERC777.Minted and IERC20.Transfer events.
Requirements
accountcannot be the zero address.- if
accountis a contract, it must implement theIERC777Recipientinterface.
_mint(address account, uint256 amount, bytes userData, bytes operatorData, bool requireReceptionAck)
internal
#Creates amount tokens and assigns them to account, increasing
the total supply.
If requireReceptionAck is set to true, and if a send hook is
registered for account, the corresponding function will be called with
operator, data and operatorData.
See IERC777Sender and IERC777Recipient.
Emits IERC777.Minted and IERC20.Transfer events.
Requirements
accountcannot be the zero address.- if
accountis a contract, it must implement theIERC777Recipientinterface.
_send(address from, address to, uint256 amount, bytes userData, bytes operatorData, bool requireReceptionAck)
internal
#Send tokens
_burn(address from, uint256 amount, bytes data, bytes operatorData)
internal
#Burn tokens
_approve(address holder, address spender, uint256 value)
internal
#See ERC20._approve.
Note that accounts cannot have allowance issued by their operators.
_spendAllowance(address owner, address spender, uint256 amount)
internal
#Updates owner s allowance for spender based on spent amount.
Does not update the allowance amount in case of infinite allowance. Revert if not enough allowance is available.
Might emit an IERC20.Approval event.
_beforeTokenTransfer(address operator, address from, address to, uint256 amount)
internal
#Hook that is called before any token transfer. This includes
calls to ERC777.send, ERC20.transfer, ERC777.operatorSend, ERC20.transferFrom, minting and burning.
Calling conditions:
- when
fromandtoare both non-zero,amountoffrom's tokens will be to transferred toto. - when
fromis zero,amounttokens will be minted forto. - when
tois zero,amountoffrom's tokens will be burned. fromandtoare never both zero.
To learn more about hooks, head to xref:ROOT:extending-contracts#using-hooks[Using Hooks].
import "@openzeppelin/contracts/token/ERC777/IERC777.sol";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.
Functions
- name()
- symbol()
- granularity()
- totalSupply()
- balanceOf(owner)
- send(recipient, amount, data)
- burn(amount, data)
- isOperatorFor(operator, tokenHolder)
- authorizeOperator(operator)
- revokeOperator(operator)
- defaultOperators()
- operatorSend(sender, recipient, amount, data, operatorData)
- operatorBurn(account, amount, data, operatorData)
Events
name() → string
external
#Returns the name of the token.
symbol() → string
external
#Returns the symbol of the token, usually a shorter version of the name.
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.
totalSupply() → uint256
external
#Returns the amount of tokens in existence.
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 IERC777.Sent event.
Requirements
- the caller must have at least
amounttokens. recipientcannot be the zero address.- if
recipientis a contract, it must implement theIERC777Recipientinterface.
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 IERC777.Burned event.
Requirements
- the caller must have at least
amounttokens.
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 ERC777.operatorSend and ERC777.operatorBurn.
authorizeOperator(address operator)
external
#Make an account an operator of the caller.
See ERC777.isOperatorFor.
Emits an IERC777.AuthorizedOperator event.
Requirements
operatorcannot be calling address.
revokeOperator(address operator)
external
#Revoke an account's operator status for the caller.
See ERC777.isOperatorFor and ERC777.defaultOperators.
Emits a IERC777.RevokedOperator event.
Requirements
operatorcannot be calling address.
defaultOperators() → address[]
external
#Returns the list of default operators. These accounts are operators
for all token holders, even if ERC777.authorizeOperator was never called on
them.
This list is immutable, but individual holders may revoke these via
ERC777.revokeOperator, in which case ERC777.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 IERC777.Sent event.
Requirements
sendercannot be the zero address.sendermust have at leastamounttokens.- the caller must be an operator for
sender. recipientcannot be the zero address.- if
recipientis a contract, it must implement theIERC777Recipientinterface.
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 IERC777.Burned event.
Requirements
accountcannot be the zero address.accountmust have at leastamounttokens.- the caller must be an operator for
account.
Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData)
event
#Emitted when amount tokens are created by operator and assigned to to.
Note that some additional user data and operatorData can be logged in the event.
Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData)
event
#Emitted when operator destroys amount tokens from account.
Note that some additional user data and operatorData can be logged in the event.
AuthorizedOperator(address indexed operator, address indexed tokenHolder)
event
#Emitted when operator is made operator for tokenHolder.
RevokedOperator(address indexed operator, address indexed tokenHolder)
event
#Emitted when operator is revoked its operator status for tokenHolder.
Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData)
event
#import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";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.
import "@openzeppelin/contracts/token/ERC777/IERC777Sender.sol";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.
import "@openzeppelin/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol";ERC777 token, including:
- Preminted initial supply
- No access control mechanism (for minting/pausing) and hence no governance
Available since v3.4.
Functions
ERC777
- name()
- symbol()
- decimals()
- granularity()
- totalSupply()
- balanceOf(tokenHolder)
- send(recipient, amount, data)
- transfer(recipient, amount)
- burn(amount, data)
- isOperatorFor(operator, tokenHolder)
- authorizeOperator(operator)
- revokeOperator(operator)
- defaultOperators()
- operatorSend(sender, recipient, amount, data, operatorData)
- operatorBurn(account, amount, data, operatorData)
- allowance(holder, spender)
- approve(spender, value)
- transferFrom(holder, recipient, amount)
- _mint(account, amount, userData, operatorData)
- _mint(account, amount, userData, operatorData, requireReceptionAck)
- _send(from, to, amount, userData, operatorData, requireReceptionAck)
- _burn(from, amount, data, operatorData)
- _approve(holder, spender, value)
- _spendAllowance(owner, spender, amount)
- _beforeTokenTransfer(operator, from, to, amount)
IERC20
IERC777
constructor(string name, string symbol, address[] defaultOperators, uint256 initialSupply, address owner)
public
#Mints initialSupply amount of token and transfers them to owner.
See ERC777.constructor.