Calculate Pool Metrics

Calculate key performance indicators for liquidity pools.

Quick Start

// Get pool and calculate basic metrics
const pool = await sdk.Pool.getPool(poolId)

// Current price
const price = TickMath.sqrtPriceX64ToPrice(
  pool.current_sqrt_price,
  9,  // decimalsA
  6   // decimalsB
)

// TVL in tokens
const tvlA = Number(pool.coinAmountA) / 10**9
const tvlB = Number(pool.coinAmountB) / 10**6

console.log({
  price: price.toFixed(4),
  tvlSUI: tvlA,
  tvlUSDC: tvlB
})

Price Calculations

Current Price

import { TickMath } from '@ferra-labs/clmm'

// From sqrt price
const price = TickMath.sqrtPriceX64ToPrice(
  pool.current_sqrt_price,
  pool.coinTypeA.decimals,
  pool.coinTypeB.decimals
)

// From tick index
const priceFromTick = TickMath.tickIndexToPrice(
  pool.current_tick_index,
  decimalsA,
  decimalsB
)

Price Range

// Get min/max prices for a position
const position = await sdk.Position.getPositionById(positionId)

const minPrice = TickMath.tickIndexToPrice(
  position.tick_lower_index,
  decimalsA,
  decimalsB
)

const maxPrice = TickMath.tickIndexToPrice(
  position.tick_upper_index,
  decimalsA,
  decimalsB
)

console.log(`Price range: ${minPrice} - ${maxPrice}`)

TVL Calculation

Pool TVL

async function calculatePoolTVL(pool: Pool, priceInUSD: number) {
  // Get token amounts
  const amountA = Number(pool.coinAmountA) / 10**decimalsA
  const amountB = Number(pool.coinAmountB) / 10**decimalsB
  
  // Calculate USD values (assuming token B is USD stable)
  const tvlB_USD = amountB
  const tvlA_USD = amountA * priceInUSD
  
  const totalTVL = tvlA_USD + tvlB_USD
  
  return {
    tvl: totalTVL,
    breakdown: {
      tokenA: { amount: amountA, usd: tvlA_USD },
      tokenB: { amount: amountB, usd: tvlB_USD }
    }
  }
}

Position Value

async function calculatePositionValue(positionId: string) {
  const position = await sdk.Position.getPositionById(positionId)
  const pool = await sdk.Pool.getPool(position.pool)
  
  // Get token amounts from liquidity
  const amounts = ClmmPoolUtil.getCoinAmountFromLiquidity(
    new BN(pool.current_sqrt_price),
    position.tick_lower_index,
    position.tick_upper_index,
    new BN(position.liquidity),
    false
  )
  
  const valueA = Number(amounts.coinA) / 10**decimalsA
  const valueB = Number(amounts.coinB) / 10**decimalsB
  
  return { valueA, valueB }
}

APR Calculations

Fee APR

async function calculateFeeAPR(poolId: string, period = 7) {
  // Get historical fees (from your API/indexer)
  const historicalFees = await getPoolFees(poolId, period)
  
  // Get current TVL
  const pool = await sdk.Pool.getPool(poolId)
  const tvl = await calculatePoolTVL(pool, currentPrice)
  
  // Calculate daily average
  const avgDailyFees = historicalFees.total / period
  
  // Annualize
  const annualFees = avgDailyFees * 365
  const feeAPR = (annualFees / tvl.tvl) * 100
  
  return feeAPR
}

Total APR with Rewards

async function calculateTotalAPR(poolId: string) {
  // Fee APR
  const feeAPR = await calculateFeeAPR(poolId)
  
  // Reward APR
  const emissions = await sdk.Rewarder.emissionsEveryDay(poolId)
  const pool = await sdk.Pool.getPool(poolId)
  const tvl = await calculatePoolTVL(pool, currentPrice)
  
  let rewardAPR = 0
  if (emissions) {
    emissions.forEach(emission => {
      const yearlyEmissions = emission.emissions * 365
      const emissionValueUSD = yearlyEmissions * tokenPriceUSD
      rewardAPR += (emissionValueUSD / tvl.tvl) * 100
    })
  }
  
  return {
    feeAPR,
    rewardAPR,
    totalAPR: feeAPR + rewardAPR
  }
}

Volume Metrics

Estimate from Fees

function estimateVolume(fees: number, feeRate: number) {
  // Volume = Fees / Fee Rate
  const feePercent = feeRate / 1000000 // Convert from basis points
  return fees / feePercent
}

// Example: 24h volume from fees
async function get24hVolume(poolId: string) {
  const pool = await sdk.Pool.getPool(poolId)
  const feeRate = Number(pool.fee_rate)
  
  // Get 24h fees (from your data source)
  const fees24h = await get24hFees(poolId)
  
  return estimateVolume(fees24h, feeRate)
}

Price Impact

Calculate for Swap

async function calculatePriceImpact(
  pool: Pool,
  amount: BN,
  a2b: boolean,
  byAmountIn: boolean
) {
  // Get ticks for calculation
  const ticks = await sdk.Pool.fetchTicks({
    pool_id: pool.poolAddress,
    coinTypeA: pool.coinTypeA,
    coinTypeB: pool.coinTypeB
  })
  
  // Calculate swap result
  const result = sdk.Swap.calculateRates({
    currentPool: pool,
    coinTypeA: pool.coinTypeA,
    coinTypeB: pool.coinTypeB,
    decimalsA: 9,
    decimalsB: 6,
    a2b,
    byAmountIn,
    amount,
    swapTicks: ticks
  })
  
  return {
    priceImpact: result.priceImpactPct,
    effectivePrice: calculateEffectivePrice(result),
    isExceed: result.isExceed
  }
}

Liquidity Distribution

Active Liquidity

async function getActiveLiquidity(poolId: string) {
  const pool = await sdk.Pool.getPool(poolId)
  const currentTick = pool.current_tick_index
  
  // Get positions
  const positions = await sdk.Pool.getPositionList(
    pool.position_manager.positions_handle
  )
  
  // Calculate in-range liquidity
  let activeLiquidity = new BN(0)
  let totalLiquidity = new BN(0)
  
  positions.data.forEach(pos => {
    const liquidity = new BN(pos.liquidity)
    totalLiquidity = totalLiquidity.add(liquidity)
    
    if (pos.tick_lower_index <= currentTick && 
        currentTick < pos.tick_upper_index) {
      activeLiquidity = activeLiquidity.add(liquidity)
    }
  })
  
  return {
    active: activeLiquidity.toString(),
    total: totalLiquidity.toString(),
    utilization: activeLiquidity.mul(new BN(100)).div(totalLiquidity)
  }
}

Complete Example

async function getPoolMetrics(poolId: string) {
  const pool = await sdk.Pool.getPool(poolId)
  
  // 1. Price metrics
  const currentPrice = TickMath.sqrtPriceX64ToPrice(
    pool.current_sqrt_price, 9, 6
  )
  
  // 2. TVL calculation
  const tvl = await calculatePoolTVL(pool, currentPrice.toNumber())
  
  // 3. Volume (24h)
  const volume24h = await get24hVolume(poolId)
  
  // 4. APR calculation
  const apr = await calculateTotalAPR(poolId)
  
  // 5. Liquidity metrics
  const liquidity = await getActiveLiquidity(poolId)
  
  // 6. Fee tier
  const feeTier = Number(pool.fee_rate) / 10000 // basis points to percent
  
  return {
    price: currentPrice.toFixed(6),
    tvl: {
      usd: tvl.tvl.toFixed(2),
      tokenA: tvl.breakdown.tokenA,
      tokenB: tvl.breakdown.tokenB
    },
    volume24h: volume24h.toFixed(2),
    apr: {
      fee: apr.feeAPR.toFixed(2),
      rewards: apr.rewardAPR.toFixed(2),
      total: apr.totalAPR.toFixed(2)
    },
    liquidity: {
      utilization: `${liquidity.utilization}%`,
      active: liquidity.active,
      total: liquidity.total
    },
    feeTier: `${feeTier}%`
  }
}

// Usage
const metrics = await getPoolMetrics(poolId)
console.log('Pool Metrics:', metrics)

Important Notes

  • TVL calculation requires external price feeds

  • APR is estimated based on historical data

  • Volume calculation depends on fee collection data

  • Price impact varies with liquidity distribution

  • Metrics should be cached for performance

  • Consider using indexer for historical data

Last updated