DeFi:Uniswap v2协议原理解析

3,462 阅读8分钟

一.什么是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'的币,在交易前后,满足以下等式(暂时不考虑手续费):

B5E9019E2513BC7501A33F992326FD58.jpg

在uniswap v2中,每次会收取0.3%的手续费,即p = 0.003,这笔手续费从交易者的x'中扣除分发给流动性提供者。因此,只有x' *(1-p)的A数量来兑换y'数量的B。剩下p * x'会作为手续费被添加到池子中,此时,上面的等式会变为:

B32F9C99FE6064A0AF728F16B56D50A1(1).jpg

以上就是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

1474FC89E792783CAD19A98EAF042D84.jpg

  • 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使用的价格预言机称为TWAPTime-Weighted Average Price),即时间加权平均价格。不同于chainlink预言机取自多个不同交易所的数据作为数据源,TWAP的数据源来自于Uniswap自身的交易数据,价格的计算等操作都是在链上执行的。因此,TWAP是属于链上预言机。

  • 原理与计算

Uniswap V2 中的价格预言,其实就是通过两个公式计算而来。接下来我会逐步分析。

4@LBGW2Q[R91N6I7]171$LK.png

如上图可知,合约第一个区块为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()函数,存在维护成本。UniswapV3TWAP则解决了这个问题。(下一篇会介绍)

3. Flash Swaps(闪电交换)

  • 实现原理

  1. 借贷方先向合约借贷x,y token中的一个(或者两个都借贷)

  2. 借贷方指定借贷的数量,以及回调函数的参数,调用flashswap方法

  3. 合约会先将用户请求借贷的token按照指定数量发给借贷方

  4. 发送完毕后,Uniswap Pair合约会向借贷方指定的合约的地址调用指定的回调函数,并将回调函数的参数传入

  5. 调用完成后,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

参考文章:价格预言机的使用总结