本文简单介绍了部分去中心化交易所以及聚合器,并探讨了其中利用程式码可能存在的套利,从合约程式码层面分析了套利的原理,但在实际中能否成功还和诸多因素相关,如 GAS,节点速度等。
(前情提要:锁定北韩骇客?美国制裁币安用户钱包,含200万美元BTC、ETH、USDT..)
(背景补充:Tornado Cash 骇客发起「归还治理权」提案,社群气愤又无奈:被耍着玩)
本文目录
本文将分析部分去中心化交易所以及聚合器在合约程式码上可能存在的套利机会。概述
去中心化金融(英语:Decentralized finance,俗称 DeFi)是一种创建於区块链上的金融,它不依赖券商、交易所或银行等金融机构提供金融工具,而是利用区块链上的智能合约进行金融活动。在 DeFi 中存在了大量的套利机会,包括但不限於清算、差价套利。本文将分析部分去中心化交易所(DEX)以及聚合器(Aggregator)在合约程式码上可能存在的套利机会。
分析Uniswap
Uniswap 是一个采用了自动做市商(AMM)模型的去中心化的加密货币交易平台,目前有两个流行的版本,分别是 Uniswap V2 和 Uniswap V3,我们将分别分析其中可能存在的套利机会。
Uniswap V2 Router
在 Uniswap V2 中,使用者一般是通过 Router 合约与 Pair 合约以及 Factory 合约进行互动。通常来说 Router 只是会在交易中中转代币,而不会储存代币,但由於种种原因,如空投、转帐失误导致 Router 合约中储存了某些代币。那麽如何将这些代币提取出来呢?
通过分析 Uniswap V2 Router 02 合约的程式码,发现存在 removeLiquidityETHSupportingFeeOnTransferTokens 函式:
该函式用於移除其中一个代币为 WETH 的流动性,其内部呼叫 removeLiquidity 函式时传入的 to 的地址为 address (this),也就是会将两种代币先转移到 Router 合约中,然後 Router 合约再将两种代币转移到指定的地址。这里虽然转移的 WETH 的数量是 removeLiquidity 返回的,无法修改,但是转移的另一种 Token 的数量是 balanceOf (address (this)),即 Router 合约中的该代币的余额。
因此根据上述分析,我们能得到一个套利的流程:
局限性:
如果该代币之前没有和 WETH 组流动性,当第一次新增流动性时会损失一小部分流动性(MINIMUM_LIQUIDITY);
暂时未发现提取 Router 02 合约中的 WETH 和 ETH 的方法。
Uniswap V2 Pair
Uniswap V2 Pair 合约,即所谓的流动性池,储存着提供流动性的 2 种代币,因为 Pair 合约中使用的是 reserve 来记录余额而不是 balanceOf (address (this)),因此有人直接误转流动性代币到合约中时会出现 balance 和 reserve 出现差值,而 Pair 合约中存在平衡函式 skim,我们可以呼叫该函式将这差值数量的代币给提取出来:
可以看到该函式会将流动性池中两种流动性代币的 balance 和 reserve 差值数量的代币转移到 to 地址。
流动性池中除了这两种代币外,也会因为误转、空投等原因存在其他的 ERC 20 代币,如何提取这一部分的代币呢?
对 Pair 合约的程式码分析後发现无法提取这一部分代币,只有一种情况例外:当流动性池中存在该池的 LP 代币时。
出现这种情况我们可以呼叫 Pair 合约的 burn 函式,移除流动性,取出相应的两种流动性代币:
Uniswap V3 SwapRouter
Uniswap V3 的 SwapRouter 合约中也会存在和 Uniswap V2 Router 一样的情况,存在 ERC 20 代币和 ETH,但是幸运的是 SwapRouter 合约提供了几个函式可以方便提取其中的代币。
提取 ERC 20 代币我们可以使用 sweepToken 函式:
提取 ETH 我们可以使用 refundETH 函式:
也能够直接呼叫 unwrapWETH 9 函式将 WETH 还原成 ETH 并提取出来:
以上是对 Uniswap V3 SwapRouter 合约的套利分析。
在对 Uniswap V3 Pool 合约的程式码进行分析後,发现没有办法提取其合约中的其他代币,也不存在如 Uniswap V2 Pair 合约中 balance 和 reserve 有差值的情况。
SushiSwap
SushiSwap 最初是一个 Uniswap 的分叉专案,後来发展成为一个独立的生态系统,提供了许多不同的金融服务和産品。因为 SushiSwap 和 Uniswap V2 一样,因此上述的针对 Uniswap V2 的套利手段对与 SushiSwap 也同样适用。
SushiXSwap
SushiXSwap 是 SushiSwap 推出的基於 LayerZero 的全链交易协议,支援的网路包括 Optimism、Arbitrum、Fantom、BNB Chain、Polygon 和 Avalanche。使用者可以在支援的网路以及资産之间进行跨链交易。
如何提取 SushiXSwap 合约中的代币呢?
SushiXSwap 中主要的功能都通过 cook 函式实现,该函式提供了一系列的操作,支援操作列表如下:
其中有一个操作 ACTION_DST_WITHDRAW_TOKEN,其程式码实现如下:
首先将传入 cook 函式的 data 进行解码,然後判断 amount 是否等於 0 ,等於 0 则将 amount 的值设为该合约的 ERC 20 代币的余额或者 ETH 的余额。最後呼叫 _transferTokens 将代币转移到指定的地址:
因此我们只需要构造传入 cook 函式的 actions 和 datas,即将 actions 设定为 ACTION_DST_WITHDRAW_TOKEN ,在 data 中构造想要转移的代币、接收地址、数量,即可转移出 SushiXSwap 合约中的代币。
Sushi BentoBox
Sushi BentoBox 是 SushiSwap 生态系统中的一个模组。BentoBox 是一个高度灵活的去中心化金融(DeFi)利率优化産品。简单来说,它是一个允许使用者储存、借用和赚取利息的智能合约平台。BentoBox 的主要目的是优化使用者在 DeFi 领域中的收益。
以太坊上的 BentoBox 合约中储存了大量了代币,那麽该合约是否存在套利的空间呢?
在 BentoBox 合约中使用者可以通过 deposit 函式进行存款操作,函式的实现如下:
可以看到使用者传入指定的代币地址,扣款地址,接收地址,数量,股份数量,函式首先做了一系列校验,然後将 amount 或者 share 进行转换,关键点在 195 – 198 行,这里做了一个校验 :amount <= _tokenBalanceOf (token).sub (total.elastic)。
在 BentoBox 合约中某种代币的余额使用的是 total.elastic 来记录,类似 Uniswap Pair 合约中的 reserve,某些情况下会和 _tokenBalanceOf (token) 産生差值, 我们可以利用 deposit 函式这里的特性,将差值部分真实转换成自己在 BentoBox 合约中的余额。
因此我们传入引数时将 token 设定为存在差值的代币地址,将 amount 的值设定为差值,然後将 from 设定为 BentoBox 合约的地址,将 to 设定为自己的地址,在 207 行时由於地址为 BentoBox 合约地址,因此不会进行转帐,只是平衡了 total.elastic 和 _tokenBalanceOf (token) 的值,将其转换为 to 地址在合约内的余额。
DODO
DODO 是一个去中心化交易平台,使用独创的主动做市商(PMM)演算法为 Web3 资産提供高效的链上流动性。DODO 既自己提供流动性,也聚合其它交易所的流动性。
DODO 有一系列合约,其中使用者会通过 DODO V2 Proxy 02 合约进行代币的兑换。和 Uniswap Router 合约类似,该合约也会因为各种原因存在一些代币,我们应当如何提取这些代币?
DODO V2 Proxy 02
在 DODO V2 Proxy 02 合约中存在 externalSwap 函式,用来呼叫 DODO 聚合的外部平台进行兑换,如 0x , 1inch,程式码实现如下:
1719-1721 行在对传入的引数做校验,然後 1724 行校验 fromToken 是否为 ETH,不是的话则会将呼叫者的代币转移到合约中,然後进行授权,在分析了 DODOAPPROVE 合约的程式码後发现只需要将 fromTokenAmount 设定为 0 即可绕过:
然後会对呼叫的外部合约做校验,是白名单内的才能够呼叫,这里的 swapTarget,calldataConcat 都是由使用者可控的,因此可以将 swapTarget 设定为 0x 或者 1inch 的合约地址,然後 calldataConcat 设定为其合约的 view 函式的编码,从而让返回的值为 true,也能通过後面的 require 校验:
接下来会将合约中的 toToken,全部转移给呼叫者,这里的 toToken 可以是 ERC 20 代币,也可以是 ETH,传送完後会进行最小的预期数量校验,我们将 minReturnAmount 的值设定为非常小的值即可通过。最後两个函式呼叫无关紧要。
通过以上的步骤我们就能够提取出 DODO V2 Proxy 02 合约中的 ERC 20 代币以及 ETH。
1inch
1inch 是一个去中心化交易所(DEX)聚合器,它从多个 DEX 中汇集流动性,以便为使用者提供最佳的代币兑换价格。通过整合来自不同来源的流动性,1inch 帮助使用者优化交易并在各个平台之间找到最优惠的价格。1inch 的智能合约自动在各个去中心化交易所之间进行交易,使使用者能够轻松地在不同交易所之间获取最佳价格和最低滑点。此外,1inch 还提供了其他功能,如流动性挖矿和治理代币。
1inch 的主要合约是 AggregationRouter,现在使用较多的是 V 4 和 V 5 版本,这两个合约也会因为各种原因存在一些代币,我们可以通过构造的传入函式中的引数,提取合约中的代币。
AggregationRouterV 5
AggregationRouterV 5 合约存在 swap 函式,其实现如下:
校验了 desc 中的 minReturnAmount 後,从 desc 中获取 srcToken 和 dstToken,接下来 986-997 行可以通过构造 desc 结构体中的 flags 和 srcToken 进行绕过:
然後执行函式 _execute, 这里会进行 call 呼叫,并会校验执行状态,由於 executor 由使用者传入,因此这里我们可以使用 0 地址进行绕过:
然後获取合约中 dstToken 的余额。1007-1018 行我们可以构造 desc 中 flags 以及 minReturnAmount 进行绕过:
最後会将合约中的 dstToken 余额都转到 dstReceiver 地址中,该地址也由使用者控制:
通过以上的步骤,我们能构造传入 swap 函式的引数从而将 AggregationRouterV 5 合约中的代币提走。
AggregationRouterV 4
AggregationRouterV 4 与 AggregationRouterV 5 差别不大,AggregationRouterV 4 中也存在 swap 函式,实现如下:
可以发现跟 AggregationRouterV 5 的 swap 函式的实现是一样的,只是 AggregationRouterV 5 对 call 进行了优化,因此使用和 AggregationRouterV 5 一样的方法即可提取出存在 AggregationRouterV 4 合约中的代币。
总结
本文简单介绍了部分去中心化交易所以及聚合器,并探讨了其中可能存在的套利,从合约程式码层面分析了套利的原理,但在实际中能否成功还和诸多因素相关,如 GAS,节点速度等。
📍相关报导📍
传奇骇客开呛Kucoin!悬赏「100万美元」找出27万笔个资外泄,奖金仅5千
骇客谈判指南》加密资产被盗时该如何处理?
里程碑!欧盟批准加密监管法《MiCA》,币安CZ:世界最大市场拥抱Web3