JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

MEV:三明治攻擊、套利與黑暗森林

每一個區塊都是一場迷你拍賣——競標「重新排序現實」的權利。看懂機器人如何從你的交易中榨取價值、親手算一次三明治攻擊與原子套利,並理解提議者與建構者分離如何重塑「誰賺到這筆錢」。

走進黑暗森林

2020 年 8 月,兩位研究者 Dan Robinson 與 Georgios Konstantopoulos 發表了一篇文章,標題叫《以太坊是一座黑暗森林》。他們發現一個持有真實資金、卻有漏洞的合約,想搶在惡意者之前把錢救出來。他們寫好一筆乾淨的搶救交易並廣播出去——它卻從未成功。一個他們聞所未聞的機器人,正盯著未確認交易暫存的那片公開等候區,看見了他們的交易,複製了其中有利可圖的內容、付了更高的費用,搶先被打包進區塊。機器人把錢拿走了。森林,是有眼睛的。

那片等候區就是 記憶池(mempool)——網路中每個節點互相傳播的「待處理交易」公開集合。機器人之所以能贏,原因是結構性的:區塊鏈處理交易時,順序是由某個人決定的,而這個順序本身具有金錢價值。區塊生產者(或任何能影響排序的人)藉由在區塊內重新排序、插入或審查交易所能榨取的利潤,就叫做 最大可提取價值(MEV)

三種經典招式:套利、清算、三明治

MEV 不是單一現象,而是一整族策略,由名為「搜尋者(searchers)」的專門機器人執行。三種招式涵蓋了大部分價值,它們落在從「良性」到「有毒」的光譜上。

  1. 套利(arbitrage)——當同一種資產在兩個 AMM 上價格不同,搜尋者就在一筆原子交易內,於便宜的一邊買進、貴的一邊賣出。這通常是良性的:它把價格推回一致,讓 DEX 報價保持誠實。它直接建立在你先前學過的恆定乘積公式之上。
  2. 清算競速(liquidation racing)——當借款人的健康因子跌破 1,部位即可被清算,協議會提供獎勵給償還債務的人。搜尋者爭相成為清算者、賺取那筆獎勵。這同樣大致是健康的:它讓借貸市場保持有清償能力(正是上一篇的主題)。
  3. 三明治攻擊(sandwich attack)——搜尋者盯上你待處理的兌換,在它前面一筆後面一筆分別交易,利用你自己交易造成的價格變動獲利,留給你一個更差的成交價。這是有毒的 MEV:它直接從一般使用者身上拿走價值。我們接下來會解剖一筆。

三明治的解剖:一個實算範例

取一個流動性池,內有 10 ETH 與 20,000 USDC,因此不變量為 k = x·y = 200,000,現價為 2,000 USDC/ETH。一位受害者想用 2,000 USDC 買進 ETH,而且——關鍵在此——設了寬鬆的滑點容忍度,比方說 10%,所以即使成交價差很多,他的交易也不會回退。為了讓算術乾淨,我們先忽略 0.3% 手續費與 gas。

基準情況(無攻擊者)。 受害者的 2,000 USDC 使 USDC 儲備升到 y = 22,000,於是 x = 200,000 / 22,000 = 9.0909 ETH。他會拿到 10 − 9.0909 = 0.9091 ETH,實際成交價為 2,200 USDC/ETH。現在來看攻擊者如何動手腳。

  1. 搶先(買進)。 攻擊者看見受害者待處理的兌換,把自己的買單插在前面,同樣花 2,000 USDC。儲備變為 y = 22,000、x = 9.0909,攻擊者拿到 0.9091 ETH。此時池子為(9.0909 ETH, 22,000 USDC)——價格已被推升到約 2,420。
  2. 受害者執行。 他的 2,000 USDC 此時把 y 推到 24,000,於是 x = 200,000 / 24,000 = 8.3333。受害者只拿到 9.0909 − 8.3333 = 0.7576 ETH——實際成交價變成 2,640 USDC/ETH,而非 2,200。他允許的 10% 滑點,正是讓這一切得逞的原因。
  3. 回壓(賣出)。 攻擊者接著把那 0.9091 ETH 賣回。儲備:x = 8.3333 + 0.9091 = 9.2424,y = 200,000 / 9.2424 = 21,639。他拿回 24,000 − 21,639 = 2,361 USDC。利潤 = 2,361 − 2,000 = 約 361 USDC,無風險,扣掉 gas。受害者損失的金額大致就是這麼多。

這個攻擊之所以可能,純粹是因為受害者的交易在記憶池裡可見,而且滑點容忍度太鬆。攻擊者甚至會解一道最佳化題:把搶先單放到盡可能大,但把受害者的價格推過他設定的最低輸出下限——否則交易會回退、三明治就失敗。三筆交易——搶先、受害者、回壓——必須緊鄰且嚴格按此順序落地。這個排序需求,就是整場遊戲的核心。

原子套利與閃電貸

套利是 MEV 的良性引擎。假設兩個 ETH/USDC 池價格偏離:A 池有 100 ETH / 200,000 USDC(價 2,000),B 池有 100 ETH / 220,000 USDC(價 2,200)。ETH 在 A 比較便宜,於是搜尋者在 A 買、賣進 B——全部在一筆交易內完成,要嘛整筆成功、要嘛整筆回退。

從 A 買 2 ETH: k = 100·200,000 = 20,000,000;新 x = 98、新 y = 20,000,000 / 98 = 204,082,故花費 4,082 USDC。把那 2 ETH 賣進 B: k = 100·220,000 = 22,000,000;新 x = 102、新 y = 22,000,000 / 102 = 215,686,搜尋者收到 220,000 − 215,686 = 4,314 USDC。利潤 ≈ 4,314 − 4,082 = 232 USDC,無風險且原子,扣掉 gas。(真實機器人會算出兩池邊際價格相等處的最佳交易量,以擷取最大值。)

原子性的魔法在此:搜尋者完全不需要自有資金。他可以用閃電貸借入資金——一種在同一筆交易內借出並還清的無抵押貸款——跑完套利、還掉貸款、賺走價差。若任何一步失敗,整筆交易回退,貸款等於從未發生。

// Atomic two-pool arbitrage funded by a flash loan (Solidity-style pseudocode)
function arb(uint amountUSDC) external {
    // 1. Borrow with no collateral; the lender calls back into this contract.
    flashLender.flashLoan(USDC, amountUSDC, abi.encode(amountUSDC));
}

function onFlashLoan(uint amountUSDC) external {
    require(msg.sender == address(flashLender));
    // 2. Buy ETH cheap on Pool A.
    uint ethOut = poolA.swap(USDC -> ETH, amountUSDC);
    // 3. Sell that ETH dear on Pool B.
    uint usdcBack = poolB.swap(ETH -> USDC, ethOut);
    // 4. Repay principal + fee; the WHOLE tx reverts if we can't.
    uint owed = amountUSDC + flashFee;
    require(usdcBack > owed, "unprofitable: revert, lose only gas");
    USDC.transfer(address(flashLender), owed);
    // 5. Keep the spread.
    USDC.transfer(searcher, usdcBack - owed);
}
借入、套利、還款——同一筆交易內全有或全無。請注意:把同一個閃電貸原語指向一個可被操縱的價格預言機(而非誠實套利),就會變成閃電貸攻擊(bZx 及許多預言機操縱漏洞即如此)。

底層的拍賣:從 gas 戰爭到 PBS

如果許多搜尋者同時看到同一個機會,鏈如何決定誰贏?早期的方式很殘酷:優先 gas 拍賣(priority gas auction, PGA)。機器人即時互相加碼優先費用(給區塊生產者的小費)來競價,因為付得高的交易會被排在前面。PGA 既吵又浪費——輸掉的機器人仍要為回退的交易付 gas,競價也灌爆了網路。《Flash Boys 2.0》論文記錄了這些真實發生的拍賣。

公開記憶池的 PGA 模型有兩個問題。第一,它會洩漏:把你有利可圖的交易包貼到記憶池,等於邀請別人複製(黑暗森林問題)。第二,它把 MEV 利潤推向「誰的驗證者最精密」,有讓區塊生產中心化之虞。對此的回應是 Flashbots,以及一套名為提議者與建構者分離(PBS)的架構。

提議者與建構者分離把「做出一個區塊」這件事拆成兩個角色。建構者(builders)互相競爭,組裝出他們所能組裝最有價值的區塊——把搜尋者的交易包塞進去——並附上一個出價(願意付給提議者多少)。提議者(proposers)(被選中出塊的驗證者)只要挑最高出價即可。在今日的以太坊,這套機制是在協議之外透過名為 MEV-Boost 的軟體與受信任的區塊中繼運行的;協議內版本(enshrined PBS)則是未來的升級。

  1. 搜尋者把封裝好的交易包(例如一筆套利或三明治)私下送給建構者——絕不進公開記憶池,因此沒人能複製。
  2. 建構者組裝完整區塊、模擬執行,然後把(區塊 + 出價)提交給中繼。
  3. 中繼持有區塊本體,驗證它有效且確實會支付所宣稱的金額,只把區塊標頭與出價展示給提議者。
  4. 提議者簽署出價最高的標頭(在看到本體之前就承諾);中繼隨後揭露本體以便發布。這種「先承諾後揭露」讓提議者無法偷走建構者的 MEV。

效果很顯著:如今約九成的以太坊區塊是透過 MEV-Boost 建構的。PBS 讓 MEV 普及化——一個小型的家用驗證者,賺到的「MEV 調整後」報酬幾乎與巨型質押機構相同,因為兩者都只是把自己的區塊空間賣給同一個競爭性的建構者市場。這對出塊的去中心化是真正的勝利。

防禦手段,以及無人能逃的取捨

你能保護自己嗎?部分能。誠實的結論是:MEV 是一個公開、有序、無需許可帳本的結構性性質——你刪不掉它,只能重新分配、把有毒的形式降到最低、或改變誰來擷取它。每種防禦都要用某種代價來換。

  1. 收緊滑點上限。 設一個低的最大滑點(嚴格的最低輸出)能讓多數三明治無利可圖,因為攻擊者還沒把你的價格推遠,你的交易就回退了。代價:在波動大或流動性薄的市場,誠實的交易會更常失敗。
  2. 私有訂單流。 透過私有 RPC(如 Flashbots Protect、MEV Blocker)把你的交易直接送給建構者,而不進公開記憶池,這樣沒有搜尋者看得到、也就無從三明治。代價:你現在信任那些建構者,而且把訂單流集中到少數私有管道,會削弱網路的中立性。
  3. 批次拍賣。 像 CoW Protocol 這類協議收集大量訂單,由互相競爭的求解者(solvers)以單一統一結算價一起結算。批次內沒有排序優勢,批次內的三明治便不可能;直接撮合反向訂單(需求的巧合,coincidence of wants)甚至能勝過 AMM 價格。代價:增加延遲,並依賴求解者市場。
  4. 加密記憶池。 用門檻加密(如 Shutter)把交易加密,使其內容在排序確定之後才由委員會解密,在此之前始終隱藏。建構者讀不到的東西就無法重新排序。代價:額外延遲,以及一個新的活性假設——解密委員會必須保持誠實且在線。

PBS 本身也有陰暗面。建構者與中繼市場已經中心化:少數幾個建構者生產了大部分區塊,少數幾個中繼坐在關鍵路徑上。由於中繼能選擇納入哪些交易,受 OFAC 制裁的位址曾被「合規過濾」的中繼審查——這是社群正以「納入清單(inclusion lists)」與提議者強制的排序規則來對抗的中立性問題。而隨著以太坊邁向更快的最終性再質押層帶來綁定資本的新方式,MEV 不斷找到新的表面——包括跨鏈 MEV,由於跨鏈交易並非原子,它更難處理。