白皮书原版:https://uniswap.org/whitepaper.pdf
Uniswap v2 Core
Hayden Adams hayden@uniswap.org
Noah Zinsmeister noah@uniswap.org
Dan Robinsondan@paradigm.xyz
摘要
本技术白皮书说明了Uniswap v2核心合约的一些设计方案。涵盖了合约的新特性---包括任意ERC20交易对,一个硬化的价格oracle机制,允许其他合约在给定的时间间隔内估算时间加权的平均价格,“flash swaps”允许交易者在付款之前收取资产并且把它们用在别的地方,还有可以在将来被打开的协议手续费开关。V2重构了合约,减少了供给面。本白皮书描述了Uniswap v2核心合约的机制,包含存储了LP资金的pair合约和用于实例化pair合约的factory合约。
1.介绍
Uniswap v1是一个基于以太坊的智能合约链上系统,实现了一个基于“常量乘积公式”的自动流动性协议。每一对Uniswap v1都存储了两种资产的资金池,并且提供了这两种资产的流动性,维持了这两种资产池内资金乘积保持不变。交易者需要支付每笔交易0.3%的手续费,这些费用将会给流动性提供者(LP)。这个合约是不可升级的。
Uniswap v2是基于同一个公式的新实现,具有几个非常理想的新特性。最重要的是,它允许创建任意的ERC20/ERC20交易对,而不是只支持ERC20和ETH之间的交易对。它还提供了一个硬化了的价格oracle机制,在每个区块最开始累计两种资产的相对价格。这郧西以太坊上的其他合约在给定的时间间隔内估算时间加权的平均价格。最后,它支持“flash swaps”,使交易者免费获取资产并把它们用在链上的其他地方,只需要在交易的最后支付或返还资产。
虽然合约使不可以被升级的,但是有一个私钥可以更新factory合约内的变量,打开1/6手续费的开关。这个开关最开始是关闭的,也许会在以后打开,届时LP将只能收取0.25%的手续费,而不是0.3%。
在第三章会讨论到,Uniswap v2修复了Uniswap v1的很多小错误,同时重构了整个实现,减少了Uniswap的供给面,并且通过最小化核心合约中存储LP基金的逻辑,使整个系统更容易升级。
本白皮书描述了核心合约的机制,以及用于实例化合约的factory合约。实际上,使用Uniswap v2需要通过一个路由合约调用pair合约,计算交易或存款金额,并将资金转移到pair合约。
2.新特性
2.1 ERC-20对
Uniswap v1使用ETH作为资产之间的桥接。每一对pair都需要ETH作为其中一种资产。这让路由变得简单,每一次ABC和XYZ之间的交易都要通过ETH/ABC和ETH/XYZ,减少了流动性的分散。
然而,这个规则给LP增加了大量的花费。所有LP都必须接触ETH,并且需要承受ETH价格相对其他资产变动时带来的的无常形损失。当两种资产ABC和XYZ相关时----比如,如果他们都是USD稳定币---那么ABC/XYZ的LP承受的损失会少于ABC/ETH或XYZ/ETH对。
使用ETH作为强制的桥接资产同时还会增加交易者的花费。相比ABC/XYZ交易对,使用ETH最为桥接,交易者必须支付两倍的手续费,同时承受两次下滑。
Uniswap v2允许LP创建任意ERC20pair合约。
对任意ERC20pair的扩散会让找到最佳路径交易特定pair变得更难,但是更高层的路由可以解决这一点(无论是链上还是链下)
2.2 价格Oracle
Uniswap在时间t内提供的临界价格(不包含手续费)可以用资产a的池内资金除以资产b的池内资金来计算。
由于价格不正确时,套利者会在Uniswap上交易以此套利。所以Uniswap提供的价会倾向相关市场里资产的价格,如Angeris et al [2]所示。这意味着它可以用作一个近似的价格oracle。
然而,Uniswap v1作为一个链上价格oracle并不安全,因为它很容易被操控。假设其他合约使用当前的ETH-DAI价格结算一个衍生品。一个希望操控价格的攻击者可以从ETH-DAIpair购买ETH,出发衍生品合约的结算(导致它用膨胀后的价格结算),然后再将ETH卖回ETH-DAI pair,让ETH回到它真正的价格上。这些操作甚至可以发生在原子操作中,或者由一个控制了交易顺序的矿工打包在一个区块里。
Uniswap v2通过在每个区块的第一笔交易(换句话说,就是在上一个区块最后一笔交易以后)中计算和记录价格,改进了这个oracle的功能。在同一个块中,价格会变得难以操控。如果一个攻击者提交了一笔交易,在区块的最后尝试去修改价格,其他套利者可以在同一区块提交另一笔交易将价格迅速修改回来。一个矿工(或者一个可以用足够gas填充一整个区块的攻击者)还是可以操控一个block内的价格,但是除非他们能继续挖出下一个区块,否则套利的结果并没有优势。
特别地,Uniswap v2通过在每个区块第一笔与该合约交互的交易中,追踪该区块开始时的累计价格来积累这个价格。每个价格都被上一次更新的区块的时间间隔加权。这意味着任意时间点的累计价格(更新后)都是之前每一秒价格的总和。
为了估算从时间t1到时间t2的时间加权平均价格,一个外部调用者可以在t1和t2分别检查累计价格,用t2的累计价格减去t1的累计价格,然后除以t2减去t1(注意合约本身并不会记录历史的累计值,调用者需要在周期开始时自己读取和存储这个值)
该oracle的用户可以自己选择何时开始和结束这个阶段。选择较长的时间间隔会让攻击者花费更大的代价操控价格,但是会使价格更新更不及时。
一个复杂的问题是:我们应该计算A相对B的价格,还是B相对A的价格?虽然在特定的时间点,A相对B的价格永远是B相对A的价格的倒数,但是在一个期间的加权平均值却不是这样。比如,加入USD/ETH的价格在Block1时为100,Block2时为200,那么USD/ETH的平均价格则是200,但是ETH/USD的平均价格确实1/150。由于合约并不知道用户会使用哪一个资产作为计算单位,Uniswap v2会同时追踪这两个价格。
另一个复杂的问题是,有人可以将资产发送到pair合约,改变其余额和编辑价格,不需要与合约交互,因此也不会触发oracle价格的更新。如果合约只是简单的检查自己的余额并且基于当前价格更新oracle,那么一个攻击者可以通过在一个区块中第一次调用该合约之前迅速发送资产到合约地址来操控价格。如果上一笔交易是在X秒之前的去快速,那么该合约会错误的将新价格乘以X并累计它,虽然没有人有机会用该价格交易。为了防止这样的事,核心合约会在每一次交互后缓存资金池的金额,用缓存中的数字更新oracle,而不是使用当前的数字。除了保护oracle免受操纵之外,此更改还支持下面章节3.2中描述的契约重新架构。
2.2.1 精度
由于solidity对非整数数字数据类型没有很好的支持,因此Uniswap v2使用简单的二进制定点格式来编码和操纵价格。具体地说,给定时刻的价格存储为UQ112.112数字,这意味着在小数点的两边指定了112个小数位的精度,没有符号。这些数字的范围为[0,2的112次方−1],精度为1/2的112次方。
选择UQ112.112格式是出于一个实用的原因-因为这些数字可以存储在uint224中,这在uint256中留下了32位的存储槽空闲。Reserve变量每个存储在一个uint112,也留下32位在一个(打包)256位存储槽空闲。特别的,最近一次更新的区块时间戳和reserve一次存储,会用2的32次方取膜让它可以被房价32位的存储中。另外,尽管在任何给定时刻的价格(存储为UQ112.112号)被保证适合224位,但这个价格在一个间隔内的积累却不是。存储槽的末端额外的32位用于存储A/B和B/A的累计价格,用于存储重复累加价格导致的溢出位。这种设计意味着oracle在每个区块的第一次交易中只增加了额外的三个SSTORE操作(目前的成本约为1.5万gas)。
主要的缺点是32位不足以存储不会溢出的时间戳值。事实上,Unix时间戳溢出一个uint32的日期是02/07/2106。为了确保这个系统在这个日期之后继续正常运行,并且在2的32次方 - 1秒之后,oracle只需要在每个时间间隔(大约136年)至少检查一次价格。这是因为累积的核心方法(以及时间戳的修改)实际上是溢出安全的,这意味着,如果oracle使用适当的(简单的)溢出算法来计算增量,那么跨溢出区间的交易可以适当地考虑。
2.3 Flash Swaps
在Uniswap v1中,用户使用XYZ购买ABC需要将XYZ先发送给合约之后才可以收到ABC。如果用户需要购买的ABC来获得他们支付的XYZ,这是不方便的。比如,用户也许想在其他合约中用ABC去买XYZ来套利,或者他们可能通过出售抵押品来偿还Uniswap来在Maker或Compound平仓。
Uniswap v2增加了一个新特性,使用户可以在支付资产之前获取并使用使用它,只要他们可以将支付操作包含在一个原子性交易中。swap函数在转移用户请求的token和执行不变式之间调用一个可选的用户指定的回调合约。一旦回调完成,合约会检查新的余额并确定条件可以满足(扣除手续费后)。如果该合约没有足够的资金,则整个交易都会被返回。
2.4 协议手续费
。。。看不懂公式了,反正有个开关打开以后就会把手续费的1/6给feeTo地址,现在还没有打开。然后因为每次有人交易都进行手续费阶段的花会花很多gas,所以只在池子金额变化时进行结算。白皮书里给了计算累计手续费的公式但是我没看明白,感兴趣的自己去看吧。
可以再参考这个:https://blog.csdn.net/sanqima/article/details/109667469
2.5池股的元交易
由Uniswap v2对创建的池共享本身支持元事务。这意味着用户可以通过签名授权池共享的转让,而不是通过他们的地址进行链上交易。任何人都可以通过调用permit函数、支付gas费以及在同一事务中执行其他操作来代表用户提交这个签名。