status | flip | authors | sponsor | updated |
---|---|---|---|---|
Implemented |
258 |
Joshua Hannan ([email protected]) Cody Bouche ([email protected]) |
Joshua Hannan ([email protected]) |
2024-03-11 |
Enforce that NFT projects store their NFTs in their Collection
in an access(contract)
dictionary field and provide a default function
for iterating over the NFT IDs in the collection.
The original NFT standard enforced that Collection
s had a field for storing NFTs:
pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
In the V2 NFT Standard, it was decided that we wanted to give projects more flexibility for how they store their NFTs, so this requirement was removed. We didn't realize at the time that this requirement actually had benefits like allowing more sophisticated and standardized scripts that interacted with collections, like iterating through IDs in a collection without having to load all of them into memory at once.
The conversation that triggered this is in Discord. A pull request with the suggested code changes is in the flow-nft github repository.
This FLIP proposes adding the ownedNFTs
field back to the standard:
access(contract) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
It also proposes adding a function to NonFungibleToken.Collection
, forEachID()
,
that allows iterating through the IDs in a collection without having
to load all of them into memory first:
/// Allows a given function to iterate through the list
/// of owned NFT IDs in a collection without first
/// having to load the entire list into memory
access(all) fun forEachID(_ f: fun (UInt64): Bool): Void {
self.ownedNFTs.forEachKey(f)
}
The function specification provides a default implementation so that projects don't have to implement the function themselves.
With a standard specification for how to store NFTs, developers can have more confidence in understanding any given NFT project's storage.
Without this storage specification, there would be no way to get all the IDs in a large collection without hitting the computation limit.
This also allows the standard to define more sophisticated functionality that
interacts with stored NFTs, like we have done with adding the forEachID()
function.
In the future, there may be other functionality that is enabled
by having standardized storage.
This could make things a little more awkward for developers who do want to define
a more sophisticated system for storing NFTs
because they will still have to have the ownedNFTs
field,
but it doesn't prevent them at all because they can simply ignore the field requirement
and do whatever else they want.
- Keep the standard the same:
- This would make some projects like evaluate not be able to function properly who rely on the iterator feature for their app.
- Only introduce the
forEachID()
function with a default implementation but without the storage requirement- This would not potentially be a breaking change but would leave it up to the projects to implement the function, which is not reliable. We are far enough from the upgrade that this change should be acceptable.
- Introduce a Cadence feature that allows getting slices from the IDs array
- There isn't time to do this before the Cadence 1.0 upgrade.
The forEachID()
also has a limit (200k) on how many IDs it can access,
but that is much larger than almost any collection on Flow will ever be.
- Build and test time will stay the same. they are relatively small changes.
- Check out the Cadence 1.0 migration guide for instructions on how to update contracts to the new standards:
- FCL, emulator, and other such tools should not be affected.
- The upgrade will go out on the networks at the same time as Cadence 1.0 (Crescendo) if approved.