Adding Liquidity

Providing liquidity means opening a new tick — a concentrated sphere of liquidity defined by a radius r and a hyperplane offset k. The LP deposits an equal amount of every pool token and receives shares in that tick.

Key Concepts

r and k

Every tick is a sphere in n-dimensional token space. The two parameters are:

  • r (radius, AMOUNT_SCALE units) — Controls how much capital is in the tick and how wide the liquidity range is. Larger r = more capital = higher absolute fee earnings.
  • k (hyperplane offset, AMOUNT_SCALE units) — Sets where the tick boundary sits in price space. Tighter k (closer to center) = higher capital efficiency but activates sooner during depegs.

Depeg Price

Rather than computing k directly, you specify a depeg price: the stablecoin price at which the tick transitions from INTERIOR to BOUNDARY. For example, 0.99 means your tick becomes active (constrains trading) when any token falls to 99¢ relative to the others.

Depeg PriceMax depeg toleratedCapital Efficiency
0.9990.1%Very high — activates on tiny depegs
0.991%High — good default for stablecoins
0.955%Moderate — tolerates larger depegs
0.9010%Low — wide range, lower efficiency

Step-by-Step Flow

import { TaurusClient, tickParamsFromDepegPrice, computeDepositPerToken } from '@taurusswap/sdk';

const client = new TaurusClient();
const pool   = await client.getPoolState();

// ── Step 1: Choose depeg price and deposit amount ────────────────────────────
const DEPEG_PRICE      = 0.99;          // 1% depeg tolerance
const DEPOSIT_PER_TOKEN = 100_000_000n; // 100 USDC (raw microunits) per token

// ── Step 2: Compute tick parameters (r, k) ──────────────────────────────────
const { r, k } = await client.tickParamsFromDepegPrice(DEPEG_PRICE, DEPOSIT_PER_TOKEN);
// r and k are in AMOUNT_SCALE units (raw / 1_000)

// ── Step 3: Verify deposit amount ───────────────────────────────────────────
// computeDepositPerToken returns the exact raw microunits needed per token
const deposit = computeDepositPerToken(r, k, pool.n, pool.sqrtN, pool.invSqrtN);
console.log('Deposit per token:', Number(deposit) / 1e6, 'USD');

// ── Step 4: Build transaction group ─────────────────────────────────────────
const { txns, depositPerTokenRaw, tickId } = await client.buildAddLiquidityTxns({
  sender: 'YOUR_ADDRESS',
  r,
  k,
});
// depositPerTokenRaw is the ASA transfer amount per token
// tickId is the ID the new tick will receive (pool.numTicks before the call)

console.log('Will deposit:', Number(depositPerTokenRaw) / 1e6, 'per token');
console.log('New tick ID will be:', tickId);

// ── Step 5: Sign and submit ──────────────────────────────────────────────────
// const signedTxns = await wallet.signTransaction(txns);
// const { txid }   = await client.algod.sendRawTransaction(signedTxns).do();
// await algosdk.waitForConfirmation(client.algod, txid, 4);

Transaction Group Layout

For a pool with n = 5 tokens:

┌──────────────────────────────────────────┐
│ Tx 0–k: Budget top-up (opcode overhead)  │
│ Tx k+1: ASA Transfer  user → pool        │  ← token 0, amount = depositPerTokenRaw
│ Tx k+2: ASA Transfer  user → pool        │  ← token 1
│   ...                                    │
│ Tx k+n: ASA Transfer  user → pool        │  ← token n-1
│ Tx k+n+1: App call  add_tick()           │
│   args: [r, k, tickId]                   │
│   creates tick: box and position: box    │
└──────────────────────────────────────────┘
Total: budget_txns + n ASA transfers + 1 app call

Capital Efficiency

Tighter ticks earn more fees per dollar because they provide denser virtual liquidity. Use client.getCapitalEfficiency to compare configurations:

const { efficiency, depositPerToken } = await client.getCapitalEfficiency(
  0.99,   // depegPrice
  r,      // tick radius in AMOUNT_SCALE units
);

console.log(`Capital efficiency: ${efficiency.toFixed(1)}×`);
// e.g. "12.5×" means this tick earns 12.5× more fees per dollar than a full-range pool

APR Estimate

client.estimateAPR combines 24h fee volume from the Indexer with the capital efficiency multiplier to project annualised yield:

const apr = await client.estimateAPR(
  0.99,          // depegPrice
  100_000_000n,  // depositPerTokenRaw (100 USD per token)
);

console.log('APR estimate:',      (apr.apr * 100).toFixed(2) + '%');
console.log('Daily fee USD:',     apr.dailyFeeUsd.toFixed(4));
console.log('Efficiency mult:',   apr.efficiencyMultiplier.toFixed(1) + '×');
Note: APR estimates are based on the past 24h volume. Actual returns depend on trading activity and how long your tick stays INTERIOR.

Zap: Single-Token Deposit

Users often only have one token. A zap splits it into equal portions of all n pool tokens via sequential swaps, then adds liquidity:

// Plan the zap (no network calls — pure function)
const plan = await client.computeZap(
  0,             // sourceTokenIdx — the token the user has
  500_000_000n,  // totalAmountRaw — 500 USDC
);

plan.swaps.forEach((s) => {
  console.log(`Swap ${s.fromIdx}→${s.toIdx}: ${Number(s.amountIn)/1e6} → ${Number(s.amountOut)/1e6}`);
});
console.log('Deposit per token:', Number(plan.depositPerToken) / 1e6);
console.log('Avg price impact:', (plan.avgPriceImpact * 100).toFixed(3) + '%');

// Build all transaction groups (swaps first, then add liquidity)
const { swapTxnGroups, addLiquidityTxns } = await client.buildZapTxns({
  sender:        'YOUR_ADDRESS',
  sourceTokenIdx: 0,
  totalAmountRaw: 500_000_000n,
  depegPrice:     0.99,
  slippageBps:    50,
});

// Submit swaps sequentially first, then add liquidity
for (const group of swapTxnGroups) {
  const signed = await wallet.signTransaction(group);
  const { txid } = await client.algod.sendRawTransaction(signed).do();
  await algosdk.waitForConfirmation(client.algod, txid, 4);
}
const signed = await wallet.signTransaction(addLiquidityTxns);
const { txid } = await client.algod.sendRawTransaction(signed).do();
await algosdk.waitForConfirmation(client.algod, txid, 4);
console.log('Liquidity added, tick ID:', /* from pool.numTicks before the call */);

Low-Level: addLiquidity

For scripts and bots that hold the key directly:

import { addLiquidity, tickParamsFromDepegPrice } from '@taurusswap/sdk';
import algosdk from 'algosdk';

const account = algosdk.mnemonicToSecretKey('...');
const pool    = await readPoolState(algod, POOL_APP_ID);
const { r, k } = tickParamsFromDepegPrice(0.99, 100_000_000n, pool.n, pool.sqrtN, pool.invSqrtN);

const { txId, tickId, depositPerTokenRaw } = await addLiquidity({
  client: algod,
  poolAppId: POOL_APP_ID,
  sender: account.addr,
  r,
  k,
  signer: async (txns) => txns.map((t) => t.signTxn(account.sk)),
});

console.log('Tick created:', tickId, '— TX:', txId);