If you are still NFT Twitter adjacent, you've seen a firehouse of tweets about compressed NFTs. Just like with Candy Machine V1, they are all the rage. Today we are focused on step one of minting a compressed NFT, minting a tree on-chain
.
I've found a few great explanations on what compressed NFTs are:
Alchemy's: What are compressed NFTs?
Metaplex's: Expanding Digital Assets with Compression for NFTs
The main goal of compressed NFTs is to dramatically decrease the cost of minting to greatly widen the adoption of Solana NFTs.
When working with toy Solana projects, I've found that using a Next.js app is the best way to get started quickly. In my experience, you need a node server to work with Metaplex code. With the api folder, you can get a lot done without having to worry about compatibility and code splitting.
Getting started
We need to install relevant dependencies
npm install @solana/spl-account-compression @solana/web3.js @metaplex-foundation/mpl-bubblegum @mintee/wrapped-connection
The first part of working with compressed NFTs is familiarizing yourself with the connection wrapper. If you follow any example, you will see that it extends the normal @solana/web3.js
Connection class with some helpers around Keypairs and compressed NFTs. You pass in your RPC URL and a keypair to sign/pay for transactions.
import WrappedConnection from "@mintee/wrapped-connection"
import {
Keypair,
PublicKey,
SystemProgram,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
const keypair = new Keypair()
const connectionWrapper = WrappedConnection.getConnectionWrapper("https://api.mainnet-beta.solana.com", keypair);
We are going to define a function called mintTree()
. When minting an account to hold your tree, you need to define the depth and buffer size. 2^{DEPTH} is the capacity of the tree.
When working with Solana, you have to calculate how large the account size needs to be upfront. When working with compressed NFTs, you have a higher up-front cost, but each mint is cheaper.
export async function mintTree() {
const payer = connectionWrapper.payer.publicKey;
const treeKeypair = new Keypair();
const maxDepth = 14
const maxBufferSize = 64
// create account size based on number of NFTs
const space = getConcurrentMerkleTreeAccountSize(maxDepth, maxBufferSize);
// get tree authority
const [treeAuthority, _bump] = await PublicKey.findProgramAddressSync(
[treeKeypair.publicKey.toBuffer()],
BUBBLEGUM_PROGRAM_ID
);
Now that we have created the instructions for minting an account we need to write the transactions for allocating the account and creating the tree.
const createTreeIx = createCreateTreeInstruction(
{
merkleTree: treeKeypair.publicKey,
treeAuthority,
treeCreator: payer,
payer,
logWrapper: SPL_NOOP_PROGRAM_ID,
compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
},
{
maxBufferSize,
maxDepth,
public: false,
},
BUBBLEGUM_PROGRAM_ID
);
let tx = new Transaction().add(allocTreeIx).add(createTreeIx);
tx.feePayer = payer;
After sending the transaction we will get back an assetId. The assetId is a PDA of Bubblegum. It the equivalent of a token address. This is where compressed NFTs get controversial. They are a pretty unique RPC extension, so if you mint a compressed NFT on Helius per se, you have to use that RPC to get back the info.
try {
await sendAndConfirmTransaction(
connectionWrapper,
tx,
[treeKeypair, connectionWrapper.payer],
{
commitment: "confirmed",
skipPreflight: true,
}
);
console.log(
"Successfull created merkle tree for account: " + treeKeypair.publicKey
);
return treeKeypair.publicKey;
} catch (e) {
console.error("Failed to create merkle tree: ", e);
throw e;
}
}
Top comments (1)
🔥