Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Uniswap V3 释疑: 集中流动性, 无常损失和滑点

Uniswap V3 释疑: 集中流动性, 无常损失和滑点

作者头像
Tiny熊
发布于 2023-01-09 09:49:07
发布于 2023-01-09 09:49:07
2.1K01
代码可运行
举报
运行总次数:1
代码可运行

译文出自:登链翻译计划[1] 译者:songmint[2] 校对:Tiny 熊[3]

Uniswap 协议是一组原生的 ETH 的智能合约,它可以实现 ERC20 代币与 ERC20 代币的交换, 以及 ERC20 代币与 ETH 之间的的交换。

Uniswap 使用自动做市商 (AMM) 算法来执行交易。用户以代币对的形式创建流动性池子,并在其中提供流动性。执行交易就是将所提供的代币存入池中,并从池中提取所请求的代币。交易费则以被请求代币的形式, 分配给流动性提供者 (LP)。

Uniswap V3[4]是该协议的最新版本,引入了集中流动性等诸多概念。在 V3 中,根据提供流动性的风险,存在几个可用的费用等级。费用在池中的 2 种代币上收取,而不会重新投资到池中。

UNI 是 Uniswap 协议的治理代币。将来,UNI 代币持有者可能有资格获得协议费用[5]。当前的协议费率为 0%。UNI 代币持有者可以更改协议费率。

集中流动性

Uniswap V3 使用集中流动性[6] 做市算法 (CLMM),这是比标准的常数乘积做市 (CPMM) 算法更有效的算法.

每个池中有两种代币,分别是 token0 和 token1。token0 的价格 (P) 以 token1 表示。例如,UNI<>ETH 池中,每 1 个 ETH 可以兑换 100 个 UNI。

在 CLMM( 集中流动性做市算法)中,LP 必须选择合适的价格范围以提供流动性。如果价格 P 移到某个池的范围之外,该池的流动性将变为非活跃状态。交易将在下一个可用的池中进行。

在 CLMM 中,池子跟踪价格的平方根[7] (P) 和池中的流动性 (L)。此时已不再需要池中的已有代币数量用来计算兑换结果。

以下公式定义了代币数量、价格和流动性之间的关系。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# x 表示token0的数量, y 表示token1的数量
# 以token1为单位 计算出的token0的价格
P = y / x

# 流动性是代币数量的几何平方数
L = sqrt(x*y)

在 V3 中,流动性被定义为:给定平方根 P 的变化值,token1 数量的变化值。基于此概念,下面的公式可用于计算你请求的代币数量。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Δy = Δ(P) * L
Δx = Δ(1/P) * L

上述公式用于计算相邻 tick 的价格变动。其中 tick 是一个整数,可用于计算价格。tick 计算价格的公式如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
P = 1.0001^i
sqrt(P) = 1.0001^(i/2)
i = log(sqrt(P)) * 2 / log(1.0001)

每个 tick 与相邻 tick 的距离为 0.1%。如果一笔交易导致的价格变动超出了该 tick 对应的价格范围,则交易按照顺序跨越过一个个 tick, 每达到一个 tick 就进行交换,直到交易请求中的所有代币都被交换完成。

当价格处于两个 tick 之间的价格范围内时, CLMM 遵循常数乘积公式。因此 CLMM 可以被看做是常数乘积公式的变体。

下面是我编写的 python 脚本,模拟了使用 CLMM 进行交易的过程。我忽略了交易手续费,只实现了从 token1 到 token0 的交换。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

import math


def calc_tick(rp):
    # P = 1.0001 ^ i
    # sqrt(P) = 1.0001 ^ (i / 2)
    # i = log(sqrt(P)) * 2 / log(1.0001)
    return (math.log(rp) * 2) / math.log(1.0001)



def calc_sqrt_price(i):
    # sqrt(P) = 1.0001 ^ (i / 2)
    return math.pow(1.0001, i/2)




def swap(offered_y, x, y):
    delta_y = offered_y
    liquidity = math.sqrt(x * y)
    delta_sqrt_price = delta_y / liquidity
    sqrt_price = math.sqrt(y / x)
    tick_start = math.floor(calc_tick(sqrt_price))
    tick_finish = math.floor(calc_tick(sqrt_price + delta_sqrt_price))
    diff = tick_finish - tick_start
    delta_x = 0
    for tick in range(0, diff):
        # calculate the delta_sqrt_price
        tick_sqrt_price = calc_sqrt_price(tick_start + tick + 1)
        delta_sqrt_price = tick_sqrt_price - sqrt_price
        inverse_delta_sqrt_price = (1 / sqrt_price) - (1 / tick_sqrt_price)
        # check how much y is left to swap
        if delta_y - (delta_sqrt_price * liquidity) > 0:
            delta_y -= (delta_sqrt_price * liquidity)
            delta_x += (liquidity * inverse_delta_sqrt_price)
        else:
            # delta_y is exhausted for the integer value of tick
            break
    # apply the same logic for an exchange within adjacent tick
    if delta_y > 0:
        delta_sqrt_price = delta_y / liquidity
        fractional_tick = calc_tick(sqrt_price + delta_sqrt_price)
        tick_sqrt_price = calc_sqrt_price(fractional_tick)
        inverse_delta_sqrt_price = (1 / sqrt_price) - (1 / tick_sqrt_price)
        delta_x += (liquidity * inverse_delta_sqrt_price)
    return delta_x



# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    print(swap(1, 10000000, 100000))

在 V3 中,流动性池被表示为 NFT, 这是因为每个池都彼此不同。由于交易对于价格的影响, 单个交易可能需要跨越多个流动性池。

与标准常数乘积算法相比,集中流动性的效率更高。CLMM 在每个池子的价格范围内使用池子中的全部流动性。而 CPMM 将流动性分布在 0 到无穷大之间。CLMM 能做到这一点,是因为有不同的公式来计算池子的新状态(译者注:状态包含流动性,tick 值,价格等)。

价格影响

当一笔交易再次与池子进行代币交换时,池中代币的比例会发生变化。池中代币的比例是代币 0 相对于代币 1 的价格(P)。

在交换开始时,池子中的代币比例是 100UNI : 1ETH。但是直接用 1ETH 兑换是不会得到 100UNI 的,这是因为随着交换的进行,池子中的代币比例发生了变化。这称为交易的价格影响[8]

让我们以 UNI<>ETH 池子为例。当前比率为每 1 个 ETH 兑换 100 个 UNI。我们将使用 V2 中的 CPMM 公式,因为计算起来相对容易,但是依然适用于 V3。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# x and y are number of tokens
# x_uni = 10000, y_eth = 100
x_uni * y_eth = k
(x_uni - recieve) * (y_eth + deposit) = k
(10000 - receive) * (100 + 1) = 10000 * 100
receive = 10000 - (10000 * 100 / 101)
receive = 99.0099

在上面的计算中,可以看到付出 1 ETH, 可以获得 99.0099 UNI 代币。虽然池中代币的比例发生了变化,但代币数量的乘积仍然相同。

滑点

一笔交易如果提供了更高的 gas, 那么该笔交易先于其他较低 gas 的交易执行。但是我们无法预测交易执行的具体时间点。在交易广播和交易执行之间的时间间隙中,可能池子已经发生了变化。池子状态的改变可能导致交易价格与预期的价格大相径庭。这种价格变化被认为是滑点.

无常损失

流动性提供者通过提供流动性来承担风险。池中的代币比例将根据当前市场价格不断变化。套利者与流动性池进行交易,使得代币比率(就是价格)与其他更大市场中的代币比率(价格)相匹配。这种代币的再平衡对 LP 来说是有风险的。因为当他们决定从池中撤回资金时,池中会有更多已经相对贬值的代币。

举个例子,下面的示例使用 V2 的 CPMM,因为它有一个简单的公式,但 V3 的概念也相同。

Alice 和 Bob 决定了 BTC<>ETH 池的资金。我们将看到不同时间点,流动池的状态。为了计算池的状态,我们需要使用两个方程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# token_x and token_y 分别是代币的数量
# k 是常数乘积,r是代币的比率
token_x * token_y = k
token_x / token_y = r
# substituting the value of token_y
# 替换方程中的token_y,计算得到
token_x^2 / r = k
token_x = (k*r)
token_y = (k/r)

token_x = BTC, token_y = ETH

At T0 r = 1/10 初始池中状态 = 900 BTC + 9000 ETH Alice 存入 100 BTC + 1000 ETH 最终池中状态 = 1000 BTC + 10000 ETH Alice 拥有 10% 的池子份额

At T1 r = 1/8 初始池中状态 = 1118 BTC + 8944 ETH Bob 存入 80 BTC + 640 ETH 最终池中状态 = 1198 BTC + 9584 ETH Bob 拥有 6.67% 的池子份额 Alice 如今拥有 9.33%的池子份额

At T2 r = 1/5 初始池中状态 = 1515.36 BTC + 7576.8 ETH

Alice 决定提取资金 Alice 将获得整个池代币的 9.33%么,计算得到为 141.38 BTC + 706.91 ETH. 按当前价格计算,折合为 208.76 BTC. 如果 Alice 选择直接持有代币而非提供流动性,那么她将拥有 100 BTC + 1000 ETH, 按照当前价格计算,折合为 300 BTC. 所以 Alice 因为做市,实际损失了 17.24 个 BTC

最终池中状态 = 1373.98 BTC + 6869.89 ETH

Bob 拥有了 7.356%的池中份额,并且决定继续保留资金在池子中.

At T3 r = 1:8 初始池中状态 = 1086.22 BTC + 8689.76 ETH Bob 决定提取资金 Bob 将获得整个池代币的 7.356% ,计算得到为 79.9 BTC + 639.218 ETH. 按照当前价格, 折合为 159.8 BTC. (由于进位错误,我们直接看做 160 而不是 159.8) 如果 Bob 没有注入流动性,那么 他将拥有 80 BTC + 640 ETH。按照当前价格计算,折合为 160 BTC. 我们看到 Bob 并没有损失, 这是因为此时池中的代币比率相对他的存入时刻的比率, 并没有发生变化。

这就是它被称为无常损失的原因。如果池中的代币比率与你存入代币时的比率相同,将不会有任何损失。

LP 从每笔交易中收取交易费。如果 LP 收取的交易费用大于无常损失,则 LP 可以从池中提取资金,获得正收益。

原文链接:https://kushgoyal.com/uniswap-v3-expalined-concentrated-liquidity/

参考资料

[1]

登链翻译计划: https://github.com/lbc-team/Pioneer

[2]

songmint: https://learnblockchain.cn/people/13263

[3]

Tiny 熊: https://learnblockchain.cn/people/15

[4]

Uniswap V3: https://uniswap.org/blog/uniswap-v3/

[5]

协议费用: https://docs.uniswap.org/concepts/V3-overview/fees#protocol-fees

[6]

集中流动性: https://docs.uniswap.org/concepts/V3-overview/concentrated-liquidity

[7]

价格的平方根: https://uniswap.org/whitepaper-v3.pdf

[8]

价格影响: https://docs.uniswap.org/concepts/introduction/swaps#price-impact

Twitter : https://twitter.com/NUpchain Discord : https://discord.gg/pZxy3CU8mh

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
《纸上谈兵·solidity》第 25 课:简化版的去中心化交易所(DEX)简化版
孟斯特
2025/09/02
2000
《纸上谈兵·solidity》第 25 课:简化版的去中心化交易所(DEX)简化版
《纸上谈兵·solidity》第 35 课:去中心化交易所(DEX)实战 — 合约设计
下面是一个 精简但功能完整 的 DEX 实现:Token(测试代币)、LPToken、Pair、Factory、Router。所有合约基于 pragma ^0.8.20 并使用 OpenZeppelin。
孟斯特
2025/09/19
1450
《纸上谈兵·solidity》第 35 课:去中心化交易所(DEX)实战 — 合约设计
剖析DeFi交易产品之UniswapV4:Swap
Swap 可分为两种场景:单池交易和跨池交易。在 PoolManager 合约里,要完成交易流程,会涉及到 lock()、swap()、settle()、take() 四个函数。单池交易时只需要调一次 swap() 函数,而跨池交易时则需要多次调用 swap() 函数来完成。
Keegan小钢
2023/12/11
4290
剖析DeFi交易产品之UniswapV4:Swap
如何理解Uniswap v3 流动性头寸的价值
请跳到此系列文章的_part 1_[4] 和 _part 2_[5] , 您可以学习到为何 Uniswap v3 流动性代币[译者注:即头寸]为何类似于看涨期权空头和看跌期权空头[的组合,译者注]
Tiny熊
2023/01/09
1.1K0
如何理解Uniswap v3 流动性头寸的价值
Uniswap V2 学习笔记2. 交易算法
大家好, 今天继续分享 Uniswap V2 的学习心得, 今天的内容是 Uniswap[2]的交易算法
Tiny熊
2022/05/25
1.9K0
价格预言机的使用总结(三):UniswapV3篇
前面两篇文章分别讲解了 Chainlink 和 UniswapV2 的 TWAP。Chainlink 属于链下预言机,其价格源取自多个交易所,但所支持的 token 比较有限,主要适用于获取主流 token 的价格。UniswapV2 的 TWAP 则是链上预言机,可适用于获取 Uniswap 上已有的任何 token 价格,主要缺陷就是需要链下程序定时触发更新价格,存在维护成本。UniswapV3 的 TWAP 则解决了这个缺陷问题,本文就来聊聊 UniswapV3 的 TWAP 机制,以及如何正式使用。
Keegan小钢
2022/06/07
2.4K0
价格预言机的使用总结(三):UniswapV3篇
UniSwap V3协议浅析(下)
NoDelegateCall合约的主要功能是提供一个修饰器来阻止对使用修饰器修饰过的函数进行delegatecall调用,合约代码如下:
Al1ex
2021/07/21
2.5K0
UniSwap V3协议浅析(下)
剖析DeFi交易产品之Uniswap:V2上篇
在 DeFi 赛道中,DEX 无疑是最核心的一块,而 Uniswap 又是整个 DEX 领域中的龙头,如 SushiSwap、PancakeSwap 等都是 Fork 了 Uniswap 的。虽然网上关于 Uniswap 的文章已经挺多,但大多都只是从机制上进行介绍,很少谈及具体实现,也存在一些问题没能解答,比如:手续费分配是如何实现的?最优路径是如何得出的?TWAP 怎么用?注入流动性时返回多少 LP Token 是如何计算的?因此,我从代码层面去剖析 Uniswap,搞清楚这些问题,同时也对 Uniswap 从整体到细节都有所理解。
Keegan小钢
2021/08/20
1.8K0
剖析DeFi交易产品之UniswapV3:头寸管理合约
实现用户层面的流动性头寸管理的合约是 NonfungiblePositionManager 合约,其实现比较复杂,还继承了很多子合约,限于篇幅,我们无法全都一一讲解,就只能挑一些重点的来讲。
Keegan小钢
2023/11/08
6250
剖析DeFi交易产品之UniswapV3:头寸管理合约
如何把Uniswap v2作为预言机使用
Uniswap 是目前最流行的去中心化交易所,估计大家读已经了解它, 但我还是先把基础知识再过一遍。
Tiny熊
2021/02/25
1.9K0
如何把Uniswap v2作为预言机使用
Uniswap V2 源码学习 (三). 手续费和交易池估值
前面我们已经大致了解了 uniswap 的交易算法[2], 今天我们一起看看 Uniswap 手续费是怎么计算的
Tiny熊
2022/05/25
1.5K0
Uniswap V2 源码学习 (三). 手续费和交易池估值
剖析DeFi交易产品之UniswapV3:概述篇
UniswapV3 于 2021 年 5 月上线,相比 UniswapV2,改动很大,也变得复杂很多,最主要的有以下这几点改动:
Keegan小钢
2023/11/07
9250
剖析DeFi交易产品之UniswapV3:概述篇
uniswap的工作原理(下)
市场价格=池子里DAI的数量/池子里ETH的数量(P市场=X/Y)。假设市场数量趋近于无穷大,兑换价格无限趋近于X/Y
用户7976544
2020/11/14
2.7K1
uniswap的工作原理(下)
如何在合约中集成 Uniswap v3
如果你还不熟悉Uniswap[4],它是一个去中心化的交易所(DEX),依靠外部流动性提供者将代币添加到流动池配对中,用户可以直接交易这些代币。
Tiny熊
2021/06/10
2.5K0
如何在合约中集成 Uniswap v3
UniswapV2协议解析
本篇文章主要对Uniswap V2协议的工作原理、项目构成、源码实现等部分进行详细解读。
Al1ex
2021/07/21
3.7K2
UniswapV2协议解析
剖析DeFi交易产品之UniswapV4:添加/移除流动性
前一篇文章我们已经知道了创建新池子的流程,那接下来就要添加流动性了。而其实,在 PoolManager 合约里,添加和移除流动性都是在同一个函数里统一处理的。当然,要完成添加或移除流动性的全流程,会涉及到多个函数。接下来我们展开一一细说。
Keegan小钢
2023/11/30
3320
剖析DeFi交易产品之UniswapV4:添加/移除流动性
DAPP流动性矿池挖矿分红开发丨DAPP流动性矿池挖矿分红系统开发详细及逻辑丨流动性矿池挖矿系统开发方案
Smart contract:Smart contract is a program running on the ETH blockchain,which defines the logic behind the state changes on the blockchain.In abstract,smart contract is a rule that can be executed automatically.In real life,a contract needs to have a special execution role after the contract is formulated.Smart contract automates this step,and it will be executed only if the conditions specified in the smart contract are met.
系统_I8O28578624
2023/02/21
5170
LP流动性挖矿系统开发(详细讲解)丨LP流动性质押开发(逻辑分析)
core偏核心逻辑,单个swap的逻辑。periphery偏外围服务,一个个swap的基础上构建服务。单个swap,两种代币形成的交易对,俗称“池子”。每个交易对有一些基本属性:reserve0/reserve1以及total supply。reserve0/reserve1是交易对的两种代币的储存量。total supply是当前流动性代币的总量。每个交易对都对应一个流动性代币(LPT-liquidity provider token)。简单的说,LPT记录了所有流动性提供者的贡献。所有流动性代币的总和就是total supply。Uniswap协议的思想是reserve0*reserve1的乘积不变。
系统_I8O28578624
2022/12/09
1.1K0
剖析DeFi交易产品之UniswapV3:Pool合约
UniswapV3Pool 合约则复杂很多了,其引用的库合约就达到了 13 个,通过 using 方式使用的也达到了 9 个,如下所示:
Keegan小钢
2023/11/07
5220
剖析DeFi交易产品之UniswapV3:Pool合约
IDO预售代币合约系统开发技术说明及源码分析
Core逻辑实现了单个交易对的逻辑。通过UniswapV2Factory可以创建一个个Pair(交易池)。每个具体实现逻辑在UniswapV2Pair中。
DD_MrsFu123
2022/08/02
8100
推荐阅读
相关推荐
《纸上谈兵·solidity》第 25 课:简化版的去中心化交易所(DEX)简化版
更多 >
领券
一站式MCP教程库,解锁AI应用新玩法
涵盖代码开发、场景应用、自动测试全流程,助你从零构建专属AI助手
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验