# Alpha Vault Formulas
Source: https://docs.meteora.ag/anti-sniper-suite/alpha-vault/alpha-vault-formulas
Alpha Vault implements a sophisticated vesting and token distribution mechanism with support for both pro-rata and first-come-first-served (FCFS) allocation modes.
# Linear Vesting Formula
The core vesting mechanism follows a linear time-based release schedule:
```math theme={"system"}
\text{claimable\_tokens} = \frac{\text{elapsed\_time} \times \text{total\_bought\_tokens}}{\text{total\_vesting\_duration}}
```
**Where:**
* `elapsed_time` = time since vesting start
* `total_bought_tokens` = total tokens purchased by all users
* `total_vesting_duration` = total duration of vesting period
***
# Individual Token Claim Formula
```math theme={"system"}
\text{user\_claimable} = \frac{\text{total\_claimable} \times \text{user\_deposit}}{\text{total\_vault\_deposit}} - \text{already\_claimed}
```
**Where:**
* `total_claimable` = total tokens available for claiming at current time
* `user_deposit` = individual user's deposit amount
* `total_vault_deposit` = sum of all user deposits in the vault
* `already_claimed` = tokens already claimed by the user
***
# Refund Calculation Formulas
## Base Refund Calculation
```math theme={"system"}
\text{refund} = \frac{\text{unswapped\_amount} \times \text{user\_deposit}}{\text{total\_deposit}}
```
## Deposit Overflow Refund (Pro-rata Vaults)
```math theme={"system"}
\text{overflow\_refund} = \frac{\text{excess\_deposit} \times \text{user\_deposit}}{\text{total\_deposit}}
```
**Where:**
* `excess_deposit` = total deposits exceeding the maximum buying cap
* `unswapped_amount` = tokens that weren't successfully swapped
***
# Swappable Amount Calculation
## Pro-rata Mode
```math theme={"system"}
\text{max\_swappable} = \min(\text{total\_deposit}, \text{max\_buying\_cap})
```
## FCFS Mode
```math theme={"system"}
\text{max\_swappable} = \text{total\_deposit}
```
**Where:**
* `max_buying_cap` = maximum tokens that can be purchased (for pro-rata mode only)
* `total_deposit` = sum of all user deposits
***
# Vault Mode Specifications
## Pro-rata Mode
* No maximum buying cap restriction
* Distributes tokens proportionally among all participants
* Provides refunds for excess deposits
* Suitable for unlimited token sales
## FCFS Mode
* Enforces maximum buying cap
* Tokens distributed on first-come-first-served basis
* No overflow refunds (all deposits are valid)
* Suitable for fair distribution with limited token supply
# Alpha Vault Modes
Source: https://docs.meteora.ag/anti-sniper-suite/alpha-vault/alpha-vault-modes
There are 2 modes for the Alpha Vault:
* Pro Rata Mode
* FCFS Mode (First Come First Serve)
# Pro Rata Mode
In Pro Rata mode, the Alpha Vault is able to accept unlimited deposits of SOL or USDC, even exceeding the Alpha Vault Max Buy Cap.
After depositing SOL or USDC, depositors can choose to withdraw anytime before the end of the deposit period if they change their mind.
Once the deposit period ends, users can no longer deposit more SOL or USDC or withdraw their earlier deposit. The vault becomes active and after a short buffer period, will begin using the funds collected to buy tokens from the pool.
However, the Alpha Vault would only buy tokens up to the max buy cap. As such, if the deposits by users into the Alpha Vault had exceeded the max buy cap, there will be unused funds, and they can be withdrawn by depositors.
For example, you deposited 100 USDC and TVL in the vault (total deposited) is 10M USDC, but the vault max cap is 1M USDC. Only 1/10th of your USDC deposit will be used to purchase tokens. 90 USDC from your 100 USDC deposit will be unused and returned to you.
All vault users get their tokens at the same price and the amount of tokens received is proportional to your share of the total amount of SOL or USDC deposited.
# FCFS Mode
FCFS (First Come First Serve) follows a similar process to Pro Rata mode, but with the following differences:
Unlike Pro rata mode, in FCFS mode, during the deposit period, Alpha Vault max buying cap = max amount of deposits the Alpha Vault accepts. Users can deposit as much as they want initially, but as soon as the vault’s reserve reaches the deposit/buy cap, then no one can deposit more (TVL cannot exceed Vault Max Cap). In other words, deposits are first come first served, up to the Alpha Vault max deposit/buy cap.
For example: If Vault Max Cap is 1M USDC, and a single user is the first to deposit 1M USDC right when deposits open, the vault gets fully filled and no longer accepts further deposits.
By default, each user has no individual deposit cap, which means a single user can technically fill up the entire Alpha Vault deposit/buy cap. However, if required, the project can specify an individual user cap and/or submit a whitelist to allow only certain wallets to deposit.
Once a user deposits funds, the user cannot withdraw them, even during the deposit period.
In FCFS mode, there won’t be any unused USDC or SOL. All deposits would be used to buy the token.
After the Alpha Vault buys the tokens, all depositors will also get tokens at the same average price.
# What's Alpha Vault?
Source: https://docs.meteora.ag/anti-sniper-suite/alpha-vault/what-is-alpha-vault
Available on **DAMM v1**, **DLMM** and **DAMM v2**Meteora UI for DAMM v2 with Alpha Vault is coming soon!
The Alpha Vault is a complementary anti-bot mechanism used together with a Launch Pool that provides early access for genuine supporters to deposit and purchase tokens before the pool starts trading, thereby getting tokens at the earliest price and helping to safeguard the token launch against sniper bots.
Projects who use the Alpha Vault have the flexibility to tailor vault parameters to suit their specific token launch requirements, such as setting maximum purchase limits and defining the lock-up and vesting periods for users.
# Key Features and Benefits
The Alpha Vault is whitelisted to buy tokens from the liquidity pool before the launch activation slot, enabling users to purchase tokens at the earliest (and likely lowest) price before sniper bots can access the pool.
All vault users receive tokens at the same average price, with the amount of tokens distributed proportionally to their share of the total SOL or USDC deposited in the vault.
Projects can configure vault parameters such as lock-up periods (1+ days) and vesting schedules (several days) to encourage purchases by genuine project supporters.
# How does it work?
The Alpha Vault for the Launch Pool is first created together with the Launch Pool, using the project’s preferred configurations for the Alpha Vault and pool, including:
* Alpha Vault mode: Pro rata or FCFS
* To accept SOL or USDC deposits
* Alpha Vault Max Buy Cap
* Pool activation slot/time
* Token lock-up period
* Vesting Period for token claims
* To whitelist addresses for deposits or not
* Individual address purchase cap
## Deposit Period
The Alpha Vault doesn’t hold any tokens at the start. During the deposit period, the Alpha Vault will accept either SOL or USDC from depositors.
There needs to be a buffer period of at least roughly \~1 hour 5 min between the end of the Alpha Vault deposit period and the pool activation time.
## Buying Period
The Alpha Vault is whitelisted to buy tokens from the pool BEFORE the pool is activated to start trading. After the deposit period ends (and before the pool starts trading), the SOL or USDC collected in the Alpha Vault is used to purchase tokens from the pool.
This is essentially a token swap, which means SOL or USDC from the Alpha Vault goes into the pool, while tokens purchased from the pool go into the Alpha Vault. The token pool price would increase from the initial price, based on the token amount purchased by the Alpha Vault.
If the Alpha Vault is using the Pro rata mode (which accepts unlimited deposits), depositors are able to withdraw any unused SOL or USDC that exceeded the Alpha Vault max buy cap.
## Token Claiming
When the token unlocks for claiming, the Alpha Vault then distributes the tokens to depositors. Depositors get tokens at the same price, and the amount of tokens received is based on their share of the total deposits.
Creators can configure the Alpha Vault to their preference; whether token claiming is unlocked immediately when the pool starts trading or at a later time/date, and whether there is a vesting period for token claims.
This vesting solution has the dual benefit of mitigating against sniper bots as well as encouraging purchase from the strongest and most genuine supporters of the project, since they would be more willing to hold their tokens for a longer period. This helps ensure greater alignment between projects and token holders.
## Example Flow of Pro Rata Mode
# Alpha Vault with Whitelist
For some launches, the project may want to restrict which wallet addresses are allowed to deposit funds into the Alpha Vault, so in the config file used in the script to create the Alpha Vault, the `whitelistMode` needs to be specified.
1. `permissionless`: No whitelist, anyone can deposit into the Alpha Vault
2. `permission_with_authority`: In this mode, only the Alpha Vault creator can create escrow account with max\_cap. This allows the creator to use a permissioned (with whitelist) setup without having to use the merkle tree.
* Creator needs to pay SOL rent for each escrow account for the whitelisted wallets, so this Alpha Vault whitelist mode is suitable for scenarios where there are very few whitelisted addresses (e.g. ≤ 100).
* If they need to support a lot more whitelisted addresses, they should still use the merkle tree (PermissionWithMerkleProof whitelist mode).
3. `permission_with_merkle_proof`: In this mode, only wallets that are whitelisted can deposit into the Alpha Vault.
* [CSV file](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/data/whitelist_wallet_example.csv) containing the list of whitelisted wallets needs to be provided by the project to Meteora, for the Merkle proof to be hosted by Meteora and shown on the UI.
* Alpha Vault deposits should not open until the Merkle proof is hosted by Meteora.
# Past Alpha Vault Launches
Projects that have used Alpha Vault for their token launches include **UpRock** (UPT), **Sanctum** (CLOUD), **dVin Labs** (VIN), **deBridge** (DBR), **Streamflow** (STREAM), **SonicVM** (SONIC), and **Sendcoin** (SEND).
Read the CLOUD Launch Case Study [here](https://meteoraag.medium.com/dlmm-case-study-the-cloud-launch-08eaa5ab3b9c).
# Which Launch Pools support Alpha Vault?
Available on DLMM, DAMM v1, and DAMM v2.
# Fee Market Cap Scheduler Math
Source: https://docs.meteora.ag/anti-sniper-suite/fee-market-cap-scheduler/fee-market-cap-scheduler-math
There are two types of Fee Market Cap Schedulers:
1. **Linear** (Mode 3)
2. **Exponential** (Mode 4)
# Math Formula
## Step 1: Calculate Passed Periods
The number of periods passed is determined by how much the sqrt price has increased from the initial price:
Where:
* `current_sqrt_price`: The current sqrt price of the pool
* `initial_sqrt_price`: The initial sqrt price when the pool was created
* `sqrt_price_step_bps`: The sqrt price increase (in bps) required to advance one period
## Step 2: Calculate Current Fee
There are two modes for fee calculation:
### Linear Fee Market Cap Scheduler (Mode 3)
The fee decreases by a percentage of the current fee for each period passed.
# Scheduler Expiration
The scheduler has an expiration mechanism to ensure fees eventually reach the minimum:
```
Expiration Point = Activation Point + Scheduler Expiration Duration
```
* If `current_point > expiration_point`, the scheduler expires
* When expired, the fee defaults to the **minimum fee** (fee calculated at `number_of_period`)
* This prevents fees from staying high indefinitely if the price doesn't increase
# Edge Cases
| Condition | Behavior |
| --------------------------------------- | --------------------------------------------------- |
| `current_sqrt_price <= init_sqrt_price` | `passed_period = 0` (fee stays at cliff fee) |
| `passed_period > number_of_period` | `passed_period = number_of_period` (fee at minimum) |
| Scheduler expired | Fee defaults to minimum fee |
| Alpha Vault buying (before activation) | Fee at minimum fee |
# Example Calculations
## Linear Mode Example
Given:
* `cliff_fee_numerator`: 500,000,000 (50% fee)
* `number_of_period`: 100
* `sqrt_price_step_bps`: 100 (1% sqrt price step)
* `reduction_factor`: 4,950,000
* `init_sqrt_price`: 1,000,000
* `current_sqrt_price`: 1,050,000 (5% increase)
**Step 1: Calculate passed period**
```
Passed Period = (1,050,000 - 1,000,000) × 10,000 / (1,000,000 × 100)
= 50,000 × 10,000 / 100,000,000
= 5 periods
```
**Step 2: Calculate fee**
```
Fee = 500,000,000 - (5 × 4,950,000)
= 500,000,000 - 24,750,000
= 475,250,000 (≈ 47.5% fee)
```
## Exponential Mode Example
Given:
* `cliff_fee_numerator`: 500,000,000 (50% fee)
* `number_of_period`: 100
* `sqrt_price_step_bps`: 100 (1% sqrt price step)
* `reduction_factor`: 390 (3.9% reduction per period)
* `init_sqrt_price`: 1,000,000
* `current_sqrt_price`: 1,050,000 (5% increase)
**Step 1: Calculate passed period**
```
Passed Period = 5 periods (same as above)
```
**Step 2: Calculate fee**
```
Fee = 500,000,000 × (1 - 390/10,000)^5
= 500,000,000 × (0.961)^5
= 500,000,000 × 0.8154
= 407,700,000 (≈ 40.8% fee)
```
# Fee Numerator Conversion
To convert fee numerator to percentage:
```
Fee Percentage = Fee Numerator / 10,000,000
```
Examples:
* 500,000,000 = 50% fee
* 10,000,000 = 1% fee
* 100,000,000 = 10% fee
# What's Fee Market Cap Scheduler?
Source: https://docs.meteora.ag/anti-sniper-suite/fee-market-cap-scheduler/what-is-fee-market-cap-scheduler
Available on **DAMM v2**
Fee Market Cap Scheduler is a configurable fee reduction mechanism based on **price movement (market cap growth)** rather than time. Unlike the Fee Time Scheduler which reduces fees over a fixed time period regardless of price action, Fee Market Cap Scheduler only reduces fees when the token price increases.
# How does it work?
Fee Market Cap Scheduler tracks the sqrt price movement from the initial pool price. As the price increases, the fee decreases according to the configured schedule.
Fee Market Cap Scheduler applies to **graduated DAMM v2 pools** (post-migration), not to pre-graduation DBC bonding curve pools. The fee behavior during the bonding curve phase is controlled by the pre-graduation pool fee settings (Fee Scheduler or Rate Limiter).
Fee Market Cap Scheduler requires the following parameters to be configured:
* **Cliff Fee Numerator**: The starting fee of the scheduler (e.g., 50%).
* **Number Of Periods**: The total number of fee reduction periods.
* **Sqrt Price Step Bps**: The sqrt price increase (in basis points) required to advance one period.
* **Scheduler Expiration Duration**: The maximum duration after which the scheduler expires and defaults to minimum fee.
* **Reduction Factor**: The amount to reduce the fee by per period.
With these parameters, the starting fee will be **Cliff Fee Numerator** and will reduce based on how much the sqrt price has increased from the initial price. Each time the sqrt price increases by **Sqrt Price Step Bps**, the fee advances one period and reduces by **Reduction Factor**.
The change in fee can be based on a **Linear** or **Exponential** fee curve.
Fee decreases at a constant rate as the token price increases. At the same price point, the fee is higher compared to exponential decay.
Fee decreases rapidly at first, then slows down as the token price increases. At the same price point, the fee is lower compared to linear decay.
# Example Configuration
A typical Fee Market Cap Scheduler configuration:
* **Starting Fee**: 50%
* **Ending Fee**: 0.5% (after 100 periods)
* **Sqrt Price Step**: 1% (100 bps) per period
* **Expiration**: 24 hours
This means:
* Fee starts at 50% when the pool launches
* Each 1% increase in sqrt price reduces the fee
* After 100% sqrt price increase, fee reaches minimum 0.5%
* If price doesn't increase enough within 24 hours, fee defaults to 0.5%
Once the `scheduler_expiration_duration` has elapsed, the fee **permanently** defaults to the minimum fee regardless of price movement. This expiration is irreversible even if the price subsequently drops, the fee will remain at the minimum level.
# Simulator
Experiment with different Fee Market Cap Scheduler configurations using the simulator below. Simply clone the spreadsheet and modify the fields to test various scenarios.
Clone this Google Sheet to simulate and experiment with different Fee Market Cap Scheduler configurations.
# Which Launch Pools support Fee Market Cap Scheduler?
Fee Market Cap Scheduler is available as an option for DAMM v2 Launch Pools.
Fee Market Cap Scheduler is mutually exclusive with Fee Time Scheduler and Rate Limiter. Developers must choose one base fee mode for their pool.
# Fee Time Scheduler Math
Source: https://docs.meteora.ag/anti-sniper-suite/fee-time-scheduler/fee-time-scheduler-math
There are two types of fee time schedulers:
1. **Linear**
2. **Exponential**
# Linear Fee Time Scheduler Formula
A linear fee time scheduler is a fee reduction mechanism that decreases trading fees at a constant rate over time.
For Linear \[0]:
Where:
* `cliff_fee_numerator`: The initial fee amount at the start
* `number_of_periods`: The number of time periods
* `reduction_factor`: The constant amount by which the fee decreases each period (expressed in basis points)
# Exponential Fee Time Scheduler Formula
An exponential fee time scheduler is a fee reduction mechanism that decreases trading fees by a percentage of the current rate over time.
For Exponential \[1]:
Where:
* `cliff_fee_numerator`: The initial fee amount at the start
* `reduction_factor`: The reduction factor (expressed in basis points)
* `number_of_periods`: The number of time period
# What's Fee Time Scheduler?
Source: https://docs.meteora.ag/anti-sniper-suite/fee-time-scheduler/what-is-fee-time-scheduler
Available on **DAMM v1**, **DAMM v2** and **DBC**
Fee time scheduler is a configurable fee decay over time.
Creators have the option to use a pool with a configurable fee schedule (time-based) where the base fee starts high and drops over time (linearly or exponentially). This is designed to deter sniper bots by imposing higher fees during the start of the launch and initial launch phase.
# How does it work?
Fee Time Scheduler requires the following parameters to be configured:
* **Cliff Fee Numerator**: The starting fee of the fee time scheduler.
* **Number Of Periods**: The number of time periods to reduce the fee by.
* **Period Frequency**: The frequency of the number of periods.
* **Fee Reduction Factor**: The amount of basis points to reduce the fee by.
With these parameters, the starting fee will be **Cliff Fee Numerator** and the fee will be reduced by **Fee Reduction Factor** for the total duration of **Number Of Periods** multiplied by **Period Frequency**.
The change in fee can be based on a **linear** or **exponential** fee curve.
# DAMM v1 Fee Time Scheduler
In DAMM V1 max fees you can set is 50% and minimum is 0.25%
DAMM v1 uses an off-chain fee time scheduler. For a DAMM v1 pool using the fee time scheduler, the default global fee schedule config used on the Meteora frontend is based on a **Linear** curve, with the following schedule:
Initial fee rate when the pool begins trading
10 minutes after the initial 15% rate begins
120 minutes after the 7% rate starts
120 minutes after the 5% rate starts
120 minutes after the 2% rate starts
120 minutes after the 1% rate starts
950 minutes after the 0.5% rate starts
# DAMM v2 Fee Time Scheduler
In DAMM V2 max fees you can set is 99% and minimum is 0.01%
DAMM v2 uses an on-chain fee time scheduler. For a DAMM v2 pool using the fee time scheduler, the default fee schedule config used on the Meteora frontend is based on an **Exponential** curve, 50% when pool trading starts, and dropping every second for 120 min, ending at 0.25%. DAMM v2 also offers creators and integrators the option of a Linear curve if required.
Read about how [Pump.Science](https://meteoraag.medium.com/damm-v2-case-study-pump-science-d18501c5ef4b) uses DAMM v2's Fee Time Scheduler for its token launchpad.
## Example of an Exponential Fee Time Scheduler
The exponential fee time scheduler reduces fees by a percentage of the current rate over time.
Initial fee rate when the pool begins trading
10 minutes after the initial 50% rate begins
10 minutes after the 32.15% rate starts
10 minutes after the 20.67% rate starts
10 minutes after the 13.29% rate starts
10 minutes after the 8.55% rate starts
10 minutes after the 5.50% rate starts
10 minutes after the 3.53% rate starts
10 minutes after the 2.27% rate starts
10 minutes after the 1.46% rate starts
10 minutes after the 0.94% rate starts
10 minutes after the 0.60% rate starts
10 minutes after the 0.39% rate starts
## Example of a Linear Fee Time Scheduler
Unlike the exponential fee time scheduler which reduces fees by a percentage of the current rate, a linear scheduler reduces fees by a constant rate at each time interval.
# DBC Fee Time Scheduler
In DBC max fees you can set is 99% and minimum is 0.25%
Partners (e.g. launchpads) that integrate DBC to create and launch tokens on their platform, can also configure a fee scheduler as part of the virtual bonding curve.
This way, even before the token is migrated to an actual liquidity pool, snipers that are the first to buy tokens on the virtual bonding curve are subjected to higher swap fees.
## First Swap with Minimum Fee
DBC supports an optional `enableFirstSwapWithMinFee` configuration that allows the pool creator to perform their first swap (buy) without anti-sniper fees. This is particularly useful when:
* Creating a pool and making an initial purchase in a single transaction
* The pool creator wants to acquire tokens at launch without paying elevated anti-sniper fees
When enabled, the first swap instruction in a transaction that includes pool creation will use the minimum base fee instead of the elevated anti-sniper fee. Subsequent swaps will be subject to the normal fee scheduler.
# Which Launch Pools supports Fee Time Scheduler?
Fee Time Scheduler is available as an option for DAMM v1 Launch Pools, DAMM v2 Launch Pools, as well as Dynamic Bonding Curve (DBC).
In addition, Fee Time Scheduler can be used together with Dynamic Fee to bolster the defence against sniper bots at launch.
# Anti Sniper Suite
Source: https://docs.meteora.ag/anti-sniper-suite/home
Sniping tokens is a feature. Choose to turn it on or off with Meteora's Anti Sniper Suite.
For any token launch, sniper bots have an incredibly unfair advantage as they can buy up a substantial portion of the initial token supply right at the activation slot, at the earliest/lowest prices, in order to sell for a quick profit. This prevents tokens from being widely distributed and severely disadvantages genuine users and supporters of the token project.
Meteora has developed an advanced Anti-Sniper Suite (A.S.S.) to counter the threat of mercenary sniper bots during token launches, helping to provide a fairer experience for the community.
# A.S.S. Core Components
Configurable fee decay over time designed to deter sniper bots by imposing higher fees during the initial launch phase.
Configurable fee decay that reduces fees progressively as the token price increases from its starting point.
Configurable fee slope designed to deter sniper bots by increasing the fee depending on the trade size.
A complementary anti-bot mechanism that provides early access for genuine supporters to purchase tokens before the pool starts trading.
# A.S.S. Progress
# Rate Limiter Math
Source: https://docs.meteora.ag/anti-sniper-suite/rate-limiter/rate-limiter-math
Rate Limiter is a configurable fee slope that can charge fees ranging from the configured `base_fee` up to 99% fee (`MAX_FEE`).
# Rate Limiter Formula
The rate limiter uses a progressive fee calculation with the following key components:
Parameters:
* `reference_amount` (x₀): The base reference amount
* `cliff_fee_numerator` (c): The base fee rate
* `fee_increment_bps` (i): The fee increment in basis points
* `max_limiter_duration`: Duration for which the rate limiter is active
The formula depends on the relationship between input\_amount and reference\_amount:
**Case 1: `input_amount ≤ reference_amount`**
```math theme={"system"}
\text{Fee} = \text{Input Amount} \times \text{c}
```
**Case 2: `input_amount > reference_amount`**
First, decompose the excess amount:
```math theme={"system"}
\text{Input Amount} = x_0 + (a \times x_0 + b)
```
where:
* `a`: floor division of `(Input Amount - x₀) / x₀`
* `b`: remainder of `(Input Amount - x₀) mod x₀`
Then calculate fees based on whether we exceed the maximum index:
Max Index can be calculated as:
```math theme={"system"}
\text{Max Index} = \frac{\text{MAX\_FEE\_NUMERATOR} - c}{\text{fee\_increment\_numerator}}
```
where:
* `fee_increment_numerator = (fee_increment_bps * FEE_DENOMINATOR) / 10_000`
**If `a < max_index`**
```math theme={"system"}
\text{Fee} = x_0 \times (c + c \times a + i \times a \times (a+1) / 2) + b \times (c + i \times (a+1))
```
**If `a ≥ max_index`**
```math theme={"system"}
d = a - \text{Max Index}
```
# What's Rate Limiter?
Source: https://docs.meteora.ag/anti-sniper-suite/rate-limiter/what-is-rate-limiter
Available on **DBC** and **DAMM v2**
Rate Limiter is a configurable fee slope designed to deter sniper bots by increasing the fee depending on the trade size.
For example, if a user swaps 100 SOL, then the first SOL will be charged as 1%, the next SOL will be charged as 5%... until it fulfils the full input amount.
Similar to how tax brackets work in the real world, the fee slope increases when the trade size increases.
# How does it work?
Rate Limiter requires the following parameters to be configured:
* **Cliff Fee Numerator**: The base fee of the rate limiter.
* **Reference Amount**: The amount of tokens that will be charged at the base fee.
* **Fee Increment Bps**: The amount of basis points to increase the fee by.
* **Max Limiter Duration**: The maximum duration of the rate limiter.
With these parameters, the fee slope will increase by the **Fee Increment Bps** for each increment of **Reference Amount** of tokens swapped. This rate limiter will last for the duration of **Max Limiter Duration**. Any swap amount below the **Reference Amount** will be charged the **Cliff Fee Numerator**.
# Requirements for Rate Limiter
The rate limiter mode is only available if collect fee mode is in quote token only, and when the user buys the token (not sell).
Rate limiter doesn't allow user to send multiple swap instructions (or CPI) to the same pool in 1 transaction.
Developers have to choose between using Fee Scheduler or Rate Limiter for their pool.
Max limiter duration must be less than or equal to 12 hours.
Example:
If you have:
* `reference_amount` = 1 SOL
* `cliff_fee_numerator` = 1% (100 bps)
* `fee_increment_bps` = 100 bps (1%)
Then:
* Trading 1 SOL: 1% fee
* Trading 2 SOL: 1.5% average fee
* Trading 3 SOL: 2% average fee
* And so on...
# Which Launch Pools support Rate Limiter?
Rate Limiter is available as an option for Dynamic Bonding Curve (DBC) and DAMM v2 Launch Pools.
# get_alpha_vault_configs
Source: https://docs.meteora.ag/api-reference/alpha-vault/get_alpha_vault_configs
/api-reference/damm-v1/openapi.json get /alpha-vault-configs
# get_alpha_vaults
Source: https://docs.meteora.ag/api-reference/alpha-vault/get_alpha_vaults
/api-reference/damm-v1/openapi.json get /alpha-vault
# get_all_analytics
Source: https://docs.meteora.ag/api-reference/analytics/get_all_analytics
/api-reference/stake2earn/openapi.json get /analytics/all
# get_apy_by_time_range
Source: https://docs.meteora.ag/api-reference/apy/get_apy_by_time_range
/api-reference/dynamic-vault/openapi.json get /apy_filter/{token_mint}/{start_timestamp}/{end_timestamp}
Returns APY information for a specific token mint within a given time range
# get_apy_state
Source: https://docs.meteora.ag/api-reference/apy/get_apy_state
/api-reference/dynamic-vault/openapi.json get /apy_state/{token_mint}
Returns APY (Annual Percentage Yield) information for strategies associated with a specific token mint
# Overview
Source: https://docs.meteora.ag/api-reference/damm-v1/overview
**All DAMM V1 APIs have rate limit of 10 Requests per second or 10 RPS.**
Request for Meteora's DAMM v1 Alpha Vault using `GET` `/alpha-vault`
Request for Meteora's DAMM v1 Alpha Vault configs using `GET` `/alpha-vault-configs`
Request for Meteora's DAMM v1 Pools with farm using `GET` `/farm`
Request for Meteora's DAMM v1 Pools configs using `GET` `/pool-configs`
Request for Meteora's DAMM v1 Pools using `GET` `/pools`
Request for Meteora's DAMM v1 Pools metrics using `GET` `/pools-metrics`
Request for Meteora's DAMM v1 Pools metrics by search filter using `GET` `/pools/search`
Request for Meteora's DAMM v1 Pools by tokenA vault lp using `POST` `/get_pools_by_a_vault_lp`
Request for Meteora's DAMM v1 Pools fee configs using `GET` `/fee-config/{config_address}`
# Devnet API
Source: https://docs.meteora.ag/api-reference/damm-v2/devnet
DAMM V2 API for Solana Devnet
This API serves **Solana Devnet** data only. For mainnet, see the [DAMM v2 API Schema](/api-reference/damm-v2/overview).
The DAMM V2 Devnet API is available at `https://dammv2-api.devnet.meteora.ag`.
Explore and test all DAMM V2 Devnet API endpoints interactively.
# Overview
Source: https://docs.meteora.ag/api-reference/damm-v2/overview
**All DAMM V2 APIs have a rate limit of 10 requests per second (10 RPS).** Explore the full spec at the [Swagger UI](https://damm-v2.datapi.meteora.ag/swagger-ui/).
## Pools
Returns a paginated list of pools using `GET` `/pools`
Returns a paginated list of pool groups using `GET` `/pools/groups`
Returns pools that belong to a specific pool group using `GET` `/pools/groups/{lexical_order_mints}`
Returns metadata and current state for a single pool using `GET` `/pools/{address}`
Returns OHLCV candles for a single pool over a time range using `GET` `/pools/{address}/ohlcv`
Returns historical volume for a pool aggregated into time buckets using `GET` `/pools/{address}/volume/history`
## Stats
Returns aggregated protocol-level metrics across all pools using `GET` `/stats/protocol_metrics`
# Group
Source: https://docs.meteora.ag/api-reference/damm-v2/pools/group
/api-reference/damm-v2/openapi.json get /pools/groups/{lexical_order_mints}
Returns a paginated list of pools that belong to a specific pool group
# Groups
Source: https://docs.meteora.ag/api-reference/damm-v2/pools/groups
/api-reference/damm-v2/openapi.json get /pools/groups
Returns a paginated list of pool groups
# Historical Volume
Source: https://docs.meteora.ag/api-reference/damm-v2/pools/historical-volume
/api-reference/damm-v2/openapi.json get /pools/{address}/volume/history
Returns historical volume for a pool aggregated into time buckets
**Notes**
- If both `start_time` and `end_time` are provided, the result covers the range `[start_time, end_time]`
- If only one of `start_time` or `end_time` is provided, the missing bound is inferred using the selected `timeframe`
- If neither is provided, a default range is used based on `timeframe`
# OHLCV
Source: https://docs.meteora.ag/api-reference/damm-v2/pools/ohlcv
/api-reference/damm-v2/openapi.json get /pools/{address}/ohlcv
Returns OHLCV candles for a single pool over a time range
**Notes**
- If both `start_time` and `end_time` are provided, candles are returned in the range `[start_time, end_time]`
- If only one of `start_time` or `end_time` is provided, the missing bound is inferred using the selected `timeframe`
- If neither is provided, a default range is used based on `timeframe`
# Pool
Source: https://docs.meteora.ag/api-reference/damm-v2/pools/pool
/api-reference/damm-v2/openapi.json get /pools/{address}
Returns metadata and current state for a single pool
# Pools
Source: https://docs.meteora.ag/api-reference/damm-v2/pools/pools
/api-reference/damm-v2/openapi.json get /pools
Returns a paginated list of pools
# Protocol Overview
Source: https://docs.meteora.ag/api-reference/damm-v2/stats/protocol-overview
/api-reference/damm-v2/openapi.json get /stats/protocol_metrics
Returns aggregated protocol-level metrics across all pools
# Devnet API
Source: https://docs.meteora.ag/api-reference/dlmm/devnet
DLMM API for Solana Devnet
This API serves **Solana Devnet** data only. For mainnet, see the [DLMM API Schema](/api-reference/dlmm/overview).
The DLMM Devnet API is available at `https://dlmm-api.devnet.meteora.ag`.
Explore and test all DLMM Devnet API endpoints interactively.
# Overview
Source: https://docs.meteora.ag/api-reference/dlmm/overview
**All DLMM APIs have a rate limit of 30 requests per second (30 RPS).** Explore the full spec at the [Swagger UI](https://dlmm.datapi.meteora.ag/swagger-ui/).
## Pools
Returns a paginated list of pools using `GET` `/pools`
Returns a paginated list of pool groups using `GET` `/pools/groups`
Returns pools that belong to a specific pool group using `GET` `/pools/groups/{lexical_order_mints}`
Returns metadata and current state for a single pool using `GET` `/pools/{address}`
Returns OHLCV candles for a single pool over a time range using `GET` `/pools/{address}/ohlcv`
Returns historical volume for a pool aggregated into time buckets using `GET` `/pools/{address}/volume/history`
## Stats
Returns aggregated protocol-level metrics across all pools using `GET` `/stats/protocol_metrics`
# Group
Source: https://docs.meteora.ag/api-reference/dlmm/pools/group
/api-reference/dlmm/openapi.json get /pools/groups/{lexical_order_mints}
Returns a paginated list of pools that belong to a specific pool group
# Groups
Source: https://docs.meteora.ag/api-reference/dlmm/pools/groups
/api-reference/dlmm/openapi.json get /pools/groups
Returns a paginated list of pool groups
# Historical Volume
Source: https://docs.meteora.ag/api-reference/dlmm/pools/historical-volume
/api-reference/dlmm/openapi.json get /pools/{address}/volume/history
Returns historical volume for a pool aggregated into time buckets
**Notes**
- If both `start_time` and `end_time` are provided, the result covers the range `[start_time, end_time]`
- If only one of `start_time` or `end_time` is provided, the missing bound is inferred using the selected `timeframe`
- If neither is provided, a default range is used based on `timeframe`
# OHLCV
Source: https://docs.meteora.ag/api-reference/dlmm/pools/ohlcv
/api-reference/dlmm/openapi.json get /pools/{address}/ohlcv
Returns OHLCV candles for a single pool over a time range
**Notes**
- If both `start_time` and `end_time` are provided, candles are returned in the range `[start_time, end_time]`
- If only one of `start_time` or `end_time` is provided, the missing bound is inferred using the selected `timeframe`
- If neither is provided, a default range is used based on `timeframe`
# Pool
Source: https://docs.meteora.ag/api-reference/dlmm/pools/pool
/api-reference/dlmm/openapi.json get /pools/{address}
Returns metadata and current state for a single pool
# Pools
Source: https://docs.meteora.ag/api-reference/dlmm/pools/pools
/api-reference/dlmm/openapi.json get /pools
Returns a paginated list of pools
# Protocol Overview
Source: https://docs.meteora.ag/api-reference/dlmm/stats/protocol-overview
/api-reference/dlmm/openapi.json get /stats/protocol_metrics
Returns aggregated protocol-level metrics across all pools
# Overview
Source: https://docs.meteora.ag/api-reference/dynamic-vault/overview
**Dynamic Vault APIs have no rate limit.**
Request for Meteora's Dynamic Vault info using `GET` `/vault_info`
Request for Meteora's Dynamic Vault addresses using `GET` `/vault_addresses`
Request for Meteora's Dynamic Vault state using `GET` `/vault_state/{token_mint}`
Request for Meteora's Dynamic Vault APY state using `GET` `/apy_state/{token_mint}`
Request for Meteora's Dynamic Vault APY by time range using `GET` `/apy_filter/{token_mint}/{start_timestamp}/{end_timestamp}`
Request for Meteora's Dynamic Vault virtual price using `GET` `/virtual_price/{token_mint}/{strategy}`
# get_fee_configs
Source: https://docs.meteora.ag/api-reference/fee-configs/get_fee_configs
/api-reference/damm-v1/openapi.json get /fee-config/{config_address}
# Schemas
Source: https://docs.meteora.ag/api-reference/home
13 items
7 items
9 items
4 items
6 items
# filter_and_get_pool_info
Source: https://docs.meteora.ag/api-reference/pools/filter_and_get_pool_info
/api-reference/damm-v1/openapi.json get /pools/search
# get_all_pool_configs
Source: https://docs.meteora.ag/api-reference/pools/get_all_pool_configs
/api-reference/damm-v1/openapi.json get /pool-configs
# get_pools
Source: https://docs.meteora.ag/api-reference/pools/get_pools
/api-reference/damm-v1/openapi.json get /pools
# get_pools_by_a_vault_lp
Source: https://docs.meteora.ag/api-reference/pools/get_pools_by_a_vault_lp
/api-reference/damm-v1/openapi.json post /pools_by_a_vault_lp
# get_pools_metrics
Source: https://docs.meteora.ag/api-reference/pools/get_pools_metrics
/api-reference/damm-v1/openapi.json get /pools-metrics
# get_pools_with_farm
Source: https://docs.meteora.ag/api-reference/pools/get_pools_with_farm
/api-reference/damm-v1/openapi.json get /farms
# Overview
Source: https://docs.meteora.ag/api-reference/stake2earn/overview
**Stake2earn APIs have no rate limit.**
Request for Meteora's Stake2Earn Analytics using `GET` `/analytics/all`
Request for Meteora's Stake2Earn Vaults using `GET` `/vault/all`
Request for Meteora's Stake2Earn Vaults by filter using `GET` `/vault/filter`
Request for Meteora's Stake2Earn Vaults by vault address using `GET` `/vault/{vault_address}`
# filter_vaults
Source: https://docs.meteora.ag/api-reference/vaults/filter_vaults
/api-reference/stake2earn/openapi.json get /vault/filter
# get_all_vaults
Source: https://docs.meteora.ag/api-reference/vaults/get_all_vaults
/api-reference/stake2earn/openapi.json get /vault/all
# get_one_vault
Source: https://docs.meteora.ag/api-reference/vaults/get_one_vault
/api-reference/stake2earn/openapi.json get /vault/{vault_address}
# get_vault_addresses
Source: https://docs.meteora.ag/api-reference/vaults/get_vault_addresses
/api-reference/dynamic-vault/openapi.json get /vault_addresses
Returns a list of vault addresses with their associated information
# get_vault_info
Source: https://docs.meteora.ag/api-reference/vaults/get_vault_info
/api-reference/dynamic-vault/openapi.json get /vault_info
Returns detailed information about all monitored vaults including their states, strategies, and performance metrics
# get_vault_state
Source: https://docs.meteora.ag/api-reference/vaults/get_vault_state
/api-reference/dynamic-vault/openapi.json get /vault_state/{token_mint}
Returns the current state of a specific vault identified by its token mint address
# get_virtual_price
Source: https://docs.meteora.ag/api-reference/virtual-price/get_virtual_price
/api-reference/dynamic-vault/openapi.json get /virtual_price/{token_mint}/{strategy}
Returns virtual price information for a specific strategy within a vault
# Overview
Source: https://docs.meteora.ag/developer-guide/guides/alpha-vault/overview
Before getting started building on Alpha Vault, you should read the following resource to get a better understanding of how Meteora's Alpha Vault works:
Alpha Vault is a complementary anti-bot mechanism used together with a Launch Pool that provides early access for genuine supporters to deposit and purchase tokens before the pool starts trading.
Alpha Vault has 2 modes: Prorata and FCFS. Prorata allows users to deposit over the max buying cap, with proportional distribution. FCFS allows users to deposit up to the max buying cap, with first-come-first-serve distribution.
***
# Alpha Vault Program
At Meteora, we’ve developed a `Node.js <> Typescript SDK` to make deploying and managing your Alpha Vault easier. The following sections includes information on installing and using the SDKs. It also covers where to find the latest code, and how to contribute to these repositories.
## Program Details
Meteora Alpha Vault Program IDL
Network
Program ID
Mainnet
vaU6kP7iNEGkbmPkLmZfGwiGxd4Mob24QQCie5R9kd2
Devnet
vaU6kP7iNEGkbmPkLmZfGwiGxd4Mob24QQCie5R9kd2
## Official SDKs
Official Meteora Alpha Vault Typescript SDK
# Example Scripts
Source: https://docs.meteora.ag/developer-guide/guides/alpha-vault/typescript-sdk/example-scripts
Alpha Vault
**Alpha Vaults can be configured to either be permissionless or permissioned.**
* For `Permissionless` Alpha Vaults, anyone can deposit assets into the Alpha Vault after creation.
* For permissioned Alpha Vaults, only whitelisted addresses can deposit assets into the Alpha Vault after creation. There are 2 types of permissioned Alpha Vaults:
* `PermissionedWithAuthority` - In this mode, only the Alpha Vault creator can create escrow account with max\_cap. This allows the creator to easily use a permissioned (with whitelist) setup without having to use the merkle tree. Creator needs to pay SOL rent for each escrow account for the whitelisted wallets, so this Alpha Vault whitelist mode is suitable for scenarios where there are very few whitelisted addresses `(e.g. <=100)`. If they need to support a lot more whitelisted addresses, they should still use the merkle tree (PermissionWithMerkleProof whitelist mode).
* `PermissionedWithMerkleProof` - In this mode, only wallets that are whitelisted can deposit into the Alpha Vault. CSV file containing the list of whitelisted wallets needs to be provided by the project to Meteora, for the Merkle proof to be hosted by Meteora and shown on the UI. Alpha Vault deposits should not open until the Merkle proof is hosted by Meteora.
# Example Timeline of an Alpha Vault
# Code Examples
### Creating an Alpha Vault
This example shows how to create a new DAMM v1 Pool that also adds a permissionless Alpha Vault.
You have to find a pool config and vault config that meets your requirements. Please contact us on [discord](https://discord.gg/meteora) if you need new pool configs or vault configs. Currently, only SOL or USDC is accepted as the quote token when initializing a DAMM v1 Pool with Alpha Vault in a permissionless setup.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
SYSVAR_CLOCK_PUBKEY,
} from "@solana/web3.js";
import AlphaVault, { DYNAMIC_AMM_PROGRAM_ID, PoolType, VaultMode } from "..";
import AmmImpl from "@meteora-ag/dynamic-amm-sdk";
import {
ActivationType,
Clock,
ClockLayout,
createTokenAndMint,
loadKeypairFromFile,
} from "./utils";
import dotenv from "dotenv";
import { BN } from "bn.js";
import { derivePoolAddressWithConfig } from "@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils";
dotenv.config();
async function createDummyMints(connection: Connection, payer: Keypair) {
console.log("Creating mint A");
const mintAInfo = await createTokenAndMint(
connection,
payer,
6,
100_000_000_000
);
console.log("Creating mint B");
const mintBInfo = await createTokenAndMint(
connection,
payer,
6,
100_000_000_000
);
return {
mintAInfo,
mintBInfo,
};
}
/**
* @param connection
* @param creator
* @param activationType Pool activation based on time or slot
* @param maximumActivationDuration Maximum duration for pool to be activation after creation
* @param minimumLockDuration Minimum duration for bought token be locked
* @param maximumLockDuration Maximum duration for bought token to be locked
* @param minimumVestingDuration Minimum duration for bought token to be vested
* @param maximumVestingDuration Maximum duration for bought token be vested
* @param vaultMode Vault mode: fcfs or prorata
*/
async function getPoolConfigByRequirement(
connection: Connection,
creator: PublicKey,
activationType: ActivationType,
maximumActivationDuration: number,
minimumLockDuration: number,
maximumLockDuration: number,
minimumVestingDuration: number,
maximumVestingDuration: number,
vaultMode: VaultMode
) {
// 1. Pool configs that can be used by anyone to create pool
const publicPoolConfigs =
await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
connection,
PublicKey.default
);
// 2. Pool configs that can only be used by specific pubkey to create pool
const creatorPoolConfigs =
await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
connection,
creator
);
// 3. Look for pool configs that have vault support
const poolConfigsWithVaultSupport = [
...publicPoolConfigs,
...creatorPoolConfigs,
].filter((config) => config.account.vaultConfigKey != PublicKey.default);
console.log(
`Gotten ${poolConfigsWithVaultSupport.length} usable pool configs with vault support`
);
const configFuture =
vaultMode === VaultMode.FCFS
? AlphaVault.getFcfsConfigs(connection)
: AlphaVault.getProrataConfigs(connection);
const configs = await configFuture;
for (const programAccount of poolConfigsWithVaultSupport) {
const { account } = programAccount;
// 3.1 Pool activation type and duration matches
if (
account.activationType == activationType &&
account.activationDuration.toNumber() >= maximumActivationDuration
) {
const vaultConfig = configs.find((c) =>
c.publicKey.equals(account.vaultConfigKey)
);
if (!vaultConfig) {
continue;
}
const startVestingDuration =
vaultConfig.account.startVestingDuration.toNumber();
const endVestingDuration =
vaultConfig.account.endVestingDuration.toNumber();
const vestingDuration = endVestingDuration - startVestingDuration;
// 3.2 Vault activation type, lock and vesting duration matches
if (
startVestingDuration >= minimumLockDuration &&
startVestingDuration <= maximumLockDuration &&
vestingDuration >= minimumVestingDuration &&
vestingDuration <= maximumVestingDuration &&
vaultConfig.account.activationType == activationType
) {
return programAccount;
}
}
}
return null;
}
async function createDynamicPoolWithPermissionlessVault(
connection: Connection,
payer: Keypair
) {
const { mintAInfo, mintBInfo } = await createDummyMints(connection, payer);
// Pool and vault requirement
const maximumActivationDuration = 86400; // 1 day
const minimumLockDuration = 60 * 30; // 30 minutes
const maximumLockDuration = 86400; // 1 day
const minimumVestingDuration = 60 * 60; // 1 hour
const maximumVestingDuration = 60 * 60 * 24 * 7; // 1 week
const vaultMode = VaultMode.PRORATA;
// 1. Find pool config where it allow user to create pool with customizable start trading time which start from NOW -> NOW + 24H
// With lock duration fall between 30 minutes -> 1 days (non customizable)
// And vesting duration fall between 1 hour -> 1 week (non customizable)
// And prorata vault
const poolConfig = await getPoolConfigByRequirement(
connection,
payer.publicKey,
ActivationType.Timestamp,
maximumActivationDuration,
minimumLockDuration,
maximumLockDuration,
minimumVestingDuration,
maximumVestingDuration,
vaultMode
);
console.log("Got pool config");
console.log(poolConfig);
const clockAccount = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY);
const clock: Clock = ClockLayout.decode(clockAccount.data);
// Pool start trade after created for 5 hour
const activationPoint = clock.unixTimestamp.add(new BN(3600 * 5));
// 2. Create the pool
const transactions =
await AmmImpl.createPermissionlessConstantProductPoolWithConfig2(
connection,
payer.publicKey,
mintAInfo.mint,
mintBInfo.mint,
new BN(100_000_000),
new BN(100_000_000),
poolConfig.publicKey,
{
activationPoint,
}
);
console.log("Creating pool");
for (const tx of transactions) {
const txHash = await sendAndConfirmTransaction(connection, tx, [payer]);
console.log(txHash);
}
const poolPubkey = derivePoolAddressWithConfig(
mintAInfo.mint,
mintBInfo.mint,
poolConfig.publicKey,
DYNAMIC_AMM_PROGRAM_ID
);
console.log("Pool created", poolPubkey.toBase58());
// 3. Create the alpha vault
const initPermissionlessVaultTx = await AlphaVault.createPermissionlessVault(
connection,
{
baseMint: mintAInfo.mint,
quoteMint: mintBInfo.mint,
poolType: PoolType.DYNAMIC,
vaultMode: VaultMode.PRORATA,
poolAddress: poolPubkey,
config: poolConfig.account.vaultConfigKey,
},
payer.publicKey
);
console.log("Creating vault");
const txHash = await sendAndConfirmTransaction(
connection,
initPermissionlessVaultTx,
[payer]
);
console.log(txHash);
}
const connection = new Connection(clusterApiUrl("devnet"));
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to create dynamic pool with permissionless vault
* Please contact meteora team if the existing pool and vault config doesn't meet the requirement
* Currently only dynamic pool support permissionless vault
*/
createDynamicPoolWithPermissionlessVault(connection, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
**Note for token vesting period:**
* `startVestingSlot = poolState.activationSlot + startVestingDuration`
* `endVestingSlot = poolState.activationSlot + endVestingDuration`
* `startVestingPoint`: Absolute value, the slot or timestamp that start vesting depend on the pool activation type. If no vesting is required, you should put this as 1 sec after the pool's activationPoint
* `endVestingPoint`: Absolute value, the slot or timestamp that end vesting depend on the pool activation type. If no vesting is required, this should be the same as startVestingPoint
### Main Steps
This example demonstrates how to use the permissioned Alpha Vault to achieve authorization of user deposit with whitelisted wallet and deposit cap.
1. Update address and deposit cap. Check `whitelist_wallet.csv`.
2. Create a pool with permissioned vault. Check `createDynamicPoolWithPermissionedVault.ts` for more details.
3. Generate merkle tree, and create merkle root config. Check `createMerkleRootConfig.ts` for more details.
4. Deposit with merkle proof. Check `depositWithProof.ts` for more details.
Whitelist CSV file example: [whitelist\_wallet.csv](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/data/whitelist_wallet_example.csv)
This example shows how to create a DAMM v1 Pool with permissioned Alpha Vault (that has a whitelist and deposit cap).
You have to find a pool config and vault config that meets your requirements. Please contact us on [discord](https://discord.gg/meteora) if you need new pool configs or vault configs. Currently, only SOL or USDC is accepted as the quote token when initializing a DAMM v1 Pool with Alpha Vault in a permissionless setup.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
SYSVAR_CLOCK_PUBKEY,
} from "@solana/web3.js";
import AlphaVault, { DYNAMIC_AMM_PROGRAM_ID, PoolType, VaultMode } from "../..";
import AmmImpl from "@meteora-ag/dynamic-amm-sdk";
import {
ActivationType,
Clock,
ClockLayout,
createTokenAndMint,
loadKeypairFromFile,
} from "../utils";
import dotenv from "dotenv";
import { BN } from "bn.js";
import { derivePoolAddressWithConfig } from "@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils";
dotenv.config();
async function createDummyMints(connection: Connection, payer: Keypair) {
console.log("Creating mint A");
const mintAInfo = await createTokenAndMint(
connection,
payer,
6,
100_000_000_000
);
console.log("Creating mint B");
const mintBInfo = await createTokenAndMint(
connection,
payer,
6,
100_000_000_000
);
return {
mintAInfo,
mintBInfo,
};
}
/**
* @param connection
* @param creator
* @param activationType Pool activation based on time or slot
* @param maximumActivationDuration Maximum duration for pool to be activation after creation
* @param minimumLockDuration Minimum duration for bought token be locked
* @param maximumLockDuration Maximum duration for bought token to be locked
* @param minimumVestingDuration Minimum duration for bought token to be vested
* @param maximumVestingDuration Maximum duration for bought token be vested
* @param vaultMode Vault mode: fcfs or prorata
*/
async function getPoolConfigByRequirement(
connection: Connection,
creator: PublicKey,
activationType: ActivationType,
maximumActivationDuration: number,
minimumLockDuration: number,
maximumLockDuration: number,
minimumVestingDuration: number,
maximumVestingDuration: number,
vaultMode: VaultMode
) {
// 1. Pool configs that can be used by anyone to create pool
const publicPoolConfigs =
await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
connection,
PublicKey.default
);
// 2. Pool configs that can only be used by specific pubkey to create pool
const creatorPoolConfigs =
await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
connection,
creator
);
// 3. Look for pool configs that have vault support
const poolConfigsWithVaultSupport = [
...publicPoolConfigs,
...creatorPoolConfigs,
].filter((config) => config.account.vaultConfigKey != PublicKey.default);
console.log(
`Gotten ${poolConfigsWithVaultSupport.length} usable pool configs with vault support`
);
const configFuture =
vaultMode === VaultMode.FCFS
? AlphaVault.getFcfsConfigs(connection)
: AlphaVault.getProrataConfigs(connection);
const configs = await configFuture;
for (const programAccount of poolConfigsWithVaultSupport) {
const { account } = programAccount;
// 3.1 Pool activation type and duration matches
if (
account.activationType == activationType &&
account.activationDuration.toNumber() >= maximumActivationDuration
) {
const vaultConfig = configs.find((c) =>
c.publicKey.equals(account.vaultConfigKey)
);
if (!vaultConfig) {
continue;
}
const startVestingDuration =
vaultConfig.account.startVestingDuration.toNumber();
const endVestingDuration =
vaultConfig.account.endVestingDuration.toNumber();
const vestingDuration = endVestingDuration - startVestingDuration;
// 3.2 Vault activation type, lock and vesting duration matches
if (
startVestingDuration >= minimumLockDuration &&
startVestingDuration <= maximumLockDuration &&
vestingDuration >= minimumVestingDuration &&
vestingDuration <= maximumVestingDuration &&
vaultConfig.account.activationType == activationType
) {
return programAccount;
}
}
}
return null;
}
async function createDynamicPoolWithPermissionedVault(
connection: Connection,
payer: Keypair
) {
const { mintAInfo, mintBInfo } = await createDummyMints(connection, payer);
// Pool and vault requirement
const maximumActivationDuration = 86400; // 1 day
const minimumLockDuration = 60 * 30; // 30 minutes
const maximumLockDuration = 86400; // 1 day
const minimumVestingDuration = 60 * 60; // 1 hour
const maximumVestingDuration = 60 * 60 * 24 * 7; // 1 week
const vaultMode = VaultMode.PRORATA;
// 1.Find pool config where it allow user to create pool with customizable start trading time which start from NOW -> NOW + 24H
// With lock duration fall between 30 minutes -> 1 days (non customizable)
// And vesting duration fall between 1 hour -> 1 week (non customizable)
// And prorata vault
const poolConfig = await getPoolConfigByRequirement(
connection,
payer.publicKey,
ActivationType.Timestamp,
maximumActivationDuration,
minimumLockDuration,
maximumLockDuration,
minimumVestingDuration,
maximumVestingDuration,
vaultMode
);
console.log("Got pool config");
console.log(poolConfig);
const clockAccount = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY);
const clock: Clock = ClockLayout.decode(clockAccount.data);
// Pool start trade after created for 5 hour
const activationPoint = clock.unixTimestamp.add(new BN(3600 * 5));
// 2. Create the pool
const transactions =
await AmmImpl.createPermissionlessConstantProductPoolWithConfig2(
connection,
payer.publicKey,
mintAInfo.mint,
mintBInfo.mint,
new BN(100_000_000),
new BN(100_000_000),
poolConfig.publicKey,
{
activationPoint,
}
);
console.log("Creating pool");
for (const tx of transactions) {
const txHash = await sendAndConfirmTransaction(connection, tx, [payer]);
console.log(txHash);
}
const poolPubkey = derivePoolAddressWithConfig(
mintAInfo.mint,
mintBInfo.mint,
poolConfig.publicKey,
DYNAMIC_AMM_PROGRAM_ID
);
console.log("Pool created", poolPubkey.toBase58());
// 3. Create the alpha vault
const initPermissionlessVaultTx = await AlphaVault.createPermissionedVault(
connection,
{
baseMint: mintAInfo.mint,
quoteMint: mintBInfo.mint,
poolType: PoolType.DYNAMIC,
vaultMode: VaultMode.PRORATA,
poolAddress: poolPubkey,
config: poolConfig.account.vaultConfigKey,
},
payer.publicKey
);
console.log("Creating vault");
const txHash = await sendAndConfirmTransaction(
connection,
initPermissionlessVaultTx,
[payer]
);
console.log(txHash);
}
const connection = new Connection(clusterApiUrl("devnet"));
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to create dynamic pool with permissioned vault
* Please contact meteora team if the existing pool and vault config doesn't meet the requirement
* Currently only dynamic pool support permissioned vault
*/
createDynamicPoolWithPermissionedVault(connection, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
### Creating a Merkle Root Config
This example shows how to create a merkle root config after generating a merkle tree, which is required to verify the whitelisted wallet address data, and enable deposits by whitelisted wallets.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "../utils";
import { AlphaVault } from "../../alpha-vault";
import dotenv from "dotenv";
import { createMerkleTree, loadWhitelistWalletCsv } from "./utils";
import { BN } from "bn.js";
dotenv.config();
async function createMerkleRootConfig(
vault: PublicKey,
csvPath: string,
payer: Keypair
) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
// 1. Load whitelist wallet from csv file
const whitelistWallets = await loadWhitelistWalletCsv(csvPath);
console.log("Loaded whitelist wallets");
console.log(whitelistWallets);
// 2. Create merkle tree
const tree = await createMerkleTree(connection, alphaVault, whitelistWallets);
// 3. Create merkle root config
// If the tree grew too large, one can partition it into multiple tree by setting different version
const version = new BN(0);
const createMerkleRootConfigTx = await alphaVault.createMerkleRootConfig(
tree.getRoot(),
version,
payer.publicKey
);
// 4. Send transaction
console.log("Sending transaction");
const txHash = await sendAndConfirmTransaction(
connection,
createMerkleRootConfigTx,
[payer]
);
console.log(txHash);
}
// Permissioned alpha vault
const vault = new PublicKey("ARGqVVUPPqtqH9UeBHvYsv7AtZv623YdEaEziZ1pdDUs");
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
const whitelistWalletCsvFilepath =
"src/examples/permissioned/whitelist_wallet.csv";
/**
* This example shows how to create merkle root config for permissioned alpha vault
*/
createMerkleRootConfig(vault, whitelistWalletCsvFilepath, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
### Depositing into an Alpha Vault
This example shows how to deposit SOL or USDC into an Alpha Vault. Deposit can only happen before the end of the deposit period.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "./utils";
import { AlphaVault } from "../alpha-vault";
import BN from "bn.js";
import dotenv from "dotenv";
dotenv.config();
async function depositToAlphaVault(
vault: PublicKey,
depositAmount: BN,
payer: Keypair
) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
const depositTx = await alphaVault.deposit(depositAmount, payer.publicKey);
console.log(`Depositing ${depositAmount.toString()}`);
const txHash = await sendAndConfirmTransaction(connection, depositTx, [
payer,
]);
console.log(txHash);
const escrow = await alphaVault.getEscrow(payer.publicKey);
console.log("Escrow info");
console.log(escrow);
}
// Alpha vault to be deposited to
const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
const depositAmount = new BN(100_000);
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to deposit to alpha vault. Deposit can only happen before the deposit close.
*/
depositToAlphaVault(vault, depositAmount, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
This example shows how to deposit into a permissioned alpha vault using a whitelisted wallet. Deposit can only happen before the end of the deposit period.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "../utils";
import { AlphaVault } from "../../alpha-vault";
import BN from "bn.js";
import dotenv from "dotenv";
import Decimal from "decimal.js";
import { deriveMerkleRootConfig } from "../../alpha-vault/helper";
import { createMerkleTree, loadWhitelistWalletCsv } from "./utils";
import { PROGRAM_ID } from "../../alpha-vault/constant";
dotenv.config();
async function depositToPermissionedAlphaVault(
vault: PublicKey,
depositAmount: BN,
csvPath: string,
payer: Keypair
) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
// 1. Load whitelisted wallet
const whitelistedWallets = await loadWhitelistWalletCsv(csvPath);
// 2. Create merkle tree
const tree = await createMerkleTree(
connection,
alphaVault,
whitelistedWallets
);
// 3. Get wallet proof info
const depositorWhitelistInfo = whitelistedWallets.find((w) =>
w.wallet.equals(payer.publicKey)
);
const quoteMint = await connection.getTokenSupply(alphaVault.vault.quoteMint);
const toNativeAmountMultiplier = new Decimal(10 ** quoteMint.value.decimals);
const nativeDepositCap = new BN(
depositorWhitelistInfo.depositCap.mul(toNativeAmountMultiplier).toString()
);
const depositorProof = tree
.getProof(payer.publicKey, nativeDepositCap)
.map((buffer) => {
return Array.from(new Uint8Array(buffer));
});
const [merkleRootConfig] = deriveMerkleRootConfig(
alphaVault.pubkey,
new BN(0),
new PublicKey(PROGRAM_ID["mainnet-beta"])
);
// 4. Deposit
const depositTx = await alphaVault.deposit(depositAmount, payer.publicKey, {
merkleRootConfig,
maxCap: nativeDepositCap,
proof: depositorProof,
});
console.log(`Depositing ${depositAmount.toString()}`);
const txHash = await sendAndConfirmTransaction(connection, depositTx, [
payer,
]);
console.log(txHash);
const escrow = await alphaVault.getEscrow(payer.publicKey);
console.log("Escrow info");
console.log(escrow);
}
// Alpha vault to be deposited to
const vault = new PublicKey("ARGqVVUPPqtqH9UeBHvYsv7AtZv623YdEaEziZ1pdDUs");
const depositAmount = new BN(100_000);
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
const whitelistWalletCsvFilepath =
"src/examples/permissioned/whitelist_wallet.csv";
/**
* This example shows how to deposit to permissioned alpha vault. Deposit can only happen before the deposit close.
*/
depositToPermissionedAlphaVault(
vault,
depositAmount,
whitelistWalletCsvFilepath,
payer
)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
### Withdrawing from an Alpha Vault
This example shows how to withdraw SOL or USDC from an Alpha Vault. Withdraw function only available before the end of the deposit period, and the function is applicable only when the Alpha Vault is using Pro rata mode.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "./utils";
import { AlphaVault } from "../alpha-vault";
import BN from "bn.js";
import dotenv from "dotenv";
dotenv.config();
async function withdrawFromAlphaVault(
vault: PublicKey,
withdrawAmount: BN,
payer: Keypair
) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
const withdrawTx = await alphaVault.withdraw(withdrawAmount, payer.publicKey);
console.log(`Withdrawing ${withdrawAmount.toString()}`);
const txHash = await sendAndConfirmTransaction(connection, withdrawTx, [
payer,
]);
console.log(txHash);
const escrow = await alphaVault.getEscrow(payer.publicKey);
console.log("Escrow info");
console.log(escrow);
}
// Alpha vault to be withdraw from
const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
const withdrawAmount = new BN(100_000);
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to withdraw from an alpha vault. Withdraw can only happen before the deposit close,
* and it applicable only when the vault is in Prorata mode.
*/
withdrawFromAlphaVault(vault, withdrawAmount, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
This example shows how to withdraw unused SOL or USDC deposit from an Alpha Vault after the Alpha Vault has completed the purchase of tokens from the liquidity pool. This is applicable only for Alpha Vault using Pro rata mode.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "./utils";
import { AlphaVault } from "../alpha-vault";
import BN from "bn.js";
import dotenv from "dotenv";
dotenv.config();
async function withdrawRemainingFromAlphaVault(
vault: PublicKey,
payer: Keypair
) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
const withdrawRemainingTx = await alphaVault.withdrawRemainingQuote(
payer.publicKey
);
console.log(`Withdrawing unused fund`);
const txHash = await sendAndConfirmTransaction(
connection,
withdrawRemainingTx,
[payer]
);
console.log(txHash);
const escrow = await alphaVault.getEscrow(payer.publicKey);
console.log("Escrow info");
console.log(escrow);
}
// Alpha vault to be withdraw / refund from
const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to withdraw remaining unused deposit from an alpha vault after the vault done buying.
*/
withdrawRemainingFromAlphaVault(vault, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
### Cranking an Alpha Vault
This example shows how to crank an Alpha Vault to purchase the base token from the liquidity pool during the crank period. Alpha Vault would purchase tokens using the SOL or USDC deposited into the Alpha Vault earlier.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "./utils";
import { AlphaVault } from "../alpha-vault";
import dotenv from "dotenv";
import { PoolType } from "../alpha-vault/type";
dotenv.config();
async function fillVaultWithDynamicAmm(vault: PublicKey, payer: Keypair) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
console.log(
"Pool type: ",
alphaVault.vault.poolType == PoolType.DYNAMIC ? "Dynamic AMM" : "DLMM"
);
// Dynamic AMM require only single fill transaction
const fillVaultWithDynamicAmmTransaction = await alphaVault.fillVault(
payer.publicKey
);
console.log("Fill vault with dynamic AMM");
const txHash = await sendAndConfirmTransaction(
connection,
fillVaultWithDynamicAmmTransaction,
[payer]
);
console.log(txHash);
}
// Alpha vault to be cranked
const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to crank the vault to purchase base token from the pool, with deposited token from the vault.
*/
fillVaultWithDynamicAmm(vault, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
This example shows how to crank an Alpha Vault to purchase the base token from the liquidity pool during the crank period. Alpha Vault would purchase tokens using the SOL or USDC deposited into the Alpha Vault earlier.
Typically, we have a keeper that cranks the Alpha Vault to automatically purchase tokens from the pool. However, if the auto-crank fails, you can visit this [fillVaultDlmm.ts](https://github.com/MeteoraAg/alpha-vault-sdk/blob/main/ts-client/src/examples/fillVaultDlmm.ts) and input your PublicKey.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "./utils";
import { AlphaVault } from "../alpha-vault";
import dotenv from "dotenv";
import { PoolType, VaultMode } from "../alpha-vault/type";
dotenv.config();
async function fillVaultWithDlmm(vault: PublicKey, payer: Keypair) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
console.log(
"Pool type: ",
alphaVault.vault.poolType == PoolType.DYNAMIC ? "Dynamic AMM" : "DLMM"
);
// DLMM require require one to many transactions
while (true) {
const fillVaultWithDLMMTransaction = await alphaVault.fillVault(
payer.publicKey
);
if (!fillVaultWithDLMMTransaction) {
// Vault bought out the whole pool and still have remaining
break;
}
console.log("Fill vault with DLMM");
const txHash = await sendAndConfirmTransaction(
connection,
fillVaultWithDLMMTransaction,
[payer]
);
console.log(txHash);
await alphaVault.refreshState();
const inAmountCap =
alphaVault.vault.vaultMode == VaultMode.FCFS
? alphaVault.vault.totalDeposit
: alphaVault.vault.totalDeposit.lt(alphaVault.vault.maxBuyingCap)
? alphaVault.vault.totalDeposit
: alphaVault.vault.maxBuyingCap;
if (inAmountCap.eq(alphaVault.vault.swappedAmount)) {
break;
}
}
}
// Alpha vault to be cranked
const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to crank the vault to purchase base token from the pool, with deposited token from the vault.
*/
fillVaultWithDlmm(vault, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
### Claiming from an Alpha Vault
This example shows how to claim tokens from an Alpha Vault after it has purchased those tokens from the liquidity pool. Claiming can only happen after the start of the vesting period.
**Important Reminder**: Claim start time should NOT be earlier than Pool activation time
For a new token launch, the project should ensure that token claiming from the Alpha Vault is NOT possible before the launch pool trading activation or before the token starts trading anywhere, whether on a Dynamic AMM or DLMM Pool. If users are able to claim tokens before the launch pool/token starts trading, they may create a separate market with a price that deviates from the project's preferred launch price.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "./utils";
import { AlphaVault } from "../alpha-vault";
import dotenv from "dotenv";
dotenv.config();
async function claimBoughtTokenFromAlphaVault(
vault: PublicKey,
payer: Keypair
) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
const claimTx = await alphaVault.claimToken(payer.publicKey);
console.log("Claiming bought token");
const txHash = await sendAndConfirmTransaction(connection, claimTx, [payer]);
console.log(txHash);
const escrow = await alphaVault.getEscrow(payer.publicKey);
console.log("Escrow info");
console.log(escrow);
}
// Alpha vault to be deposited to
const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to claim bought token from an alpha vault. Claim can only happen when the vesting start.
*/
claimBoughtTokenFromAlphaVault(vault, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
### Close Escrow Account
When a user deposits to the vault, it will create an escrow account, which stores the user info, such as deposit, claimed token, etc. Once user fully claims all tokens, they can close the escrow account.
Close escrow can only happen after vesting of tokens is complete, and the escrow has claimed all the bought token. This example shows how to close an escrow account and get rental back.
```typescript theme={"system"}
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { loadKeypairFromFile } from "./utils";
import { AlphaVault } from "../alpha-vault";
import dotenv from "dotenv";
dotenv.config();
async function closeEscrow(vault: PublicKey, payer: Keypair) {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const alphaVault = await AlphaVault.create(connection, vault);
const claimTx = await alphaVault.closeEscrow(payer.publicKey);
console.log("Close escrow");
const txHash = await sendAndConfirmTransaction(connection, claimTx, [payer]);
console.log(txHash);
}
// Alpha vault to be deposited to
const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
/**
* This example shows how to close an escrow account and get rental back. Close escrow can only happen after vesting is complete, and escrow have claimed all the bought token.
*/
closeEscrow(vault, payer)
.then(() => {
console.log("Done");
})
.catch(console.error);
```
## Configure Alpha Vault Timings
If you are integrating the Alpha Vault program and need to view and select the predefined timings for the various phases, such as:
* Deposit open time (only for FCFS mode currently)
* Deposit close time
* Vault crank/buy start time
* Vault crank/buy end time
* Withdraw unused USDC or SOL after crank is successful
* Pool Activation time
* Token claim start time
* Vesting start time
* Vesting end time
There must be a \~1 hour 5 minutes period between the deposit close time and the pool activation time.
You can use this config endpoint that has predefined timings created by Meteora.
View all available pool configurations for DAMM v1 Pools with Alpha Vault.
Browse all vault configurations for DAMM v1 Pools with Alpha Vault.
If your preferred configs are not available in the predefined config lists above, and you want more customization, please contact the Meteora team.
## Config endpoint based on Pool Activation Timing
This config endpoint is tied to the pool activation timing, so all timings for the different Alpha Vault phases is derived from the pool activation timing.
In this example below, the claim process will start 3600 seconds (1 hour) after pool activation, and it will end 7200 seconds (2 hours) after pool activation. In other words, after the pool starts trading, tokens are locked first and released for claiming 3600 seconds (1 hour) later.
```typescript theme={"system"}
{
maxBuyingCap: new BN(10000000),
index,
startVestingDuration: new BN(3600),
endVestingDuration: new BN(7200),
escrowFee: new BN(0),
individualDepositingCap: new BN(50000),
activationType: ActivationType.TIMESTAMP,
depositingPoint: new BN(1028979080),
}
```
## Considerations for Slot Parameters
### Alpha Vault Slot Progression
```math theme={"system"}
d \rightarrow j \rightarrow p \rightarrow a \rightarrow s \rightarrow e
```
### Current Slot Condition
```math theme={"system"}
\text{current\_slot} < p
```
Alpha Vault will start to buy from the pool from pre\_activation\_slot ($p$)
### Slot Constraints
```math theme={"system"}
d + 3000 \leq j
```
```math theme={"system"}
j > \text{current\_slot}
```
```math theme={"system"}
j + 750 = p
```
```math theme={"system"}
p + 9000 = a
```
```math theme={"system"}
a < s
```
```math theme={"system"}
e \geq s
```
## User Submission Requirements
```math theme={"system"}
\{d, a, s, e\}
```
## Slot Calculation Guidelines
### Recommended Calculation Sequence
1. **Get Current Slot**
```math theme={"system"}
\text{current\_slot} = \text{getCurrentSlot()}
```
2. **Calculate Activation Slot**
```math theme={"system"}
a = \text{current\_slot} + 9000 + 750 + \text{buffer}
```
3. **Calculate Depositing Slot**
```math theme={"system"}
d = a - 9000 - 3000 - 750 - \text{buffer}
```
4. **Set Vesting Slots**
```math theme={"system"}
e \geq s > a
```
## Slot-to-Timestamp Conversion
```math theme={"system"}
3000 = 20 minutes
```
```math theme={"system"}
750 = 5 minutes
```
```math theme={"system"}
9000 = 1 hour
```
**Note for Quote mint:**
New endpoint only supports wSOL or USDC as Quote mint on mainnet.
Devnet has more flexibility regarding the Quote mint; please reach out to the team.
## Variable Definitions
Where:
* $d$ = depositing\_slot
* $j$ = last\_join\_slot
* $p$ = pre\_activation\_slot
* $a$ = activation\_slot
* $s$ = start\_vesting\_slot
* $e$ = end\_vesting\_slot
## Important Reminders
### A) Claim start time should NOT be earlier than Pool activation time
For a new token launch, the project should ensure that token claiming from the Alpha Vault is NOT possible before the launch pool trading activation or before the token starts trading anywhere, whether on a Dynamic AMM or DLMM Pool. If users are able to claim tokens before the launch pool/token starts trading, they may create a separate market with a price that deviates from the project's preferred launch price.
### B) For Memecoins that want to permanently lock liquidity, lock it before Pool activation time
If the Alpha Vault is used for a Memecoin launch pool, and the project wants to permanently lock liquidity in the Memecoin pool, they should ideally lock the liquidity BEFORE the pool starts trading, so that swap fees from locked liquidity are captured the second trading starts.
In a scenario where:
* The pool started trading - t0
* Liquidity gets deposited to the pool by the project, but not locked - t1
* Subsequently, that liquidity is permanently locked by the project - t2
The project will not be able to claim swap fees earned from t1 to t2, since fees from t1 to t2 are assigned to the LP token before the LP token gets permanently locked. When the LP token gets locked, the earlier fees are locked along with it.
The project will only be able to claim swap fees from locked liquidity starting from t2.
### C) Quote token must be SOL or USDC
Only SOL or USDC is accepted as the quote token when initializing a Dynamic AMM or DLMM Pool with Alpha Vault.
### D) For permissionless Alpha Vault (any wallet can deposit), is there a way to set an individual user cap?
Permissionless FCFS Alpha Vault allows you to set an individual cap, but this will be the same individual cap for everyone.
### E) If no vesting is required, what should the startVestingPoint and endVestingPoint be?
* `startVestingPoint`: Absolute value, the slot or timestamp that start vesting depend on the pool activation type. If no vesting is required, you should put this as 1 sec after the pool's `activationPoint`
* `endVestingPoint`: Absolute value, the slot or timestamp that end vesting depend on the pool activation type. If no vesting is required, this should be the same as startVestingPoint
### F) How do you determine the Alpha Vault deposit close time?
**Crank start point (time when vault buys tokens from the pool):**
* Timestamp-based: `Crank start point = activationPoint - 3600`
* Slot-based: `Crank start point = activationPoint - 9000`
**Vault deposit close point (time when vault deposits close):**
* Timestamp-based Vault: `Deposit close point = Crank start point - 5 min`
* Slot-based Vault: `Deposit close point = Crank start point - 750`
### G) How to crank the Alpha Vault so that it purchases the token from the pool?
Typically, we have a keeper that cranks the Alpha Vault to automatically purchase tokens from the pool.
However, if the auto-crank fails, you can visit this [fillVaultDlmm.ts](https://github.com/MeteoraAg/alpha-vault-sdk/blob/main/ts-client/src/examples/fillVaultDlmm.ts) repo and input your PublicKey.
# Getting Started
Source: https://docs.meteora.ag/developer-guide/guides/alpha-vault/typescript-sdk/getting-started
Alpha Vault
This guide provides instructions on how to get started with building on Meteora's Alpha Vault program using the Alpha Vault TypeScript SDK.
Before you begin, here are some important resources:
Meteora Alpha Vault Typescript SDK
Meteora Alpha Vault NPM Package
# Installation
To use the SDK in your project, install it using your preferred package manager:
```bash theme={"system"}
npm install @meteora-ag/alpha-vault @solana/web3.js
```
```bash theme={"system"}
pnpm install @meteora-ag/alpha-vault @solana/web3.js
```
```bash theme={"system"}
yarn add @meteora-ag/alpha-vault @solana/web3.js
```
# Initialization
Once installed, you can initialize the SDK in your TypeScript/JavaScript project like this:
```typescript theme={"system"}
import { Connection } from "@solana/web3.js";
import { AlphaVault } from "@meteora-ag/alpha-vault";
// Initialize a connection to the Solana network (e.g., Mainnet)
const connection = new Connection("https://api.mainnet-beta.solana.com");
// Intialize the Alpha Vault address
const vault = new PublicKey("H5g71iFUErXyF5D2NcDxP2bJuhdrPBjnDtrVMuPBtnWz");
// Create a new instance of the AlphaVault
const alphaVault = await AlphaVault.create(connection, vault.publicKey);
```
# Testing the SDK (for contributors)
If you have cloned the SDK repository and want to run the built-in tests:
```bash theme={"system"}
# Install dependencies
cd ts-client
bun install
# Run tests
bun test
```
# Development Resources
## Faucets
When working on devnet, you might need test tokens. Here is a helpful faucet.
# Examples
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/cpi/examples
DAMM v1
This [repository](https://github.com/MeteoraAg/cpi-examples) contains examples for Cross-Program Invocation (CPI) that interacts with the DAMM v1 program.
# Dependencies
* **Anchor:** `0.28.0`
* **Solana:** `1.16.1`
* **Rust:** `1.68.0`
# CPI Examples
Example of swapping using Dynamic AMM via CPI.
Example of initializing a pool using Dynamic AMM via CPI.
Example of initializing a pool with configuration using Dynamic AMM via CPI.
Example of locking liquidity using Dynamic AMM via CPI.
Example of claiming fees using Dynamic AMM via CPI.
Comprehensive tests for all the CPI examples.
# Farm Integration
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/farming-sdk/farm-integration
DAMM v1 with Farm
DAMM v1 Pools with Farms are permissioned. Refer to the guide [here](/overview/products/damm-v1/pools-with-farms) on how to get a farming pool created.
# Code Examples
The following code provides detailed examples on how to integrate DAMM v1 pools with farms using the Farming TypeScript SDK.
## Stake
```typescript theme={"system"}
import AmmImpl, { MAINNET_POOL } from "@meteora-ag/dynamic-amm-sdk";
import { PoolFarmImpl } from "@meteora-ag/farming-sdk";
import { Connection } from "@solana/web3.js";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const pool = await AmmImpl.create(connection, MAINNET_POOL.USDC_USDT);
const lpBalance = await pool.getUserBalance(wallet.publicKey);
const farm = await PoolFarmImpl.create(
connection,
new PublicKey("YOUR_FARM_ADDRESS")
);
const stakeTx = await farm.deposit(wallet.publicKey, lpBalance);
```
## Claim
```typescript theme={"system"}
import { PoolFarmImpl } from "@meteora-ag/farming-sdk";
import { Connection } from "@solana/web3.js";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const farm = await PoolFarmImpl.create(
connection,
new PublicKey("YOUR_FARM_ADDRESS")
);
const claimTx = await farm.claim(wallet.publicKey);
```
## Unstake
```typescript theme={"system"}
import { PoolFarmImpl } from "@meteora-ag/farming-sdk";
import { Connection } from "@solana/web3.js";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const farm = await PoolFarmImpl.create(
connection,
new PublicKey("YOUR_FARM_ADDRESS")
);
const farmBalance = await farm.getUserBalance(wallet.publicKey);
const unStakeTx = await farm.withdraw(wallet.publicKey, farmBalance);
```
## Check Stake Balance
```typescript theme={"system"}
import { PoolFarmImpl } from "@meteora-ag/farming-sdk";
import { Connection } from "@solana/web3.js";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const farm = await PoolFarmImpl.create(
connection,
new PublicKey("YOUR_FARM_ADDRESS")
);
const farmBalance = await farm.getUserBalance(wallet.publicKey);
```
# Getting Started
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/farming-sdk/getting-started
DAMM v1 with Farm
This guide provides instructions on how to get started with building on Meteora's DAMM v1 Farming program using the Farming TypeScript SDK.
Before you begin, here are some important resources:
Meteora DAMM v1 Farming Typescript SDK
Meteora DAMM v1 Farming NPM Package
# Installation
To use the Farming SDK in your project, install it using your preferred package manager:
```bash theme={"system"}
npm install @meteora-ag/dynamic-amm-sdk @meteora-ag/farming-sdk @solana/web3.js
```
```bash theme={"system"}
pnpm install @meteora-ag/dynamic-amm-sdk @meteora-ag/farming-sdk @solana/web3.js
```
```bash theme={"system"}
yarn add @meteora-ag/dynamic-amm-sdk @meteora-ag/farming-sdk @solana/web3.js
```
# Initialization
Once installed, you can initialize the Farming SDK in your TypeScript/JavaScript project like this:
```typescript theme={"system"}
import { PoolFarmImpl } from "@meteora-ag/farming-sdk";
import { Connection } from "@solana/web3.js";
// Connection, Wallet, and AnchorProvider to interact with the network
const mainnetConnection = new Connection("https://api.mainnet-beta.solana.com");
const farmingPools = await PoolFarmImpl.getFarmAddressesByPoolAddress(
USDC_acUSDC_POOL
);
// farmingPools is an array (A pool can have multiple farms)
const farmingPool = farmingPools[0];
const farm = await PoolFarmImpl.create(
mainnetConnection,
farmingPool.farmAddress
);
```
You can also get the pool with farm address from the DAMM v1 Pool With Farms [endpoint](/api-reference/pools/get_pools_with_farm).
# Development Resources
## Faucets
When working on devnet, you might need test tokens. Here is a helpful faucet.
# Overview
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/overview
Before getting started building on DAMM v1, you should read the following resource to get a better understanding of how Meteora's DAMM v1 works:
DAMM v1 is Meteora's first AMM product that allows you to provide liquidity to a pool and earn yield from other landing protocols.
DAMM v1 pools with farms allows you to seed rewards to the pool such that liquidity providers can stake their LP tokens to earn the seeded rewards.
Each DAMM v1 pool is a PDA of token mints + config. DAMM v1 configs are available on both mainnet and devnet.
***
# DAMM v1 Program
At Meteora, we’ve developed a `Node.js <> Typescript SDK` and `Rust CPI Examples` to make deploying and managing your DAMM v1 liquidity pool easier. The following sections includes information on installing and using the SDKs and Rust CPI Examples. It also covers where to find the latest code, and how to contribute to these repositories.
## Program Details
### DAMM v1
Meteora DAMM v1 Program IDL
Network
Program ID
Mainnet
Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB
Devnet
Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB
### Farming
Meteora Farming Program IDL
Network
Program ID
Mainnet
FarmuwXPWXvefWUeqFAa5w6rifLkq5X6E8bimYvrhCB1
Devnet
FarmuwXPWXvefWUeqFAa5w6rifLkq5X6E8bimYvrhCB1
## Official SDKs
Official Meteora DAMM v1 Typescript SDK
Official Meteora DAMM v1 Farming Typescript SDK
Official Meteora DAMM v1 Rust CPI Examples
# Pool Fee Configs
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/pool-fee-configs
DAMM v1 pool addresses are derived differently depending on the pool type. Only some pools require a config key - others use just the token mints and curve information.
* **Permissionless pools w/o config**: `curveType` + `tokenAMint` + `tokenBMint`
* **Permissionless pools w/ config**: `tokenAMint` + `tokenBMint` + `config`
* **Permissioned pools**: Use arbitrary addresses (not PDAs)
* **Customizable pools**: `"pool"` + `tokenAMint` + `tokenBMint`
Configs are basically where you configure the fees of the pool and the time the pool starts trading.
In a config, if the `pool_creator_authority` is `11111111111111111111111111111111`, that means that it is a public config and anyone can use the config to create their DAMM v1 pool.
If you would like a private config, such that the `pool_creator_authority` is your specific public address, you can reach out to the team on [discord](https://discord.gg/meteora) to create a private config.
```json theme={"system"}
[
{
config_address: "FiENCCbPi3rFh5pW2AJ59HC53yM32eLaCjMKxRqanKFJ",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 0,
},
{
config_address: "7cADCeqcUsNvYdGFGcPbvghFUwcELovYmHNSauhu2PSh",
trade_fee_bps: 9900,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "24bvHXAxxVT2HxuoBptyG9guhE4vUKUTzFWPVBmHRCzw",
activation_type: 1,
},
{
config_address: "8aPHoLN8ke6PhWeYA7ELi19fppptVYUCQvqKWR5yP1sn",
trade_fee_bps: 150,
protocol_fee_bps: 2000,
activation_duration: 1512000,
vault_config_key: "7ixojP8Zuu4csfTycHi8ywQymHm9zxAhu1TjnFuJaq2R",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 0,
},
{
config_address: "6GEE5m3fYnYD9TgwmPAoeNr3mNaDAhwYjUg2tgmttJYa",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "G9xwsDRa3KUW3JJr9Z38szTVschFCbrCq8NySVXxRGL1",
pool_creator_authority: "anovRrVgxBMyFBZkfcQqVi1AaaJTZEmJ2hVY5V3yCdu",
activation_type: 0,
},
{
config_address: "8NWep2us5HrSPXvf2VGJSHJG9pVr1J3UehVBhE2q9mHU",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 1512000,
vault_config_key: "HHVfAboWxsCsWtdHbyL3BNCvxfAdAcV3QPe8s8NtZxRX",
pool_creator_authority: "ChSAh3XXTxpp5n2EmgSCm6vVvVPoD1L9VrK3mcQkYz7m",
activation_type: 0,
},
{
config_address: "DHuQ3sg5WactGD27KFPebFMUj8B8RZt8KG9NNoCchaKD",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 1512000,
vault_config_key: "DEpRg7voUQcKZapijVKiGPJN2iTGxjQswDoooanrmSHT",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 0,
},
{
config_address: "3Uc2fi7sKEDP1aKUYqc2xGvyD5uNcfoLyMDXa1tBamNt",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 1512000,
vault_config_key: "DEpRg7voUQcKZapijVKiGPJN2iTGxjQswDoooanrmSHT",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 0,
},
{
config_address: "38cy1kpruGc3Xbni4fUF2W1dyh4EbJ4LzccdpnPZxhJk",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FXBXnxEEfwZJA1xnyJzKEhhJXmussKXKRdq5cAh19dbC",
activation_type: 0,
},
{
config_address: "485RajDpU3b39KsQBn4cjnHbkvuodyK6XPpyeTAHnsRC",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 604800,
vault_config_key: "E8WUpiScTWhsdgMaBBGJ8rdUoQuq9P6c7PBcWtrzm6U6",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "4v3NV94mEL4Y3DMVHziPxUe78gmvp74Ez6dLXNQQBwa5",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 604800,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "3ewpimT1McmuHM7CZkehEi3ZHVYg1QiASVxR91GK7Z1L",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 604800,
vault_config_key: "5R3JS7mfW8BCRiQvv4532qaicSc92Hk8JrfBArF4t6Ax",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "BdfD7rrTZEWmf8UbEBPVpvM3wUqyrR8swjAy5SNT8gJ2",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 1512000,
vault_config_key: "2sxe5NvHunqQo485dC7akSKfs2cgq7vaeBe1mRehewP3",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 0,
},
{
config_address: "DxzwNxJTS9VVizrZTnPZe7UAHHkMiN4tbShVitjt3euG",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 1512000,
vault_config_key: "Hhf8R5ebqy4iGPutXmgkJEoioYRy4HJ2mWBhj8tR9KV5",
pool_creator_authority: "anojxBnCMwxvfTrinN6LHbfgYc6yCAdHuvBsFi2Fdjq",
activation_type: 0,
},
{
config_address: "A2md47Zy7pMZuDgSZ7X5HVxrJ32zGrTojdx1WMHjuCuB",
trade_fee_bps: 700,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "45HL2k1QSWczLoqkuAqGfaj5tdHhNDqXL2qeSesN5Gif",
activation_type: 1,
},
{
config_address: "35ZKxwm4K2RTGYoxR3hm3AaL9LFC7zjvxQLyeYBHwrcR",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 16216,
vault_config_key: "DtMkmYxhLCe2mUtkAJjhmBBwGgkdr3e8DuPfWzs5WDf",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 0,
},
{
config_address: "69dxLrPXj1avncD31xiadpHba5b7NEw1ghL8rHCUro76",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 192855,
vault_config_key: "6ocT1Ar8rrsR5MDov9wkmRnv57MYQz4QXnGu1Tn49Pbi",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 0,
},
{
config_address: "4D813BWmm5xSPv7Dda3GNXj14m3cup1crZbZVAZ4iCG6",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "Bd7gSYbgi1sxBZi6rjHs18vnk5zBP71miHgK2Y5w5k1",
activation_type: 0,
},
{
config_address: "GBpFbo2mggDxLW4WzEpus5XEP6DCUBcRXvnA1DVwApP6",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 32653,
vault_config_key: "83ado8rmkVtEvPuwkchDGS3JzhQqRbKqc6bKY2k8ZC7r",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 0,
},
{
config_address: "Du4XRRCirGLBgEotrVbAZnZ3eLdo7gUPwC9ce4zzDgFi",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 1,
},
{
config_address: "AC1hTVdvqiaDtnE3fX2Pf5DmVXLhikgEYBYxjWqY3iZh",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "6Awx9h9cvvPQyu6Eiov6F3Z4j3q9M3Gr2Fz1CaLsgdiv",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "GnfMQ8oPzq84oK4PxTjhC1aUEMrLLasDfF9LsmW46U7j",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "Fp6CXYfHwJQtrLt2iUbj8TPBAfC82sKGwsjfuWGoMKyR",
trade_fee_bps: 1000,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "DNUT6Fzn9Q9Fyatjtrigazn2N8eoKzFkjWvNvrxHN7bX",
activation_type: 0,
},
{
config_address: "ABfKwZb2jtM64MmATmuevT9xXV6AqshfGLumAjH2gikG",
trade_fee_bps: 400,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "FunNTdfawkoBfjJbdsQwo8ZBSKTRHFkpoFUiJQqMepef",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "EGY9HAUcYvbkQcKUARyKXt8qSRayG8Y8694kcUcyKQo4",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 1,
},
{
config_address: "4wvNjCvuoqUEomJqvvoSH7oCDsUqcbeV8DUUs3S3cXms",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "48ZoRd8WFe3bKJeYHnamkkCEXY6kUSqydNg4vYa9Vjmh",
pool_creator_authority: "anoushVdsZq6xLX2pBZ3LWEDPNaHEEY42tKb16xZb9q",
activation_type: 1,
},
{
config_address: "DL1F76GaYj7z6sPHnwQj6dyHtDTHE3CyxG8pVUHynS52",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "34vg8kLiGUQrhUckmKdrirYRmsurcs9m9dtM63JvwSEe",
pool_creator_authority: "anosuzWaGV7Fi1452Cf27MnodcUbszjbYPwDEmDVse7",
activation_type: 1,
},
{
config_address: "5Yv9kVumEY3NAX1tjmPvjfTb8Sb2voopyxdAf2UFeWf",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "5voS8cf3KSumjN23VBnu1N3hCj9Hbyo8aSpSQVQiEQt3",
activation_type: 0,
},
{
config_address: "QdCFZZbjsKN2wp6kbGCov5r9CjAB9chWHLwq8nSHfY3",
trade_fee_bps: 1000,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "5833XAhnaeQ8pStDVA31m8ZgkzxY7RvgnAPRWwtn68b3",
pool_creator_authority: "trcjA29PVgBUM8BbxSVK2mbSc7igZyDQKfQut3W8mWZ",
activation_type: 1,
},
{
config_address: "F75cbaYrHRThofUQLEqHWNpADu9fJNuLrLLDaDSsCvFR",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "HhFWLvAbLs4GZU7v5iGEi1FQKSYmqCqZ3ApBBrhvh6uE",
activation_type: 0,
},
{
config_address: "EgHWiMBpy4mpdTbyaUQ399frFh8iBCsGk8uYnRnPPDdk",
trade_fee_bps: 700,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "GugKgxKf8Y8RYzxsHBwJKcAEWmDiCaQ1wiZF3gmq62sU",
activation_type: 1,
},
{
config_address: "87umT3FP4ezojp6p1e5ALXGSJWmn3h7pusmuk6t3o3Jg",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "HT4XxpmNukMsLtjJFbmN4WQKSx4UxmvqboKZtPw5rkXF",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 1512000,
vault_config_key: "9hi8rMnE5QA2KsQSvUNgsc5kqznPRL43JsNHhFgZvRDA",
pool_creator_authority: "DHLXnJdACTY83yKwnUkeoDjqi4QBbsYGa1v8tJL76ViX",
activation_type: 0,
},
{
config_address: "3LyWzCpB29o4Gi5to4AE8jQEXqnm1av3QhKo5gbSHJWm",
trade_fee_bps: 400,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "7kXYNBXZ4wQH87Da4NLqneoEq4oCopLgSqGQZCy1s28w",
trade_fee_bps: 30,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "DzE3A8Yjuqk61Z4gQ71f2Jx8MgcX7RpxwWzYU3mKCvyh",
trade_fee_bps: 30,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "2XVW9ZzocjYoahYJj4nQb6cCNu42mAFKtEuufnEJjCM3",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "4ZK7qyjRs6KLKFG8m49fLqmLUruunCo4uNLXguFiP1F7",
activation_type: 0,
},
{
config_address: "3H1DdJxJppT8vq9Cv8xva354gkFAfB6x1t71B9KGrfzt",
trade_fee_bps: 250,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "DzG1zpeUVFoEXSq2WHtvx6pAX4DjqnXnUi8AYK6TRLXr",
activation_type: 1,
},
{
config_address: "9NshK22ZKzZHBZtNbvTh1TGV9PZSgdpnKudoGrNzjum2",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "79q4DhyeFTGPxY4vbxaHz8D6cCCwCLH99t3wtiHb8icC",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "85t6rsA3Dm8kTW1rSVjVPNJs4DQtZv7uCMjpaRTH9hQA",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "2rk6ph7H23zMMtoPJw2v6nqq3sGETewvFSiDMt2pB2Sp",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "36oTYeP9K1qEpF3UVRokvjJYrcbA5PZeinYMnd1TgRz1",
pool_creator_authority: "LaiYARKctGpkYLhUxCBsnhxnwwP9swpu4Wcfzvs4bzo",
activation_type: 1,
},
{
config_address: "GQRTZNmE5w1ViwfS72anN2kQejtYRp5fqcXRUsUoXEVt",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "GKuKzmj3bHqd3MVag37rrtVGxP37PzM7pJYF6AYk7Vwq",
pool_creator_authority: "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
activation_type: 1,
},
{
config_address: "AdopETzHcuDbXR2YqtX8UFGesRJ53wumDyfvrbSrvGcV",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "3nwnr3PqGpU7XNaqbyHm7HfrEESkFZaoYu2if8z3kvGr",
trade_fee_bps: 600,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "E144z18vbrojT8w9qv6TVatBMnH8SxTk3PX8JpSLsXGk",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 2592000,
vault_config_key: "GKuKzmj3bHqd3MVag37rrtVGxP37PzM7pJYF6AYk7Vwq",
pool_creator_authority: "LaiYARKctGpkYLhUxCBsnhxnwwP9swpu4Wcfzvs4bzo",
activation_type: 1,
},
{
config_address: "BXBjS1um9TA5s2eYt7bsPmJsxpEEMjmudAUgkPnz5D2n",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "5hB9XMUWdMwA3sDhW7msjPiu3UeFbHyEAurmJC2XrQ93",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "4Q1wpjoQqm9wiwUBinWD1QJjBAqBWXv9PRctRGV6SyMi",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "2kw9BzuMa3S7ETeDUwQ4ihCi8z5EA1Y55kTQLK42UUs1",
trade_fee_bps: 600,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "GJeDrVC2gt4rZtYsEws6i97nwqmEYSPsKxPu7HqQNJc",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "xcombpd6QNcPgGDox13Gzs6AThBkpBynRAPwoGv5qEh",
activation_type: 1,
},
{
config_address: "FjpxYsPxRdoATF196DaQSRb678HZse9vDUHGPgmNvQhz",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "vpayTUGQn1tfgz3pRXsiHyLED7REYtdxN5ZJmVwu6dx",
activation_type: 1,
},
{
config_address: "3bc9EutYtZtiaBknKYS3kNMLE6zQ2GsyxrmEZWMwsmvU",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "4bHoVqLH2cK9t5Mz6ENuULXdv6N7CP33kqSVfVCFArhw",
activation_type: 1,
},
{
config_address: "Ax8R8UL4ZKFm5f4MxUUnFd43ZJiuNuxDCj3siBXPvu4i",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "CtgkceNT71em6gztgda2PoTpewTubY6WiVpZA5SZrbna",
activation_type: 1,
},
{
config_address: "G8SbKnvHwmrnYTKrL9f5fzzTodzrJuWC8BSabMZX6ggL",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "8SXKreuYDfwNzxrK5ETALMHTMohZYvzCRWyhVEJpoxmS",
activation_type: 1,
},
{
config_address: "B6FT4AHhQJ7BttrC1i223km5bYRUA2nVwBR7k5TVwLtx",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "67zLsVD39roVXCtoqs9W1Fzh9Bnz6iCwmF7sY1GEvic6",
activation_type: 1,
},
{
config_address: "Cqq1zjgSj78BZv5e3HGYkspnVuFgCzuuykckonmT3wmp",
trade_fee_bps: 500,
protocol_fee_bps: 2000,
activation_duration: 2678400,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "CtgkceNT71em6gztgda2PoTpewTubY6WiVpZA5SZrbna",
activation_type: 1,
},
{
config_address: "AwByp1HCpy1EWhBVJFy8SXWHNPTmRcYxuRGXKBNZN22P",
trade_fee_bps: 50,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "D97BFQdyppBEPxE9pc4t1ojRzE7ya5ktqUYQeBdr7fhm",
activation_type: 0,
},
{
config_address: "EhNrnrrZsLZ1Q3nFX6BWgBa6AztjrQkUJjrQEM5KJoua",
trade_fee_bps: 50,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "2wqYZThKrjdzyDCwuSKa9QYxYfukT1UFfYJd5Tt4NiKz",
activation_type: 0,
},
{
config_address: "DqqQ2kta9GAkCHzGrNAwJGDn4XDZp9SDYUBFz4z7rKRN",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "EvZRp56QkDXxBE25DitmEBnRBtgzRc5oQohv6eYHUSyP",
activation_type: 1,
},
{
config_address: "9NvCMmU23J6jajinr7snjuYAv5hWbsBXoBTTLAunNL5j",
trade_fee_bps: 50,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "KaHqWi9jE5bC9TNWfcESW3BPs3sqZkPys2HacJ4Schu",
activation_type: 1,
},
{
config_address: "MxnhNaNkt4kS5byYRPU7SbFbN2pixk1XePEEdTLE98s",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "11111111111111111111111111111111",
activation_type: 1,
},
{
config_address: "F7RtuspF6svK3q11gwumdYDfVz7GDvXEs86RMegkCS5c",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "2dWpb3GMTKsExWiEaLdthx8eTZyEmsbENsbrGadd3obA",
activation_type: 1,
},
{
config_address: "AmHTt1YgaVAMo3Ztb87RrwFXWrak7ACNM51fSrCxNPsA",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "2jFFmkuS7xDgCZezogc1nhL491KT6ivvyL1CKnyuLNgj",
activation_type: 1,
},
{
config_address: "6wcDesYCyem9PS1JkrHS8sRk1CvXhFt3MkPYZyK2g34A",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "CmikaQRrP82CsQxyoQmgC1sZxWbG89FDaio2L4t4RYJH",
activation_type: 1,
},
{
config_address: "4eaVQQpBJn1xkiTnJsdLKtcmRhbLmevA4fza5wU9Y3pY",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FkhLsJc5BvwdnZvGzRCyYPUffaFqMQ58z8cbJxa45Cbn",
activation_type: 1,
},
{
config_address: "F3xuaKzaQja4CKSqhjvQyQiNa9YfixS9QYLTeEQMWivP",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "6J3fiYDbNd2SfqFdc5JUf1Jsrt6ckKF4XkiSBVCEQuJ8",
activation_type: 1,
},
{
config_address: "9gYBdabTKGtd8mQxJ4UgaRFR71f7SnB5e8MrvPCwRgVz",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "5VnZiCLgzvb83uAYGEnKuyV4AiPMKJR8TidentThDWLa",
activation_type: 1,
},
{
config_address: "33r7QuiGoRsvxuM3TTzPhuAiXiK3CJSahFz8o1cqX4Sj",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "PawsUuwP1YGsSgJGepigiDCRpPJtfJFMqjNGSueSqhf",
activation_type: 1,
},
{
config_address: "BG9eoMRXUCYZqLB2xyQxDqErXMcqc3JzaEVTJGKpiNH9",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FDWrKWnAmrmJTGjaS5ztxNT6STuFYaYhgRUZd3MewQeY",
activation_type: 0,
},
{
config_address: "EtwbXRxV8b46Vkho5EhMshi9qEU7xv6sMQnPHK3fX8WR",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FDWrKWnAmrmJTGjaS5ztxNT6STuFYaYhgRUZd3MewQeY",
activation_type: 0,
},
{
config_address: "VEtZapzJXreco3cbzUT8ZszawsRvRRQzGN5GBaCMwWh",
trade_fee_bps: 30,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FDWrKWnAmrmJTGjaS5ztxNT6STuFYaYhgRUZd3MewQeY",
activation_type: 0,
},
{
config_address: "8z2tYtwiAkby1tMSdf1hG2Ni8MFBk43o9tYey5zegNDh",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FDWrKWnAmrmJTGjaS5ztxNT6STuFYaYhgRUZd3MewQeY",
activation_type: 0,
},
{
config_address: "3BuQgW3g75azhKeE3yzaqeWkmwezuDGwF6FT5py3mFrt",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FDWrKWnAmrmJTGjaS5ztxNT6STuFYaYhgRUZd3MewQeY",
activation_type: 0,
},
{
config_address: "EkvP7d5yKxovj884d2DwmBQbrHUWRLGK6bympzrkXGja",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FhVo3mqL8PW5pH5U2CN4XE33DokiyZnUwuGpH2hmHLuM",
activation_type: 0,
},
{
config_address: "E4H8USswQ8h8vg2V4TESSefCjKbHSJW3eo4DtPQYfPfP",
trade_fee_bps: 200,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "BC1KA2Rvrea8NqjXBggFga2YnFikWfqtqoTfkjaAN2QH",
activation_type: 1,
},
{
config_address: "6Vhwg9wY65rbMep2wLJatigaF3KXyJUiYgCDynudwK8p",
trade_fee_bps: 500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "HeXJcGfU4qrqGpKAf8bxdYynBgFgTeCphV7YPx9rTMig",
activation_type: 1,
},
{
config_address: "7v5vBdUQHTNeqk1HnduiXcgbvCyVEZ612HLmYkQoAkik",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FhVo3mqL8PW5pH5U2CN4XE33DokiyZnUwuGpH2hmHLuM",
activation_type: 0,
},
{
config_address: "8f848CEy8eY6PhJ3VcemtBDzPPSD4Vq7aJczLZ3o8MmX",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FhVo3mqL8PW5pH5U2CN4XE33DokiyZnUwuGpH2hmHLuM",
activation_type: 0,
},
{
config_address: "HBxB8Lf14Yj8pqeJ8C4qDb5ryHL7xwpuykz31BLNYr7S",
trade_fee_bps: 30,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FhVo3mqL8PW5pH5U2CN4XE33DokiyZnUwuGpH2hmHLuM",
activation_type: 0,
},
{
config_address: "9EZYAJrcqNWNQzP2trzZesP7XKMHA1jEomHzbRsdX8R2",
trade_fee_bps: 400,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FhVo3mqL8PW5pH5U2CN4XE33DokiyZnUwuGpH2hmHLuM",
activation_type: 0,
},
{
config_address: "8cdKo87jZU2R12KY1BUjjRPwyjgdNjLGqSGQyrDshhud",
trade_fee_bps: 600,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "FhVo3mqL8PW5pH5U2CN4XE33DokiyZnUwuGpH2hmHLuM",
activation_type: 0,
},
{
config_address: "DHLo9myvBGbdAL4wn2hkVwphUvFndtzU6zxDqA11m8x6",
trade_fee_bps: 9900,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "GL6VhXKBV9Had23RqU4zm3XDoguuiixN8foqaXSLskDt",
activation_type: 1,
},
{
config_address: "4ZJdHvduu88ZUiJ5ryqUbTDP3dLZjYT5Cfeb8MPqJh9G",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "HeXJcGfU4qrqGpKAf8bxdYynBgFgTeCphV7YPx9rTMig",
activation_type: 1,
},
{
config_address: "9hPtZgNhanLvReByrwyqr9uxhW8TMUg9S4My32nZLGDo",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "HeXJcGfU4qrqGpKAf8bxdYynBgFgTeCphV7YPx9rTMig",
activation_type: 1,
},
{
config_address: "7WrjmZfwqLLfPxBXKM6EJ3fQcYe6x5rwQuPe1BuupBYF",
trade_fee_bps: 100,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "DzG1zpeUVFoEXSq2WHtvx6pAX4DjqnXnUi8AYK6TRLXr",
activation_type: 1,
},
{
config_address: "HFXUgLuJ9hY6tSeqvGUT9J4dJHyZkuP3rogiZR2NgXaT",
trade_fee_bps: 30,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "DzG1zpeUVFoEXSq2WHtvx6pAX4DjqnXnUi8AYK6TRLXr",
activation_type: 1,
},
{
config_address: "2puU1kzQVM5ATDsxCRGixQM9dadmVGd7sTqNJQFBvnKg",
trade_fee_bps: 500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "H4tyRJRzBeppnYCXKpPWsanqf2147QhriJdG4yaBmigr",
activation_type: 1,
},
{
config_address: "Cau4rq22bZEEscAe9TL7CEKnAJjss8csRtKXqjQHmfuj",
trade_fee_bps: 25,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "H4tyRJRzBeppnYCXKpPWsanqf2147QhriJdG4yaBmigr",
activation_type: 1,
},
{
config_address: "5vd4r737pWhmuvrq6E5vea66PYD2WfqGTwsyrV2YEodG",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "H4tyRJRzBeppnYCXKpPWsanqf2147QhriJdG4yaBmigr",
activation_type: 1,
},
{
config_address: "21PjsfQVgrn56jSypUT5qXwwSjwKWvuoBCKbVZrgTLz4",
trade_fee_bps: 1500,
protocol_fee_bps: 2000,
activation_duration: 0,
vault_config_key: "11111111111111111111111111111111",
pool_creator_authority: "CGsqR7CTqTwbmAUTPnfg9Bj9GLJgkrUD9rhjh3vHEYvh",
activation_type: 0,
},
]
```
The list of config key addresses on devnet can be found [here](/api-reference/pools/get_all_pool_configs).
If you want to create an Alpha Vault along with your DAMM v1 pool, you will need to find a `pool_config_key` that is mapped to a `vault_config_key` that meets your requirements.
```json theme={"system"}
{
"prorata_configs": [
{
"address": "5R3JS7mfW8BCRiQvv4532qaicSc92Hk8JrfBArF4t6Ax",
"max_buying_cap": 1000,
"start_vesting_duration": 3600,
"end_vesting_duration": 7200,
"escrow_fee": 0,
"activation_type": 1
},
{
"address": "DxFmi5KH9eqykWAeQ4E7Xughf2TT3nuSpS3zbFYZGGbW",
"max_buying_cap": 10,
"start_vesting_duration": 1,
"end_vesting_duration": 36000,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "DtMkmYxhLCe2mUtkAJjhmBBwGgkdr3e8DuPfWzs5WDf",
"max_buying_cap": 10000,
"start_vesting_duration": 1,
"end_vesting_duration": 18000,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "6ocT1Ar8rrsR5MDov9wkmRnv57MYQz4QXnGu1Tn49Pbi",
"max_buying_cap": 10000,
"start_vesting_duration": 1,
"end_vesting_duration": 192857,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "83ado8rmkVtEvPuwkchDGS3JzhQqRbKqc6bKY2k8ZC7r",
"max_buying_cap": 1000000,
"start_vesting_duration": 1,
"end_vesting_duration": 32653,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "6Awx9h9cvvPQyu6Eiov6F3Z4j3q9M3Gr2Fz1CaLsgdiv",
"max_buying_cap": 18446744073,
"start_vesting_duration": 1,
"end_vesting_duration": 1,
"escrow_fee": 0,
"activation_type": 1
},
{
"address": "G9xwsDRa3KUW3JJr9Z38szTVschFCbrCq8NySVXxRGL1",
"max_buying_cap": 350,
"start_vesting_duration": 1,
"end_vesting_duration": 1365237,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "GKuKzmj3bHqd3MVag37rrtVGxP37PzM7pJYF6AYk7Vwq",
"max_buying_cap": 200,
"start_vesting_duration": 86400,
"end_vesting_duration": 259200,
"escrow_fee": 0,
"activation_type": 1
},
{
"address": "36oTYeP9K1qEpF3UVRokvjJYrcbA5PZeinYMnd1TgRz1",
"max_buying_cap": 200,
"start_vesting_duration": 86400,
"end_vesting_duration": 259200,
"escrow_fee": 0,
"activation_type": 1
}
],
"fcfs_configs": [
{
"address": "HHVfAboWxsCsWtdHbyL3BNCvxfAdAcV3QPe8s8NtZxRX",
"max_depositing_cap": 1177,
"start_vesting_duration": 1,
"end_vesting_duration": 36853081,
"depositing_duration_until_last_join_point": 9000,
"individual_depositing_cap": 1000000,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "DEpRg7voUQcKZapijVKiGPJN2iTGxjQswDoooanrmSHT",
"max_depositing_cap": 1177,
"start_vesting_duration": 1,
"end_vesting_duration": 36940618,
"depositing_duration_until_last_join_point": 8551,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "FgWCWqAwUpYpwLa22F6emXN5c9gQMvDkyfYfKzffzuoX",
"max_depositing_cap": 1,
"start_vesting_duration": 4500,
"end_vesting_duration": 31500,
"depositing_duration_until_last_join_point": 36000,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "2sxe5NvHunqQo485dC7akSKfs2cgq7vaeBe1mRehewP3",
"max_depositing_cap": 125,
"start_vesting_duration": 1,
"end_vesting_duration": 1,
"depositing_duration_until_last_join_point": 41959,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "7ixojP8Zuu4csfTycHi8ywQymHm9zxAhu1TjnFuJaq2R",
"max_depositing_cap": 10,
"start_vesting_duration": 1,
"end_vesting_duration": 24107,
"depositing_duration_until_last_join_point": 24107,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "Hhf8R5ebqy4iGPutXmgkJEoioYRy4HJ2mWBhj8tR9KV5",
"max_depositing_cap": 125,
"start_vesting_duration": 1,
"end_vesting_duration": 1,
"depositing_duration_until_last_join_point": 33098,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "9hi8rMnE5QA2KsQSvUNgsc5kqznPRL43JsNHhFgZvRDA",
"max_depositing_cap": 10,
"start_vesting_duration": 1,
"end_vesting_duration": 24713,
"depositing_duration_until_last_join_point": 33103,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "3QmGDNGSnwwBYNAgokmVkcT6dM7PZGJLziV7VfC4f5er",
"max_depositing_cap": 1,
"start_vesting_duration": 57142,
"end_vesting_duration": 73469,
"depositing_duration_until_last_join_point": 57142,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
},
{
"address": "E8WUpiScTWhsdgMaBBGJ8rdUoQuq9P6c7PBcWtrzm6U6",
"max_depositing_cap": 1000,
"start_vesting_duration": 9000,
"end_vesting_duration": 18000,
"depositing_duration_until_last_join_point": 9000,
"individual_depositing_cap": 100,
"escrow_fee": 0,
"activation_type": 1
},
{
"address": "EGY9HAUcYvbkQcKUARyKXt8qSRayG8Y8694kcUcyKQo4",
"max_depositing_cap": 50,
"start_vesting_duration": 1,
"end_vesting_duration": 1,
"depositing_duration_until_last_join_point": 7200,
"individual_depositing_cap": 50,
"escrow_fee": 0,
"activation_type": 1
},
{
"address": "48ZoRd8WFe3bKJeYHnamkkCEXY6kUSqydNg4vYa9Vjmh",
"max_depositing_cap": 50,
"start_vesting_duration": 1,
"end_vesting_duration": 1,
"depositing_duration_until_last_join_point": 14100,
"individual_depositing_cap": 50,
"escrow_fee": 0,
"activation_type": 1
},
{
"address": "34vg8kLiGUQrhUckmKdrirYRmsurcs9m9dtM63JvwSEe",
"max_depositing_cap": 143,
"start_vesting_duration": 86400,
"end_vesting_duration": 86400,
"depositing_duration_until_last_join_point": 7200,
"individual_depositing_cap": 143,
"escrow_fee": 0,
"activation_type": 1
},
{
"address": "5833XAhnaeQ8pStDVA31m8ZgkzxY7RvgnAPRWwtn68b3",
"max_depositing_cap": 135,
"start_vesting_duration": 1,
"end_vesting_duration": 1,
"depositing_duration_until_last_join_point": 10500,
"individual_depositing_cap": 135,
"escrow_fee": 0,
"activation_type": 1
}
]
}
```
The list of vault config keys on devnet can be found [here](/api-reference/alpha-vault/get_alpha_vault_configs).If there is no existing config in the list that fits your project's requirement, you can reach out to the team on [discord](https://discord.gg/meteora) to create a new config.
# Adding a Fee Scheduler to a Config
For DAMM v1, the anti-snipe Fee Scheduler is applied offchain. Our team at Meteora can assist in applying a custom fee scheduler for your pools where we will create a dedicated config key for your team with `pool_creator_authority` linked to your signer wallet for pool creation.
Because the fee scheduler is applied offchain, Meteora would need to customize the fee curve/schedule for you. You can't do it on your own.
You can use the following API endpoint to check the associated fee scheduler configuration of a config key.
Get the associated fee scheduler configurations for each existing pool config.
# Understanding Pool Config Fields
| Field | Description |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `config_address` | Config key address |
| `trade_fee_bps` | Pool trading fee |
| `protocol_fee_bps` | Protocol fee charged from the total trading fee (fixed at 2000 = 20% for constant product pools; 0 for stable swap pools) |
| `activation_duration` | Used to determine when exactly the pool will start trading |
| `vault_config_key` | Alpha vault config key. Address of the vault config key. If it is `11111111111111111111111111111111`, means no alpha vault. |
| `pool_creator_authority` | Address which can use the pool config key to create a pool. If it is `11111111111111111111111111111111`, it's public and available for everyone to use |
| `activation_type` | Pool activation type. `0` = slot, `1` = time |
**Pool Activation Time Calculation (depending on the `activation_type`)**
* `current_time + activation_duration`
* `current_slot + activation_duration`
# Pool Config Example
```json theme={"system"}
{
"config_address": "FiENCCbPi3rFh5pW2AJ59HC53yM32eLaCjMKxRqanKFJ",
"trade_fee_bps": 1500,
"protocol_fee_bps": 2000,
"activation_duration": 0,
"vault_config_key": "11111111111111111111111111111111",
"pool_creator_authority": "11111111111111111111111111111111",
"activation_type": 0
}
```
# User Flow Example
A pool config may or may not have an associated vault config. There's no vault config associated when the `vault_config_key` is `11111111111111111111111111111111`.
When the pool config has a vault config, user can create the pool + Alpha Vault that is binded (auto-whitelisted) by the pool. The Alpha Vault created will inherit the parameters (Pro Rata / FCFS + buying\_cap, vesting duration, etc.) from the vault config.
## Creating Pool ABC/SOL with an Alpha Vault
Let's say a user wants to create the pool ABC/SOL with an Alpha Vault, the user will need to:
1. **Check for pool config** that have `vault_config_key` not = `1111...`, and `pool_creator_authority` is the user or `1111...` (accessible by the public)
2. **Based on the vault requirement** the user wants, the user will need to:
* a) Check all the pool configs from step 1, which are each mapped to a `vault_config_key`, as well as
* b) Check for vault config and look for one that fits the requirement
3. **If the user finds a requirement** that suits their needs, they can use that `pool_config_key` to create the pool, then use the pool config-mapped `vault_config_key` to create the vault. As long as `vault_config_key` is used, the vault is automatically whitelisted upon pool creation.
All the settings are already predefined by `pool_config` + its mapped `vault_config_key`.
The permutations for pool config + Alpha Vault are created by Meteora. Please reach out to us on [discord](https://discord.gg/meteora) if you need a specific configuration.
### Pool Config Example
```json theme={"system"}
{
"config_address": "8aPHoLN8ke6PhWeYA7ELi19fppptVYUCQvqKWR5yP1sn",
"trade_fee_bps": 150,
"protocol_fee_bps": 2000,
"activation_duration": 1512000,
"vault_config_key": "7ixojP8Zuu4csfTycHi8ywQymHm9zxAhu1TjnFuJaq2R",
"pool_creator_authority": "5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi",
"activation_type": 0
}
```
### Alpha Vault Config Example
```json theme={"system"}
{
"address": "7ixojP8Zuu4csfTycHi8ywQymHm9zxAhu1TjnFuJaq2R",
"max_depositing_cap": 10,
"start_vesting_duration": 1,
"end_vesting_duration": 24107,
"depositing_duration_until_last_join_point": 24107,
"individual_depositing_cap": 1,
"escrow_fee": 0,
"activation_type": 0
}
```
In this example above, only the `pool_creator_authority` => `5unTfT2kssBuNvHPY6LbJfJpLqEcdMxGYLWHwShaeTLi` can use the pool config `8aPHoLN8ke6PhWeYA7ELi19fppptVYUCQvqKWR5yP1sn` to create a pool with the below settings:
* **1.5% fee**
* **20% protocol fee** and **80%** LP fee (fixed Meteora fee for constant product pools)
* Pool starts trading after **1512000 slot** upon creation
* **Slot based activation**
You can also create a binded Alpha Vault with **FCFS config** as shown below:
* Max deposit cap = **10 token**
* Vested over **24106 slot** after pool activate
* Deposit opens at **24107 slot** before vault crank
* Every escrow maximum can only deposit **1 token**
# Example Scripts
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/typescript-sdk/example-scripts
DAMM v1
DAMM v1 SDK supports 3 types of pools:
* **Constant Product Pool (Volatile Pool)** - For non-stablecoin pairs (e.g. SOL-USDC)
* **Stable Pool** - For stablecoin pairs (e.g. USDC-USDT)
* **Stake2Earn Pool** - DAMM v1 pool with Stake2Earn vault mechanism for top stakers
Below are code examples showing how to interact with the `AmmImpl` instance to create these pools and perform key DAMM v1 actions.
If the DAMM v1 Pool is being launched with an Alpha Vault, SOL or USDC must be used as the quote token.
## Create Constant Product Pool (Volatile Pool)
This script creates a Volatile Pool, which is a Dynamic AMM Pool where one or both tokens are non-stablecoins (e.g. SOL-USDC).
```typescript theme={"system"}
import AmmImpl, { PROGRAM_ID } from '@meteora-ag/dynamic-amm-sdk';
import { derivePoolAddressWithConfig } from '@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils';
import { BN } from 'bn.js';
// Token A/B address of the pool.
const tokenAMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
// Configuration address for the pool. It will decide the fees of the pool.
const config = new PublicKey('...');
// Amount of token A and B to be deposited to the pool.
const tokenAAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
// Get pool address
const programId = new PublicKey(PROGRAM_ID);
const poolPubkey = derivePoolAddressWithConfig(tokenAMint, tokenBMint, config, programId);
// Create pool
const transactions = await AmmImpl.createPermissionlessConstantProductPoolWithConfig(
provider.connection,
mockWallet.publicKey, // payer
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
config,
// { // if you need to set the activation point earlier than the default derived from the config
// activationPoint: startTime !== 'now' ? new BN(Math.floor(new Date(startTime).getTime() / 1000)) : undefined,
// },
);
for (const transaction of transactions) {
transaction.sign(mockWallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
```
## Create Stable Pool
This script creates a Stable Pool, which is a Dynamic AMM Pool where both tokens are stablecoins (e.g. USDC-USDT).
**Note:** When using `createPermissionlessPool` to create a permissionless stable pool, it requires the pool to be seeded with a 1:1 token amount (e.g. 1 USDC, 1 USDT).
```typescript theme={"system"}
import AmmImpl, { derivePoolAddress } from '@meteora-ag/dynamic-amm-sdk';
import { BN } from 'bn.js';
// Token A/B address of the pool.
const tokenAMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
const tokenADecimal = 6;
const tokenBDecimal = 6;
const feeBps = new BN(1); // 0.01%
// Get pool address
const poolPubkey = derivePoolAddress(
provider.connection,
tokenAMint,
tokenBMint,
tokenADecimal,
tokenBDecimal,
true, // stable
feeBps,
);
// Create pool
const transactions = await AmmImpl.createPermissionlessPool(
provider.connection,
mockWallet.publicKey, // payer
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
true, // stable,
feeBps,
);
for (const transaction of transactions) {
transaction.sign(mockWallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
```
## Create Memecoin Pool
This script creates a Memecoin Pool, which is a Dynamic AMM Pool with a fee scheduler and initial liquidity permanently locked at creation.
```typescript theme={"system"}
import AmmImpl, { PROGRAM_ID } from '@meteora-ag/dynamic-amm-sdk';
import { derivePoolAddressWithConfig } from '@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils';
import { BN } from 'bn.js';
import { roundToNearestMinutes } from 'date-fns';
// Token A/B address of the pool.
const memecoinMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
const memecoinAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
// Create pool
const programId = new PublicKey(PROGRAM_ID);
const CONFIG_KEY = new PublicKey('..');
const feeConfigurations = await AmmImpl.getFeeConfigurations(provider.connection, {
programId,
});
const feeConfig = feeConfigurations.find(({ publicKey }) => publicKey.equals(CONFIG_KEY));
const transactions = await AmmImpl.createPermissionlessConstantProductMemecoinPoolWithConfig(
provider.connection,
mockWallet.publicKey, // payer
memecoinMint,
tokenBMint,
memecoinAmount,
tokenBAmount,
feeConfig.publicKey,
{ isMinted: true },
);
```
## Create Stake2Earn Pool
This script creates a Stake2Earn Pool, which is a Memecoin Pool with a Stake2Earn Vault mechanism, where top stakers earn fees from the locked liquidity in the Stake2Earn Vault.
```typescript theme={"system"}
import AmmImpl, { PROGRAM_ID } from '@meteora-ag/dynamic-amm-sdk';
import { derivePoolAddressWithConfig } from '@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils';
import { BN } from 'bn.js';
import { roundToNearestMinutes } from 'date-fns';
// Token A/B address of the pool.
const memecoinMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
const memecoinAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
// Create pool
const programId = new PublicKey(PROGRAM_ID);
const CONFIG_KEY = new PublicKey('..');
const feeConfigurations = await AmmImpl.getFeeConfigurations(provider.connection, {
programId,
});
const feeConfig = feeConfigurations.find(({ publicKey }) => publicKey.equals(CONFIG_KEY));
// with Stake2Earn vault
const feeDurationInDays = 7;
const numOfStakers = 1000;
const feeClaimStartTime = roundToNearestMinutes(new Date(), {
nearestTo: 30,
});
const cooldownDurationInHours = 6;
const transactions = await AmmImpl.createPermissionlessConstantProductMemecoinPoolWithConfig(
provider.connection,
mockWallet.publicKey, // payer
memecoinMint,
tokenBMint,
memecoinAmount,
tokenBAmount,
feeConfig.publicKey,
{ isMinted: true },
{
feeVault: {
secondsToFullUnlock: feeDurationInDays ? new BN(feeDurationInDays * 86400) : new BN(0),
topListLength: numOfStakers || 0,
startFeeDistributeTimestamp: feeClaimStartTime ? new BN(feeClaimStartTime.getTime() / 1000) : null,
unstakeLockDuration: cooldownDurationInHours ? new BN(cooldownDurationInHours * 3600) : new BN(0),
},
// other options
},
);
for (const transaction of transactions) {
transaction.sign(mockWallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
```
For Alpha Vault integration, please refer to [Alpha Vault Integration](/developer-guide/guides/alpha-vault/typescript-sdk/getting-started).
## Common Pool Operations
These operations are common across all pool types.
### Get the pool's LP token supply
```typescript theme={"system"}
// To refetch the pool's latest supply
// Alternatively, use `AmmImpl.poolState.lpSupply`
const lpSupply = await pool.getLpSupply();
```
### Check user's LP balance in the pool
```typescript theme={"system"}
// Get the user's ATA LP balance
const userLpBalance = await pool.getUserBalance(mockWallet.publicKey);
```
### Update pool state
```typescript theme={"system"}
// It's recommended to update the deposit before perform any quotation
await pool.updateState();
```
## Constant Product Pool Operations
Operations specific to Constant Product (Volatile) pools.
### Deposit
```typescript theme={"system"}
const balance = true;
const slippage = 0.1; // Max to 2 decimal place
const inAmountALamport = new BN(1 * 10 ** constantProductPool.tokenAMint.decimals);
// Get deposit quote
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = constantProductPool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
const depositTx = await constantProductPool.deposit(
mockWallet.publicKey,
tokenAInAmount,
tokenBInAmount,
poolTokenAmountOut,
); // Web3 Transaction Object
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
```
### Withdraw
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** constantProductPool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = constantProductPool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
); // use lp balance for full withdrawal
const withdrawTx = await constantProductPool.withdraw(
mockWallet.publicKey,
poolTokenAmountIn,
tokenAOutAmount,
tokenBOutAmount,
); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx); // Transaction hash
```
### Swap
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const inAmountLamport = new BN(0.1 * 10 ** constantProductPool.tokenB.decimals);
const { minSwapOutAmount } = constantProductPool.getSwapQuote(
new PublicKey(constantProductPool.tokenB.address),
inAmountLamport,
slippage,
);
const swapTx = await constantProductPool.swap(
mockWallet.publicKey,
new PublicKey(constantProductPool.tokenB.address),
inAmountLamport,
minSwapOutAmount,
);
const swapResult = await provider.sendAndConfirm(swapTx);
```
## Stable Pool Operations
Operations specific to Stable pools.
### Balance deposit to stable pool
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const balance = true;
const inAmountALamport = new BN(0.1 * 10 ** stablePool.tokenA.decimals);
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = stablePool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
const depositTx = await stablePool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut); // Web3 Transaction Object
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
```
### Double-sided imbalance deposit to stable pool
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const balance = false;
const inAmountALamport = new BN(0.1 * 10 ** stablePool.tokenA.decimals);
const inAmountBLamport = new BN(0.1 * 10 ** stablePool.tokenB.decimals);
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = stablePool.getDepositQuote(
inAmountALamport,
inAmountBLamport,
balance,
slippage,
); // Web3 Transaction Object
const depositTx = await stablePool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut);
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
```
### Single-sided imbalance deposit to stable pool
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const balance = false;
const inAmountALamport = new BN(0.1 * 10 ** stablePool.tokenA.decimals);
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = stablePool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
); // Web3 Transaction Object
const depositTx = await stablePool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut);
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
```
### Balance withdraw from stable pool
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** stablePool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = stablePool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
); // use lp balance for full withdrawal
const withdrawTx = await stablePool.withdraw(mockWallet.publicKey, poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx);
```
### Imbalance withdraw from stable pool
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** stablePool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = stablePool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
new PublicKey(stablePool.tokenA.address), // Pass in token A/B mint to perform imbalanced withdraw
);
const withdrawTx = await stablePool.withdraw(mockWallet.publicKey, poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx);
```
### Swap
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const inAmountLamport = new BN(0.1 * 10 ** stablePool.tokenB.decimals);
const { minSwapOutAmount } = stablePool.getSwapQuote(
new PublicKey(stablePool.tokenB.address),
inAmountLamport,
slippage,
);
const swapTx = await stablePool.swap(
mockWallet.publicKey,
new PublicKey(stablePool.tokenB.address),
inAmountLamport,
minSwapOutAmount,
);
const swapResult = await provider.sendAndConfirm(swapTx);
```
## Memecoin Pool Operations
Operations specific to Memecoin pools.
### Deposit
```typescript theme={"system"}
const balance = true;
const slippage = 0.1; // Max to 2 decimal place
const inAmountALamport = new BN(1 * 10 ** memecoinPool.tokenA.decimals);
// Get deposit quote for constant product
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = memecoinPool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
const depositTx = await memecoinPool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut); // Web3 Transaction Object
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
```
### Withdraw
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** memecoinPool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = memecoinPool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
); // use lp balance for full withdrawal
const withdrawTx = await memecoinPool.withdraw(
mockWallet.publicKey,
poolTokenAmountIn,
tokenAOutAmount,
tokenBOutAmount,
); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx); // Transaction hash
```
### Swap
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const inAmountLamport = new BN(0.1 * 10 ** memecoinPool.tokenB.decimals);
const { minSwapOutAmount } = memecoinPool.getSwapQuote(
new PublicKey(memecoinPool.tokenB.address),
inAmountLamport,
slippage,
);
const swapTx = await memecoinPool.swap(
mockWallet.publicKey,
new PublicKey(memecoinPool.tokenB.address),
inAmountLamport,
minSwapOutAmount,
);
const swapResult = await provider.sendAndConfirm(swapTx);
```
## Integration Considerations
### Any constraints on the quote token?
No constraint on the quote token for a Dynamic AMM Pool. However, if the Dynamic AMM Pool is being launched with an Alpha Vault, SOL or USDC must be used as the quote token.
### On DAMM v1, can you create two pools with the same token pair and configuration?
**Using TypeScript SDK**
Referencing index.ts in the SDK, there are various endpoints available. For example:
* `CreatePermissionlessConstantProductPoolWithConfig2`: Creates a pool using a unique config; This endpoint allows the shortening of pool activation time.
* `CreatePermissionlessConstantProductPoolWithConfig`: Creates a pool using a unique config; This endpoint does not allow the shortening of pool activation time.
* `CreatePermissionlessConstantProductMemecoinPoolwithConfig`: Creates a DAMM v1 Memecoin-type Pool with a fee scheduler and liquidity locked at creation.
* `CreateCustomizablePermissionlessConstantProductPool`: Creates a pool with customization, including fixed fee tier. Useful for token launches and launchpads.
* `CreatePermissionlessPool`: Creates a pool using a set of default fixed fee tiers. This is mainly used to create a stable pool.
Technically, when using the TypeScript SDK, one pool can be created using one endpoint, and another pool (with the same fee configuration) can be created with a different endpoint.
But when using the same endpoint, only one pool with the specific fee configuration can be created. In other words, when using the same endpoint, it is not possible to create two pools with the same token pair and fee configuration.
If two pools with the same token pair and fee configuration are created (using different endpoints), they should both still be displayed on the Meteora website UI.
# Getting Started
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/typescript-sdk/getting-started
DAMM v1
This guide provides instructions on how to get started with building on Meteora's DAMM v1 program using the DAMM v1 TypeScript SDK.
Before you begin, here are some important resources:
Meteora DAMM v1 Typescript SDK
Meteora DAMM v1 NPM Package
# Installation
To use the DAMM v1 SDK in your project, install it using your preferred package manager:
```bash theme={"system"}
npm install @meteora-ag/dynamic-amm-sdk @solana/web3.js
```
```bash theme={"system"}
pnpm install @meteora-ag/dynamic-amm-sdk @solana/web3.js
```
```bash theme={"system"}
yarn add @meteora-ag/dynamic-amm-sdk @solana/web3.js
```
# Initialization
Once installed, you can initialize the DAMM v1 SDK in your TypeScript/JavaScript project like this:
```typescript theme={"system"}
import AmmImpl, { MAINNET_POOL } from '@meteora-ag/dynamic-amm-sdk';
import { Connection } from '@solana/web3.js';
const mainnetConnection = new Connection('https://api.mainnet-beta.solana.com');
// Create pool instances
// e.g. creating a DAMM v1 pool
const constantProductPool = await AmmImpl.create(mainnetConnection, MAINNET_POOL.USDC_SOL);
// e.g. creating multiple DAMM v1 pools
const pools = [MAINNET_POOL.USDC_SOL, MAINNET_POOL.USDT_USDC];
const [dammV1Pool1, dammV1Pool2] = await AmmImpl.createMultiple(mainnetConnection, pools);
```
# Testing the SDK (for contributors)
If you have cloned the SDK repository and want to run the built-in tests:
Only for DAMM v1 SDK.
```bash theme={"system"}
# Install dependencies
cd ts-client
bun install
# Run tests
bun test
```
# Development Resources
## Faucets
When working on devnet, you might need test tokens. Here is a helpful faucet.
# SDK Functions
Source: https://docs.meteora.ag/developer-guide/guides/damm-v1/typescript-sdk/sdk-functions
DAMM v1
## Create Pool Functions
### createPermissionlessConstantProductPoolWithConfig
Creates a new permissionless constant product pool with a predefined configuration.
**Function**
```typescript theme={"system"}
async createPermissionlessConstantProductPoolWithConfig(
connection: Connection,
payer: PublicKey,
tokenAMint: PublicKey,
tokenBMint: PublicKey,
tokenAAmount: BN,
tokenBAmount: BN,
config: PublicKey,
opt?: {
cluster?: Cluster;
programId?: string;
lockLiquidity?: boolean;
swapLiquidity?: {
inAmount: BN;
minAmountOut: BN;
};
skipAAta?: boolean;
skipBAta?: boolean;
}
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
payer: PublicKey // Wallet paying for the transaction
tokenAMint: PublicKey // Mint address for token A
tokenBMint: PublicKey // Mint address for token B
tokenAAmount: BN // Initial amount of token A to deposit
tokenBAmount: BN // Initial amount of token B to deposit
config: PublicKey // The configuration account for the pool
opt?: { // Optional parameters
cluster?: Cluster; // The Solana cluster (mainnet, devnet, etc.)
programId?: string; // Custom program ID if different from default
lockLiquidity?: boolean; // Whether to permanently lock the initial liquidity
swapLiquidity?: { // Optional swap parameters for initial liquidity
inAmount: BN; // Amount to swap in
minAmountOut: BN; // Minimum amount to receive from swap
};
skipAAta?: boolean; // Skip creating associated token account for token A
skipBAta?: boolean; // Skip creating associated token account for token B
}
```
**Returns**
An array of transactions that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
// Token A/B address of the pool.
const tokenAMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
// Configuration address for the pool. It will decide the fees of the pool.
const config = new PublicKey('...');
// Amount of token A and B to be deposited to the pool.
const tokenAAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
const transactions = await AmmImpl.createPermissionlessConstantProductPoolWithConfig(
provider.connection,
wallet.publicKey,
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
config,
);
for (const transaction of transactions) {
transaction.sign(wallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
```
**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 account
***
### createPermissionlessConstantProductPoolWithConfig2
Creates a new permissionless constant product pool with a predefined configuration. This function is similar to `createPermissionlessConstantProductPoolWithConfig` but only if you need to set the activation point earlier than the default derived from the config.
**Function**
```typescript theme={"system"}
async createPermissionlessConstantProductPoolWithConfig2(
connection: Connection,
payer: PublicKey,
tokenAMint: PublicKey,
tokenBMint: PublicKey,
tokenAAmount: BN,
tokenBAmount: BN,
config: PublicKey,
opt?: {
cluster?: Cluster;
programId?: string;
lockLiquidity?: boolean;
swapLiquidity?: {
// always swap B to A
inAmount: BN;
minAmountOut: BN;
};
stakeLiquidity?: {
ratio?: Decimal;
param: Omit;
};
activationPoint?: BN;
}
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
payer: PublicKey // Wallet paying for the transaction
tokenAMint: PublicKey // Mint address for token A
tokenBMint: PublicKey // Mint address for token B
tokenAAmount: BN // Initial amount of token A to deposit
tokenBAmount: BN // Initial amount of token B to deposit
config: PublicKey // The configuration account for the pool
opt?: { // Optional parameters
cluster?: Cluster; // The Solana cluster (mainnet, devnet, etc.)
programId?: string; // Custom program ID if different from default
lockLiquidity?: boolean; // Whether to permanently lock the initial liquidity
swapLiquidity?: { // Optional swap parameters for initial liquidity
inAmount: BN; // Amount to swap in
minAmountOut: BN; // Minimum amount to receive from swap
};
stakeLiquidity?: { // Optional stake parameters for initial liquidity
ratio?: Decimal; // Stake ratio
param: Omit; // Stake parameters
};
activationPoint?: BN; // Activation point for the pool
}
```
**Returns**
An array of transactions that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
// Token A/B address of the pool.
const tokenAMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
// Configuration address for the pool. It will decide the fees of the pool.
const config = new PublicKey('...');
// Amount of token A and B to be deposited to the pool.
const tokenAAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
const startTime = 'now' // const startTime = new Date('2024-12-20T15:30:00Z').toISOString();
const transactions = await AmmImpl.createPermissionlessConstantProductPoolWithConfig2(
provider.connection,
wallet.publicKey, // payer
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
config,
{
activationPoint: startTime !== 'now' ? new BN(Math.floor(new UTCDate(startTime).getTime() / 1000)) : undefined,
},
);
for (const transaction of transactions) {
transaction.sign(wallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
```
**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 account
* The `activationPoint` parameter is the timestamp in seconds since the Unix epoch. If you want to set it to the current time, you can use `'now'`.
***
### createPermissionlessPool
Creates a new permissionless constant product pool.
**Function**
```typescript theme={"system"}
async createPermissionlessPool(
connection: Connection,
payer: PublicKey,
mintA: PublicKey,
mintB: PublicKey,
tokenAAmount: BN,
tokenBAmount: BN,
isStable: boolean,
tradeFeeBps: BN,
opt?: {
programId?: string;
skipAta?: boolean;
}
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // The Solana connection instance
payer: PublicKey // The wallet paying for the transaction
mintA: PublicKey // The mint address for token A
mintB: 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
isStable: boolean // Whether the pool is stable
tradeFeeBps: BN // Trade fee in basis points
opt?: { // Optional parameters
programId?: string; // Custom program ID if different from default
skipAta?: boolean; // Skip creating associated token account for token A
}
```
**Returns**
A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
// Token A/B address of the pool.
const tokenAMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
const tokenADecimal = 6;
const tokenBDecimal = 6;
const feeBps = new BN(1); // 0.01%
// Get pool address
const poolPubkey = derivePoolAddress(
provider.connection,
tokenAMint,
tokenBMint,
tokenADecimal,
tokenBDecimal,
true, // stable
feeBps,
);
// Create pool
const transactions = await AmmImpl.createPermissionlessPool(
provider.connection,
wallet.publicKey, // payer
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
true, // stable,
feeBps,
);
for (const transaction of transactions) {
transaction.sign(wallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
```
**Notes**
* Both token amounts must be greater than zero
* If using native SOL, it will be automatically wrapped to wSOL
* The `tradeFeeBps` parameter is the trade fee in basis points.
* The `isStable` parameter is whether the pool is stable.
* The `skipAta` parameter is whether to skip creating associated token account for token A.
***
### createPermissionlessConstantProductMemecoinPoolWithConfig
Creates a new permissionless constant product memecoin pool with a predefined configuration.
**Function**
```typescript theme={"system"}
async createPermissionlessConstantProductMemecoinPoolWithConfig(
connection: Connection,
payer: PublicKey,
tokenAMint: PublicKey,
tokenBMint: PublicKey,
tokenAAmount: BN,
tokenBAmount: BN,
config: PublicKey,
memecoinInfo: {
isMinted?: boolean;
keypair?: Keypair;
payer?: PublicKey;
assetData?: DataV2;
mintAuthority?: PublicKey;
freezeAuthority?: PublicKey | null;
decimals?: number;
mintAmount?: BN;
},
opt?: {
cluster?: Cluster;
programId?: string;
lockLiquidity?: boolean;
swapLiquidity?: {
inAmount: BN;
minAmountOut: BN;
};
stakeLiquidity?: {
ratio?: Decimal;
};
skipAAta?: boolean;
skipBAta?: boolean;
feeVault?: {
secondsToFullUnlock: BN;
topListLength: number;
startFeeDistributeTimestamp: BN | null;
unstakeLockDuration: BN;
};
}
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
payer: PublicKey // Wallet paying for the transaction
tokenAMint: PublicKey // Mint address for token A
tokenBMint: PublicKey // Mint address for token B
tokenAAmount: BN // Initial amount of token A to deposit
tokenBAmount: BN // Initial amount of token B to deposit
config: PublicKey // The configuration account for the pool
memecoinInfo: {
isMinted?: boolean; // Whether the memecoin is minted
keypair?: Keypair; // Keypair for the memecoin
payer?: PublicKey; // Payer for the memecoin
assetData?: DataV2; // Asset data for the memecoin
mintAuthority?: PublicKey; // Mint authority for the memecoin
freezeAuthority?: PublicKey | null; // Freeze authority for the memecoin
decimals?: number; // Decimals for the memecoin
mintAmount?: BN; // Mint amount
}
opt?: { // Optional parameters
cluster?: Cluster; // The Solana cluster (mainnet, devnet, etc.)
programId?: string; // Custom program ID if different from default
lockLiquidity?: boolean; // Whether to permanently lock the initial liquidity
swapLiquidity?: { // Optional swap parameters for initial liquidity
inAmount: BN; // Amount to swap in
minAmountOut: BN; // Minimum amount to receive from swap
};
stakeLiquidity?: { // Optional stake parameters for initial liquidity
ratio?: Decimal; // Stake ratio
};
skipAAta?: boolean; // Skip creating associated token account for token A
skipBAta?: boolean; // Skip creating associated token account for token B
feeVault?: {
secondsToFullUnlock: BN; // Seconds to full unlock
topListLength: number; // Top list length
startFeeDistributeTimestamp: BN | null; // Start fee distribute timestamp
unstakeLockDuration: BN; // Unstake lock duration
};
}
```
**Returns**
An array of transactions that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
// Token A/B address of the pool.
const memecoinMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
const memecoinAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
// Create pool
const programId = new PublicKey(PROGRAM_ID);
const CONFIG_KEY = new PublicKey('...');
const feeConfigurations = await AmmImpl.getFeeConfigurations(provider.connection, {
programId,
});
const feeConfig = feeConfigurations.find(({ publicKey }) => publicKey.equals(CONFIG_KEY));
// Create pool
const transactions = await AmmImpl.createPermissionlessConstantProductMemecoinPoolWithConfig(
provider.connection,
wallet.publicKey, // payer
memecoinMint,
tokenBMint,
memecoinAmount,
tokenBAmount,
feeConfig.publicKey,
{ isMinted: true },
);
for (const transaction of transactions) {
transaction.sign(wallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
```
**Notes**
* Both token amounts must be greater than zero
* If using native SOL, it will be automatically wrapped to wSOL
* The `memecoinInfo` parameter is the information for the memecoin.
* The `feeVault` parameter is the information for the fee vault.
***
## State Functions
### getLpSupply
Get the total supply of the pool.
**Function**
```typescript theme={"system"}
async getLpSupply(): Promise
```
**Returns**
The total supply of the pool.
**Example**
```typescript theme={"system"}
const lpSupply = await pool.getLpSupply();
```
**Notes**
* The `pool` parameter is the instance of the pool.
***
### getUserBalance
Get the balance of a user in the pool.
**Function**
```typescript theme={"system"}
async getUserBalance(owner: PublicKey): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The owner of the pool
```
**Returns**
The balance of the user in the pool.
**Example**
```typescript theme={"system"}
const userLpBalance = await pool.getUserBalance(wallet.publicKey);
```
**Notes**
* The `pool` parameter is the instance of the pool.
* The `owner` parameter is the address of the user.
***
### getSwapQuote
Get the swap quote for a given amount of token.
**Function**
```typescript theme={"system"}
getSwapQuote(
inTokenMint: PublicKey,
inAmountLamport: BN,
slippage: number,
swapInitiator?: PublicKey
): Promise<{
swapInAmount: BN;
swapOutAmount: BN;
minSwapOutAmount: BN;
fee: BN;
priceImpact: Decimal;
}>
```
**Parameters**
```typescript theme={"system"}
inTokenMint: PublicKey, // Mint address for the input token
inAmountLamport: BN, // Amount of input token to swap
slippage: number, // Slippage tolerance
swapInitiator?: PublicKey // Optional swap initiator
```
**Returns**
The swap quote containing the following parameters:
```typescript theme={"system"}
{
swapInAmount: BN;
swapOutAmount: BN;
minSwapOutAmount: BN;
fee: BN;
priceImpact: Decimal;
}
```
**Example**
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const inAmountLamport = new BN(0.1 * 10 ** pool.tokenB.decimals);
const { swapInAmount, swapOutAmount, minSwapOutAmount, fee, priceImpact } = await pool.getSwapQuote(
new PublicKey(pool.tokenB.address),
inAmountLamport,
slippage, // 0.01
);
```
**Notes**
* The `inTokenMint` parameter is the mint address of the input token.
* The `inAmountLamport` parameter is the amount of input token to swap.
* The `slippage` parameter is the slippage tolerance.
* The `swapInitiator` parameter is the address of the swap initiator.
***
### getDepositQuote
Get the deposit quote for a given amount of token.
**Function**
```typescript theme={"system"}
getDepositQuote(
tokenAInAmount: BN,
tokenBInAmount: BN,
balance: boolean,
slippage: number
): Promise
```
**Parameters**
```typescript theme={"system"}
tokenAInAmount: BN, // Amount of token A to deposit
tokenBInAmount: BN, // Amount of token B to deposit
balance: boolean, // Whether to use the balance of the user
slippage: number // Slippage tolerance
```
**Returns**
The deposit quote containing the following parameters:
```typescript theme={"system"}
{
poolTokenAmountOut: BN;
minPoolTokenAmountOut: BN;
tokenAInAmount: BN;
tokenBInAmount: BN;
}
```
**Example**
```typescript theme={"system"}
const balance = true;
const slippage = 0.1; // Max to 2 decimal place
const inAmountALamport = new BN(1 * 10 ** pool.tokenAMint.decimals);
const { poolTokenAmountOut, minPoolTokenAmountOut, tokenAInAmount, tokenBInAmount } = pool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
```
**Notes**
* The `tokenAInAmount` parameter is the amount of token A to deposit.
* The `tokenBInAmount` parameter is the amount of token B to deposit.
* The `balance` parameter is whether to use the balance of the user.
* The `slippage` parameter is the slippage tolerance.
***
### getWithdrawQuote
Get the withdraw quote for a given amount of pool token.
**Function**
```typescript theme={"system"}
getWithdrawQuote(
withdrawTokenAmount: BN,
slippage: number,
tokenMint?: PublicKey
): Promise
```
**Parameters**
```typescript theme={"system"}
withdrawTokenAmount: BN, // Amount of pool token to withdraw
slippage: number, // Slippage tolerance
tokenMint?: PublicKey // Optional mint address for the token
```
**Returns**
The withdraw quote containing the following parameters:
```typescript theme={"system"}
{
poolTokenAmountIn: BN;
minTokenAOutAmount: BN;
minTokenBOutAmount: BN;
tokenAOutAmount: BN;
tokenBOutAmount: BN;
}
```
**Example**
```typescript theme={"system"}
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** pool.decimals);
const { poolTokenAmountIn, minTokenAOutAmount, minTokenBOutAmount, tokenAOutAmount, tokenBOutAmount } = pool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
);
```
**Notes**
* The `withdrawTokenAmount` parameter is the amount of pool token to withdraw.
* The `slippage` parameter is the slippage tolerance.
***
### updateState
Update the state of the pool.
**Function**
```typescript theme={"system"}
updateState()
```
**Returns**
No return value.
**Example**
```typescript theme={"system"}
await pool.updateState();
```
**Notes**
* The `pool` parameter is the instance of the pool.
***
## Pool Functions
### deposit
Deposit tokens into the pool.
**Function**
```typescript theme={"system"}
async deposit(
owner: PublicKey,
tokenAInAmount: BN,
tokenBInAmount: BN,
poolTokenAmount: BN,
): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey, // The owner of the pool
tokenAInAmount: BN, // Amount of token A to deposit
tokenBInAmount: BN, // Amount of token B to deposit
poolTokenAmount: BN, // Amount of pool token to deposit
```
**Returns**
The transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const balance = true;
const slippage = 0.1; // Max to 2 decimal place
const inAmountALamport = new BN(1 * 10 ** constantProductPool.tokenAMint.decimals);
// Get deposit quote
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = pool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
const depositTx = await pool.deposit(
wallet.publicKey,
tokenAInAmount,
tokenBInAmount,
poolTokenAmountOut,
);
const depositResult = await provider.sendAndConfirm(depositTx);
```
**Notes**
* The `owner` parameter is the address of the owner.
* The `tokenAInAmount` parameter is the amount of token A to deposit.
* The `tokenBInAmount` parameter is the amount of token B to deposit.
* The `poolTokenAmount` parameter is the amount of pool token to deposit.
***
### withdraw
Withdraw tokens from the pool.
**Function**
```typescript theme={"system"}
async withdraw(
owner: PublicKey,
lpTokenAmount: BN,
tokenAOutAmount: BN,
tokenBOutAmount: BN,
): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey, // The owner of the pool
lpTokenAmount: BN, // Amount of pool token to withdraw
tokenAOutAmount: BN, // Amount of token A to withdraw
tokenBOutAmount: BN, // Amount of token B to withdraw
```
**Returns**
The transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const slippage = 0.1;
const outTokenAmountLamport = new BN(0.1 * 10 ** pool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = pool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
);
const withdrawTx = await pool.withdraw(
wallet.publicKey,
poolTokenAmountIn,
tokenAOutAmount,
tokenBOutAmount,
);
const withdrawResult = await provider.sendAndConfirm(withdrawTx);
```
**Notes**
* The `owner` parameter is the address of the owner.
* The `lpTokenAmount` parameter is the amount of pool token to withdraw.
* The `tokenAOutAmount` parameter is the amount of token A to withdraw.
* The `tokenBOutAmount` parameter is the amount of token B to withdraw.
***
### swap
Swap tokens in the pool.
**Function**
```typescript theme={"system"}
async swap(
owner: PublicKey,
inTokenMint: PublicKey,
inAmountLamport: BN,
outAmountLamport: BN,
referralOwner?: PublicKey,
): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey, // The owner of the pool
inTokenMint: PublicKey, // Mint address for the input token
inAmountLamport: BN, // Amount of input token to swap
outAmountLamport: BN, // Amount of output token to receive
referralOwner?: PublicKey // Optional referral owner
```
**Returns**
The transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const slippage = 0.1;
const inAmountLamport = new BN(0.1 * 10 ** pool.tokenB.decimals);
const { minSwapOutAmount } = pool.getSwapQuote(
new PublicKey(pool.tokenB.address),
inAmountLamport,
slippage,
);
const swapTx = await pool.swap(
mockWallet.publicKey,
new PublicKey(pool.tokenB.address),
inAmountLamport,
minSwapOutAmount,
);
const swapResult = await provider.sendAndConfirm(swapTx);
```
**Notes**
* The `owner` parameter is the address of the owner.
* The `inTokenMint` parameter is the mint address of the input token.
* The `inAmountLamport` parameter is the amount of input token to swap.
* The `outAmountLamport` parameter is the amount of output token to receive.
* The `referralOwner` parameter is the address of the referral owner.
# Pool Liquidity Modes
Source: https://docs.meteora.ag/developer-guide/guides/damm-v2/compounding-fee-pools
How to create DAMM v2 pools using concentrated liquidity or compounding fee mode
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).
| Mode | `collectFeeMode` | Price Range | Single-Sided | Fee Behaviour |
| ----------- | ---------------- | -------------------- | ------------ | -------------------------------------------------- |
| BothToken | `0` | Concentrated or full | ✅ | Fees claimable in both tokens |
| OnlyB | `1` | Concentrated or full | ✅ | Fees claimable in quote token only |
| Compounding | `2` | Full range only | ❌ | Portion 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
```typescript theme={"system"}
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: 2`** — `CollectFeeMode.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
```typescript theme={"system"}
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,
});
```
# Integration
Source: https://docs.meteora.ag/developer-guide/guides/damm-v2/go-sdk/integration
DAMM v2
The `damm-v2-go` provides a convenient way to interact with the DAMM v2 instructions directly.
Before you begin, here are some important resources:
Meteora DAMM v2 Go SDK
# Getting Started
To use the Go SDK and test locally, you can use the following command:
## Clone the repository
```bash theme={"system"}
git clone https://github.com/MeteoraAg/damm-v2-go.git
```
## Install dependencies
```bash theme={"system"}
go mod tidy
```
## Run the examples
Before running the examples, you need to set the private keys and public keys in the examples.
```bash theme={"system"}
go run examples/.go
```
# Examples
Example showing how to claim accumulated fees from a position
Retrieve all position NFT accounts owned by a specific user
Fetch pool information and current state
Get detailed information about a specific position
Retrieve all positions associated with a user account
Check unclaimed rewards available for a position
Find user positions within a specific pool
# Overview
Source: https://docs.meteora.ag/developer-guide/guides/damm-v2/overview
Before getting started building on DAMM v2, you should read the following resource to get a better understanding of how Meteora's DAMM v2 works:
DAMM v2 is one of Meteora's advanced AMM product that allows you to provide concentrated or spot or single-sided liquidity to a pool and in return minting an NFT that represents your position.
Each DAMM v2 pool is a PDA of token mints + config. There are 2 main types of DAMM v2 configs: Static config and Dynamic config.
***
# DAMM v2 Program
At Meteora, we’ve developed a `Node.js <> Typescript SDK`, a `Rust SDK` and a `Go SDK` to make deploying and managing your DAMM v2 liquidity pool easier. The following sections includes information on installing and using the SDKs. It also covers where to find the latest code, and how to contribute to these repositories.
## Program Details
Meteora DAMM v2 Program
Meteora DAMM v2 Program IDL
Network
Program ID
Mainnet
cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
Devnet
cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
Authority
Address
Pool Authority
HLnpSz9h2S4hiLQ43rnSD9XkcUThA7B8hQMKmDaiTLcC
## Compounding Fee Mode
DAMM v2 v0.2.0 introduces a third fee collection mode (`collect_fee_mode = 2`).
| `collect_fee_mode` | Fee Token | Fee on Input? |
| ------------------ | ------------ | ------------------- |
| 0 (BothToken) | Output token | No (fee on output) |
| 1 (OnlyB) | Token B | Only for B→A trades |
| 2 (Compounding) | Token B | Only for B→A trades |
In Compounding mode, a percentage of the collected fee (set by `compounding_fee_bps` on the config) is automatically reinvested back into pool reserves rather than accruing to LP positions. This portion is reported as `compounding_fee` in `EvtSwap2`. The remaining claimable portion is reported as `claiming_fee`.
Compounding mode pools use a constant-product formula with no concentrated liquidity range.
## Official SDKs
Official Meteora DAMM v2 Typescript SDK
Official Meteora DAMM v2 Rust SDK
Official Meteora DAMM v2 Go SDK
# Pool Fee Configs
Source: https://docs.meteora.ag/developer-guide/guides/damm-v2/pool-fee-configs
* initialize\_pool requires a static config key to create the pool. Each DAMM v2 pool is a PDA of tokenAMint + tokenBMint + staticConfig.
* initialize\_pool\_with\_dynamic\_config requires a dynamic config key to create the pool. Each DAMM v2 pool is a PDA of tokenAMint + tokenBMint + dynamicConfig.
* initialize\_customizable\_pool does not require any config key and is also known as the DAMM v2 Launch Pool. Each DAMM v2 launch pool is a PDA of tokenAMint + tokenBMint.
Configs are basically where you configure the fees of the pool, the collect fee mode, and the dynamic fee. There are 2 types of config:
1. Static config - can be used by anyone to create a pool.
2. Dynamic config - can only be used by the `pool_creator_authority` to create a pool.
# Static Configs
Anyone can use one of the static config keys to create a pool. Currently, we have 72 config keys created for devnet and mainnet. Integrators can consider using a static config if tokens cannot be bought (leaked) before the token launch time. But launchpads typically use a dynamic config.
To fetch all static config key addresses, you can use the `getAllConfigs` function in the [Typescript SDK ](https://github.com/MeteoraAg/damm-v2-sdk/blob/cdd71c0282e3555989fc255c5fba335ade5a443b/src/CpAmm.ts#L712).
Integrators cannot change the configuration for that particular static config key.When `dynamicFee = true`, the dynamic fee adds on a maximum of 20% of the minimum base fee. For example, if you have a fee scheduler that decays from a maximum fee of 50% and minimum fee of 2%, having dynamic fee enabled will add a 0.4% fee on top of the 2% minimum fee when the token has high volatility.
```json theme={"system"}
[
{
"index": 0,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 2500000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "8CNy9goNQNLM4wtgRw528tUQGMKD3vSuFRZY2gLGLLvF"
},
{
"index": 1,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 2500000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "82p7sVzQWZfCrmStPhsG8BYKwheQkUiXSs2wiqdhwNxr"
},
{
"index": 2,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 2500000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "FzvMYBQ29z2J21QPsABpJYYxQBEKGsxA6w6J2HYceFj8"
},
{
"index": 3,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 2500000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "EQbqYxecZuJsVt6g5QbKTWpNWa3QyWQE5NWz5AZBAiNv"
},
{
"index": 4,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 3000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "9RuAyDH81GB9dhks6MzHva2objQJxHvqRRfyKKdfmkxk"
},
{
"index": 5,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 3000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "GqRo1PG5KZc4QqZn1RCcnEGC8E7yRscHaW1fQp9St9Lz"
},
{
"index": 6,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 3000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "3KLdspUofc75aaEAJdBo1o6D6cyzXJVtGB8PgpWJEiaR"
},
{
"index": 7,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 3000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "9xKsCsiv8eeBohobb8Z1snLZzVKKATGqmY69vJHyCzvu"
},
{
"index": 8,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 10000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "EVRn9bAekgZsVVAHt25AUjA7qpKh4ac7uUMpoSGqgS5U"
},
{
"index": 9,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 10000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "7BJfgt3ahTtCfXkPMRbS6YneR92JuwsU1dyayhmNBL11"
},
{
"index": 10,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 10000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "GXZLjqmebpsy74vqTD6DqSTugTKVwoTi8fZwLAXBsMNN"
},
{
"index": 11,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 10000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "AeLtDKgw3XnXbr3Kgfbcb7KiZULVCQ5mXaFDiG9n7EgW"
},
{
"index": 12,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 20000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "G8pJy5Hsxeko5srUxDUF6cpuPJ3r53MbMucbpLhNC8NU"
},
{
"index": 13,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 20000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "BcgnWGkrvEQm4hChY6R4wDuwshsvmnnh1Hmzvrm7M8FQ"
},
{
"index": 14,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 20000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "HdqGCsprdhmgqaCXjJzGnKib2SGQvmT9XKYmR7ZjMqmi"
},
{
"index": 15,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 20000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "HQ6vW45Kug23h2A4LkyUqB4UFfGx4LqY1uZLLfQemEjU"
},
{
"index": 16,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 40000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "Gjsr13rp68pMXrpwekfygphynT1hjRzbLLQLHTeQNfQq"
},
{
"index": 17,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 40000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "BjJKkSVvDiMt6qM9vc5MAtFHTxpaYTbgrD6KuwUQhj7u"
},
{
"index": 18,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 40000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "FivzJShpkDj7tdLv6hYSyLcZEAF2FsqNfw8W8mPc8op2"
},
{
"index": 19,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 40000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "DT1PBa3RRvd2GDjKuMJHrcyrus7cM5oqL3eY6tR63uUk"
},
{
"index": 20,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 60000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "5UMffQ4jEJgjS2rFoyTWNyh3Xf3ek3LFPyr89RfYQRbu"
},
{
"index": 21,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 60000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "7y8Y3kuKphxBoyesTaKV2WQLtu884zhVCDtxqrCP4HWv"
},
{
"index": 22,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 60000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "9YmoetVvZx1vrfJ9fD8X5YG3FQXREK6ZiPzRghP33Wbf"
},
{
"index": 23,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 60000000,
"numberOfPeriod": 0,
"reductionFactor": 0,
"periodFrequency": 0,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "Ha2bAcxbLrFr5RiugBgeJVLx1JE7gq16rzAuqUED1v3f"
},
{
"index": 24,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3454861,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "GtDtC9gJEAyMje1AW1McMoAFpGqcfYPwnGMBJ3VLS54Q"
},
{
"index": 25,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3454861,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "4A95FoEsswvuCEDSFnd8uXBgdkQPqzrjJv2roev8c9mm"
},
{
"index": 26,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3454861,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "CsPBLWzLWTJ3p8PG28zQ31Eq3dPpw1wV55JxpRYzdVxg"
},
{
"index": 27,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3454861,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "G9EUpuBrDZHQAeaifkx5xbiajAGbB6HHJ4xcVmZyd3eQ"
},
{
"index": 28,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 432,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "7f8zQkCTmEE2yPjKoEGpWxcTaw6VYcjB1P3DxnpfFNCc"
},
{
"index": 29,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 432,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "G6Sukhgcmaf32PucWqCTMHn4jtWjE2TZTk59eQPSVKsy"
},
{
"index": 30,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 432,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "CLL5Wi7pi9SwHiSwtMyz1xbX6HDq3defpotWUFxwu4oj"
},
{
"index": 31,
"baseFeeValue": 2500000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 432,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "9jma77W3ZsJXPude5tnmC51EhMjKHzwsHCz1gFmbfJBc"
},
{
"index": 32,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3451389,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "EQadgQ6mGX7fHWxWbLiq7LCsKs6RLyoD3gDCKWzAB3qi"
},
{
"index": 33,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3451389,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "F28LTGGMKxKmicskcBpVd5BD2Dj73bhcvVbBiCBpg7fQ"
},
{
"index": 34,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3451389,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "3DpKWH6VXcJewqMQcVXQfuSfb95qrbq847wCTTDzviWt"
},
{
"index": 35,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3451389,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "2gnXvkRvYZ3iosu4d8G7KmZR6Ki9GXPMoxbx5NR4e8bz"
},
{
"index": 36,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 417,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "BdYG3xCpAYPYPnksHGhVfEMHk3gqt1Y7uqdWUsSUzf4y"
},
{
"index": 37,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 417,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "uPhetWqk4hhf9swL8xdbABfmGh4GyQ9nVAeYpvnC6pb"
},
{
"index": 38,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 417,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "TBuzuEMMQizTjpZhRLaUPavALhZmD8U1hwiw1pWSCSq"
},
{
"index": 39,
"baseFeeValue": 3000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 417,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "3z9HHXyWEXc7L3EPEQ5mN8cPoq9wBZr8y2bRiEwUu9u2"
},
{
"index": 40,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3402778,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "ABWG34FJMHaWSwP2uJrX2S6dKXDmz93MCVSBk9BKZHrs"
},
{
"index": 41,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3402778,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "HrBAyo6rf8i6dF8S8kh6QsjTmesmFhDoHvwSrsUHKdbX"
},
{
"index": 42,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3402778,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "DXoY3hDAuvQudWTjpepSJ1bn1yd6jovuvPweHwc1e83P"
},
{
"index": 43,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3402778,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "69CwWBvDBGvZ9P6bB9UnMwnDcQ136UFuDn2UEZ7Rb5We"
},
{
"index": 44,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 321,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "BDAbqqPRRg44tsDUEUPFjVaReX1mavngTc9H9SFPDo6F"
},
{
"index": 45,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 321,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "EZDtwCGcoe3f7BWFxaMrYDTq2WZMrcBZbUktoBKYvYiM"
},
{
"index": 46,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 321,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "341nQvGfd3b6HXMEaMafZwk5DkHmrZDh7Q2j4BbTCHyk"
},
{
"index": 47,
"baseFeeValue": 10000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 321,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "6Vt8pYzHmtMr4H5v1qp8gR9uot11xVfbjTHmbm9SXMGB"
},
{
"index": 48,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3333333,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "F7xJjVwqvVBoAkYV3TdZesu4ckwzzVQEebaPiZVqT4Ly"
},
{
"index": 49,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3333333,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "84tnQ4tQ4N8QGwoEEXcCdWfjSeuL8SfNjsdZWLZ9UiY4"
},
{
"index": 50,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3333333,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "HKqzgVzaKkX7NPXyVNWuVegtgujkiJ2ZLvpszR1iZjhd"
},
{
"index": 51,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3333333,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "5LWDYbiD3LwEhAd3eeHpjJscACKo4XdTDzycdHFSBCvE"
},
{
"index": 52,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 265,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "H6hnWjg6LtpHPK1wN89ieb7Eex9wV2UJkw7pPH2DHSNd"
},
{
"index": 53,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 265,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "FjPMSBmrawY7b5We2jv7asshi6ZWnMrfYSPUn5ZDzqmA"
},
{
"index": 54,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 265,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "DgXZtoBcBumq96AtGkG1X4xh9fvHnWwyYuXqaenjeKoe"
},
{
"index": 55,
"baseFeeValue": 20000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 265,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "2rGPJyTHFvHH44hVfcotPXjXNGHCsiLFUaRfVkXXVCYB"
},
{
"index": 56,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3194444,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "EcfqEkLSeGzDtZrTJWcbDxptfR2nWfX6cjJLFkgttwY6"
},
{
"index": 57,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3194444,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "GkC7zppTNPjBeoZfKCR9ExbNSycpwi5VphvktqpyPdx3"
},
{
"index": 58,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3194444,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "7tcR7XawzXCSAtAavjVYU2Rx5RK8mE9rsyrErfYRpkw4"
},
{
"index": 59,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3194444,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "A4JGKvpXKGfpkSgBSLmR7obESYhqqaeVEve71nWmS4zU"
},
{
"index": 60,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 208,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "GGD1oNYU62ux15XXpSMeoKcfznHTtu85qLeKrhY7MMMZ"
},
{
"index": 61,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 208,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "4hKGzanVuqCaVHbXm9rXnYJeJvzWcq5HDogKcrVYh4gP"
},
{
"index": 62,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 208,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "G4Y8SphEjVCESkodbFU7sjgaPZRykD55dabccDa8Lv7M"
},
{
"index": 63,
"baseFeeValue": 40000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 208,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "GnERyyZgr9JdZ5dCFC46APkcPNZdUQgrJmRqoeBX55dg"
},
{
"index": 64,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3055556,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "C11DxNAH4NBGNHGzTCq9ZUcJrVJ9dEG5CLwSmis3Y6HJ"
},
{
"index": 65,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3055556,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "2rbDaKQjxiFgMsYoQxLRaPvtXuLFUUQmypN5bYmJqPjY"
},
{
"index": 66,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3055556,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "7gE2roG5cBM5hpqDQvQ2J7ZsQE4CqM6eE8sKQ6NTaqRS"
},
{
"index": 67,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 144,
"reductionFactor": 3055556,
"periodFrequency": 600,
"feeSchedulerMode": 0
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "6Fs8KLaRA1T1aecBVca4VPpJi27oAPLDZUPbrUocEN12"
},
{
"index": 68,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 175,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": true,
"configAccount": "7SDjNZxM4rGNdYF3MyAkDetZ2TNFUxdDUGGE1C3kCeAd"
},
{
"index": 69,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 175,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": true,
"configAccount": "2yAJha5NVgq5mEitTUvdWSUKrcYvxAAc2H6rPDbEQqSu"
},
{
"index": 70,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 175,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 1,
"dynamicFee": false,
"configAccount": "E4VmzCAgMN2GGAhiRipGfJhaP411Ap7YFy8WmnnV2CKs"
},
{
"index": 71,
"baseFeeValue": 60000000,
"baseFee": {
"cliffFeeNumerator": 500000000,
"numberOfPeriod": 120,
"reductionFactor": 175,
"periodFrequency": 60,
"feeSchedulerMode": 1
},
"collectFeeMode": 0,
"dynamicFee": false,
"configAccount": "DJN8YHxQKZnF7bL2GwuKNB2UcfhKCqRspfLe7YYEN3rr"
}
]
```
# Dynamic Configs
In a dynamic config, only a specified address (configured in the `pool_creator_authority` field) can create a pool with that config. If you are a launchpad or integrator, this helps you prevent front-running of the token launch pool.
If you're a launchpad or integrator that's keen to create your own unique custom pool config key with custom `pool_fees`, please reach out to the team on [discord](https://discord.gg/meteora).
# Integration
Source: https://docs.meteora.ag/developer-guide/guides/damm-v2/rust-sdk/integration
DAMM v2
The `rust-sdk` provides a convenient way to interact with the DAMM v2 program.
Before you begin, here are some important resources:
Meteora DAMM v2 Rust SDK
# Getting Started
To use the Rust SDK, you need to add it as a dependency in your `Cargo.toml` file. Since it's a local dependency in this workspace, you can add it by specifying its path:
```toml theme={"system"}
[dependencies]
rust-sdk = { path = "../rust-sdk" } # Adjust the path accordingly
cp-amm = { path = "../programs/cp-amm" } # The sdk also needs the cp-amm crate
solana-sdk = "1.18.12" # For Pubkey
```
# API Reference
## `get_quote`
Calculates the result of a swap for a given pool.
### Parameters
* `pool: &Pool`: A reference to the `Pool` state account, deserialized from on-chain data.
* `current_timestamp: u64`: The current blockchain timestamp.
* `current_slot: u64`: The current blockchain slot.
* `actual_amount_in: u64`: The amount of the input token to be swapped.
* `a_to_b: bool`: The direction of the swap. `true` for token A to token B, `false` for token B to token A.
* `has_referral: bool`: Indicates if a referral fee should be considered.
### Returns
A `Result` which contains the details of the swap if successful, including `amount_out`, fees, and new liquidity states.
# Getting Started
Source: https://docs.meteora.ag/developer-guide/guides/damm-v2/typescript-sdk/getting-started
DAMM v2
This guide provides instructions on how to get started with building on Meteora's DAMM v2 program using the DAMM v2 TypeScript SDK.
Before you begin, here are some important resources:
Meteora DAMM v2 Typescript SDK
Meteora DAMM v2 NPM Package
# Installation
To use the SDK in your project, install it using your preferred package manager:
```bash theme={"system"}
npm install @meteora-ag/cp-amm-sdk @solana/web3.js
```
```bash theme={"system"}
pnpm install @meteora-ag/cp-amm-sdk @solana/web3.js
```
```bash theme={"system"}
yarn add @meteora-ag/cp-amm-sdk @solana/web3.js
```
# Initialization
Once installed, you can initialize the SDK in your TypeScript/JavaScript project like this:
```typescript theme={"system"}
import { Connection } from "@solana/web3.js";
import { CpAmm } from "@meteora-ag/cp-amm-sdk";
// Initialize a connection to the Solana network (e.g., Mainnet)
const connection = new Connection("https://api.mainnet-beta.solana.com");
// Create a new instance of the CpAmm SDK
const cpAmm = new CpAmm(connection);
```
# Testing the SDK (for contributors)
If you have cloned the SDK repository and want to run the built-in tests:
```bash theme={"system"}
# Install dependencies
pnpm install
# Run tests
pnpm test
```
# Development Resources
## Faucets
When working on devnet, you might need test tokens. Here is a helpful faucet.
# SDK Functions
Source: https://docs.meteora.ag/developer-guide/guides/damm-v2/typescript-sdk/sdk-functions
DAMM v2
## Core Functions
### createPool
Creates a new standard pool according to a predefined configuration.
**Function**
```typescript theme={"system"}
async createPool(params: CreatePoolParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
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 | null; // The slot or timestamp for activation
tokenAAmount: BN; // Initial amount of token A to deposit
tokenBAmount: BN; // Initial amount of token B to deposit
initSqrtPrice: BN; // Initial sqrt price in Q64 format
liquidityDelta: BN; // Initial liquidity delta in Q64 format
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
isLockLiquidity?: boolean; // true if you wanna permanent lock position after pool created.
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
// First, fetch the config and prepare pool creation parameters
const configState = await cpAmm.fetchConfigState(configAddress);
const initPrice = 10; // 1 base token = 10 quote token
const initSqrtPrice = getSqrtPriceFromPrice(initPrice, tokenADecimal, tokenBDecimal);
// Use preparePoolCreationParams to compute initial liquidity
const { liquidityDelta } = cpAmm.preparePoolCreationParams({
tokenAAmount: new BN(5_000_000_000), // 5 tokenA with 9 decimals
tokenBAmount: new BN(50_000_000_000), // 50 tokenB with 9 decimals
minSqrtPrice: configState.sqrtMinPrice,
maxSqrtPrice: configState.sqrtMaxPrice,
collectFeeMode: configState.collectFeeMode,
});
const createPoolTx = await cpAmm.createPool({
payer: wallet.publicKey,
creator: wallet.publicKey,
config: configAddress,
positionNft: positionNftMint,
tokenAMint,
tokenBMint,
activationPoint: null,
tokenAAmount: new BN(5_000_000_000),
tokenBAmount: new BN(50_000_000_000),
initSqrtPrice,
liquidityDelta,
tokenAProgram,
tokenBProgram,
});
```
**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 account
* Pool creation automatically creates an initial position
* Use `preparePoolCreationParams` to calculate proper `initSqrtPrice` and `liquidityDelta`
***
### createCustomPool
Creates a customizable pool with specific fee parameters, reward settings, and activation conditions.
**Function**
```typescript theme={"system"}
async createCustomPool(params: InitializeCustomizeablePoolParams): Promise<{
tx: Transaction;
pool: PublicKey;
position: PublicKey;
}>
```
**Parameters**
```typescript theme={"system"}
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
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: BothToken, 1: OnlyB, 2: Compounding)
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
isLockLiquidity?: boolean; // true if you wanna permanent lock position after pool created.
}
interface PoolFeesParams {
baseFee: BaseFee; // Base fee configuration (encoded via getBaseFeeParams)
compoundingFeeBps: number; // Compounding fee in basis points (only for Compounding collect fee mode)
padding: number; // Padding for future use
dynamicFee: DynamicFee | null; // Optional dynamic fee configuration (via getDynamicFeeParams), null to disable
}
// Base Fee Mode Types:
// 0 = Fee Time Scheduler Linear
// 1 = Fee Time Scheduler Exponential
// 2 = Rate Limiter
// 3 = Fee Market Cap Scheduler Linear
// 4 = Fee Market Cap Scheduler Exponential
// For Fee Time Scheduler (baseFeeMode 0 or 1):
interface FeeTimeSchedulerBaseFee {
cliffFeeNumerator: BN; // Starting fee numerator (e.g., 500000000 = 50%)
baseFeeMode: number; // 0 = Linear, 1 = Exponential
numberOfPeriod: number; // Number of fee reduction periods
periodFrequency: BN; // Time between periods (slots or seconds)
reductionFactor: BN; // Fee reduction per period
}
// For Rate Limiter (baseFeeMode 2):
interface RateLimiterBaseFee {
cliffFeeNumerator: BN; // Base fee numerator (e.g., 10000000 = 1%)
baseFeeMode: number; // 2 = Rate Limiter
feeIncrementBps: number; // Fee increment in basis points per reference amount
maxLimiterDuration: number; // Maximum duration for rate limiter
maxFeeBps: number; // Maximum fee cap in basis points
referenceAmount: BN; // Reference amount for fee calculation
}
// For Fee Market Cap Scheduler (baseFeeMode 3 or 4):
interface FeeMarketCapSchedulerBaseFee {
cliffFeeNumerator: BN; // Starting fee numerator (e.g., 500000000 = 50%)
baseFeeMode: number; // 3 = Linear, 4 = Exponential
numberOfPeriod: number; // Number of fee reduction periods
sqrtPriceStepBps: number; // Sqrt price step in bps to advance one period
schedulerExpirationDuration: number; // Duration after which scheduler expires
reductionFactor: BN; // Fee reduction per period
}
```
**Returns**
An object containing:
* `tx`: The transaction to sign and send
* `pool`: The public key of the created pool
* `position`: The public key of the initial position
**Example**
```typescript theme={"system"}
// First, prepare the pool creation parameters
const { initSqrtPrice, liquidityDelta } = cpAmm.preparePoolCreationParams({
tokenAAmount: new BN(5_000_000_000),
tokenBAmount: new BN(20_000_000),
minSqrtPrice: MIN_SQRT_PRICE,
maxSqrtPrice: MAX_SQRT_PRICE,
collectFeeMode: CollectFeeMode.BothToken,
});
const baseFeeParams = getBaseFeeParams(
{
baseFeeMode: BaseFeeMode.FeeTimeSchedulerExponential,
feeTimeSchedulerParam: {
startingFeeBps: 5000,
endingFeeBps: 25,
numberOfPeriod: 50,
totalDuration: 300,
},
},
9,
ActivationType.Timestamp
);
const dynamicFeeParams = getDynamicFeeParams(25); // max dynamic fee is 20% of 0.25%
const poolFees: PoolFeesParams = {
baseFee: baseFeeParams,
compoundingFeeBps: 0,
padding: 0,
dynamicFee: dynamicFeeParams,
};
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),
sqrtMinPrice: MIN_SQRT_PRICE,
sqrtMaxPrice: MAX_SQRT_PRICE,
initSqrtPrice: initSqrtPrice,
liquidityDelta: liquidityDelta,
poolFees,
hasAlphaVault: false,
collectFeeMode: 0, // 0: BothToken, 1: OnlyB, 2: Compounding
activationPoint: new BN(Date.now()),
activationType: 1, // 0: slot, 1: timestamp
tokenAProgram,
tokenBProgram,
});
```
**Notes**
* Use this function instead of `createPool` when you need custom fee structures
* Use `preparePoolCreationParams` to calculate proper `initSqrtPrice` and `liquidityDelta`
***
### createCustomPoolWithDynamicConfig
Creates a customizable pool with dynamic configuration, allowing for specific fee parameters with specified pool creator authority
**Function**
```typescript theme={"system"}
async createCustomPoolWithDynamicConfig(params: InitializeCustomizeablePoolWithDynamicConfigParams): Promise<{
tx: Transaction;
pool: PublicKey;
position: PublicKey;
}>
```
**Parameters**
```typescript theme={"system"}
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: BothToken, 1: OnlyB, 2: Compounding)
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
isLockLiquidity?: boolean; // true if you wanna permanent lock position after pool created.
}
```
**Returns**
An object containing:
* `tx`: The transaction to sign and send
* `pool`: The public key of the created pool
* `position`: The public key of the initial position
**Example**
```typescript theme={"system"}
// 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,
collectFeeMode: CollectFeeMode.BothToken,
});
const baseFeeParams = getBaseFeeParams(
{
baseFeeMode: BaseFeeMode.FeeTimeSchedulerExponential,
feeTimeSchedulerParam: {
startingFeeBps: 5000,
endingFeeBps: 25,
numberOfPeriod: 50,
totalDuration: 300,
},
},
9,
ActivationType.Timestamp
);
const dynamicFeeParams = getDynamicFeeParams(25); // max dynamic fee is 20% of 0.25%
const poolFees: PoolFeesParams = {
baseFee: baseFeeParams,
compoundingFeeBps: 0,
padding: 0,
dynamicFee: dynamicFeeParams,
};
const { tx, pool, position } = await cpAmm.createCustomPoolWithDynamicConfig({
payer: wallet.publicKey,
creator: wallet.publicKey,
config: dynamicConfigAddress,
poolCreatorAuthority: poolCreatorAuth.publicKey,
positionNft: positionNftMint,
tokenAMint: usdcMint,
tokenBMint: btcMint,
tokenAAmount,
tokenBAmount,
sqrtMinPrice,
sqrtMaxPrice,
initSqrtPrice,
liquidityDelta,
poolFees,
hasAlphaVault: false,
collectFeeMode: 0, // 0: BothToken, 1: OnlyB, 2: Compounding
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**
```typescript theme={"system"}
async createPosition(params: CreatePositionParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
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**
```typescript theme={"system"}
const createPositionTx = await cpAmm.createPosition({
owner: wallet.publicKey,
payer: wallet.publicKey,
pool: poolAddress,
positionNft: positionNftMint,
});
const tx = await createPositionTx.transaction();
const result = await wallet.sendTransaction(tx, connection);
```
**Notes**
* The `positionNft` should be a new mint that doesn't already have a position
* Creating a position doesn't automatically add liquidity
* After creating a position, use `addLiquidity` to provide tokens
***
### getLiquidityDelta
Calculates the liquidity delta based on the provided token amounts and price ranges.
**Function**
```typescript theme={"system"}
async getLiquidityDelta(params: LiquidityDeltaParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface LiquidityDeltaParams {
maxAmountTokenA: BN; // Maximum amount of token A to use
maxAmountTokenB: BN; // Maximum amount of token B to use
sqrtMaxPrice: BN; // Maximum sqrt price for the range
sqrtMinPrice: BN; // Minimum sqrt price for the range
sqrtPrice: BN; // Current sqrt price
collectFeeMode: CollectFeeMode; // How fees are collected (BothToken, OnlyB, or Compounding)
}
```
**Returns**
A BN representing the liquidity delta in Q64 format.
### getQuote
Calculates the expected output amount for a swap, including fees and slippage protection.
**Function**
```typescript theme={"system"}
async getQuote(params: GetQuoteParams): Promise<{
swapInAmount: BN;
consumedInAmount: BN;
swapOutAmount: BN;
minSwapOutAmount: BN;
totalFee: BN;
priceImpact: number;
}>
```
**Parameters**
```typescript theme={"system"}
interface GetQuoteParams {
inAmount: BN; // The amount of input token to swap
inputTokenMint: PublicKey; // The mint of the input token
slippage: number; // Slippage tolerance in percentage (e.g., 0.5 for 0.5%)
poolState: PoolState; // The state of the pool
currentTime: number; // Current timestamp (for time-based fees)
currentSlot: number; // Current slot (for slot-based fees)
inputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
outputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
tokenADecimal: number; // The decimal of the input token
tokenBDecimal: number; // The decimal of the output token
hasReferral?: boolean; // Whether the swap has a referral token account
}
```
**Returns**
An object containing:
* `swapInAmount`: The original input amount
* `consumedInAmount`: The actual input amount used (after transfer fees)
* `swapOutAmount`: The expected output amount
* `minSwapOutAmount`: The minimum output amount accounting for slippage
* `totalFee`: The total fee to be paid
* `priceImpact`: The price impact of the swap as a percentage
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const currentSlot = await connection.getSlot();
const blockTime = await connection.getBlockTime(currentSlot);
const quote = await cpAmm.getQuote({
inAmount: new BN(100_000_000), // 100 USDC
inputTokenMint: usdcMint,
slippage: 0.5, // 0.5% slippage
poolState,
currentTime: blockTime,
currentSlot,
inputTokenInfo: {
mint: usdcMint,
currentEpoch: currentEpoch,
},
outputTokenInfo: {
mint: btcMint,
currentEpoch: currentEpoch,
},
tokenADecimal: 6,
tokenBDecimal: 9,
hasReferral: false,
});
console.log(`Expected output: ${quote.swapOutAmount.toString()}`);
console.log(`Minimum output: ${quote.minSwapOutAmount.toString()}`);
console.log(`Fee: ${quote.totalFee.toString()}`);
console.log(`Price impact: ${quote.priceImpact.toFixed(2)}%`);
```
**Notes**
* Always check the price impact before executing a swap
* The `slippage` parameter protects users from price movements
* Use the `minSwapOutAmount` as the `minimumAmountOut` parameter for `swap`
* For Token2022 tokens with transfer fees, provide the token info parameters
***
### getQuote2
Calculates the expected output amount or input amount for a swap depending on the swap mode. There are 3 swap modes: ExactIn, ExactOut, PartialFill.
**Function**
```typescript theme={"system"}
async getQuote2(params: GetQuote2Params): Promise<{
includedFeeInputAmount: BN;
excludedFeeInputAmount: BN;
amountLeft: BN;
outputAmount: BN;
nextSqrtPrice: BN;
claimingFee: BN;
compoundingFee: BN;
protocolFee: BN;
referralFee: BN;
priceImpact: Decimal;
minimumAmountOut?: BN;
maximumAmountIn?: BN;
}>
```
**Parameters**
```typescript theme={"system"}
interface GetQuote2Params {
inputTokenMint: PublicKey; // The mint of the input token
slippage: number; // Slippage tolerance in percentage (e.g., 0.5 for 0.5%)
currentPoint: BN; // Current point depending on the activation type
poolState: PoolState; // The state of the pool
inputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
outputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
tokenADecimal: number; // The decimal of the input token
tokenBDecimal: number; // The decimal of the output token
hasReferral: boolean; // Whether the swap has a referral token account
swapMode: SwapMode; // The swap mode
amountIn?: BN; // The amount of input token to swap (for ExactIn and PartialFill modes)
amountOut?: BN; // The amount of output token to swap (for ExactOut mode)
}
```
**Returns**
An object containing:
* `includedFeeInputAmount`: The input amount including all applicable fees
* `excludedFeeInputAmount`: The input amount excluding fees
* `amountLeft`: The remaining amount after the swap (if any)
* `outputAmount`: The expected output amount
* `nextSqrtPrice`: The next sqrt price after the swap
* `claimingFee`: The portion of the trading fee claimable by LPs
* `compoundingFee`: The portion of the trading fee compounded back into pool liquidity (only for `Compounding` collect fee mode)
* `protocolFee`: The protocol fee charged for the swap
* `referralFee`: The referral fee charged for the swap
* `priceImpact`: The price impact of the swap
* `minimumAmountOut` (optional): The minimum output amount guaranteed (for ExactIn and PartialFill modes)
* `maximumAmountIn` (optional): The maximum input amount allowed (for ExactOut mode)
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const currentPoint = await getCurrentPoint(
connection,
poolState.activationType
);
const quote = await cpAmm.getQuote2({
inputTokenMint: poolState.tokenBMint,
slippage: 0.5,
currentPoint,
poolState,
tokenADecimal: 6,
tokenBDecimal: 9,
hasReferral: false,
swapMode: SwapMode.PartialFill,
amountIn: new BN(1_000_000_000),
});
```
**Notes**
* Always check the price impact before executing a swap
* The `slippage` parameter protects users from price movements
* For Token2022 tokens with transfer fees, provide the token info parameters
***
### getDepositQuote
Calculates the deposit quote for adding liquidity to a pool based on a single token input.
**Function**
```typescript theme={"system"}
async getDepositQuote(params: GetDepositQuoteParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface GetDepositQuoteParams {
inAmount: BN; // The amount of input token
isTokenA: boolean; // Whether the input token is token A
minSqrtPrice: BN; // Minimum sqrt price
maxSqrtPrice: BN; // Maximum sqrt price
sqrtPrice: BN; // Current sqrt price
inputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
outputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
collectFeeMode: CollectFeeMode; // How fees are collected (BothToken, OnlyB, or Compounding)
tokenAAmount: BN; // Current token A amount in the pool (required for Compounding mode)
tokenBAmount: BN; // Current token B amount in the pool (required for Compounding mode)
liquidity: BN; // Current liquidity of the pool (required for Compounding mode)
}
```
**Returns**
An object containing:
* `actualInputAmount`: The actual input amount (after transfer fees)
* `consumedInputAmount`: The full input amount including transfer fees
* `liquidityDelta`: The amount of liquidity that will be added
* `outputAmount`: The calculated amount of the other token to be paired
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const depositQuote = await cpAmm.getDepositQuote({
inAmount: new BN(1_000_000_000), // 1,000 USDC
isTokenA: true, // USDC is token A
minSqrtPrice: poolState.sqrtMinPrice,
maxSqrtPrice: poolState.sqrtMaxPrice,
sqrtPrice: poolState.sqrtPrice,
collectFeeMode: poolState.collectFeeMode,
tokenAAmount: poolState.tokenAAmount,
tokenBAmount: poolState.tokenBAmount,
liquidity: poolState.liquidity,
});
console.log(`Liquidity delta: ${depositQuote.liquidityDelta.toString()}`);
console.log(`Required token B: ${depositQuote.outputAmount.toString()}`);
```
**Notes**
* Use this to calculate how much of token B is needed when adding token A (or vice versa)
* Particularly useful for single-sided liquidity provision
* The function handles Token2022 transfer fees if token info is provided
***
### getWithdrawQuote
Calculates the withdrawal quote for removing liquidity from a pool.
**Function**
```typescript theme={"system"}
async getWithdrawQuote(params: GetWithdrawQuoteParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface GetWithdrawQuoteParams {
liquidityDelta: BN; // The amount of liquidity to withdraw
sqrtPrice: BN; // Current sqrt price
maxSqrtPrice: BN; // Maximum sqrt price
minSqrtPrice: BN; // Minimum sqrt price
inputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
outputTokenInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
collectFeeMode: CollectFeeMode; // How fees are collected (BothToken, OnlyB, or Compounding)
tokenAAmount: BN; // Current token A amount in the pool (required for Compounding mode)
tokenBAmount: BN; // Current token B amount in the pool (required for Compounding mode)
liquidity: BN; // Current liquidity of the pool (required for Compounding mode)
}
```
**Returns**
An object containing:
* `liquidityDelta`: The amount of liquidity being removed
* `outAmountA`: The calculated amount of token A to receive
* `outAmountB`: The calculated amount of token B to receive
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionState = await cpAmm.fetchPositionState(positionAddress);
// Calculate quote for removing half the liquidity
const liquidityToRemove = positionState.liquidity.div(new BN(2));
const withdrawQuote = await cpAmm.getWithdrawQuote({
liquidityDelta: liquidityToRemove,
sqrtPrice: poolState.sqrtPrice,
minSqrtPrice: poolState.sqrtMinPrice,
maxSqrtPrice: poolState.sqrtMaxPrice,
collectFeeMode: poolState.collectFeeMode,
tokenAAmount: poolState.tokenAAmount,
tokenBAmount: poolState.tokenBAmount,
liquidity: poolState.liquidity,
});
console.log(`Expected token A: ${withdrawQuote.outAmountA.toString()}`);
console.log(`Expected token B: ${withdrawQuote.outAmountB.toString()}`);
```
**Notes**
* Use this to estimate the tokens you'll receive when removing liquidity
* The function handles Token2022 transfer fees if token info is provided
* The calculation accounts for the current price relative to the position's price range
***
### swap
Executes a token swap in the pool.
**Function**
```typescript theme={"system"}
async swap(params: SwapParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface SwapParams {
payer: PublicKey; // The wallet paying for the transaction
pool: PublicKey; // Address of the pool to swap in
inputTokenMint: PublicKey; // Mint of the input token
outputTokenMint: PublicKey; // Mint of the output token
amountIn: BN; // Amount of input token to swap
minimumAmountOut: BN; // Minimum amount of output token (slippage protection)
tokenAVault: PublicKey; // Pool's token A vault
tokenBVault: PublicKey; // Pool's token B vault
tokenAMint: PublicKey; // Pool's token A mint
tokenBMint: PublicKey; // Pool's token B mint
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
receiver?: PublicKey; // Optional receiver of the input and output tokens
referralTokenAccount?: PublicKey; // Optional referral account for fees
poolState?: PoolState; // Optional pool state to pass in to atomically fetch the pool state
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const currentSlot = await connection.getSlot();
const blockTime = await connection.getBlockTime(currentSlot);
// Get quote first
const quote = await cpAmm.getQuote({
inAmount: new BN(100_000_000), // 100 USDC
inputTokenMint: poolState.tokenAMint,
slippage: 0.5,
poolState,
currentTime: blockTime,
currentSlot,
});
// Execute swap
const swapTx = await cpAmm.swap({
payer: wallet.publicKey,
pool: poolAddress,
inputTokenMint: poolState.tokenAMint,
outputTokenMint: poolState.tokenBMint,
amountIn: new BN(100_000_000),
minimumAmountOut: quote.minSwapOutAmount,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAProgram: TOKEN_PROGRAM_ID,
tokenBProgram: TOKEN_PROGRAM_ID,
});
```
**Notes**
* Get a quote first using `getQuote` to determine the `minimumAmountOut`
* The SDK handles wrapping/unwrapping of SOL automatically
* Token accounts are created automatically if they don't exist
* The transaction will fail if the output amount would be less than `minimumAmountOut`
* Optional referral tokenAccount will receive a portion of fees if the pool is configured for referrals
***
### swap2
Executes a token swap in the pool depending on the swap mode. There are 3 swap modes: ExactIn, ExactOut, PartialFill.
**Function**
```typescript theme={"system"}
async swap2(params: Swap2Params): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface Swap2Params {
payer: PublicKey; // The wallet paying for the transaction
pool: PublicKey; // Address of the pool to swap in
inputTokenMint: PublicKey; // Mint of the input token
outputTokenMint: PublicKey; // Mint of the output token
tokenAMint: PublicKey; // Pool's token A mint
tokenBMint: PublicKey; // Pool's token B mint
tokenAVault: PublicKey; // Pool's token A vault
tokenBVault: PublicKey; // Pool's token B vault
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
referralTokenAccount: PublicKey | null; // Referral account for fees, null if none
receiver?: PublicKey; // Optional receiver of the input and output tokens
poolState?: PoolState; // Optional pool state to avoid refetching
// Union type: provide one of the following swap mode configurations:
// ExactIn: { swapMode: SwapMode.ExactIn, amountIn: BN, minimumAmountOut: BN }
// ExactOut: { swapMode: SwapMode.ExactOut, amountOut: BN, maximumAmountIn: BN }
// PartialFill: { swapMode: SwapMode.PartialFill, amountIn: BN, minimumAmountOut: BN }
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const currentPoint = await getCurrentPoint(
connection,
poolState.activationType
);
// Get quote first
const quote = await cpAmm.getQuote2({
inputTokenMint: poolState.tokenBMint,
slippage: 0.5,
currentPoint,
poolState,
tokenADecimal: 6,
tokenBDecimal: 9,
hasReferral: false,
swapMode: SwapMode.PartialFill,
amountIn: new BN(1_000_000_000),
});
// Execute swap
const swap2Tx = await cpAmm.swap2({
payer: wallet.publicKey,
pool: poolAddress,
inputTokenMint: poolState.tokenAMint,
outputTokenMint: poolState.tokenBMint,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAProgram: TOKEN_PROGRAM_ID,
tokenBProgram: TOKEN_PROGRAM_ID,
referralTokenAccount: null,
swapMode: SwapMode.PartialFill,
amountIn: new BN(1_000_000_000),
minimumAmountOut: quote.minimumAmountOut,
});
```
**Notes**
* Get a quote first using `getQuote2` to determine the `minimumAmountOut` or `maximumAmountIn` depending on the swap mode
* The SDK handles wrapping/unwrapping of SOL automatically
* Token accounts are created automatically if they don't exist
* The transaction will fail if the output amount would be less than `minimumAmountOut` or the input amount would be greater than `maximumAmountIn` depending on the swap mode
* Optional referral tokenAccount will receive a portion of fees if the pool is configured for referrals
***
### addLiquidity
Adds liquidity to an existing position.
**Function**
```typescript theme={"system"}
async addLiquidity(params: AddLiquidityParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface AddLiquidityParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The ata account of position nft
liquidityDelta: 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**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionState = await cpAmm.fetchPositionState(positionAddress);
// Get deposit quote
const depositQuote = await cpAmm.getDepositQuote({
inAmount: new BN(1_000_000_000), // 1,000 USDC
isTokenA: true,
minSqrtPrice: poolState.sqrtMinPrice,
maxSqrtPrice: poolState.sqrtMaxPrice,
sqrtPrice: poolState.sqrtPrice,
collectFeeMode: poolState.collectFeeMode,
tokenAAmount: poolState.tokenAAmount,
tokenBAmount: poolState.tokenBAmount,
liquidity: poolState.liquidity,
});
// Add liquidity
const addLiquidityTx = await cpAmm.addLiquidity({
owner: wallet.publicKey,
pool: poolAddress,
position: positionAddress,
positionNftAccount: positionNftAccount,
liquidityDelta: depositQuote.liquidityDelta,
maxAmountTokenA: new BN(1_000_000_000),
maxAmountTokenB: depositQuote.outputAmount,
tokenAAmountThreshold: maxAmountTokenA,
tokenBAmountThreshold: maxAmountTokenB,
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAProgram,
tokenBProgram,
});
```
**Notes**
* Calculate the liquidity delta first using `getDepositQuote`
* 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
***
### createPositionAndAddLiquidity
Creates a new position and adds liquidity in a single transaction. Handles both native SOL and other tokens, automatically wrapping/unwrapping SOL as needed.
**Function**
```typescript theme={"system"}
async createPositionAndAddLiquidity(params: CreatePositionAndAddLiquidity): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface CreatePositionAndAddLiquidity {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool to create a position in
positionNft: PublicKey; // The mint for the position NFT
liquidityDelta: BN; // The amount of liquidity to add
maxAmountTokenA: BN; // Maximum token A amount to deposit
maxAmountTokenB: BN; // Maximum token B amount to deposit
tokenAAmountThreshold: BN; // Minimum token A threshold (slippage protection)
tokenBAmountThreshold: BN; // Minimum token B threshold (slippage protection)
tokenAMint: PublicKey; // Pool's token A mint
tokenBMint: PublicKey; // Pool's token B mint
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**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionNftMint = Keypair.generate();
const depositQuote = cpAmm.getDepositQuote({
inAmount: new BN(1_000_000_000),
isTokenA: true,
minSqrtPrice: poolState.sqrtMinPrice,
maxSqrtPrice: poolState.sqrtMaxPrice,
sqrtPrice: poolState.sqrtPrice,
collectFeeMode: poolState.collectFeeMode,
tokenAAmount: poolState.tokenAAmount,
tokenBAmount: poolState.tokenBAmount,
liquidity: poolState.liquidity,
});
const tx = await cpAmm.createPositionAndAddLiquidity({
owner: wallet.publicKey,
pool: poolAddress,
positionNft: positionNftMint.publicKey,
liquidityDelta: depositQuote.liquidityDelta,
maxAmountTokenA: new BN(1_000_000_000),
maxAmountTokenB: depositQuote.outputAmount,
tokenAAmountThreshold: new BN(1_000_000_000),
tokenBAmountThreshold: depositQuote.outputAmount,
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAProgram: TOKEN_PROGRAM_ID,
tokenBProgram: TOKEN_PROGRAM_ID,
});
```
**Notes**
* Combines `createPosition` and `addLiquidity` into a single transaction for convenience
* The SDK handles wrapping/unwrapping of SOL automatically
* Token accounts are created automatically if they don't exist
***
### removeLiquidity
Removes a specific amount of liquidity from an existing position.
**Function**
```typescript theme={"system"}
async removeLiquidity(params: RemoveLiquidityParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface RemoveLiquidityParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
position: PublicKey; // The position address
positionNftAccount?: PublicKey; // The position NFT account
liquidityDelta: BN; // The amount of liquidity to remove in Q64 format
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
vestings?: Array<{ account: PublicKey }>; // Optional vesting accounts to refresh
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionState = await cpAmm.fetchPositionState(positionAddress);
// Get withdraw quote for half of the liquidity
const liquidityToRemove = positionState.unlockedLiquidity.div(new BN(2));
const withdrawQuote = await cpAmm.getWithdrawQuote({
liquidityDelta: liquidityToRemove,
sqrtPrice: poolState.sqrtPrice,
minSqrtPrice: poolState.sqrtMinPrice,
maxSqrtPrice: poolState.sqrtMaxPrice,
collectFeeMode: poolState.collectFeeMode,
tokenAAmount: poolState.tokenAAmount,
tokenBAmount: poolState.tokenBAmount,
liquidity: poolState.liquidity,
});
const removeLiquidityTx = await cpAmm.removeLiquidity({
owner: wallet.publicKey,
pool: poolAddress,
position: positionAddress,
positionNftAccount: positionNftAccount,
liquidityDelta: liquidityToRemove,
tokenAAmountThreshold: new BN(0),
tokenBAmountThreshold: new BN(0),
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAProgram,
tokenBProgram,
});
```
**Notes**
* You can only remove unlocked liquidity
* 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
* Removing all liquidity doesn't close the position
***
### removeAllLiquidity
Removes all available liquidity from a position.
**Function**
```typescript theme={"system"}
async removeAllLiquidity(params: RemoveAllLiquidityParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface RemoveAllLiquidityParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The ata account of position nft
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
vestings?: Array<{ account: PublicKey }>; // Optional vesting accounts to refresh if position has vesting lock
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionState = await cpAmm.fetchPositionState(positionAddress);
const removeAllLiquidityTx = await cpAmm.removeAllLiquidity({
owner: wallet.publicKey,
pool: poolAddress,
position: positionAddress,
positionNftAccount: positionNftAccount,
tokenAAmountThreshold: new BN(0),
tokenBAmountThreshold: new BN(0),
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAProgram,
tokenBProgram,
});
```
**Notes**
* This removes all unlocked liquidity in one transaction
* The position remains open after removing all liquidity
* You can't remove locked liquidity (use `refreshVesting` first if needed)
* The SDK handles wrapping/unwrapping of SOL automatically
***
### removeAllLiquidityAndClosePosition
Removes all liquidity from a position and closes it in a single transaction.
**Function**
```typescript theme={"system"}
async removeAllLiquidityAndClosePosition(params: RemoveAllLiquidityAndClosePositionParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface RemoveAllLiquidityAndClosePositionParams {
owner: PublicKey; // The owner of the position
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The position NFT account
positionState: PositionState; // The current position state
poolState: PoolState; // The current pool state
tokenAAmountThreshold: BN; // Minimum acceptable token A amount (slippage protection)
tokenBAmountThreshold: BN; // Minimum acceptable token B amount (slippage protection)
currentPoint: BN; // Current timestamp or slot number for vesting calculations
vestings?: Array<{ account: PublicKey; vestingState: VestingState }>; // Optional vesting accounts
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionState = await cpAmm.fetchPositionState(positionAddress);
// Check if position is locked
if (cpAmm.isLockedPosition(positionState)) {
console.error("Cannot close a locked position");
return;
}
// Build transaction to remove all liquidity and close position
const tx = await cpAmm.removeAllLiquidityAndClosePosition({
owner: wallet.publicKey,
position: positionAddress,
positionNftAccount: positionNftAccount,
positionState: positionState,
poolState: poolState,
tokenAAmountThreshold: new BN(0),
tokenBAmountThreshold: new BN(0),
});
```
**Notes**
* This combines multiple operations in a single transaction:
1. Claims any accumulated fees
2. Removes all liquidity
3. Closes the position and returns the rent
* The position must be completely unlocked
* The function will throw an error if the position has any locked liquidity
* This is more gas-efficient than doing these operations separately
* If there are vesting schedules, they must be refreshed before closing the position
***
### mergePosition
Merges liquidity from one position into another in a single transaction.
**Function**
```typescript theme={"system"}
async mergePosition(params: MergePositionParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface MergePositionParams {
owner: PublicKey; // The owner of both positions
positionA: PublicKey; // Target position to merge into
positionB: PublicKey; // Source position to merge from
positionBState: PositionState; // State of the source position
poolState: PoolState; // State of the pool
positionANftAccount: PublicKey; // ata account of target position NFT
positionBNftAccount: PublicKey; // ata account of source position NFT
tokenAAmountAddLiquidityThreshold: BN; // Minimum token A amount for add liquidity
tokenBAmountAddLiquidityThreshold: BN; // Minimum token B amount for add liquidity
tokenAAmountRemoveLiquidityThreshold: BN; // Minimum token A amount for remove liquidity
tokenBAmountRemoveLiquidityThreshold: BN; // Minimum token B amount for remove liquidity
currentPoint: BN; // Current timestamp or slot number for vesting calculations
positionBVestings?: Array<{ account: PublicKey; vestingState: VestingState }>; // Optional vesting accounts for position B
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionAState = await cpAmm.fetchPositionState(positionAAddress); // Target position
const positionBState = await cpAmm.fetchPositionState(positionBAddress); // Source position to merge from
// Check if position is locked
if (cpAmm.isLockedPosition(positionBState)) {
console.error("Cannot merge a locked position");
return;
}
// Build transaction to merge positions
const tx = await cpAmm.mergePosition({
owner: wallet.publicKey,
positionA: positionAAddress,
positionB: positionBAddress,
positionBState: positionBState,
poolState: poolState,
positionANftAccount: positionANftAccount,
positionBNftAccount: positionBNftAccount,
tokenAAmountAddLiquidityThreshold: new BN(U64_MAX),
tokenBAmountAddLiquidityThreshold: new BN(u64_MAX),
tokenAAmountRemoveLiquidityThreshold: new BN(0),
tokenBAmountRemoveLiquidityThreshold: new BN(0),
});
```
**Notes**
* This function combines multiple operations:
1. Claims any accumulated fees from the source position
2. Removes all liquidity from the source position
3. Adds the liquidity to the target position
4. Closes the source position
* Both positions must be owned by the same wallet
* The source position must be completely unlocked
* This is more gas-efficient than performing these operations separately
* Set appropriate thresholds to protect against slippage for both add and remove operations
***
### lockPosition
Builds a transaction to lock a position with vesting schedule.
**Function**
```typescript theme={"system"}
async lockPosition(params: LockPositionParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface LockPositionParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
payer: PublicKey; // The wallet paying for the transaction
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The position NFT account
cliffPoint: BN | null; // The cliff point (slot or timestamp)
periodFrequency: BN; // How often liquidity unlocks
cliffUnlockLiquidity: BN; // Amount to unlock at cliff
liquidityPerPeriod: BN; // Amount to unlock per period
numberOfPeriod: number; // Number of vesting periods
vestingAccount?: PublicKey; // The vesting account to create (required for when innerPosition is not provided or false)
innerPosition?: boolean; // Whether the position is an inner position (required to be true for when vestingAccount is not provided)
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
With vesting account:
```typescript theme={"system"}
const vestingAccount = Keypair.generate();
const lockPositionTx = await cpAmm.lockPosition({
owner: wallet.publicKey,
pool: poolAddress,
payer: wallet.publicKey,
vestingAccount: vestingAccount.publicKey,
position: positionAddress,
positionNftAccount: positionNftAccount,
cliffPoint: new BN(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days cliff
periodFrequency: new BN(24 * 60 * 60 * 1000), // 1 day periods
cliffUnlockLiquidity: new BN(0), // No initial unlock
liquidityPerPeriod: positionState.unlockedLiquidity.div(new BN(30)), // Unlock over 30 days
numberOfPeriod: 30, // 30 periods
});
```
Without vesting account:
```typescript theme={"system"}
const lockPositionTx = await cpAmm.lockPosition({
owner: wallet.publicKey,
pool: poolAddress,
payer: wallet.publicKey,
position: positionAddress,
positionNftAccount: positionNftAccount,
cliffPoint: new BN(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days cliff
periodFrequency: new BN(24 * 60 * 60 * 1000), // 1 day periods
cliffUnlockLiquidity: new BN(0), // No initial unlock
liquidityPerPeriod: positionState.unlockedLiquidity.div(new BN(30)), // Unlock over 30 days
numberOfPeriod: 30, // 30 periods
innerPosition: true,
});
```
**Notes**
* Locking positions is useful for creating various incentive mechanisms
* The vesting schedule controls how quickly liquidity unlocks over time
* Locked liquidity cannot be withdrawn until it becomes unlocked
* The vesting account is a new account that must be created
* The function only locks currently unlocked liquidity
***
### permanentLockPosition
Permanently locks a portion of liquidity in a position.
**Function**
```typescript theme={"system"}
async permanentLockPosition(params: PermanentLockParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface PermanentLockParams {
owner: PublicKey; // The owner of the position
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The position NFT account
pool: PublicKey; // The pool address
unlockedLiquidity: BN; // Amount of liquidity to permanently lock
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const positionState = await cpAmm.fetchPositionState(positionAddress);
// Permanently lock half of the unlocked liquidity
const liquidityToLock = positionState.unlockedLiquidity.div(new BN(2));
const lockTx = await cpAmm.permanentLockPosition({
owner: wallet.publicKey,
position: positionAddress,
positionNftAccount: positionNftAccount,
pool: poolAddress,
unlockedLiquidity: liquidityToLock,
});
```
**Notes**
* Permanently locked liquidity can never be withdrawn
* This is useful for deep liquidity protocols or governance mechanisms
* Once liquidity is permanently locked, this action cannot be reversed
* The owner can still collect fees from permanently locked liquidity
***
### refreshVesting
Refreshes vesting status of a position to unlock available liquidity.
**Function**
```typescript theme={"system"}
async refreshVesting(params: RefreshVestingParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface RefreshVestingParams {
owner: PublicKey; // The owner of the position
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The position NFT account
pool: PublicKey; // The pool address
vestingAccounts: PublicKey[]; // Array of vesting accounts to refresh
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
// Get all vesting accounts for the position
const vestings = await cpAmm.getAllVestingsByPosition(positionAddress);
const refreshVestingTx = await cpAmm.refreshVesting({
owner: wallet.publicKey,
position: positionAddress,
positionNftAccount: positionNftAccount,
pool: poolAddress,
vestingAccounts: vestings.map((v) => v.publicKey),
});
```
**Notes**
* Call this function to update the vesting state and unlock available liquidity
* Should be called periodically to ensure liquidity is properly unlocked
* If all liquidity is unlocked, the vesting account remains but is no longer used
* Must be called before removing liquidity if position has vesting accounts
***
### claimPositionFee
Claims accumulated fees for a position.
**Function**
```typescript theme={"system"}
async claimPositionFee(params: ClaimPositionFeeParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface ClaimPositionFeeParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The position NFT account
tokenAVault: PublicKey; // The pool's token A vault
tokenBVault: PublicKey; // The pool's token B vault
tokenAMint: PublicKey; // The mint of token A
tokenBMint: PublicKey; // The mint of token B
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
receiver?: Pubkey; // the wallet that will receive the fees (optional)
tempWSolAccount?: Pubkey; // the temporary wallet that will receive the fees (optional)
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const claimFeeTx = await cpAmm.claimPositionFee({
owner: wallet.publicKey,
pool: poolAddress,
position: positionAddress,
positionNftAccount: positionNftAccount,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAProgram,
tokenBProgram,
});
```
**Notes**
* Fees are collected when trades occur in the pool
* Only the position owner can claim fees
* Fees are earned on both token A and token B based on the amount of liquidity provided
* Fees accumulate over time and should be claimed periodically
* The SDK handles wrapping/unwrapping of SOL automatically
### claimPositionFee2
Claims accumulated fees for a position.
**Function**
```typescript theme={"system"}
async claimPositionFee2(params: ClaimPositionFeeParams2): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface ClaimPositionFeeParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
position: PublicKey; // The position address
positionNftAccount: PublicKey; // The position NFT account
tokenAVault: PublicKey; // The pool's token A vault
tokenBVault: PublicKey; // The pool's token B vault
tokenAMint: PublicKey; // The mint of token A
tokenBMint: PublicKey; // The mint of token B
tokenAProgram: PublicKey; // Token program for token A
tokenBProgram: PublicKey; // Token program for token B
receiver: Pubkey; // The wallet that will receive the fees
feePayer?: PublicKey; // Specific fee payer for transaction. Default fee payer is position's owner
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const claimFeeTx = await cpAmm.claimPositionFee2({
owner: wallet.publicKey,
pool: poolAddress,
position: positionAddress,
receiver: receiverAddress,
positionNftAccount: positionNftAccount,
tokenAVault: poolState.tokenAVault,
tokenBVault: poolState.tokenBVault,
tokenAMint: poolState.tokenAMint,
tokenBMint: poolState.tokenBMint,
tokenAProgram,
tokenBProgram,
});
```
**Notes**
* Fees are collected when trades occur in the pool
* Only the position owner can claim fees
* Fees will claim to receiver address
* Fees are earned on both token A and token B based on the amount of liquidity provided
* The SDK handles wrapping/unwrapping of SOL automatically
***
### initializeReward
Initializes a reward for a pool.
**Function**
```typescript theme={"system"}
async initializeReward(params: InitializeRewardParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface InitializeRewardParams {
rewardIndex: number; // 0: for creators or admins, 1: for admins only
rewardDuration: BN; // Duration of the reward
pool: PublicKey; // The pool address
rewardMint: PublicKey; // The reward mint address
funder: PublicKey; // The
payer: PublicKey; // The payer address
creator: PublicKey; // The creator address
rewardMintProgram: PublicKey; // The reward mint program address
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const initializeRewardTx = await cpAmm.initializeReward({
rewardIndex: 0,
rewardDuration: new BN(1000000000),
pool: poolAddress,
rewardMint: rewardMintAddress,
funder: wallet.publicKey,
payer: wallet.publicKey,
creator: wallet.publicKey,
rewardMintProgram: rewardMintProgramAddress,
});
```
**Notes**
* Only the pool creator can initialize a reward
* The funder is the account that will fund the reward
* The payer is the account that will pay for the initialize reward transaction
* The creator is the account that is the creator of the pool
* The reward mint program is the program that will mint the reward
* Pool creators can only initialize rewards for `rewardIndex` = 0. `rewardIndex` = 1 is a permissioned reward initialization for admins only.
***
### initializeAndFundReward
Initializes and funds a reward for a pool.
**Function**
```typescript theme={"system"}
async initializeAndFundReward(params: InitializeAndFundReward): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface InitializeAndFundRewardParams {
rewardIndex: number; // 0: for creators or admins, 1: for admins only
rewardDuration: BN; // Duration of the reward
pool: PublicKey; // The pool address
creator: PublicKey; // The creator address
payer: PublicKey; // The payer address
rewardMint: PublicKey; // The reward mint address
carryForward: boolean; // Whether to carry forward the reward
amount: BN; // The amount to fund
rewardMintProgram: PublicKey; // The reward mint program address
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const initializeAndFundRewardTx = await cpAmm.initializeAndFundReward({
rewardIndex: 0,
rewardDuration: new BN(1000000000),
pool: poolAddress,
creator: wallet.publicKey,
payer: wallet.publicKey,
rewardMint: rewardMintAddress,
carryForward: true,
amount: new BN(1000000000),
rewardMintProgram: rewardMintProgramAddress,
});
```
**Notes**
* Only the pool creator can initialize a reward
* The creator in this case is also the funder of the reward
* The payer is the account that will pay for the initialize reward transaction
* The reward mint program is the program that will mint the reward
* Pool creators can only initialize rewards for `rewardIndex` = 0. `rewardIndex` = 1 is a permissioned reward initialization for admins only.
* The carryForward parameter specifies whether to carry forward the reward
***
### updateRewardDuration
Updates the duration of a reward.
**Function**
```typescript theme={"system"}
async updateRewardDuration(params: UpdateRewardDurationParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface UpdateRewardDurationParams {
pool: PublicKey; // The pool address
signer: PublicKey; // The signer of the transaction
rewardIndex: number; // Index of the reward to update
newDuration: BN; // New duration of the reward
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const updateRewardDurationTx = await cpAmm.updateRewardDuration({
pool: poolAddress,
signer: wallet.publicKey,
rewardIndex: 0,
newDuration: new BN(1000000000),
});
```
**Notes**
* Only the pool creator or admin can update the duration of a reward
* The new duration must be greater than the current duration
* The signer must be the pool creator or admin depending on the `rewardIndex`
***
### updateRewardFunder
Updates the funder of a reward.
**Function**
```typescript theme={"system"}
async updateRewardFunder(params: UpdateRewardFunderParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface UpdateRewardFunderParams {
pool: PublicKey; // The pool address
signer: PublicKey; // The signer of the transaction
rewardIndex: number; // Index of the reward to update
newFunder: PublicKey; // The new funder of the reward
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const updateRewardFunderTx = await cpAmm.updateRewardFunder({
pool: poolAddress,
signer: wallet.publicKey,
rewardIndex: 0,
newFunder: newFunderAddress,
});
```
**Notes**
* Only the pool creator can update the funder of a reward
* The new funder must be a valid public key
* The signer must be the pool creator or admin depending on the `rewardIndex`
***
### fundReward
Funds a reward for a pool.
**Function**
```typescript theme={"system"}
async fundReward(params: FundRewardParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface FundRewardParams {
funder: PublicKey; // The funder address
rewardIndex: number; // Index of the reward to fund
pool: PublicKey; // The pool address
carryForward: boolean; // Whether to carry forward the reward
amount: BN; // The amount to fund
rewardMint: PublicKey; // The reward token mint address
rewardVault: PublicKey; // The reward vault address
rewardMintProgram: PublicKey; // The reward mint's program id
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const fundRewardTx = await cpAmm.fundReward({
funder: wallet.publicKey,
rewardIndex: 0,
pool: poolAddress,
carryForward: true,
amount: new BN(1000000000),
rewardMint: rewardMintAddress,
rewardVault: rewardVaultAddress,
rewardMintProgram: rewardMintProgramAddress,
});
```
**Notes**
* Only the pool creator can fund rewards
* The rewardIndex parameter specifies which reward token to fund
* The carryForward parameter specifies whether to carry forward the reward
* The amount parameter specifies the amount to fund
***
### claimReward
Claims reward tokens from a position.
**Function**
```typescript theme={"system"}
async claimReward(params: ClaimRewardParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface ClaimRewardParams {
user: PublicKey; // The user claiming rewards
position: PublicKey; // The position address
poolState: PoolState; // The current pool state
positionState: PositionState; // The current position state
positionNftAccount: PublicKey; // The position NFT account
rewardIndex: number; // Index of the reward to claim
isSkipReward: boolean; // Whether to skip reward transfer
feePayer?: PublicKey; // Specific fee payer for transaction. Default fee payer is user
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionState = await cpAmm.fetchPositionState(positionAddress);
// Claim reward at index 0
const claimRewardTx = await cpAmm.claimReward({
user: wallet.publicKey,
position: positionAddress,
poolState: poolState,
positionState: positionState,
positionNftAccount: positionNftAccount,
rewardIndex: 0,
isSkipReward: false,
feePayer: wallet.publicKey,
});
```
**Notes**
* Pools can have multiple reward tokens configured
* The rewardIndex parameter specifies which reward token to claim
* Rewards accrue based on the amount of liquidity provided and duration
* Only the position owner can claim rewards
* The SDK handles wrapping/unwrapping of SOL automatically
***
### withdrawIneligibleReward
Withdraws ineligible reward tokens from a pool.
**Function**
```typescript theme={"system"}
async withdrawIneligibleReward(params: WithdrawIneligibleRewardParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface WithdrawIneligibleRewardParams {
rewardIndex: number; // Index of the reward to withdraw
pool: PublicKey; // The pool address
funder: PublicKey; // The funder address to withdraw to
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const withdrawIneligibleRewardTx = await cpAmm.withdrawIneligibleReward({
rewardIndex: 0,
pool: poolAddress,
funder: wallet.publicKey,
});
```
**Notes**
* Only the pool creator can withdraw ineligible rewards
* The rewardIndex parameter specifies which reward token to withdraw
* The funder parameter specifies the address to withdraw to
***
### closePosition
Closes a position with no liquidity.
**Function**
```typescript theme={"system"}
async closePosition(params: ClosePositionParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface ClosePositionParams {
owner: PublicKey; // The owner of the position
pool: PublicKey; // The pool address
position: PublicKey; // The position address
positionNftMint: PublicKey; // The position NFT mint
positionNftAccount: PublicKey; // The position NFT account
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const positionState = await cpAmm.fetchPositionState(positionAddress);
// Check if position has no liquidity
if (
!positionState.unlockedLiquidity.isZero() ||
!positionState.vestedLiquidity.isZero() ||
!positionState.permanentLockedLiquidity.isZero()
) {
console.error("Position still has liquidity");
return;
}
const closePositionTx = await cpAmm.closePosition({
owner: wallet.publicKey,
pool: positionState.pool,
position: positionAddress,
positionNftMint: positionState.nftMint,
positionNftAccount: positionNftAccount,
});
```
**Notes**
* Position must have zero liquidity before closing
* Use `removeAllLiquidity` first if the position still has liquidity
* Closing a position returns the rent to the owner
* This function only closes the position account, not the NFT
* For a full cleanup, use `removeAllLiquidityAndClosePosition` instead
***
### splitPosition
Splits a position into two positions.
**Function**
```typescript theme={"system"}
async splitPosition(params: SplitPositionParams): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface SplitPositionParams {
firstPositionOwner: PublicKey; // The owner of the first position
secondPositionOwner: PublicKey; // The owner of the second position
pool: PublicKey; // The pool address
firstPosition: PublicKey; // The first position address
firstPositionNftAccount: PublicKey; // The first position NFT account
secondPosition: PublicKey; // The second position address
secondPositionNftAccount: PublicKey; // The second position NFT account
unlockedLiquidityPercentage: number; // The percentage of unlocked liquidity to split
permanentLockedLiquidityPercentage: number; // The percentage of permanent locked liquidity to split
feeAPercentage: number; // The percentage of fee A to split
feeBPercentage: number; // The percentage of fee B to split
reward0Percentage: number; // The percentage of reward 0 to split
reward1Percentage: number; // The percentage of reward 1 to split
innerVestingLiquidityPercentage: number; // The percentage of inner vesting liquidity to split
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const firstPosition = await client.getUserPositionByPool(
poolAddress,
firstUser.publicKey
);
const secondPositionKP = Keypair.generate();
const createSecondPositionTx = await client.createPosition({
owner: secondUser.publicKey,
payer: secondUser.publicKey,
pool: poolAddress,
positionNft: secondPositionKP.publicKey,
});
const createSignature = await sendAndConfirmTransaction(
connection,
createSecondPositionTx,
[secondUser, secondPositionKP],
{
commitment: "confirmed",
skipPreflight: true,
}
);
console.log("Second position created:", createSignature);
const secondPosition = await client.getUserPositionByPool(
poolAddress,
secondUser.publicKey
);
const splitPositionTx = await client.splitPosition({
firstPositionOwner: firstUser.publicKey,
secondPositionOwner: secondUser.publicKey,
pool: poolAddress,
firstPosition: firstPosition[0].position,
firstPositionNftAccount: firstPosition[0].positionNftAccount,
secondPosition: secondPosition[0].position,
secondPositionNftAccount: secondPosition[0].positionNftAccount,
unlockedLiquidityPercentage: 50,
permanentLockedLiquidityPercentage: 0,
feeAPercentage: 50,
feeBPercentage: 50,
reward0Percentage: 50,
reward1Percentage: 50,
innerVestingLiquidityPercentage: 50,
});
```
**Notes**
* The first position must already exist for that pool
* The second position can be a new empty position for that same pool
***
### splitPosition2
Splits a position into two positions via numerator.
**Function**
```typescript theme={"system"}
async splitPosition2(params: SplitPosition2Params): TxBuilder
```
**Parameters**
```typescript theme={"system"}
interface SplitPosition2Params {
firstPositionOwner: PublicKey; // The owner of the first position
secondPositionOwner: PublicKey; // The owner of the second position
pool: PublicKey; // The pool address
firstPosition: PublicKey; // The first position address
firstPositionNftAccount: PublicKey; // The first position NFT account
secondPosition: PublicKey; // The second position address
secondPositionNftAccount: PublicKey; // The second position NFT account
numerator: number; // The numerator to split the position by, which is a percentage of the position
}
```
**Returns**
A transaction builder (`TxBuilder`) that can be used to build, sign, and send the transaction.
**Example**
```typescript theme={"system"}
const firstPosition = await client.getUserPositionByPool(
poolAddress,
firstUser.publicKey
);
const secondPositionKP = Keypair.generate();
const createSecondPositionTx = await client.createPosition({
owner: secondUser.publicKey,
payer: secondUser.publicKey,
pool: poolAddress,
positionNft: secondPositionKP.publicKey,
});
const createSignature = await sendAndConfirmTransaction(
connection,
createSecondPositionTx,
[secondUser, secondPositionKP],
{
commitment: "confirmed",
skipPreflight: true,
}
);
console.log("Second position created:", createSignature);
const secondPosition = await client.getUserPositionByPool(
poolAddress,
secondUser.publicKey
);
const splitPosition2Tx = await client.splitPosition2({
firstPositionOwner: firstUser.publicKey,
secondPositionOwner: secondUser.publicKey,
pool: poolAddress,
firstPosition: firstPosition[0].position,
firstPositionNftAccount: firstPosition[0].positionNftAccount,
secondPosition: secondPosition[0].position,
secondPositionNftAccount: secondPosition[0].positionNftAccount,
numerator: SPLIT_POSITION_DENOMINATOR / 2,
});
```
**Notes**
* The first position must already exist for that pool
* The second position can be a new empty position for that same pool
***
## State Functions
### fetchConfigState
Fetches the Config state of the program.
**Function**
```typescript theme={"system"}
async fetchConfigState(config: PublicKey): Promise
```
**Parameters**
* `config`: Public key of the config account.
**Returns**
Parsed ConfigState.
**Example**
```typescript theme={"system"}
const configState = await cpAmm.fetchConfigState(configAddress);
console.log(configState);
```
**Notes**
* Throws an error if the config account does not exist
***
### fetchPoolState
Fetches the Pool state.
**Function**
```typescript theme={"system"}
async fetchPoolState(pool: PublicKey): Promise
```
**Parameters**
* `pool`: Public key of the pool.
**Returns**
Parsed PoolState.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
console.log(`Current Price: ${poolState.sqrtPrice.toString()}`);
console.log(`Liquidity: ${poolState.liquidity.toString()}`);
```
**Notes**
* Throws an error if the pool account does not exist
* Contains all essential information about the pool including prices, liquidity, and fees
***
### fetchPoolStatesByTokenAMint
Fetches all Pool states by tokenAMint.
**Function**
```typescript theme={"system"}
async fetchPoolStatesByTokenAMint(tokenAMint: PublicKey): Promise>
```
**Parameters**
* `tokenAMint`: Public key of the tokenA mint.
**Returns**
Array of matched pool accounts and their state.
**Example**
```typescript theme={"system"}
const poolStates = await cpAmm.fetchPoolStatesByTokenAMint(tokenAMint);
console.log(`Found ${poolStates.length} pools`);
poolStates.forEach((pool, i) => {
console.log(`Pool ${i}: ${pool.publicKey.toString()}`);
console.log(`- Pool State: ${JSON.stringify(pool.account)}`);
});
```
**Notes**
* Returns an empty array if no pools are found for the given tokenAMint
* Contains all essential information about the pool including pool address, prices, liquidity, and fees
***
### fetchPoolFees
Fetches and decodes the pool fee configuration for a given pool. Automatically determines the base fee mode and returns the decoded fee parameters.
**Function**
```typescript theme={"system"}
async fetchPoolFees(pool: PublicKey): Promise
```
**Parameters**
* `pool`: Public key of the pool.
**Returns**
Decoded pool fees (`PodAlignedFeeTimeScheduler`, `PodAlignedFeeRateLimiter`, or `PodAlignedFeeMarketCapScheduler`) depending on the base fee mode, or throws if the pool is not found.
**Example**
```typescript theme={"system"}
const decodedFees = await cpAmm.fetchPoolFees(poolAddress);
console.log(`Decoded fees: ${JSON.stringify(decodedFees)}`);
```
**Notes**
* Throws an error if the pool account does not exist
* Automatically determines the correct decoder based on `baseFeeMode`
***
### fetchPositionState
Fetches the Position state.
**Function**
```typescript theme={"system"}
async fetchPositionState(position: PublicKey): Promise
```
**Parameters**
* `position`: Public key of the position.
**Returns**
Parsed PositionState.
**Example**
```typescript theme={"system"}
const positionState = await cpAmm.fetchPositionState(positionAddress);
console.log(
`Unlocked Liquidity: ${positionState.unlockedLiquidity.toString()}`
);
console.log(`Vested Liquidity: ${positionState.vestedLiquidity.toString()}`);
console.log(
`Permanent Locked Liquidity: ${positionState.permanentLockedLiquidity.toString()}`
);
```
**Notes**
* Throws an error if the position account does not exist
* Contains information about liquidity amounts, fee collection, and rewards
***
### getMultipleConfigs
Fetches multiple Config states in a single RPC call.
**Function**
```typescript theme={"system"}
async getMultipleConfigs(configs: PublicKey[]): Promise
```
**Parameters**
* `configs`: Array of public keys of config accounts.
**Returns**
Array of parsed ConfigState.
**Example**
```typescript theme={"system"}
const configStates = await cpAmm.getMultipleConfigs([configAddress1, configAddress2]);
configStates.forEach((config, i) => {
console.log(`Config ${i}: activation type = ${config.activationType}`);
});
```
**Notes**
* Throws an error if any config account does not exist
* More efficient than calling `fetchConfigState` multiple times
***
### getMultiplePools
Fetches multiple Pool states in a single RPC call.
**Function**
```typescript theme={"system"}
async getMultiplePools(pools: PublicKey[]): Promise
```
**Parameters**
* `pools`: Array of public keys of pool accounts.
**Returns**
Array of parsed PoolState.
**Example**
```typescript theme={"system"}
const poolStates = await cpAmm.getMultiplePools([poolAddress1, poolAddress2]);
poolStates.forEach((pool, i) => {
console.log(`Pool ${i}: liquidity = ${pool.liquidity.toString()}`);
});
```
**Notes**
* Throws an error if any pool account does not exist
* More efficient than calling `fetchPoolState` multiple times
***
### getMultiplePositions
Fetches multiple Position states in a single RPC call.
**Function**
```typescript theme={"system"}
async getMultiplePositions(positions: PublicKey[]): Promise
```
**Parameters**
* `positions`: Array of public keys of position accounts.
**Returns**
Array of parsed PositionState.
**Example**
```typescript theme={"system"}
const positionStates = await cpAmm.getMultiplePositions([positionAddress1, positionAddress2]);
positionStates.forEach((pos, i) => {
console.log(`Position ${i}: unlocked liquidity = ${pos.unlockedLiquidity.toString()}`);
});
```
**Notes**
* Throws an error if any position account does not exist
* More efficient than calling `fetchPositionState` multiple times
***
### getAllConfigs
Retrieves all config accounts.
**Function**
```typescript theme={"system"}
async getAllConfigs(): Promise>
```
**Returns**
Array of config public keys and their states.
**Example**
```typescript theme={"system"}
const configs = await cpAmm.getAllConfigs();
console.log(`Found ${configs.length} configs`);
configs.forEach((config, i) => {
console.log(`Config ${i}: ${config.publicKey.toString()}`);
});
```
***
### getAllPools
Retrieves all pool accounts.
**Function**
```typescript theme={"system"}
async getAllPools(): Promise>
```
**Returns**
Array of pool public keys and their states.
**Example**
```typescript theme={"system"}
const pools = await cpAmm.getAllPools();
console.log(`Found ${pools.length} pools`);
pools.forEach((pool, i) => {
console.log(`Pool ${i}: ${pool.publicKey.toString()}`);
console.log(`- Token A: ${pool.account.tokenAMint.toString()}`);
console.log(`- Token B: ${pool.account.tokenBMint.toString()}`);
});
```
***
### getAllPositions
Retrieves all position accounts.
**Function**
```typescript theme={"system"}
async getAllPositions(): Promise>
```
**Returns**
Array of position public keys and their states.
**Example**
```typescript theme={"system"}
const positions = await cpAmm.getAllPositions();
console.log(`Found ${positions.length} positions`);
```
***
### getAllPositionsByPool
Gets all positions for a specific pool.
**Function**
```typescript theme={"system"}
async getAllPositionsByPool(pool: PublicKey): Promise>
```
**Parameters**
* `pool`: Public key of the pool.
**Returns**
List of positions for the pool.
**Example**
```typescript theme={"system"}
const poolPositions = await cpAmm.getAllPositionsByPool(poolAddress);
console.log(`Pool has ${poolPositions.length} positions`);
```
***
### getUserPositionByPool
Gets all positions of a user for a specific pool.
**Function**
```typescript theme={"system"}
async getUserPositionByPool(pool: PublicKey, user: PublicKey): Promise>
```
**Parameters**
* `pool`: Public key of the pool.
* `user`: Public key of the user.
**Returns**
List of user positions for the pool.
**Example**
```typescript theme={"system"}
const userPoolPositions = await cpAmm.getUserPositionByPool(
poolAddress,
wallet.publicKey
);
console.log(`User has ${userPoolPositions.length} positions in this pool`);
```
***
### getPositionsByUser
Gets all positions of a user across all pools.
**Function**
```typescript theme={"system"}
async getPositionsByUser(user: PublicKey): Promise>
```
**Parameters**
* `user`: Public key of the user.
**Returns**
Array of user positions already sorted by liquidity.
**Example**
```typescript theme={"system"}
const userPositions = await cpAmm.getPositionsByUser(wallet.publicKey);
console.log(`User has ${userPositions.length} total positions`);
```
**Notes**
* Positions are sorted by total liquidity in descending order
* Returns position NFT accounts, position addresses, and full position states
***
### getAllVestingsByPosition
Retrieves all vesting accounts associated with a position.
**Function**
```typescript theme={"system"}
async getAllVestingsByPosition(position: PublicKey): Promise>
```
**Parameters**
* `position`: Public key of the position.
**Returns**
Array of vesting account public keys and their states.
**Example**
```typescript theme={"system"}
const vestings = await cpAmm.getAllVestingsByPosition(positionAddress);
console.log(`Position has ${vestings.length} vesting accounts`);
```
***
### isLockedPosition
Checks if a position has any locked liquidity.
**Function**
```typescript theme={"system"}
isLockedPosition(position: PositionState): boolean
```
**Parameters**
* `position`: The position state.
**Returns**
Boolean indicating whether the position has locked liquidity.
**Example**
```typescript theme={"system"}
const positionState = await cpAmm.fetchPositionState(positionAddress);
if (cpAmm.isLockedPosition(positionState)) {
console.log("Position has locked liquidity");
} else {
console.log("Position has no locked liquidity");
}
```
***
### isPermanentLockedPosition
Checks if a position is permanently locked.
**Function**
```typescript theme={"system"}
isPermanentLockedPosition(positionState: PositionState): boolean
```
**Parameters**
* `positionState`: The position state.
**Returns**
Boolean indicating whether the position has permanent locked liquidity.
**Example**
```typescript theme={"system"}
const positionState = await cpAmm.fetchPositionState(positionAddress);
if (cpAmm.isPermanentLockedPosition(positionState)) {
console.log("Position is permanently locked");
} else {
console.log("Position is not permanently locked");
}
```
***
### canUnlockPosition
Checks if a position can be unlocked based on its locking state and vesting schedules. Useful to determine eligibility before calling `removeAllLiquidity` or `closePosition`.
**Function**
```typescript theme={"system"}
canUnlockPosition(
positionState: PositionState,
vestings: Array<{ account: PublicKey; vestingState: VestingState }>,
currentPoint: BN,
): { canUnlock: boolean; reason?: string }
```
**Parameters**
* `positionState`: The current state of the position.
* `vestings`: Array of vesting accounts and their states (from `getAllVestingsByPosition`).
* `currentPoint`: Current timestamp or slot number (depending on pool activation type).
**Returns**
An object containing:
* `canUnlock`: Whether the position can be unlocked.
* `reason` (optional): Reason why the position cannot be unlocked.
**Example**
```typescript theme={"system"}
const positionState = await cpAmm.fetchPositionState(positionAddress);
const vestings = await cpAmm.getAllVestingsByPosition(positionAddress);
const currentSlot = await connection.getSlot();
const { canUnlock, reason } = cpAmm.canUnlockPosition(
positionState,
vestings.map((v) => ({ account: v.publicKey, vestingState: v.account })),
new BN(currentSlot),
);
if (canUnlock) {
console.log("Position can be unlocked");
} else {
console.log(`Cannot unlock: ${reason}`);
}
```
**Notes**
* Returns `{ canUnlock: false, reason: "Position is permanently locked" }` if the position has permanent locked liquidity
* Returns `{ canUnlock: false, reason: "Position has incomplete vesting schedule" }` if any vesting schedule is still active
* Returns `{ canUnlock: true }` if no locks or all vesting schedules are complete
***
### isPoolExist
Checks if a pool exists.
**Function**
```typescript theme={"system"}
async isPoolExist(pool: PublicKey): Promise
```
**Parameters**
* `pool`: Public key of the pool.
**Returns**
Boolean indicating whether the pool exists.
**Example**
```typescript theme={"system"}
const exists = await cpAmm.isPoolExist(poolAddress);
if (exists) {
console.log("Pool exists");
} else {
console.log("Pool does not exist");
}
```
***
## Helper Functions
### preparePoolCreationParams
Prepares parameters required for pool creation, including initial sqrt price and liquidity.
**Function**
```typescript theme={"system"}
preparePoolCreationParams(params: PreparePoolCreationParams): PreparedPoolCreation
```
**Parameters**
```typescript theme={"system"}
interface PreparePoolCreationParams {
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
tokenAInfo?: any; // Token info for Token2022 transfer fee calculations
tokenBInfo?: any; // Token info for Token2022 transfer fee calculations
collectFeeMode: CollectFeeMode; // How fees are collected (BothToken, OnlyB, or Compounding)
}
```
**Returns**
An object containing:
* `initSqrtPrice`: The initial sqrt price in Q64 format
* `liquidityDelta`: The initial liquidity in Q64 format
**Example**
```typescript theme={"system"}
const { initSqrtPrice, liquidityDelta } = cpAmm.preparePoolCreationParams({
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,
collectFeeMode: CollectFeeMode.BothToken,
});
console.log(`Initial sqrt price: ${initSqrtPrice.toString()}`);
console.log(`Initial liquidity: ${liquidityDelta.toString()}`);
```
**Notes**
* This function calculates the correct initial price and liquidity based on the token amounts
* Both token amounts must be greater than zero
* The function handles Token2022 transfer fees if token info is provided
***
### preparePoolCreationSingleSide
Calculates liquidity delta for single-sided pool creation where only token A is provided. Only supports initialization where the initial price equals the minimum sqrt price.
**Function**
```typescript theme={"system"}
preparePoolCreationSingleSide(params: PreparePoolCreationSingleSide): BN
```
**Parameters**
```typescript theme={"system"}
interface PreparePoolCreationSingleSide {
tokenAAmount: BN; // Amount of token A to deposit
minSqrtPrice: BN; // Minimum sqrt price
maxSqrtPrice: BN; // Maximum sqrt price
initSqrtPrice: BN; // Initial sqrt price (must equal minSqrtPrice)
tokenAInfo?: {
mint: Mint;
currentEpoch: number;
}; // Token info for Token2022 transfer fee calculations
collectFeeMode: CollectFeeMode; // How fees are collected (BothToken, OnlyB, or Compounding)
}
```
**Returns**
A BN representing the liquidity delta.
**Example**
```typescript theme={"system"}
const initSqrtPrice = getSqrtPriceFromPrice("100", tokenADecimal, tokenBDecimal);
const liquidityDelta = cpAmm.preparePoolCreationSingleSide({
tokenAAmount: new BN(10_000_000_000),
minSqrtPrice: initSqrtPrice,
maxSqrtPrice: MAX_SQRT_PRICE,
initSqrtPrice,
collectFeeMode: CollectFeeMode.BothToken,
});
console.log(`Liquidity delta: ${liquidityDelta.toString()}`);
```
**Notes**
* Only supports single-sided deposits where `initSqrtPrice` equals `minSqrtPrice`
* Throws an error if `initSqrtPrice` does not equal `minSqrtPrice`
* Handles Token2022 transfer fees if token info is provided
***
### isVestingComplete
Checks if a vesting schedule is ready for full release.
**Function**
```typescript theme={"system"}
function isVestingComplete(
vestingData: VestingState,
currentPoint: BN
): boolean;
```
**Parameters**
* `vestingData`: The vesting account state data
* `currentPoint`: Current timestamp or slot number
**Returns**
Boolean indicating whether the vesting schedule is complete and all liquidity can be released.
**Example**
```typescript theme={"system"}
const vestings = await cpAmm.getAllVestingsByPosition(positionAddress);
if (vestings.length > 0) {
const isComplete = isVestingComplete(vestings[0].account, new BN(Date.now()));
if (isComplete) {
console.log("Vesting schedule is complete, all liquidity can be released");
} else {
console.log("Vesting schedule is still active");
}
}
```
**Notes**
* This function checks if the current point (timestamp or slot) has passed the end of the vesting schedule
* The end point is calculated as: cliffPoint + (periodFrequency \* numberOfPeriods)
* Returns true if currentPoint >= endPoint, false otherwise
* Useful to determine if a position can be fully unlocked
***
### getTotalLockedLiquidity
Gets the total amount of liquidity in the vesting schedule.
**Function**
```typescript theme={"system"}
function getTotalLockedLiquidity(vestingData: VestingState): BN;
```
**Parameters**
* `vestingData`: The vesting account state data
**Returns**
The total locked liquidity amount as a BN.
**Example**
```typescript theme={"system"}
const vestings = await cpAmm.getAllVestingsByPosition(positionAddress);
if (vestings.length > 0) {
const totalLocked = getTotalLockedLiquidity(vestings[0].account);
console.log(`Total locked liquidity: ${totalLocked.toString()}`);
}
```
**Notes**
* Calculates the sum of cliff unlock liquidity and periodic unlock liquidity
* Formula: cliffUnlockLiquidity + (liquidityPerPeriod \* numberOfPeriod)
* This is the total amount of liquidity that was initially locked in the vesting schedule
* Does not account for already released liquidity
***
### getAvailableVestingLiquidity
Calculates the available liquidity to withdraw based on vesting schedule.
**Function**
```typescript theme={"system"}
function getAvailableVestingLiquidity(
vestingData: VestingState,
currentPoint: BN
): BN;
```
**Parameters**
* `vestingData`: The vesting account state data
* `currentPoint`: Current timestamp or slot number
**Returns**
The amount of liquidity available to withdraw as a BN.
**Example**
```typescript theme={"system"}
const vestings = await cpAmm.getAllVestingsByPosition(positionAddress);
if (vestings.length > 0) {
const availableLiquidity = getAvailableVestingLiquidity(
vestings[0].account,
new BN(Date.now())
);
console.log(
`Available liquidity to withdraw: ${availableLiquidity.toString()}`
);
}
```
### getMaxAmountWithSlippage
Calculates the maximum amount after applying a slippage rate.
**Function**
```typescript theme={"system"}
function getMaxAmountWithSlippage(amount: BN, rate: number): BN;
```
**Parameters**
* `amount`: The base amount as a BN
* `rate`: The slippage rate as a percentage (e.g., 0.5 for 0.5%)
**Returns**
The maximum amount after applying slippage as a BN.
**Example**
```typescript theme={"system"}
const tokenAmount = new BN(1_000_000_000); // 1,000 tokens
const slippageRate = 0.5; // 0.5% slippage allowance
const maxAmount = getMaxAmountWithSlippage(tokenAmount, slippageRate);
console.log(`Maximum amount with slippage: ${maxAmount.toString()}`);
```
**Notes**
* Used when you need to calculate the upper bound of an amount with slippage tolerance
* Formula: amount \* (100 + rate) / 100
* Common use case: Setting a maximum deposit amount when adding liquidity
* Slippage rate is expressed as a percentage and supports up to 2 decimal places
***
### getAmountWithSlippage
Calculates the minimum amount after applying a slippage rate.
**Function**
```typescript theme={"system"}
function getAmountWithSlippage(
amount: BN,
slippageBps: number,
swapMode: SwapMode
): BN;
```
**Parameters**
* `amount`: The base amount as a BN
* `slippageBps`: The slippage rate in basis points (e.g., 100 bps for 1%)
* `swapMode`: The swap mode (ExactIn, PartialFill, ExactOut)
**Returns**
The minimum amount after applying slippage as a BN (for ExactIn/PartialFill) or maximum amount in (for ExactOut).
**Example**
```typescript theme={"system"}
const expectedOutput = new BN(1_000_000_000); // 1,000 tokens
const slippageBps = 50; // 0.5% slippage allowance
const amountWithSlippage = getAmountWithSlippage(
expectedOutput,
slippageBps,
SwapMode.ExactIn
);
console.log(`Amount with slippage: ${amountWithSlippage.toString()}`);
```
**Notes**
* Used when you need to calculate the lower bound of an amount with slippage tolerance
* Formula: amount \* (100 - slippageBps) / 100 (for ExactIn/PartialFill) or amount \* (100 + slippageBps) / 100 (for ExactOut)
* Common use case: Setting a minimum output amount when swapping tokens
* Slippage rate is expressed as a percentage and supports up to 2 decimal places
***
### getPriceImpact
Calculates the price impact as a percentage.
**Function**
```typescript theme={"system"}
function getPriceImpact(actualAmount: BN, idealAmount: BN): number;
```
**Parameters**
* `actualAmount`: The actual amount after slippage in token units
* `idealAmount`: The theoretical amount without slippage in token units
**Returns**
The price impact as a percentage (e.g., 1.5 means 1.5%).
**Example**
```typescript theme={"system"}
const idealAmount = new BN(1_000_000_000); // 1,000 tokens (theoretical)
const actualAmount = new BN(990_000_000); // 990 tokens (actual)
const impact = getPriceImpact(actualAmount, idealAmount);
console.log(`Price impact: ${impact.toFixed(2)}%`);
```
**Notes**
* Used to express how much a transaction will affect the price
* Formula: ((idealAmount - actualAmount) / idealAmount) \* 100
* Higher price impact indicates a greater effect on the market price
* Common use case: Showing users the effect of their swap on the pool
***
## Price Conversion Utilities
### getPriceFromSqrtPrice
Converts a sqrt price in Q64 format to a human-readable price.
**Function**
```typescript theme={"system"}
function getPriceFromSqrtPrice(
sqrtPrice: BN,
tokenADecimal: number,
tokenBDecimal: number
): string;
```
**Parameters**
* `sqrtPrice`: The sqrt price in Q64 format
* `tokenADecimal`: The number of decimals for token A
* `tokenBDecimal`: The number of decimals for token B
**Returns**
The price as a string in human-readable format.
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const price = getPriceFromSqrtPrice(
poolState.sqrtPrice,
6, // USDC has 6 decimals
9 // SOL has 9 decimals
);
console.log(`Current price: ${price} USDC per SOL`);
```
**Notes**
* Converts the internal sqrt price representation to a human-readable price
* Formula: (sqrtPrice >> 64)^2 \* 10^(tokenADecimal - tokenBDecimal)
* The result represents the price of token B in terms of token A
* Useful for displaying current pool prices to users
***
### getSqrtPriceFromPrice
Converts a human-readable price to a sqrt price in Q64 format.
**Function**
```typescript theme={"system"}
function getSqrtPriceFromPrice(
price: string,
tokenADecimal: number,
tokenBDecimal: number
): BN;
```
**Parameters**
* `price`: The price as a string in human-readable format
* `tokenADecimal`: The number of decimals for token A
* `tokenBDecimal`: The number of decimals for token B
**Returns**
The sqrt price as a BN in Q64 format.
**Example**
```typescript theme={"system"}
const price = "0.05"; // 0.05 USDC per SOL
const sqrtPrice = getSqrtPriceFromPrice(
price,
6, // USDC has 6 decimals
9 // SOL has 9 decimals
);
console.log(`Sqrt price in Q64 format: ${sqrtPrice.toString()}`);
```
**Notes**
* Converts a human-readable price to the internal sqrt price representation
* Formula: `sqrt(price / 10^(tokenADecimal - tokenBDecimal)) << 64`
* Useful when creating pools with a specific initial price
* Can be used to define price boundaries for concentrated liquidity positions
***
## Fee Calculation Utilities
### getUnClaimLpFee
Calculates unclaimed fees and rewards for a position.
**Function**
```typescript theme={"system"}
function getUnClaimLpFee(
poolState: PoolState,
positionState: PositionState
): {
feeTokenA: BN;
feeTokenB: BN;
rewards: BN[];
};
```
**Parameters**
* `poolState`: The current state of the pool
* `positionState`: The current state of the position
**Returns**
An object containing:
* `feeTokenA`: Unclaimed fees in token A
* `feeTokenB`: Unclaimed fees in token B
* `rewards`: Array of unclaimed reward amounts for each reward token
**Example**
```typescript theme={"system"}
const poolState = await cpAmm.fetchPoolState(poolAddress);
const positionState = await cpAmm.fetchPositionState(positionAddress);
const unclaimed = getUnClaimLpFee(poolState, positionState);
console.log(`Unclaimed token A fees: ${unclaimed.feeTokenA.toString()}`);
console.log(`Unclaimed token B fees: ${unclaimed.feeTokenB.toString()}`);
unclaimed.rewards.forEach((reward, i) => {
console.log(`Unclaimed reward ${i}: ${reward.toString()}`);
});
```
### getBaseFeeNumerator
Calculates the current base fee numerator based on the configured fee scheduler mode and elapsed periods.
**Function**
```typescript theme={"system"}
function getBaseFeeNumerator(
cliffFeeNumerator: BN,
numberOfPeriod: number,
periodFrequency: BN,
reductionFactor: BN,
baseFeeMode: BaseFeeMode,
currentPoint: BN,
activationPoint: BN
): BN;
```
**Parameters**
* `baseFeeMode`: The fee reduction mode (Fee Scheduler Linear or Exponential)
* `cliffFeeNumerator`: The initial maximum fee numerator (starting point)
* `period`: The number of elapsed periods since fee reduction began
* `reductionFactor`: The rate of fee reduction per period
**Mathematical Formula**
**Linear Mode:**
```
fee = cliffFeeNumerator - (period × reductionFactor)
```
**Exponential Mode:**
```
fee = cliffFeeNumerator × (1 - reductionFactor/BASIS_POINT_MAX)^period
```
**Returns**
* `BN`: The calculated base fee numerator for the current period
### getDynamicFeeNumerator
Calculates a dynamic fee component based on market volatility
**Function**
```typescript theme={"system"}
function getDynamicFeeNumerator(
volatilityAccumulator: BN,
binStep: BN,
variableFeeControl: BN
): BN;
```
**Parameters**
* `volatilityAccumulator`: Accumulated measure of market volatility over time
* `binStep`: The price bin step size used in the liquidity distribution system
* `variableFeeControl`: Control parameter that determines how much volatility affects fees
**Mathematical Formula**
```
squareVfaBin = (volatilityAccumulator × binStep)²
vFee = variableFeeControl × squareVfaBin
dynamicFee = (vFee + 99,999,999,999) ÷ 100,000,000,000
```
**Returns**
* `BN`: The calculated dynamic fee numerator
* Returns `0` if `variableFeeControl` is zero (dynamic fees disabled)
### bpsToFeeNumerator
Converts basis points to fee numerator format.
**Mathematical Formula**
```
feeNumerator = (bps × FEE_DENOMINATOR) ÷ BASIS_POINT_MAX
```
### feeNumeratorToBps
Converts fee numerator back to basis points.
**Mathematical Formula**
```
bps = (feeNumerator × BASIS_POINT_MAX) ÷ FEE_DENOMINATOR
```
### getBaseFeeParams
Get and prepares the base fee parameters of the pool.
**Function**
```typescript theme={"system"}
getBaseFeeParams(
baseFeeParams: {
baseFeeMode: BaseFeeMode;
rateLimiterParam?: {
baseFeeBps: number;
feeIncrementBps: number;
referenceAmount: number;
maxLimiterDuration: number;
maxFeeBps: number;
};
feeTimeSchedulerParam?: {
startingFeeBps: number;
endingFeeBps: number;
numberOfPeriod: number;
totalDuration: number;
};
feeMarketCapSchedulerParam?: {
startingFeeBps: number;
endingFeeBps: number;
numberOfPeriod: number;
sqrtPriceStepBps: number;
schedulerExpirationDuration: number;
};
},
tokenBDecimal: number,
activationType: ActivationType): BaseFee
```
**Parameters**
```typescript theme={"system"}
connection: Connection, // rpc connection
baseFeeParams: {
baseFeeMode: BaseFeeMode; // base fee mode
rateLimiterParam?: { // if you choose BaseFeeMode.RateLimiter mode
baseFeeBps: number; // base fee in basis points
feeIncrementBps: number; // fee increment in basis points
referenceAmount: number; // reference amount (in terms of quote token)
maxLimiterDuration: number; // max limiter duration in seconds
maxFeeBps: number; // max fee in basis points
};
feeTimeSchedulerParam?: { // if you choose BaseFeeMode.FeeTimeSchedulerLinear or BaseFeeMode.FeeTimeSchedulerExponential mode
startingFeeBps: number; // starting fee in basis points
endingFeeBps: number; // ending fee in basis points
numberOfPeriod: number; // number of periods
totalDuration: number; // total duration in seconds
};
feeMarketCapSchedulerParam?: { // if you choose BaseFeeMode.FeeMarketCapSchedulerLinear or BaseFeeMode.FeeMarketCapSchedulerExponential mode
startingFeeBps: number; // starting fee in basis points
endingFeeBps: number; // ending fee in basis points
numberOfPeriod: number; // number of periods
sqrtPriceStepBps: number; // sqrt price step in basis points
schedulerExpirationDuration: number; // scheduler expiration duration in seconds
};
},
tokenBDecimal: number, // token B decimal
activationType: ActivationType // activation type
```
**Returns**
The base fee parameters in encoded Borsh format. (data: number\[])
**Example**
```typescript theme={"system"}
const baseFee = getBaseFeeParams(
{
baseFeeMode: BaseFeeMode.FeeMarketCapSchedulerLinear,
feeMarketCapSchedulerParam: {
startingFeeBps: 5000,
endingFeeBps: 100,
numberOfPeriod: 180,
sqrtPriceStepBps: 200,
schedulerExpirationDuration: 2592000,
},
},
6,
ActivationType.Timestamp
);
```
**Notes**
* Returns the base fee parameters in encoded Borsh format. (data: number\[])
### getDynamicFeeParams
Calculates the parameters needed for dynamic fee. This function will always return dynamic fee parameters that are configured to be 20% of the feeBps that you input in.
**Key Features**
* Configures volatility-based fee parameters
* Sets maximum price change thresholds
* Calculates variable fee control parameters
***
## Fee Codec Functions
These functions are used to encode and decode base fee parameters. There are two serialization formats:
* **Borsh format (30 bytes)**: Used in `EvtInitializePool` events
* **PodAligned format (32 bytes)**: Used in `poolState` account data
### encodeFeeTimeSchedulerParams
Encodes Fee Time Scheduler parameters into Borsh format for pool creation.
**Function**
```typescript theme={"system"}
encodeFeeTimeSchedulerParams(
cliffFeeNumerator: BN,
numberOfPeriod: number,
periodFrequency: BN,
reductionFactor: BN,
baseFeeMode: BaseFeeMode
): Buffer
```
**Parameters**
* `cliffFeeNumerator`: Starting fee numerator (e.g., 500000000 = 50%)
* `numberOfPeriod`: Number of fee reduction periods
* `periodFrequency`: Time between periods (slots or seconds)
* `reductionFactor`: Fee reduction per period
* `baseFeeMode`: `BaseFeeMode.FeeTimeSchedulerLinear` (0) or `BaseFeeMode.FeeTimeSchedulerExponential` (1)
**Returns**
A `Buffer` containing the Borsh-encoded fee parameters.
**Example**
```typescript theme={"system"}
const encoded = encodeFeeTimeSchedulerParams(
new BN(500000000), // 50% starting fee
100, // 100 periods
new BN(6), // 6 seconds between periods
new BN(4900000), // reduction factor
BaseFeeMode.FeeTimeSchedulerLinear
);
```
***
### encodeFeeMarketCapSchedulerParams
Encodes Fee Market Cap Scheduler parameters into Borsh format for pool creation.
**Function**
```typescript theme={"system"}
encodeFeeMarketCapSchedulerParams(
cliffFeeNumerator: BN,
numberOfPeriod: number,
sqrtPriceStepBps: number,
schedulerExpirationDuration: number,
reductionFactor: BN,
baseFeeMode: BaseFeeMode
): Buffer
```
**Parameters**
* `cliffFeeNumerator`: Starting fee numerator (e.g., 500000000 = 50%)
* `numberOfPeriod`: Number of fee reduction periods
* `sqrtPriceStepBps`: Sqrt price step in basis points to advance one period
* `schedulerExpirationDuration`: Duration after which scheduler expires (slots or seconds)
* `reductionFactor`: Fee reduction per period
* `baseFeeMode`: `BaseFeeMode.FeeMarketCapSchedulerLinear` (3) or `BaseFeeMode.FeeMarketCapSchedulerExponential` (4)
**Returns**
A `Buffer` containing the Borsh-encoded fee parameters.
**Example**
```typescript theme={"system"}
const encoded = encodeFeeMarketCapSchedulerParams(
new BN(500000000), // 50% starting fee
100, // 100 periods
100, // 1% sqrt price step
86400, // 24 hours expiration
new BN(4950000), // reduction factor
BaseFeeMode.FeeMarketCapSchedulerLinear
);
```
***
### encodeFeeRateLimiterParams
Encodes Rate Limiter parameters into Borsh format for pool creation.
**Function**
```typescript theme={"system"}
encodeFeeRateLimiterParams(
cliffFeeNumerator: BN,
feeIncrementBps: number,
maxLimiterDuration: number,
maxFeeBps: number,
referenceAmount: BN
): Buffer
```
**Parameters**
* `cliffFeeNumerator`: Base fee numerator (e.g., 10000000 = 1%)
* `feeIncrementBps`: Fee increment in basis points per reference amount
* `maxLimiterDuration`: Maximum duration for rate limiter (slots or seconds)
* `maxFeeBps`: Maximum fee cap in basis points
* `referenceAmount`: Reference amount for fee calculation (in lamports)
**Returns**
A `Buffer` containing the Borsh-encoded fee parameters.
**Example**
```typescript theme={"system"}
const encoded = encodeFeeRateLimiterParams(
new BN(10000000), // 1% base fee
10, // 0.1% fee increment per reference amount
10, // 10 slots/seconds max duration
5000, // 50% max fee cap
new BN(1000000000) // 1 SOL reference amount
);
```
***
### decodeFeeTimeSchedulerParams
Decodes Borsh-encoded Fee Time Scheduler parameters (from `EvtInitializePool` events).
**Function**
```typescript theme={"system"}
decodeFeeTimeSchedulerParams(data: Buffer): BorshFeeTimeScheduler
```
**Parameters**
* `data`: A `Buffer` containing Borsh-encoded fee data (30 bytes)
**Returns**
```typescript theme={"system"}
interface BorshFeeTimeScheduler {
cliffFeeNumerator: BN;
numberOfPeriod: number;
periodFrequency: BN;
reductionFactor: BN;
baseFeeMode: number;
padding: number[];
}
```
**Example**
```typescript theme={"system"}
// Decode from EvtInitializePool event
const decoded = decodeFeeTimeSchedulerParams(eventData.baseFee.data);
console.log(`Starting Fee: ${decoded.cliffFeeNumerator.toString()}`);
console.log(`Number of Periods: ${decoded.numberOfPeriod}`);
```
***
### decodeFeeMarketCapSchedulerParams
Decodes Borsh-encoded Fee Market Cap Scheduler parameters (from `EvtInitializePool` events).
**Function**
```typescript theme={"system"}
decodeFeeMarketCapSchedulerParams(data: Buffer): BorshFeeMarketCapScheduler
```
**Parameters**
* `data`: A `Buffer` containing Borsh-encoded fee data (30 bytes)
**Returns**
```typescript theme={"system"}
interface BorshFeeMarketCapScheduler {
cliffFeeNumerator: BN;
numberOfPeriod: number;
sqrtPriceStepBps: number;
schedulerExpirationDuration: number;
reductionFactor: BN;
baseFeeMode: number;
padding: number[];
}
```
**Example**
```typescript theme={"system"}
// Decode from EvtInitializePool event
const decoded = decodeFeeMarketCapSchedulerParams(eventData.baseFee.data);
console.log(`Starting Fee: ${decoded.cliffFeeNumerator.toString()}`);
console.log(`Sqrt Price Step: ${decoded.sqrtPriceStepBps} bps`);
```
***
### decodeFeeRateLimiterParams
Decodes Borsh-encoded Rate Limiter parameters (from `EvtInitializePool` events).
**Function**
```typescript theme={"system"}
decodeFeeRateLimiterParams(data: Buffer): BorshFeeRateLimiter
```
**Parameters**
* `data`: A `Buffer` containing Borsh-encoded fee data (30 bytes)
**Returns**
```typescript theme={"system"}
interface BorshFeeRateLimiter {
cliffFeeNumerator: BN;
feeIncrementBps: number;
maxLimiterDuration: number;
maxFeeBps: number;
referenceAmount: BN;
baseFeeMode: number;
padding: number[];
}
```
**Example**
```typescript theme={"system"}
// Decode from EvtInitializePool event
const decoded = decodeFeeRateLimiterParams(eventData.baseFee.data);
console.log(`Base Fee: ${decoded.cliffFeeNumerator.toString()}`);
console.log(`Max Fee: ${decoded.maxFeeBps} bps`);
```
***
### decodePodAlignedFeeTimeScheduler
Decodes PodAligned Fee Time Scheduler parameters (from `poolState` account data).
**Function**
```typescript theme={"system"}
decodePodAlignedFeeTimeScheduler(data: Buffer): PodAlignedFeeTimeScheduler
```
**Parameters**
* `data`: A `Buffer` containing PodAligned fee data (32 bytes)
**Returns**
```typescript theme={"system"}
interface PodAlignedFeeTimeScheduler {
cliffFeeNumerator: BN;
numberOfPeriod: number;
periodFrequency: BN;
reductionFactor: BN;
baseFeeMode: number;
padding: number[];
}
```
**Example**
```typescript theme={"system"}
// Decode from poolState account
const poolState = await program.account.pool.fetch(poolAddress);
const decoded = decodePodAlignedFeeTimeScheduler(
Buffer.from(poolState.poolFees.baseFee.data)
);
console.log(`Current Fee Config: ${decoded.cliffFeeNumerator.toString()}`);
```
***
### decodePodAlignedFeeMarketCapScheduler
Decodes PodAligned Fee Market Cap Scheduler parameters (from `poolState` account data).
**Function**
```typescript theme={"system"}
decodePodAlignedFeeMarketCapScheduler(data: Buffer): PodAlignedFeeMarketCapScheduler
```
**Parameters**
* `data`: A `Buffer` containing PodAligned fee data (32 bytes)
**Returns**
```typescript theme={"system"}
interface PodAlignedFeeMarketCapScheduler {
cliffFeeNumerator: BN;
numberOfPeriod: number;
sqrtPriceStepBps: number;
schedulerExpirationDuration: number;
reductionFactor: BN;
baseFeeMode: number;
padding: number[];
}
```
**Example**
```typescript theme={"system"}
// Decode from poolState account
const poolState = await program.account.pool.fetch(poolAddress);
const decoded = decodePodAlignedFeeMarketCapScheduler(
Buffer.from(poolState.poolFees.baseFee.data)
);
console.log(`Expiration Duration: ${decoded.schedulerExpirationDuration}`);
```
***
### decodePodAlignedFeeRateLimiter
Decodes PodAligned Rate Limiter parameters (from `poolState` account data).
**Function**
```typescript theme={"system"}
decodePodAlignedFeeRateLimiter(data: Buffer): PodAlignedFeeRateLimiter
```
**Parameters**
* `data`: A `Buffer` containing PodAligned fee data (32 bytes)
**Returns**
```typescript theme={"system"}
interface PodAlignedFeeRateLimiter {
cliffFeeNumerator: BN;
feeIncrementBps: number;
maxLimiterDuration: number;
maxFeeBps: number;
referenceAmount: BN;
baseFeeMode: number;
padding: number[];
}
```
**Example**
```typescript theme={"system"}
// Decode from poolState account
const poolState = await program.account.pool.fetch(poolAddress);
const decoded = decodePodAlignedFeeRateLimiter(
Buffer.from(poolState.poolFees.baseFee.data)
);
console.log(`Reference Amount: ${decoded.referenceAmount.toString()}`);
```
***
## Decoding BaseFee Summary
When decoding `baseFee.data`, choose the decoder based on **data source** and **`baseFeeMode`**:
| Data Source | Format | Size | baseFeeMode 0-1 | baseFeeMode 2 | baseFeeMode 3-4 |
| ------------------------- | ---------- | -------- | ---------------------------------- | -------------------------------- | --------------------------------------- |
| `EvtInitializePool` event | Borsh | 30 bytes | `decodeFeeTimeSchedulerParams` | `decodeFeeRateLimiterParams` | `decodeFeeMarketCapSchedulerParams` |
| `poolState` account | PodAligned | 32 bytes | `decodePodAlignedFeeTimeScheduler` | `decodePodAlignedFeeRateLimiter` | `decodePodAlignedFeeMarketCapScheduler` |
# Bonding Curve Configs
Source: https://docs.meteora.ag/developer-guide/guides/dbc/bonding-curve-configs
Every DBC pool must be created using a config key that defines the pool's parameters. Each DBC pool is a PDA of `baseMint` + `quoteMint` + `config`.
Configs are basically where you configure the pre-graduation pool fees, post-graduation pool fees, the collect fee mode, the dynamic fee, the bonding curve shape, token vesting and more.
This guide will cover what each field in the configuration means and how you can configure your ideal bonding curve settings.
# Context
* **Partner** -> Launchpad (identified via the `feeClaimer` field in the DBC curve config)
* **Creator** -> Token Pool Creator (identified via the `creator` field in the DBC pool state)
# Example of a DBC Curve Config
A typical DBC curve config will look like this when you parse it into the `create_config` instruction on the DBC program:
```json theme={"system"}
{
poolFees: {
baseFee: {
cliffFeeNumerator: new BN(10000000),
firstFactor: 0,
secondFactor: new BN(0),
thirdFactor: new BN(0),
baseFeeMode: 0
},
dynamicFee: {
binStep: 1,
binStepU128: new BN(1844674407370955),
filterPeriod: 10,
decayPeriod: 120,
reductionFactor: 5000,
maxVolatilityAccumulator: 14460000,
variableFeeControl: 956
}
},
activationType: 1,
collectFeeMode: 0,
migrationOption: 1,
tokenType: 1,
tokenDecimal: 6,
migrationQuoteThreshold: new BN(85000000000),
partnerLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
partnerPermanentLockedLiquidityPercentage: 50,
creatorPermanentLockedLiquidityPercentage: 50,
sqrtStartPrice: new BN(95072344172433750),
lockedVesting: {
amountPerPeriod: new BN(0),
cliffDurationFromMigrationTime: new BN(0),
frequency: new BN(0),
numberOfPeriod: new BN(0),
cliffUnlockAmount: new BN(0)
},
migrationFeeOption: 2,
tokenSupply: {
preMigrationTokenSupply: new BN(1000000000000000),
postMigrationTokenSupply: new BN(1000000000000000)
},
creatorTradingFeePercentage: 0,
tokenUpdateAuthority: 1,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
migratedPoolFee: { collectFeeMode: 0, dynamicFee: 0, poolFeeBps: 0, compoundingFeeBps: 0 },
poolCreationFee: new BN(0),
enableFirstSwapWithMinFee: false,
partnerLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
cliffDurationFromMigrationTime: 0,
frequency: 0
},
creatorLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
cliffDurationFromMigrationTime: 0,
frequency: 0
},
migratedPoolBaseFeeMode: 0,
padding: [],
curve: [
{
sqrtPrice: new BN(380289371323205464),
liquidity: new BN(101410499496546307411360885487802)
},
{
sqrtPrice: new BN(79226673521066979257578248091),
liquidity:new BN(3434578513360188981331421)
}
]
}
```
# Curve Config Parameters
There are 3 ways you can go about to create your DBC curve config key onchain. You can either:
1. Head to [launch.meteora.ag](https://launch.meteora.ag) and use the UI to create your DBC curve config key.
2. Use the build curve functions in the [DBC Typescript SDK](/developer-guide/guides/dbc/typescript-sdk/getting-started) to create your DBC curve config key. These build curve functions abstracts the math complexity of the bonding curve while still allowing you to have full control over the curve structure.
3. Doing the math and creating the curve config key manually and parsing it into the `create_config` instruction.
## Tokenomics Configuration
### `tokenType`
* 0: SPL Token
* 1: Token2022 Token
Currently DBC does not support any Token2022 extensions.
### `tokenDecimal`
* The number of token decimals of the `baseMint` token.
### `tokenSupply`
* The total token supply of the token can be set as `fixed` or `dynamic`
* If the token supply is set to `fixed`, you need to set the `preMigrationTokenSupply` and `postMigrationTokenSupply` fields.
```
tokenSupply: {
preMigrationTokenSupply: new BN(1000000000000000),
postMigrationTokenSupply: new BN(1000000000000000)
}
```
* If the token supply is set to `dynamic`, you can set `tokenSupply` as null.
```
{
"tokenSupply": null
}
```
### `tokenUpdateAuthority`
* The token authority of the `baseMint` token that can be configured based on the launchpad's preference.
* The token authority can be set to:
* 0: `CreatorUpdateAuthority` would give the `creator` the authority to update the token metadata.
* 1: `Immutable` would make the token metadata immutable and mint authority to be revoked.
* 2: `PartnerUpdateAuthority` would give the `partner` the authority to update the token metadata.
* 3: `CreatorUpdateAndMintAuthority` would give the `creator` the authority to update the token metadata and mint authority.
* 4: `PartnerUpdateAndMintAuthority` would give the `partner` the authority to update the token metadata and mint authority.
### `lockedVesting`
* The vesting of `baseMint` tokens that can be configured based on the launchpad's preference.
* This `lockedVesting` only starts after the pool has migrated.
* The tokens are locked in a `lockEscrow` powered by [Jupiter Lock](https://dev.jup.ag/docs/lock) program.
* The `lockedVesting` is a struct that contains the following fields:
* `amountPerPeriod` - The amount of tokens that will be unlocked per period (in lamports).
* `cliffDurationFromMigrationTime` - The duration of the cliff period from the migration time.
* `frequency` - The frequency of the vesting (in seconds).
* `numberOfPeriod` - The number of periods of the vesting.
* `cliffUnlockAmount` - The amount of tokens that will be unlocked at the cliff period (in lamports).
## Pre-Graduation DBC Configuration
### `sqrtStartPrice`
* The starting price of the token in the bonding curve pool in the sqrt price format.
* You can calculate the `sqrtPrice` from the `price` by using the following formula:
* `price = (sqrtPrice >> 64)^2 * 10^(tokenADecimal - tokenBDecimal)`
### `poolFees`
The pool fees **only** apply to the pre-graduation DBC pool.
* The pool fees comprises of the `baseFee` and `dynamicFee`
**Minimum base fee is 25 bps (0.25%).** Configs with a base fee lower than 25 bps will be rejected by the program.
#### `baseFee`
* The base fee is a struct the contains the following fields:
* `cliffFeeNumerator` - The initial numerator of the pool fee.
* `firstFactor` - Depending on the `baseFeeMode`, this field will be either `numberOfPeriod` or `feeIncrementBps`.
* If the `baseFeeMode` is set to 0 or 1 (Fee Scheduler), this field will be `numberOfPeriod`.
* If the `baseFeeMode` is set to 2 (Rate Limiter), this field will be `feeIncrementBps`.
* `secondFactor` - Depending on the `baseFeeMode`, this field will be either `periodFrequency` or `maxLimiterDuration`.
* If the `baseFeeMode` is set to 0 or 1 (Fee Scheduler), this field will be `periodFrequency`.
* If the `baseFeeMode` is set to 2 (Rate Limiter), this field will be `maxLimiterDuration`.
* `thirdFactor` - Depending on the `baseFeeMode`, this field will be either `reductionFactor` or `referenceAmount`.
* If the `baseFeeMode` is set to 0 or 1 (Fee Scheduler), this field will be `reductionFactor`.
* If the `baseFeeMode` is set to 2 (Rate Limiter), this field will be `referenceAmount`.
* `baseFeeMode` - The mode of the base fee.
* 0: Linear Fee Scheduler
* 1: Exponential Fee Scheduler
* 2: Rate Limiter
#### `dynamicFee`
* The dynamic fee is an optional struct that contains the following fields:
* `binStep` - u16 value representing the bin step in bps
* `binStepU128` - u128 value for a more accurate bin step
* `filterPeriod` - Minimum time that must pass between fee updates
* `decayPeriod` - Period after the volatility starts decaying (must be > filterPeriod)
* `reductionFactor` - Controls how quickly volatility decys over time
* `maxVolatilityAccumulator` - Multiplier that determines how much volatility affects fees
* `variableFeeControl` - Caps the maximum volatility that can be accumulated
Example:
```
dynamicFee: {
binStep: 1,
binStepU128: new BN(1844674407370955),
filterPeriod: 10,
decayPeriod: 120,
reductionFactor: 5000,
maxVolatilityAccumulator: 14460000,
variableFeeControl: 956
}
```
* The dynamic fee can be set to `null` if you don't want to enable the dynamic fee.
Example:
```
dynamicFee: null
```
### `creatorTradingFeePercentage`
* By default, if the `creatorTradingFeePercentage` === 0, the creator will not receive any trading fees from the pre-graduation DBC pool, and all the fees will go to the `feeClaimer` which belongs to the `partner` launchpad.
* The `creatorTradingFeePercentage` is a u16 value representing the trading fee in percentage.
### `activationType`
* The `activationType` is a u8 value representing the activation type of the DBC pool.
* 0: `Slot` -> Calculated in terms of slots (0.4 seconds = 400ms).
* 1: `Timestamp` -> Calculated in terms of seconds. (1 second = 1000ms)
### `collectFeeMode`
* The `collectFeeMode` is a u8 value representing the collect fee mode of the DBC pool.
* 0: `Quote Token` -> The trading fees collected in the pre-graduation DBC pool is collected in the quote token.
* 1: `Output Token` -> The trading fees collected in the pre-graduation DBC pool is collected in the output token.
### `enableFirstSwapWithMinFee`
* When set to `true`, allows the pool creator to perform their first swap (buy) without anti-sniper fees.
* This is particularly useful when creating a pool and making an initial purchase in a single transaction.
* The first swap instruction in a transaction that includes pool creation will use the minimum base fee instead of the elevated anti-sniper fee.
* Subsequent swaps will be subject to the normal fee scheduler or rate limiter.
This feature should be used carefully as it creates an exception to the anti-sniper protection. It is designed for legitimate pool creators who want to acquire tokens at launch without paying elevated anti-sniper fees.
When `enableFirstSwapWithMinFee` is enabled, the `swap` and `swap2` instructions require the `SYSVAR_INSTRUCTIONS_PUBKEY` to be included in the remaining accounts to verify the transaction context.
Example:
```typescript theme={"system"}
// Enable first swap with minimum fee for pool creators
enableFirstSwapWithMinFee: true
```
### `migrationQuoteThreshold`
* The `migrationQuoteThreshold` is a u128 value representing the amount of quote token that will be needed to be collected in the pre-graduation DBC pool to qualify for the pool to be ready for migration.
* In order for the token to graduate from pre-graduation to post-graduation, the `poolState.quoteReserve` must be greater than or equal to the `poolConfig.migrationQuoteThreshold`.
* If you want your pool to automatically migrate when the `poolState.quoteReserve` is greater than or equal to the `poolConfig.migrationQuoteThreshold`, you would need to set the `migrationQuoteThreshold` to have a minimum value of 750 USD. You can read more about our migration keepers [here](/developer-guide/guides/dbc/overview#migration-keeper)
### `migrationFee`
The maximum `feePercentage` for migration fees is **99%**.
* The `migrationFee` is the amount of quote token that you want to collect as fee when the token pool migrates from pre-graduation to post-graduation.
* This `migrationFee` will be collected from the `migrationQuoteThreshold` amount of quote token.
* The `migrationFee` is a struct that contains the following fields:
* `feePercentage` - The fee percentage of the migration fee. The value must be between 0% and 50%.
* `creatorFeePercentage` - The fee percentage of the creator fee. The value must be between 0% and 100%.
* For example, if you want to collect 10% fee of the `migrationQuoteThreshold` amount of quote token, you would need to set the `migrationFee` to:
```
migrationFee: {
feePercentage: 10,
creatorFeePercentage: 0
}
```
* Additionally, if you want to fee split 50% of this 10% fee between the `partner` and `creator`, you can set the `creatorFeePercentage` to 50.
```
migrationFee: {
feePercentage: 10,
creatorFeePercentage: 50
}
```
* So essentially, if your `migrationQuoteThreshold` is 100 SOL, a 10% migrationFee would mean that 90 SOL will be migrated to the post-graduation pool's LP, and the remaining 10 SOL will be collected as fee.
### `curve`
* The `curve` is an array of objects that contains the following fields:
* `sqrtPrice` - The sqrt price of the curve segment.
* `liquidity` - The liquidity of the curve segment.
* When configuring the curve segments, you would need to adhere to the [math formulas of the bonding curve](/overview/products/dbc/bonding-curve-formulas) to ensure that the curve is valid.
## Post-Graduation DAMM Pool Configuration
### `migrationOption`
* The `migrationOption` is a u8 value representing the type of the post-graduation pool after the bonding curve has completed.
* 0: `DAMM v1` -> The pool will be migrated to a DAMM v1 pool.
* 1: `DAMM v2` -> The pool will be migrated to a DAMM v2 pool.
### `migrationFeeOption`
* The `migrationFeeOption` are fee configs that have been pre-defined for the DBC Pool Authority to use.
* You can find the list of the pre-defined fee configs [here](/developer-guide/guides/dbc/overview#damm-fee-config-keys).
**For DAMM v1**, the `collectFeeMode` of the post-graduation pool is set to `Output Token`.**For DAMM v2**, the `collectFeeMode` of the post-graduation pool is set to `Quote Token`. Additionally, because dynamic fee is enabled in the DAMM v2 fee config, there will be an additional 20% of the chosen base fee added to the total fee.
* The `migrationFeeOption` is a u8 value representing the pool fee of the post-graduation pool.
* 0: `FixedBps25` -> The pool fee of the post-graduation pool will be 25 bps.
* 1: `FixedBps30` -> The pool fee of the post-graduation pool will be 30 bps.
* 2: `FixedBps100` -> The pool fee of the post-graduation pool will be 100 bps.
* 3: `FixedBps200` -> The pool fee of the post-graduation pool will be 200 bps.
* 4: `FixedBps400` -> The pool fee of the post-graduation pool will be 400 bps.
* 5: `FixedBps600` -> The pool fee of the post-graduation pool will be 600 bps.
* 6: `Customizable` -> Only if your `migrationOption` is set to `DAMM v2`. You can set the pool fees of the post-graduation pool in the `migratedPoolFee` struct.
When using the SDK's `buildCurve*` functions with `marketCapFeeSchedulerParams` configured in `migratedPoolFee`, the SDK automatically overrides `migrationFeeOption` to `Customizable` (6) regardless of what you set. This is required by the on-chain program.
### `migratedPoolFee`
* The `migratedPoolFee` is only available if your `migrationOption` is set to `DAMM v2` and `migrationFeeOption` is set to `Customizable` \[6].
* The `migratedPoolFee` is a struct that contains the following fields:
* `collectFeeMode` - The collect fee mode of the post-graduation pool.
* `dynamicFee` - The dynamic fee of the post-graduation pool.
* `poolFeeBps` - The pool fee of the post-graduation pool.
* `compoundingFeeBps` - The compounding fee rate in basis points. Must be non-zero when `collectFeeMode` is `2` (Compounding), and must be `0` for all other modes.
When `marketCapFeeSchedulerParams` is configured, `poolFeeBps` must be greater than 0 as it serves as the starting (cliff) fee for the market cap fee scheduler.
#### `migratedPoolFee.collectFeeMode` options
Controls how trading fees are collected in the graduated DAMM v2 pool:
* `0` (`QuoteToken`) — Fees are collected in the quote token only. Maps to DAMM v2's `OnlyB` mode.
* `1` (`OutputToken`) — Fees are collected in the output token of each swap (both tokens). Maps to DAMM v2's `BothToken` mode.
* `2` (`Compounding`) — Fees are automatically reinvested into the LP position. Requires `compoundingFeeBps` to be non-zero.
Example — Compounding fee mode:
```typescript theme={"system"}
migratedPoolFee: {
collectFeeMode: 2, // Compounding
dynamicFee: 0,
poolFeeBps: 100, // 1% base fee
compoundingFeeBps: 50 // 0.5% compounded back into LP
}
```
When `collectFeeMode` is set to `2` (Compounding), `compoundingFeeBps` must be greater than `0`. When using any other mode, `compoundingFeeBps` must be `0`.
### `liquidityPercentage`
* There are 4 types of Liquidity Percentage parameters that you can configure.
* These 4 Liquidity Percentage parameters must add up to 100%.
* `partnerLiquidityPercentage` - The percentage of the LP that will be allocated to the partner in the graduated pool (0-100)
* `creatorLiquidityPercentage` - The percentage of the LP that will be allocated to the creator in the graduated pool (0-100)
* `partnerPermanentLockedLiquidityPercentage` - The percentage of the permanently locked LP that will be allocated to the partner in the graduated pool (0-100)
* `creatorPermanentLockedLiquidityPercentage` - The percentage of the permanently locked LP that will be allocated to the creator in the graduated pool (0-100)
**Minimum 10% Locked Liquidity Requirement (Day 1 Post-Migration)**
Configs require that at least 10% of liquidity remains locked at day 1 (86400 seconds) after migration. How this is achieved depends on your migration option:
**For DAMM v1 Migration:**
* Must use **permanent locked liquidity only**: `partnerPermanentLockedLiquidityPercentage` + `creatorPermanentLockedLiquidityPercentage` >= 10
* LP vesting is **NOT available** for DAMM v1
**For DAMM v2 Migration:**
* **Option A - Permanent locked liquidity only**: `partnerPermanentLockedLiquidityPercentage` + `creatorPermanentLockedLiquidityPercentage` >= 10
* **Option B - LP vesting only**: If using LP vesting (`partnerLiquidityVestingInfo` or `creatorLiquidityVestingInfo`) without permanent locks, the vested liquidity locked at day 1 must be >= 10%
* **Option C - Combination of permanent + vesting liquidity**: If using both permanent locked liquidity and LP vesting, the combined locked liquidity at day 1 must be >= 10%
The SDK validates this using `MIN_LOCKED_LIQUIDITY_BPS = 1000` (10%).
Example:
```
// All the LP are locked forever in the post-graduation pool
liquidityPercentage: {
partnerLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
partnerPermanentLockedLiquidityPercentage: 50,
creatorPermanentLockedLiquidityPercentage: 50
}
```
#### LP Vesting (DAMM v2 only)
In addition to the 4 liquidity percentage parameters, you can optionally configure LP vesting for DAMM v2 migrations:
* `partnerLiquidityVestingInfoParams` - Optional vesting configuration for the partner's LP position
* `creatorLiquidityVestingInfoParams` - Optional vesting configuration for the creator's LP position
These parameters are only applicable when `migrationOption` is set to `DAMM v2`. Each vesting info uses the `LiquidityVestingInfoParameters` struct with the following fields:
* `vestingPercentage` - The percentage of non-permanently-locked LP to vest (0-100)
* `bpsPerPeriod` - Basis points released per vesting period (e.g., 100 = 1% per period)
* `numberOfPeriods` - Number of vesting periods
* `cliffDurationFromMigrationTime` - The cliff duration in seconds from migration time before vesting starts
* `totalDuration` - The total vesting duration in seconds
LP vesting durations are **always in seconds** regardless of the pool's `activationType` setting (Slot or Timestamp).When LP vesting is configured, the `migrateToDammV2` endpoint will require vesting accounts for the positions.
**Vesting Contribution to Locked Liquidity**
LP vesting contributes to the minimum 10% locked liquidity requirement. The SDK calculates how much liquidity remains locked at day 1 (86400 seconds) post-migration based on your vesting schedule.
Use the helper function `getLiquidityVestingInfoParams()` to construct valid vesting parameters and `getVestingLockedLiquidityBpsAtNSeconds()` to calculate locked BPS at a specific time.
Example:
```typescript theme={"system"}
// Configure vesting for 50% of partner's non-locked LP
// 7-day cliff, 30-day total vesting
partnerLiquidityVestingInfoParams: {
vestingPercentage: 50, // 50% of LP will vest
bpsPerPeriod: 100, // 1% released per period
numberOfPeriods: 100, // 100 vesting periods
cliffDurationFromMigrationTime: 7 * 24 * 60 * 60, // 7 days cliff (604800 seconds)
totalDuration: 30 * 24 * 60 * 60, // 30 days total vesting (2592000 seconds)
}
```
**SDK Helper Function:**
```typescript theme={"system"}
import { getLiquidityVestingInfoParams } from "@meteora-ag/dynamic-bonding-curve-sdk";
// Use the helper to build valid vesting params
// Parameters: vestingPercentage, bpsPerPeriod, numberOfPeriods, cliffDurationFromMigrationTime, totalDuration
const vestingParams = getLiquidityVestingInfoParams(
50, // vestingPercentage: 50% of LP will vest
100, // bpsPerPeriod: 1% released per period
100, // numberOfPeriods: 100 vesting periods
7 * 24 * 60 * 60, // cliffDurationFromMigrationTime: 7 days cliff
30 * 24 * 60 * 60 // totalDuration: 30 days total vesting
);
// Returns LiquidityVestingInfoParameters:
// {
// vestingPercentage: 50,
// bpsPerPeriod: 100,
// numberOfPeriods: 100,
// cliffDurationFromMigrationTime: 604800,
// totalDuration: 2592000
// }
```
### `poolCreationFee`
* Partners can configure a `poolCreationFee` in SOL lamports when creating a config.
* When token creators create a pool using this config (through `initializeVirtualPoolWithSplToken` or `initializeVirtualPoolWithToken2022`), they will need to pay this fee in SOL.
* Partners can later claim this fee using the `claimPartnerPoolCreationFee` function.
* Meteora (protocol) receives 10% of the collected pool creation fees.
Example:
```typescript theme={"system"}
// Set pool creation fee to 0.1 SOL
poolCreationFee: new BN(100000000) // 0.1 SOL in lamports
```
### `migratedPoolBaseFeeMode`
* The `migratedPoolBaseFeeMode` configures the base fee mode for the **post-graduation DAMM v2 pool**.
* This is only applicable when `migrationOption` is set to `DAMM v2` (1).
* The available modes are:
* 0: `FeeTimeSchedulerLinear` -> Fee decreases linearly over time after migration.
* 1: `FeeTimeSchedulerExponential` -> Fee decreases exponentially over time after migration.
* 2: `RateLimiter` -> **Not supported** for DAMM v2 migration. Will throw an error if used.
* 3: `FeeMarketCapSchedulerLinear` -> Fee decreases linearly based on sqrt price increase (market cap growth) after migration.
* 4: `FeeMarketCapSchedulerExponential` -> Fee decreases exponentially based on sqrt price increase (market cap growth) after migration.
* Defaults to `FeeTimeSchedulerLinear` (0) if not specified.
Modes 3 and 4 (Fee Market Cap Scheduler) require `migratedPoolMarketCapFeeSchedulerParams` to be configured. See the [Fee Market Cap Scheduler](/anti-sniper-suite/fee-market-cap-scheduler/what-is-fee-market-cap-scheduler) documentation for more details.
### `migratedPoolMarketCapFeeSchedulerParams`
* This parameter is only required when `migratedPoolBaseFeeMode` is set to `FeeMarketCapSchedulerLinear` (3) or `FeeMarketCapSchedulerExponential` (4) and `migrationOption` is set to `DAMM v2` (1).
* The `migratedPoolMarketCapFeeSchedulerParams` is a struct that contains the following fields:
* `numberOfPeriod` - The total number of fee reduction periods.
* `sqrtPriceStepBps` - The sqrt price increase (in basis points) required to advance one fee reduction period.
* `schedulerExpirationDuration` - The maximum duration (in seconds) after which the scheduler expires and the fee permanently defaults to the minimum fee.
* `reductionFactor` - The amount to reduce the fee by per period.
When using `migratedPoolMarketCapFeeSchedulerParams`, all fields (`numberOfPeriod`, `sqrtPriceStepBps`, `schedulerExpirationDuration`) must be greater than zero.
### Protocol Migration Fee
There is a fixed **0.2% (20 bps) protocol migration fee** that is applied during the migration process from the DBC bonding curve to the post-graduation DAMM pool. This fee is deducted from the quote reserve during migration and is separate from any `migrationFee` configured by the partner.
# Creating the Curve Config
When creating the DBC Curve Config, you need to call the `create_config` instruction on the DBC program with the following parameters:
1. `config` - The DBC curve config account public key. This will be the address that stores the curve config settings.
2. `quoteMint` - The quote mint public key that will be paired with the base mint. All pools created with this DBC curve config address will be paired with this quote mint.
3. `feeClaimer` - The fee claimer public key is a wallet signer address that will belong to the launchpad to claim the partner fees.
4. `leftoverReceiver` - The leftover receiver public key is a wallet that will receive the leftover tokens in the bonding curve after the pool has migrated.
5. `payer` - The payer public key is a wallet signer that will pay for the creation of the DBC curve config account.
# Build Curve Helper functions
Creating a curve config key is a highly complex process that involves understanding how the math of the bonding curve works. To make this process easier, we have created a set of helper functions in the [DBC Typescript SDK](/developer-guide/guides/dbc/typescript-sdk/getting-started) that will help you create the curve config key.
### [buildCurve](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurve)
* This function is useful when you want to create a curve config with a specific `migrationQuoteThreshold` and `percentageSupplyOnMigration`.
* The `percentageSupplyOnMigration` is the percentage of the total token supply that you want to be migrated into the post-graduation pool's LP.
### [buildCurveWithMarketCap](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithmarketcap)
* This function is useful when you want to create a curve config that has a specific starting token price and an ending migration token price.
* The `initialMarketCap` is the initial market cap of the token when the pre-graduation pool is first created.
* The `migrationMarketCap` is the market cap of the token when the pre-graduation pool is ready to migrate to the post-graduation pool.
### [buildCurveWithTwoSegments](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithtwosegments)
* This function is useful when you want to create a 2 constant product curve structure with a specific `initialMarketCap`, `migrationMarketCap` and `percentageSupplyOnMigration`.
* The `percentageSupplyOnMigration` is the percentage of the total token supply that you want to be migrated into the post-graduation pool's LP.
* The `initialMarketCap` is the initial market cap of the token when the pre-graduation pool is first created.
* The `migrationMarketCap` is the market cap of the token when the pre-graduation pool is ready to migrate to the post-graduation pool.
### [buildCurveWithLiquidityWeights](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithliquidityweights)
* This function is useful when you want to create a curve config with a unique price action (flat, exponential, etc.) with a specific initial market cap, migration market cap and liquidity weights.
* The `liquidityWeights` is an array of values that you want to be the exponent of the liquidity of the curve segments. Using these liquidity weights, you can control how thick or thin each curve segment's liquidity is to control the price action of the curve.
* The `initialMarketCap` is the initial market cap of the token when the pre-graduation pool is first created.
* The `migrationMarketCap` is the market cap of the token when the pre-graduation pool is ready to migrate to the post-graduation pool.
### [buildCurveWithMidPrice](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithmidprice)
* This function is useful when you want to create a 2 constant product curve structure with a specific mid-point price. This allows you to control the price at which the two curve segments meet.
* The `initialMarketCap` is the initial market cap of the token when the pre-graduation pool is first created.
* The `migrationMarketCap` is the market cap of the token when the pre-graduation pool is ready to migrate to the post-graduation pool.
* The `midPrice` is the price at which the two curve segments will meet (the breakpoint price between the two constant product curves).
* The `percentageSupplyOnMigration` is the percentage of the total token supply that you want to be migrated into the post-graduation pool's LP.
### [buildCurveWithCustomSqrtPrices](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithcustomsqrtprices)
* This function is useful when you want full control over the curve by specifying custom sqrt price breakpoints directly.
* The `sqrtPrices` is an array of custom sqrt prices that must be in ascending order. The first element is the starting price (pMin) and the last element is the migration price (pMax).
* The `liquidityWeights` is an optional array of weights for each segment between the sqrt price breakpoints. If omitted, liquidity is distributed evenly across all segments. If provided, the array length must be `sqrtPrices.length - 1`.
# Integration
Source: https://docs.meteora.ag/developer-guide/guides/dbc/go-sdk/integration
DBC
The `dbc-go` provides a convenient way interact with the DAMM v2 instructions directly.
Before you begin, here are some important resources:
Meteora DBC Go SDK
# Getting Started
To use the Go SDK and test locally, you can use the following command:
## Clone the repository
```bash theme={"system"}
git clone https://github.com/MeteoraAg/dbc-go.git
```
## Install dependencies
```bash theme={"system"}
go mod tidy
```
## Run the examples
Before running the examples, you need to set the private keys and public keys in the examples.
```bash theme={"system"}
go run examples/.go
```
# Examples
Example showing how to create a new pool and perform SOL swaps
Example showing how to create a new pool and perform USDC swaps
Claim accumulated trading fees for pool creators
Claim accumulated trading fees for partners
Retrieve pool configuration settings and parameters
Get detailed fee metrics and statistics for a pool
Fetch pool information and current state
Monitor the progress of the bonding curve for a pool
Transfer creator fees from one account to another
# Overview
Source: https://docs.meteora.ag/developer-guide/guides/dbc/overview
Before getting started building on DBC, you should read the following resource to get a better understanding of how Meteora's DBC works:
DBC is Meteora's first bonding curve pool product that allows you to initialize a virtual reserve pool and migrate to either a DAMM v1 or DAMM v2 pool.
Each DBC pool is a PDA of token mints + config. A DBC Curve Config Key contains all the settings that will dictate the behavior of your DBC pool, which includes bonding curve shape, pre-graduation fees, post-graduation fees, and more.
***
# DBC Program
At Meteora, we’ve developed a `Node.js <> Typescript SDK`, a `Rust SDK` and a `Go SDK` to make deploying and managing your DBC virtual pool easier. The following sections includes information on installing and using the SDKs. It also covers where to find the latest code, and how to contribute to these repositories.
## Program Details
Meteora DBC Program
Meteora DBC Program IDL
Network
Program ID
Mainnet
dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN
Devnet
dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN
Authority
Address
Pool Authority
FhVo3mqL8PW5pH5U2CN4XE33DokiyZnUwuGpH2hmHLuM
## Official SDKs
Official Meteora DBC Typescript SDK
Official Meteora DBC Rust SDK
Official Meteora DBC Go SDK
***
# Swap Modes
DBC supports two swap instructions:
| Instruction | Modes |
| ----------- | ------------------------------------------ |
| `swap` | ExactIn only |
| `swap2` | ExactIn (0), PartialFill (1), ExactOut (2) |
`swap2` includes additional information in the `EvtSwap2` event such as `quoteReserveAmount`, `migrationThreshold`, and `includedFeeInputAmount`.
For pools with Rate Limiter enabled (`baseFeeMode == 2`), the `SYSVAR_INSTRUCTIONS_PUBKEY` must be included in the remaining accounts of the swap instruction.
# Pool Creator Transfer
Pool creators can transfer their creator rights to a new address using the `transfer_pool_creator` instruction. This transfers all creator privileges including fee claiming rights and surplus withdrawal.
***
# Migration
DBC pools can be migrated to either a DAMM v1 or DAMM v2 pool. The DAMM v1 and DAMM v2 pools are both derived from the `baseMint`, `quoteMint` and `dammConfig`.
### Flow of migration
#### DAMM V1
1. `createDammV1MigrationMetadata`
2. `createLocker` (if the token has locked vesting)
3. `migrateToDammV1`
4. `lockDammV1LpToken` (if `creatorPermanentLockedLiquidityPercentage` or `partnerPermanentLockedLiquidityPercentage` > 0)
5. `claimDammV1LpToken` (if `creatorLiquidityPercentage` or `partnerLiquidityPercentage` > 0)
#### Liquidity Vesting (DAMM V2 only)
If `partnerLiquidityVestingInfoParams` or `creatorLiquidityVestingInfoParams` are configured, vesting is handled directly via LP positions during migration. No separate `migration_metadata` account is required.
#### DAMM V2
1. `createLocker` (if the token has locked vesting)
2. `migrateToDammV2`
DAMM v2 migration now uses positions directly for vesting, removing the need for a separate `migration_metadata` account. This simplifies the migration flow and reduces the number of accounts and transactions required.
## DAMM Fee Config Keys
The following section depicts the `dammConfig` key for each pool type.
### DAMM v1 Migration Fee Config Keys:
Accessible via `DAMM_V1_MIGRATION_FEE_ADDRESS[i]` in the DBC Typescript SDK.
Migration Fee Option
Config Key
0
8f848CEy8eY6PhJ3VcemtBDzPPSD4Vq7aJczLZ3o8MmX
1
HBxB8Lf14Yj8pqeJ8C4qDb5ryHL7xwpuykz31BLNYr7S
2
7v5vBdUQHTNeqk1HnduiXcgbvCyVEZ612HLmYkQoAkik
3
EkvP7d5yKxovj884d2DwmBQbrHUWRLGK6bympzrkXGja
4
9EZYAJrcqNWNQzP2trzZesP7XKMHA1jEomHzbRsdX8R2
5
8cdKo87jZU2R12KY1BUjjRPwyjgdNjLGqSGQyrDshhud
### DAMM v2 Migration Fee Config Keys:
Accessible via `DAMM_V2_MIGRATION_FEE_ADDRESS[i]` in the DBC Typescript SDK.
Migration Fee Option
Config Key
0
7F6dnUcRuyM2TwR8myT1dYypFXpPSxqwKNSFNkxyNESd
1
2nHK1kju6XjphBLbNxpM5XRGFj7p9U8vvNzyZiha1z6k
2
Hv8Lmzmnju6m7kcokVKvwqz7QPmdX9XfKjJsXz8RXcjp
3
2c4cYd4reUYVRAB9kUUkrq55VPyy2FNQ3FDL4o12JXmq
4
AkmQWebAwFvWk55wBoCr5D62C6VVDTzi84NJuD9H7cFD
5
DbCRBj8McvPYHJG1ukj8RE15h2dCNUdTAESG49XpQ44u
6
A8gMrEPJkacWkcb3DGwtJwTe16HktSEfvwtuDh2MCtck
## Migration Keeper
We run 2 migration keepers to automatically migrate DBC pools to DAMM pools.
The Migration Keepers only runs on **Mainnet**.
Keeper addresses that we are running:
1. [CQdrEsYAxRqkwmpycuTwnMKggr3cr9fqY8Qma4J9TudY](https://solscan.io/account/CQdrEsYAxRqkwmpycuTwnMKggr3cr9fqY8Qma4J9TudY)
* `pool_config.migration_quote_threshold` either requires:
* 10 SOL
* 750 USDC
* 1500 JUP
2. [DeQ8dPv6ReZNQ45NfiWwS5CchWpB2BVq1QMyNV8L2uSW](https://solscan.io/account/DeQ8dPv6ReZNQ45NfiWwS5CchWpB2BVq1QMyNV8L2uSW)
* `pool_config.migration_quote_threshold` requires:
* \>= 750 USD (`quote_mint` token)
## Manual Migrator
We have also created a [Manual Migrator](https://migrator.meteora.ag) user interface that allows you to manually migrate your DBC pool to a DAMM pool.
The Manual Migrator runs on both **Mainnet** and **Devnet**.Depending on your DBC Config Key, the migration process will require you to sign more than one transaction to call each instruction.
# Integration
Source: https://docs.meteora.ag/developer-guide/guides/dbc/rust-sdk/integration
DBC
The `dynamic-bonding-curve-sdk` provides a convenient way to interact with the Dynamic Bonding Curve program.
Before you begin, here are some important resources:
Meteora DBC Rust SDK
# `quote_exact_in`
This function calculates the result of a swap for a given amount of an exact input token.
**Function**
```rust theme={"system"}
pub fn quote_exact_in(
pool: &VirtualPool,
config: &PoolConfig,
swap_base_for_quote: bool,
current_timestamp: u64,
current_slot: u64,
in_amount: u64,
has_referral: bool,
) -> Result
```
**Parameters**
* `pool`: A reference to the `VirtualPool` state.
* `config`: A reference to the `PoolConfig` for the pool.
* `swap_base_for_quote`: A boolean indicating the direction of the trade. `true` for swapping base token for quote token, `false` otherwise.
* `current_timestamp`: The current Solana cluster timestamp.
* `current_slot`: The current Solana cluster slot.
* `in_amount`: The amount of input tokens for the swap, excluding any transfer fees.
* `has_referral`: A boolean indicating if a referral fee should be considered.
**Returns**
It returns a `Result`, where `SwapResult2` contains detailed information about the outcome of the swap, such as the amount in, fees, and the next sqrt price of the token.
# `quote_exact_out`
This function calculates the result of a swap for a given amount of an exact output token.
**Function**
```rust theme={"system"}
pub fn quote_exact_out(
pool: &VirtualPool,
config: &PoolConfig,
swap_base_for_quote: bool,
current_timestamp: u64,
current_slot: u64,
out_amount: u64,
) -> Result
```
**Parameters**
* `pool`: A reference to the `VirtualPool` state.
* `config`: A reference to the `PoolConfig` for the pool.
* `swap_base_for_quote`: A boolean indicating the direction of the trade. `true` for swapping base token for quote token, `false` otherwise.
* `current_timestamp`: The current Solana cluster timestamp.
* `current_slot`: The current Solana cluster slot.
* `out_amount`: The amount of output tokens for the swap, excluding any transfer fees.
**Returns**
It returns a `Result`, where `SwapResult2` contains detailed information about the outcome of the swap, such as the amount in, fees, and the next sqrt price of the token.
# `quote_partial_fill`
This function calculates the result of a swap for a given amount of a partial input token. This is useful for trading terminals to not be hurt by the last swap overpaying.
**Function**
```rust theme={"system"}
pub fn quote_partial_fill(
pool: &VirtualPool,
config: &PoolConfig,
swap_base_for_quote: bool,
current_timestamp: u64,
current_slot: u64,
in_amount: u64,
has_referral: bool,
) -> Result
```
**Parameters**
* `pool`: A reference to the `VirtualPool` state.
* `config`: A reference to the `PoolConfig` for the pool.
* `swap_base_for_quote`: A boolean indicating the direction of the trade. `true` for swapping base token for quote token, `false` otherwise.
* `current_timestamp`: The current Solana cluster timestamp.
* `current_slot`: The current Solana cluster slot.
* `in_amount`: The amount of input tokens for the swap, excluding any transfer fees.
* `has_referral`: A boolean indicating if a referral fee should be considered.
**Returns**
It returns a `Result`, where `SwapResult2` contains detailed information about the outcome of the swap, such as the amount in, fees, and the next sqrt price of the token.
# Example Scripts
Source: https://docs.meteora.ag/developer-guide/guides/dbc/typescript-sdk/example-scripts
DBC
# Create DBC Config Key
This script creates a DBC Config Key using the `buildCurveWithMarketCap` function (this function helps to abstract the math complexity of creating a DBC Config Key).
You can also use the `buildCurve`, `buildCurveWithTwoSegments`, and `buildCurveWithLiquidityWeights` functions to create a DBC Config Key.
* [buildCurve](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurve) is a function that primarily uses `migrationQuoteThreshold` and `percentageSupplyOnMigration` to build the curve config. This function is useful when you want to create a curve config with a specific migration quote threshold and percentage of supply on migration.
* [buildCurveWithMarketCap](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithmarketcap) is a function that primarily uses `initialMarketCap` and `migrationMarketCap` to build the curve config. This function is useful when you want to create a curve config that has a specific starting token price and an ending migration token price.
* [buildCurveWithTwoSegments](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithtwosegments) is a function that uses `initialMarketCap`, `migrationMarketCap` and `percentageSupplyOnMigration` to build the curve config. This function is useful when you want to create a 2 constant product curve structure with a specific initial market cap, migration market cap and percentage of supply on migration.
* [buildCurveWithMidPrice](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithmidprice) is a function that uses `initialMarketCap`, `migrationMarketCap` and `midPrice` to build the curve config. This function is useful when you want to create a two segment curve config with a specific mid price.
* [buildCurveWithLiquidityWeights](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithliquidityweights) is a function that uses `initialMarketCap`, `migrationMarketCap` and `liquidityWeights` to build the curve config. This function is useful when you want to create a curve config with a unique price action (flat, exponential, etc.) with a specific initial market cap, migration market cap and liquidity weights.
* [buildCurveWithCustomSqrtPrices](/developer-guide/guides/dbc/typescript-sdk/sdk-functions#buildcurvewithcustomsqrtprices) is a function that uses `sqrtPrices` (an array of sqrt price values) and optional `liquidityWeights` to build the curve config. This function is useful when you want full control over the exact price points in your curve, using the `createSqrtPrices` helper to convert human-readable prices to sqrt prices.
```typescript theme={"system"}
import {
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from '@solana/web3.js'
import {
buildCurveWithMarketCap,
DynamicBondingCurveClient,
ActivationType,
CollectFeeMode,
BaseFeeMode,
MigrationFeeOption,
MigrationOption,
TokenDecimal,
TokenType,
TokenUpdateAuthorityOption,
} from '@meteora-ag/dynamic-bonding-curve-sdk'
import { NATIVE_MINT } from '@solana/spl-token'
async function buildCurveWithMarketCapAndCreateConfig() {
const keypair = []
const wallet = Keypair.fromSecretKey(new Uint8Array(keypair))
console.log(`Using wallet: ${wallet.publicKey.toString()}`)
const connection = new Connection(
'https://api.mainnet-beta.solana.com',
'confirmed'
)
const config = Keypair.generate()
console.log(`Config account: ${config.publicKey.toString()}`)
const curveConfig = buildCurveWithMarketCap({
token: {
tokenType: TokenType.SPL,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.NINE,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 100,
endingFeeBps: 100,
numberOfPeriod: 0,
totalDuration: 0,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 50,
poolCreationFee: 0,
enableFirstSwapWithMinFee: false,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.FixedBps100,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
},
liquidityDistribution: {
partnerLiquidityPercentage: 0,
partnerPermanentLockedLiquidityPercentage: 50,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 50,
},
lockedVesting: {
totalLockedVestingAmount: 0,
numberOfVestingPeriod: 0,
cliffUnlockAmount: 0,
totalVestingDuration: 0,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Slot,
initialMarketCap: 30,
migrationMarketCap: 540,
})
console.log(curveConfig)
try {
const client = new DynamicBondingCurveClient(connection, 'confirmed')
const transaction = await client.partner.createConfig({
config: config.publicKey,
feeClaimer: new PublicKey('YOUR_FEE_CLAIMER_ADDRESS'),
leftoverReceiver: new PublicKey('YOUR_LEFTOVER_RECEIVER_ADDRESS'),
payer: wallet.publicKey,
quoteMint: NATIVE_MINT,
...curveConfig,
})
const { blockhash } = await connection.getLatestBlockhash('confirmed')
transaction.recentBlockhash = blockhash
transaction.feePayer = wallet.publicKey
transaction.partialSign(config)
const signature = await sendAndConfirmTransaction(
connection,
transaction,
[wallet, config],
{ commitment: 'confirmed' }
)
console.log(`Config created successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${signature}`
)
console.log(`Config address: ${config.publicKey.toString()}`)
} catch (error) {
console.error('Failed to create config:', error)
}
}
buildCurveWithMarketCapAndCreateConfig()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
```
# Create DBC Token Pool
This script creates a DBC Token Pool using the `createPool` function.
```typescript theme={"system"}
import {
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from '@solana/web3.js'
import { DynamicBondingCurveClient } from '@meteora-ag/dynamic-bonding-curve-sdk'
async function createPool() {
const payerKeypair = []
const payer = Keypair.fromSecretKey(new Uint8Array(payerKeypair))
console.log(`Payer wallet: ${payer.publicKey.toString()}`)
const poolCreatorKeypair = []
const poolCreator = Keypair.fromSecretKey(
new Uint8Array(poolCreatorKeypair)
)
console.log(`Pool creator wallet: ${poolCreator.publicKey.toString()}`)
const connection = new Connection(
'https://api.mainnet-beta.solana.com',
'confirmed'
)
const configAddress = new PublicKey('YOUR_CONFIG_KEY_ADDRESS')
console.log(`Using config: ${configAddress.toString()}`)
try {
const baseMint = Keypair.generate()
console.log(`Generated base mint: ${baseMint.publicKey.toString()}`)
const createPoolParam = {
baseMint: baseMint.publicKey,
config: configAddress,
name: 'YOUR_POOL_NAME',
symbol: 'YOUR_POOL_SYMBOL',
uri: 'YOUR_POOL_IMAGE_URI',
payer: payer.publicKey,
poolCreator: poolCreator.publicKey,
}
const client = new DynamicBondingCurveClient(connection, 'confirmed')
console.log('Creating pool transaction...')
const poolTransaction = await client.pool.createPool(createPoolParam)
const signature = await sendAndConfirmTransaction(
connection,
poolTransaction,
[payer, baseMint, poolCreator],
{
commitment: 'confirmed',
skipPreflight: true,
}
)
console.log('Transaction confirmed!')
console.log(
`Pool created: https://solscan.io/tx/${signature}?cluster=devnet`
)
} catch (error) {
console.error('Failed to create pool:', error)
console.log('Error details:', JSON.stringify(error, null, 2))
}
}
createPool()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
```
# Swap Buy in DBC Token Pool
This script initializes a swap buy transaction in a DBC Token Pool using the `swap` function.
```typescript theme={"system"}
import {
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from '@solana/web3.js'
import { DynamicBondingCurveClient } from '@meteora-ag/dynamic-bonding-curve-sdk'
import BN from 'bn.js'
async function swapBuy() {
const keypair = []
const wallet = Keypair.fromSecretKey(new Uint8Array(keypair))
console.log(`Using wallet: ${wallet.publicKey.toString()}`)
const connection = new Connection(
'https://api.mainnet-beta.solana.com',
'confirmed'
)
const poolAddress = new PublicKey('YOUR_POOL_ADDRESS')
console.log(`Swapping in pool: ${poolAddress.toString()}`)
try {
const client = new DynamicBondingCurveClient(connection, 'confirmed')
const swapParam = {
amountIn: new BN(1 * 1e9), // 1 SOL
minimumAmountOut: new BN(0), // Can get this param from swapQuote
swapBaseForQuote: false,
owner: wallet.publicKey,
pool: poolAddress,
referralTokenAccount: null, // Can parse in a token account address to collect fees
}
const swapTransaction = await client.pool.swap(swapParam)
const swapSignature = await sendAndConfirmTransaction(
connection,
swapTransaction,
[wallet],
{
commitment: 'confirmed',
skipPreflight: true,
maxRetries: 5,
}
)
console.log(
`Swap executed: https://solscan.io/tx/${swapSignature}?cluster=devnet`
)
} catch (error) {
console.error('Failed to execute swap:', error)
}
}
swapBuy()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
```
# Swap Quote in DBC Token Pool
This script initializes a swap quotation in a DBC Token Pool using the `swapQuote` function.
```typescript theme={"system"}
import { Connection, PublicKey } from '@solana/web3.js'
import { DynamicBondingCurveClient } from '@meteora-ag/dynamic-bonding-curve-sdk'
import BN from 'bn.js'
async function swapQuote() {
const connection = new Connection(
'https://api.mainnet-beta.solana.com',
'confirmed'
)
const poolAddress = new PublicKey('YOUR_POOL_ADDRESS')
console.log(`Getting swap quote for pool: ${poolAddress.toString()}`)
try {
const client = new DynamicBondingCurveClient(connection, 'confirmed')
const virtualPoolState = await client.state.getPool(poolAddress)
if (!virtualPoolState) {
throw new Error(`Pool not found: ${poolAddress.toString()}`)
}
const poolConfigState = await client.state.getPoolConfig(
virtualPoolState.config
)
const amountIn = new BN('383233860117676543')
const swapBaseForQuote = true
const hasReferral = false
const currentPoint = new BN(0)
console.log('Calculating swap quote...')
try {
if (
!virtualPoolState.sqrtPrice ||
virtualPoolState.sqrtPrice.isZero()
) {
throw new Error(
'Invalid pool state: sqrtPrice is zero or undefined'
)
}
if (!poolConfigState.curve || poolConfigState.curve.length === 0) {
throw new Error('Invalid config state: curve is empty')
}
const quote = await client.pool.swapQuote({
virtualPool: virtualPoolState,
config: poolConfigState,
swapBaseForQuote,
amountIn,
slippageBps: 100,
hasReferral,
currentPoint,
})
console.log('Swap Quote:', {
amountIn: amountIn.toString(),
amountOut: quote.amountOut.toString(),
minimumAmountOut: quote.minimumAmountOut.toString(),
nextSqrtPrice: quote.nextSqrtPrice.toString(),
fee: {
trading: quote.fee.trading.toString(),
protocol: quote.fee.protocol.toString(),
referral: quote.fee.referral?.toString() || '0',
},
price: {
beforeSwap: quote.price.beforeSwap.toString(),
afterSwap: quote.price.afterSwap.toString(),
},
})
} catch (error) {
console.error('Failed to calculate swap quote:', error)
console.log('Pool state:', {
sqrtPrice:
virtualPoolState.sqrtPrice?.toString() || 'undefined',
baseReserve:
virtualPoolState.baseReserve?.toString() || 'undefined',
quoteReserve:
virtualPoolState.quoteReserve?.toString() || 'undefined',
})
console.log('Config state:', {
curveLength: poolConfigState.curve?.length || 0,
collectFeeMode: poolConfigState.collectFeeMode,
})
}
} catch (error) {
console.error('Failed to get swap quote:', error)
console.log('Error details:', JSON.stringify(error, null, 2))
}
}
swapQuote()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
```
# Migrate to DAMM v1
This script migrates a DBC Token Pool to DAMM V1.
The migration process follows these steps:
1. Create Migration Metadata (skip if metadata exists)
2. Create Locker (checks if baseMint token has Locked Vesting, and if lockEscrow has been created)
3. Migrate to DAMM V1 (if isMigrated = 0)
4. Lock or Claim Partner Or Creator LP
* Lock Partner LP (if partnerPermanentLockedLiquidityPercentage > 0)
* Lock Creator LP (if creatorPermanentLockedLiquidityPercentage > 0)
* Claim Partner LP (if partnerLiquidityPercentage > 0)
* Claim Creator LP (if creatorLiquidityPercentage > 0)
```typescript theme={"system"}
import {
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from '@solana/web3.js'
import {
deriveDammV1MigrationMetadataAddress,
deriveBaseKeyForLocker,
deriveEscrow,
DAMM_V1_MIGRATION_FEE_ADDRESS,
DynamicBondingCurveClient,
} from '@meteora-ag/dynamic-bonding-curve-sdk'
import { BN } from 'bn.js'
async function migrateToDammV1() {
const keypair = []
const wallet = Keypair.fromSecretKey(new Uint8Array(keypair))
console.log(`Using wallet: ${wallet.publicKey.toString()}`)
const connection = new Connection(
'https://api.mainnet-beta.solana.com',
'confirmed'
)
try {
const client = new DynamicBondingCurveClient(connection, 'confirmed')
const poolAddress = new PublicKey(
'YOUR_POOL_ADDRESS'
)
const poolState = await client.state.getPool(poolAddress)
const config = new PublicKey(
'YOUR_CONFIG_KEY_ADDRESS'
)
const poolConfigState = await client.state.getPoolConfig(config)
// Step 1: Check if migration metadata exists
console.log('Checking if migration metadata exists...')
const migrationMetadata =
deriveDammV1MigrationMetadataAddress(poolAddress)
console.log('Migration metadata address:', migrationMetadata.toString())
const metadataAccount =
await connection.getAccountInfo(migrationMetadata)
if (!metadataAccount) {
console.log('Creating migration metadata...')
const createMetadataTx =
await client.migration.createDammV1MigrationMetadata({
payer: wallet.publicKey,
virtualPool: poolAddress,
config: config,
})
const { blockhash } =
await connection.getLatestBlockhash('confirmed')
createMetadataTx.recentBlockhash = blockhash
createMetadataTx.feePayer = wallet.publicKey
const metadataSignature = await sendAndConfirmTransaction(
connection,
createMetadataTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`Migration metadata created successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${metadataSignature}?cluster=devnet`
)
} else {
console.log('Migration metadata already exists')
}
// Step 2: Check for locked vesting and create locker if needed
if (
poolConfigState.lockedVestingConfig.amountPerPeriod.gt(new BN(0)) ||
poolConfigState.lockedVestingConfig.cliffUnlockAmount.gt(new BN(0))
) {
// Check if escrow already exists
const base = deriveBaseKeyForLocker(poolAddress)
const escrow = deriveEscrow(base)
const escrowAccount = await connection.getAccountInfo(escrow)
if (!escrowAccount) {
console.log('Found locked vesting, creating locker...')
const createLockerTx = await client.migration.createLocker({
virtualPool: poolAddress,
payer: wallet.publicKey,
})
const { blockhash: lockerBlockhash } =
await connection.getLatestBlockhash('confirmed')
createLockerTx.recentBlockhash = lockerBlockhash
createLockerTx.feePayer = wallet.publicKey
const lockerSignature = await sendAndConfirmTransaction(
connection,
createLockerTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`Locker created successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${lockerSignature}?cluster=devnet`
)
} else {
console.log('Escrow already exists, skipping locker creation')
}
} else {
console.log('No locked vesting found, skipping locker creation')
}
// Step 3: Migrate to DAMM V1
if (!poolState.isMigrated) {
console.log('Migrating to DAMM V1...')
const migrateTx = await client.migration.migrateToDammV1({
payer: wallet.publicKey,
virtualPool: poolAddress,
dammConfig:
DAMM_V1_MIGRATION_FEE_ADDRESS[
poolConfigState.migrationFeeOption
],
})
const { blockhash: migrateBlockhash } =
await connection.getLatestBlockhash('confirmed')
migrateTx.recentBlockhash = migrateBlockhash
migrateTx.feePayer = wallet.publicKey
const migrateSignature = await sendAndConfirmTransaction(
connection,
migrateTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`Migration to DAMM V1 completed successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${migrateSignature}?cluster=devnet`
)
} else {
console.log('Pool already migrated to DAMM V1')
}
// Step 4.1: Lock LP tokens for creator and partner
if (poolConfigState.creatorPermanentLockedLiquidityPercentage > 0) {
console.log('Locking LP tokens for creator...')
const lockCreatorTx = await client.migration.lockDammV1LpToken({
payer: wallet.publicKey,
virtualPool: poolAddress,
dammConfig:
DAMM_V1_MIGRATION_FEE_ADDRESS[
poolConfigState.migrationFeeOption
],
isPartner: false,
})
const { blockhash: lockCreatorBlockhash } =
await connection.getLatestBlockhash('confirmed')
lockCreatorTx.recentBlockhash = lockCreatorBlockhash
lockCreatorTx.feePayer = wallet.publicKey
const lockCreatorSignature = await sendAndConfirmTransaction(
connection,
lockCreatorTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`LP tokens locked for creator successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${lockCreatorSignature}`
)
}
// Step 4.2: Lock LP tokens for partner
if (poolConfigState.partnerPermanentLockedLiquidityPercentage > 0) {
console.log('Locking LP tokens for partner...')
const lockCreatorTx = await client.migration.lockDammV1LpToken({
payer: wallet.publicKey,
virtualPool: poolAddress,
dammConfig:
DAMM_V1_MIGRATION_FEE_ADDRESS[
poolConfigState.migrationFeeOption
],
isPartner: false,
})
const { blockhash: lockCreatorBlockhash } =
await connection.getLatestBlockhash('confirmed')
lockCreatorTx.recentBlockhash = lockCreatorBlockhash
lockCreatorTx.feePayer = wallet.publicKey
const lockCreatorSignature = await sendAndConfirmTransaction(
connection,
lockCreatorTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`LP tokens locked for creator successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${lockCreatorSignature}`
)
}
// Step 4.3: Claim LP tokens for creator
if (poolConfigState.creatorLiquidityPercentage > 0) {
console.log('Claiming LP tokens for creator...')
const claimCreatorTx = await client.migration.claimDammV1LpToken({
payer: wallet.publicKey,
virtualPool: poolAddress,
dammConfig:
DAMM_V1_MIGRATION_FEE_ADDRESS[
poolConfigState.migrationFeeOption
],
isPartner: false,
})
const { blockhash: claimCreatorBlockhash } =
await connection.getLatestBlockhash('confirmed')
claimCreatorTx.recentBlockhash = claimCreatorBlockhash
claimCreatorTx.feePayer = wallet.publicKey
const claimCreatorSignature = await sendAndConfirmTransaction(
connection,
claimCreatorTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`LP tokens claimed for creator successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${claimCreatorSignature}?cluster=devnet`
)
}
// Step 4.4: Claim LP tokens for partner
if (poolConfigState.partnerLiquidityPercentage > 0) {
console.log('Claiming LP tokens for partner...')
const claimPartnerTx = await client.migration.claimDammV1LpToken({
payer: wallet.publicKey,
virtualPool: poolAddress,
dammConfig:
DAMM_V1_MIGRATION_FEE_ADDRESS[
poolConfigState.migrationFeeOption
],
isPartner: true,
})
const { blockhash: claimPartnerBlockhash } =
await connection.getLatestBlockhash('confirmed')
claimPartnerTx.recentBlockhash = claimPartnerBlockhash
claimPartnerTx.feePayer = wallet.publicKey
const claimPartnerSignature = await sendAndConfirmTransaction(
connection,
claimPartnerTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`LP tokens claimed for partner successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${claimPartnerSignature}?cluster=devnet`
)
}
} catch (error) {
console.error('Failed to migrate to DAMM V1:', error)
}
}
migrateToDammV1()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
```
# Migrate to DAMM v2
This script migrates a DBC Token Pool to DAMM V2.
The migration process follows these steps:
1. Create Migration Metadata (skip if metadata exists)
2. Create Locker (checks if baseMint token has Locked Vesting, and if lockEscrow has been created)
3. Migrate to DAMM V2 (if isMigrated = 0)
```typescript theme={"system"}
import {
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
} from '@solana/web3.js'
import {
DynamicBondingCurveClient,
DAMM_V2_MIGRATION_FEE_ADDRESS,
deriveDammV2MigrationMetadataAddress,
deriveBaseKeyForLocker,
deriveEscrow,
} from '@meteora-ag/dynamic-bonding-curve-sdk'
import { BN } from 'bn.js'
async function migrateToDammV2() {
const keypair = []
const wallet = Keypair.fromSecretKey(new Uint8Array(keypair))
console.log(`Using wallet: ${wallet.publicKey.toString()}`)
const connection = new Connection(
'https://api.mainnet-beta.solana.com',
'confirmed'
)
try {
const client = new DynamicBondingCurveClient(connection, 'confirmed')
const poolAddress = new PublicKey(
'6tCCyVyaXRZ2x1pzAAK5fA3FXRhDuH3NQ5cyUTUuv4Xv'
)
const virtualPoolState = await client.state.getPool(poolAddress)
const config = new PublicKey(
'6tCCyVyaXRZ2x1pzAAK5fA3FXRhDuH3NQ5cyUTUuv4Xv'
)
const poolConfigState = await client.state.getPoolConfig(config)
if (!virtualPoolState) {
throw new Error(`Pool not found: ${poolAddress.toString()}`)
}
// Step 1: Check for locked vesting and create locker if needed
if (
poolConfigState.lockedVestingConfig.amountPerPeriod.gt(new BN(0)) ||
poolConfigState.lockedVestingConfig.cliffUnlockAmount.gt(new BN(0))
) {
// Check if locker already exists
const base = deriveBaseKeyForLocker(poolAddress)
const escrow = deriveEscrow(base)
const escrowAccount = await connection.getAccountInfo(escrow)
if (!escrowAccount) {
console.log('Locker not found, creating locker...')
const createLockerTx = await client.migration.createLocker({
virtualPool: poolAddress,
payer: wallet.publicKey,
})
const { blockhash: lockerBlockhash } =
await connection.getLatestBlockhash('confirmed')
createLockerTx.recentBlockhash = lockerBlockhash
createLockerTx.feePayer = wallet.publicKey
const lockerSignature = await sendAndConfirmTransaction(
connection,
createLockerTx,
[wallet],
{ commitment: 'confirmed' }
)
console.log(`Locker created successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${lockerSignature}?cluster=devnet`
)
} else {
console.log('Locker already exists, skipping creation')
}
} else {
console.log('No locked vesting found, skipping locker creation')
}
// Step 2: Migrate to DAMM V2
if (!virtualPoolState.isMigrated) {
console.log('Migrating to DAMM V2...')
const migrateTx = await client.migration.migrateToDammV2({
payer: wallet.publicKey,
virtualPool: poolAddress,
dammConfig: DAMM_V2_MIGRATION_FEE_ADDRESS[poolConfigState.migrationFeeOption],
})
const { blockhash: migrateBlockhash } =
await connection.getLatestBlockhash('confirmed')
migrateTx.transaction.recentBlockhash = migrateBlockhash
migrateTx.transaction.feePayer = wallet.publicKey
const migrateSignature = await sendAndConfirmTransaction(
connection,
migrateTx.transaction,
[
wallet,
migrateTx.firstPositionNftKeypair,
migrateTx.secondPositionNftKeypair,
],
{ commitment: 'confirmed' }
)
console.log(`Migration to DAMM V2 completed successfully!`)
console.log(
`Transaction: https://solscan.io/tx/${migrateSignature}?cluster=devnet`
)
} else {
console.log('Pool already migrated to DAMM V2')
}
} catch (error) {
console.error('Failed to migrate to DAMM V2:', error)
}
}
migrateToDammV2()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
```
# Getting Started
Source: https://docs.meteora.ag/developer-guide/guides/dbc/typescript-sdk/getting-started
DBC
This guide provides instructions on how to get started with building on Meteora's DBC program using the DBC TypeScript SDK.
Before you begin, here are some important resources:
Meteora DAMM v2 Typescript SDK
Meteora DBC NPM Package
# Installation
To use the SDK in your project, install it using your preferred package manager:
```bash theme={"system"}
npm install @meteora-ag/dynamic-bonding-curve-sdk @solana/web3.js
```
```bash theme={"system"}
pnpm install @meteora-ag/dynamic-bonding-curve-sdk @solana/web3.js
```
```bash theme={"system"}
yarn add @meteora-ag/dynamic-bonding-curve-sdk @solana/web3.js
```
# Initialization
Once installed, you can initialize the SDK in your TypeScript/JavaScript project like this:
```typescript theme={"system"}
import { Connection } from "@solana/web3.js";
import { DynamicBondingCurveClient } from "@meteora-ag/dynamic-bonding-curve-sdk";
// Initialize a connection to the Solana network (e.g., Mainnet)
const connection = new Connection("https://api.mainnet-beta.solana.com");
// Create a new instance of the DynamicBondingCurveClient
const dbcClient = new DynamicBondingCurveClient(connection, "confirmed");
```
# Testing the SDK (for contributors)
If you have cloned the SDK repository and want to run the built-in tests:
```bash theme={"system"}
# Install dependencies
bun install
# Run tests
bun test
```
# Development Resources
## Faucets
When working on devnet, you might need test tokens. Here is a helpful faucet.
# SDK Functions
Source: https://docs.meteora.ag/developer-guide/guides/dbc/typescript-sdk/sdk-functions
DBC
## Partner Functions
### createConfig
Creates a new config key that will dictate the behavior of all pools created with this key. This is where you set the pool fees, migration options, the bonding curve shape, and more.
**Function**
```typescript theme={"system"}
async createConfig(params: CreateConfigParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreateConfigParams {
payer: PublicKey // The wallet paying for the transaction
config: PublicKey // The config account address (generated by the partner)
feeClaimer: PublicKey // The wallet that will be able to claim the fee
leftoverReceiver: PublicKey // The wallet that will receive the bonding curve leftover
quoteMint: PublicKey // The quote mint address
poolFees: {
baseFee: {
cliffFeeNumerator: BN // Initial fee numerator (base fee)
firstFactor: number // feeScheduler: numberOfPeriod, rateLimiter: feeIncrementBps
secondFactor: BN // feeScheduler: periodFrequency, rateLimiter: maxLimiterDuration
thirdFactor: BN // feeScheduler: reductionFactor, rateLimiter: referenceAmount
baseFeeMode: number // 0: FeeSchedulerLinear, 1: FeeSchedulerExponential, 2: RateLimiter
}
dynamicFee: {
// Optional dynamic fee
binStep: number // u16 value representing the bin step in bps
binStepU128: BN // u128 value for a more accurate bin step
filterPeriod: number // Minimum time that must pass between fee updates
decayPeriod: number // Period after the volatility starts decaying (must be > filterPeriod)
reductionFactor: number // Controls how quickly volatility decys over time
variableFeeControl: number // Multiplier that determines how much volatility affects fees
maxVolatilityAccumulator: number // Caps the maximum volatility that can be accumulated
} | null
}
collectFeeMode: number // 0: QuoteToken, 1: OutputToken
migrationOption: number // 0: DAMM V1, 1: DAMM v2
activationType: number // 0: Slot, 1: Timestamp
tokenType: number // 0: SPL, 1: Token2022
tokenDecimal: number // The number of decimals for the token
partnerLiquidityPercentage: number // The percentage of the LP that will be allocated to the partner in the graduated pool (0-100)
partnerPermanentLockedLiquidityPercentage: number // The percentage of the locked LP that will be allocated to the partner in the graduated pool (0-100)
creatorLiquidityPercentage: number // The percentage of the LP that will be allocated to the creator in the graduated pool (0-100)
creatorPermanentLockedLiquidityPercentage: number // The percentage of the locked LP that will be allocated to the creator in the graduated pool (0-100)
migrationQuoteThreshold: BN // The quote threshold for migration
sqrtStartPrice: BN // The starting price of the pool
lockedVesting: {
// Optional locked vesting (BN (0) for all fields for no vesting)
amountPerPeriod: BN // The amount of tokens that will be vested per period
cliffDurationFromMigrationTime: BN // The duration of the waiting time before the vesting starts
frequency: BN // The frequency of the vesting
numberOfPeriod: BN // The number of periods of the vesting
cliffUnlockAmount: BN // The amount of tokens that will be unlocked when vesting starts
}
migrationFeeOption: number // 0: Fixed 25bps, 1: Fixed 30bps, 2: Fixed 100bps, 3: Fixed 200bps, 4: Fixed 400bps, 5: Fixed 600bps, 6: Customizable (only for DAMM v2)
tokenSupply: {
// Optional token supply
preMigrationTokenSupply: BN // The token supply before migration
postMigrationTokenSupply: BN // The token supply after migration
} | null
creatorTradingFeePercentage: number // The percentage of the trading fee that will be allocated to the creator
tokenUpdateAuthority: number // 0 - CreatorUpdateAuthority, 1 - Immutable, 2 - PartnerUpdateAuthority, 3 - CreatorUpdateAndMintAuthority, 4 - PartnerUpdateAndMintAuthority
migrationFee: {
// Optional migration fee (set as 0 for feePercentage and creatorFeePercentage for no migration fee)
feePercentage: number // The percentage of fee taken from migration quote threshold (0-99)
creatorFeePercentage: number // The fee share percentage for the creator from the migration fee (0-100)
}
migratedPoolFee: {
// Only when migrationOption = MET_DAMM_V2 (1) and migrationFeeOption = Customizable (6)
collectFeeMode: number // 0: QuoteToken, 1: OutputToken
dynamicFee: number // 0: Disabled, 1: Enabled
poolFeeBps: number // The pool fee in basis points. Minimum 10, Maximum 1000 bps.
}
poolCreationFee: BN // The pool creation fee
partnerLiquidityVestingInfo: {
vestingPercentage: number // The percentage of the liquidity that will be vested
bpsPerPeriod: number // The basis points per period
numberOfPeriods: number // The number of periods
cliffDurationFromMigrationTime: number // The duration of the waiting time before the vesting starts
frequency: number // The frequency of the vesting
}
creatorLiquidityVestingInfo: {
vestingPercentage: number // The percentage of the liquidity that will be vested
bpsPerPeriod: number // The basis points per period
numberOfPeriods: number // The number of periods
cliffDurationFromMigrationTime: number // The duration of the waiting time before the vesting starts
frequency: number // The frequency of the vesting
}
migratedPoolBaseFeeMode: number // 0: FeeTimeSchedulerLinear, 1: FeeTimeSchedulerExponential, 3: FeeMarketCapSchedulerLinear, 4: FeeMarketCapSchedulerExponential (defaults to FeeTimeSchedulerLinear)
migratedPoolMarketCapFeeSchedulerParams: {
// Defaults to all 0. Configure only when migratedPoolBaseFeeMode = FeeMarketCapSchedulerLinear or FeeMarketCapSchedulerExponential
numberOfPeriod: number // The number of periods
sqrtPriceStepBps: number // The square root price step in basis points
schedulerExpirationDuration: number // The scheduler expiration duration in seconds
reductionFactor: BN // The reduction factor
}
enableFirstSwapWithMinFee: boolean // Whether to enable first swap with minimum fee (defaults to false)
padding: []
curve: {
// The curve of the pool
sqrtPrice: BN // The square root of the curve point price
liquidity: BN // The liquidity of the curve point
}[]
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.partner.createConfig({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
config: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
feeClaimer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
leftoverReceiver: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
quoteMint: new PublicKey('So11111111111111111111111111111111111111112'),
poolFees: {
baseFee: {
cliffFeeNumerator: new BN('25000000'),
firstFactor: 0,
secondFactor: new BN('0'),
thirdFactor: new BN('0'),
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
},
dynamicFee: {
binStep: 1,
binStepU128: new BN('1844674407370955'),
filterPeriod: 10,
decayPeriod: 120,
reductionFactor: 1000,
variableFeeControl: 100000,
maxVolatilityAccumulator: 100000,
},
},
activationType: 0,
collectFeeMode: 0,
migrationOption: 0,
tokenType: 0,
tokenDecimal: 9,
migrationQuoteThreshold: new BN('1000000000'),
partnerLiquidityPercentage: 25,
creatorLiquidityPercentage: 25,
partnerPermanentLockedLiquidityPercentage: 25,
creatorPermanentLockedLiquidityPercentage: 25,
sqrtStartPrice: new BN('58333726687135158'),
lockedVesting: {
amountPerPeriod: new BN('0'),
cliffDurationFromMigrationTime: new BN('0'),
frequency: new BN('0'),
numberOfPeriod: new BN('0'),
cliffUnlockAmount: new BN('0'),
},
migrationFeeOption: 0,
tokenSupply: null,
creatorTradingFeePercentage: 0,
tokenUpdateAuthority: 0,
migrationFee: {
feePercentage: 25,
creatorFeePercentage: 50,
},
poolCreationFee: new BN(1_000_000_000),
creatorLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
frequency: 0,
cliffDurationFromMigrationTime: 0,
},
partnerLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
frequency: 0,
cliffDurationFromMigrationTime: 0,
},
migratedPoolBaseFeeMode: DammV2BaseFeeMode.FeeTimeSchedulerLinear,
migratedPoolMarketCapFeeSchedulerParams: {
numberOfPeriod: 0,
sqrtPriceStepBps: 0,
schedulerExpirationDuration: 0,
reductionFactor: new BN('0'),
},
padding: [],
curve: [
{
sqrtPrice: new BN('233334906748540631'),
liquidity: new BN('622226417996106429201027821619672729'),
},
{
sqrtPrice: new BN('79226673521066979257578248091'),
liquidity: new BN('1'),
},
],
enableFirstSwapWithMinFee: false,
migratedPoolFee: {
dynamicFee: 0,
poolFeeBps: 0,
collectFeeMode: 0,
},
})
```
**Notes**
When creating a new configuration for a dynamic bonding curve, several validations are performed to ensure the parameters are valid:
**Pool Fees**
* Base fee must have a positive cliff fee numerator
* If using Fee Scheduler (Linear or Exponential):
* All parameters (firstFactor, secondFactor, thirdFactor) must be set if any are set
* Cliff fee numerator must be positive
* For Linear mode, final fee must not be negative
* Min and max fee numerators must be within valid range (MIN\_FEE\_NUMERATOR to MAX\_FEE\_NUMERATOR)
* Fee numerators must be less than FEE\_DENOMINATOR
* If using Rate Limiter:
* Can only be used with QuoteToken collect fee mode
* All parameters must be set for non-zero rate limiter
* Max limiter duration must be within limits based on activation type
* Fee increment numerator must be less than FEE\_DENOMINATOR
* Cliff fee numerator must be within valid range
* Min and max fee numerators must be within valid range
**Fee Mode**
* Collect fee mode must be either `QuoteToken` (0) or `OutputToken` (1)
**Migration and Token Type**
* For migration to DAMM v1 (MigrationOption: 0), token type must be type SPL (TokenType: 0)
**Activation Type**
* Must be either Slot (0) or Timestamp (1)
**Graduated DAMM V1/V2 Pool Fee (migrationFeeOption)**
* Must be a valid option: FixedBps25 (0), FixedBps30 (1), FixedBps100 (2), FixedBps200 (3), FixedBps400 (4), FixedBps600 (5), Customizable (6)
* Customizable (6) is only allowed for DAMM V2 migration
* When `marketCapFeeSchedulerParams` is configured in `migratedPoolFee`, the on-chain program requires `migrationFeeOption` to be `Customizable` (6). The SDK's `buildCurve*` functions handle this automatically by overriding `migrationFeeOption` to `Customizable` when `marketCapFeeSchedulerParams` is present.
* For fixed options (0-5), all `migratedPoolFee` fields must be zero (defaults). Custom values are ignored.
**Migration Fee**
* Migration fee percentage must be between 0 and 99
* Creator fee percentage must be between 0 and 100
**Token Decimals**
* Must be between 6 and 9
**Liquidity Percentages (Graduated pool)**
* The sum of partner liquidity LP, creator liquidity LP, partner locked liquidity LP, creator locked liquidity LP, partner vested liquidity LP and creator vested liquidity LP percentages must equal 100(%).
* Must ensure that there is minimum 1000 bps of locked liquidity after 1 day duration (86400 seconds). The locked liquidity can be vested liquidity or permanently locked liquidity.
**Migration Quote Threshold**
* Must be greater than 0
**Price**
* Square root start price must be within valid range (MIN\_SQRT\_PRICE to MAX\_SQRT\_PRICE)
**Curve**
* Must have at least one point and not exceed MAX\_CURVE\_POINT
* First curve point must have sqrt price greater than sqrt start price and positive liquidity
* Curve points must be in ascending order by sqrt price
* All points must have positive liquidity
* Last point's sqrt price must not exceed MAX\_SQRT\_PRICE
**Locked Vesting**
* If the values are not all zeros (no Locked Vesting), then:
* Frequency must be greater than 0
* Total amount of tokens vested (cliffUnlockAmount + amountPerPeriod \* numberOfPeriod) must be greater than 0
**Token Supply**
* If specified:
* Leftover receiver must be a valid non-default PublicKey
* Post-migration supply must not exceed pre-migration supply
* Pre-migration supply must be sufficient to cover minimum base supply with buffer
* Post-migration supply must be sufficient to cover minimum base supply without buffer
**Token Update Authority**
* Must be either CreatorUpdateAuthority (0), Immutable (1), PartnerUpdateAuthority (2), CreatorUpdateAndMintAuthority (3), PartnerUpdateAndMintAuthority (4)
**Pool Creation Fee**
* Can be 0.
* If non-zero, must be between `1_000_000` and `100_000_000_000` lamports of SOL
**Migrated Pool Base Fee Mode**
* Must be either `FeeTimeSchedulerLinear` (0), `FeeTimeSchedulerExponential` (1), `FeeMarketCapSchedulerLinear` (3), `FeeMarketCapSchedulerExponential` (4)
* `FeeTimeSchedulerLinear` (0) and `FeeTimeSchedulerExponential` (1) required `migratedPoolMarketCapFeeSchedulerParams` to be all set to 0.
* `FeeMarketCapSchedulerLinear` (3) and `FeeMarketCapSchedulerExponential` (4) required `migratedPoolMarketCapFeeSchedulerParams` to be provided.
* **Migrated Pool MarketCap Fee Scheduler Params**
* If `migratedPoolBaseFeeMode` is `FeeMarketCapSchedulerLinear` or `FeeMarketCapSchedulerExponential`, then `migratedPoolMarketCapFeeSchedulerParams` must be provided. Else set all parameter to 0.
* **Enable First Swap With Minimum Fee**
* Enable only when you want to concatenate a swap instruction with create pool instruction in a single transaction.
**Migrated Pool Fee**
* Configures the graduated pool fee parameters for the migrated DAMM V2 pool.
* Only applies when `migrationOption = MET_DAMM_V2` (1).
* When using `migrationFeeOption = Customizable` (6), you can configure: `collectFeeMode`, `dynamicFee`, and `poolFeeBps`.
* When `marketCapFeeSchedulerParams` is configured:
* `poolFeeBps` must be greater than 0 (serves as the starting/cliff fee for the market cap scheduler).
* `baseFeeMode` must be `FeeMarketCapSchedulerLinear` (3) or `FeeMarketCapSchedulerExponential` (4).
* `endingBaseFeeBps` must be strictly less than the bonding curve's `endingFeeBps`.
* For DAMM V1 migration, all migrated pool fee parameters are ignored.
***
### createPartnerMetadata
Creates a new partner metadata account. This partner metadata will be tagged to a wallet address that holds the config keys.
**Function**
```typescript theme={"system"}
async createPartnerMetadata(params: CreatePartnerMetadataParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreatePartnerMetadataParams {
name: string // The name of the partner
website: string // The website of the partner
logo: string // The logo of the partner
feeClaimer: PublicKey // The wallet that will be able to claim the fee
payer: PublicKey // The wallet that will pay for the transaction
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.partner.createPartnerMetadata({
name: 'Meteora',
website: 'https://meteora.ag',
logo: 'https://launch.meteora.ag',
feeClaimer: wallet.publicKey,
payer: wallet.publicKey,
})
```
***
### claimPartnerTradingFee
Claims the trading fee for the partner. A partner is the `feeClaimer` in the config key.
**Function**
```typescript theme={"system"}
async claimPartnerTradingFee(params: ClaimTradingFeeParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface ClaimTradingFeeParams {
pool: PublicKey // The pool address
feeClaimer: PublicKey // The wallet that will claim the fee
payer: PublicKey // The wallet that will pay for the transaction
maxBaseAmount: BN // The maximum base amount to claim (use 0 to not claim base tokens)
maxQuoteAmount: BN // The maximum quote amount to claim (use 0 to not claim quote tokens)
receiver?: PublicKey | null // The wallet that will receive the tokens (optional)
tempWSolAcc?: PublicKey | null // The temporary wallet that will receive the tokens (optional)
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.partner.claimPartnerTradingFee({
pool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
feeClaimer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
payer: new PublicKey('payer1234567890abcdefghijklmnopqrstuvwxyz'),
maxBaseAmount: new BN(1000000),
maxQuoteAmount: new BN(1000000),
receiver: new PublicKey('receiver1234567890abcdefghijklmnopqrstuvwxyz'),
tempWSolAcc: new PublicKey(
'tempWSolAcc1234567890abcdefghijklmnopqrstuvwxyz'
),
})
```
**Notes**
* The feeClaimer of the pool must be the same as the feeClaimer in the `ClaimTradingFeeParam` params.
* You can indicate maxBaseAmount or maxQuoteAmount to be 0 to not claim Base or Quote tokens respectively.
* If you indicated a `receiver`, the receiver **is not** required to sign the transaction, however, you must provide a `tempWSolAcc` if the receiver != creato and if the quote mint is SOL.
***
### claimPartnerTradingFee2
Claims the trading fee for the partner. A partner is the `feeClaimer` in the config key.
**Function**
```typescript theme={"system"}
async claimPartnerTradingFee2(params: ClaimTradingFee2Params): Promise
```
**Parameters**
```typescript theme={"system"}
interface ClaimTradingFee2Params {
pool: PublicKey // The pool address
feeClaimer: PublicKey // The wallet that will claim the fee
payer: PublicKey // The wallet that will pay for the transaction
maxBaseAmount: BN // The maximum base amount to claim (use 0 to not claim base tokens)
maxQuoteAmount: BN // The maximum quote amount to claim (use 0 to not claim quote tokens)
receiver?: PublicKey | null // The wallet that will receive the tokens
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.partner.claimPartnerTradingFee2({
pool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
feeClaimer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
payer: new PublicKey('payer1234567890abcdefghijklmnopqrstuvwxyz'),
maxBaseAmount: new BN(1000000),
maxQuoteAmount: new BN(1000000),
receiver: new PublicKey('receiver1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The feeClaimer of the pool must be the same as the feeClaimer in the `ClaimTradingFee2Param` params.
* You can indicate maxBaseAmount or maxQuoteAmount to be 0 to not claim Base or Quote tokens respectively.
* Can be used in case the partner is a squad multisig account.
***
### partnerWithdrawMigrationFee
Withdraws the partner's migration fee from the pool.
**Function**
```typescript theme={"system"}
async partnerWithdrawMigrationFee(params: WithdrawMigrationFeeParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface WithdrawMigrationFeeParams {
virtualPool: PublicKey // The virtual pool address
sender: PublicKey // The wallet that will claim the fee
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.partner.partnerWithdrawMigrationFee({
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
sender: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The sender of the pool must be the same as the partner (`feeClaimer`) in the config key.
***
### partnerWithdrawSurplus
Withdraws the partner's surplus from the pool.
**Function**
```typescript theme={"system"}
async partnerWithdrawSurplus(params: PartnerWithdrawSurplusParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface PartnerWithdrawSurplusParams {
feeClaimer: PublicKey // The wallet that will claim the fee
virtualPool: PublicKey // The virtual pool address
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.partner.partnerWithdrawSurplus({
feeClaimer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
})
```
**Notes**
* The feeClaimer of the pool must be the same as the feeClaimer in the `PartnerWithdrawSurplusParam` params.
***
### claimPartnerPoolCreationFee
Claims the partner's pool creation fee from the pool. (The pool creation fee is paid by the user)
**Function**
```typescript theme={"system"}
async claimPartnerPoolCreationFee(params: ClaimPartnerPoolCreationFeeParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface ClaimPartnerPoolCreationFeeParams {
virtualPool: PublicKey // The virtual pool address
feeReceiver: PublicKey // The wallet that will claim the fee
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.partner.claimPartnerPoolCreationFee({
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
feeReceiver: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The signer of the transaction must be the same as the feeClaimer in the `virtualPool`'s config.
***
## Build Curve Functions
### buildCurve
Builds a new constant product curve. This function does the math for you to create a curve structure based on percentage of supply on migration and migration quote threshold.
**Function**
```typescript theme={"system"}
function buildCurve(params: BuildCurveParams): ConfigParameters
```
**Parameters**
All `buildCurve*` functions share the same base parameters (`BuildCurveBaseParams`), organized into nested groups:
```typescript theme={"system"}
interface BuildCurveParams {
// Token configuration
token: {
tokenType: TokenType // 0: SPL, 1: Token2022
tokenBaseDecimal: TokenDecimal // 6, 7, 8, or 9
tokenQuoteDecimal: TokenDecimal // 6, 7, 8, or 9
tokenUpdateAuthority: TokenUpdateAuthorityOption // 0: CreatorUpdateAuthority, 1: Immutable, 2: PartnerUpdateAuthority, 3: CreatorUpdateAndMintAuthority, 4: PartnerUpdateAndMintAuthority
totalTokenSupply: number // The total token supply
leftover: number // The leftover amount that can be withdrawn by leftover receiver
}
// Fee configuration
fee: {
baseFeeParams: BaseFeeParams // Either FeeScheduler or RateLimiter (see below)
dynamicFeeEnabled: boolean // Whether dynamic fee is enabled
collectFeeMode: CollectFeeMode // 0: QuoteToken, 1: OutputToken
creatorTradingFeePercentage: number // The percentage of the trading fee allocated to the creator
poolCreationFee: number // The pool creation fee paid by the token pool creator (in SOL)
enableFirstSwapWithMinFee: boolean // Enable only when bundling swap with create pool instruction
}
// Migration configuration
migration: {
migrationOption: MigrationOption // 0: DAMM V1, 1: DAMM V2
migrationFeeOption: MigrationFeeOption // 0-5: Fixed fee options, 6: Customizable (DAMM V2 only)
migrationFee: {
feePercentage: number // Percentage of fee taken from migration quote threshold (0-99)
creatorFeePercentage: number // Fee share percentage for the creator from the migration fee (0-100)
}
migratedPoolFee?: {
// Optional. Configure only for DAMM V2 migration.
collectFeeMode: CollectFeeMode // 0: QuoteToken, 1: OutputToken
dynamicFee: DammV2DynamicFeeMode // 0: Disabled, 1: Enabled
poolFeeBps: number // The pool fee in basis points
baseFeeMode?: DammV2BaseFeeMode // 0: FeeTimeSchedulerLinear, 1: FeeTimeSchedulerExponential, 3: FeeMarketCapSchedulerLinear, 4: FeeMarketCapSchedulerExponential
marketCapFeeSchedulerParams?: {
// Configure for market cap-based fee scheduling
endingBaseFeeBps: number // The ending base fee in basis points (must be < bonding curve's endingFeeBps)
numberOfPeriod: number // The number of periods
sqrtPriceStepBps: number // The square root price step in basis points
schedulerExpirationDuration: number // The scheduler expiration duration in seconds
}
}
}
// Liquidity distribution for the graduated pool
liquidityDistribution: {
partnerLiquidityPercentage: number // Partner LP percentage (0-100)
partnerPermanentLockedLiquidityPercentage: number // Partner permanent locked LP percentage (0-100)
partnerLiquidityVestingInfoParams?: {
// Optional partner liquidity vesting (DAMM V2 only)
vestingPercentage: number
bpsPerPeriod: number
numberOfPeriods: number
cliffDurationFromMigrationTime: number
totalDuration: number
}
creatorLiquidityPercentage: number // Creator LP percentage (0-100)
creatorPermanentLockedLiquidityPercentage: number // Creator permanent locked LP percentage (0-100)
creatorLiquidityVestingInfoParams?: {
// Optional creator liquidity vesting (DAMM V2 only)
vestingPercentage: number
bpsPerPeriod: number
numberOfPeriods: number
cliffDurationFromMigrationTime: number
totalDuration: number
}
}
// Locked vesting configuration (set all to 0 for no vesting)
lockedVesting: {
totalLockedVestingAmount: number // The total locked vesting amount
numberOfVestingPeriod: number // The number of vesting periods
cliffUnlockAmount: number // Tokens unlocked when vesting starts
totalVestingDuration: number // Total vesting duration in seconds
cliffDurationFromMigrationTime: number // Wait time before vesting starts in seconds
}
activationType: ActivationType // 0: Slot, 1: Timestamp
// buildCurve-specific parameters:
percentageSupplyOnMigration: number // The percentage of the supply that will be migrated
migrationQuoteThreshold: number // The quote threshold for migration (in quote token units)
}
```
**BaseFeeParams** (used by all `buildCurve*` functions):
```typescript theme={"system"}
// Either FeeSchedulerLinear/FeeSchedulerExponential mode:
type BaseFeeParams =
| {
baseFeeMode:
| BaseFeeMode.FeeSchedulerLinear
| BaseFeeMode.FeeSchedulerExponential
feeSchedulerParam: {
startingFeeBps: number // The starting fee in basis points
endingFeeBps: number // The ending fee in basis points
numberOfPeriod: number // The number of periods
totalDuration: number // The total duration of the fee scheduler
}
}
// OR RateLimiter mode:
| {
baseFeeMode: BaseFeeMode.RateLimiter
rateLimiterParam: {
baseFeeBps: number // The base fee in basis points
feeIncrementBps: number // The fee increment in basis points
referenceAmount: number // The reference amount for rate limiting
maxLimiterDuration: number // The maximum duration for rate limiting
}
}
```
**Returns**
* A `ConfigParameters` object that can be spread into `createConfig`.
**Example**
```typescript theme={"system"}
// Example 1: Simple fixed fee option (no custom migrated pool fee needed)
const curveConfig = buildCurve({
token: {
tokenType: TokenType.SPL,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.NINE,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 500,
endingFeeBps: 100,
numberOfPeriod: 10,
totalDuration: 3600,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 0,
poolCreationFee: 0,
enableFirstSwapWithMinFee: false,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.FixedBps100,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
},
liquidityDistribution: {
partnerLiquidityPercentage: 0,
partnerPermanentLockedLiquidityPercentage: 100,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 0,
},
lockedVesting: {
totalLockedVestingAmount: 0,
numberOfVestingPeriod: 0,
cliffUnlockAmount: 0,
totalVestingDuration: 0,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Timestamp,
percentageSupplyOnMigration: 25,
migrationQuoteThreshold: 1,
})
// Example 2: Customizable with market cap fee scheduler
const curveConfigWithScheduler = buildCurve({
token: {
tokenType: TokenType.Token2022,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.NINE,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 500,
endingFeeBps: 100,
numberOfPeriod: 10,
totalDuration: 3600,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 0,
poolCreationFee: 0,
enableFirstSwapWithMinFee: true,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.FixedBps100, // Will be auto-overridden to Customizable
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
migratedPoolFee: {
collectFeeMode: CollectFeeMode.QuoteToken,
dynamicFee: DammV2DynamicFeeMode.Enabled,
poolFeeBps: 120,
baseFeeMode: DammV2BaseFeeMode.FeeMarketCapSchedulerLinear,
marketCapFeeSchedulerParams: {
endingBaseFeeBps: 25, // Must be less than bonding curve's endingFeeBps (100)
numberOfPeriod: 100,
sqrtPriceStepBps: 10,
schedulerExpirationDuration: 1000000,
},
},
},
liquidityDistribution: {
partnerLiquidityPercentage: 55,
partnerPermanentLockedLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 0,
partnerLiquidityVestingInfoParams: {
vestingPercentage: 30,
bpsPerPeriod: 1000,
cliffDurationFromMigrationTime: 86400,
numberOfPeriods: 10,
totalDuration: 100,
},
creatorLiquidityVestingInfoParams: {
vestingPercentage: 15,
bpsPerPeriod: 1,
cliffDurationFromMigrationTime: 86400,
numberOfPeriods: 10000,
totalDuration: 333333,
},
},
lockedVesting: {
totalLockedVestingAmount: 1000000,
numberOfVestingPeriod: 10,
cliffUnlockAmount: 0,
totalVestingDuration: 10000,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Timestamp,
percentageSupplyOnMigration: 10,
migrationQuoteThreshold: 300,
})
// Use the curve config in createConfig
const transaction = await client.partner.createConfig({
config: configKeypair.publicKey,
feeClaimer: wallet.publicKey,
leftoverReceiver: wallet.publicKey,
payer: wallet.publicKey,
quoteMint: NATIVE_MINT,
...curveConfig,
})
```
**Notes**
* `buildCurve` helps you create a curve structure based on percentage of supply on migration and migration quote threshold.
* If `dynamicFeeEnabled` is true, the dynamic fee will be enabled and capped at 20% of minimum base fee.
* `lockedVesting.totalVestingDuration` and `lockedVesting.cliffDurationFromMigrationTime` are calculated in terms of seconds.
* `feeSchedulerParam.totalDuration` is calculated based on your `activationType` and `activationTime`. Slot is 400ms, Timestamp is 1000ms.
* **Migration Fee Option behavior:**
* **Fixed options (0-5):** Uses default migrated pool fee parameters. Any custom `migratedPoolFee` values are ignored.
* **Customizable (6):** Uses your custom `migratedPoolFee` values. Falls back to defaults for any omitted fields.
* **Auto-override:** When `marketCapFeeSchedulerParams` is configured inside `migratedPoolFee`, the SDK automatically overrides `migrationFeeOption` to `Customizable` regardless of what you set. This is required by the on-chain program.
* When using `marketCapFeeSchedulerParams`:
* `baseFeeMode` must be `DammV2BaseFeeMode.FeeMarketCapSchedulerLinear` (3) or `FeeMarketCapSchedulerExponential` (4).
* `endingBaseFeeBps` must be strictly less than the bonding curve's `baseFeeParams.feeSchedulerParam.endingFeeBps`.
* `poolFeeBps` must be greater than 0.
* For DAMM V1 migration, all `migratedPoolFee` parameters are ignored and defaults are used.
***
### buildCurveWithMarketCap
Builds a new constant product curve with customisable parameters based on market cap. This function does the math for you to create a curve structure based on initial market cap and migration market cap.
**Function**
```typescript theme={"system"}
function buildCurveWithMarketCap(
params: BuildCurveWithMarketCapParams
): ConfigParameters
```
**Parameters**
```typescript theme={"system"}
interface BuildCurveWithMarketCapParams {
// Inherits all fields from BuildCurveBaseParams (token, fee, migration, liquidityDistribution, lockedVesting, activationType)
// See buildCurve for the full BuildCurveBaseParams definition.
token: TokenConfig
fee: FeeConfig
migration: MigrationConfig
liquidityDistribution: LiquidityDistributionConfig
lockedVesting: LockedVestingParams
activationType: ActivationType
// buildCurveWithMarketCap-specific parameters:
initialMarketCap: number // The initial market cap that your token will start with
migrationMarketCap: number // The migration market cap that your token will be at migration
}
```
**Returns**
* A `ConfigParameters` object.
**Example**
```typescript theme={"system"}
const curveConfig = buildCurveWithMarketCap({
token: {
tokenType: TokenType.Token2022,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.NINE,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 120,
endingFeeBps: 120,
numberOfPeriod: 0,
totalDuration: 0,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 0,
poolCreationFee: 0,
enableFirstSwapWithMinFee: true,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.Customizable,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
migratedPoolFee: {
collectFeeMode: CollectFeeMode.QuoteToken,
dynamicFee: DammV2DynamicFeeMode.Enabled,
poolFeeBps: 120,
},
},
liquidityDistribution: {
partnerLiquidityPercentage: 55,
partnerPermanentLockedLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 0,
partnerLiquidityVestingInfoParams: {
vestingPercentage: 30,
bpsPerPeriod: 1000,
cliffDurationFromMigrationTime: 86400,
numberOfPeriods: 10,
totalDuration: 100,
},
creatorLiquidityVestingInfoParams: {
vestingPercentage: 15,
bpsPerPeriod: 1,
cliffDurationFromMigrationTime: 86400,
numberOfPeriods: 10000,
totalDuration: 333333,
},
},
lockedVesting: {
totalLockedVestingAmount: 1000000,
numberOfVestingPeriod: 10,
cliffUnlockAmount: 0,
totalVestingDuration: 10000,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Timestamp,
initialMarketCap: 100,
migrationMarketCap: 3000,
})
const transaction = await client.partner.createConfig({
config: configKeypair.publicKey,
feeClaimer: wallet.publicKey,
leftoverReceiver: wallet.publicKey,
payer: wallet.publicKey,
quoteMint: NATIVE_MINT,
...curveConfig,
})
```
**Notes**
* `buildCurveWithMarketCap` helps you create a curve structure based on initial market cap and migration market cap.
* If `dynamicFeeEnabled` is true, the dynamic fee will be enabled and capped at 20% of minimum base fee.
* `lockedVesting.totalVestingDuration` and `lockedVesting.cliffDurationFromMigrationTime` are in seconds.
* `feeSchedulerParam.totalDuration` is based on your `activationType`. Slot is 400ms, Timestamp is 1000ms.
* See [buildCurve](#buildCurve) notes for details on migration fee option behavior and `marketCapFeeSchedulerParams` constraints.
***
### buildCurveWithTwoSegments
Builds a new constant product curve with two segments. This function does the math for you to create a curve structure based on initial market cap, migration market cap and percentage of supply on migration.
**Function**
```typescript theme={"system"}
function buildCurveWithTwoSegments(
params: BuildCurveWithTwoSegmentsParams
): ConfigParameters
```
**Parameters**
```typescript theme={"system"}
interface BuildCurveWithTwoSegmentsParams {
// Inherits all fields from BuildCurveBaseParams (token, fee, migration, liquidityDistribution, lockedVesting, activationType)
// See buildCurve for the full BuildCurveBaseParams definition.
token: TokenConfig
fee: FeeConfig
migration: MigrationConfig
liquidityDistribution: LiquidityDistributionConfig
lockedVesting: LockedVestingParams
activationType: ActivationType
// buildCurveWithTwoSegments-specific parameters:
initialMarketCap: number // The initial market cap that your token will start with
migrationMarketCap: number // The migration market cap that your token will be at migration
percentageSupplyOnMigration: number // The percentage of the supply that will be migrated
}
```
**Returns**
* A `ConfigParameters` object.
**Example**
```typescript theme={"system"}
const curveConfig = buildCurveWithTwoSegments({
token: {
tokenType: TokenType.Token2022,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.NINE,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 120,
endingFeeBps: 120,
numberOfPeriod: 0,
totalDuration: 0,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 0,
poolCreationFee: 0,
enableFirstSwapWithMinFee: true,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.Customizable,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
migratedPoolFee: {
collectFeeMode: CollectFeeMode.QuoteToken,
dynamicFee: DammV2DynamicFeeMode.Enabled,
poolFeeBps: 120,
},
},
liquidityDistribution: {
partnerLiquidityPercentage: 55,
partnerPermanentLockedLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 0,
},
lockedVesting: {
totalLockedVestingAmount: 0,
numberOfVestingPeriod: 0,
cliffUnlockAmount: 0,
totalVestingDuration: 0,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Timestamp,
initialMarketCap: 5000,
migrationMarketCap: 1000000,
percentageSupplyOnMigration: 10,
})
const transaction = await client.partner.createConfig({
config: configKeypair.publicKey,
feeClaimer: wallet.publicKey,
leftoverReceiver: wallet.publicKey,
payer: wallet.publicKey,
quoteMint: NATIVE_MINT,
...curveConfig,
})
```
**Notes**
* `buildCurveWithTwoSegments` helps you create a curve structure based on initial market cap, migration market cap and percentage of supply on migration.
* If `dynamicFeeEnabled` is true, the dynamic fee will be enabled and capped at 20% of minimum base fee.
* `lockedVesting.totalVestingDuration` and `lockedVesting.cliffDurationFromMigrationTime` are in seconds.
* `feeSchedulerParam.totalDuration` is based on your `activationType`. Slot is 400ms, Timestamp is 1000ms.
* See [buildCurve](#buildCurve) notes for details on migration fee option behavior and `marketCapFeeSchedulerParams` constraints.
***
### buildCurveWithMidPrice
Builds a custom constant product curve with a mid price. This will create a two segment curve with a start price -> mid price, and a mid price -> migration price.
**Function**
```typescript theme={"system"}
function buildCurveWithMidPrice(
params: BuildCurveWithMidPriceParams
): ConfigParameters
```
**Parameters**
```typescript theme={"system"}
interface BuildCurveWithMidPriceParams {
// Inherits all fields from BuildCurveBaseParams (token, fee, migration, liquidityDistribution, lockedVesting, activationType)
// See buildCurve for the full BuildCurveBaseParams definition.
token: TokenConfig
fee: FeeConfig
migration: MigrationConfig
liquidityDistribution: LiquidityDistributionConfig
lockedVesting: LockedVestingParams
activationType: ActivationType
// buildCurveWithMidPrice-specific parameters:
initialMarketCap: number // The initial market cap
migrationMarketCap: number // The migration market cap
midPrice: number // The mid price where the curve segments
percentageSupplyOnMigration: number // The percentage of the supply that will be migrated
}
```
**Returns**
* A `ConfigParameters` object.
**Example**
```typescript theme={"system"}
const curveConfig = buildCurveWithMidPrice({
token: {
tokenType: TokenType.Token2022,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.NINE,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 120,
endingFeeBps: 120,
numberOfPeriod: 0,
totalDuration: 0,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 0,
poolCreationFee: 0,
enableFirstSwapWithMinFee: true,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.Customizable,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
migratedPoolFee: {
collectFeeMode: CollectFeeMode.QuoteToken,
dynamicFee: DammV2DynamicFeeMode.Enabled,
poolFeeBps: 120,
},
},
liquidityDistribution: {
partnerLiquidityPercentage: 55,
partnerPermanentLockedLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 0,
},
lockedVesting: {
totalLockedVestingAmount: 0,
numberOfVestingPeriod: 0,
cliffUnlockAmount: 0,
totalVestingDuration: 0,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Timestamp,
initialMarketCap: 5000,
migrationMarketCap: 1000000,
midPrice: 141.75,
percentageSupplyOnMigration: 20,
})
const transaction = await client.partner.createConfig({
config: configKeypair.publicKey,
feeClaimer: wallet.publicKey,
leftoverReceiver: wallet.publicKey,
payer: wallet.publicKey,
quoteMint: NATIVE_MINT,
...curveConfig,
})
```
**Notes**
* `buildCurveWithMidPrice` helps you create a curve structure based on initial market cap, migration market cap and mid price.
* What does mid price do?
* The `midPrice` is the price at which the curve will be segmented into two parts between the start price and the migration price.
* The `percentageSupplyOnMigration` is the percentage of the supply that will be migrated.
* If `dynamicFeeEnabled` is true, the dynamic fee will be enabled and capped at 20% of minimum base fee.
* `lockedVesting.totalVestingDuration` and `lockedVesting.cliffDurationFromMigrationTime` are in seconds.
* `feeSchedulerParam.totalDuration` is based on your `activationType`. Slot is 400ms, Timestamp is 1000ms.
* See [buildCurve](#buildCurve) notes for details on migration fee option behavior and `marketCapFeeSchedulerParams` constraints.
***
### buildCurveWithLiquidityWeights
Builds a super customizable constant product curve graph configuration based on different liquidity weights. This function does the math for you to create a curve structure based on initial market cap, migration market cap and liquidity weights.
**Function**
```typescript theme={"system"}
function buildCurveWithLiquidityWeights(
params: BuildCurveWithLiquidityWeightsParams
): ConfigParameters
```
**Parameters**
```typescript theme={"system"}
interface BuildCurveWithLiquidityWeightsParams {
// Inherits all fields from BuildCurveBaseParams (token, fee, migration, liquidityDistribution, lockedVesting, activationType)
// See buildCurve for the full BuildCurveBaseParams definition.
token: TokenConfig
fee: FeeConfig
migration: MigrationConfig
liquidityDistribution: LiquidityDistributionConfig
lockedVesting: LockedVestingParams
activationType: ActivationType
// buildCurveWithLiquidityWeights-specific parameters:
initialMarketCap: number // The initial market cap
migrationMarketCap: number // The migration market cap
liquidityWeights: number[] // The liquidity weights for each segment (max 16 elements)
}
```
**Returns**
* A `ConfigParameters` object.
**Example**
```typescript theme={"system"}
let liquidityWeights: number[] = []
for (let i = 0; i < 16; i++) {
liquidityWeights[i] = new Decimal(1.2).pow(new Decimal(i)).toNumber()
}
const curveConfig = buildCurveWithLiquidityWeights({
token: {
tokenType: TokenType.Token2022,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.NINE,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 120,
endingFeeBps: 120,
numberOfPeriod: 0,
totalDuration: 0,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 0,
poolCreationFee: 0,
enableFirstSwapWithMinFee: true,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.Customizable,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
migratedPoolFee: {
collectFeeMode: CollectFeeMode.QuoteToken,
dynamicFee: DammV2DynamicFeeMode.Enabled,
poolFeeBps: 120,
},
},
liquidityDistribution: {
partnerLiquidityPercentage: 55,
partnerPermanentLockedLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 0,
},
lockedVesting: {
totalLockedVestingAmount: 0,
numberOfVestingPeriod: 0,
cliffUnlockAmount: 0,
totalVestingDuration: 0,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Timestamp,
initialMarketCap: 5000,
migrationMarketCap: 1000000,
liquidityWeights,
})
const transaction = await client.partner.createConfig({
config: configKeypair.publicKey,
feeClaimer: wallet.publicKey,
leftoverReceiver: wallet.publicKey,
payer: wallet.publicKey,
quoteMint: NATIVE_MINT,
...curveConfig,
})
```
**Notes**
* `buildCurveWithLiquidityWeights` helps you create a curve structure based on initial market cap, migration market cap and liquidity weights.
* What does liquidity weights do?
* The `liquidityWeights` is an array of numbers that determines how liquidity is distributed across the curve's price ranges.
* The maximum number of liquidity weights\[i] is `16`.
* Each element in the array represents the liquidity weight for a specific curve segment (total `16` curve segments).
* For each segment of the curve, the liquidity is scaled by liquidityWeights\[i] (where `i` is the liquidityWeight index).
* This means that as you move along the curve (from lower to higher price ranges), the liquidity in each curve segment can be controlled.
* Effects of changing liquidity weights
1. `All liquidityWeights[i] === 1`: All segments have the same liquidity. The curve is linear.
2. `liquidityWeights[i] < liquidityWeights[i+1]`: Lower liquidity at lower prices. Price moves more at lower prices and less at higher prices.
3. `liquidityWeights[i] > liquidityWeights[i+1]`: Higher liquidity at lower prices. Price moves less at lower prices and more at higher prices.
* If `dynamicFeeEnabled` is true, the dynamic fee will be enabled and capped at 20% of minimum base fee.
* `lockedVesting.totalVestingDuration` and `lockedVesting.cliffDurationFromMigrationTime` are in seconds.
* `feeSchedulerParam.totalDuration` is based on your `activationType`. Slot is 400ms, Timestamp is 1000ms.
* See [buildCurve](#buildCurve) notes for details on migration fee option behavior and `marketCapFeeSchedulerParams` constraints.
***
### buildCurveWithCustomSqrtPrices
Builds a super customizable constant product curve graph configuration based on custom sqrt prices. This function does the math for you to create a curve structure based on custom sqrt prices and optional liquidity weights.
**Function**
```typescript theme={"system"}
function buildCurveWithCustomSqrtPrices(
params: BuildCurveWithCustomSqrtPricesParams
): ConfigParameters
```
**Parameters**
```typescript theme={"system"}
interface BuildCurveWithCustomSqrtPricesParams {
// Inherits all fields from BuildCurveBaseParams (token, fee, migration, liquidityDistribution, lockedVesting, activationType)
// See buildCurve for the full BuildCurveBaseParams definition.
token: TokenConfig
fee: FeeConfig
migration: MigrationConfig
liquidityDistribution: LiquidityDistributionConfig
lockedVesting: LockedVestingParams
activationType: ActivationType
// buildCurveWithCustomSqrtPrices-specific parameters:
sqrtPrices: BN[] // Array of custom sqrt prices (must be in ascending order, min 2 elements)
liquidityWeights?: number[] // Optional weights for each segment. Length must be sqrtPrices.length - 1. If not provided, liquidity is distributed evenly.
}
```
**Returns**
* A `ConfigParameters` object.
**Example**
```typescript theme={"system"}
const customPrices = [0.000001, 0.00000105, 0.000002, 0.001]
const tokenBaseDecimal = TokenDecimal.SIX
const tokenQuoteDecimal = TokenDecimal.SIX
// convert prices to sqrtPrices
const sqrtPrices = createSqrtPrices(
customPrices,
tokenBaseDecimal,
tokenQuoteDecimal
)
// define custom liquidity weights for custom segments (optional)
// length must be sqrtPrices.length - 1, or leave undefined for even distribution
const liquidityWeights = [2, 1, 1]
const curveConfig = buildCurveWithCustomSqrtPrices({
token: {
tokenType: TokenType.Token2022,
tokenBaseDecimal: TokenDecimal.SIX,
tokenQuoteDecimal: TokenDecimal.SIX,
tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable,
totalTokenSupply: 1_000_000_000,
leftover: 0,
},
fee: {
baseFeeParams: {
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
feeSchedulerParam: {
startingFeeBps: 120,
endingFeeBps: 120,
numberOfPeriod: 0,
totalDuration: 0,
},
},
dynamicFeeEnabled: true,
collectFeeMode: CollectFeeMode.QuoteToken,
creatorTradingFeePercentage: 0,
poolCreationFee: 0,
enableFirstSwapWithMinFee: true,
},
migration: {
migrationOption: MigrationOption.MET_DAMM_V2,
migrationFeeOption: MigrationFeeOption.Customizable,
migrationFee: { feePercentage: 0, creatorFeePercentage: 0 },
migratedPoolFee: {
collectFeeMode: CollectFeeMode.QuoteToken,
dynamicFee: DammV2DynamicFeeMode.Enabled,
poolFeeBps: 120,
},
},
liquidityDistribution: {
partnerLiquidityPercentage: 55,
partnerPermanentLockedLiquidityPercentage: 0,
creatorLiquidityPercentage: 0,
creatorPermanentLockedLiquidityPercentage: 0,
},
lockedVesting: {
totalLockedVestingAmount: 0,
numberOfVestingPeriod: 0,
cliffUnlockAmount: 0,
totalVestingDuration: 0,
cliffDurationFromMigrationTime: 0,
},
activationType: ActivationType.Timestamp,
sqrtPrices,
liquidityWeights,
})
const transaction = await client.partner.createConfig({
config: configKeypair.publicKey,
feeClaimer: wallet.publicKey,
leftoverReceiver: wallet.publicKey,
payer: wallet.publicKey,
quoteMint: NATIVE_MINT,
...curveConfig,
})
```
**Notes**
* `buildCurveWithCustomSqrtPrices` helps you create a curve structure based on custom sqrt prices and optional liquidity weights.
* What does sqrt prices do?
* The `sqrtPrices` is an array of BN values representing the sqrt prices of the curve segments.
* The length of the `sqrtPrices` array must be at least 2.
* The first price will be the starting price (pMin) and the last price will be the migration price (pMax).
* The prices must be in ascending order.
* Use `createSqrtPrices()` helper to convert regular prices to sqrt prices.
* What does liquidity weights do?
* The `liquidityWeights` is an array of numbers that determines how liquidity is distributed across the curve's price ranges.
* The maximum number of liquidity weights\[i] is `16`.
* Each element in the array represents the liquidity weight for a specific curve segment.
* If not provided, liquidity is distributed evenly across all segments.
* The length of the `liquidityWeights` array must be `sqrtPrices.length - 1`.
* Effects of changing liquidity weights
1. `All liquidityWeights[i] === 1`: All segments have the same liquidity. The curve is linear.
2. `liquidityWeights[i] < liquidityWeights[i+1]`: Lower liquidity at lower prices. Price moves more at lower prices and less at higher prices.
3. `liquidityWeights[i] > liquidityWeights[i+1]`: Higher liquidity at lower prices. Price moves less at lower prices and more at higher prices.
* If `dynamicFeeEnabled` is true, the dynamic fee will be enabled and capped at 20% of minimum base fee.
* `lockedVesting.totalVestingDuration` and `lockedVesting.cliffDurationFromMigrationTime` are in seconds.
* `feeSchedulerParam.totalDuration` is based on your `activationType`. Slot is 400ms, Timestamp is 1000ms.
* See [buildCurve](#buildCurve) notes for details on migration fee option behavior and `marketCapFeeSchedulerParams` constraints.
***
## Pool Functions
### createPool
Creates a new pool with the config key.
**Function**
```typescript theme={"system"}
async createPool(params: CreatePoolParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreatePoolParams {
baseMint: PublicKey // The base mint address (generated by you)
config: PublicKey // The config account address
name: string // The name of the pool
symbol: string // The symbol of the pool
uri: string // The uri of the pool
payer: PublicKey // The payer of the transaction
poolCreator: PublicKey // The pool creator of the transaction
}
```
**Returns**
* A transaction that requires signatures from the payer, the baseMint keypair, and the poolCreator before being submitted to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.pool.createPool({
baseMint: new PublicKey('0987654321zyxwvutsrqponmlkjihgfedcba'),
config: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
name: 'Meteora',
symbol: 'MET',
uri: 'https://launch.meteora.ag',
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
poolCreator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The payer must be the same as the payer in the `CreatePoolParam` params.
* The poolCreator is required to sign when creating the pool.
* The baseMint token type must be the same as the config key's token type.
***
### createConfigAndPool
Creates a config key and a token pool in a single transaction.
**Function**
```typescript theme={"system"}
async createConfigAndPool(params: CreateConfigAndPoolParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreateConfigAndPoolParams {
payer: PublicKey // The wallet paying for the transaction
config: PublicKey // The config account address (generated by the partner)
feeClaimer: PublicKey // The wallet that will be able to claim the fee
leftoverReceiver: PublicKey // The wallet that will receive the bonding curve leftover
quoteMint: PublicKey // The quote mint address
poolFees: {
baseFee: {
cliffFeeNumerator: BN // Initial fee numerator (base fee)
firstFactor: number // feeScheduler: numberOfPeriod, rateLimiter: feeIncrementBps
secondFactor: BN // feeScheduler: periodFrequency, rateLimiter: maxLimiterDuration
thirdFactor: BN // feeScheduler: reductionFactor, rateLimiter: referenceAmount
baseFeeMode: number // 0: FeeSchedulerLinear, 1: FeeSchedulerExponential, 2: RateLimiter
}
dynamicFee: {
// Optional dynamic fee
binStep: number // u16 value representing the bin step in bps
binStepU128: BN // u128 value for a more accurate bin step
filterPeriod: number // Minimum time that must pass between fee updates
decayPeriod: number // Period after the volatility starts decaying (must be > filterPeriod)
reductionFactor: number // Controls how quickly volatility decys over time
variableFeeControl: number // Multiplier that determines how much volatility affects fees
maxVolatilityAccumulator: number // Caps the maximum volatility that can be accumulated
} | null
}
collectFeeMode: number // 0: QuoteToken, 1: OutputToken
migrationOption: number // 0: DAMM V1, 1: DAMM v2
activationType: number // 0: Slot, 1: Timestamp
tokenType: number // 0: SPL, 1: Token2022
tokenDecimal: number // The number of decimals for the token
partnerLiquidityPercentage: number // The percentage of the LP that will be allocated to the partner in the graduated pool (0-100)
partnerPermanentLockedLiquidityPercentage: number // The percentage of the locked LP that will be allocated to the partner in the graduated pool (0-100)
creatorLiquidityPercentage: number // The percentage of the LP that will be allocated to the creator in the graduated pool (0-100)
creatorPermanentLockedLiquidityPercentage: number // The percentage of the locked LP that will be allocated to the creator in the graduated pool (0-100)
migrationQuoteThreshold: BN // The quote threshold for migration
sqrtStartPrice: BN // The starting price of the pool
lockedVesting: {
// Optional locked vesting (BN (0) for all fields for no vesting)
amountPerPeriod: BN // The amount of tokens that will be vested per period
cliffDurationFromMigrationTime: BN // The duration of the waiting time before the vesting starts
frequency: BN // The frequency of the vesting
numberOfPeriod: BN // The number of periods of the vesting
cliffUnlockAmount: BN // The amount of tokens that will be unlocked when vesting starts
}
migrationFeeOption: number // 0: Fixed 25bps, 1: Fixed 30bps, 2: Fixed 100bps, 3: Fixed 200bps, 4: Fixed 400bps, 5: Fixed 600bps, 6: Customizable (only for DAMM v2)
tokenSupply: {
// Optional token supply
preMigrationTokenSupply: BN // The token supply before migration
postMigrationTokenSupply: BN // The token supply after migration
} | null
creatorTradingFeePercentage: number // The percentage of the trading fee that will be allocated to the creator
tokenUpdateAuthority: number // 0 - CreatorUpdateAuthority, 1 - Immutable, 2 - PartnerUpdateAuthority, 3 - CreatorUpdateAndMintAuthority, 4 - PartnerUpdateAndMintAuthority
migrationFee: {
// Optional migration fee (set as 0 for feePercentage and creatorFeePercentage for no migration fee)
feePercentage: number // The percentage of fee taken from migration quote threshold (0-99)
creatorFeePercentage: number // The fee share percentage for the creator from the migration fee (0-100)
}
migratedPoolFee: {
// Only when migrationOption = MET_DAMM_V2 (1) and migrationFeeOption = Customizable (6)
collectFeeMode: number // 0: QuoteToken, 1: OutputToken
dynamicFee: number // 0: Disabled, 1: Enabled
poolFeeBps: number // The pool fee in basis points. Minimum 10, Maximum 1000 bps.
}
migratedPoolBaseFeeMode: number // 0: FeeTimeSchedulerLinear, 1: FeeTimeSchedulerExponential, 3: FeeMarketCapSchedulerLinear, 4: FeeMarketCapSchedulerExponential (defaults to FeeTimeSchedulerLinear)
migratedPoolMarketCapFeeSchedulerParams: {
// Defaults to all 0. Configure only when migratedPoolBaseFeeMode = FeeMarketCapSchedulerLinear or FeeMarketCapSchedulerExponential
numberOfPeriod: number // The number of periods
sqrtPriceStepBps: number // The square root price step in basis points
schedulerExpirationDuration: number // The scheduler expiration duration in seconds
reductionFactor: BN // The reduction factor
}
enableFirstSwapWithMinFee: boolean // Whether to enable first swap with minimum fee (defaults to false)
poolCreationFee: BN // The pool creation fee
partnerLiquidityVestingInfo: {
vestingPercentage: number // The percentage of the liquidity that will be vested
bpsPerPeriod: number // The basis points per period
numberOfPeriods: number // The number of periods
cliffDurationFromMigrationTime: number // The duration of the waiting time before the vesting starts
frequency: number // The frequency of the vesting
}
creatorLiquidityVestingInfo: {
vestingPercentage: number // The percentage of the liquidity that will be vested
bpsPerPeriod: number // The basis points per period
numberOfPeriods: number // The number of periods
cliffDurationFromMigrationTime: number // The duration of the waiting time before the vesting starts
frequency: number // The frequency of the vesting
}
padding: []
curve: {
// The curve of the pool
sqrtPrice: BN // The square root of the curve point price
liquidity: BN // The liquidity of the curve point
}[]
preCreatePoolParam: {
baseMint: PublicKey // The base mint address (generated by you)
name: string // The name of the pool
symbol: string // The symbol of the pool
uri: string // The uri of the pool
poolCreator: PublicKey // The pool creator of the transaction
}
}
```
**Returns**
* A transaction that requires signatures from the payer, the baseMint keypair, and the config keypair before being submitted to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.pool.createConfigAndPool({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
config: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
feeClaimer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
leftoverReceiver: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
quoteMint: new PublicKey('So11111111111111111111111111111111111111112'),
poolFees: {
baseFee: {
cliffFeeNumerator: new BN('25000000'),
firstFactor: 0,
secondFactor: new BN('0'),
thirdFactor: new BN('0'),
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
},
dynamicFee: {
binStep: 1,
binStepU128: new BN('1844674407370955'),
filterPeriod: 10,
decayPeriod: 120,
reductionFactor: 1000,
variableFeeControl: 100000,
maxVolatilityAccumulator: 100000,
},
},
activationType: 0,
collectFeeMode: 0,
migrationOption: 0,
tokenType: 0,
tokenDecimal: 9,
migrationQuoteThreshold: new BN('1000000000'),
partnerLiquidityPercentage: 25,
creatorLiquidityPercentage: 25,
partnerPermanentLockedLiquidityPercentage: 25,
creatorPermanentLockedLiquidityPercentage: 25,
sqrtStartPrice: new BN('58333726687135158'),
lockedVesting: {
amountPerPeriod: new BN('0'),
cliffDurationFromMigrationTime: new BN('0'),
frequency: new BN('0'),
numberOfPeriod: new BN('0'),
cliffUnlockAmount: new BN('0'),
},
migrationFeeOption: 0,
tokenSupply: null,
creatorTradingFeePercentage: 0,
tokenUpdateAuthority: 0,
migrationFee: {
feePercentage: 25,
creatorFeePercentage: 50,
},
poolCreationFee: new BN(1_000_000_000),
creatorLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
frequency: 0,
cliffDurationFromMigrationTime: 0,
},
partnerLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
frequency: 0,
cliffDurationFromMigrationTime: 0,
},
migratedPoolBaseFeeMode: DammV2BaseFeeMode.FeeTimeSchedulerLinear,
migratedPoolMarketCapFeeSchedulerParams: {
numberOfPeriod: 0,
sqrtPriceStepBps: 0,
schedulerExpirationDuration: 0,
reductionFactor: new BN('0'),
},
padding: [],
curve: [
{
sqrtPrice: new BN('233334906748540631'),
liquidity: new BN('622226417996106429201027821619672729'),
},
{
sqrtPrice: new BN('79226673521066979257578248091'),
liquidity: new BN('1'),
},
],
enableFirstSwapWithMinFee: false,
migratedPoolFee: {
dynamicFee: 0,
poolFeeBps: 0,
collectFeeMode: 0,
},
preCreatePoolParam: {
baseMint: new PublicKey('0987654321zyxwvutsrqponmlkjihgfedcba'),
name: 'Meteora',
symbol: 'MET',
uri: 'https://launch.meteora.ag/icons/logo.svg',
poolCreator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
},
})
```
**Notes**
* The payer must be the same as the payer in the `CreateConfigAndPoolParam` params.
* The poolCreator is required to sign when creating the pool.
* The baseMint token type must be the same as the config key's token type.
* You can use any of the build curve functions to create the curve configuration.
***
### createConfigAndPoolWithFirstBuy
Creates a config key and a token pool and buys the token immediately.
**Function**
```typescript theme={"system"}
async createConfigAndPoolWithFirstBuy(params: CreateConfigAndPoolWithFirstBuyParams): Promise<{
createConfigTx: Transaction
createPoolTx: Transaction
}>
```
**Parameters**
```typescript theme={"system"}
interface CreateConfigAndPoolWithFirstBuyParams {
payer: PublicKey // The wallet paying for the transaction
config: PublicKey // The config account address (generated by the partner)
feeClaimer: PublicKey // The wallet that will be able to claim the fee
leftoverReceiver: PublicKey // The wallet that will receive the bonding curve leftover
quoteMint: PublicKey // The quote mint address
poolFees: {
baseFee: {
cliffFeeNumerator: BN // Initial fee numerator (base fee)
firstFactor: number // feeScheduler: numberOfPeriod, rateLimiter: feeIncrementBps
secondFactor: BN // feeScheduler: periodFrequency, rateLimiter: maxLimiterDuration
thirdFactor: BN // feeScheduler: reductionFactor, rateLimiter: referenceAmount
baseFeeMode: number // 0: FeeSchedulerLinear, 1: FeeSchedulerExponential, 2: RateLimiter
}
dynamicFee: {
// Optional dynamic fee
binStep: number // u16 value representing the bin step in bps
binStepU128: BN // u128 value for a more accurate bin step
filterPeriod: number // Minimum time that must pass between fee updates
decayPeriod: number // Period after the volatility starts decaying (must be > filterPeriod)
reductionFactor: number // Controls how quickly volatility decys over time
variableFeeControl: number // Multiplier that determines how much volatility affects fees
maxVolatilityAccumulator: number // Caps the maximum volatility that can be accumulated
} | null
}
collectFeeMode: number // 0: QuoteToken, 1: OutputToken
migrationOption: number // 0: DAMM V1, 1: DAMM v2
activationType: number // 0: Slot, 1: Timestamp
tokenType: number // 0: SPL, 1: Token2022
tokenDecimal: number // The number of decimals for the token
partnerLiquidityPercentage: number // The percentage of the LP that will be allocated to the partner in the graduated pool (0-100)
partnerPermanentLockedLiquidityPercentage: number // The percentage of the locked LP that will be allocated to the partner in the graduated pool (0-100)
creatorLiquidityPercentage: number // The percentage of the LP that will be allocated to the creator in the graduated pool (0-100)
creatorPermanentLockedLiquidityPercentage: number // The percentage of the locked LP that will be allocated to the creator in the graduated pool (0-100)
migrationQuoteThreshold: BN // The quote threshold for migration
sqrtStartPrice: BN // The starting price of the pool
lockedVesting: {
// Optional locked vesting (BN (0) for all fields for no vesting)
amountPerPeriod: BN // The amount of tokens that will be vested per period
cliffDurationFromMigrationTime: BN // The duration of the waiting time before the vesting starts
frequency: BN // The frequency of the vesting
numberOfPeriod: BN // The number of periods of the vesting
cliffUnlockAmount: BN // The amount of tokens that will be unlocked when vesting starts
}
migrationFeeOption: number // 0: Fixed 25bps, 1: Fixed 30bps, 2: Fixed 100bps, 3: Fixed 200bps, 4: Fixed 400bps, 5: Fixed 600bps, 6: Customizable (only for DAMM v2)
tokenSupply: {
// Optional token supply
preMigrationTokenSupply: BN // The token supply before migration
postMigrationTokenSupply: BN // The token supply after migration
} | null
creatorTradingFeePercentage: number // The percentage of the trading fee that will be allocated to the creator
tokenUpdateAuthority: number // 0 - CreatorUpdateAuthority, 1 - Immutable, 2 - PartnerUpdateAuthority, 3 - CreatorUpdateAndMintAuthority, 4 - PartnerUpdateAndMintAuthority
migrationFee: {
// Optional migration fee (set as 0 for feePercentage and creatorFeePercentage for no migration fee)
feePercentage: number // The percentage of fee taken from migration quote threshold (0-99)
creatorFeePercentage: number // The fee share percentage for the creator from the migration fee (0-100)
}
migratedPoolFee: {
// Only when migrationOption = MET_DAMM_V2 (1) and migrationFeeOption = Customizable (6)
collectFeeMode: number // 0: QuoteToken, 1: OutputToken
dynamicFee: number // 0: Disabled, 1: Enabled
poolFeeBps: number // The pool fee in basis points. Minimum 10, Maximum 1000 bps.
}
migratedPoolBaseFeeMode: number // 0: FeeTimeSchedulerLinear, 1: FeeTimeSchedulerExponential, 3: FeeMarketCapSchedulerLinear, 4: FeeMarketCapSchedulerExponential (defaults to FeeTimeSchedulerLinear)
migratedPoolMarketCapFeeSchedulerParams: {
// Defaults to all 0. Configure only when migratedPoolBaseFeeMode = FeeMarketCapSchedulerLinear or FeeMarketCapSchedulerExponential
numberOfPeriod: number // The number of periods
sqrtPriceStepBps: number // The square root price step in basis points
schedulerExpirationDuration: number // The scheduler expiration duration in seconds
reductionFactor: BN // The reduction factor
}
enableFirstSwapWithMinFee: boolean // Whether to enable first swap with minimum fee (defaults to false)
poolCreationFee: BN // The pool creation fee
partnerLiquidityVestingInfo: {
vestingPercentage: number // The percentage of the liquidity that will be vested
bpsPerPeriod: number // The basis points per period
numberOfPeriods: number // The number of periods
cliffDurationFromMigrationTime: number // The duration of the waiting time before the vesting starts
frequency: number // The frequency of the vesting
}
creatorLiquidityVestingInfo: {
vestingPercentage: number // The percentage of the liquidity that will be vested
bpsPerPeriod: number // The basis points per period
numberOfPeriods: number // The number of periods
cliffDurationFromMigrationTime: number // The duration of the waiting time before the vesting starts
frequency: number // The frequency of the vesting
}
padding: []
curve: {
// The curve of the pool
sqrtPrice: BN // The square root of the curve point price
liquidity: BN // The liquidity of the curve point
}[]
preCreatePoolParam: {
baseMint: PublicKey // The base mint address (generated by you)
name: string // The name of the pool
symbol: string // The symbol of the pool
uri: string // The uri of the pool
poolCreator: PublicKey // The pool creator of the transaction
}
firstBuyParam?: {
// Optional first buy param
buyer: PublicKey // The buyer of the transaction
receiver?: PublicKey // Optional: The receiver of the transaction
buyAmount: BN // The amount of tokens to buy
minimumAmountOut: BN // The minimum amount of tokens to receive
referralTokenAccount: PublicKey | null // The referral token account (optional)
}
}
```
**Returns**
An object of transactions containing:
* `createConfigTx`: config creation transaction
* `createPoolTx`: pool creation transaction, with first-buy instructions included when `firstBuyParam` is provided and `buyAmount > 0`
**Example**
```typescript theme={"system"}
const amountIn = await prepareSwapAmountParam(1, NATIVE_MINT, connection)
const transactions = await client.pool.createConfigAndPoolWithFirstBuy({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
config: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
feeClaimer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
leftoverReceiver: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
quoteMint: new PublicKey('So11111111111111111111111111111111111111112'),
poolFees: {
baseFee: {
cliffFeeNumerator: new BN('25000000'),
firstFactor: 0,
secondFactor: new BN('0'),
thirdFactor: new BN('0'),
baseFeeMode: BaseFeeMode.FeeSchedulerLinear,
},
dynamicFee: {
binStep: 1,
binStepU128: new BN('1844674407370955'),
filterPeriod: 10,
decayPeriod: 120,
reductionFactor: 1000,
variableFeeControl: 100000,
maxVolatilityAccumulator: 100000,
},
},
activationType: 0,
collectFeeMode: 0,
migrationOption: 0,
tokenType: 0,
tokenDecimal: 9,
migrationQuoteThreshold: new BN('1000000000'),
partnerLiquidityPercentage: 25,
creatorLiquidityPercentage: 25,
partnerPermanentLockedLiquidityPercentage: 25,
creatorPermanentLockedLiquidityPercentage: 25,
sqrtStartPrice: new BN('58333726687135158'),
lockedVesting: {
amountPerPeriod: new BN('0'),
cliffDurationFromMigrationTime: new BN('0'),
frequency: new BN('0'),
numberOfPeriod: new BN('0'),
cliffUnlockAmount: new BN('0'),
},
migrationFeeOption: 0,
tokenSupply: null,
creatorTradingFeePercentage: 0,
tokenUpdateAuthority: 0,
migrationFee: {
feePercentage: 25,
creatorFeePercentage: 50,
},
poolCreationFee: new BN(1_000_000_000),
creatorLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
frequency: 0,
cliffDurationFromMigrationTime: 0,
},
partnerLiquidityVestingInfo: {
vestingPercentage: 0,
bpsPerPeriod: 0,
numberOfPeriods: 0,
frequency: 0,
cliffDurationFromMigrationTime: 0,
},
migratedPoolBaseFeeMode: DammV2BaseFeeMode.FeeTimeSchedulerLinear,
migratedPoolMarketCapFeeSchedulerParams: {
numberOfPeriod: 0,
sqrtPriceStepBps: 0,
schedulerExpirationDuration: 0,
reductionFactor: new BN('0'),
},
padding: [],
curve: [
{
sqrtPrice: new BN('233334906748540631'),
liquidity: new BN('622226417996106429201027821619672729'),
},
{
sqrtPrice: new BN('79226673521066979257578248091'),
liquidity: new BN('1'),
},
],
enableFirstSwapWithMinFee: false,
migratedPoolFee: {
dynamicFee: 0,
poolFeeBps: 0,
collectFeeMode: 0,
},
preCreatePoolParam: {
baseMint: new PublicKey('0987654321zyxwvutsrqponmlkjihgfedcba'),
name: 'Meteora',
symbol: 'MET',
uri: 'https://launch.meteora.ag/icons/logo.svg',
poolCreator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
},
firstBuyParam: {
buyer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
buyAmount: amountIn,
minimumAmountOut: new BN(1),
referralTokenAccount: null,
},
})
```
**Notes**
* The payer must be the same as the payer in the `CreateConfigAndPoolWithFirstBuyParam` params.
* The `createConfigTx` requires the payer and config to sign the transaction.
* The `createPoolTx` requires the payer, poolCreator, and baseMint to sign the transaction. If `firstBuyParam` is provided, it also requires buyer/payer signatures for the appended first-buy instructions.
* If the `firstBuyParam` is not provided, `createPoolTx` includes only pool-creation instructions.
* The `receiver` parameter is an optional account. If provided, the token will be sent to the receiver address.
***
### createPoolWithFirstBuy
Creates a new pool with the config key and buys the token immediately.
**Function**
```typescript theme={"system"}
async createPoolWithFirstBuy(params: CreatePoolWithFirstBuyParams): Promise<{
createPoolTx: Transaction
}>
```
**Parameters**
```typescript theme={"system"}
interface CreatePoolWithFirstBuyParams {
createPoolParam: {
baseMint: PublicKey // The base mint address (generated by you)
config: PublicKey // The config account address
name: string // The name of the pool
symbol: string // The symbol of the pool
uri: string // The uri of the pool
payer: PublicKey // The payer of the transaction
poolCreator: PublicKey // The pool creator of the transaction
}
firstBuyParam?: {
// Optional first buy param
buyer: PublicKey // The buyer of the transaction
receiver?: PublicKey // Optional: The receiver of the transaction
buyAmount: BN // The amount of tokens to buy
minimumAmountOut: BN // The minimum amount of tokens to receive
referralTokenAccount: PublicKey | null // The referral token account (optional)
}
}
```
**Returns**
An object containing `createPoolTx`, where first-buy instructions are included when `firstBuyParam` is provided and `buyAmount > 0`.
**Example**
```typescript theme={"system"}
const amountIn = await prepareSwapAmountParam(1, NATIVE_MINT, connection)
const transaction = await client.pool.createPoolWithFirstBuy({
createPoolParam: {
baseMint: new PublicKey('0987654321zyxwvutsrqponmlkjihgfedcba'),
config: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
name: 'Meteora',
symbol: 'MET',
uri: 'https://launch.meteora.ag/icons/logo.svg',
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
poolCreator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
},
firstBuyParam: {
buyer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
buyAmount: amountIn,
minimumAmountOut: new BN(1),
referralTokenAccount: null,
},
})
```
**Notes**
* The `poolCreator` is required to sign when creating the pool.
* The `buyer` is required to sign when `firstBuyParam` is provided.
* The `baseMint` token type must be the same as the config key's token type.
* The `minimumAmountOut` parameter protects against slippage. Set it to a value slightly lower than the expected output.
* The `referralTokenAccount` parameter is an optional token account. If provided, the referral fee will be applied to the transaction.
* The `receiver` parameter is an optional account. If provided, the token will be sent to the receiver address.
***
### createPoolWithPartnerAndCreatorFirstBuy
Creates a new pool with the config key and buys the token immediately with partner and creator.
**Function**
```typescript theme={"system"}
async createPoolWithPartnerAndCreatorFirstBuy(params: CreatePoolWithPartnerAndCreatorFirstBuyParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreatePoolWithPartnerAndCreatorFirstBuyParams {
createPoolParam: {
baseMint: PublicKey // The base mint address (generated by you)
config: PublicKey // The config account address
name: string // The name of the pool
symbol: string // The symbol of the pool
uri: string // The uri of the pool
payer: PublicKey // The payer of the transaction
poolCreator: PublicKey // The pool creator of the transaction
}
partnerFirstBuyParam?: {
// Optional partner first buy param
partner: PublicKey // The launchpad partner
receiver: PublicKey // The receiver of the transaction
buyAmount: BN // The amount of tokens to buy
minimumAmountOut: BN // The minimum amount of tokens to receive
referralTokenAccount: PublicKey | null // The referral token account (optional)
}
creatorFirstBuyParam?: {
// Optional creator first buy param
creator: PublicKey // The pool creator
receiver: PublicKey // The receiver of the transaction
buyAmount: BN // The amount of tokens to buy
minimumAmountOut: BN // The minimum amount of tokens to receive
referralTokenAccount: PublicKey | null // The referral token account (optional)
}
}
```
**Returns**
A single transaction containing pool creation and optional partner/creator first buy instructions. Partner and creator swap instructions are appended when their corresponding params are provided with `buyAmount > 0`.
**Example**
```typescript theme={"system"}
const creatorAmountIn = await prepareSwapAmountParam(
0.5,
NATIVE_MINT,
connection
)
const partnerAmountIn = await prepareSwapAmountParam(
0.1,
NATIVE_MINT,
connection
)
const transaction = await client.pool.createPoolWithPartnerAndCreatorFirstBuy({
createPoolParam: {
baseMint: new PublicKey('0987654321zyxwvutsrqponmlkjihgfedcba'),
config: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
name: 'Meteora',
symbol: 'MET',
uri: 'https://launch.meteora.ag/icons/logo.svg',
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
poolCreator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
},
partnerFirstBuyParam: {
partner: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
receiver: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
buyAmount: partnerAmountIn,
minimumAmountOut: new BN(1),
referralTokenAccount: null,
},
creatorFirstBuyParam: {
creator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
receiver: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
buyAmount: creatorAmountIn,
minimumAmountOut: new BN(1),
referralTokenAccount: null,
},
})
```
**Notes**
* The `poolCreator` is required to sign when creating the pool.
* The `partner` is required to sign when `partnerFirstBuyParam` is provided with `buyAmount > 0`.
* The `creator` is required to sign when `creatorFirstBuyParam` is provided with `buyAmount > 0`.
* The `baseMint` token type must be the same as the config key's token type.
* The `minimumAmountOut` parameter protects against slippage. Set it to a value slightly lower than the expected output.
* The `referralTokenAccount` parameter is an optional token account. If provided, the referral fee will be applied to the transaction.
***
### swap
Swaps between base and quote or quote and base on the Dynamic Bonding Curve.
**Function**
```typescript theme={"system"}
async swap(params: SwapParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface SwapParams {
owner: PublicKey // The person swapping the tokens
amountIn: BN // The amount of quote or base tokens to swap
minimumAmountOut: BN // The minimum amount of quote or base tokens to receive
swapBaseForQuote: boolean // Whether to swap base for quote. true = swap base for quote, false = swap quote for base
poolAddress: PublicKey // The pool address
referralTokenAccount: PublicKey | null // The referral token account (optional)
payer?: PublicKey // The payer of the transaction (optional)
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const amountIn = await prepareSwapAmountParam(1, NATIVE_MINT, connection)
const virtualPoolState = await client.state.getPool(poolAddress)
const poolConfigState = await client.state.getPoolConfig(
virtualPoolState.config
)
const currentPoint = await getCurrentPoint(
connection,
poolConfigState.activationType
)
const quote = await client.pool.swapQuote({
virtualPool: virtualPoolState.account,
config: poolConfigState,
swapBaseForQuote: false,
amountIn,
slippageBps: 50,
hasReferral: false,
currentPoint,
swapMode: SwapMode.PartialFill,
})
const transaction = await client.pool.swap({
owner: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
amountIn: new BN(1000000000),
minimumAmountOut: new BN(0),
swapBaseForQuote: false,
pool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
referralTokenAccount: null,
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The owner must have sufficient balance for the swap.
* For SOL swaps, the owner needs additional SOL for transaction fees (approximately 0.01 SOL).
* When swapping quote for base (buying tokens), set `swapBaseForQuote` to `false`.
* When swapping base for quote (selling tokens), set `swapBaseForQuote` to `true`.
* The `minimumAmountOut` parameter protects against slippage. Set it to a value slightly lower than the expected output.
* The `referralTokenAccount` parameter is an optional token account. If provided, the referral fee will be applied to the transaction.
* If the transaction fails with "insufficient balance", check that you have enough tokens plus fees for the transaction.
* The pool address can be derived using `deriveDbcPoolAddress`.
* The `payer` parameter is optional. If not provided, the owner will be used as the payer to fund ATA creation.
***
### swapQuote
Gets the exact swap out quotation in between quote and base swaps (only ExactIn).
**Function**
```typescript theme={"system"}
swapQuote(params: SwapQuoteParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface SwapQuoteParams {
virtualPool: VirtualPool // The virtual pool address
config: PoolConfig // The pool config address
swapBaseForQuote: boolean // True for base->quote, false for quote->base
amountIn: BN // The amount of tokens to swap in
slippageBps?: number // The slippage in bps
hasReferral: boolean // Whether to include a referral fee
currentPoint: BN // The current point
}
```
**Returns**
The exact swap out quotation in between quote and base swaps (only ExactIn).
**Example**
```typescript theme={"system"}
const amountIn = await prepareSwapAmountParam(1, NATIVE_MINT, connection)
const virtualPoolState = await client.state.getPool(poolAddress)
const poolConfigState = await client.state.getPoolConfig(
virtualPoolState.config
)
const currentPoint = await getCurrentPoint(
connection,
poolConfigState.activationType
)
const quote = await client.pool.swapQuote({
virtualPool: virtualPoolState,
config: poolConfigState,
swapBaseForQuote: false,
amountIn,
slippageBps: 50,
hasReferral: false,
currentPoint,
})
```
**Notes**
* The `swapMode` parameter determines the type of swap:
* `SwapMode.ExactIn`: Swap exact input amount
* `SwapMode.PartialFill`: Allow partial fills
* `SwapMode.ExactOut`: Swap for exact output amount
* The `amountIn` is the amount of tokens you want to swap, denominated in the smallest unit and token decimals. (e.g., lamports for SOL).
* The `slippageBps` parameter protects against slippage. Set it to a value slightly lower than the expected output.
* The `referralTokenAccount` parameter is an optional token account. If provided, the referral fee will be applied to the transaction.
***
***
### swap2
Swaps between base and quote or quote and base on the Dynamic Bonding Curve with specific swap modes (ExactIn, ExactOut, PartialFill).
**Function**
```typescript theme={"system"}
swap2(params: Swap2Params): Promise
```
**Parameters**
```typescript theme={"system"}
interface Swap2Params {
owner: PublicKey // The wallet performing the swap
pool: PublicKey // The pool address to swap on
swapBaseForQuote: boolean // True for base->quote, false for quote->base
referralTokenAccount: PublicKey | null // The referral token account (optional)
payer?: PublicKey // The payer of the transaction (optional)
} & (
| {
swapMode: SwapMode.ExactIn // Swap exact input amount
amountIn: BN // The exact amount to swap in
minimumAmountOut: BN // Minimum amount expected out (slippage protection)
}
| {
swapMode: SwapMode.PartialFill // Allow partial fills
amountIn: BN // The amount to swap in
minimumAmountOut: BN // Minimum amount expected out (slippage protection)
}
| {
swapMode: SwapMode.ExactOut // Swap for exact output amount
amountOut: BN // The exact amount desired out
maximumAmountIn: BN // Maximum amount willing to pay in (slippage protection)
}
)
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const amountIn = await prepareSwapAmountParam(1, NATIVE_MINT, connection)
const virtualPoolState = await client.state.getPool(poolAddress)
const poolConfigState = await client.state.getPoolConfig(
virtualPoolState.config
)
const currentPoint = await getCurrentPoint(
connection,
poolConfigState.activationType
)
const quote = await client.pool.swapQuote2({
virtualPool: virtualPoolState.account,
config: poolConfigState,
swapBaseForQuote: false,
amountIn,
slippageBps: 50,
hasReferral: false,
currentPoint,
swapMode: SwapMode.PartialFill,
})
const transaction = await client.pool.swap2({
amountIn,
minimumAmountOut: quote.minimumAmountOut,
swapMode: SwapMode.PartialFill,
swapBaseForQuote: false,
owner: wallet.publicKey,
pool: poolAddress,
referralTokenAccount: null,
payer: payer.publicKey,
})
```
**Notes**
* The `swapMode` parameter determines the type of swap:
* `SwapMode.ExactIn`: Swap exact input amount
* `SwapMode.PartialFill`: Allow partial fills
* `SwapMode.ExactOut`: Swap for exact output amount
* The `amountIn` is the amount of tokens you want to swap, denominated in the smallest unit and token decimals. (e.g., lamports for SOL).
* The `minimumAmountOut` parameter protects against slippage. Set it to a value slightly lower than the expected output.
* The `maximumAmountIn` parameter protects against slippage. Set it to a value slightly higher than the expected input.
* The `referralTokenAccount` parameter is an optional token account. If provided, the referral fee will be applied to the transaction.
* The `payer` parameter is optional. If not provided, the owner will be used as the payer to fund ATA creation.
***
### swapQuote2
Gets the exact swap out quotation in between quote and base swaps with specific swap modes (ExactIn, ExactOut, PartialFill).
**Function**
```typescript theme={"system"}
swapQuote2(params: SwapQuote2Params): Promise
```
**Parameters**
```typescript theme={"system"}
interface SwapQuote2Params {
virtualPool: VirtualPool // The virtual pool address
config: PoolConfig // The pool config address
swapBaseForQuote: boolean // True for base->quote, false for quote->base
hasReferral: boolean // Whether to include a referral fee
currentPoint: BN // The current point
slippageBps?: number // The slippage in bps
} & (
| {
swapMode: SwapMode.ExactIn // Swap exact input amount
amountIn: BN // The exact amount to swap in
}
| {
swapMode: SwapMode.PartialFill // Allow partial fills
amountIn: BN // The amount to swap in
}
| {
swapMode: SwapMode.ExactOut // Swap for exact output amount
amountOut: BN // The exact amount to swap out
}
)
```
**Returns**
The exact swap out quotation in between quote and base swaps with specific swap modes (ExactIn, ExactOut, PartialFill).
**Example**
```typescript theme={"system"}
const amountIn = await prepareSwapAmountParam(1, NATIVE_MINT, connection)
const virtualPoolState = await client.state.getPool(poolAddress)
const poolConfigState = await client.state.getPoolConfig(
virtualPoolState.config
)
const currentPoint = await getCurrentPoint(
connection,
poolConfigState.activationType
)
const quote = await client.pool.swapQuote2({
virtualPool: virtualPoolState.account,
config: poolConfigState,
swapBaseForQuote: false,
amountIn,
slippageBps: 50,
hasReferral: false,
currentPoint,
swapMode: SwapMode.PartialFill,
})
```
**Notes**
* The `swapMode` parameter determines the type of swap:
* `SwapMode.ExactIn`: Swap exact input amount
* `SwapMode.PartialFill`: Allow partial fills
* `SwapMode.ExactOut`: Swap for exact output amount
* The `amountIn` is the amount of tokens you want to swap, denominated in the smallest unit and token decimals. (e.g., lamports for SOL).
* The `slippageBps` parameter protects against slippage. Set it to a value slightly lower than the expected output.
* The `referralTokenAccount` parameter is an optional token account. If provided, the referral fee will be applied to the transaction.
***
## Migration Functions
### createLocker
Creates a new locker account when migrating from Dynamic Bonding Curve to DAMM V1 or DAMM V2. This function is called when `lockedVestingParam` is enabled in the config key.
**Function**
```typescript theme={"system"}
async createLocker(params: CreateLockerParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreateLockerParams {
payer: PublicKey // The payer of the transaction
virtualPool: PublicKey // The virtual pool address
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.migration.createLocker({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
})
```
**Notes**
* This function is called when `lockedVesting` is enabled in the config key.
***
### withdrawLeftover
Withdraws leftover tokens from the Dynamic Bonding Curve pool.
**Function**
```typescript theme={"system"}
async withdrawLeftover(params: WithdrawLeftoverParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface WithdrawLeftoverParams {
payer: PublicKey // The payer of the transaction
virtualPool: PublicKey // The virtual pool address
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.migration.withdrawLeftover({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
})
```
**Notes**
* This function is called when there are leftover tokens in the Dynamic Bonding Curve pool after migration.
* The leftover tokens will be sent to the `leftoverReceiver` that was specified in the config key.
***
### createDammV1MigrationMetadata
Creates a new DAMM V1 migration metadata account.
**Function**
```typescript theme={"system"}
async createDammV1MigrationMetadata(params: CreateDammV1MigrationMetadataParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreateDammV1MigrationMetadataParams {
payer: PublicKey // The payer of the transaction
virtualPool: PublicKey // The virtual pool address
config: PublicKey // The config address
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.migration.createDammV1MigrationMetadata({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
config: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* This function must be called before `migrateToDammV1`.
***
### migrateToDammV1
Migrates the Dynamic Bonding Curve pool to DAMM V1.
**Function**
```typescript theme={"system"}
async migrateToDammV1(params: MigrateToDammV1Params): Promise
```
**Parameters**
```typescript theme={"system"}
interface MigrateToDammV1Params {
payer: PublicKey // The payer of the transaction
virtualPool: PublicKey // The virtual pool address
dammConfig: PublicKey // The damm graduation fee config address
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.migration.migrateToDammV1({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
dammConfig: new PublicKey('8f848CEy8eY6PhJ3VcemtBDzPPSD4Vq7aJczLZ3o8MmX'),
})
```
**Notes**
* Ensure that when attempting to migrate the virtual pool, all these validation checks have already been met:
1. The `MigrationFeeOption` must be a valid enum value with a valid base fee in basis points
2. The pool's config account must have:
* pool\_creator\_authority matching the pool\_authority key
* activation\_duration set to 0
* partner\_fee\_numerator set to 0
* vault\_config\_key set to the default Pubkey (all zeros)
3. The virtual pool's migration progress must be in the LockedVesting state
4. The pool must be "complete" based on the migration\_quote\_threshold (checked via is\_curve\_complete)
5. The migration option must be valid and specifically set to MeteoraDamm
6. The account relationships must be valid:
* virtual\_pool must have matching base\_vault and quote\_vault
* virtual\_pool must have a matching config
* migration\_metadata must have a matching virtual\_pool
* You can get the dammConfig key from the [README.md](https://github.com/MeteoraAg/dynamic-bonding-curve-sdk/blob/main/packages/dynamic-bonding-curve/README.md), or you can use `DAMM_V1_MIGRATION_FEE_ADDRESS[i]` to get the dammConfig key address.
***
### lockDammV1LpToken
Locks a DAMM V1 LP token for a partner or creator.
**Function**
```typescript theme={"system"}
async lockDammV1LpToken(params: DammLpTokenParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface DammLpTokenParams {
payer: PublicKey // The payer of the transaction
virtualPool: PublicKey // The virtual pool address
dammConfig: PublicKey // The damm graduation fee config address
isPartner: boolean // Whether the LP token is a partner
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.migration.lockDammV1LpToken({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
dammConfig: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
isPartner: true,
})
```
**Notes**
* This function is called when the `creatorPermanentLockedLiquidityPercentage` or `partnerPermanentLockedLiquidityPercentage` is > 0.
* You can get the dammConfig key from the [README.md](https://github.com/MeteoraAg/dynamic-bonding-curve-sdk/blob/main/packages/dynamic-bonding-curve/README.md), or you can use `DAMM_V1_MIGRATION_FEE_ADDRESS[i]` to get the dammConfig key address.
***
### claimDammV1LpToken
Claims a DAMM V1 LP token for a partner or creator.
**Function**
```typescript theme={"system"}
async claimDammV1LpToken(params: DammLpTokenParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface DammLpTokenParams {
payer: PublicKey // The payer of the transaction
virtualPool: PublicKey // The virtual pool address
dammConfig: PublicKey // The damm graduation fee config address
isPartner: boolean // Whether the LP token is a partner
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.migration.claimDammV1LpToken({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
dammConfig: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
isPartner: true,
})
```
**Notes**
* This function is called when the `creatorLiquidityPercentage` or `partnerLiquiditypercentage` is > 0.
* You can get the dammConfig key from the [README.md](https://github.com/MeteoraAg/dynamic-bonding-curve-sdk/blob/main/packages/dynamic-bonding-curve/README.md), or you can use `DAMM_V1_MIGRATION_FEE_ADDRESS[i]` to get the dammConfig key address.
***
### migrateToDammV2
Migrates the Dynamic Bonding Curve pool to DAMM V2.
**Function**
```typescript theme={"system"}
async migrateToDammV2(params: MigrateToDammV2Params): Promise
```
**Parameters**
```typescript theme={"system"}
interface MigrateToDammV2Params {
payer: PublicKey // The payer of the transaction
virtualPool: PublicKey // The virtual pool address
dammConfig: PublicKey // The damm graduation fee config address
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.migration.migrateToDammV2({
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
dammConfig: new PublicKey('7F6dnUcRuyM2TwR8myT1dYypFXpPSxqwKNSFNkxyNESd'),
})
```
**Notes**
* Ensure that when attempting to migrate the virtual pool, all these validation checks have already been met:
1. The `MigrationFeeOption` must be a valid enum value with a valid base fee in basis points
2. The pool's config account must have:
* pool\_creator\_authority matching the pool\_authority key
* partner\_fee\_percent set to 0
* sqrt\_min\_price equal to MIN\_SQRT\_PRICE
* sqrt\_max\_price equal to MAX\_SQRT\_PRICE
* vault\_config\_key set to the default Pubkey (all zeros)
3. The virtual pool's migration progress must be in the LockedVesting state
4. The pool must be "complete" based on the migration\_quote\_threshold (checked via is\_curve\_complete)
5. The migration option must be valid and specifically set to DammV2
6. The account relationships must be valid:
* virtual\_pool must have matching base\_vault and quote\_vault
* virtual\_pool must have a matching config
* migration\_metadata must have a matching virtual\_pool
* first\_position\_nft\_mint must not equal second\_position\_nft\_mint
7. Exactly one remaining account must be provided (for the DAMM V2 config)
* You can get the dammConfig key from the [README.md](https://github.com/MeteoraAg/dynamic-bonding-curve-sdk/blob/main/packages/dynamic-bonding-curve/README.md), or you can use `DAMM_V2_MIGRATION_FEE_ADDRESS[i]` to get the dammConfig key address.
***
## Creator Functions
### createPoolMetadata
Creates a new pool metadata account.
**Function**
```typescript theme={"system"}
async createPoolMetadata(params: CreateVirtualPoolMetadataParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreateVirtualPoolMetadataParams {
virtualPool: PublicKey // The virtual pool address
name: string // The name of the pool
website: string // The website of the pool
logo: string // The logo of the pool
creator: PublicKey // The creator of the pool
payer: PublicKey // The payer of the transaction
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.creator.createPoolMetadata({
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
creator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
name: 'Meteora',
website: 'https://launch.meteora.ag',
logo: 'https://launch.meteora.ag/icons/logo.svg',
feeClaimer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
payer: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
***
### claimCreatorTradingFee
Claims a creator trading fee. If your pool's config key has `creatorTradingFeePercentage` > 0, you can use this function to claim the trading fee for the pool creator.
**Function**
```typescript theme={"system"}
async claimCreatorTradingFee(params: ClaimCreatorTradingFeeParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface ClaimCreatorTradingFeeParams {
creator: PublicKey // The creator of the pool
payer: PublicKey // The payer of the transaction
pool: PublicKey // The pool address
maxBaseAmount: BN // The maximum amount of base tokens to claim
maxQuoteAmount: BN // The maximum amount of quote tokens to claim
receiver?: PublicKey | null // The wallet that will receive the tokens (optional)
tempWSolAcc?: PublicKey | null // The temporary wallet that will receive the tokens (optional)
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.creator.claimCreatorTradingFee({
creator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
payer: new PublicKey('payer1234567890abcdefghijklmnopqrstuvwxyz'),
pool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
maxBaseAmount: new BN(1000000000),
maxQuoteAmount: new BN(1000000000),
receiver: new PublicKey('receiver1234567890abcdefghijklmnopqrstuvwxyz'),
tempWSolAcc: new PublicKey(
'tempWSolAcc1234567890abcdefghijklmnopqrstuvwxyz'
),
})
```
**Notes**
* The creator of the pool must be the same as the creator in the `ClaimCreatorTradingFeeParams` params.
* You can indicate maxBaseAmount or maxQuoteAmount to be 0 to not claim Base or Quote tokens respectively.
* If you indicated a `receiver`, the receiver **is not** required to sign the transaction, however, you must provide a `tempWSolAcc` if the receiver != creator and if the quote mint is SOL.
***
### claimCreatorTradingFee2
Claims a creator trading fee. If your pool's config key has `creatorTradingFeePercentage` > 0, you can use this function to claim the trading fee for the pool creator.
**Function**
```typescript theme={"system"}
async claimCreatorTradingFee2(params: ClaimCreatorTradingFee2Params): Promise
```
**Parameters**
```typescript theme={"system"}
interface ClaimCreatorTradingFee2Params {
creator: PublicKey // The creator of the pool
payer: PublicKey // The payer of the transaction
pool: PublicKey // The pool address
maxBaseAmount: BN // The maximum amount of base tokens to claim
maxQuoteAmount: BN // The maximum amount of quote tokens to claim
receiver?: PublicKey | null // The wallet that will receive the tokens
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.creator.claimCreatorTradingFee2({
creator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
payer: new PublicKey('payer1234567890abcdefghijklmnopqrstuvwxyz'),
pool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
maxBaseAmount: new BN(1000000000),
maxQuoteAmount: new BN(1000000000),
receiver: new PublicKey('receiver1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The creator of the pool must be the same as the creator in the `ClaimCreatorTradingFee2Params` params.
* You can indicate maxBaseAmount or maxQuoteAmount to be 0 to not claim Base or Quote tokens respectively.
* Can be used in case the creator is a squad multisig account.
***
### creatorWithdrawSurplus
Withdraws surplus tokens from the pool.
**Function**
```typescript theme={"system"}
async creatorWithdrawSurplus(params: CreatorWithdrawSurplusParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface CreatorWithdrawSurplusParams {
creator: PublicKey // The creator of the pool
virtualPool: PublicKey // The virtual pool address
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.creator.creatorWithdrawSurplus({
creator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
})
```
**Notes**
* The creator of the pool must be the same as the creator in the `CreatorWithdrawSurplusParams` params.
***
### creatorWithdrawMigrationFee
Withdraws the creator's migration fee from the pool.
**Function**
```typescript theme={"system"}
async creatorWithdrawMigrationFee(params: WithdrawMigrationFeeParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface WithdrawMigrationFeeParams {
virtualPool: PublicKey // The virtual pool address
sender: PublicKey // The wallet that will claim the fee
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.creator.creatorWithdrawMigrationFee({
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
sender: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The sender of the pool must be the same as the creator (`poolCreator`) in the virtual pool.
***
### transferPoolCreator
Transfers the pool creator to a new wallet.
**Function**
```typescript theme={"system"}
async transferPoolCreator(params: TransferPoolCreatorParams): Promise
```
**Parameters**
```typescript theme={"system"}
interface TransferPoolCreatorParams {
virtualPool: PublicKey // The virtual pool address
creator: PublicKey // The current creator of the pool
newCreator: PublicKey // The new creator of the pool
}
```
**Returns**
* A transaction that can be signed and sent to the network.
**Example**
```typescript theme={"system"}
const transaction = await client.creator.transferPoolCreator({
virtualPool: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
creator: new PublicKey('boss1234567890abcdefghijklmnopqrstuvwxyz'),
newCreator: new PublicKey('newCreator1234567890abcdefghijklmnopqrstuvwxyz'),
})
```
**Notes**
* The creator of the pool must be the signer of the transaction.
***
## State Functions
### getPoolConfig
Gets all details about the config.
**Function**
```typescript theme={"system"}
async getPoolConfig(configAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
configAddress: PublicKey | string // The address of the config key
```
**Returns**
* A `PoolConfig` object containing the config key details.
**Example**
```typescript theme={"system"}
const config = await client.state.getPoolConfig(configAddress)
```
***
### getPoolConfigs
Retrieves all configs.
**Function**
```typescript theme={"system"}
async getPoolConfigs(): Promise[]>
```
**Returns**
* An array of configs created by various users.
* Check return type here.
**Example**
```typescript theme={"system"}
const configs = await client.state.getPoolConfigs()
```
***
### getPoolConfigsByOwner
Retrieves all configs owned by a specific wallet.
**Function**
```typescript theme={"system"}
async getPoolConfigsByOwner(owner: PublicKey | string): Promise[]>
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey | string // The owner's wallet address
```
**Returns**
* An array of configs owned by the specified wallet.
* Check return type here.
**Example**
```typescript theme={"system"}
const configs = await client.state.getPoolConfigsByOwner(wallet.publicKey)
```
***
### getPool
Gets the details of a specific pool.
**Function**
```typescript theme={"system"}
async getPool(poolAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey | string // The address of the pool
```
**Returns**
* A `VirtualPool` object containing the pool's details, or null if not found.
```typescript theme={"system"}
type VolatilityTracker = {
lastUpdateTimestamp: BN
padding: number[]
sqrtPriceReference: BN
volatilityAccumulator: BN
volatilityReference: BN
}
type Metrics = {
totalProtocolBaseFee: BN
totalProtocolQuoteFee: BN
totalTradingBaseFee: BN
totalTradingQuoteFee: BN
}
type VirtualPool = {
volatilityTracker: VolatilityTracker
config: PublicKey
creator: PublicKey
baseMint: PublicKey
baseVault: PublicKey
quoteVault: PublicKey
baseReserve: BN
quoteReserve: BN
protocolBaseFee: BN
protocolQuoteFee: BN
partnerBaseFee: BN
partnerQuoteFee: BN
sqrtPrice: BN
activationPoint: BN
poolType: number
isMigrated: number
isPartnerWithdrawSurplus: number
isProtocolWithdrawSurplus: number
migrationProgress: number
isWithdrawLeftover: number
isCreatorWithdrawSurplus: number
migrationFeeWithdrawStatus: number
metrics: Metrics
finishCurveTimestamp: BN
creatorBaseFee: BN
creatorQuoteFee: BN
padding1: BN[]
}
```
**Example**
```typescript theme={"system"}
const pool = await client.state.getPool(poolAddress)
```
***
### getPools
Retrieves all pools.
**Function**
```typescript theme={"system"}
async getPools(): Promise[]>
```
**Returns**
* An array of all virtual pools created through DBC.
* Check return type of VirtualPool here.
**Example**
```typescript theme={"system"}
const pools = await client.state.getPools()
```
***
### getPoolsByConfig
Retrieves all pools by config key address.
**Function**
```typescript theme={"system"}
async getPoolsByConfig(configAddress: PublicKey | string): Promise[]>
```
**Parameters**
```typescript theme={"system"}
configAddress: PublicKey | string // The address of the config key
```
**Returns**
* It give all `virtual pools` created with a specific config key.
* Check return type of VirtualPool here.
**Example**
```typescript theme={"system"}
const pools = await client.state.getPoolsByConfig(configAddress)
```
***
### getPoolsByCreator
Retrieves all pools by creator address.
**Function**
```typescript theme={"system"}
async getPoolsByCreator(creatorAddress: PublicKey | string): Promise[]>
```
**Parameters**
```typescript theme={"system"}
creatorAddress: PublicKey | string // The address of the creator
```
**Returns**
* It give all `virtual pools` created with a specific wallet address.
* Check return type of VirtualPool here.
**Example**
```typescript theme={"system"}
const pools = await client.state.getPoolsByCreator(creatorAddress)
```
***
### getPoolByBaseMint
Gets the pool by base mint.
**Function**
```typescript theme={"system"}
async getPoolByBaseMint(baseMint: PublicKey | string): Promise | null>
```
**Parameters**
```typescript theme={"system"}
baseMint: PublicKey | string // The address of the base mint
```
**Returns**
* A `VirtualPool` object containing the pool's details, or null if not found.
* Check return type of VirtualPool here.
**Example**
```typescript theme={"system"}
const pool = await client.state.getPoolByBaseMint(baseMint)
```
***
### getPoolMigrationQuoteThreshold
Gets the migration quote threshold for a specific pool.
**Function**
```typescript theme={"system"}
async getPoolMigrationQuoteThreshold(poolAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey | string // The address of the pool
```
**Returns**
* A `BN` object representing the migration quote threshold.
**Example**
```typescript theme={"system"}
const threshold = await client.state.getPoolMigrationQuoteThreshold(poolAddress)
```
***
### getPoolQuoteTokenCurveProgress
Gets the progress of the curve by comparing current quote reserve to migration threshold.
**Function**
```typescript theme={"system"}
async getPoolQuoteTokenCurveProgress(poolAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey | string // The address of the pool
```
**Returns**
* A number between 0 and 1 representing the curve progress.
**Example**
```typescript theme={"system"}
const progress = await client.state.getPoolQuoteTokenCurveProgress(poolAddress)
```
***
### getPoolBaseTokenCurveProgress
Gets the progress of the curve based on base tokens sold relative to total base tokens available for trading.
**Function**
```typescript theme={"system"}
async getPoolBaseTokenCurveProgress(poolAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey | string // The address of the pool
```
**Returns**
* A number between 0 and 1 representing the curve progress.
**Example**
```typescript theme={"system"}
const progress = await client.state.getPoolBaseTokenCurveProgress(poolAddress)
```
***
### getPoolMetadata
* Gets the metadata for a specific pool.
* Can only be used if metadata is set using createPoolMetadata function.
**Function**
```typescript theme={"system"}
async getPoolMetadata(poolAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey | string // The address of the pool
```
**Returns**
* An array of `VirtualPoolMetadata` objects containing the pool's metadata.
```typescript theme={"system"}
type VirtualPoolMetadata = {
virtualPool: PublicKey
padding: BN[]
name: string
website: string
logo: string
}
```
**Example**
```typescript theme={"system"}
const metadata = await client.state.getPoolMetadata(poolAddress)
```
***
### getPartnerMetadata
Gets the metadata for a specific partner.
**Function**
```typescript theme={"system"}
async getPartnerMetadata(walletAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
walletAddress: PublicKey | string // The partner's wallet address
```
**Returns**
* An array of `PartnerMetadata` objects containing the partner's metadata.
```typescript theme={"system"}
type partnerMetadata = {
feeClaimer: PublicKey
padding: BN[]
name: string
website: string
logo: string
}
```
**Example**
```typescript theme={"system"}
const metadata = await client.state.getPartnerMetadata(wallet.publicKey)
```
***
### getDammV1LockEscrow
Gets the lock escrow details for a DAMM V1 pool.
**Function**
```typescript theme={"system"}
async getDammV1LockEscrow(lockEscrowAddress: PublicKey | string): Promise
```
**Parameters**
```typescript theme={"system"}
lockEscrowAddress: PublicKey | string // The address of the lock escrow
```
**Returns**
* A `LockEscrow` object containing the lock escrow details.
```typescript theme={"system"}
type lockEscrow = {
pool: PublicKey
owner: PublicKey
escrowVault: PublicKey
bump: number
totalLockedAmount: BN
lpPerToken: BN
unclaimedFeePending: BN
aFee: BN
bFee: BN
}
```
**Example**
```typescript theme={"system"}
const escrow = await client.state.getDammV1LockEscrow(escrowAddress)
```
***
### getDammV1MigrationMetadata
Gets the DAMM V1 migration metadata for a specific pool.
**Function**
```typescript theme={"system"}
async getDammV1MigrationMetadata(poolAddress: PublicKey): Promise
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey // The address of the DBC pool
```
**Returns**
A `MeteoraDammMigrationMetadata` object containing the DAMM V1 migration metadata.
```typescript theme={"system"}
type meteoraDammMigrationMetadata = {
virtualPool: PublicKey
padding0: number | number[]
partner: PublicKey
lpMint: PublicKey
partnerLockedLiquidity: BN
partnerLiquidity: BN
creatorLockedLiquidity: BN
creatorLiquidity: BN
creatorLockedStatus: number
partnerLockedStatus: number
creatorClaimStatus: number
partnerClaimStatus: number
padding: number[]
}
```
**Example**
```typescript theme={"system"}
const metadata = await client.state.getDammV1MigrationMetadata(poolAddress)
```
***
### getPoolFeeMetrics
Gets the fee metrics for a specific pool.
**Function**
```typescript theme={"system"}
async getPoolFeeMetrics(poolAddress: PublicKey): Promise<{
current: {
partnerBaseFee: BN
partnerQuoteFee: BN
creatorBaseFee: BN
creatorQuoteFee: BN
}
total: {
totalTradingBaseFee: BN
totalTradingQuoteFee: BN
}
}>
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey // The address of the pool
```
**Returns**
* An object containing current and total fee metrics for the pool.
```typescript theme={"system"}
{
current: {
partnerBaseFee: BN
partnerQuoteFee: BN
creatorBaseFee: BN
creatorQuoteFee: BN
}
total: {
totalTradingBaseFee: BN
totalTradingQuoteFee: BN
}
}
```
**Example**
```typescript theme={"system"}
const metrics = await client.state.getPoolFeeMetrics(poolAddress)
```
***
### getPoolFeeBreakdown
Gets the fee breakdown for a specific pool.
**Function**
```typescript theme={"system"}
async getPoolFeeBreakdown(poolAddress: PublicKey): Promise<
{
creator: {
unclaimedBaseFee: BN
unclaimedQuoteFee: BN
claimedBaseFee: BN
claimedQuoteFee: BN
totalBaseFee: BN
totalQuoteFee: BN
}
partner: {
unclaimedBaseFee: BN
unclaimedQuoteFee: BN
claimedBaseFee: BN
claimedQuoteFee: BN
totalBaseFee: BN
totalQuoteFee: BN
}
}>
```
**Parameters**
```typescript theme={"system"}
poolAddress: PublicKey // The address of the pool
```
**Returns**
* An object containing current and total fee breakdown for the pool.
```typescript theme={"system"}
{
creator: {
unclaimedBaseFee: BN
unclaimedQuoteFee: BN
claimedBaseFee: BN
claimedQuoteFee: BN
totalBaseFee: BN
totalQuoteFee: BN
}
partner: {
unclaimedBaseFee: BN
unclaimedQuoteFee: BN
claimedBaseFee: BN
claimedQuoteFee: BN
totalBaseFee: BN
totalQuoteFee: BN
}
}
```
**Example**
```typescript theme={"system"}
const breakdown = await client.state.getPoolFeeBreakdown(poolAddress)
```
***
### getPoolsFeesByConfig
Gets all fees for pools linked to a specific config key.
**Function**
```typescript theme={"system"}
async getPoolsFeesByConfig(configAddress: PublicKey): Promise>
```
**Parameters**
```typescript theme={"system"}
configAddress: PublicKey // The address of the pool config
```
**Returns**
* An array of objects containing quote fee metrics for each pool.
```typescript theme={"system"}
type FeeMetrics = {
poolAddress: PublicKey
partnerBaseFee: BN
partnerQuoteFee: BN
creatorBaseFee: BN
creatorQuoteFee: BN
totalTradingBaseFee: BN
totalTradingQuoteFee: BN
}
```
**Example**
```typescript theme={"system"}
const fees = await client.state.getPoolsFeesByConfig(configAddress)
```
***
### getPoolsFeesByCreator
Gets all fees for pools linked to a specific creator.
**Function**
```typescript theme={"system"}
async getPoolsFeesByCreator(creatorAddress: PublicKey): Promise>
```
**Parameters**
```typescript theme={"system"}
creatorAddress: PublicKey // The address of the creator
```
**Returns**
* An array of objects containing quote fee metrics for each pool.
```typescript theme={"system"}
type FeeMetrics = {
poolAddress: PublicKey
partnerBaseFee: BN
partnerQuoteFee: BN
creatorBaseFee: BN
creatorQuoteFee: BN
totalTradingBaseFee: BN
totalTradingQuoteFee: BN
}
```
**Example**
```typescript theme={"system"}
const fees = await client.state.getPoolsFeesByCreator(creatorAddress)
```
***
## Helper Functions
### deriveDbcPoolAddress
Derives the address of a Dynamic Bonding Curve pool.
**Function**
```typescript theme={"system"}
function deriveDbcPoolAddress(
quoteMint: PublicKey,
baseMint: PublicKey,
config: PublicKey
): PublicKey
```
**Parameters**
```typescript theme={"system"}
quoteMint: PublicKey // The quote mint
baseMint: PublicKey // The base mint
config: PublicKey // The config
```
**Returns**
* The address of the Dynamic Bonding Curve pool.
**Example**
```typescript theme={"system"}
const dbcPoolAddress = deriveDbcPoolAddress(
quoteMint: new PublicKey('abcdefghijklmnopqrstuvwxyz1234567890'),
baseMint: new PublicKey('1234567890abcdefghijklmnopqrstuvwxyz'),
config: new PublicKey('config1234567890abcdefghijklmnopqrstuvwxyz')
)
```
***
### deriveDammV1PoolAddress
Derives the address of a DAMM V1 pool.
**Function**
```typescript theme={"system"}
function deriveDammV1PoolAddress(
dammConfig: PublicKey,
tokenAMint: PublicKey,
tokenBMint: PublicKey
): PublicKey
```
**Parameters**
```typescript theme={"system"}
dammConfig: PublicKey // The DAMM V1 graduation config key (retrievable from the README.md)
tokenAMint: PublicKey // The A token mint
tokenBMint: PublicKey // The B token mint
```
**Returns**
* The address of the DAMM V1 pool.
**Example**
```typescript theme={"system"}
const poolConfig = await client.state.getPoolConfig(configAddress)
const dammV1PoolAddress = deriveDammV1PoolAddress(
dammConfig: DAMM_V1_MIGRATION_FEE_ADDRESS[poolConfig.migrationFeeOption],
tokenAMint: new PublicKey('tokenA1234567890abcdefghijklmnopqrstuvwxyz'),
tokenBMint: new PublicKey('tokenB1234567890abcdefghijklmnopqrstuvwxyz')
)
```
***
### deriveDammV2PoolAddress
Derives the address of a DAMM V2 pool.
**Function**
```typescript theme={"system"}
function deriveDammV2PoolAddress(
dammConfig: PublicKey,
tokenAMint: PublicKey,
tokenBMint: PublicKey
): PublicKey
```
**Parameters**
```typescript theme={"system"}
dammConfig: PublicKey // The DAMM V2 graduation config key (retrievable from the README.md)
tokenAMint: PublicKey // The A token mint
tokenBMint: PublicKey // The B token mint
```
**Returns**
* The address of the DAMM V2 pool.
**Example**
```typescript theme={"system"}
const poolConfig = await client.state.getPoolConfig(configAddress)
const dammV2PoolAddress = deriveDammV2PoolAddress(
dammConfig: DAMM_V2_MIGRATION_FEE_ADDRESS[poolConfig.migrationFeeOption],
tokenAMint: new PublicKey('tokenA1234567890abcdefghijklmnopqrstuvwxyz'),
tokenBMint: new PublicKey('tokenB1234567890abcdefghijklmnopqrstuvwxyz')
)
```
***
### deriveDbcTokenVaultAddress
Derives the address of a DBC token vault.
**Function**
```typescript theme={"system"}
function deriveDbcTokenVaultAddress(pool: PublicKey, mint: PublicKey): PublicKey
```
**Parameters**
```typescript theme={"system"}
pool: PublicKey // The pool address
mint: PublicKey // The mint address
```
**Returns**
* The address of the DBC token vault.
**Example**
```typescript theme={"system"}
const dbcTokenVaultAddress = deriveDbcTokenVaultAddress(
pool: new PublicKey('pool1234567890abcdefghijklmnopqrstuvwxyz'),
mint: new PublicKey('token1234567890abcdefghijklmnopqrstuvwxyz')
)
```
***
## Calculation Functions
### getFeeSchedulerParams
Gets the fee scheduler parameters for a specific pool config.
**Function**
```typescript theme={"system"}
function getFeeSchedulerParams(
startingFeeBps: number,
endingFeeBps: number,
feeSchedulerMode: number,
numberOfPeriod: number,
totalDuration: number
): BaseFeeParams
```
**Parameters**
```typescript theme={"system"}
startingFeeBps: number // The starting fee in basis points
endingFeeBps: number // The ending fee in basis points
feeSchedulerMode: number // 0: Linear, 1: Exponential
numberOfPeriod: number // The number of periods
totalDuration: number // The total duration of the fee scheduler
```
**Returns**
* A `BaseFee` object containing the calculated fee scheduler parameters.
```typescript theme={"system"}
type BaseFee = {
cliffFeeNumerator: BN
firstFactor: number
secondFactor: BN
thirdFactor: BN
baseFeeMode: BaseFeeMode
}
```
**Example**
```typescript theme={"system"}
const baseFeeParams = getFeeSchedulerParams(
startingFeeBps: 5000,
endingFeeBps: 100,
feeSchedulerMode: 1,
numberOfPeriod: 600,
totalDuration: 600
)
```
**Notes**
* The `totalDuration` is the total duration of the fee scheduler. It must be calculated based on your `activationType`. If you use `ActivationType.Slot`, the `totalDuration` is denominated in terms of 400ms (slot). If you use `ActivationType.Timestamp`, the `totalDuration` is denominated in terms of 1000ms (timestamp).
* `startingFeeBps` must always be greater than or equal to `endingFeeBps`.
* `totalDuration` must always be greater than or equal to `numberOfPeriod`.
***
### getRateLimiterParams
Gets the fee scheduler parameters for a specific pool config.
**Function**
```typescript theme={"system"}
function getRateLimiterParams(
baseFeeBps: number,
feeIncrementBps: number,
referenceAmount: number,
maxLimiterDuration: number,
tokenQuoteDecimal: TokenDecimal,
activationType: ActivationType
): BaseFeeParams
```
**Parameters**
```typescript theme={"system"}
baseFeeBps: number // The base fee in basis points
feeIncrementBps: number // The fee increment in basis points
referenceAmount: number // The reference amount (in terms of quote token)
maxLimiterDuration: number // The max rate limiter duration
tokenQuoteDecimal: TokenDecimal // The token quote decimal
activationType: ActivationType // The activation type
```
**Returns**
* A `BaseFee` object containing the calculated rate limiter parameters.
```typescript theme={"system"}
type BaseFeeParams = {
cliffFeeNumerator: BN
firstFactor: number
secondFactor: BN
thirdFactor: BN
baseFeeMode: BaseFeeMode
}
```
**Example**
```typescript theme={"system"}
const baseFeeParams = getRateLimiterParams(
baseFeeBps: 100,
feeIncrementBps: 100,
referenceAmount: 1, // 1 SOL
maxLimiterDuration: 600, // 600 slots
tokenQuoteDecimal: TokenDecimal.NINE,
activationType: ActivationType.Slot
)
```
**Notes**
* The `maxLimiterDuration` is the max duration of the rate limiter. It must be calculated based on your `activationType`. If you use `ActivationType.Slot`, the `maxLimiterDuration` is denominated in terms of 400ms (slot). If you use `ActivationType.Timestamp`, the `maxLimiterDuration` is denominated in terms of 1000ms (timestamp).
* `referenceAmount` must always be greater than 0. This parameter takes into account the quoteMint decimals. For example, if you use `TokenDecimal.NINE`, the `referenceAmount` must be 1 (1 SOL).
* `maxLimiterDuration` must always be greater than 0.
* `tokenQuoteDecimal` must always be greater than 0.
* `activationType` must always be greater than 0.
* `baseFeeBps` must always be greater than 0.
***
### getDynamicFeeParams
Gets the dynamic fee parameters for a specific pool. Calculated the fee based on the minimum base fee (capped at 20% of base fee). Please note that the maxPriceChangeBps must be less than or equal to 1500 (15%).
**Function**
```typescript theme={"system"}
function getDynamicFeeParams(
baseFeeBps: number,
maxPriceChangeBps: number
): DynamicFeeParams
```
**Parameters**
```typescript theme={"system"}
baseFeeBps: number // The base fee in basis points
maxPriceChangeBps: number // The maximum price change in basis points
```
**Returns**
* A `DynamicFeeParams` object containing the calculated dynamic fee parameters.
```typescript theme={"system"}
type dynamicFeeParameters = {
binStep: number
binStepU128: BN
filterPeriod: number
decayPeriod: number
reductionFactor: number
maxVolatilityAccumulator: number
variableFeeControl: number
}
```
**Example**
```typescript theme={"system"}
const dynamicFeeParams = getDynamicFeeParams(
baseFeeBps: 5000,
maxPriceChangeBps: 1500
)
```
***
### getLockedVestingParams
Gets the locked vesting parameters for a specific pool.
**Function**
```typescript theme={"system"}
function getLockedVestingParams(
totalLockedVestingAmount: number,
numberOfVestingPeriod: number,
cliffUnlockAmount: number,
totalVestingDuration: number,
cliffDurationFromMigrationTime: number,
tokenBaseDecimal: TokenDecimal
): LockedVestingParams
```
**Parameters**
```typescript theme={"system"}
totalLockedVestingAmount: number // The total locked vesting amount
numberOfVestingPeriod: number // The number of vesting periods
cliffUnlockAmount: number // The amount of tokens that will be unlocked when vesting starts
totalVestingDuration: number // The total vesting duration in seconds
cliffDurationFromMigrationTime: number // The duration of the waiting time before the vesting starts
tokenBaseDecimal: TokenDecimal // The number of decimals for the base token
```
**Returns**
* A `LockedVestingParams` object containing the calculated locked vesting parameters.
```typescript theme={"system"}
type LockedVestingParams = {
amountPerPeriod: BN
cliffDurationFromMigrationTime: BN
frequency: BN
numberOfPeriod: BN
cliffUnlockAmount: BN
}
```
**Example**
```typescript theme={"system"}
const lockedVestingParams = getLockedVestingParams(
totalLockedVestingAmount: 100000000,
numberOfVestingPeriod: 600,
cliffUnlockAmount: 1000,
totalVestingDuration: 600,
cliffDurationFromMigrationTime: 600,
tokenBaseDecimal: 6,
)
```
**Notes**
* The `totalVestingDuration` is the total duration of the vesting. It must be calculated in terms of seconds => 1000ms (timestamp).
***
### getQuoteReserveFromNextSqrtPrice
Gets the quote reserve from the next sqrt price instead of getting from the pool state.
**Function**
```typescript theme={"system"}
function getQuoteReserveFromNextSqrtPrice(
nextSqrtPrice: BN,
config: PoolConfig
): BN
```
**Parameters**
```typescript theme={"system"}
nextSqrtPrice: BN // The next sqrt price that you can fetch from swap cpi logs
config: PoolConfig // The pool config
```
**Returns**
* A `BN` object containing the calculated quote reserve.
**Example**
```typescript theme={"system"}
const poolConfig = await client.state.getPoolConfig(configAddress)
const quoteReserve = getQuoteReserveFromNextSqrtPrice(
nextSqrtPrice: new BN('13663931917038696),
config: poolConfig
)
```
**Notes**
* The `nextSqrtPrice` is the next sqrt price that you can fetch from swap cpi logs.
* The `config` is the pool config that the token pool used to launch.
# Examples
Source: https://docs.meteora.ag/developer-guide/guides/dlmm/cpi/examples
DLMM
This [repository](https://github.com/MeteoraAg/cpi-examples) contains examples for CPI (Cross-Program Invocation) that interacts with the DLMM programs.
# Dependencies
* **Anchor:** 0.28.0
* **Solana:** 1.16.1
* **Rust:** 1.68.0
# CPI Examples
Example implementation of Cross-Program Invocation for DLMM swap operations.
Test cases and examples for CPI integration with DLMM programs.
# Rust Examples
Command-line interface examples for DLMM SDK integration and usage.
Market making strategies and examples using the DLMM SDK.
# Overview
Source: https://docs.meteora.ag/developer-guide/guides/dlmm/overview
Before getting started building on DLMM, you should read the following resource to get a better understanding of how Meteora's DLMM works:
DLMM is one of Meteora's highly sophisticated product that allows you to provide concentrated liquidity to a pool and earn dynamic fees that increases or decreases based on the market volatility.
DLMM supports Token 2022 tokens with a variety of extensions, enabling tokens with enhanced functionality to be easily integrated into DLMM pools. Check out the list of extensions that DLMM supports here.
***
# DLMM Program
At Meteora, we’ve developed a `Node.js <> Typescript SDK` and `Rust CPI Examples` to make deploying and managing your DLMM liquidity pool easier. The following sections includes information on installing and using the SDKs and Rust CPIs. It also covers where to find the latest code, and how to contribute to these repositories.
We also outline a list of unofficial community SDKs made by our wonderful community.
## Program Details
Meteora DLMM Program IDL
Network
Program ID
Mainnet
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo
Devnet
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo
## Pool Types
DLMM supports four pool types:
| Pool Type | Description |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `Permissionless` | Standard open pool, no special requirements. |
| `PermissionlessV2` | Latest pool type with Token 2022 support, extended config parameters, and `function_type` setting. Created via `initialize_lb_pair2`. |
| `Permission` | Admin-controlled pool for token launches with activation point, pre-activation duration, and lock duration settings. |
| `CustomizablePermissionless` | Open pool with creator-controlled on/off switch, customizable base fee, activation point, and Alpha Vault support. |
`PermissionlessV2` pools no longer enforce SOL/USDC quote token constraints — any token pair is supported.
## Function Type
When creating a `PermissionlessV2` pool, a `function_type` parameter is required:
| Function Type | Description |
| --------------------- | ------------------------------------------------------ |
| `LiquidityMining` (0) | Pool supports farming rewards via `initialize_reward`. |
The `initialize_reward` instruction only works on pools with `function_type = LiquidityMining`. Pools created without this function type cannot have farming rewards added later.
## Dynamic Positions
DLMM supports `PositionV2`, which supports up to **1,400 bins** per position — a significant increase from the previous 70-bin limit. This is achieved through extended byte data attached to the position account, which is allocated on demand as the position grows.
### Position Resize
Positions can be resized dynamically without closing and reopening:
| Instruction | Description |
| -------------------------------------------------------- | ------------------------------------------------ |
| `increase_position_length` / `increase_position_length2` | Expand the position's bin range. |
| `decrease_position_length` | Shrink the position from the lower or upper end. |
### Rebalance Liquidity
The `rebalance_liquidity` instruction allows position owners to combine multiple liquidity operations (add, remove, shift) and resize the position in a single instruction.
It supports a `shrink_mode` parameter:
| Shrink Mode | Description |
| --------------- | ------------------------------------------ |
| `ShrinkBoth` | Shrink empty bins on both sides. |
| `NoShrinkLeft` | Keep left (lower) bins, shrink right only. |
| `NoShrinkRight` | Keep right (upper) bins, shrink left only. |
| `NoShrinkBoth` | Do not shrink on either side. |
### Additional Position Instructions
| Instruction | Description |
| ------------------------- | -------------------------------------------------------------------------- |
| `initialize_position2` | Creates a position, succeeding silently if it already exists (idempotent). |
| `close_position_if_empty` | Closes a position only if it has no liquidity; otherwise does nothing. |
| `migrate_position` | Migrates a v1 position to v2 format. |
## Bin Array Initialization
**Breaking change:** The `initialize_bin_array` instruction now sets all bin prices during initialization and consumes approximately **250,000 compute units**. Integrations should allocate additional CU for this instruction. The instruction is idempotent — re-initializing an existing bin array does not return an error.
## Token 2022 Support
DLMM supports Token 2022 tokens with the following permissionless extensions:
* `TransferFeeConfig` / `TransferFeeAmount`
* `TokenMetadata` / `MetadataPointer`
* `ConfidentialTransferMint` / `ConfidentialTransferFeeConfig`
Extensions like `PermanentDelegate`, `TransferHook`, and `MintCloseAuthority` require a **Token Badge** to be initialized by the program admin before they can be used in DLMM pools.
Transfer hook mints are supported permissionlessly if both the transfer hook program and transfer hook authority have been revoked.
## Official SDKs
Official Meteora DLMM Typescript SDK
Official Meteora DLMM Rust CPI Examples
## Community SDKs
These SDKs are not officially maintained by our team — only the `Node.js <> Typescript SDK` and `Rust CPI Examples` are.
Unofficial Python SDK for DLMM built by the community
# Getting Started
Source: https://docs.meteora.ag/developer-guide/guides/dlmm/typescript-sdk/getting-started
DLMM
This guide provides instructions on how to get started with building on Meteora's DLMM program using the DLMM TypeScript SDK.
Before you begin, here are some important resources:
Meteora DLMM Typescript SDK
Meteora DLMM NPM Package
# Installation
To use the SDK in your project, install it using your preferred package manager:
```bash theme={"system"}
npm install @meteora-ag/dlmm @solana/web3.js
```
```bash theme={"system"}
pnpm install @meteora-ag/dlmm @solana/web3.js
```
```bash theme={"system"}
yarn add @meteora-ag/dlmm @solana/web3.js
```
# Initialization
Once installed, you can initialize the DLMM client in your `Node.js` project like this:
```typescript theme={"system"}
import DLMM from '@meteora-ag/dlmm'
import { Connection, PublicKey } from '@solana/web3.js';
const mainnetConnection = new Connection('https://api.mainnet-beta.solana.com');
// Create pool instances
// e.g. creating a DLMM pool
// You can get your desired pool address from the API https://dlmm.datapi.meteora.ag/pair/all
const USDC_USDT_POOL_ADDRESS = new PublicKey('ARwi1S4DaiTG5DX7S4M4ZsrXqpMD1MrTmbu9ue2tpmEq')
const dlmmPool = await DLMM.create(connection, USDC_USDT_POOL_ADDRESS);
// e.g. creating multiple pools
const dlmmMultiplePools = await DLMM.createMultiple(connection, [USDC_USDT_POOL_ADDRESS, ...otherPoolAddresses]);
```
# Testing the SDK (for contributors)
If you have cloned the SDK repository and want to run the built-in tests:
```bash theme={"system"}
# Install dependencies
cd ts-client
bun install
# Run tests
bun test
```
# Development Resources
## Faucets
When working on devnet, you might need test tokens. Here is a helpful faucet.
# SDK Functions
Source: https://docs.meteora.ag/developer-guide/guides/dlmm/typescript-sdk/sdk-functions
DLMM
## Common Types
These types are referenced throughout the SDK functions.
### StrategyType
```typescript theme={"system"}
enum StrategyType {
Spot, // Uniform distribution across all bins
Curve, // Bell-curve distribution concentrated near the active bin
BidAsk, // V-shaped distribution with more weight at price extremes
}
```
### StrategyParameters
```typescript theme={"system"}
interface StrategyParameters {
maxBinId: number; // Upper bound of the target bin range
minBinId: number; // Lower bound of the target bin range
strategyType: StrategyType; // Distribution strategy
singleSidedX?: boolean; // If true, deposit only token X (ask side only)
}
```
### ActivationType
```typescript theme={"system"}
enum ActivationType {
Slot, // Activation based on slot number
Timestamp, // Activation based on Unix timestamp
}
```
***
## Pool Functions
### create
Creates an instance of the DLMM pool given the pool address.
**Function**
```typescript theme={"system"}
async create(
connection: Connection,
dlmm: PublicKey,
opt?: {
cluster?: Cluster | "localhost";
programId?: PublicKey;
}
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
dlmm: PublicKey // The DLMM pool address
opt?: { // Optional parameters
cluster?: Cluster | "localhost"; // The Solana cluster (mainnet, devnet, etc.)
programId?: PublicKey; // Custom program ID if different from default
}
```
**Returns**
An instance of the DLMM pool.
**Example**
```typescript theme={"system"}
// Creating a DLMM pool
// You can get your desired pool address from the API https://dlmm.datapi.meteora.ag/pair/all
const USDC_USDT_POOL = new PublicKey('ARwi1S4DaiTG5DX7S4M4ZsrXqpMD1MrTmbu9ue2tpmEq')
const dlmmPool = await DLMM.create(connection, USDC_USDT_POOL);
```
**Notes**
* The pool addresses can be fetched from the DLMM API [https://dlmm.datapi.meteora.ag/pair/all](https://dlmm.datapi.meteora.ag/pair/all)
* The `opt` parameter is optional and can be used to specify the cluster and program ID.
***
### createMultiple
Creates multiple instances of the DLMM pool given the pool addresses.
**Function**
```typescript theme={"system"}
async createMultiple(
connection: Connection,
dlmmList: Array,
opt?: {
cluster?: Cluster | "localhost";
programId?: PublicKey;
}
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
dlmmList: Array // The array of DLMM pool addresses
opt?: { // Optional parameters
cluster?: Cluster | "localhost"; // The Solana cluster (mainnet, devnet, etc.)
programId?: PublicKey; // Custom program ID if different from default
}
```
**Returns**
An array of DLMM instances.
**Example**
```typescript theme={"system"}
// Creating a DLMM pool
// You can get your desired pool address from the API https://dlmm.datapi.meteora.ag/pair/all
const USDC_USDT_POOL = new PublicKey('ARwi1S4DaiTG5DX7S4M4ZsrXqpMD1MrTmbu9ue2tpmEq')
const dlmmPool = await DLMM.createMultiple(connection, [USDC_USDT_POOL, ...]);
```
**Notes**
* The pool addresses can be fetched from the DLMM API [https://dlmm.datapi.meteora.ag/pair/all](https://dlmm.datapi.meteora.ag/pair/all)
* The `opt` parameter is optional and can be used to specify the cluster and program ID.
***
### createCustomizablePermissionlessLbPair
Creates a customizable permissionless LB pair. This function only supports token program.
**Function**
```typescript theme={"system"}
static async createCustomizablePermissionlessLbPair(
connection: Connection,
binStep: BN,
tokenX: PublicKey,
tokenY: PublicKey,
activeId: BN,
feeBps: BN,
activationType: ActivationType,
hasAlphaVault: boolean,
creatorKey: PublicKey,
activationPoint?: BN,
creatorPoolOnOffControl?: boolean,
opt?: {
cluster?: Cluster | "localhost";
programId?: PublicKey;
};
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
binStep: BN // Bin step of the pair
tokenX: PublicKey // Token X mint address
tokenY: PublicKey // Token Y mint address
activeId: BN // Active bin ID
feeBps: BN // Fee in basis points
activationType: ActivationType // Activation type
hasAlphaVault: boolean // Whether the pair has an alpha vault
creatorKey: PublicKey // Creator key
activationPoint?: BN // Optional activation point
creatorPoolOnOffControl?: boolean // Optional creator pool on/off control
opt?: Opt // Optional parameters
```
**Returns**
A transaction to create the customizable permissionless LB pair.
**Example**
```typescript theme={"system"}
const WEN = new PublicKey('WENWENvqqNya429ubCdR81ZmD69brwQaaBYY6p3LCpk')
const USDC = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
const binId = 8388608
const feeBps = new BN(100)
const activationPoint = new BN(1720000000)
const owner = new Keypair()
// Create a customizable permissionless LB pair
const transaction = await DLMM.createCustomizablePermissionlessLbPair(
connection,
new BN(binStep),
WEN,
USDC,
new BN(binId.toString()),
feeBps,
ActivationType.Slot,
false, // No alpha vault.
owner.publicKey,
activationPoint,
false,
{
cluster: "localhost",
}
);
```
**Notes**
* If Alpha Vault is enabled, the program will deterministically whitelist the alpha vault to swap before the pool start trading. Check: [https://github.com/MeteoraAg/alpha-vault-sdk](https://github.com/MeteoraAg/alpha-vault-sdk) `initialize{Prorata|Fcfs}Vault` method to create the alpha vault.
***
### createCustomizablePermissionlessLbPair2
Creates a customizable permissionless LB pair with specified parameters. This function supports both token and token2022 programs.
**Function**
```typescript theme={"system"}
static async createCustomizablePermissionlessLbPair2(
connection: Connection,
binStep: BN,
tokenX: PublicKey,
tokenY: PublicKey,
activeId: BN,
feeBps: BN,
activationType: ActivationType,
hasAlphaVault: boolean,
creatorKey: PublicKey,
activationPoint?: BN,
creatorPoolOnOffControl?: boolean,
opt?: Opt
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
binStep: BN // The bin step for the pair
tokenX: PublicKey // The mint of the first token
tokenY: PublicKey // The mint of the second token
activeId: BN // The ID of the initial active bin (starting price)
feeBps: BN // The fee rate for swaps in basis points
activationType: ActivationType // The type of activation for the pair
hasAlphaVault: boolean // Whether the pair has an alpha vault
creatorKey: PublicKey // The public key of the creator
activationPoint?: BN // Optional timestamp for activation
creatorPoolOnOffControl?: boolean // Optional creator control flag
opt?: Opt // Optional cluster and program ID
```
**Returns**
A transaction to create the customizable permissionless LB pair.
**Example**
```typescript theme={"system"}
const WEN = new PublicKey('WENWENvqqNya429ubCdR81ZmD69brwQaaBYY6p3LCpk')
const USDC = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
const binId = 8388608
const feeBps = new BN(100)
const activationPoint = new BN(1720000000)
const owner = new Keypair()
const transaction = await DLMM.createCustomizablePermissionlessLbPair2(
connection,
new BN(25), // 0.25% bin step
WEN,
USDC,
new BN(binId.toString()), // active bin ID representing starting price
new BN(feeBps.toString()), // 1% fee
ActivationType.Timestamp,
false, // no alpha vault
owner.publicKey,
activationPoint,
false,
{
cluster: "localhost",
}
);
```
**Notes**
* This creates a customizable permissionless pair that supports both token and token2022 programs
* The active bin ID represents the starting price of the pool
* Fee is specified in basis points (100 = 1%)
***
### createLbPair
Creates a new liquidity pair that supports only token program.
**Function**
```typescript theme={"system"}
static async createLbPair(
connection: Connection,
funder: PublicKey,
tokenX: PublicKey,
tokenY: PublicKey,
binStep: BN,
baseFactor: BN,
presetParameter: PublicKey,
activeId: BN,
opt?: Opt
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
funder: PublicKey // The public key of the funder
tokenX: PublicKey // The mint of the first token
tokenY: PublicKey // The mint of the second token
binStep: BN // The bin step for the pair
baseFactor: BN // The base factor for the pair
presetParameter: PublicKey // The public key of the preset parameter account
activeId: BN // The ID of the initial active bin
opt?: Opt // Optional parameters
```
**Returns**
A transaction to create the LB pair.
**Example**
```typescript theme={"system"}
const WEN = new PublicKey('WENWENvqqNya429ubCdR81ZmD69brwQaaBYY6p3LCpk')
const USDC = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
const activeBinId = 8388608
const binStep = new BN(25)
const baseFactor = new BN(10000)
const presetParamPda = derivePresetParameter2(
binStep,
baseFactor,
programId
);
const activationPoint = new BN(1720000000)
const owner = new Keypair()
const transaction = await DLMM.createLbPair(
connection,
owner.publicKey,
WEN,
USDC,
binStep,
baseFactor, // base factor
presetParamPda,
activeBinId // active bin ID
);
```
**Notes**
* Throws an error if the pair already exists
* Only supports token program
***
### createLbPair2
Creates a new liquidity pair that supports both token and token2022 programs.
**Function**
```typescript theme={"system"}
static async createLbPair2(
connection: Connection,
funder: PublicKey,
tokenX: PublicKey,
tokenY: PublicKey,
presetParameter: PublicKey,
activeId: BN,
opt?: Opt
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
funder: PublicKey // The public key of the funder
tokenX: PublicKey // The mint of the first token
tokenY: PublicKey // The mint of the second token
presetParameter: PublicKey // The public key of the preset parameter account
activeId: BN // The ID of the initial active bin
opt?: Opt // Optional parameters
```
**Returns**
A transaction to create the LB pair.
**Example**
```typescript theme={"system"}
const WEN = new PublicKey('WENWENvqqNya429ubCdR81ZmD69brwQaaBYY6p3LCpk')
const USDC = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
const activeBinId = 8388608
const binStep = new BN(25)
const baseFactor = new BN(10000)
const programId = LBCLMM_PROGRAM_IDS["mainnet-beta"]
const presetParamPda = derivePresetParameter2(
binStep,
baseFactor,
programId
);
const transaction = await DLMM.createLbPair2(
connection,
owner.publicKey,
WEN,
USDC,
presetParamPda,
activeBinId // active bin ID
);
```
**Notes**
* Throws an error if the pair already exists
* Supports both token and token2022 programs
***
### initializePositionAndAddLiquidityByStrategy
Initializes a new position and adds liquidity using a specified strategy.
**Function**
```typescript theme={"system"}
async initializePositionAndAddLiquidityByStrategy({
positionPubKey,
totalXAmount,
totalYAmount,
strategy,
user,
slippage,
}: TInitializePositionAndAddLiquidityParamsByStrategy): Promise
```
**Parameters**
```typescript theme={"system"}
positionPubKey: PublicKey // The public key of the position account (usually new Keypair())
totalXAmount: BN // Total amount of token X to add
totalYAmount: BN // Total amount of token Y to add
strategy: StrategyParameters // Strategy parameters (can use calculateStrategyParameter)
user: PublicKey // The public key of the user account
slippage?: number // Optional slippage percentage
```
**Returns**
A transaction for initializing the position and adding liquidity.
**Example**
```typescript theme={"system"}
const positionKeypair = new Keypair();
const btcInAmount = new BN(1).mul(new BN(10 ** btcDecimal));
const usdcInAmount = new BN(24000).mul(new BN(10 ** usdcDecimal));
const strategy = {
strategyType: StrategyType.SpotBalanced,
minBinId: 8388600,
maxBinId: 8388620,
};
const transaction = await dlmmPool.initializePositionAndAddLiquidityByStrategy({
positionPubKey: positionKeypair.publicKey,
totalXAmount: btcInAmount,
totalYAmount: usdcInAmount,
strategy,
user: userPublicKey,
slippage: 1 // 1% slippage
});
```
**Notes**
* `positionPubKey`: The public key of the position account (usually use `new Keypair()`). The keypair must be passed as a signer when sending the transaction.
* `strategy`: The strategy parameters defining the bin range and distribution type.
* For bin ranges that exceed a single position's width, use `initializeMultiplePositionAndAddLiquidityByStrategy` instead.
***
### addLiquidityByStrategy
Adds liquidity to an existing position using a specified strategy.
**Function**
```typescript theme={"system"}
async addLiquidityByStrategy({
positionPubKey,
totalXAmount,
totalYAmount,
strategy,
user,
slippage,
}: TInitializePositionAndAddLiquidityParamsByStrategy): Promise
```
**Parameters**
```typescript theme={"system"}
positionPubKey: PublicKey // The public key of the existing position
totalXAmount: BN // Total amount of token X to add
totalYAmount: BN // Total amount of token Y to add
strategy: StrategyParameters // Strategy parameters
user: PublicKey // The public key of the user account
slippage?: number // Optional slippage percentage
```
**Returns**
A transaction for adding liquidity to the position.
**Example**
```typescript theme={"system"}
const btcInAmount = new BN(1).mul(new BN(10 ** btcDecimal));
const usdcInAmount = new BN(24000).mul(new BN(10 ** usdcDecimal));
const transaction = await dlmmPool.addLiquidityByStrategy({
positionPubKey: position.publicKey,
totalXAmount: btcInAmount,
totalYAmount: usdcInAmount,
strategy: {
minBinId: 8388600,
maxBinId: 8388620,
strategyType: StrategyType.SpotBalanced,
},
user: userPublicKey,
slippage: 1
});
```
**Notes**
* `positionPubKey`: The public key of an existing position to add liquidity to.
* `strategy`: The strategy parameters defining the bin range and distribution type. The bin range must fall within the existing position bounds. To auto-expand, use `addLiquidityByStrategyChunkable` instead.
***
### addLiquidityByStrategyChunkable
Adds liquidity to an existing position using a specified strategy. Automatically expands the position if the target bin range extends beyond the current position bounds (up to 70 bins maximum). Returns an array of transactions for chunkable execution.
**Function**
```typescript theme={"system"}
async addLiquidityByStrategyChunkable({
positionPubKey,
totalXAmount,
totalYAmount,
strategy,
user,
slippage,
}: TInitializePositionAndAddLiquidityParamsByStrategy): Promise
```
**Parameters**
```typescript theme={"system"}
positionPubKey: PublicKey // The public key of the existing position
totalXAmount: BN // Total amount of token X to add
totalYAmount: BN // Total amount of token Y to add
strategy: StrategyParameters // Strategy parameters defining the bin range and type
user: PublicKey // The public key of the user
slippage?: number // Optional slippage percentage
```
**Returns**
An array of transactions. Multiple transactions may be returned when the bin range spans many bins.
**Example**
```typescript theme={"system"}
const transactions = await dlmmPool.addLiquidityByStrategyChunkable({
positionPubKey: position.publicKey,
totalXAmount: new BN(1_000_000),
totalYAmount: new BN(24_000_000),
strategy: {
minBinId: 8388600,
maxBinId: 8388670,
strategyType: StrategyType.SpotBalanced,
},
user: userPublicKey,
slippage: 1,
});
for (const tx of transactions) {
await sendAndConfirmTransaction(connection, tx, [userKeypair]);
}
```
**Notes**
* Automatically expands the position if the target bin range is larger than the current position bounds (up to 70 bins maximum).
* Returns multiple transactions when the range requires it. Sign and send each transaction sequentially.
* Differs from `addLiquidityByStrategy`, which returns a single transaction and does not auto-expand.
***
### initializeMultiplePositionAndAddLiquidityByStrategy
Initializes multiple positions and adds liquidity across all of them using a single strategy. Use this when depositing into a bin range that exceeds a single position's maximum width.
**Function**
```typescript theme={"system"}
async initializeMultiplePositionAndAddLiquidityByStrategy(
positionKeypairGenerator: (count: number) => Promise,
totalXAmount: BN,
totalYAmount: BN,
strategy: StrategyParameters,
owner: PublicKey,
payer: PublicKey,
slippagePercentage: number
): Promise
```
**Parameters**
```typescript theme={"system"}
positionKeypairGenerator: (count: number) => Promise
// Async function that generates the required keypairs
totalXAmount: BN // Total amount of token X to add
totalYAmount: BN // Total amount of token Y to add
strategy: StrategyParameters // Strategy parameters defining the bin range and type
owner: PublicKey // Owner of the positions
payer: PublicKey // Payer for rent and transaction fees
slippagePercentage: number // Slippage tolerance as a percentage
```
**Returns**
```typescript theme={"system"}
{
instructionsByPositions: {
positionKeypair: Keypair;
initializePositionIx: TransactionInstruction;
initializeAtaIxs: TransactionInstruction[];
addLiquidityIxs: TransactionInstruction[][];
}[];
}
```
An object where each entry contains the keypair and all instructions needed to initialize and fund one position.
**Example**
```typescript theme={"system"}
const response = await dlmmPool.initializeMultiplePositionAndAddLiquidityByStrategy(
async (count) => Array.from({ length: count }, () => new Keypair()),
new BN(1_000_000),
new BN(24_000_000),
{
minBinId: 8388550,
maxBinId: 8388700,
strategyType: StrategyType.SpotBalanced,
},
userPublicKey,
userPublicKey,
1 // 1% slippage
);
for (const { positionKeypair, initializePositionIx, initializeAtaIxs, addLiquidityIxs } of response.instructionsByPositions) {
// Build and send transactions for each position
}
```
**Notes**
* The number of positions is automatically calculated from the bin range width.
* `positionKeypairGenerator` receives the required count and must return that many fresh `Keypair` instances.
* Use this when `strategy.minBinId` to `strategy.maxBinId` exceeds the per-position maximum bin count.
***
### removeLiquidity
Removes liquidity from a position with options to claim rewards and close the position.
**Function**
```typescript theme={"system"}
async removeLiquidity({
user,
position,
fromBinId,
toBinId,
bps,
shouldClaimAndClose = false,
skipUnwrapSOL = false,
}: {
user: PublicKey;
position: PublicKey;
fromBinId: number;
toBinId: number;
bps: BN;
shouldClaimAndClose?: boolean;
skipUnwrapSOL?: boolean;
}): Promise
```
**Parameters**
```typescript theme={"system"}
user: PublicKey // The public key of the user account
position: PublicKey // The public key of the position account
fromBinId: number // Starting bin ID to remove liquidity from
toBinId: number // Ending bin ID to remove liquidity from
bps: BN // Percentage of liquidity to remove (in basis points)
shouldClaimAndClose?: boolean // Whether to claim rewards and close position (default: false)
skipUnwrapSOL?: boolean // Whether to skip unwrapping wSOL to SOL (default: false)
```
**Returns**
An array of transactions for removing liquidity.
**Example**
```typescript theme={"system"}
// Remove 50% of liquidity from position
const transaction = await dlmmPool.removeLiquidity({
user: userPublicKey,
position: positionPublicKey,
fromBinId: 8388600,
toBinId: 8388620,
bps: new BN(5000), // 50% in basis points
shouldClaimAndClose: false
});
```
**Notes**
* `fromBinId` and `toBinId` must be within the position's bin range.
* `bps`: Basis points of liquidity to remove (e.g. 5000 = 50%, 10000 = 100%).
* `shouldClaimAndClose`: When true, claims all rewards and closes the position after removing liquidity.
* `skipUnwrapSOL`: When true, keeps withdrawn SOL as wrapped SOL (wSOL) instead of unwrapping.
***
### swapQuote
Returns a quote for a swap operation.
**Function**
```typescript theme={"system"}
swapQuote(
inAmount: BN,
swapForY: boolean,
allowedSlippage: BN,
binArrays: BinArrayAccount[],
isPartialFill?: boolean,
maxExtraBinArrays: number = 0
): SwapQuote
```
**Parameters**
```typescript theme={"system"}
inAmount: BN // Amount of lamports to swap in
swapForY: boolean // True to swap X to Y, false for Y to X
allowedSlippage: BN // Allowed slippage in basis points
binArrays: BinArrayAccount[] // Bin arrays for the swap quote
isPartialFill?: boolean // Whether partial fill is allowed
maxExtraBinArrays?: number // Maximum extra bin arrays to return
```
**Returns**
A SwapQuote object containing swap information.
**Example**
```typescript theme={"system"}
const binArrays = await dlmmPool.getBinArrayForSwap(true, 5);
const swapQuote = dlmmPool.swapQuote(
new BN(1000000), // 1 token input
true, // swap X for Y
new BN(100), // 1% slippage
binArrays,
false, // no partial fill
2 // max extra bin arrays
);
```
**Notes**
* This is a synchronous method — it computes the quote locally without RPC calls.
* `allowedSlippage` is in BPS (basis points). To convert from percentage: `SLIPPAGE_PERCENTAGE * 100` (e.g., 1% = 100 BPS).
* Use `getBinArrayForSwap` to fetch the required `binArrays` parameter.
* The returned `SwapQuote.binArraysPubkey` can be passed directly to the `swap` method.
***
### swapQuoteExactOut
Returns a quote for a swap with exact output amount.
**Function**
```typescript theme={"system"}
swapQuoteExactOut(
outAmount: BN,
swapForY: boolean,
allowedSlippage: BN,
binArrays: BinArrayAccount[],
maxExtraBinArrays: number = 0
): SwapQuoteExactOut
```
**Parameters**
```typescript theme={"system"}
outAmount: BN // Amount of lamports to swap out
swapForY: boolean // True to swap X to Y, false for Y to X
allowedSlippage: BN // Allowed slippage in basis points
binArrays: BinArrayAccount[] // Bin arrays for the swap quote
maxExtraBinArrays?: number // Maximum extra bin arrays to return
```
**Returns**
A SwapQuoteExactOut object containing swap information.
**Example**
```typescript theme={"system"}
const binArrays = await dlmmPool.getBinArrayForSwap(true, 5);
const swapQuote = dlmmPool.swapQuoteExactOut(
new BN(1000000), // 1 token output
true, // swap X for Y
new BN(100), // 1% slippage
binArrays,
2 // max extra bin arrays
);
```
**Notes**
* This is a synchronous method — it computes the quote locally without RPC calls.
* `allowedSlippage` is in BPS (basis points). To convert from percentage: `SLIPPAGE_PERCENTAGE * 100`.
* The returned `SwapQuoteExactOut.binArraysPubkey` can be passed directly to the `swapExactOut` method.
***
### swapExactOut
Executes a swap operation with exact output amount.
**Function**
```typescript theme={"system"}
async swapExactOut({
inToken,
outToken,
outAmount,
maxInAmount,
lbPair,
user,
binArraysPubkey,
}: SwapExactOutParams): Promise
```
**Parameters**
```typescript theme={"system"}
inToken: PublicKey // The public key of input token mint
outToken: PublicKey // The public key of output token mint
outAmount: BN // Exact amount of output token to receive
maxInAmount: BN // Maximum amount of input token to spend
lbPair: PublicKey // The public key of the liquidity pool
user: PublicKey // The public key of the user account
binArraysPubkey: PublicKey[] // Array of bin arrays involved in swap
```
**Returns**
A transaction for executing the exact out swap.
**Example**
```typescript theme={"system"}
const swapTx = await dlmmPool.swapExactOut({
inToken: tokenXMint,
outToken: tokenYMint,
outAmount: new BN(1000000),
maxInAmount: new BN(1100000),
lbPair: dlmmPool.pubkey,
user: userPublicKey,
binArraysPubkey: swapQuote.binArraysPubkey
});
```
**Notes**
* Use `swapQuoteExactOut` to compute `maxInAmount` and `binArraysPubkey` before calling this method.
***
### swapWithPriceImpact
Executes a swap with price impact constraints.
**Function**
```typescript theme={"system"}
async swapWithPriceImpact({
inToken,
outToken,
inAmount,
lbPair,
user,
priceImpact,
binArraysPubkey,
}: SwapWithPriceImpactParams): Promise
```
**Parameters**
```typescript theme={"system"}
inToken: PublicKey // The public key of input token mint
outToken: PublicKey // The public key of output token mint
inAmount: BN // Amount of input token to swap
lbPair: PublicKey // The public key of the liquidity pool
user: PublicKey // The public key of the user account
priceImpact: BN // Accepted price impact in basis points
binArraysPubkey: PublicKey[] // Array of bin arrays involved in swap
```
**Returns**
A transaction for executing the swap with price impact constraints.
**Example**
```typescript theme={"system"}
const swapTx = await dlmmPool.swapWithPriceImpact({
inToken: tokenXMint,
outToken: tokenYMint,
inAmount: new BN(1000000),
lbPair: dlmmPool.pubkey,
user: userPublicKey,
priceImpact: new BN(50), // 0.5% max price impact
binArraysPubkey: binArrays.map(b => b.publicKey)
});
```
**Notes**
* `priceImpact` is in BPS (e.g., 50 = 0.5%). The swap will fail on-chain if the actual price impact exceeds this threshold.
***
### swap
Executes a swap operation.
**Function**
```typescript theme={"system"}
async swap({
inToken,
outToken,
inAmount,
minOutAmount,
lbPair,
user,
binArraysPubkey,
}: SwapParams): Promise
```
**Parameters**
```typescript theme={"system"}
inToken: PublicKey // The public key of input token mint
outToken: PublicKey // The public key of output token mint
inAmount: BN // Amount of input token to swap
minOutAmount: BN // Minimum amount of output token expected
lbPair: PublicKey // The public key of the liquidity pool
user: PublicKey // The public key of the user account
binArraysPubkey: PublicKey[] // Array of bin arrays involved in swap
```
**Returns**
A transaction for executing the swap.
**Example**
```typescript theme={"system"}
// Execute swap
const swapTx = await dlmmPool.swap({
inToken: tokenXMint,
outToken: tokenYMint,
inAmount: new BN(1000000),
minOutAmount: new BN(950000), // accounting for slippage
lbPair: dlmmPool.pubkey,
user: userPublicKey,
binArraysPubkey: swapQuote.binArraysPubkey
});
```
**Notes**
* Use `swapQuote` to compute `minOutAmount` and `binArraysPubkey` before calling this method.
* The swap will fail on-chain if the output is less than `minOutAmount`.
***
### claimLMReward
Claims liquidity mining rewards for a specific position.
**Function**
```typescript theme={"system"}
async claimLMReward({
owner,
position,
}: {
owner: PublicKey;
position: LbPosition;
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the position owner
position: LbPosition // The position object containing position data
```
**Returns**
An array of transactions for claiming LM rewards.
**Example**
```typescript theme={"system"}
// Claim LM rewards for a position
const position = await dlmmPool.getPosition(positionPublicKey);
const claimTxs = await dlmmPool.claimLMReward({
owner: userPublicKey,
position
});
```
**Notes**
* This function is only available for LB pairs with liquidity mining rewards.
* Throws an error if the position has no LM rewards to claim.
***
### claimAllLMRewards
Claims all liquidity mining rewards for multiple positions.
**Function**
```typescript theme={"system"}
async claimAllLMRewards({
owner,
positions,
}: {
owner: PublicKey;
positions: LbPosition[];
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the positions owner
positions: LbPosition[] // Array of position objects
```
**Returns**
Array of transactions for claiming all LM rewards.
**Example**
```typescript theme={"system"}
const positions = await dlmmPool.getPositionsByUserAndLbPair(userPublicKey);
const claimTxs = await dlmmPool.claimAllLMRewards({
owner: userPublicKey,
positions: positions.userPositions
});
```
**Notes**
* This function is only available for LB pairs with liquidity mining rewards.
***
### claimSwapFee
Claims swap fees earned by a specific position.
**Function**
```typescript theme={"system"}
async claimSwapFee({
owner,
position,
}: {
owner: PublicKey;
position: LbPosition;
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the position owner
position: LbPosition // The position object containing position data
```
**Returns**
An array of transactions for claiming swap fees.
**Example**
```typescript theme={"system"}
const position = await dlmmPool.getPosition(positionPublicKey);
const claimFeeTxs = await dlmmPool.claimSwapFee({
owner: userPublicKey,
position
});
```
**Notes**
* Throws an error if the position has no swap fees to claim.
***
### claimAllSwapFee
Claims swap fees for multiple positions.
**Function**
```typescript theme={"system"}
async claimAllSwapFee({
owner,
positions,
}: {
owner: PublicKey;
positions: LbPosition[];
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the positions owner
positions: LbPosition[] // Array of position objects
```
**Returns**
Array of transactions for claiming all swap fees.
**Example**
```typescript theme={"system"}
// Claim all swap fees for user positions
const positions = await dlmmPool.getPositionsByUserAndLbPair(userPublicKey);
const claimFeeTxs = await dlmmPool.claimAllSwapFee({
owner: userPublicKey,
positions: positions.userPositions
});
```
**Notes**
* Batch claims swap fees across all provided positions. Each position generates its own transaction(s).
***
### claimAllRewards
Claims all rewards (both LM rewards and swap fees) for multiple positions.
**Function**
```typescript theme={"system"}
async claimAllRewards({
owner,
positions,
}: {
owner: PublicKey;
positions: LbPosition[];
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the positions owner
positions: LbPosition[] // Array of position objects
```
**Returns**
Array of transactions for claiming all rewards.
**Example**
```typescript theme={"system"}
const positions = await dlmmPool.getPositionsByUserAndLbPair(userPublicKey);
const claimAllTxs = await dlmmPool.claimAllRewards({
owner: userPublicKey,
positions: positions.userPositions
});
```
**Notes**
* Combines both `claimAllLMRewards` and `claimAllSwapFee` into a single call for convenience.
***
### claimAllRewardsByPosition
Claims all rewards (both LM rewards and swap fees) for a specific position.
**Function**
```typescript theme={"system"}
async claimAllRewardsByPosition({
owner,
position,
}: {
owner: PublicKey;
position: LbPosition;
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the position owner
position: LbPosition // The position object to claim rewards for
```
**Returns**
Array of transactions for claiming all rewards for the position.
**Example**
```typescript theme={"system"}
// Claim all rewards for a specific position
const position = await dlmmPool.getPosition(positionPublicKey);
const claimAllTxs = await dlmmPool.claimAllRewardsByPosition({
owner: userPublicKey,
position
});
```
**Notes**
* Claims both LM rewards and swap fees for a single position in one call.
***
### closePosition
Closes a position and recovers the rent.
**Function**
```typescript theme={"system"}
async closePosition({
owner,
position,
}: {
owner: PublicKey;
position: LbPosition;
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the position owner
position: LbPosition // The position object to close
```
**Returns**
A transaction for closing the position.
**Example**
```typescript theme={"system"}
// Close a position
const position = await dlmmPool.getPosition(positionPublicKey);
const closeTx = await dlmmPool.closePosition({
owner: userPublicKey,
position
});
```
**Notes**
* Position must have zero liquidity before closing. Use `removeLiquidity` with `shouldClaimAndClose: true` to remove liquidity, claim, and close in one step.
***
### closePositionIfEmpty
Closes a position if it is empty, otherwise does nothing.
**Function**
```typescript theme={"system"}
async closePositionIfEmpty({
owner,
position,
}: {
owner: PublicKey;
position: LbPosition;
}): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the position owner
position: LbPosition // The position object to close
```
**Returns**
A transaction for closing the position if empty.
**Example**
```typescript theme={"system"}
// Close position if empty
const position = await dlmmPool.getPosition(positionPublicKey);
const closeTx = await dlmmPool.closePositionIfEmpty({
owner: userPublicKey,
position
});
```
**Notes**
* Useful for cleanup after liquidity has been fully withdrawn from a position.
***
### quoteCreatePosition
Quotes the cost of creating a position with a given strategy.
**Function**
```typescript theme={"system"}
async quoteCreatePosition({ strategy }: TQuoteCreatePositionParams)
```
**Parameters**
```typescript theme={"system"}
strategy: StrategyParameters // Strategy parameters containing min/max bin IDs
```
**Returns**
An object containing cost breakdown information.
**Example**
```typescript theme={"system"}
// Quote position creation cost
const quote = await dlmmPool.quoteCreatePosition({
strategy: {
minBinId: 8388600,
maxBinId: 8388620,
strategyType: StrategyType.SpotBalanced,
}
});
```
**Notes**
* Useful for estimating costs before committing to a position. Includes rent for position accounts, bin arrays, and optional bitmap extension.
***
### createEmptyPosition
Creates an empty position and initializes the corresponding bin arrays if needed.
**Function**
```typescript theme={"system"}
async createEmptyPosition({
positionPubKey,
minBinId,
maxBinId,
user,
}: {
positionPubKey: PublicKey;
minBinId: number;
maxBinId: number;
user: PublicKey;
})
```
**Parameters**
```typescript theme={"system"}
positionPubKey: PublicKey // The public key of the position account
minBinId: number // Lower bin ID of the position
maxBinId: number // Upper bin ID of the position
user: PublicKey // The public key of the user account
```
**Returns**
A transaction for creating the empty position.
**Example**
```typescript theme={"system"}
const positionKeypair = Keypair.generate();
const createTx = await dlmmPool.createEmptyPosition({
positionPubKey: positionKeypair.publicKey,
minBinId: 8388600,
maxBinId: 8388620,
user: userPublicKey
});
```
**Notes**
* Creates the position account and initializes any required bin arrays. Add liquidity separately using `addLiquidityByStrategy`.
***
### seedLiquidity
Creates multiple grouped instructions. The grouped instructions will be \[init ata + send lamport for token provde], \[initialize bin array + initialize position instructions] and \[deposit instruction]. Each grouped instructions can be executed parallelly.
**Function**
```typescript theme={"system"}
async seedLiquidity(
owner: PublicKey,
seedAmount: BN,
curvature: number,
minPrice: number,
maxPrice: number,
base: PublicKey,
payer: PublicKey,
feeOwner: PublicKey,
operator: PublicKey,
lockReleasePoint: BN,
shouldSeedPositionOwner: boolean = false
): Promise
```
**Parameters**
```typescript theme={"system"}
owner: PublicKey // The public key of the positions owner
seedAmount: BN // Lamport amount to be seeded to the pool
curvature: number // Distribution curvature parameter
minPrice: number // Start price in UI format
maxPrice: number // End price in UI format
base: PublicKey // Base key for position derivation
payer: PublicKey // Account rental fee payer
feeOwner: PublicKey // Fee owner key
operator: PublicKey // Operator key
lockReleasePoint: BN // Timelock point for position withdrawal
shouldSeedPositionOwner?: boolean // Whether to send token to position owner
```
**Returns**
A SeedLiquidityResponse containing grouped instructions and cost breakdown.
**Example**
```typescript theme={"system"}
const curvature = 0.6;
const minPrice = 0.000001;
const maxPrice = 0.00003;
const currentSlot = await connection.getSlot();
const lockDuration = new BN(86400 * 31);
const lockReleaseSlot = lockDuration.add(new BN(currentSlot));
const seedResponse = await dlmmPool.seedLiquidity(
ownerPublicKey,
new BN(200_000_000_000),
curvature,
minPrice,
maxPrice,
baseKeypair.publicKey,
payerPublicKey,
feeOwnerPublicKey,
operatorPublicKey,
lockReleaseSlot,
true
);
```
**Notes**
* `owner`: The public key of the positions owner.
* `seedAmount`: Lamport amount to be seeded to the pool.
* `minPrice`: Start price in UI format
* `maxPrice`: End price in UI format
* `base`: Base key
* `txPayer`: Account rental fee payer
* `feeOwner`: Fee owner key. Default to position owner
* `operator`: Operator key
* `lockReleasePoint`: Timelock. Point (slot/timestamp) the position can withdraw the liquidity,
* `shouldSeedPositionOwner` (optional): Whether to send 1 lamport amount of token X to the position owner to prove ownership.
***
### seedLiquiditySingleBin
Seeds liquidity into a single bin at a specific price.
**Function**
```typescript theme={"system"}
async seedLiquiditySingleBin(
payer: PublicKey,
base: PublicKey,
seedAmount: BN,
price: number,
roundingUp: boolean,
positionOwner: PublicKey,
feeOwner: PublicKey,
operator: PublicKey,
lockReleasePoint: BN,
shouldSeedPositionOwner: boolean = false
): Promise
```
**Parameters**
```typescript theme={"system"}
payer: PublicKey // The public key of the tx payer
base: PublicKey // Base key for position derivation
seedAmount: BN // Token X lamport amount to be seeded
price: number // TokenX/TokenY Price in UI format
roundingUp: boolean // Whether to round up the price
positionOwner: PublicKey // The owner of the position
feeOwner: PublicKey // Position fee owner
operator: PublicKey // Operator of the position
lockReleasePoint: BN // The lock release point of the position
shouldSeedPositionOwner?: boolean // Whether to send token to position owner
```
**Returns**
A SeedLiquiditySingleBinResponse containing instructions and cost breakdown.
**Example**
```typescript theme={"system"}
const initialPrice = 0.000001;
const seedResponse = await dlmmPool.seedLiquiditySingleBin(
payerPublicKey,
baseKeypair.publicKey,
new BN(1000000),
initialPrice,
true,
ownerPublicKey,
feeOwnerPublicKey,
operatorPublicKey,
new BN(Date.now() / 1000 + 86400)
);
```
**Notes**
* `payer`: The public key of the tx payer.
* `base`: Base key
* `seedAmount`: Token X lamport amount to be seeded to the pool.
* `price`: TokenX/TokenY Price in UI format
* `roundingUp`: Whether to round up the price
* `positionOwner`: The owner of the position
* `feeOwner`: Position fee owner
* `operator`: Operator of the position. Operator able to manage the position on behalf of the position owner. However, liquidity withdrawal issue by the operator can only send to the position owner.
* `lockReleasePoint`: The lock release point of the position.
* `shouldSeedPositionOwner` (optional): Whether to send 1 lamport amount of token X to the position owner to prove ownership.
***
### initializeBinArrays
Initializes bin arrays for the given bin array indexes if they weren't initialized.
**Function**
```typescript theme={"system"}
async initializeBinArrays(binArrayIndexes: BN[], funder: PublicKey)
```
**Parameters**
```typescript theme={"system"}
binArrayIndexes: BN[] // Array of bin array indexes to initialize
funder: PublicKey // The public key of the funder
```
**Returns**
Array of transaction instructions to initialize the bin arrays.
**Example**
```typescript theme={"system"}
// Initialize specific bin arrays
const binArrayIndexes = [new BN(-1), new BN(0), new BN(1)];
const instructions = await dlmmPool.initializeBinArrays(
binArrayIndexes,
funderPublicKey
);
```
**Notes**
* Only initializes bin arrays that don't already exist on-chain. Use `binIdToBinArrayIndex` to compute the required indexes.
***
### initializePositionByOperator
Initializes a position with an operator that can manage it on behalf of the owner.
**Function**
```typescript theme={"system"}
async initializePositionByOperator({
lowerBinId,
positionWidth,
owner,
feeOwner,
base,
operator,
payer,
lockReleasePoint,
}: {
lowerBinId: BN;
positionWidth: BN;
owner: PublicKey;
feeOwner: PublicKey;
operator: PublicKey;
payer: PublicKey;
base: PublicKey;
lockReleasePoint: BN;
}): Promise
```
**Parameters**
```typescript theme={"system"}
lowerBinId: BN // Lower bin ID of the position
positionWidth: BN // Width of the position
owner: PublicKey // Owner of the position
feeOwner: PublicKey // Owner of the fees earned by the position
operator: PublicKey // Operator of the position
payer: PublicKey // Payer for the position account rental
base: PublicKey // Base key for position derivation
lockReleasePoint: BN // The lock release point of the position
```
**Returns**
A transaction for initializing the position by operator.
**Example**
```typescript theme={"system"}
const initTx = await dlmmPool.initializePositionByOperator({
lowerBinId: new BN(5660),
positionWidth: MAX_BIN_PER_POSITION,
owner: ownerPublicKey,
feeOwner: feeOwnerPublicKey,
operator: operatorPublicKey,
payer: payerPublicKey,
base: baseKeypair.publicKey,
lockReleasePoint: new BN(Date.now() / 1000 + 86400)
});
```
**Notes**
* `lowerBinId`: Lower bin ID of the position. This represent the lowest price of the position
* `positionWidth`: Width of the position. This will decide the upper bin id of the position, which represents the highest price of the position. UpperBinId = lowerBinId + positionWidth
* `owner`: Owner of the position.
* `operator`: Operator of the position. Operator able to manage the position on behalf of the position owner. However, liquidity withdrawal issue by the operator can only send to the position owner.
* `base`: Base key
* `feeOwner`: Owner of the fees earned by the position.
* `payer`: Payer for the position account rental.
* `lockReleasePoint`: The lock release point of the position.
***
### setPairStatusPermissionless
Sets the status of a permissionless LB pair to either enabled or disabled.
**Function**
```typescript theme={"system"}
async setPairStatusPermissionless(
enable: boolean,
creator: PublicKey
)
```
**Parameters**
```typescript theme={"system"}
enable: boolean // If true, enables the pair; if false, disables it
creator: PublicKey // The public key of the pool creator
```
**Returns**
A transaction for setting the pair status.
**Example**
```typescript theme={"system"}
const statusTx = await dlmmPool.setPairStatusPermissionless(
true,
creatorPublicKey
);
```
**Notes**
* Requires `creator_pool_on_off_control` to be true and type `CustomizablePermissionless`
* Pool creator can enable/disable anytime before activation
* After activation, creator can only enable the pair
***
### setActivationPoint
Sets the activation point for the LB pair.
**Function**
```typescript theme={"system"}
async setActivationPoint(activationPoint: BN)
```
**Parameters**
```typescript theme={"system"}
activationPoint: BN // The activation point (timestamp/slot)
```
**Returns**
A transaction for setting the activation point.
**Example**
```typescript theme={"system"}
const activationTx = await dlmmPool.setActivationPoint(
new BN(Date.now() / 1000 + 3600)
);
```
**Notes**
* The activation point determines when the pool becomes active. Interpretation depends on `ActivationType` (slot number or Unix timestamp).
***
### setPairStatus
Sets the pair status (enabled/disabled) for admin-controlled pairs.
**Function**
```typescript theme={"system"}
async setPairStatus(enabled: boolean): Promise
```
**Parameters**
```typescript theme={"system"}
enabled: boolean // Whether to enable or disable the pair
```
**Returns**
A transaction for setting the pair status.
**Example**
```typescript theme={"system"}
const statusTx = await dlmmPool.setPairStatus(true); // enable
```
**Notes**
* Only available for admin-controlled (permissioned) pairs. For permissionless pairs, use `setPairStatusPermissionless`.
***
## State Functions
### getLbPairs
Retrieves all LB pair accounts for the DLMM program.
**Function**
```typescript theme={"system"}
static async getLbPairs(
connection: Connection,
opt?: Opt
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
opt?: Opt // Optional cluster and program ID
```
**Returns**
An array of LB pair account objects.
**Example**
```typescript theme={"system"}
const allPairs = await DLMM.getLbPairs(connection);
```
**Notes**
* Returns all pairs on-chain.
***
### getCustomizablePermissionlessLbPairIfExists
Retrieves the public key of a customizable permissionless LB pair if it exists.
**Function**
```typescript theme={"system"}
static async getCustomizablePermissionlessLbPairIfExists(
connection: Connection,
tokenX: PublicKey,
tokenY: PublicKey,
opt?: Opt
): Promise
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
tokenX: PublicKey // Token X mint address
tokenY: PublicKey // Token Y mint address
opt?: Opt // Optional parameters
```
**Returns**
Public key of the pair if it exists, null otherwise.
**Example**
```typescript theme={"system"}
const WEN = new PublicKey('WENWENvqqNya429ubCdR81ZmD69brwQaaBYY6p3LCpk')
const USDC = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
const pairPubkey = await DLMM.getCustomizablePermissionlessLbPairIfExists(
connection,
WEN,
USDC,
{
cluster: "localhost",
}
);
```
***
### getPosition
Retrieves position information for a given position public key.
**Function**
```typescript theme={"system"}
async getPosition(positionPubKey: PublicKey): Promise
```
**Parameters**
```typescript theme={"system"}
positionPubKey: PublicKey // The public key of the position account
```
**Returns**
An LbPosition object containing position data and metadata.
**Example**
```typescript theme={"system"}
const position = await dlmmPool.getPosition(positionPublicKey);
```
**Notes**
* Returns position data including bin range, liquidity distribution, and fee/reward accruals.
***
### getAllPresetParameters
Retrieves all preset parameter accounts for the DLMM program.
**Function**
```typescript theme={"system"}
static async getAllPresetParameters(
connection: Connection,
opt?: Opt
): Promise<{
presetParameter: PresetParameterAccount[];
presetParameter2: PresetParameter2Account[];
}>
```
**Parameters**
```typescript theme={"system"}
connection: Connection // Solana connection instance
opt?: Opt // Optional cluster and program ID
```
**Returns**
An object containing preset parameter accounts.
**Example**
```typescript theme={"system"}
const presetParams = await DLMM.getAllPresetParameters(connection);
```
**Notes**
* Returns both `presetParameter` (v1) and `presetParameter2` (v2) accounts. Use `presetParameter2` for new pool creation with `createLbPair2`.
***
### getAllLbPairPositionsByUser
Retrieves all LB pair positions for a given user.
**Function**
```typescript theme={"system"}
static async getAllLbPairPositionsByUser(
connection: Connection,
userPubKey: PublicKey,
opt?: Opt,
getPositionsOpt?: GetPositionsOpt
): Promise