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

xyz*_*xyz 6 python cryptocurrency web3py uniswap

我想计算 Uniswap v3 中特定池中锁定的总价值。我无法为此使用子图 API。

在此输入图像描述

我可以使用 uniswapV3pool 合约函数获取当前流动性/范围内流动性:

in_range_liquidity = uniswapV3pool_contract.functions.liquidity().call()
Run Code Online (Sandbox Code Playgroud)

我得到了流动性的结果10608850786221311055。我是否需要对其进行处理才能获得美元价值或其他值?

最后,这只是当前的流动性,我需要总锁定价值,其中包括池中的活跃和不活跃流动性。

kfx*_*kfx 7

Uniswap v3 池中锁定的总价值并不总是容易获得。流动性本身并不能很好地衡量池中实际代币数量。Uniswap v3 流动性描述的是虚拟代币数量的集中流动性价值,而不是实际数量。

balanceOf作为最简单的选择,您可以通过调用矿池合约上的函数来获取链上金额:

balanceToken0 = poolContract.functions.balanceOf(token0Address).call()
Run Code Online (Sandbox Code Playgroud)

该价值还包括无人认领的费用。在 Uniswap v3 中,这些费用不属于流动性的一部分。如果您想获得有助于流动性的代币金额,那么调用balanceOf是不够的。它为您提供了两种不同的链上计算选项:

a) 以非零流动性迭代所有价格变动范围。

b) 迭代所有未平仓头寸。

接下来是一些实现方法 (a) 的快速且未优化的 Python 代码。它需要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
Run Code Online (Sandbox Code Playgroud)

tickSpacing()TICK_SPACING 的值可以从矿池合约的函数中读取。或者,如果您知道矿池的掉期费用水平,则可以使用常数:1% 的矿池始终以 200 作为刻度间隔,等等。

MIN_TICK 和 MAX_TICK 的值可以通过 tickBitmap()调用并分别查看最低和最高初始化刻度来获得。它非常复杂,更适合单独的问题。在最坏的情况下,您可能需要覆盖整个刻度范围,即 -887272 到 +887272 之间。因此,首先您可以使用这些值向下/向上舍入到刻度间距值。

编辑:的平方根1.0001 ^ tick等于 1.0001 ^ (tick / 2),在这些行中使用这一事实可以使计算变得简单:

sqrtPriceLow = 1.0001 ** (tick // 2)
sqrtPriceHigh = 1.0001 ** ((tick + TICK_SPACING) // 2)
Run Code Online (Sandbox Code Playgroud)