什么是压缩 NFT(cNFT)
🔍 压缩 NFT(Compressed NFT,简称 cNFT) 通过 State Compression(状态压缩) 把 NFT 的全部元数据做一次性哈希处理,仅把根哈希存入链上的 Merkle 树账户,从而将节点存储成本拉低到传统铸造方式的千分之一:
- 传统方式铸造 100 万枚 NFT,需约 24,000 SOL
- 压缩方式铸造 100 万枚 cNFT,仅需 ≤ 10 SOL
核心关键词:压缩 NFT、cNFT、State Compression、Merkle 树、低成本、批量铸造
实现路径拆解
- NFT 元数据做哈希 → 存为「叶子」
- Merkle 树逐级合并 → 生成 32 字节「根哈希」
- RPC 服务商提前索引元数据 → 提供 Read API 随时查询
Concurrent Merkle 树的三把钥匙
为了让多枚叶子(=NFT)在同区块里并发修改而互不阻塞,Solana 采用 concurrent Merkle 树,需人工定义三项参数:
| 参数 | 作用 | 经济权衡 |
|---|---|---|
| maxDepth | 决定叶子总量 2^maxDepth | ↑越大 → 支持越多 NFT,账户初始化费用↑ |
| maxBufferSize | 同一 slot 可并发写数量 | ↑越大 → 支持密集销售,账户规模↑ |
| canopyDepth | 上链缓存的证明节点层级 | ↑越大 → 后续验证更轻,费用↑ |
选择思路:
- 预估 NFT 总量 → 取 maxDepth = ⌈log2(总量)⌉
- 铸造高峰期并发数 → maxBufferSize
- 是否需要复杂链上交互(如实时报价、挂单) → 提升 canopyDepth
简易 6 步创建你的第一条 cNFT 系列
1. 创建项目
mkdir cnft-demo && cd cnft-demo
npm init -y
npm install @metaplex-foundation/mpl-bubblegum \
@solana/web3.js \
umi @metaplex-foundation/umi \
@metaplex-foundation/umi-bundle-defaults \
@metaplex-foundation/umi-signer-wallet-adapters \
@metaplex-foundation/umi-plugin-bundle \
@metaplex-foundation/umi-public-keys \
@metaplex-foundation/mpl-token-metadata \
esrun2. 准备 Collection NFT
- 使用 Token Metadata Program 先铸造一张「合集 NFT」,作为后续全部 cNFT 的父级。
3. 初始化 Merkle 树账户
创建 create-tree.ts:
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { dasApi } from '@metaplex-foundation/digital-asset-standard-api'
import { mplBubblegum } from '@metaplex-foundation/mpl-bubblegum'
import { createTree } from '@metaplex-foundation/mpl-bubblegum'
import { signerIdentity, generateSigner } from '@metaplex-foundation/umi'
const umi = createUmi('https://api.devnet.solana.com').use(mplBubblegum()).use(dasApi())
// .use(keypairIdentity(你的密钥对))
const merkleTree = generateSigner(umi)
await createTree(umi, {
merkleTree,
maxDepth: 20, // 100 万
maxBufferSize: 64, // 并发适中
canopyDepth: 14, // 方便后续验证
public: false // 只有创建者可铸造
}).sendAndConfirm(umi)
console.log('Tree:', merkleTree.publicKey.toString())执行:
npx esrun create-tree.ts4. 铸造 cNFT
新建 mint.ts:
await mintToCollectionV1(umi, {
leafOwner: 目标钱包,
merkleTree: merkleTree.publicKey,
collection: 你的CollectionNFT.publicKey,
metadata: {
name: 'Demo cNFT',
uri: 'https://your-cdn.com/metadata/1.json',
sellerFeeBasisPoints: 500,
creators: [{address: 你的地址, verified: true, share: 100}]
},
}).sendAndConfirm(umi)5. 读取数据
fetch.ts
const assetId = findLeafAssetIdPda(umi, {merkleTree: merkleTree.publicKey, leafIndex: 0})
const asset = await umi.rpc.getAsset(assetId[0])
console.log(asset.content.metadata)6. Transfer
transfer.ts
const res = await transfer(umi, {
leafOwner: 原持有钱包,
newLeafOwner: 新钱包,
merkleTree: merkleTree.publicKey,
assetId: assetId[0],
})常见问题与解答
Q1:把元数据仅存在链上哈希,会不会哪天完全丢失?
A:不会。通过 State Compression 铸造的每一笔数据都写入 Solana 账本的最早交易日志,目前主流 RPC 商同步无限期存档;即便单一节点过期,也可全链重放获取原始数据。
Q2:我能自由调整 Merkle 树的三把钥匙吗?
A:只能一次性设定;预算允许可把 maxDepth 取大,当未来 NFT 数量超出时再建新树即可。
Q3:传统钱包是否支持展示 cNFT?
A:需 RPC 端支持 Digital Asset Standard(DAS)Read API;主流插件钱包已陆续适配,Zero、Glow、OK 钱包测试通过。
Q4:用户如何知道 cNFT 属于哪个合集?
A:铸造时必须绑定 Collection NFT 的 Mint ID;链上验证其母合集的署名。
Q5:我能在链上直接改动 cNFT 元数据 URI 吗?
A:可以,通过 Bubblegum 的 updateMetadata 指令改写叶子值即可,但需重新计算 Merkle 证明并提供完整路径。
Q6:成本极限可降低多少?
A:实测 Devnet 单枚 cNFT 总 Gas 成本 ~0.000005 SOL;相较传统 Token Metadata 减少 99%+。
接下来的挑战
- 将脚本改成在 mainnet 批量铸造真实项目
- 打造前端 UI,支持用户一键 mint cNFT
- 在 anchor 合约内动态铸造并转赠 cNFT 给游戏玩家
你已经掌握了 Solana 低成本批量发行数字资产的核心武器,接下来就交给创意与实践了!