A Solana program for minting compressed NFTs (cNFTs) using Metaplex Bubblegum.
- Merkle Tree creation 2JYmC87AQHSAx3Htz7aqFWs1opwHcG4nKVihDWvRbyfXyu5UWAaDYNwM26pHSFDwwkcj3LJjof4HUe1dtBNFjqy3
This program provides functionality to mint compressed NFTs on Solana using the Metaplex Bubblegum protocol. Compressed NFTs are significantly cheaper to mint than traditional NFTs because they use Merkle trees and state compression.
- ✅ Mint single compressed NFTs
- ✅ Batch mint multiple compressed NFTs
- ✅ Support for creators and collections
- ✅ Full TypeScript client support
- Rust (latest stable version)
- Solana CLI (v1.18.0 or later)
- Anchor (v0.29.0 or later)
- Node.js (v18 or later)
- Yarn or npm
- Clone the repository:
git clone <your-repo-url>
cd bubbblegum- Install dependencies:
yarn install
# or
npm install- Build the program:
anchor build- Configure Solana CLI for localnet:
solana config set --url localhost- Generate a keypair if you don't have one:
solana-keygen new- Start a local validator:
solana-test-validator- In a new terminal, deploy the program:
anchor deployThis calls Bubblegum directly without going through the wrapper program:
import { mintCnft, createCreator } from "./client/mintCnft";
import { PublicKey, Keypair } from "@solana/web3.js";
const metadata = {
name: "My Compressed NFT",
symbol: "MCNFT",
uri: "https://example.com/metadata.json",
sellerFeeBasisPoints: 500, // 5%
creators: [
createCreator(payer.publicKey, 100, true),
],
};
const signature = await mintCnft(
program,
connection,
payer,
treeConfig,
merkleTree,
leafOwner,
metadata
);This uses your deployed wrapper program (useful if you want to add custom logic):
import { mintCnftViaWrapper, createCreator } from "./client/mintCnftWrapper";
const metadata = {
name: "My Compressed NFT",
symbol: "MCNFT",
uri: "https://example.com/metadata.json",
sellerFeeBasisPoints: 500, // 5%
creators: [
createCreator(payer.publicKey, 100, true),
],
};
const signature = await mintCnftViaWrapper(
program,
connection,
payer,
treeConfig,
merkleTree,
leafOwner,
metadata
);Direct Bubblegum call:
import { mintCnftBatch } from "./client/mintCnft";
const metadataList = [
{
name: "NFT #1",
symbol: "COLL",
uri: "https://example.com/1.json",
sellerFeeBasisPoints: 500,
},
{
name: "NFT #2",
symbol: "COLL",
uri: "https://example.com/2.json",
sellerFeeBasisPoints: 500,
},
];
const signature = await mintCnftBatch(
program,
connection,
payer,
treeConfig,
merkleTree,
leafOwner,
metadataList
);Using wrapper program:
import { mintCnftBatchViaWrapper } from "./client/mintCnftWrapper";
const signature = await mintCnftBatchViaWrapper(
program,
connection,
payer,
treeConfig,
merkleTree,
leafOwner,
metadataList
);programs/bubbblegum/src/lib.rs- Main program logic (wrapper that calls Bubblegum via CPI)client/mintCnft.ts- TypeScript client functions (direct Bubblegum calls)client/mintCnftWrapper.ts- TypeScript client functions (via wrapper program)tests/bubbblegum.ts- Test suitetests/helpers/tree.ts- Helper functions for tree managementexamples/mint-example.ts- Complete example script
-
Merkle Tree Setup: Before minting, you need to create a Merkle tree using the Bubblegum SDK. See
tests/helpers/tree.tsfor an example. -
Tree Authority: The tree authority must sign transactions for minting. Make sure the payer is the tree authority or has been delegated.
-
Program ID: When you build the program with
anchor build, Anchor will generate a new program ID. The placeholder ID in the code will be automatically replaced. After building, updateAnchor.tomlwith the generated program ID. -
Direct vs Wrapper:
- Direct calls (
mintCnft.ts) call Bubblegum directly - simpler and more efficient - Wrapper calls (
mintCnftWrapper.ts) go through your program - useful if you want to add custom validation or logic
- Direct calls (
-
Costs: Compressed NFTs are much cheaper than regular NFTs, but you still need SOL for transaction fees.
Run the test suite:
anchor testanchor deploy- Update
Anchor.tomlto use devnet - Build and deploy:
anchor build
anchor deploy --provider.cluster devnet- Update
Anchor.tomlto use mainnet - Build and deploy:
anchor build
anchor deploy --provider.cluster mainnetMIT