Skip to main content

Token Registry Program

Overview

The Token Registry Program is a standard program designed for issuing and managing new tokens on the Aleo blockchain. It operates as a singleton program because on Aleo, all imported programs must be known and deployed before the importing program, and dynamic cross-program calls are not currently supported which makes composability difficult to implement. This means that a DeFi program must be compiled with support for all token programs that it will ever interact with. If a new token program is subsequently deployed on-chain, the DeFi program will need to be re-compiled and redeployed on chain in order to interact with that token.

In the near-term, support for program upgradability will resolve this but currently, the issue is circumvented by means of the token registry which can manage balances for many different ARC-20 tokens. This program would be the standard "hub" that all tokens and DeFi programs interface with. Individual ARC-20 tokens can register with the registry and mint new tokens via this program. Transfers of token value will occur by direct call to the registry rather than the ARC-20 program itself. The benefit of this approach is that DeFi programs do not need to be compiled with any special knowledge of individual ARC-20 tokens: their sole dependency will be the registry. Hence the deployment of new tokens does not require re-deployment of DeFi programs. Similarly, individual ARC-20 tokens can also be compiled with dependence on the registry, but no dependence on the DeFi programs. The registry thus allows interoperability between new tokens and DeFi programs, with no need for program re-deployment. As a secondary benefit, the registry will provide privacy benefits (via an improved anonymity set) because all private transfers within the registry will conceal the identity of the specific token being transferred.

This standard is emerged from extensive discussions and the approval of the ARC-21 proposal to enable token interoperability across different applications.

This documentation outlines the functions of the Token Registry Program and provides guidance on how to use it. The original source code can be found here.

How to use the Token Registry Program

Anyone can create a new token on Aleo using the token_registry.aleo program by calling the register_token transition with a unique token ID and specifying any name, symbol, decimals, and maximum supply. An optional external_authorization_required boolean grants extra control over token available to spend by requiring extra approval from an external_authorization_party, the external_authorization_party can unlocks certain amount of balances for spending with expiration over a specific owner's token using prehook_public or prehook_private. The admin can also set external_authorization_party to another address with update_token_management later if needed.

Once a token is registered, the tokens can be minted either publicly using mint_public or privately to a specific recipient using mint_private with roles MINTER_ROLE or SUPPLY_MANAGER_ROLE if not admin. The tokens can also be burned either publicly with burn_public or privately with burn_private with roles BURNER_ROLE or SUPPLY_MANAGER_ROLE if not admin.

The token owner then can transfer the token either publicly using transfer_public or privately to a specific recipient using transfer_private. The token can also be converted from public to private using transfer_public_to_private or from private to public using transfer_private_to_public.

For an example of how the flow works, please refer to the Usage Example with Token Registry Program.

Token Registry Program Data Structures

Token Record

  record Token {
owner: address,
amount: u128,
token_id: field,
external_authorization_required: bool,
authorized_until: u32
}

Token Record Fields

  • owner: The address of the token owner.
  • amount: The amount of tokens in the account.
  • token_id: The unique identifier for the token.
  • external_authorization_required: Whether or not the token requires external authorization.
  • authorized_until: The block height until which the token is authorized.

Token Metadata Struct

  struct TokenMetadata {
token_id: field,
name: u128, // ASCII text represented in bits, and the u128 value of the bitstring
symbol: u128, // ASCII text represented in bits, and the u128 value of the bitstring
decimals: u8,
supply: u128,
max_supply: u128,
admin: address,
external_authorization_required: bool, // whether or not this token requires authorization from an external program before transferring
external_authorization_party: address
}

Token Metadata Struct Fields

  • token_id: The unique identifier for the token.
  • name: The name of the token.
  • symbol: The symbol of the token.
  • decimals: The number of decimals for the token.
  • supply: The total supply of the token.
  • max_supply: The maximum supply of the token.
  • admin: The address of the token admin.
  • external_authorization_required: Whether or not the token requires external authorization.
  • external_authorization_party: The address of the external authorization party.

Token Owner Struct

  struct TokenOwner {
account: address,
token_id: field
}

Token Owner Struct Fields

  • account: The address of the token owner.
  • token_id: The unique identifier for the token.

Balance Struct

  struct Balance {
token_id: field,
account: address,
balance: u128,
authorized_until: u32
}

Balance Struct Fields

  • token_id: The unique identifier for the token.
  • account: The address of the token owner.
  • balance: The balance of the token.
  • authorized_until: The block height until which the token is authorized.

Allowance Struct

  struct Allowance {
account: address,
spender: address,
token_id: field
}

Allowance Struct Fields

  • account: The address of the token owner.
  • spender: The address of the spender.
  • token_id: The unique identifier for the token.

Token Registry Program Mappings

mapping registered_tokens: field => TokenMetadata;
Mapping of token IDs to token metadata structs.

mapping balances: field => Balance;
Mapping of the hash of the token ID and the account address to the balance struct.

mapping allowances: field => Allowance;
Mapping of the hash of the token ID, the account address, and the spender address to the allowance struct.

mapping roles: field => u8;
Mapping of the hash of the token ID and the account address to the role.

Token Registry Program Constants

const CREDITS_RESERVED_TOKEN_ID: field = 3443843282313283355522573239085696902919850365217539366784739393210722344986field;
Token ID reserved for the ALEO token.

const MINTER_ROLE: u8 = 1u8;
Role for the minter.

const BURNER_ROLE: u8 = 2u8;
Role for the burner.

const SUPPLY_MANAGER_ROLE: u8 = 3u8;
Role for the supply manager.

Token Registry Program Functions

The Token Registry Program includes the following functions:

initialize()

Description

Initializes the Token Registry Program by registering the ALEO token with predefined metadata. The token is initialized with a specific token ID, name "credits", symbol "credits", 6 decimals, and a max supply of 10 quadrillion. The program sets itself (wrapped_credits.aleo) as the admin and disables external authorization requirements to ensure the token metadata cannot be modified after initialization.

Parameters

Parameters are hardcoded in program to safeguard against frontrunning.

Returns

None.

register_token()

Description

Registers a new token with the Token Registry Program.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public name: u128: The name of the token.
  • public symbol: u128: The symbol of the token.
  • public decimals: u8: The number of decimals for the token.
  • public max_supply: u128: The maximum supply of the token.
  • public external_authorization_required: bool: Whether or not the token requires external authorization.
  • public external_authorization_party: address: The address of the external authorization party.

Returns

  • Future: A Future to finalize the token registration.

update_token_management()

Description

Updates the token management settings.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public admin: address: The address of the admin.
  • public external_authorization_party: address: The address of the external authorization party.

Returns

  • Future: A Future to finalize the token management update.

set_role()

Description

Sets the role for a specific token ID.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public account: address: The address of the account.
  • public role: u8: The role to set.

Returns

  • Future: A Future to finalize the role set.

remove_role()

Description

Removes the role for a specific token ID.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public account: address: The address of the account.

Returns

  • Future: A Future to finalize the role removal.

mint_public()

Description

Mints a new token publicly by the specific token ID's admin.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public recipient: address: The address of the recipient.
  • public amount: u128: The amount of tokens to mint.
  • public authorized_until: u32: The block height until which the token is authorized.

Returns

  • Future: A Future to finalize the mint.

mint_private()

Description

Mints a new token privately by the specific token ID's admin.

Parameters

  • public token_id: field: The unique identifier for the token.
  • recipient: address: The address of the recipient that is not visible to the public.
  • public amount: u128: The amount of tokens to mint.
  • public external_authorization_required: bool: Whether or not the token requires external authorization.
  • public authorized_until: u32: The block height until which the token is authorized.

Returns

  • Token: The token record.
  • Future: A Future to finalize the mint.

burn_public()

Description

Burns a token publicly by the specific token ID's admin.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public owner: address: The address of the owner.
  • public amount: u128: The amount of tokens to burn.

Returns

  • Future: A Future to finalize the burn.

burn_private()

Description

Burns a token privately by the specific token ID's admin.

Parameters

  • input_record: Token: The token record.
  • public amount: u128: The amount of tokens to burn.

Returns

  • Token: The token record with remaining balance.
  • Future: A Future to finalize the burn.

prehook_public()

Description

A function for the authorized party to modify authorized amount and new expiration publicly.

Parameters

  • public owner: address: The address of the owner.
  • public amount: u128: The amount of tokens to prehook.
  • public authorized_until: u32: The block height until which the token is authorized.

Returns

  • Future: A Future to finalize the prehook.

prehook_private()

Description

A function for the authorized party to modify authorized amount and new expiration privately.

Parameters

  • input_record: Token: The token record.
  • amount: u128: The amount of tokens to prehook.
  • authorized_until: u32: The block height until which the token is authorized.

Returns

  • Token: The unauthorized token record.
  • Token: The authorized token record.
  • Future: A Future to finalize the prehook.

transfer_public()

Description

Transfers a token publicly by the token owner.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public recipient: address: The address of the recipient.
  • public amount: u128: The amount of tokens to transfer.

Returns

  • Future: A Future to finalize the transfer.

transfer_public_as_signer()

Description

Transfers a token publicly by the token owner as the transaction signer in any arbitrary program calls.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public recipient: address: The address of the recipient.
  • public amount: u128: The amount of tokens to transfer.

Returns

  • Future: A Future to finalize the transfer.

approve_public()

Description

Approves a token for a spender to be able to transfer the token on behalf of the owner.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public spender: address: The address of the spender.
  • public amount: u128: The amount of tokens to approve.

Returns

  • Future: A Future to finalize the approval.

unapprove_public()

Description

Revokes or reduces the approval for a spender to transfer the token on behalf of the owner.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public spender: address: The address of the spender.
  • public amount: u128: The amount of tokens to unapprove.

Returns

  • Future: A Future to finalize the unapproval.

transfer_from_public()

Description

Transfers a token from the owner to the recipient after getting approval from the owner.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public owner: address: The address of the owner.
  • public recipient: address: The address of the recipient.
  • public amount: u128: The amount of tokens to transfer.

Returns

  • Future: A Future to finalize the transfer.

transfer_public_to_private()

Description

Convert public token to private token by its owner.

Parameters

  • public token_id: field: The unique identifier for the token.
  • recipient: address: The address of the recipient that is not visible to the public.
  • public amount: u128: The amount of tokens to transfer.
  • public external_authorization_required: bool: Whether or not the token requires external authorization.

Returns

  • Token: The token record.
  • Future: A Future to finalize the transfer.

transfer_from_public_to_private()

Description

Convert public token to private token on behalf of the token owner after getting approval from the owner.

Parameters

  • public token_id: field: The unique identifier for the token.
  • public owner: address: The address of the owner.
  • recipient: address: The address of the recipient that is not visible to the public.
  • public amount: u128: The amount of tokens to transfer.
  • public external_authorization_required: bool: Whether or not the token requires external authorization.

Returns

  • Token: The token record.
  • Future: A Future to finalize the transfer.

transfer_private()

Description

Transfers a token privately by the token owner.

Parameters

  • recipient: address: The address of the recipient that is not visible to the public.
  • amount: u128: The amount of tokens to transfer.
  • input_record: Token: The token record.

Returns

  • Token: The remaining token record.
  • Token: The receiving token record.
  • Future: A Future to finalize the transfer.

transfer_private_to_public()

Description

Convert private token to public token by the token owner.

Parameters

  • public recipient: address: The address of the recipient that is visible to the public.
  • public amount: u128: The amount of tokens to transfer.
  • input_record: Token: The token record.

Returns

  • Token: The remaining token record.
  • Future: A Future to finalize the transfer.

join()

Description

Joins two private token records and become one single record. Does not change the total amount of the tokens.

Parameters

  • private token_1: Token: The first token record.
  • private token_2: Token: The second token record.

Returns

  • Token: The joined token record.

split()

Description

Splits a private token record into two new token records. Does not change the total amount of the tokens.

Parameters

  • private token: Token: The token record.
  • private amount: u128: The amount of tokens to split.

Returns

  • Token: The splitted token record.
  • Token: The remaining token record.