How to get all tick ranges with non-zero liquidity to finally calculate Total Value Locked Uniswap V3?

Question:

The aim is to calculate the uniswap v3 pool’s total value locked (TVL).

import json
from web3 import Web3
from collections import namedtuple

infura_url = 'https://mainnet.infura.io/v3/******'
web3 = Web3(Web3.HTTPProvider(infura_url))

def read_json_file(directory:str, file_name: str):
    try:
        file_path = directory + file_name
        f_ = open(file_path, 'r')
    except Exception as e:
        print(f"Unable to open the {file_path} file")
        raise e
    else:
        json_data = json.loads(f_.read())
    return json_data

# uniswap_ETH_USDT.v3
abi = read_json_file('./', 'abis/uniswapV3Pool.json')
address = '0x4e68Ccd3E89f51C3074ca5072bbAC773960dFa36'
exchange_contract = web3.eth.contract(address=Web3.toChecksumAddress(address), abi=abi)

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

amounts0 = 0
amounts1 = 0
liquidity = 0
slot0 = exchange_contract.functions.slot0().call()
sqrtPriceCurrent = slot0[0] / (1 << 96)
MIN_TICK = -887272
MAX_TICK = 887272
TICK_SPACING = exchange_contract.functions.tickSpacing().call()


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(*exchange_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, tick) # for better output, should correct for the amount of decimals before printing

This does print liquidity in MIN_TICK and MAX_TICK but takes a lot of time and waste web3 calls as it is iterating on zero liquidity ticks also. Right now these are hardcoded, here I want to know what can be the value of min-max so that range does not contain any zero liquidity tick.

Asked By: AtiqGauri

||

Answers:

No offense but you are following a hard way, which needs to use TickBitmap to get the next initialized tick (Remember not all ticks are initialized unless necessary.)

Alternatively the easy way to get a pool’s TVL is to query Uniswap V3’s subgraph: like

{
  pool(id: "0x4e68ccd3e89f51c3074ca5072bbac773960dfa36") {
    id
    token0 {symbol}
    totalValueLockedToken0
    token1 {symbol}
    totalValueLockedToken1
  }
}

(for some reason it doesn’t show result if you put checksum address)

or

{
  pools(first: 5) {
    id
    token0 {symbol}
    totalValueLockedToken0
    token1 {symbol}
    totalValueLockedToken1
  }
}
Answered By: Bing
  • Getting pair token balance of contracts

web3.eth.contract(address=token_address,abi=abi).functions.balanceOf(contract_address).call()

  • and then get current price of each token / USDT by calling function slot0 in pool tokenA/USDT & tokenB/USDT

slot0 = contract.functions.slot0().call()

sqrtPriceCurrent = slot0[0] / (1 << 96)

priceCurrent = sqrtPriceCurrent ** 2

decimal_diff = USDT_decimal – TOKEN_A_decimal

token_price = 10**(-decimal_diff)/( priceCurrent) if token0_address == USDT_address else priceCurrent/(10**decimal_diff)

  • Finally, TVL = sum(token_balance * token_price)

** Remember: check price from big pool

Answered By: Hiep Ho