清算看起来是 DeFi 里最干净的机会。一个仓位变得可清算,你把它平掉,拿走奖励。规则是公开的,利润事先就定死了。
而这恰恰是它难的原因。 所有人都能看到同样的仓位在接近同样的阈值,于是整场竞争坍缩成一件事:谁先落块。
这场比赛没有发令枪
大多数交易机会都始于一个事件:一次上新、一笔大额 swap、一个价格成交。清算始于一个"缺席" —— 某个仓位因为别处的价格动了而越过阈值,而链上不会有任何东西宣布这件事。
所以对不同的机器人来说,比赛的起跑时刻是不同的,取决于各自怎么盯。每五秒轮询一次的,发现得晚;盯着预言机的,在价格更新的那一刻就知道了。
★但先发现只有在你也先落块的时候才有意义。★ 两个在同一瞬间发现同一个仓位的机器人,接下来就是一场纯粹的提交竞赛 —— 而那由费用、重试行为和路由决定。
两种盯法
轮询健康度。 定时用 getProgramAccounts 读所有仓位、算健康度、对低于阈值的动手。简单,但规模一大就很贵 —— 几百个账户短周期轮询,额度烧得飞快。
// 批量取,别循环。一次调用最多 100 个账户。
const accounts = await connection.getMultipleAccountsInfo(positionPubkeys);
const atRisk = accounts
.map((acc, i) => ({ pubkey: positionPubkeys[i], state: deserialize(acc.data) }))
.filter((p) => healthFactor(p.state) < 1.05); // 盯"接近",不只盯"已越过"
★过滤条件要设在"接近阈值",不是"已经越过"。★ 等你轮询到健康度低于 1.0 的时候,这个机会已经在被争抢了。盯住 1.05 附近的仓位,你才有时间准备。
盯价格源。 仓位之所以变得可清算,是因为价格动了。如果你盯的是预言机更新而不是仓位本身,你和协议在同一刻知道这个变化。
connection.onAccountChange(
oracleAccount,
(info) => {
const price = parsePrice(info.data);
// 只对已知处在边缘的仓位重算健康度。
const nowEligible = watchlist.filter((p) => healthAt(p, price) < 1.0);
nowEligible.forEach(submitLiquidation);
},
"processed",
);
这才是有意义的优化:★事先算好"哪个仓位在哪个价位变得可清算",然后对价格更新做出反应,而不是重新扫一遍全部。★
如果检测已经够快、问题在"先落块",免费领个 BoltTx key 改一行就能拿来做对比。
清算为什么会拥堵
清算机会是成簇出现的。一次剧烈的价格移动会让很多仓位同时变得可清算,而所有盯着的机器人在同一秒内做出反应。
于是又是那个熟悉的陷阱:你的机器人在测试时表现很好,在生产环境里每一场有竞争的清算都输。测试发生在网络平静时;★而清算恰恰发生在不平静的时候。★
那一刻决定胜负的三件事:
import { ComputeBudgetProgram } from "@solana/web3.js";
// 费用按账户竞争。每个竞争的机器人都在写
// 和你相同的仓位账户与金库账户。
const recent = await connection.getRecentPrioritizationFees({
lockedWritableAccounts: [positionAccount, vaultAccount],
});
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: 400_000 }),
);
再加上持续重试到 blockhash 过期,以及一条在区块空间被抢时扛得住的提交路径。
用清算奖励来倒推该出多少手续费
清算的收益是确定的,这意味着费用决策是算术,不是猜测。
// 清算奖励(lamport),减去你要付的费用。
const bonusLamports = collateralValue * bonusRate;
const baseFee = 5_000; // 签名成本
const priorityCost = (cuPrice * cuLimit) / 1_000_000;
const netIfWon = bonusLamports - baseFee - priorityCost;
const costIfLost = baseFee; // ★输掉的比赛照样要付这个★
★最后那一行是大多数机器人忽略的。★ 输掉一场清算竞赛不是免费的 —— 你为一笔"上链后失败"或者"根本没上链"的交易付了基础费。
如果你参与十次清算、赢两次,你的费用成本是十次尝试对两次收益。一个 20% 胜率的机器人,每次赢都得覆盖五次尝试的成本 —— 这会改变"多少费用是理性的"这个判断。
清算特有的失败模式
别人先到了。 你的交易落块然后 revert,因为仓位已经健康了。你为此付了基础费。这是竞争的正常成本。
仓位自己恢复了。 你的交易落块之前价格回去了。结果一样、成因不同 —— 而这指向收紧延迟,不是加钱。
计算预算耗尽。 清算往往要触碰很多账户,计算量大。★CU limit 估低了会让一笔本来能赢的交易失败★ —— 这是这份清单上最不该发生的损失。开发阶段拿一个真实仓位模拟一次。
预言机价格过期。 你用一个协议已经不接受的价格算出了可清算性,交易在协议自己的过期检查上 revert。
上链应该是什么水平
我们投递节点上的真实交易:中位确认 336 毫秒 —— 不到一个 slot。
在一场有竞争的清算里,落在第 2 个 slot 和第 5 个 slot 的差别,通常就是"拿到奖励"和"白付基础费"的差别。
★行情剧烈时那个数字会拉长★ —— 大部分交易不受影响,少数明显变慢。而清算就活在这少数里,因为造成清算的价格移动,和让网络拥堵的是同一批事件。
该测的是什么
只看胜率,说明不了你输在哪里。
log({
position,
eligibleSlot, // 越过阈值的时刻
detectSlot, // 你发现的时刻
submitSlot,
landSlot,
detectLag: detectSlot - eligibleSlot, // ★盯法问题★
landLag: landSlot - submitSlot, // ★提交问题★
outcome, // 赢 / revert / 从未上链
});
★detectLag 和 landLag 指向完全不同的解法。★ 检测滞后大,说明该换盯法;落块滞后大,说明是费用、重试或路由。优化错了那一个,就是团队花几个月胜率纹丝不动的原因。
BoltTx 在这里的位置
我们做提交。不做预言机数据源、不做仓位索引、不做协议集成。
提交走我们自建的四区域投递节点,带 SWQoS 路由,不暴露公共 mempool —— 交易在落块之前,传输途中观察不到。这一点在清算场景下有实际意义:你的交易本身就暴露了你要吃哪个仓位。
你在本地签名。我们不托管资金、不代签、不修改交易内容。tip 带在交易里、从你自己的钱包链上支付,交易失败时跟着一起 revert —— 这是 Solana 原子交易的机制决定的。只有到达链上的交易才计费。
免费领 API key,没有月费:
// 检测那边不用动,只换发送端点。
const sender = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");
然后在几场有竞争的清算里记录 landLag,做个对比。
常见问题
Solana 清算机器人是怎么工作的? 它盯着借贷仓位的健康度接近清算阈值,一旦某个变得可清算就提交清算交易。协议为平掉仓位支付奖励,而多个机器人会争抢同一个机会。
我的清算机器人为什么总是输? 通常输在提交而不是检测。如果你能很快发现可清算仓位、却晚三个以上 slot 落块,损失在费用、重试行为、或者价格移动带来的拥堵下的路由。
该轮询仓位还是盯预言机? 盯价格源更快,因为仓位变得可清算是价格更新的结果。事先算好哪个仓位在哪个价位翻转,然后对预言机做出反应,而不是重新扫全部。
怎么在不撞限流的前提下监控很多仓位?
用 getMultipleAccounts 批量取,别循环调 getAccountInfo。盯住"接近阈值"的仓位而不是扫描全部,并考虑用预言机订阅替代仓位轮询。
清算机器人的 priority fee 该设多少? 按已知的奖励来定,而不是按固定常数。而且要把"输掉的比赛照样付基础费"算进去 —— 你每赢一次的真实成本,是费用乘以尝试次数。
我的清算交易为什么 revert 了? 常见原因:别的机器人先到了、仓位已经健康;价格在你落块前回升了;计算预算不够;或者你用的预言机价格被协议判定为过期。
清算需要多少计算预算? 比大多数指令多,因为清算要触碰很多账户。开发阶段拿一个真实仓位模拟,把上限设在结果略高处 —— 估低了会让一笔本来能赢的交易失败。
Solana 上做清算现在还赚钱吗? 在竞争激烈的协议上利润很薄,由执行决定胜负。关注度低的协议和不常见的抵押品类型还有空间。但无论哪种,决定因素都是落块速度而不是策略。
清算需要 MEV 保护吗? 私密提交路径有帮助,因为你的交易本身就暴露了你要平哪个仓位。但它不会消除竞争,因为别的机器人可以独立看到同一个可清算仓位。
健康度到多少该触发我的机器人? 在仓位越过阈值之前就开始跟踪,而不是在它越过的那一刻。从 1.05 左右开始盯,你才有时间准备和预热路径;等到低于 1.0 才动,你已经晚起跑了。
清算为什么会扎堆出现? 因为一次价格移动会让很多仓位同时变得可清算。而同一次移动也让网络拥堵 —— 这就是为什么清算机会和困难的提交条件总是一起到来。
免费档 RPC 能跑清算机器人吗? 小规模的监控也许可以。但在一次剧烈行情中拼提交,共享端点是最糟的情况,因为它们恰好在那些时刻最忙。
怎么判断瓶颈在检测还是提交? 记录仓位变得可清算的 slot、你发现它的 slot、以及你的交易落块的 slot。检测滞后和落块滞后指向完全不同的解法。
该做部分清算还是全额清算? 取决于协议规则和你的资金量。部分清算降低资金要求、竞争可能也小一些,但每笔赚得按比例更少,而基础费一分不少。
两个机器人清算同一个仓位会怎样? 先落块的成功。第二个会 revert,因为仓位已经不可清算了 —— 而它照样为一笔"到达链上并失败"的交易付了基础费。