原文:《 Solving the issue with slippage in EIP-4626 》by Nick Addison

編譯:ChinaDeFi

簡介

EIP-4626 提供了一種將代幣投資到投資池( 通常稱為金庫) 的標準方法。當我們存入自己的資產(ERC-20 代幣)時,我們會收到一個份額代幣,代表我們在金庫裡的資產。金庫將把匯集的資產投資到一個或多個基礎平台,為持有者產生收益。

EIP-4626 標準的一個結果是,存款和鑄幣函數沒有提供指定回報的最小份額或資產金額的方法。這通常用於防止高滑點或三明治攻擊。 mStable 如何通過其Meta Vaults 解決這個問題——在保持符合標準的同時減輕高滑點攻擊?本文描述了這些挑戰,並解釋了他們的方法是如何工作的。

EIP-4626 和mStable 金庫存款

mStable EIP-4626 的首個金庫將投資於基於Curve 3Pool 的Convex 池。從EIP-4626 的角度來看,金庫的資產是Curve 3Pool 的流動性提供者代幣(3Crv)。存款函數是EIP-4626 規範的一部分,它指定要存入多少資產以及將接收金庫份額的帳戶。存款函數返回給接收方會鑄造多少金庫份額。

function deposit(uint256 assets, address receiver)

external

returns (uint256 shares);

例如,存入3Crv Convex mUSD 金庫將從調用方轉移3Crv,並將vcx3CRV-mUSD 金庫份額轉移到接收方。

如何解決EIP-4626中的高滑點問題?

EIP-4626 標準的強大之處在於,在投資池中有一種通用的投資方法,但對資產可以投資到底層平台的內容和時間沒有限制。對於mStable 的3Crv Convx mUSD 金庫來說, 3Crv 被添加到Curve mUSD Metapool 中,然後產生的流動性提供者代幣(musd3Crv) 被存入Convex mUSD 池中,該池會投資於Curve mUSD gauge 並獲得更高的回報。

這個過程中的一個技術挑戰是如何防止三明治攻擊。

如何解決EIP-4626中的高滑點問題?

什麼是三明治攻擊?如何預防它們?

當我們向Curve Metapool( 或任何其他池) 添加流動性時,我們指定自己想存入的資產數量和流動性提供者(LP) 代幣的最小數量。對於mUSD Metapool,金額是一個包含兩項的數組。第一個是mUSD 的量,第二個是3Crv 的量。 3Crv Convex 金庫只存3Crv,因此金額數組的第一項將為零。

function add_liquidity(uint256[2] memory amounts, uint256 min_mint_amount)

external

returns (uint256);

開發金庫時的一個技術挑戰是我們如何設置預期流動性提供者代幣的最小數量。

僅僅將min_mint_amount 設置為零是不夠的,因為它會讓存款交易受到三明治攻擊。但在我們深入了解三明治攻擊是如何工作之前,我們需要更多地了解Curve Metapool 定價是如何工作的。由於金庫只添加兩個池代幣(mUSD 和3Crv) 中的一個,因此它接收到的Metapool 流動性提供者(LP) 代幣的數量將取決於Metapool 中mUSD 和3Crv 的餘額。池中的3Crv 越多,當僅將3Crv 添加到Metapool 時,返回的LP 代幣就越少。

例如,如果Curve 的mUSD Metapool 添加了200 萬個mUSD,600 萬個3Crv 和100k 個3Crv,則將收到100,068 個LP 代幣(musd3Crv)。如果Metapool 有600 萬個mUSD,添加了200 萬個3Crv 和100k 個3Crv,將收到100,892 個LP 代幣(musd3Crv)。

那麼三明治攻擊是如何實現的呢?

攻擊者在將交易包含到區塊之前,就會監控Mempool 中可能被利用的交易。為了利用交易,他們賄賂區塊生產者,將他們的交易包含在可利用的交易之前和之後。也就是說,他們將易受攻擊的交易與自己的交易夾在一起。如果有一筆交易將3Crv 添加到最低LP 金額為零的mUSD Metapool,則攻擊者的第一筆交易將是減少Metapool 中的mUSD 數量。這意味著在易受攻擊的添加流動性交易中收到的Metapool LP 代幣數量遠低於應有的數量。在第三個交易中,攻擊者返還在第一個交易中刪除的mUSD,並將收益裝入囊中。

例子

使用Curve 的mUSD Metapool,池中有6,000,000 mUSD 和3Crv, 11,917,295 個LP 代幣(musd3Crv) 和1.018095 美元的虛擬價格。

攻擊者通過使用6,500,000 (54.5%) 池流動性提供者(musd3Crv) 代幣從池中提取5,973,425 的mUSD,使用他們池中的大部分流動性提供者代幣(musd3Crv) 來平衡池。使用remove_liquidity_one_coin 函數進行單邊提款,池中剩下0.43% mUSD 和99.56% 3Crv。虛擬價格上漲了近1%,至1.019105,因為大量不平衡的提現為池收取了費用。

受害者使用add_liquidity 函數將100,000 個3Crv 添加到不平衡的池中,且沒有最小流動性提供者數量。如果池是平衡的,受害者得到81978 個LP 代幣而不是100371 個。這意味著受害者得到的LP 代幣比他們應該得到的少18,393 個(18%)。以美元計算,受害者得到的美元價值減少了18,643(18%)。

對於第三個也是最後一個交易,攻擊者使用add_liquidity 將他們從第一個交易中提取的5,973,425 個mUSD 添加回池中,以接收6,503,610 個LP 代幣(musd3Crv)。比第一次交易多取了3610 美元。池的虛擬價格將增加1% 至1.019216,因為這是另一個不平衡的交易。以美元計算,攻擊者的LP 價值從6,500,000 * 1.018095 = 6,617,617 美元上升到6,503,610 * 1.019216 = 6,628,583 美元,增加了10,966 美元(1.65%)。

如果受害者損失了18643 美元價值,而攻擊者只獲得了10966 美元價值,那麼缺失的7677 美元價值在哪裡?

使池失衡的0.04% 費用由流動性提供者和Curve 投票託管的CRV (veCRV) 持有者平均分攤。攻擊者未持有的5,417,295 LP 代幣的價值從5,515,323 美元增加到5,520,794 美元。這比池費用的50% 增加了5,471 美元。增加的美元價值歸於託管CRV (veCRV) 持有人。

Curve 的保護

為了防止三明治攻擊,在向Curve Metapool 添加流動性時,需要指定一個合理的最小LP 代幣數量。通常,DeFi 協議會在交易中傳入相當數量的金額。 Curve 池中的add_liquidity 函數就是min_mint_amount 的一個很好的例子。但是對於標準的EIP-4626 存款函數,沒有定義參數來指定最小金額,因此我們無法傳入相當數量的鏈下計算的Metapool LP 代幣。

Curve 池有一個calc_token_amount 函數,它可以計算池代幣存款收到的LP 代幣數量。但這不能用來防止三明治攻擊。如果已經運行了一個交易來平衡池,那麼calc_token_amount 函數將只返回當前不公平的LP 代幣數量。

function calc_token_amount(uint256[2] memory amounts, bool is_deposit) external view returns (uint256);

因此問題仍然存在,EIP-4626 函數沒有辦法傳遞最小量。打破標準來添加這一點是不可取的,使用預言機也是次優的。我們需要鏈上方法。

mStable 的方法

mStable 的金庫獲得一個公平的Metapool LP 代幣價格的方法是使用Curve Metapool 和Curve 3Pool 的虛擬價格。 get_virtual_price 函數以美元為單位返回池的流動性提供者代幣的價格。它通過計算池的不變式來實現這一點,該不變式是池中代幣的美元價值除以代幣的總供應量。由於池中代幣的餘額不影響池的不變值或總美元價值,虛擬價格不會受到三明治攻擊。

function get_virtual_price() external view returns (uint256);

對於存入mStable 金庫的存款,我們需要在Curve 的3Pool LP 代幣(3Crv) 中對Metapool LP 代幣進行定價,因為這是我們在金庫中使用的資產。為此,我們得到3Pool 虛擬價格,並將其除以Metapool LP 代幣價格。

fair Metapool LP tokens = 3Crv assets *

3Pool virtual price /

Metapool virtual price

一旦我們有了一個合理的價格,我們就可以通過目前配置為1% 的滑點係數來降低它。這個調整後的公平價格用於計算在向池中添加3Crv 流動性時可以接收的Curve Metapool LP 代幣(musd3Crv) 的最小數量。

存款的全部流程如下:

如何解決EIP-4626中的高滑點問題?

結論

雖然標准在標準化和獲得採用方面起著巨大的作用,但像這樣的問題提醒我們,在DeFi 方面沒有輕鬆的勝利。我們需要認識到現有標準的局限性,並為它們尋找最佳的解決方案。