三角套利是加密交易中的一種策略,利用單個市場內或跨多個市場的匯率變動。該方法包括三個連續交易:將初始加密貨幣換成第二種,第二種換成第三種,最終將第三種加密貨幣換回初始加密貨幣,所有這些都是爲了獲利。因此,“三角”一詞概括了其三步驟過程。
AI生成的圖像
在去中心化交易所(DEX)上,三角套利的機會通常是由於多個池之間的流動性差異造成的。它們通常是短暫的,僅持續幾秒甚至更短的時間,因爲交易所會迅速調整任何價格差異。因此,配備了快速執行交易功能的自動化交易算法被用來利用這些短暫的差異。爲了幫助理解這個概念,下面是一個例子:
以上的三角交易始於 01 — 用 60,000 美元的 USDC 購買了 1 個 wBTC,接着是 02 — 用 1 個 wBTC 購買了 16 個 WETH,最後是 03 — 用 16 個 WETH 賣出了 66,000 美元的 USDC。在旅程結束時,我們將獲得 6,000 美元的 USDC 作爲利潤。
在 Uniswap v3 上有兩種多跳交換的方式:精確輸入和精確輸出。顧名思義,第一種方式期望以精確數量的代幣作爲交換的輸入,並在交換結束時以指定數量的代幣按照交換率輸出;而後一種方式期望以指定數量的代幣作爲輸出,只有足夠數量的代幣作爲輸入才能以交換率完成交換。
由於三角套利的業務特性,我們希望以精確數量的代幣作爲輸入,將其交換成另一種加密貨幣,然後再次交換回原始代幣以獲取利潤。
address constant SWAP_ROUTER_02 = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
contract MultiHopSwap {
using SafeERC20 for IERC20;
ISwapRouter02 private constant ROUTER = ISwapRouter02(SWAP_ROUTER_02);
uint256 private constant MAX_INT =
115792089237316195423570985008687907853269984665640564039457584007913129639935;
function swapExactInputMultiHop(uint256 amountIn) external {
IERC20(USDC).safeApprove(address(ROUTER), MAX_INT);
IERC20(WETH).safeApprove(address(ROUTER), MAX_INT);
IERC20(DAI).safeApprove(address(ROUTER), MAX_INT);
bytes memory path =
abi.encodePacked(USDC, uint24(3000), WETH, uint24(3000), DAI, uint24(3000), USDC) ;
ISwapRouter02.ExactInputParams memory params = ISwapRouter02
.ExactInputParams({
path: path,
recipient: address(this),
amountIn: amountIn,
amountOutMinimum: 1
});
ROUTER.exactInput(params);
}
}
路由器在促進流動性提供方面起着至關重要的作用。由於它們是無狀態的,並且不持有代幣餘額,因此可以安全地替換路由器。因此,路由器具有從 01 開始的發布編號。在我們的實現中,我們在主網上使用 Router02,地址 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45。
SafeERC20 是圍繞 ERC20 交易構建的保護層,確保我們合約與 ERC20 代幣進行安全交互。與常規的 ERC20 函數不同,SafeERC20 通過驗證 ERC20 操作的布爾返回值來增強安全性。如果任何操作失敗,交易將被回滾,從而最小化風險。此外,SafeERC20 還可適應缺乏布爾返回值的非標準 ERC20 代幣,提供了在代幣管理方面的靈活性和健壯性。通過批準最大數量,我們允許 Router02 代表我們轉移代幣。如果不這樣做,您將期望看到 STF 錯誤消息,其中 STF 意味着 TransferHelper.safeTransferFrom 函數中的 require 斷言導致執行被還原。
接下來,我們將看看如何定義三角路徑:
bytes memory path = abi.encodePacked(USDC, uint24(3000),
WETH, uint24(3000),
DAI, uint24(3000),
USDC) ;
通過 abi.encodePacked,Solidity 將多個值緊密地打包在一起,而不添加任何填充。它串聯了每個參數的原始二進制數據。不難理解,這些參數將套利交易與手續費在加密貨幣對之間順序化。路徑從 USDC 開始,停止在 USDC,期望獲利。然後,它被 ExactInputParams 包裝,加上其他必要的參數,並輸入路由器進行多跳交換。
我們使用相同的技術,通過模擬來分叉主網。一旦確認合約已經收到了 10 個 USDC,就可以觸發多跳交換,如下所示:
it("performs multi hop swap", async () => {
balance = await swap.tokenBalance(USDC);
console.log(`Current balance of USDC = ${balance}`);
console.log(`Swapping ${initialFundingHuman} USDC`);
const tx = await swap.swapExactInputMultiHop(ethers.parseUnits(initialFundingHuman, DECIMALS));
receipt = await tx.wait();
balance = await swap.tokenBalance(USDC);
console.log(`Current balance of USDC = ${balance}`);
expect(balance).not.equal(0);
});
測試結果應如下所示:
USDC balance of whale: 170961218210457n
Impersonation Started.
Impersonation completed.
Current balance of USDC = 100000000
Swapping 100 USDC
Current balance of USDC = 91677417
在經歷了一番波折之後,我們虧損了 — 顯然,路徑上的現貨匯率並不對我們有利,但你已經了解了在 Uniswap v3 上如何利用多跳交換進行三角套利的想法。
我還沒說過嗎?DeFi 生態系統中最強大的資金來源就是閃電貸款。你不需要太多創意,就可以構建一個利用閃電貸款和我所教的多跳交換的三角套利交易策略。更新後的順序圖如下所示:
閃電貸款資助的 Uniswap v3 三角套利順序圖(爲簡潔起見忽略了一些操作)
請查看我的原始碼,其中包括在 Uniswap v3 上實現的閃電貸款和多跳交換 — https://medium.com/cryptocurrency-scripts/flash-loan-on-uniswap-v3-84bca2bfe255。消化這個順序圖,並完成自己的作業,以合並智能合約。
首先,我們要查看的是由三筆交易組成的路徑:爲了獲利,它們必須是正確的三對加密貨幣以及正確的匯率。爲了找到所有這些正確性,您需要開發一個程序,對三角套利模式中的可交易對進行排列組合,並模擬交換以檢查盈利能力。從區塊鏈中檢索匯率可能很慢,如果有太多待驗證盈利能力的路徑,這將進一步減慢過程。您可能希望通過根據 DEX 的 GraphQL 定價端點(例如 Uniswap v3)提供的表面價格計算利潤和損失來縮小三角路徑的列表,因爲 GraphQL API 比區塊鏈更快地提供行情數據。一旦路徑被縮小,再使用從鏈上檢索的報價運行它們,以獲得更準確的利潤和損失計算。
通過閃電貸款增加投資可以進一步提高利潤 —— 以低利率借入代幣,並將其投資於有利可圖的策略,總是一個好主意。從理論上講,只要總利潤足以覆蓋閃電貸款和交換手續費,三角套利策略就被認爲是盈利的。一個關鍵的技巧是在交易合約中設置邏輯,如果總盈利檢查失敗,則使閃電貸款交易失敗,因爲當交易失敗時,所有操作將回滾,您無需承擔損失甚至交易的費用。這段邏輯將起到一種全能的門衛作用,以防止對我們不利的滑點或匯率波動。
話雖如此,無論交易成功與否,燃氣費都是您無法擺脫的東西,可能是您從三角套利中虧損的主要原因。始終評估您的策略交易燃氣費,並將其計入淨利潤計算中。請參考我的原始碼中的燃氣費估算測試用例。
三角套利是加密交易中的一種策略,利用單個市場內或跨多個市場的匯率變動。該方法包括三個連續交易:將初始加密貨幣換成第二種,第二種換成第三種,最終將第三種加密貨幣換回初始加密貨幣,所有這些都是爲了獲利。因此,“三角”一詞概括了其三步驟過程。
AI生成的圖像
在去中心化交易所(DEX)上,三角套利的機會通常是由於多個池之間的流動性差異造成的。它們通常是短暫的,僅持續幾秒甚至更短的時間,因爲交易所會迅速調整任何價格差異。因此,配備了快速執行交易功能的自動化交易算法被用來利用這些短暫的差異。爲了幫助理解這個概念,下面是一個例子:
以上的三角交易始於 01 — 用 60,000 美元的 USDC 購買了 1 個 wBTC,接着是 02 — 用 1 個 wBTC 購買了 16 個 WETH,最後是 03 — 用 16 個 WETH 賣出了 66,000 美元的 USDC。在旅程結束時,我們將獲得 6,000 美元的 USDC 作爲利潤。
在 Uniswap v3 上有兩種多跳交換的方式:精確輸入和精確輸出。顧名思義,第一種方式期望以精確數量的代幣作爲交換的輸入,並在交換結束時以指定數量的代幣按照交換率輸出;而後一種方式期望以指定數量的代幣作爲輸出,只有足夠數量的代幣作爲輸入才能以交換率完成交換。
由於三角套利的業務特性,我們希望以精確數量的代幣作爲輸入,將其交換成另一種加密貨幣,然後再次交換回原始代幣以獲取利潤。
address constant SWAP_ROUTER_02 = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
contract MultiHopSwap {
using SafeERC20 for IERC20;
ISwapRouter02 private constant ROUTER = ISwapRouter02(SWAP_ROUTER_02);
uint256 private constant MAX_INT =
115792089237316195423570985008687907853269984665640564039457584007913129639935;
function swapExactInputMultiHop(uint256 amountIn) external {
IERC20(USDC).safeApprove(address(ROUTER), MAX_INT);
IERC20(WETH).safeApprove(address(ROUTER), MAX_INT);
IERC20(DAI).safeApprove(address(ROUTER), MAX_INT);
bytes memory path =
abi.encodePacked(USDC, uint24(3000), WETH, uint24(3000), DAI, uint24(3000), USDC) ;
ISwapRouter02.ExactInputParams memory params = ISwapRouter02
.ExactInputParams({
path: path,
recipient: address(this),
amountIn: amountIn,
amountOutMinimum: 1
});
ROUTER.exactInput(params);
}
}
路由器在促進流動性提供方面起着至關重要的作用。由於它們是無狀態的,並且不持有代幣餘額,因此可以安全地替換路由器。因此,路由器具有從 01 開始的發布編號。在我們的實現中,我們在主網上使用 Router02,地址 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45。
SafeERC20 是圍繞 ERC20 交易構建的保護層,確保我們合約與 ERC20 代幣進行安全交互。與常規的 ERC20 函數不同,SafeERC20 通過驗證 ERC20 操作的布爾返回值來增強安全性。如果任何操作失敗,交易將被回滾,從而最小化風險。此外,SafeERC20 還可適應缺乏布爾返回值的非標準 ERC20 代幣,提供了在代幣管理方面的靈活性和健壯性。通過批準最大數量,我們允許 Router02 代表我們轉移代幣。如果不這樣做,您將期望看到 STF 錯誤消息,其中 STF 意味着 TransferHelper.safeTransferFrom 函數中的 require 斷言導致執行被還原。
接下來,我們將看看如何定義三角路徑:
bytes memory path = abi.encodePacked(USDC, uint24(3000),
WETH, uint24(3000),
DAI, uint24(3000),
USDC) ;
通過 abi.encodePacked,Solidity 將多個值緊密地打包在一起,而不添加任何填充。它串聯了每個參數的原始二進制數據。不難理解,這些參數將套利交易與手續費在加密貨幣對之間順序化。路徑從 USDC 開始,停止在 USDC,期望獲利。然後,它被 ExactInputParams 包裝,加上其他必要的參數,並輸入路由器進行多跳交換。
我們使用相同的技術,通過模擬來分叉主網。一旦確認合約已經收到了 10 個 USDC,就可以觸發多跳交換,如下所示:
it("performs multi hop swap", async () => {
balance = await swap.tokenBalance(USDC);
console.log(`Current balance of USDC = ${balance}`);
console.log(`Swapping ${initialFundingHuman} USDC`);
const tx = await swap.swapExactInputMultiHop(ethers.parseUnits(initialFundingHuman, DECIMALS));
receipt = await tx.wait();
balance = await swap.tokenBalance(USDC);
console.log(`Current balance of USDC = ${balance}`);
expect(balance).not.equal(0);
});
測試結果應如下所示:
USDC balance of whale: 170961218210457n
Impersonation Started.
Impersonation completed.
Current balance of USDC = 100000000
Swapping 100 USDC
Current balance of USDC = 91677417
在經歷了一番波折之後,我們虧損了 — 顯然,路徑上的現貨匯率並不對我們有利,但你已經了解了在 Uniswap v3 上如何利用多跳交換進行三角套利的想法。
我還沒說過嗎?DeFi 生態系統中最強大的資金來源就是閃電貸款。你不需要太多創意,就可以構建一個利用閃電貸款和我所教的多跳交換的三角套利交易策略。更新後的順序圖如下所示:
閃電貸款資助的 Uniswap v3 三角套利順序圖(爲簡潔起見忽略了一些操作)
請查看我的原始碼,其中包括在 Uniswap v3 上實現的閃電貸款和多跳交換 — https://medium.com/cryptocurrency-scripts/flash-loan-on-uniswap-v3-84bca2bfe255。消化這個順序圖,並完成自己的作業,以合並智能合約。
首先,我們要查看的是由三筆交易組成的路徑:爲了獲利,它們必須是正確的三對加密貨幣以及正確的匯率。爲了找到所有這些正確性,您需要開發一個程序,對三角套利模式中的可交易對進行排列組合,並模擬交換以檢查盈利能力。從區塊鏈中檢索匯率可能很慢,如果有太多待驗證盈利能力的路徑,這將進一步減慢過程。您可能希望通過根據 DEX 的 GraphQL 定價端點(例如 Uniswap v3)提供的表面價格計算利潤和損失來縮小三角路徑的列表,因爲 GraphQL API 比區塊鏈更快地提供行情數據。一旦路徑被縮小,再使用從鏈上檢索的報價運行它們,以獲得更準確的利潤和損失計算。
通過閃電貸款增加投資可以進一步提高利潤 —— 以低利率借入代幣,並將其投資於有利可圖的策略,總是一個好主意。從理論上講,只要總利潤足以覆蓋閃電貸款和交換手續費,三角套利策略就被認爲是盈利的。一個關鍵的技巧是在交易合約中設置邏輯,如果總盈利檢查失敗,則使閃電貸款交易失敗,因爲當交易失敗時,所有操作將回滾,您無需承擔損失甚至交易的費用。這段邏輯將起到一種全能的門衛作用,以防止對我們不利的滑點或匯率波動。
話雖如此,無論交易成功與否,燃氣費都是您無法擺脫的東西,可能是您從三角套利中虧損的主要原因。始終評估您的策略交易燃氣費,並將其計入淨利潤計算中。請參考我的原始碼中的燃氣費估算測試用例。