7. Metaplex 代币元数据
虽然 Token-2022 提供了内置的元数据扩展,但 Metaplex 的 Token Metadata 程序仍然是 Solana 生态中最广泛使用的元数据方案,特别是在 NFT 领域。
7.1 为什么需要元数据
原生的 SPL Token 只存储数学信息:供应量、精度、权限。钱包显示代币时需要知道:
- 代币名称(如 "USD Coin")
- 符号(如 "USDC")
- Logo 图片
- 项目描述
- 其他属性
没有元数据,用户在钱包中只会看到一串无意义的地址。
7.2 Metadata Account 结构
Metaplex 使用独立的 Metadata Account 存储代币信息。这个账户通过 PDA 机制与 Mint 账户关联:
Metadata PDA = findProgramAddress( ["metadata", METADATA_PROGRAM_ID, MINT_ADDRESS], METADATA_PROGRAM_ID )
核心字段:
tsxinterface Metadata { // 基础信息 name: string; // 代币名称(最多 32 字符) symbol: string; // 交易符号(最多 10 字符) uri: string; // 指向链下 JSON 的 URL // 权限控制 updateAuthority: PublicKey; // 谁可以修改元数据 isMutable: boolean; // 是否允许修改 // 版税(主要用于 NFT) sellerFeeBasisPoints: number; // 二次销售版税 (如 500 = 5%) creators: Creator[]; // 创作者及分成比例 // 集合(主要用于 NFT) collection: Collection | null; uses: Uses | null; }
7.3 使用 Metaplex SDK
安装依赖:
bashnpm install @metaplex-foundation/mpl-token-metadata @metaplex-foundation/umi @metaplex-foundation/umi-bundle-defaults
创建带元数据的代币:
tsx// create-token-with-metaplex.ts import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'; import { mplTokenMetadata, createV1, TokenStandard } from '@metaplex-foundation/mpl-token-metadata'; import { generateSigner, percentAmount, keypairIdentity } from '@metaplex-foundation/umi'; import { loadWallet } from './config'; async function createTokenWithMetaplex() { // 初始化 Umi const umi = createUmi('https://api.devnet.solana.com') .use(mplTokenMetadata()); // 加载钱包 const wallet = loadWallet(); const umiKeypair = umi.eddsa.createKeypairFromSecretKey(wallet.secretKey); umi.use(keypairIdentity(umiKeypair)); // 生成 Mint 密钥对 const mint = generateSigner(umi); console.log('创建带 Metaplex 元数据的代币...'); // 创建代币(同时创建 Mint 和 Metadata) await createV1(umi, { mint, name: 'Solana University Token', symbol: 'SOLU', uri: 'https://arweave.net/your-metadata-json', sellerFeeBasisPoints: percentAmount(0), // 无版税 decimals: 6, tokenStandard: TokenStandard.Fungible, }).sendAndConfirm(umi); console.log('创建成功!'); console.log('Mint 地址:', mint.publicKey); } createTokenWithMetaplex();
7.4 更新元数据
如果元数据设置为可变(isMutable = true),可以后续更新:
tsx// update-metadata.ts import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'; import { mplTokenMetadata, updateV1, fetchMetadataFromSeeds } from '@metaplex-foundation/mpl-token-metadata'; import { publicKey, keypairIdentity } from '@metaplex-foundation/umi'; import { loadWallet } from './config'; async function updateMetadata(mintAddress: string) { const umi = createUmi('https://api.devnet.solana.com') .use(mplTokenMetadata()); const wallet = loadWallet(); const umiKeypair = umi.eddsa.createKeypairFromSecretKey(wallet.secretKey); umi.use(keypairIdentity(umiKeypair)); const mint = publicKey(mintAddress); // 获取当前元数据 const metadata = await fetchMetadataFromSeeds(umi, { mint }); console.log('当前名称:', metadata.name); // 更新元数据 await updateV1(umi, { mint, data: { ...metadata, name: 'Updated Token Name', symbol: 'NEW', }, }).sendAndConfirm(umi); console.log('更新成功!'); }
7.5 链下元数据 JSON 规范
URI 指向的 JSON 文件应遵循以下格式:
json{ "name": "Solana University Token", "symbol": "SOLU", "description": "Solana 大学官方学习激励代币,用于奖励优秀学员", "image": "https://arweave.net/your-logo-image", "external_url": "https://academy.soldevcamp.com", "attributes": [], "properties": { "category": "currency", "files": [ { "uri": "https://arweave.net/your-logo-image", "type": "image/png" } ] } }
链下存储选择:
| 方案 | 特点 | 适用场景 |
|---|---|---|
| Arweave | 永久存储,一次付费 | NFT、长期项目 |
| IPFS + Pinata | 需要持续付费维护 | 一般项目 |
| AWS S3 / 云存储 | 中心化,但便宜稳定 | 开发测试、内部项目 |