In this guide, Metsumi will walk you through the steps to create a DAMM v2 launch pool on Meteora. Whether you’re a seasoned developer or just starting out, this guide has got you covered to deploy liquidity and launch your project on Meteora.

What You’ll Achieve

By the end of this quicklaunch, you’ll have built a liquidity pool on Meteora by:
  • Configuring your liquidity pool settings
  • Interacting with our DAMM v2 program
  • See your liquidity pool in action on Meteora
Why Meteora?Meteora is a hyper optimized liquidity layer that ensures that your project’s provided liquidity is secure, sustainable and composable for anyone to trade on. By following this guide, you’ll be able to launch a balanced / concentrated / one-sided liquidity pool with dynamic fees on Meteora in just a few quick and easy steps.

Prerequisites

  • Node.js >= 18.0.0
  • pnpm >= 10.0.0
If you don’t have pnpm installed, you can install it by running the following command.
Terminal
npm install -g pnpm

Steps

1

Clone and Setup Meteora Invent

Meteora Invent is a toolkit consisting of everything you need to invent innovative token launches on Meteora. Run the following command in your terminal to get started.
Terminal
git clone https://github.com/MeteoraAg/meteora-invent.git
Once you’ve cloned the repository, you’ll have a new project directory with a meteora-invent folder. Run the following to install pnpm and the project dependencies.
Terminal
cd meteora-invent
pnpm install
2

Optional: Start a Local Test Validator

In Meteora Invent we provide an optional command for you to run a local validator to test your pool before deploying it to devnet or mainnet. Run the following command in your code editor terminal to get started.
Terminal
pnpm studio start-test-validator
This will start a local validator on your machine which will be hosted on http://localhost:8899.

3

Setup Environment Variables

We provide an easy way to setup environment variables when getting started. Run the following command in your code editor terminal to get started.
Terminal
cp studio/.env.example studio/.env
This will copy the example environment variables file to your .env file. Configure the following variables:
  • PRIVATE_KEY - Your private key for the wallet you will be using to deploy the pool.
Therafter, you will need to run this command to generate a keypair from your wallet private key.
Terminal
pnpm studio generate-keypair

# For devnet (airdrops 5 SOL)
pnpm studio generate-keypair --network devnet --airdrop

# For localnet (airdrops 5 SOL)
# Ensure that you have already started the local validator with pnpm start-test-validator
pnpm studio generate-keypair --network localnet --airdrop
This will generate a keypair.json file in the studio directory which will be used for all actions in this guide.

4

Configure your DAMM v2 Pool

Navigate to the studio/config/damm_v2_config.jsonc file and configure your DAMM v2 pool settings.

Your can configure everything DAMM v2 pool related in this file.
The comments in the file are to help you understand the different settings you can configure. Please ensure that you read through the comments while configuring your pool.
damm_v2_config.jsonc
 {
   /* rpcUrl is required. You can switch between mainnet, devnet and localnet or use your own RPC URL. */
   "rpcUrl": "https://api.devnet.solana.com", // mainnet: https://api.mainnet-beta.solana.com | devnet: https://api.devnet.solana.com | localnet: http://localhost:8899

   /* dryRun is required. If true, transactions will be simulated and not executed. If false, transactions will be executed. */
   "dryRun": false,

   /* keypairFilePath is required and will be the payer + signer for all transactions */
   "keypairFilePath": "./keypair.json",

   /* computeUnitPriceMicroLamports is required and can be adjusted to fit your needs */
   "computeUnitPriceMicroLamports": 100000,

   /* quoteMint is required for the following actions:
   * 1. damm-v2-create-balanced-pool
   * 2. damm-v2-create-one-sided-pool
   * SOL: So11111111111111111111111111111111111111112 | USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | any other token address
   */
   "quoteMint": "So11111111111111111111111111111111111111112",

   /* If you have a baseMint already created, you can specify it in the cli command via --baseMint flag. If you don't have a baseMint, you can create a new one using createBaseToken.
   * Either use --baseMint flag or createBaseToken, but not both.
   */
   "createBaseToken": {
     "supply": 1000000000, // total amount of base token to be minted
     "decimals": 6, // decimals of the base token
     // "tokenMintKeypairFilePath": "./mint-keypair.json", // path to token mint keypair if you have a specific keypair for the token mint. If not provided, a new keypair will be generated.
     "name": "YOUR_TOKEN_NAME", // token name
     "symbol": "YOUR_TOKEN_SYMBOL", // token symbol
     "authorities": {
       "mint": "YOUR_MINT_AUTHORITY_ADDRESS", // token mint authority address. <PublicKey | null>
       "freeze": "YOUR_FREEZE_AUTHORITY_ADDRESS", // token freeze authority address. <PublicKey | null>
       "update": "YOUR_UPDATE_AUTHORITY_ADDRESS" // token update authority address. <PublicKey | null>
     },
     /* Optional Metaplex Token Metadata Properties
     * Read more about the properties here: https://developers.metaplex.com/token-metadata
     */
     "sellerFeeBasisPoints": 0, // Royalty fee in basis points (0-10000)
     "creators": null, // Array of creator objects of the token (optional)
     "collection": null, // Collection info (optional)
     "uses": null, // Usage restrictions (optional)
     "metadata": {
       // "uri": "https://gateway.irys.xyz/123456789", // if you already have a metadata URI created, you can specify it here

       /* Only use the following parameters for createBaseToken if you don't have an existing metadata uri
       * This will create an image uri and a new metadata uri and upload everything to Irys
       */
       "image": "./data/image/test-token.jpg", // this can be a URL of the image address (e.g. https://example.com/token-image.png) or the image file path (e.g. ./data/image/test-token.jpg)
       "description": "YOUR_TOKEN_DESCRIPTION", // token description
       "website": "https://example.com", // project website
       "twitter": "https://x.com/yourproject", // twitter URL
       "telegram": "https://t.me/yourproject" // telegram URL
     }
   },

   /* dammV2Config is only used in the following actions:
   * 1. damm-v2-create-balanced-pool
   * 2. damm-v2-create-one-sided-pool
   */
   "dammV2Config": {
     "creator": "YOUR_CREATOR_ADDRESS", // creator address
     "baseAmount": 100000000, // base token amount
     "quoteAmount": null, // quote token amount
     "initPrice": 0.001, // initial price (in terms of quote/base   price) 1 SOL / 1000000000 = initialPrice
     "maxPrice": null, // max price (in terms of quote/base price)
     "poolFees": {
       "maxBaseFeeBps": 120, // max base fee (in basis points)
       "minBaseFeeBps": 120, // min base fee (in basis points)
       "numberOfPeriod": 0, // number of period
       "totalDuration": 0, // total duration (If activationType is 0 (slots), totalDuration = duration / 0.4 | If activationType is 1 (timestamp), totalDuration = duration)
       "feeSchedulerMode": 0, // 0 - Fee Scheduler: Linear | 1 - Fee Scheduler: Exponential
       "useDynamicFee": true // if useDynamicFee is true, the default dynamic fee configuration will be 20% of minBaseFeeBps

       /* Optional Configuration.
       * Only used if you want to configure dynamic fee and not use the default dynamic fee configuration
       * Formula: dynamicFee = (variableFeeControl * (volatilityAccumulator * binStep)^2 + 99_999_999_999) / 100_000_000_000
       */
       // "dynamicFeeConfig": {
       //   "filterPeriod": 10, // Time period (in slots/seconds) over which volatility is measured and smoothed
       //   "decayPeriod": 120, // Time period (in slots/seconds) over which volatility accumulator decays back to zero
       //   "reductionFactor": 5000, // Volatility decay rate in basis points (5000 = 50% reduction per decay period)
       //   "variableFeeControl": 14460000, // Scaling factor that controls how much volatility affects dynamic fees
       //   "maxVolatilityAccumulator": 239 // Maximum allowed volatility accumulator value (caps dynamic fee calculation)
       // }
     },
     "collectFeeMode": 1, // 0 - Both Token | 1 - Token B Only
     "activationType": 1, // 0 - Slot | 1 - Timestamp
     "activationPoint": null, // Activation time of the pool depending on activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp))
     "hasAlphaVault": false // If true, the alpha vault will be created after the pool is created
   },

   /* addLiquidity is only used in the following actions:
   * 1. damm-v2-add-liquidity
   */
   "addLiquidity": {
     "amountIn": 5, // this is the amount of token A or token B that will be added to the pool (in terms of the token amount)
     "isTokenA": false // if your amountIn is in terms of token A, set isTokenA to true, if your amountIn is in terms of token B, set isTokenA to false
   },

   /* splitPosition is only used in the following actions:
   * 1. damm-v2-split-position
   */
   "splitPosition": {
     "newPositionOwner": "YOUR_NEW_POSITION_OWNER_ADDRESS", // this is the address that will receive the new DAMM v2 NFT position
     "unlockedLiquidityPercentage": 50, // this is the percentage of unlocked liquidity that will be split and transferred to the newPositionOwner's position
     "permanentLockedLiquidityPercentage": 50, // this is the percentage of permanent locked liquidity that will be split and transferred to the newPositionOwner's position
     "feeAPercentage": 50, // this is the percentage of unclaimed fee that will be transferred to the newPositionOwner's position
     "feeBPercentage": 50, // this is the percentage of unclaimed fee that will be transferred to the newPositionOwner's position
     "reward0Percentage": 50, // this is the percentage of unclaimed reward that will be transferred to the newPositionOwner's position
     "reward1Percentage": 50 // this is the percentage of unclaimed reward that will be transferred to the newPositionOwner's position
   },

   /* alphaVault is only used in the following actions:
   * 1. damm-v2-create-balanced-pool
   * 2. damm-v2-create-one-sided-pool
   * There are 2 types of alpha vault: First Come First Serve (FCFS) and Prorata.
   */
   "alphaVault": {
     "poolType": "damm2", // DLMM = dlmm | DAMM v1 = dynamic | DAMM v2 = damm2
     "alphaVaultType": "fcfs", // FCFS = fcfs | Prorata = prorata

     /* Only use the following parameters for alphaVaultType: fcfs
     * 1. maxDepositCap
     * 2. individualDepositingCap
     */
     "maxDepositCap": 10000, // Maximum total amount (in quote token) that can be deposited across all users in the vault
     "individualDepositingCap": 1, // Maximum amount (in quote token) that each individual user can deposit

     /* Only use the following parameters for alphaVaultType: prorata
     * 1. maxBuyingCap
     */
     // "maxBuyingCap": 10000, // Maximum total amount (in quote token) that can be bought across all users in the vault

     "depositingPoint": 1733626299, // When users can start depositing depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp))
     "startVestingPoint": 1746808201, // When token vesting begins and users can start claiming their vested tokens depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp))
     "endVestingPoint": 1746808201, // When token vesting ends and all tokens become fully claimable depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp))
     "escrowFee": 0, // Fee amount (in quote token) charged when creating a stake escrow account
     "whitelistMode": "permissionless" // Whitelist mode: permissionless | permissioned_with_merkle_proof | permissioned_with_authority

     /* Optional Configuration: whitelistFilePath
     * Only use when whitelistMode is permissioned_with_merkle_proof or permissioned_with_authority
     */
     // "whitelistFilepath": "./data/whitelist_wallet.csv", // Optional path to CSV file containing whitelisted wallet addresses and their deposit caps (format: wallet,deposit_cap)

     /* Optional Configuration: merkleProofBaseUrl, chunkSize, kvProofFilepath, cloudflareKvProofUpload
     * Only use when whitelistMode is permissioned_with_merkle_proof
     */
     // "merkleProofBaseUrl": "https://example.workers.dev/", // Base URL endpoint where merkle proofs are stored and can be retrieved for whitelisted wallet verification
     // "chunkSize": 1000, // Optional batch size for processing large whitelist files or merkle tree operations to avoid memory/performance issues
     // "kvProofFilepath": "./data/kv_proofs", // Optional path to key-value file storing pre-computed merkle proofs for whitelisted addresses
     // "cloudflareKvProofUpload": {
     //   "kvNamespaceId": "YOUR_KV_NAMESPACE_ID",
     //   "accountId": "YOUR_ACCOUNT_ID",
     //   "apiKey": "YOUR_API_KEY"
     // }
   }
 }
The toolkit contains logic to make it easier for you to create the DAMM v2 pool such as:
  • Minting a new baseMint token or parsing in an existing baseMint token.
  • Launching the DAMM v2 pool immediately or at a certain activationPoint (in slots or timestamp depending on the activationType).
  • Fully customizable pool fees (including fee scheduler and dynamic fee settings).
  • Optional creation of an Alpha Vault with your DAMM v2 launch pool.
5

Create your DAMM v2 Pool

After configuring your DAMM v2 pool settings in damm_v2_config.jsonc, you can now create your pool by running the following command.
If you don’t have a base mint, you can configure createBaseToken in the config file and run the following command.
pnpm studio damm-v2-create-balanced-pool
If you already have a base mint, you can provide it via the CLI with a --baseMint flag and run the following command.
pnpm studio damm-v2-create-balanced-pool --baseMint <YOUR_BASE_MINT_ADDRESS>
Creating a balanced pool will require the quoteAmount to be set in the damm_v2_config.jsonc file.
Voilà! You’ve successfully created your DAMM v2 pool on Meteora. You can now see your pool in action on Meteora either on Meteora’s mainnet or devnet app.