đī¸Shyft compressed NFT APIs
Easy APIs for minting, transferring (bulk), burning (bulk) and reading compressed NFTs
How do compressed NFTs work?
Compressing an NFT involves the following steps:
Tree authority: This is a program that is authorized to add new leaves to the Merkle tree using the account-compression program. It also handles the encoding of cryptographic hashes.
Leaf authority: This attribute is given to a wallet account that owns a leaf. The wallet account has the authority to replace, remove, and decompress the leaf.
There are two types of authorities in compressed NFTs:
Mint account: This account is authorized to mint new NFTs.
Associated token account: This account holds the NFTs and manages their transfer to other accounts.
Wallet account: This account owns a leaf and has the authority to replace, remove, and decompress it.
Compressed NFT authorities are attributes associated with an NFT account that specify its capabilities. Each NFT account has three subordinate accounts:
Metadata verification: The Bubblegum program from Metaplex verifies the metadata associated with an NFT.
Account compression: The account-compression program from Bubblegum adds a new leaf to the Merkle tree.
On-chain update: The Merkle tree is updated on-chain by account compression to reflect the new state of the world.
Blockchain update: Any changes made to the Merkle tree are written to the Solana blockchain.
Off-chain indexing: Off-chain indexers keep track of modifications made to the Merkle tree and manage the necessary information and authorizations to support decentralized applications and programs.
Where are compressed NFTs stored?
Compressed NFTs store their metadata off-chain in a Merkle tree, which is monitored by an indexer and accessed through Solana RPC service providers. Compared to storing the same data on-chain, this method is more cost-effective. Essentially, the data is off-chain, while a much smaller proof of the data in the form of the Merkle tree root is stored on-chain.
Create Merkle Tree
The setup of the tree is a crucial aspect of creating compressed NFTs, as it determines the cost of creation and cannot be modified once established. To create the tree, the @solana/spl-account-compression SDK offers helper functions that enable the following steps:
Determine the desired tree size. Allocate space for the tree on-chain by generating a new Keypair. Create the tree and assign ownership to the Bubblegum program.
POST /sol/v1/nft/compressed/create_tree
Creates a merkle tree.
Body (raw)
network: Solana blockchain environment (devnet/mainnet-beta)
wallet_address: The tree authority and the payer of the transaction.
max_depth_size_pair: A JSON object, e.g,
{ "max_depth": 14, "max_buffer_size": 64 }
max_depth: The maximum depth of a binary tree, such as a Merkle tree, refers to the longest distance from any leaf node to the root node. In the case of Merkle trees, each leaf node represents a piece of data and is paired with another leaf node. To determine the maximum number of nodes that can be stored in a Merkle tree based on its maximum depth, we can use the following formula:
nodes_count = 2 ^ maxDepth
. This formula calculates the total number of nodes in the tree by raising 2 to the power of the maximum depth.max_buffer_size: The maximum buffer size of a tree represents the maximum number of changes that can be made to the tree while still maintaining the validity of the root hash. In a regular tree, the root hash is a single hash that encompasses all the leaf data. Therefore, modifying any leaf node would make the proof required for any subsequent leaf node modification invalid. However, in a concurrent tree, a log of updates is maintained to keep track of these modifications for generating the necessary proofs. This log of updates is referred to as the changelog buffer, and its size is determined at the creation of the tree and is set as the
max_buffer_size
value.
So the valid values are:
canopy_depth: The "canopy depth" or "canopy size" refers to the number of proof nodes that are stored or cached on-chain for a specific proof path. This value is important in the context of storing a portion of the proof on-chain, which can impact the cost and composability of a compressed NFT collection.
fee_payer: (optional) If mentioned this is the account that will be used for paying the transaction gas fee.
Mint Compressed NFT
This API allows you to mint NFTs from an already uploaded metadata URI. Metadata_uri should open a JSON document conforming to the Metaplex Non-Fungible Token Standard. If the JSON does not confirm to the Metaplex standard, the API returns an error.
The NFT's on-chain metadata is retrieved from the off-chain metadata present at the given URI.
POST /sol/v1/nft/compressed/mint
Body (raw)
network: Solana blockchain environment (devnet/mainnet-beta)
creator_wallet: The creator/payer of the NFT.
merkle_tree: Merkle tree address.
metadata_uri: URI that contains metadata of the NFT (metaplex non-fungible-standard) in JSON file format.
max_supply: (optional) Maximum number of clones/edition mints possible for this NFT. Default 0 for one-of-a-kind NFT.
collection_address: (optional) On-chain address of the collection represented by an NFT, with max_supply of 0.
primary_sale_happend: (optional) Indicating that the first sale has happened. Default is
false
.is_mutable: (optional) - In future update NFT possible or not depends on the value. Default is
true
.receiver: (optional) Account address which will receive the newly created NFT.
is_delegate_authority: (optional) Delegate authority to the receiver. Default is
false
.fee_payer: (optional) If mentioned this is the account that will be used for paying the transaction gas fee.
priority_fee: (optional) Prioritization fee of transaction in micro Lamports. A micro Lamport is 0.000001 Lamports.
service_charge: (optional) Transaction fee to be paid by the fee_payer (if not mentioned then creator_wallet) of the transaction. This fee can be charged in SOL or any SPL-20 token. Below is the structure of the
service_charge
key.receiver: string
- An address that will receive the service charge amount.amount: number
- The amount of currency to be charged.token(optional): string
- The address of the SPL token, the service charge currency. By default, SOL is charged.
Transfer Compressed NFT
Transfer an already minted NFT from one wallet to another.
POST /sol/v1/nft/compressed/transfer
Body (raw)
network: Solana blockchain environment (devnet/mainnet-beta)
sender: Public key of the wallet to transfer from
nft_address: Address of the token to transfer
receiver: Wallet address of the receiver
fee_payer: (optional) If mentioned this is the account that will be used for paying the transaction gas fee.
priority_fee: (optional) Prioritization fee of transaction in micro Lamports. A micro Lamport is 0.000001 Lamports.
Burn Compressed NFT
Burn a particular NFT.
You will get an encoded transaction in response which you can sign in your front end or back end using the same wallet as used in the API.
We have already deployed a dev tool to sign and send transactions for quick testing https://shyft-insider.vercel.app/.
DELETE /sol/v1/nft/compressed/burn
Body (raw)
network: Solana blockchain environment (devnet/mainnet-beta)
nft_address: Address of the token to transfer
wallet_address: Owner of the NFT
priority_fee: (optional) Prioritization fee of transaction in micro Lamports. A micro Lamport is 0.000001 Lamports.
Burn Multiple Compressed NFTs
Bulk burn wallet cNFTs.
Body (raw)
network: Solana blockchain environment (devnet/mainnet-beta)
wallet_address: Source wallet address, holding the NFTs
nft_addresses: Addresses of the cNFT to burn (maximum 50 addresses are allowed)
priority_fee: (optional) Prioritization fee of transaction in micro Lamports. A micro Lamport is 0.000001 Lamports.
You can burn as many cNFTs. But a maximum of 2-3 burns could be packed in a single transaction, rest can be counted as packed as well. So in response encoded_transactions
return an array of transactions.
You will get encoded transactions in response which you can sign in your front end or back end using the same wallet as used in the API.
We have already deployed a dev tool to sign and send transactions for quick testing https://shyft-insider.vercel.app/
DELETE /sol/v1/nft/compressed/burn_many
Update Compressed NFT
Update metdata of a particular cNFT.
You will get an encoded transaction and signers in response which you can sign in your front end or back end using the same wallet as used in the API.
We have already deployed a dev tool to sign and send transactions for quick testing https://shyft-insider.vercel.app/.
Body (raw)
network: Solana blockchain environment (only
mainnet-beta
supported)authority: Either collection authority (collection NFT's update_authority) or tree owner/delegate, depending on whether the item is in a verified collection
nft_address: Addresses of the cNFT to update
name (optional): cNFT Name (max 32 char allowed)
symbol (optional): cNFT Symbol (max 10 char allowed)
metadata_uri (optional): URI that contains metadata of the NFT (metaplex non-fungible-standard) in JSON file format.
royalty: (optional) represents how much percentage of secondary sales the original creator gets. Ranges from (0-100), 0 being the original creator gets nothing and 100 being the original creator gets the entire amount from the secondary sales
primary_sale_happend (optional): A boolean that indicates whether the asset has been sold before.
is_mutable (optional): A boolean that indicates whether the asset can be updated again. When changing this to
false
, any future updates will fail.fee_payer: (optional) The account that pays the transaction gas fee.
priority_fee: (optional) Prioritization fee of transaction in micro Lamports. A micro Lamport is 0.000001 Lamports.
POST /sol/v1/nft/compressed/update
Read All Compressed NFTs ( by Owner Address)
Returns on-chain and off-chain data of all NFTs in the wallet.
GET /sol/v1/nft/compressed/read_all
Query Params
network: Solana blockchain environment (devnet/mainnet-beta)
wallet_address: Wallet address
collection: (optional) To display wallet cNFTs associated with a specific collection, you can use this filter that isolates cNFTs based on their collection address and then present them.
refresh:(optional) Include this if the cached cNFTs for this wallet need to be refreshed.
Read Compressed NFT
Returns on-chain and off-chain NFT data.
GET /sol/v1/nft/compressed/read
Query Params
network: Solana blockchain environment (devnet/mainnet-beta)
nft_address: Address of the NFT that you want to read
Read Wallet cNFTs
A paginated version of Read All Compressed NFTs API, returns the list of cNFTs in a wallet. A maximum of 50 NFTs are returned in a single API request.
GET /sol/v2/nft/compressed/read_all
Query Params
network: Solana blockchain environment (testnet/devnet/mainnet-beta)
wallet_address: Your wallet address
collection: (optional) To display wallet cNFTs associated with a specific collection, you can use this filter that isolates cNFTs based on their collection address and then present them.
refresh:(optional) Include this if the cached cNFTs for this wallet need to be refreshed.
page:(optional) Default value is 1.
size:(optional) Default value is 50.
Read Selected cNFTs
Returns on-chain and off-chain data of selected compressed NFTs.
First call might be slightly slow, we cache automatically so that subsequent calls are lightning-fast.
POST /sol/v1/nft/compressed/read_selected
Body Params
network: Solana blockchain environment (testnet/devnet/mainnet-beta)
nft_addresses: (array of strings) Selected addresses (minimum 1 and maximum 10 cNFTs could be fetched)
refresh:(optional) Include this if the cached NFTs need to be refreshed.