Create: DAMM v2 Pool
Summary
Dynamic AMM v2 (DAMM v2) is a brand new constant-product AMM program for liquidity pools, with a set of features to optimize transaction fees and provide greater flexibility for liquidity providers, launchpads, and token launches. Read an overview of key DAMM v2 features & benefits here.
Below we provide the steps to use Bun to configure and run sample scripts to conveniently set up a DAMM v2 Launch Pool on your own.
Getting Started
Clone repo: https://github.com/MeteoraAg/meteora-pool-setup
Config list to reference: https://github.com/MeteoraAg/meteora-pool-setup/tree/main/config
Program id:
cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
Dependencies
We need bun to run the scripts, install it via bun installation. Then install the dependencies by running the command bun install
Scripts
The following code examples can be used to initialize and seed a DAMM v2 pool on Meteora. It allows you to configure parameters for the pool, including fees, pricing, and activation conditions, before executing initialization and seeding commands.
Create customizable DAMM V2 pool
Clone repo: https://github.com/MeteoraAg/meteora-pool-setup
Configuration file example here: https://github.com/MeteoraAg/meteora-pool-setup/blob/main/config/create_damm_v2_customize_pool_default_dynamic_fee.json
Run the script with the config file (specified in the CLI) which is updated with your preferred parameters.
bun run src/create_damm_v2_customizable_pool.ts --config ./config/create_damm_v2_customize_pool.json
Note: you have to Replace
<./config/create_damm_v2_customize_pool.json>
with the path to your config file, after you have set your config parameters.
Configuration Details
General configuration
rpcUrl
: Solana RPC URL to get data and send transactions.keypairFilePath
: Keypair file path to send transactions.dryRun
: Set to false to send transactions.computeUnitPriceMicroLamports
: CU price in micro lamports unit. For example: 100000.createBaseToken
: Configuration to create base token.baseMint
: Base token address if thecreateBaseToken
field is not set.quoteSymbol
: Quote token symbol, onlySOL
orUSDC
is supported.quoteMint
: Quote token mint, in case the user wants to create a DLMM launch pool with a token other than SOL or USDC.dynamicAmm
: Dynamic AMM pool configuration.dynamicAmmV2
: Dynamic AMM V2 pool configuration.dlmm
: DLMM pool configuration.alphaVault
: Fcfs or Prorata Alpha Vault configuration.
Some configuration constraints:
createBaseToken
andbaseMint
cannot be used together.dynamicAmm
anddlmm
cannot be used together.
Create Base Token configuration
mintBaseTokenAmount
: Base token amount to be minted.baseDecimals
: Base token decimal.
Dynamic AMM V2 configuration
baseAmount
: Base token amount.quoteAmount
: Quote token amount (Nullable value)initPrice
: Initial price for the poolmaxPrice
: Max price range setup (null to use default)poolFees
:maxBaseFeeBps
: Starting fee in basis points (e.g., 25 = 0.25%). It is base fee if scheduler is not set.minBaseFeeBps
: Target fee after reduction periods. Should be equalmaxBaseFeeBps
when fee scheduler is not used.numberOfPeriod
: Number of periods for fee reduction scheduletotalDuration
: Total duration of the fee schedule (in slots or seconds based on activation type).totalDuration == 0
if theFeeScheduler
not be set up.feeSchedulerMode
: Fee scheduler mode (0 = linear, 1 = exponential)useDynamicFee
: Whether to use dynamic fee calculation based on price volatility (true/false)dynamicFeeConfig
: Configuration when useDynamicFee is true if not provide will use as default params in scriptsfilterPeriod
: Period for filtering price updatesdecayPeriod
: Period for decaying volatility accumulatorreductionFactor
: Factor for reducing the volatility impactvariableFeeControl
: Parameter controlling the variable fee responsemaxVolatilityAccumulator
: Maximum value for the volatility accumulator
collectFeeMode
: Fee collection mode (0 = base + quote, 1 = only quote)activationType
: To activate pool trading base onslot
ortimestamp
.activationPoint
: To activate pool trading at a point, either slot value or timestamp value base onactivationType
.hasAlphaVault
: Whether alpha vault is enabled or not for this pool.
Alpha Vault configuration
poolType
:dynamic
ordlmm
pool type.alphaVaultType
: Alpha Vault type, could befcfs
orprorata
depositingPoint
: Absolute value that, the slot or timestamp that allows deposit depend on the pool activation type.startVestingPoint
: Absolute value, the slot or timestamp that start vesting depend on the pool activation type.endVestingPoint
: Absolute value, the slot or timestamp that end vesting depend on the pool activation type.maxDepositCap
: Maximum deposit cap.individualDepositingCap
: Individual deposit cap.escrowFee
: Fee to create stake escrow account.whitelistMode
:permissionless
orpermission_with_merkle_proof
orpermission_with_authority
.
Pro rata configuration
depositingPoint
: Absolute value that, the slot or timestamp that allows deposit depend on the pool activation type.startVestingPoint
: Absolute value, the slot or timestamp that start vesting depend on the pool activation type.endVestingPoint
: Absolute value, the slot or timestamp that end vesting depend on the pool activation type.maxBuyingCap
: Maximum buying cap.escrowFee
: Fee to create stake escrow account.whitelistMode
:permissionless
orpermission_with_merkle_proof
orpermission_with_authority
.
Technical FAQ
Please read this section.
Alternative: Using TypeScript SDK to create a DAMM v2 Pool
Getting Started
The TypeScript SDK provides a set of tools and methods to interact with the Meteora Dynamic CP-AMM (DAMM v2) program.
Program Repo on Github: https://github.com/MeteoraAg/cp-amm
TypeScript SDK on Github: https://github.com/MeteoraAg/cp-amm-sdk/tree/main
Program ID (mainnet-beta): cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
Program ID (devnet): cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
Below you can find the main functions to for a new pool:
createPool
createCustomPool
createCustomPoolWithDynamicConfig
createPosition
addLiquidity
1. Install dependencies and initialize instance
1.1 Install
pnpm install @meteora-ag/cp-amm-sdk
# or
yarn add @meteora-ag/cp-amm-sdk
1.2 Initialization
import { Connection } from "@solana/web3.js";
import { CpAmm } from "@meteora-ag/cp-amm-sdk";
// Initialize a connection to the Solana network
const connection = new Connection("https://api.mainnet-beta.solana.com");
// Create a new instance of the CpAmm SDK
const cpAmm = new CpAmm(connection);
1.3 Test
pnpm install
pnpm test
1.4 Faucets
2. Core Functions and Use Cases
createPool
Creates a new standard pool according to a predefined configuration.
Function
async createPool(params: CreatePoolParams): TxBuilder
Parameters
interface CreatePoolParams {
payer: PublicKey; // The wallet paying for the transaction
creator: PublicKey; // The creator of the pool
config: PublicKey; // The configuration account for the pool
positionNft: PublicKey; // The mint for the initial position NFT
tokenAMint: PublicKey; // The mint address for token A
tokenBMint: PublicKey; // The mint address for token B
activationPoint: BN; // 0: slot, 1: timestamp
tokenAAmount: BN; // Initial amount of token A to deposit
tokenBAmount: BN; // Initial amount of token B to deposit
minSqrtPrice: BN; // Minimum sqrt price (typically MIN_SQRT_PRICE)
maxSqrtPrice: BN; // Maximum sqrt price (typically MAX_SQRT_PRICE)
tokenADecimal: number; // Decimal places for token A
tokenBDecimal: number; // Decimal places for token B
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
}
Returns
A transaction builder (TxBuilder
) that can be used to build, sign, and send the transaction.
Example
const createPoolTx = await cpAmm.createPool({
payer: wallet.publicKey,
creator: wallet.publicKey,
config: configAddress,
positionNft: positionNftMint,
tokenAMint: usdcMint,
tokenBMint: solMint,
activationPoint: new BN(Date.now()),
tokenAAmount: new BN(1_000_000_000), // 1,000 USDC with 6 decimals
tokenBAmount: new BN(5_000_000_000), // 5 SOL with 9 decimals
minSqrtPrice: MIN_SQRT_PRICE,
maxSqrtPrice: MAX_SQRT_PRICE,
tokenADecimal: 6,
tokenBDecimal: 9,
tokenAProgram: TOKEN_PROGRAM_ID,
tokenBProgram: TOKEN_PROGRAM_ID
});
const tx = await createPoolTx.transaction();
const Function = await wallet.sendTransaction(tx, connection);
Notes
Both token amounts must be greater than zero
If using native SOL, it will be automatically wrapped to wSOL
The
config
parameter should be a valid configuration accountPool creation automatically creates an initial position
To set your Pool and Fee Config, please read the instructions in Setting Pool and Fee Config for DAMM v2
createCustomPool
Creates a customizable pool with specific fee parameters, reward settings, and activation conditions.
Function
async createCustomPool(params: InitializeCustomizeablePoolParams): Promise<{
tx: Transaction;
pool: PublicKey;
position: PublicKey;
}>
Parameters
interface InitializeCustomizeablePoolParams {
payer: PublicKey; // The wallet paying for the transaction
creator: PublicKey; // The creator of the pool
positionNft: PublicKey; // The mint for the initial position NFT
tokenAMint: PublicKey; // The mint address for token A
tokenBMint: PublicKey; // The mint address for token B
tokenAAmount: BN; // Initial amount of token A to deposit
tokenBAmount: BN; // Initial amount of token B to deposit
minSqrtPrice: BN; // Minimum sqrt price
maxSqrtPrice: BN; // Maximum sqrt price
tokenADecimal: number; // Decimal places for token A
tokenBDecimal: number; // Decimal places for token B
poolFees: PoolFees; // Fee configuration
hasAlphaVault: boolean; // Whether the pool has an alpha vault
collectFeeMode: number; // How fees are collected (0: normal, 1: alpha)
activationPoint: BN; // The slot or timestamp for activation
activationType: number; // 0: slot, 1: timestamp
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
}
interface PoolFees {
baseFee: {
feeSchedulerMode: number; // 0: Linear, 1: Exponential
cliffFeeNumerator: number;
numberOfPeriod: number;
reductionFactor: number;
periodFrequency: number;
};
partnerFee?: {
partnerAddress: PublicKey;
partnerFeeNumerator: number;
};
dynamicFee?: {
initialized: boolean;
volatilityAccumulator?: number;
binStep?: number;
variableFeeControl?: {
maxFeeNumerator: number;
minFeeNumerator: number;
volatilityThreshold: number;
feeDamper: number;
};
};
}
Returns
An object containing:
tx
: The transaction to sign and sendpool
: The public key of the created poolposition
: The public key of the initial position
Example
const poolFees = {
baseFee: {
feeSchedulerMode: 0, // 0: Linear, 1: Exponential
cliffFeeNumerator: 1_000_000,
numberOfPeriod: 0,
reductionFactor: 0,
periodFrequency: 0
},
partnerFee: {
partnerAddress: partnerWallet.publicKey,
partnerFeeNumerator: 1000,
},
dynamicFee: {
initialized: false
}
};
const { tx, pool, position } = await cpAmm.createCustomPool({
payer: wallet.publicKey,
creator: wallet.publicKey,
positionNft: positionNftMint,
tokenAMint: usdcMint,
tokenBMint: btcMint,
tokenAAmount: new BN(5_000_000_000),
tokenBAmount: new BN(20_000_000),
minSqrtPrice: MIN_SQRT_PRICE,
maxSqrtPrice: MAX_SQRT_PRICE,
tokenADecimal: 6,
tokenBDecimal: 8,
poolFees,
hasAlphaVault: false,
collectFeeMode: 0, // 0: BothToken, 1: onlyB
activationPoint: new BN(Date.now()),
activationType: 1, // 0: slot, 1: timestamp
tokenAProgram: TOKEN_PROGRAM_ID,
tokenBProgram: TOKEN_PROGRAM_ID
});
const Function = await wallet.sendTransaction(tx, connection);
Notes
Use this function instead of
createPool
when you need custom fee structuresDynamic fees can adjust based on market volatility
Partner fees allow a portion of trading fees to be directed to a specific account
Alpha vault is an advanced feature for protocol-owned liquidity
createCustomPoolWithDynamicConfig
Creates a customizable pool with dynamic configuration, allowing for specific fee parameters with specified pool creator authority
Function
async createCustomPoolWithDynamicConfig(params: InitializeCustomizeablePoolWithDynamicConfigParams): Promise<{
tx: Transaction;
pool: PublicKey;
position: PublicKey;
}>
Parameters
interface InitializeCustomizeablePoolWithDynamicConfigParams {
payer: PublicKey; // The wallet paying for the transaction
creator: PublicKey; // The creator of the pool
positionNft: PublicKey; // The mint for the initial position NFT
tokenAMint: PublicKey; // The mint address for token A
tokenBMint: PublicKey; // The mint address for token B
tokenAAmount: BN; // Initial amount of token A to deposit
tokenBAmount: BN; // Initial amount of token B to deposit
sqrtMinPrice: BN; // Minimum sqrt price
sqrtMaxPrice: BN; // Maximum sqrt price
initSqrtPrice: BN; // Initial sqrt price in Q64 format
liquidityDelta: BN; // Initial liquidity in Q64 format
poolFees: PoolFeesParams; // Fee configuration
hasAlphaVault: boolean; // Whether the pool has an alpha vault
collectFeeMode: number; // How fees are collected (0: normal, 1: alpha)
activationPoint: BN | null; // The slot or timestamp for activation (null for immediate)
activationType: number; // 0: slot, 1: timestamp
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
config: PublicKey; // dynamic config account
poolCreatorAuthority: PublicKey; // Authority allowed to create pools with this config
}
Returns
An object containing:
tx
: The transaction to sign and sendpool
: The public key of the created poolposition
: The public key of the initial position
Example
// First, prepare the pool creation parameters
const tokenAAmount = new BN(5_000_000_000);
const tokenBAmount = new BN(20_000_000);
const sqrtPrice = getSqrtPriceFromPrice("172", tokenADecimal, tokenBDecimal);
const sqrtMinPrice = getSqrtPriceFromPrice("4", tokenADecimal, tokenBDecimal);
const sqrtMaxPrice = getSqrtPriceFromPrice("400", tokenADecimal, tokenBDecimal);
const { initSqrtPrice, liquidityDelta } = cpAmm.getLiquidityDelta({
maxAmountTokenA: tokenAAmount,
maxAmountTokenB: tokenBAmount,
sqrtMaxPrice,
sqrtMinPrice,
sqrtPrice,
});
const baseFeeParams = getBaseFeeParams(25, 25, FeeSchedulerMode.Linear, 0, 0); // base fee: 0.25%
const dynamicFeeParams = getDynamicFeeParams(25); // max dynamic fee 0.25%
const poolFees: PoolFeesParams = {
baseFee: baseFeeParams,
protocolFeePercent: 20,
partnerFeePercent: 0,
referralFeePercent: 20,
dynamicFee: dynamicFeeParams,
};
const { tx, pool, position } = await cpAmm.createCustomPoolWithDynamicConfig({
payer
creator,
config: dynamicConfigAddress,
poolCreatorAuthority: poolCreatorAuth.publicKey,
positionNft: positionNftMint,
tokenAMint: usdcMint,
tokenBMint: btcMint,
tokenAAmount,
tokenBAmount,
sqrtMinPrice,
sqrtMaxPrice,
initSqrtPrice,
liquidityDelta,
poolFees,
hasAlphaVault: false,
collectFeeMode: 0, // 0: Both tokens, 1: Only token B
activationPoint: null,
activationType: 1, // 0: slot, 1: timestamp
tokenAProgram: TOKEN_PROGRAM_ID,
tokenBProgram: TOKEN_PROGRAM_ID,
});
createPosition
Creates a new position in an existing pool.
Function
async createPosition(params: CreatePositionParams): TxBuilder
Parameters
interface CreatePositionParams {
owner: PublicKey; // The owner of the position
payer: PublicKey; // The wallet paying for the transaction
pool: PublicKey; // The pool to create a position in
positionNft: PublicKey; // The mint for the position NFT
}
Returns
A transaction builder (TxBuilder
) that can be used to build, sign, and send the transaction.
Example
const createPositionTx = await cpAmm.createPosition({
owner: wallet.publicKey,
payer: wallet.publicKey,
pool: poolAddress,
positionNft: positionNftMint
});
const tx = await createPositionTx.transaction();
const Function = await wallet.sendTransaction(tx, connection);
Notes
The
positionNft
should be a new mint that doesn't already have a positionCreating a position doesn't automatically add liquidity
After creating a position, use
addLiquidity
to provide tokens
addLiquidity
Adds liquidity to an existing position.
Function
async addLiquidity(params: AddLiquidityParams): TxBuilder
Parameters
interface AddLiquidityParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
position: PublicKey; // The position address
positionNftMint: PublicKey; // The position NFT mint
liquidityDeltaQ64: BN; // The amount of liquidity to add in Q64 format
maxAmountTokenA: BN; // Maximum amount of token A to use
maxAmountTokenB: BN; // Maximum amount of token B to use
tokenAAmountThreshold: BN; // Minimum acceptable token A amount (slippage protection)
tokenBAmountThreshold: BN; // Minimum acceptable token B amount (slippage protection)
tokenAMint: PublicKey; // The mint of token A
tokenBMint: PublicKey; // The mint of token B
tokenAVault: PublicKey; // The pool's token A vault
tokenBVault: PublicKey; // The pool's token B vault
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
}
Returns
A transaction builder (TxBuilder
) that can be used to build, sign, and send the transaction.
Example
// Calculate liquidity delta first
const liquidityDelta = await cpAmm.getLiquidityDelta({
maxAmountTokenA: new BN(1_000_000_000), // 1,000 USDC
maxAmountTokenB: new BN(5_000_000_000), // 5 SOL
sqrtPrice: poolState.sqrtPrice,
sqrtMinPrice: MIN_SQRT_PRICE,
sqrtMaxPrice: MAX_SQRT_PRICE
});
// Add liquidity
const addLiquidityTx = await cpAmm.addLiquidity({
owner: wallet.publicKey,
pool: poolAddress,
position: positionAddress,
positionNftMint: positionNftMint,
liquidityDeltaQ64: liquidityDelta,
maxAmountTokenA: new BN(1_000_000_000),
maxAmountTokenB: new BN(5_000_000_000),
tokenAAmountThreshold: new BN(0),
tokenBAmountThreshold: new BN(0),
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAProgram: TOKEN_PROGRAM_ID,
tokenBProgram: TOKEN_PROGRAM_ID
});
const tx = await addLiquidityTx.transaction();
const Function = await wallet.sendTransaction(tx, connection);
Notes
Calculate the liquidity delta first using
getLiquidityDelta
The SDK handles wrapping/unwrapping of SOL automatically
Token accounts are created automatically if they don't exist
Set appropriate thresholds to protect against slippage
For more documentation on DAMM v2 integration, please read this section.
For a high level overview of DAMM v2, please read DAMM v2 Overview.
Last updated