Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.meteora.ag/llms.txt

Use this file to discover all available pages before exploring further.

These examples are based on the local damm-v1-sdk/ts-client/src/examples files and public SDK methods. They focus on transaction construction patterns. For the full method catalog, see the SDK Reference.

Setup

import AmmImpl from "@meteora-ag/dynamic-amm-sdk";
import { Connection, Keypair, PublicKey, sendAndConfirmTransaction } from "@solana/web3.js";
import BN from "bn.js";

const connection = new Connection(process.env.RPC_URL!, "confirmed");

// Replace with your wallet adapter, backend signer, or key management flow.
const user = Keypair.generate();
const poolAddress = new PublicKey("...");
Use devnet while testing. The DAMM v1 program ID is the same for devnet and mainnet:
// Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB

Fetch Pool State

const pool = await AmmImpl.create(connection, poolAddress, {
  cluster: "mainnet-beta",
});

await pool.updateState();

const lockedLpAmount = await pool.getLockedLpAmount();
const lpSupply = await pool.getLpSupply();

console.log({
  pool: pool.address.toBase58(),
  lpMint: pool.getPoolTokenMint().toBase58(),
  tokenA: pool.tokenAMint.address.toBase58(),
  tokenB: pool.tokenBMint.address.toBase58(),
  tokenAAmount: pool.poolInfo.tokenAAmount.toString(),
  tokenBAmount: pool.poolInfo.tokenBAmount.toString(),
  virtualPriceRaw: pool.poolInfo.virtualPriceRaw.toString(),
  lockedLpAmount: lockedLpAmount.toString(),
  lpSupply: lpSupply.toString(),
});
AmmImpl.create reads the pool, both Dynamic Vault accounts, vault token accounts, vault LP mints, pool-held vault LP token accounts, clock, and depeg accounts when required.

Quote And Swap

The recommended swap flow is:
  1. Load the pool.
  2. Quote with getSwapQuote.
  3. Build the swap transaction with minSwapOutAmount.
  4. Sign, simulate when appropriate, and send.
const pool = await AmmImpl.create(connection, poolAddress, {
  cluster: "devnet",
});

const inTokenMint = pool.tokenAMint.address;
const inAmount = new BN(10_000_000);
const slippagePercent = 1;

const quote = pool.getSwapQuote(inTokenMint, inAmount, slippagePercent);

const tx = await pool.swap(
  user.publicKey,
  inTokenMint,
  quote.swapInAmount,
  quote.minSwapOutAmount,
);

const signature = await sendAndConfirmTransaction(connection, tx, [user]);

console.log({
  signature,
  outAmount: quote.swapOutAmount.toString(),
  minOutAmount: quote.minSwapOutAmount.toString(),
  fee: quote.fee.toString(),
  priceImpact: quote.priceImpact.toString(),
});
Pass a referralOwner as the optional fifth pool.swap argument when routing a host fee account for referral flows.

Deposit Liquidity

For a balanced deposit, provide one token-side amount to getDepositQuote with balance = true; the SDK computes the other side from pool state.
const pool = await AmmImpl.create(connection, poolAddress);

const tokenBInAmount = new BN(1_000_000);
const slippagePercent = 1;

const quote = pool.getDepositQuote(
  new BN(0),
  tokenBInAmount,
  true,
  slippagePercent,
);

const tx = await pool.deposit(
  user.publicKey,
  quote.tokenAInAmount,
  quote.tokenBInAmount,
  quote.minPoolTokenAmountOut,
);

const signature = await sendAndConfirmTransaction(connection, tx, [user]);
console.log(signature);
For stable pools, the SDK can also quote imbalanced deposits by calling getDepositQuote(tokenAAmount, tokenBAmount, false, slippagePercent).

Withdraw Liquidity

const pool = await AmmImpl.create(connection, poolAddress);

const lpTokenAmount = new BN(100_000);
const slippagePercent = 1;

const quote = pool.getWithdrawQuote(lpTokenAmount, slippagePercent);

const tx = await pool.withdraw(
  user.publicKey,
  quote.poolTokenAmountIn,
  quote.minTokenAOutAmount,
  quote.minTokenBOutAmount,
);

const signature = await sendAndConfirmTransaction(connection, tx, [user]);
console.log(signature);
For stable pools, pass a token mint as the third getWithdrawQuote argument to quote a single-sided withdrawal.

Create A Config-Based Pool

createPermissionlessConstantProductPoolWithConfig returns an array of transactions because vault creation, pool creation, optional locking, and optional initial swap can require multiple transactions.
import AmmImpl, { PROGRAM_ID } from "@meteora-ag/dynamic-amm-sdk";
import { derivePoolAddressWithConfig } from "@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";

const tokenAMint = new PublicKey("...");
const tokenBMint = new PublicKey("...");
const config = new PublicKey("...");

const tokenAAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);

const poolAddress = derivePoolAddressWithConfig(
  tokenAMint,
  tokenBMint,
  config,
  new PublicKey(PROGRAM_ID),
);

const transactions = await AmmImpl.createPermissionlessConstantProductPoolWithConfig(
  connection,
  user.publicKey,
  tokenAMint,
  tokenBMint,
  tokenAAmount,
  tokenBAmount,
  config,
  {
    cluster: "devnet",
    lockLiquidity: true,
  },
);

for (const tx of transactions) {
  const signature = await sendAndConfirmTransaction(connection, tx, [user]);
  console.log(signature);
}

console.log("pool", poolAddress.toBase58());
Use createPermissionlessConstantProductPoolWithConfig2 when you need to pass an activationPoint accepted by the selected config.

Find Authorized Configs

const configs = await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
  connection,
  user.publicKey,
);

for (const config of configs) {
  console.log({
    config: config.publicKey.toBase58(),
    tradeFeeNumerator: config.account.poolFees.tradeFeeNumerator.toString(),
    activationDuration: config.account.activationDuration.toString(),
  });
}
Public configs have pool_creator_authority set to the default pubkey. Private configs require the configured creator signer.

Lock LP And Claim Fees

const pool = await AmmImpl.create(connection, poolAddress);

const lpAmount = new BN(100_000);

const lockTx = await pool.lockLiquidity(
  user.publicKey,
  lpAmount,
  user.publicKey,
);

await sendAndConfirmTransaction(connection, lockTx, [user]);

const escrow = await pool.getUserLockEscrow(user.publicKey);
console.log(escrow?.fee.unClaimed);

if (escrow?.fee.unClaimed.lp?.gt(new BN(0))) {
  const claimTx = await pool.claimLockFee2(
    user.publicKey,
    escrow.fee.unClaimed.lp,
    user.publicKey,
    user.publicKey,
  );

  await sendAndConfirmTransaction(connection, claimTx, [user]);
}
claimLockFee2 is the newer claim helper. Use claimLockFee only when you need the older wrapped-SOL receiver behavior.