专栏名称: viiimaus
目录
相关文章推荐
51好读  ›  专栏  ›  viiimaus

基于DYDX闪电贷在Cofix和Uniswap之间套利

viiimaus  · CSDN  ·  · 2020-11-04 22:15

正文

请到「今天看啥」查看全文


基于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

使用双向报价机制,可以在以太坊上生成去中心化的价格。

这几个项目之后会单独细说,本篇只讲述如何组合各个合约进行套利

流程

1.闪电贷WETH
2.WETH换ETH
3.ETH换USDT
4.USDT换ETH
5.ETH换WETH
6.WETH还款
DYDX
套利合约
WETH
Cofix
Uniswap

还款后剩余资金为所的利润

套利合约

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!"
        );
        
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

callFunction方法会在调用DYDX闪电贷过程中被回调,在方法中实现收到贷款资金后需要的进行的操作。

1.WETH兑换成ETH

	WETH9(WETHAddress).withdraw(tokenBalanceBefore);
  • 1
  • 1

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));
    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

这里使用了循环操作,因为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));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

4.ETH兑换成WETH

WETH9(WETHAddress).deposit{value:tokenBalanceBefore.add(2)};
  • 1
  • 1

注意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);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

使用dydx闪电贷的代码,传入参数就是想借多少WETH。大部分代码都是按照dydx固定的参数拼接数据。

注意事项

  1. 只有出现利差的时候闪电贷套利才有效,这种机会很少,但是也没什么成本。
  2. cofix交易会挖出cofi,合约中需要有取出cofi的接口,否则就锁里面拿不出来了。
  3. 最好有脚本程序配合,发现套利机会直接发起交易套利。






请到「今天看啥」查看全文