Flash Loan套利程序开发教程(二)

Stella981
• 阅读 893

前一个教程中,我们介绍了套利机器人背后的三个主要概念:套利、基于合约的交易和乐观转账。在本文中,我们将逐步介绍如何利用nodejs和solidity构建套利机器人程序,以监视uniswap和sushiswap上的潜在套利机会并执行有利可图的套利交易。

用自己熟悉的语言学习 以太坊DApp开发Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

下面是我们的套利机器人的总体流程: Flash Loan套利程序开发教程(二)

  1. 机器人程序/Bot跟踪Uniswap和Sushiswap上的交易对
  2. 当发现有利可图的套利机会时,套利机器人将交易发送给我们已部署的合约
  3. 在一个交易中,合约将执行如下操作:
    • 使用闪电兑换从价格较低的资产池借入资产
    • 立即在价格较高的资产池售出资产
    • 偿还闪电兑换贷款并收获差额利润

1、DEX套利机器人使用的技术栈

教程中使用的技术栈如下:

  • Node.js:基础运行环境
  • Ethers.js:以太坊JS开发库
  • Infura:提供以太坊接入访问点
  • Solidity:套利智能合约

后端采用Node开发,使用Infura节点来跟踪Uniswap和Sushiswap合约中ETH和Dai的价格。我们利用Infura端点来获取主网上产出的每个新区块上的价格。

我们之所以使用Ethers.js,是因为它与Typescript(项目的原始语言)兼容。对于以太坊开发人员来说这是一个古老的问题,但有关ethers.js和web3.js之间的区别,请参阅这篇文章

2、使用.env保存套利机器人的敏感信息

这是非常重要的!由于需要存储私钥来签署主网交易,我们将所有敏感信息都放在.env文件中,此外,套利合约的地址和Infura主网端点的key也存入该文件:

PRIVATE_KEY=
FLASH_LOANER=
INFURA_KEY=

确保PRIVATE_KEY与部署FLASH_LOANER合约时使用的账号相同。另外,与PRIVATE_KEY对应的以太坊账号需要有足够的资金来支付GAS成本。

如果你不确定我们为什么这样做,请阅读这篇文章,它解释了如何避免将私钥上传到Github。如文章所述,我们需要将敏感信息放入此.env文件中,然后将其添加到.gitignore文件中,如下所示:

.env
yarn.lock
package-lock.json
node_modules

这样,当我们将信息推送到Github时,将不包括该文件在内。这一点超级、超级重要!

3、DEX合约实例化

接下来,我们在第11行和第12行上实例化Uniswap和Sushiswap合约:

// uni/sushiswap ABIs
const UniswapV2Pair = require('./abis/IUniswapV2Pair.json');
const UniswapV2Factory = require('./abis/IUniswapV2Factory.json');

Sushiswap本质上是Uniswap的一个分支,因此它们具有完全相同的合同ABI和可供我们使用的完全相同的功能…。这也是他们适合套利的另一个原因!

4、定期检查套利机会

第50行是套利机器人的关键所在。每隔一个区块时间,我们将要求Infura检查Uniswap和Sushiswap中ETH和Dai的价格。然后,我们将比较这些数字以获得“价差”或可能的利润空间。

provider.on('block', async (blockNumber) => {
    try {
      console.log(blockNumber);
      const sushiReserves = await sushiEthDai.getReserves();
      const uniswapReserves = await uniswapEthDai.getReserves();
[...]
  }
}

5、关于提前交易/Front Running

提前交易在中心化金融交易中很常见,通常利用数据速度获取微小的优势。我们不必为此担心太多,因为Uniswap和Sushiswap是去中心化交易所。它们的价格保持在链上,并且逐块变化。

即使我们想以某种方式在网络主体之前获取信息,唯一能采取行动的方法是将交易包括在下一个区块中,这对所有人都是可见的。我们需要支付高昂的GAS费来阻止抢先交易,但这大概是最大的收益。

6、避免无法获利的交易 - GAS估算

这样的DeFi交易可能非常昂贵。虽然套利活动可能获利,但利润空间更可能被GAS成本吞噬。我们的套利机器人程序的一项重要检查就是确保GAS成本不会吃掉利润。我们执行此操作,并将其包含在shouldSendTx中:

const shouldSendTx = shouldStartEth
  ? (gasCost / ETH_TRADE) < spread
  : (gasCost / (DAI_TRADE / priceUniswap)) < spread;

对于像ETH和Dai这样常见的交易对,并没有很多的获利机会。这些交易对的交易量很大,并且Uniswap和Sushiswap是比较受欢迎的交易所。从经济角度来讲,套利机会是市场效率低下的结果。如果有很多人在使用这些货币对,那么我们不太可能找到很多机会。因此需要找到更新的代币或交易所!

7、开发套利智能合约

点击这里查看套利合约的源代码。

基本上,合约是我们的套利中介。当程序检测到有利可图的机会时,它将向该合约发送资金和交易指令。我们的套利合约相对还是比较简单的。大多数代码来自Uniswap的示例代码

合约的构造函数,可以传入一些硬编码的数据,例如Uniswap和Sushiswap的合约地址。合约还有一个函数uniswapV2Call,我们在其中以乐观方式从一个交易所借入代币,在另一个交易所执行交换,然后立即偿还第一笔借款:

pragma solidity =0.6.6;

import './UniswapV2Library.sol';
import './interfaces/IUniswapV2Router02.sol';
import './interfaces/IUniswapV2Pair.sol';
import './interfaces/IERC20.sol';

contract FlashLoaner {
  address immutable factory;
  uint constant deadline = 10 days;
  IUniswapV2Router02 immutable sushiRouter;

  constructor(address _factory, address _uniRouter, address _sushiRouter) public {
    factory = _factory;  
    sushiRouter = IUniswapV2Router02(_sushiRouter);
  }

  function uniswapV2Call(address _sender, uint _amount0, uint _amount1, bytes calldata _data) external {
      address[] memory path = new address[](2);
      uint amountToken = _amount0 == 0 ? _amount1 : _amount0;
      
      address token0 = IUniswapV2Pair(msg.sender).token0();
      address token1 = IUniswapV2Pair(msg.sender).token1();

      require(msg.sender == UniswapV2Library.pairFor(factory, token0, token1), "Unauthorized"); 
      require(_amount0 == 0 || _amount1 == 0);

      path[0] = _amount0 == 0 ? token1 : token0;
      path[1] = _amount0 == 0 ? token0 : token1;

      IERC20 token = IERC20(_amount0 == 0 ? token1 : token0);
      
      token.approve(address(sushiRouter), amountToken);

      // no need for require() check, if amount required is not sent sushiRouter will revert
      uint amountRequired = UniswapV2Library.getAmountsIn(factory, amountToken, path)[0];
      uint amountReceived = sushiRouter.swapExactTokensForTokens(amountToken, amountRequired, path, msg.sender, deadline)[1];

      // YEAHH PROFIT
      token.transfer(_sender, amountReceived - amountRequired);
    
  }
}

如果有任何利润,合约会将其发送到发起交易的地址(_sender)。

8、套利机器人教程小节

尽管此代码还不适用于生产环境,但我们希望它能说明闪电交换的基本概念,同时我们也希望它能够展示出这个仅在区块链上可能存在的简单工具的强大功能!


原文链接:闪电贷套利机器人开发教程二 — 汇智网

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
P2P技术揭秘.P2P网络技术原理与典型系统开发
Modular.Java(2009.06)\.Craig.Walls.文字版.pdf:http://www.t00y.com/file/59501950(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.t00y.com%2Ffile%2F59501950)\More.E
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这