Quoting Swaps

getSwapQuote is a synchronous, pure function. It runs the full Newton-bisection solver and tick-crossing logic off-chain, producing an exact quote that matches what the on-chain contract will compute. No Algod calls needed once you have a PoolState.

Signature

function getSwapQuote(
  poolState: PoolState,
  tokenInIdx:  number, // index into pool.tokenAsaIds
  tokenOutIdx: number,
  amountInRaw: bigint, // raw microunits (1 USDC = 1_000_000n)
): SwapQuote

Basic Usage

import { readPoolState, getSwapQuote } from '@taurusswap/sdk';

const pool  = await readPoolState(algod, POOL_APP_ID);

// Sell 10 USDC (token 0) → buy USDT (token 1)
const quote = getSwapQuote(pool, 0, 1, 10_000_000n);

console.log('You receive:',   Number(quote.amountOut) / 1e6, 'USDT');
console.log('Effective rate:', quote.effectivePrice.toFixed(6));
console.log('Price impact:',  (quote.priceImpact * 100).toFixed(4) + '%');
console.log('Ticks crossed:', quote.ticksCrossed);

Via TaurusClient (async — fetches pool state from cache first):

const quote = await client.quote({
  fromIndex: 0,
  toIndex:   1,
  amountIn:  10_000_000n,
});

SwapQuote Type

interface SwapQuote {
  amountIn:           bigint;        // raw microunits — the input you provided
  amountOut:          bigint;        // raw microunits — what you receive
  priceImpact:        number;        // 0.001 = 0.1% — how much the trade moves price
  instantaneousPrice: number;        // spot price before the trade (dimensionless ratio)
  effectivePrice:     number;        // amountOut / amountIn — actual average rate
  ticksCrossed:       number;        // 0 = simple swap; >0 = swap_with_crossings on-chain
  route:              TradeSegment[]; // internal segments (AMOUNT_SCALE units)
}

interface TradeSegment {
  amountIn:       bigint;        // AMOUNT_SCALE units
  amountOut:      bigint;        // AMOUNT_SCALE units
  tickCrossedId:  number | null; // which tick was exited (null = no crossing in this segment)
  newTickState:   TickState | null; // state the crossed tick transitions to
}

Understanding Price Impact

priceImpact is computed as:

priceImpact = 1 − (effectivePrice / instantaneousPrice)

For a 100 USDC → USDT swap, if the spot rate is 1.0000 and you receive 99.97 USDT, the effective price is 0.9997 and price impact is 0.03%.

Guidelines for stablecoin swaps:

Price ImpactInterpretation
< 0.01%Normal — deep pool, small trade
0.01% – 0.1%Acceptable — moderate-sized trade
0.1% – 1%Warn the user
> 1%High — consider splitting the trade

Tick Crossings

The pool uses concentrated liquidity ticks. A large swap may exhaust one tick and "cross" into the next. The SDK handles this automatically:

  • ticksCrossed === 0 — Simple path. The contract calls swap().
  • ticksCrossed > 0 — Multi-segment path. The contract calls swap_with_crossings() with a serialised trade_recipe.

buildSwapTxns (and client.buildSwapTxns) automatically chooses the right contract method — you don't need to handle this manually.

Applying Slippage Tolerance

const quote = getSwapQuote(pool, 0, 1, 10_000_000n);

const SLIPPAGE_BPS = 50; // 0.5%
const minAmountOut = (quote.amountOut * BigInt(10_000 - SLIPPAGE_BPS)) / 10_000n;

console.log('Expected:', Number(quote.amountOut) / 1e6);
console.log('Minimum: ', Number(minAmountOut) / 1e6);

When you pass slippageBps to buildSwapTxns, it applies this formula automatically and encodes minAmountOut into the transaction as a contract-enforced floor.

Spot Prices

// Get all token prices relative to token 0 (= 1.0)
const prices = await client.getAllPrices();
// prices[0] = 1.0  (base token)
// prices[1] = 0.9998  (USDT/USDC spot rate)
// prices[2] = 1.0001  etc.

// Or with explicit base:
const pricesRelativeToUSDT = await client.getAllPrices(1);

Under the hood this calls getAllPrices(poolState, baseTokenIdx) which uses getPrice(reserves, rInt, i, j) from the sphere math module.

React Hook: Live Quote

import { useState, useEffect, useCallback } from 'react';
import { type SwapQuote, SwapTooSmallError, InsufficientLiquidityError } from '@taurusswap/sdk';
import { taurusClient } from '@/lib/taurus';

export function useSwapQuote(
  fromIndex: number,
  toIndex: number,
  amountIn: bigint | null,
) {
  const [quote, setQuote] = useState<SwapQuote | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!amountIn || amountIn <= 0n) { setQuote(null); return; }

    let cancelled = false;
    setLoading(true);

    taurusClient
      .quote({ fromIndex, toIndex, amountIn })
      .then((q) => { if (!cancelled) { setQuote(q); setError(null); } })
      .catch((err) => {
        if (cancelled) return;
        if (err instanceof SwapTooSmallError)          setError('Amount too small');
        else if (err instanceof InsufficientLiquidityError) setError('Insufficient liquidity');
        else setError('Quote failed');
        setQuote(null);
      })
      .finally(() => { if (!cancelled) setLoading(false); });

    return () => { cancelled = true; };
  }, [fromIndex, toIndex, amountIn?.toString()]);

  return { quote, error, loading };
}