Skip to main content
Version: 1.0

Non-Fungible Tokens in Cadence 1.0

On September 4th, 2024 the Flow Mainnet upgraded to Cadence 1.0. In addition to many changes to the Cadence programming language, the Cadence token standards were also streamlined and improved. All applications' scripts and transactions need to be updated. If you do not update your code, your applications do not function properly.

This document describes the changes to the Cadence Non-Fungible Token (NFT) standard and gives a step-by-step guide for how to upgrade your NFT contract from Cadence 0.42 to Cadence 1.0.

We'll be using the ExampleNFT contract as an example. Many projects have used ExampleNFT as a starting point for their projects, so it is widely applicable to most NFT developers on Flow. The upgrades required for ExampleNFT will cover 90%+ of what you'll need to do to update your contract. Each project most likely has additional logic or features that aren't included in ExampleNFT, but hopefully after reading this guide, you'll understand Cadence 1.0 well enough that you can easily make any other changes that are necessary.

Additionally, most of the changes described here also apply to anyone who is updating a Fungible Token contract or interacting with one, so keep that in mind while reading if that applies to you.

As always, there are plenty of people on the Flow team and in the community who are happy to help answer any questions you may have, so please reach out in Discord if you need any help.

Important Info

Please read the FLIP that describes the changes to the NonFungibleToken standard first.

The updated code for the V2 Non-Fungible Token standard is located in the master branch of the flow-nft repo. Please look at the PR that made the changes to understand how the standard and examples have changed. Note the changes to the NonFungibleToken, MetadataViews, ViewResolver, and NFTForwarding contracts.

Additionally, here are the import addresses for all of the important contracts related to non-fungible tokens. The second column is the import address if you are testing with a basic version of the emulator. The third column contains the import addresses if you are using the Cadence testing framework.

ContractEmulator Import AddressTesting Framework
NonFungibleToken0xf8d6e0586b0a20c70x0000000000000001
FungibleToken0xee82856bf20e2aa60x0000000000000002
ViewResolver0xf8d6e0586b0a20c70x0000000000000001
Burner0xf8d6e0586b0a20c70x0000000000000001
MetadataViews0xf8d6e0586b0a20c70x0000000000000001

See the other guides in this section of the docs for the import addresses of other important contracts in the emulator.

As for contracts that are important for NFT developers but aren't "core contracts", here is information about where to find the Cadence 1.0 Versions of Each:

NFT Catalog: The NFT Catalog has been deprecated for Cadence 1.0. Now that the token standards require implementing metadata views, NFT Catalog is not needed in its current form. The Flow team now maintains TokenList which is similar to NFT Catalog, but is decentralized. Projects can register there without needing to be approved.

NFT Storefront: See the master branch in the NFT Storefront Repo for the updated versions of the NFTStorefront and NFTStorefrontV2 contracts.

USDC: USDC was migrated to standard bridged USDC on Flow. See the repo for the latest version of the USDC contract.

Account Linking and Hybrid Custody: See the main branch in the hybrid custody repo for updated hybrid custody contracts.

This Discord announcement also contains versions of a lot of important contracts.

Use the Flow Contract Browser to find the 1.0 code of other contracts.

A note for newcomers

This guide is primarily for developers who have existing contracts deployed to Flow mainnet that they need to update for Cadence 1.0. If you don't have any contracts deployed yet, it is recommended that you start an NFT contract from scratch by either copying the ExampleNFT contract from the master branch of the flow-nft repo.

Additionally, the Flow community is working on the BasicNFT contract in the universal-collection branch of the flow-nft GitHub repo. This is a simplified version of standard NFT contracts, but has not been completed yet.

BasicNFT and UniversalCollection

As part of the improvements to the NFT standard, there is now a new NFT contract example in the flow-nft GitHub repo: BasicNFT.

BasicNFT defines a Cadence NFT in as few lines of code as possible, 137 at the moment! This is possible because the contract basically only defines the NFT resource, the essential metadata views, and a minter resource. It doesn't have to define a collection! Most collection resources are 99% boilerplate code, so it really doesn't make sense for most projects to have to define their own collection.

Instead, BasicNFT uses UniversalCollection, a contract that defines a collection resource that has all of the standard functionality that a collection needs and nothing else. From now on, any project that doesn't want to do anything unique with their collection can just import UniversalCollection and call it from their createEmptyCollection function:


_10
access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
_10
return <- UniversalCollection.createEmptyCollection(identifier: "flowBasicNFTCollection", type: Type<@BasicNFT.NFT>())
_10
}

All they have to provide is a type and an identifier for the collection. UniversalCollection.Collection will enforce that only NFTs of the given type can be accepted by the collection:


_10
access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
_10
if self.supportedType != token.getType() {
_10
panic("Cannot deposit an NFT of the given type")
_10
}

It also constructs standard paths based on the identifier provided.

UniversalCollection will be deployed to all the networks soon after the Cadence 1.0 upgrade, so developers will be able to import from it after that point.

We'll be putting out more information and guides for BasicNFT and UniversalCollection in the near future, but keep it in mind if you are thinking about deploying any new NFT contracts in the future!

Migration Guide

This guide will cover changes that are required because of upgrades to the Cadence Language as well as the token standard. The improvements will be described here as they apply to specific changes that projects need to make in order to be ready for the upgrade, but it is good to read all sources to fully understand the changes.

Please read the motivation section of the NFT-V2 FLIP to learn about why most of the changes to the standard were needed or desired.

First, we will cover the changes that come from the new token standards and then we will cover the changes that come from Cadence.

Token Standard Changes

NonFungibleToken.NFT

NonFungibleToken.NFT used to be a nested type specification, but now it is an interface!

In your code, any instance that refers to @NonFungibleToken.NFT or &NonFungibleToken.NFT need to be updated to @{NonFungibleToken.NFT} or &{NonFungibleToken.NFT} respectively.

NonFungibleToken.Collection

Similar to NFT, NonFungibleToken.Collection is now an interface.

Since Collection is an interface, you will need to update every instance in your code that refers to @NonFungibleToken.Collection or &NonFungibleToken.Collection to @{NonFungibleToken.Collection} or &{NonFungibleToken.Collection} respectively to show that it is now an interface specification instead of a concrete type specification.

Conclusion

This guide covered the most important changes that are required for the Cadence 1.0 upgrades to NFT contracts. Please ask any questions about the migrations in the #developer-questions channel in discord and good luck with your upgrades!