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

如何通过TypeScript订阅Solana链上Anchor合约事件与日志

结论

Solana 原生支持合约事件的历史查询与实时订阅能力,Anchor 框架的 TypeScript SDK 已经对事件序列化/反序列化、日志拉取、Websocket 订阅做了完整封装,不需要手动处理底层日志解析逻辑,直接按以下步骤实现即可。

前置准备

首先安装前端依赖,注意使用当前官方维护的新版 Anchor TS 包(旧版@project-serum/anchor已停止更新):

npm install @coral-xyz/anchor @solana/web3.js

在代码中初始化连接、程序实例与事件解析器,编译 Anchor 合约时生成的 IDL 文件已经自动包含了你定义的MyEvent结构信息,不需要额外编写序列化规则:

import { Program, AnchorProvider, EventParser, setProvider, PublicKey } from "@coral-xyz/anchor";
import { Connection, clusterApiUrl } from "@solana/web3.js";
// 引入本地保存的合约IDL,路径对应Anchor编译后target/idl目录下的文件
import idl from "./idl/your_contract.json";

// 初始化RPC连接,生产环境建议替换为付费RPC节点地址
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 替换为你实际接入的钱包实例,示例为Phantom等钱包注入的window.solana对象
const wallet = window.solana;
const provider = new AnchorProvider(connection, wallet, { commitment: "confirmed" });
setProvider(provider);
// 替换为你自己的链上程序公钥
const PROGRAM_ID = new PublicKey("你的程序公钥地址");
const program = new Program(idl as any, PROGRAM_ID);
// 初始化事件解析器,可直接将链上日志解析为TS对象
const eventParser = new EventParser(PROGRAM_ID, program.coder);
历史事件查询实现

通过 RPC 拉取指定范围内目标程序产生的日志,再用事件解析器批量解析即可得到历史事件。注意免费公开 RPC 对日志查询的区块范围限制较严,大跨度查询建议分批拉取,或使用支持历史日志索引的付费 RPC 服务:

/**
 * 拉取指定槽位范围内的MyEvent历史事件
 * @param startSlot 起始区块槽位
 * @param endSlot 结束区块槽位,不传默认查询到最新已确认区块
 */
async function getHistoryMyEvents(startSlot: number, endSlot?: number) {
  const logResp = await connection.getLogs({
    mentions: [PROGRAM_ID.toBase58()], // 仅过滤目标程序产生的日志
    commitment: "confirmed",
    minContextSlot: startSlot,
    maxContextSlot: endSlot
  });

  const eventList: Array<{
    slot: number;
    txSignature: string;
    data: bigint;
    label: Uint8Array;
  }> = [];

  for (const logItem of logResp.value) {
    // 跳过执行失败的交易日志
    if (logItem.err) continue;
    // 解析当前交易中包含的所有Anchor事件
    const parsedEvents = eventParser.parseLogs(logItem.logs);
    for (const event of parsedEvents) {
      // 筛选出你定义的MyEvent类型
      if (event.name === "MyEvent") {
        eventList.push({
          slot: logItem.slot,
          txSignature: logItem.signature,
          data: event.data.data as bigint,
          label: event.data.label as Uint8Array
        });
      }
    }
  }

  return eventList;
}
实时事件订阅实现

Anchor Program 实例封装了基于 Websocket 的日志订阅能力,只需要传入事件名和回调函数即可,不需要手动维护连接、解析日志:

// 注册事件监听器,第三个参数为承诺级别:processed延迟最低,finalized确定性最高
const listenerId = program.addEventListener(
  "MyEvent",
  (event, slot, txSignature) => {
    // 新事件上链后会自动触发该回调,event为已解析好的事件对象
    console.log("收到新的MyEvent事件:", {
      slot,
      txSignature,
      data: event.data as bigint,
      label: event.label as Uint8Array
    });
  },
  "confirmed"
);

// 页面卸载或不需要订阅时,记得移除监听器避免内存泄漏
function unsubscribeEvent() {
  program.removeEventListener(listenerId);
}
注意事项
  • Anchor 中emit!宏发出的事件本质是写入交易日志的固定格式数据,解析逻辑完全由 IDL 驱动,只要 IDL 和链上程序版本一致就不会出现解析错误。
  • 合约中定义的u64类型在 TS 侧会被解析为bigint类型,如果需要转为数字,注意判断数值不要超过Number.MAX_SAFE_INTEGER避免精度丢失。
  • 免费公开 RPC 普遍存在 Websocket 连接不稳定、历史日志查询范围小、请求限流的问题,生产环境请使用付费 RPC 服务。
  • 如果需要按事件字段做过滤(比如只订阅data大于特定值的事件),普通 RPC 不支持该能力,需要使用带索引功能的增强 RPC 或自建链上索引服务。

内容的提问来源于stack exchange,提问作者Senuda Jayalath

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:09:23