LogoAnchor 中文文档

TypeScript

学习如何使用 Anchor 的 TypeScript 客户端库与 Solana 程序交互

Anchor 提供了一个 TypeScript 客户端库 (@coral-xyz/anchor) 简化了在 JavaScript 或 TypeScript 中与 Solana 程序交互的过程。

@coral-xyz/anchor 库仅与 @solana/web3.js@solana/spl-token 的旧版本 (v1) 兼容。与 @solana/web3.js 的新版本 (v2) 不兼容。

客户端程序

要使用 @coral-xyz/anchor 与 Anchor 程序交互,您需要使用程序的 IDL 文件 创建一个 Program 实例。

创建 Program 实例需要程序的 IDL 和一个 AnchorProviderAnchorProvider 是一个结合了以下两项的抽象:

  • Connection - 连接到 Solana 集群(如 localhost、devnet、mainnet)
  • Wallet - (可选)用于支付和签署交易的默认钱包

在使用 Solana wallet adapter 进行前端集成时,您需要 设置 AnchorProviderProgram

example
import { Program, AnchorProvider, setProvider } from "@coral-xyz/anchor";
import { useAnchorWallet, useConnection } from "@solana/wallet-adapter-react";
import type { HelloAnchor } from "./idlType";
import idl from "./idl.json";
 
const { connection } = useConnection();
const wallet = useAnchorWallet();
 


const provider = new AnchorProvider(connection, wallet, {});
setProvider(provider);
 


export const program = new Program(idl as HelloAnchor, {
  connection,
});

在上面的代码片段中:

  • idl.json 是 Anchor 生成的 IDL 文件,位于 Anchor 项目的 /target/idl/<program-name>.json 中。
  • idlType.ts 是 IDL 类型(用于 TypeScript),位于 Anchor 项目的 /target/types/<program-name>.ts 中。

或者,您可以仅使用 IDL 和到 Solana 集群的 Connection 创建 Program 实例。这意味着没有默认的 Wallet,但允许您使用 Program 获取账户或构建指令而无需连接的钱包。

import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
import { Program } from "@coral-xyz/anchor";
import type { HelloAnchor } from "./idlType";
import idl from "./idl.json";
 
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
 


export const program = new Program(idl as HelloAnchor, {
  connection,
});

调用指令

一旦使用程序的 IDL 文件设置了 Program,您可以使用 Anchor 的 MethodsBuilder 来:

  • 构建单独的指令
  • 构建交易
  • 构建并发送交易

基本格式如下所示:

program.methods - 这是从程序的 IDL 创建指令调用的构建器 API



await program.methods
  .instructionName(instructionData)
  .accounts({})
  .signers([])
  .rpc();

Anchor 提供了多种构建程序指令的方法:

rpc() 方法 发送签名交易 与指定的指令并返回 TransactionSignature

在使用 .rpc 时,Provider 中的 Wallet 会自动包含为签名者。

// 为新账户生成 Keypair
const newAccountKp = new Keypair();
 
const data = new BN(42);
const transactionSignature = await program.methods
  .initialize(data)
  .accounts({
    newAccount: newAccountKp.publicKey,
    signer: wallet.publicKey,
    systemProgram: SystemProgram.programId,
  })
  .signers([newAccountKp])


  .rpc();

获取账户

Program 客户端简化了获取和反序列化由您的 Anchor 程序创建的账户的过程。

使用 program.account 后跟 IDL 中定义的账户类型的名称。Anchor 提供多种获取账户的方法。

使用 all() 获取特定账户类型的所有现有账户。


const accounts = await program.account.newAccount.all();

示例

下面的示例演示了如何使用 @coral-xyz/anchor 与一个简单的 Anchor 程序进行了交互。该程序有两个指令:

  • initialize – 创建并初始化一个计数器账户以存储一个值
  • increment – 增加计数器账户上存储的值
lib.rs
use anchor_lang::prelude::*;
 
declare_id!("6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC");
 
#[program]
pub mod example {
    use super::*;
 
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let counter = &ctx.accounts.counter;
        msg!("计数器账户已创建!当前计数:{}", counter.count);
        Ok(())
    }
 
    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        msg!("之前的计数器:{}", counter.count);
 
        counter.count += 1;
        msg!("计数器已增加!当前计数:{}", counter.count);
        Ok(())
    }
}
 
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,
 
    #[account(
        init,
        payer = payer,
        space = 8 + 8
    )]
    pub counter: Account<'info, Counter>,
    pub system_program: Program<'info, System>,
}
 
#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
}
 
#[account]
pub struct Counter {
    pub count: u64,
}

下面是一个与 Anchor 程序交互的 TypeScript 客户端的示例文件结构:

example.json
example.ts
example.ts
package.json

示例中的 /idl 目录包含两个文件:

  • example.json: 程序的 IDL 文件
  • example.ts: 为 IDL 生成的 TypeScript 类型定义文件

下面的选项卡包含 example.jsonexample.ts 文件作为参考,展示这些文件的样子。

{
  "address": "6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC",
  "metadata": {
    "name": "example",
    "version": "0.1.0",
    "spec": "0.1.0",
    "description": "使用 Anchor 创建"
  },
  "instructions": [
    {
      "name": "increment",
      "discriminator": [11, 18, 104, 9, 104, 174, 59, 33],
      "accounts": [
        {
          "name": "counter",
          "writable": true
        }
      ],
      "args": []
    },
    {
      "name": "initialize",
      "discriminator": [175, 175, 109, 31, 13, 152, 155, 237],
      "accounts": [
        {
          "name": "payer",
          "writable": true,
          "signer": true
        },
        {
          "name": "counter",
          "writable": true,
          "signer": true
        },
        {
          "name": "system_program",
          "address": "11111111111111111111111111111111"
        }
      ],
      "args": []
    }
  ],
  "accounts": [
    {
      "name": "Counter",
      "discriminator": [255, 176, 4, 245, 188, 253, 124, 25]
    }
  ],
  "types": [
    {
      "name": "Counter",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "count",
            "type": "u64"
          }
        ]
      }
    }
  ]
}

当您在 Anchor 项目中运行 anchor build 时,Anchor CLI 会自动生成:

  • IDL 文件(.json)在 target/idl 文件夹中(例如: target/idl/example.json

  • TypeScript 类型定义文件(.ts)在 target/types 文件夹中(例如: target/types/example.ts

下面的 example.ts 文件包含与程序交互的脚本。

example.ts
import {
  Connection,
  Keypair,
  LAMPORTS_PER_SOL,
  Transaction,
  sendAndConfirmTransaction,
} from "@solana/web3.js";
import { Program } from "@coral-xyz/anchor";
import type { Example } from "./idl/example.ts";
import idl from "./idl/example.json";
 
// 设置与集群的连接
const connection = new Connection("http://127.0.0.1:8899", "confirmed");
 
// 使用 IDL 和连接创建 Program 实例
const program = new Program(idl as Example, {
  connection,
});
 
// 为支付者和计数器账户生成新的 Keypair
const payer = Keypair.generate();
const counter = Keypair.generate();
 
// 向支付者的账户空投 SOL,以支付交易费用
const airdropTransactionSignature = await connection.requestAirdrop(
  payer.publicKey,
  LAMPORTS_PER_SOL,
);
await connection.confirmTransaction(airdropTransactionSignature);
 
// 构建初始化指令
const initializeInstruction = await program.methods
  .initialize()
  .accounts({
    payer: payer.publicKey,
    counter: counter.publicKey,
  })
  .instruction();
 
// 构建增加计数指令
const incrementInstruction = await program.methods
  .increment()
  .accounts({
    counter: counter.publicKey,
  })
  .instruction();
 
// 将两个指令添加到一个交易中
const transaction = new Transaction().add(
  initializeInstruction,
  incrementInstruction,
);
 
// 发送交易
const transactionSignature = await sendAndConfirmTransaction(
  connection,
  transaction,
  [payer, counter],
);
console.log("交易签名", transactionSignature);
 
// 获取计数器账户
const counterAccount = await program.account.counter.fetch(counter.publicKey);
console.log("计数:", counterAccount.count);

On this page

在GitHub上编辑