Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Beginner · 30 minutes

Create and Manage a Non-Fungible ASA from the Command Line Using goal

The tutorial is divided into two main phases:

  1. Non-fungible ASA creation
  2. 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

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!