由于在以太坊中的交易属性,在一笔交易中可以借出大量资金进行操作(不能超过gaslimit限制)。所以当各个交易平台有利差的时候可以进行套利(无风险套利),避免了准备大量资金。
## 相关项目
### Cofix
github:[https://github.com/Computable-Finance](https://github.com/Computable-Finance)
coifx中调用了NEST预言机的价格,完成做市、交易的操作并且去中心化。
### Uniswap
github:[https://github.com/Uniswap/uniswap-v2-core](https://github.com/Uniswap/uniswap-v2-core)
Uniswap根据交易拟合算法来完成交易,目前锁仓量最大的去中心化交易平台。
### NEST
github:[https://github.com/NEST-Protocol](https://github.com/NEST-Protocol)
使用双向报价机制,可以在以太坊上生成去中心化的价格。
> 这几个项目之后会单独细说,本篇只讲述如何组合各个合约进行套利
## 流程
“`mermaid
graph LR
A[DYDX] — 1.闪电贷WETH –> B[套利合约]
B[套利合约]–2.WETH换ETH–>D[WETH]
B[套利合约] –3.ETH换USDT–> C(Cofix)
B[套利合约] –4.USDT换ETH–> E[Uniswap]
B[套利合约] –5.ETH换WETH–>D[WETH]
B[套利合约] –6.WETH还款–>A[DYDX]
“`
> 还款后剩余资金为所的利润
## 套利合约
github:[https://github.com/MLY0813/FlashSwapForCofixAndUni/blob/main/Contract/Flash_Swap.sol](https://github.com/MLY0813/FlashSwapForCofixAndUni/blob/main/Contract/Flash_Swap.sol)
### 核心方法
“`c
// 实现操作
function callFunction(
address sender,
Account.Info memory account,
bytes memory data
) public {
MyCustomData memory mcd = abi.decode(data, (MyCustomData));
uint256 tokenBalanceBefore = IERC20(mcd.token).balanceOf(address(this));
// money
// WETH->ETH
WETH9(WETHAddress).withdraw(tokenBalanceBefore);
// ETH->USDT
uint256 loopTimes = address(this).balance.div(cofixETHSapn);
for(uint256 i = 0; i < loopTimes; i++) {
CoFiXRouter(cofixRouter).swapExactETHForTokens{value:cofixETHSapn}(USDTAddress,cofixETHSapn.sub(nestPrice),1,address(this), address(this), uint256(block.timestamp).add(100));
}
// USDT->ETH
uint256 usdtBalance = IERC20(USDTAddress).balanceOf(address(this));
address[] memory uniData = new address[](2);
uniData[0] = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
uniData[1] = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
UniswapV2Router(uniRouter).swapExactTokensForETH(usdtBalance,1,uniData,address(this),uint256(block.timestamp).add(100));
// ETH->WETH
WETH9(WETHAddress).deposit{value:tokenBalanceBefore.add(2)};
uint256 balOfLoanedToken = IERC20(mcd.token).balanceOf(address(this));
require(
balOfLoanedToken >= mcd.repayAmount,
“Not enough funds to repay dydx loan!”
);
}
“`
callFunction方法会在调用DYDX闪电贷过程中被回调,在方法中实现收到贷款资金后需要的进行的操作。
#### 1.WETH兑换成ETH
“`c
WETH9(WETHAddress).withdraw(tokenBalanceBefore);
“`
#### 2.ETH 在Cofix中兑换成USDT
“`c
uint256 loopTimes = address(this).balance.div(cofixETHSapn);
for(uint256 i = 0; i < loopTimes; i++) {
CoFiXRouter(cofixRouter).swapExactETHForTokens{value:cofixETHSapn}(USDTAddress,cofixETHSapn.sub(nestPrice),1,address(this), address(this), uint256(block.timestamp).add(100));
}
“`
这里使用了循环操作,因为cofix中有冲击成本的限制。单笔大额资金是亏钱的,所以要分成小部分资金进行兑换。
#### 3.USDT 在Uniswap中兑换成ETH
“`c
uint256 usdtBalance = IERC20(USDTAddress).balanceOf(address(this));
address[] memory uniData = new address[](2);
uniData[0] = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
uniData[1] = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
UniswapV2Router(uniRouter).swapExactTokensForETH(usdtBalance,1,uniData,address(this),uint256(block.timestamp).add(100));
“`
#### 4.ETH兑换成WETH
“`c
WETH9(WETHAddress).deposit{value:tokenBalanceBefore.add(2)};
“`
注意dydx还款的时候需要加2wei的资金
> 整个操作完成后剩余的ETH就是自己的了
—
“`c
function initiateFlashLoan(uint256 _amount)
external
{
ISoloMargin solo = ISoloMargin(dydxAddress);
uint256 marketId = _getMarketIdFromTokenAddress(dydxAddress, WETHAddress);
uint256 repayAmount = _getRepaymentAmountInternal(_amount);
IERC20(WETHAddress).approve(dydxAddress, repayAmount);
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
operations[0] = _getWithdrawAction(marketId, _amount);
operations[1] = _getCallAction(
abi.encode(MyCustomData({token: WETHAddress, repayAmount: repayAmount}))
);
operations[2] = _getDepositAction(marketId, repayAmount);
Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();
solo.operate(accountInfos, operations);
}
“`
使用dydx闪电贷的代码,传入参数就是想借多少WETH。大部分代码都是按照dydx固定的参数拼接数据。
## 注意事项
1. 只有出现利差的时候闪电贷套利才有效,这种机会很少,但是也没什么成本。
2. cofix交易会挖出cofi,合约中需要有取出cofi的接口,否则就锁里面拿不出来了。
3. 最好有脚本程序配合,发现套利机会直接发起交易套利。
基于DYDX闪电贷在Cofix和Uniswap之间套利
由于在以太坊中的交易属性,在一笔交易中可以借出大量资金进行操作(不能超过gaslimit限制)。所以当各个交易平台有利差的时候可以进行套利(无风险套利),避免了准备大量资金。
相关项目
Cofix
github:https://github.com/Computable-Finance
coifx中调用了NEST预言机的价格,完成做市、交易的操作并且去中心化。
Uniswap
github:https://github.com/Uniswap/uniswap-v2-core
Uniswap根据交易拟合算法来完成交易,目前锁仓量最大的去中心化交易平台。
NEST
github:https://github.com/NEST-Protocol
使用双向报价机制,可以在以太坊上生成去中心化的价格。
这几个项目之后会单独细说,本篇只讲述如何组合各个合约进行套利
流程
graph LR
A[DYDX] -- 1.闪电贷WETH --> B[套利合约]
B[套利合约]--2.WETH换ETH-->D[WETH]
B[套利合约] --3.ETH换USDT--> C(Cofix)
B[套利合约] --4.USDT换ETH--> E[Uniswap]
B[套利合约] --5.ETH换WETH-->D[WETH]
B[套利合约] --6.WETH还款-->A[DYDX]
还款后剩余资金为所的利润
套利合约
github:https://github.com/MLY0813/FlashSwapForCofixAndUni/blob/main/Contract/Flash_Swap.sol
核心方法
// 实现操作
function callFunction(
address sender,
Account.Info memory account,
bytes memory data
) public {
MyCustomData memory mcd = abi.decode(data, (MyCustomData));
uint256 tokenBalanceBefore = IERC20(mcd.token).balanceOf(address(this));
// money
// WETH->ETH
WETH9(WETHAddress).withdraw(tokenBalanceBefore);
// ETH->USDT
uint256 loopTimes = address(this).balance.div(cofixETHSapn);
for(uint256 i = 0; i < loopTimes; i++) {
CoFiXRouter(cofixRouter).swapExactETHForTokens{value:cofixETHSapn}(USDTAddress,cofixETHSapn.sub(nestPrice),1,address(this), address(this), uint256(block.timestamp).add(100));
}
// USDT->ETH
uint256 usdtBalance = IERC20(USDTAddress).balanceOf(address(this));
address[] memory uniData = new address[](2);
uniData[0] = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
uniData[1] = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
UniswapV2Router(uniRouter).swapExactTokensForETH(usdtBalance,1,uniData,address(this),uint256(block.timestamp).add(100));
// ETH->WETH
WETH9(WETHAddress).deposit{value:tokenBalanceBefore.add(2)};
uint256 balOfLoanedToken = IERC20(mcd.token).balanceOf(address(this));
require(
balOfLoanedToken >= mcd.repayAmount,
"Not enough funds to repay dydx loan!"
);
}
callFunction方法会在调用DYDX闪电贷过程中被回调,在方法中实现收到贷款资金后需要的进行的操作。
1.WETH兑换成ETH
WETH9(WETHAddress).withdraw(tokenBalanceBefore);
2.ETH 在Cofix中兑换成USDT
uint256 loopTimes = address(this).balance.div(cofixETHSapn);
for(uint256 i = 0; i < loopTimes; i++) {
CoFiXRouter(cofixRouter).swapExactETHForTokens{value:cofixETHSapn}(USDTAddress,cofixETHSapn.sub(nestPrice),1,address(this), address(this), uint256(block.timestamp).add(100));
}
这里使用了循环操作,因为cofix中有冲击成本的限制。单笔大额资金是亏钱的,所以要分成小部分资金进行兑换。
3.USDT 在Uniswap中兑换成ETH
uint256 usdtBalance = IERC20(USDTAddress).balanceOf(address(this));
address[] memory uniData = new address[](2);
uniData[0] = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
uniData[1] = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
UniswapV2Router(uniRouter).swapExactTokensForETH(usdtBalance,1,uniData,address(this),uint256(block.timestamp).add(100));
4.ETH兑换成WETH
WETH9(WETHAddress).deposit{value:tokenBalanceBefore.add(2)};
注意dydx还款的时候需要加2wei的资金
整个操作完成后剩余的ETH就是自己的了
function initiateFlashLoan(uint256 _amount)
external
{
ISoloMargin solo = ISoloMargin(dydxAddress);
uint256 marketId = _getMarketIdFromTokenAddress(dydxAddress, WETHAddress);
uint256 repayAmount = _getRepaymentAmountInternal(_amount);
IERC20(WETHAddress).approve(dydxAddress, repayAmount);
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
operations[0] = _getWithdrawAction(marketId, _amount);
operations[1] = _getCallAction(
abi.encode(MyCustomData({token: WETHAddress, repayAmount: repayAmount}))
);
operations[2] = _getDepositAction(marketId, repayAmount);
Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();
solo.operate(accountInfos, operations);
}
使用dydx闪电贷的代码,传入参数就是想借多少WETH。大部分代码都是按照dydx固定的参数拼接数据。
注意事项
- 只有出现利差的时候闪电贷套利才有效,这种机会很少,但是也没什么成本。
- cofix交易会挖出cofi,合约中需要有取出cofi的接口,否则就锁里面拿不出来了。
- 最好有脚本程序配合,发现套利机会直接发起交易套利。
本文参与区块链开发网写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
- 发表于 2020-11-05 10:27
- 阅读 ( 3662 )
- 学分 ( 137 )
- 分类:Solidity