31

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

 3 years ago
source link: https://learnblockchain.cn/article/1676
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

由于在以太坊中的交易属性,在一笔交易中可以借出大量资金进行操作(不能超过gaslimit限制)。所以当各个交易平台有利差的时候可以进行套利(无风险套利),避免了准备大量资金。

基于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固定的参数拼接数据。

注意事项

  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固定的参数拼接数据。

注意事项

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

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 51分钟前
  • 阅读 ( 11 )
  • 学分 ( 0 )
  • 分类:Solidity

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK