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 Price | Max depeg tolerated | Capital Efficiency |
|---|---|---|
| 0.999 | 0.1% | Very high — activates on tiny depegs |
| 0.99 | 1% | High — good default for stablecoins |
| 0.95 | 5% | Moderate — tolerates larger depegs |
| 0.90 | 10% | 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 callCapital 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 poolAPR 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);