跳到正文

ERC-4626 首次存款膨脹攻擊:捨入如何抹除份額

了解直接捐贈如何操縱空 ERC-4626 金庫的兌換率,將存款人的份額向下捨入至零,以及實作者和使用者可以如何降低風險。

更新於

僅供教育用途,不構成投資建議;投資可能導致損失。

直接回答

首次存款膨脹攻擊以空或接近空的 ERC-4626 金庫為目標。攻擊者先存入極少量資產以取得最初的份額,隨後將底層資產直接轉入金庫。這筆捐贈會在不增加 totalSupply() 的情況下增加 totalAssets(),使每份現有份額的價值上升。

如果受害者的存款按這個遭操縱的兌換率換算,整數除法可能將產出的份額向下捨入至極少甚至零。受害者的資產仍留在金庫中,而持有所有流通份額的攻擊者可以贖回被膨脹的資產請求權。這是兌換率操縱與滑價問題,並非 ERC-4626 介面本身的缺陷。

運作方式

在沒有費用或保護性偏移量的簡單金庫中,存款鑄造的份額約為 assets * totalSupply / totalAssets。ERC-4626 要求針對給定資產數量計算份額時,採用有利於金庫的向下捨入。正常兌換率下的捨入損失很小,但當份額價格被抬高後,價值低於一份份額的存款可能因捨入而損失 100%。

攻擊能否成立取決於具體實作。直接轉入 ERC-20 代幣可能在不鑄造份額的情況下增加金庫所計入的資產,尤其是當 totalAssets() 讀取金庫的代幣餘額時。攻擊者還必須在份額供應量極低時搶先於受害者操作。採用不同會計方式或明確防禦措施的金庫未必會以相同方式受到攻擊。

範例

假設一個有漏洞的空金庫初始兌換率為 1:1。攻擊者存入 1 單位資產並取得 1 份份額,然後直接捐贈 999 單位。此時,1 份份額由 1,000 單位資產支持。受害者存入 999 單位,因此直接計算的結果為 999 * 1 / 1,000 = 0 份份額(整數捨入後)。

隨後,金庫持有 1,999 單位資產,而流通的只有攻擊者的 1 份份額。如果存款操作允許產出零份額,且沒有費用或其他限制,攻擊者便能用該份額贖回全部 1,999 單位資產:最初存入的 1 單位、捐贈的 999 單位,以及受害者存入的 999 單位。扣除交易成本前,攻擊者的毛利就是受害者的 999 單位資產。

風險與防禦

實作者可以透過投入具實際意義的初始流動性、銷毀或鎖定初始份額、強制要求產出至少一份份額,或採用包含虛擬資產和虛擬份額的兌換率設計來降低風險。OpenZeppelin 的實作會加入虛擬數量,並透過小數位偏移量支援額外的份額精度;在其文件所述模型中,虛擬份額會取得部分捐贈,使操縱無利可圖或大幅提高其成本。每種防禦措施都有其假設,應針對直接轉帳、捨入邊界、費用、損失及非典型代幣行為進行測試。

使用者和整合方應將 previewDeposit() 視為報價,而不是有保證的最低值。應透過能強制執行最低可接受份額數量的函式或路由器提交存款,並在未達到該下限時回復交易。在向新建或份額供應稀少的金庫存款前,應檢查 totalAssets()totalSupply()、具體實作的換算公式,以及未經請求的代幣轉帳是否會影響會計記錄。即使前端報價有利,也無法保護一筆執行順序可能被改變的交易。

常見誤解

  • 誤解 1:ERC-4626 本身保證兌換率安全。 該標準定義了通用介面和捨入行為,但不會讓所有實作自動免受兌換率操縱。

  • 誤解 2:在 deposit() 前立即呼叫 previewDeposit() 就能保證取得該輸出。 兩次呼叫之間或交易執行前,鏈上狀態可能發生變化。存款路徑需要一個可強制執行的最低份額下限。

  • 誤解 3:只拒絕零份額存款就能消除攻擊。 這可以防止最極端的結果,但攻擊者仍可能令一筆存款只取得少量份額並遭受巨大的捨入損失。防禦措施應限制可接受的滑價,而不應只是要求結果非零。

相關主題

來源

導覽

搜尋知識庫...