Adding Liquidity
Providing liquidity to Orbital AMM means creating a new tick with specific price range parameters. This page walks through the full LP flow.
Tick Parameters
A tick is defined by:
- r— Sphere radius (how much liquidity you're providing)
- k — Hyperplane offset (defines the price range)
Instead of computing k directly, use the helper that converts from a depeg price:
import { kFromDepegPrice } from '@taurus-swap/sdk';
// For a 0.99 depeg threshold (1% depeg allowed)
const k = kFromDepegPrice(r, 0.99, n);Computing Deposit Amounts
The SDK computes how much of each token you need to deposit:
import { computeDepositPerToken } from '@taurus-swap/sdk';
const deposits = computeDepositPerToken(
poolState,
{
r: 10_000_000n, // 10M liquidity
k: kFromDepegPrice(10_000_000n, 0.99, 5)
}
);
// deposits[i] is the amount of token i to transfer
console.log('Deposit amounts:', deposits);The Deposit Flow
- Compute tick parameters (r, k)
- Calculate deposit per token
- Opt in to all token ASAs (if not already)
- Build transaction group: n ASA transfers + app call
- Sign and send
- Receive LP position NFT (box key proves ownership)
Full Example
import {
readPoolState,
computeDepositPerToken,
kFromDepegPrice,
buildAddLiquidityGroup
} from '@taurus-swap/sdk';
async function addLiquidity() {
// 1. Read current pool state
const poolState = await readPoolState(algodClient, POOL_APP_ID);
// 2. Define tick parameters
const LIQUIDITY_AMOUNT = 10_000_000n; // 10M units
const DEPEG_THRESHOLD = 0.99; // 1% depeg allowed
const r = LIQUIDITY_AMOUNT;
const k = kFromDepegPrice(r, DEPEG_THRESHOLD, poolState.n);
// 3. Compute deposit per token
const deposits = computeDepositPerToken(poolState, { r, k });
console.log('Depositing:');
deposits.forEach((amt, i) => {
const display = Number(amt) / 1e6;
console.log(` Token ${i}: ${display}`);
});
// 4. Build transaction group
const { txGroup } = await buildAddLiquidityGroup(
algodClient,
POOL_APP_ID,
account,
{
r,
k,
deposits
}
);
// 5. Sign and send
const signedTxns = await wallet.signTransaction(
txGroup.map((tx) => tx.txn)
);
const result = await algodClient
.sendGroupTransaction(signedTxns)
.do();
// 6. Wait for confirmation
const confirmation = await algosdk.waitForConfirmation(
algodClient,
result.txId,
4
);
console.log('Liquidity added in round:', confirmation['confirmed-round']);
// The tick ID is in the app call logs
const tickId = extractTickIdFromLogs(confirmation.logs);
console.log('Your tick ID:', tickId);
return { tickId, txId: result.txId };
}Transaction Group Structure
For n=5 tokens:
┌─────────────────────────────────────┐
│ Tx 0-4: ASA Transfers (5 txns) │
│ - Sender: LP │
│ - Receiver: Pool │
│ - Amount: deposits[i] for each │
├─────────────────────────────────────┤
│ Tx 5: App Call (add_tick) │
│ - Method: add_tick(r, k, ...) │
│ - Creates tick box │
│ - Creates position box │
└─────────────────────────────────────┘
Total: n + 1 transactionsOpting In to Tokens
Before adding liquidity, ensure you're opted in to all pool tokens:
import { checkAssetOptIn, buildAssetOptInTx } from '@taurus-swap/sdk';
// Check opt-in status
const optIns = await Promise.all(
poolState.tokenAsas.map((asa) =>
checkAssetOptIn(algodClient, account.addr, asa)
)
);
// Build opt-in transactions for missing assets
const optInTxs = [];
for (let i = 0; i < optIns.length; i++) {
if (!optIns[i]) {
optInTxs.push(
await buildAssetOptInTx(algodClient, poolState.tokenAsas[i])
);
}
}
// Sign and send opt-ins first
if (optInTxs.length > 0) {
const signedOptIns = await wallet.signTransaction(
optInTxs.map((tx) => tx.txn)
);
await algodClient.sendGroupTransaction(signedOptIns).do();
}Position Ownership
LP positions are stored in box storage with key:
pos:{owner_address}{tick_id}The box contains:
shares— Your share of the tick's total liquidityfeeCheckpoints— Fee growth snapshot for each token
To read your position later:
const position = await readPosition(
algodClient,
POOL_APP_ID,
account.addr,
tickId
);
console.log('Your shares:', position.shares);
console.log('Pending fees:', position.pendingFees);Removing Liquidity
To remove liquidity (withdraw your share):
import { buildRemoveLiquidityGroup } from '@taurus-swap/sdk';
const { txGroup } = await buildRemoveLiquidityGroup(
algodClient,
POOL_APP_ID,
account,
{
tickId,
sharesToRemove: position.shares // Remove all
}
);
// Sign and send...
const result = await executeAndSend(txGroup, wallet);
// You'll receive:
// - Proportional share of reserves (all tokens)
// - All accrued feesClaiming Fees
To claim fees without removing liquidity:
import { buildClaimFeesGroup } from '@taurus-swap/sdk';
const { txGroup } = await buildClaimFeesGroup(
algodClient,
POOL_APP_ID,
account,
tickId
);
// Sign and send...
// You'll receive accrued fees in all tokensNote:Fees are automatically claimed when you remove liquidity. You don't need a separate claim transaction.