新消息:试用 Parsed Events Scan API
Parsed Events Scan API 正式发布
博客/更新

Parsed Events Scan API 正式发布

Developer Experience EngineerX 上的 0xIchigoLinkedIn 上的 0xIchigoGitHub 上的 0xIchigo
Software EngineerX 上的 Jacopo FrancavillaLinkedIn 上的 Jacopo Francavilla
阅读需 11 分钟

新的 Helius Parsed Events Scan 端点可以从任意 Solana 地址的历史记录中找到你需要的交易,并仅返回已解析的匹配结果。你可以按程序、指令、原生 SOL、代币铸造地址或它们的任意组合进行过滤,无需自行构建历史数据管道。

扫描成本很低。每个请求消耗 10 个积分,另加每搜索 1,000 笔交易消耗 1 个积分。在下文分享的一项测试中,扫描端点从 3,402 笔 Pump.fun 交易中搜索最近 10 次创作者费用领取,耗时 182 毫秒,共消耗 14 个积分。相比之下,使用 getTransactionsForAddress 获取相同交易需要消耗 350 个积分(即高出 25 倍),而且此时还未解析任何交易。

下面快速了解一下:

在 Scan 端点推出之前,要从地址历史记录中查找某类活动,你需要自行构建整套管道:

  • 获取一页签名
  • 请求每笔交易
  • 使用自己的解析器解码
  • 应用过滤器
  • 重复操作,直到获得足够的匹配结果

对于活动频繁的地址,你可能需要处理数千笔交易才能找到一个匹配结果。

新的 Helius Parsed Events Scan API 端点将这套工作流移到了服务端:

  1. 发送地址和你关注的事件条件
  2. API 扫描该地址并解析匹配的交易
  3. 你只会收到匹配结果:已解析交易、交易签名或数量

你可以按以下条件匹配交易:

  • 程序(任意指令)
  • 程序和指令名称
  • 程序和原始指令判别器
  • 在一个请求中指定多个程序(最多 20 个)
  • 代币铸造地址
  • 程序和代币铸造地址

Scan API 还支持槽位、时间和签名范围,以及状态、承诺级别、排序顺序和代币账户过滤器。

因此,它非常适合以下精准历史查询:

  • 查找某个程序的每条买入或卖出指令
  • 查找钱包在 Jupiter、DFlow 和 Pump.fun 等多个链上交易平台中的完整交易历史
  • 查找钱包在指定日期范围内与某个程序交互的次数
  • 使用指令判别器搜索没有 IDL 的程序
  • 监控对程序的失败调用,并获取已解码的程序错误
  • 监控程序中的管理或配置指令,以发现费用或参数变更

按 Solana 程序指令扫描

以下请求会扫描 Pump.fun 程序历史记录,并返回包含 buy 或 sell 指令的已解析交易:

代码
curl --request POST \
  --url "https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=$HELIUS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
    "match": {
      "programs": [
        {
          "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
          "instructions": ["buy", "sell"]
        }
      ]
    },
    "limit": 100
  }'

使用此请求时,Parsed Events Scan 演示工具扫描了 261 条记录,找到 100 个匹配结果。它在 182 毫秒内返回了最近的 100 个事件,总计仅消耗 11 个积分:

指令名称可以使用程序任意已知 IDL 版本中的拼写,也可以使用 snake_case 形式。Parsed Events Scan API 会同时检查顶层指令以及通过跨程序调用(CPI)触发的内部指令。

程序通常会为同一操作提供多个版本。例如,Pump.fun 的 IDL 包含 buy、buy_exact_sol_in、buy_v2、buy_exact_quote_in_v2、sell 和 sell_v2 指令。Scan API 允许你列出想要匹配的所有指令名称。

买入和卖出占 Pump.fun 活动的大部分,因此匹配速度很快。当你需要的活动较为少见时,Scan 能节省更多成本。例如,创作者费用领取只占该程序交易的一小部分:

代码
curl --request POST \
  --url "https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=$HELIUS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
    "match": {
      "programs": [
        {
          "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
          "instructions": ["collect_creator_fee"]
        }
      ]
    },
    "limit": 10
  }'

使用 Parsed Events Scan 演示工具查找最近 10 次领取记录,可以看到该工具在 182 毫秒内扫描了 3,402 笔交易,此请求消耗 14 个积分:

相同的 getTransactionsForAddress 调用需要消耗 350 个积分,是扫描端点的 25 倍。

如果 Solana 程序没有包含命名指令的 IDL,该怎么办?

对于缺少 IDL 的 Solana 程序,你可以改用指令数据前缀,通过 Parsed Events Scan API 进行匹配。

每个判别器可以包含一到八个十六进制编码的字节。对于单个程序,你可以组合使用名称和判别器;指令只需匹配其中任意一项。例如:

代码
{
  "match": {
    "programs": [
      {
        "programId": "<PROGRAM_ADDRESS>",
        "discriminators": ["0x66063d1201daebea"]
      }
    ]
  }
}

一次扫描多个 Solana 程序

你可以在单个 Parsed Events Scan API 请求中列出最多 20 个程序。只要交易调用其中任意一个程序,就会匹配。

例如,以下请求通过一次扫描,在 Jupiter、DFlow 和 Pump.fun 中匹配某个钱包的交易:

代码
{
  "address": "<WALLET_ADDRESS>",
  "match": {
    "programs": [
      {
        "programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
        "instructions": ["route", "shared_accounts_route", "route_v2", "shared_accounts_route_v2"]
      },
      { "programId": "DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH" },
      {
        "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
        "instructions": ["buy", "buy_exact_sol_in", "buy_v2", "sell", "sell_v2"]
      }
    ]
  }
}

按代币铸造地址扫描

Scan API 还可以检查每笔交易前后的代币余额,查找涉及指定代币铸造地址的交易。默认情况下,它只统计属于被扫描地址的余额。

按代币扫描钱包时,请将 tokenAccounts 设置为 balanceChanged。在多种情况下,转入的代币只会涉及钱包的代币账户,而不会直接涉及钱包本身;因此,默认情况下,钱包历史记录不会包含这些交易。

例如,以下请求会查找 Ansem 在 2026 年 9 月的 wSOL 活动:

代码
curl --request POST \
  --url "https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=$HELIUS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "address": "<ANSEM_WALLET_ADDRESS>",
    "match": {
      "mints": [{ "mint": "So11111111111111111111111111111111111111112" }]
    },
    "tokenAccounts": "balanceChanged",
    "time": {
      "gte": 1788220800,
      "lte": 1790812800
    }
  }'

Scan API 在总计扫描 7,555 笔交易后,找到 53 笔匹配交易:

组合程序和铸造地址

开发者可以同时设置 programs 和 mints 来缩小结果范围。组合使用时,交易必须同时满足两个条件才能匹配。不过,要将程序活动缩小到单个代币,被扫描的地址比过滤器更重要。

例如,要查找某个代币的所有 Pump.fun 交易,应扫描该代币的铸造地址,而不是 Pump.fun 程序。每笔买入或卖出交易都会将铸造地址列为账户,因此默认即可匹配:

代码
{
  "address": "<MINT_ADDRESS>",
  "match": {
    "programs": [
      {
        "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
        "instructions": ["buy", "buy_exact_sol_in", "buy_v2", "sell", "sell_v2"]
      }
    ]
  }
}

铸造地址的历史记录只包含该代币的活动,而程序的历史记录包含所有代币的交易,因此扫描程序历史会将预算浪费在无关交易上。

选择匹配范围

默认情况下,只有当程序指令和铸造地址的代币余额涉及被扫描地址时,才会计入匹配。若地址拥有该代币账户,或该地址就是余额对应的铸造地址,则该代币余额涉及此地址。以下情况表示指令涉及该地址:

  • 指令的某个账户是该地址
  • 指令的某个账户是该地址拥有的代币账户
  • 该地址是铸造地址,且指令的某个账户是该铸造地址对应的代币账户
  • 该地址是被调用的程序

在程序或铸造地址上设置 "scope": "transaction",即可在交易中的任意位置统计它。当该地址仅支付费用、执行多签交易,或不是你要匹配的指令账户时,请使用此设置。

例如,以下请求会查找同时转移了 USDC 的某种代币交易。在默认范围下,USDC 余额必须属于该铸造地址,因此不会匹配任何结果:

代码
{
  "address": "<MINT_ADDRESS>",
  "match": {
    "mints": [
      { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "scope": "transaction" }
    ]
  },
  "returnShape": "signatures"
}

程序也支持相同的匹配范围。以下请求会查找由某个中继者支付费用的 Jupiter 兑换交易。

该中继者仅以费用支付者身份签署交易,因此它不是路由指令的账户之一。在默认范围下,这些交易都不会匹配:

代码
{
  "address": "<RELAYER_ADDRESS>",
  "match": {
    "programs": [
      {
        "programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
        "instructions": ["route", "shared_accounts_route", "route_v2", "shared_accounts_route_v2"],
        "scope": "transaction"
      }
    ]
  },
  "returnShape": "signatures"
}

同样的逻辑也适用于执行提案的多签成员。多签执行的指令操作的是金库账户,而不是成员账户,因此在成员的历史记录中扫描这些交易需要使用 transaction 范围。

跟踪原生 SOL

原生 SOL 没有代币余额,因此扫描会根据 lamport 进行匹配。

传入原生 SOL 铸造地址(So11111111111111111111111111111111111111111),它与封装 SOL 不同。当被扫描地址的 SOL 余额发生变化时,交易就会匹配,但不计入该地址支付的费用:

代码
{
  "address": "<WALLET_ADDRESS>",
  "match": {
    "mints": [{ "mint": "So11111111111111111111111111111111111111111" }]
  },
  "time": { "gte": 1788220800, "lt": 1790812800 }
}

这样可以捕获程序在没有转账指令的情况下支付的 SOL,例如 Pump.fun 卖出交易。它还会捕获附带的资金变动,例如 Jito 小费,以及为账户支付或从账户退还的租金。

获取已解析交易、签名或数量

returnShape 用于设置响应中为匹配结果返回的内容:

returnShape响应适用场景
transactions(默认)data 中最多包含 limit 个已解析匹配结果读取已解码的指令、转账和摘要
signatures为每个匹配结果返回 signature、slot、transactionIndex 和 blockTime需要先获取列表的回填任务和索引器
count不返回 data;scan.matchedTransactions 为数量活动检查、资格验证、分析等

例如,以下请求会统计某位交易者在 2026 年 9 月的 Pump.fun 买入次数,但不返回交易:

代码
{
  "address": "<WALLET_ADDRESS>",
  "match": {
    "programs": [
      {
        "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
        "instructions": ["buy", "buy_exact_sol_in", "buy_v2"]
      }
    ]
  },
  "returnShape": "count",
  "time": { "gte": 1788220800, "lt": 1790812800 }
}

进行计数时,signatures 和 count 会忽略 limit,并涵盖请求扫描范围内的所有匹配结果。要统计较长的历史记录,请继续分页并对 scan.matchedTransactions 求和。

这三种响应形式的费用相同。

控制每个请求扫描的历史记录量

每个扫描请求最多可检查 10,000 笔交易,并返回最多 100 个匹配结果。

budget.maxScannedTransactions 字段控制此上限,默认值为 10,000。limit 字段控制端点返回的匹配结果数量;它接受 1 到 100 之间的值,默认值为 100。

这两个控制项彼此独立,因为匹配结果可能非常稀疏。也就是说,一个请求可能扫描数千笔交易,却只返回少量匹配结果。

默认情况下,扫描请求仅包含成功的交易。

将 status 设置为 failed 或 any,即可包含失败的交易。如果程序的 IDL 定义了错误,失败交易会附带已解码的程序错误。

扫描摘要

每个响应都包含 scan 摘要:

代码
{
  "data": [],
  "paginationToken": "460903064:422",
  "scan": {
    "stoppedOn": "budget",
    "scannedTransactions": 2000,
    "matchedTransactions": 0,
    "scannedThrough": {
      "slot": 460903064,
      "blockTime": 1792856105
    },
    "creditsCharged": 12
  }
}

摘要会告诉你:

  • 扫描停止的原因
  • 扫描了多少笔交易
  • 匹配了多少笔交易
  • 扫描到的最后一个槽位和区块时间
  • 请求消耗了多少积分

扫描分页的工作方式

扫描停止时,scan.stoppedOn 字段会提供原因:

  • windowEnd:扫描已到达历史记录或时间窗口的末尾
  • limit:响应包含了所请求数量的匹配结果
  • budget:请求已达到交易扫描预算
  • deadline:请求已达到时间限制

当响应包含 paginationToken 时,请在下一个请求中发送该令牌。即使当前 data 数组为空,也应继续扫描。空结果可能表示请求在找到匹配结果之前已耗尽预算,并不意味着后面不存在匹配结果。

例如,以下循环会收集过去一小时内的 Pump.fun 交易。

请注意,time 范围和请求上限可以防止它遍历完整历史记录:

代码
const PUMP_PROGRAM = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
const ONE_HOUR_AGO = Math.floor(Date.now() / 1000) - 3600;
const MAX_REQUESTS = 50;

let paginationToken;
let requests = 0;

async function scanHistory() {
  const response = await fetch(
    `https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=${process.env.HELIUS_API_KEY}`,
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        address: PUMP_PROGRAM,
        match: {
          programs: [{ programId: PUMP_PROGRAM, instructions: ["buy", "sell"] }],
        },
        time: { gte: ONE_HOUR_AGO },
        limit: 100,
        ...(paginationToken && { paginationToken }),
      }),
    }
  );

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  }

  return response.json();
}

do {
  const page = await scanHistory();
  requests++;

  for (const transaction of page.data) {
    console.log(transaction.signature);
  }

  paginationToken = page.paginationToken;
} while (paginationToken && requests < MAX_REQUESTS);

无需客户端管道即可获得解析结果

data 中的每个项目都采用与 Parsed Events Parse Transactions 端点相同的 TransactionResult 格式。如果数据可用,结果可以包含已解码的指令、转账、账户变更、事件、交易摘要和特定协议的解析数据。如果你的应用还需要原始 Solana 交易载荷,请将 rawTransaction 设置为 "json"、"jsonParsed" 或 "base64"。

主要区别在于历史记录工作流的运行位置。

你的应用只需定义一次搜索条件,Parsed Events Scan API 会处理历史记录分页、匹配和解析,然后返回相关交易。

使用最新的 Helius SDK

我们的 TypeScript 和 Rust SDK 均支持 Parsed Events API 和新的扫描端点。

TypeScript SDK 通过 helius.parsedEvents.scan() 提供扫描功能。响应类型取决于传入的 returnShape:

代码
const { scan } = await helius.parsedEvents.scan({
  address: "<WALLET_ADDRESS>",
  match: {
    programs: [{ programId: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", instructions: ["buy", "sell"] }],
  },
  returnShape: "count",
});

console.log(scan.matchedTransactions, scan.stoppedOn);

Rust SDK 的 helius.parsed_events() 上还提供 scan、scan_signatures 和 scan_count,它们都接受相同的 ScanRequest。

Parsed Events Scan API 定价

每个 Parsed Events Scan API 请求的费用为 10 个积分,另加每扫描一页历史记录消耗 1 个积分。每页历史记录最多包含 1,000 笔交易。

例如,使用默认 10,000 笔交易预算的请求最多消耗 20 个积分。响应会在 scan.creditsCharged 中报告确切费用。

作为对比,扫描相同历史记录的成本仅为使用 getTransactionsForAddress 分页获取时的十分之一;后者每页(最多 1,000 笔交易)消耗 100 个积分。

控制用量

要控制用量,请尽量使用范围最小且可行的地址,并在可能的情况下添加槽位或时间范围。无关交易越少,每个请求能获得的有效匹配结果就越多。

使用 Parsed Events API 替代 Enhanced Transactions API

Enhanced Transactions API 仍以维护模式提供,但不会再增加新的解析器类型或功能。Parsed Events 是其后继产品,它使用 Helius 的 IDL 目录解码数千个 Solana 程序中的指令。如果你尚未迁移,请迁移到 Parsed Events API。

有什么区别?

Enhanced Transactions API 将活动归入一组固定的交易类型,例如兑换、转账和 NFT 销售;而 Parsed Events Scan API 支持按程序指令、原始判别器、代币铸造地址或这些条件的组合进行更精确的搜索。Helius 会在扫描地址历史记录时应用这些过滤器,并且只解析匹配的交易。

Parsed Events API 为开发者提供更广泛的程序覆盖范围和更强的历史查询控制能力,无需维护客户端扫描器。

开始使用

如果你知道自己需要哪些链上活动,但不想构建和维护客户端历史扫描器,请使用 Parsed Events Scan API。阅读 Scan Transaction History API 参考文档,了解完整的请求架构、响应字段、限制、错误和更多示例。

要继续探索 Scan API 的能力,请在 Helius 控制面板中使用新的 Scan 工具。尝试按程序、铸造地址以及各种过滤条件扫描地址。

订阅 Helius

及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新

放大图片