Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
Technical notes to guide developers who are implementing NFTs on the Internet Computer blockchain.
By Dominic Wörner, Developer Relations Engineer | DFINITY
An NFT, or non-fungible token, is a record on a blockchain that is associated with a particular digital or physical asset. The unique digital representation on a blockchain allows NFTs to prove ownership as well as be traded.
NFTs on the Internet Computer
The Internet Computer blockchain (IC) brings a lot of potential for NFTs. For digital assets like images, sound clips, or videos, the entire asset can live on-chain and can be included in on-chain games or metaverse experiences. Furthermore, we can imagine dynamic NFTs that change based on IC-internal and external data via HTTPS outcalls.
For many applications, the defining characteristic is their permanence and immutability (or evolution according to predefined rules). Some of the design decisions of the IC, such as the reverse-gas model and the upgradability of canister smart contracts, require the NFT developer to be particularly aware.
An NFT implementation on the IC typically has the following three functions:
- A registry that tracks ownership and allows transfers.
- A ledger or transaction history.
- The actual asset (in the case of digital assets).
Depending on the architecture, all of these functions may be in one canister or spread across multiple canisters, right up to an asset canister per individual NFT. Each of these canisters must not run out of cycles, and should be protected against arbitrary code changes. In the following sections, we discuss some of the mechanisms, tools, and ideas that support NFT developers and their users to achieve these goals.
Top up all canisters very generously
Make sure that all canisters have enough cycles to sustain a few years to begin with. Storage and computation on the IC are magnitudes less expensive than on other platforms, so this is typically not a huge investment. To make it easy for others to top up the canisters, you should consider adding the blackhole canister or some other immutable proxy canister as a controller to the NFT canisters. This allows users to use the Tip Jar service to top up the canisters.
Set a generous freezing threshold
The IC has a useful mechanism to save your canister from running out of cycles. Canisters have a configurable freezing_threshold. The freezing_threshold can be set by the controller of a canister and is given in seconds. The IC dynamically evaluates this as a threshold value in cycles. The value is such that the canister will be able to pay for its idle resources for at least the time given in freezing_threshold. To guarantee that, the canister is frozen when the cycle balance reaches the threshold, and all update calls, including the heartbeat, are immediately rejected and won’t affect the canister’s cycle balance.
The default value is approximately 30 days, but for NFTs, developers should set the freezing_threshold to at least 90 days, preferably 180 days. This makes sure that NFT developers and their users have enough time to react and top up the canisters before they finally run out of cycles.
Make sure your canisters can be monitored
On the IC, the cycle balance of a canister is only visible to controllers. Since an NFT (collection) might outlive its creator, you should plan for monitoring by third parties. You can do this via implementing a simple query method as included in the DIP721 and EXT standards.
You can also use a more complete monitoring solution like Canistergeek. Recently, the team behind Canistergeek added a new feature to their NFTgeek product that allows observing the cycles balance of popular NFT collections.
Follow best practices for efficient implementations
There are a few foot guns that could make your canister more expensive than you’d expect. Here are a few examples that you might encounter when implementing NFT canisters.
- Use of the heartbeat: A plain heartbeat without doing anything will cost ~0.055 T cycles/day. There are discussions about implementing alternatives that allow for cheaper scheduling.
Some advice for Motoko developers:
- Use TrieMap instead of HashMap to avoid the performance cliff of automatic resizing associated with HashMaps.
- Use Buffer instead of Array if you need to dynamically resize the structure
- Use Blob instead of [Nat8] for storing large binary assets
- Consider using Blob instead of [Nat8] when sending or receiving Candid vec nat8/blob values. The choice is yours but Blobs are 4x more compact and much less taxing on garbage collection (GC).
- Consider storing large Blobs in stable memory, to reduce pressure on the GC even further, especially when the manual memory management of that Blob is simple (e.g. they are only added, never deleted).
- Consider using the compacting-gc setting, especially in append-only scenarios, to allow access to larger heaps and reduce the cost of copying large, stationary objects.
Some advice for Rust developers:
- Be careful with extensive use of Vec<u8> and hence the String type if you need to (de-)serialize state for upgrades.
- Read Roman’s blog post on effective Rust canisters
Another must-read is the general article on good practices for canister development by Joachim Breitner.
To make sure you won’t get surprised by a high cycle burn rate or hitting an instruction limit, you can use the recently added performance counter API to profile your canisters even before going live. Furthermore, a list of all costs on the IC can be found here.
Implement mechanisms to backup and restore state
The IC itself does not yet support backup and restoration of the canister state, but it can be implemented in the canister itself. Regular backups are insurance against the worst-case scenario that a canister gets deallocated or there are issues with upgrading a canister. This forum post describes the approach that the Web3 social network Distrikt is using.
Consider using a dedicated service for storing the transaction history
There are dedicated services on the IC to keep an audit log of transactions, such as CAP, which can be used by an NFT collection as a service. This allows simple integration of the provenance history in explorers and wallets. Furthermore, the state of ownership could be reconstructed in case the main NFT canister gets lost. However, some drawbacks have to be considered, e.g., NFT transfers incur additional costs due to the necessary inter-canister calls.
Think about governance
The value proposition of most NFTs is their permanence and immutability, e.g., by setting the blackhole canister as the only controller. As long as NFT canisters have their developers as controllers, users depend on the trustworthiness (and operational security) of the developers. Developers should therefore make the canisters immutable or manage the canisters with a DAO. A middle ground are mechanisms like Launchtrail that make changes to a canister auditable.
Blackholing a canister has its issues as well. If there are bugs in the canister code or you’re using experimental system APIs that might get deprecated later on, the canister might stop functioning.
More information on this topic can be found in the Trust in Canisters article.
Think about economic sustainability
Ideally, your canisters implement mechanisms to generate fees that the canisters can use to pay for their existence indefinitely. A simple approach is to utilize (parts of) the transfer fee to fuel the canisters, but more elaborate schemes could involve staking or other advanced mechanisms. Please share if you know of projects implementing clever mechanisms.
Links and Resources
The following resources are community projects. Please do your own research and use them at your own risk.
NFT interface specifications and implementations
- DIP 721: An interface similar to ERC-721.
- Extendable Token (EXT): Extendable interface inspired by ERC-1155.
NFT Marketplaces and Launchpads
Start building at internetcomputer.org and join the developer community at forum.dfinity.org.
Considerations for NFT Developers on the Internet Computer was originally published in The Internet Computer Review on Medium, where people are continuing the conversation by highlighting and responding to this story.
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.