Calculate Position Fees

Track accumulated trading fees across all bins in your position. Monitor fee generation and calculate your earnings from providing liquidity.

Prerequisites

  • Position ID with active liquidity

  • Understanding of fee structure

  • Pair reserves data access

Get Position Fees

// Fetch position with fee data
async function getPositionFees(
  pair: LBPair,
  positionId: string
) {
  // Get reserves including fees
  const reserves = await sdk.Pair.getPairReserves(pair);
  const positionBins = await sdk.Position.getPositionBins(pair, positionId);
  
  let totalFeesX = 0n;
  let totalFeesY = 0n;
  
  for (const posBin of positionBins) {
    const binReserve = reserves.find(r => r.id === posBin.id);
    if (!binReserve) continue;
    
    // Calculate position's share of fees
    const shareOfFees = await calculateBinFeeShare(
      posBin.liquidity,
      binReserve,
      pair
    );
    
    totalFeesX += shareOfFees.feeX;
    totalFeesY += shareOfFees.feeY;
  }
  
  return { totalFeesX, totalFeesY };
}

Calculate Fee Share

async function calculateBinFeeShare(
  positionLiquidity: bigint,
  binReserve: BinReserves,
  pair: LBPair
): Promise<{ feeX: bigint, feeY: bigint }> {
  // Get total supply for this bin
  const totalSupply = await getTotalSupply(pair, binReserve.id);
  
  if (totalSupply === 0n) return { feeX: 0n, feeY: 0n };
  
  // Your share = (your liquidity / total) * fees
  const feeX = (positionLiquidity * binReserve.fee_x) / totalSupply;
  const feeY = (positionLiquidity * binReserve.fee_y) / totalSupply;
  
  return { feeX, feeY };
}

Simplified Fee Tracking

// Quick fee estimation using amounts
async function trackPositionFees(
  pair: LBPair,
  positionId: string
) {
  const amounts = await sdk.Position.getPositionBinsAmount(pair, positionId);
  const reserves = await sdk.Pair.getPairReserves(pair);
  
  // Calculate fees by comparing with initial deposit
  const fees = amounts.map(amount => {
    const bin = reserves.find(r => r.id === amount.id);
    if (!bin) return { id: amount.id, feeX: 0n, feeY: 0n };
    
    // Rough approximation: fees = total value - initial liquidity
    return {
      id: amount.id,
      estimatedFeesX: (bin.fee_x * amount.liquidity) / (bin.reserve_x + bin.fee_x),
      estimatedFeesY: (bin.fee_y * amount.liquidity) / (bin.reserve_y + bin.fee_y)
    };
  });
  
  return fees;
}

Fee Performance Metrics

// Calculate fee metrics
async function calculateFeeMetrics(
  pair: LBPair,
  positionId: string,
  positionAge: number // hours
) {
  const fees = await getPositionFees(pair, positionId);
  
  // Convert to USD value
  const price = getPriceFromBinId(
    pair.parameters.active_id,
    Number(pair.binStep)
  );
  
  const feesUSD = 
    Number(fees.totalFeesX) * price + 
    Number(fees.totalFeesY);
  
  // Calculate rates
  return {
    totalFeesX: fees.totalFeesX,
    totalFeesY: fees.totalFeesY,
    totalUSD: feesUSD,
    hourlyRate: feesUSD / positionAge,
    dailyRate: (feesUSD / positionAge) * 24,
    weeklyRate: (feesUSD / positionAge) * 24 * 7
  };
}

Track Fee Generation by Bin

// See which bins generate most fees
async function analyzeFeeGeneration(
  pair: LBPair,
  positionId: string
) {
  const amounts = await sdk.Position.getPositionBinsAmount(pair, positionId);
  const reserves = await sdk.Pair.getPairReserves(pair);
  
  const binAnalysis = amounts.map(amount => {
    const reserve = reserves.find(r => r.id === amount.id);
    const binPrice = getPriceFromBinId(amount.id, Number(pair.binStep));
    
    // Estimate fee portion
    const feeRatio = reserve 
      ? (reserve.fee_x + reserve.fee_y) / (reserve.reserve_x + reserve.reserve_y)
      : 0n;
    
    return {
      binId: amount.id,
      price: binPrice,
      feeGeneration: feeRatio,
      isActive: amount.id === pair.parameters.active_id
    };
  });
  
  // Sort by fee generation
  return binAnalysis.sort((a, b) => 
    Number(b.feeGeneration) - Number(a.feeGeneration)
  );
}

Display Fee Summary

// User-friendly fee display
async function getFeeSummary(
  pair: LBPair,
  positionId: string
) {
  const fees = await getPositionFees(pair, positionId);
  const amounts = await sdk.Position.getPositionBinsAmount(pair, positionId);
  
  // Calculate total position value
  const totalValue = amounts.reduce((sum, bin) => ({
    x: sum.x + bin.amountX,
    y: sum.y + bin.amountY
  }), { x: 0n, y: 0n });
  
  // Fee percentage of position
  const feePercentX = (Number(fees.totalFeesX) / Number(totalValue.x) * 100);
  const feePercentY = (Number(fees.totalFeesY) / Number(totalValue.y) * 100);
  
  return {
    fees: {
      tokenX: formatUnits(fees.totalFeesX, 18),
      tokenY: formatUnits(fees.totalFeesY, 6)
    },
    feePercent: {
      tokenX: feePercentX.toFixed(2) + "%",
      tokenY: feePercentY.toFixed(2) + "%"
    },
    totalValue: {
      tokenX: formatUnits(totalValue.x, 18),
      tokenY: formatUnits(totalValue.y, 6)
    }
  };
}

Important Notes

  • Fees accumulate in bins, not positions

  • Calculation requires bin reserves data

  • Fees auto-compound into liquidity

  • Active bins typically generate most fees

Last updated