You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用@solana/web3调用Solana智能合约的指定端点

Solana多指令智能合约调用实现方案

核心原理

Solana智能合约没有传统后端的"接口端点"概念,你提到的不同调用入口对应合约里的MetadataInstruction枚举变体。合约会将你传入交易的data字段反序列化为枚举实例,再匹配到对应的处理逻辑。
枚举序列化后的二进制结构固定为:【1字节指令标识】+【该指令对应参数的序列化数据】,其中指令标识和枚举定义顺序一一对应,比如你贴出的代码里第一个变体CreateMetadataAccount标识为0,第二个UpdateMetadataAccount标识为1,以此类推,合约就是靠这个标识判断你要调用的逻辑。

方案1:使用官方封装SDK(推荐,无需手动处理序列化)

Metaplex官方已经封装了所有Token Metadata合约的指令构造逻辑,直接调用即可,无需手动处理序列化和账户顺序问题。
首先安装依赖:
npm install @solana/web3.js @metaplex-foundation/mpl-token-metadata

调用示例(以创建元数据账户为例):

import { Connection, Keypair, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
import { createCreateMetadataAccountV3Instruction } from "@metaplex-foundation/mpl-token-metadata";

// 初始化链上连接和签名钱包
const connection = new Connection("你的Solana RPC节点地址");
const payer = Keypair.fromSecretKey(Uint8Array.from(你的钱包私钥数组));

// 提前计算元数据账户PDA地址、准备mint相关地址
const metadataPda = // 用findProgramAddressSync计算得到的元数据账户地址
const mintAddress = // 对应NFT的mint公钥
const mintAuthority = payer.publicKey;
const updateAuthority = payer.publicKey;

// 直接调用封装好的指令构造方法
const instruction = createCreateMetadataAccountV3Instruction(
  {
    metadata: metadataPda,
    mint: mintAddress,
    mintAuthority: mintAuthority,
    payer: payer.publicKey,
    updateAuthority: updateAuthority,
  },
  {
    createMetadataAccountArgsV3: {
      data: {
        name: "NFT显示名称",
        symbol: "NFT符号",
        uri: "链下元数据存储地址",
        sellerFeeBasisPoints: 500, // 版税比例,单位0.01%,500对应5%
        creators: null,
        collection: null,
        uses: null,
      },
      isMutable: true,
      collectionDetails: null,
    }
  }
);

// 发送交易上链确认
const txHash = await sendAndConfirmTransaction(
  connection,
  new Transaction().add(instruction),
  [payer]
);

其他指令比如更新元数据、创建主版本等,直接找SDK中对应的createXXXInstruction前缀方法,按照参数要求填充即可。

方案2:手动构造指令(无额外SDK依赖)

如果不想引入mpl专属SDK,也可以手动按合约要求构造指令:

  1. 确认要调用的指令对应的标识序号,和合约MetadataInstruction枚举的定义顺序完全对应
  2. 用Borsh序列化工具,按合约定义的参数结构序列化参数,拼在指令标识字节的后面作为交易的data字段
  3. 按合约要求的顺序填充keys账户数组,每个账户的isSigner、isWritable属性必须和合约要求完全一致

首先安装基础依赖:
npm install @solana/web3.js borsh buffer

手动构造示例:

import * as borsh from "borsh";
import { Connection, Keypair, PublicKey, Transaction, TransactionInstruction, sendAndConfirmTransaction } from "@solana/web3.js";
import { Buffer } from "buffer";

// 1. 定义和合约完全匹配的参数结构体
class CreateMetadataAccountArgs {
  constructor(args) {
    this.data = args.data;
    this.is_mutable = args.is_mutable;
  }
}

// 2. 定义Borsh序列化规则,字段顺序、类型必须和Rust合约完全一致
const CreateMetadataAccountArgsSchema = new Map([
  [CreateMetadataAccountArgs, {
    kind: "struct",
    fields: [
      ["data", [
        "struct", 
        [
          ["name", "string"],
          ["symbol", "string"],
          ["uri", "string"],
          ["seller_fee_basis_points", "u16"],
          ["creators", { kind: "option", type: [
            "struct", [
              ["address", "pubkey"],
              ["verified", "u8"],
              ["share", "u8"]
            ]
          ]}],
          ["collection", { kind: "option", type: "pubkey" }],
          ["uses", { kind: "option", type: "u64" }],
        ]
      ]],
      ["is_mutable", "u8"],
    ]
  }]
]);

// 3. 填充参数并序列化
const args = new CreateMetadataAccountArgs({
  data: {
    name: "测试NFT",
    symbol: "TEST",
    uri: "https://你的元数据地址.json",
    seller_fee_basis_points: 500,
    creators: null,
    collection: null,
    uses: null
  },
  is_mutable: 1
});
const serializedArgs = borsh.serialize(CreateMetadataAccountArgsSchema, args);

// 4. 拼接指令标识:CreateMetadataAccount是第一个枚举变体,标识为0(1字节)
const instructionData = Buffer.concat([Buffer.from([0]), Buffer.from(serializedArgs)]);

// 5. 构造交易指令,账户顺序必须和合约要求完全一致
const instruction = new TransactionInstruction({
  keys: [
    { pubkey: metadataPda, isSigner: false, isWritable: true },
    { pubkey: mintAddress, isSigner: false, isWritable: false },
    { pubkey: mintAuthority, isSigner: true, isWritable: false },
    { pubkey: payer.publicKey, isSigner: true, isWritable: true },
    { pubkey: updateAuthority, isSigner: false, isWritable: false },
    { pubkey: new PublicKey("SysvarRent111111111111111111111111111111111"), isSigner: false, isWritable: false },
  ],
  programId: new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"), // Token Metadata固定程序ID
  data: instructionData
});

// 6. 发送交易
const txHash = await sendAndConfirmTransaction(
  connection,
  new Transaction().add(instruction),
  [payer]
);

注意事项

  • keys数组的账户顺序、是否签名、是否可写三个属性必须和合约要求完全匹配,否则会执行失败
  • 参数序列化的结构、字段顺序、类型必须和Rust合约的定义完全一致,否则会触发反序列化错误
  • 指令标识必须和枚举定义的顺序对应,填错会匹配到错误的处理逻辑

内容的提问来源于stack exchange,提问作者Max Campbell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 03:24:03