Create and Manage a Non-Fungible ASA from the Command Line Using goal
The tutorial is divided into two main phases:
- Non-fungible ASA creation
- ASA management configuration
In the first phase, you will learn the meaning of Algorand Standard Asset properties, like: total supply, decimals, unit name and so on. We will write down the genesis transaction containing all the properties that best fit our non-fungible ASA’s needs.
In the second phase, you will understand the role of management addresses like the freeze address or the clawback address, learning how to configure your ASA management scheme.
Requirements
Steps
- 1. Introduction
- 2. Explore ./goal asset create
- 3. ASA Property: name
- 4. ASA Property: unitname
- 5. ASA Property: decimals
- 6. ASA Property: total
- 7. ASA Property: asseturl
- 8. ASA Property: creator
- 9. Asset Create Transaction
- 10. Asset ID
- 11. ASA Management Configuration
- 12. ASA Management
- 13. Asset Config Transaction
- 14. Asset Destroy Transaction
- 15. Conclusion
1. Introduction
The aim of this tutorial is understanding Algorand Standard Asset (ASA) properties and getting familiar both with their creation process and management configuration from the CLI using the goal
utility.
Taking a real use-case may help us to better understand how to choose ASA properties that best fit our needs, so we suppose someone assigned us the following requirement:
- Create two non-fungible tokens representing the digitalization of delicious typical foods from Puglia and Brazil, namely a “Panzerotto” and a “Coxinha”.
We will go through each step together to set up the properties of the required non-fungible ASAs. By completing this beginner tutorial you will be able to create a unique digital representation of a “Panzerotto” or a “Coxinha” (whatever you like the most) and any other non-fungible ASA you want.
I’ll be very happy to see “Panzerotto” ASA or “Coxinha” ASA spreading around Algorand, both because I go crazy for them and because it is proof that the tutorial has been able to effectively teach you how to accomplish this task.
Let’s go!
Learn More
- Algorand Standard Asset
2. Explore ./goal asset create
Algorand Standard Assets are shaped by different properties that can make them suitable for different use-cases. Defining these properties allows us to decide, for example, if the ASA will be scarce or not, divisible into submultiples and so on.
First thing to do when we don’t know how to proceed in the CLI? Ask for help! goal
has a wide set of commands. Since we want to create an asset, we should ask for help on the specific goal asset
command, typing:
Input
$ ./goal asset --help
Output
Manage assets
Usage:
goal asset [flags]
goal asset [command]
Available Commands:
config Configure an asset
create Create an asset
destroy Destroy an asset
freeze Freeze assets
info Look up current parameters for an asset
send Transfer assets
Flags:
-h, --help help for asset
-w, --wallet string Set the wallet to be used for the selected operation
Global Flags:
-d, --datadir stringArray Data directory for the node
-k, --kmddir string Data directory for kmd
Use "goal asset [command] --help" for more information about a command.
As you can guess we will focus on the goal asset create
command, so:
Input
$ ./goal asset create --help
Output
Post a transaction declaring and issuing a new layer-one asset on the network.
Usage:
goal asset create [flags]
Flags:
--assetmetadatab64 string base-64 encoded 32-byte commitment to asset metadata
--asseturl string URL where user can access more information about the asset (max 32 bytes)
--creator string Account address for creating an asset
--decimals uint32 The number of digits to use after the decimal point when displaying this asset. If set to 0, the asset is not divisible beyond its base unit. If set to 1, the base asset unit is tenths. If 2, the base asset unit is hundredths, and so on.
--defaultfrozen Freeze or not freeze holdings by default
--fee uint The transaction fee (automatically determined by default), in microAlgos
--firstvalid uint The first round where the transaction may be committed to the ledger
-h, --help help for create
--lastvalid uint The last round where the transaction may be committed to the ledger
-x, --lease string Lease value (base64, optional): no transaction may also acquire this lease until lastvalid
--name string Name for the entire asset
-N, --no-wait Don't wait for transaction to commit
-n, --note string Note text (ignored if --noteb64 used also)
--noteb64 string Note (URL-base64 encoded)
-o, --out string Write transaction to this file
-s, --sign Use with -o to indicate that the dumped transaction should be signed
--total uint Total amount of tokens for created asset
--unitname string Name for the unit of asset
--validrounds uint The number of rounds for which the transaction will be valid
Global Flags:
-d, --datadir stringArray Data directory for the node
-k, --kmddir string Data directory for kmd
-w, --wallet string Set the wallet to be used for the selected operation
Tip
These two requests for help are meant to encourage you to use the [--help]
flag to search for the answers you need!
We will focus on the flags strictly related to shaping the ASA.
Note
Some flags are related to general transactions properties, like [--firstvalid]
, [--lastvalid]
, [--fee]
. We are not going to dive deep into these, but you may look at the Algorand Developer Docs linked below to complete your understanding.
Learn More
- Transaction Reference
- Asset Parameters
- Asset Parameters Reference
3. ASA Property: name
--name string
The flag [--name]
, assigned as a string (within “”), identifies the complete name of the ASA. Asset name strings may contain spaces or symbols. We will choose between:
--name "Panzerotto"
or
--name "Coxinha"
Important
There is a limit of 32 bytes for [--name]
.
4. ASA Property: unitname
--unitname string
Other than by its name, an ASA can be recognized by its “unit name”. So we choose the following symbolic abbreviations:
--name PNZRT
or
--name CXNHA
Important
There is a limit of 8 bytes for [--unitname]
.
5. ASA Property: decimals
--decimals uint32
This flag determines whether the ASA is divisible or not. It deserves some attention. Like the help says, “If set to 0, the asset is not divisible beyond its base unit. If set to 1, the base asset unit is tenths. If 2, the base asset unit is hundredths, and so on.”.
Tip
If the ASA you intend to create is supposed to be divisible up to 0.0001, you will need to assign 4 as the value of this flag.
Our requirement, however, is to create “Panzerotto” or “Coxinha” as non-fungible ASAs. This requirement is not only determined by the [--decimals]
flag, but also by the ASA’s supply.
There are slightly different definitions of asset fungibility, to put it simply: a fungible asset is meant to be not unique, interchangeable, divisible in sub-parts and each of its sub-parts is indistinguishable from another sub-part.
Note
The asset ALGO, therefore, is an example of a fungible asset.
In order for “Panzerotto” or “Coxinha” to be non-fungible they must be not divisible and unique. The uniqueness property will be clarified later. So, to be non divisible in sub-parts we will set:
--decimals 0
Important
Maximum [--decimals]
is 19.
6. ASA Property: total
--total uint
With this flag we determine the total supply of the ASA.
Important
The value you pass to the [--total]
flag is intended as the total amount of the minimum unit of the ASA.
Tip
If you want to create an ASA with decimals D and a total integer supply S you have to assign to [--total]
flag the value: S * 10^D
Example
Suppose you want to create an ASA with 2 decimals and a total supply of 500, so we will set:
--total 50000
generating: 500.00 ASA
The non-fungibility requirement of the asset “Panzerotto” and “Coxinha” means they are not only indivisible must be unique, so we set:
--total 1
7. ASA Property: asseturl
--asseturl string
This string flag gives us the possibility to register a URL among ASA’s properties on Algorand blockchain, giving to its owners some additional information about the asset. We state that the official “Panzerotto” and “Coxinha” ASAs will carry their Wikipedia page into the URL, that is:
--asseturl "https://en.wikipedia.org/wiki/Panzerotti"
or
--asseturl "https://en.wikipedia.org/wiki/Coxinha"
Important
That there is a limit of 32 bytes for [--asseturl]
.
8. ASA Property: creator
--creator string
The string assigned to the [--creator]
flag specifies the public address of the asset creator account. In the genesis of the ASA the creator address will be assigned by default to all the ASA management addresses too. As we are going to analyze later, while the management addresses could be changed, the creator address represents an immutable property of the asset. Set it as the public address of an account you own.
--creator <your_account_address>
9. Asset Create Transaction
We are now ready to write down two different asset creation transactions, that of “Panzerotto” and that of “Coxinha”.
All required [flags] have been determined in the previous steps. The only flags you need to complete on your own are:
--creator <your_account_address>
And the Global [flags]:
--datadir <name_of_node_data_directory>
--wallet <name_of_node_wallet>
Like any other transaction on Algorand, the asset create may contain a note that will be associated with the transaction and registered forever on the blockchain. A note could be useful for different purposes and must be assigned to the [--note]
flag as a string (within “”). We will use it to personalize the genesis transaction of the tutorial:
--note "I have completed my tutorial on ASA creation using goal!"
Once we have understood the meaning of the flags that shape the Algorand Standard Asset, all we have to do is group this information into an asset create transaction.
Panzerotto asset create transaction
Input
$ ./goal asset create --asseturl "https://en.wikipedia.org/wiki/Panzerotti" --creator <your_account_address> --decimals 0 --name "Panzerotto" --note "I have completed my tutorial on ASA creation using goal!" --total 1 --unitname PNZRT --datadir <name_of_node_data_directory> --wallet <name_of_node_wallet>
Output
<ASSET_ID_PNZRT>
Coxinha asset create transaction
Input
$ ./goal asset create --asseturl "https://en.wikipedia.org/wiki/Coxinha" --creator <your_account_address> --decimals 0 --name "Coxinha" --note "I have completed my tutorial on ASA creation using goal!" --total 1 --unitname CXNHA --datadir <name_of_node_data_directory> --wallet <name_of_node_wallet>
Output
<ASSET_ID_CXNHA>
Choose the one you like the most and type it in the command line, then ENTER
to push the asset creation transaction to the MainNet!
Once the block containing the genesis transaction of the ASA has been added to the blockchain the asset comes to life returning the genesis transaction ID and its asset ID. Now you can find your ASA among the Algorand Standard Assets listed on a block explorer.
Learn More
- Block Explorers
10. Asset ID
Those of you familiar with database architectures know that the record’s unique identity in a database is ensured by a primary key, that is immutable and different with respect to all the others.
Similarly, the unique identity of each ASA is ensured by its asset ID. In principle someone else can create ASAs exactly with the same asset name and asset unit name that already exist on the blockchain, namely another “Panzerotto (PNZRT)”” or “Coxinha (CXNHA)”“. What really differentiates your “Panzerotto” from the one created by somebody else is actually the asset ID.
Tip
To refer exactly to your “Panzerotto (PNZRT), not any “Panzerotto (PNZRT) someone else has created, it is necessary to specifically refer to the ASA “Panzerotto (PNZRT)” by its unique asset ID <ASSET_ID_PNZRT>
.
This concept of an asset ID is very crucial to understand which assets are fungible versus non-fungible.
11. ASA Management Configuration
Now that our ASA is living on the blockchain we will analyze how to manage it through its management addresses.
To do this we will use the goal command goal asset config
. Once again we will look at command [flags] strictly related to the configuration process:
Input
$ ./goal asset config --help
Output
--asset string Unit name of asset to configure
--assetid uint Asset ID to configure
--creator string Account address for asset to configure
--fee uint The transaction fee (automatically determined by default), in microAlgos
--firstvalid uint The first round where the transaction may be committed to the ledger
-h, --help help for config
--lastvalid uint The last round where the transaction may be committed to the ledger
-x, --lease string Lease value (base64, optional): no transaction may also acquire this lease until lastvalid
--manager string Manager account to issue the config transaction (defaults to creator)
--new-clawback string New clawback address
--new-freezer string New freeze address
--new-manager string New manager address
--new-reserve string New reserve address
-N, --no-wait Don't wait for transaction to commit
-n, --note string Note text (ignored if --noteb64 used also)
--noteb64 string Note (URL-base64 encoded)
-o, --out string Write transaction to this file
-s, --sign Use with -o to indicate that the dumped transaction should be signed
--validrounds uint The number of rounds for which the transaction will be valid
As we learned in the asset creation process, there are several ways to refer to a specific ASA, for
example with a combination of the asset unit name, the asset ID and asset creator.
In order to refer exactly to one specific ASA the goal asset config
command requires values for the following flags:
--creator string
--assetid uint
and optionally:
--asset string
So, we will refer to the specific ASAs either with:
--creator <your_creator_account_address>
--assetid <ASSET_ID_PNZRT>
or
--creator <your_creator_account_address>
--assetid <ASSET_ID_CXNHA>
12. ASA Management
--manager string
The manager address, also known as manager key, is the public address that has the power to change the ASA configuration, namely the one in charge of its management. By default, the manager address coincides with the creator address, but it can be changed.
The manager address has the power to assign the following mutable addresses:
--new-clawback string
--new-freezer string
--new-manager string
--new-reserve string
We have just explained what the manager address does, but what do the other addresses represent?
Reserve address
Is the account’s address which stores the amount of ASA that has not yet been minted. The reserve address can be considered a “logical construct” that helps distinguish between circulating supply and supply to be minted. If the reserve address is different from the creator address, the creator should issue a transaction to move all funds to the new reserve address.
Important
Only when a certain quantity of ASA leaves this reserve address is it considered minted and made available for the rest of the world.
Important
The reserve address can be replaced with an empty string (“”), so that the total supply is considered “minted” by the hands of its creator.
Freeze address
This is the address of the account that has the power to prevent someone else from trading this ASA.
Attention
There could be classes of ASAs that need this kind of management in order to be compliant with some policy or regulatory requirements.
Important
The freeze address can be replaced with an empty string (“”), so that nobody is able to exercise the freeze power any more.
Clawback address
This is the address of the account that has the power to move this ASA from any owner’s account to another one.
Attention
This is given to ASAs that require the possibility, for example, to revoke the asset in case of fraud.
Important
The clawback address can be replaced with an empty string (“”), so that nobody is able to exercise the clawback power any more.
As long as freeze and clawback addresses are not empty, there exists someone in the world who can eventually prevent you from transacting this ASA or revoke it.
Warning
Once these addresses are replaced with empty strings the process is irreversible, nobody can change them any more!
13. Asset Config Transaction
Since no one should be able to revoke “Panzerotto (PNZRT)”” or “Coxinha (CXNHA)”” from their owners or prevent someone from transacting with these ASAs, we will eliminate this possibility setting:
--new-clawback ""
--new-freezer ""
We want this to be clear, declaring our will through a note in the asset configuration transaction:
--note "It’s mine as long as I want, and nobody can stop me from giving it to you!"
We are now ready to write down the whole asset configuration transaction in the command line and push it to the blockchain:
Panzerotto asset configuration transaction
$ ./goal asset config --asset PNZRT --creator <your_creator_account_address> --manager <your_creator_account_address> --new-clawback “” --new-freezer “” --note “Panzerotto is mine as long as I want, and nobody can stop me from giving it to you!” --datadir <name_of_node_data_folder> --wallet <name_of_node_wallet>
Coxinha asset configuration transaction
$ ./goal asset config --asset CXNHA --creator <your_creator_account_address> --manager <your_creator_account_address> --new-clawback “” --new-freezer “” --note “Coxinha is mine as long as I want, and nobody can stop me from giving it to you!” --datadir <name_of_node_data_folder> --wallet <name_of_node_wallet>
Type it in the command line and ENTER
to push the asset configuration transaction to the MainNet!
Once the block containing the configuration transaction of the ASA has been added to the blockchain the asset management has been shaped, returning the configuration transaction ID. You can find the configuration transaction on a block explorer.
Awesome, our ASA’s management is now fully configured! Remember that you still have the possibility to change the manager address or the reserve address.
Learn More
- Asset Configuration Transaction
14. Asset Destroy Transaction
What if we realize we made a mistake in the creation process? Can an ASA be destroyed? The manager can destroy the ASA if and only if the creator owns the total supply generated in the genesis transaction.
Thanks to this tutorial you can now figure out how to destroy an ASA!
Tip
--help
is your best friend.
15. Conclusion
Awesome, you have completed your tutorial on non-fungible ASA creation!
Now you are able to create a digital unique representation of non-fungible assets, like collectable cards, digital identity representations and so on!
Like I said in the introduction: I’m really looking forward to seeing “Panzerotto” ASA or “Coxinha” ASA spreading around Algorand! You can even think of customizing your Panzerotto picking between “fried” and “baked”, adding some of your favorite flavours like “mozzarella di bufala” or “spicy salame”, or also creating a Coxinha with “chicken and catupiry cheese”. It’s up to you!
See you on the next tutorial!