7. 开发环境与 Umi SDK

开发环境与 Umi SDK

1. 为什么是 Umi?

在 Solana 开发的早期,开发者主要使用 @solana/web3.js。虽然它功能强大,但对于 NFT 开发来说,它过于底层且繁琐。你需要手动处理序列化、账户结构布局和复杂的指令构建。

Umi 是 Metaplex 推出的现代化 Solana 客户端框架,专门为解决这些痛点而生。

核心优势

  • 统一接口:所有 Metaplex 程序(Metadata, Core, Candy Machine)都使用一致的 API 风格。
  • 类型安全:基于 TypeScript,提供极致的代码补全和类型检查体验。
  • 模块化插件:内核极小,通过 .use() 按需加载功能模块,类似于 Express 或 Koa。
  • 零依赖:不强制依赖 @solana/web3.js,使得它在浏览器和 Node.js 环境中都更轻量。

2. 项目初始化

首先,我们需要搭建一个标准的 TypeScript 项目环境。

bash
# 1. 创建项目目录 mkdir solana-nft-project cd solana-nft-project # 2. 初始化 npm 项目 npm init -y # 3. 安装核心依赖 npm install @metaplex-foundation/umi \ @metaplex-foundation/umi-bundle-defaults \ @metaplex-foundation/mpl-token-metadata \ @metaplex-foundation/mpl-core \ @solana/web3.js # 4. 安装开发依赖 (TypeScript) npm install --save-dev typescript ts-node @types/node # 5. 初始化 tsconfig npx tsc --init

3. Umi 实例配置 (The "Umi Context")

Umi 的核心是一个上下文对象 (Context)。你需要像搭积木一样配置它。

基础配置代码

新建 src/setup.ts

typescript
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'; import { keypairIdentity } from '@metaplex-foundation/umi'; import { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata'; import { mplCore } from '@metaplex-foundation/mpl-core'; import fs from 'fs'; import os from 'os'; export function createUmiInstance() { // 1. 连接 RPC 节点 (这里使用 Devnet) const umi = createUmi('https://api.devnet.solana.com'); // 2. 加载本地钱包 (id.json) // 这是你执行交易时的 "Signer" (签名者) const keypairPath = `${os.homedir()}/.config/solana/id.json`; const keypairData = JSON.parse(fs.readFileSync(keypairPath, 'utf-8')); // 将私钥转换为 Umi 的 Keypair 格式 const keypair = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(keypairData)); // 3. 注册插件 umi.use(keypairIdentity(keypair)) // 设置默认身份 .use(mplTokenMetadata()) // 启用旧版 NFT 支持 .use(mplCore()); // 启用 Core 标准支持 return umi; }

4. 核心概念解析

Signer (签名者)

在 Umi 中,能够签署交易的实体被称为 Signer

  • Identity: 你的默认身份。当你调用 createNft(umi, ...) 时,如果没有指定 payer,默认就是 umi.identity
  • Generated Signer: 临时的签名者(例如新创建的 Mint 账户,它需要签名一次以证明拥有该地址)。
typescript
import { generateSigner } from '@metaplex-foundation/umi'; // 创建一个新的随机账户 (作为 Mint) const mintSigner = generateSigner(umi); console.log(mintSigner.publicKey);

PublicKey (公钥)

Umi 使用自己的 PublicKey 类型,而不是 @solana/web3.js 的。这虽然增加了一点转换成本,但带来了更好的类型安全。

typescript
import { publicKey } from '@metaplex-foundation/umi'; // 从字符串创建 const myKey = publicKey('11111111111111111111111111111111');

Transaction Builder (交易构建器)

Umi 的操作通常返回一个 Builder 对象。你可以链式添加指令,最后再发送。

typescript
// 简单模式:构建并立即发送 await createNft(umi, { ... }).sendAndConfirm(umi); // 高级模式:组合多个指令 const builder = transactionBuilder() .add(createNft(umi, { ... })) .add(verifyCollection(umi, { ... })); await builder.sendAndConfirm(umi);

5. 你的第一个脚本:检查余额

让我们编写 src/index.ts 来验证环境是否配置成功。

typescript
import { createUmiInstance } from './setup'; import { sol } from '@metaplex-foundation/umi'; async function main() { const umi = createUmiInstance(); console.log("🔗 连接到:", umi.rpc.getEndpoint()); console.log("👤 当前身份:", umi.identity.publicKey); // 获取余额 const balance = await umi.rpc.getBalance(umi.identity.publicKey); // Umi 的金额处理更人性化 // balance 是一个带单位的对象: { basisPoints: 1500000000n, identifier: 'SOL', decimals: 9 } console.log(`💰 余额: ${Number(balance.basisPoints) / 1e9} SOL`); if (balance.basisPoints < sol(0.1).basisPoints) { console.warn("⚠️ 余额不足,请运行 'solana airdrop 2' 补充燃料!"); } } main();

运行它:

bash
npx ts-node src/index.ts
JSPlayground
EDITOR ACTIVE
Initializing JS Environment...

Umi 实例构建器

1. Create Instance
2. Set Identity
3. Register Plugins
const umi = ...
RPC Interface
Not Connected
Identity (Signer)
Anonymous
Plugins Registry
Empty