Features

Fetching Compressed NFTs

As mentioned in the Overview page, Compressed NFTs are not stored inside on-chain accounts like regular NFTs but, instead, are logged in the transactions that created and updated them.

As such, a special indexer was created to facilitate the retrieval of Compressed NFTs. This indexed data is made available through an extension of the Solana RPC methods which we call the Metaplex DAS API. In fact, the DAS API allows us to fetch any Digital Asset. This can be a Compressed NFT, a regular NFT, or even a Fungible Asset.

Since not all RPCs support the DAS API, you will need to choose your RPC provider carefully if you are planning to work with Compressed NFTs. Note that we maintain a list of all RPCs that support the Metaplex DAS API in a dedicated page.

On this page, we will learn how to fetch Compressed NFTs using the Metaplex DAS API.

Installing the Metaplex DAS API SDK

Once you have chosen an RPC provider that supports the Metaplex DAS API, you may simply send special RPC methods to fetch Compressed NFTs. However, our SDKs provide a more convenient way to get started with the DAS API by offering helper methods. Follow the instructions below to get started with the Metaplex DAS API using our SDK.

Get started with the Metaplex DAS API

When using Umi, the Metaplex DAS API plugin is automatically installed within the mplBubblegum plugin. So you are already be good to go!

If you wanted to use the DAS API plugin without importing the whole mplBubblegum plugin, you could do so by installing the Metaplex DAS API plugin directly:

npm install @metaplex-foundation/digital-asset-standard-api

After that, register the library with your Umi instance:

import { dasApi } from '@metaplex-foundation/digital-asset-standard-api';

umi.use(dasApi());

You can find more information about the methods available on the Metaplex DAS API on its repository.

Asset IDs

In order to fetch an NFT, compressed or not, we need to have access to a unique ID that identifies the NFT. We call this unique identifier the Asset ID.

  • For regular NFTs, we use the mint address of the NFT for that purpose since all other accounts simply derive from that address.
  • For compressed NFTs, we use a special PDA (Program Derived Address) that is derived from the address of the Merkle Tree and the leaf index of the Compressed NFT in the Merkle tree. We call this special PDA a Leaf Asset ID.

You typically shouldn't need to derive the Leaf Asset ID yourself since the DAS API methods will provide it for you when fetching Compressed NFTs in bulk — e.g. fetching all NFTs owned by a given address. However, if you had access to the address of the Merkle Tree and the leaf index of the cNFT, here's how you could use our SDKs to derive the Leaf Asset ID.

Find the Leaf Asset ID PDA

import { findLeafAssetIdPda } from '@metaplex-foundation/mpl-bubblegum'

const [assetId, bump] = await findLeafAssetIdPda(umi, {
  merkleTree,
  leafIndex,
})

Fetching a Compressed NFT

Fetching a Compressed NFT is as simple as calling the getAsset method of the DAS API. This method will return an Rpc Asset object that contains the following information:

  • Id: The Asset ID as discussed above.
  • Interface: A special value that defines the type of asset we are dealing with. E.g. V1_NFT OR ProgrammableNFT.
  • Ownership: An object telling us who owns the asset. This includes any delegate that may have been set and whether or not the asset is marked as frozen.
  • Mutable: A boolean indicating whether the data of the asset is updatable or not.
  • Authorities: An array of authorities, each including a scope array indicating what operations the authority is allowed to perform on the asset.
  • Content: An object containing the data of the asset. Namely, it includes its URI and a parsed metadata object.
  • Royalty: An object that defines the royalty model defined by the asset. Currently, there is only one royalty model supported which sends a percentage of the proceeds to the creator(s) of the asset.
  • Supply: When dealing with printable assets, this object provides the current and max supply of printed editions.
  • Creators: The list of creators of the asset. Each includes a verified boolean indicating whether the creator has been verified or not and a share number indicating the percentage of royalties that should be sent to the creator.
  • Grouping: An array of key/value grouping mechanisms that can help index and retrieve assets in bulk. Currently, only one grouping mechanism is supported — collection — which allows us to group assets by collection.
  • Compression: When dealing with Compressed NFTs, this object gives us various information about the leaf of the Bubblegum Tree. For instance, it provides the full hash of the leaf, but also partial hashes such as the Creator Hash and Data Hash which are used to verify the authenticity of the asset. It also gives us the Merkle Tree address, its root, sequence, etc.

Here is how one can fetch an asset from a given Asset ID using our SDKs.

Fetch a Compressed NFT

const rpcAsset = await umi.rpc.getAsset(assetId)

Fetching the Proof of a Compressed NFT

Whilst the getAsset RPC method returns a whole lot of information about the asset, it does not return the Proof of the asset. As mentioned, in the Overview page, the Proof of a Compressed NFT is a list of hashes that allow us to verify the authenticity of the asset. Without it, anyone could pretend that they have a Compressed NFT in a tree with any given data.

As such, many operations on Compressed NFTs — e.g. burning, transferring, updating, etc. — require the Proof of the asset before allowing us to perform them. Computing the Proof of an asset is possible but requires someone to know the hash of all Compressed NFTs that exist within a given tree. This is why the DAS API also keeps track of the Proof of all Compressed NFTs.

In order to access the Proof of a Compressed NFT, we may use the getAssetProof RPC method. This method will return an Rpc Asset Proof object containing the following information:

  • Proof: The proof of the Compressed NFT as promised.
  • Root: The root of the Merkle Tree that the asset belongs to. When verifying the asset using the provided Proof, we should end up with this root as the final hash.
  • Node Index: The index of the asset in the Merkle Tree if we counted every single node in the tree from left to right, top to bottom. A more useful index called the Leaf Index can be inferred from this value by the following formula: leaf_index = node_index - 2^max_depth where max_depth is the maximum depth of the Merkle Tree. The Leaf Index is the index of the asset in the Merkle Tree if we counted only the leaves of the tree — i.e. the lowest row — from left to right. This index is requested by many instructions and is used to derive the Leaf Asset ID of the asset.
  • Leaf: The full hash of the Compressed NFT.
  • Tree ID: The address of the Merkle Tree that the asset belongs to.

As you can see some of the information here is redundant from the getAsset RPC call but is provided here for convenience. However, the Proof and the Node Index of the asset can only be fetched through this method.

Here is how we can fetch the Proof of an asset using our SDKs.

Fetch the proof of a Compressed NFT

const rpcAssetProof = await umi.rpc.getAssetProof(assetId)

Fetching Multiple Compressed NFTs

The DAS API also allows us to fetch multiple assets at once using the getAssetsByOwner and getAssetsByGroup RPC methods. These methods will return a paginated Rpc Asset List object containing the following information:

  • Items: An array of Rpc Asset as described above.
  • Total: The total number of assets available based on the provided criteria.
  • Limit: The maximum number of assets we are retrieving on a page.
  • Page: When using numbered pagination, it tells us which page we are currently on.
  • Before and After: When using cursor pagination, it tells us after which and/or before which asset we are currently browsing assets. These cursors can be used to navigate to the previous and next pages.
  • Errors: A potential list of errors returned by the RPC.

Here is how we can use both of these RPC methods using our SDKs.

By Owner

Fetch Compressed NFTs by owner

const rpcAssetList = await umi.rpc.getAssetsByOwner({ owner })

By Collection

Fetch Compressed NFTs by collection

const rpcAssetList = await umi.rpc.getAssetsByGroup({
  groupKey: 'collection',
  groupValue: collectionMint,
})
Previous
Minting Compressed NFTs (cNFTs)