Skip to main content
DAMM v2 supports three collect fee modes, each suited to different LP strategies. This guide covers the two pool creation approaches developers use: concentrated liquidity (modes 0 and 1) and compounding fee (mode 2).
ModecollectFeeModePrice RangeSingle-SidedFee Behaviour
BothToken0Concentrated or fullFees claimable in both tokens
OnlyB1Concentrated or fullFees claimable in quote token only
Compounding2Full range onlyPortion of fees auto-compounds back into liquidity

Concentrated Liquidity Pools

Concentrated liquidity pools allow LPs to focus capital within a chosen price range, earning more fees per dollar deposited when the market price stays within range. These use collectFeeMode 0 (BothToken) or 1 (OnlyB). Key characteristics:
  • Custom price range — Set minPrice / maxPrice to concentrate liquidity. Use MIN_SQRT_PRICE / MAX_SQRT_PRICE for full-range.
  • Single-sided supported — Deposit only token A (one-sided) or both tokens (balanced).
  • Fees claimable — LPs claim accumulated fees separately from their position.

TypeScript SDK

import { Connection, Keypair } from "@solana/web3.js";
import {
  CpAmm,
  CollectFeeMode,
  BaseFeeMode,
  ActivationType,
  MIN_SQRT_PRICE,
  MAX_SQRT_PRICE,
  getSqrtPriceFromPrice,
  getBaseFeeParams,
  getDynamicFeeParams,
} from "@meteora-ag/cp-amm-sdk";
import BN from "bn.js";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const cpAmm = new CpAmm(connection);

const tokenADecimals = 9;
const tokenBDecimals = 6;

// Define your price range (or use MIN/MAX for full range)
const minSqrtPrice = getSqrtPriceFromPrice("0.5", tokenADecimals, tokenBDecimals);
const maxSqrtPrice = getSqrtPriceFromPrice("2.0", tokenADecimals, tokenBDecimals);

// Calculate initial sqrt price and liquidity
const { initSqrtPrice, liquidityDelta } = cpAmm.preparePoolCreationParams({
  tokenAAmount: new BN(1_000_000_000),
  tokenBAmount: new BN(1_000_000),
  minSqrtPrice,
  maxSqrtPrice,
  collectFeeMode: CollectFeeMode.BothToken, // or CollectFeeMode.OnlyB
});

// Configure fees
const baseFeeParams = getBaseFeeParams(
  {
    baseFeeMode: BaseFeeMode.FeeTimeSchedulerLinear,
    feeTimeSchedulerParam: {
      startingFeeBps: 100, // 1%
      endingFeeBps: 25,    // 0.25%
      numberOfPeriod: 10,
      totalDuration: 3600,
    },
  },
  tokenBDecimals,
  ActivationType.Timestamp
);

const poolFees = {
  baseFee: baseFeeParams,
  compoundingFeeBps: 0, // not used for concentrated liquidity
  padding: 0,
  dynamicFee: getDynamicFeeParams(25),
};

const positionNft = Keypair.generate();

const { tx, pool, position } = await cpAmm.createCustomPool({
  payer: wallet.publicKey,
  creator: wallet.publicKey,
  positionNft: positionNft.publicKey,
  tokenAMint,
  tokenBMint,
  tokenAAmount: new BN(1_000_000_000),
  tokenBAmount: new BN(1_000_000),
  sqrtMinPrice: minSqrtPrice,
  sqrtMaxPrice: maxSqrtPrice,
  initSqrtPrice,
  liquidityDelta,
  poolFees,
  hasAlphaVault: false,
  collectFeeMode: CollectFeeMode.BothToken, // 0 or 1
  activationPoint: null,
  activationType: ActivationType.Slot,
  tokenAProgram,
  tokenBProgram,
});

console.log("Pool:", pool.toString());

Compounding Fee Pools

Compounding fee pools use a constant-product full-range (x·y=k) model where a configurable percentage of trading fees are automatically reinvested back into pool liquidity as token B. The remaining fees are claimable by LPs. Key characteristics:
  • Full-range only — Uses the full price range. minPrice / maxPrice config values are ignored.
  • Balanced pools only — Both tokens required at creation. Single-sided deposits are not supported due to DEAD_LIQUIDITY.
  • collectFeeMode: 2CollectFeeMode.Compounding.
  • compoundingFeeBps — Controls the fee split (0–10000 bps). E.g. 5000 = 50% compounds back, 50% claimable.
  • Fee fields — Swap results expose claimingFee + compoundingFee instead of a single tradingFee.
Compounding pools work best for long-term LPs who want fee income to grow their position size automatically.

TypeScript SDK

import {
  CpAmm,
  CollectFeeMode,
  BaseFeeMode,
  ActivationType,
  MIN_SQRT_PRICE,
  MAX_SQRT_PRICE,
  getBaseFeeParams,
  getDynamicFeeParams,
} from "@meteora-ag/cp-amm-sdk"; // requires ^1.3.7

// Compounding pools use full range
const { initSqrtPrice, liquidityDelta } = cpAmm.preparePoolCreationParams({
  tokenAAmount: new BN(1_000_000_000),
  tokenBAmount: new BN(10_000_000_000),
  minSqrtPrice: MIN_SQRT_PRICE,
  maxSqrtPrice: MAX_SQRT_PRICE,
  collectFeeMode: CollectFeeMode.Compounding,
});

const poolFees = {
  baseFee: getBaseFeeParams(
    {
      baseFeeMode: BaseFeeMode.FeeTimeSchedulerLinear,
      feeTimeSchedulerParam: {
        startingFeeBps: 100,
        endingFeeBps: 25,
        numberOfPeriod: 10,
        totalDuration: 3600,
      },
    },
    tokenBDecimals,
    ActivationType.Timestamp
  ),
  compoundingFeeBps: 5000, // 50% of fees compound back into liquidity
  padding: 0,
  dynamicFee: getDynamicFeeParams(25),
};

const positionNft = Keypair.generate();

const { tx, pool, position } = await cpAmm.createCustomPool({
  payer: wallet.publicKey,
  creator: wallet.publicKey,
  positionNft: positionNft.publicKey,
  tokenAMint,
  tokenBMint,
  tokenAAmount: new BN(1_000_000_000),
  tokenBAmount: new BN(10_000_000_000),
  sqrtMinPrice: MIN_SQRT_PRICE, // full range
  sqrtMaxPrice: MAX_SQRT_PRICE,
  initSqrtPrice,
  liquidityDelta,
  poolFees,
  hasAlphaVault: false,
  collectFeeMode: CollectFeeMode.Compounding, // mode 2
  activationPoint: null,
  activationType: ActivationType.Slot,
  tokenAProgram,
  tokenBProgram,
});