所有狙击机器人的教程都在讲检测。WebSocket 还是轮询、Geyser 流、怎么把创建事件的解析再快三毫秒。
然后你照着搭了一个,看着它把上新检测得漂漂亮亮,而成交时价格已经翻了三倍。
检测从来就不是瓶颈。
slot 到底花在哪了
一次狙击有五个阶段。只有其中一个被反复写:
① 上新出现在链上
② 你的机器人检测到 ← 所有人都在优化这一步
③ 你的机器人决定买入
④ 构造并签名
⑤ 你的交易落块 ← ★钱是在这里输掉的★
第 2 到第 4 步是你自己的代码,而且很快 —— 解析一行日志、构造一个指令,都是亚毫秒级的事。第 5 步是网络问题,而在上新的那一刻,它慢得跟其它几步不在一个量级。
★如果你把检测快了几毫秒,却仍然晚三个 slot 落块,等于什么都没省。★ 一个 slot 的时长远大于这点差距。你优化的是一个舍入误差。
检测已经跑通、想修最后这一步?免费领个 BoltTx key 改一行配置。这篇剩下的部分讲的是为什么那一步占了大头。
上新为什么是最难的场景
拥堵不是随机的,它恰好聚集在你想交易的那些事件上。
一次上新意味着所有盯着那个程序的狙击者在同一秒内提交。区块空间被抢、所有人要写的那些账户上 priority fee 飙升、上链窗口收窄。
这造成一个特定的陷阱:★你的机器人在测试时完美运行,在生产环境失败★ —— 因为测试发生在网络清闲时,那时候每条提交路径表现都一样。差别只在高负载下才显现。
决定你能不能成交的四件事
一、priority fee 要算,不要写死
一个你上个月设的常数,大部分时候是浪费、上新时是不够。通常两者兼有。
import { ComputeBudgetProgram } from "@solana/web3.js";
// 费用是按账户竞争的,不是全局的。要传你这笔交易会写入的账户 ——
// 上新时,所有人都在写同一个 bonding curve 账户。
const recent = await connection.getRecentPrioritizationFees({
lockedWritableAccounts: [bondingCurve, yourTokenAccount],
});
const fees = recent.map((r) => r.prioritizationFee).sort((a, b) => a - b);
const median = fees[Math.floor(fees.length / 2)] ?? 0;
instructions.unshift(
ComputeBudgetProgram.setComputeUnitPrice({
// 上新是竞争最激烈的场景。中位数只是下限。
microLamports: Math.max(median * 3, 10_000),
}),
ComputeBudgetProgram.setComputeUnitLimit({ units: 120_000 }),
);
★compute unit limit 也要设。★ 不设的话会按一个远高于实际用量的默认值计费,而这恰好浪费在费用最贵的那些时刻。
二、blockhash 要在签名时才取
blockhash 有效期约 150 个区块、大约 60 秒。听起来很宽裕 —— 直到你在启动时取了一个然后一直复用。
// 错:上新触发时,这个 blockhash 已经很旧了。
const { blockhash } = await connection.getLatestBlockhash();
watchForLaunches((mint) => buildAndSend(mint, blockhash));
// 对:后台定时刷新,始终保持一个新鲜的。
let cached = await connection.getLatestBlockhash("confirmed");
setInterval(async () => {
cached = await connection.getLatestBlockhash("confirmed");
}, 5_000);
定时刷新而不是用时才取,还顺手从热路径上去掉了一次网络往返。★在"检测到"和"提交"之间,你付不起一次网络调用。★
三、重试到过期,不是只发一次
上新时单次提交就是掷硬币。
const raw = tx.serialize();
const sig = await connection.sendRawTransaction(raw, {
skipPreflight: true,
maxRetries: 0, // 重试由我们自己驱动
});
while (await connection.getBlockHeight("confirmed") <= lastValidBlockHeight) {
const { value } = await connection.getSignatureStatuses([sig]);
if (value[0]) break; // 已上链,看 .err 判断结果
await connection.sendRawTransaction(raw, {
skipPreflight: true,
maxRetries: 0,
});
await new Promise((r) => setTimeout(r, 400));
}
重发相同字节是安全的 —— 签名一样,最多被收录一次。skipPreflight 在这里很关键,因为 preflight 要花一次往返,而且它模拟的是你不会落进去的那个 slot。
四、一条高负载下扛得住的提交路径
这是唯一没法在应用层代码里解决的,所以应该放在最后查 —— 先把前三个便宜的排除掉。
验证节点按转发方的质押权重来接收转发过来的交易。区块空间充裕时这完全看不见;被抢的时候,低质押路径恰好在你最不希望的时候被降级。
上链应该是什么水平
我们投递节点上的真实交易:中位确认 336 毫秒 —— 不到一个 slot。
两个 slot 是不到一秒。对一次上新来说,第 2 个 slot 的价格和第 6 个 slot 的价格,差别足以决定整笔交易。
★拥堵时那个数字会拉长★ —— 大部分交易不受影响,少数明显变慢。而狙击就活在这少数里,因为上新本身就是拥堵。
该测的是什么
只看成交率会误导人。一个每次都以糟糕价格成交的机器人,看起来很健康。
log({
mint,
detectSlot, // 你看到上新的 slot
landSlot, // 你的买单落块的 slot
slotGap: landSlot - detectSlot,
entryPrice,
curvePriceAtDetect,
gapBps: Math.round(((entryPrice - curvePriceAtDetect) / curvePriceAtDetect) * 10_000),
});
★slotGap 告诉你执行是不是问题,gapBps 告诉你它的代价够不够大。★ 两个要分开看 —— 在 slotGap 很大的时候去优化检测,是把力气花在错误的阶段上。
说点实话
狙击竞争很激烈。看到这篇文章的所有人,对同样的上新拥有同样的公开信息,任何单一优化带来的优势都很小。
但有一点是真的:★大多数机器人在提交这一侧调得很差★ —— 写死的费用、只提交一次、过期的 blockhash、通用端点。把这些修好能让你领先大多数人,而这和"让你排第一"是两个不同的说法。
如果你现在的机器人稳定在检测后两个 slot 内落块、还是在亏钱,那问题在策略或选币,不在基础设施。先测,别假设。
BoltTx 在这里的位置
我们做第 5 步。不做检测,不做上新 feed,不做索引。
提交走我们自建的四区域投递节点,带 SWQoS 路由,不暴露公共 mempool —— 交易在落块之前,传输途中观察不到。你在本地签名,我们不托管资金、不代签、不修改交易内容。
tip 带在交易里,从你自己的钱包链上支付。交易 revert 的话 tip 跟着一起 revert —— 这是 Solana 原子交易的机制决定的。只有到达链上的交易才计费。
免费领 API key,没有月费:
// 选离你机器人最近的区域
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");
然后拿几次真实上新记录 slotGap,做个对比。
常见问题
我的 pump.fun 狙击机器人能检测到上新,为什么总是成交不了? 检测和执行是两个阶段。如果你能瞬间看到上新、却晚三个以上 slot 落块,损失在提交侧:priority fee、blockhash 新鲜度、重试行为、或者拥堵下的路由。
Solana 狙击机器人要多快? 快到能在检测后一两个 slot 内落块。检测速度没大多数教程说的那么重要 —— 解析日志省下的一毫秒,在你的交易多花一个 slot 落块面前毫无意义。
狙击机器人的 priority fee 该设多少?
用 getRecentPrioritizationFees 按你会写入的账户去查,然后为竞争场景往上乘。上新是全网最激烈的时刻,所以近期中位数是下限而不是目标。
为什么我的机器人测试时正常、真上新就挂? 测试时网络清闲,所有提交路径表现一样。上新造成拥堵,而拥堵时费用、重试行为、路由会同时开始起作用。
狙击该开 skipPreflight 吗?
该开。preflight 要花一次网络往返,而且模拟的是当前 slot —— 那不是你会落进去的那个。真正有用的模拟放在开发阶段,结果用 getSignatureStatuses 拿。
怎么在不增加延迟的前提下保持 blockhash 新鲜? 后台定时刷新,而不是用时才取。狙击那一刻去取会给热路径加一次往返,而启动时缓存的那个,等你要用时已经接近过期。
pump.fun 买入该设多少 compute unit limit? 开发阶段模拟一次拿到真实消耗,然后设一个略高的值。用默认值意味着按一个高得多的数字计费,而这恰好浪费在费用飙升的时刻。
反复重发同一笔狙击交易安全吗? 安全。相同的签名字节产生相同签名,Solana 对同一个签名最多收录一次。持续重发到 blockhash 过期是生产环境的标准做法。
落后几个 slot 就太晚了? 取决于曲线动得多快,但在一次活跃上新中,超过三四个 slot 通常你买到的价格已经把利润空间抹掉了。把检测时和成交时的价格都记下来,就能看出自己的阈值在哪。
狙击一定要用 Geyser 或专用流吗? 它对检测有帮助,但前提是提交那一侧已经调紧了。为最快的检测付费、却通过通用端点提交,是把钱花在错误的阶段上。
我的狙击交易为什么总报滑点错误? 报价到收录之间曲线动了。放宽容忍度只会让你成交得更差,而不是解决成因。如果这个情况反复出现,slot 差才是真正的变量。
不用付费 RPC 能跑狙击机器人吗? 小规模做检测有时可以。但上新时提交,共享的公共端点是最糟的情况 —— 因为在同一时刻,它正被所有其他人挤满。
狙击和抢跑有什么区别? 狙击是对一个已经上链的上新事件行动,用的是公开信息。抢跑是在一笔待确认交易被收录之前、基于对它的知情去行动。Solana 没有公共 mempool,所以后者在这里不像别的链上那样可行。
狙击机器人需要检查曲线有没有毕业吗? 需要,而且每笔买入前都要查。曲线一旦完成,交易转到 AMM 池,bonding curve 指令会失败。只在启动时查一次的机器人,会反复发出注定失败的指令。
怎么判断问题在基础设施还是在策略? 把 slot 差和入场价差分开记录。稳定在两个 slot 内落块却还在亏钱,指向选币或策略;slot 差很大,指向执行。