Price Helpers

Price Helpers

Utility functions for price conversions between human-readable formats and protocol values. Essential helpers for working with DLMM's bin-based pricing system.

Core Price Functions

// Convert bin ID to price
function getPriceFromBinId(binId: number, binStep: number): number {
  const base = 1 + binStep / 10000;
  const exponent = binId - 8388608;
  return Math.pow(base, exponent);
}

// Convert price to bin ID
function getBinIdFromPrice(price: number, binStep: number): number {
  const base = 1 + binStep / 10000;
  const binId = Math.log(price) / Math.log(base) + 8388608;
  return Math.round(binId);
}

// Get price with high precision
function getPriceFromBinIdPrecise(binId: number, binStep: number): string {
  const base = 1 + binStep / 10000;
  const exponent = binId - 8388608;
  const price = Math.pow(base, exponent);
  return price.toPrecision(18);
}

Price Formatting

// Format price for display
function formatPrice(price: number, decimals: number = 4): string {
  if (price > 10000) {
    return price.toLocaleString('en-US', { 
      maximumFractionDigits: 0 
    });
  } else if (price > 1) {
    return price.toFixed(decimals);
  } else {
    return price.toPrecision(decimals);
  }
}

// Smart format based on value
function autoFormatPrice(price: number): string {
  if (price >= 1000) return formatPrice(price, 0);
  if (price >= 1) return formatPrice(price, 2);
  if (price >= 0.01) return formatPrice(price, 4);
  return price.toPrecision(4);
}

Price Range Calculations

// Get price range from bin range
function getPriceRange(
  centerBinId: number,
  binRadius: number,
  binStep: number
): { min: number, max: number, spread: number } {
  const minPrice = getPriceFromBinId(centerBinId - binRadius, binStep);
  const maxPrice = getPriceFromBinId(centerBinId + binRadius, binStep);
  
  return {
    min: minPrice,
    max: maxPrice,
    spread: ((maxPrice - minPrice) / minPrice) * 100
  };
}

// Calculate bins needed for price range
function getBinsForPriceRange(
  currentPrice: number,
  minPrice: number,
  maxPrice: number,
  binStep: number
): { lower: number, upper: number, total: number } {
  const currentBin = getBinIdFromPrice(currentPrice, binStep);
  const minBin = getBinIdFromPrice(minPrice, binStep);
  const maxBin = getBinIdFromPrice(maxPrice, binStep);
  
  return {
    lower: currentBin - minBin,
    upper: maxBin - currentBin,
    total: maxBin - minBin + 1
  };
}

Price Conversions

// Convert between token ratios
function calculateTokenRatio(
  amountX: bigint,
  amountY: bigint,
  decimalsX: number,
  decimalsY: number
): number {
  const x = Number(amountX) / (10 ** decimalsX);
  const y = Number(amountY) / (10 ** decimalsY);
  return y / x; // Price of X in terms of Y
}

// Normalize price for different decimals
function normalizePrice(
  price: number,
  decimalsX: number,
  decimalsY: number
): number {
  const decimalDiff = decimalsY - decimalsX;
  return price * Math.pow(10, decimalDiff);
}

Bin Navigation

// Get next/previous bin prices
function getAdjacentPrices(
  binId: number,
  binStep: number,
  count: number = 5
): { below: number[], current: number, above: number[] } {
  const below = [];
  const above = [];
  
  for (let i = 1; i <= count; i++) {
    below.push(getPriceFromBinId(binId - i, binStep));
    above.push(getPriceFromBinId(binId + i, binStep));
  }
  
  return {
    below: below.reverse(),
    current: getPriceFromBinId(binId, binStep),
    above
  };
}

// Find nearest bin to target price
function getNearestBin(
  targetPrice: number,
  binStep: number
): { binId: number, actualPrice: number, difference: number } {
  const binId = getBinIdFromPrice(targetPrice, binStep);
  const actualPrice = getPriceFromBinId(binId, binStep);
  
  return {
    binId,
    actualPrice,
    difference: Math.abs(targetPrice - actualPrice)
  };
}

Price Validation

// DLMM constants
const PRICE_BOUNDS = {
  MIN_BIN_ID: 0,
  MAX_BIN_ID: 16777215, // 2^24 - 1
  REFERENCE_BIN_ID: 8388608 // Price = 1.0
};

// Validate price is within DLMM bounds
function isValidPrice(price: number, binStep: number): boolean {
  try {
    const binId = getBinIdFromPrice(price, binStep);
    return binId >= PRICE_BOUNDS.MIN_BIN_ID && 
           binId <= PRICE_BOUNDS.MAX_BIN_ID;
  } catch {
    return false;
  }
}

// Get max/min prices for bin step
function getPriceBounds(binStep: number): { min: number, max: number } {
  return {
    min: getPriceFromBinId(PRICE_BOUNDS.MIN_BIN_ID, binStep),
    max: getPriceFromBinId(PRICE_BOUNDS.MAX_BIN_ID, binStep)
  };
}

Utility Functions

// Quick helpers
const priceHelpers = {
  // Get current price from pair
  getCurrentPrice: (pair: LBPair) => 
    getPriceFromBinId(pair.parameters.active_id, Number(pair.binStep)),
  
  // Calculate price impact
  getPriceImpact: (startBin: number, endBin: number, binStep: number) => {
    const startPrice = getPriceFromBinId(startBin, binStep);
    const endPrice = getPriceFromBinId(endBin, binStep);
    return ((endPrice - startPrice) / startPrice) * 100;
  },
  
  // Format pair price for display
  formatPairPrice: (pair: LBPair, decimals?: number) => {
    const price = getPriceFromBinId(pair.parameters.active_id, Number(pair.binStep));
    return autoFormatPrice(price);
  }
};

Last updated