3. 监听链上事件 (WebSocket)

速度的源头:从轮询到推送

在区块链上,"快"意味着一切。 如果你还在用 while(true) 循环每秒查询一次"有没有新币",那你已经输在了起跑线上。因为 HTTP 请求的往返延迟加上轮询间隔,足以让价格翻倍。

专业的狙击机器人使用的是 WebSocket 推送


3.1 基础代码:建立 WebSocket 连接

在 Solana Web3.js 中,最基础的监听方法是 onLogs。这相当于在链上装了一个摄像头,只要有交易涉及特定程序,你的代码就会被触发。

标准监听模板

typescript
import { Connection, PublicKey } from "@solana/web3.js"; // 1. 连接到支持 WSS 的 RPC 节点 const connection = new Connection("https://api.mainnet-beta.solana.com", { wsEndpoint: "wss://api.mainnet-beta.solana.com", }); const PROGRAM_ID = new PublicKey("..."); // 你要监听的目标程序 // 2. 开启监听 const subscriptionId = connection.onLogs( PROGRAM_ID, (logs, context) => { // 回调函数:每当有相关交易发生时触发 if (logs.err) return; // 忽略失败的交易 console.log("收到新交易:", logs.signature); console.log("执行日志:", logs.logs); }, "processed" // 3. 承诺级别:追求极致速度 );

3.2 实战:监听 Pump.fun 发射

Pump.fun 是当前最大的土狗工厂。我们要监听它的造币动作。

关键指纹

  1. Program ID: 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P
  2. 指令日志: 当通过 Pump.fun 发币时,链上日志中会出现 Instruction: Create

代码实现

typescript
const PUMP_FUN_PROGRAM = new PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); connection.onLogs( PUMP_FUN_PROGRAM, ({ logs, err, signature }) => { if (err) return; // 必须过滤掉执行失败的交易 // 核心逻辑:在日志中寻找 "Create" 指令 const isMintAuth = logs.some(log => log.includes("Instruction: Create")); if (isMintAuth) { console.log(`🔥 发现新币发射!签名: ${signature}`); // ⚠️ 注意:标准日志不直接包含 Token Mint 地址 // 你通常需要再次发起请求获取交易详情 (见下文 "双跳问题") fetchTransactionDetails(signature); } }, "processed" );

3.3 进阶:双跳问题 (The Double-Hop Problem)

上面的代码有一个致命缺陷:日志里没有代币地址 (Mint Address)。 日志只告诉你"有人发币了",但没告诉你"发的是哪个币"。

标准 RPC 的慢速流程

  1. Hop 1 (WebSocket): 收到推送 -> "签名 xxx 刚刚执行了 Pump.fun Create"。
  2. Hop 2 (HTTP): 机器人必须发起 getTransaction(xxx) 请求获取交易详情,解析其中的账户列表,才能找到 Mint 地址。
typescript
// ❌ 慢速做法:收到日志后再去查询 async function fetchTransactionDetails(sig: string) { const tx = await connection.getParsedTransaction(sig, { maxSupportedTransactionVersion: 0 }); const mint = tx?.meta?.postTokenBalances[0]?.mint; // 这个网络请求可能耗时 200ms+,在狙击中是致命的 }

解决方案:Geyser gRPC (职业玩家的选择)

Geyser 插件直接运行在验证者节点内部。它推送的数据是完整的。 当收到推送时,数据包里已经包含了所有涉及的账户(AccountKeys)。

极速流程 (Geyser):

  1. Stream: 收到数据包 -> 包含 Logs + AccountKeys。
  2. Parse: 本地直接从 AccountKeys[1] (举例) 拿到 Mint 地址。
  3. Buy: 立即买入。0 网络延迟。

gRPC 代码示例

使用 yellowstone-grpc 客户端订阅流式数据的伪代码:

typescript
// ✅ 极速做法:使用 Geyser gRPC 订阅 import Client from "@triton-one/yellowstone-grpc"; // 连接到支持 gRPC 的节点 (通常是付费的) const client = new Client("http://grpc-endpoint.com", "your-auth-token"); const stream = await client.subscribe(); // 1. 发送订阅配置:只听 Pump.fun 的交易 stream.write({ transactions: { pumpFunFilter: { vote: false, failed: false, accountInclude: ["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"], // 监听该程序相关交易 }, }, accounts: {}, slots: {}, }); // 2. 处理实时推送 stream.on("data", (data) => { if (data.transaction) { const tx = data.transaction.transaction; // 💥 关键点:这里直接就有所有涉及的账户地址 // 对于 Pump.fun 'Create' 指令,Mint 地址通常在固定位置 (如 index 1 或 2) // 无需发起第二次 HTTP 请求! const accountKeys = tx.transaction.message.accountKeys; const mintAddress = accountKeys[1]; // 假设位置 console.log(`🚀 零延迟捕获新币: ${mintAddress}`); // triggerBuy(mintAddress); } });

3.4 监听 Raydium 流动性池

当代币"毕业"或直接在 DEX 上市时,我们需要监听 Raydium 的流动性添加事件。

  • Program ID: 675kPX9M1NAe2gk7kh2nar73UyTP8yA202tenuLF5784
  • 目标指令: initialize2 (V4 池子创建)。
typescript
const RAYDIUM_PROGRAM = new PublicKey("675kPX9M1NAe2gk7kh2nar73UyTP8yA202tenuLF5784"); connection.onLogs( RAYDIUM_PROGRAM, ({ logs, err, signature }) => { if (err) return; // 监听 "initialize2" 指令 if (logs.some(l => l.includes("initialize2"))) { console.log(`🌊 监测到流动性添加!${signature}`); // 立即触发买入逻辑 } }, "processed" );

过滤噪音

链上充斥着大量失败的交易和无关的交互。你的过滤器必须高效,尽量使用字符串匹配而不是复杂的正则,以节省微秒级的 CPU 时间。


3.5 承诺级别 (Commitment) 的选择

在代码中,commitment 参数决定了你多快能看到数据。

typescript
connection.onLogs(..., "processed"); // 🚀 最快 connection.onLogs(..., "confirmed"); // 🐢 慢 400-800ms
  1. processed (最快)

    • 含义:节点刚刚处理完,还没全网确认。
    • 延迟:~0ms (实时)。
    • 狙击必须用这个
  2. confirmed (稳健)

    • 含义:全网 66% 节点已投票。
    • 延迟:~400-800ms。
    • 适合:普通转账确认,不适合狙击。

风险提示:使用 processed 可能会遇到分叉 (Fork)。即你看到的交易最终被全网丢弃了。对于狙击来说,这是必须承担的风险。

JSPlayground
EDITOR ACTIVE
Initializing JS Environment...
WebSocket Stream
Filter Active
Live Feed
Waiting for blockchain events...
Tip: Modify the code to filter for Pump.fun (6EF8...) and Create instruction.