Uniswap介绍
介绍
引用官方文档的定义
The Uniswap protocol is a peer-to-peer system designed for exchanging cryptocurrencies (ERC-20 Tokens) on the Ethereum blockchain. The protocol is implemented as a set of persistent, non-upgradable smart contracts; designed to prioritize censorship resistance, security, self-custody, and to function without any trusted intermediaries who may selectively restrict access.
Uniswap是一个点对点的去中心化加密货币(或者说是符合ERC20协议的货币)交易系统,用户能使用这个交易所自由地完成各种ERC20 token之间或ETH的兑换。
发展历程
Uniswap想法诞生:2017年6月22日,Vitalik发表文章《On Path Independence》
Uniswap创世人登场:2017年7月6日,Hayden Adams被西门子解雇,在其朋友Karl Floersch的影响下开始关注以太坊,并学习智能合约开发。
Uniswap-v1面世:2018年,在Hayden Adams与以太坊有关的人士讨论不断完善并在自身努力下,Uniswap-v1版本于11月2日部署到以太坊主网。
Uniswap的发展:自2020年后,Uniswap逐渐推出新的版本从v2到如今处于开发中的v4版本。Uniswap已经成为以太坊上交易量最大的DEX之一。
人物介绍:Hayden Adams ,是 Uniswap 的创始人之一,也是该项目的重要推动者和领导者。Adams 在加利福尼亚州长大,拥有工程和计算机科学的背景。
Adams 在2018年创建了 Uniswap,并在其初期的开发过程中积极参与。他在设计 Uniswap 时采用了自动化市场制造商(AMM)的概念,使得任何人都可以提供流动性,并从交易费中获取收益,而无需依赖传统的市场制造商或中介。
随着 Uniswap 的发展壮大,Adams 的领导和技术指导成为了项目成功的重要因素之一。他致力于推动项目的不断创新和发展,并与团队合作,不断改进 Uniswap 协议,以满足用户和市场的需求。
Adams 的努力和才华使得 Uniswap 成为了全球范围内 DeFi 生态系统中最重要和受欢迎的项目之一,同时也为加密货币和区块链技术的发展做出了重要贡献。
(人物介绍由ChatGPT生成,详细的人物故事和Uniswap的诞生过程可参考《A Short History of Uniswap》)
Uniswap-v1原理
自动做市商(automated market makers,AMM)
在上述Uniswap的发展历程中中介绍到其设计灵感来源于《On Path Independence》,该文章描述了链上做市商的方式——即,AMM。
AMM是组成DeFi生态系统的一部分,它以一个简单的数学公式(恒定乘积公式,Constant Product Formula)为核心实现无许可和自动化的数字资产交易。
流动性(Liquidity):在AMM中的流动性是指将一种资产转化为另一种资产,这里资产可以是以太坊上的erc20代币
流动性提供者(Liquidity Provider,LP):LP也可认为是做市商,LP一般会为添加一对代币池子以供交易。LP可以通过向交易者收交易手续费,作为无偿损失的补偿。
恒定乘积公式
恒定乘积公式:x*y = k
- x和y代表流动性池中的token的总量
- 不管交易怎样变化,市场始终无法脱离这条曲线
- 交易失去token和获得token只与交易前后的状态有关,与交易价格变化路径无关
通过恒定乘积公式我们能计算交易者swap买卖一种token获得另一种token的数量、LP为流动性池子添加流动性和移除流动性获得的Share
这里的share是指实现AMM的合约发行的token,这个token也可以理解为LP为池子的流动性量化体现。计算:share = √ ( x * y ) = √ k。
LP可以通过添加流动性mint share,通过移除流动性burn share
LP取回池中的一定数量的token对(使用移除流动性方法),需要通过恒定乘积公式去burn一定数量的share
添加流动性
LP向池中添加流动性,根据添加token对x与y的数量去计算需要mint的share数量。我们需要保证添加流动性时,池中价格保持不变,即p(添加前) = x/y 等于p(移除后) (x+dx)/(y+dy)
交易
不管交易者在池中买卖token多少token,始终满足x * y = k。我们可以通过该公式计算卖dx计算得到dy
移除流动性
当LP想要拿回池中的token对时,需要移除池中的流动性。我们需要确保移除流动时保持价格不变,即p(移除前) = x/y 等于p(移除后) (x-dx)/(y-dy)
Uniswap-v1代码
Uniswap v1使用vyper语言编写,这里我将使用solidity重构Uniswap的代码对其进行分析
v1的代码有两部分:Exchange和Factory
Exchange:Token和ETH代币对,相当与一个池子,能进行添加、移除流动性和uniswap
Factory:用与创建新的Toekn与ETH的代币对,也可以查询代币对对应的Exchange
Exchange
exchange实现了ERC20标准,该合约通过添加ETH和Token流动性铸造代币,移除流动性销毁代币以获得ETH和Token。(合约铸造铸造代币下文成为LPT)此外合约提供了ETH与Token的代币兑换、Token与ETH的代币兑换、Token与ETH的价格和Token与另一种Token的兑换等方法
添加/移除流动性
addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline)
向资金池添加流动性
- min_liquidity:用户期望获得最小的LP代币,如果铸造代币过少交易会回滚
- max_tokens:用户提供的最大Token数量,如果计算出花费Token大于这个值交易会回滚
- deadline:交易确认时间,交易超过该时限会回滚
代码逻辑:
- 检查时限是否超过
- 用户添加ETH和Token数量不能为零
- 添加流动性有两种情况:
- 添加流动性:通过添加流动性公式计算出花费Token的数量和能铸造出的LPT,如果花费Token数量大于max_tokens或能铸造出的LPT小于min_liquidity就需要回滚交易
- 添加初始流动性:池子最初价格有该笔交易决定,铸造的LPT与转移的ETH数量一致,添加的Token数量等于max_tokens
- 需要将token转移到合约地址(transferFrom)
1 | function addLiquidity( |
removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline)
向资金池移除流动性
- amount:想要销毁LPT数量
- min_eth:用户最少能取出的ETH数量,如果能取出的最小ETH小于该值,交易会回滚
- min_tokens:用户最少能取出的Token数量,如果能取出的最小Token小于该值,交易会回滚
- deadline:交易确认时间,交易超过该时限会回滚
代码逻辑与添加流动性类似
- 检查输入参数是否满足条件,amount,min_eth,min_tokens大于零,当前时间没有时限。
- 计算给定销毁shares能够取出多少Token和ETH
- 检查取出的Token和Eth是否满足最小期望
1 | function removeLiquidity( |
价格查询
基础
getInputPrice(uint256 input_amount, uint256 input_reserve, uint256 output_reserve) -> uint256
1 | function getInputPrice( |
getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256
1 | function getOutputPrice( |
以上面两个函数为基础得到计算eth与toekn之间的价格
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数量
兑换
exchange的其他函数包括有:ETH与Token的兑换、Token与ETH的兑换、Token与Token之间的兑换
代码通过内部ethToTokenInput
、ethToTokenOutput
、tokenToEthOutput
等函数兑换逻辑,一般先获得可以买/卖的代币/eth数量,确认能获得预期数量的token/eth,然后进行转账交易.
这里粗滤介绍下v1代码功能,因为v1使用的人太少加之v1是最早的版本,具体的操作和测试留到v2进行。关于代码具体细节可以看源码,或者重构的代码。
ETH与Token的兑换
ethToTokenSwapInput
ethToTokenTransferInput
ethToTokenOutput
ethToTokenSwapOutput
Token与ETH的兑换
tokenToEthSwapInput
tokenToEthTransferInput
tokenToEthSwapOutput
tokenToEthTransferOutput
Token与Token之间的兑换
tokenToTokenSwapInput
tokenToTokenTransferInput
tokenToTokenSwapOutput
tokenToTokenTransferOutput
tokenToExchangeSwapInput
tokenToExchangeTransferInput
tokenToExchangeSwapOutput
tokenToExchangeTransferOutput
Factory
factory通过createExchange创建exchange,一个代币创建一个exchange
1 | function createExchange(address token) public returns(address) { |
参考资料
梁培利的个人空间-梁培利个人主页-哔哩哔哩视频 (bilibili.com)
Uniswap V1 原理与源码解析: https://juejin.cn/post/7172903744147980325
Uniswap源码仓库:https://github.com/Uniswap/v1-contracts