欢迎订阅专栏 :10分钟Solana-性能web3
搭建一个 Solana NFT 项目,核心是围绕 Anchor 框架 与 Metaplex Core 标准 展开。下面会带你走过从环境准备到合约部署的完整流程。
🔧 第一步:环境准备
在开始之前,请确保你的开发环境已安装以下工具:
| 工具 | 说明 | 版本要求 |
|---|---|---|
| Rust | Solana 合约的编程语言 | latest stable |
| Solana CLI | 与 Solana 网络交互的命令行工具 | latest |
| Anchor CLI | 核心开发框架 | v0.30.1 或更高 |
| Node.js | 运行测试脚本 | v16 或更高 |
安装命令参考:
bash
# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安装 Solana CLI
sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
# 安装 Anchor CLI (使用 avm)
cargo install --git https://github.com/solana-foundation/anchor avm --locked
avm install latest
avm use latest
安装完成后,将 Solana CLI 指向开发网(Devnet)并创建测试钱包:
bash
solana config set --url https://api.devnet.solana.com
solana-keygen new
solana airdrop 2 # 领取测试 SOL
🚀 第二步:创建 Anchor 项目
使用 anchor init 命令创建一个新项目:
bash
anchor init my-nft-project
cd my-nft-project
添加依赖 :在 programs/my-nft-project/Cargo.toml 中添加 mpl-core crate:
toml
[dependencies]
anchor-lang = "0.30.1"
mpl-core = { version = "0.8.0", features = ["anchor"] } # 启用 anchor 功能
📝 第三步:编写 NFT 合约
打开 programs/my-nft-project/src/lib.rs,编写一个创建 NFT Collection 和铸造 NFT 的合约:
rust
use anchor_lang::prelude::*;
use mpl_core::{
ID as MPL_CORE_ID,
accounts::BaseCollectionV1,
instructions::CreateV2CpiBuilder,
};
declare_id!("你的程序ID");
#[program]
pub mod my_nft_project {
use super::*;
/// 创建 NFT Collection
pub fn create_collection(
ctx: Context<CreateCollection>,
name: String,
uri: String,
) -> Result<()> {
// 使用 CPI 调用 Metaplex Core 程序创建 Collection
let cpi_program = ctx.accounts.mpl_core_program.to_account_info();
CreateV2CpiBuilder::new(cpi_program)
.collection(&ctx.accounts.collection.to_account_info())
.payer(&ctx.accounts.payer.to_account_info())
.authority(Some(&ctx.accounts.authority.to_account_info()))
.system_program(&ctx.accounts.system_program.to_account_info())
.name(name)
.uri(uri)
.invoke()?;
Ok(())
}
/// 铸造 NFT 到 Collection
pub fn mint_nft(
ctx: Context<MintNft>,
name: String,
uri: String,
) -> Result<()> {
let cpi_program = ctx.accounts.mpl_core_program.to_account_info();
CreateV2CpiBuilder::new(cpi_program)
.asset(&ctx.accounts.asset.to_account_info())
.collection(Some(&ctx.accounts.collection.to_account_info()))
.payer(&ctx.accounts.payer.to_account_info())
.authority(Some(&ctx.accounts.authority.to_account_info()))
.system_program(&ctx.accounts.system_program.to_account_info())
.name(name)
.uri(uri)
.invoke()?;
Ok(())
}
}
/// CreateCollection 指令的账户结构
#[derive(Accounts)]
pub struct CreateCollection<'info> {
/// 新的 Collection 账户 (需是新生成的密钥对)
#[account(mut)]
pub collection: Signer<'info>,
/// 支付交易费用
#[account(mut)]
pub payer: Signer<'info>,
/// 拥有管理权限的账户
pub authority: Signer<'info>,
/// 系统程序
pub system_program: Program<'info, System>,
/// Metaplex Core 程序
#[account(address = MPL_CORE_ID)]
pub mpl_core_program: Program<'info, System>,
}
/// MintNft 指令的账户结构
#[derive(Accounts)]
pub struct MintNft<'info> {
/// 新的 Asset 账户
#[account(mut)]
pub asset: Signer<'info>,
/// 目标 Collection 账户 (需已存在)
pub collection: Account<'info, BaseCollectionV1>,
/// 支付交易费用
#[account(mut)]
pub payer: Signer<'info>,
/// 拥有管理权限的账户
pub authority: Signer<'info>,
/// 系统程序
pub system_program: Program<'info, System>,
/// Metaplex Core 程序
#[account(address = MPL_CORE_ID)]
pub mpl_core_program: Program<'info, System>,
}
代码要点:
- 使用 CPI(跨程序调用) 调用 Metaplex Core 程序来创建 Collection 和 Asset
BaseCollectionV1是 Core 标准中 Collection 的账户类型CreateV2CpiBuilder是 Core 提供的 CPI 构建器- Collection 账户必须是新生成的密钥对,不能重用已有地址
🏗️ 第四步:构建与部署
构建合约:
bash
anchor build
部署到 Devnet:
bash
anchor deploy
部署成功后,控制台会打印出程序的 Program ID 。将其更新到 lib.rs 的 declare_id! 宏中。
🧪 第五步:编写测试
在 tests/my-nft-project.ts 中编写测试脚本,使用 TypeScript 与合约交互:
typescript
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { MyNftProject } from "../target/types/my_nft_project";
describe("my-nft-project", () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.MyNftProject as Program<MyNftProject>;
it("创建 Collection 并铸造 NFT", async () => {
// 生成 Collection 的密钥对
const collectionKeypair = anchor.web3.Keypair.generate();
// 调用 createCollection 指令
await program.methods
.createCollection("My Collection", "https://example.com/collection.json")
.accounts({
collection: collectionKeypair.publicKey,
payer: provider.wallet.publicKey,
authority: provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
mplCoreProgram: new anchor.web3.PublicKey("CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d"),
})
.signers([collectionKeypair, provider.wallet.payer])
.rpc();
// 生成 Asset 的密钥对
const assetKeypair = anchor.web3.Keypair.generate();
// 调用 mintNft 指令
await program.methods
.mintNft("My NFT", "https://example.com/nft.json")
.accounts({
asset: assetKeypair.publicKey,
collection: collectionKeypair.publicKey,
payer: provider.wallet.publicKey,
authority: provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
mplCoreProgram: new anchor.web3.PublicKey("CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d"),
})
.signers([assetKeypair, provider.wallet.payer])
.rpc();
});
});
运行测试:
bash
anchor test
这会自动启动本地验证器、部署程序并执行测试。
🧠 理解 Metaplex Core 的核心概念
上面的代码中多次提到了几个 Core 的核心概念,理解它们有助于你更好地开发和定制:
| 概念 | 说明 |
|---|---|
| Asset | Core 标准中的 NFT,采用单账户设计,将所有权和元数据存储在 Asset 自身,而非依赖多个账户 |
| Collection | NFT 的集合,用于组织和管理一组 Asset,共享元数据和插件 |
| Plugin(插件) | Core 的扩展机制,可以为 Asset 或 Collection 附加版税(Royalties) 、冻结(Freeze) 、属性(Attributes) 等功能 |
| CPI(跨程序调用) | 从你的程序调用 Metaplex Core 程序的方式来创建和管理 Asset |
📚 资源与进阶
| 资源 | 说明 |
|---|---|
| Metaplex Core 官方文档 | 最权威的参考,涵盖所有指南和 API |
| 在 Anchor 中使用 Metaplex Core | 官方中文指南,涵盖安装、账户反序列化、CPI 模式 |
| 创建 Core Asset | 使用 JavaScript SDK 创建 NFT 的指南 |
| 创建 Core Collection | 创建 Collection 的详细说明 |
建议阅读顺序:
- 先通读 在 Anchor 中使用 Metaplex Core 了解基础
- 参考示例项目
smart-contract-using-the-latest-Metaplex-mpl-core-Anchor-dependencies - 根据业务需求为 NFT 添加插件(如版税、属性等)
如果需要深入了解某个具体环节(如插件系统、Candy Machine 集成等),可以随时告诉我。