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 will 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 information
Please read the NFT-V2 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:
Contract | Emulator import address | Testing framework |
---|---|---|
NonFungibleToken | 0xf8d6e0586b0a20c7 | 0x0000000000000001 |
FungibleToken | 0xee82856bf20e2aa6 | 0x0000000000000002 |
ViewResolver | 0xf8d6e0586b0a20c7 | 0x0000000000000001 |
Burner | 0xf8d6e0586b0a20c7 | 0x0000000000000001 |
MetadataViews | 0xf8d6e0586b0a20c7 | 0x0000000000000001 |
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 theNFTStorefront
andNFTStorefrontV2
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
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:
_10access(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:
_10access(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 of 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 programming language as well as the token standard. The improvements are 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
must 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!