Building NFTs on Algorand
Article Quick Glance
Building NFTs on Algorand
- NFTs can be built using Algorand’s layer 1 ASAs in seconds.
- Highly customized NFTs with unique transfer logic can be built using Stateful Smart Contracts.
- NFTs built using ASAs can be manipulated with unique logic using Stateless Smart Contracts.
- Highly configurable NFT applications can be built using a combination of Atomic Transfers, ASAs, Stateful and Stateless Smart Contracts.
Algorand supports tokenizing any asset whether it is fungible or non-fungible. This generally can be done without writing any smart contract code and is supported in the protocol. This allows transactions associated with your token to be finalized very quickly. Algorand also supports layer 1 smart contracts that perform at this same level. These contracts can be used to create various types of applications and can be integrated with or extend fungible or non-fungible tokens. The focus of this article is to cover the different options an NFT creator has available when building on the Algorand blockchain.
Algorand provides many layer 1 features including Algorand Standard Assets (ASA), Atomic Transfers, and Smart Contracts. These features are powerful and can be configured to work with each other in unique ways. This provides a lot of flexibility. This article will start with the easiest way to build an NFT and then further elaborate on additional layer 1 feature combinations that can be used to create more complex tokens.
Algorand Standard Assets (ASAs) to Create NFTs
The primary method a developer or Algorand user can use to build and deploy an NFT is by using the ASA feature. This feature is a layer 1 primitive that allows an NFT or FT to be created in seconds. These assets require no smart contract code. It only takes one transaction on the Algorand blockchain to create an NFT. This transaction describes the properties, both mutable and immutable, of the token.
The immutable properties are configured once and can never be changed once the NFT is created. The required parameters are the Creator field which is automatically populated by the sender of the initial creation transaction, the Total number of the asset which represents a unit count for NFTs this should be set to 1, implied Decimals which allow each unit of an FT to be subdivided, and DefaultFrozen which specifies whether the token can be traded by default. For an NFT decimals should be set to 0. If an NFT is configured as default frozen, the token has to be unfrozen before it can be traded with others.
The optional immutable properties include the AssetName which is up to a 32-byte string that can be used to name your asset class, the UnitName which is an 8-byte string that specifies the name of a unit of the asset (ie USDC), the URL property is a 32-byte string that allows a URL to be appended to the asset which can be used to specify a location off-chain with additional details about the asset and a MetaDataHash which is a 32-byte field intended to be used to store a hash of some off-chain data such as certificate of ownership.
The mutable properties consist of a set of four addresses that allow the NFT to be configured to operate in some fashion, such as a restricted token. These include the ManagerAddress which can be used to change the other three addresses, the ReserveAddress which can be used to hold logical unminted tokens, the FreezeAddress which can be used to freeze or unfreeze an NFT for any account, and the ClawbackAddress which allows the NFT to be taken from one account and given to another. Any of these addresses can be locked by clearing it, which effectively locks that configuration for the life of the token. As long as an address has not been cleared the manager address can change it at any time. These addresses can be any type of address: single key, multiSig or logicSig. Later sections of this article describe the use of stateless smart contracts to specify program logic which control the operation of these mutable addresses.
The URL and MetaData Hash fields can be used to store data about the NFT which may be stored off-chain on some system like IPFS. This is the simplest way to create an NFT on Algorand and it takes seconds to accomplish. You can issue this transaction using the command line tool (‘goal’), any of the SDKs or for demo purposes take a look at the algodesk.io web app. Check out the video below to see how the web app can be used to create a token. For information on using the SDKs or ‘goal’ to create the token take a look at the developer documentation.
Currently, an account can only opt into (transact) no more than 1000 tokens. This limit can be circumvented by using multiple accounts and for added simplicity, these accounts can be rekeyed to the same private key. Also, note that for every token opted into the minimum account balance is raised by 0.1 Algos.
For more information on ASAs see the developer documentation.
Stateful Smart Contracts and NFTs
Algorand provides two types of layer 1 smart contracts. Stateful and Stateless.
Stateful contracts are layer 1 smart contracts that live on-chain and have access to many on-chain values, such as balances, tokens owned and last block time. Additionally, these contracts can store global and local values. Global values are associated with the contract themselves and local values are associated with users that interact with the contract. When using local storage, stateful smart contracts can act very similar to Algorand Standard Assets. In fact, recreating the ASA standard has been done as a test stateful smart contract. Local storage values are actually stored in the account’s ledger space similar to the amount of Algos and ASAs the account owns.
Implementing an NFT in a stateful smart contract can be done by creating a unique asset that has a set of custom properties with logic. This asset would then be stored in global or local state. This NFT can then be passed to individual accounts by storing it in the user’s local storage. If this NFT is transferred to another account, it would then be moved from the sender’s local storage to the receiver’s local storage by the stateful smart contract. As an example, global state could be used to present an NFT as up for sale. Once it is sold, it would be moved from global to the receiver’s local state. Algorand’s Indexer could then be used in this case to quickly list all the NFTs associated with this stateful smart contract. If you need custom logic to control the creation or transfer of the NFT, this code would be implemented in the stateful smart contract. To see an example of creating a custom asset in a stateful contract written in PyTeal, see this example.
A drawback of this approach is that wallets currently do not support listing these types of NFTs. Additionally, accounts currently can only opt into (participate) a total of 10 stateful smart contracts that make use of local storage. Also, note that for every stateful smart contract opted into the minimum account balance will increase as described in the developer documentation. As with ASAs this limit can be circumvented using multiple accounts with the possibility to rekey them to the same private key.
For more information on stateful smart contracts see the developer documentation.
Stateless Contracts With NFTs
Stateless smart contracts do not store any on-chain data or access on-chain values. They evaluate transactions or transaction groups at the time the transaction(s) is submitted. Stateless contracts can be compiled to produce an Algorand address, which functions like any other address. This account can hold NFTs, FTs or Algos. In fact, it can receive any of these freely from any other account without the contract’s logic being evaluated. When a transaction is issued from the stateless contract the logic is evaluated and if successful will allow the transaction to go through. If the logic fails, so will the transaction. These types of contracts are often used to build escrow-style accounts where withdrawals can be controlled by logic.
As stated earlier, Stateless contracts can be used as any of the mutable addresses that control an NFT. As an example, the reserve address could be set to a stateless contract. If this address is being used to mint tokens, the logic would be evaluated anytime a token left the reserve account. If the logic fails, the token would not be minted. If the logic succeeded, the token would be minted. The same can be done for freezing and unfreezing an NFT with a stateless contract. By using a stateless contract here, the operation would not be approved unless the logic was approved. Clawback can also be set to a stateless contract. This would initiate the logic anytime a clawback operation occurred.
This approach requires writing the stateless contracts but will continue to integrate well with Algorand wallets. A minimum of Algos will be required in each of the contracts to handle transaction fees. Once the ASA is in the wild though, any two users could exchange the token and no logic will be executed.
For more information on stateless smart contracts see the developer documentation.
Manipulate NFTs with A Combination of Features
Any of the scenarios above can also be further enhanced by using Algorand Atomic Transfers. Atomic Transfers allow up to 16 transactions to be submitted simultaneously, where if any of the transactions fail, they all fail. All of the transactions in the group can be interrogated by either a stateful or stateless contract in order to approve the logic. The only requirement is that one of the transactions must be a call to the stateful contract or make a transaction from a stateless contract. As an example, in the crowdfunding sample, when a donation call is made to the stateful smart contract, the code checks to see if it is grouped with a payment transaction to the escrow account that holds the donations. In this same example, When the donation is set to be made to an individual, the logic of the escrow is evaluated when the payout occurs. This stateless smart contract will not pay out unless the transaction from it is also grouped with a call to the stateful smart contract which executes that logic as well.
Using Atomic Transfers with a combination of Assets and Smart contracts allows developers to build unique applications. For example, a slightly more complicated approach for executing custom transfer logic between any two users using ASAs, atomic transfers, stateless contracts, and stateful contracts see this example.
Using Algorand, many unique methods exist to build complex and quick NFTs. This article discussed a few methodologies that can be used. These methods rely on Algorand layer 1 features that will perform at a very efficient and fast pace, allowing developers to not only create feature-rich applications but offer their Dapp users great performance.