Reading Pool State

The readPoolState function decodes all on-chain state into a typedPoolState object. This is your entry point for any pool interaction.

Usage

import { readPoolState } from '@taurus-swap/sdk';

const poolState = await readPoolState(algodClient, POOL_APP_ID);

PoolState Type

interface PoolState {
  // Basic info
  n: number;              // Number of tokens
  appId: number;          // Contract app ID

  // Consolidated state
  sumX: bigint;           // Sum of all reserves (∑xᵢ)
  sumXSq: bigint;         // Sum of squared reserves (∑xᵢ²)
  rInt: bigint;           // Interior radius
  sBound: bigint;         // Boundary effective radius
  kBound: bigint;         // Boundary hyperplane offset
  totalR: bigint;         // Total liquidity (sum of all tick radii)

  // Scaling
  virtualOffset: bigint;  // AMOUNT_SCALE (1000)

  // Fees
  feeBps: number;         // Fee in basis points
  feeGrowth: bigint[];    // Fee growth per token (n values)

  // Tick info
  numTicks: number;       // Number of active ticks

  // Per-token data
  reserves: bigint[];     // Reserve of each token (microunits)
  tokenAsas: number[];    // ASA ID of each token
  tokenDecimals: number[]; // Decimal places of each token
}

Field Descriptions

Basic Info

  • n — Number of tokens in the pool. For a 5-stablecoin pool, n = 5.
  • appId — The Algorand app ID. Used for all subsequent calls.

Consolidated State

  • sumX — Sum of all reserves. Used to compute α (position along equal-price axis).
  • sumXSq — Sum of squared reserves. Used to compute ‖w‖ (orthogonal component).
  • rInt — Interior radius. Sum of radii for all interior ticks.
  • sBound — Boundary effective radius. Sum of effective radii for boundary ticks.
  • kBound — The outermost boundary hyperplane offset.
  • totalR — Total liquidity. Sum of all tick radii (interior + boundary).

Scaling

  • virtualOffset — Always 1000 (AMOUNT_SCALE). Used for unit conversions.

Fees

  • feeBps — Fee in basis points. 30 = 0.3%, 100 = 1%.
  • feeGrowth — Array of n values. feeGrowth[i] is the cumulative fee growth for token i. Used for LP fee claims.

Tick Info

  • numTicks — Number of active ticks. A fresh pool starts with 0.

Per-Token Data

  • reserves — Array of n reserve values in microunits. Convert to display units using tokenDecimals.
  • tokenAsas — Array of n ASA IDs. Use these to identify tokens.
  • tokenDecimals — Array of n decimal places. USDC/USDT use 6.

Example: Displaying Reserves

const poolState = await readPoolState(algodClient, POOL_APP_ID);

// Format reserves for display
const formattedReserves = poolState.reserves.map((reserve, i) => {
  const decimals = poolState.tokenDecimals[i];
  const display = Number(reserve) / (10 ** decimals);
  const token = poolState.tokenAsas[i];
  return `${display.toLocaleString()} (ASA ${token})`;
});

console.log('Pool reserves:');
formattedReserves.forEach((r, i) => console.log(`  Token ${i}: ${r}`));

Handling Fresh Pools

A newly deployed pool may not have all boxes initialized. Handle gracefully:

import { readPoolState, BoxNotFoundError } from '@taurus-swap/sdk';

try {
  const poolState = await readPoolState(algodClient, POOL_APP_ID);
  console.log('Pool is initialized');
} catch (err) {
  if (err instanceof BoxNotFoundError) {
    console.log('Pool not initialized yet - waiting for first liquidity deposit');
    // Show "Pool not ready" UI
  } else {
    throw err;
  }
}

Polling for Updates

Pool state changes with every swap and liquidity operation. Poll periodically:

import { useEffect, useState } from 'react';
import { readPoolState } from '@taurus-swap/sdk';

function usePoolState(appId: number) {
  const [state, setState] = useState<PoolState | null>(null);

  useEffect(() => {
    const fetch = async () => {
      const s = await readPoolState(algodClient, appId);
      setState(s);
    };

    fetch();
    const interval = setInterval(fetch, 30_000);  // 30 seconds
    return () => clearInterval(interval);
  }, [appId]);

  return state;
}

Reading Tick State

import { readTickState } from '@taurus-swap/sdk';

const tick = await readTickState(algodClient, POOL_APP_ID, tickId);

console.log('Tick state:', {
  r: tick.r,              // Sphere radius
  k: tick.k,              // Hyperplane offset
  state: tick.state,      // 'INTERIOR' or 'BOUNDARY'
  totalShares: tick.totalShares,
  effectiveRadius: tick.effectiveRadius
});

Reading Position State

import { readPosition } from '@taurus-swap/sdk';

const position = await readPosition(
  algodClient,
  POOL_APP_ID,
  address,
  tickId
);

console.log('Position:', {
  shares: position.shares,
  pendingFees: position.pendingFees,  // Already computed!
  feeCheckpoints: position.feeCheckpoints
});
Note: The pendingFeesfield is computed client-side using the fee growth formula. It's not stored on-chain.