Closed sampajotphipps closed 5 years ago
Tangential discussion, can we simply rename this to directly track the issue number? It doesnt make sense for us to arbitrarily add or subtract numbers, if we follow the issue number everyone understands why its numbered such, and you can directly reference it as so: #04.
@qoire Good point. I've made the change.
In the part where you discuss ATSTokenRecipient and tokensReceived hook, you have this line
"The following rules apply when calling the tokensToSend hook: "
I think it should be tokensReceived instead of tokensToSend, right?
I think that it would be beneficial to include a Created event so that third parties would be able to monitor tokens that may be deployed on the network.
@nakakaka9
I think it should be tokensReceived instead of tokensToSend, right?
Yes you are right, good catch.
@dev-dennis-guye
I think that it would be beneficial to include a Created event so that third parties would be able to monitor tokens that may be deployed on the network.
Our plan is to include this in the token registry. Whenever there is a change in the contract interface, an event must be emitted to broadcast the new interface (see ERC-820).
FINAL CALL - For comments, feedback and suggestions.
Had some comments internally regarding some confusion for granularity
: This parameter only applies when we are talking about the smallest divisible unit of the token. For example a token with a granularity of 10
means that it could only increment or decrement by (in the smallest unit) 10^-17.
Likewise a token with a granularity of 10^18 could only increment or decrement by 1. The precision of the underlying value is always assumed to be 10^18 is always and will always be 10^18. See section Risks & Assumptions
for more details
Changing status to Accepted. (References to implementations in both Java and Solidity are included.)
Title: Aion Token Standard Author(s): Sam Pajot-Phipps, Yao Sun, Stephane Gosselin Type: ASC (Aion Standards and Conventions) Status: Accepted Creation Date: September 12th, 2018 Contact Information: sam@aion.network, qoire@protonmail.com, s.gosselin@queensu.ca
Summary
A fungible token standard to meet the functionality requirements of current dApp developers and enable cross-chain token movements.
Value Proposition
To enable the creation and management of innovative fungible cross-chain digital assets on the Aion blockchain and other connected networks.
Motivation
The primary motivation for the proposal is to provide the dApp's that are building on the Aion blockchain with a common standard to implement fungible tokens while enabling cross-chain functionality for their asset with minimal effort. The secondary motivation is to define the required contract interfaces and events to communicate with bridges and identify any upgrade requirements for current token standards on remote blockchains to allow communication with bridges.
Non-Goals
The scope of this standard is limited to on-chain functionality for fungible tokens. This standard does not address how cross-chain token movements should be reflected on third party services or tools such as blockchain explorers, wallets or exchanges.
Success Metrics
There are two key indicators of success for this standard: 1) Number of contract deployments 2) Number of deployed contracts with defined operators for cross-chain movements
Description
Fungible tokens have proven to be one of the core building blocks of the current decentralized web era. This next-generation fungible token standard reflects the evolving needs of dApp developers for core functionality and security.
The Aion Fungible Token Standard has been designed to address the shortcomings of token standards on other existing blockchains by blurring the line between layer one and layer two. At the core of the design is the ability to perform cross chain token transfers while maintaining security and stable total supply. Additional features include safe transfers, token callbacks, and mint/burn interface.
This standard aims to provide a reliable interface which 3rd party tools can use when building products on top of Aion.
High-Level Architecture
This diagram provides a high-level overview of the proposed contract architecture related to fungible tokens to enable cross-chain movements and communicate with bridges.
Note: The scope of this AIP is limited to the ATS contract highlighted. In the diagram below the Aion blockchain is the Home chain.
Specification
Definitions
bridgeId
, Bridge Contracts andnetworkId
Methods
General
The
constant
functions detailed below MUST be implemented.name
functionReturns the name of the token, e.g.,
"MyToken"
.symbol
functionReturns the symbol of the token, e.g.,
"MYT"
.totalSupply
functionGet the total number of minted tokens across all chains.
balanceOf
functionGet the balance of the account with address
tokenHolder
on Home chain.NOTE:
balanceOf(address(this))
is the frozen token supply and MUST be equal tototalSupply
minusliquidSupply
.NOTE: The balance MUST be zero (
0
) or higher.granularity
functionGet the smallest part of the token that's not divisible.
In other words, the granularity is the smallest number of tokens (in the basic unit) which MAY be minted, sent, burned, frozen, or thawed in any transaction.
The following rules MUST be applied regarding the granularity:
1
.revert
.NOTE: Most of the tokens SHOULD have a granularity of
1
unless there is a good reason for not allowing divisibility of the token.Operators
An
operator
is an address which is allowed to send, burn and freeze tokens on behalf of another address.The following rules apply to any operator:
isOperatorFor
MUST returntrue
.isOperatorFor
MUST returnfalse
.AuthorizedOperator
event with the correct values when a token holder authorizes an address as its operator as defined in the [AuthorizedOperator
Event][authorizedoperator].RevokedOperator
event with the correct values when a token holder revokes an address as its operator as defined in the [RevokedOperator
Event][revokedoperator].NOTE: A token holder MAY have multiple operators at the same time.
NOTE: A token holder MAY authorize an already authorized operator. An
AuthorizedOperator
MUST be emitted each time.NOTE: A token holder MAY revoke an already revoked operator. A
RevokedOperator
MUST be emitted each time.AuthorizedOperator
eventIndicates the authorization of
operator
as an operator fortokenHolder
.NOTE: This event MUST NOT be emitted outside of an operator authorization process.
RevokedOperator
eventIndicates the revocation of
operator
as an operator fortokenHolder
.NOTE: This event MUST NOT be emitted outside of an operator revocation process.
The
authorizeOperator
,revokeOperator
andisOperatorFor
functions described below MUST be implemented to manage operators. Token contracts MAY implement other functions to manage operators.authorizeOperator
functionSet a third party
operator
address as an operator ofmsg.sender
to send, burn or freeze tokens on its behalf.NOTE: The token holder (
msg.sender
) is always an operator for itself. This right MUST NOT be revoked. This function MUSTrevert
if it is called to authorize the token holder (msg.sender
) as an operator for itself (i.e. ifoperator
is equal tomsg.sender
).revokeOperator
functionRemove the right of the
operator
address to be an operator formsg.sender
and to send, burn or freeze tokens on its behalf.NOTE: The token holder (
msg.sender
) is always an operator for itself. This right MUST NOT be revoked. This function MUSTrevert
if it is called to revoke the token holder (msg.sender
) as an operator for itself (i.e., ifoperator
is equal tomsg.sender
).isOperatorFor
functionIndicate whether the
operator
address is an operator of thetokenHolder
address.Cross Chain Movements
liquidSupply
functionIndicate the total supply of tokens currently in circulation on this chain.
NOTE: The liquid supply MUST be equal to
totalSupply
minusbalanceOf(address(this))
.NOTE: The liquid supply MUST be equal to the sum of the balances of all addresses other than
address(this)
as returned by thebalanceOf
function.thaw
function[WIP: Define bridge registry interface]
Called by bridge contract through the bridge registry when tokens moved from remote chain.
NOTE: MUST emit
Thawed
event.NOTE: MUST revert if called from an address not associated registered with bridgeId in bridge registry.
NOTE: MUST revert if called from bridgeId not approved in bridge registry.
Thawed
eventIndicate a thaw of
amount
of tokens from thefrom
address on remote chain to theto
address on home chain.freeze
function[WIP: Define bridge registry interface]
Called by a token holder to move tokens to remote chain.
NOTE: MUST emit
Froze
event.NOTE: MUST revert if bridgeId not approved in bridge registry.
operatorFreeze
function[WIP: Define bridge registry interface]
Called by an operator to move tokens to remote chain on behalf of token holder.
NOTE: MUST emit
Froze
event.NOTE: MUST revert if bridgeId not approved in bridge registry.
Froze
eventIndicate a freeze of
amount
of tokens from thefrom
address on home chain to theto
address on remote chain.Sending Tokens
When an operator sends an
amount
of tokens from a token holder to a recipient with the associateddata
andoperatorData
, the token contract MUST apply the following rules:amount
.amount
.amount
—such that its resulting balance is greater or equal to zero (0
) after the send.Sent
event with the correct values as defined in the [Sent
Event][sent].operatorData
.tokensToSend
hook of the token holder if the token holder registers anATSTokenSender
implementation via [ERC820].tokensReceived
hook of the recipient if the recipient registers anATSTokenRecipient
implementation via [ERC820].data
andoperatorData
MUST be immutable during the entire send process—hence the samedata
andoperatorData
MUST be used to call both hooks and emit theSent
event.The token contract MUST
revert
when sending in any of the following cases:0x0
.0
).The token contract MAY send tokens from many token holders, to many recipients, or both. In this case:
amount
.amount
.Sent
event MUST be emitted for every token holder and recipient pair with the corresponding amount for each pair.Sent
event MUST be equal to the total sentamount
.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: Transfer of tokens MAY be chained. For example, if a contract upon receiving tokens sends them further to another address. In this case, the previous send rules apply to each send, in order.
NOTE: Sending an amount of zero (
0
) tokens is valid and MUST be treated as a regular send.Implementation Requirement:
tokensToSend
hook before updating the state.tokensReceived
hook after updating the state.I.e.,
tokensToSend
MUST be called first, then the balances MUST be updated to reflect the send, and finallytokensReceived
MUST be called afterward. Thus abalanceOf
call withintokensToSend
returns the balance of the address before the send and abalanceOf
call withintokensReceived
returns the balance of the address after the send.NOTE: The
data
field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically,data
is used to describe the intent behind the send. TheoperatorData
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 theoperatorData
, or at most, it would log theoperatorData
.Sent
eventIndicate a send of
amount
of tokens from thefrom
address to theto
address by theoperator
address.NOTE: This event MUST NOT be emitted outside of a send or an [ERC20] transfer process.
The
send
andoperatorSend
functions described below MUST be implemented to send tokens. Token contracts MAY implement other functions to send tokens.NOTE: An address MAY send an amount of
0
, which is valid and MUST be treated as a regular send.send
functionSend the
amount
of tokens from the addressmsg.sender
to the addressto
.The operator and the token holder MUST both be the
msg.sender
.operatorSend
functionSend the
amount
of tokens on behalf of the addressfrom
to the addressto
.The operator MUST be
msg.sender
. The value offrom
MAY be0x0
, then thefrom
(token holder) used for the send MUST bemsg.sender
(theoperator
).Reminder: If the operator address is not an authorized operator of the
from
address, then the send process MUSTrevert
.NOTE:
from
andmsg.sender
MAY be the same address. I.e., an address MAY calloperatorSend
for itself. This call MUST be equivalent tosend
with the addition that the operator MAY specify an explicit value foroperatorData
(which cannot be done with thesend
function).Minting Tokens
Minting tokens is the act of producing new tokens. This standard intentionally does not define specific functions to mint tokens. This intent comes from the wish not to limit the use of the standard as the minting process is generally an implementation detail.
Nonetheless, the rules below MUST be respected when minting for a recipient:
totalSupply
remains equal on all chains.address(this)
when minting is initiated on other chain such that the correctliquidSupply
is maintained.0x0
MUST NOT be decreased.Minted
event with the correct values as defined in the [Minted
Event][minted].tokensReceived
hook of the recipient if the recipient registers anATSTokenRecipient
implementation via [ERC820].data
andoperatorData
MUST be immutable during the entire mint process—hence the samedata
andoperatorData
MUST be used to call thetokensReceived
hook and emit theMinted
event.The token contract MUST
revert
when minting in any of the following cases:ATSTokenRecipient
interface via [ERC820].0x0
.NOTE: 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 (or addresses) receiving the initial supply.
The token contract MAY mint tokens for multiple recipients at once. In this case:
Minted
event MUST be emitted for every recipient with the corresponding amount for each recipient.Minted
event MUST be equal to the total mintedamount
.NOTE: Minting an amount of zero (
0
) tokens is valid and MUST be treated as a regular mint.NOTE: The
data
field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically,data
is used to describe the intent behind the mint. TheoperatorData
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 theoperatorData
, or at most, it would log theoperatorData
.Minted
eventIndicate the minting of
amount
of tokens to theto
address by theoperator
address.NOTE: This event MUST NOT be emitted outside of a mint process.
Burning Tokens
Burning tokens is the act of destroying existing tokens. ATS explicitly defines two functions to burn tokens (
burn
andoperatorBurn
). These functions facilitate the integration of the burning process in wallets and dapps. However, the token contract MAY prevent some or all token holders from burning tokens for any reason. The token contract MAY also define other functions to burn tokens.The rules below MUST be respected when burning the tokens of a token holder:
totalSupply
remains equal on all chains.address(this)
when burned is initiated on other chain such that the correctliquidSupply
is maintained.0x0
MUST NOT be increased.Burned
event with the correct values as defined in the [Burned
Event][burned].tokensToSend
hook of the token holder if the token holder registers anATSTokenSender
implementation via [ERC820].operatorData
MUST be immutable during the entire burn process—hence the sameoperatorData
MUST be used to call thetokensToSend
hook and emit theBurned
event.data
field of thetokensToSend
hook MUST be empty.The token contract MUST
revert
when burning in any of the following cases:0x0
.The token contract MAY burn tokens for multiple token holders at once. In this case:
Burned
event MUST be emitted for every token holder with the corresponding amount for each token holder.Burned
event MUST be equal to the total burnedamount
.NOTE: Burning an amount of zero (
0
) tokens is valid and MUST be treated as a regular burn.Burned
eventIndicate the burning of
amount
of tokens from thefrom
address by theoperator
address.NOTE: This event MUST NOT be emitted outside of a burn process.
The
burn
andoperatorBurn
functions described below MUST be implemented to burn tokens. Token contracts MAY implement other functions to burn tokens.burn
functionBurn the
amount
of tokens from the addressmsg.sender
.The operator and the token holder MUST both be the
msg.sender
.operatorBurn
functionBurn the
amount
of tokens on behalf of the addressfrom
.The operator MUST be
msg.sender
. The value offrom
MAY be0x0
, then thefrom
(token holder) used for the burn MUST bemsg.sender
(theoperator
).Reminder: If the operator address is not an authorized operator of the
from
address, then the burn process MUSTrevert
.NOTE: The operator MAY pass any information via
operatorData
. TheoperatorData
MUST only be provided by the operator.NOTE:
from
andmsg.sender
MAY be the same address. I.e., an address MAY calloperatorBurn
for itself. This call MUST be equivalent toburn
with the addition that the operator MAY specify an explicit value foroperatorData
(which cannot be done with theburn
function).ATSTokenSender
And ThetokensToSend
HookThe
tokensToSend
hook notifies of any decrement of balance (send and burn) for a given token holder. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing theATSTokenSender
interface described below via [ERC820].NOTE: A regular address MAY register a different address 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.
tokensToSend
Notify a send or burn (if
to
is0x0
) ofamount
tokens from thefrom
address to theto
address by theoperator
address.NOTE: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process.
The following rules apply when calling the
tokensToSend
hook:tokensToSend
hook MUST be called every time the balance is decremented.tokensToSend
hook MUST be called before the state is updated—i.e. before the balance is decremented.operator
MUST be the address which triggered the decrease of the balance.from
MUST be the address of the token holder whose balance is decreased.to
MUST be the address of the recipient whose balance is increased for a send.to
MUST be0x0
for a burn.amount
MUST be the number of tokens the token holder balance is decreased by.data
MUST contain the extra information provided by the token holder (if any) for a send.data
MUST be empty for a burn.operatorData
MUST contain the extra information provided by the address which triggered the decrease of the balance (if any).revert
ing. (I.e., reject the withdrawal of tokens from its account.)NOTE: Multiple token holders MAY use the same implementation of
ATSTokenSender
.NOTE: An address can register at most one implementation at any given time for all tokens. Hence the
ATSTokenSender
MUST expect to be called by different token contracts. Themsg.sender
of thetokensToSend
call is expected to be the address of the token contract.ATSTokenRecipient
And ThetokensReceived
HookThe
tokensReceived
hook notifies of any increment of the balance (send and mint) for a given recipient. Any address (regular or contract) wishing to be notified of token credits to their address MAY register the address of a contract implementing theATSTokenSender
interface described below via [ERC820].If the recipient is a contract, which has not registered an
ATSTokenRecipient
implementation; the token contract:revert
if thetokensReceived
hook is called from a mint or send call.tokensReceived
hook is called from an ERC20transfer
ortransferFrom
call.NOTE: A regular address MAY register a different address—the address of a contract—implementing the interface on its behalf. A contract MUST register either its address or the address of another contract and said address MUST implement the interface on its behalf.
tokensReceived
Notify a send or mint (if
from
is0x0
) ofamount
tokens from thefrom
address to theto
address by theoperator
address.NOTE: This function MUST NOT be called outside of a mint, send or [ERC20] transfer process.
The following rules apply when calling the
tokensToSend
hook:The
tokensReceived
hook MUST be called every time the balance is incremented.The
tokensReceived
hook MUST be called after the state is updated—i.e. after the balance is incremented.operator
MUST be the address which triggered the increase of the balance.from
MUST be the address of the token holder whose balance is decreased for a send.from
MUST be0x0
for a mint.to
MUST be the address of the recipient whose balance is increased.amount
MUST be the number of tokens the recipient balance is increased by.operatorData
MUST contain the extra information provided by the address which triggered the increase of the balance (if any).The token holder MAY block an increase of its balance by
revert
ing. (I.e., reject the reception of tokens.)NOTE: Multiple token holders MAY use the same implementation of
ATSTokenRecipient
.NOTE: An address can register at most one implementation at any given time for all tokens. Hence the
ATSTokenRecipient
MUST expect to be called by different token contracts. Themsg.sender
of thetokensReceived
call is expected to be the address of the token contract.Solidity Interface
Logic
This standard is based on ERC-777 from Ethereum. The following modifications have been made for additional functionality.
defaultOperators
removed to guarantee operators are always opt-in.liquidSupply()
,thaw()
,freeze()
,operatorFreeze()
functions added for cross chain transfers.burn()
,operatorBurn()
functions added for applications using slashing.Interface Registration
[WIP: Define token registry]
Cross Chain Functionality
[WIP: Define bridge registry interface]
Cross-chain token transfers implies the total supply of a token is potentially shared across a number of distinct blockchains. This total supply must be invariant across all chains, as such if tokens are minted or burned on one chain, the equivalent must be done on other chains. Our approach introduces a distinction between
totalSupply
andliquidSupply
wheretotalSupply
represents the sum of liquid tokens across all chains andliquidSupply
represents the sum of liquid tokens on the home chain. As such,totalSupply
minusliquidSupply
is the sum of tokens which are used on other chains and therefore currently frozen on the home chain. This frozen balance is held in the ATS contract and is equal tobalanceOf(address(this))
.To send a cross chain token transfer from the home chain to the remote chain, the sender must freeze the token on home chain and specify the remote chain and remote token receiver address using the
freeze
oroperatorFreeze
functions. The Bridge Contract then relays the transaction to the destination chain and thaws the appropriate token amount.To send a cross chain token transfer from a remote chain to home chain, the sender must first freeze their remote tokens by sending them to the storage contract and emitting an event which specifies the destination address on the home chain and the Bridge Contract to use. The Bridge Contract then relays the transaction to the home chain and calls the
thaw
function.NOTE: An ATS token contract must register an approved Bridge Contract by calling
setPermission(bytes32 bridgeId, bool status)
in the Bridge Registry. [WIP: review security implication for async permission changes between chains]Risks & Assumptions
This standard is natively compatible with the ERC-777 standard from Ethereum and can be made compatible with the ERC-20 standard as an implementation detail.
[ERC20] compatibility notes:
The decimals of the token MUST always be
18
. For a pure ATS token the [ERC20]decimal
function is OPTIONAL, and its existence MUST NOT be relied upon when interacting with the token contract. (The decimal value of18
is implied.) For an [ERC20] compatible token, thedecimal
function is REQUIRED and MUST return18
. (In [ERC20], thedecimals
function is OPTIONAL, but if the value of the function is not present, it is not clearly defined and may be assumed to be0
. Hence for compatibility reasons,decimals
MUST be implemented for [ERC20] compatible tokens.)The
name
,symbol
,totalSupply
, andbalanceOf
constant
functions MUST be backward compatible with [ERC20].While a
Sent
event MUST NOT be emitted when minting or burning, if the token contract is [ERC20] backward compatible, aTransfer
event with thefrom
orto
parameter set to0x0
SHOULD be emitted. The [ERC20] standard does not define the concept of burning tokens, but this is a commonly accepted practice.The
tokensToSend
andtokensReceived
hook takes precedence over [ERC20] and MUST be called (if registered) when calling [ERC20]'stransfer
andtransferFrom
event. When called from atransfer
,operator
MUST be the same value as thefrom
. When called from atransferFrom
,operator
MUST be the address which issued thetransferFrom
call.Test Cases
N/A
Implementations
Reference Implementation
Dependencies
The implementation of the Bridge Registry standard is a dependency to enable cross-chain movements. The Bridge Registry will be a new AIP.
The implementation of the Bridge Contract standard is a dependency to enable cross-chain movements. The Bridge Operator will be a new AIP.
The implementation of the Token Registry standard will be proposed as a new AIP.
Copyright
All AIP’s are public domain. Copyright waiver: https://creativecommons.org/publicdomain/zero/1.0/