简体   繁体   English

如何计算 Uniswap v3 矿池在链上的总锁定价值(TVL)?

[英]How to calculate Uniswap v3 pool's Total Value Locked (TVL) on chain?

I want to calculate the total value locked in a particular pool in Uniswap v3.我想计算锁定在 Uniswap v3 中特定池中的总价值。 I can't use the subgraph API for this.我不能为此使用子图 API。

在此处输入图像描述

I can get current liquidity / in range liquidity using uniswapV3pool contract function:我可以使用 uniswapV3pool 合约 function 获得当前流动性/范围内的流动性:

in_range_liquidity = uniswapV3pool_contract.functions.liquidity().call()

I get the result 10608850786221311055 for liquidity.我得到流动性结果10608850786221311055 Do I need to process it to get the USD value or something else?我是否需要处理它以获得美元价值或其他东西?

Finally this is just current liquidity, I need total locked value, which includes both active and inactive liquidity in the pool.最后,这只是当前流动性,我需要总锁定价值,其中包括池中的活跃和非活跃流动性。

The total value locked in Uniswap's v3 pool is not always straightforward to get.锁定在 Uniswap v3 池中的总价值并不总是那么容易获得。 The liquidity itself not a good measure of the real token amounts in the pool.流动性本身并不是衡量池中实际代币数量的好方法。 Uniswap v3 liquidity describes the concentrated liquidity value of the virtual token amounts, not the real amounts. Uniswap v3 流动性描述了虚拟代币数量的集中流动性价值,而不是实际数量。

As the simplest option, you can get the on-chain amounts by calling the balanceOf function on the pool's contract:作为最简单的选择,您可以通过调用矿池合约上的balanceOf function 来获取链上金额:

balanceToken0 = poolContract.functions.balanceOf(token0Address).call()

This value is going to also include unclaimed fees.该值还将包括无人认领的费用。 In Uniswap v3, these fees are not part of the liquidity.在 Uniswap v3 中,这些费用不属于流动性的一部分。 If you want to get the token amounts that contribute to liquidity, then a balanceOf call is not sufficient.如果您想获得有助于流动性的代币数量,那么调用balanceOf是不够的。 It leaves you with two different options for on-chain calculations:它为您提供了两种不同的链上计算选项:

a) Iterate over all tick ranges with non-zero liquidity. a) 迭代所有具有非零流动性的报价区间。

b) Iterate over all open positions. b) 遍历所有未平仓头寸。

What follows is some quick and unoptimized Python code that implements the approach (a).下面是一些快速且未优化的 Python 代码,用于实现方法 (a)。 It needs MIN_TICK , MAX_TICK , TICK_SPACING , as well as URL , POOL_ADDRESS and V3_ABI to be defined.它需要MIN_TICKMAX_TICKTICK_SPACING以及URLPOOL_ADDRESSV3_ABI

from collections import namedtuple
from web3 import Web3

web3 = Web3(Web3.HTTPProvider(URL))
pool = Web3.toChecksumAddress(POOL_ADDRESS)
contract = web3.eth.contract(address=POOL_ADDRESS, abi=V3_ABI)

Tick = namedtuple("Tick", "liquidityGross liquidityNet feeGrowthOutside0X128 feeGrowthOutside1X128 tickCumulativeOutside secondsPerLiquidityOutsideX128 secondsOutside initialized")

amounts0 = 0
amounts1 = 0
liquidity = 0
slot0 = contract.functions.slot0().call()
sqrtPriceCurrent = slot0[0] / (1 << 96)

def calculate_token0_amount(liquidity, sp, sa, sb):
    sp = max(min(sp, sb), sa)
    return liquidity * (sb - sp) / (sp * sb)

def calculate_token1_amount(liquidity, sp, sa, sb):
    sp = max(min(sp, sb), sa)
    return liquidity * (sp - sa)

for tick in range(MIN_TICK, MAX_TICK, TICK_SPACING):
  tickRange = Tick(*contract.functions.ticks(tick).call())
  liquidity += tickRange.liquidityNet
  sqrtPriceLow = 1.0001 ** (tick // 2)
  sqrtPriceHigh = 1.0001 ** ((tick + TICK_SPACING) // 2)
  amounts0 += calculate_token0_amount(liquidity, sqrtPriceCurrent, sqrtPriceLow, sqrtPriceHigh)
  amounts1 += calculate_token1_amount(liquidity, sqrtPriceCurrent, sqrtPriceLow, sqrtPriceHigh)

print(amounts0, amounts1) # for better output, should correct for the amount of decimals before printing

The value of TICK_SPACING can be read from the tickSpacing() function of the pool's contract. TICK_SPACING 的值可以从矿池合约的tickSpacing() function 中读取。 Alteratively, if you know swap fee levels of the pool, you can use a constant: 1% pools have always have 200 as the tick spacing, etc.或者,如果您知道矿池的隔夜利息水平,您可以使用一个常量:1% 的矿池总是有 200 作为刻度间隔,等等。

The values of MIN_TICK and MAX_TICK can be obtained from tickBitmap() calls and looking at the lowest and the highest initialized tick respectively. MIN_TICK 和 MAX_TICK 的值可以从tickBitmap()调用中获得,并分别查看最低和最高的初始化刻度。 It's quite complex and a better fit for a separate question.它非常复杂,更适合单独的问题。 At the worst case if you may need to cover the whole tick range, which spans between -887272 and +887272.在最坏的情况下,如果您可能需要覆盖跨度为 -887272 和 +887272 的整个刻度范围。 So for a start you can use these values rounded down / up to the tick spacing value.因此,一开始您可以使用这些值向下/向上舍入到刻度间距值。

Edit: the square root of 1.0001 ^ tick is equal to 1.0001 ^ (tick / 2), a fact that use in these lines to make the computation simples:编辑: 1.0001 ^ tick的平方根等于 1.0001 ^ (tick / 2),在这些行中使用这一事实使计算变得简单:

sqrtPriceLow = 1.0001 ** (tick // 2)
sqrtPriceHigh = 1.0001 ** ((tick + TICK_SPACING) // 2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM