这几天我写了一个DEX交易聚合器(1)

简介: 这几天我写了一个DEX交易聚合器


前言

目前,DeFi 赛道中,专门做 DEX 交易聚合的产品挺多的,以下是其中一些平台:



image.png

可以看到,这些平台都聚合了很多家 DEX,包括 AMM(自动做市商)模式的 DEX,也包括 Orderbook 模式的 DEX,主要功能都是为了将各个 DEX 的分散流动性整合到一起,提供最优的价格、最佳的深度和清晰简洁的界面。

这几天我也写了一个 DEX 交易聚合器,纯合约的。不过功能还比较简单,只聚合了 UniswapV2SushiSwap,且只实现了从这两个平台中找出最优成交价来实现每笔交易。虽然只是个简单的交易聚合器,却也接连踩了好几个坑,这也暴露出了我的一些知识盲区。下面我就分享下在这过程中的一些经验和总结。

技术调研

既然接入的是 UniswapV2SushiSwap,而且是从合约层面去接入的,所以第一步就是先要调研如何接入。

UniswapV2 的合约分为了两个项目:

  • uniswap-v2-core
  • uniswap-v2-periphery

uniswap-v2-core 的核心有三个合约:

  • UniswapV2ERC20:UNI-V2 代币合约
  • UniswapV2Factory:工厂合约
  • UniswapV2Pair:配对合约

UNI-V2 代币合约即是 LP Token 合约,工厂合约则主要用来创建配对合约,配对合约则维护着每个币对的流动性池子,另外,配对合约还继承了 UniswapV2ERC20 合约,即是说,配对合约同时也是 LP Token 合约

uniswap-v2-periphery 被称为外围,其实就是供外部接入使用的,其主要有三个合约:

  • UniswapV2Migrator:迁移合约,用来将 v1 的流动性迁移到 v2 用的
  • UniswapV2Router01:旧版的路由合约
  • UniswapV2Router02:新版的路由合约,现在都是用这个

Uniswap 前端的兑换、添加流动性等操作其实都是通过和路由合约交互完成的,所以这个路由合约也是我们的聚合交易接入 Uniswap 的入口合约。以下页面是官方文档中对 Router02 的介绍:

至于 SushiSwap,则是完全复用了 UniswapV2Router02 合约作为接入 SushiSwap 的入口,只是和 Uniswap 的合约地址不一样而已

不过,调研路由合约后发现,兑换的两个币种之间的路径,其实从是外部传入给到路由合约的。在 Uniswap 中,路径的选择算法实现是被封装在前端的 SDK 里的,但我所做的聚合器需在合约里自己完成最优路径的寻找,这成为了第一个难题。

最优路径

用户兑换时选定的两个币种 tokenA 和 tokenB,有时候并不存在直接配对的流动性池子。但是,只要存在另一个币种 tokenC,满足 tokenA 和 tokenC 存在流动性池子,tokenB 和 tokenC 也存在流动性池子,那么,只要先将 tokenA 换成 tokenC,再将 tokenC 换成 tokenB,tokenA 和 tokenB 就可以完成兑换,如此,tokenA > tokenC > tokenB 就组成了 tokenA 和 tokenB 兑换的一条路径。

这种路径可能存在不止一条,比如,也可能存在 tokenA > tokenD > tokenB,甚至 tokenA > tokenC > tokenD > tokenB。当然,如果 tokenA 和 tokenB 之间存在直接配对的流动性池子,那么 tokenA > tokenB 也是一条路径。

因为每个池子的流动性不一样,当指定币种数量后,比如指定 100 个 tokenA,那么每条路径最后兑换出来的 tokenB 数量其实也是不一样的。对用户来说,自然是希望能兑换回来的 token 数量越多越好,所以,这些路径中,那条兑换结果数量最多的就能成为最优路径

有些人可能会陷入一个误区,觉得最优路径应该是最短路径,而实际上:最短路径不一定是最优路径。比如,ETH-WBTC 其实存在直接配对的流动性池子,所以最短路径就是 ETH > WBTC,但是,在界面查询时看到匹配的最优路径却是 ETH > USDC > WBTC,请看下图:

不过,币种那么多,要如何才能高效地找到一条最优路径呢?

寻找最优路径

寻找最优路径的第一步,要先找出所有潜在路径。但是,币种那么多,不可能将所有币种都进行路径组合,尤其在合约层面,效率太低了。其实,如果看看 Uniswap 前端页面,选择代币时,可以看到列出了几种常用代币,如下图:

可以看到,这些都是最主流的代币,所有代币都是与这些代币中的一种或多种配对组成流动性池子的。因此,只要用这些代币作为路径组合的中间币种即可,而无需考虑全部代币。

另外,路径也不能太长,最长的就如 tokenA > tokenC > tokenD > tokenB 就够了。

总而言之,tokenA 兑换 tokenB 可遍历的路径包括:

  • tokenA > tokenB:只有两个代币存在直接配对的流动性池子时,该路径才有效
  • tokenA > tokenC > tokenB:tokenC 就是常用代币中的一种,要求 tokenA-tokenC 和 tokenC-tokenB 分别都存在流动性池子
  • tokenA > tokenC > tokenD > tokenB:tokenC 和 tokenD 是常用代币列表中的两种代币,要求 tokenA-tokenC、tokenC-tokenD、tokenD-tokenB 这三个配对的流动性池子是有效的

对每个有效路径读取出最后价格,对比后就知道最优路径是哪个了。

合约设计

设计上也很简单,核心的合约类图如下:


image.png


而实例关系图则如下:

Aggreswap 中保存一个 dexs 数组,用来存放所支持的 DEX,当调用 swap() 时,则遍历所有 Dex,查出具有最优价格的 Dex 并转给该 Dex 的 Handler 实例去完成兑换工作。

UniswapV2Handler 中则会保存常用代币列表 baseTokens。每次兑换时,则遍历 baseTokens,组装出每条有效路径并读取价格,从而查询出最优价格和路径,再去调用路由合约完成兑换工作。

Aggreswap 和每个 Handler 实现都统一用 ISwap 接口做交互,则具备了灵活性,而且调用方还可以根据需要绕开 Aggreswap 而与具体的 Handler 进行交互,且交互接口无需改动。

合约设计的整体思路就大致如此了,简单易理解。但具体实现时所犯过的错,我觉得很有必要分享下。


相关文章
|
安全 区块链
SOL链(Solana链)智能合约系统开发功能需求/案例设计/步骤指南/源码程序
Developing a smart contract system based on SOL chain (Solana chain) can achieve various functions and applications. The following are some common SOL chain smart contract system development features:
|
机器人 区块链
币圈Swap夹子套利搬砖机器人合约部署源码开发
mapping(address => bool) private[ isApproved ]; mapping(address => mapping(address => uint256)) private[ swapOrders ];
|
SQL Oracle 关系型数据库
使用JSqlParser 解析sql
使用JSqlParser 解析sql
3380 0
|
JavaScript 前端开发 应用服务中间件
【qkl】JavaScript连接web3钱包,实现测试网络中的 Sepolia ETH余额查询、转账功能
【区块链】JavaScript连接web3钱包,实现测试网络中的 Sepolia ETH余额查询、转账功能
969 0
|
11月前
|
JSON 搜索推荐 API
淘宝商品详情优惠券API接口全攻略
淘宝商品详情优惠券API接口助力电商精准营销。通过商品ID,开发者可精准检索与特定商品相关的优惠券信息,包括面额、使用门槛、领取条件、有效期等详细数据,并实时监测优惠券状态。此接口支持个性化筛选参数,如优惠券面额范围和类型,返回JSON格式的优惠券列表及状态信息,满足数据整合、营销活动策划等需求,提升用户体验和运营效率。示例代码展示了Python调用方法,帮助快速集成。 供稿者:Taobaoapi2014
|
自然语言处理 算法 机器人
智能电话销售机器人源码搭建部署系统电话机器人源码
智能电话销售机器人源码搭建部署系统电话机器人源码
247 4
|
存储 区块链
Solidity语言详解
Solidity语言详解
416 0
|
Java API 开发者
Spring框架在Java Web开发中的最佳实践
Spring框架在Java Web开发中的最佳实践
246 2