一.什么是Uniswap v2
Uniswap是基于以太坊上的去中心化交易所,有v1,v2,v3三个版本。本文介绍的Uniswap v2是使用最广泛的版本,其内部以恒定乘积公式(AMM算法)模型为基础,通过流动性提供者(Liquidity Provider)提供流动性来支持币对交易,并将手续费分发给流动性提供者,用来激励更多的流动性提供者加入,支持uniswap的运行。本文将详细介绍Uniswap v2内部原理。
二.运行原理
在Uniswap V2中,交易使用的是恒定乘积公式的自动做市商模式,在一个币对的流动性池中,每次交易后,两个币种数量的乘积不会改变,保持为常数K(在实际交易中,因为存在手续费和整型精度问题的影响,交易后的K值会变大,但不会变小)
1.代币交易
假设池子中有A和B两种币组成(USDT,AAVE等),当前池子中A的数量为x,B的数量为y,两个币的乘积为k,即:x * y = k。此时,交易者使用数量为x'换取数量为y'的币,在交易前后,满足以下等式(暂时不考虑手续费):
在uniswap v2中,每次会收取0.3%的手续费,即p = 0.003,这笔手续费从交易者的x'中扣除分发给流动性提供者。因此,只有x' *(1-p)的A数量来兑换y'数量的B。剩下p * x'会作为手续费被添加到池子中,此时,上面的等式会变为:
以上就是Uniswap v2中交易的计算方法,对比之下,可以看出有手续费时,用相同数量的A币,所兑换出来的B币数量会减少。并且交易者使用的x'的数量并没有变化,所以k = ( x + x') * ( y - y')这一结果略大于k = x * y的结果。即k的结果不是一成不变,会略微增长。
2.交易路由
在Uniswap中,并不是任意两种币都有对应的流动性池,如果交易者想要把USDT兑换成AAVE,但没有对应的池子(只是举例,实际当中可能存在),只有ETH/USDT,AAVE/ETH的池子。那么,交易者需先将USDT换成ETH,再使用ETH换成AAVE。Uniswap V2合约支持多池子的连锁交易,在交易时,在参数path中提供兑换链路上各个币的合约,在该例子中的顺序为USDT->ETH->AAVE,智能合约会按照该顺序依次换币。交易者需在每个池子中缴纳手续费,所以交易应该避免交易的路由过长。
3.滑点
定义
滑点一般指预设成交价位与真实成交价位的偏差,恒定乘积AMM也存在滑点,一旦发生交易,池中资产的数量发生变化,资产实际的交易执行价就会发生变化,产生滑点。交易额越大,滑点越大,交易者的损失越大。
滑点有两种公式。本文介绍第二种,反映交易者成交后的损失
1.(成交平均价格 - 初始价格)/ 初始价格 => Uniswap v3
2.(成交后价格 - 初始价格)/ 初始价格 => Uniswap v1/v2
滑点的推导
- 流动性池里有两种代币(BNB,USDT),
X代表USDT在池中的数量,Y代表BNB在池中的数量。某交易者用dx数量USDT购买dy数量的BNB。
- Example
假设当前BNB/USDT的流动性池中有20个BNB和10000个USDT。此时可知道 1BNB = 500 USDT 理论上可以用250USDT换取0.5BNB,但实际上却不可以。
k = x * y = 20 * 10000
20 * 10000 = (20 - dy) * (10000 + 250)
=> dy = 0.487
表明只能用250USDT换取0.487BNB。
此时交易后的BNB价格为
250/0.487 = 513 USDT (即此时购买1个BNB需要513个USDT)
根据滑点的计算公式可知:
slippageUSDT = dx/x = 250/10000 = 2.5%
slippagebnb = (513-500)/500 = 2.6%
以上可得出:交易量dx越大,产生的滑点就越大,偏离实际价位就越大(看上面的图),然而当池中的代币存储越多,dx所带来的变化就越小,滑点变化也越小,降低了用户的交易损耗。
- 利用滑点计算TVL(池子深度)
一般池子内的锁仓量(TVL)也就是池子深度代表了项目的热度及安全性,是非常重要的数字指标,深度越小,项目越危险,实际兑换过程中,根据滑点可以迅速计算出池子TVL,作为我们投资的辅助依据。
三.Uniswap v2新特性
和 Uniswap v1相比,Uniswap v2带来了一系列改变,这些变动建立在第一个迭代引入的交换和流动性机制的基础上。
1. ERC20<=>ERC20的代币交换功能。
Uniswap V1只有ETH和其他代币(erc20)之间交换,如果需要erc20和erc20之间交换,则要以ETH作为中间代币来促进交换过程。在v2版本中,取消了这一要求,交易者可以体验erc20和erc20代币的直接交换功能,不再需要ETH作为中间介质。交易次数减少,节省了gas费。
2. Oracle (价格预言机)
-
链上预言机
在未引入Oracle时,uniswap可能存在资产的偏差阈值较大,价格更新较慢等问题。Uniswap V2使用的价格预言机称为TWAP(Time-Weighted Average Price),即时间加权平均价格。不同于chainlink预言机取自多个不同交易所的数据作为数据源,TWAP的数据源来自于Uniswap自身的交易数据,价格的计算等操作都是在链上执行的。因此,TWAP是属于链上预言机。
-
原理与计算
Uniswap V2 中的价格预言,其实就是通过两个公式计算而来。接下来我会逐步分析。
如上图可知,合约第一个区块为block 122,此时的价格和时间差都为0。所以
priceCumulative = 0。
到了block 123时,取自上个区块中最后一次交易的价格10.2,且时间差为7,所以可计算此时的
priceCumulative=10.2 * 7 = 71.4
再到下一个区块 124,去上个区块中最后一笔交易10.3,且时间差为8,可计算出此时的
priceCumulative = 71.4 + (10.3 * 8) = 153.8
block 125同理可计算出此时的
priceCumulative = 153.8 + (10.5 * 5) = 206.3
有了这个基础之后,就可以计算TWAP了。
想必大家从上图就可以清晰的知道如何计算TWAP。该图,是计算时间间隔为1小时的 TWAP,取自开始和结束时的累计价格和两个区块之间的时间戳。用两者的累计价格相减除以时间间隔即可得到这一小时内的TWAP价格了。这是TWAP 最简单的计算方式,也称为固定时间窗口的 TWAP。还有一种方式是基于滑动时间窗口来计算的(这里就不予介绍了)
-
总结
主要介绍了被广泛使用的一种链上预言机 TWAP(时间加权平均价格) ,且介绍了固定时间窗口算法的TWAP。虽然,TWAP是由 Uniswap 推出的,也有很多其他 DEX (去中心化交易所)也采用了和 Uniswap 一样的底层实现,如 SushiSwap、PancakeSwap 等,所以这些 DEX 也可以用同样的算法计算出对应的 TWAP。
但使用 UniswapV2 的TWAP,其主要缺点是需要链下程序定时触发合约中的update()函数,存在维护成本。UniswapV3 的TWAP则解决了这个问题。(下一篇会介绍)
3. Flash Swaps(闪电交换)
-
实现原理
-
借贷方先向合约借贷x,y token中的一个(或者两个都借贷)
-
借贷方指定借贷的数量,以及回调函数的参数,调用flashswap方法
-
合约会先将用户请求借贷的token按照指定数量发给借贷方
-
发送完毕后,Uniswap Pair合约会向借贷方指定的合约的地址调用指定的回调函数,并将回调函数的参数传入
-
调用完成后,Uniswap Pair合约检查x,y token是否满足恒定乘积公式
以上过程中都发送在同一个交易中。
-
举例
假设有200个tokenA,1000tokenB。用户想要200个tokenB,此时他可以不用预先支付40tokenA而得到B。用户可以先向合约借贷200tokenB,再去其他defi平台上使用200个tokenB换取60个tokenA,最后将获得的60个tokenA中40个还给流动性池中。这样,流动性池中的token数量不仅没有变化,用户还从中获利。
-
总结
flashswap 可以用来进行 AMM 之间套利,借贷平台清算等操作。flash swap 类似于一个功能更强的闪电贷,一个接口即可完成借贷和交易的操作。flashswap是defi颠覆性操作之一,改变了传统金融借贷和交易的复杂性。也是uniswap这么多年屹立不倒的主要原因之一。
参考文章:什么是flashswap
参考文章:价格预言机的使用总结