ERC777
Details of ERC777 can be found in ERC777.
#
Dependencymetis_erc777 = { git = "https://github.com/patractlabs/metis", default-features = false }
#
Storage#[cfg_attr(feature = "std", derive(::ink_storage::traits::StorageLayout))]#[derive(Debug, SpreadLayout)]pub struct Data<E: Env> { /// Total token supply. pub total_supply: Lazy<E::Balance>, /// Mapping from owner to number of owned token. pub balances: StorageHashMap<E::AccountId, E::Balance>, /// Mapping of the token amount which an account is allowed to withdraw /// from another account. pub allowances: StorageHashMap<(E::AccountId, E::AccountId), E::Balance>, /// Metadatas Symbols of ERC777 Token, by (name, symbol) pub metadatas: Lazy<(u8, String, String)>,
/// This isn't ever read from - it's only used to respond to the defaultOperators query. pub default_operators_array: Lazy<Vec<E::AccountId>>,
/// Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators). pub default_operators: StorageHashMap<E::AccountId, ()>,
/// For each account, a mapping of its operators and revoked default operators. pub operators: StorageHashMap<(E::AccountId, E::AccountId), ()>, pub revoked_default_operators: StorageHashMap<(E::AccountId, E::AccountId), ()>,}
#
Mutable Functions#
sendMoves 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
operator_data
. See erc777_sender
and erc777_recipient
.
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 theerc777_recipient
interface.
fn send( &mut self, recipient: E::AccountId, amount: E::Balance, data: Vec<u8>, ) -> Result<()> { self._send( Self::caller(), recipient, amount, data, Vec::default(), true, ) }
#
transferMoves amount
tokens from the caller's account to recipient
.
Returns a boolean value indicating whether the operation succeeded.
Emits a Transfer
event.
fn transfer(&mut self, recipient: &E::AccountId, amount: E::Balance) -> Result<()> { let null_account = &E::AccountId::default(); let from = &Self::caller();
if recipient == null_account { return Err(Error::AccountIsZero) }
let null_data = &Vec::<u8>::default();
self._call_tokens_to_send( &from, &Some(&from), &Some(&recipient), &amount, null_data, null_data, );
self._move(&from, &from, &recipient, &amount, null_data, null_data)?;
self._call_tokens_received( &from, &Some(&from), &Some(&recipient), &amount, null_data, null_data, false, );
Ok(()) }
#
burnDestroys 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 operator_data
. See erc777_sender
.
Emits a Burned
event.
Requirements
- the caller must have at least
amount
tokens.
fn burn(&mut self, amount: E::Balance, data: Vec<u8>) -> Result<()> { self._burn(Self::caller(), amount, data, Vec::default()) }
#
authorize_operatorMake an account an operator of the caller.
See is_operator_for
.
Emits an AuthorizedOperator
event.
Requirements
operator
cannot be calling address.
fn authorize_operator(&mut self, operator: E::AccountId) { let caller = Self::caller(); assert!(caller != operator, "ERC777: authorizing self as operator");
let key = (caller.clone(), operator.clone());
if self.get().is_default_operator(&operator) { self.get_mut().revoked_default_operators.take(&key); } else { self.get_mut().operators.insert(key, ()); }
self.emit_event_authorized_operator(operator, caller); }
#
revoke_operatorRevoke an account's operator status for the caller.
See is_operator_for
and default_operators
.
Emits a RevokedOperator
event.
Requirements
operator
cannot be calling address.
fn revoke_operator(&mut self, operator: E::AccountId) { let caller = Self::caller(); assert!(caller != operator, "ERC777: revoke self as operator");
let key = (caller.clone(), operator.clone());
if self.get().is_default_operator(&operator) { self.get_mut().revoked_default_operators.insert(key, ()); } else { self.get_mut().operators.take(&key); }
self.emit_event_revoked_operator(operator, caller); }
#
operator_sendMoves 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
operator_data
. See erc777_sender
and erc777_recipient
.
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 theerc777_recipient
interface.
fn operator_send( &mut self, sender: E::AccountId, recipient: E::AccountId, amount: E::Balance, data: Vec<u8>, operator_data: Vec<u8>, ) -> Result<()> { assert!( self.get().is_operator_for(&Self::caller(), &sender), "ERC777: caller is not an operator for holder" );
self._send(sender, recipient, amount, data, operator_data, true) }
#
operator_burnDestroys 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 operator_data
. See erc777_sender
.
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
.
fn operator_burn( &mut self, account: E::AccountId, amount: E::Balance, data: Vec<u8>, operator_data: Vec<u8>, ) -> Result<()> { assert!( self.get().is_operator_for(&Self::caller(), &account), "ERC777: caller is not an operator for holder" );
self._burn(account, amount, data, operator_data) }
#
approveSets amount
as the allowance of spender
over the caller's tokens.
Returns a boolean value indicating whether the operation succeeded.
IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
Emits an Approval
event.
fn approve(&mut self, spender: &E::AccountId, amount: E::Balance) -> Result<()> { self._approve(&Self::caller(), spender, amount) }
#
transfer_fromMoves amount
tokens from sender
to recipient
using the
allowance mechanism. amount
is then deducted from the caller's
allowance.
Returns a boolean value indicating whether the operation succeeded.
Emits a Transfer
event.
fn transfer_from( &mut self, holder: &E::AccountId, recipient: &E::AccountId, amount: E::Balance, ) -> Result<()> { let caller = &Self::caller(); let null_account = &E::AccountId::default();
if recipient == null_account { return Err(Error::AccountIsZero) }
let current_allowance = self.get().allowance(holder, caller); if current_allowance < amount { return Err(Error::InsufficientAllowance) }
let spender = Self::caller();
self._call_tokens_to_send( &spender, &Some(&holder), &Some(&recipient), &amount, &Vec::default(), &Vec::default(), );
self._approve(holder, caller, current_allowance - amount)?;
self._move( &spender, &holder, &recipient, &amount, &Vec::default(), &Vec::default(), )?;
self._call_tokens_received( &spender, &Some(&holder), &Some(&recipient), &amount, &Vec::default(), &Vec::default(), false, );
Ok(()) }
#
Immutable Functions#
nameReturns the name of the token.
fn name(&self) -> String { self.get().name().clone() }
#
symbolReturns the symbol of the token, usually a shorter version of the name.
fn symbol(&self) -> String { self.get().symbol().clone() }
#
decimalsReturns the number of decimals used to get its user representation.
For example, if decimals
equals 2
, a balance of 505
tokens should
be displayed to a user as 5,05
(505 / 10 ** 2
).
Tokens usually opt for a value of 18, imitating the relationship between
Ether and Wei in ETH. This is the value ERC20
uses, unless this function is
overridden;
NOTE: This information is only used for display purposes: it in no way affects any of the arithmetic of the contract
fn decimals(&self) -> u8 { self.get().decimals().clone() }
#
granularityReturns 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.
fn granularity(&self) -> E::Balance { E::Balance::from(1_u8) }
#
total_supplyReturns the amount of tokens in existence.
fn total_supply(&self) -> E::Balance { self.get().total_supply() }
#
balance_ofReturns the amount of tokens owned by account
.
fn balance_of(&self, account: &E::AccountId) -> E::Balance { self.get().balance_of(account) }
#
is_operator_forReturns true if an account is an operator of token_holder
.
Operators can send and burn tokens on behalf of their owners. All
accounts are their own operator.
See operator_send
and operator_burn
.
fn is_operator_for( &self, operator: E::AccountId, token_holder: E::AccountId, ) -> bool { self.get().is_operator_for(&operator, &token_holder) }
#
default_operatorsReturns the list of default operators. These accounts are operators
for all token holders, even if authorize_operator
was never called on
them.
This list is immutable, but individual holders may revoke these via
revoke_operator
, in which case is_operator_for
will return false.
fn default_operators(&self) -> Vec<E::AccountId> { self.get().default_operators_array.clone() }
#
allowanceReturns the remaining number of tokens that spender
will be
allowed to spend on behalf of owner
through transfer_from
. This is
zero by default.
This value changes when approve
or transfer_from
are called.
fn allowance(&self, owner: &E::AccountId, spender: &E::AccountId) -> E::Balance { self.get().allowance(owner, spender) }
#
Internal FunctionsThere are some internal functions can help developer to add self-defined messages:
_mint
_mint_required_reception_ack
_burn
#
_mintCreates 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 operator_data
.
See erc777_sender
and erc777_recipient
.
Emits Minted
and Transfer
events.
Requirements
account
cannot be the zero address.- if
account
is a contract, it must implement theerc777_recipient
interface.
fn _mint( &mut self, account: E::AccountId, amount: E::Balance, user_data: Vec<u8>, operator_data: Vec<u8>, ) -> Result<()> { self._mint_required_reception_ack(account, amount, user_data, operator_data, true) }
#
_mint_required_reception_ackCreates 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 operator_data
.
See erc777_sender
and erc777_recipient
.
Emits Minted
and Transfer
events.
Requirements
account
cannot be the zero address.- if
account
is a contract, it must implement theerc777_recipient
interface.
fn _mint_required_reception_ack( &mut self, account: E::AccountId, amount: E::Balance, user_data: Vec<u8>, operator_data: Vec<u8>, required_reception_ack: bool, ) -> Result<()> { let null_account = E::AccountId::default();
if account == null_account { return Err(Error::AccountIsZero) }
let operator = Self::caller();
self._before_token_transfer(&operator, &None, &Some(&account), &amount)?;
// Update state variables let current_total = self.get().total_supply(); let current_balance = self.get().balance_of(&account);
self.get_mut().set_total_supply(current_total + amount); self.get_mut() .set_balance(&account, current_balance + amount);
self._call_tokens_received( &operator, &None, &Some(&account), &amount, &user_data, &operator_data, required_reception_ack, );
self.emit_event_minted( operator, account.clone(), amount, user_data, operator_data, ); self.emit_event_transfer(None, Some(account), amount);
Ok(()) }
#
_burnBurn tokens
Params:
- from address token holder address
- amount uint256 amount of tokens to burn
- data bytes extra information provided by the token holder
- operator_data bytes extra information provided by the operator (if any)
fn _burn( &mut self, from: E::AccountId, amount: E::Balance, data: Vec<u8>, operator_data: Vec<u8>, ) -> Result<()> { let null_account = E::AccountId::default();
assert!(from != null_account, "ERC777: burn from the zero address");
let operator = Self::caller();
self._call_tokens_to_send( &operator, &Some(&from), &None, &amount, &data, &operator_data, );
self._before_token_transfer(&operator, &Some(&from), &None, &amount)?;
// Update state variables let from_balance = self.get().balance_of(&from); assert!( from_balance >= amount, "ERC777: burn amount exceeds balance" ); self.get_mut().set_balance(&from, from_balance - amount);
let current_total = self.get().total_supply(); self.get_mut().set_total_supply(current_total - amount);
self.emit_event_burned(operator, from.clone(), amount, data, operator_data); self.emit_event_transfer(Some(from), None, amount);
Ok(()) }
#
Hooks#
_before_token_transferHook that is called before any token transfer. This includes
calls to send
, transfer
, operator_send
, 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.
fn _before_token_transfer( &mut self, _operator: &E::AccountId, _from: &Option<&E::AccountId>, _to: &Option<&E::AccountId>, _amount: &E::Balance, ) -> Result<()> { Ok(()) }
#
Events#
TransferEvent emitted when a token transfer occurs.
#[ink(event)] #[metis(erc777)] pub struct Transfer { #[ink(topic)] pub from: Option<AccountId>, #[ink(topic)] pub to: Option<AccountId>, pub value: Balance, }
#
ApprovalEvent emitted when an approval occurs that spender
is allowed to
withdraw up to the amount of value
tokens from owner
.
#[ink(event)] #[metis(erc777)] pub struct Approval { #[ink(topic)] pub owner: AccountId, #[ink(topic)] pub spender: AccountId, pub value: Balance, }
#
SentIndicate a send of amount
of tokens from the from
address to the to
address by the operator
address.
NOTE: This event MUST NOT be emitted outside of a send or an ERC-20 transfer process.
#[ink(event)] #[metis(erc777)] pub struct Sent { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub from: AccountId, #[ink(topic)] pub to: AccountId, pub amount: Balance, pub data: Vec<u8>, pub operator_data: Vec<u8>, }
#
MintedIndicate the minting of amount
of tokens to the to
address by
the operator
address.
NOTE: This event MUST NOT be emitted outside of a mint process.
#[ink(event)] #[metis(erc777)] pub struct Minted { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub to: AccountId, pub amount: Balance, pub data: Vec<u8>, pub operator_data: Vec<u8>, }
#
BurnedIndicate the burning of amount
of tokens from the from
address
by the operator
address.
NOTE: This event MUST NOT be emitted outside of a burn process.
#[ink(event)] #[metis(erc777)] pub struct Burned { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub from: AccountId, pub amount: Balance, pub data: Vec<u8>, pub operator_data: Vec<u8>, }
#
AuthorizedOperatorIndicates the authorization of operator
as an operator for holder
.
NOTE: This event MUST NOT be emitted outside of an operator authorization process.
#[ink(event)] #[metis(erc777)] pub struct AuthorizedOperator { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub token_holder: AccountId, }
#
RevokedOperatorIndicates the revocation of operator
as an operator for holder
.
NOTE: This event MUST NOT be emitted outside of an operator revocation process.
#[ink(event)] #[metis(erc777)] pub struct RevokedOperator { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub token_holder: AccountId, }
#
Usage ExampleTo make a new erc777-like token, we should import erc777 at first:
#[metis_lang::contract]pub mod erc777_contract { use super::super::behavior; pub use erc777::{ Error, Result, }; use metis_erc777 as erc777; use metis_lang::{ import, metis, };
#[ink(storage)] #[import(erc777)] pub struct Erc777 { erc777: erc777::Data<Erc777>, }
// Note: Now version of metis not support auto impl for erc777 #[cfg(not(feature = "ink-as-dependency"))] impl erc777::Impl<Erc777> for Erc777 {}}
Note: Now version of metis not support auto impl for erc777.
Should add:
#[cfg(not(feature = "ink-as-dependency"))] impl erc777::Impl<Erc777> for Erc777 {}
Then add the event for erc777:
/// Event emitted when a token transfer occurs. #[ink(event)] #[metis(erc777)] pub struct Transfer { #[ink(topic)] pub from: Option<AccountId>, #[ink(topic)] pub to: Option<AccountId>, pub value: Balance, }
/// Event emitted when an approval occurs that `spender` is allowed to withdraw /// up to the amount of `value` tokens from `owner`. #[ink(event)] #[metis(erc777)] pub struct Approval { #[ink(topic)] pub owner: AccountId, #[ink(topic)] pub spender: AccountId, pub value: Balance, }
/// Indicate a send of `amount` of tokens from the `from` address to the `to` /// address by the `operator` address. /// /// NOTE: This event MUST NOT be emitted outside of /// a send or an ERC-20 transfer process. #[ink(event)] #[metis(erc777)] pub struct Sent { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub from: AccountId, #[ink(topic)] pub to: AccountId, pub amount: Balance, pub data: Vec<u8>, pub operator_data: Vec<u8>, }
/// Indicate the minting of `amount` of tokens to the `to` address by /// the `operator` address. /// /// NOTE: This event MUST NOT be emitted outside of a mint process. #[ink(event)] #[metis(erc777)] pub struct Minted { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub to: AccountId, pub amount: Balance, pub data: Vec<u8>, pub operator_data: Vec<u8>, }
/// Indicate the burning of `amount` of tokens from the `from` address /// by the `operator` address. /// /// NOTE: This event MUST NOT be emitted outside of a burn process. #[ink(event)] #[metis(erc777)] pub struct Burned { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub from: AccountId, pub amount: Balance, pub data: Vec<u8>, pub operator_data: Vec<u8>, }
/// Indicates the authorization of `operator` as an operator for `holder`. /// /// NOTE: This event MUST NOT be emitted outside /// of an operator authorization process. #[ink(event)] #[metis(erc777)] pub struct AuthorizedOperator { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub token_holder: AccountId, }
/// Indicates the revocation of `operator` as an operator for `holder`. /// /// NOTE: This event MUST NOT be emitted outside /// of an operator revocation process. #[ink(event)] #[metis(erc777)] pub struct RevokedOperator { #[ink(topic)] pub operator: AccountId, #[ink(topic)] pub token_holder: AccountId, }
impl the constructor for contract:
impl Erc777 { #[ink(constructor)] pub fn new( name: String, symbol: String, decimals: u8, initial_supply: Balance, ) -> Self { let mut instance = Self { erc777: erc777::Data::new(), };
erc777::Impl::init(&mut instance, name, symbol, decimals, initial_supply);
// other logics instance } }
Then implement the messages for contract:
```rust impl Erc777 { /// Returns the name of the token. #[ink(message)] pub fn name(&self) -> String { erc777::Impl::name(self) }
/// Returns the symbol of the token, usually a shorter version of the name. #[ink(message)] pub fn symbol(&self) -> String { erc777::Impl::symbol(self) }
/// Returns the number of decimals used to get its user representation. /// For example, if `decimals` equals `2`, a balance of `505` tokens should /// be displayed to a user as `5,05` (`505 / 10 ** 2`). /// /// Tokens usually opt for a value of 18, imitating the relationship between /// Ether and Wei in ETH. This is the value `ERC20` uses, unless this function is /// overridden; /// /// NOTE: This information is only used for _display_ purposes: it in /// no way affects any of the arithmetic of the contract #[ink(message)] pub fn decimals(&self) -> u8 { erc777::Impl::decimals(self) }
/// 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. #[ink(message)] pub fn granularity(&self) -> Balance { erc777::Impl::granularity(self) }
/// Returns the amount of tokens in existence. #[ink(message)] pub fn total_supply(&self) -> Balance { erc777::Impl::total_supply(self) }
/// Returns the amount of tokens owned by `account`. #[ink(message)] pub fn balance_of(&self, owner: AccountId) -> Balance { erc777::Impl::balance_of(self, &owner) }
/// 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 /// `operator_data`. See `erc777_sender` and `erc777_recipient`. /// /// 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 the `erc777_recipient` interface. #[ink(message)] pub fn send( &mut self, recipient: AccountId, amount: Balance, data: Vec<u8>, ) -> Result<()> { erc777::Impl::send(self, recipient, amount, data) }
/// Moves `amount` tokens from the caller's account to `recipient`. /// /// Returns a boolean value indicating whether the operation succeeded. /// /// Emits a `Transfer` event. #[ink(message)] pub fn transfer(&mut self, to: AccountId, value: Balance) -> Result<()> { erc777::Impl::transfer(self, &to, value) }
/// 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 `operator_data`. See `erc777_sender`. /// /// Emits a `Burned` event. /// /// Requirements /// /// - the caller must have at least `amount` tokens. #[ink(message)] pub fn burn(&mut self, amount: Balance, data: Vec<u8>) -> Result<()> { erc777::Impl::burn(self, amount, data) }
/// Returns true if an account is an operator of `token_holder`. /// Operators can send and burn tokens on behalf of their owners. All /// accounts are their own operator. /// /// See `operator_send` and `operator_burn`. #[ink(message)] pub fn is_operator_for( &self, operator: AccountId, token_holder: AccountId, ) -> bool { erc777::Impl::is_operator_for(self, operator, token_holder) }
/// Make an account an operator of the caller. /// /// See `is_operator_for`. /// /// Emits an `AuthorizedOperator` event. /// /// Requirements /// /// - `operator` cannot be calling address. #[ink(message)] pub fn authorize_operator(&mut self, operator: AccountId) { erc777::Impl::authorize_operator(self, operator) }
/// Revoke an account's operator status for the caller. /// /// See `is_operator_for` and `default_operators`. /// /// Emits a `RevokedOperator` event. /// /// Requirements /// /// - `operator` cannot be calling address. #[ink(message)] pub fn revoke_operator(&mut self, operator: AccountId) { erc777::Impl::revoke_operator(self, operator) }
/// Returns the list of default operators. These accounts are operators /// for all token holders, even if `authorize_operator` was never called on /// them. /// /// This list is immutable, but individual holders may revoke these via /// `revoke_operator`, in which case `is_operator_for` will return false. #[ink(message)] pub fn default_operators(&self) -> Vec<AccountId> { erc777::Impl::default_operators(self) }
/// 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 /// `operator_data`. See `erc777_sender` and `erc777_recipient`. /// /// Emits a `Sent` event. /// /// Requirements /// /// - `sender` cannot be the zero address. /// - `sender` must have at least `amount` tokens. /// - the caller must be an operator for `sender`. /// - `recipient` cannot be the zero address. /// - if `recipient` is a contract, it must implement the `erc777_recipient` interface. #[ink(message)] pub fn operator_send( &mut self, sender: AccountId, recipient: AccountId, amount: Balance, data: Vec<u8>, operator_data: Vec<u8>, ) -> Result<()> { erc777::Impl::operator_send( self, sender, recipient, amount, data, operator_data, ) }
/// 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 `operator_data`. See `erc777_sender`. /// /// Emits a `Burned` event. /// /// Requirements /// /// - `account` cannot be the zero address. /// - `account` must have at least `amount` tokens. /// - the caller must be an operator for `account`. #[ink(message)] pub fn operator_burn( &mut self, account: AccountId, amount: Balance, data: Vec<u8>, operator_data: Vec<u8>, ) -> Result<()> { erc777::Impl::operator_burn(self, account, amount, data, operator_data) }
/// Returns the remaining number of tokens that `spender` will be /// allowed to spend on behalf of `owner` through `transfer_from`. This is /// zero by default. /// /// This value changes when `approve` or `transfer_from` are called. #[ink(message)] pub fn allowance(&self, owner: AccountId, spender: AccountId) -> Balance { erc777::Impl::allowance(self, &owner, &spender) }
/// Sets `amount` as the allowance of `spender` over the caller's tokens. /// /// Returns a boolean value indicating whether the operation succeeded. /// /// IMPORTANT: Beware that changing an allowance with this method brings the risk /// that someone may use both the old and the new allowance by unfortunate /// transaction ordering. One possible solution to mitigate this race /// condition is to first reduce the spender's allowance to 0 and set the /// desired value afterwards: /// <https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729> /// /// Emits an `Approval` event. #[ink(message)] pub fn approve(&mut self, spender: AccountId, value: Balance) -> Result<()> { erc777::Impl::approve(self, &spender, value) }
/// Moves `amount` tokens from `sender` to `recipient` using the /// allowance mechanism. `amount` is then deducted from the caller's /// allowance. /// /// Returns a boolean value indicating whether the operation succeeded. /// /// Emits a `Transfer` event. #[ink(message)] pub fn transfer_from( &mut self, from: AccountId, to: AccountId, value: Balance, ) -> Result<()> { erc777::Impl::transfer_from(self, &from, &to, value) }
/// 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 `operator_data`. /// /// See `erc777_sender` and `erc777_recipient`. /// /// Emits `Minted` and `Transfer` events. /// /// Requirements /// /// - `account` cannot be the zero address. /// - if `account` is a contract, it must implement the `erc777_recipient` interface. #[ink(message)] pub fn mint(&mut self, to: AccountId, value: Balance) -> Result<()> { erc777::Impl::_mint(self, to, value, Vec::default(), Vec::default()) } }
In the end, we can add some other messages.