一文讀懂DeFi上的閃電貸(附如何利用閃電貸套利)

買賣虛擬貨幣

2月16日,bZx被爆遭到“攻擊”,操縱多個DeFi專案上的代幣價格,從而15秒實現套利36萬美元。涉及多個DeFi明星專案如Compound,DyDx,Uniswap,kyber,bZx。這個攻擊利用了DeFi上最新的閃電貸(flashloans)功能。正如bZx所說,這種攻擊是所見過的最複雜的攻擊之一,只有對每種DeFi協議及其各種工具有非常深入的瞭解才有可能,傳統金融體系中沒有類似的東西。

什麼是閃電貸(flashloans)?怎麼利用閃電貸(flashloans)來套利?本期金色硬核(Hardcore)綜合編譯AbitrageDAO和PeckShield最早和最新的閃電貸套利研究。

AbitrageDAO是Stake資本團隊建立的一個DeFi套利基金,聯合鏈上流動性和鏈下機器人來尋求套利機會。PeckShield為區塊鏈安全公司。

最新進展:2月18日bZx發推宣佈再次暫停,疑似再次被攻擊,這一次攻擊者或獲利2388個ETH。

在交易世界中,套利是一種利用市場之間的價格差異來獲利的策略。套利機會在金融市場中以各種形式存在。加密貨幣也不例外,很多交易所之間有著套利機會。套利有助於減少資產在不同市場中的價格差異,它還有助於提高流動性。

我們(AbitrageDAO)專注於在以太坊上執行的具有合約可填充流動性(Contract Fillable Liquidity ,CFL)的去中心化交易所。有CFL的去中心化交易所包括Oasis,0x relayers,Uniswap,Bancor和Kyber。有CFL的交易所允許交易者在以太坊區塊鏈的一個區塊交易中利用套利機會。

什麼是閃電貸(flash loans)

閃電貸(flash loans)是為開發人員設計的,可以在無需提供任何抵押的情況下立即進行貸款。所有這些都要在一個交易(一個以太坊區塊)中完成。開發人員可以從Aave儲備池中借錢(注:flash loans最早討論來自Aave協議,第一筆flash loans也來自Aave),條件是在交易結束之前將流動資金返還到資金池中。如果這種流動性未能及時返回儲備庫,則交易將被撤回,從而確保儲備池的安全。

閃電貸有許多有趣的用例,包括:

  • 去中心化交易所之間的套利

  • 多個借貸平臺如Compound,dYdX或Nuo上清算貸款

  • 再融資,例如從Aave提取DAI,關閉MakerDAO CDP,獲取抵押品,在Compound上存款,開倉,取回DAI,退還DAI加手續費

這使得更多參與者可以在套利和清算間發揮作用,因為不需要任何資金就可以開始。套利機會通常不需要太多資金(在100-10000美元之間)。另一方面,清算需要大量資金來清算借款人頭寸。Compound或單抵押DAI(SAI)的許多清算需要ETH或DAI超過100萬美元。

ArbitrageDAO是低抵押/無抵押閃電貸的最佳用例。但我們相信,在未來幾個月中,將看到許多使用閃電貸的激動人心的專案。

第一筆閃電貸

ArbitrageDAO於2020年1月18日完成第一筆無抵押的閃電貸。見下圖Camilla Russo的報道。

為了證明閃電貸的巨大潛力,我們決定聚焦於特定的套利策略,但也可應用於許多其他方面。你可以在此處檢視ArbitrageDAO從錢包發起的交易:https://etherscan.io/address/0x8645abffe4fad9e0c6c18afff30ef6aea438008c

https://etherscan.io/tx/0x4555a69b40fa465b60406c4d23e2eb98d8aee51def21faa28bb7d2b4a73ab1a9

在上述套利交易中,我們在Aave上借了超過3100個DAI。

更多交易:

截止2020年1月23日,AbitrageDAO總共從Aave借了大約9400個DAI,盈利33個DAI。

最新套利案例:bZx 2月15日閃電貸套利過程全披露

bZx 2月15日閃電貸套利過程來自安全公司派盾的分析。

這不是預言機攻擊。相反,這是一個非常聰明巧妙的套利,它確實利用了bZx智慧合約中的一個錯誤,以允許本應鎖定的bZx資金流向Uniswap,並進一步將洩漏的資金吸收到Compound頭寸中。

套利五步驟

交易在這裡0xb5c8bd9430b6cc87a0e2fe110ece6bf527fa4f170a4bc8cd032f768fc5219838,它是在2020-02-15 01:38:57 + UTC的區塊高度9484688上。如上圖所示,此攻擊可以分為五個不同的步驟:閃電貸借款、吸籌、保證金拉昇、出貨、償還閃電貸(Flashloan Borrow, Hoard, Margin Pump, Dump, Flashloan Repay)。

1:閃電貸借款。這一步利用了dYdX的閃電貸功能借入10000個ETH。

執行此步驟後,攻擊者資產負債如下資產,無收益。

2:吸籌。利用借來的貸款,攻擊者將5500 ETH存入Compound作為抵押品,借入112 WBTC。這是正常的Compound操作,此吸籌的WBTC將在步驟4中出貨。

完成此步驟後,攻擊者的資產負債表如下,仍然無收益。

3:保證金拉昇。吸籌之後,此步驟利用bZx保證金交易功能以賣空ETH兌得WBTC(即sETHwBTCx5)。具體來說,攻擊者存入1300 ETH並呼叫bZx保證金交易功能,即mintWithEther(連續呼叫marginTradeFromDeposit)。保證金交易功能利用KyberSwap將借入的5637.623762 ETH交換為51.345576 WBTC。請注意,5倍槓桿借入ETH。實質上將1 WBTC的兌換率提高到109.8 WETH,大約是正常兌換率(~38.5 WETH/WBTC)的三倍。

具體來說,為完成此交易,bZx將訂單轉發給KyberSwap,後者隨後會查詢其儲備金並找到最佳匯率,實際上KyberUniswap儲備庫。此步驟實質是將Uniswap中的WBTC價格提高了三倍。

此步驟應由內建的完整性檢查阻止,此操作可驗證掉期後頭寸不會變為預設值。但是,此攻擊發生時,沒有進行此檢查,我們稍後將在智慧合約錯誤部分中檢查詳細資訊。

完成此步驟後,攻擊者的資產負債表如下,仍然無收益。

4:出貨。隨著Uniswap中WBTC價格的飆升,攻擊者將Uniswap中從Compound中借來的112 WBTC賣出換成WETH。

此出貨步驟獲得6871.4127388702245 ETH的淨收益,平均兌換率為1 WBTC = 61.4 WETH。執行此步驟之後,攻擊者獲得可觀的利潤,資產負債表如下:

5:償還閃電貸。攻擊者使用從112 WBTC出貨中獲得的6871.4127388702245 ETH,將10000ETH的貸款償還給dYdX,從而完成閃電貸。

這一步後,可以重新計算一下資產負債。最終,攻擊者獲得71個ETH的套利,外加兩個頭寸,一個頭寸為Compound(+ 5500WETH / -112WBTC),另一個頭寸為bZx(-4337WETH / + 51WBTC)。當bZx頭寸處於預設狀態時,Compound頭寸非常有利可圖。在利用漏洞之後,攻擊者立即開始安排償還Compound債務(112BTC)來贖回抵押品(5500WETH)。對於bZx頭寸,攻擊者不再顯示任何興趣。

考慮到1 WBTC = 38.5WETH(或1 WETH = 0.025BTC)的市場均價,攻擊者可以獲得112 WBTC等價的4300 ETH。結果,攻擊者獲得了71 WETH + 5500 WETH -4300 ETH = 1271 ETH,大約35.59萬美元(假設ETH價格為280美元)。

bZx智慧合約錯誤

這次攻擊背後的魔力是Uniswap WBTC/ETH是如何被操縱至高達61.4的利潤的。如第3步所述,當正常市場價格僅為38左右時,WBTC / ETH價格被拉昇至109.8。換句話說,這一巨大價差是被有意操縱的。但是,如此巨大的價差會導致bZx頭寸處於抵押不足狀態。但是為什麼要允許抵押不足狀態存在,這自然導致在bZx智慧合約實現中發現隱藏的錯誤。

保證金拉昇功能從marginTradeFromDeposit()開始。

如上圖所示,marginTradeFromDeposit()在第840行將第四個引數設定為true的情況下呼叫_borrowTokenAndUse()

在_borrowTokenAndUse()內部,當amountIsADeposit為true時,在行1348中呼叫_getBorrowAmountAndRate()。返回的借款金額將儲存在sendAmounts [1]中。

同樣在_borrowTokenAndUse()中,在amountIsADeposit == true的情況下,在1355行中將sendAmounts [1]的值填充為sendAmounts [6](將在後面看到)。稍後,在第1370行中呼叫_borrowTokenAndUseFinal()。

在第1414行中,_borrowTokenAndUseFinal()透過IBZx介面呼叫takeOrderFromiToken(),以使交易流進入bZxContract。

下面有趣的部分到了。在第145–153行中,有一個require()呼叫以檢查該頭寸是否健康。不幸的是,在loadDataBytes.length == 0 && sentAmounts [6] == sentAmounts [1]的情況下,完整性檢查(sanity check)bZxOracle :: shoudLiquidate()被跳過了。這正是觸發漏洞以避免完整性檢查的條件。

如果我們看一下bZxOracle :: shouldLiquidate(),則第514行中的檢查getCurrentMarginAmount()<= loanOrder.maintenanceMarginAmount可以透過捕獲保證金提升步驟來完成這項工作,從而可以防止這種攻擊。

參考資料:

Flash Boys | Arbitrage DAO

https://medium.com/@bneiluj/flash-boys-arbitrage-dao-c0b96d094f93

bZx Hack Full Disclosure (With Detailed Profit Analysis)

https://medium.com/@peckshield/bzx-hack-full-disclosure-with-detailed-profit-analysis-e6b1fa9b18fc

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;