【问题标题】:How to calculate Uniswap v3 pool's Total Value Locked (TVL) on chain?如何计算 Uniswap v3 矿池在链上的总锁定价值(TVL)?
【发布时间】:2022-11-18 18:46:07
【问题描述】:

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

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

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

我得到了流动性的结果10608850786221311055。我是否需要处理它以获得美元价值或其他东西?

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

【问题讨论】:

    标签: python cryptocurrency web3py uniswap


    【解决方案1】:

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

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

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

    该值还将包括无人认领的费用。在 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
    

    TICK_SPACING 的值可以从矿池合约的 tickSpacing() 函数中读取。或者,如果您知道矿池的隔夜利息水平,您可以使用一个常量: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)
    

    【讨论】:

    • 如何获取MIN_TICKMAX_TICKTICK_SPACING 的值
    • @AtiqGauri 我扩展了答案
    • MIN_TICK 和 MAX_TICK 作为 -887272 和 +887272 将永远计算上述脚本,并且在 web3 调用方面非常昂贵。如果我提出另一个关于如何获得所有非零刻度范围的问题,那么你能帮我回答吗?多谢,伙计!
    • kfx TVL的定义是什么,有官方说的吗?是代币数量乘以它们的价格还是其他?
    猜你喜欢
    • 2022-10-18
    • 2021-02-16
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多