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.
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 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:
_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 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!