Última atividade 1 month ago

geekmind revisou este gist 1 month ago. Ir para a revisão

1 file changed, 333 insertions, 240 deletions

meteora_stale_pool_arb.html

@@ -3,7 +3,7 @@
3 3 <head>
4 4 <meta charset="UTF-8" />
5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 - <title>Solana Meteora 过期池套利拆解:299 万美金消失的 150 秒</title>
6 + <title>299 万美金、150 秒、9 笔交易 —— 一个 Meteora 旧池子被反向 rug 的链上拆解</title>
7 7 <style>
8 8 :root {
9 9 --bg: #0d1117;
@@ -28,7 +28,7 @@
28 28 line-height: 1.7;
29 29 }
30 30 .wrap {
31 - max-width: 920px;
31 + max-width: 960px;
32 32 margin: 0 auto;
33 33 padding: 48px 28px 96px;
34 34 }
@@ -49,10 +49,16 @@
49 49 margin-bottom: 16px;
50 50 border: 1px solid rgba(247, 185, 85, 0.3);
51 51 }
52 + .tag.verified {
53 + background: rgba(63, 185, 80, 0.12);
54 + color: var(--green);
55 + border-color: rgba(63, 185, 80, 0.3);
56 + margin-left: 8px;
57 + }
52 58 h1 {
53 - font-size: 34px;
54 - line-height: 1.25;
55 - margin: 0 0 12px;
59 + font-size: 32px;
60 + line-height: 1.3;
61 + margin: 0 0 14px;
56 62 font-weight: 700;
57 63 letter-spacing: -0.01em;
58 64 }
@@ -78,9 +84,10 @@
78 84 border: 1px solid var(--border);
79 85 padding: 1px 6px;
80 86 border-radius: 4px;
81 - font-size: 13.5px;
87 + font-size: 13px;
82 88 color: var(--accent);
83 89 font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
90 + word-break: break-all;
84 91 }
85 92 .stats {
86 93 display: grid;
@@ -147,12 +154,13 @@
147 154 width: 100%;
148 155 border-collapse: collapse;
149 156 margin: 18px 0;
150 - font-size: 14px;
157 + font-size: 13.5px;
151 158 }
152 159 th, td {
153 160 padding: 10px 12px;
154 161 border-bottom: 1px solid var(--border);
155 162 text-align: left;
163 + vertical-align: top;
156 164 }
157 165 th {
158 166 background: var(--panel2);
@@ -162,6 +170,9 @@
162 170 text-transform: uppercase;
163 171 letter-spacing: 0.03em;
164 172 }
173 + td.num { font-variant-numeric: tabular-nums; text-align: right; }
174 + td.green { color: var(--green); }
175 + td.red { color: var(--red); }
165 176 ol.steps {
166 177 counter-reset: s;
167 178 list-style: none;
@@ -204,8 +215,13 @@
204 215 background: rgba(248, 81, 73, 0.08);
205 216 border-color: rgba(248, 81, 73, 0.3);
206 217 }
218 + .callout.update {
219 + background: rgba(247, 185, 85, 0.08);
220 + border-color: rgba(247, 185, 85, 0.3);
221 + }
207 222 .callout strong { color: var(--accent2); }
208 223 .callout.warn strong { color: var(--red); }
224 + .callout.update strong { color: var(--accent); }
209 225 footer {
210 226 margin-top: 64px;
211 227 padding-top: 24px;
@@ -215,10 +231,16 @@
215 231 }
216 232 footer a { color: var(--accent2); text-decoration: none; }
217 233 footer a:hover { text-decoration: underline; }
234 + .addr {
235 + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
236 + font-size: 12px;
237 + color: var(--accent2);
238 + word-break: break-all;
239 + }
218 240
219 241 @media (max-width: 640px) {
220 242 .wrap { padding: 28px 16px 64px; }
221 - h1 { font-size: 26px; }
243 + h1 { font-size: 24px; }
222 244 .stats { grid-template-columns: repeat(2, 1fr); }
223 245 }
224 246 </style>
@@ -227,17 +249,18 @@
227 249 <div class="wrap">
228 250
229 251 <header>
230 - <span class="tag">Solana · MEV · DEX 套利</span>
231 - <h1>299 万美金,150 秒蒸发<br/>—— Meteora 过期池套利完整拆解</h1>
232 - <p class="subtitle">用图解搞懂:DLMM 的 bin 是什么,为什么旧 LP 池会变成"白送代币的提款机",以及套利机器人是怎么把它们一口气吞掉的。</p>
252 + <span class="tag">Solana · MEV · Stale Pool</span>
253 + <span class="tag verified">已用 Solscan 验证 · v2</span>
254 + <h1>299 万美金、150 秒、9 笔交易<br/>—— 一个 Meteora 旧池子被「反向 rug」的链上拆解</h1>
255 + <p class="subtitle">事件发生于 2026-05-01 19:06:54 UTC(slot 416936447 起 3 个连续 slot)。本文基于 Solscan 链上真实数据复盘,颠覆了对"过期池套利"方向的常见误解。</p>
233 256 </header>
234 257
235 258 <section>
236 259 <div class="stats">
237 - <div class="stat"><div class="num">$2.99M</div><div class="lbl">被抽走金额</div></div>
260 + <div class="stat"><div class="num">$2.99M</div><div class="lbl">总抽走金额</div></div>
238 261 <div class="stat"><div class="num">150s</div><div class="lbl">总耗时</div></div>
239 - <div class="stat"><div class="num">6 + 1</div><div class="lbl">机器人 + 鲸鱼</div></div>
240 - <div class="stat"><div class="num">10 个月</div><div class="lbl">池子无人维护</div></div>
262 + <div class="stat"><div class="num">3 + 4</div><div class="lbl">主力 + 散兵 bot</div></div>
263 + <div class="stat"><div class="num">10 个月</div><div class="lbl">DLMM 池子未维护</div></div>
241 264 </div>
242 265
243 266 <div class="quote">
@@ -245,14 +268,19 @@
245 268 <span class="src">—— @anshu_code, X / 2026-05-06</span>
246 269 </div>
247 270
248 - <p>这条推文讲的,是 Solana 链上一个被忽略了 10 个月的 <strong>Meteora DLMM 流动性池</strong>,在 150 秒内被 6 个套利机器人和一个大户合力"洗"了一遍,搬走 299 万美金。本文用图把它拆开讲清楚。</p>
271 + <div class="callout update">
272 + <strong>v2 更新说明:</strong>本报告 v1 基于推文文字推理,方向<strong>讲反了</strong>。链上实测后已修正:stale 池子里装的不是"等卖的便宜代币",而是"愿意高价收购废纸的 USDC"。机器人不是去捡便宜币,是去把<strong>近乎归零的代币塞进去换真金白银</strong>。下文 §3-§5 全部基于 Solscan 实测数据。
273 + </div>
249 274 </section>
250 275
251 - <h2>1. 它属于哪一类套利?</h2>
252 - <p>这种玩法的术语叫 <strong>Stale Pool Arbitrage(过期池套利)</strong>。靶子是那些 <em>LP 挂上去就不再维护</em> 的集中流动性池——挂的还是几个月前的"老价格",外部市场早已涨飞,池子却毫无觉察。</p>
276 + <h2>1. 事件一句话总结</h2>
277 + <p>有个 LP 在 2025 年 7 月左右往 Meteora 上一个 ANB-USDC 的 DLMM 池子里塞了至少 <strong>$1.4M 的 USDC</strong>,挂在 ANB ~ $0.01-$0.05/枚的价格档位(bins)上。10 个月后,ANB 真实市价跌到了 <strong>$0.0000113/枚</strong>(缩水 ~1000 倍),LP 没有移除流动性也没人交易这个池子,<strong>active bin 卡在原位不动</strong>。2026/5/1 这个池子被一群套利机器人发现,3 个 slot 内 ~$1.4M USDC 全被搬空,单笔最大利润 <strong>$696,194</strong>。</p>
278 +
279 + <h2>2. 这次的"鲸鱼"是谁,钱是怎么流的?</h2>
280 + <p>推文里说的"1 whale, 6 bots, 9 transactions"——这里的 whale <strong>不是来 swap 的大户</strong>,而是池子的 LP 本人。机器人不是从某个交易者身上薅羊毛,而是<strong>直接把 LP 当年存进去的 USDC 一捆捆拎走</strong>。</p>
253 281
254 282 <figure>
255 - <svg viewBox="0 0 760 280" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="过期池套利示意">
283 + <svg viewBox="0 0 880 380" xmlns="http://www.w3.org/2000/svg">
256 284 <defs>
257 285 <linearGradient id="bg1" x1="0" x2="0" y1="0" y2="1">
258 286 <stop offset="0" stop-color="#1c2330"/>
@@ -261,264 +289,329 @@
261 289 <marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
262 290 <path d="M0,0 L8,3 L0,6 z" fill="#f7b955"/>
263 291 </marker>
292 + <marker id="arrow_red" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
293 + <path d="M0,0 L8,3 L0,6 z" fill="#f85149"/>
294 + </marker>
264 295 </defs>
265 - <rect width="760" height="280" fill="url(#bg1)" rx="10"/>
266 -
267 - <!-- Raydium box -->
268 - <rect x="40" y="60" width="240" height="160" fill="#0d1117" stroke="#3fb950" stroke-width="1.5" rx="10"/>
269 - <text x="160" y="90" text-anchor="middle" fill="#3fb950" font-size="15" font-weight="700">Raydium / 真实市场</text>
270 - <text x="160" y="135" text-anchor="middle" fill="#e6edf3" font-size="13">代币 X 已涨到</text>
271 - <text x="160" y="170" text-anchor="middle" fill="#3fb950" font-size="32" font-weight="700">$1.00</text>
272 - <text x="160" y="195" text-anchor="middle" fill="#8b949e" font-size="11">活跃交易 · 价格随市场实时更新</text>
273 -
274 - <!-- Meteora box -->
275 - <rect x="480" y="60" width="240" height="160" fill="#0d1117" stroke="#f85149" stroke-width="1.5" rx="10"/>
276 - <text x="600" y="90" text-anchor="middle" fill="#f85149" font-size="15" font-weight="700">Meteora 旧池子</text>
277 - <text x="600" y="135" text-anchor="middle" fill="#e6edf3" font-size="13">10 个月没人交易</text>
278 - <text x="600" y="170" text-anchor="middle" fill="#f85149" font-size="32" font-weight="700">$0.001</text>
279 - <text x="600" y="195" text-anchor="middle" fill="#8b949e" font-size="11">价格停在 LP 创建时的水平</text>
280 -
281 - <!-- Bridge / arrow -->
282 - <text x="380" y="130" text-anchor="middle" fill="#f7b955" font-size="13" font-weight="700">价差 1000×</text>
283 - <line x1="290" y1="150" x2="470" y2="150" stroke="#f7b955" stroke-width="2" marker-end="url(#arrow)"/>
284 - <text x="380" y="180" text-anchor="middle" fill="#8b949e" font-size="11">套利机器人在这里下手</text>
296 + <rect width="880" height="380" fill="url(#bg1)" rx="10"/>
297 +
298 + <!-- LP -->
299 + <rect x="40" y="40" width="170" height="80" fill="#0d1117" stroke="#bc8cff" stroke-width="1.5" rx="10"/>
300 + <text x="125" y="65" text-anchor="middle" fill="#bc8cff" font-size="14" font-weight="700">"鲸鱼" = LP</text>
301 + <text x="125" y="85" text-anchor="middle" fill="#e6edf3" font-size="11">10 个月前</text>
302 + <text x="125" y="103" text-anchor="middle" fill="#bc8cff" font-size="13" font-weight="700">灌入 ≥ $1.4M USDC</text>
303 +
304 + <!-- Stale Pool -->
305 + <rect x="320" y="20" width="240" height="120" fill="#0d1117" stroke="#f85149" stroke-width="2" rx="10"/>
306 + <text x="440" y="48" text-anchor="middle" fill="#f85149" font-size="14" font-weight="700">ANB-USDC DLMM 池子</text>
307 + <text x="440" y="70" text-anchor="middle" fill="#e6edf3" font-size="11">USDC 沉睡在高价 bins</text>
308 + <text x="440" y="92" text-anchor="middle" fill="#8b949e" font-size="11">愿意按 $0.01/ANB 收购</text>
309 + <text x="440" y="114" text-anchor="middle" fill="#f85149" font-size="11">(真实市价仅 $0.0000113)</text>
310 + <text x="440" y="132" text-anchor="middle" fill="#f85149" font-size="11" font-weight="700">10 个月没人动它</text>
311 +
312 + <!-- Arrow LP → Pool -->
313 + <line x1="210" y1="80" x2="316" y2="80" stroke="#bc8cff" stroke-width="2" marker-end="url(#arrow)"/>
314 +
315 + <!-- Source pool (cheap ANB) -->
316 + <rect x="320" y="180" width="240" height="80" fill="#0d1117" stroke="#3fb950" stroke-width="1.5" rx="10"/>
317 + <text x="440" y="208" text-anchor="middle" fill="#3fb950" font-size="14" font-weight="700">ANB-USDC DAMM v2</text>
318 + <text x="440" y="230" text-anchor="middle" fill="#e6edf3" font-size="11">价格紧贴市价</text>
319 + <text x="440" y="250" text-anchor="middle" fill="#3fb950" font-size="11">$0.20 USDC ≈ 25M ANB</text>
320 +
321 + <!-- Bots -->
322 + <rect x="660" y="40" width="180" height="80" fill="#0d1117" stroke="#f7b955" stroke-width="1.5" rx="10"/>
323 + <text x="750" y="65" text-anchor="middle" fill="#f7b955" font-size="14" font-weight="700">7 个套利 bot</text>
324 + <text x="750" y="85" text-anchor="middle" fill="#e6edf3" font-size="11">总投入 ≈ $1.5 USDC</text>
325 + <text x="750" y="105" text-anchor="middle" fill="#f7b955" font-size="13" font-weight="700">总取出 ≈ $2.99M USDC</text>
326 +
327 + <!-- Bot to source pool -->
328 + <line x1="660" y1="105" x2="565" y2="200" stroke="#f7b955" stroke-width="2" marker-end="url(#arrow)"/>
329 + <text x="640" y="160" fill="#f7b955" font-size="11">① 用几毛钱</text>
330 + <text x="640" y="178" fill="#f7b955" font-size="11">买几千万 ANB</text>
331 +
332 + <!-- Bot to stale pool -->
333 + <line x1="565" y1="105" x2="660" y2="80" stroke="#f7b955" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="0"/>
334 + <text x="563" y="158" fill="#f7b955" font-size="11" text-anchor="end">② 把 ANB 砸进 stale 池</text>
335 + <text x="563" y="176" fill="#f7b955" font-size="11" text-anchor="end">换出 $282K-$696K USDC</text>
336 +
337 + <!-- ANB to stale pool arrow -->
338 + <line x1="440" y1="180" x2="440" y2="142" stroke="#f7b955" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="4 3"/>
339 +
340 + <!-- Bot grabs USDC -->
341 + <line x1="558" y1="78" x2="660" y2="65" stroke="#f85149" stroke-width="2" marker-end="url(#arrow_red)"/>
342 +
343 + <!-- Footer -->
344 + <line x1="40" y1="305" x2="840" y2="305" stroke="#30363d" stroke-width="1" stroke-dasharray="3 3"/>
345 + <text x="40" y="333" fill="#8b949e" font-size="12">资金净流向:</text>
346 + <text x="160" y="333" fill="#bc8cff" font-size="12" font-weight="700">LP(whale)的 USDC</text>
347 + <text x="320" y="333" fill="#8b949e" font-size="12">→</text>
348 + <text x="345" y="333" fill="#f85149" font-size="12" font-weight="700">stale DLMM 池</text>
349 + <text x="465" y="333" fill="#8b949e" font-size="12">→</text>
350 + <text x="490" y="333" fill="#f7b955" font-size="12" font-weight="700">套利 bots</text>
351 + <text x="40" y="358" fill="#8b949e" font-size="11">机器人付出的成本只有:base fee + Jito tip + 几毛钱用来买 ANB;剩下全是利润。</text>
285 352 </svg>
286 - <figcaption>同一种代币,两个池子,价格差 1000 倍。差距在 LP 不维护时会一直存在。</figcaption>
353 + <figcaption>真实链上资金流:LP 当年灌入的 USDC,10 个月后被机器人用近乎为零的成本「赎」走。</figcaption>
287 354 </figure>
288 355
289 - <h2>2. 先理解 DLMM:什么是 bin?</h2>
290 - <p>Meteora DLMM(Dynamic Liquidity Market Maker)跟 Uniswap v3 思路一样:把价格切成一格一格的"档位",每一档叫 <strong>bin</strong>。LP 不是在一条曲线上放钱,而是把代币塞进具体某几个 bin 里。</p>
356 + <h2>3. Stale 池子结构(修正版)</h2>
357 + <p>这次的关键是:池子里"过期"的不是代币,是 <strong>USDC</strong>。LP 当时挂的是"<em>限价买单</em>"——把 USDC 塞在 active bin 下方,挂在 ANB = $0.005、$0.01、$0.05 这种<strong>它认为合理</strong>的价格上。ANB 价格崩了 1000 倍后,这些 USDC 还在原位,等着按"老价格"收购 ANB。</p>
291 358
292 359 <figure>
293 - <svg viewBox="0 0 760 320" xmlns="http://www.w3.org/2000/svg">
294 - <rect width="760" height="320" fill="url(#bg1)" rx="10"/>
295 -
296 - <!-- Active bin marker -->
297 - <line x1="380" y1="40" x2="380" y2="280" stroke="#f7b955" stroke-width="1" stroke-dasharray="4 4"/>
298 - <text x="380" y="32" text-anchor="middle" fill="#f7b955" font-size="13" font-weight="700">↓ Active Bin(当前价)</text>
299 -
300 - <!-- Bins -->
301 - <g font-family="ui-monospace, monospace" font-size="11">
302 - <!-- Y bins (left, USDC) -->
303 - <g>
304 - <rect x="60" y="180" width="48" height="100" fill="#3fb950" opacity="0.85" rx="3"/>
305 - <rect x="115" y="160" width="48" height="120" fill="#3fb950" opacity="0.85" rx="3"/>
306 - <rect x="170" y="140" width="48" height="140" fill="#3fb950" opacity="0.85" rx="3"/>
307 - <rect x="225" y="120" width="48" height="160" fill="#3fb950" opacity="0.85" rx="3"/>
308 - <rect x="280" y="105" width="48" height="175" fill="#3fb950" opacity="0.85" rx="3"/>
309 - <text x="84" y="298" text-anchor="middle" fill="#8b949e">$0.5</text>
310 - <text x="139" y="298" text-anchor="middle" fill="#8b949e">$0.6</text>
311 - <text x="194" y="298" text-anchor="middle" fill="#8b949e">$0.7</text>
312 - <text x="249" y="298" text-anchor="middle" fill="#8b949e">$0.8</text>
313 - <text x="304" y="298" text-anchor="middle" fill="#8b949e">$0.9</text>
314 - </g>
315 - <!-- Active -->
316 - <rect x="358" y="100" width="44" height="180" fill="#f7b955" opacity="0.9" rx="3"/>
317 - <text x="380" y="298" text-anchor="middle" fill="#f7b955" font-weight="700">$1.0</text>
318 -
319 - <!-- X bins (right, token) -->
320 - <g>
321 - <rect x="430" y="105" width="48" height="175" fill="#bc8cff" opacity="0.85" rx="3"/>
322 - <rect x="485" y="120" width="48" height="160" fill="#bc8cff" opacity="0.85" rx="3"/>
323 - <rect x="540" y="140" width="48" height="140" fill="#bc8cff" opacity="0.85" rx="3"/>
324 - <rect x="595" y="160" width="48" height="120" fill="#bc8cff" opacity="0.85" rx="3"/>
325 - <rect x="650" y="180" width="48" height="100" fill="#bc8cff" opacity="0.85" rx="3"/>
326 - <text x="454" y="298" text-anchor="middle" fill="#8b949e">$1.1</text>
327 - <text x="509" y="298" text-anchor="middle" fill="#8b949e">$1.2</text>
328 - <text x="564" y="298" text-anchor="middle" fill="#8b949e">$1.3</text>
329 - <text x="619" y="298" text-anchor="middle" fill="#8b949e">$1.4</text>
330 - <text x="674" y="298" text-anchor="middle" fill="#8b949e">$1.5</text>
331 - </g>
360 + <svg viewBox="0 0 880 360" xmlns="http://www.w3.org/2000/svg">
361 + <rect width="880" height="360" fill="url(#bg1)" rx="10"/>
362 +
363 + <!-- Title -->
364 + <text x="440" y="34" text-anchor="middle" fill="#e6edf3" font-size="15" font-weight="700">DLMM bins 真实分布(创建时 vs 被发现时)</text>
365 +
366 + <!-- LP setup time -->
367 + <text x="40" y="78" fill="#bc8cff" font-size="13" font-weight="700">10 个月前 · LP 设置时</text>
368 + <text x="40" y="96" fill="#8b949e" font-size="11">假设当时 ANB 市价 ≈ $0.01</text>
369 + <g>
370 + <rect x="40" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
371 + <rect x="95" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
372 + <rect x="150" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
373 + <rect x="205" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
374 + <rect x="260" y="110" width="50" height="60" fill="#f7b955" rx="3"/>
375 + <rect x="315" y="110" width="50" height="60" fill="#bc8cff" opacity="0.6" rx="3"/>
376 + <text x="65" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.005</text>
377 + <text x="120" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.007</text>
378 + <text x="175" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.008</text>
379 + <text x="230" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.009</text>
380 + <text x="285" y="188" text-anchor="middle" fill="#f7b955" font-size="10" font-weight="700">$0.01</text>
381 + <text x="340" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.012</text>
382 + <text x="65" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
383 + <text x="120" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
384 + <text x="175" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
385 + <text x="230" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
332 386 </g>
333 -
334 - <!-- Labels -->
335 - <text x="194" y="80" text-anchor="middle" fill="#3fb950" font-size="13" font-weight="700">下方 bins</text>
336 - <text x="194" y="98" text-anchor="middle" fill="#3fb950" font-size="11">装 USDC(限价买单)</text>
337 -
338 - <text x="564" y="80" text-anchor="middle" fill="#bc8cff" font-size="13" font-weight="700">上方 bins</text>
339 - <text x="564" y="98" text-anchor="middle" fill="#bc8cff" font-size="11">装 代币 X(限价卖单)</text>
340 - </svg>
341 - <figcaption>DLMM 池子结构:active bin 把价格分成左右两半。左边的 bin 装 USDC,右边的装代币。</figcaption>
342 - </figure>
343 -
344 - <div class="callout">
345 - <strong>关键三点:</strong>
346 - <ol style="margin:8px 0 0; padding-left: 20px;">
347 - <li>每个 bin 对应一个<strong>固定</strong>的兑换价(创建时算好的常数)。</li>
348 - <li>active bin <strong>下方</strong>的 bins 装 Y(USDC),是"低价等买 X 的限价买单"。</li>
349 - <li>active bin <strong>上方</strong>的 bins 装 X(代币),是"高价等卖出的限价卖单"。</li>
350 - </ol>
351 - </div>
352 -
353 - <h2>3. 为什么 bin 会"老价格存在"?</h2>
354 - <p>这是这次事件最反直觉的地方。<strong>DLMM 池子的价格不会自动跟着外部市场走</strong>——它只在<em>有人在本池子做 swap</em>的时候才移动 active bin。</p>
355 -
356 - <figure>
357 - <svg viewBox="0 0 760 360" xmlns="http://www.w3.org/2000/svg">
358 - <rect width="760" height="360" fill="url(#bg1)" rx="10"/>
359 -
360 - <!-- Time axis -->
361 - <line x1="60" y1="320" x2="700" y2="320" stroke="#30363d" stroke-width="1"/>
362 - <text x="60" y="345" fill="#8b949e" font-size="11">Day 0</text>
363 - <text x="380" y="345" fill="#8b949e" font-size="11">Day 1 ~ 300(无人交易)</text>
364 - <text x="700" y="345" text-anchor="end" fill="#8b949e" font-size="11">Day 300(被发现)</text>
365 -
366 - <!-- Raydium price line - rising -->
367 - <text x="60" y="48" fill="#3fb950" font-size="12" font-weight="700">Raydium 真实市价</text>
368 - <path d="M60,290 Q200,280 300,200 T700,80" stroke="#3fb950" stroke-width="2.5" fill="none"/>
369 - <circle cx="60" cy="290" r="4" fill="#3fb950"/>
370 - <circle cx="700" cy="80" r="5" fill="#3fb950"/>
371 - <text x="80" y="285" fill="#3fb950" font-size="11">$0.001</text>
372 - <text x="688" y="74" text-anchor="end" fill="#3fb950" font-size="11" font-weight="700">$1.00 ↑↑↑</text>
373 -
374 - <!-- Meteora price line - flat -->
375 - <text x="60" y="200" fill="#f85149" font-size="12" font-weight="700">Meteora 池子 active bin</text>
376 - <line x1="60" y1="290" x2="640" y2="290" stroke="#f85149" stroke-width="2.5" stroke-dasharray="6 4"/>
377 - <circle cx="60" cy="290" r="4" fill="#f85149"/>
378 - <circle cx="640" cy="290" r="4" fill="#f85149"/>
379 - <text x="380" y="282" text-anchor="middle" fill="#f85149" font-size="11">10 个月一动不动 · 一直停在 $0.001</text>
380 -
381 - <!-- Gap arrow -->
382 - <line x1="660" y1="80" x2="660" y2="280" stroke="#f7b955" stroke-width="1.5" stroke-dasharray="3 3"/>
383 - <line x1="650" y1="80" x2="670" y2="80" stroke="#f7b955" stroke-width="1.5"/>
384 - <line x1="650" y1="280" x2="670" y2="280" stroke="#f7b955" stroke-width="1.5"/>
385 - <text x="678" y="180" fill="#f7b955" font-size="13" font-weight="700">价差</text>
386 - <text x="678" y="198" fill="#f7b955" font-size="11">1000×</text>
387 + <text x="40" y="220" fill="#8b949e" font-size="11">↑ active bin 在 $0.01 · 下方 4 格 USDC 等买</text>
388 +
389 + <!-- 10 months later -->
390 + <text x="480" y="78" fill="#f85149" font-size="13" font-weight="700">10 个月后 · 被发现时</text>
391 + <text x="480" y="96" fill="#8b949e" font-size="11">真实市价跌到 $0.0000113,但池子……</text>
392 + <g>
393 + <rect x="480" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
394 + <rect x="535" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
395 + <rect x="590" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
396 + <rect x="645" y="110" width="50" height="60" fill="#3fb950" opacity="0.85" rx="3"/>
397 + <rect x="700" y="110" width="50" height="60" fill="#f7b955" rx="3"/>
398 + <rect x="755" y="110" width="50" height="60" fill="#bc8cff" opacity="0.6" rx="3"/>
399 + <text x="505" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.005</text>
400 + <text x="560" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.007</text>
401 + <text x="615" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.008</text>
402 + <text x="670" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.009</text>
403 + <text x="725" y="188" text-anchor="middle" fill="#f7b955" font-size="10" font-weight="700">$0.01</text>
404 + <text x="780" y="188" text-anchor="middle" fill="#8b949e" font-size="10">$0.012</text>
405 + <text x="505" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
406 + <text x="560" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
407 + <text x="615" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
408 + <text x="670" y="142" text-anchor="middle" fill="#fff" font-size="11">USDC</text>
409 + </g>
410 + <text x="480" y="220" fill="#f85149" font-size="11" font-weight="700">↑ active bin 还在 $0.01 · 下方 USDC 一动没动</text>
411 + <text x="480" y="238" fill="#f85149" font-size="11">外部市价已是 $0.0000113,池子按 $0.005-$0.01 一个收</text>
412 +
413 + <!-- Arrow connecting -->
414 + <line x1="380" y1="140" x2="476" y2="140" stroke="#8b949e" stroke-width="1.5" stroke-dasharray="3 3" marker-end="url(#arrow)"/>
415 + <text x="428" y="135" text-anchor="middle" fill="#8b949e" font-size="11">10 个月没人交易</text>
416 + <text x="428" y="155" text-anchor="middle" fill="#8b949e" font-size="11">active bin 不动</text>
417 +
418 + <!-- Bot exploit arrow -->
419 + <text x="640" y="280" text-anchor="middle" fill="#f7b955" font-size="13" font-weight="700">套利 bot 发现:</text>
420 + <text x="640" y="300" text-anchor="middle" fill="#e6edf3" font-size="12">"我手里 50M ANB 在外面只值 $565,"</text>
421 + <text x="640" y="320" text-anchor="middle" fill="#e6edf3" font-size="12">"塞进这个池子能换到 $696,194 的 USDC"</text>
422 + <text x="640" y="340" text-anchor="middle" fill="#f7b955" font-size="12" font-weight="700">→ 一笔 atomic tx 全部搞定</text>
387 423 </svg>
388 - <figcaption>外部市场涨了 1000 倍,Meteora 池子的 active bin 却没移动半步——因为没人来这里 swap。</figcaption>
424 + <figcaption>关键洞察:DLMM 的"stale"是双向的——这次过期的方向是 USDC bins 在等高价收 ANB,机器人对它做的是「砸盘式套利」而非「捡漏式套利」。</figcaption>
389 425 </figure>
390 426
391 - <p>所以"代币涨了为什么 bin 还能低价存在"的答案是:</p>
392 427 <div class="callout warn">
393 - <strong>Solana 链上没有"全局市场价"。</strong>每个 DEX 池子都是独立的小宇宙。Raydium 的价格涨到 $1 跟 Meteora 这个池子毫无机械联系——除非有套利机器人主动来"对齐"它。在它被发现之前,那批挂在 $0.001、$0.0011、$0.005、$0.01 ... 的 X 代币就一直**安静地坐在那儿等买家**。
428 + <strong>所以:</strong>"代币涨了为什么 bin 还能低价存在"这个问题,在这个事件里其实反过来——是<strong>代币归零了,bin 还在按高价收</strong>。本质都是一回事:<em>DLMM 的 active bin 必须有交易才会移动,外部价格变化跟池子无关</em>。漂移可以是任意方向,stale 一旦形成,被发现的那刻就是清算。
394 429 </div>
395 430
396 - <h2>4. 攻击是怎么发生的(图解)</h2>
397 - <p>为了讲清楚机器人具体在干什么,下面把那笔 transaction 拆成 4 个画面:</p>
398 -
399 - <figure>
400 - <svg viewBox="0 0 760 480" xmlns="http://www.w3.org/2000/svg">
401 - <rect width="760" height="480" fill="url(#bg1)" rx="10"/>
402 -
403 - <!-- Frame 1 -->
404 - <text x="20" y="34" fill="#f7b955" font-size="13" font-weight="700">① 池子初始状态:active bin 在 $0.001,上方塞满便宜 X 代币</text>
405 - <g transform="translate(40, 50)">
406 - <rect x="0" y="0" width="40" height="60" fill="#f7b955" rx="2"/>
407 - <rect x="48" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
408 - <rect x="96" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
409 - <rect x="144" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
410 - <rect x="192" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
411 - <rect x="240" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
412 - <rect x="288" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
413 - <rect x="336" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
414 - <text x="20" y="78" text-anchor="middle" fill="#f7b955" font-size="10">$0.001</text>
415 - <text x="68" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.002</text>
416 - <text x="116" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.005</text>
417 - <text x="164" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.01</text>
418 - <text x="212" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.05</text>
419 - <text x="260" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.2</text>
420 - <text x="308" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.5</text>
421 - <text x="356" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$1.0</text>
422 - <text x="450" y="38" fill="#bc8cff" font-size="11">每个紫格里都有大量代币 X,标价远低于市价</text>
423 - </g>
424 -
425 - <!-- Frame 2 -->
426 - <text x="20" y="148" fill="#f7b955" font-size="13" font-weight="700">② 机器人灌入 USDC,吞掉第一格 bin(按 $0.001 买)</text>
427 - <g transform="translate(40, 164)">
428 - <rect x="0" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="2" rx="2"/>
429 - <rect x="48" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
430 - <rect x="96" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
431 - <rect x="144" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
432 - <rect x="192" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
433 - <rect x="240" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
434 - <rect x="288" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
435 - <rect x="336" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
436 - <text x="20" y="78" text-anchor="middle" fill="#3fb950" font-size="10" font-weight="700">已吃完</text>
437 - <text x="450" y="38" fill="#3fb950" font-size="11">代币 X 进入机器人钱包,bin #1 变成 USDC</text>
438 - </g>
439 -
440 - <!-- Frame 3 -->
441 - <text x="20" y="262" fill="#f7b955" font-size="13" font-weight="700">③ active bin 推到下一格,继续吃(按 $0.002, $0.005, $0.01... 一路买上去)</text>
442 - <g transform="translate(40, 278)">
443 - <rect x="0" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
444 - <rect x="48" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
445 - <rect x="96" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
446 - <rect x="144" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
447 - <rect x="192" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
448 - <rect x="240" y="0" width="40" height="60" fill="#f7b955" rx="2"/>
449 - <rect x="288" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
450 - <rect x="336" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
451 - <text x="450" y="38" fill="#f7b955" font-size="11">active bin 一格格往上推,直到逼近真实市价 $1.0</text>
452 - </g>
453 -
454 - <!-- Frame 4 -->
455 - <text x="20" y="378" fill="#f7b955" font-size="13" font-weight="700">④ 同一笔 transaction 里把吃到的 X 全部发到 Raydium 按 $1.0 卖出</text>
456 - <g transform="translate(40, 394)">
457 - <rect x="0" y="0" width="80" height="60" fill="#161b22" stroke="#bc8cff" stroke-width="1.5" rx="6"/>
458 - <text x="40" y="26" text-anchor="middle" fill="#bc8cff" font-size="11" font-weight="700">Meteora</text>
459 - <text x="40" y="44" text-anchor="middle" fill="#8b949e" font-size="10">买 X · 极便宜</text>
431 + <h2>4. 链上真实数据(3 笔顶级 tx)</h2>
432 + <p>所有数据来自 Solscan 的 transaction explorer。这三笔合计 <strong>$1.38M</strong>(占总额 46%),其余 6 笔是更小的尾单。</p>
460 433
461 - <text x="160" y="34" fill="#f7b955" font-size="20">→</text>
434 + <table>
435 + <thead>
436 + <tr>
437 + <th>#</th>
438 + <th>利润 (USDC)</th>
439 + <th>Slot</th>
440 + <th>Bot 钱包</th>
441 + <th>路径</th>
442 + <th>抢量</th>
443 + <th>消耗</th>
444 + </tr>
445 + </thead>
446 + <tbody>
447 + <tr>
448 + <td>1</td>
449 + <td class="num green">+$696,194</td>
450 + <td>416936448</td>
451 + <td><span class="addr">ESuvjv…cJbg8</span></td>
452 + <td>USDC → ANX → ANB → USDC<br/><span style="color:var(--text-dim); font-size:12px">3 跳,绕 ANX 中转</span></td>
453 + <td>Jito 2.3 SOL<br/>($205)</td>
454 + <td>1.25M CU</td>
455 + </tr>
456 + <tr>
457 + <td>2</td>
458 + <td class="num green">+$403,294</td>
459 + <td>416936447</td>
460 + <td><span class="addr">2QfBNK…nWW2T</span></td>
461 + <td>USDC → ANB → USDC<br/><span style="color:var(--text-dim); font-size:12px">2 跳,自定义 arb 程序 sattC</span></td>
462 + <td>Priority<br/>0.5 SOL ($45)</td>
463 + <td>0.65M CU</td>
464 + </tr>
465 + <tr>
466 + <td>3</td>
467 + <td class="num green">+$282,761</td>
468 + <td>416936449</td>
469 + <td><span class="addr">MRiYA4…JvoCsa</span></td>
470 + <td>USDC → ANB → USDC<br/><span style="color:var(--text-dim); font-size:12px">2 跳,nonce 账户 + 自定义 arb 程序</span></td>
471 + <td>Jito 5 SOL<br/>($447)</td>
472 + <td>0.36M CU</td>
473 + </tr>
474 + </tbody>
475 + </table>
462 476
463 - <rect x="200" y="0" width="80" height="60" fill="#161b22" stroke="#3fb950" stroke-width="1.5" rx="6"/>
464 - <text x="240" y="26" text-anchor="middle" fill="#3fb950" font-size="11" font-weight="700">Raydium</text>
465 - <text x="240" y="44" text-anchor="middle" fill="#8b949e" font-size="10">卖 X · 市价</text>
477 + <h3>解剖 #1:$696,194 那一笔</h3>
478 + <p>这是单笔最大利润。<strong>3 跳路径</strong>,绕了一个中间币 ANX 来增加每一步的"汇率优势":</p>
466 479
467 - <text x="320" y="34" fill="#f7b955" font-size="20">→</text>
480 + <ol class="steps">
481 + <li><strong>付 $0.227 USDC,从 ANX-USDC DAMM v2 池换出 72,793 个 ANX</strong>(这就是 bot 唯一掏的"本金")</li>
482 + <li><strong>把 72,793 ANX 塞进 ANX-ANB DAMM v2 池,换出 50,011,673 ANB</strong>(这步在正常池子完成,价格紧贴市价)</li>
483 + <li><strong>把 50,011,673 ANB 塞进 stale 的 ANB-USDC DLMM 池,换出 $696,194 USDC</strong>(这就是 stale 池被薅的一刻)</li>
484 + <li><strong>给 Jitotip 5 转 2.3 SOL($205)抢落地</strong></li>
485 + </ol>
468 486
469 - <rect x="360" y="0" width="120" height="60" fill="#161b22" stroke="#f7b955" stroke-width="1.5" rx="6"/>
470 - <text x="420" y="26" text-anchor="middle" fill="#f7b955" font-size="11" font-weight="700">机器人钱包</text>
471 - <text x="420" y="44" text-anchor="middle" fill="#f7b955" font-size="10" font-weight="700">+ $400K USDC</text>
487 + <p>整笔交易完成后,stale 池子的 USDC 余额从 <strong>$1,412,213 → $716,018</strong>,单笔被搬走 49%。</p>
488 +
489 + <div class="panel">
490 + <strong>4 条指令,1 笔 atomic tx:</strong>
491 + <pre style="margin:8px 0 0; color:var(--text-dim); font-size:13px; font-family:ui-monospace,monospace; overflow-x:auto;">
492 + #1 ComputeBudget: SetComputeUnitLimit
493 + #2 Meteora DAMM v2: swap2 ← USDC → ANX
494 + #3 Meteora DAMM v2: swap2 ← ANX → ANB
495 + #4 Meteora DLMM: swap2 ← ANB → USDC(stale 池)
496 + #5 System Program: transfer ← Jito tip 2.3 SOL
497 + </pre>
498 + <p style="margin:10px 0 0; color:var(--text-dim); font-size:13px;">使用了 3 个 Address Lookup Tables 压缩账户引用,否则 33 个账户塞不进 1232 字节的 tx 大小限制。</p>
499 + </div>
472 500
473 - <text x="540" y="38" fill="#8b949e" font-size="11">所有指令打包进 1 笔 tx,</text>
474 - <text x="540" y="54" fill="#8b949e" font-size="11">失败回滚 → 永远不会亏</text>
475 - </g>
476 - </svg>
477 - <figcaption>套利的整个动作:低价吃光 → 市价卖出 → 同一笔交易原子完成。</figcaption>
478 - </figure>
501 + <h2>5. 三种不同 bot 的策略对比</h2>
502 + <p>3 笔交易、3 个独立钱包、3 套差异显著的策略——这说明它们是 3 个独立团队同时盯到了这个池子:</p>
479 503
480 - <h3>事件时间线</h3>
481 504 <table>
482 505 <thead>
483 - <tr><th>时刻</th><th>角色</th><th>动作</th><th>结果</th></tr>
506 + <tr>
507 + <th></th>
508 + <th>Bot 1(ESuvjv…)</th>
509 + <th>Bot 2(2QfBNK…)</th>
510 + <th>Bot 3(MRiYA4…)</th>
511 + </tr>
484 512 </thead>
485 513 <tbody>
486 - <tr><td>T+0s</td><td>鲸鱼</td><td>大额 swap,第一次"打开"这个被遗忘的池子</td><td>active bin 开始移动</td></tr>
487 - <tr><td>T+0.4s</td><td>Bot 1</td><td>监听器触发,发起反向套利</td><td>$0.16 成本 → $403K 盈利</td></tr>
488 - <tr><td>T+1.2s</td><td>Bot 2</td><td>下一个 block 抢落地</td><td>$0.23 成本 → $696K 盈利</td></tr>
489 - <tr><td>T+0~150s</td><td>Bot 3-6</td><td>剩余 bin 慢慢被扫</td><td>累计接近 $3M</td></tr>
490 - <tr><td>T+150s</td><td>—</td><td>active bin 已逼近 Raydium 市价</td><td>套利窗口关闭</td></tr>
514 + <tr><th>抢落地手段</th><td>Jito bundle + tip</td><td>纯 priority fee</td><td>Jito bundle + tip + nonce</td></tr>
515 + <tr><th>路径长度</th><td>3 跳(绕 ANX)</td><td>2 跳</td><td>2 跳</td></tr>
516 + <tr><th>程序结构</th><td>直接调 Meteora 程序</td><td>自定义 on-chain arb 程序<br/><span class="addr">sattC…</span></td><td>自定义 on-chain arb 程序<br/><span class="addr">AN225k…</span></td></tr>
517 + <tr><th>付的"过路费"</th><td>$205 → Jito 验证者</td><td>$45 → 当 leader</td><td>$447 → Jito 验证者</td></tr>
518 + <tr><th>本金 USDC</th><td>$0.227</td><td>$0.156</td><td>$0.127</td></tr>
519 + <tr><th>毛利</th><td>$696,194</td><td>$403,294</td><td>$282,761</td></tr>
520 + <tr><th>"过路费 / 毛利"</th><td>0.029%</td><td>0.011%</td><td>0.158%</td></tr>
491 521 </tbody>
492 522 </table>
493 523
494 - <h2>5. 技术实现骨架(如果你想做)</h2>
524 + <div class="callout">
525 + <strong>有意思的是 Bot 3 的 tip 反而最高($447)但抢到的利润最少。</strong>原因可能是:池子被前两笔搬空了 696K + 403K = 1.1M,留给 Bot 3 的 USDC 只剩 ~580K,所以即便它愿意付更多 tip,可吃的肉本身已经少了。
526 + </div>
495 527
496 - <ol class="steps">
497 - <li><strong>扫描全网 Meteora DLMM 池找"stale"标的。</strong>拉所有 DLMM 池的 PDA 账户,用 SDK 读 active bin 价格,跟 Jupiter / Birdeye 拿到的市价对比。差 5-10% 以上的进候选池。这一步可以离线一天扫一次。</li>
498 - <li><strong>实时盯盘候选池。</strong>用 Helius / Triton 的 Geyser gRPC 或 <code>accountSubscribe</code> WebSocket 订阅这些池子账户,状态一变就 push 给你(延迟 50-200ms)。</li>
499 - <li><strong>盈亏模拟。</strong>调用 <code>@meteora-ag/dlmm</code> 模拟从这个池子买 X、再到 Raydium 卖的总收益。扣掉两边手续费、Solana 优先费、Jito tip 后还赚才发交易。</li>
500 - <li><strong>原子 transaction。</strong>把"Meteora 买 + Raydium 卖"两条 swap 指令打到同一笔 tx 里,每个指令都设 <code>min_out_amount</code>,价格滑了整笔回滚。账户多塞不下时用 Address Lookup Table (LUT) 压缩。</li>
501 - <li><strong>抢落地。</strong>普通 RPC 抢不过别人。主流做法:Jito bundle(带 tip)+ Helius Sender / Triton Cascade 同时发出去,哪个先 land 算哪个。tip 大小是 bot 之间最常调的旋钮。</li>
502 - </ol>
528 + <h2>6. Stale 池余额的"清算曲线"</h2>
529 + <figure>
530 + <svg viewBox="0 0 760 280" xmlns="http://www.w3.org/2000/svg">
531 + <rect width="760" height="280" fill="url(#bg1)" rx="10"/>
532 + <!-- Axes -->
533 + <line x1="80" y1="40" x2="80" y2="220" stroke="#30363d" stroke-width="1"/>
534 + <line x1="80" y1="220" x2="700" y2="220" stroke="#30363d" stroke-width="1"/>
535 +
536 + <!-- Y labels -->
537 + <text x="74" y="48" text-anchor="end" fill="#8b949e" font-size="10">$1.4M</text>
538 + <text x="74" y="98" text-anchor="end" fill="#8b949e" font-size="10">$1.0M</text>
539 + <text x="74" y="148" text-anchor="end" fill="#8b949e" font-size="10">$600K</text>
540 + <text x="74" y="198" text-anchor="end" fill="#8b949e" font-size="10">$200K</text>
541 + <text x="74" y="220" text-anchor="end" fill="#8b949e" font-size="10">$0</text>
542 +
543 + <!-- X labels -->
544 + <text x="160" y="240" text-anchor="middle" fill="#8b949e" font-size="11">slot 416936447</text>
545 + <text x="380" y="240" text-anchor="middle" fill="#8b949e" font-size="11">slot 416936448</text>
546 + <text x="600" y="240" text-anchor="middle" fill="#8b949e" font-size="11">slot 416936449</text>
547 +
548 + <!-- Bars showing pool USDC drain -->
549 + <!-- Pre tx2: 2.18M -->
550 + <rect x="100" y="40" width="120" height="180" fill="#3fb950" opacity="0.5"/>
551 + <text x="160" y="58" text-anchor="middle" fill="#fff" font-size="11" font-weight="700">$2.18M</text>
552 + <text x="160" y="32" text-anchor="middle" fill="#3fb950" font-size="10">事件前</text>
553 +
554 + <!-- Post tx2: 1.77M (lost 403K) -->
555 + <rect x="320" y="92" width="120" height="128" fill="#f7b955" opacity="0.6"/>
556 + <text x="380" y="110" text-anchor="middle" fill="#fff" font-size="11" font-weight="700">$1.41M</text>
557 + <text x="380" y="32" text-anchor="middle" fill="#f7b955" font-size="10">tx#2 后 (-$403K)</text>
558 +
559 + <!-- Post tx1: 716K (lost 696K) -->
560 + <rect x="540" y="170" width="60" height="50" fill="#f85149" opacity="0.7"/>
561 + <text x="570" y="166" text-anchor="middle" fill="#fff" font-size="11" font-weight="700">$716K</text>
562 + <text x="570" y="32" text-anchor="middle" fill="#f85149" font-size="10">tx#1 后 (-$696K)</text>
563 +
564 + <!-- Post tx3: 298K (lost 282K) -->
565 + <rect x="620" y="200" width="60" height="20" fill="#f85149" opacity="0.9"/>
566 + <text x="650" y="195" text-anchor="middle" fill="#fff" font-size="11" font-weight="700">$298K</text>
567 + <text x="650" y="32" text-anchor="middle" fill="#f85149" font-size="10">tx#3 后 (-$282K)</text>
568 +
569 + <text x="380" y="266" text-anchor="middle" fill="#8b949e" font-size="11">Stale 池 USDC 余额(仅显示 3 笔最大 tx 的影响)</text>
570 + </svg>
571 + <figcaption>3 个连续 slot 内,USDC 从 $2.18M 跌到 $298K,跌幅 86%。剩余的 $298K 在后续 6 笔小 tx 里被分掉。</figcaption>
572 + </figure>
503 573
504 - <div class="callout">
505 - <strong>提示:</strong>这种机会真正的瓶颈不在策略本身,而在<strong>抢速度</strong>和<strong>风险控制</strong>。一旦池子被发现,每个 block 都有 5-20 个机器人在抢同一笔利润。原子 + Jito + 充足的 priority fee 是最低门槛。
574 + <h2>7. 修正后的核心结论</h2>
575 +
576 + <div class="callout update">
577 + <strong>方向修正:</strong>过期池套利可以走两个方向:
578 + <ol style="margin:8px 0 0; padding-left:22px;">
579 + <li>代币涨了,但 LP 把 X 代币挂在低价 bins 等卖 → bot 用 USDC 把廉价代币<strong>买光</strong>转手到市场。</li>
580 + <li><strong>代币跌了,但 LP 把 USDC 挂在高价 bins 等买 → bot 用近乎为零成本的代币把高价 USDC <strong>赎光</strong>。</strong>(本次事件)</li>
581 + </ol>
582 + 两种方向本质一致:DLMM 的 active bin 必须靠交易才能移动,没人交易就漂移成"过期"。
506 583 </div>
507 584
508 - <h2>6. 一句话总结</h2>
585 + <h3>对 LP 的启示</h3>
586 + <p>提供 DLMM 集中流动性的人,必须明白挂出去的 bin 等价于<strong>限价订单簿</strong>。如果你挂在 active bin 下方放 USDC,等价于"愿意按这些价位买代币"——代币涨了你赚,代币归零你亏。如果代币只是冷门、流动性低,更没人会来推动 active bin。所以 LP 必须:</p>
587 + <ol style="padding-left:22px;">
588 + <li>给 bins 设一个"我能接受的最低价格"和"最高价格"区间,超出就会暴露。</li>
589 + <li>对低市值 / 高波动代币,至少每周检查一次,必要时用 SDK 调用 <code>removeLiquidity</code> 收回。</li>
590 + <li>不要假设"价格往哪个方向走,DLMM 都能自适应"——它不会。</li>
591 + </ol>
592 +
593 + <h3>对套利者的启示</h3>
594 + <p>这种"反向 stale 池"在 Solana 链上数量比想象中多。扫描方法和 v1 报告里描述的一致:拉所有 DLMM 池 → 算出每个池子的 active bin 隐含价格 → 跟 Jupiter 聚合市价对比 → 价差超过阈值就放进监听清单。<strong>关键是阈值要双向:</strong></p>
595 + <ul style="padding-left:22px;">
596 + <li>active bin 价 &gt;&gt; 市价:池子里 USDC 太贵,可以把代币塞进去赎 USDC(本次事件)</li>
597 + <li>active bin 价 &lt;&lt; 市价:池子里代币太便宜,可以付 USDC 把代币买光(v1 描述的方向)</li>
598 + </ul>
599 +
600 + <h2>8. 一句话最终总结</h2>
509 601 <div class="quote">
510 - <strong>Bin 不会自动更新价格</strong>,DLMM 池子只在被交易时才移动 active bin。LP 创建池子后 10 个月不维护,外部市场暴涨 1000 倍——池子里那些"高于原始 active bin 但远低于市场价"的 bins 就成了静悄悄挂着的「便宜代币堆」,等着第一个发现它的套利机器人一口气全吃光。
602 + 这次事件不是机器人"截胡了某个大额 swap",而是机器人发现了一个 LP 留下的"<strong>10 个月没人维护的限价单簿</strong>",用近乎为零的成本(几毛钱本金 + 几百美金 Jito tip)把这个限价单簿里的 USDC 一次性结清。鲸鱼不是 swap 用户,鲸鱼就是当初那个 LP——他亲手把钱挂在过期价位上 10 个月,等到第一个发现的人来收。
511 603 </div>
512 604
513 - <p>这就是 stale pool / stale LP arbitrage。错不在 Meteora 协议,而在 LP 自己。这种漏洞跟 Uniswap v3 在以太坊上遇到的"untracked LP"问题完全一样,只是 Solana 上池子多、LP 散、被发现的速度极快——这次连 1 秒都没撑住。</p>
514 -
515 605 <footer>
516 - <p>资料来源:
606 + <p>资料来源 ·
517 607 <a href="https://x.com/anshu_code/status/2051888998671581324" target="_blank">@anshu_code 主推</a> ·
518 - <a href="https://x.com/anshu_code/status/2051392982327468463" target="_blank">前一条引用</a> ·
519 - Meteora DLMM 文档 · Jupiter / Helius 公开技术资料
608 + <a href="https://x.com/anshu_code/status/2051889010621219025" target="_blank">9 笔交易清单</a> ·
609 + Solscan:
610 + <a href="https://solscan.io/tx/J8TY8VkjZpAAm78GwbnEE1xkBwGdheQ4C1VsZA7Cwcv1AyDw3PxTQJ3eWh9YZmZyLQnLD3fuHBsihXbX4sTATi8" target="_blank">$696K tx</a> ·
611 + <a href="https://solscan.io/tx/3pb5512ttABHr8mKCM8MTfqTHqbQYxuFMQu8vrof6j24fdRz3LSp4LiLoNhbjtNec43UjFivQGTjjDEKaJ5AYhtx" target="_blank">$403K tx</a> ·
612 + <a href="https://solscan.io/tx/5Z1zXUMKKrxmDfreMAFWTp11mwMxVqusbVSfbokUFURZ2xkYfUuXNzNuYMh2vn55eFDhGgHRkQEHRtoSr4i2sTah" target="_blank">$282K tx</a>
520 613 </p>
521 - <p>本文为根据公开链上数据和推文内容做的技术拆解,不构成投资建议;过期池套利涉及极高的速度竞争和资金风险,复刻前请自行评估。</p>
614 + <p>本文为根据公开链上数据和推文做的技术拆解,不构成投资建议;过期池套利涉及极高的速度竞争与资金风险,复刻前请自行评估。</p>
522 615 </footer>
523 616
524 617 </div>

geekmind revisou este gist 1 month ago. Ir para a revisão

1 file changed, 526 insertions

meteora_stale_pool_arb.html(arquivo criado)

@@ -0,0 +1,526 @@
1 + <!DOCTYPE html>
2 + <html lang="zh-CN">
3 + <head>
4 + <meta charset="UTF-8" />
5 + <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 + <title>Solana Meteora 过期池套利拆解:299 万美金消失的 150 秒</title>
7 + <style>
8 + :root {
9 + --bg: #0d1117;
10 + --panel: #161b22;
11 + --panel2: #1c2330;
12 + --border: #30363d;
13 + --text: #e6edf3;
14 + --text-dim: #8b949e;
15 + --accent: #f7b955;
16 + --accent2: #58a6ff;
17 + --green: #3fb950;
18 + --red: #f85149;
19 + --purple: #bc8cff;
20 + }
21 + * { box-sizing: border-box; }
22 + html, body {
23 + margin: 0; padding: 0;
24 + background: var(--bg);
25 + color: var(--text);
26 + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
27 + "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
28 + line-height: 1.7;
29 + }
30 + .wrap {
31 + max-width: 920px;
32 + margin: 0 auto;
33 + padding: 48px 28px 96px;
34 + }
35 + header {
36 + border-bottom: 1px solid var(--border);
37 + padding-bottom: 28px;
38 + margin-bottom: 36px;
39 + }
40 + .tag {
41 + display: inline-block;
42 + background: rgba(247, 185, 85, 0.12);
43 + color: var(--accent);
44 + padding: 4px 12px;
45 + border-radius: 999px;
46 + font-size: 12px;
47 + letter-spacing: 0.04em;
48 + text-transform: uppercase;
49 + margin-bottom: 16px;
50 + border: 1px solid rgba(247, 185, 85, 0.3);
51 + }
52 + h1 {
53 + font-size: 34px;
54 + line-height: 1.25;
55 + margin: 0 0 12px;
56 + font-weight: 700;
57 + letter-spacing: -0.01em;
58 + }
59 + .subtitle {
60 + color: var(--text-dim);
61 + font-size: 16px;
62 + margin: 0;
63 + }
64 + h2 {
65 + font-size: 22px;
66 + margin: 56px 0 14px;
67 + padding-left: 12px;
68 + border-left: 4px solid var(--accent);
69 + }
70 + h3 {
71 + font-size: 17px;
72 + margin: 28px 0 10px;
73 + color: var(--accent2);
74 + }
75 + p { margin: 12px 0; }
76 + code {
77 + background: var(--panel2);
78 + border: 1px solid var(--border);
79 + padding: 1px 6px;
80 + border-radius: 4px;
81 + font-size: 13.5px;
82 + color: var(--accent);
83 + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
84 + }
85 + .stats {
86 + display: grid;
87 + grid-template-columns: repeat(4, 1fr);
88 + gap: 12px;
89 + margin: 28px 0;
90 + }
91 + .stat {
92 + background: var(--panel);
93 + border: 1px solid var(--border);
94 + border-radius: 10px;
95 + padding: 18px 16px;
96 + text-align: center;
97 + }
98 + .stat .num {
99 + font-size: 26px;
100 + font-weight: 700;
101 + color: var(--accent);
102 + margin-bottom: 4px;
103 + font-variant-numeric: tabular-nums;
104 + }
105 + .stat .lbl {
106 + color: var(--text-dim);
107 + font-size: 12.5px;
108 + }
109 + .quote {
110 + background: var(--panel);
111 + border-left: 3px solid var(--accent2);
112 + padding: 16px 20px;
113 + border-radius: 0 8px 8px 0;
114 + color: var(--text);
115 + font-size: 15px;
116 + margin: 18px 0;
117 + }
118 + .quote .src {
119 + display: block;
120 + margin-top: 8px;
121 + color: var(--text-dim);
122 + font-size: 12.5px;
123 + }
124 + .panel {
125 + background: var(--panel);
126 + border: 1px solid var(--border);
127 + border-radius: 12px;
128 + padding: 22px 24px;
129 + margin: 22px 0;
130 + }
131 + figure {
132 + margin: 22px 0;
133 + background: var(--panel);
134 + border: 1px solid var(--border);
135 + border-radius: 12px;
136 + padding: 22px 18px 14px;
137 + }
138 + figcaption {
139 + color: var(--text-dim);
140 + font-size: 13px;
141 + text-align: center;
142 + margin-top: 10px;
143 + }
144 + svg { display: block; max-width: 100%; height: auto; margin: 0 auto; }
145 +
146 + table {
147 + width: 100%;
148 + border-collapse: collapse;
149 + margin: 18px 0;
150 + font-size: 14px;
151 + }
152 + th, td {
153 + padding: 10px 12px;
154 + border-bottom: 1px solid var(--border);
155 + text-align: left;
156 + }
157 + th {
158 + background: var(--panel2);
159 + color: var(--text-dim);
160 + font-weight: 600;
161 + font-size: 13px;
162 + text-transform: uppercase;
163 + letter-spacing: 0.03em;
164 + }
165 + ol.steps {
166 + counter-reset: s;
167 + list-style: none;
168 + padding: 0;
169 + }
170 + ol.steps > li {
171 + counter-increment: s;
172 + position: relative;
173 + padding: 14px 18px 14px 56px;
174 + margin: 10px 0;
175 + background: var(--panel);
176 + border: 1px solid var(--border);
177 + border-radius: 10px;
178 + }
179 + ol.steps > li::before {
180 + content: counter(s);
181 + position: absolute;
182 + left: 16px;
183 + top: 14px;
184 + width: 28px;
185 + height: 28px;
186 + border-radius: 50%;
187 + background: var(--accent);
188 + color: #1d1300;
189 + font-weight: 700;
190 + text-align: center;
191 + line-height: 28px;
192 + font-size: 14px;
193 + }
194 + .callout {
195 + background: rgba(88, 166, 255, 0.08);
196 + border: 1px solid rgba(88, 166, 255, 0.3);
197 + border-radius: 10px;
198 + padding: 14px 18px;
199 + margin: 18px 0;
200 + color: var(--text);
201 + font-size: 14.5px;
202 + }
203 + .callout.warn {
204 + background: rgba(248, 81, 73, 0.08);
205 + border-color: rgba(248, 81, 73, 0.3);
206 + }
207 + .callout strong { color: var(--accent2); }
208 + .callout.warn strong { color: var(--red); }
209 + footer {
210 + margin-top: 64px;
211 + padding-top: 24px;
212 + border-top: 1px solid var(--border);
213 + color: var(--text-dim);
214 + font-size: 13px;
215 + }
216 + footer a { color: var(--accent2); text-decoration: none; }
217 + footer a:hover { text-decoration: underline; }
218 +
219 + @media (max-width: 640px) {
220 + .wrap { padding: 28px 16px 64px; }
221 + h1 { font-size: 26px; }
222 + .stats { grid-template-columns: repeat(2, 1fr); }
223 + }
224 + </style>
225 + </head>
226 + <body>
227 + <div class="wrap">
228 +
229 + <header>
230 + <span class="tag">Solana · MEV · DEX 套利</span>
231 + <h1>299 万美金,150 秒蒸发<br/>—— Meteora 过期池套利完整拆解</h1>
232 + <p class="subtitle">用图解搞懂:DLMM 的 bin 是什么,为什么旧 LP 池会变成"白送代币的提款机",以及套利机器人是怎么把它们一口气吞掉的。</p>
233 + </header>
234 +
235 + <section>
236 + <div class="stats">
237 + <div class="stat"><div class="num">$2.99M</div><div class="lbl">被抽走金额</div></div>
238 + <div class="stat"><div class="num">150s</div><div class="lbl">总耗时</div></div>
239 + <div class="stat"><div class="num">6 + 1</div><div class="lbl">机器人 + 鲸鱼</div></div>
240 + <div class="stat"><div class="num">10 个月</div><div class="lbl">池子无人维护</div></div>
241 + </div>
242 +
243 + <div class="quote">
244 + "$2,993,502 drained from a single Solana pool in 150 seconds. 1 whale. 6 bots. 9 transactions. 1 misconfigured Meteora pool that sat for 10 months."
245 + <span class="src">—— @anshu_code, X / 2026-05-06</span>
246 + </div>
247 +
248 + <p>这条推文讲的,是 Solana 链上一个被忽略了 10 个月的 <strong>Meteora DLMM 流动性池</strong>,在 150 秒内被 6 个套利机器人和一个大户合力"洗"了一遍,搬走 299 万美金。本文用图把它拆开讲清楚。</p>
249 + </section>
250 +
251 + <h2>1. 它属于哪一类套利?</h2>
252 + <p>这种玩法的术语叫 <strong>Stale Pool Arbitrage(过期池套利)</strong>。靶子是那些 <em>LP 挂上去就不再维护</em> 的集中流动性池——挂的还是几个月前的"老价格",外部市场早已涨飞,池子却毫无觉察。</p>
253 +
254 + <figure>
255 + <svg viewBox="0 0 760 280" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="过期池套利示意">
256 + <defs>
257 + <linearGradient id="bg1" x1="0" x2="0" y1="0" y2="1">
258 + <stop offset="0" stop-color="#1c2330"/>
259 + <stop offset="1" stop-color="#161b22"/>
260 + </linearGradient>
261 + <marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
262 + <path d="M0,0 L8,3 L0,6 z" fill="#f7b955"/>
263 + </marker>
264 + </defs>
265 + <rect width="760" height="280" fill="url(#bg1)" rx="10"/>
266 +
267 + <!-- Raydium box -->
268 + <rect x="40" y="60" width="240" height="160" fill="#0d1117" stroke="#3fb950" stroke-width="1.5" rx="10"/>
269 + <text x="160" y="90" text-anchor="middle" fill="#3fb950" font-size="15" font-weight="700">Raydium / 真实市场</text>
270 + <text x="160" y="135" text-anchor="middle" fill="#e6edf3" font-size="13">代币 X 已涨到</text>
271 + <text x="160" y="170" text-anchor="middle" fill="#3fb950" font-size="32" font-weight="700">$1.00</text>
272 + <text x="160" y="195" text-anchor="middle" fill="#8b949e" font-size="11">活跃交易 · 价格随市场实时更新</text>
273 +
274 + <!-- Meteora box -->
275 + <rect x="480" y="60" width="240" height="160" fill="#0d1117" stroke="#f85149" stroke-width="1.5" rx="10"/>
276 + <text x="600" y="90" text-anchor="middle" fill="#f85149" font-size="15" font-weight="700">Meteora 旧池子</text>
277 + <text x="600" y="135" text-anchor="middle" fill="#e6edf3" font-size="13">10 个月没人交易</text>
278 + <text x="600" y="170" text-anchor="middle" fill="#f85149" font-size="32" font-weight="700">$0.001</text>
279 + <text x="600" y="195" text-anchor="middle" fill="#8b949e" font-size="11">价格停在 LP 创建时的水平</text>
280 +
281 + <!-- Bridge / arrow -->
282 + <text x="380" y="130" text-anchor="middle" fill="#f7b955" font-size="13" font-weight="700">价差 1000×</text>
283 + <line x1="290" y1="150" x2="470" y2="150" stroke="#f7b955" stroke-width="2" marker-end="url(#arrow)"/>
284 + <text x="380" y="180" text-anchor="middle" fill="#8b949e" font-size="11">套利机器人在这里下手</text>
285 + </svg>
286 + <figcaption>同一种代币,两个池子,价格差 1000 倍。差距在 LP 不维护时会一直存在。</figcaption>
287 + </figure>
288 +
289 + <h2>2. 先理解 DLMM:什么是 bin?</h2>
290 + <p>Meteora DLMM(Dynamic Liquidity Market Maker)跟 Uniswap v3 思路一样:把价格切成一格一格的"档位",每一档叫 <strong>bin</strong>。LP 不是在一条曲线上放钱,而是把代币塞进具体某几个 bin 里。</p>
291 +
292 + <figure>
293 + <svg viewBox="0 0 760 320" xmlns="http://www.w3.org/2000/svg">
294 + <rect width="760" height="320" fill="url(#bg1)" rx="10"/>
295 +
296 + <!-- Active bin marker -->
297 + <line x1="380" y1="40" x2="380" y2="280" stroke="#f7b955" stroke-width="1" stroke-dasharray="4 4"/>
298 + <text x="380" y="32" text-anchor="middle" fill="#f7b955" font-size="13" font-weight="700">↓ Active Bin(当前价)</text>
299 +
300 + <!-- Bins -->
301 + <g font-family="ui-monospace, monospace" font-size="11">
302 + <!-- Y bins (left, USDC) -->
303 + <g>
304 + <rect x="60" y="180" width="48" height="100" fill="#3fb950" opacity="0.85" rx="3"/>
305 + <rect x="115" y="160" width="48" height="120" fill="#3fb950" opacity="0.85" rx="3"/>
306 + <rect x="170" y="140" width="48" height="140" fill="#3fb950" opacity="0.85" rx="3"/>
307 + <rect x="225" y="120" width="48" height="160" fill="#3fb950" opacity="0.85" rx="3"/>
308 + <rect x="280" y="105" width="48" height="175" fill="#3fb950" opacity="0.85" rx="3"/>
309 + <text x="84" y="298" text-anchor="middle" fill="#8b949e">$0.5</text>
310 + <text x="139" y="298" text-anchor="middle" fill="#8b949e">$0.6</text>
311 + <text x="194" y="298" text-anchor="middle" fill="#8b949e">$0.7</text>
312 + <text x="249" y="298" text-anchor="middle" fill="#8b949e">$0.8</text>
313 + <text x="304" y="298" text-anchor="middle" fill="#8b949e">$0.9</text>
314 + </g>
315 + <!-- Active -->
316 + <rect x="358" y="100" width="44" height="180" fill="#f7b955" opacity="0.9" rx="3"/>
317 + <text x="380" y="298" text-anchor="middle" fill="#f7b955" font-weight="700">$1.0</text>
318 +
319 + <!-- X bins (right, token) -->
320 + <g>
321 + <rect x="430" y="105" width="48" height="175" fill="#bc8cff" opacity="0.85" rx="3"/>
322 + <rect x="485" y="120" width="48" height="160" fill="#bc8cff" opacity="0.85" rx="3"/>
323 + <rect x="540" y="140" width="48" height="140" fill="#bc8cff" opacity="0.85" rx="3"/>
324 + <rect x="595" y="160" width="48" height="120" fill="#bc8cff" opacity="0.85" rx="3"/>
325 + <rect x="650" y="180" width="48" height="100" fill="#bc8cff" opacity="0.85" rx="3"/>
326 + <text x="454" y="298" text-anchor="middle" fill="#8b949e">$1.1</text>
327 + <text x="509" y="298" text-anchor="middle" fill="#8b949e">$1.2</text>
328 + <text x="564" y="298" text-anchor="middle" fill="#8b949e">$1.3</text>
329 + <text x="619" y="298" text-anchor="middle" fill="#8b949e">$1.4</text>
330 + <text x="674" y="298" text-anchor="middle" fill="#8b949e">$1.5</text>
331 + </g>
332 + </g>
333 +
334 + <!-- Labels -->
335 + <text x="194" y="80" text-anchor="middle" fill="#3fb950" font-size="13" font-weight="700">下方 bins</text>
336 + <text x="194" y="98" text-anchor="middle" fill="#3fb950" font-size="11">装 USDC(限价买单)</text>
337 +
338 + <text x="564" y="80" text-anchor="middle" fill="#bc8cff" font-size="13" font-weight="700">上方 bins</text>
339 + <text x="564" y="98" text-anchor="middle" fill="#bc8cff" font-size="11">装 代币 X(限价卖单)</text>
340 + </svg>
341 + <figcaption>DLMM 池子结构:active bin 把价格分成左右两半。左边的 bin 装 USDC,右边的装代币。</figcaption>
342 + </figure>
343 +
344 + <div class="callout">
345 + <strong>关键三点:</strong>
346 + <ol style="margin:8px 0 0; padding-left: 20px;">
347 + <li>每个 bin 对应一个<strong>固定</strong>的兑换价(创建时算好的常数)。</li>
348 + <li>active bin <strong>下方</strong>的 bins 装 Y(USDC),是"低价等买 X 的限价买单"。</li>
349 + <li>active bin <strong>上方</strong>的 bins 装 X(代币),是"高价等卖出的限价卖单"。</li>
350 + </ol>
351 + </div>
352 +
353 + <h2>3. 为什么 bin 会"老价格存在"?</h2>
354 + <p>这是这次事件最反直觉的地方。<strong>DLMM 池子的价格不会自动跟着外部市场走</strong>——它只在<em>有人在本池子做 swap</em>的时候才移动 active bin。</p>
355 +
356 + <figure>
357 + <svg viewBox="0 0 760 360" xmlns="http://www.w3.org/2000/svg">
358 + <rect width="760" height="360" fill="url(#bg1)" rx="10"/>
359 +
360 + <!-- Time axis -->
361 + <line x1="60" y1="320" x2="700" y2="320" stroke="#30363d" stroke-width="1"/>
362 + <text x="60" y="345" fill="#8b949e" font-size="11">Day 0</text>
363 + <text x="380" y="345" fill="#8b949e" font-size="11">Day 1 ~ 300(无人交易)</text>
364 + <text x="700" y="345" text-anchor="end" fill="#8b949e" font-size="11">Day 300(被发现)</text>
365 +
366 + <!-- Raydium price line - rising -->
367 + <text x="60" y="48" fill="#3fb950" font-size="12" font-weight="700">Raydium 真实市价</text>
368 + <path d="M60,290 Q200,280 300,200 T700,80" stroke="#3fb950" stroke-width="2.5" fill="none"/>
369 + <circle cx="60" cy="290" r="4" fill="#3fb950"/>
370 + <circle cx="700" cy="80" r="5" fill="#3fb950"/>
371 + <text x="80" y="285" fill="#3fb950" font-size="11">$0.001</text>
372 + <text x="688" y="74" text-anchor="end" fill="#3fb950" font-size="11" font-weight="700">$1.00 ↑↑↑</text>
373 +
374 + <!-- Meteora price line - flat -->
375 + <text x="60" y="200" fill="#f85149" font-size="12" font-weight="700">Meteora 池子 active bin</text>
376 + <line x1="60" y1="290" x2="640" y2="290" stroke="#f85149" stroke-width="2.5" stroke-dasharray="6 4"/>
377 + <circle cx="60" cy="290" r="4" fill="#f85149"/>
378 + <circle cx="640" cy="290" r="4" fill="#f85149"/>
379 + <text x="380" y="282" text-anchor="middle" fill="#f85149" font-size="11">10 个月一动不动 · 一直停在 $0.001</text>
380 +
381 + <!-- Gap arrow -->
382 + <line x1="660" y1="80" x2="660" y2="280" stroke="#f7b955" stroke-width="1.5" stroke-dasharray="3 3"/>
383 + <line x1="650" y1="80" x2="670" y2="80" stroke="#f7b955" stroke-width="1.5"/>
384 + <line x1="650" y1="280" x2="670" y2="280" stroke="#f7b955" stroke-width="1.5"/>
385 + <text x="678" y="180" fill="#f7b955" font-size="13" font-weight="700">价差</text>
386 + <text x="678" y="198" fill="#f7b955" font-size="11">1000×</text>
387 + </svg>
388 + <figcaption>外部市场涨了 1000 倍,Meteora 池子的 active bin 却没移动半步——因为没人来这里 swap。</figcaption>
389 + </figure>
390 +
391 + <p>所以"代币涨了为什么 bin 还能低价存在"的答案是:</p>
392 + <div class="callout warn">
393 + <strong>Solana 链上没有"全局市场价"。</strong>每个 DEX 池子都是独立的小宇宙。Raydium 的价格涨到 $1 跟 Meteora 这个池子毫无机械联系——除非有套利机器人主动来"对齐"它。在它被发现之前,那批挂在 $0.001、$0.0011、$0.005、$0.01 ... 的 X 代币就一直**安静地坐在那儿等买家**。
394 + </div>
395 +
396 + <h2>4. 攻击是怎么发生的(图解)</h2>
397 + <p>为了讲清楚机器人具体在干什么,下面把那笔 transaction 拆成 4 个画面:</p>
398 +
399 + <figure>
400 + <svg viewBox="0 0 760 480" xmlns="http://www.w3.org/2000/svg">
401 + <rect width="760" height="480" fill="url(#bg1)" rx="10"/>
402 +
403 + <!-- Frame 1 -->
404 + <text x="20" y="34" fill="#f7b955" font-size="13" font-weight="700">① 池子初始状态:active bin 在 $0.001,上方塞满便宜 X 代币</text>
405 + <g transform="translate(40, 50)">
406 + <rect x="0" y="0" width="40" height="60" fill="#f7b955" rx="2"/>
407 + <rect x="48" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
408 + <rect x="96" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
409 + <rect x="144" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
410 + <rect x="192" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
411 + <rect x="240" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
412 + <rect x="288" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
413 + <rect x="336" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
414 + <text x="20" y="78" text-anchor="middle" fill="#f7b955" font-size="10">$0.001</text>
415 + <text x="68" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.002</text>
416 + <text x="116" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.005</text>
417 + <text x="164" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.01</text>
418 + <text x="212" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.05</text>
419 + <text x="260" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.2</text>
420 + <text x="308" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$0.5</text>
421 + <text x="356" y="78" text-anchor="middle" fill="#8b949e" font-size="10">$1.0</text>
422 + <text x="450" y="38" fill="#bc8cff" font-size="11">每个紫格里都有大量代币 X,标价远低于市价</text>
423 + </g>
424 +
425 + <!-- Frame 2 -->
426 + <text x="20" y="148" fill="#f7b955" font-size="13" font-weight="700">② 机器人灌入 USDC,吞掉第一格 bin(按 $0.001 买)</text>
427 + <g transform="translate(40, 164)">
428 + <rect x="0" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="2" rx="2"/>
429 + <rect x="48" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
430 + <rect x="96" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
431 + <rect x="144" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
432 + <rect x="192" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
433 + <rect x="240" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
434 + <rect x="288" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
435 + <rect x="336" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
436 + <text x="20" y="78" text-anchor="middle" fill="#3fb950" font-size="10" font-weight="700">已吃完</text>
437 + <text x="450" y="38" fill="#3fb950" font-size="11">代币 X 进入机器人钱包,bin #1 变成 USDC</text>
438 + </g>
439 +
440 + <!-- Frame 3 -->
441 + <text x="20" y="262" fill="#f7b955" font-size="13" font-weight="700">③ active bin 推到下一格,继续吃(按 $0.002, $0.005, $0.01... 一路买上去)</text>
442 + <g transform="translate(40, 278)">
443 + <rect x="0" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
444 + <rect x="48" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
445 + <rect x="96" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
446 + <rect x="144" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
447 + <rect x="192" y="0" width="40" height="60" fill="#3fb950" opacity="0.5" stroke="#3fb950" stroke-width="1" rx="2"/>
448 + <rect x="240" y="0" width="40" height="60" fill="#f7b955" rx="2"/>
449 + <rect x="288" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
450 + <rect x="336" y="0" width="40" height="60" fill="#bc8cff" opacity="0.85" rx="2"/>
451 + <text x="450" y="38" fill="#f7b955" font-size="11">active bin 一格格往上推,直到逼近真实市价 $1.0</text>
452 + </g>
453 +
454 + <!-- Frame 4 -->
455 + <text x="20" y="378" fill="#f7b955" font-size="13" font-weight="700">④ 同一笔 transaction 里把吃到的 X 全部发到 Raydium 按 $1.0 卖出</text>
456 + <g transform="translate(40, 394)">
457 + <rect x="0" y="0" width="80" height="60" fill="#161b22" stroke="#bc8cff" stroke-width="1.5" rx="6"/>
458 + <text x="40" y="26" text-anchor="middle" fill="#bc8cff" font-size="11" font-weight="700">Meteora</text>
459 + <text x="40" y="44" text-anchor="middle" fill="#8b949e" font-size="10">买 X · 极便宜</text>
460 +
461 + <text x="160" y="34" fill="#f7b955" font-size="20">→</text>
462 +
463 + <rect x="200" y="0" width="80" height="60" fill="#161b22" stroke="#3fb950" stroke-width="1.5" rx="6"/>
464 + <text x="240" y="26" text-anchor="middle" fill="#3fb950" font-size="11" font-weight="700">Raydium</text>
465 + <text x="240" y="44" text-anchor="middle" fill="#8b949e" font-size="10">卖 X · 市价</text>
466 +
467 + <text x="320" y="34" fill="#f7b955" font-size="20">→</text>
468 +
469 + <rect x="360" y="0" width="120" height="60" fill="#161b22" stroke="#f7b955" stroke-width="1.5" rx="6"/>
470 + <text x="420" y="26" text-anchor="middle" fill="#f7b955" font-size="11" font-weight="700">机器人钱包</text>
471 + <text x="420" y="44" text-anchor="middle" fill="#f7b955" font-size="10" font-weight="700">+ $400K USDC</text>
472 +
473 + <text x="540" y="38" fill="#8b949e" font-size="11">所有指令打包进 1 笔 tx,</text>
474 + <text x="540" y="54" fill="#8b949e" font-size="11">失败回滚 → 永远不会亏</text>
475 + </g>
476 + </svg>
477 + <figcaption>套利的整个动作:低价吃光 → 市价卖出 → 同一笔交易原子完成。</figcaption>
478 + </figure>
479 +
480 + <h3>事件时间线</h3>
481 + <table>
482 + <thead>
483 + <tr><th>时刻</th><th>角色</th><th>动作</th><th>结果</th></tr>
484 + </thead>
485 + <tbody>
486 + <tr><td>T+0s</td><td>鲸鱼</td><td>大额 swap,第一次"打开"这个被遗忘的池子</td><td>active bin 开始移动</td></tr>
487 + <tr><td>T+0.4s</td><td>Bot 1</td><td>监听器触发,发起反向套利</td><td>$0.16 成本 → $403K 盈利</td></tr>
488 + <tr><td>T+1.2s</td><td>Bot 2</td><td>下一个 block 抢落地</td><td>$0.23 成本 → $696K 盈利</td></tr>
489 + <tr><td>T+0~150s</td><td>Bot 3-6</td><td>剩余 bin 慢慢被扫</td><td>累计接近 $3M</td></tr>
490 + <tr><td>T+150s</td><td>—</td><td>active bin 已逼近 Raydium 市价</td><td>套利窗口关闭</td></tr>
491 + </tbody>
492 + </table>
493 +
494 + <h2>5. 技术实现骨架(如果你想做)</h2>
495 +
496 + <ol class="steps">
497 + <li><strong>扫描全网 Meteora DLMM 池找"stale"标的。</strong>拉所有 DLMM 池的 PDA 账户,用 SDK 读 active bin 价格,跟 Jupiter / Birdeye 拿到的市价对比。差 5-10% 以上的进候选池。这一步可以离线一天扫一次。</li>
498 + <li><strong>实时盯盘候选池。</strong>用 Helius / Triton 的 Geyser gRPC 或 <code>accountSubscribe</code> WebSocket 订阅这些池子账户,状态一变就 push 给你(延迟 50-200ms)。</li>
499 + <li><strong>盈亏模拟。</strong>调用 <code>@meteora-ag/dlmm</code> 模拟从这个池子买 X、再到 Raydium 卖的总收益。扣掉两边手续费、Solana 优先费、Jito tip 后还赚才发交易。</li>
500 + <li><strong>原子 transaction。</strong>把"Meteora 买 + Raydium 卖"两条 swap 指令打到同一笔 tx 里,每个指令都设 <code>min_out_amount</code>,价格滑了整笔回滚。账户多塞不下时用 Address Lookup Table (LUT) 压缩。</li>
501 + <li><strong>抢落地。</strong>普通 RPC 抢不过别人。主流做法:Jito bundle(带 tip)+ Helius Sender / Triton Cascade 同时发出去,哪个先 land 算哪个。tip 大小是 bot 之间最常调的旋钮。</li>
502 + </ol>
503 +
504 + <div class="callout">
505 + <strong>提示:</strong>这种机会真正的瓶颈不在策略本身,而在<strong>抢速度</strong>和<strong>风险控制</strong>。一旦池子被发现,每个 block 都有 5-20 个机器人在抢同一笔利润。原子 + Jito + 充足的 priority fee 是最低门槛。
506 + </div>
507 +
508 + <h2>6. 一句话总结</h2>
509 + <div class="quote">
510 + <strong>Bin 不会自动更新价格</strong>,DLMM 池子只在被交易时才移动 active bin。LP 创建池子后 10 个月不维护,外部市场暴涨 1000 倍——池子里那些"高于原始 active bin 但远低于市场价"的 bins 就成了静悄悄挂着的「便宜代币堆」,等着第一个发现它的套利机器人一口气全吃光。
511 + </div>
512 +
513 + <p>这就是 stale pool / stale LP arbitrage。错不在 Meteora 协议,而在 LP 自己。这种漏洞跟 Uniswap v3 在以太坊上遇到的"untracked LP"问题完全一样,只是 Solana 上池子多、LP 散、被发现的速度极快——这次连 1 秒都没撑住。</p>
514 +
515 + <footer>
516 + <p>资料来源:
517 + <a href="https://x.com/anshu_code/status/2051888998671581324" target="_blank">@anshu_code 主推</a> ·
518 + <a href="https://x.com/anshu_code/status/2051392982327468463" target="_blank">前一条引用</a> ·
519 + Meteora DLMM 文档 · Jupiter / Helius 公开技术资料
520 + </p>
521 + <p>本文为根据公开链上数据和推文内容做的技术拆解,不构成投资建议;过期池套利涉及极高的速度竞争和资金风险,复刻前请自行评估。</p>
522 + </footer>
523 +
524 + </div>
525 + </body>
526 + </html>
Próximo Anterior