uniswap v1原理

简介:

Uniswap 本质上是一个主动的买卖所,能够主动地和用户交互并兑换ETH和ERC-20代币,兑换比例的承认(即价格)采用恒定乘积主动做市体系(constant-product automated market maker),也便是说,买卖所资金池内的ETH和ERC-20代币数量的乘积整体是恒定的。

DeFi领域最具影响力的创新之一是主动化做市商(AMM), 同时AMM也是去中心化买卖所(DEX)最为要害的技术之一。Uniswap爆发式增长,迅速成长为DeFi龙头,v1版别作为一个概念验证版别,代码也最简略,最适合入门,下面介绍v1

主动化做市商

流动性供给者

经过智能合约完结市商功用,流动性供给者将持有的资产存入智能合约,合约依照预先设定的规则与买卖双方完结买卖,并将买卖手续费付出给流动性供给者

任何人都能够在uniswap上创立流动池,一个流动池由一个代币对构成。

假如你有一个项目发行了R代币,你就能够创立ETH/R的TokenPair为你的代币供给流动性。价格便是根据你供给两种代币的数量比值承认的。

假如你供给10个ETH,1000个R,那么中心价便是1R=0.01ETH.

可是价格不是原封不动的,他是需求反映供需联系的。当R添加时,他的价格就会下降。

怎样核算的呢?

恒定乘积公式: x × y=k (x和y分别是两种代币的储备量,买卖时保持k不变。)

A0EF87FAFFA49E8B4C60718A0A3B8F83.png

假如交流2个ETH:

IMG_9463.JPG

也便是说需求存入250个R。

再看下面三个公式:

6F44B095C95379A8D92F83AF1FE45817.png

中心价和履行价是不一样的,称作滑点。买卖前后中心价变高了,这是反映了市场的供需联系。而且根据曲线看是不会出现流动性枯竭的,两种代币的储备是不会变成0的,跟着储备量削减,价格会急剧上升。

除了流动性供给者(也便是上面那种状况),还有流动性添加者能够添加流动性

流动性添加者

流动性添加者,也称为做市商。以R-ETH的池子为例,做市商往池子里添加这两种币种,并取得LP Token(做市凭证)。当他们取消做市的时候,把LP Token换成DAI和ETH,并同时取得做市期间取得的买卖手续费。

在做市商供给了流动性今后,用户就能够和这个池子进行买卖了,能够选择把DAI换成ETH,也能够把ETH换成DAI。买卖的过程中,需求给流动性供给者付出手续费,现在是收取付出币种的0.3%。

Uniswap V1存在的问题:

1.不能直接创立两种ERC20代币的流动性池,只能创立ETH和ERC20代币的流动性池.这样两种ERC20代币就不能直接兑换,需求经过ETH转化。

2.在实践的运行过程中,受制于以太坊吞吐量和速度的问题,Uniswap也遭遇过价格操作的状况。

Uniswap V1源码解析

代码仓库:bengda233/uniswap-v1-contracts: 🐍Uniswap V1 smart contracts (github.com)

Uniswap V1是用Vyper言语进行开发的,Vyper是一种语法和Python非常挨近的言语。

V1的体系分为两个部分:
Exchange: 用于进行ETH和ERC-20代币之间的兑换。
Factory:用于创立和记录一切的Exchange,也用于查询代币对应的Exchange。

Exchange

exchange里一切办法的合集:

  • setup(token_addr: address) 结构函数,可是现在部署不支持运用,因为exchange合约在factory里结构
  • addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256 向资金池中添加流动性。

流程:
1.用户调用该办法并发送一定量的ETH

2.Uniswap经过比较发送的ETH量和池子中的ETH数量,核算用户需求发送的代币数量,并将该数量从用户转给自己(因为Uniswap Exchange要求用户依照当时资金池中的ETH和代币的比例添加流动性)
需求存入的token数量= 存入的ETH数量 * 当时池子总token数量 / 当时池子中ETH数量(未更新) + 1

  1. 向用户发放LP(Liquidity Pool)代币,其数量为AmountLPToken(证明用户确实供给了流动性及用户流动性所占的比例)
    用户拿到的LP数量 = 存入的ETH数量 * 总LP数量 / 当时池子中ETH数量(未更新)

因为Uniswap去中心化的特性,添加流动性的买卖发出时和承认时流动性池的兑换比例(或者说价格)可能不同。为了避免这个问题给用户造成的丢失,addLiquidity函数供给了三个参数进行控制:

min_liquidity:用户期望的LP代币数量。假如终究产生的LP代币数量过少,则买卖会回滚避免丢失。
max_tokens:用户想要供给的最大代币量。假如核算得出的代币数量大于这个参数,代表用户不愿意供给更多代币,买卖也会回滚。
deadline:时限。假如买卖承认的区块时刻大于deadline,也会回滚。

  • removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256): 取回流动性

流程:
1.用户输入想要取出的LP数量

2.uniswap核算回来的ETH数量和token数量
回来ETH数量= 想要取出的LP数量* 当时池里ETH数量 / 总LP数量
回来token数量 = 想要取出的LP数量* 当时池里token数量 / 总LP数量

3.检查是否大于用户的期望值,是就返给用户,否就回滚

  • getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) 准确指定换入(input)值,承认池子中输入单位和输出单位存量时,准确的输入数量能换出输出数量。

image.png

输入的0.3%作为买卖费用,剩下的进入池子。以此来算出能够兑换的Output.

  • getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:承认输入品种、输出品种以及输出金额。核算办法为:

image.png

uniswap供给的四个价格查询的函数:

  • getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256: 输入要卖出的ETH数量,回来能得到的token数量
  • getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei):输入要买的token数量,回来需求给出的ETH数量
  • getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei):输入要卖的token数量,回来得到的token数量
  • getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256输入得到的ETH数量,回来需求的token数量

Eth与代币间的互换:
来看内部完结的四个函数

ethToTokenInput:经过准确的ETH输入量eth_sold 核算价格并交流代币。经过getInputPrice核算输出的代币数量。相同包含了min_tokens最小代币输出量和deadline的时刻约束。
ethToTokenOutput:经过准确的代币输出量tokens_bought 核算价格并交流代币。经过getOutputPrice核算输入的ETH数量,并可能在ETH需求量小于用户发送量时产生Refund。相同包含了min_tokens最小代币输出量和deadline的时刻约束。
tokenToEthInput:与上同理
tokenToEthOutput:与上同理

用ETH以兑换代币的四个办法

  • ethToTokenSwapInput
  • ethToTokenTransferInput
  • ethToTokenOutput
  • ethToTokenSwapOutput

swap与transfer的区别是:swap的接收者为调用者自己,而transfer的调用者能够恣意指定。

用token对换ETH的四个办法

  • tokenToEthSwapInput
  • tokenToEthTransferInput
  • tokenToEthSwapOutput
  • tokenToEthTransferOutput

代币之间互换

  • tokenToTokenInput 输入卖出的token数量,要买入别的的token的exchange合约地址和最小预期值 得到能买入的数量。
    先算出能够买入的ETH数量,再用这个ETH去别的的token的exchange合约买token。

  • tokenToTokenOutput输入想要买入的token数量,要买入别的的token的exchange合约地址和最小预期值 得到需求卖出的数量。
    先算出需求的ETH数量,再根据ETH数量回来需求的token数量。

用token对换token的四个办法

  • tokenToTokenSwapInput
  • tokenToTokenTransferInput
  • tokenToTokenSwapOutput
  • tokenToTokenTransferOutput
  • tokenToExchangeSwapInput
  • tokenToExchangeTransferInput
  • tokenToExchangeSwapOutput
  • tokenToExchangeTransferOutput

上面四个和下面四个的区别在于上面的是输入需求对换token的地址,下面是输入对换token的exchange合约地址

Factory

Factory里一切办法的合集:

initializeFactory(template: address):初始化Factory,只要创立时被调用。template是链上部署的合约,用于作为后续创立的Exchange的模板。

createExchange(token: address) -> address:根据template模板和token地址创立一个新的Exchange,并回来合约地址。随后调用新创立的Exchange的setup函数设置代币地址,并将新创立的Exchange记录在合约内。

留意:在做验证的过程中,函数约束每一个代币只能对应一个Exchange,这是为了约束某个代币的一切流动性都划分在一个池子中,添加池子中对应的存储量,下降买卖的滑点。

参阅:
DeFi | Uniswap V1原理解析 – 知乎 (zhihu.com)
DeFi发展史:Uniswap V1 源码阅读和剖析 | Hexo (iondex.github.io)