# 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:
```math theme={"system"} \text{Passed Period} = \frac{(\text{Current Sqrt Price} - \text{Initial Sqrt Price}) \times {10,000}}{\text{Initial Sqrt Price} \times \text{Sqrt Price Step Bps}} ```
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)
```math theme={"system"} \text{Current Fee} = \text{Cliff Fee Numerator} - (\text{Passed Period} \times \text{Reduction Factor}) ```
The fee decreases by a constant amount (`reduction_factor`) for each period passed. ### Exponential Fee Market Cap Scheduler (Mode 4)
```math theme={"system"} \text{Current Fee} = \text{Cliff Fee Numerator} \times \left(1 - \frac{\text{Reduction Factor}}{10,000}\right)^{\text{Passed Period}} ```
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. Linear Fee Market Cap Scheduler Fee decreases at a constant rate as the token price increases. At the same price point, the fee is higher compared to exponential decay. Exponential Fee Market Cap Scheduler 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]:
```math theme={"system"} \text{Ending Fee} = \text{Cliff Fee Numerator} - (\text{Number Of Periods} \times \text{Reduction Factor}) ```
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]:
```math theme={"system"} \text{Ending Fee} = \text{Cliff Fee Numerator} \times \left(1 - \frac{\text{Reduction Factor}}{10000}\right)^{\text{Number Of Periods}} ```
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} ```
```math theme={"system"} \text{Fee} = x_0 \times (c + c \times \text{Max Index} + i \times \text{Max Index} \times (\text{Max Index}+1) / 2) + (d \times x_0 + b) \times \text{Max Fee} ```
# 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> ``` **Parameters** ```typescript theme={"system"} connection: Connection // Solana connection instance userPubKey: PublicKey // The user's wallet public key opt?: Opt // Optional cluster and program ID getPositionsOpt?: GetPositionsOpt // Optional chunked fetch settings (chunkSize, onChunkFetched, isParallelExecution) ``` **Returns** A Map containing LB pair addresses and their position information. **Example** ```typescript theme={"system"} // Get all positions for a user const userPositions = await DLMM.getAllLbPairPositionsByUser( connection, userPublicKey ); userPositions.forEach((positionInfo, lbPairAddress) => { console.log(`Positions in pool ${lbPairAddress}:`, positionInfo); }); ``` **Notes** * Use `getPositionsOpt` for large accounts to control chunk size and enable parallel execution. *** ### refetchStates Refetches and updates the current state of the DLMM instance. **Function** ```typescript theme={"system"} async refetchStates(): Promise ``` **Parameters** None. **Returns** Promise that resolves when states are updated. **Example** ```typescript theme={"system"} await dlmmPool.refetchStates(); console.log('Updated active bin:', dlmmPool.lbPair.activeId); ``` **Notes** * Call this to refresh the DLMM instance's cached state (active bin, reserves, etc.) before operations that depend on current on-chain data. *** ### getBinArrays Returns all bin arrays for the current LB pair. **Function** ```typescript theme={"system"} async getBinArrays(): Promise ``` **Parameters** None. **Returns** Array of bin array accounts. **Example** ```typescript theme={"system"} const binArrays = await dlmmPool.getBinArrays(); ``` **Notes** * Fetches all on-chain bin arrays for this pool. For swap-specific arrays, use `getBinArrayForSwap` instead. *** ### getBinArrayForSwap Retrieves bin arrays needed for a swap operation. **Function** ```typescript theme={"system"} async getBinArrayForSwap( swapForY: boolean, count = 4 ): Promise ``` **Parameters** ```typescript theme={"system"} swapForY: boolean // Direction of swap (true for X to Y) count?: number // Number of bin arrays to retrieve (default: 4) ``` **Returns** Array of bin array accounts for the swap. **Example** ```typescript theme={"system"} const binArrays = await dlmmPool.getBinArrayForSwap(true, 5); ``` **Notes** * Retrieves bin arrays around the active bin in the swap direction. Pass the result to `swapQuote` or `swapQuoteExactOut`. *** ### getFeeInfo Calculates and returns fee information for the pool. **Function** ```typescript theme={"system"} getFeeInfo(): FeeInfo ``` **Parameters** None. **Returns** FeeInfo object containing fee percentages. **Example** ```typescript theme={"system"} const feeInfo = dlmmPool.getFeeInfo(); console.log('Base fee rate:', feeInfo.baseFeeRatePercentage.toString()); console.log('Max fee rate:', feeInfo.maxFeeRatePercentage.toString()); console.log('Protocol fee:', feeInfo.protocolFeePercentage.toString()); ``` **Notes** * Returns fee rates as `Decimal` percentages. For example, a `baseFeeRatePercentage` of `0.25` means 0.25%. *** ### getDynamicFee Calculates the current dynamic fee for the pool. **Function** ```typescript theme={"system"} getDynamicFee(): Decimal ``` **Parameters** None. **Returns** Current dynamic fee as a Decimal percentage. **Example** ```typescript theme={"system"} const dynamicFee = dlmmPool.getDynamicFee(); console.log('Current dynamic fee:', dynamicFee.toString(), '%'); ``` **Notes** * The dynamic fee includes both the base fee and the variable fee (which changes based on volatility). *** ### getEmissionRate Returns the emission rates for LM rewards. **Function** ```typescript theme={"system"} getEmissionRate(): EmissionRate ``` **Parameters** None. **Returns** An EmissionRate object containing reward emission rates. **Example** ```typescript theme={"system"} const emissionRate = dlmmPool.getEmissionRate(); console.log('Reward one rate:', emissionRate.rewardOne?.toString()); console.log('Reward two rate:', emissionRate.rewardTwo?.toString()); ``` **Notes** * Returns `undefined` for a reward slot if no reward is configured for that slot. *** ### getBinsAroundActiveBin Retrieves bins around the active bin within specified ranges. **Function** ```typescript theme={"system"} async getBinsAroundActiveBin( numberOfBinsToTheLeft: number, numberOfBinsToTheRight: number ): Promise<{ activeBin: number; bins: BinLiquidity[] }> ``` **Parameters** ```typescript theme={"system"} numberOfBinsToTheLeft: number // Number of bins to retrieve on the left numberOfBinsToTheRight: number // Number of bins to retrieve on the right ``` **Returns** Object containing the active bin ID and array of bin liquidity data. **Example** ```typescript theme={"system"} const { activeBin, bins } = await dlmmPool.getBinsAroundActiveBin(10, 10); console.log('Active bin:', activeBin); console.log('Total bins:', bins.length); ``` **Notes** * Useful for displaying liquidity distribution around the current price. *** ### getBinsBetweenMinAndMaxPrice Retrieves bins within a specified price range. **Function** ```typescript theme={"system"} async getBinsBetweenMinAndMaxPrice( minPrice: number, maxPrice: number ): Promise<{ activeBin: number; bins: BinLiquidity[] }> ``` **Parameters** ```typescript theme={"system"} minPrice: number // Minimum price for filtering bins maxPrice: number // Maximum price for filtering bins ``` **Returns** Object containing the active bin ID and filtered bin liquidity data. **Example** ```typescript theme={"system"} const result = await dlmmPool.getBinsBetweenMinAndMaxPrice(1.0, 1.2); console.log('Bins in price range:', result.bins.length); ``` **Notes** * Prices are in human-readable format (e.g., 1.0 for 1 token Y per token X). *** ### getBinsBetweenLowerAndUpperBound Retrieves bins between specified bin IDs. **Function** ```typescript theme={"system"} async getBinsBetweenLowerAndUpperBound( lowerBinId: number, upperBinId: number, lowerBinArray?: BinArray, upperBinArray?: BinArray ): Promise<{ activeBin: number; bins: BinLiquidity[] }> ``` **Parameters** ```typescript theme={"system"} lowerBinId: number // Lower bound bin ID upperBinId: number // Upper bound bin ID lowerBinArray?: BinArray // Optional cached lower bin array upperBinArray?: BinArray // Optional cached upper bin array ``` **Returns** Object containing the active bin ID and bin liquidity data in the range. **Example** ```typescript theme={"system"} const result = await dlmmPool.getBinsBetweenLowerAndUpperBound( 8388600, 8388620 ); ``` **Notes** * Optionally pass cached `BinArray` objects to avoid redundant RPC calls. *** ### getActiveBin Retrieves information about the currently active bin. **Function** ```typescript theme={"system"} async getActiveBin(): Promise ``` **Parameters** None. **Returns** BinLiquidity object for the active bin. **Example** ```typescript theme={"system"} const activeBin = await dlmmPool.getActiveBin(); console.log('Active bin ID:', activeBin.binId); console.log('Active bin price:', activeBin.pricePerToken); ``` **Notes** * The function retrieves the active bin ID and its corresponding price. *** ### getPositionsByUserAndLbPair Retrieves positions by user for the current LB pair. **Function** ```typescript theme={"system"} async getPositionsByUserAndLbPair( userPubKey?: PublicKey, getPositionsOpt?: GetPositionsOpt ): Promise<{ activeBin: BinLiquidity; userPositions: Array; }> ``` **Parameters** ```typescript theme={"system"} userPubKey?: PublicKey // Optional user public key getPositionsOpt?: GetPositionsOpt // Optional chunked fetch settings (chunkSize, onChunkFetched, isParallelExecution) ``` **Returns** Object containing active bin and user positions. **Example** ```typescript theme={"system"} // Get user positions for this pool const result = await dlmmPool.getPositionsByUserAndLbPair(userPublicKey); console.log('User has', result.userPositions.length, 'positions'); console.log('Active bin:', result.activeBin.binId); ``` **Notes** * Returns the active bin state alongside positions for convenience. * Use `getPositionsOpt` for wallets with many positions to control chunk size and enable parallel execution. *** ### getPairPubkeyIfExists Retrieves the public key of an LB pair if it exists. **Function** ```typescript theme={"system"} static async getPairPubkeyIfExists( connection: Connection, tokenX: PublicKey, tokenY: PublicKey, binStep: BN, baseFactor: BN, baseFeePowerFactor: BN, opt?: Opt ): Promise ``` **Parameters** ```typescript theme={"system"} connection: Connection // Solana connection instance tokenX: PublicKey // Token X mint address tokenY: PublicKey // Token Y mint address binStep: BN // Bin step of the pair baseFactor: BN // Base factor of the pair baseFeePowerFactor: BN // Base fee power factor opt?: Opt // Optional parameters ``` **Returns** Public key of the pair if it exists, null otherwise. **Example** ```typescript theme={"system"} const dlmm = await DLMM.create(connection, pairKey, opt); const pairPubkey = await DLMM.getPairPubkeyIfExists( connection, dlmm.lbPair.tokenXMint, dlmm.lbPair.tokenYMint, new BN(dlmm.lbPair.binStep), new BN(dlmm.lbPair.parameters.baseFactor), new BN(dlmm.lbPair.parameters.baseFeePowerFactor), ); ``` **Notes** * Requires `getProgramAccounts` RPC support. Not available on all RPC providers. *** ### getMaxPriceInBinArrays Gets the maximum price from the provided bin arrays. **Function** ```typescript theme={"system"} async getMaxPriceInBinArrays( binArrayAccounts: BinArrayAccount[] ): Promise ``` **Parameters** ```typescript theme={"system"} binArrayAccounts: BinArrayAccount[] // Array of bin array accounts ``` **Returns** Maximum price as a string. **Example** ```typescript theme={"system"} const binArrays = await dlmmPool.getBinArrays(); const maxPrice = await dlmmPool.getMaxPriceInBinArrays(binArrays); console.log('Maximum price:', maxPrice); ``` **Notes** * Returns the human-readable price of the highest bin that contains token X liquidity. *** ### getLbPairLockInfo Retrieves all pair positions that have locked liquidity. **Function** ```typescript theme={"system"} async getLbPairLockInfo( lockDurationOpt?: number, getPositionsOpt?: GetPositionsOpt ): Promise ``` **Parameters** ```typescript theme={"system"} lockDurationOpt?: number // Minimum position lock duration to filter by getPositionsOpt?: GetPositionsOpt // Optional chunked fetch settings (chunkSize, onChunkFetched, isParallelExecution) ``` **Returns** A PairLockInfo object containing information about locked positions. **Example** ```typescript theme={"system"} const lockInfo = await dlmmPool.getLbPairLockInfo(86400); // 1 day minimum console.log('Locked positions:', lockInfo.positions.length); lockInfo.positions.forEach(pos => { console.log('Position:', pos.positionAddress.toString()); console.log('Lock release:', pos.lockReleasePoint); }); ``` **Notes** * Filters positions by minimum lock duration when `lockDurationOpt` is provided. * Use `getPositionsOpt` for pairs with many positions to control chunk size and enable parallel execution. *** ### canSyncWithMarketPrice Checks if the pool can sync with a given market price. **Function** ```typescript theme={"system"} canSyncWithMarketPrice(marketPrice: number, activeBinId: number) ``` **Parameters** ```typescript theme={"system"} marketPrice: number // Market price to check sync compatibility activeBinId: number // Current active bin ID ``` **Returns** Boolean indicating if sync is possible. **Example** ```typescript theme={"system"} // Check if can sync with market price const activeBin = await dlmmPool.getActiveBin(); const canSync = dlmmPool.canSyncWithMarketPrice(1.05, activeBin.binId); if (canSync) { console.log('Can sync with market price'); } else { console.log('Cannot sync - liquidity exists between current and market price'); } ``` **Notes** * Returns `false` if there is liquidity between the current active bin and the target market price bin, as syncing would skip over that liquidity. *** ### isSwapDisabled Checks if swapping is disabled for a given swap initiator. **Function** ```typescript theme={"system"} isSwapDisabled(swapInitiator: PublicKey) ``` **Parameters** ```typescript theme={"system"} swapInitiator: PublicKey // Address of the swap initiator ``` **Returns** Boolean indicating if swap is disabled for the initiator. **Example** ```typescript theme={"system"} const isDisabled = dlmmPool.isSwapDisabled(userPublicKey); if (isDisabled) { console.log('Swap is disabled for this user'); } else { console.log('Swap is enabled'); } ``` **Notes** * Returns true if pair status is disabled * For permissioned pairs, checks activation time and pre-activation settings * Considers special pre-activation swap addresses *** ## Helper Functions ### syncWithMarketPrice Synchronizes the pool with a given market price. **Function** ```typescript theme={"system"} async syncWithMarketPrice( marketPrice: number, owner: PublicKey ): Promise ``` **Parameters** ```typescript theme={"system"} marketPrice: number // Market price to sync with owner: PublicKey // Owner of the transaction ``` **Returns** Transaction for syncing with market price. **Example** ```typescript theme={"system"} const syncTx = await dlmmPool.syncWithMarketPrice(1.05, userPublicKey); ``` **Notes** * Check `canSyncWithMarketPrice` first to verify the sync is possible. *** ### toPricePerLamport Converts a real price of bin to a lamport value **Function** ```typescript theme={"system"} toPricePerLamport(price: number): string ``` **Parameters** ```typescript theme={"system"} price: number // Real price to convert ``` **Returns** Price per lamport as a string. **Example** ```typescript theme={"system"} const pricePerLamport = dlmmPool.toPricePerLamport(1.05); console.log('Price per lamport:', pricePerLamport); ``` **Notes** * Inverse of `fromPricePerLamport`. Use this when constructing on-chain operations from UI prices. *** ### fromPricePerLamport Converts a price per lamport value to a real price of bin **Function** ```typescript theme={"system"} fromPricePerLamport(pricePerLamport: number): string ``` **Parameters** ```typescript theme={"system"} pricePerLamport: number // Price per lamport to convert ``` **Returns** Real price as a string. **Example** ```typescript theme={"system"} const realPrice = dlmmPool.fromPricePerLamport(1050000); console.log('Real price:', realPrice); ``` **Notes** * Inverse of `toPricePerLamport`. Use this when displaying on-chain prices to users. *** ## Auto-fill & Strategy Helpers These standalone utility functions compute optimal token amounts or per-bin distributions for a given strategy type. ### autoFillXByStrategy Given a known amount of token Y and the current active bin state, calculates the balanced token X amount required for a two-sided deposit using the specified strategy. **Function** ```typescript theme={"system"} autoFillXByStrategy( activeId: number, binStep: number, amountY: BN, amountXInActiveBin: BN, amountYInActiveBin: BN, minBinId: number, maxBinId: number, strategyType: StrategyType ): BN ``` **Parameters** ```typescript theme={"system"} activeId: number // Current active bin ID binStep: number // Bin step of the pool amountY: BN // Amount of token Y to deposit amountXInActiveBin: BN // Amount of token X currently in the active bin amountYInActiveBin: BN // Amount of token Y currently in the active bin minBinId: number // Lower bound of the target bin range maxBinId: number // Upper bound of the target bin range strategyType: StrategyType // Spot, Curve, or BidAsk ``` **Returns** The balanced token X amount (`BN`) to pair with the given token Y amount. **Example** ```typescript theme={"system"} import { autoFillXByStrategy } from '@meteora-ag/dlmm'; const amountX = autoFillXByStrategy( dlmmPool.lbPair.activeId, dlmmPool.lbPair.binStep, amountY, activeBinXAmount, activeBinYAmount, minBinId, maxBinId, StrategyType.Spot ); ``` **Notes** * Only applicable for balanced two-sided deposits. * Uses the active bin's token ratio to determine the matching X amount. *** ### autoFillYByStrategy Given a known amount of token X and the current active bin state, calculates the balanced token Y amount required for a two-sided deposit using the specified strategy. **Function** ```typescript theme={"system"} autoFillYByStrategy( activeId: number, binStep: number, amountX: BN, amountXInActiveBin: BN, amountYInActiveBin: BN, minBinId: number, maxBinId: number, strategyType: StrategyType ): BN ``` **Parameters** ```typescript theme={"system"} activeId: number // Current active bin ID binStep: number // Bin step of the pool amountX: BN // Amount of token X to deposit amountXInActiveBin: BN // Amount of token X currently in the active bin amountYInActiveBin: BN // Amount of token Y currently in the active bin minBinId: number // Lower bound of the target bin range maxBinId: number // Upper bound of the target bin range strategyType: StrategyType // Spot, Curve, or BidAsk ``` **Returns** The balanced token Y amount (`BN`) to pair with the given token X amount. **Example** ```typescript theme={"system"} import { autoFillYByStrategy } from '@meteora-ag/dlmm'; const amountY = autoFillYByStrategy( dlmmPool.lbPair.activeId, dlmmPool.lbPair.binStep, amountX, activeBinXAmount, activeBinYAmount, minBinId, maxBinId, StrategyType.Spot ); ``` **Notes** * Mirrors `autoFillXByStrategy` but returns the required Y amount when X is the known quantity. *** ### toAmountsBothSideByStrategy Distributes amounts of token X and token Y across a bin range according to a strategy type. Returns per-bin amounts for both tokens. **Function** ```typescript theme={"system"} toAmountsBothSideByStrategy( activeId: number, binStep: number, minBinId: number, maxBinId: number, amountX: BN, amountY: BN, amountXInActiveBin: BN, amountYInActiveBin: BN, strategyType: StrategyType, mintX: Mint, mintY: Mint, clock: Clock ): { binId: number; amountX: BN; amountY: BN }[] ``` **Parameters** ```typescript theme={"system"} activeId: number // Current active bin ID binStep: number // Bin step of the pool minBinId: number // Lower bound of the target bin range maxBinId: number // Upper bound of the target bin range amountX: BN // Total token X to distribute amountY: BN // Total token Y to distribute amountXInActiveBin: BN // Amount of token X currently in the active bin amountYInActiveBin: BN // Amount of token Y currently in the active bin strategyType: StrategyType // Spot, Curve, or BidAsk mintX: Mint // Mint info for token X (from DLMM instance) mintY: Mint // Mint info for token Y (from DLMM instance) clock: Clock // Clock info (from DLMM instance) ``` **Returns** An array of `{ binId, amountX, amountY }` objects representing the per-bin token distribution. **Example** ```typescript theme={"system"} import { toAmountsBothSideByStrategy } from '@meteora-ag/dlmm'; const binDistributions = toAmountsBothSideByStrategy( dlmmPool.lbPair.activeId, dlmmPool.lbPair.binStep, minBinId, maxBinId, totalAmountX, totalAmountY, activeBinXAmount, activeBinYAmount, StrategyType.Spot, dlmmPool.tokenX.mint, dlmmPool.tokenY.mint, dlmmPool.clock ); ``` *** ### suggestBalancedXParametersFromY Given a token Y amount for a rebalance deposit, calculates the balanced `x0`, `deltaX`, and total `amountX` parameters to pair with it. **Function** ```typescript theme={"system"} suggestBalancedXParametersFromY( y0: BN, deltaY: BN, minDeltaId: BN, maxDeltaId: BN, activeId: BN, binStep: BN, favorXInActiveBin: boolean, builder: LiquidityStrategyParameterBuilder ): { x0: BN; deltaX: BN; amountX: BN } ``` **Parameters** ```typescript theme={"system"} y0: BN // Base amount of token Y in the active bin deltaY: BN // Per-bin increment for token Y on the bid side minDeltaId: BN // Minimum delta from the active bin maxDeltaId: BN // Maximum delta from the active bin activeId: BN // Current active bin ID binStep: BN // Bin step of the pool favorXInActiveBin: boolean // Whether to favor token X in the active bin builder: LiquidityStrategyParameterBuilder // Strategy-specific parameter builder instance ``` **Returns** An object with `x0` (base amount), `deltaX` (per-bin increment), and `amountX` (total token X needed). **Example** ```typescript theme={"system"} import { suggestBalancedXParametersFromY, getLiquidityStrategyParameterBuilder } from '@meteora-ag/dlmm'; const builder = getLiquidityStrategyParameterBuilder(StrategyType.Spot); const { x0, deltaX, amountX } = suggestBalancedXParametersFromY( y0, deltaY, minDeltaId, maxDeltaId, new BN(dlmmPool.lbPair.activeId), new BN(dlmmPool.lbPair.binStep), false, builder ); ``` **Notes** * Primarily used when constructing rebalance deposit parameters. * The `builder` instance should match the intended strategy type. *** ### suggestBalancedYParametersFromX Given a token X amount for a rebalance deposit, calculates the balanced `y0`, `deltaY`, and total `amountY` parameters to pair with it. **Function** ```typescript theme={"system"} suggestBalancedYParametersFromX( x0: BN, deltaX: BN, minDeltaId: BN, maxDeltaId: BN, activeId: BN, binStep: BN, favorXInActiveBin: boolean, builder: LiquidityStrategyParameterBuilder ): { y0: BN; deltaY: BN; amountY: BN } ``` **Parameters** ```typescript theme={"system"} x0: BN // Base amount of token X in the active bin deltaX: BN // Per-bin increment for token X on the ask side minDeltaId: BN // Minimum delta from the active bin maxDeltaId: BN // Maximum delta from the active bin activeId: BN // Current active bin ID binStep: BN // Bin step of the pool favorXInActiveBin: boolean // Whether to favor token X in the active bin builder: LiquidityStrategyParameterBuilder // Strategy-specific parameter builder instance ``` **Returns** An object with `y0` (base amount), `deltaY` (per-bin increment), and `amountY` (total token Y needed). **Example** ```typescript theme={"system"} import { suggestBalancedYParametersFromX, getLiquidityStrategyParameterBuilder } from '@meteora-ag/dlmm'; const builder = getLiquidityStrategyParameterBuilder(StrategyType.Spot); const { y0, deltaY, amountY } = suggestBalancedYParametersFromX( x0, deltaX, minDeltaId, maxDeltaId, new BN(dlmmPool.lbPair.activeId), new BN(dlmmPool.lbPair.binStep), false, builder ); ``` **Notes** * Mirror of `suggestBalancedXParametersFromY` for when token X is the known quantity. *** ## Bin & Price Math ### binDeltaToMinMaxBinId Converts a bin delta value and an active bin ID into symmetric min and max bin IDs. **Function** ```typescript theme={"system"} binDeltaToMinMaxBinId( binDelta: number, activeBinId: number ): { minBinId: number; maxBinId: number } ``` **Parameters** ```typescript theme={"system"} binDelta: number // Number of bins on each side of the active bin activeBinId: number // Current active bin ID ``` **Returns** An object with `minBinId` (`activeId - delta`) and `maxBinId` (`activeId + delta`). **Example** ```typescript theme={"system"} import { binDeltaToMinMaxBinId } from '@meteora-ag/dlmm'; const { minBinId, maxBinId } = binDeltaToMinMaxBinId(10, dlmmPool.lbPair.activeId); // Creates a 21-bin range: 10 below and 10 above the active bin ``` *** ### binIdToBinArrayIndex Converts a bin ID to the index of the bin array that contains it. **Function** ```typescript theme={"system"} binIdToBinArrayIndex(binId: BN): BN ``` **Parameters** ```typescript theme={"system"} binId: BN // The bin ID to convert ``` **Returns** The bin array index (`BN`) containing the given bin. **Example** ```typescript theme={"system"} import { binIdToBinArrayIndex } from '@meteora-ag/dlmm'; const binArrayIndex = binIdToBinArrayIndex(new BN(dlmmPool.lbPair.activeId)); ``` *** ### getBinCount Calculates the total number of bins in an inclusive range. **Function** ```typescript theme={"system"} getBinCount(minBinId: number, maxBinId: number): number ``` **Parameters** ```typescript theme={"system"} minBinId: number // The minimum bin ID of the range maxBinId: number // The maximum bin ID of the range ``` **Returns** The number of bins in the range (inclusive). **Example** ```typescript theme={"system"} import { getBinCount } from '@meteora-ag/dlmm'; const count = getBinCount(8388600, 8388620); // returns 21 ``` *** ### getBinFromBinArray Retrieves a specific bin from a bin array account by its bin ID. **Function** ```typescript theme={"system"} getBinFromBinArray(binId: number, binArray: BinArray): Bin ``` **Parameters** ```typescript theme={"system"} binId: number // The bin ID to retrieve binArray: BinArray // The bin array account containing the bin ``` **Returns** The `Bin` object at the given bin ID. **Example** ```typescript theme={"system"} import { getBinFromBinArray } from '@meteora-ag/dlmm'; const binArrays = await dlmmPool.getBinArrays(); const bin = getBinFromBinArray(dlmmPool.lbPair.activeId, binArrays[0].account); ``` *** ### getBinIdIndexInBinArray Returns the local (zero-based) index of a bin ID within a specific bin array's range. **Function** ```typescript theme={"system"} getBinIdIndexInBinArray( binId: BN, lowerBinId: BN, upperBinId: BN ): number ``` **Parameters** ```typescript theme={"system"} binId: BN // The bin ID to locate lowerBinId: BN // The lower bound bin ID of the bin array upperBinId: BN // The upper bound bin ID of the bin array ``` **Returns** The zero-based index of the bin within the array. **Example** ```typescript theme={"system"} import { getBinIdIndexInBinArray, getBinArrayLowerUpperBinId, binIdToBinArrayIndex } from '@meteora-ag/dlmm'; const binArrayIndex = binIdToBinArrayIndex(new BN(dlmmPool.lbPair.activeId)); const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex); const index = getBinIdIndexInBinArray(new BN(dlmmPool.lbPair.activeId), lowerBinId, upperBinId); ``` *** ### getBinArrayLowerUpperBinId Returns the lower and upper bin IDs (inclusive) covered by a given bin array index. **Function** ```typescript theme={"system"} getBinArrayLowerUpperBinId(binArrayIndex: BN): [BN, BN] ``` **Parameters** ```typescript theme={"system"} binArrayIndex: BN // The bin array index ``` **Returns** A tuple `[lowerBinId, upperBinId]` representing the bin range covered by the bin array. **Example** ```typescript theme={"system"} import { getBinArrayLowerUpperBinId, binIdToBinArrayIndex } from '@meteora-ag/dlmm'; const binArrayIndex = binIdToBinArrayIndex(new BN(dlmmPool.lbPair.activeId)); const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex); ``` *** ### getPriceOfBinByBinId Calculates the price at a specific bin ID given the pool's bin step. **Function** ```typescript theme={"system"} getPriceOfBinByBinId(binId: number, binStep: number): Decimal ``` **Parameters** ```typescript theme={"system"} binId: number // The bin ID binStep: number // The bin step of the pool (in basis points) ``` **Returns** The price at that bin as a `Decimal` value (token X per token Y, in raw lamport terms). **Example** ```typescript theme={"system"} import { getPriceOfBinByBinId } from '@meteora-ag/dlmm'; const price = getPriceOfBinByBinId(dlmmPool.lbPair.activeId, dlmmPool.lbPair.binStep); console.log('Active bin price (per lamport):', price.toString()); ``` **Notes** * Returns the price in lamport terms. Multiply by the token decimal adjustment (`10^(decimalX - decimalY)`) to get the human-readable token price. *** ## Distribution Helpers ### calculateSpotDistribution Computes a uniform (spot) token distribution across a set of bins relative to the active bin. **Function** ```typescript theme={"system"} calculateSpotDistribution( activeBin: number, binIds: number[] ): { binId: number; xAmountBpsOfTotal: BN; yAmountBpsOfTotal: BN }[] ``` **Parameters** ```typescript theme={"system"} activeBin: number // The active bin ID binIds: number[] // Array of bin IDs to include in the distribution ``` **Returns** An array of objects with each bin's share of token X and token Y in basis points. **Example** ```typescript theme={"system"} import { calculateSpotDistribution } from '@meteora-ag/dlmm'; const binIds = Array.from({ length: 21 }, (_, i) => 8388600 + i); const distribution = calculateSpotDistribution(dlmmPool.lbPair.activeId, binIds); ``` *** ### calculateBidAskDistribution Computes a bid-ask (V-shaped) token distribution across a set of bins, placing more weight at the price extremes. **Function** ```typescript theme={"system"} calculateBidAskDistribution( activeBin: number, binIds: number[] ): { binId: number; xAmountBpsOfTotal: BN; yAmountBpsOfTotal: BN }[] ``` **Parameters** ```typescript theme={"system"} activeBin: number // The active bin ID binIds: number[] // Array of bin IDs to include ``` **Returns** An array of distribution objects with bid/ask-weighted basis point shares for each bin. **Example** ```typescript theme={"system"} import { calculateBidAskDistribution } from '@meteora-ag/dlmm'; const distribution = calculateBidAskDistribution(dlmmPool.lbPair.activeId, binIds); ``` *** ### calculateNormalDistribution Computes a normal (bell-curve) token distribution across a set of bins, concentrating liquidity near the active bin. **Function** ```typescript theme={"system"} calculateNormalDistribution( activeBin: number, binIds: number[] ): { binId: number; xAmountBpsOfTotal: BN; yAmountBpsOfTotal: BN }[] ``` **Parameters** ```typescript theme={"system"} activeBin: number // The active bin ID binIds: number[] // Array of bin IDs to include ``` **Returns** An array of distribution objects with normal-weighted basis point shares for each bin. **Example** ```typescript theme={"system"} import { calculateNormalDistribution } from '@meteora-ag/dlmm'; const distribution = calculateNormalDistribution(dlmmPool.lbPair.activeId, binIds); ``` *** ### toAmountAskSide Distributes a total token X amount across the ask-side bins (above the active bin) according to given weight distributions. **Function** ```typescript theme={"system"} toAmountAskSide( activeId: number, binStep: number, totalAmount: BN, distributions: { binId: number; weight: number }[], mintX: Mint, clock: Clock ): { binId: number; amount: BN }[] ``` **Parameters** ```typescript theme={"system"} activeId: number // Active bin ID binStep: number // Bin step of the pool totalAmount: BN // Total amount of token X to distribute distributions: { binId: number; weight: number }[] // Weight distribution for each ask-side bin mintX: Mint // Mint info for token X (from DLMM instance) clock: Clock // Clock info (from DLMM instance) ``` **Returns** An array of `{ binId, amount }` objects representing per-bin token X amounts. **Example** ```typescript theme={"system"} import { toAmountAskSide } from '@meteora-ag/dlmm'; const askAmounts = toAmountAskSide( dlmmPool.lbPair.activeId, dlmmPool.lbPair.binStep, totalAmountX, askSideWeights, dlmmPool.tokenX.mint, dlmmPool.clock ); ``` *** ### toAmountBidSide Distributes a total token Y amount across the bid-side bins (at and below the active bin) according to given weight distributions. **Function** ```typescript theme={"system"} toAmountBidSide( activeId: number, totalAmount: BN, distributions: { binId: number; weight: number }[], mintY: Mint, clock: Clock ): { binId: number; amount: BN }[] ``` **Parameters** ```typescript theme={"system"} activeId: number // Active bin ID totalAmount: BN // Total amount of token Y to distribute distributions: { binId: number; weight: number }[] // Weight distribution for each bid-side bin mintY: Mint // Mint info for token Y (from DLMM instance) clock: Clock // Clock info (from DLMM instance) ``` **Returns** An array of `{ binId, amount }` objects representing per-bin token Y amounts. **Example** ```typescript theme={"system"} import { toAmountBidSide } from '@meteora-ag/dlmm'; const bidAmounts = toAmountBidSide( dlmmPool.lbPair.activeId, totalAmountY, bidSideWeights, dlmmPool.tokenY.mint, dlmmPool.clock ); ``` *** ### toAmountBothSide Distributes token X and token Y across both bid and ask bins according to given weight distributions, taking the active bin's existing liquidity ratio into account. **Function** ```typescript theme={"system"} toAmountBothSide( activeId: number, binStep: number, amountX: BN, amountY: BN, amountXInActiveBin: BN, amountYInActiveBin: BN, distributions: { binId: number; weight: number }[], mintX: Mint, mintY: Mint, clock: Clock ): { binId: number; amountX: BN; amountY: BN }[] ``` **Parameters** ```typescript theme={"system"} activeId: number // Active bin ID binStep: number // Bin step of the pool amountX: BN // Total token X to distribute amountY: BN // Total token Y to distribute amountXInActiveBin: BN // Current token X in the active bin amountYInActiveBin: BN // Current token Y in the active bin distributions: { binId: number; weight: number }[] // Combined bid and ask weight distributions mintX: Mint // Mint info for token X (from DLMM instance) mintY: Mint // Mint info for token Y (from DLMM instance) clock: Clock // Clock info (from DLMM instance) ``` **Returns** An array of `{ binId, amountX, amountY }` objects for both sides of the distribution. **Example** ```typescript theme={"system"} import { toAmountBothSide } from '@meteora-ag/dlmm'; const amounts = toAmountBothSide( dlmmPool.lbPair.activeId, dlmmPool.lbPair.binStep, totalAmountX, totalAmountY, activeBinXAmount, activeBinYAmount, weightDistributions, dlmmPool.tokenX.mint, dlmmPool.tokenY.mint, dlmmPool.clock ); ``` *** ### toAmountIntoBins Converts rebalance deposit parameters into per-bin amounts for both sides of the active bin. Used to build deposit instructions in the rebalance flow. **Function** ```typescript theme={"system"} toAmountIntoBins( activeId: BN, minDeltaId: BN, maxDeltaId: BN, deltaX: BN, deltaY: BN, x0: BN, y0: BN, binStep: BN, favorXInActiveBin: boolean ): { binId: BN; amountX: BN; amountY: BN }[] ``` **Parameters** ```typescript theme={"system"} activeId: BN // Current active bin ID minDeltaId: BN // Minimum bin delta from the active bin (negative = bid side) maxDeltaId: BN // Maximum bin delta from the active bin (positive = ask side) deltaX: BN // Per-bin increment for token X on the ask side deltaY: BN // Per-bin increment for token Y on the bid side x0: BN // Base amount of token X in the active bin y0: BN // Base amount of token Y in the active bin binStep: BN // Bin step of the pool favorXInActiveBin: boolean // Whether to deposit token X in the active bin ``` **Returns** An array of `{ binId, amountX, amountY }` covering the full target range. **Example** ```typescript theme={"system"} import { toAmountIntoBins } from '@meteora-ag/dlmm'; const amounts = toAmountIntoBins( new BN(dlmmPool.lbPair.activeId), minDeltaId, maxDeltaId, deltaX, deltaY, x0, y0, new BN(dlmmPool.lbPair.binStep), true ); ``` *** ## Swap & Fee Utilities ### getOutAmount Calculates the output amount for a swap within a single bin given an input amount. **Function** ```typescript theme={"system"} getOutAmount(bin: Bin, inAmount: BN, swapForY: boolean): BN ``` **Parameters** ```typescript theme={"system"} bin: Bin // The bin to simulate the swap in inAmount: BN // The input token amount swapForY: boolean // true = swapping token X for Y, false = swapping Y for X ``` **Returns** The output token amount (`BN`) for the given input. **Example** ```typescript theme={"system"} import { getOutAmount, getBinFromBinArray } from '@meteora-ag/dlmm'; const binArrays = await dlmmPool.getBinArrays(); const activeBin = getBinFromBinArray(dlmmPool.lbPair.activeId, binArrays[0].account); const outAmount = getOutAmount(activeBin, new BN(1_000_000), true); ``` *** ### getSlippageMaxAmount Calculates the maximum acceptable token amount after applying an upward slippage tolerance. **Function** ```typescript theme={"system"} getSlippageMaxAmount(amount: BN, slippage: number): BN ``` **Parameters** ```typescript theme={"system"} amount: BN // The reference token amount slippage: number // Slippage percentage (e.g. 1 for 1%) ``` **Returns** The maximum acceptable amount after slippage. Returns `U64_MAX` if slippage is 100%. **Example** ```typescript theme={"system"} import { getSlippageMaxAmount } from '@meteora-ag/dlmm'; const maxOut = getSlippageMaxAmount(expectedOutAmount, 1); // 1% slippage ``` *** ### getSlippageMinAmount Calculates the minimum acceptable token amount after applying a downward slippage tolerance. **Function** ```typescript theme={"system"} getSlippageMinAmount(amount: BN, slippage: number): BN ``` **Parameters** ```typescript theme={"system"} amount: BN // The reference token amount slippage: number // Slippage percentage (e.g. 1 for 1%) ``` **Returns** The minimum acceptable amount after deducting slippage. **Example** ```typescript theme={"system"} import { getSlippageMinAmount } from '@meteora-ag/dlmm'; const minIn = getSlippageMinAmount(expectedInAmount, 0.5); // 0.5% slippage ``` *** ### getVariableFee Computes the variable fee component for a pool based on its bin step and volatility accumulator parameters. **Function** ```typescript theme={"system"} getVariableFee( binStep: number, sParameter: sParameters, vParameter: vParameters ): BN ``` **Parameters** ```typescript theme={"system"} binStep: number // Bin step of the pool sParameter: sParameters // Static fee parameters (from pool state) vParameter: vParameters // Volatile fee parameters (from pool state) ``` **Returns** The variable fee amount (`BN`). **Example** ```typescript theme={"system"} import { getVariableFee } from '@meteora-ag/dlmm'; const variableFee = getVariableFee( dlmmPool.lbPair.binStep, dlmmPool.lbPair.parameters, dlmmPool.lbPair.vParameters ); ``` *** ### swapExactInQuoteAtBin Simulates a swap-exact-in operation within a single bin and returns the amounts, fees, and protocol fees. **Function** ```typescript theme={"system"} swapExactInQuoteAtBin( bin: Bin, binStep: number, sParameter: sParameters, vParameter: vParameters, inAmount: BN, swapForY: boolean ): { amountIn: BN; amountOut: BN; fee: BN; protocolFee: BN; } ``` **Parameters** ```typescript theme={"system"} bin: Bin // The bin to quote within binStep: number // Bin step of the pool sParameter: sParameters // Static fee parameters vParameter: vParameters // Volatile fee parameters inAmount: BN // Exact input amount swapForY: boolean // true = swap X for Y, false = swap Y for X ``` **Returns** An object containing `amountIn`, `amountOut`, `fee`, and `protocolFee`. **Example** ```typescript theme={"system"} import { swapExactInQuoteAtBin, getBinFromBinArray } from '@meteora-ag/dlmm'; const binArrays = await dlmmPool.getBinArrays(); const activeBin = getBinFromBinArray(dlmmPool.lbPair.activeId, binArrays[0].account); const quote = swapExactInQuoteAtBin( activeBin, dlmmPool.lbPair.binStep, dlmmPool.lbPair.parameters, dlmmPool.lbPair.vParameters, new BN(1_000_000), true ); console.log('Amount out:', quote.amountOut.toString()); console.log('Fee:', quote.fee.toString()); ``` *** ### swapExactOutQuoteAtBin Simulates a swap-exact-out operation within a single bin and returns the required input amount, fees, and protocol fees. **Function** ```typescript theme={"system"} swapExactOutQuoteAtBin( bin: Bin, binStep: number, sParameter: sParameters, vParameter: vParameters, outAmount: BN, swapForY: boolean ): { amountIn: BN; amountOut: BN; fee: BN; protocolFee: BN; } ``` **Parameters** ```typescript theme={"system"} bin: Bin // The bin to quote within binStep: number // Bin step of the pool sParameter: sParameters // Static fee parameters vParameter: vParameters // Volatile fee parameters outAmount: BN // Desired exact output amount swapForY: boolean // true = swap X for Y, false = swap Y for X ``` **Returns** An object containing `amountIn`, `amountOut`, `fee`, and `protocolFee`. **Example** ```typescript theme={"system"} import { swapExactOutQuoteAtBin, getBinFromBinArray } from '@meteora-ag/dlmm'; const binArrays = await dlmmPool.getBinArrays(); const activeBin = getBinFromBinArray(dlmmPool.lbPair.activeId, binArrays[0].account); const quote = swapExactOutQuoteAtBin( activeBin, dlmmPool.lbPair.binStep, dlmmPool.lbPair.parameters, dlmmPool.lbPair.vParameters, new BN(500_000), true ); console.log('Required input:', quote.amountIn.toString()); ``` *** ### getAndCapMaxActiveBinSlippage Converts a slippage percentage to a maximum allowed bin drift, capped at a provided maximum. **Function** ```typescript theme={"system"} getAndCapMaxActiveBinSlippage( slippagePercentage: number, binStep: number, maxActiveBinSlippage: number ): number ``` **Parameters** ```typescript theme={"system"} slippagePercentage: number // Slippage tolerance as a percentage (0 = use cap directly) binStep: number // Bin step of the pool (in basis points) maxActiveBinSlippage: number // Hard cap on the number of bins the active bin can drift ``` **Returns** The maximum number of bins (`number`) the active bin is allowed to move. **Example** ```typescript theme={"system"} import { getAndCapMaxActiveBinSlippage } from '@meteora-ag/dlmm'; const maxBinSlippage = getAndCapMaxActiveBinSlippage(1, dlmmPool.lbPair.binStep, 100); ``` **Notes** * If `slippagePercentage` is 0 or null, `maxActiveBinSlippage` is returned directly. *** ## PDA Derivations ### deriveBinArray Derives the program-derived address (PDA) for a bin array account. **Function** ```typescript theme={"system"} deriveBinArray( lbPair: PublicKey, index: BN, programId: PublicKey ): [PublicKey, number] ``` **Parameters** ```typescript theme={"system"} lbPair: PublicKey // The LB pair address index: BN // Bin array index programId: PublicKey // DLMM program ID ``` **Returns** A tuple of `[PublicKey, bump]` for the bin array PDA. **Example** ```typescript theme={"system"} import { deriveBinArray, binIdToBinArrayIndex } from '@meteora-ag/dlmm'; const programId = new PublicKey('LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo'); const index = binIdToBinArrayIndex(new BN(dlmmPool.lbPair.activeId)); const [binArrayPda] = deriveBinArray(dlmmPool.pubkey, index, programId); ``` *** ### deriveBinArrayBitmapExtension Derives the PDA for the bin array bitmap extension account of an LB pair. **Function** ```typescript theme={"system"} deriveBinArrayBitmapExtension( lbPair: PublicKey, programId: PublicKey ): [PublicKey, number] ``` **Parameters** ```typescript theme={"system"} lbPair: PublicKey // The LB pair address programId: PublicKey // DLMM program ID ``` **Returns** A tuple of `[PublicKey, bump]` for the bitmap extension PDA. **Example** ```typescript theme={"system"} import { deriveBinArrayBitmapExtension } from '@meteora-ag/dlmm'; const programId = new PublicKey('LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo'); const [bitmapExtension] = deriveBinArrayBitmapExtension(dlmmPool.pubkey, programId); ``` *** ### deriveCustomizablePermissionlessLbPair Derives the PDA for a customizable permissionless LB pair given two token mints. **Function** ```typescript theme={"system"} deriveCustomizablePermissionlessLbPair( tokenX: PublicKey, tokenY: PublicKey, programId: PublicKey ): [PublicKey, number] ``` **Parameters** ```typescript theme={"system"} tokenX: PublicKey // Mint address of token X tokenY: PublicKey // Mint address of token Y programId: PublicKey // DLMM program ID ``` **Returns** A tuple of `[PublicKey, bump]` for the LB pair PDA. **Example** ```typescript theme={"system"} import { deriveCustomizablePermissionlessLbPair } from '@meteora-ag/dlmm'; const programId = new PublicKey('LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo'); const [lbPairAddress] = deriveCustomizablePermissionlessLbPair( tokenXMint, tokenYMint, programId ); ``` *** ### deriveLbPair Derives the PDA for an LB pair given two token mints and a bin step. **Function** ```typescript theme={"system"} deriveLbPair( tokenX: PublicKey, tokenY: PublicKey, binStep: BN, programId: PublicKey ): [PublicKey, number] ``` **Parameters** ```typescript theme={"system"} tokenX: PublicKey // Mint address of token X tokenY: PublicKey // Mint address of token Y binStep: BN // Bin step of the pair programId: PublicKey // DLMM program ID ``` **Returns** A tuple of `[PublicKey, bump]` for the LB pair PDA. **Example** ```typescript theme={"system"} import { deriveLbPair } from '@meteora-ag/dlmm'; const [lbPairAddress] = deriveLbPair(tokenXMint, tokenYMint, new BN(25), programId); ``` `deriveLbPair` is deprecated. Use `deriveLbPair2` instead. *** ### deriveLbPair2 Derives the PDA for an LB pair using both bin step and base factor. Use this when multiple pools exist for the same token pair and bin step. **Function** ```typescript theme={"system"} deriveLbPair2( tokenX: PublicKey, tokenY: PublicKey, binStep: BN, baseFactor: BN, programId: PublicKey ): [PublicKey, number] ``` **Parameters** ```typescript theme={"system"} tokenX: PublicKey // Mint address of token X tokenY: PublicKey // Mint address of token Y binStep: BN // Bin step of the pair baseFactor: BN // Base factor for the pair's fee structure programId: PublicKey // DLMM program ID ``` **Returns** A tuple of `[PublicKey, bump]` for the LB pair PDA. **Example** ```typescript theme={"system"} import { deriveLbPair2 } from '@meteora-ag/dlmm'; const [lbPairAddress] = deriveLbPair2( tokenXMint, tokenYMint, new BN(25), new BN(10000), programId ); ``` *** ### deriveLbPairWithPresetParamWithIndexKey Derives the PDA for an LB pair using a preset parameter account key and two token mints. **Function** ```typescript theme={"system"} deriveLbPairWithPresetParamWithIndexKey( presetParameterKey: PublicKey, tokenX: PublicKey, tokenY: PublicKey, programId: PublicKey ): [PublicKey, number] ``` **Parameters** ```typescript theme={"system"} presetParameterKey: PublicKey // The preset parameter account address tokenX: PublicKey // Mint address of token X tokenY: PublicKey // Mint address of token Y programId: PublicKey // DLMM program ID ``` **Returns** A tuple of `[PublicKey, bump]` for the LB pair PDA. **Example** ```typescript theme={"system"} import { deriveLbPairWithPresetParamWithIndexKey } from '@meteora-ag/dlmm'; const presetParams = await dlmmPool.getAllPresetParameters(); const [lbPairAddress] = deriveLbPairWithPresetParamWithIndexKey( presetParams[0].publicKey, tokenXMint, tokenYMint, programId ); ``` *** ## Position Utilities ### calculatePositionSize Calculates the on-chain account size (in bytes) required for a position with a given number of bins. **Function** ```typescript theme={"system"} calculatePositionSize(binCount: BN): BN ``` **Parameters** ```typescript theme={"system"} binCount: BN // Number of bins the position will hold ``` **Returns** The account size in bytes (`BN`). **Example** ```typescript theme={"system"} import { calculatePositionSize } from '@meteora-ag/dlmm'; const size = calculatePositionSize(new BN(20)); ``` *** ### getExtendedPositionBinCount Returns the number of bins in a position that exceed the default position width. Returns zero if the position fits within the default width. **Function** ```typescript theme={"system"} getExtendedPositionBinCount(minBinId: BN, maxBinId: BN): BN ``` **Parameters** ```typescript theme={"system"} minBinId: BN // Minimum bin ID of the position maxBinId: BN // Maximum bin ID of the position ``` **Returns** The number of extended bins (`BN`), or zero if no extension is needed. **Example** ```typescript theme={"system"} import { getExtendedPositionBinCount } from '@meteora-ag/dlmm'; const extendedBins = getExtendedPositionBinCount( new BN(position.positionData.lowerBinId), new BN(position.positionData.upperBinId) ); ``` *** ### getPositionCountByBinCount Calculates the number of position accounts required to cover a given number of bins, rounding up. **Function** ```typescript theme={"system"} getPositionCountByBinCount(binCount: number): number ``` **Parameters** ```typescript theme={"system"} binCount: number // Total number of bins to cover ``` **Returns** The number of positions required (`number`). **Example** ```typescript theme={"system"} import { getPositionCountByBinCount, getBinCount } from '@meteora-ag/dlmm'; const binCount = getBinCount(minBinId, maxBinId); const positionCount = getPositionCountByBinCount(binCount); console.log(`Need ${positionCount} positions for ${binCount} bins`); ``` *** ### getPositionExpandRentExemption Calculates the additional rent-exemption lamports needed to expand an existing position to accommodate more bins. **Function** ```typescript theme={"system"} async getPositionExpandRentExemption( currentMinBinId: BN, currentMaxBinId: BN, connection: Connection, binCountToExpand: BN ): Promise ``` **Parameters** ```typescript theme={"system"} currentMinBinId: BN // Current lower bound of the position currentMaxBinId: BN // Current upper bound of the position connection: Connection // Solana connection instance binCountToExpand: BN // Number of additional bins to accommodate ``` **Returns** The additional rent-exemption lamports (`number`) required for the expansion. **Example** ```typescript theme={"system"} import { getPositionExpandRentExemption } from '@meteora-ag/dlmm'; const extraRent = await getPositionExpandRentExemption( new BN(position.positionData.lowerBinId), new BN(position.positionData.upperBinId), connection, new BN(20) ); console.log('Extra rent needed:', extraRent, 'lamports'); ``` **Notes** * Returns 0 if the expanded width stays within the default position size. *** ### getPositionLowerUpperBinIdWithLiquidity Returns the effective lower and upper bin IDs of a position, trimmed to only the bins that actually hold liquidity. **Function** ```typescript theme={"system"} getPositionLowerUpperBinIdWithLiquidity( position: PositionData ): { lowerBinId: BN; upperBinId: BN } | null ``` **Parameters** ```typescript theme={"system"} position: PositionData // The position data object ``` **Returns** An object with `lowerBinId` and `upperBinId` for the active liquidity range, or `null` if the position has no liquidity. **Example** ```typescript theme={"system"} import { getPositionLowerUpperBinIdWithLiquidity } from '@meteora-ag/dlmm'; const liquidityRange = getPositionLowerUpperBinIdWithLiquidity(positionData); if (liquidityRange) { console.log('Liquidity from bin', liquidityRange.lowerBinId.toString()); console.log('to bin', liquidityRange.upperBinId.toString()); } ``` *** ### getPositionRentExemption Calculates the minimum rent-exemption lamports required for a new position account with a given number of bins. **Function** ```typescript theme={"system"} async getPositionRentExemption( connection: Connection, binCount: BN ): Promise ``` **Parameters** ```typescript theme={"system"} connection: Connection // Solana connection instance binCount: BN // Number of bins the position will hold ``` **Returns** The minimum rent-exemption lamports (`number`) for the position account. **Example** ```typescript theme={"system"} import { getPositionRentExemption, getBinCount } from '@meteora-ag/dlmm'; const binCount = new BN(getBinCount(minBinId, maxBinId)); const rentLamports = await getPositionRentExemption(connection, binCount); console.log('Position rent:', rentLamports, 'lamports'); ``` *** ### getBinArraysRequiredByPositionRange Returns the bin array PDAs and their indexes required to initialize positions covering a continuous bin range. **Function** ```typescript theme={"system"} getBinArraysRequiredByPositionRange( pair: PublicKey, fromBinId: BN, toBinId: BN, programId: PublicKey ): { key: PublicKey; index: BN }[] ``` **Parameters** ```typescript theme={"system"} pair: PublicKey // The LB pair address fromBinId: BN // Start bin ID of the range toBinId: BN // End bin ID of the range programId: PublicKey // DLMM program ID ``` **Returns** An array of objects containing each bin array `key` (PDA) and its `index`. **Example** ```typescript theme={"system"} import { getBinArraysRequiredByPositionRange } from '@meteora-ag/dlmm'; const programId = new PublicKey('LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo'); const requiredBinArrays = getBinArraysRequiredByPositionRange( dlmmPool.pubkey, new BN(minBinId), new BN(maxBinId), programId ); ``` *** ### isBinIdWithinBinArray Checks whether a given bin ID falls within the range covered by a specified bin array index. **Function** ```typescript theme={"system"} isBinIdWithinBinArray(activeId: BN, binArrayIndex: BN): boolean ``` **Parameters** ```typescript theme={"system"} activeId: BN // The bin ID to check binArrayIndex: BN // The bin array index to check against ``` **Returns** `true` if the bin is within the bin array's range, `false` otherwise. **Example** ```typescript theme={"system"} import { isBinIdWithinBinArray, binIdToBinArrayIndex } from '@meteora-ag/dlmm'; const binArrayIndex = binIdToBinArrayIndex(new BN(dlmmPool.lbPair.activeId)); const isWithin = isBinIdWithinBinArray(new BN(targetBinId), binArrayIndex); ``` *** ### updateBinArray Applies the current LM reward state to a bin array in-memory, distributing accumulated rewards into each bin. Used when computing reward accruals off-chain. **Function** ```typescript theme={"system"} updateBinArray( activeId: BN, clock: Clock, allRewardInfos: RewardInfos, binArray: BinArray ): void ``` **Parameters** ```typescript theme={"system"} activeId: BN // Current active bin ID clock: Clock // Current clock state allRewardInfos: RewardInfos // Pool reward info (from LB pair state) binArray: BinArray // The bin array account to update (mutated in place) ``` **Returns** Nothing. The `binArray` is mutated in place. **Example** ```typescript theme={"system"} import { updateBinArray } from '@meteora-ag/dlmm'; updateBinArray( new BN(dlmmPool.lbPair.activeId), dlmmPool.clock, dlmmPool.lbPair.rewardInfos, binArrayAccount ); ``` *** ## Rebalance Utilities ### RebalancePosition A class that encapsulates the state of an existing position for rebalance simulation. Create instances using the static `RebalancePosition.create()` factory method. **Class** ```typescript theme={"system"} class RebalancePosition { address: PublicKey; lowerBinId: BN; upperBinId: BN; owner: PublicKey; shouldClaimFee: boolean; shouldClaimReward: boolean; static async create( params: CreateRebalancePositionParams ): Promise; async simulateRebalance( connection: Connection, binStep: BN, tokenXDecimal: BN, tokenYDecimal: BN, withdraws: RebalanceWithWithdraw[], deposits: RebalanceWithDeposit[] ): Promise; totalAmounts(): BN[]; totalFeeAmounts(): BN[]; totalRewardAmounts(): BN[]; } ``` **CreateRebalancePositionParams** ```typescript theme={"system"} { program: Program; pairAddress: PublicKey; positionAddress: PublicKey; positionData: PositionData; shouldClaimFee: boolean; shouldClaimReward: boolean; } ``` **Example** ```typescript theme={"system"} import { RebalancePosition } from '@meteora-ag/dlmm'; const rebalancePos = await RebalancePosition.create({ program: dlmmPool.program, pairAddress: dlmmPool.pubkey, positionAddress: positionAddress, positionData: positionData, shouldClaimFee: true, shouldClaimReward: true, }); const simulation = await rebalancePos.simulateRebalance( connection, new BN(dlmmPool.lbPair.binStep), new BN(tokenXDecimal), new BN(tokenYDecimal), withdrawParams, depositParams ); ``` *** ### RebalancePositionBinArrayRentalCostQuote Interface describing the rental cost breakdown for bin arrays required during a rebalance. **Interface** ```typescript theme={"system"} interface RebalancePositionBinArrayRentalCostQuote { binArrayExistence: Set; // Set of existing bin array addresses (as strings) binArrayCount: number; // Total number of bin arrays needed binArrayCost: number; // Lamports required for new bin arrays bitmapExtensionCost: number; // Lamports required for bitmap extension (if needed) } ``` **Notes** * Returned alongside `SimulateRebalanceResp` from rebalance quote methods. * `binArrayCost` covers only bin arrays that do not already exist on-chain. * `bitmapExtensionCost` is non-zero only if the rebalance requires bins outside the default bitmap range. *** ### RebalanceWithDeposit Interface defining the parameters for a deposit leg of a rebalance operation. **Interface** ```typescript theme={"system"} interface RebalanceWithDeposit { minDeltaId: BN; // minBinId = activeId + minDeltaId maxDeltaId: BN; // maxBinId = activeId + maxDeltaId x0: BN; // Base amount of token X in the active bin y0: BN; // Base amount of token Y in the active bin deltaX: BN; // Per-bin increment of token X on the ask side deltaY: BN; // Per-bin increment of token Y on the bid side favorXInActiveBin: boolean; // Whether to deposit token X into the active bin } ``` **Notes** * `minDeltaId` and `maxDeltaId` are relative to the `activeId` at the time of the rebalance. * Use `suggestBalancedXParametersFromY` or `suggestBalancedYParametersFromX` to compute balanced parameter values. *** ### RebalanceWithWithdraw Interface defining the parameters for a withdrawal leg of a rebalance operation. **Interface** ```typescript theme={"system"} interface RebalanceWithWithdraw { minBinId: BN | null; // Start of withdrawal range (null = start from activeId) maxBinId: BN | null; // End of withdrawal range (null = end at activeId) bps: BN; // Basis points of liquidity to withdraw (10000 = 100%) } ``` **Notes** * Set `minBinId` to `null` to withdraw from the active bin downwards. * Set `maxBinId` to `null` to withdraw up to the active bin. * A `bps` of `10000` withdraws 100% of liquidity within the specified range. *** ### SimulateRebalanceResp Interface representing the result of a rebalance simulation, used to preview amounts and costs before executing the transaction. **Interface** ```typescript theme={"system"} interface SimulateRebalanceResp { amountXDeposited: BN; // Expected token X to be deposited amountYDeposited: BN; // Expected token Y to be deposited actualAmountXDeposited: BN; // Actual token X after compression actualAmountYDeposited: BN; // Actual token Y after compression actualAmountXWithdrawn: BN; // Actual token X withdrawn actualAmountYWithdrawn: BN; // Actual token Y withdrawn rewardAmountsClaimed: BN[]; // Reward amounts claimed per reward token depositParams: RebalanceAddLiquidityParam[]; // Encoded deposit instructions withdrawParams: RebalanceRemoveLiquidityParam[]; // Encoded withdraw instructions rentalCostLamports: BN; // Total lamports needed for bin array rent } ``` **Example** ```typescript theme={"system"} const simulation = await rebalancePos.simulateRebalance( connection, binStep, tokenXDecimal, tokenYDecimal, withdraws, deposits ); console.log('Token X to deposit:', simulation.amountXDeposited.toString()); console.log('Token Y to deposit:', simulation.amountYDeposited.toString()); console.log('Rental cost (lamports):', simulation.rentalCostLamports.toString()); ``` *** ### getAutoFillAmountByRebalancedPosition Determines the amount of the deficient token needed to bring a rebalanced position back into balance, and specifies whether it is a bid-side (token Y) or ask-side (token X) deposit. **Function** ```typescript theme={"system"} getAutoFillAmountByRebalancedPosition( rebalancePosition: RebalancePosition, strategyType: StrategyType ): { amount: BN; isBidSide: boolean } ``` **Parameters** ```typescript theme={"system"} rebalancePosition: RebalancePosition // The rebalance position instance (from RebalancePosition.create) strategyType: StrategyType // The target strategy type (Spot, Curve, or BidAsk) ``` **Returns** An object with `amount` (the token amount needed) and `isBidSide` (`true` = token Y needed, `false` = token X needed). **Example** ```typescript theme={"system"} import { getAutoFillAmountByRebalancedPosition } from '@meteora-ag/dlmm'; const { amount, isBidSide } = getAutoFillAmountByRebalancedPosition( rebalancePos, StrategyType.Spot ); if (isBidSide) { console.log('Need to deposit', amount.toString(), 'of token Y'); } else { console.log('Need to deposit', amount.toString(), 'of token X'); } ``` **Notes** * Typically used after constructing a `RebalancePosition` to determine how much of one token to supply for a one-sided top-up. # Overview Source: https://docs.meteora.ag/developer-guide/guides/dynamic-fee-sharing/overview Before getting started building on Dynamic Fee Sharing, you should read the following resource to get a better understanding of how Meteora's Dynamic Fee Sharing works: Dynamic Fee Sharing is a program that allows any project to configure a fee sharing mechanism for their fees earned by initializing a fee vault and funding fees into the vault. *** # Dynamic Fee Sharing Program At Meteora, we’ve developed a `Node.js <> Typescript SDK` to make deploying and managing your Dynamic Fee Sharing vault easier. The following sections includes information on installing and using the SDK. It also covers where to find the latest code, and how to contribute to these repositories. ## Program Details Meteora Dynamic Fee Sharing Program Meteora Dynamic Fee Sharing Program IDL
Network Program ID
Mainnet dfsdo2UqvwfN8DuUVrMRNfQe11VaiNoKcMqLHVvDPzh
Devnet dfsdo2UqvwfN8DuUVrMRNfQe11VaiNoKcMqLHVvDPzh
## Fee Vault Types Dynamic Fee Sharing offers two types of fee vaults to accommodate different use cases: A fee vault created with an external keypair. Provides flexibility for standalone fee-sharing arrangements. A fee vault derived from a base account. Ideal for protocol integrations where the vault is tied to another entity. ### Non-PDA Fee Vault A Non-PDA Fee Vault uses a regular Solana account (keypair-based) for the fee vault address. The vault address is generated externally and must be provided as a signer during initialization. **Characteristics:** * Fee vault address is a randomly generated keypair * The keypair must be stored and managed externally * Multiple vaults can be created for the same token mint and owner * Simpler to understand and implement **When to Use:** * Creating standalone fee vaults without ties to other protocol entities * Need to create multiple fee-sharing arrangements for the same token * Vault lifecycle is independent of any base account * Simpler integration without deterministic address requirements **Address Derivation:** ``` Fee Vault Account: External keypair (random address) Token Vault: PDA([TOKEN_VAULT_PREFIX, fee_vault_address], program_id) ``` ### PDA Fee Vault A PDA Fee Vault uses a Program Derived Account (PDA) for the fee vault address. The vault address is deterministically derived from a base account and token mint, making it recoverable and tied to a specific entity. **Characteristics:** * Fee vault address is derived from seeds: `[FEE_VAULT_PREFIX, base_address, token_mint]` * No external keypair storage needed - address is always recoverable * Only ONE vault per (base account, token mint) combination * Base account must sign during initialization **When to Use:** * Vault is logically tied to another account (e.g., AMM pool, bonding curve, liquidity position) * Need deterministic address derivation for protocol integration * Want to avoid external keypair management * Address should be recoverable from (base, token\_mint) pair * Integrating with features that reference a base entity **Address Derivation:** ``` Fee Vault Account: PDA([FEE_VAULT_PREFIX, base_address, token_mint], program_id) Token Vault: PDA([TOKEN_VAULT_PREFIX, fee_vault_address], program_id) ``` ### Comparison | Aspect | Non-PDA Fee Vault | PDA Fee Vault | | ---------------------- | ---------------------------------------- | ---------------------------------- | | **Address Generation** | External keypair (random) | Derived from seeds (deterministic) | | **Address Recovery** | Requires storing keypair | Derivable from (base, token\_mint) | | **Uniqueness** | Multiple vaults per (owner, token\_mint) | One vault per (base, token\_mint) | | **Signer Requirement** | Fee vault keypair signs init | Base keypair signs init | | **Tied to Entity** | No | Yes (via base account) | | **Use Case** | Standalone vaults | Protocol-integrated vaults | Both vault types share the same underlying state structure and support identical operations after initialization: funding fees, claiming fees, and fee distribution via the checkpoint mechanism. *** ## Official SDKs Official Meteora Dynamic Fee Sharing Typescript SDK # Getting Started Source: https://docs.meteora.ag/developer-guide/guides/dynamic-fee-sharing/typescript-sdk/getting-started Dynamic Fee Sharing This guide provides instructions on how to get started with building on Meteora's Dynamic Fee Sharing program using the Dynamic Fee Sharing TypeScript SDK. Before you begin, here are some important resources: Meteora Dynamic Fee Sharing Typescript SDK Meteora Dynamic Fee Sharing 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-fee-sharing-sdk @solana/web3.js ``` ```bash theme={"system"} pnpm install @meteora-ag/dynamic-fee-sharing-sdk @solana/web3.js ``` ```bash theme={"system"} yarn add @meteora-ag/dynamic-fee-sharing-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 { DynamicFeeSharingClient } from "@meteora-ag/dynamic-fee-sharing-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 DynamicFeeSharingClient const client = new DynamicFeeSharingClient(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/dynamic-fee-sharing/typescript-sdk/sdk-functions Dynamic Fee Sharing ## Core Functions ### createFeeVault Creates a fee vault. **Function** ```typescript theme={"system"} async createFeeVault(params: CreateFeeVaultParam): Promise ``` **Parameters** ```typescript theme={"system"} interface CreateFeeVaultParams { feeVault: PublicKey; // The fee vault address tokenMint: PublicKey; // The token mint address tokenProgram: PublicKey; // The token program address owner: PublicKey; // The owner of the fee vault payer: PublicKey; // The wallet that will pay for the transaction userShare: UserShare[]; // The user share of the fee vault } interface UserShare { address: PublicKey; // The user address share: number; // The user share } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const feeVault = Keypair.generate(); const transaction = await client.createFeeVault({ feeVault: feeVault.publicKey, tokenMint: new PublicKey("tokenMint1234567890abcdefghijklmnopqrstuvwxyz"), tokenProgram: TOKEN_PROGRAM_ID, owner: owner.publicKey, payer: payer.publicKey, userShare: [ { address: new PublicKey("user1234567890abcdefghijklmnopqrstuvwxyz"), share: 60, }, { address: new PublicKey("user1234567890abcdefghijklmnopqrstuvwxyz"), share: 40, }, ], }); ``` **Notes** * The `payer` and `feeVault` is required to sign the transaction. * `UserShare` is an array of objects with `address` and `share`. * Minimum: At least 2 users must be included * Maximum: No more than 5 users can be included *** ### createFeeVaultPda Creates a fee vault PDA. **Function** ```typescript theme={"system"} async createFeeVaultPda(params: CreateFeeVaultPdaParams): Promise ``` **Parameters** ```typescript theme={"system"} interface CreateFeeVaultParams { base: PublicKey; // The base address tokenMint: PublicKey; // The token mint address owner: PublicKey; // The owner of the fee vault payer: PublicKey; // The wallet that will pay for the transaction userShare: UserShare[]; // The user share of the fee vault } interface UserShare { address: PublicKey; // The user address share: number; // The user share } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = Keypair.generate(); const transaction = await client.createFeeVaultPda({ base: base.publicKey, tokenMint: new PublicKey("tokenMint1234567890abcdefghijklmnopqrstuvwxyz"), owner: owner.publicKey, payer: payer.publicKey, userShare: [ { address: new PublicKey("user1234567890abcdefghijklmnopqrstuvwxyz"), share: 60, }, { address: new PublicKey("user1234567890abcdefghijklmnopqrstuvwxyz"), share: 40, }, ], }); ``` **Notes** * The `payer` and `base` is required to sign the transaction. * `UserShare` is an array of objects with `address` and `share`. * Minimum: At least 2 users must be included * Maximum: No more than 5 users can be included *** ### fundFeeVault Funds the fee vault. **Function** ```typescript theme={"system"} async fundFeeVault(params: FundFeeVaultParams): Promise ``` **Parameters** ```typescript theme={"system"} interface FundFeeVaultParams { fundAmount: BN; // The amount to fund feeVault: PublicKey; // The fee vault address funder: PublicKey; // The funder address } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const transaction = await client.fundFeeVault({ fundAmount: new BN(1000000), feeVault: new PublicKey("user1234567890abcdefghijklmnopqrstuvwxyz"), funder: funder.publicKey, }); ``` **Notes** * The `funder` is required to sign the transaction. *** ### fundByClaimDammV2Fee Funds the fee vault by claiming fee from a DAMM v2 pool. **Function** ```typescript theme={"system"} async fundByClaimDammV2Fee(params: FundByClaimDammV2FeeParams): Promise ``` **Parameters** ```typescript theme={"system"} interface FundByClaimDammV2FeeParams { signer: PublicKey; // The signer of the transaction owner: PublicKey; // The owner of the fee vault feeVault: PublicKey; // The fee vault address dammV2Pool: PublicKey; // The DAMM v2 pool address dammV2Position: PublicKey; // The DAMM v2 position address dammV2PositionNftAccount: PublicKey; // The DAMM v2 position NFT account address dammV2PoolState?: PoolState; // The DAMM v2 pool state } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"); const tokenMint = new PublicKey("So11111111111111111111111111111111111111112"); const feeVault = deriveFeeVaultPdaAddress(base, tokenMint); const transaction = await client.fundByClaimDammV2Fee({ signer: signer.publicKey, owner: owner.publicKey, feeVault, dammV2Pool: new PublicKey("dammv2Pool1234567890abcdefghijklmnopqrstuvwxyz"), dammV2Position: new PublicKey( "dammv2Position1234567890abcdefghijklmnopqrstuvwxyz" ), dammV2PositionNftAccount: new PublicKey( "dammv2PositionNftAccount1234567890abcdefghijklmnopqrstuvwxyz" ), }); ``` **Notes** * The `signer` is required to sign the transaction. * If you have not set the owner of the position NFT account to the fee vault, you can use the `setTokenAccountOwnerTx` function to set it. * The `dammV2PoolState` is optional and will be fetched from the network if not provided. *** ### fundByClaimDammV2Reward Funds the fee vault by claiming reward from a DAMM v2 pool. **Function** ```typescript theme={"system"} async fundByClaimDammV2Reward(params: FundByClaimDammV2RewardParams): Promise ``` **Parameters** ```typescript theme={"system"} interface FundByClaimDammV2RewardParams { signer: PublicKey; // The signer of the transaction rewardIndex: number; // The reward index feeVault: PublicKey; // The fee vault address dammV2Position: PublicKey; // The DAMM v2 position address dammV2PositionNftAccount: PublicKey; // The DAMM v2 position NFT account address dammV2Pool: PublicKey; // The DAMM v2 pool address dammV2PoolState?: PoolState; // The DAMM v2 pool state } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"); const tokenMint = new PublicKey("So11111111111111111111111111111111111111112"); const feeVault = deriveFeeVaultPdaAddress(base, tokenMint); const transaction = await client.fundByClaimDammV2Reward({ signer: signer.publicKey, rewardIndex: 0, feeVault, dammV2Pool: new PublicKey("dammv2Pool1234567890abcdefghijklmnopqrstuvwxyz"), dammV2Position: new PublicKey( "dammv2Position1234567890abcdefghijklmnopqrstuvwxyz" ), dammV2PositionNftAccount: new PublicKey( "dammv2PositionNftAccount1234567890abcdefghijklmnopqrstuvwxyz" ), }); ``` **Notes** * The `signer` is required to sign the transaction. * The `rewardIndex` is the index of the reward to claim. * The `dammV2PoolState` is optional and will be fetched from the network if not provided. *** ### fundByClaimDbcCreatorTradingFee Funds the fee vault by claiming creator trading fee from a DBC pool. **Function** ```typescript theme={"system"} async fundByClaimDbcCreatorTradingFee(params: FundByClaimDbcCreatorTradingFeeParam): Promise ``` **Parameters** ```typescript theme={"system"} interface FundByClaimDbcCreatorTradingFeeParams { signer: PublicKey; // The signer of the transaction creator: PublicKey; // The creator of the fee vault feeVault: PublicKey; // The fee vault address poolConfig: PublicKey; // The DBC config address virtualPool: PublicKey; // The DBC pool address poolConfigState?: PoolConfig; // The DBC config state virtualPoolState?: VirtualPool; // The DBC pool state } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"); const tokenMint = new PublicKey("So11111111111111111111111111111111111111112"); const feeVault = deriveFeeVaultPdaAddress(base, tokenMint); const transaction = await client.fundByClaimDbcCreatorTradingFee({ signer: signer.publicKey, creator: creator.publicKey, feeVault, poolConfig: new PublicKey("poolConfig1234567890abcdefghijklmnopqrstuvwxyz"), virtualPool: new PublicKey("virtualPool1234567890abcdefghijklmnopqrstuvwxyz"), }); ``` **Notes** * The `signer` is required to sign the transaction. * The `virtualPoolState` is optional and will be fetched from the network if not provided. * The `poolConfigState` is optional and will be fetched from the network if not provided. * You would need to ensure that the DBC pool config's creator is the fee vault address. *** ### fundByClaimDbcPartnerTradingFee Funds the fee vault by claiming partner trading fee from a DBC pool. **Function** ```typescript theme={"system"} async fundByClaimDbcPartnerTradingFee(params: FundByClaimDbcPartnerTradingFeeParams): Promise ``` **Parameters** ```typescript theme={"system"} interface FundByClaimDbcPartnerTradingFeeParams { signer: PublicKey; // The signer of the transaction feeClaimer: PublicKey; // The fee claimer of the fee vault feeVault: PublicKey; // The fee vault address poolConfig: PublicKey; // The DBC config address virtualPool: PublicKey; // The DBC pool address poolConfigState?: PoolConfig; // The DBC config state virtualPoolState?: VirtualPool; // The DBC pool state } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"); const tokenMint = new PublicKey("So11111111111111111111111111111111111111112"); const feeVault = deriveFeeVaultPdaAddress(base, tokenMint); const transaction = await client.fundByClaimDbcPartnerTradingFee({ signer: signer.publicKey, feeClaimer: feeClaimer.publicKey, feeVault, poolConfig: new PublicKey("poolConfig1234567890abcdefghijklmnopqrstuvwxyz"), virtualPool: new PublicKey("virtualPool1234567890abcdefghijklmnopqrstuvwxyz"), }); ``` **Notes** * The `signer` is required to sign the transaction. * The `virtualPoolState` is optional and will be fetched from the network if not provided. * The `poolConfigState` is optional and will be fetched from the network if not provided. * You would need to ensure that the DBC pool config's fee claimer is the fee vault address. *** ### fundByWithdrawDbcCreatorSurplus Funds the fee vault by withdrawing creator surplus from a DBC pool. **Function** ```typescript theme={"system"} async fundByWithdrawDbcCreatorSurplus(params: FundByWithdrawDbcCreatorSurplusParams): Promise ``` **Parameters** ```typescript theme={"system"} interface FundByWithdrawDbcCreatorSurplusParams { signer: PublicKey; // The signer of the transaction feeVault: PublicKey; // The fee vault address poolConfig: PublicKey; // The DBC config address virtualPool: PublicKey; // The DBC pool address poolConfigState?: PoolConfig; // The DBC config state virtualPoolState?: VirtualPool; // The DBC pool state } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"); const tokenMint = new PublicKey("So11111111111111111111111111111111111111112"); const feeVault = deriveFeeVaultPdaAddress(base, tokenMint); const transaction = await client.fundByWithdrawDbcCreatorSurplus({ signer: signer.publicKey, feeVault, poolConfig: new PublicKey("poolConfig1234567890abcdefghijklmnopqrstuvwxyz"), virtualPool: new PublicKey("virtualPool1234567890abcdefghijklmnopqrstuvwxyz"), }); ``` **Notes** * The `signer` is required to sign the transaction. * The `virtualPoolState` is optional and will be fetched from the network if not provided. * The `poolConfigState` is optional and will be fetched from the network if not provided. * You would need to ensure that the DBC pool config's creator is the fee vault address. *** ### fundByWithdrawDbcPartnerSurplus Funds the fee vault by withdrawing partner surplus from a DBC pool. **Function** ```typescript theme={"system"} async fundByWithdrawDbcPartnerSurplus(params: FundByWithdrawDbcPartnerSurplusParams): Promise ``` **Parameters** ```typescript theme={"system"} interface FundByWithdrawDbcPartnerSurplusParams { signer: PublicKey; // The signer of the transaction feeVault: PublicKey; // The fee vault address poolConfig: PublicKey; // The DBC config address virtualPool: PublicKey; // The DBC pool address poolConfigState?: PoolConfig; // The DBC config state virtualPoolState?: VirtualPool; // The DBC pool state } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"); const tokenMint = new PublicKey("So11111111111111111111111111111111111111112"); const feeVault = deriveFeeVaultPdaAddress(base, tokenMint); const transaction = await client.fundByWithdrawDbcPartnerSurplus({ signer: signer.publicKey, feeVault, poolConfig: new PublicKey("poolConfig1234567890abcdefghijklmnopqrstuvwxyz"), virtualPool: new PublicKey("virtualPool1234567890abcdefghijklmnopqrstuvwxyz"), }); ``` **Notes** * The `signer` is required to sign the transaction. * The `virtualPoolState` is optional and will be fetched from the network if not provided. * The `poolConfigState` is optional and will be fetched from the network if not provided. * You would need to ensure that the DBC pool config's fee claimer is the fee vault address. *** ### fundByWithdrawDbcMigrationFee Funds the fee vault by withdrawing migration fee from a DBC pool. **Function** ```typescript theme={"system"} async fundByWithdrawDbcMigrationFee(params: FundByWithdrawDbcMigrationFeeParams): Promise ``` **Parameters** ```typescript theme={"system"} interface FundByWithdrawDbcMigrationFeeParams { signer: PublicKey; // The signer of the transaction isPartner: boolean; // Whether the fee vault is a partner feeVault: PublicKey; // The fee vault address poolConfig: PublicKey; // The DBC config address virtualPool: PublicKey; // The DBC pool address poolConfigState?: PoolConfig; // The DBC config state virtualPoolState?: VirtualPool; // The DBC pool state } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const base = new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"); const tokenMint = new PublicKey("So11111111111111111111111111111111111111112"); const feeVault = deriveFeeVaultPdaAddress(base, tokenMint); const transaction = await client.fundByWithdrawDbcMigrationFee({ signer: signer.publicKey, isPartner: true, feeVault, poolConfig: new PublicKey("poolConfig1234567890abcdefghijklmnopqrstuvwxyz"), virtualPool: new PublicKey("virtualPool1234567890abcdefghijklmnopqrstuvwxyz"), }); ``` **Notes** * The `signer` is required to sign the transaction. * The `virtualPoolState` is optional and will be fetched from the network if not provided. * The `poolConfigState` is optional and will be fetched from the network if not provided. * You would need to ensure that the DBC pool config's fee claimer / creator is the fee vault address. *** ### claimUserFee Claims the fee for the user. **Function** ```typescript theme={"system"} async claimUserFee(claimUserFeeParam: ClaimUserFeeParam): Promise ``` **Parameters** ```typescript theme={"system"} interface ClaimUserFeeParams { feeVault: PublicKey; // The fee vault address user: PublicKey; // The user address 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.claimUserFee({ feeVault: new PublicKey("user1234567890abcdefghijklmnopqrstuvwxyz"), user: user.publicKey, payer: payer.publicKey, }); ``` **Notes** * The `payer` and `user` is required to sign the transaction. *** ## State Functions ### getFeeVault Get the fee vault state. **Function** ```typescript theme={"system"} async getFeeVault(feeVault: PublicKey): Promise ``` **Parameters** ```typescript theme={"system"} feeVault: PublicKey; ``` **Returns** A fee vault state object. **Example** ```typescript theme={"system"} const feeVault = await client.getFeeVault( new PublicKey("vault1234567890abcdefghijklmnopqrstuvwxyz") }); ``` **Notes** * This function returns the fee vault state. *** ### getFeeBreakdown Get the fee breakdown in the fee vault. **Function** ```typescript theme={"system"} async getFeeBreakdown(feeVault: PublicKey): Promise<{ totalFundedFee: BN; totalClaimedFee: BN; totalUnclaimedFee: BN; userFees: { address: PublicKey; totalFee: BN; feeClaimed: BN; feeUnclaimed: BN; }[]; }> ``` **Parameters** ```typescript theme={"system"} feeVault: PublicKey; ``` **Returns** A fee breakdown object. **Example** ```typescript theme={"system"} const feeBreakdown = await client.getFeeBreakdown( new PublicKey("vault1234567890abcdefghijklmnopqrstuvwxyz") ); console.log(feeBreakdown); ``` **Notes** * This function returns the fee breakdown object consisting of the total funded fee, total claimed fee, total unclaimed fee, and user fees. *** ## Helper Functions ### deriveFeeVaultPdaAddress Derive the fee vault PDA address. **Function** ```typescript theme={"system"} deriveFeeVaultPdaAddress(base: PublicKey, tokenMint: PublicKey): PublicKey ``` **Parameters** ```typescript theme={"system"} base: PublicKey; tokenMint: PublicKey; ``` **Returns** A PDA address. **Example** ```typescript theme={"system"} const feeVaultPda = deriveFeeVaultPdaAddress( new PublicKey("base1234567890abcdefghijklmnopqrstuvwxyz"), new PublicKey("tokenMint1234567890abcdefghijklmnopqrstuvwxyz") ); ``` **Notes** * This function returns the PDA address of the fee vault. *** ### convertToLamportsBN Convert to lamports in BN type. **Function** ```typescript theme={"system"} convertToLamportsBN(amount: number | string, tokenDecimal: number): BN ``` **Parameters** ```typescript theme={"system"} amount: number | string; tokenDecimal: number; ``` **Returns** A token amount in BN type. **Example** ```typescript theme={"system"} const fundAmount = convertToLamportsBN(1, 9); ``` **Notes** * This function returns the lamports in BN type. *** ### setTokenAccountOwnerTx Set the owner of a token account. **Function** ```typescript theme={"system"} setTokenAccountOwnerTx(tokenAccount: PublicKey, from: PublicKey, to: PublicKey, tokenProgramId: PublicKey): Transaction ``` **Parameters** ```typescript theme={"system"} tokenAccount: PublicKey; from: PublicKey; to: PublicKey; tokenProgramId: PublicKey; ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const transaction = setTokenAccountOwnerTx( new PublicKey("tokenAccount1234567890abcdefghijklmnopqrstuvwxyz"), from.publicKey, to.publicKey, TOKEN_2022_PROGRAM_ID ); ``` **Notes** * This function returns the transaction that can be signed and sent to the network. * Can be used to transfer DAMM v2 position NFT to the fee vault. # Vault Periphery Source: https://docs.meteora.ag/developer-guide/guides/dynamic-vault/affiliate/vault-periphery Dynamic Vault If you are a lending platform, you can use the `vault-periphery` program to integrate with the Dynamic Vault program as a partner. Example implementation of a program that integrates with vault program on-chain. # Overview Source: https://docs.meteora.ag/developer-guide/guides/dynamic-vault/overview Before getting started building on Dynamic Vault, you should read the following resource to get a better understanding of how Meteora's Dynamic Vault works: Dynamic Vault is a vault that rebalances every minute across lending platforms to find the best possible yield while prioritizing keeping user funds as accessible as possible. *** # Dynamic Vault Program At Meteora, we’ve developed a `Node.js <> Typescript SDK` to make deploying and managing your Dynamic Vault easier. The following sections includes information on installing and using the SDK. It also covers where to find the latest code, and how to contribute to these repositories. ## Program Details Meteora Dynamic Vault Program IDL
Network Program ID
Mainnet 24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi
Devnet 24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi
## Official SDKs Official Meteora Dynamic Vault Typescript SDK # Integration Source: https://docs.meteora.ag/developer-guide/guides/dynamic-vault/rust-sdk/integration Dynamic Vault The `rust-client` provides a convenient way to interact with the Dynamic Vault program. Before you begin, here are some important resources: Meteora Dynamic Vault Rust SDK # Dependencies Add `mercurial-vault` to dependencies: ```toml theme={"system"} mercurial-vault = { version="0.4.2", features= ["cpi", "mainnet"] } ``` # Functions ### Fetch Vault State ```rust theme={"system"} let (vault, _vault_bump) = Pubkey::find_program_address( &[b"vault".as_ref(), token_mint.as_ref(), mercurial_vault::get_base_key().as_ref()], &mercurial_vault::id(), ); ``` ```rust theme={"system"} let vault_state: mercurial_vault::state::Vault = program_client.account(vault)?; ``` Once you have the vault state, you can retrieve key vault information such as: #### Total unlocked amount in vault Get the total amount of tokens that are available for withdrawal. The vault will lock the yield claimed initially and release them over a pre-defined period of time. ```rust theme={"system"} // Total unlocked amount in the vault available for withdrawal // current_time is current Solana node timestamp total_unlocked_amount = vault_state.get_unlocked_amount(current_time) ``` #### Total reserve in the vault We currently keep 10% of the total deposits in the vault to support swaps and immediate withdrawals. ```rust theme={"system"} // Get the vault reserve value // Get the token vault data let token_data: anchor_spl::token::TokenAccount = program_client.account(vault_data.token_vault)?; vault_reserves = token_data.amount //vault reserve value ``` #### Total LP supply for the vault Retrieve the total LP token amount in the vault. ```rust theme={"system"} // Get total total LP supply let token_mint: anchor_spl::token::Mint = program_client.account(vault_data.lp_mint)?; total_lp_supply = token_mint.supply ``` #### Vault virtual price calculation Get the current virtual price for the vault. ```rust theme={"system"} // Calculate vault virtual price using unlocked amount and lp supply virtual_price = total_unlocked_amount / total_lp_supply ``` ### Deposit Liquidity into the Dynamic Vault ```rust theme={"system"} // Retrieve the value for vault // You can use the one of our supported token_mints (you can find the token_mint values in the "Constants" section let (vault, _vault_bump) = Pubkey::find_program_address( &[b"vault".as_ref(), token_mint.as_ref(), mercurial_vault::get_base_key().as_ref()], &mercurial_vault::id(), ); // Retrieve the value of token_vault let (token_vault, _token_vault_bump) = Pubkey::find_program_address( &[b"token_vault".as_ref(), vault.as_ref()], &program_client.id(), ); //Retrieve the value of vault_state to get the lp_mint value let vault_state: mercurial_vault::state::Vault = program_client.account(vault)?; let lp_mint = vault_state.lp_mint; // Retrieve user_token and user_lp values using the get_or_create_ata fn let user_token = get_or_create_ata(program_client, token_mint, program_client.payer())?; let user_lp = get_or_create_ata(program_client, lp_mint, program_client.payer())?; ``` ```rust theme={"system"} let builder = program_client .request() .accounts(mercurial_vault::accounts::DepositWithdrawLiquidity { vault, token_vault, lp_mint, user_token, user_lp, user: program_client.payer(), token_program: spl_token::id(), }) .args(mercurial_vault::instruction::Deposit { token_amount, // total amount of tokens to be deposited minimum_lp_token_amount: 0, }); let signature = builder.send()?; ``` ### Withdraw Liquidity from Dynamic Vault ```rust theme={"system"} // Retrieve the vault let (vault, _vault_bump) = Pubkey::find_program_address( &[b"vault".as_ref(), token_mint.as_ref(), mercurial_vault::get_base_key().as_ref()], &mercurial_vault::id(), ); // Retrieve the vault of token_vault let (token_vault, _token_vault_bump) = Pubkey::find_program_address( &[b"token_vault".as_ref(), vault.as_ref()], &program_client.id(), ); //Retrieve the value of vault_state to get the lp_mint value let vault_state: mercurial_vault::state::Vault = program_client.account(vault)?; let lp_mint = vault_state.lp_mint; // Retrieve user_token and user_lp values using the get_or_create_ata fn let user_token = get_or_create_ata(program_client, token_mint, program_client.payer())?; let user_lp = get_or_create_ata(program_client, lp_mint, program_client.payer())?; ``` ```rust theme={"system"} let builder = program_client .request() .accounts(mercurial_vault::accounts::DepositWithdrawLiquidity { vault, token_vault, lp_mint, user_token, user_lp, user: program_client.payer(), token_program: spl_token::id(), }) .args(mercurial_vault::instruction::Withdraw { unmint_amount, //total amount of LP tokens to withdraw min_out_amount: 0, }); let signature = builder.send()?; ``` ### Withdraw Directly from Lending Platforms If you are integrating the vaults directly onto your platform, you can use this function to withdraw funds directly from a selected lending platform. ```rust theme={"system"} // Get the vault pubkey using the token_mint of the vault let (vault, _) = Pubkey::find_program_address( &[b"vault".as_ref(), token_mint.as_ref(), mercurial_vault::get_base_key().as_ref()], &mercurial_vault::id(), ); // Retrieve the vault state let vault_data: mercurial_vault::state::Vault = program_client.account(vault)?; // Iterate through all the lending platform pools integrated with the vault for (i, &strategy_pubkey) in vault_data.strategies.iter().enumerate(){ // get strategy pubkey println!("{}", strategy_pubkey); } ``` ```rust theme={"system"} // Get the strategy_state using the strategy_pubkey let strategy_state: mercurial_vault::state::Strategy = program_client.account(strategy_pubkey)?; // Call the fn to withdraw funds directly from the strategy let strategy_handler = get_strategy_handler(strategy_state.strategy_type); strategy_handler.withdraw_directly_from_strategy( &program_client, strategy, token_mint, base, unmint_amount, )? ``` # Getting Started Source: https://docs.meteora.ag/developer-guide/guides/dynamic-vault/typescript-sdk/getting-started Dynamic Vault This guide provides instructions on how to get started with building on Meteora's Dynamic Vault program using the Dynamic Vault TypeScript SDK. Before you begin, here are some important resources: Meteora Dynamic Vault Typescript SDK Meteora Dynamic 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/vault-sdk @solana/web3.js @solana/spl-token-registry ``` ```bash theme={"system"} pnpm install @meteora-ag/vault-sdk @solana/web3.js @solana/spl-token-registry ``` ```bash theme={"system"} yarn add @meteora-ag/vault-sdk @solana/web3.js @solana/spl-token-registry ``` # 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 VaultImpl from '@meteora-ag/vault-sdk'; import { StaticTokenListResolutionStrategy, TokenInfo } from "@solana/spl-token-registry"; // Initialize a connection to the Solana network (e.g., Mainnet) const connection = new Connection("https://api.mainnet-beta.solana.com"); // Retrieve the token info for the vault (example: SOL) const tokenMap = new StaticTokenListResolutionStrategy().resolve(); const SOL_TOKEN_INFO = tokenMap.find(token => token.symbol === 'SOL') as TokenInfo; // Getting a Vault Implementation instance (SOL) const vault: VaultImpl = await VaultImpl.create( connection, SOL_TOKEN_INFO, { cluster: 'mainnet-beta' } ); ``` # 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.

# Quickstart Source: https://docs.meteora.ag/developer-guide/guides/dynamic-vault/typescript-sdk/quickstart Dynamic Vault This is a devnet quickstart guide. ```bash theme={"system"} npm i @meteora-ag/vault-sdk @project-serum/anchor @solana/web3.js @solana/spl-token @solana/spl-token-registry ``` ```typescript theme={"system"} import { StaticTokenListResolutionStrategy, TokenInfo } from "@solana/spl-token-registry"; import VaultImpl from '@meteora-ag/vault-sdk'; import { BN } from 'bn.js'; ``` Set up the devnet connection: ```typescript theme={"system"} const devnetConnection = new Connection('https://api.devnet.solana.com/', { commitment: 'confirmed' }); ``` As this demo will be done using a devnet wallet, we can use the Solana airdrop function to deposit some initial SOL into the wallet. Define the SOL airdrop function as shown below. We have already included this function in the util.ts file for easy access and use: ```typescript theme={"system"} const airDropSol = async (connection: Connection, publicKey: PublicKey, amount = 1 * LAMPORTS_PER_SOL) => { try { const airdropSignature = await connection.requestAirdrop( publicKey, amount, ); const latestBlockHash = await connection.getLatestBlockhash(); await connection.confirmTransaction({ blockhash: latestBlockHash.blockhash, lastValidBlockHeight: latestBlockHash.lastValidBlockHeight, signature: airdropSignature, }); } catch (error) { console.error(error); throw error; } }; ``` To trigger the airdrop to your devnet wallet, simply call the function with devnetConnection and your mockWallet public key as input parameters: ```typescript theme={"system"} // Airdrop to devnet wallet await airDropSol(devnetConnection, mockWallet.publicKey); ``` Retrieve the token info required to initialize the vault instance. We use the SOL token as an example here: ```typescript theme={"system"} // Retrieve the token info for the vault (example: SOL) const tokenMap = new StaticTokenListResolutionStrategy().resolve(); const SOL_TOKEN_INFO = tokenMap.find(token => token.symbol === 'SOL') as TokenInfo; ``` Set up the vault instance using the connection and the token info: ```typescript theme={"system"} // Getting a Vault Implementation instance (SOL) const vault: VaultImpl = await VaultImpl.create( devnetConnection, SOL_TOKEN_INFO, { cluster: 'devnet' } ); ``` If you are an affiliate partner, you have to pass in an additional parameter - affiliateId when setting up the vault instance. The affiliateId is the partner wallet address that was used to set up the affiliate relationship with the Meteora Dynamic Yield layer: ```typescript theme={"system"} // Getting a Vault Implementation instance (SOL) const vaultImpl: VaultImpl = await VaultImpl.create( devnetConnection, SOL_TOKEN_INFO, { cluster: 'devnet', // Replace with your own Partner ID! affiliateId: new PublicKey('7236FoaWTXJyzbfFPZcrzg3tBpPhGiTgXsGWvjwrYfiF') } ); ``` Retrieve on-chain data from the vault and off-chain APY data from API. Key info includes total amount currently unlocked for user withdrawals, virtual price and the various strategies connected to the vault. The code for this can be found in getVaultDetails.ts: ```typescript theme={"system"} // Get on-chain data from the vault and off-chain data from the api export const getVaultDetails = async (vaultImpl: VaultImpl) => { //Get the total unlocked amount in vault that is withdrawable by users const vaultUnlockedAmount = (await vaultImpl.getWithdrawableAmount()).toNumber(); //Calculate virtual price using the vault's unlocked amount and lp supply const virtualPrice = (vaultUnlockedAmount / vaultImpl.lpSupply.toNumber()) || 0; // Get the off-chain data from API const URL = KEEPER_URL['devnet']; const vaultStateAPI: VaultStateAPI = await (await fetch(`${URL}/vault_state/${SOL_TOKEN_INFO.address}`)).json(); const totalAllocation = vaultStateAPI.strategies.reduce((acc, item) => acc + item.liquidity, vaultStateAPI.token_amount) return { lpSupply: (await vaultImpl.getVaultSupply()).toString(), withdrawableAmount: vaultUnlockedAmount, virtualPrice, usd_rate: vaultStateAPI.usd_rate, closest_apy: vaultStateAPI.closest_apy, // 1 hour average APY average_apy: vaultStateAPI.average_apy, // 24 hour average APY long_apy: vaultStateAPI.long_apy, // 7 day average APY earned_amount: vaultStateAPI.earned_amount, // total fees earned by vault virtual_price: vaultStateAPI.virtual_price, total_amount: vaultStateAPI.total_amount, total_amount_with_profit: vaultStateAPI.total_amount_with_profit, token_amount: vaultStateAPI.token_amount, fee_amount: vaultStateAPI.fee_amount, lp_supply: vaultStateAPI.lp_supply, strategyAllocation: vaultStateAPI.strategies .map(item => ({ name: item.strategy_name, liquidity: item.liquidity, allocation: ((item.liquidity / totalAllocation) * 100).toFixed(0), maxAllocation: item.max_allocation, })) .concat({ name: 'Vault Reserves', liquidity: vaultStateAPI.token_amount, allocation: ((vaultStateAPI.token_amount / totalAllocation) * 100).toFixed(0), maxAllocation: 0, }) .sort((a, b) => b.liquidity - a.liquidity), } } ``` You can trigger the function and get the vault details via the following: ```typescript theme={"system"} const vaultDetails = await getVaultDetails(vault); console.log(vaultDetails); ``` The steps below will allow you to deposit tokens into the vault by specifying the source wallet and the amount you want to deposit: ```typescript theme={"system"} // Deposits into the vault const depositAmount = 0.1; const depositTx = await vault.deposit(mockWallet.publicKey, new BN(depositAmount * 10 ** SOL_TOKEN_INFO.decimals)); // 0.1 SOL const depositResult = await provider.sendAndConfirm(depositTx); ``` The steps below will allow you to withdraw tokens from the vault by specifying the destination wallet and the amount you want to withdraw from the vault: ```typescript theme={"system"} // Withdraw from the vault const withdrawAmount = 0.05; const withdrawTx = await vault.withdraw(mockWallet.publicKey, new BN(withdrawAmount * 10 ** SOL_TOKEN_INFO.decimals)); // 0.05 SOL const withdrawResult = await provider.sendAndConfirm(withdrawTx); // Transaction hash ``` If you are an affiliate partner, you can retrieve information about the partner account: ```typescript theme={"system"} const partnerInfo = await vaultImpl.getAffiliateInfo(); console.log('Result:', { 'publicKey': mockWallet.publicKey.toString(), 'balance': (await vaultImpl.getUserBalance(mockWallet.publicKey)).toString(), 'Partner Token': partnerInfo.partnerToken.toString(), 'Vault': partnerInfo.vault.toString(), 'Total Fee': partnerInfo.totalFee.toString(), 'Fee Ratio': partnerInfo.feeRatio.toString(), 'Cumulative Fee': partnerInfo.cummulativeFee.toString(), }) ``` # SDK Functions Source: https://docs.meteora.ag/developer-guide/guides/dynamic-vault/typescript-sdk/sdk-functions Dynamic Vault ## Core Functions ### createPermissionlessVaultInstruction Creates an instruction to initialize a new permissionless vault. **Function** ```typescript theme={"system"} static async createPermissionlessVaultInstruction( connection: Connection, payer: PublicKey, tokenMint: PublicKey, opt?: { cluster?: Cluster; programId?: string; } ): Promise ``` **Parameters** ```typescript theme={"system"} interface CreatePermissionlessVaultParams { connection: Connection; // Solana connection instance payer: PublicKey; // The wallet paying for the transaction tokenMint: PublicKey; // The mint address of the token for the vault opt?: { cluster?: Cluster; // Network cluster (mainnet-beta, devnet, testnet) programId?: string; // Custom program ID (optional) }; } ``` **Returns** A transaction instruction that can be used to initialize the vault. **Example** ```typescript theme={"system"} const instruction = await VaultImpl.createPermissionlessVaultInstruction( connection, wallet.publicKey, usdcMint, { cluster: 'mainnet-beta', programId: CUSTOM_PROGRAM_ID // optional } ); const transaction = new Transaction().add(instruction); const signature = await wallet.sendTransaction(transaction, connection); ``` **Notes** * Creates all necessary PDAs for the vault including vault account, token vault, and LP mint * The vault will be permissionless, allowing anyone to deposit and withdraw * Payer will cover the rent costs for the new accounts *** ### fetchMultipleUserBalance Fetches LP token balances for multiple vaults for a specific user. **Function** ```typescript theme={"system"} static async fetchMultipleUserBalance( connection: Connection, lpMintList: Array, owner: PublicKey ): Promise> ``` **Parameters** ```typescript theme={"system"} interface FetchMultipleUserBalanceParams { connection: Connection; // Solana connection instance lpMintList: Array; // Array of LP mint addresses owner: PublicKey; // The user's wallet address } ``` **Returns** An array of BN values representing the user's LP token balance for each vault. **Example** ```typescript theme={"system"} const lpMints = [vault1LpMint, vault2LpMint, vault3LpMint]; const balances = await VaultImpl.fetchMultipleUserBalance( connection, lpMints, wallet.publicKey ); balances.forEach((balance, index) => { console.log(`Vault ${index} LP balance: ${balance.toString()}`); }); ``` **Notes** * Returns 0 for vaults where the user has no LP tokens * Efficiently fetches multiple balances in a single call * Useful for portfolio overview displays *** ### createMultiple Creates multiple vault instances from token mint addresses. **Function** ```typescript theme={"system"} static async createMultiple( connection: Connection, tokenMints: Array, opt?: { seedBaseKey?: PublicKey; allowOwnerOffCurve?: boolean; cluster?: Cluster; programId?: string; affiliateId?: PublicKey; affiliateProgramId?: string; } ): Promise> ``` **Parameters** ```typescript theme={"system"} interface CreateMultipleParams { connection: Connection; // Solana connection instance tokenMints: Array; // Array of token mint addresses opt?: { seedBaseKey?: PublicKey; // Optional seed for deterministic PDAs allowOwnerOffCurve?: boolean; // Allow off-curve owner accounts cluster?: Cluster; // Network cluster programId?: string; // Custom vault program ID affiliateId?: PublicKey; // Affiliate partner ID affiliateProgramId?: string; // Affiliate program ID }; } ``` **Returns** An array of `VaultImpl` instances for the specified token mints. **Example** ```typescript theme={"system"} const tokenMints = [usdcMint, solMint, btcMint]; const vaults = await VaultImpl.createMultiple(connection, tokenMints, { cluster: 'mainnet-beta', affiliateId: partnerPublicKey }); vaults.forEach((vault, index) => { console.log(`Vault ${index}: ${vault.vaultPda.toString()}`); }); ``` **Notes** * Efficiently creates multiple vault instances in parallel * All vaults must already exist on-chain * Useful for initializing a portfolio of vaults *** ### createMultipleWithPda Creates multiple vault instances from vault PDA addresses. **Function** ```typescript theme={"system"} static async createMultipleWithPda( connection: Connection, vaultsPda: Array, opt?: { seedBaseKey?: PublicKey; allowOwnerOffCurve?: boolean; cluster?: Cluster; programId?: string; affiliateId?: PublicKey; affiliateProgramId?: string; } ): Promise> ``` **Parameters** ```typescript theme={"system"} interface CreateMultipleWithPdaParams { connection: Connection; // Solana connection instance vaultsPda: Array; // Array of vault PDA addresses opt?: { seedBaseKey?: PublicKey; // Optional seed for deterministic PDAs allowOwnerOffCurve?: boolean; // Allow off-curve owner accounts cluster?: Cluster; // Network cluster programId?: string; // Custom vault program ID affiliateId?: PublicKey; // Affiliate partner ID affiliateProgramId?: string; // Affiliate program ID }; } ``` **Returns** An array of `VaultImpl` instances for the specified vault PDAs. **Example** ```typescript theme={"system"} const vaultPdas = [vault1Pda, vault2Pda, vault3Pda]; const vaults = await VaultImpl.createMultipleWithPda(connection, vaultPdas, { affiliateId: partnerPublicKey, affiliateProgramId: CUSTOM_AFFILIATE_PROGRAM_ID }); console.log(`Created ${vaults.length} vault instances`); ``` **Notes** * Use this when you already have the vault PDA addresses * More direct than `createMultiple` when PDAs are known * Supports affiliate integration for revenue sharing *** ### create Creates a single vault instance from a token mint address. **Function** ```typescript theme={"system"} static async create( connection: Connection, tokenAddress: PublicKey, opt?: { seedBaseKey?: PublicKey; allowOwnerOffCurve?: boolean; cluster?: Cluster; programId?: string; affiliateId?: PublicKey; affiliateProgramId?: string; } ): Promise ``` **Parameters** ```typescript theme={"system"} interface CreateParams { connection: Connection; // Solana connection instance tokenAddress: PublicKey; // Token mint address opt?: { seedBaseKey?: PublicKey; // Optional seed for deterministic PDAs allowOwnerOffCurve?: boolean; // Allow off-curve owner accounts cluster?: Cluster; // Network cluster programId?: string; // Custom vault program ID affiliateId?: PublicKey; // Affiliate partner ID affiliateProgramId?: string; // Affiliate program ID }; } ``` **Returns** A `VaultImpl` instance for the specified token. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint, { cluster: 'mainnet-beta', affiliateId: partnerPublicKey }); console.log(`Vault PDA: ${vault.vaultPda.toString()}`); console.log(`Token Mint: ${vault.tokenMint.address.toString()}`); console.log(`LP Supply: ${vault.tokenLpMint.supply.toString()}`); ``` **Notes** * Use this for creating a single vault instance * The vault must already exist on-chain * Automatically fetches and caches vault state information *** ### getUserBalance Gets the user's LP token balance for this vault. **Function** ```typescript theme={"system"} async getUserBalance(owner: PublicKey): Promise ``` **Parameters** ```typescript theme={"system"} interface GetUserBalanceParams { owner: PublicKey; // The user's wallet address } ``` **Returns** A BN representing the user's LP token balance. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint); const userBalance = await vault.getUserBalance(wallet.publicKey); console.log(`User LP balance: ${userBalance.toString()}`); // Convert to human readable format const balanceInTokens = userBalance.div(new BN(10).pow(new BN(vault.tokenLpMint.decimals))); console.log(`User balance: ${balanceInTokens.toString()} LP tokens`); ``` **Notes** * Returns 0 if the user has no LP tokens * Handles both direct deposits and affiliate deposits * Balance represents share of the vault's total assets *** ### getVaultSupply Gets the total LP token supply for the vault. **Function** ```typescript theme={"system"} async getVaultSupply(): Promise ``` **Returns** A BN representing the total LP token supply. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint); const totalSupply = await vault.getVaultSupply(); console.log(`Total LP supply: ${totalSupply.toString()}`); // Calculate user's share percentage const userBalance = await vault.getUserBalance(wallet.publicKey); const userSharePercentage = userBalance.mul(new BN(100)).div(totalSupply); console.log(`User owns ${userSharePercentage.toString()}% of the vault`); ``` **Notes** * Refetches the latest LP mint supply from the blockchain * Updates the cached `tokenLpMint` property * Use the cached `vault.tokenLpMint.supply` for performance if recent data is sufficient *** ### getWithdrawableAmount Gets the amount of assets that can be immediately withdrawn from the vault. **Function** ```typescript theme={"system"} async getWithdrawableAmount(): Promise ``` **Returns** A BN representing the withdrawable amount in base token units. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint); const withdrawableAmount = await vault.getWithdrawableAmount(); console.log(`Withdrawable amount: ${withdrawableAmount.toString()}`); // Convert to human readable format (assuming USDC with 6 decimals) const withdrawableUsdc = withdrawableAmount.div(new BN(1_000_000)); console.log(`Withdrawable: ${withdrawableUsdc.toString()} USDC`); ``` **Notes** * Amount may be less than total vault assets due to strategy allocations * Uses current on-chain time for calculations * Does not account for user's specific LP token balance *** ### refreshVaultState Refreshes the cached vault state and token mint information. **Function** ```typescript theme={"system"} async refreshVaultState(): Promise ``` **Returns** Void. Updates the instance's `vaultState` and `tokenMint` properties. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint); // Check current state console.log(`Current liquidity: ${vault.vaultState.totalLiquidity.toString()}`); // Refresh state to get latest data await vault.refreshVaultState(); // Check updated state console.log(`Updated liquidity: ${vault.vaultState.totalLiquidity.toString()}`); ``` **Notes** * Call this before deposit/withdraw operations to ensure latest state * Updates both vault state and token mint data * Essential for accurate calculations in dynamic environments *** ### deposit Deposits tokens into the vault and receives LP tokens in return. **Function** ```typescript theme={"system"} async deposit(owner: PublicKey, baseTokenAmount: BN): Promise ``` **Parameters** ```typescript theme={"system"} interface DepositParams { owner: PublicKey; // The depositor's wallet address baseTokenAmount: BN; // Amount of base tokens to deposit } ``` **Returns** A `Transaction` ready to be signed and sent. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint, { affiliateId: partnerPublicKey }); // Deposit 1,000 USDC (with 6 decimals) const depositAmount = new BN(1_000_000_000); const depositTx = await vault.deposit(wallet.publicKey, depositAmount); // Sign and send transaction const signature = await wallet.sendTransaction(depositTx, connection); console.log(`Deposit transaction: ${signature}`); ``` **Notes** * Automatically handles SOL wrapping for native SOL vaults * Creates necessary token accounts if they don't exist * Supports affiliate revenue sharing if configured * The transaction includes all necessary pre-instructions * LP tokens are minted proportional to the deposit amount *** ### withdraw Withdraws tokens from the vault by burning LP tokens. **Function** ```typescript theme={"system"} async withdraw(owner: PublicKey, baseTokenAmount: BN): Promise ``` **Parameters** ```typescript theme={"system"} interface WithdrawParams { owner: PublicKey; // The withdrawer's wallet address baseTokenAmount: BN; // Amount of LP tokens to burn for withdrawal } ``` **Returns** A `Transaction` ready to be signed and sent. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint); // Get user's LP token balance const userBalance = await vault.getUserBalance(wallet.publicKey); // Withdraw half of user's position const withdrawAmount = userBalance.div(new BN(2)); const withdrawTx = await vault.withdraw(wallet.publicKey, withdrawAmount); // Sign and send transaction const signature = await wallet.sendTransaction(withdrawTx, connection); console.log(`Withdraw transaction: ${signature}`); ``` **Notes** * Automatically handles SOL unwrapping for native SOL vaults * May withdraw from vault reserves or underlying strategies * Supports affiliate revenue sharing if configured * The `baseTokenAmount` parameter refers to LP tokens to burn, not underlying tokens to receive * Automatically selects the optimal withdrawal strategy based on liquidity availability *** ### getStrategiesState Gets the state of all strategies associated with the vault. **Function** ```typescript theme={"system"} async getStrategiesState(): Promise> ``` **Returns** An array of `StrategyState` objects representing the vault's strategies. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint); const strategies = await vault.getStrategiesState(); strategies.forEach((strategy, index) => { console.log(`Strategy ${index}:`); console.log(` Current Liquidity: ${strategy.currentLiquidity.toString()}`); console.log(` Performance Fee: ${strategy.performanceFee.toString()}`); }); console.log(`Total strategies: ${strategies.length}`); ``` **Notes** * Excludes the vault's internal strategy (VAULT\_STRATEGY\_ADDRESS) * Useful for understanding vault composition and performance * Each strategy represents a different yield farming or liquidity provision approach *** ### getAffiliateInfo Gets affiliate partnership information for the vault. **Function** ```typescript theme={"system"} async getAffiliateInfo(): Promise ``` **Returns** An `AffiliateInfo` object containing partnership details. **Example** ```typescript theme={"system"} const vault = await VaultImpl.create(connection, usdcMint, { affiliateId: partnerPublicKey }); try { const affiliateInfo = await vault.getAffiliateInfo(); console.log(`Partner fee rate: ${affiliateInfo.feeRate}%`); console.log(`Total fees earned: ${affiliateInfo.totalFeesEarned.toString()}`); } catch (error) { console.log('No affiliate information found'); } ``` **Notes** * Only available when vault is created with an `affiliateId` * Throws an error if no affiliate program is configured * Contains fee rates, total fees earned, and partnership terms *** ## State Functions ### getAllVaultState Fetches state information for multiple vaults by token mint addresses. **Function** ```typescript theme={"system"} async getAllVaultState( tokensAddress: Array, program: VaultProgram, seedBaseKey?: PublicKey ): Promise> ``` **Parameters** * `tokensAddress`: Array of token mint addresses * `program`: The vault program instance * `seedBaseKey`: Optional seed for deterministic PDAs **Returns** Array of vault state information including PDA, state, and mint data. **Example** ```typescript theme={"system"} const provider = new AnchorProvider(connection, wallet, {}); const program = new Program(IDL, PROGRAM_ID, provider); const tokenMints = [usdcMint, solMint]; const vaultsInfo = await getAllVaultState(tokenMints, program); vaultsInfo.forEach((vaultInfo, index) => { console.log(`Vault ${index}: ${vaultInfo.vaultPda.toString()}`); console.log(`Total Liquidity: ${vaultInfo.vaultState.totalLiquidity.toString()}`); }); ``` *** ### getAllVaultStateByPda Fetches state information for multiple vaults by their PDA addresses. **Function** ```typescript theme={"system"} async getAllVaultStateByPda( vaultsPda: Array, program: VaultProgram ): Promise> ``` **Parameters** * `vaultsPda`: Array of vault PDA addresses * `program`: The vault program instance **Returns** Array of vault state information including PDA, state, and mint data. **Example** ```typescript theme={"system"} const vaultPdas = [vault1Pda, vault2Pda]; const vaultsInfo = await getAllVaultStateByPda(vaultPdas, program); console.log(`Fetched ${vaultsInfo.length} vault states`); ``` *** ### getVaultState Fetches state information for a single vault by token mint address. **Function** ```typescript theme={"system"} async getVaultState( tokenAddress: PublicKey, program: VaultProgram, seedBaseKey?: PublicKey ): Promise ``` **Parameters** * `tokenAddress`: Token mint address * `program`: The vault program instance * `seedBaseKey`: Optional seed for deterministic PDAs **Returns** Vault state information including PDA, state, and mint data. **Example** ```typescript theme={"system"} const vaultInfo = await getVaultState(usdcMint, program); console.log(`Vault PDA: ${vaultInfo.vaultPda.toString()}`); console.log(`LP Mint: ${vaultInfo.vaultState.lpMint.toString()}`); ``` *** ### getVaultStateByPda Fetches state information for a single vault by its PDA address. **Function** ```typescript theme={"system"} async getVaultStateByPda( vaultPda: PublicKey, program: VaultProgram ): Promise ``` **Parameters** * `vaultPda`: Vault PDA address * `program`: The vault program instance **Returns** Vault state information including PDA, state, and mint data. **Example** ```typescript theme={"system"} const vaultInfo = await getVaultStateByPda(vaultPda, program); console.log(`Token Mint: ${vaultInfo.vaultState.tokenMint.toString()}`); console.log(`Total Supply: ${vaultInfo.vaultLpMint.supply.toString()}`); ``` *** ### getVaultLiquidity Gets the current liquidity amount in the vault's token account. **Function** ```typescript theme={"system"} async getVaultLiquidity( connection: Connection, tokenVaultPda: PublicKey ): Promise ``` **Parameters** * `connection`: Solana connection instance * `tokenVaultPda`: The vault's token account PDA **Returns** The liquidity amount as a string, or null if the account doesn't exist. **Example** ```typescript theme={"system"} const liquidity = await getVaultLiquidity(connection, vault.tokenVaultPda); if (liquidity) { console.log(`Vault liquidity: ${liquidity} tokens`); } else { console.log('Vault account not found'); } ``` *** ## Helper Functions ### calculateWithdrawableAmount Calculates the amount that can be withdrawn based on current time and vault state. **Function** ```typescript theme={"system"} function calculateWithdrawableAmount(currentTime: BN, vaultState: VaultState): BN ``` **Parameters** * `currentTime`: Current blockchain timestamp * `vaultState`: The vault's current state **Returns** The withdrawable amount as a BN. **Example** ```typescript theme={"system"} import { getOnchainTime } from './utils'; const currentTime = await getOnchainTime(connection); const withdrawable = calculateWithdrawableAmount(currentTime, vault.vaultState); console.log(`Withdrawable: ${withdrawable.toString()}`); ``` **Notes** * Accounts for time-based withdrawal restrictions * Used internally by the `getWithdrawableAmount` method * Essential for implementing withdrawal limits and unlock schedules # Overview Source: https://docs.meteora.ag/developer-guide/guides/presale-vault/overview This program is still in beta and is subject to breaking changes. Before getting started building on Presale Vault, you should read the following resource to get a better understanding of how Meteora's Presale Vault works: Presale Vault allows users to contribute using any SPL token and later claim their allocated presale tokens once the presale concludes. *** # Presale Vault Program At Meteora, we’ve developed a `Node.js <> Typescript SDK` to make deploying and managing your Presale Vault easier. The following sections includes information on installing and using the SDK. It also covers where to find the latest code, and how to contribute to these repositories. ## Program Details Meteora Presale Vault Program Meteora Presale Vault Program IDL
Network Program ID
Mainnet presSVxnf9UU8jMxhgSMqaRwNiT36qeBdNeTRKjTdbj
Devnet presSVxnf9UU8jMxhgSMqaRwNiT36qeBdNeTRKjTdbj
## Official SDKs Official Meteora Presale Vault Typescript SDK # Getting Started Source: https://docs.meteora.ag/developer-guide/guides/presale-vault/typescript-sdk/getting-started Presale Vault This guide provides instructions on how to get started with building on Meteora's Presale Vault program using the Presale Vault TypeScript SDK. Before you begin, here are some important resources: Meteora Presale Vault Typescript SDK Meteora Presale Vault NPM Package Meteora Presale Vault Examples # Installation To use the SDK in your project, install it using your preferred package manager: ```bash theme={"system"} npm install @meteora-ag/presale @solana/web3.js ``` ```bash theme={"system"} pnpm install @meteora-ag/presale @solana/web3.js ``` ```bash theme={"system"} yarn add @meteora-ag/presale @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 Presale, { PRESALE_PROGRAM_ID, derivePresale } from "@meteora-ag/presale"; // Initialize a connection to the Solana network (e.g., Mainnet) const connection = new Connection("https://api.mainnet-beta.solana.com"); const baseKeypair = Keypair.generate(); const presaleAddress = derivePresale( new PublicKey("YOUR_BASE_MINT"), new PublicKey("YOUR_QUOTE_MINT"), baseKeypair.publicKey, PRESALE_PROGRAM_ID ); // Create a new instance of the CpAmm SDK const presaleInstance = await Presale.create( connection, presaleAddress, PRESALE_PROGRAM_ID ); ``` # 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.

# CPI Examples Source: https://docs.meteora.ag/developer-guide/guides/stake2earn/cpi/examples Stake2Earn This [repository](https://github.com/MeteoraAg/cpi-examples) contains examples for CPI (Cross-Program Invocation) that interacts with the Stake2Earn program. # Dependencies * **Anchor:** 0.28.0 * **Solana:** 1.16.1 * **Rust:** 1.68.0 # CPI Example implementation of Cross-Program Invocation for initializing a Stake2Earn Vault. Test cases and examples for CPI integration with Stake2Earn programs. # Overview Source: https://docs.meteora.ag/developer-guide/guides/stake2earn/overview Before getting started building on Stake2Earn, you should read the following resource to get a better understanding of how Meteora's Stake2Earn works: Stake2Earn is a helper program that allows token holders to stake their tokens and pool creators to delegate LP fees to the top token stakers. Stake2Earn is currently only compatible with DAMM v1 Pools. *** # Stake2Earn Program At Meteora, we’ve developed a `Node.js <> Typescript SDK` to make deploying and managing your Stake2Earn easier. The following sections includes information on installing and using the SDK. It also covers where to find the latest code, and how to contribute to these repositories. ## Program Details Meteora Stake2Earn Program IDL
Network Program ID
Mainnet FEESngU3neckdwib9X3KWqdL7Mjmqk9XNp3uh5JbP4KP
Devnet FEESngU3neckdwib9X3KWqdL7Mjmqk9XNp3uh5JbP4KP
## Official SDKs Official Meteora Stake2Earn Typescript SDK # Example Scripts Source: https://docs.meteora.ag/developer-guide/guides/stake2earn/typescript-sdk/example-scripts Stake2Earn # Create a Stake2Earn Vault This script contains the following steps: 1. Mint a token 2. Create DAMM v1 Pool 3. Create Stake2Earn Vault 4. Lock user's LP tokens to Stake2Earn Vault ```typescript theme={"system"} import AmmImpl from "@meteora-ag/dynamic-amm-sdk"; import { NATIVE_MINT } from "@solana/spl-token"; import { Connection, Keypair, PublicKey } from "@solana/web3.js"; import BN from "bn.js"; import { StakeForFee } from "../stake-for-fee"; import { DEFAULT_KEYPAIR_PATH, DEVNET_URL, handleSendTransaction, initializeMintAndMint, loadKeypairFromFile, } from "./utils"; import { createFeeVault, createPool, lockLiquidityToFeeVault } from "./actions"; import { U64_MAX } from "../stake-for-fee/constants"; const connection = new Connection(DEVNET_URL); const poolConfigKey = new PublicKey( "BdfD7rrTZEWmf8UbEBPVpvM3wUqyrR8swjAy5SNT8gJ2" ); const mintADecimal = 9; const mintANativeAmountMultiplier = 10 ** mintADecimal; const mintAmount = 10_000; const stakeFarmAmount = 1_000; async function createPoolAndInteractWithFeeVaultExample() { const keypair = loadKeypairFromFile(DEFAULT_KEYPAIR_PATH); console.log(`Wallet ${keypair.publicKey} connected`); const amountAToMint = BigInt(mintAmount) * BigInt(mintANativeAmountMultiplier); const amountAToDeposit = BigInt(mintAmount - stakeFarmAmount) * BigInt(mintANativeAmountMultiplier); // 1,000 reserve to stake const amountB = BigInt(1_000_000); console.log("Create mint A"); const mintA = await initializeMintAndMint( connection, keypair, keypair, mintADecimal, amountAToMint ); console.log("1. Create dynamic vaults and pool"); const poolKey = await createPool( keypair, mintA, NATIVE_MINT, new BN(amountAToDeposit.toString()), new BN(amountB.toString()), poolConfigKey ); const pool = await AmmImpl.create(connection, poolKey); console.log("2. Create fee vault"); const currentSlot = await connection.getSlot("confirmed"); const currentOnchainTimestamp = await connection.getBlockTime(currentSlot); // Number of top stakers const topListLength = 10; // Number of seconds to withdraw unstaked token const unstakeLockDuration = new BN(3600 * 24); // Number of seconds for the swap fee fully dripped to stakers const secondsToFullUnlock = new BN(3600 * 24 * 7); // Timestamp to start fee distribution / drip to stakers const startFeeDistributeTimestamp = new BN(currentOnchainTimestamp + 10); // delay 10 seconds to be able to claim await createFeeVault( poolKey, pool.poolState.tokenAMint, keypair, topListLength, unstakeLockDuration, secondsToFullUnlock, startFeeDistributeTimestamp ); console.log("3. Lock user LP for fee vault"); await lockLiquidityToFeeVault(poolKey, pool, keypair, 10_000); // 10_000 means 100% of LP is being lock console.log("4. Connect to the fee vault"); const feeVault = await StakeForFee.create(connection, poolKey); console.log("5. Stake amount"); const stakeAmount = new BN( (BigInt(stakeFarmAmount) * BigInt(mintANativeAmountMultiplier)).toString() ); // 1,000 stake token (make sure you have enough balance in your wallet) const stakeTx = await feeVault.stake(stakeAmount, keypair.publicKey); const stakeSignature = await handleSendTransaction( connection, stakeTx, keypair ); console.log("Stake Signature", stakeSignature); console.log("6. Get stake balance"); await feeVault.refreshStates(); const userEscrow = await feeVault.getUserStakeAndClaimBalance( keypair.publicKey ); const stakeBalance = userEscrow.stakeEscrow.stakeAmount.toNumber() / 10 ** feeVault.accountStates.tokenAMint.decimals; console.log("Stake Balance", stakeBalance); const claimableFeeA = (userEscrow.unclaimFee.feeA.toNumber() || 0) / 10 ** feeVault.accountStates.tokenAMint.decimals; console.log("Claimable Fee A", claimableFeeA); const claimableFeeB = (userEscrow.unclaimFee.feeB.toNumber() || 0) / 10 ** feeVault.accountStates.tokenBMint.decimals; console.log("Claimable Fee B", claimableFeeB); console.log("7. Claim fee"); const claimFeeTx = await feeVault.claimFee( keypair.publicKey, new BN(U64_MAX) ); for (const [index, tx] of claimFeeTx.entries()) { const signature = await handleSendTransaction(connection, tx, keypair); console.log(`Claim Fee Signature ${index + 1}`, signature); } console.log("8. Unstake"); const unstakeKeyPair = new Keypair(); const unstakeTx = await feeVault.unstake( userEscrow.stakeEscrow.stakeAmount, unstakeKeyPair.publicKey, keypair.publicKey ); const unstakeSignature = await handleSendTransaction(connection, unstakeTx, [ unstakeKeyPair, keypair, ]); console.log("Unstake Signature", unstakeSignature); console.log("9. Cancel unstaked"); const cancelUnstake = await feeVault.cancelUnstake( unstakeKeyPair.publicKey, keypair.publicKey ); const cancelUnstakeSignature = await handleSendTransaction( connection, cancelUnstake, keypair ); console.log("Cancel Unstake Signature", cancelUnstakeSignature); // ⚠️ This only works after unstake period is over console.log("10. Withdraw unstake"); const withdrawUnstake = await feeVault.withdraw( unstakeKeyPair.publicKey, keypair.publicKey ); const withdrawUnstakeSignature = await handleSendTransaction( connection, withdrawUnstake, keypair ); console.log("Withdraw Unstake Signature", withdrawUnstakeSignature); } createPoolAndInteractWithFeeVaultExample() .then(() => console.log("Done")) .catch(console.error); ``` # Stake Tokens into Stake2Earn Vault ```typescript theme={"system"} const stakeAmount = new BN( 1_000 * 10 ** feeFarm.accountStates.tokenAMint.decimals ); // 1,000 stake token (make sure you have enough balance in your wallet) const stakeTx = await feeFarm.stake(stakeAmount, mockWallet.publicKey); const stakeTxHash = await provider.sendAndConfirm(stakeTx); // Transaction hash ``` # Unstake Tokens from Stake2Earn Vault ```typescript theme={"system"} const unstakeKeyPair = new Keypair(); const unstakeTx = await feeVault.unstake( userEscrow.stakeEscrow.stakeAmount, unstakeKeyPair.publicKey, mockWallet.publicKey ); unstakeTx.partialSign(unstakeKeyPair); // Make sure to partial sign unstakeKeypair const unstakeTxHash = await provider.sendAndConfirm(unstakeTx); // Transaction hash ``` # Get Stake and Claimable Balance ```typescript theme={"system"} await feeFarm.refreshStates(); // make sure to refresh states to get the latest data const userEscrow = await feeFarm.getUserStakeAndClaimBalance( mockWallet.publicKey ); const stakeBalance = userStakeEscrow.stakeEscrow.stakeAmount.toNumber() / 10 ** feeFarm.accountStates.tokenAMint.decimals; const claimableFeeA = fromLamports( userStakeEscrow.unclaimFee.feeA || 0, feeFarm.accountStates.tokenAMint.decimals ); const claimableFeeB = fromLamports( userStakeEscrow.unclaimFee.feeB || 0, feeFarm.accountStates.tokenBMint.decimals ); ``` # Claim Fee ```typescript theme={"system"} const claimFeeTx = await feeVault.claimFee( mockWallet.publicKey, new BN(U64_MAX) ); // second param is max amount, so usually we just put max number BN.js can support const claimfeeTxHash = await provider.sendAndConfirm(claimFeeTx); // Transaction hash ``` # Get Unstake Period (Seconds) ```typescript theme={"system"} const unstakePeriodInSeconds = feeFarm.accountStates.feeVault.configuration.unstakeLockDuration.toNumber(); ``` # Cancel Unstake ```typescript theme={"system"} const cancelUnstakeTx = await feeFarm.cancelUnstake( unstakeKeyPair.publicKey, mockWallet.publicKey ); const cancelUnstakeTxHash = await provider.sendAndConfirm(cancelUnstakeTx); ``` # Withdraw Unstaked Tokens from Stake2Earn Vault ```typescript theme={"system"} const withdrawUnstake = await feeFarm.withdraw( unstakeKeyPair.publicKey, mockWallet.publicKey ); ``` # Important Considerations ### Stake2Earn Staking Rewards Distribution Start Time You are recommended to configure your Stake2Earn staking rewards distribution start time (fee claim start time) to be approximately 48 hours after launch. This allows more time for total fee rewards to accumulate from trading activity in the memecoin pool. A bigger total fee reward would help make your Stake2Earn Vault look more appealing to potential stakers. \###Difference Between Locking Liquidity via Stake2Earn vs Directly Locking Liquidity in the Memecoin Pool User lock and Stake2Earn lock use the same lock mechanism on a DAMM v1 Pool. But users and Stake2Earn vaults have their own personal lock escrow account for the pool. When a user permanently locks liquidity directly on the Memecoin Pool page, the user is locking the LP token to their own personal escrow account for the pool. Fees from this locked liquidity go to the user's wallet. However, when a user locks via the Stake2Earn creation process, the user is locking the LP to their unique Stake2Earn Vault stake escrow account. Therefore, fees from this locked liquidity go to the Stake2Earn Vault, which then distributes fees to the top stakers. ### How to Find the Stake2Earn Vault Address and a User Wallet's Unique Personal Stake Escrow Address? Use a wallet simulator (e.g. Sherlock extension) and paste the user's wallet address. Try to stake or unstake tokens in a Stake2Earn Vault. Click "Open explorer" and on the explorer page search for Vault and/or Stake Escrow fields to find the respective addresses. ### Other Considerations * If you plan to use a multisig on the Meteora website, please make sure it is the SquadsX multisig, as that is the only type supported on Meteora website. Otherwise, you can't manage liquidity through the website. * There can only be one Stake2Earn Vault attached to each Memecoin Pool. # Getting Started Source: https://docs.meteora.ag/developer-guide/guides/stake2earn/typescript-sdk/getting-started Stake2Earn This guide provides instructions on how to get started with building on Meteora's Stake2Earn program using the Stake2Earn TypeScript SDK. Before you begin, here are some important resources: Meteora Stake2Earn Typescript SDK Meteora Stake2Earn NPM Package # Installation To use the SDK in your project, install it using your preferred package manager: ```bash theme={"system"} npm install @meteora-ag/m3m3 @solana/web3.js ``` ```bash theme={"system"} pnpm install @meteora-ag/m3m3 @solana/web3.js ``` ```bash theme={"system"} yarn add @meteora-ag/m3m3 @solana/web3.js ``` # Initialization Once installed, you can initialize the SDK in your TypeScript/JavaScript project like this: ```typescript theme={"system"} import StakeForFee from "@meteora-ag/m3m3"; import { PublicKey } from "@solana/web3.js"; // Initialize a connection to the Solana network (e.g., Mainnet) const connection = new Connection("https://api.mainnet-beta.solana.com"); // Intialize the DAMM v1 pool const poolAddress = new PublicKey( "G2MRSjNjCbFUmMf32Z1aXYhy6pc1ihLyYg6orKedyjJG" ); // Create a new instance of the Stake2Earn const stake2earn = await StakeForFee.create(connection, poolAddress); ``` # 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.

# Overview Source: https://docs.meteora.ag/developer-guide/guides/zap/overview Before getting started building on Zap, you should read the following resource to get a better understanding of how Meteora's Zap works: Zap is a wrapper program that provides utility functions that allow users to zap in/out from Meteora AMMs or Jupiter. For example, a user can claim both token fee rewards and immediately swap any of the token through DAMM v2, DLMM or Jupiter to receive the other token. *** # Zap Program At Meteora, we’ve developed a `Node.js <> Typescript SDK` to make Zapping in or out of AMMs easier. The following sections includes information on installing and using the SDK. It also covers where to find the latest code, and how to contribute to these repositories. ## Program Details Meteora Zap Program IDL
Network Program ID
Mainnet zapvX9M3uf5pvy4wRPAbQgdQsM1xmuiFnkfHKPvwMiz
Devnet zapvX9M3uf5pvy4wRPAbQgdQsM1xmuiFnkfHKPvwMiz
## Official SDKs Official Meteora Zap Typescript SDK # Getting Started Source: https://docs.meteora.ag/developer-guide/guides/zap/typescript-sdk/getting-started Zap This guide provides instructions on how to get started with building on Meteora's Zap program using the Zap TypeScript SDK. Before you begin, here are some important resources: Meteora Zap Typescript SDK Meteora Zap NPM Package # Installation To use the SDK in your project, install it using your preferred package manager: ```bash theme={"system"} npm install @meteora-ag/zap-sdk @solana/web3.js ``` ```bash theme={"system"} pnpm install @meteora-ag/zap-sdk @solana/web3.js ``` ```bash theme={"system"} yarn add @meteora-ag/zap-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 { Zap } from "@meteora-ag/zap-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 Zap SDK const zap = new Zap(connection); ``` # 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/zap/typescript-sdk/sdk-functions Zap ## Zap Functions ### zapOut Executes a generic zap out operation with custom parameters. **Function** ```typescript theme={"system"} async zapOut(params: ZapOutParams): Promise ``` **Parameters** ```typescript theme={"system"} interface ZapOutParams { userTokenInAccount: PublicKey; zapOutParams: ZapOutParameters; remainingAccounts: AccountMeta[]; ammProgram: PublicKey; preInstructions: TransactionInstruction[]; postInstructions: TransactionInstruction[]; } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const preUserTokenBalance = ( await this.connection.getTokenAccountBalance(userInputMintAta) ).value.amount; const remainingAccounts = await getDammV2RemainingAccounts( this.connection, poolAddress, user, userInputMintAta, outputTokenAccountAta, inputTokenProgram, outputTokenProgram ); const payloadData = createDammV2SwapPayload(amountIn, minimumSwapAmountOut); const transaction = await client.zap.zapOut({ userTokenInAccount: new PublicKey( "userTokenInAccount1234567890abcdefghijklmnopqrstuvwxyz" ), zapOutParams: { percentage: 100, offsetAmountIn: AMOUNT_IN_DAMM_V2_OFFSET, preUserTokenBalance: preUserTokenBalance, maxSwapAmount: new BN(1000000000), payloadData: payloadData, }, remainingAccounts: remainingAccounts, ammProgram: DAMM_V2_PROGRAM_ID, }); ``` **Notes** * This is a generic function that can be used to zap out from any AMM program. In this example, we are using zap out of DAMM v2 pool. *** ### zapOutThroughJupiter Executes a zap out operation through Jupiter Aggregator v6. **Function** ```typescript theme={"system"} async zapOutThroughJupiter(params: ZapOutThroughJupiterParams): Promise ``` **Parameters** ```typescript theme={"system"} interface ZapOutThroughJupiterParams { user: PublicKey; inputMint: PublicKey; outputMint: PublicKey; inputTokenProgram: PublicKey; outputTokenProgram: PublicKey; jupiterSwapResponse: JupiterSwapInstructionResponse; maxSwapAmount: BN; percentageToZapOut: number; } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const quoteResponse = await getJupiterQuote( inputMint, outputMint, swapAmount, 40, 50, true, true, true, "https://lite-api.jup.ag" ); const swapInstructionResponse = await getJupiterSwapInstruction( wallet.publicKey, quoteResponse ); const inputMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); const zapOutTx = await zap.zapOutThroughJupiter({ user: wallet.publicKey, inputMint, outputMint, inputTokenProgram, outputTokenProgram, jupiterSwapResponse: swapInstructionResponse, maxSwapAmount: new BN(1000000000), percentageToZapOut: 100, }); ``` **Notes** * This function is used to zap out through Jupiter Aggregator v6. * The flow is as such: * Get quote response from Jupiter API * Get swap instruction from Jupiter API using quote response * Get token programs for input and output mints * Build zap transaction using the swap instruction * Send zap transaction *** ### zapOutThroughDammV2 Executes a zap out operation through DAMM v2 pool. **Function** ```typescript theme={"system"} async zapOutThroughDammV2(params: ZapOutThroughDammV2Params): Promise ``` **Parameters** ```typescript theme={"system"} interface ZapOutThroughDammV2Params { user: PublicKey; poolAddress: PublicKey; inputMint: PublicKey; outputMint: PublicKey; inputTokenProgram: PublicKey; outputTokenProgram: PublicKey; amountIn: BN; minimumSwapAmountOut: BN; maxSwapAmount: BN; percentageToZapOut: number; } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const inputMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); const outputMint = new PublicKey("So11111111111111111111111111111111111111112"); const zapOutTx = await zap.zapOutThroughDlmm({ user: wallet.publicKey, poolAddress: new PublicKey("CGPxT5d1uf9a8cKVJuZaJAU76t2EfLGbTmRbfvLLZp5j"), inputMint, outputMint, inputTokenProgram, outputTokenProgram, amountIn: new BN(1000000000), minimumSwapAmountOut: new BN(0), maxSwapAmount: new BN(1000000000), percentageToZapOut: 100, }); ``` **Notes** * This function is used to zap out through DAMM v2 pool. * The flow is as such: * Get token programs for input mint * Build zap transaction * Send zap transaction *** ### zapOutThroughDlmm Executes a zap out operation through DLMM. **Function** ```typescript theme={"system"} async zapOutThroughDlmm(params: ZapOutThroughDlmmParams): Promise ``` **Parameters** ```typescript theme={"system"} interface ZapOutThroughDlmmParams { user: PublicKey; lbPairAddress: PublicKey; inputMint: PublicKey; outputMint: PublicKey; inputTokenProgram: PublicKey; outputTokenProgram: PublicKey; amountIn: BN; minimumSwapAmountOut: BN; maxSwapAmount: BN; percentageToZapOut: number; } ``` **Returns** A transaction that can be signed and sent to the network. **Example** ```typescript theme={"system"} const inputMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); const outputMint = new PublicKey("So11111111111111111111111111111111111111112"); const zapOutTx = await zap.zapOutThroughDlmm({ user: wallet.publicKey, lbPairAddress: new PublicKey("5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6"), inputMint, outputMint, inputTokenProgram, outputTokenProgram, amountIn: new BN(1000000000), minimumSwapAmountOut: new BN(0), maxSwapAmount: new BN(1000000000), percentageToZapOut: 100, }); ``` **Notes** * This function is used to zap out through DLMM. * The flow is as such: * Get token programs for input mint * Build zap transaction * Send zap transaction *** ## Helper Functions ### getTokenProgramFromMint Get token program from mint. **Function** ```typescript theme={"system"} async getTokenProgramFromMint( connection: Connection, mint: PublicKey ): Promise ``` **Parameters** ```typescript theme={"system"} interface GetTokenProgramFromMintParams { connection: Connection; mint: PublicKey; } ``` **Returns** A token program. **Example** ```typescript theme={"system"} const tokenProgram = await getTokenProgramFromMint(connection, inputMint); ``` **Notes** * This function is used to get token program from mint. *** ### getJupiterQuote Get Jupiter quote from Jupiter API. **Function** ```typescript theme={"system"} async getJupiterQuote( inputMint: PublicKey, outputMint: PublicKey, amount: BN, maxAccounts: number, slippageBps: number, dynamicSlippage: boolean = false, onlyDirectRoutes: boolean, restrictIntermediateTokens: boolean, apiUrl: string = "https://lite-api.jup.ag", apiKey?: string ): Promise ``` **Parameters** ```typescript theme={"system"} interface GetJupiterQuoteParams { inputMint: PublicKey; outputMint: PublicKey; amount: BN; maxAccounts: number; slippageBps: number; dynamicSlippage: boolean = false; onlyDirectRoutes: boolean; restrictIntermediateTokens: boolean; apiUrl: string = "https://lite-api.jup.ag"; apiKey?: string; } ``` **Returns** A Jupiter quote response. **Example** ```typescript theme={"system"} const quoteResponse = await getJupiterQuote( new PublicKey("So11111111111111111111111111111111111111112"), new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), new BN(1000000000), 40, 50, true, true, true, "https://lite-api.jup.ag" ); ``` **Notes** * This function is used to get Jupiter quote from Jupiter API. * Any issues with the api you can check out [Jupiter's Quote API Documentation](https://dev.jup.ag/docs/swap-api/get-quote) *** ### getJupiterSwapInstruction Get Jupiter swap instruction from Jupiter API. **Function** ```typescript theme={"system"} async getJupiterSwapInstruction( userPublicKey: PublicKey, quoteResponse: JupiterQuoteResponse, apiUrl: string = "https://lite-api.jup.ag", apiKey?: string ): Promise ``` **Parameters** ```typescript theme={"system"} interface GetJupiterSwapInstructionParams { inputMint: PublicKey; quoteResponse: JupiterQuoteResponse; apiUrl: string = "https://lite-api.jup.ag"; apiKey?: string; } ``` **Returns** A Jupiter swap instruction response. **Example** ```typescript theme={"system"} const quoteResponse = await getJupiterQuote( new PublicKey("So11111111111111111111111111111111111111112"), new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"), new BN(1000000000), 40, 50, true, true, true, "https://lite-api.jup.ag" ); const swapInstructionResponse = await getJupiterSwapInstruction( wallet.publicKey, quoteResponse apiUrl: "https://lite-api.jup.ag", ); ``` **Notes** * This function is used to get Jupiter swap instruction from Jupiter API. * Any issues with the api you can check out [Jupiter's Swap Instruction API Documentation](https://dev.jup.ag/docs/swap-api/build-swap-transaction#build-your-own-transaction-with-instructions) # Overview Source: https://docs.meteora.ag/developer-guide/home Everything you need to know to get started building on Meteora # Programs We write innovative programs that power the future of DeFi. With novel products like DLMM, DAMM v1 & v2, DBC and more, we are pushing the boundaries of what is possible on Solana. ## Active Programs Active = will have new developments and still actively maintained
Program Program ID Open Source
DLMM LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo
DAMM v2 cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
DBC dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN
Presale Vault \[Beta] presSVxnf9UU8jMxhgSMqaRwNiT36qeBdNeTRKjTdbj
Alpha Vault vaU6kP7iNEGkbmPkLmZfGwiGxd4Mob24QQCie5R9kd2
Dynamic Fee Sharing dfsdo2UqvwfN8DuUVrMRNfQe11VaiNoKcMqLHVvDPzh
Zap zapvX9M3uf5pvy4wRPAbQgdQsM1xmuiFnkfHKPvwMiz
## Legacy Programs Legacy = will not have new developments but still maintained
Program Program ID Open Source
DAMM v1 Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB
Dynamic Vault 24Uqj9JCLxUeoC3hGfh5W3s9FM9uCHDS2SG3LYwBpyTi
Stake2Earn FEESngU3neckdwib9X3KWqdL7Mjmqk9XNp3uh5JbP4KP
Farm FarmuwXPWXvefWUeqFAa5w6rifLkq5X6E8bimYvrhCB1
Mercurial Stable Swap MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky
# Devnet Our programs are deployed on devnet as well at [https://devnet.meteora.ag](https://devnet.meteora.ag). # Quick Launch Quick Launch abstracts the need for understanding Meteora integration complexities by providing an all-in-one interface that any developer can use to create, enter commands and deploy liquidity pools on Solana. Configure and launch a concentrated liquidity DLMM pool with or without Alpha Vault on Meteora in just a few quick and easy steps. Configure and launch a balanced or one-sided DAMM v2 pool with or without Alpha Vault on Meteora in just a few quick and easy steps. Configure and launch a freshly minted DAMM v1 pool with or without Alpha Vault on Meteora in just a few quick and easy steps. Configure and launch an entirely new dynamic bonding curve pool on Meteora in just a few quick and easy steps. # Invent with Metsumi [Meteora Invent](/developer-guide/invent/actions) is a playground for developers to quickly test and experiment with Meteora's programs. Metsumi is your personal launch assistant engineered to help you launch anything and do any action in just a few configurations and CLI commands. # Guides DLMM (Dynamic Liquidity Market Maker) implements a bin-based liquidity distribution model with algorithmic fee adjustment mechanisms based on market volatility metrics. Liquidity providers can deploy capital across discrete price bins with configurable spreads, enabling concentrated liquidity positioning with real-time fee optimization through volatility-sensitive pricing algorithms. DAMM v2 (Dynamic Automatic Market Maker v2) implements a constant-product invariant (x\*y=k) with enhanced features including SPL/Token-2022 compatibility, optional concentrated liquidity ranges, position NFTs, algorithmic onchain fee scheduling, programmable fee distribution mechanisms, and native yield farming integration. DAMM v1 (Dynamic Automatic Market Maker v1) utilizes a constant-product formula with infinite price range support (0 \< P \< ∞) and integrated yield aggregation through external lending protocol interfaces. The architecture enables composite yield generation via swap fee accrual and external DeFi protocol interaction, with automated capital efficiency optimization. Dynamic Bonding Curve (DBC) implements customizable mathematical pricing functions with configurable curve parameters for token launch mechanisms. The protocol supports arbitrary curve geometries with programmable price discovery algorithms, featuring virtual AMM states that migrate to dynamic AMM pools upon reaching predetermined liquidity thresholds through automated graduation logic. Presale Vault allows users to contribute using any SPL token and later claim their allocated presale tokens once the presale concludes. Presale vault creators can choose to create a presale vault with a fixed price, FCFS or Prorata mode, and a whitelist of addresses. Creators can also classify different tiers of participants with different token allocations, minimum and maximum deposit amounts, and deposit fees. Dynamic Vaults implement algorithmic yield optimization through multi-protocol asset allocation strategies, utilizing the Hermes yield aggregation engine for automated capital deployment across lending markets. The system employs mathematical optimization algorithms to maximize risk-adjusted returns for DAMM v1 and memecoin pool liquidity providers through dynamic rebalancing mechanisms. Alpha Vault implements a complementary anti-bot mechanism for token launches, providing early access for genuine supporters to deposit and purchase tokens before public trading begins. The system features configurable parameters including deposit caps, lock-up periods, and vesting schedules, with support for both pro-rata and FCFS distribution modes across DLMM, DAMM v1, and DAMM v2 launch pools. Stake2Earn is a mechanism where top memecoin stakers compete to earn fee rewards from permanently-locked liquidity in the memecoin pool, transforming memecoins from a race to dump to a race to stake. Dynamic Fee Sharing is a helper program that allows for the creation of fee vaults where collected fees can be automatically distributed among multiple recipients based on predetermined share allocations. Zap is a wrapper program that provides utility functions that allow users to zap in/out from any AMMs or Jupiter. For example, a user can claim both token fee rewards and immediately swap any of the token through DAMM v2, DLMM or Jupiter to receive the other token. # Actions Source: https://docs.meteora.ag/developer-guide/invent/actions Do any onchain actions on Meteora's programs with Meteora Invent Launch anything and do any onchain action on Meteora in just a few configurations and commands. Metsumi, your personal launch assistant is engineered to help you to test fast and launch fast, accelerating your development process by 100x. # Prerequisites * Node.js >= 18.0.0 * pnpm >= 10.0.0 *If you don't have pnpm installed, you can install it by running the following command.* ```bash Terminal theme={"system"} npm install -g pnpm ``` # Steps Meteora Invent is a toolkit consisting of everything you need to invent innovative token launches on Meteora. Run the following command in your terminal to get started. ```bash Terminal theme={"system"} git clone https://github.com/MeteoraAg/meteora-invent.git ``` Once you've cloned the repository, you'll have a new project directory with a meteora-invent folder. Run the following to install pnpm and the project dependencies. ```bash Terminal theme={"system"} cd meteora-invent pnpm install ``` Copy the `.env.example` file to `.env` and configure the environment variables. ```bash Terminal theme={"system"} cp studio/.env.example studio/.env ``` Configure the following variables: * `PRIVATE_KEY` - Your private key for the wallet you will be using to deploy the pool. You can also run the studio scripts on localnet - [http://localhost:8899](http://localhost:8899) with the following command ```bash Terminal theme={"system"} pnpm studio start-test-validator ``` This will start a local validator on your machine which will be hosted on `http://localhost:8899`. Generate a keypair from your private key: ```bash Terminal theme={"system"} # For devnet (airdrops 5 SOL) pnpm studio generate-keypair --network devnet # For localnet (airdrops 5 SOL) # Ensure that you have already started the local validator with pnpm start-test-validator pnpm studio generate-keypair --network localnet ``` This will generate a `keypair.json` file in the `studio` directory which will be used for all actions. Configure the config files in the `studio/config` directory. * Configure [DLMM](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/config/dlmm_config.jsonc) * Configure [DAMM v2](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/config/damm_v2_config.jsonc) * Configure [DAMM v1](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/config/damm_v1_config.jsonc) * Configure [DBC](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/config/dbc_config.jsonc) * Configure [Alpha Vault](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/config/alpha_vault_config.jsonc) After configuring the settings in the JSON files, you can proceed to choose the action you want to perform with Metsumi. # Actions ## DLMM Launch a DLMM customizable launch pool Seed Liquidity with your preferred curve Seed Liquidity in a single bin Set your DLMM Pool Status ## DAMM v2 Launch a DAMM v2 balanced pool Launch a DAMM v2 one-sided pool Split an existing LP Position on DAMM v2 pool Claim an existing DAMM v2 pool position fee Add liquidity to an existing DAMM v2 pool position Remove liquidity from an existing DAMM v2 pool position (includes refresh vesting and closing position) Close an existing DAMM v2 pool position ## DAMM v1 Launch a DAMM v1 constant product launch pool Lock liquidity for a DAMM v1 pool Create a Stake2Earn Farm for a DAMM v1 pool Lock liquidity for a Stake2Earn Farm pool ## DBC Launch a Dynamic Bonding Curve token pool Create a Dynamic Bonding Curve config containing the settings for pre-graduation and post-graduation pools Claim partner and/or creator trading fees for a DBC pool Migrate your DBC pool to a DAMM v1 pool Migrate your DBC pool to a DAMM v2 pool Swap (Buy/Sell) tokens on a DBC pool ## Alpha Vault Create an Alpha Vault with an already existing DAMM v1 or DAMM v2 or DLMM pool ## Presale Vault Create a Fixed Price or FCFS or Prorata Presale Vault # Fun Launch Source: https://docs.meteora.ag/developer-guide/invent/scaffolds/fun-launch Build a Launchpad platform for launching tokens with Meteora's Dynamic Bonding Curve Program in just a few steps In this guide, Metsumi will walk you through the steps to create a launchpad platform for launching tokens with Meteora's Dynamic Bonding Curve Program. # Features Built-in integration for Meteora's DBC program to create token pools with your DBC config key. You can configure your DBC config key on [launch.meteora.ag](https://launch.meteora.ag) and get started within minutes. Productin-grade search functionalities and real-time data from websocket APIs. Provide up-to-date information including token price, volume and holder count on your launchpad platform without worrying about the nitty-gritty details of indexing data. Ready-to-use trading interface with all the features you need for users to trade your tokens without leaving the platform. Comprises of with Trading View's charts and open source Jupiter APIs that includes volume analysis and trading marks. # Tech Stack * Next.js * TypeScript * Tailwind CSS * Solana Web3.js * Dynamic Bonding Curve SDK * Cloudflare R2 for storage # Prerequisites * Node.js >= 18.0.0 * pnpm >= 10.0.0 ## Setup Meteora Invent is a toolkit consisting of everything you need to invent innovative token launches on Meteora. Run the following command in your terminal to get started. ```bash Terminal theme={"system"} git clone https://github.com/MeteoraAg/meteora-invent.git ``` Once you've cloned the repository, you'll have a new project directory with a meteora-invent folder. Run the following to install pnpm and the project dependencies. ```bash Terminal theme={"system"} cd meteora-invent pnpm install ``` Copy the `.env.example` file to `.env` and configure the environment variables. ```bash theme={"system"} cp scaffolds/fun-launch/.env.example scaffolds/fun-launch/.env ``` ```env theme={"system"} # Cloudflare R2 Storage R2_ACCESS_KEY_ID=your_r2_access_key_id R2_SECRET_ACCESS_KEY=your_r2_secret_access_key R2_ACCOUNT_ID=your_r2_account_id R2_BUCKET=your_r2_bucket_name # Solana RPC URL RPC_URL=your_rpc_url # Pool Configuration POOL_CONFIG_KEY=your_pool_config_key ``` **Getting R2 Credentials** 1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com) 2. Navigate to R2 3. Create a new bucket or select an existing one 4. Go to "Manage R2 API Tokens" 5. Create a new API token with the following permissions: * Account R2 Storage: Edit * Bucket: Your bucket name 6. Copy the Access Key ID and Secret Access Key 7. Your Account ID can be found in the Cloudflare dashboard URL or in the Account Home page **Getting RPC URL** You can get your RPC URL from any 3rd party provider like [Triton](https://triton.one/) or [Helius](https://www.helius.dev). **Getting Pool Config Key** You can get your pool config key from [Meteora Launch](https://launch.meteora.ag) or execute an action with Metsumi to create a DBC config in [Meteora Invent](/developer-guide/invent/actions#dbc). ```bash theme={"system"} pnpm --filter @meteora-invent/scaffold/fun-launch dev ``` ```bash theme={"system"} pnpm --filter @meteora-invent/scaffold/fun-launch build ``` # DAMM v1 Launch Pool Source: https://docs.meteora.ag/developer-guide/quick-launch/damm-v1-launch-pool Configure and Launch a DAMM v1 Pool on Meteora using nothing but a configuration file and a few CLI commands In this guide, Metsumi will walk you through the steps to create a DAMM v1 launch pool on Meteora. Whether you’re a seasoned developer or just starting out, this guide has got you covered to deploy liquidity and launch your project on Meteora. # What You'll Achieve By the end of this quicklaunch, you’ll have built a liquidity pool on Meteora by: * Configuring your liquidity pool settings * Interacting with our DAMM v1 program * See your liquidity pool in action on Meteora **Why Meteora?** Meteora is a hyper optimized liquidity layer that ensures that your project's provided liquidity is secure, sustainable and composable for anyone to trade on. By following this guide, you'll be able to launch a balanced constant product liquidity pool with auto yield accuaral on Meteora in just a few quick and easy steps. # Prerequisites * Node.js >= 18.0.0 * pnpm >= 10.0.0 *If you don't have pnpm installed, you can install it by running the following command.* ```bash Terminal theme={"system"} npm install -g pnpm ``` # Steps Meteora Invent is a toolkit consisting of everything you need to invent innovative token launches on Meteora. Run the following command in your terminal to get started. ```bash Terminal theme={"system"} git clone https://github.com/MeteoraAg/meteora-invent.git ``` Once you've cloned the repository, you'll have a new project directory with a meteora-invent folder. Run the following to install pnpm and the project dependencies. ```bash Terminal theme={"system"} cd meteora-invent pnpm install ``` In Meteora Invent we provide an optional command for you to run a local validator to test your pool before deploying it to devnet or mainnet. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} pnpm studio start-test-validator ``` This will start a local validator on your machine which will be hosted on `http://localhost:8899`.

We provide an easy way to setup environment variables when getting started. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} cp studio/.env.example studio/.env ``` This will copy the example environment variables file to your `.env` file. Configure the following variables: * `PRIVATE_KEY` - Your private key for the wallet you will be using to deploy the pool. Therafter, you will need to run this command to generate a keypair from your wallet private key. ```bash Terminal theme={"system"} pnpm studio generate-keypair # For devnet (airdrops 5 SOL) pnpm studio generate-keypair --network devnet --airdrop # For localnet (airdrops 5 SOL) # Ensure that you have already started the local validator with pnpm start-test-validator pnpm studio generate-keypair --network localnet --airdrop ``` This will generate a `keypair.json` file in the `studio` directory which will be used for all actions in this guide.

Navigate to the `studio/config/damm_v1_config.jsonc` file and configure your DAMM v1 pool settings.

Your can configure everything DAMM v1 pool related in this file. The comments in the file are to help you understand the different settings you can configure. Please ensure that you read through the comments while configuring your pool. ```jsonc damm_v1_config.jsonc theme={"system"} { /* rpcUrl is required. You can switch between mainnet, devnet and localnet or use your own RPC URL. */ "rpcUrl": "https://api.devnet.solana.com", // mainnet: https://api.mainnet-beta.solana.com | devnet: https://api.devnet.solana.com | localnet: http://localhost:8899 /* dryRun is required. If true, transactions will be simulated and not executed. If false, transactions will be executed. */ "dryRun": false, /* keypairFilePath is required and will be the payer + signer for all transactions */ "keypairFilePath": "./keypair.json", /* computeUnitPriceMicroLamports is required and can be adjusted to fit your needs */ "computeUnitPriceMicroLamports": 100000, /* quoteMint is required for the following actions: * 1. damm-v1-create-pool * 2. damm-v1-lock-liquidity * SOL: So11111111111111111111111111111111111111112 | USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | any other token address */ "quoteMint": "So11111111111111111111111111111111111111112", /* If you have a baseMint already created, you can specify it in the cli command via --baseMint flag. If you don't have a baseMint, you can create a new one using createBaseToken. * Either use --baseMint flag or createBaseToken, but not both. */ "createBaseToken": { "supply": 1000000000, // total amount of base token to be minted "decimals": 6, // decimals of the base token // "tokenMintKeypairFilePath": "./mint-keypair.json", // path to token mint keypair if you have a specific keypair for the token mint. If not provided, a new keypair will be generated. "name": "Test Token", // token name "symbol": "TT", // token symbol "authorities": { "mint": "YOUR_MINT_AUTHORITY_ADDRESS", // token mint authority address. "freeze": "YOUR_FREEZE_AUTHORITY_ADDRESS", // token freeze authority address. "update": "YOUR_UPDATE_AUTHORITY_ADDRESS" // token update authority address. }, /* Optional Metaplex Token Metadata Properties * Read more about the properties here: https://developers.metaplex.com/token-metadata */ "sellerFeeBasisPoints": 0, // Royalty fee in basis points (0-10000) "creators": null, // Array of creator objects of the token (optional) "collection": null, // Collection info (optional) "uses": null, // Usage restrictions (optional) "metadata": { // "uri": "https://gateway.irys.xyz/123456789", // if you already have a metadata URI created, you can specify it here /* Only use the following parameters for createBaseToken if you don't have an existing metadata uri * This will create an image uri and a new metadata uri and upload everything to Irys */ "image": "./data/image/test-token.jpg", // this can be a URL of the image address (e.g. https://example.com/token-image.png) or the image file path (e.g. ./data/image/test-token.jpg) "description": "YOUR_TOKEN_DESCRIPTION", // token description "website": "https://example.com", // project website "twitter": "https://x.com/yourproject", // twitter URL "telegram": "https://t.me/yourproject" // telegram URL } }, /* dammV1Config is only used in the following actions: * 1. damm-v1-create-pool */ "dammV1Config": { "baseAmount": 100, // base token amount "quoteAmount": 0.001, // quote token amount "tradeFeeNumerator": 2500, // pool fee in bps "activationType": 1, // 0 - Slot | 1 - Timestamp "activationPoint": null, // Activation time of the pool depending on activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "hasAlphaVault": false // If true, the alpha vault will be created after the pool is created }, /* dammV1LockLiquidity is only used in the following actions: * 1. damm-v1-lock-liquidity * 2. damm-v1-lock-liquidity-stake2earn */ "dammV1LockLiquidity": { "allocations": [ { "percentage": 80, // percentage of the LP tokens that will be allocated to address 1 "address": "YOUR_ADDRESS_1" // address 1 }, { "percentage": 20, // percentage of the LP tokens that will be allocated to address 2 "address": "YOUR_ADDRESS_2" // address 2 } ] }, /* stake2EarnFarm is only used in the following actions: * 1. damm-v1-create-stake2earn-farm */ "stake2EarnFarm": { "topListLength": 100, // Maximum number of top stakers eligible for fee rewards (minimum 50, maximum 1000) "unstakeLockDurationSecs": 25200, // 7-hour cooldown period before unstaked tokens can be withdrawn "secondsToFullUnlock": 86400, // 24-hour period for locked fees to fully drip/release to stakers "startFeeDistributeTimestamp": 1753441790 // Start date for fee distribution (Jan 24, 2025 17:49:50 UTC) }, /* alphaVault is only used in the following actions: * 1. damm-v1-create-pool * There are 2 types of alpha vault: First Come First Serve (FCFS) and Prorata. */ "alphaVault": { "poolType": "dynamic", // DLMM = dlmm | DAMM v1 = dynamic | DAMM v2 = damm2 "alphaVaultType": "fcfs", // FCFS = fcfs | Prorata = prorata /* Only use the following parameters for alphaVaultType: fcfs * 1. maxDepositCap * 2. individualDepositingCap */ "maxDepositCap": 10000, // Maximum total amount (in quote token) that can be deposited across all users in the vault "individualDepositingCap": 1, // Maximum amount (in quote token) that each individual user can deposit /* Only use the following parameters for alphaVaultType: prorata * 1. maxBuyingCap */ // "maxBuyingCap": 10000, // Maximum total amount (in quote token) that can be bought across all users in the vault "depositingPoint": 1733626299, // When users can start depositing depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "startVestingPoint": 1746808201, // When token vesting begins and users can start claiming their vested tokens depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "endVestingPoint": 1746808201, // When token vesting ends and all tokens become fully claimable depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "escrowFee": 0, // Fee amount (in quote token) charged when creating a stake escrow account "whitelistMode": "permissionless" // Whitelist mode: permissionless | permissioned_with_merkle_proof | permissioned_with_authority /* Optional Configuration: whitelistFilePath * Only use when whitelistMode is permissioned_with_merkle_proof or permissioned_with_authority */ // "whitelistFilepath": "./data/whitelist_wallet.csv", // Optional path to CSV file containing whitelisted wallet addresses and their deposit caps (format: wallet,deposit_cap) /* Optional Configuration: merkleProofBaseUrl, chunkSize, kvProofFilepath, cloudflareKvProofUpload * Only use when whitelistMode is permissioned_with_merkle_proof */ // "merkleProofBaseUrl": "https://example.workers.dev/", // Base URL endpoint where merkle proofs are stored and can be retrieved for whitelisted wallet verification // "chunkSize": 1000, // Optional batch size for processing large whitelist files or merkle tree operations to avoid memory/performance issues // "kvProofFilepath": "./data/kv_proofs", // Optional path to key-value file storing pre-computed merkle proofs for whitelisted addresses // "cloudflareKvProofUpload": { // "kvNamespaceId": "YOUR_KV_NAMESPACE_ID", // "accountId": "YOUR_ACCOUNT_ID", // "apiKey": "YOUR_API_KEY" // } } } ``` The toolkit contains logic to make it easier for you to create the DAMM v1 pool such as: * Minting a new `baseMint` token or parsing in an existing `baseMint` token. * Launching the DAMM v1 pool immediately or at a certain `activationPoint` (in slots or timestamp depending on the `activationType`). * Optional creation of an Alpha Vault with your DAMM v1 launch pool.
After configuring your DAMM v1 pool settings in `damm_v1_config.jsonc`, you can now create your pool by running the following command. These commands will create your pool and

*If you don't have a base mint, you can configure `createBaseToken` in the config file and run the following command.* ```bash theme={"system"} pnpm studio damm-v1-create-pool ``` *If you already have a base mint created, you can provide it via the CLI with a `--baseMint` flag and run the following command.* ```bash theme={"system"} pnpm studio damm-v1-create-pool --baseMint ``` This will create your pool with liquidity deposited from your `keypair.json` and print the pool address and other relevant information to the console.

Voilà! You've successfully created your DAMM v1 pool on Meteora. You can now see your pool in action on Meteora either on Meteora's [mainnet](https://app.meteora.ag) or [devnet](https://devnet.meteora.ag) app. # DAMM v2 Launch Pool Source: https://docs.meteora.ag/developer-guide/quick-launch/damm-v2-launch-pool Configure and Launch a DAMM v2 Pool on Meteora using nothing but a configuration file and a few CLI commands In this guide, Metsumi will walk you through the steps to create a DAMM v2 launch pool on Meteora. Whether you’re a seasoned developer or just starting out, this guide has got you covered to deploy liquidity and launch your project on Meteora. # What You'll Achieve By the end of this quicklaunch, you’ll have built a liquidity pool on Meteora by: * Configuring your liquidity pool settings * Interacting with our DAMM v2 program * See your liquidity pool in action on Meteora **Why Meteora?** Meteora is a hyper optimized liquidity layer that ensures that your project's provided liquidity is secure, sustainable and composable for anyone to trade on. By following this guide, you'll be able to launch a balanced / concentrated / one-sided liquidity pool with dynamic fees on Meteora in just a few quick and easy steps. # Prerequisites * Node.js >= 18.0.0 * pnpm >= 10.0.0 *If you don't have pnpm installed, you can install it by running the following command.* ```bash Terminal theme={"system"} npm install -g pnpm ``` # Steps Meteora Invent is a toolkit consisting of everything you need to invent innovative token launches on Meteora. Run the following command in your terminal to get started. ```bash Terminal theme={"system"} git clone https://github.com/MeteoraAg/meteora-invent.git ``` Once you've cloned the repository, you'll have a new project directory with a meteora-invent folder. Run the following to install pnpm and the project dependencies. ```bash Terminal theme={"system"} cd meteora-invent pnpm install ``` In Meteora Invent we provide an optional command for you to run a local validator to test your pool before deploying it to devnet or mainnet. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} pnpm studio start-test-validator ``` This will start a local validator on your machine which will be hosted on `http://localhost:8899`.

We provide an easy way to setup environment variables when getting started. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} cp studio/.env.example studio/.env ``` This will copy the example environment variables file to your `.env` file. Configure the following variables: * `PRIVATE_KEY` - Your private key for the wallet you will be using to deploy the pool. Therafter, you will need to run this command to generate a keypair from your wallet private key. ```bash Terminal theme={"system"} pnpm studio generate-keypair # For devnet (airdrops 5 SOL) pnpm studio generate-keypair --network devnet --airdrop # For localnet (airdrops 5 SOL) # Ensure that you have already started the local validator with pnpm start-test-validator pnpm studio generate-keypair --network localnet --airdrop ``` This will generate a `keypair.json` file in the `studio` directory which will be used for all actions in this guide.

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

Your can configure everything DAMM v2 pool related in this file. The comments in the file are to help you understand the different settings you can configure. Please ensure that you read through the comments while configuring your pool. ```jsonc damm_v2_config.jsonc theme={"system"} { /* rpcUrl is required. You can switch between mainnet, devnet and localnet or use your own RPC URL. */ "rpcUrl": "https://api.devnet.solana.com", // mainnet: https://api.mainnet-beta.solana.com | devnet: https://api.devnet.solana.com | localnet: http://localhost:8899 /* dryRun is required. If true, transactions will be simulated and not executed. If false, transactions will be executed. */ "dryRun": false, /* keypairFilePath is required and will be the payer + signer for all transactions */ "keypairFilePath": "./keypair.json", /* computeUnitPriceMicroLamports is required and can be adjusted to fit your needs */ "computeUnitPriceMicroLamports": 100000, /* quoteMint is required for the following actions: * 1. damm-v2-create-balanced-pool * 2. damm-v2-create-one-sided-pool * SOL: So11111111111111111111111111111111111111112 | USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | any other token address */ "quoteMint": "So11111111111111111111111111111111111111112", /* If you have a baseMint already created, you can specify it in the cli command via --baseMint flag. If you don't have a baseMint, you can create a new one using createBaseToken. * Either use --baseMint flag or createBaseToken, but not both. */ "createBaseToken": { "supply": 1000000000, // total amount of base token to be minted "decimals": 6, // decimals of the base token // "tokenMintKeypairFilePath": "./mint-keypair.json", // path to token mint keypair if you have a specific keypair for the token mint. If not provided, a new keypair will be generated. "name": "YOUR_TOKEN_NAME", // token name "symbol": "YOUR_TOKEN_SYMBOL", // token symbol "authorities": { "mint": "YOUR_MINT_AUTHORITY_ADDRESS", // token mint authority address. "freeze": "YOUR_FREEZE_AUTHORITY_ADDRESS", // token freeze authority address. "update": "YOUR_UPDATE_AUTHORITY_ADDRESS" // token update authority address. }, /* Optional Metaplex Token Metadata Properties * Read more about the properties here: https://developers.metaplex.com/token-metadata */ "sellerFeeBasisPoints": 0, // Royalty fee in basis points (0-10000) "creators": null, // Array of creator objects of the token (optional) "collection": null, // Collection info (optional) "uses": null, // Usage restrictions (optional) "metadata": { // "uri": "https://gateway.irys.xyz/123456789", // if you already have a metadata URI created, you can specify it here /* Only use the following parameters for createBaseToken if you don't have an existing metadata uri * This will create an image uri and a new metadata uri and upload everything to Irys */ "image": "./data/image/test-token.jpg", // this can be a URL of the image address (e.g. https://example.com/token-image.png) or the image file path (e.g. ./data/image/test-token.jpg) "description": "YOUR_TOKEN_DESCRIPTION", // token description "website": "https://example.com", // project website "twitter": "https://x.com/yourproject", // twitter URL "telegram": "https://t.me/yourproject" // telegram URL } }, /* dammV2Config is only used in the following actions: * 1. damm-v2-create-balanced-pool * 2. damm-v2-create-one-sided-pool */ "dammV2Config": { "creator": "YOUR_CREATOR_ADDRESS", // creator address "baseAmount": 100000000, // base token amount "quoteAmount": null, // quote token amount "initPrice": 0.001, // initial price (in terms of quote/base price) 1 SOL / 1000000000 = initialPrice "maxPrice": null, // max price (in terms of quote/base price) "poolFees": { "maxBaseFeeBps": 120, // max base fee (in basis points) "minBaseFeeBps": 120, // min base fee (in basis points) "numberOfPeriod": 0, // number of period "totalDuration": 0, // total duration (If activationType is 0 (slots), totalDuration = duration / 0.4 | If activationType is 1 (timestamp), totalDuration = duration) "feeSchedulerMode": 0, // 0 - Fee Scheduler: Linear | 1 - Fee Scheduler: Exponential "useDynamicFee": true // if useDynamicFee is true, the default dynamic fee configuration will be 20% of minBaseFeeBps /* Optional Configuration. * Only used if you want to configure dynamic fee and not use the default dynamic fee configuration * Formula: dynamicFee = (variableFeeControl * (volatilityAccumulator * binStep)^2 + 99_999_999_999) / 100_000_000_000 */ // "dynamicFeeConfig": { // "filterPeriod": 10, // Time period (in slots/seconds) over which volatility is measured and smoothed // "decayPeriod": 120, // Time period (in slots/seconds) over which volatility accumulator decays back to zero // "reductionFactor": 5000, // Volatility decay rate in basis points (5000 = 50% reduction per decay period) // "variableFeeControl": 14460000, // Scaling factor that controls how much volatility affects dynamic fees // "maxVolatilityAccumulator": 239 // Maximum allowed volatility accumulator value (caps dynamic fee calculation) // } }, "collectFeeMode": 1, // 0 - Both Token | 1 - Token B Only "activationType": 1, // 0 - Slot | 1 - Timestamp "activationPoint": null, // Activation time of the pool depending on activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "hasAlphaVault": false // If true, the alpha vault will be created after the pool is created }, /* addLiquidity is only used in the following actions: * 1. damm-v2-add-liquidity */ "addLiquidity": { "amountIn": 5, // this is the amount of token A or token B that will be added to the pool (in terms of the token amount) "isTokenA": false // if your amountIn is in terms of token A, set isTokenA to true, if your amountIn is in terms of token B, set isTokenA to false }, /* splitPosition is only used in the following actions: * 1. damm-v2-split-position */ "splitPosition": { "newPositionOwner": "YOUR_NEW_POSITION_OWNER_ADDRESS", // this is the address that will receive the new DAMM v2 NFT position "unlockedLiquidityPercentage": 50, // this is the percentage of unlocked liquidity that will be split and transferred to the newPositionOwner's position "permanentLockedLiquidityPercentage": 50, // this is the percentage of permanent locked liquidity that will be split and transferred to the newPositionOwner's position "feeAPercentage": 50, // this is the percentage of unclaimed fee that will be transferred to the newPositionOwner's position "feeBPercentage": 50, // this is the percentage of unclaimed fee that will be transferred to the newPositionOwner's position "reward0Percentage": 50, // this is the percentage of unclaimed reward that will be transferred to the newPositionOwner's position "reward1Percentage": 50 // this is the percentage of unclaimed reward that will be transferred to the newPositionOwner's position }, /* alphaVault is only used in the following actions: * 1. damm-v2-create-balanced-pool * 2. damm-v2-create-one-sided-pool * There are 2 types of alpha vault: First Come First Serve (FCFS) and Prorata. */ "alphaVault": { "poolType": "damm2", // DLMM = dlmm | DAMM v1 = dynamic | DAMM v2 = damm2 "alphaVaultType": "fcfs", // FCFS = fcfs | Prorata = prorata /* Only use the following parameters for alphaVaultType: fcfs * 1. maxDepositCap * 2. individualDepositingCap */ "maxDepositCap": 10000, // Maximum total amount (in quote token) that can be deposited across all users in the vault "individualDepositingCap": 1, // Maximum amount (in quote token) that each individual user can deposit /* Only use the following parameters for alphaVaultType: prorata * 1. maxBuyingCap */ // "maxBuyingCap": 10000, // Maximum total amount (in quote token) that can be bought across all users in the vault "depositingPoint": 1733626299, // When users can start depositing depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "startVestingPoint": 1746808201, // When token vesting begins and users can start claiming their vested tokens depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "endVestingPoint": 1746808201, // When token vesting ends and all tokens become fully claimable depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "escrowFee": 0, // Fee amount (in quote token) charged when creating a stake escrow account "whitelistMode": "permissionless" // Whitelist mode: permissionless | permissioned_with_merkle_proof | permissioned_with_authority /* Optional Configuration: whitelistFilePath * Only use when whitelistMode is permissioned_with_merkle_proof or permissioned_with_authority */ // "whitelistFilepath": "./data/whitelist_wallet.csv", // Optional path to CSV file containing whitelisted wallet addresses and their deposit caps (format: wallet,deposit_cap) /* Optional Configuration: merkleProofBaseUrl, chunkSize, kvProofFilepath, cloudflareKvProofUpload * Only use when whitelistMode is permissioned_with_merkle_proof */ // "merkleProofBaseUrl": "https://example.workers.dev/", // Base URL endpoint where merkle proofs are stored and can be retrieved for whitelisted wallet verification // "chunkSize": 1000, // Optional batch size for processing large whitelist files or merkle tree operations to avoid memory/performance issues // "kvProofFilepath": "./data/kv_proofs", // Optional path to key-value file storing pre-computed merkle proofs for whitelisted addresses // "cloudflareKvProofUpload": { // "kvNamespaceId": "YOUR_KV_NAMESPACE_ID", // "accountId": "YOUR_ACCOUNT_ID", // "apiKey": "YOUR_API_KEY" // } } } ``` The toolkit contains logic to make it easier for you to create the DAMM v2 pool such as: * Minting a new `baseMint` token or parsing in an existing `baseMint` token. * Launching the DAMM v2 pool immediately or at a certain `activationPoint` (in slots or timestamp depending on the `activationType`). * Fully customizable pool fees (including fee scheduler and dynamic fee settings). * Optional creation of an Alpha Vault with your DAMM v2 launch pool.
After configuring your DAMM v2 pool settings in `damm_v2_config.jsonc`, you can now create your pool by running the following command. *If you don't have a base mint, you can configure `createBaseToken` in the config file and run the following command.* ```bash theme={"system"} pnpm studio damm-v2-create-balanced-pool ``` *If you already have a base mint, you can provide it via the CLI with a `--baseMint` flag and run the following command.* ```bash theme={"system"} pnpm studio damm-v2-create-balanced-pool --baseMint ``` Creating a balanced pool will require the `quoteAmount` to be set in the `damm_v2_config.jsonc` file. *If you don't have a base mint, you can configure `createBaseToken` in the config file and run the following command.* ```bash theme={"system"} pnpm studio damm-v2-create-one-sided-pool ``` *If you already have a base mint, you can provide it via the CLI with a `--baseMint` flag and run the following command.* ```bash theme={"system"} pnpm studio damm-v2-create-one-sided-pool --baseMint ``` This will create your pool with liqudity deposited from your `keypair.json` and print the pool address and other relevant information to the console.

Voilà! You've successfully created your DAMM v2 pool on Meteora. You can now see your pool in action on Meteora either on Meteora's [mainnet](https://app.meteora.ag) or [devnet](https://devnet.meteora.ag) app. # DBC Token Launch Pool Source: https://docs.meteora.ag/developer-guide/quick-launch/dbc-token-launch-pool Configure and Launch a DBC Token Pool on Meteora using nothing but a configuration file and a few CLI commands In this guide, Metsumi will walk you through the steps to create a DBC token launch pool on Meteora. Whether you’re a seasoned developer or just starting out, this guide has got you covered to deploy liquidity and launch your project on Meteora. # What You'll Achieve By the end of this quicklaunch, you’ll have built a liquidity pool on Meteora by: * Configuring your bonding curve pool and graduated DAMM v1/v2 pool settings * Interacting with our Dynamic Bonding Curve program * See your token tradeable across all trading terminals e.g. Jupiter Pro, Axiom, Photon etc. **Why Meteora?** Meteora is a hyper optimized liquidity layer that ensures that your project's provided liquidity is secure, sustainable and composable for anyone to trade on. By following this guide, you'll be able to launch a bonding curve config and a token pool using the bonding curve config on Meteora in just a few quick and easy steps. # Prerequisites * Node.js >= 18.0.0 * pnpm >= 10.0.0 *If you don't have pnpm installed, you can install it by running the following command.* ```bash Terminal theme={"system"} npm install -g pnpm ``` # Steps Meteora Invent is a toolkit consisting of everything you need to invent innovative token launches on Meteora. Run the following command in your terminal to get started. ```bash Terminal theme={"system"} git clone https://github.com/MeteoraAg/meteora-invent.git ``` Once you've cloned the repository, you'll have a new project directory with a meteora-invent folder. Run the following to install pnpm and the project dependencies. ```bash Terminal theme={"system"} cd meteora-invent pnpm install ``` In Meteora Invent we provide an optional command for you to run a local validator to test your pool before deploying it to devnet or mainnet. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} pnpm studio start-test-validator ``` This will start a local validator on your machine which will be hosted on `http://localhost:8899`.

We provide an easy way to setup environment variables when getting started. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} cp studio/.env.example studio/.env ``` This will copy the example environment variables file to your `.env` file. Configure the following variables: * `PRIVATE_KEY` - Your private key for the wallet you will be using to deploy the pool. Therafter, you will need to run this command to generate a keypair from your wallet private key. ```bash Terminal theme={"system"} pnpm studio generate-keypair # For devnet (airdrops 5 SOL) pnpm studio generate-keypair --network devnet --airdrop # For localnet (airdrops 5 SOL) # Ensure that you have already started the local validator with pnpm start-test-validator pnpm studio generate-keypair --network localnet --airdrop ``` This will generate a `keypair.json` file in the `studio` directory which will be used for all actions in this guide.

Navigate to the `studio/config/dbc_config.jsonc` file and configure your DBC token pool settings.

Your can configure everything DBC token pool related in this file. The comments in the file are to help you understand the different settings you can configure. Please ensure that you read through the comments while configuring your pool. ```jsonc dbc_config.jsonc theme={"system"} { /* rpcUrl is required. You can switch between mainnet, devnet and localnet or use your own RPC URL. */ "rpcUrl": "https://api.devnet.solana.com", // mainnet: https://api.mainnet-beta.solana.com | devnet: https://api.devnet.solana.com | localnet: http://localhost:8899 /* dryRun is required. If true, transactions will be simulated and not executed. If false, transactions will be executed. */ "dryRun": false, /* keypairFilePath is required and will be the payer + signer for all transactions */ "keypairFilePath": "./keypair.json", /* computeUnitPriceMicroLamports is required and can be adjusted to fit your needs */ "computeUnitPriceMicroLamports": 100000, /* quoteMint is required for the following actions: * 1. dbc-create-config * 2. dbc-create-pool (if there is no configKeyAddress) * SOL: So11111111111111111111111111111111111111112 | USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | any other token address */ "quoteMint": "So11111111111111111111111111111111111111112", /* dbcConfig is only used in the following actions: * 1. dbc-create-config * 2. dbc-create-pool (if there is no --config flag indicated in the command) */ "dbcConfig": { "buildCurveMode": 0, // 0 - buildCurve | 1 - buildCurveWithMarketCap | 2 - buildCurveWithTwoSegments | 3 - buildCurveWithLiquidityWeights | 4 - buildCurveWithMidPrice | 5 - buildCurveWithCustomSqrtPrices /* Only use the following parameters for buildCurveMode: 0 (buildCurve) * 1. percentageSupplyOnMigration * 2. migrationQuoteThreshold */ "percentageSupplyOnMigration": 20, // percentage of total token supply to be migrated "migrationQuoteThreshold": 10, // migration quote threshold needed to migrate the DBC token pool /* Only use the following parameters for buildCurveMode: 1 (buildCurveWithMarketCap) * 1. initialMarketCap * 2. migrationMarketCap */ // "initialMarketCap": 20, // the market cap of the DBC token pool when the pool is created specified in terms of quoteMint (not in lamports) // "migrationMarketCap": 600, // the market cap of the DBC token pool when the pool graduates specified in terms of quoteMint (not in lamports) /* Only use the following parameters for buildCurveMode: 2 (buildCurveWithTwoSegments) * 1. initialMarketCap * 2. migrationMarketCap * 3. percentageSupplyOnMigration */ // "initialMarketCap": 20, // the market cap of the DBC token pool when the pool is created specified in terms of quoteMint (not in lamports) // "migrationMarketCap": 600, // the market cap of the DBC token pool when the pool graduates specified in terms of quoteMint (not in lamports) // "percentageSupplyOnMigration": 20, // percentage of total token supply to be migrated /* Only use the following parameters for buildCurveMode: 3 (buildCurveWithLiquidityWeights) * 1. initialMarketCap * 2. migrationMarketCap * 3. liquidityWeights */ // "initialMarketCap": 20, // the market cap of the DBC token pool when the pool is created specified in terms of quoteMint (not in lamports) // "migrationMarketCap": 600, // the market cap of the DBC token pool when the pool graduates specified in terms of quoteMint (not in lamports) // "liquidityWeights": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], // a array of 16 liquidity weights for each liquidity segment in the curve /* Only use the following parameters for buildCurveMode: 4 (buildCurveWithMidPrice) * 1. initialMarketCap * 2. migrationMarketCap * 3. midPrice * 4. percentageSupplyOnMigration */ // "initialMarketCap": 20, // the market cap of the DBC token pool when the pool is created specified in terms of quoteMint (not in lamports) // "migrationMarketCap": 600, // the market cap of the DBC token pool when the pool graduates specified in terms of quoteMint (not in lamports) // "midPrice": 0.001, // the mid-point price of the curve in terms of quoteMint // "percentageSupplyOnMigration": 20, // percentage of total token supply to be migrated /* Only use the following parameters for buildCurveMode: 5 (buildCurveWithCustomSqrtPrices) * 1. sqrtPrices - array of custom sqrt prices (must be in ascending order, at least 2 elements) * 2. liquidityWeights - optional weights for each segment (length must be sqrtPrices.length - 1) */ // "sqrtPrices": [], // array of custom sqrt prices (ascending order). First = starting price (pMin), Last = migration price (pMax) // "liquidityWeights": [1, 2, 3], // optional: weights for each segment. If omitted, liquidity is distributed evenly /* Token Configuration */ "token": { "totalTokenSupply": 1000000000, // total token supply (not in lamports) "tokenBaseDecimal": 6, // token base decimal "tokenQuoteDecimal": 9, // token quote decimal "tokenType": 0, // 0 - SPL | 1 - Token 2022 "tokenUpdateAuthority": 1, // 0 - CreatorUpdateAuthority | 1 - Immutable | 2 - PartnerUpdateAuthority | 3 - CreatorUpdateAndMintAuthority | 4 - PartnerUpdateAndMintAuthority "leftover": 0 // leftover tokens in the bonding curve (claimable once pool migrates) }, /* Fee Configuration */ "fee": { "baseFeeParams": { "baseFeeMode": 0, // 0 - Fee Scheduler: Linear | 1 - Fee Scheduler: Exponential | 2 - Rate Limiter "feeSchedulerParam": { "startingFeeBps": 100, // starting fee (max 99% fee === 9900 bps) "endingFeeBps": 100, // ending fee (minimum 0.01% fee === 1 bps) "numberOfPeriod": 0, // number of period "totalDuration": 0 // total duration (If activationType is 0 (slots), totalDuration = duration / 0.4 | If activationType is 1 (timestamp), totalDuration = duration) } /* "baseFeeMode": 2, // 2 - Rate Limiter "rateLimiterParam": { "baseFeeBps": 200, // base fee (max 99% base fee === 9900 bps) "feeIncrementBps": 200, // fee increment (max fee increment = 9900 bps - baseFeeBps) "referenceAmount": 0, // reference amount (not in lamports) "maxLimiterDuration": 0 // if activationType is 0 (slots), maxLimiterDuration = duration / 0.4, if activationType is 1 (timestamp), maxLimiterDuration = duration) } */ }, "dynamicFeeEnabled": true, // If true, dynamic fee will add 20% of minimum base fee to the total fee. "collectFeeMode": 0, // 0 - Quote Token | 1 - Output Token "creatorTradingFeePercentage": 0, // Bonding curve trading fee sharing (0% to 100%) - 0% means all trading fees go to the partner "poolCreationFee": 0, // Pool creation fee in SOL (0 or between 0.001 SOL to 100 SOL). Token creators pay this fee when creating a pool. Partner can claim this fee later. "enableFirstSwapWithMinFee": false // If true, allows the pool creator to do their first swap (buy) without anti-sniper fees. Useful for single-transaction pool creation + first buy. }, /* Migration Configuration */ "migration": { "migrationOption": 1, // 0 - Migrate to DAMM v1 | 1 - Migrate to DAMM v2 "migrationFeeOption": 3, // 0 - LP Fee 0.25% | 1 - LP Fee 0.3% | 2 - LP Fee 1% | 3 - LP Fee 2% | 4 - LP Fee 4% | 5 - LP Fee 6% | 6 - Customizable "migrationFee": { "feePercentage": 0, // Percentage of fee taken from migration quote threshold once pool migrates (0% to 50%) "creatorFeePercentage": 0 // Percentage of the migrationFee.feePercentage claimable by creator (0% to 100%) } /* Migrated Pool Fee (DAMM v2 only) * Configure migratedPoolFee when using migrationFeeOption: 6 (Customizable) or when configuring marketCapFeeSchedulerParams. * Note: When marketCapFeeSchedulerParams is configured, the SDK will automatically set migrationFeeOption to Customizable (6). */ // "migratedPoolFee": { // "collectFeeMode": 0, // 0 - Quote Token | 1 - Output Token // "dynamicFee": 0, // 0: Disabled, 1: Enabled // "poolFeeBps": 100, // The pool fee in basis points. Minimum 10, Maximum 1000 bps. Required when marketCapFeeSchedulerParams is configured. // "baseFeeMode": 3, // 3 - FeeMarketCapSchedulerLinear | 4 - FeeMarketCapSchedulerExponential (only for DAMM v2) // "marketCapFeeSchedulerParams": { // "endingBaseFeeBps": 50, // The ending (minimum) base fee in basis points // "numberOfPeriod": 100, // The total number of fee reduction periods // "sqrtPriceStepBps": 100, // The sqrt price increase (in bps) required to advance one period // "schedulerExpirationDuration": 86400 // The maximum duration (seconds) after which the scheduler expires and defaults to minimum fee // } // } }, /* LP Distribution Configuration (must total 100%) * IMPORTANT: At least 10% of LP must remain locked/vesting for at least 1 day post-migration. * * For DAMM v1: partnerPermanentLockedLiquidityPercentage + creatorPermanentLockedLiquidityPercentage >= 10% * * For DAMM v2: 3 options to achieve 10% locked/vesting: * Option 1 (Permanent Only): Set creator + partner permanent locked percentages >= 10% (LP locked forever) * Option 2 (Vesting Only): Use creator + partner vestingInfoParams with cliffDurationFromMigrationTime >= 86400 (1 day) * Option 3 (Combination): Mix permanent + vesting to reach 10% (5% permanent + 5% vesting >= 1 day) */ "liquidityDistribution": { "partnerLiquidityPercentage": 45, // Partner claimable LP (withdrawable LP once pool migrates) "creatorLiquidityPercentage": 45, // Creator claimable LP (withdrawable LP once pool migrates) "partnerPermanentLockedLiquidityPercentage": 5, // Partner permanently locked LP (permanently locked LP once pool migrates) "creatorPermanentLockedLiquidityPercentage": 5 // Creator permanently locked LP (permanently locked LP once pool migrates) // NOTE: Total liquidity percentages (partner + creator + partnerLocked + creatorLocked + partnerVested + creatorVested) must equal 100% // NOTE: Must have minimum 10% (1000 bps) of locked liquidity after 1 day (86400 seconds). This can be permanently locked or vested liquidity. /* LP Vesting (DAMM v2 only) * Optional vesting schedule for partner/creator LP tokens after migration. * Only applicable when migrationOption = 1 (DAMM v2). */ // "partnerLiquidityVestingInfoParams": { // "vestingPercentage": 50, // % of non-permanent LP to vest (0-100) // "bpsPerPeriod": 100, // BPS released per period (100 = 1%) // "numberOfPeriods": 100, // Total vesting periods // "cliffDurationFromMigrationTime": 86400, // Cliff delay in seconds (86400 = 1 day) // "totalDuration": 2592000 // Total vesting duration in seconds (30 days) // }, // "creatorLiquidityVestingInfoParams": { // "vestingPercentage": 50, // "bpsPerPeriod": 100, // "numberOfPeriods": 100, // "cliffDurationFromMigrationTime": 86400, // "totalDuration": 2592000 // } }, /* Locked Vesting Configuration */ "lockedVesting": { "totalLockedVestingAmount": 0, // total locked vesting amount (not in lamports) "numberOfVestingPeriod": 0, // number of vesting period "cliffUnlockAmount": 0, // cliff unlock amount (not in lamports) "totalVestingDuration": 0, // total vesting duration (in seconds) "cliffDurationFromMigrationTime": 0 // cliff duration from migration time (in seconds) }, "activationType": 1, // 0 - Slot | 1 - Timestamp "leftoverReceiver": "Dc85YcHkAWs62ndssWcGN5V4xYaQzPzgUDiRGtvnZas6", // leftover receiver address "feeClaimer": "Dc85YcHkAWs62ndssWcGN5V4xYaQzPzgUDiRGtvnZas6" // fee claimer address }, /* dbcPool is only used in the following actions: * 1. dbc-create-pool */ "dbcPool": { // "baseMintKeypairFilepath": "./mint-keypair.json", // optional base mint keypair file path "name": "YOUR_TOKEN_NAME", // token name "symbol": "YOUR_TOKEN_SYMBOL", // token symbol "metadata": { // "uri": "https://gateway.irys.xyz/123456789", // if you already have a metadata URI created, you can specify it here /* Only use the following parameters for createBaseToken if you don't have an existing metadata uri * This will create an image uri and a new metadata uri and upload everything to Irys */ "image": "./data/image/test-token.jpg", // this can be a URL of the image address (e.g. https://example.com/token-image.png) or the image file path (e.g. ./data/image/test-token.jpg) "description": "YOUR_TOKEN_DESCRIPTION", // token description "website": "https://example.com", // project website "twitter": "https://x.com/yourproject", // twitter URL "telegram": "https://t.me/yourproject" // telegram URL } }, /* dbcSwap is only used in the following actions: * 1. dbc-swap (Buy or Sell) */ "dbcSwap": { "amountIn": 1.03, // the amount of quoteMint or baseMint to be swapped "slippageBps": 100, // slippage in bps "swapBaseForQuote": false, // if true, swap base for quote | if false, swap quote for base "referralTokenAccount": null // optional referral token account address } } ``` Creating a DBC token pool will automatically mint the token within the same `initialize_virtual_pool`instruction, so if you want to provide a vanity mint address, you will need to specify the `baseMintKeypairFilepath` in the `dbc_config.jsonc` file. The toolkit contains logic to make it easier for you to create the DBC token pool such as: * Configuring your bonding curve shape based on your `buildCurveMode`. * Launching the DBC config and token pool using the config immediately. * Configuring your Anti-Sniping settings (such as Fee Scheduler or Rate Limiter) easily. * Setting up liquidity vesting schedules for DAMM v2 migrations. * Configuring market cap-based fee schedules for graduated pools. * Enabling first swap with minimum fee for pool creators. * Abstracts the math behind crafting the bonding curve.
After configuring your DBC token pool settings in `dbc_config.jsonc`, you can now create your token pool by running the following command. *If you don't have a DBC config key, you can run the following command and the config key + pool will be created together.* ```bash theme={"system"} pnpm studio dbc-create-pool ``` *If you already have an existing DBC config key, you can provide it via the CLI with a `--config` flag and run the following command.* ```bash theme={"system"} pnpm studio dbc-create-pool --config ``` This will create your DBC curve config (if there is no config key) and token pool. You will also be able to see the token address and other relevant information in the console.

Voilà! You've successfully created your DBC token pool on Meteora. You can now see your token in action on [Jupiter Pro](https://jup.ag/pro), [Axiom](https://axiom.trade/discover) or [Photon](https://photon-sol.tinyastro.io/en/discover). # DLMM Launch Pool Source: https://docs.meteora.ag/developer-guide/quick-launch/dlmm-launch-pool Configure and Launch a DLMM Pool on Meteora using nothing but a configuration file and a few CLI commands In this guide, Metsumi will walk you through the steps to create a DLMM launch pool on Meteora. Whether you’re a seasoned developer or just starting out, this guide has got you covered to deploy liquidity and launch your project on Meteora. # What You'll Achieve By the end of this quicklaunch, you’ll have built a liquidity pool on Meteora by: * Configuring your liquidity pool settings * Interacting with our DLMM program * See your liquidity pool in action on Meteora **Why Meteora?** Meteora is a hyper optimized liquidity layer that ensures that your project's provided liquidity is secure, sustainable and composable for anyone to trade on. By following this guide, you'll be able to launch a concentrated liquidity pool with dynamic fees on Meteora in just a few quick and easy steps. # Prerequisites * Node.js >= 18.0.0 * pnpm >= 10.0.0 *If you don't have pnpm installed, you can install it by running the following command.* ```bash Terminal theme={"system"} npm install -g pnpm ``` # Steps Meteora Invent is a toolkit consisting of everything you need to invent innovative token launches on Meteora. Run the following command in your terminal to get started. ```bash Terminal theme={"system"} git clone https://github.com/MeteoraAg/meteora-invent.git ``` Once you've cloned the repository, you'll have a new project directory with a meteora-invent folder. Run the following to install pnpm and the project dependencies. ```bash Terminal theme={"system"} cd meteora-invent pnpm install ``` In Meteora Invent we provide an optional command for you to run a local validator to test your pool before deploying it to devnet or mainnet. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} pnpm studio start-test-validator ``` This will start a local validator on your machine which will be hosted on `http://localhost:8899`.

We provide an easy way to setup environment variables when getting started. Run the following command in your code editor terminal to get started. ```bash Terminal theme={"system"} cp studio/.env.example studio/.env ``` This will copy the example environment variables file to your `.env` file. Configure the following variables: * `PRIVATE_KEY` - Your private key for the wallet you will be using to deploy the pool. Therafter, you will need to run this command to generate a keypair from your wallet private key. ```bash Terminal theme={"system"} pnpm studio generate-keypair # For devnet (airdrops 5 SOL) pnpm studio generate-keypair --network devnet --airdrop # For localnet (airdrops 5 SOL) # Ensure that you have already started the local validator with pnpm start-test-validator pnpm studio generate-keypair --network localnet --airdrop ``` This will generate a `keypair.json` file in the `studio` directory which will be used for all actions in this guide.

Navigate to the `studio/config/dlmm_config.jsonc` file and configure your DLMM pool settings.

Your can configure everything DLMM pool related in this file. The comments in the file are to help you understand the different settings you can configure. Please ensure that you read through the comments while configuring your pool. ```jsonc dlmm_config.jsonc theme={"system"} { /* rpcUrl is required. You can switch between mainnet, devnet and localnet or use your own RPC URL. */ "rpcUrl": "https://api.devnet.solana.com", // mainnet: https://api.mainnet-beta.solana.com | devnet: https://api.devnet.solana.com | localnet: http://localhost:8899 /* dryRun is required. If true, transactions will be simulated and not executed. If false, transactions will be executed. */ "dryRun": false, /* keypairFilePath is required and will be the payer + signer for all transactions */ "keypairFilePath": "./keypair.json", /* computeUnitPriceMicroLamports is required and can be adjusted to fit your needs */ "computeUnitPriceMicroLamports": 100000, /* quoteMint is required for the following actions: * 1. dlmm-create-pool * 2. dlmm-seed-liquidity-lfg * 3. dlmm-seed-liquidity-single-bin * 4. dlmm-set-pool-status * SOL: So11111111111111111111111111111111111111112 | USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | any other token address */ "quoteMint": "So11111111111111111111111111111111111111112", /* If you have a baseMint already created, you can specify it in the cli command via --baseMint flag. If you don't have a baseMint, you can create a new one using createBaseToken. * Either use --baseMint flag or createBaseToken, but not both. */ "createBaseToken": { "supply": 1000000000, // total amount of base token to be minted "decimals": 6, // decimals of the base token // "tokenMintKeypairFilePath": "./mint-keypair.json", // path to token mint keypair if you have a specific keypair for the token mint. If not provided, a new keypair will be generated. "name": "YOUR_TOKEN_NAME", // token name "symbol": "YOUR_TOKEN_SYMBOL", // token symbol "authorities": { "mint": "YOUR_MINT_AUTHORITY_ADDRESS", // token mint authority address. "freeze": "YOUR_FREEZE_AUTHORITY_ADDRESS", // token freeze authority address. "update": "YOUR_UPDATE_AUTHORITY_ADDRESS" // token update authority address. }, /* Optional Metaplex Token Metadata Properties * Read more about the properties here: https://developers.metaplex.com/token-metadata */ "sellerFeeBasisPoints": 0, // Royalty fee in basis points (0-10000) "creators": null, // Array of creator objects of the token (optional) "collection": null, // Collection info (optional) "uses": null, // Usage restrictions (optional) "metadata": { // "uri": "https://gateway.irys.xyz/123456789", // if you already have a metadata URI created, you can specify it here /* Only use the following parameters for createBaseToken if you don't have an existing metadata uri * This will create an image uri and a new metadata uri and upload everything to Irys */ "image": "./data/image/test-token.jpg", // this can be a URL of the image address (e.g. https://example.com/token-image.png) or the image file path (e.g. ./data/image/test-token.jpg) "description": "YOUR_TOKEN_DESCRIPTION", // token description "website": "https://example.com", // project website "twitter": "https://x.com/yourproject", // twitter URL "telegram": "https://t.me/yourproject" // telegram URL } }, /* dlmmConfig is only used in the following actions: * 1. dlmm-create-pool */ "dlmmConfig": { "binStep": 25, // Price increment/decrement percentage in basis points (400 = 4% price step between bins) "feeBps": 1, // Trading fee in basis points (200 = 2% fee per swap) "initialPrice": 1.333, // Initial price(in terms of quote/base price) "activationType": 1, // 0 - Slot | 1 - Timestamp "activationPoint": null, // Activation time of the pool depending on activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "priceRounding": "up", // Price calculation rounding direction for bin ID conversion "creatorPoolOnOffControl": true, // Pool creator permission to enable/disable trading for permissionless pools "hasAlphaVault": false // If true, the alpha vault will be created after the pool is created }, /* lfgSeedLiquidity is only used in the following actions: * 1. dlmm-seed-liquidity-lfg * https://ilm.jup.ag/ */ "lfgSeedLiquidity": { "minPrice": 0.003393, // Minimum price boundary for liquidity distribution range "maxPrice": 0.004393, // Maximum price boundary for liquidity distribution range "curvature": 0.6, // Distribution curvature factor (1/k) controlling liquidity concentration (0-1, lower = more concentrated) "seedAmount": "200000", // Total amount of liquidity to seed into the pool (in token units) "operatorKeypairFilepath": "./keypair.json", // File path to operator's private key for signing seeding transactions "positionOwner": "YOUR_POSITION_OWNER_ADDRESS", // Public key of the position owner who controls the liquidity "feeOwner": "YOUR_FEE_OWNER_ADDRESS", // Public key entitled to claim trading fees from this position "lockReleasePoint": 0, // Timestamp/slot when position becomes withdrawable (0 = immediately unlocked) "seedTokenXToPositionOwner": true // Whether to send 1 lamport of token X to position owner as ownership proof }, /* singleBinSeedLiquidity is only used in the following actions: * 1. dlmm-seed-liquidity-single-bin */ "singleBinSeedLiquidity": { "price": 1.333, // Exact price where liquidity will be concentrated in a single bin "priceRounding": "up", // Price calculation rounding direction for bin ID conversion. "up" = round up, "down" = round down "seedAmount": "750000000", // Amount of token X (base token) to seed into the single bin (in token units) "operatorKeypairFilepath": "./keypair.json", // File path to operator's private key for signing seeding transactions "positionOwner": "YOUR_POSITION_OWNER_ADDRESS", // Public key of the position owner who controls the liquidity "feeOwner": "YOUR_FEE_OWNER_ADDRESS", // Public key entitled to claim trading fees from this position "lockReleasePoint": 0, // Timestamp/slot when position becomes withdrawable (0 = immediately unlocked) "seedTokenXToPositionOwner": true // Whether to send 1 lamport of token X to position owner as ownership proof }, /* setDlmmPoolStatus is only used in the following actions: * 1. dlmm-set-pool-status */ "setDlmmPoolStatus": { "enabled": true // true = enable trading | false = disable trading }, /* alphaVault is only used in the following actions: * 1. dlmm-create-pool * There are 2 types of alpha vault: First Come First Serve (FCFS) and Prorata. */ "alphaVault": { "poolType": "dlmm", // DLMM = dlmm | DAMM v1 = dynamic | DAMM v2 = damm2 "alphaVaultType": "fcfs", // FCFS = fcfs | Prorata = prorata /* Only use the following parameters for alphaVaultType: fcfs * 1. maxDepositCap * 2. individualDepositingCap */ "maxDepositCap": 10000, // Maximum total amount (in quote token) that can be deposited across all users in the vault "individualDepositingCap": 1, // Maximum amount (in quote token) that each individual user can deposit /* Only use the following parameters for alphaVaultType: prorata * 1. maxBuyingCap */ // "maxBuyingCap": 10000, // Maximum total amount (in quote token) that can be bought across all users in the vault "depositingPoint": 1755421200, // When users can start depositing depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "startVestingPoint": 1755507600, // When token vesting begins and users can start claiming their vested tokens depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "endVestingPoint": 1755507600, // When token vesting ends and all tokens become fully claimable depending on pool's activationType (Calculate in slots if activationType is 0 (slots) | Calculate in seconds if activationType is 1 (timestamp)) "escrowFee": 0, // Fee amount (in quote token) charged when creating a stake escrow account "whitelistMode": "permissionless" // Whitelist mode: permissionless | permissioned_with_merkle_proof | permissioned_with_authority /* Optional Configuration: whitelistFilePath * Only use when whitelistMode is permissioned_with_merkle_proof or permissioned_with_authority */ // "whitelistFilepath": "./data/whitelist_wallet.csv", // Optional path to CSV file containing whitelisted wallet addresses and their deposit caps (format: wallet,deposit_cap) /* Optional Configuration: merkleProofBaseUrl, chunkSize, kvProofFilepath, cloudflareKvProofUpload * Only use when whitelistMode is permissioned_with_merkle_proof */ // "merkleProofBaseUrl": "https://example.workers.dev/", // Base URL endpoint where merkle proofs are stored and can be retrieved for whitelisted wallet verification // "chunkSize": 1000, // Optional batch size for processing large whitelist files or merkle tree operations to avoid memory/performance issues // "kvProofFilepath": "./data/kv_proofs", // Optional path to key-value file storing pre-computed merkle proofs for whitelisted addresses // "cloudflareKvProofUpload": { // "kvNamespaceId": "YOUR_KV_NAMESPACE_ID", // "accountId": "YOUR_ACCOUNT_ID", // "apiKey": "YOUR_API_KEY" // } } } ``` The toolkit contains logic to make it easier for you to create the DLMM pool such as: * Minting a new `baseMint` token or parsing in an existing `baseMint` token. * Launching the DLMM pool immediately or at a certain `activationPoint` (in slots or timestamp depending on the `activationType`). * Optional creation of an Alpha Vault with your DLMM launch pool.
After configuring your DLMM pool settings in `dlmm_config.jsonc`, you can now create your pool by running the following command. *If you don't have a base mint, you can configure `createBaseToken` in the config file and run the following command.* ```bash theme={"system"} pnpm studio dlmm-create-pool ``` *If you already have a base mint created, you can provide it via the CLI with a `--baseMint` flag and run the following command.* ```bash theme={"system"} pnpm studio dlmm-create-pool --baseMint ``` This will create your pool and print the pool address and other relevant information to the console.

After creating your DLMM pool, you can now seed your pool with liquidity. *If you want to seed your pool with liquidity using the LFG model, you can run the following command.* Please take note that the `dlmm-seed-liquidity-lfg` command will only work when your DLMM launch pool is not activated yet. You can configure the pool activation time using the `activationPoint` parameter in the `dlmm_config.jsonc` file. ```bash Terminal theme={"system"} pnpm studio dlmm-seed-liquidity-lfg --baseMint ``` This will seed your DLMM pool with liquidity based on the `curvature`, `minPrice` and `maxPrice` parameters that you have set in the `dlmm_config.jsonc` file. If you want to learn how the liquidity curvature works, you can head to [https://ilm.jup.ag/](https://ilm.jup.ag/) to learn more. *If you want to seed your pool with liquidity in a single bin, you can run the following command.* Please take note that the `dlmm-seed-liquidity-single-bin` command will only work when your DLMM launch pool is not activated yet. You can configure the pool activation time using the `activationPoint` parameter in the `dlmm_config.jsonc` file. ```bash Terminal theme={"system"} pnpm studio dlmm-seed-liquidity-single-bin --baseMint ``` This will seed your DLMM pool with liquidity in a single bin based on the `price` and `seedAmount` parameters that you have set in the `dlmm_config.jsonc` file.

Voilà! You've successfully created your DLMM pool on Meteora. You can now see your pool in action on Meteora either on Meteora's [mainnet](https://app.meteora.ag) or [devnet](https://devnet.meteora.ag) app. # Integrate with DAMM v2 Source: https://docs.meteora.ag/developer-guide/trading-terminals/integrate-with-damm-v2 Everything you need to know to integrate with Meteora's DAMM v2 Program Trading Terminals can easily integrate with Meteora DAMM v2 by following this guide that explains in detail how to get the necessary data from indexing the DAMM v2 program. ## Total Fees ``` totalFees = baseFees + dynamicFees ``` ### Base Fees Base Fees includes either a Flat Fee, Fee Scheduler, Rate Limiter, or Fee Market Cap Scheduler. `BaseFeeMode` can be enums 0, 1, 2, 3, or 4. * 0 = Linear Fee Time Scheduler * 1 = Exponential Fee Time Scheduler * 2 = Rate Limiter * 3 = Linear Fee Market Cap Scheduler * 4 = Exponential Fee Market Cap Scheduler #### Decoding BaseFee The `baseFee.data` field is a `number[]` (byte array) that requires decoding when indexed. The decoder type depends on the **data source** and **`baseFeeMode`**. **From `EvtInitializePool` event** (Borsh serialization, 30 bytes): * `baseFeeMode` 0-1: Use `BorshFeeTimeScheduler` * `baseFeeMode` 2: Use `BorshFeeRateLimiter` * `baseFeeMode` 3-4: Use `BorshFeeMarketCapScheduler` **From `poolState` account** (Pod-aligned serialization, 32 bytes): * `baseFeeMode` 0-1: Use `PodAlignedFeeTimeScheduler` * `baseFeeMode` 2: Use `PodAlignedFeeRateLimiter` * `baseFeeMode` 3-4: Use `PodAlignedFeeMarketCapScheduler` #### Flat Fee You can fetch the flat fee directly from the `cliffFeeNumerator` in the `baseFee` object if all other parameters are 0. ```typescript theme={"system"} // Example - Flat fee baseFee: { cliffFeeNumerator: 10000000, // 1% flat fee baseFeeMode: 0, numberOfPeriod: 0, periodFrequency: 0, reductionFactor: 0 } ``` The Fee Scheduler depends on the `poolState.activationType`. * If the `poolState.activationType == 0`, then `numberOfPeriod` and `periodFrequency` is calculated in `SLOT == 400ms` * If the `poolState.activationType == 1`, then `numberOfPeriod` and `periodFrequency` is calculated in `SECONDS == 1000ms` #### Fee Time Scheduler * For Fee Time Scheduler, the fee reduces over time based on the scheduler configuration. * `baseFeeMode` can be 0 (Linear) or 1 (Exponential). ```typescript theme={"system"} interface FeeTimeScheduler { 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 based on activationType) reductionFactor: BN; // Fee reduction per period } ``` You can refer to the math formula for the Fee Time Scheduler [here](/anti-sniper-suite/fee-time-scheduler/fee-time-scheduler-math) Here are some examples of how the Fee Time Scheduler works: ```typescript theme={"system"} // Fee Time Scheduler: 50% reduce to 1% in 10 minutes linearly { cliffFeeNumerator: new BN(500000000), // 50% starting fee baseFeeMode: 0, // Linear mode numberOfPeriod: 100, // 100 periods periodFrequency: new BN(1), // Time between periods reductionFactor: new BN(4900000), // Reduction factor per period } ``` ```typescript theme={"system"} // Fee Time Scheduler: 50% reduce to 1% in 10 minutes exponentially { cliffFeeNumerator: new BN(500000000), // 50% starting fee baseFeeMode: 1, // Exponential mode numberOfPeriod: 100, // 60 periods periodFrequency: new BN(1), // Time between periods reductionFactor: new BN(383), // Reduction factor per period } ``` #### Rate Limiter * For Rate Limiter, the fee increases exponentially based on trade size to prevent large trades from manipulating the market. * `baseFeeMode` can only be 2. When integrating swaps with Rate Limiter pools (`baseFeeMode == 2`), you must include `SYSVAR_INSTRUCTIONS_PUBKEY` in the remaining accounts of the swap instruction. ```typescript theme={"system"} interface FeeRateLimiter { 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 (slots or seconds) maxFeeBps: number; // Maximum fee cap in basis points referenceAmount: BN; // Reference amount for fee calculation } ``` You can refer to the math formula for the Rate Limiter [here](/anti-sniper-suite/rate-limiter/rate-limiter-math) Here are some examples of how the Rate Limiter works: ```typescript theme={"system"} // Rate Limiter: Starts at 1% fee -> Exponential increase in fee for 10 slots based on trade size // 0.5 SOL trade // fee = 0.5 SOL * 0.1% = 0.0005 SOL // 1.5 SOL trade // fee = 1 SOL * 0.1% + 0.5 SOL * 0.2% = 0.002 SOL // 3 SOL trade // fee = 1 SOL * 0.1% + 1 SOL * 0.2% + 1 SOL * 0.3% = 0.006 SOL { cliffFeeNumerator: new BN(10000000), // Base fee numerator (1%) baseFeeMode: 2, // Rate limiter mode feeIncrementBps: 10, // Fee increment per reference amount in basis points maxFeeBps: 5000, // Max fee cap in basis points (50%) referenceAmount: new BN(1000000000), // Reference amount in lamports (1 SOL) maxLimiterDuration: 10, // Duration in slots/seconds } ``` #### Fee Market Cap Scheduler * Fee Market Cap Scheduler reduces fees based on **price movement (market cap growth)** rather than time. This is different from Fee Time Scheduler which reduces fees over time regardless of price action. * `baseFeeMode` can be 3 (Linear) or 4 (Exponential). ```typescript theme={"system"} interface FeeMarketCapScheduler { 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 (slots or seconds) reductionFactor: BN; // Fee reduction per period } ``` You can refer to the detailed math formula for the Fee Market Cap Scheduler [here](/anti-sniper-suite/fee-market-cap-scheduler/fee-market-cap-scheduler-math) Here are some examples of how the Fee Market Cap Scheduler works: ```typescript theme={"system"} // Fee Market Cap Scheduler: 50% starting fee, reduces linearly based on price growth { cliffFeeNumerator: new BN(500000000), // 50% starting fee baseFeeMode: 3, // Linear mode numberOfPeriod: 100, // 100 periods sqrtPriceStepBps: 100, // 1% sqrt price step per period schedulerExpirationDuration: 86400, // 24 hours expiration reductionFactor: new BN(4950000), // Linear reduction factor } ``` ```typescript theme={"system"} // Fee Market Cap Scheduler: 50% starting fee, reduces exponentially based on price growth { cliffFeeNumerator: new BN(500000000), // 50% starting fee baseFeeMode: 4, // Exponential mode numberOfPeriod: 100, // 100 periods sqrtPriceStepBps: 100, // 1% sqrt price step per period schedulerExpirationDuration: 86400, // 24 hours expiration reductionFactor: new BN(390), // Exponential reduction factor (bps) } ``` ### Dynamic Fees (Variable Fee) You can refer to the Dynamic Fee calculation [here](/overview/products/damm-v2/pool-fees-calculation#dynamic-fee-variable-fee) ## Pool Version (fee\_version) The `fee_version` field on a pool state indicates its version. Pool version determines the maximum allowed fee. | `fee_version` | Max Fee | | ------------- | ------- | | 0 (V0) | 50% | | 1 (V1) | 99% | All newly created pools are V1. ## Plotting Charts Using Transfer logs from Swap transactions is not the correct way of getting the token price as we have Anti-Sniper Suite features that can cause huge fee deductions from `TokenAmountIn` OR `TokenAmountOut`. Plotting the token chart price from these will lead to a very ugly chart. The correct way is to fetch the `EvtSwap2` CPI logs from the Swap transaction. `EvtSwap` is an older version of the swap CPI logs and might be deprecated in the future. Use `EvtSwap2` instead. Because of the Anti-Sniper Suite features, you will have to apply the following checks to get the correct token price either before/after the fee deduction. \[1.1] Firstly, you will need to identify where the fees are coming from (either from input or output): ``` feeOnInput: (collectFeeMode == 1 && tradeDirection == 1) || (collectFeeMode == 2 && tradeDirection == 1) ? true : false ``` \[1.2] Next, calculate the amount and plot price depending on where the fees are coming from (either from input or output): ``` if (feeOnInput): price = excludedFeeInputAmount / outputAmount if (!feeOnInput): price = excludedFeeInputAmount / (outputAmount + tradingFee + protocolFee + referralFee + compoundingFee) ``` **Breaking change in v0.2.0:** `EvtSwap2` no longer contains a `partner_fee` field. It has been replaced by `compounding_fee`. Update any integrations that previously read `partner_fee` from swap CPI logs to use `compounding_fee` instead. The total trading fee is now: `tradingFee = claimingFee + compoundingFee` ### Collect Fee Mode 2 (Compounding) When `collectFeeMode == 2`, the pool operates in **Compounding** mode. This affects how you interpret swap events and price calculations: * Fees are always collected in Token B (quote token), regardless of trade direction. * For B→A trades (`tradeDirection == 1`), fees are deducted from the input amount (`feeOnInput = true`). * A percentage of the fee (configured by `compounding_fee_bps`) is automatically reinvested back into the pool reserves rather than being claimable by LPs. This portion appears as `compounding_fee` in `EvtSwap2`. * The pool uses a constant-product formula (no concentrated liquidity range) in this mode. **Fee collection summary by mode and direction:** | `collectFeeMode` | A→B trade | B→A trade | | ---------------- | ----------------- | -------------------------------- | | 0 (BothToken) | Fee on B (output) | Fee on A (output) | | 1 (OnlyB) | Fee on B (output) | Fee on B (input) | | 2 (Compounding) | Fee on B (output) | Fee on B (input) + auto-compound | **`SwapResult2` fields (v0.2.0+):** ```typescript theme={"system"} interface SwapResult2 { included_fee_input_amount: BN; // Input amount including fee (when feeOnInput) excluded_fee_input_amount: BN; // Input amount excluding fee amount_left: BN; // Remaining amount after swap output_amount: BN; // Output amount to recipient next_sqrt_price: BN; // Pool sqrt price after swap claiming_fee: BN; // Fee claimable by LPs compounding_fee: BN; // Fee auto-reinvested into reserves (replaces partner_fee) protocol_fee: BN; // Fee taken by protocol referral_fee: BN; // Fee taken by referral account } ``` ## Trading Volume Track from Swap CPI logs: ``` // Depending on Trade Direction: trading_volume += actualAmountIn * token_price ``` ## Liquidity In the DAMM v2 pool, the liquidity is fetched from the `tokenAVault` and `tokenBVault` of the DAMM v2 pool. ``` liquidity = tokenAVault * tokenAPrice + tokenBVault * tokenBPrice ``` ## Locked or Vested Liquidity In DAMM v2, there are 3 different modes for liquidity: 1. `lockedLiquidity` - which means that the liquidity is permanently locked 2. `vestedLiquidity` - which means that the liquidity is vestedLiquidity 3. `unlockedLiquidity` - which means that the liquidity is unlocked and claimable You can use our DAMM v2 API [endpoint](/api-reference/pools/get_pool_vesting_list) that tracks pool positions and show accurately whether the liquidity is locked or not on your trading terminal. ### How to Identify Launchpads Using DAMM v2 You can ping us on Discord to get a list of all launchpads configuration who are launching on DAMM v2 directly so that you can index them on your trading terminal. Open a ticket on [discord](https://discord.gg/meteora) to get access to the list. ## Referral Account * For trading terminals, we have a feature that enables trading terminals to earn referral fees from all swaps that happen on our Meteora DAMM v2 program as long as they were swapped through your trading terminal. * For referral fees, include your referral token account in the swap instruction and you will receive **20%** of the protocol fee for all swaps. # Integrate with DBC Source: https://docs.meteora.ag/developer-guide/trading-terminals/integrate-with-dbc Everything you need to know to integrate with Meteora's DBC Program Trading Terminals can easily integrate with Meteora DBC by following this guide that explains in detail how to get the necessary data from indexing the DBC program. ## Bonding Curve Progress ### Core Formula ``` bondingCurveProgress = poolState.quoteReserve / poolConfigState.migration_quote_threshold ``` There are 2 ways you can get the quote reserve: 1. From the `poolState.quoteReserve` state in a DBC pool. 2. From the `nextSqrtPrice` in the swap CPI logs. 3. Directly from `EvtSwap2` swap CPI logs. #### 1. Get Quote Reserve from Pool State ```typescript theme={"system"} const client = new DynamicBondingCurveClient(connection, "confirmed"); const poolState = await client.state.getPool(poolAddress); const quoteReserve = poolState.quoteReserve; ``` #### 2. Get Quote Reserve from Next Sqrt Price Using the `get_quote_token_from_sqrt_price` function ```rust theme={"system"} pub fn get_quote_token_from_sqrt_price(next_sqrt_price: u128, config: &PoolConfig) -> Result { let mut total_amount = U256::ZERO; for i in 0..MAX_CURVE_POINT { let lower_sqrt_price = if i == 0 { config.sqrt_start_price } else { config.curve[i - 1].sqrt_price }; if next_sqrt_price > lower_sqrt_price { let upper_sqrt_price = if next_sqrt_price < config.curve[i + 1].sqrt_price { next_sqrt_price } else { config.curve[i + 1].sqrt_price }; let max_amount_in = get_delta_amount_quote_unsigned_256( lower_sqrt_price, upper_sqrt_price, config.curve[i].liquidity, Rounding::Up, )?; total_amount = total_amount.safe_add(max_amount_in)?; } } Ok(total_amount) } ``` Alternatively, you can use the `getQuoteReserveFromNextSqrtPrice` function in the [DBC TypeScript SDK](https://github.com/MeteoraAg/dynamic-bonding-curve-sdk/blob/main/packages/dynamic-bonding-curve/docs.md#getQuoteReserveFromNextSqrtPrice) as it is the typescript version of the above function. #### 3. Directly from `EvtSwap2` swap CPI logs Example of an `EvtSwap2` swap CPI logs: ```json theme={"system"} { "pool": "51mjM3ne2AiMHfeox78yjwwks7tF6sYokuuMkibAkSpn", "config": "H4r8wEqix3mN6WDv7qZKaAdQj3GYg7xBMbFND4Cx9Bwt", "tradeDirection": 0, "hasReferral": false, "swapParameters": { "amount0": "797867598488800000", "amount1": "4900009949", "swapMode": 0 }, "swapResult": { "includedFeeInputAmount": "797867598488800000", "excludedFeeInputAmount": "797867598488800000", "amountLeft": "0", "outputAmount": "4900499999", "nextSqrtPrice": "748125024131879", "tradingFee": "39600000", "protocolFee": "9900000", "referralFee": "0" }, "quoteReserveAmount": "1", "migrationThreshold": "5000000000", "currentTimestamp": "1756275517" } ``` ## Total Fees ``` totalFees = baseFees + dynamicFees ``` ### Base Fees Base Fees includes either a Flat Fee or a Fee Scheduler or Rate Limiter. `BaseFeeMode` can only be enums 0, 1, or 2. * 0 = Linear Fee Scheduler * 1 = Exponential Fee Scheduler * 2 = Rate Limiter #### Flat Fee You can fetch the flat fee directly from the `cliffFeeNumerator` in the `baseFee` object if `firstFactor`, `secondFactor`, and `thirdFactor` are all 0. ```typescript theme={"system"} // Example baseFee: { cliffFeeNumerator: , // 1% flat fee firstFactor: 0, secondFactor: , thirdFactor: , baseFeeMode: 0 } ``` The Fee Scheduler and Rate Limiter depends on the `poolState.activationType`. * If the `poolState.activationType == 0`, then `numberOfPeriod` and `periodFrequency` is calculated in `SLOT == 400ms` * If the `poolState.activationType == 1`, then `numberOfPeriod` and `periodFrequency` is calculated in `SECONDS == 1000ms` #### Fee Scheduler * For Fee Scheduler, it contains `numberOfPeriod`, `periodFrequency`, and `reductionFactor` which are paired with the `firstFactor`, `secondFactor`, and `thirdFactor` respectively. * `baseFeeMode` can only be 0 or 1. ```typescript theme={"system"} interface BaseFee = { cliffFeeNumerator: BN firstFactor: number // numberOfPeriod secondFactor: BN // periodFrequency thirdFactor: BN // reductionFactor baseFeeMode: BaseFeeMode // 0 or 1 } ``` You can refer to the math formula for the Fee Scheduler [here](/anti-sniper-suite/fee-time-scheduler/fee-time-scheduler-math) Here are some examples of how the Fee Scheduler works: ```typescript theme={"system"} // Fee Scheduler: 50% reduce to 1% in 10 minutes linearly baseFee: { cliffFeeNumerator: , firstFactor: 60, // numberOfPeriods secondFactor: , // periodFrequency thirdFactor: , // reduction factor baseFeeMode: 0 }, ``` ```typescript theme={"system"} // Fee Scheduler: 50% reduce to 1% in 10 minutes exponentially baseFee: { cliffFeeNumerator: , firstFactor: 60, // numberOfPeriods secondFactor: , // periodFrequency thirdFactor: , // reduction factor baseFeeMode: 1 }, ``` #### Rate Limiter * For Rate Limiter, it contains `feeIncrementBps`, `maxLimiterDuration`, and `referenceAmount` which are paired with the `firstFactor`, `secondFactor`, and `thirdFactor` respectively. * `baseFeeMode` can only be 2. ```typescript theme={"system"} interface BaseFee = { cliff_fee_numerator: BN first_factor: number //feeIncrementBps secondFactor: BN // maxLimiterDuration thirdFactor: BN // referenceAmount baseFeeMode: BaseFeeMode // 2 } ``` You can refer to the math formula for the Rate Limiter [here](/anti-sniper-suite/rate-limiter/rate-limiter-math) Here are some examples of how the Rate Limiter works: ```typescript theme={"system"} // Rate Limiter: Starts at 1% fee -> Exponential increase in fee for 10 slots based on trade size // 0.5 SOL trade // fee = 0.5 SOL * 0.1% = 0.0005 SOL // 1.5 SOL trade // fee = 1 SOL * 0.1% + 0.5 SOL * 0.2% = 0.002 SOL // 3 SOL trade // fee = 1 SOL * 0.1% + 1 SOL * 0.2% + 1 SOL * 0.3% = 0.006 SOL baseFee: { cliffFeeNumerator: new BN(10_000_000), firstFactor: 10, // feeIncrementBps secondFactor: new BN(10), // maxLimiterDuration thirdFactor: new BN(1000000000), // referenceAmount baseFeeMode: 2, // rate limiter mode } ``` ### Dynamic Fees (Variable Fee) You can refer to the Dynamic Fee calculation [here](/overview/products/dbc/trading-fees-calculation#dynamic-fee-variable-fee) ## Plotting Charts Using Transfer logs from Swap transactions is not the correct way of getting the token price as we have Anti-Sniper Suite features that can cause huge fee deductions from `TokenAmountIn` OR `TokenAmountOut`. Plotting the token chart price from these will lead to a very ugly chart. The correct way is to fetch the `EvtSwap2` CPI logs from the Swap transaction. `EvtSwap` is an older version of the swap CPI logs and might be deprecated in the future. Use `EvtSwap2` instead. Because of the Anti-Sniper Suite features, you will have to apply the following checks to get the correct token price either before/after the fee deduction. ``` if excludedFeeInputAmount != includedFeeInputAmount then: -> excludedFeeInputAmount <> outputAmount if excludedFeeInputAmount == includedFeeInputAmount then: -> excludedFeeInputAmount <> outputAmount + tradingFee + protocolFee + referralFee ``` ## Trading Volume Track from Swap CPI logs: ``` // Depending on Trade Direction: trading_volume += excludedFeeInputAmount * token_price ``` ## Liquidity In the bonding curve, the liquidity is fetched from the virtual quote reserve of the bonding curve pool. ``` liquidity = poolState.quoteReserve * quoteTokenPrice ``` ## Locked Vesting ``` total_vesting_amount = cliff_unlock_amount + (amount_per_period * number_of_period) ``` ## Migration * You can check whether the DBC pool has migrated via the `isMigrated` flag from the [DBC pool state](https://github.com/MeteoraAg/dynamic-bonding-curve/blob/main/programs/dynamic-bonding-curve/src/state/virtual_pool.rs). * You can also check the MigrationProgress from the [DBC pool state](https://github.com/MeteoraAg/dynamic-bonding-curve/blob/main/programs/dynamic-bonding-curve/src/state/virtual_pool.rs) via the `MigrationProgress` parameter. ```rust theme={"system"} IsMigrated::NotMigrated // 0 IsMigrated::Migrated // 1 ``` ```rust theme={"system"} MigrationProgress::PreBondingCurve // 0 MigrationProgress::PostBondingCurve // 1 MigrationProgress::LockedVesting // 2 MigrationProgress::CreatedPool // 3 ``` ### Post-Migration Fee Collection Mode (DAMM v2) When a DBC pool graduates to DAMM v2, the fee collection behavior depends on the `collectFeeMode` set in the pool's `migratedPoolFee` config. Trading terminals should be aware of these modes when displaying fee or liquidity information for graduated pools: | `collectFeeMode` | Behavior | | ----------------- | ------------------------------------------------------------------------------------------------------ | | `0` (QuoteToken) | Fees accumulate in the quote token. Maps to DAMM v2 `OnlyB`. | | `1` (OutputToken) | Fees accumulate in the output token of each trade. Maps to DAMM v2 `BothToken`. | | `2` (Compounding) | Fees are automatically reinvested into the LP position. No separate claimable fee balance accumulates. | For graduated DAMM v2 pools with `collectFeeMode: 2` (Compounding), trading fee revenue is reflected in growing LP position value rather than a separate fee balance. Displaying "claimable fees" for these pools is not applicable. ### Meteora's DBC Migration Keepers * We run a total of 2 DBC Migration Keepers to migrate the DBC pools. These migration keepers each have their individual threshold requirements of >= 750 USD worth of `quoteReserve` to migrate the pool provided `quoteReserve >= migrationQuoteThreshold`. * You can check out the migration keepers [here](/developer-guide/guides/dbc/overview#migration-keeper). * If you would like to clear our tokens that are stuck (such that their `quoteReserve` is less than 750 USD worth of `quoteToken`), you can use the [Manual Migrator](https://migrator.meteora.ag/) to manually migrate the pool. ### How to Identify Launchpads Using DBC You can ping us on Discord to get a list of all launchpads configuration so that you can index them on your trading terminal. Open a ticket on [discord](https://discord.gg/meteora) to get access to the list. ## Referral Account * For trading terminals, we have a feature that enables trading terminals to earn referral fees from all swaps that happen on our Meteora DBC program as long as they were swapped through your trading terminal. * For referral fees, include your referral token account in the swap instruction and you will receive **20%** of the protocol fee for all swaps. # Build with Meteora Source: https://docs.meteora.ag/index
Metsumi
Metsumi
Metsumi
Welcome to Meteora's Documentation!
Build with Meteora
Learn how to launch liquidity pools, craft bonding curves, and provide liquidity on the most secure and dynamic liquidity layer in all of DeFi.
Product Suite
Develop with Meteora's comprehensive tech stack
Liquidity pools are the core foundation and backbone of Decentralized Finance (DeFi). Develop with the most comprehensive set of programs offering a full range of Meteora's products like [DLMM](/developer-guide/guides/dlmm/overview), [DAMM v2](/developer-guide/guides/damm-v2/overview), [DAMM v1](/developer-guide/guides/damm-v1/overview) and [DBC](/developer-guide/guides/dbc/overview). At Meteora, we push the boundaries of what is possible in DeFi through wrapper and helper programs on top of our core products. Quick Launch abstracts the need for understanding Meteora integration complexities by providing an all-in-one interface that any developer can use to create, enter commands and deploy liquidity pools on Solana. [Meteora Invent](/developer-guide/invent/actions) is a playground for developers to quickly test and experiment with Meteora's programs. Metsumi is your personal launch assistant engineered to help you launch anything and do any action in just a few configurations and CLI commands. Actions allows you to do anything and everything on Meteora's programs in just a few configurations and CLI commands. Scaffolds are ready-to-use client-side frontend templates that allows you to accelerate your development process by 100x.
Anti Sniper Suite
Sniping tokens is a feature. Choose to turn it on or off with Meteora's Anti Sniper Suite.
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.
User Guide
Sniping tokens is a feature. Choose to turn it on or off with Meteora's Anti Sniper Suite.
Providing liquidity can be a complex process if you're new to the space. Our user guide will walk you through the process of providing liquidity on Meteora's user interface. Meteora is a dynamic liquidity protocol designed to boost fee earnings for liquidity providers on Solana. This guide will walk you through the process of providing liquidity across Meteora's liquidity pools programs.
Trading Terminals
All tokens launched via Meteora's pools programs are immediately tradeable across all major trading terminals.
Are you a Trading Terminal looking to integrate with Meteora? Check out our documentation for Trading Terminals to get started.
Join the LP Army
The LP Army is a movement and community of the best liquidity providers in crypto.
We're building the greatest community of Liquidity Providers to bring LPing to the masses so more people can earn yield on their assets. We're builders and educators who LP better together. Join the movement!
# Cookies Notice and Policy Source: https://docs.meteora.ag/legal/cookies-notice-and-policy **Last updated: 10 October 2025** Welcome to Meteora's website (accessible at [https://www.meteora.ag/](https://www.meteora.ag/)) (the "**Website**"), maintained and operated for the purposes of providing news, information, and updates about Meteora. This Cookies Notice and Policy (the "**Cookie Policy**") explains the types of cookies and similar technologies that are utilised on the Website. It also explains what rights and choices you have in respect of the cookies and similar technologies that are utilised by us on the Website. The Cookie Policy is incorporated into and forms part of our Website's Terms of Service which is located at [https://docs.meteora.ag/legal/terms-of-service](https://docs.meteora.ag/legal/terms-of-service) (the "Terms") and our Privacy Policy which is located at [https://docs.meteora.ag/legal/terms-of-service#12-privacy-policy](https://docs.meteora.ag/legal/terms-of-service#12-privacy-policy) and [https://docs.meteora.ag/legal/privacy-policy](https://docs.meteora.ag/legal/privacy-policy) (the "Privacy Policy"). Except as otherwise stated in this Cookie Policy, our Privacy Policy will apply to our processing of the data that we collect via cookies. We reserve the right to modify this Cookie Policy at any time and encourage you to review this Cookie Policy each time you access the Website. Capitalised terms in this Cookie Policy shall have the meaning given to them in the Terms or the Privacy Policy, unless the context requires otherwise. *** ## What are Cookies and Why Do We Use Them 1. Cookies are small pieces of text used to store information in web browsers. Cookies are used to store and receive identifiers and other information on computers, phones and other devices. They can also be used for other purposes, such as helping online services troubleshoot errors and better understand how their services are being used. Cookies set by us are called first-party cookies. We also use third-party cookies – which are cookies from a domain different from the domain of the website you are visiting. Other technologies, such as pixels, web beacons, local storage or data that we store on your web browser or device, identifiers associated with your device and other software, may be used for similar purposes. In this Cookie Policy, we refer to all of these technologies as "cookies". 2. The cookies used on the Website or as part of any Content made available on our Website may be necessary for the provision of certain services, features or functionalities, or may be optional and utilised only for your convenience (such as by personalising content), for advertising or marketing purposes (such as for tailoring and measuring advertisements or personalising advertisements), and/or other purposes. Cookies enable us to offer the Website and the Content to you and to understand the information that we receive about you, including information about your use of other websites and apps, whether or not you are registered or logged in. 3. The cookies that we use include session cookies, which are deleted when you close your browser, and persistent cookies, which stay in your browser until they expire, or you delete them. *** ## Types of Cookies that We Use 4. The following types of cookies may be used on the Website: | Cookie Name | Provider | Type | Duration | | -------------- | ---------------- | ---------- | ----------------------------------------- | | `_ga*` | Google Analytics | Optional | Session/persistent cookies up to 400 days | | `AMP_*` | Amplitude | Optional | Session/persistent cookies up to 1 year | | `cf_clearance` | Cloudflare | Persistent | Up to 1 year | 5. The cookies that we use and how we use them may change over time as we improve and update the Website and the Content made available therein. *** ## How Do We Use Cookies 6. We may place cookies on your computer or device and receive information stored in cookies when you use or visit:
**(a)** the Website;
**(b)** any Content that are made available on or through the Website; or
**(c)** any websites, services and applications provided by third parties that are made available on or through the Website (such as Third-Party Service and Third-Party Content).
7. Third-party companies (such as Third Party Providers) may also use cookies on their own websites, products, applications and/or services in connection with the Website and/or the Content made available therein. To understand how other companies use cookies, please refer to their respective cookie policies. *** ## Managing Cookies 8. Most browsers allow you to manage how cookies are set and used as you're browsing, and to clear cookies and browsing data. Also, your browser may have settings letting you manage cookies on a site-by-site basis. For example, Google Chrome's settings at `chrome://settings/cookies` allow you to delete existing cookies, allow or block all cookies, and set cookie preferences for websites. Google Chrome also offers Incognito mode, which deletes your browsing history and clears cookies from the Incognito windows on your device after you close all of your Incognito windows. 9. Most mobile devices and applications also allow you to manage how similar technologies, such as unique identifiers used to identify an app or device, are set and used. For example, the Advertising ID on Android devices or Apple's Advertising Identifier can be managed in your device's settings, while app-specific identifiers may typically be managed in the app's settings. 10. Kindly note that if you delete or block certain cookies, you may not be able to use all the Content made available on the Website. *** ## How To Contact Us 11. If you have any enquiries or feedback on our Cookie Policy, or if you wish to make any request, you may contact us by this email: **Email Address:** [privacy@meteora.ag](mailto:privacy@meteora.ag) *** ## Additional Information 12. For additional information about cookies, including how to see what cookies have been set on your device and how to manage and delete them, please visit: * [www.allaboutcookies.org](https://www.allaboutcookies.org) * [www.youronlinechoices.eu](https://www.youronlinechoices.eu) # MiCAR White Paper - MET Token Source: https://docs.meteora.ag/legal/mica White Paper in accordance with Article 6 of the Markets in Crypto Assets Regulation (MiCAR) for the European Union (EU) & European Economic Area (EEA) Download the full MiCAR - MET Token White Paper # Privacy Policy Source: https://docs.meteora.ag/legal/privacy-policy **Last updated: 28 April 2026** Welcome to Meteora’s website (accessible at [https://www.meteora.ag/](https://www.meteora.ag/)) (the "**Website**"), provided and operated by Meteora Nova Limited (the "**Company**", "**we**", "**our**" or "**us**"). The Company maintains and operates the Website for the purposes of providing news, information, and updates about the Meteora protocol and ecosystem. We take your privacy rights and the protection of personal data very seriously, and strive to collect, use, disclose and process any personal data collected in a manner that complies with applicable data protection and privacy legislation, including without limitation, the British Virgin Islands’ Data Protection Act, 2021 (the "**Data Protection Legislation**"). This Privacy Policy sets out what personal data we collect, how we use and share your personal data, and your choices concerning our information practices. This Privacy Policy is incorporated into and forms part of our Website’s [Terms of Use](/legal/terms-of-service) (the "**Terms**"). Before accessing and using the Website or any of the Content made available thereon, or submitting any personal data to the Company via the Website, please read through this Privacy Policy and review it carefully. By accessing and/or using the Website or Content, you agree to our collection, use, disclosure and processing of your personal data as set out in this Privacy Policy. If you do not agree to this Privacy Policy, please do not access or use the Website or any of our Content. We reserve the right to modify this Privacy Policy at any time without notice. You are advised to review this Privacy Policy each time you access the Website. *** ## Definitions and Interpretation * **"Personal data"** (or "**personal information**" as the case may be) in this Privacy Policy shall have the meaning given to it in the Data Protection Legislation. * Capitalised terms in this Privacy Policy shall have the meaning given to them in the Terms, unless the context requires otherwise. Other terms used in this Privacy Policy shall have the meanings given to them in the Data Protection Legislation (where the context so permits). *** ## Updates to This Privacy Policy * We may revise this Privacy Policy from time to time without any prior notice. By continuing to access and/or use the Website or any of the Content made available therein, you are deemed to acknowledge and accept such changes to this Privacy Policy. *** ## What Personal Data We May Collect * In order to access and/or use the Website and any of the Content made available therein, you may be required to provide us and we may collect the following categories of personal information: * **Identification Information:** Name, email address, social media handle and phone number (as the case may be) for any communication or marketing purposes. * **Wallet Information:** Details of your Digital Wallet (such as the wallet address) when you create or link your Digital Wallet with the Website. * **Communication Information:** Information you share with us as part of any enquiries, emails, surveys, or feedback. * **Social Media Information:** Information received from your interactions with our social media platforms or information provided by the social media platforms, including aggregate information and analytics of our followers or viewers. * **Internet Activity Information:** When you visit, use, or interact with the Website or any of the Content made available therein, the following information may be created and automatically logged in our systems: * **Device Information:** The manufacturer and model, operating system, IP address and unique identifiers of the device, as well as the browser you use to access the Website. The information we collect may vary based on your device type and settings. * **Usage Information:** Information about how you use our Website, such as the types of content that you view or engage with, the features you use, the actions you take, and the time, frequency, and duration of your activities. * **Email Open/Click Information:** We may use pixels in our email campaigns that allow us to collect your email and IP address as well as the date and time you open an email or click on any links in the email. *** ## When We May Collect, Use and/or Disclose Your Personal Data * We generally do not collect your personal data: * if you are just visiting or browsing the Website without connecting or linking your Digital Wallets; * unless it is provided to us voluntarily by you directly or via a third party who has been duly authorised by you to disclose your personal data to us (your "authorised representative") after (i) you (or your authorised representative) have been notified of the purposes for which the data is collected, and (ii) you (or your authorised representative) have provided consent (whether written or by conduct) to the collection and usage of your personal data for those purposes; or * collection and use of personal data without consent is permitted or required by the Data Protection Legislation or other laws. We will seek your consent before collecting any additional personal data and before using your personal data for a purpose which has not been notified to you (except where permitted or authorised by law). * We may collect and use your personal data for any or all of the following purposes: * performing obligations in the course of or in connection with allowing you access or use of our Website and any of the Content made available therein; * verifying your Digital Wallet or identity, where we are required to do so (whether by law or otherwise); * provision of the Website and any of the Content made available therein, including to provide, operate, maintain, and secure the Website and any of the Content made available therein; * processing payments for transactions made on or through the Website; * marketing and advertising purposes, including to send you direct marketing communications as permitted by law, and notify you of special promotions, offers and events by email and other means; * responding to, handling, and processing queries, requests, applications, complaints, and feedback from you; * managing your relationship with us; * contacting you in respect of any matters relating to transactions made on or through the Website; * complying with any applicable laws, regulations, codes of practice, guidelines, or rules, or to assist in law enforcement and investigations conducted by any governmental and/or regulatory authority; * any other purposes for which you have provided such information; * transmitting to any unaffiliated third parties including our third-party service providers and agents, and relevant governmental and/or regulatory authorities, whether in the British Virgin Islands or abroad, for the aforementioned purposes; and * any other incidental business purposes related to or in connection with the above. * The purposes listed in the above clauses may continue to apply even in situations where your relationship with us (for example, pursuant to a contract) has been terminated or altered in any way, for a reasonable period thereafter (including, where applicable, a period to enable us to enforce our rights under a contract with you). *** ## When Your Personal Data May Be Disclosed to Third Parties * We may disclose your personal data described above to third parties or in specific situations without further notice to you, unless required by applicable law. Such disclosures may occur in the following instances: * **Performance of Services:** When necessary for fulfilling obligations related to transactions made on or through the Website, or your access and use of the Website and/or any Content made available therein, we may disclose personal data to third parties involved in delivering these services. * **Service Providers:** To support our business operations and provide certain services, we may share personal data with third-party providers, partners, affiliates, and service providers. This includes those offering hosting and cloud services, IT support, email communication and newsletter services, advertising and marketing services, payment processing, customer relationship management, customer support, and analytics services. These third parties may access, process, or store personal data as needed to perform their functions, in accordance with our instructions. * **Professional Advisors:** We may share personal data with our professional advisors, such as legal and accounting firms, when necessary for them to provide services to us. * **Business Transfers:** If we are involved in a merger, acquisition, financing, reorganization, bankruptcy, receivership, dissolution, sale of all or a portion of our assets, or transition of service to another provider (collectively a "**Business Transaction**"), your personal data may be shared in the diligence process with counterparties and others assisting with the Business Transaction and transferred to a successor or affiliate as part of or following that Business Transaction along with other assets. * **Legal Requirements:** While we do not voluntarily share personal data with government authorities or regulators, we may disclose your information when required to do so by law, regulation, court order, or other legal obligation. * Your personal data may be made publicly available in certain instances, including when you: * post any content on our Website; and * make any social media posts with your social media accounts which we may repost or share on our own social media platforms. * For the purposes of registration, verification or provision of any of our Content, we may rely on third parties who may collect, use, disclose or process your personal data for their own purposes, and without our involvement or reference to us. We are not liable or responsible for the collection, use, disclosure or processing of your personal data by such third parties. *** ## Use of Cookies and Other Technologies * We may deploy one or more of the following technologies to collect Internet Activity Information in order to enhance your user experience, understand how you interact with any of the Content made available on the Website, and improve our offerings: * **Cookies:** These are small text files placed on your device that allow us to uniquely identify your browser or store information and settings. Cookies help improve your experience by enabling smooth navigation between pages, remembering your preferences, supporting specific functionalities, analyzing user activity and patterns, and facilitating targeted advertising. * **Local Storage Technologies:** Technologies such as HTML5 may be used to provide functionality similar to cookies but with the ability to store larger amounts of data. This information can be stored directly on your device, including outside your browser, in relation to specific applications. * **Web Beacons (Pixel Tags/Clear GIFs):** These help us confirm when a webpage or email has been accessed or opened, or when specific content has been viewed or clicked. Web beacons are typically used to track user engagement and optimize the content we deliver. * **Data Analytics Tools:** We may use technologies and tools provided by third party partners to collect information from our users through the Website in order to better understand their needs and usage patterns, which can be used to inform future improvements to the Website and provide a more personalized experience. Information being collected may include, without limitation, the following: 1. Users, pageviews, sessions 2. Source (e.g. Google, social, direct) 3. Time spent on site 4. Users info (geographical location, browser type and language, device type and operating system) For instance, we use the Google Analytics tool on the Website. For more information, please visit Google Analytics’ Privacy Policy. To learn more about how to opt-out of Google Analytics’ use of your information, please [click here](https://tools.google.com/dlpage/gaoptout). * You should refer to our [Cookies Notice and Policy](/legal/cookies-notice-and-policy) for more information relating to the various cookies and related technologies that are used on our Platform. *** ## Withdrawing Your Consent * The consent that you provide for the collection, use and disclosure of your personal data will remain valid until such time it is being withdrawn by you in writing. You may withdraw consent and request us to stop collecting, using and/or disclosing your personal data for any or all of the purposes listed above by submitting your request in writing or via email to us at the contact details provided below. * Upon receipt of your written request to withdraw your consent, we may require reasonable time (depending on the complexity of the request and its impact on our relationship with you) for your request to be processed and for us to notify you of the consequences of us acceding to the same, including any legal consequences which may affect your rights and liabilities to us. In general, we shall seek to process your request within fourteen (14) business days of receiving it. * Whilst we respect your decision to withdraw your consent, please note that depending on the nature and scope of your request, we may not be in a position to continue to grant you access and/or use of the Website and/or any of the Content made available therein and we shall, in such circumstances, notify you before completing the processing of your request. Should you decide to cancel your withdrawal of consent, please inform us via email. * Please note that withdrawing consent does not affect our right to continue to collect, use and disclose personal data where such collection, use and disclosure without consent is permitted or required under applicable laws. *** ## How to Access or Correct Your Personal Data * If you wish to make (a) an access request for access to a copy of the personal data which we hold about you or information about the ways in which we use or disclose your personal data, or (b) a correction request to correct or update any of your personal data which we hold about you, you may submit your request via email to us at the contact details provided below. * Please note that a reasonable fee may be charged for an access request. If so, we will inform you of the fee before processing your request. * We will respond to your request as soon as reasonably possible. In general, our response will be within thirty (30) business days. Should we not be able to respond to your request within thirty (30) days after receiving your request, we will inform you in writing within thirty (30) days of the time by which we will be able to respond to your request. If we are unable to provide you with any personal data or to make a correction requested by you, we shall generally inform you of the reasons why we are unable to do so (except where we are not required to do so under the Data Protection Legislation). *** ## Safeguarding Your Personal Data * To safeguard your personal data from unauthorised access, collection, use, disclosure, copying, modification, disposal or similar risks, we have or will implement appropriate administrative, physical and technical safeguards. These include limiting the collection of personal data, enforcing strong authentication and access controls (such as secure password practices and restricting data access to a need-to-know basis), encrypting data, maintaining up-to-date antivirus protection, regularly updating our operating system and other software, securely erasing storage devices before disposal, applying web security measures against risks, and conducting regular security reviews and testing. * You should be aware, however, that no method of transmission over the Internet or method of electronic storage is completely secure. While security cannot be guaranteed, we strive to protect the security of your information and are constantly reviewing and enhancing our information security measures. However, no security measures are failsafe, and we cannot guarantee the security of your personal data. You use the Website and/or any of the Content made available therein at your own risk. *** ## Accuracy of Personal Data * We generally rely on personal data provided by you (or your authorised representative). In order to ensure that your personal data is up-to-date, complete and accurate, please update us if there are changes to your personal data by via email at the contact details provided below. Failure to do so may affect or impact your continued use of the Website and/or any Content made available therein. *** ## When We May Retain Your Personal Data * We may retain your personal data for as long as it is necessary to fulfil the purpose for which it was collected, or as required or permitted by applicable laws. * We will cease to retain your personal data, or remove the means by which the data can be associated with you, as soon as it is reasonable to assume that such retention no longer serves the purpose for which the personal data was collected, and is no longer necessary for legal or business purposes. *** ## International Transfers of Personal Data * We generally do not transfer your personal data to countries outside of your country of origin and the British Virgin Islands. However, we may be required to do so in order to complete the fulfilment of any transactions made by you on or through the Website (for example, if we were to facilitate a registration for an event held outside of your country or the British Virgin Islands). * Apart from as stated above, we will obtain your consent for the transfer of any personal data to countries outside of your country of origin and the British Virgin Islands and we will take steps to ensure that your personal data continues to receive a standard of protection that is at least comparable to that provided under the Data Protection Legislation. *** ## Your California Privacy Rights The California Consumer Privacy Act or "**CCPA**" (Cal. Civ. Code § 1798.100 et seq.) affords consumers residing in California certain rights with respect to their personal information. If you are a California resident, this section applies to you. * **California Consumer Privacy Act** We may collect the following categories of personal information: identifiers, financial information, biometric information, internet or electric network activity information, and geolocation data. Please refer to Clause 4 for more details on the types of personal information that we collect. We collect personal information for the purposes set out in this Privacy Policy. For avoidance of doubt, we do not sell your personal information. * Subject to certain limitations, you have the right to (1) request to know more about the categories and specific pieces of personal information we collect, use, and disclose, (2) request deletion of your personal information, and (3) not be discriminated against for exercising these rights. You may make these requests by contacting us at [privacy@meteora.ag](mailto:privacy@meteora.ag). We will verify your request by asking you to provide information related to your recent interactions with us. We will not discriminate against you if you exercise your rights under the CCPA. *** ## Additional Disclosures for Individuals in Europe If you are located in the European Economic Area ("**EEA**"), the United Kingdom, or Switzerland, you have certain rights and protections under the law regarding the processing of your personal data, and this section applies to you. * **Legal Basis for Processing** When we process your personal data, we will do so in reliance on the following lawful bases: * To perform our responsibilities under our contract with you (e.g., processing payments for and providing the products and services you requested). * When we have a legitimate interest in processing your personal data to operate our business or protect our interests (e.g., to provide, maintain, and improve our products and services, conduct data analytics, and communicate with you). * To comply with our legal obligations (e.g., to maintain a record of your consents and track those who have opted out of communications). * When we have your consent to do so (e.g., when you opt in to receive communications from us). When consent is the legal basis for our processing of your personal data, you may withdraw such consent at any time. * **Data Retention** We store other personal data for as long as necessary to carry out the purposes for which we originally collected it and for other legitimate business purposes, including to meet our legal, regulatory, or other compliance obligations. * **Data Subject Requests** Subject to certain limitations, you have the right to request access to the personal data we hold about you and to receive your data in a portable format, the right to ask that your personal data be corrected or erased, and the right to object to, or request that we restrict, certain processing. If you would like to exercise any of these rights, please contact us at [privacy@meteora.ag](mailto:privacy@meteora.ag). * **Questions or Complaints** If you have a concern about our processing of personal data that we are not able to resolve, you have the right to lodge a complaint with the Data Protection Authority where you reside. Contact details for your Data Protection Authority can be found using the links below: For individuals in the EEA: [https://edpb.europa.eu/about-edpb/board/members\_en](https://edpb.europa.eu/about-edpb/board/members_en) For individuals in the UK: [https://ico.org.uk/global/contact-us/](https://ico.org.uk/global/contact-us/) *** ## How to Contact Us * If you have any enquiries or feedback on our personal data protection policies and procedures, or if you wish to make any request, you may contact us by this email: **Email Address:** [privacy@meteora.ag](mailto:privacy@meteora.ag) # Stake2Earn Terms of Service Source: https://docs.meteora.ag/legal/stake2earn-terms-of-service M3M3 is a distributed set of specially-developed smart contracts (each, a "Smart Contract") deployed on the Solana blockchain or such other compatible blockchain network, as the case may be (each, the "relevant Blockchain Network") which allows any user additional tools to interact with automated market maker protocols. The M3M3 Smart Contracts innovate on established protocols such as “Meteora” to provide additional tooling for creators of token projects, for example allowing them to create and customise parameters for specialised “memecoin” liquidity pools, or create staking pools ("Vaults") which represent a customised software package launched by creators of token projects. M3M3 may be visualised on a user interface that the user can interact with, including but not limited to the website at [https://app.meteora.ag/pools#stake2earnpools](https://app.meteora.ag/pools#stake2earnpools) and each of their subdomains, or our mobile or web applications (the "Site"). The Smart Contracts and the Site are collectively referred to in these Terms as (the "App"). Using the App, users can interact with the underlying Smart Contracts to create Vaults, view their Vaults created or accessed, and interact with other users in M3M3 ecosystem. The Company's sole role is the deployment of the Smart Contracts, and accordingly any interaction with Vaults take place solely on the relevant Blockchain Network. It is important that you understand that smart contract protocols such as M3M3 simply comprise a set of autonomous blockchain-based smart contracts deployed on the relevant Blockchain Network, operated directly by users calling functions on it (which allows them to interact with other users in a multi-party peer-to-peer manner). There is no further control by or interaction with the original entity which had deployed the smart contract (i.e. the Company), which entity solely functions as a provider of technical tools for users, and is not offering any sort of securities product or regulated service nor does it hold any user assets on custody. Any rewards earned by user interactions arise solely out of their involvement in the protocol by taking on the risk of interacting with other users (in particular, creators launching token projects) and the ecosystem. Meteora Nova Limited (the "Company", "we", "our" or "us") is making the App available to you. Before you use the App, the Smart Contracts, or the Site, however, you will need to agree to these Terms of Use and any terms and conditions incorporated herein by reference (collectively, these "Terms"). PLEASE READ THESE TERMS CAREFULLY BEFORE USING THE APP, THE SMART CONTRACTS, OR THE SITE. THESE TERMS GOVERN YOUR USE OF THE APP, THE SMART CONTRACTS, AND THE SITE, UNLESS WE HAVE EXECUTED A SEPARATE WRITTEN AGREEMENT WITH YOU FOR THAT PURPOSE. WE ARE ONLY WILLING TO MAKE THE APP, THE SMART CONTRACTS, AND THE SITE AVAILABLE TO YOU IF YOU ACCEPT ALL OF THESE TERMS. BY USING THE APP, THE SMART CONTRACTS, THE SITE, OR ANY PART OF THEM, OR BY CLICKING "I ACCEPT" BELOW OR INDICATING YOUR ACCEPTANCE IN AN ADJOINING BOX, YOU ARE CONFIRMING THAT YOU UNDERSTAND AND AGREE TO BE BOUND BY ALL OF THESE TERMS. IF YOU ARE ACCEPTING THESE TERMS ON BEHALF OF A COMPANY OR OTHER LEGAL ENTITY, YOU REPRESENT THAT YOU HAVE THE LEGAL AUTHORITY TO ACCEPT THESE TERMS ON THAT ENTITY’S BEHALF, IN WHICH CASE "YOU" WILL MEAN THAT ENTITY. IF YOU DO NOT HAVE SUCH AUTHORITY, OR IF YOU DO NOT ACCEPT ALL OF THESE TERMS, THEN WE ARE UNWILLING TO MAKE THE APP, THE SMART CONTRACTS, OR THE SITE AVAILABLE TO YOU. IF YOU DO NOT AGREE TO THESE TERMS, YOU MAY NOT ACCESS OR USE THE APP, THE SMART CONTRACTS, OR THE SITE. By clicking "I Accept" or otherwise indicating your Acceptance, you agree to be bound by these Terms and affirm that you are of legal age to enter into these Terms where you live and have the legal capacity to enter into these Terms. Without limiting the foregoing, by using the App, you acknowledge and understand that laws regarding digital assets, financial instruments, or investment products which may include digital assets, may vary from jurisdiction to jurisdiction, and it is your sole obligation to ensure that you fully comply with any law, regulation or directive, relevant to your jurisdiction with regard to the use of the App. For the avoidance of doubt, the ability to access the App does not necessarily mean that the App, or your activities through it, are legal under the laws, regulations or directives relevant to your jurisdiction. All of the App or the services made available through the App may not be available to all users, and we reserve the right to assess or reassess at any time your eligibility to use all or part of the App. The App does not constitute, and may not be used for the purposes of, an offer or solicitation to anyone in any jurisdiction in which such offer or solicitation is not authorised, or to any person to whom it is unlawful to make such an offer or solicitation. Supplemental terms and conditions or documents that may be posted on the App from time to time are hereby expressly incorporated herein by reference. We reserve the right, in our sole discretion, to make changes to the Terms from time to time. We will alert you of any changes by updating the “Last Updated" date of these Terms (on the first page hereof), and you waive any right to receive specific notice of each such change. It is your responsibility to periodically review these Terms to stay informed of updates. You will be subject to and will be deemed to have been made aware of and to have accepted, the changes in any revised Terms by your continued use of the Site, the App, and the Smart Contracts after the date such revised Terms are posted. *** ## Table of Contents 1. [Introduction](#1-introduction) 2. [The App](#2-the-app) 3. [Services](#3-services) 4. [Fees and Payment](#4-fees-and-payment) 5. [Intellectual Property and Content](#5-intellectual-property-and-content) 6. [User Terms](#6-user-terms) 7. [Risks Borne by Users](#7-risks-borne-by-users) 8. [External Sites](#8-external-sites) 9. [Disclaimers](#9-disclaimers) 10. [Limitation of Liability](#10-limitation-of-liability) 11. [Indemnity](#11-indemnity) 12. [Privacy Policy](#12-privacy-policy) 13. [Consent to Electronic Disclosures and Signatures](#13-consent-to-electronic-disclosures-and-signatures) 14. [Governing Law and Dispute Resolution](#14-governing-law-and-dispute-resolution) 15. [Notices](#15-notices) 16. [Entire Agreement](#16-entire-agreement) 17. [Force Majeure](#17-force-majeure) 18. [Third Party Rights](#18-third-party-rights) 19. [No Agency or Partnership](#19-no-agency-or-partnership) 20. [Interpretation](#20-interpretation) 21. [Assignment](#21-assignment) 22. [Illegality](#22-illegality) 23. [Waiver](#23-waiver) 24. [Severability](#24-severability) 25. [Survival](#25-survival) 26. [English Language](#26-english-language) *** ## 1. Introduction ### 1.1 Eligibility and Restricted Territories To be eligible to use the App, the Smart Contracts, the Site and the Services (as defined below), you must be of legal age to enter into these Terms where you live and have the legal capacity to enter into these Terms. The App, the Smart Contracts, the Site and the Services is strictly NOT offered to persons or entities who reside in, are citizens of, are incorporated in, or have a registered office in any Restricted Territory, as defined below (any such person or entity from a Restricted Territory shall be a Restricted Person). If you are a Restricted Person, then do not attempt to access or use the App, the Smart Contracts, the Site or the Services. Use of a virtual private network (e.g., a VPN) or other means by Restricted Persons to access or use the App, the Smart Contracts, the Site or the Services is prohibited. **Restricted Territory** means the British Virgin Islands, the United States, China, Myanmar (Burma), Cote D'Ivoire (Ivory Coast), Cuba, Crimea and Sevastopol, Democratic Republic of Congo, Iran, Iraq, Libya, Mali, Nicaragua, Democratic People’s Republic of Korea (North Korea), Somalia, Sudan, Syria, Yemen, Zimbabwe, Russia, or any other state, country or region that is subject to sanctions enforced by the United States or the European Union. ### 1.2 Availability of Services The App, the Smart Contracts, the Site or the Services made available through the App (or any portion thereof) may not be available to all users, and we reserve the right to assess or reassess at any time your eligibility to use all or part of the App, the Smart Contracts, the Site or the Services. ### 1.3 No Offer or Solicitation The App, the Smart Contracts, the Site and the Services does not constitute, and may not be used for the purposes of, an offer or solicitation to anyone in any jurisdiction in which such offer or solicitation is not authorised, or to any person to whom it is unlawful to make such an offer or solicitation. ### 1.4 Jurisdictional Compliance Without limiting the foregoing, by using the App, the Smart Contracts, the Site or the Services, you acknowledge and understand that laws regarding digital assets, cryptocurrency derivatives, financial instruments, or investment products which may include digital assets, may vary from jurisdiction to jurisdiction, and it is your sole obligation to ensure that you fully comply with any law, regulation or directive, relevant to your jurisdiction with regard to the use of the App, the Smart Contracts, the Site or the Services. For the avoidance of doubt, the ability to access the App, the Smart Contracts, the Site or the Services does not necessarily mean that same (or your activities through it) are legal under the laws, regulations or directives relevant to your jurisdiction. ## 2. The App 2.1. To most easily access the App, you may first install a web browser (such as the Google Chrome web browser) and an electronic wallet compatible with the relevant Blockchain Network (such as the Phantom or Solflare electronic wallet). These electronic wallet services provide a visual representation allowing you to interact with the relevant Blockchain Network to purchase, store, and engage in transactions with various digital assets. You will not be able to engage in any transactions on the App other than through your selected electronic wallet service, or other browsers compatible with the relevant Blockchain Network. 2.2. Transactions that take place via the visual user interface on the App are confirmed via the relevant Blockchain Network. You understand that your public address on the relevant Blockchain Network will be made publicly visible whenever you engage in a transaction on the App. 2.3. The visual user interface provided on the Website facilitates your ability to access M3M3. The interface is distinct from the decentralised M3M3 software network. M3M3 is public, permissionless, and runs on open-source self-executing software; while the interface itself merely enables you to initiate messages to M3M3 in order to perform functions or access Services thereon. The interface is one of the means of accessing M3M3, but not the exclusive means of access. 2.4. M3M3 is a non-custodial protocol, therefore the App does not hold or control your digital assets. Any digital assets which you may acquire through the usage of the App will be held and administered solely by you through your selected electronic wallet, and we shall have no access to or responsibility in regard to such electronic wallet or digital asset held therein. It is solely your responsibility to select the wallet service provider to use in connection with the App, and your use of such electronic wallet will be subject to the governing terms of use or privacy policy of the provider of such wallet. We neither own nor control your selected electronic wallet service, Google Chrome, any electronic wallet, the relevant Blockchain Network, or any other third party site, product, or service that you might access, visit, or use for the purpose of enabling you to use the various features of the App. We will not be liable for the acts or omissions of any such third parties, nor will we be liable for any damage that you may suffer as a result of your transactions or any other interaction with any such third parties. 2.5. The Company will not create any hosted wallet for you or otherwise custody digital assets on your behalf, and it is your sole responsibility to maintain the security of your selected electronic wallet. In the event that you lose access to your electronic wallet, private key(s), password(s), or other method(s) of securing your wallet, all digital assets held in such wallet may be irretrievable, and the Company will be unable to assist you in any way. You hereby irrevocably waive, release and discharge all claims, whether known or unknown to you, against the Company, its affiliates and their respective shareholders, members, directors, officers, employees, agents and representatives related to your use of any wallet software, associated loss of digital assets, transaction failures, or any other defects that arise in the course of your use of your electronic wallet, including any losses that may obtain as a result of any failure of any Smart Contracts, the Site or the App. 2.6. The Company reserves the right to modify, suspend or discontinue, temporarily or permanently, all or any part of the Site or the App with or without notice. You agree that the Company will not be liable to you or to any third party for any modification, suspension or discontinuance of all or any part of the Site or the App. 2.7. The publicly deployed Smart Contracts you interact with are experimental in nature and you should not utilise the Smart Contracts or Vaults for deployment of any substantial amount of digital assets. 2.8. We reserve the right to disable access to the App, the Site or the interface at any time in the event of any breach of the Terms, including without limitation, if we, in our sole discretion, believe that you, at any time, fail to satisfy the eligibility requirements set forth in the Terms. Further, we reserve the right to limit or restrict access to the App or the Site by any person or entity, or within any geographic area or legal jurisdiction, at any time and at our sole discretion. We will not be liable to you for any losses or damages you may suffer as a result of or in connection with the App or the Site being inaccessible to you at any time or for any reason. ## 3. Services 3.1. The Company has deployed the Smart Contracts on the relevant Blockchain Network for users to utilise in accordance with these Terms. Users may directly call the functions of the Smart Contracts directly, or access them via the user interface provided by the App. 3.2. The M3M3 Smart Contracts innovate on established protocols such as “Meteora” to provide additional tooling for creators of token projects. For example, M3M3 allows project team to create and customise parameters for specialised “memecoin” liquidity pools or create staking Vaults in order to potentially share trading fees on that project’s native tokens with stakers. The SDK would allow third party projects and launchpads to easily integrate M3M3 functionality into their projects and launchpads. 3.3. Once the pools and/or Vaults are created, projects and users will be able to self-administer their digital holdings based on parameters set by the project or user. All interactions between creator teams launching projects and users on M3M3 operate in a peer-to-peer manner; these parties enter into a direct contractual relationship via the autonomous Smart Contracts and/or other smart contracts deployed by various other third party networks, and therefore creators wholly assume all responsibility towards the participating user in their project, pool or Vault. There is no further control by or interaction with the Company (or the relevant affiliate) which had deployed the Smart Contract(s). The Company and its affiliates shall in no circumstances be construed as a party to said peer-to-peer direct contractual relationship, is not liable for performance of obligations thereunder, nor does it bear any financial or commercial risk or provide any warranties or assurances in connection with the same. 3.4. The App merely provides a visual user interface allowing users to interact with Vaults and to interact with third party project teams, and does not act as an agent for any user or project. Although the App is intended to display accurate and timely information regarding Vaults and possible swaps, the App or relevant tools/information may not always be entirely accurate, complete or current and may also include technical inaccuracies or typographical errors. The pricing information data provided through the App does not represent an offer, a solicitation of an offer, or any advice regarding, or recommendation to enter into, a transaction with the Company or the App. Accordingly, users should verify all information before relying on it, and all decisions based on information contained on the App or tools/information tools are at the sole responsibility of each user. Notwithstanding any of the other provisions in these Terms, any photographs, graphic illustrations, videos, models, charts, designs, or examples on the site are strictly for information purposes only and have no contractual value nor do they form the basis of any contract with the Company. 3.5. Neither the Company, the Site nor the App provides any digital asset exchange or portfolio/fund management services in connection with the Vaults. If you choose to engage in transactions with Vaults or any other users, then such decisions and transactions and any consequences flowing therefrom are your sole responsibility. In no event shall the Company, its affiliates or their respective directors or employees be responsible or liable to you or anyone else, directly or indirectly, for any damage or loss arising from or relating to any interaction or continued interaction with Vaults, or reliance on any information provided on the Site or the App (including, without limitation, directly or indirectly resulting from errors in, omissions of or alterations to any such information). 3.6. THE APP SOLELY FUNCTIONS AS A VISUAL USER INTERFACE. IN NO CIRCUMSTANCES SHALL THE COMPANY, THE SMART CONTRACTS, THE SITE OR THE APP BE CONSTRUED AS A DIGITAL ASSET EXCHANGE, BROKER, DEALER, FUND MANAGER, FINANCIAL INSTITUTION, EXCHANGE, CUSTODIAN, ROBO-ADVISOR, INTERMEDIARY, OR CREDITOR. THE SITE DOES FACILITATE OR ARRANGE TRANSACTIONS BETWEEN BUYERS AND SELLERS, INCLUDING WITH RESPECT TO ANY TRANSACTIONS THAT OCCUR IN CONNECTION WITH ANY VAULT, WHICH TRANSACTIONS OCCUR ON THE RELEVANT BLOCKCHAIN NETWORK. THE COMPANY IS NOT A COUNTERPARTY TO ANY TRANSACTION FACILITATED BY THE SMART CONTRACTS, THE SITE OR THE APP OR FOR ANY USER OF THE SITE. NEITHER THE SMART CONTRACTS, THE SITE OR THE APP PROVIDES FINANCIAL ADVISORY, LEGAL, REGULATORY, OR TAX SERVICES DIRECTLY, INDIRECTLY, IMPLICITLY, OR IN ANY OTHER MANNER, AND YOU SHOULD NOT CONSIDER ANY CONTENT CONTAINED IN THESE TERMS OR OTHERWISE POSTED ON THE SITE TO BE A SUBSTITUTE FOR PROFESSIONAL FINANCIAL, LEGAL, REGULATORY, TAX OR OTHER ADVICE. THE COMPANY DOES NOT SUPPORT OR ENDORSE ANY VAUL OR POOL CREATED BY ANY USER OF M3M3, AND EACH SUCH CREATOR IS AN INDEPENDENT AGENT WITH NO EMPLOYMENT OR OTHER CONTRACTUAL RELATIONSHIP WITH THE COMPANY. 3.7. The Company reserves the right to suspend or terminate access to the Site or the App by any creator of Vaults or user of Vaults for any reason whatsoever (including without limitation for a breach of these Terms). You agree that the Company will not be liable to you or to any third party for any suspension or termination of any user. 3.8. Access to the Smart Contracts, the App or the Site may become degraded or unavailable during times of significant volatility or volume. This could result in the inability to interact with third-party services for periods of time and may also lead to support response time delays. The Company cannot guarantee that the Smart Contracts, the App or the Site will be available without interruption and neither do we guarantee that requests to interact with third-party services will be successful. ## 4. Fees and Payment 4.1. If you elect to interact with Vaults, all transactions will be conducted solely through the relevant Blockchain Network. We will have no insight into or control over these payments or transactions, nor do we have the ability to reverse any transactions. With that in mind, we will have no liability to you or to any third party for any claims or damages that may arise as a result of any transactions that you engage in via the App, or using the Smart Contracts, or any other transactions that you conduct via the relevant Blockchain Network. 4.2. The relevant Blockchain Network typically requires the payment of a transaction fee (a "**Transaction Fee**") for every transaction that occurs on the relevant Blockchain Network. The Transaction Fee funds the network of computers that run the decentralised network. This means that you will need to pay a Transaction Fee for each transaction that occurs via the Smart Contracts. For example, every Solana transaction requires a base fee (SOL) to compensate validators for processing the transaction. An optional prioritization fee is also available to increase the probability that the transaction is processed by the current leader (validator). 4.3. You may be subject to certain additional fees and commissions, including fees imposed by creators of Vaults for accessing and utilising the Vaults as notified to you prior to engaging with any pool or Vault. The Company also reserves the right to levy additional fees for access via the Smart Contracts, the Site or the App in the future. You agree to promptly pay all aforementioned fees and commissions.\[A1] 4.4. Notwithstanding anything in these Terms to the contrary, you will be solely responsible to pay any and all sales, use, value-added and other taxes, duties, and assessments (except taxes on the Company's net income) now or hereafter claimed or imposed by any governmental authority (collectively, "**Taxes**") associated with your use of the App (including, without limitation, any Taxes that may become payable as the result of your ownership or transfer of digital assets or interaction with any Vault, or relating to M3M3). ## 5. Intellectual Property and Content 5.1. The Company owns the Site and the App. You acknowledge and agree that the Company (or, as applicable, its affiliates) owns all legal right, title and interest in and to all other elements of the site and the App, and all intellectual property rights therein (including, without limitation, all designs, systems, methods, information, computer code, software, services, website design, "look and feel", organisation, compilation of the content, code, data and database, functionality, audio, video, text, photograph, graphics, copyright, trademarks (if any), and all other elements of the App (collectively, the "**Materials**"). You acknowledge that the Materials are protected by copyright, trade dress, patent, and trademark laws, international conventions, other relevant intellectual property and proprietary rights, and applicable laws. All Materials are the copyrighted property of The Company or its licensors, and all trademarks, service marks, and trade names associated with the App or otherwise contained in the Materials are proprietary to The Company or its licensors. Except as expressly set forth herein, your use of the App does not grant you ownership of or any other rights with respect to any content, code, data, or other Materials that you may access on or through the App. We reserve all rights in and to the Materials that are not expressly granted to you in these Terms. For the sake of clarity, you understand and agree: that (a) your interaction with Vaults or usage of the Smart Contracts, the Site or the App does not give you any rights or licenses in or to the Materials other than those expressly contained in these Terms; (b) you do not have the right to license, sell, rent, lease, transfer, assign, distribute, host, reproduce, distribute, or otherwise commercialise any elements of the Materials without our prior written consent in each case, which consent we may withhold in our sole and absolute discretion; (c) you shall not modify, make derivative works of, disassemble, reverse compile or reverse engineer any part of the Materials; and (d) you will not apply for, register, or otherwise use or attempt to use any of the Company's trademarks or service marks, or any confusingly similar marks, anywhere in the world. 5.2. By interacting with Vaults, you are granted a limited, non-exclusive, non-transferable, revocable license to use the site and the App for your personal use. Neither these Terms nor your access to the Smart Contracts, the site and the App transfers to you or any third party any rights, title or interest in or to intellectual property rights in the Materials, except for the limited access rights expressly set forth in these Terms. The Company expressly reserves all rights not granted in these Terms. There are no implied licenses granted under these Terms. 5.3. By acceptance of these Terms, you agree and acknowledge that all information and content provided by you, including your username, your contact list, Vaults created or Vaults interacted with, any messages, posts, comments or user generated content (the "**UGC**") in any communication channel (including without limitation Twitter, Discord or Telegram) shall be considered non-confidential and non-proprietary information. By providing such UGC, you specifically grant the Company a non-exclusive, irrevocable, transferable, sub-licensable, royalty-free, worldwide license to use, copy, duplicate store, present and publish all or any part of the UGC, and the Company shall be free to use such UGC in any manner or media whatsoever, on an unrestricted basis and without any attribution or royalties or other compensation to you, including, without limitation, within or outside the Site or the App, and in any digital or printed media. 5.4. You acknowledge that you shall be responsible for any UGC that you submit or transmit through the Site or the App, including your responsibility as to the legality, reliability, appropriateness, originality and copyright of any such information or material. Additionally, you represent and warrant that: (a) you own all right title and interest in any UGC provided by you, (b) such UGC does not violate any applicable laws, and (c) the posting of your UGC by us (in any manner or media whatsoever, on an unrestricted basis) does not (and will not) violate the privacy rights, publicity rights, copyright, contract rights or any other rights of any individual or make derogatory remarks regarding, defame or otherwise criticise any person or entity. You shall be solely liable for any damage resulting from any infringement or other violation of the copyright, trademarks or other proprietary rights of any individual or entity, and for any other harm or losses resulting from any UGC.\[A2] 5.5. You acknowledge and agree that any questions, comments, suggestions, ideas, feedback or other information regarding the Smart Contracts, the Site and the App ("Feedback") provided by you to us are non-confidential and should become our sole property. We should own exclusive rights, including all intellectual property rights, and should be entitled to the unrestricted use and dissemination of these Feedback to any lawful purpose, commercial, or otherwise, without acknowledgment or compensation for you. You hereby waive any moral rights to any such Feedback, and you hereby warrant that any such Feedback are original with you or that you have the right to submit such Feedback. You agree there should be no recourse against us for any alleged or actual infringement or misappropriation of any proprietary right in your Feedback. ## 6. User Terms 6.1. You agree that you are responsible for your own conduct while accessing or using the App, and for any consequences thereof. You agree to use the App only for purposes that are legal, proper and in accordance with these Terms and any applicable laws or regulations, including without limitation you may not, and may not allow any third party to: (a) send, upload, distribute or disseminate any unlawful, defamatory, harassing, abusive, fraudulent, obscene, or otherwise objectionable content; (b) distribute viruses, worms, defects, Trojan horses, corrupted files, hoaxes, or any other items of a destructive or deceptive nature; (c) impersonate another person (via the use of an email address or otherwise); (d) upload, post, transmit or otherwise make available through the App any content that infringes the intellectual proprietary rights of any party; (e) use the App to violate the legal rights (such as rights of privacy and publicity) of others; (f) engage in, promote, or encourage illegal activity (including, without limitation, money laundering); (g) interfere with other users' enjoyment of the App; (h) exploit the App for any unauthorised commercial purpose; (i) modify, adapt, translate, decompile, disassemble or reverse engineer any portion of the App; (j) attempt to bypass any measure of the Site designed to prevent or restrict access to the Site, or any portion of the Site or the App; (k) harass, intimidate, or threaten any of our employees or agents engaged in providing any portion of the Site or the App to you; (l) remove any copyright, trademark or other proprietary rights notices contained in or on the App, the Contents or any part of it; (m) reformat or frame any portion of the App; (n) display any content on the App that contains any hate-related or violent content or contains any other material, products or services that violate or encourage conduct that would violate any criminal laws, any other applicable laws, or any third party rights; (o) use any robot, spider, site search/retrieval application, or other device to retrieve or index any portion of the App or the content posted on the App, or to collect information about its users for any unauthorised purpose; (p) upload or transmit (or attempt to upload or to transmit) any material that acts as a passive or active information collection or transmission mechanism, including without limitation, clear graphics interchange formats (“gifs”), 1×1 pixels, web bugs, cookies, or other similar devices (sometimes referred to as “spyware” or “passive collection mechanisms” or “pcms”); (q) access or use the App by automated means or under false or fraudulent pretences; (r) access or use the App for the purpose of, directly or indirectly, creating or enabling a party to create a product or service that is competitive with any of our products or services; (s) use the Site, the App and the Smart Contracts to advertise or offer to sell goods and services; (t) conduct any activity that violates any applicable law, rule, or regulation concerning the integrity of trading markets, including (but not limited to) the manipulative tactics commonly known as spoofing, wash trading, cornering, accommodation trading, fictitious transactions, "money pass" (i.e. transactions without a net change in either party's open positions but with a resulting profit to one party and a loss to the other party), front-running, or pre-arranged or non-competitive transactions, or transactions designed to mislead external parties, or (u) disparage, tarnish, or otherwise harm, in our opinion, us and/or the Site, the App, and the Smart Contracts. If you engage in any of the activities prohibited by this Section 6, we may, at our sole and absolute discretion, without notice to you, and without limiting any of our other rights or remedies at law or in equity, immediately suspend or terminate your access to the Site or the App and delete your UGC from the Site. 6.2. By using the Site, the App and the Smart Contracts, you represent and warrant that: (a) you have read and understood these Terms and all documentation on the App or the Site; (b) you have good and sufficient experience and understanding of the functionality, usage, storage, transmission mechanisms and other material characteristics of cryptographic tokens, token storage mechanisms (such as token wallets), blockchain technology, blockchain-like technology and blockchain-based software systems to understand these Terms and to appreciate the risks and implications of creating or interacting with Vaults; (c) you acknowledge and agree that we may impose eligibility criteria to access certain functionality in respect of M3M3 which may require you to incur additional time and money costs; (d) you create and interact with Vaults for your own account and shall not do the same on behalf of any other entity or person; (e) your creation or interaction with Vaults complies with applicable law and regulation in your jurisdiction, and the law and regulation of any jurisdiction to which you may be subject (including, but not limited to legal capacity and any other threshold requirements for creating and interacting with Vaults, and interacting with other users of M3M3, any foreign exchange or regulatory restrictions applicable to creating and interacting with Vaults, and any governmental or other consents that may need to be obtained); (f) all information you submit will be true, accurate, current, and complete (if you provide any information that is untrue, inaccurate, not current, or incomplete, we have the right to refuse or terminate your current or future use of the Site and the App (or any portion thereof)); (g) you will maintain the accuracy of such information and promptly update such information as necessary; (h) you have the legal capacity and you agree to comply with these Terms; (i) you are not a minor in the jurisdiction in which you reside; (j) you will not use the Site, the App and the Smart Contracts for any illegal and unauthorised purpose; (k) you will not use the Site, the App and the Smart Contracts for any commercial purpose (save as approved by the Company in writing); (l) your use of the Site, the App and the Smart Contracts will not violate any applicable law or regulation; and (m) any funds or digital assets staked or deposited in Vaults are not derived from or related to any unlawful activities, including but not limited to money laundering or terrorist financing and all applicable statutes of all jurisdictions in which you are located, resident, organised or operating, and/or to which it may otherwise be subject and the rules and regulations thereunder (collectively, the "Compliance Regulations"), and you will not use the Smart Contracts, the Site or the App to finance, engage in, or otherwise support any unlawful activities or in a manner which aids or facilitates another party in the same. To the extent required by applicable laws and regulations, you shall fully comply with all Compliance Regulations. 6.3. We reserve the right to (but shall not be obliged to in any event to) conduct "Know Your Customer" and "Anti-Money Laundering" checks on you (including digital address or wallet screening) if deemed necessary by us (at our sole discretion) or such checks become required under applicable laws in any jurisdiction. Upon our request, you shall immediately provide us with information and documents that we, in our sole discretion, deem necessary or appropriate to conduct "Know Your Customer" and "Anti-Money Laundering" checks. Such documents may include, but are not limited to, passports, driver's licenses, utility bills, photographs of associated individuals, government identification cards or sworn statements before notaries or other equivalent professionals. Notwithstanding anything herein, we may, in its sole discretion, refuse to provide access to the Site or the Site to you until such requested information is provided, or in the event that, based on information available to us, you are suspected of using the Smart Contracts, the Site or the App in connection with any money laundering, terrorism financing, or any other illegal activity. In addition, we shall be entitled to use any possible efforts for preventing money laundering, terrorism financing or any other illegal activity, including without limitation blocking of your access to the Smart Contracts, the App or the Site or providing your information to any regulatory authority. 6.4. You are responsible for complying with applicable laws (including tax laws) in connection with usage of the Smart Contracts, the Site, the App or interactions with Vaults. You agree that we are not responsible for determining whether or which laws may apply to said interactions. You are advised to consult your own lawyers regarding of the legality and implications of any such activities. You are solely responsible for reporting and paying any taxes arising from your usage of the Smart Contracts, the Site, the App or interactions with Vaults. ## 7. Risks Borne by Users **IMPORTANT RISK NOTICE:** You acknowledge and agree that the Services, the Site and the App are currently in the initial development stages and there are a variety of unforeseeable risks with utilising the foregoing. In the worst scenario, this could lead to the loss of all or part of your digital assets interacting with the Services, the Site, the App or the Smart Contracts. **IF YOU DECIDE TO UTILISE SERVICES YOU EXPRESSLY ACKNOWLEDGE, ACCEPT AND ASSUME THE BELOW RISKS AND AGREE NOT TO HOLD THE COMPANY OR ANY OF THEIR AFFILIATES RESPONSIBLE FOR THE FOLLOWING RISKS:** 7.1. Using the App and interacting with Vaults carry financial risk. You acknowledge and agree that you are aware of such risks, including the following: (a) transactions relating to digital assets are very risky, and such digital assets are, by their nature, highly experimental, risky, volatile and generally irreversible. You should not make any transactional decision without first conducting your own research. You are solely and exclusively responsible for determining whether any Vault, any transaction, or strategy, or any other product or service in connection with the same is appropriate or suitable for you based on your own objectives and personal and financial situation. You acknowledge and agree that you will access and use the Smart Contracts, the Site and the App and interact with Vaults at your own risk. 7.2. You represent that you have sufficient knowledge, market sophistication, professional advice and experience to make your own evaluation of the merits and risks of any interaction with Vaults and the underlying digital assets. You accept all consequences of participating in such interactions, including the risk that you may lose access to your digital assets indefinitely. All decisions to interact with Vaults are made solely by you. Notwithstanding anything in these Terms, the Company accepts no responsibility whatsoever for and will in no circumstances be liable to you in connection with any interaction with Vaults and the underlying digital assets. Under no circumstances will the operation of all or any portion of the Smart Contracts, the Site or the App be deemed to create a relationship that includes any management of any assets, or the provision or tendering of investment advice. 7.3. Digital assets are not legal tender, are not backed by the government, and are not subject to any "Deposit Insurance Scheme" or protections under any banking or securities laws. The Company is not a bank and does not offer any lending services, fiduciary services, or security broking services. 7.4. The prices of blockchain assets are extremely volatile. Fluctuations in the price of other digital assets could materially and adversely affect the value of your digital assets held in Vaults, which may also be subject to significant price volatility. We cannot guarantee that any users interacting with Vaults will not lose money. 7.5. Neither the Smart Contracts, Site, the App or Vaults hold in custody, store, send, or receive any of your digital assets. This is because your digital assets exist only by virtue of the ownership record maintained on the relevant Blockchain Network. Any transfer of digital assets occurs within the relevant Blockchain Network, and not on the Smart Contracts, Site, the App or Vaults. 7.6. Public blockchain-based transactions (including but not limited to transactions automatically executed by smart contracts) are generally considered irreversible when confirmed. Any transaction that will interact with smart contracts or be recorded on a public blockchain must be recorded with extreme caution. 7.7. All smart contracts (including the Smart Contracts) may contain security vulnerabilities, errors, failures, bugs or economic loopholes which may be exploited by third parties, causing you to suffer losses in connection with any digital assets re-deployed by Vaults. Interaction with these Smart Contracts are entirely at your own responsibility and liability, and the Company is not a party to the Smart Contracts. 7.8. No creator of any Vault will be able to guarantee the future performance of digital assets held in a Vault, any specific level of performance, the success of any strategy or your overall results from interacting with any Vaults. When reviewing the information, portfolio, performance, opinions of these creators, do not assume that such party is unbiased, independent or qualified to provide financial information or opinions. Past performance and risk scores have many inherent limitations and are not indicative of future results. No representation or guarantee is being made that any creator of Vaults will or is likely to achieve gains or losses similar to the past performance. The actual percentage gains or losses experienced by users will vary depending on many factors. 7.9. Hackers or other malicious groups or organisations may attempt to interfere with the Smart Contracts, the Site, the App or Vaults in a variety of ways, including, but not limited to, malware attacks, denial of service attacks, consensus-based attacks, Sybil attacks, smurfing and spoofing, which may result in losses incurred by you. Furthermore, because the relevant Blockchain Network comprises open-source software, there is the risk that the software underlying the Services may contain intentional or unintentional bugs or weaknesses that may negatively affect the Services or the Smart Contracts, or result in the loss of the user’s digital assets, or the loss of the user’s ability to access or control their digital assets. In the event of such a software bug or weakness, there may be no remedy, and users are not guaranteed any remedy, refund or compensation. 7.10. Further, when you interact with Vaults or trade on any blockchain network, you accept that there is the inherent risk of the transaction being vulnerable to automated software programs (MEV bots) deployed by third parties which operate within decentralized finance (DeFi) ecosystem and exploit blockchain mechanics such as transaction ordering and transaction fee/gas price bidding to gain an advantage over specific users, or automated software programs (sniper bots) which executes trades buys or front-runs orders in respect of digital assets as soon as they are available on centralised or decentralised exchanges, which may be deployed by bad actors in connection with market manipulation or insider trading activities. The Company cannot be responsibility for losses suffered due to any of the foregoing, which are inherent to transactions on open blockchain networks. 7.11. The regulatory status of digital assets, and distributed ledger technology is unclear or unsettled in many jurisdictions. While every effort has been taken to ensure that the Services, the Site, the App and the Smart Contracts are compliant with local laws, it is difficult to predict how or whether regulatory agencies may apply existing regulation with respect to the same. It is likewise difficult to predict how or whether legislatures or regulatory agencies may implement changes to law and regulation affecting distributed ledger technology and its applications, including the Services, the Site, the App or the Smart Contracts. Regulatory actions could negatively impact the Company in various ways, and thus the Services may not be available in certain areas. 7.12. The underlying smart contracts run on a variety of supported blockchain networks, using specially-developed smart contracts. Accordingly, upgrades to the relevant Blockchain Network, a hard fork in the relevant Blockchain Network, re-organisations of blockchain structure or blocks, or a change in how transactions are confirmed on the relevant Blockchain Network may have unintended, adverse effects on the smart contracts built thereon, including the Smart Contracts. 7.13. The Site, Services and Smart Contracts may rely on or utilise a variety of external third party services or software, including without limitation decentralised cloud storage services, analytics tools, oracles, hence therefore the Services may be adversely affected by any number of risks related to these third party services/software, which may be compromised in the event of security vulnerabilities, cyberattacks, malicious activity, or technical interruptions. ## 8. External Sites The Site or the App may include hyperlinks to other web sites or resources (collectively, "External Sites"), which are provided solely for your convenience. We have no control over any External Sites. You acknowledge and agree that we are not responsible for the availability of any External Sites, and that we do not endorse any advertising, products or other materials on or made available from any External Sites. Furthermore, you acknowledge and agree that we are not liable for any loss or damage which may be incurred as a result of the availability or unavailability of the External Sites, or as a result of any reliance placed by you upon the completeness, accuracy or existence of any advertising, products or other materials on, or made available from, any External Sites. ## 9. Disclaimers 9.1. YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR ACCESS TO AND USE OF THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS IS AT YOUR SOLE RISK, AND THAT THE APP IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED. TO THE FULLEST EXTENT PERMISSIBLE PURSUANT TO APPLICABLE LAW, THE COMPANY, ITS SUBSIDIARIES, AFFILIATES, AND LICENSORS MAKE NO EXPRESS WARRANTIES AND HEREBY DISCLAIM ALL IMPLIED WARRANTIES REGARDING THE APP AND ANY PART OF IT (INCLUDING, WITHOUT LIMITATION, THE SMART CONTRACTS, THE SITE, THE APP, VAULTS, OR ANY EXTERNAL WEBSITES), INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, CORRECTNESS, ACCURACY, OR RELIABILITY. WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE COMPANY, ITS SUBSIDIARIES, AFFILIATES, AND LICENSORS DO NOT REPRESENT OR WARRANT TO YOU THAT: (A) YOUR ACCESS TO OR USE OF THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS WILL MEET YOUR REQUIREMENTS, (B) YOUR ACCESS TO OR USE OF THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS WILL BE UNINTERRUPTED, TIMELY, SECURE OR FREE FROM ERROR, (C) USAGE DATA PROVIDED THROUGH THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS WILL BE ACCURATE, (D) THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS, OR ANY CONTENT, SERVICES, OR FEATURES MADE AVAILABLE ON OR THROUGH THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS, OR (E) THAT ANY DATA THAT YOU DISCLOSE WHEN YOU USE THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS WILL BE SECURE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES IN CONTRACTS WITH CONSUMERS, SO SOME OR ALL OF THE ABOVE EXCLUSIONS MAY NOT APPLY TO YOU. 9.2. YOU ACCEPT THE INHERENT SECURITY RISKS OF PROVIDING INFORMATION AND DEALING ONLINE OVER THE INTERNET, AND AGREE THAT THE COMPANY HAS NO LIABILITY OR RESPONSIBILITY FOR ANY BREACH OF SECURITY UNLESS IT IS DUE TO THE COMPANY'S WILFUL DEFAULT. 9.3. DIGITAL ASSETS ARE INTANGIBLE DIGITAL ASSETS THAT EXIST ONLY BY VIRTUE OF THE OWNERSHIP RECORD MAINTAINED IN THE RELEVANT BLOCKCHAIN NETWORK. ALL SMART CONTRACTS IN CONNECTION WITH M3M3 ECOSYSTEM ARE DEPLOYED ON AND INTERACTIONS/TRANSACTIONS WITH THE SAME OCCUR ON THE DECENTRALISED LEDGER WITHIN THE RELEVANT BLOCKCHAIN NETWORK. WE HAVE NO CONTROL OVER AND MAKE NO GUARANTEES OR PROMISES WITH RESPECT TO SMART CONTRACTS. 9.4. THE COMPANY IS NOT RESPONSIBLE FOR LOSSES DUE TO BLOCKCHAINS OR ANY OTHER FEATURES OF THE RELEVANT BLOCKCHAIN NETWORK OR YOUR SELECTED ELECTRONIC WALLET SERVICE, INCLUDING BUT NOT LIMITED TO LATE REPORT BY DEVELOPERS OR REPRESENTATIVES (OR NO REPORT AT ALL) OF ANY ISSUES WITH THE BLOCKCHAIN SUPPORTING THE RELEVANT BLOCKCHAIN NETWORK, INCLUDING FORKS, TECHNICAL NODE ISSUES, OR ANY OTHER ISSUES HAVING FUND LOSSES AS A RESULT. ## 10. Limitation of Liability 10.1. YOU UNDERSTAND AND AGREE THAT WE, OUR SUBSIDIARIES, AFFILIATES, AND LICENSORS WILL NOT BE LIABLE TO YOU OR TO ANY THIRD PARTY FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR EXEMPLARY DAMAGES WHICH YOU MAY INCUR IN CONNECTION WITH THE SMART CONTRACTS, THE SITE, THE APP OR VAULTS, HOWSOEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, INCLUDING, WITHOUT LIMITATION, ANY LOSS OF PROFITS (WHETHER INCURRED DIRECTLY OR INDIRECTLY), LOSS OF GOODWILL OR BUSINESS REPUTATION, LOSS OF DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR ANY OTHER INTANGIBLE LOSS, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 10.2. YOU AGREE THAT OUR TOTAL, AGGREGATE LIABILITY TO YOU FOR ANY AND ALL CLAIMS ARISING OUT OF OR RELATING TO THESE TERMS OR YOUR ACCESS TO OR USE OF (OR YOUR INABILITY TO ACCESS OR USE) ANY PORTION OF THE SMART CONTRACTS, THE SITE, THE APP OR VAULTS, WHETHER IN CONTRACT, TORT, STRICT LIABILITY, OR ANY OTHER LEGAL THEORY, IS LIMITED TO THE LOWER OF (A) THE AMOUNTS YOU ACTUALLY PAID US UNDER THESE TERMS IN THE 12 MONTH PERIOD PRECEDING THE DATE THE CLAIM AROSE, OR (B) US\$200. 10.3. YOU ACKNOWLEDGE AND AGREE THAT WE HAVE MADE THE SMART CONTRACTS, THE SITE, THE APP AND VAULTS AVAILABLE TO YOU AND ENTERED INTO THESE TERMS IN RELIANCE UPON THE WARRANTY DISCLAIMERS AND LIMITATIONS OF LIABILITY SET FORTH HEREIN, WHICH REFLECT A REASONABLE AND FAIR ALLOCATION OF RISK BETWEEN THE PARTIES AND FORM AN ESSENTIAL BASIS OF THE BARGAIN BETWEEN US. WE WOULD NOT BE ABLE TO PROVIDE THE APP TO YOU WITHOUT THESE LIMITATIONS. 10.4. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, AND SOME JURISDICTIONS ALSO LIMIT DISCLAIMERS OR LIMITATIONS OF LIABILITY FOR PERSONAL INJURY FROM CONSUMER PRODUCTS, SO THE ABOVE LIMITATIONS MAY NOT APPLY TO PERSONAL INJURY CLAIMS. ## 11. Indemnity You agree to hold harmless and indemnify the Company and its subsidiaries, affiliates, officers, agents, employees, advertisers, licensors, suppliers or partners from and against any claim, liability, loss, damage (actual and consequential) of any kind or nature, suit, judgment, litigation cost, and attorneys' fees arising out of or in any way related to (a) your breach of these Terms, (b) your misuse of the Smart Contracts, the Site, the App or the Vaults, or (c) your violation of any applicable laws, rules or regulations in connection with your access to or use of the App. You agree that the Company will have control of the defence or settlement of any such claims. ## 12. Privacy Policy 12.1. Our Privacy Policy describes the ways the Company collects, uses, stores and discloses your personal information, and is hereby incorporated by this reference into these Terms. You agree to the collection, use, storage, and disclosure of your data in accordance with the aforementioned Privacy Policy. 12.2. The Company will maintain certain data that you transmit to the Site and the App for the purpose of managing the performance of the Site and the App, as well as data relating to your use of the Site or the App. Although we perform regular routine backups of data, the Company is solely responsible for all data that you transmit or that release to any activity you have undertaken using the Site or the App. You agree that we shall have no liability to you for any loss or corruption of any such data, and you hereby waive any right of action against us arising from any such loss or corruption of such data. ## 13. Consent to Electronic Disclosures and Signatures 13.1. Because the Company operates only on the Internet, it is necessary for you to consent to transact business with us online and electronically. As part of doing business with us, therefore, we also need you to consent to our providing you certain disclosures electronically via the Site. By agreeing to these Terms, you agree to receive electronically all documents, communications, notices, contracts, and agreements arising from or relating to your use of the Site and Services. 13.2. By accepting these Terms or contacting us in any manner, you expressly consent to be contacted by us, our agents, representatives, affiliates, or anyone calling on our behalf for any and all purposes, in any way, including notifications, messages and/or calls delivered using automated systems. Notwithstanding the aforementioned, any form of communication from the Company will be provided to you electronically through the Site or (if applicable) via email to the email address provided. If you require paper copies of any agreements or disclosures, you may print such documents desired. 13.3. Your consent to receive disclosures and transact business electronically, and our agreement to do so, applies to any transactions to which such disclosures relate, whether between you and the Company or a third party by and through the Services. Your consent will remain in effect for so long as you are a user and, if you are no longer a user, will continue until such a time as all disclosures relevant to Services received through the Site. 13.4. You may withdraw your consent to receive agreements or disclosures electronically by contacting us at [meteora\_support@meteora.ag](mailto:meteora_support@meteora.ag). However, once you have withdrawn your consent you will not be able to access the Services or the Site. ## 14. Governing Law and Dispute Resolution 14.1. These Terms will be governed by and construed in accordance with the laws of the British Virgin Islands, without regard to conflict of law rules and principles (whether of the British Virgin Islands or any other jurisdiction) that would cause the application of the laws of any other jurisdiction. 14.2. All disputes arising out of or in connection with these Terms (including without limitation the enforceability of this Section 14 or any question regarding its existence, validity or termination, your access or use of the App, the Site, or the Smart Contracts, or to any products sold or distributed through the App, the Site, or the Smart Contracts) shall be referred to and finally resolved by arbitration administered by arbitration in accordance with the BVI IAC Arbitration Rules for the time being in force, which rules are deemed to be incorporated by reference in this Section 14. The place of arbitration shall be Road Town, Tortola, British Virgin Islands, unless the Parties agree otherwise. The number of arbitrators shall be one. The language to be used in the arbitral proceedings shall be English. The award of the arbitrator will be final and binding, and any judgment on the award rendered by the arbitrator may be entered in any court of competent jurisdiction. Each party will cover its own fees and costs associated with the arbitration proceedings. Notwithstanding the foregoing, the Company may seek and obtain injunctive relief in any jurisdiction in any court of competent jurisdiction, and you agree that these Terms are specifically enforceable by the Company through injunctive relief and other equitable remedies without proof of monetary damages. ## 15. Notices To give us notice under these Terms, the user must contact the Company by email at **[meteora\_support@meteora.ag](mailto:meteora_support@meteora.ag)** ## 16. Entire Agreement These Terms constitute the entire legal agreement between you and the Company, govern your access to and use of the Smart Contracts, the Site, the App or the Vaults, and completely replace any prior or contemporaneous agreements between the parties related to your access to or use of the Smart Contracts, the Site, the App or the Vaults, whether oral or written. ## 17. Force Majeure The Company shall not be liable for delays, failure in performance or interruption of service which result directly or indirectly from any cause or condition beyond its reasonable control, including but not limited to, significant market volatility, any delay or failure due to any act of God, act of civil or military authorities, act of terrorists, civil disturbance, war, strike or other labour dispute, fire, interruption in telecommunications or Internet services or network provider services, failure of equipment and/or software, other catastrophe or any other occurrence which is beyond its reasonable control, and shall not affect the validity and enforceability of any remaining provisions. ## 18. Third Party Rights There are no third party beneficiaries to these Terms. A person who is not a party under these Terms has no right under any applicable law to enforce or to enjoy the benefit of these Terms. ## 19. No Agency or Partnership Nothing in these Terms create any agency, partnership, joint venture or any similar relationship between the Company and you, nor cause the Company and you to be deemed acting in concert in any respect. ## 20. Interpretation The language in these Terms will be interpreted as to its fair meaning, and not strictly for or against any party. ## 21. Assignment You may not assign any or your rights or obligations under these Terms, whether by operation of law or otherwise, without our prior written consent. Notwithstanding anything contained herein, we may assign our rights and obligations under these Terms in our sole discretion (without your consent) to an affiliate for any reason, including without limitation any assignment or novation in connection with a reincorporation to change the Company's domicile. ## 22. Illegality Should any provision or part-provision of these Terms is or becomes invalid, illegal or unenforceable in any respect under any law of any jurisdiction, it shall be deemed modified to the minimum extent necessary to make it valid, legal and enforceable; if such modification is not possible, the relevant provision or part-provision shall be deemed deleted. Any modification to or deletion of a provision or part-provision pursuant to this Section 22 shall not affect or impair the validity and enforceability of the rest of these Terms, nor the validity and enforceability of such provision or part-provision under the law of any other jurisdiction. ## 23. Waiver Our failure to enforce any provision of these Terms will not be deemed a waiver of such provision, nor of the right to enforce such provision. ## 24. Severability If any provision of these Terms shall be determined to be invalid or unenforceable under any rule, law, or regulation of any local, state, or federal government agency, such provision will be changed and interpreted to accomplish the objectives of the provision to the greatest extent possible under any applicable law and the validity or enforceability of any other provision of these Terms shall not be affected. If such construction is not possible, the invalid or unenforceable portion will be severed from these Terms but the rest of these Terms will remain in full force and effect. ## 25. Survival The following provisions of these Terms shall survive termination of your use or access to the Site: Sections 5, 9, 10, 11, 14, and any other provision that by its terms survives termination of your use or access to the Site. ## 26. English Language Notwithstanding any other provision of these Terms, any translation of these Terms is provided for your convenience. The meanings of terms, conditions, and representations herein are subject to their definitions and interpretations in the English language. In the event of conflict or ambiguity between the English language version and translated versions of these terms, the English language version shall prevail. You acknowledge that you have read and understood the English language version of these Terms. # Terms of Service Source: https://docs.meteora.ag/legal/terms-of-service Meteora is a distributed set of specially-developed smart contracts (each, a "Smart Contract") deployed on the Solana blockchain or such other compatible blockchain network, as the case may be (each, the "relevant Blockchain Network") which allows any user to trade digital asset pairs directly in a peer-to-peer manner via Liquidity Pools (as defined herein). The Dynamic Liquidity Market Maker (DLMM) Smart Contracts underlying Meteora offer a variety of innovations to decentralised exchanges, for example high capital efficiency (supporting high volume trading with low liquidity requirements through the concentrating of tokens at or around the current market value), zero slippage (swap tokens with zero slippage or price impact within active bin), dynamic fees (liquidity providers earn dynamic swap fees during high market volatility to compensate for impermanent loss) and flexible liquidity (liquidity providers can build Liquidity Pools with flexible liquidity distributions according to their volatility strategies, e.g. single-sided liquidity with only one token). The Liquidity Pools and Meteora may be visualised on a user interface that the user can interact with, including but not limited to the website at [https://www.meteora.ag/](https://www.meteora.ag/) and each of their subdomains, or our mobile or web applications (the "Site"). The Smart Contracts and the Site are collectively referred to in these Terms as (the "App"). Using the App, users can interact with the underlying Smart Contracts to create Liquidity Pools, view their Liquidity Pools created or accessed, and interact with other users in Meteora ecosystem. The Company's sole role is the deployment of the Smart Contracts, and accordingly any interaction with Liquidity Pools take place solely on the relevant Blockchain Network. It is important that you understand that smart contract protocols such as Meteora simply comprise a set of autonomous blockchain-based smart contracts deployed on the relevant Blockchain Network, operated directly by users calling functions on it (which allows them to interact with other users in a multi-party peer-to-peer manner). There is no further control by or interaction with the original entity which had deployed the smart contract (i.e. the Company), which entity solely functions as a provider of technical tools for users, and is not offering any sort of securities product or regulated service nor does it hold any user assets on custody. Any rewards earned by user interactions arise solely out of their involvement in the protocol by taking on the risk of interacting with other users and the ecosystem. Meteora Nova Limited (the "Company", "we", "our" or "us") is making the App available to you. Before you use the App, the Smart Contracts, or the Site, however, you will need to agree to these Terms of Use and any terms and conditions incorporated herein by reference (collectively, these "Terms"). PLEASE READ THESE TERMS CAREFULLY BEFORE USING THE APP, THE SMART CONTRACTS, OR THE SITE. THESE TERMS GOVERN YOUR USE OF THE APP, THE SMART CONTRACTS, AND THE SITE, UNLESS WE HAVE EXECUTED A SEPARATE WRITTEN AGREEMENT WITH YOU FOR THAT PURPOSE. WE ARE ONLY WILLING TO MAKE THE APP, THE SMART CONTRACTS, AND THE SITE AVAILABLE TO YOU IF YOU ACCEPT ALL OF THESE TERMS. BY USING THE APP, THE SMART CONTRACTS, THE SITE, OR ANY PART OF THEM, OR BY CLICKING "I ACCEPT" BELOW OR INDICATING YOUR ACCEPTANCE IN AN ADJOINING BOX, YOU ARE CONFIRMING THAT YOU UNDERSTAND AND AGREE TO BE BOUND BY ALL OF THESE TERMS. IF YOU ARE ACCEPTING THESE TERMS ON BEHALF OF A COMPANY OR OTHER LEGAL ENTITY, YOU REPRESENT THAT YOU HAVE THE LEGAL AUTHORITY TO ACCEPT THESE TERMS ON THAT ENTITY’S BEHALF, IN WHICH CASE "YOU" WILL MEAN THAT ENTITY. IF YOU DO NOT HAVE SUCH AUTHORITY, OR IF YOU DO NOT ACCEPT ALL OF THESE TERMS, THEN WE ARE UNWILLING TO MAKE THE APP, THE SMART CONTRACTS, OR THE SITE AVAILABLE TO YOU. IF YOU DO NOT AGREE TO THESE TERMS, YOU MAY NOT ACCESS OR USE THE APP, THE SMART CONTRACTS, OR THE SITE. By clicking "I Accept" or otherwise indicating your Acceptance, you agree to be bound by these Terms and affirm that you are of legal age to enter into these Terms where you live and have the legal capacity to enter into these Terms. Without limiting the foregoing, by using the App, you acknowledge and understand that laws regarding digital assets, financial instruments, or investment products which may include digital assets, may vary from jurisdiction to jurisdiction, and it is your sole obligation to ensure that you fully comply with any law, regulation or directive, relevant to your jurisdiction with regard to the use of the App. For the avoidance of doubt, the ability to access the App does not necessarily mean that the App, or your activities through it, are legal under the laws, regulations or directives relevant to your jurisdiction. All of the App or the services made available through the App may not be available to all users, and we reserve the right to assess or reassess at any time your eligibility to use all or part of the App. The App does not constitute, and may not be used for the purposes of, an offer or solicitation to anyone in any jurisdiction in which such offer or solicitation is not authorised, or to any person to whom it is unlawful to make such an offer or solicitation. Supplemental terms and conditions or documents that may be posted on the App from time to time are hereby expressly incorporated herein by reference. We reserve the right, in our sole discretion, to make changes to the Terms from time to time. We will alert you of any changes by updating the “Last Updated" date of these Terms (on the first page hereof), and you waive any right to receive specific notice of each such change. It is your responsibility to periodically review these Terms to stay informed of updates. You will be subject to and will be deemed to have been made aware of and to have accepted, the changes in any revised Terms by your continued use of the Site, the App, and the Smart Contracts after the date such revised Terms are posted. *** ## Table of Contents 1. [Introduction](#1-introduction) 2. [The App](#2-the-app) 3. [Services](#3-services) 4. [Fees and Payment](#4-fees-and-payment) 5. [Intellectual Property and Content](#5-intellectual-property-and-content) 6. [User Terms](#6-user-terms) 7. [Risks Borne by Users](#7-risks-borne-by-users) 8. [External Sites](#8-external-sites) 9. [Disclaimers](#9-disclaimers) 10. [Limitation of Liability](#10-limitation-of-liability) 11. [Indemnity](#11-indemnity) 12. [Privacy Policy](#12-privacy-policy) 13. [Consent to Electronic Disclosures and Signatures](#13-consent-to-electronic-disclosures-and-signatures) 14. [Governing Law and Dispute Resolution](#14-governing-law-and-dispute-resolution) 15. [Notices](#15-notices) 16. [Entire Agreement](#16-entire-agreement) 17. [Force Majeure](#17-force-majeure) 18. [Third Party Rights](#18-third-party-rights) 19. [No Agency or Partnership](#19-no-agency-or-partnership) 20. [Interpretation](#20-interpretation) 21. [Assignment](#21-assignment) 22. [Illegality](#22-illegality) 23. [Waiver](#23-waiver) 24. [Severability](#24-severability) 25. [Survival](#25-survival) 26. [English Language](#26-english-language) *** ## 1. Introduction 1. To be eligible to use the App, the Smart Contracts, the Site and the Services (as defined below), you must be of legal age to enter into these Terms where you live and have the legal capacity to enter into these Terms. The App, the Smart Contracts, the Site and the Services is strictly NOT offered to persons or entities who reside in, are citizens of, are incorporated in, or have a registered office in any Restricted Territory, as defined below (any such person or entity from a Restricted Territory shall be a Restricted Person). If you are a Restricted Person, then do not attempt to access or use the App, the Smart Contracts, the Site or the Services. Use of a virtual private network (e.g., a VPN) or other means by Restricted Persons to access or use the App, the Smart Contracts, the Site or the Services is prohibited. **Restricted Territory** means the British Virgin Islands, the United States, China, Myanmar (Burma), Cote D'Ivoire (Ivory Coast), Cuba, Crimea and Sevastopol, Democratic Republic of Congo, Iran, Iraq, Libya, Mali, Nicaragua, Democratic People’s Republic of Korea (North Korea), Somalia, Sudan, Syria, Yemen, Zimbabwe, Russia, or any other state, country or region that is subject to sanctions enforced by the United States or the European Union. 2. The App, the Smart Contracts, the Site or the Services made available through the App (or any portion thereof) may not be available to all users, and we reserve the right to assess or reassess at any time your eligibility to use all or part of the App, the Smart Contracts, the Site or the Services. 3. The App, the Smart Contracts, the Site and the Services does not constitute, and may not be used for the purposes of, an offer or solicitation to anyone in any jurisdiction in which such offer or solicitation is not authorised, or to any person to whom it is unlawful to make such an offer or solicitation. 4. Without limiting the foregoing, by using the App, the Smart Contracts, the Site or the Services, you acknowledge and understand that laws regarding digital assets, cryptocurrency derivatives, financial instruments, or investment products which may include digital assets, may vary from jurisdiction to jurisdiction, and it is your sole obligation to ensure that you fully comply with any law, regulation or directive, relevant to your jurisdiction with regard to the use of the App, the Smart Contracts, the Site or the Services. For the avoidance of doubt, the ability to access the App, the Smart Contracts, the Site or the Services does not necessarily mean that same (or your activities through it) are legal under the laws, regulations or directives relevant to your jurisdiction. ## 2. The App 1. To most easily access the App, you may first install a web browser (such as the Google Chrome web browser) and an electronic wallet compatible with the relevant Blockchain Network, such as the Phantom or Solflare electronic wallet. These electronic wallet services provide a visual representation allowing you to interact with the relevant Blockchain Network to purchase, store, and engage in transactions with various digital assets. You will not be able to engage in any transactions on the App other than through your selected electronic wallet service, or other browsers compatible with the relevant Blockchain Network. 2. Transactions that take place via the visual user interface on the App are confirmed via the relevant Blockchain Network. You understand that your public address on the relevant Blockchain Network will be made publicly visible whenever you engage in a transaction on the App. 3. The visual user interface provided on the Website facilitates your ability to access Meteora. The interface is distinct from the decentralised Meteora network. Meteora is public, permissionless, and runs on open-source self-executing software; while the interface itself merely enables you to initiate messages to Meteora in order to perform functions or access Services thereon. The interface is one of the means of accessing Meteora, but not the exclusive means of access. 4. Meteora is a non-custodial protocol, therefore the App does not hold or control your digital assets. Any digital assets which you may acquire through the usage of the App will be held and administered solely by you through your selected electronic wallet, and we shall have no access to or responsibility in regard to such electronic wallet or digital asset held therein. It is solely your responsibility to select the wallet service provider to use in connection with the App, and your use of such electronic wallet will be subject to the governing terms of use or privacy policy of the provider of such wallet. We neither own nor control your selected electronic wallet service, Google Chrome, any electronic wallet, the relevant Blockchain Network, or any other third party site, product, or service that you might access, visit, or use for the purpose of enabling you to use the various features of the App. We will not be liable for the acts or omissions of any such third parties, nor will we be liable for any damage that you may suffer as a result of your transactions or any other interaction with any such third parties. 5. The Company will not create any hosted wallet for you or otherwise custody digital assets on your behalf, and it is your sole responsibility to maintain the security of your selected electronic wallet. In the event that you lose access to your electronic wallet, private key(s), password(s), or other method(s) of securing your wallet, all digital assets held in such wallet may be irretrievable, and the Company will be unable to assist you in any way. You hereby irrevocably waive, release and discharge all claims, whether known or unknown to you, against the Company, its affiliates and their respective shareholders, members, directors, officers, employees, agents and representatives related to your use of any wallet software, associated loss of digital assets, transaction failures, or any other defects that arise in the course of your use of your electronic wallet, including any losses that may obtain as a result of any failure of any Smart Contracts, the Site or the App. 6. The Company reserves the right to modify, suspend or discontinue, temporarily or permanently, all or any part of the Site or the App with or without notice. You agree that the Company will not be liable to you or to any third party for any modification, suspension or discontinuance of all or any part of the Site or the App. 7. The publicly deployed Smart Contracts you interact with are experimental in nature and you should not utilise the Smart Contracts or Liquidity Pools for deployment of any substantial amount of digital assets. 8. We reserve the right to disable access to the App, the Site or the interface at any time in the event of any breach of the Terms, including without limitation, if we, in our sole discretion, believe that you, at any time, fail to satisfy the eligibility requirements set forth in the Terms. Further, we reserve the right to limit or restrict access to the App or the Site by any person or entity, or within any geographic area or legal jurisdiction, at any time and at our sole discretion. We will not be liable to you for any losses or damages you may suffer as a result of or in connection with the App or the Site being inaccessible to you at any time or for any reason. ## 3. Services 1. The Company has deployed the Smart Contracts on the relevant Blockchain Network for users to utilise in accordance with these Terms. Users may directly call the functions of the Smart Contracts directly, or access them via the user interface provided by the App. 2. Meteora allows users to trade digital asset pairs directly in a peer-to-peer manner. Users will be able to act as market makers or liquidity providers for these transactions by staking/pooling their digital assets into decentralised liquidity pools (Liquidity Pools) to provide the necessary liquidity for transactions by other users. These digital assets may comprise various fungible cryptocurrencies in the market. 3. Liquidity Pools and the underlying digital asset pairings will be selected and created by liquidity providers, who allow other users to access these Liquidity Pools to conduct trades. Any party may trade and/or become a liquidity provider (LP) for a pool by depositing an equivalent value of each underlying token to the Liquidity Pool in return for pool tokens (LP tokens). All trades conducted via Meteora would be performed in a non-custodial manner and users remain in control of their digital assets. Through allocating different amounts of tokens at diverse price points, project teams are able to build their desired liquidity shape with the DLMM that best fits their liquidity provider (LP) goals. 4. All interactions between liquidity providers and traders on Meteora operate in a peer-to-peer manner. Liquidity providers and traders on Meteora enter into a direct contractual relationship via the autonomous Smart Contracts and/or other smart contracts deployed by various other third party networks, and therefore liquidity providers wholly assume all responsibility towards the user of the Liquidity Pools. There is no further control by or interaction with the Company (or the relevant affiliate) which had deployed the Smart Contract(s). The Company and its affiliates shall in no circumstances be construed as a party to said peer-to-peer direct contractual relationship, is not liable for performance of obligations thereunder, nor does it bear any financial or commercial risk or provide any warranties or assurances in connection with the same. 5. The App merely provides a visual user interface allowing users to interact with Liquidity Pools and to access liquidity provided by liquidity providers, and does not act as an agent for any of the users. Although the App is intended to display accurate and timely information regarding Liquidity Pools and possible swaps, the App or relevant tools/information may not always be entirely accurate, complete or current and may also include technical inaccuracies or typographical errors. The pricing information data provided through the App does not represent an offer, a solicitation of an offer, or any advice regarding, or recommendation to enter into, a transaction with the Company or the App. Accordingly, users should verify all information before relying on it, and all decisions based on information contained on the App or tools/information tools are at the sole responsibility of each user. Notwithstanding any of the other provisions in these Terms, any photographs, graphic illustrations, videos, models, charts, designs, or examples on the site are strictly for information purposes only and have no contractual value nor do they form the basis of any contract with the Company. 6. Neither the Company, the Site nor the App provides any digital asset exchange or portfolio/fund management services in connection with the Liquidity Pools. If you choose to engage in transactions with liquidity providers in Liquidity Pools or any other users, then such decisions and transactions and any consequences flowing therefrom are your sole responsibility. In no event shall the Company, its affiliates or their respective directors or employees be responsible or liable to you or anyone else, directly or indirectly, for any damage or loss arising from or relating to any interaction or continued interaction with Liquidity Pools, or reliance on any information provided on the Site or the App (including, without limitation, directly or indirectly resulting from errors in, omissions of or alterations to any such information). 7. THE APP SOLELY FUNCTIONS AS A VISUAL USER INTERFACE. IN NO CIRCUMSTANCES SHALL THE COMPANY, THE SMART CONTRACTS, THE SITE OR THE APP BE CONSTRUED AS A DIGITAL ASSET EXCHANGE, BROKER, DEALER, FUND MANAGER, FINANCIAL INSTITUTION, EXCHANGE, CUSTODIAN, ROBO-ADVISOR, INTERMEDIARY, OR CREDITOR. THE SITE DOES FACILITATE OR ARRANGE TRANSACTIONS BETWEEN BUYERS AND SELLERS, INCLUDING WITH RESPECT TO ANY TRANSACTIONS THAT OCCUR IN CONNECTION WITH A LIQUIDITY POOL, WHICH TRANSACTIONS OCCUR ON THE RELEVANT BLOCKCHAIN NETWORK. THE COMPANY IS NOT A COUNTERPARTY TO ANY TRANSACTION FACILITATED BY THE SMART CONTRACTS, THE SITE OR THE APP OR FOR ANY USER OF THE SITE. NEITHER THE SMART CONTRACTS, THE SITE OR THE APP PROVIDES FINANCIAL ADVISORY, LEGAL, REGULATORY, OR TAX SERVICES DIRECTLY, INDIRECTLY, IMPLICITLY, OR IN ANY OTHER MANNER, AND YOU SHOULD NOT CONSIDER ANY CONTENT CONTAINED IN THESE TERMS OR OTHERWISE POSTED ON THE SITE TO BE A SUBSTITUTE FOR PROFESSIONAL FINANCIAL, LEGAL, REGULATORY, TAX OR OTHER ADVICE. THE COMPANY DOES NOT SUPPORT OR ENDORSE ANY LIQUIDITY POOL CREATED BY ANY USER OF METEORA, AND EACH SUCH CREATOR IS AN INDEPENDENT AGENT WITH NO EMPLOYMENT OR OTHER CONTRACTUAL RELATIONSHIP WITH THE COMPANY. 8. The Company reserves the right to suspend or terminate access to the Site or the App by any creator of Liquidity Pools or user of Liquidity Pools for any reason whatsoever (including without limitation for a breach of these Terms). You agree that the Company will not be liable to you or to any third party for any suspension or termination of any user. 9. Access to the Smart Contracts, the App or the Site may become degraded or unavailable during times of significant volatility or volume. This could result in the inability to interact with third-party services for periods of time and may also lead to support response time delays. The Company cannot guarantee that the Smart Contracts, the App or the Site will be available without interruption and neither do we guarantee that requests to interact with third-party services will be successful. ## 4. Fees and Payment 1. If you elect to interact with Liquidity Pools, all transactions will be conducted solely through the relevant Blockchain Network. We will have no insight into or control over these payments or transactions, nor do we have the ability to reverse any transactions. With that in mind, we will have no liability to you or to any third party for any claims or damages that may arise as a result of any transactions that you engage in via the App, or using the Smart Contracts, or any other transactions that you conduct via the relevant Blockchain Network. 2. The relevant Blockchain Network typically requires the payment of a transaction fee (a "**Gas Fee**") for every transaction that occurs on the relevant Blockchain Network. The Gas Fee funds the network of computers that run the decentralised network. This means that you will need to pay a Gas Fee for each transaction that occurs via the Smart Contracts. 3. You may be subject to certain additional fees and commissions, including fees imposed by creators of Liquidity Pools for accessing and utilising the Liquidity Pools as notified to you prior to engaging with any digital asset swap or liquidity provision. The Company also reserves the right to levy additional fees for access via the Smart Contracts, the Site or the App in the future. You agree to promptly pay all aforementioned fees and commissions. 4. Notwithstanding anything in these Terms to the contrary, you will be solely responsible to pay any and all sales, use, value-added and other taxes, duties, and assessments (except taxes on the Company's net income) now or hereafter claimed or imposed by any governmental authority (collectively, "**Taxes**") associated with your use of the App (including, without limitation, any Taxes that may become payable as the result of your ownership or transfer of digital assets or interaction with any Liquidity Pool, or relating to Meteora). ## 5. Intellectual Property and Content 1. The Company owns the Site and the App. You acknowledge and agree that the Company (or, as applicable, its affiliates) owns all legal right, title and interest in and to all other elements of the site and the App, and all intellectual property rights therein (including, without limitation, all designs, systems, methods, information, computer code, software, services, website design, "look and feel", organisation, compilation of the content, code, data and database, functionality, audio, video, text, photograph, graphics, copyright, trademarks (if any), and all other elements of the App (collectively, the "**Materials**"). You acknowledge that the Materials are protected by copyright, trade dress, patent, and trademark laws, international conventions, other relevant intellectual property and proprietary rights, and applicable laws. All Materials are the copyrighted property of The Company or its licensors, and all trademarks, service marks, and trade names associated with the App or otherwise contained in the Materials are proprietary to The Company or its licensors. Except as expressly set forth herein, your use of the App does not grant you ownership of or any other rights with respect to any content, code, data, or other Materials that you may access on or through the App. We reserve all rights in and to the Materials that are not expressly granted to you in these Terms. For the sake of clarity, you understand and agree: that (a) your interaction with Liquidity Pools or usage of the Smart Contracts, the Site or the App does not give you any rights or licenses in or to the Materials other than those expressly contained in these Terms; (b) you do not have the right to license, sell, rent, lease, transfer, assign, distribute, host, reproduce, distribute, or otherwise commercialise any elements of the Materials without our prior written consent in each case, which consent we may withhold in our sole and absolute discretion; (c) you shall not modify, make derivative works of, disassemble, reverse compile or reverse engineer any part of the Materials; and (d) you will not apply for, register, or otherwise use or attempt to use any of the Company's trademarks or service marks, or any confusingly similar marks, anywhere in the world. 2. By interacting with Liquidity Pools, you are granted a limited, non-exclusive, non-transferable, revocable license to use the site and the App for your personal use. Neither these Terms nor your access to the Smart Contracts, the site and the App transfers to you or any third party any rights, title or interest in or to intellectual property rights in the Materials, except for the limited access rights expressly set forth in these Terms. The Company expressly reserves all rights not granted in these Terms. There are no implied licenses granted under these Terms. 3. By acceptance of these Terms, you agree and acknowledge that all information and content provided by you, including your username, your contact list, Liquidity Pools created or Liquidity Pools interacted with, any messages, posts, comments or user generated content (the "UGC") in any communication channel (including without limitation Twitter, Discord or Telegram) shall be considered non-confidential and non-proprietary information. By providing such UGC, you specifically grant the Company a non-exclusive, irrevocable, transferable, sub-licensable, royalty-free, worldwide license to use, copy, duplicate store, present and publish all or any part of the UGC, and the Company shall be free to use such UGC in any manner or media whatsoever, on an unrestricted basis and without any attribution or royalties or other compensation to you, including, without limitation, within or outside the Site or the App, and in any digital or printed media. 4. You acknowledge that you shall be responsible for any UGC that you submit or transmit through the Site or the App, including your responsibility as to the legality, reliability, appropriateness, originality and copyright of any such information or material. Additionally, you represent and warrant that: (a) you own all right title and interest in any UGC provided by you, (b) such UGC does not violate any applicable laws, and (c) the posting of your UGC by us (in any manner or media whatsoever, on an unrestricted basis) does not (and will not) violate the privacy rights, publicity rights, copyright, contract rights or any other rights of any individual or make derogatory remarks regarding, defame or otherwise criticise any person or entity. You shall be solely liable for any damage resulting from any infringement or other violation of the copyright, trademarks or other proprietary rights of any individual or entity, and for any other harm or losses resulting from any UGC. 5. You acknowledge and agree that any questions, comments, suggestions, ideas, feedback or other information regarding the Smart Contracts, the Site and the App ("Feedback") provided by you to us are non-confidential and should become our sole property. We should own exclusive rights, including all intellectual property rights, and should be entitled to the unrestricted use and dissemination of these Feedback to any lawful purpose, commercial, or otherwise, without acknowledgment or compensation for you. You hereby waive any moral rights to any such Feedback, and you hereby warrant that any such Feedback are original with you or that you have the right to submit such Feedback. You agree there should be no recourse against us for any alleged or actual infringement or misappropriation of any proprietary right in your Feedback. ## 6. User Terms 1. You agree that you are responsible for your own conduct while accessing or using the App, and for any consequences thereof. You agree to use the App only for purposes that are legal, proper and in accordance with these Terms and any applicable laws or regulations, including without limitation you may not, and may not allow any third party to: (a) send, upload, distribute or disseminate any unlawful, defamatory, harassing, abusive, fraudulent, obscene, or otherwise objectionable content; (b) distribute viruses, worms, defects, Trojan horses, corrupted files, hoaxes, or any other items of a destructive or deceptive nature; (c) impersonate another person (via the use of an email address or otherwise); (d) upload, post, transmit or otherwise make available through the App any content that infringes the intellectual proprietary rights of any party; (e) use the App to violate the legal rights (such as rights of privacy and publicity) of others; (f) engage in, promote, or encourage illegal activity (including, without limitation, money laundering); (g) interfere with other users' enjoyment of the App; (h) exploit the App for any unauthorised commercial purpose; (i) modify, adapt, translate, decompile, disassemble or reverse engineer any portion of the App; (j) attempt to bypass any measure of the Site designed to prevent or restrict access to the Site, or any portion of the Site or the App; (k) harass, intimidate, or threaten any of our employees or agents engaged in providing any portion of the Site or the App to you; (l) remove any copyright, trademark or other proprietary rights notices contained in or on the App, the Contents or any part of it; (m) reformat or frame any portion of the App; (n) display any content on the App that contains any hate-related or violent content or contains any other material, products or services that violate or encourage conduct that would violate any criminal laws, any other applicable laws, or any third party rights; (o) use any robot, spider, site search/retrieval application, or other device to retrieve or index any portion of the App or the content posted on the App, or to collect information about its users for any unauthorised purpose; (p) upload or transmit (or attempt to upload or to transmit) any material that acts as a passive or active information collection or transmission mechanism, including without limitation, clear graphics interchange formats (“gifs”), 1×1 pixels, web bugs, cookies, or other similar devices (sometimes referred to as “spyware” or “passive collection mechanisms” or “pcms”); (q) access or use the App by automated means or under false or fraudulent pretences; (r) access or use the App for the purpose of, directly or indirectly, creating or enabling a party to create a product or service that is competitive with any of our products or services; (s) use the Site, the App and the Smart Contracts to advertise or offer to sell goods and services; (t) conduct any activity that violates any applicable law, rule, or regulation concerning the integrity of trading markets, including (but not limited to) the manipulative tactics commonly known as spoofing, wash trading, cornering, accommodation trading, fictitious transactions, "money pass" (i.e. transactions without a net change in either party's open positions but with a resulting profit to one party and a loss to the other party), front-running, or pre-arranged or non-competitive transactions, or transactions designed to mislead external parties, or (u) disparage, tarnish, or otherwise harm, in our opinion, us and/or the Site, the App, and the Smart Contracts. If you engage in any of the activities prohibited by this Section 6, we may, at our sole and absolute discretion, without notice to you, and without limiting any of our other rights or remedies at law or in equity, immediately suspend or terminate your access to the Site or the App and delete your UGC from the Site. 2. By using the Site, the App and the Smart Contracts, you represent and warrant that: (a) you have read and understood these Terms and all documentation on the App or the Site; (b) you have good and sufficient experience and understanding of the functionality, usage, storage, transmission mechanisms and other material characteristics of cryptographic tokens, token storage mechanisms (such as token wallets), blockchain technology, blockchain-like technology and blockchain-based software systems to understand these Terms and to appreciate the risks and implications of creating or interacting with Liquidity Pools; (c) you acknowledge and agree that we may impose eligibility criteria to access certain functionality in respect of Meteora which may require you to incur additional time and money costs; (d) you create and interact with Liquidity Pools for your own account and shall not do the same on behalf of any other entity or person; (e) your creation or interaction with Liquidity Pools complies with applicable law and regulation in your jurisdiction, and the law and regulation of any jurisdiction to which you may be subject (including, but not limited to legal capacity and any other threshold requirements for creating and interacting with Liquidity Pools, and interacting with other users of Meteora, any foreign exchange or regulatory restrictions applicable to creating and interacting with Liquidity Pools, and any governmental or other consents that may need to be obtained); (f) all information you submit will be true, accurate, current, and complete (if you provide any information that is untrue, inaccurate, not current, or incomplete, we have the right to refuse or terminate your current or future use of the Site and the App (or any portion thereof)); (g) you will maintain the accuracy of such information and promptly update such information as necessary; (h) you have the legal capacity and you agree to comply with these Terms; (i) you are not a minor in the jurisdiction in which you reside; (j) you will not use the Site, the App and the Smart Contracts for any illegal and unauthorised purpose; (k) you will not use the Site, the App and the Smart Contracts for any commercial purpose (save as approved by the Company in writing); (l) your use of the Site, the App and the Smart Contracts will not violate any applicable law or regulation; and (m) any funds or digital assets staked or deposited in Liquidity Pools are not derived from or related to any unlawful activities, including but not limited to money laundering or terrorist financing and all applicable statutes of all jurisdictions in which you are located, resident, organised or operating, and/or to which it may otherwise be subject and the rules and regulations thereunder (collectively, the "Compliance Regulations"), and you will not use the Smart Contracts, the Site or the App to finance, engage in, or otherwise support any unlawful activities or in a manner which aids or facilitates another party in the same. To the extent required by applicable laws and regulations, you shall fully comply with all Compliance Regulations. 3. We reserve the right to (but shall not be obliged to in any event to) conduct "Know Your Customer" and "Anti-Money Laundering" checks on you (including digital address or wallet screening) if deemed necessary by us (at our sole discretion) or such checks become required under applicable laws in any jurisdiction. Upon our request, you shall immediately provide us with information and documents that we, in our sole discretion, deem necessary or appropriate to conduct "Know Your Customer" and "Anti-Money Laundering" checks. Such documents may include, but are not limited to, passports, driver's licenses, utility bills, photographs of associated individuals, government identification cards or sworn statements before notaries or other equivalent professionals. Notwithstanding anything herein, we may, in its sole discretion, refuse to provide access to the Site or the Site to you until such requested information is provided, or in the event that, based on information available to us, you are suspected of using the Smart Contracts, the Site or the App in connection with any money laundering, terrorism financing, or any other illegal activity. In addition, we shall be entitled to use any possible efforts for preventing money laundering, terrorism financing or any other illegal activity, including without limitation blocking of your access to the Smart Contracts, the App or the Site or providing your information to any regulatory authority. 4. You are responsible for complying with applicable laws (including tax laws) in connection with usage of the Smart Contracts, the Site, the App or interactions with Liquidity Pools. You agree that we are not responsible for determining whether or which laws may apply to said interactions. You are advised to consult your own lawyers regarding of the legality and implications of any such activities. You are solely responsible for reporting and paying any taxes arising from your usage of the Smart Contracts, the Site, the App or interactions with Liquidity Pools. ## 7. Risks Borne by Users **IMPORTANT RISK NOTICE:** You acknowledge and agree that the Services, the Site and the App are currently in the initial development stages and there are a variety of unforeseeable risks with utilising the foregoing. In the worst scenario, this could lead to the loss of all or part of your digital assets interacting with the Services, the Site, the App or the Smart Contracts. **IF YOU DECIDE TO UTILISE SERVICES YOU EXPRESSLY ACKNOWLEDGE, ACCEPT AND ASSUME THE BELOW RISKS AND AGREE NOT TO HOLD THE COMPANY OR ANY OF THEIR AFFILIATES RESPONSIBLE FOR THE FOLLOWING RISKS:** 2\. Using the App and interacting with Liquidity Pools carry financial risk. You acknowledge and agree that you are aware of such risks, including the following: (a) transactions relating to digital assets are very risky, and such digital assets are, by their nature, highly experimental, risky, volatile and generally irreversible. You should not make any transactional decision without first conducting your own research. You are solely and exclusively responsible for determining whether any Liquidity Pool, any transaction, or strategy, or any other product or service in connection with the same is appropriate or suitable for you based on your own objectives and personal and financial situation. You acknowledge and agree that you will access and use the Smart Contracts, the Site and the App and interact with Liquidity Pools at your own risk. 3\. You represent that you have sufficient knowledge, market sophistication, professional advice and experience to make your own evaluation of the merits and risks of any interaction with Liquidity Pools and the underlying digital assets. You accept all consequences of participating in such interactions, including the risk that you may lose access to your digital assets indefinitely. All decisions to interact with Liquidity Pools are made solely by you. Notwithstanding anything in these Terms, the Company accepts no responsibility whatsoever for and will in no circumstances be liable to you in connection with any interaction with Liquidity Pools and the underlying digital assets. Under no circumstances will the operation of all or any portion of the Smart Contracts, the Site or the App be deemed to create a relationship that includes any management of any assets, or the provision or tendering of investment advice. 4\. Digital assets are not legal tender, are not backed by the government, and are not subject to any "Deposit Insurance Scheme" or protections under any banking or securities laws. The Company is not a bank and does not offer any lending services, fiduciary services, or security broking services. 5\. The prices of blockchain assets are extremely volatile. Fluctuations in the price of other digital assets could materially and adversely affect the value of your digital assets held in Liquidity Pools, which may also be subject to significant price volatility. We cannot guarantee that any users interacting with Liquidity Pools will not lose money. 6\. Neither the Smart Contracts, Site, the App or Liquidity Pools hold in custody, store, send, or receive any of your digital assets. This is because your digital assets exist only by virtue of the ownership record maintained on the relevant Blockchain Network. Any transfer of digital assets occurs within the relevant Blockchain Network, and not on the Smart Contracts, Site, the App or Liquidity Pools. 7\. Public blockchain-based transactions (including but not limited to transactions automatically executed by smart contracts) are generally considered irreversible when confirmed. Any transaction that will interact with smart contracts or be recorded on a public blockchain must be recorded with extreme caution. 8\. All smart contracts (including the Smart Contracts) may contain security vulnerabilities, errors, failures, bugs or economic loopholes which may be exploited by third parties, causing you to suffer losses in connection with any digital assets re-deployed by Liquidity Pools. Interaction with these Smart Contracts are entirely at your own responsibility and liability, and the Company is not a party to the Smart Contracts. 9\. No creator of Liquidity Pools will be able to guarantee the future performance of digital assets held in a Liquidity Pool, any specific level of performance, the success of any strategy or your overall results from interacting with Liquidity Pools. When reviewing the information, portfolio, performance, opinions of these creators, do not assume that such party is unbiased, independent or qualified to provide financial information or opinions. Past performance and risk scores have many inherent limitations and are not indicative of future results. No representation or guarantee is being made that any creator of Liquidity Pools will or is likely to achieve gains or losses similar to the past performance. The actual percentage gains or losses experienced by users will vary depending on many factors. 10\. Hackers or other malicious groups or organisations may attempt to interfere with the Smart Contracts, the Site, the App or Liquidity Pools in a variety of ways, including, but not limited to, malware attacks, denial of service attacks, consensus-based attacks, Sybil attacks, smurfing and spoofing, which may result in losses incurred by you. Furthermore, because the relevant Blockchain Network comprises open-source software, there is the risk that the software underlying the Services may contain intentional or unintentional bugs or weaknesses that may negatively affect the Services or the Smart Contracts, or result in the loss of the user’s digital assets, or the loss of the user’s ability to access or control their digital assets. In the event of such a software bug or weakness, there may be no remedy, and users are not guaranteed any remedy, refund or compensation. 11\. Further, when you interact with Liquidity Pools or trade on any blockchain network, you accept that there is the inherent risk of the transaction being vulnerable to automated software programs (MEV bots) deployed by third parties which operate within decentralized finance (DeFi) ecosystem and exploit blockchain mechanics such as transaction ordering and gas price bidding to gain an advantage over specific users, or automated software programs (sniper bots) which executes trades buys or front-runs orders in respect of digital assets as soon as they are available on centralised or decentralised exchanges, which may be deployed by bad actors in connection with market manipulation or insider trading activities. The Company cannot be responsibility for losses suffered due to any of the foregoing, which are inherent to transactions on open blockchain networks. 12\. The regulatory status of digital assets, and distributed ledger technology is unclear or unsettled in many jurisdictions. While every effort has been taken to ensure that the Services, the Site, the App and the Smart Contracts are compliant with local laws, it is difficult to predict how or whether regulatory agencies may apply existing regulation with respect to the same. It is likewise difficult to predict how or whether legislatures or regulatory agencies may implement changes to law and regulation affecting distributed ledger technology and its applications, including the Services, the Site, the App or the Smart Contracts. Regulatory actions could negatively impact the Company in various ways, and thus the Services may not be available in certain areas. 13\. The underlying smart contracts run on a variety of supported blockchain networks, using specially-developed smart contracts. Accordingly, upgrades to the relevant Blockchain Network, a hard fork in the relevant Blockchain Network, re-organisations of blockchain structure or blocks, or a change in how transactions are confirmed on the relevant Blockchain Network may have unintended, adverse effects on the smart contracts built thereon, including the Smart Contracts. 14\. The Site, Services and Smart Contracts may rely on or utilise a variety of external third party services or software, including without limitation decentralised cloud storage services, analytics tools, oracles, hence therefore the Services may be adversely affected by any number of risks related to these third party services/software, which may be compromised in the event of security vulnerabilities, cyberattacks, malicious activity, or technical interruptions. ## 8. External Sites The Site or the App may include hyperlinks to other web sites or resources (collectively, "External Sites"), which are provided solely for your convenience. We have no control over any External Sites. You acknowledge and agree that we are not responsible for the availability of any External Sites, and that we do not endorse any advertising, products or other materials on or made available from any External Sites. Furthermore, you acknowledge and agree that we are not liable for any loss or damage which may be incurred as a result of the availability or unavailability of the External Sites, or as a result of any reliance placed by you upon the completeness, accuracy or existence of any advertising, products or other materials on, or made available from, any External Sites. ## 9. Disclaimers 1. YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR ACCESS TO AND USE OF THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS IS AT YOUR SOLE RISK, AND THAT THE APP IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED. TO THE FULLEST EXTENT PERMISSIBLE PURSUANT TO APPLICABLE LAW, THE COMPANY, ITS SUBSIDIARIES, AFFILIATES, AND LICENSORS MAKE NO EXPRESS WARRANTIES AND HEREBY DISCLAIM ALL IMPLIED WARRANTIES REGARDING THE APP AND ANY PART OF IT (INCLUDING, WITHOUT LIMITATION, THE SMART CONTRACTS, THE SITE, THE APP, LIQUIDITY POOLS, OR ANY EXTERNAL WEBSITES), INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, CORRECTNESS, ACCURACY, OR RELIABILITY. WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE COMPANY, ITS SUBSIDIARIES, AFFILIATES, AND LICENSORS DO NOT REPRESENT OR WARRANT TO YOU THAT: (A) YOUR ACCESS TO OR USE OF THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS WILL MEET YOUR REQUIREMENTS, (B) YOUR ACCESS TO OR USE OF THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS WILL BE UNINTERRUPTED, TIMELY, SECURE OR FREE FROM ERROR, (C) USAGE DATA PROVIDED THROUGH THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS WILL BE ACCURATE, (D) THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS, OR ANY CONTENT, SERVICES, OR FEATURES MADE AVAILABLE ON OR THROUGH THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS, OR (E) THAT ANY DATA THAT YOU DISCLOSE WHEN YOU USE THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS WILL BE SECURE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES IN CONTRACTS WITH CONSUMERS, SO SOME OR ALL OF THE ABOVE EXCLUSIONS MAY NOT APPLY TO YOU. 2. YOU ACCEPT THE INHERENT SECURITY RISKS OF PROVIDING INFORMATION AND DEALING ONLINE OVER THE INTERNET, AND AGREE THAT THE COMPANY HAS NO LIABILITY OR RESPONSIBILITY FOR ANY BREACH OF SECURITY UNLESS IT IS DUE TO THE COMPANY'S WILFUL DEFAULT. 3. DIGITAL ASSETS ARE INTANGIBLE DIGITAL ASSETS THAT EXIST ONLY BY VIRTUE OF THE OWNERSHIP RECORD MAINTAINED IN THE RELEVANT BLOCKCHAIN NETWORK. ALL SMART CONTRACTS IN CONNECTION WITH METEORA ECOSYSTEM ARE DEPLOYED ON AND INTERACTIONS/TRANSACTIONS WITH THE SAME OCCUR ON THE DECENTRALISED LEDGER WITHIN THE RELEVANT BLOCKCHAIN NETWORK. WE HAVE NO CONTROL OVER AND MAKE NO GUARANTEES OR PROMISES WITH RESPECT TO SMART CONTRACTS. 4. THE COMPANY IS NOT RESPONSIBLE FOR LOSSES DUE TO BLOCKCHAINS OR ANY OTHER FEATURES OF THE RELEVANT BLOCKCHAIN NETWORK OR YOUR SELECTED ELECTRONIC WALLET SERVICE, INCLUDING BUT NOT LIMITED TO LATE REPORT BY DEVELOPERS OR REPRESENTATIVES (OR NO REPORT AT ALL) OF ANY ISSUES WITH THE BLOCKCHAIN SUPPORTING THE RELEVANT BLOCKCHAIN NETWORK, INCLUDING FORKS, TECHNICAL NODE ISSUES, OR ANY OTHER ISSUES HAVING FUND LOSSES AS A RESULT. ## 10. Limitation of Liability 1. YOU UNDERSTAND AND AGREE THAT WE, OUR SUBSIDIARIES, AFFILIATES, AND LICENSORS WILL NOT BE LIABLE TO YOU OR TO ANY THIRD PARTY FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR EXEMPLARY DAMAGES WHICH YOU MAY INCUR IN CONNECTION WITH THE SMART CONTRACTS, THE SITE, THE APP OR LIQUIDITY POOLS, HOWSOEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, INCLUDING, WITHOUT LIMITATION, ANY LOSS OF PROFITS (WHETHER INCURRED DIRECTLY OR INDIRECTLY), LOSS OF GOODWILL OR BUSINESS REPUTATION, LOSS OF DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR ANY OTHER INTANGIBLE LOSS, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 2. YOU AGREE THAT OUR TOTAL, AGGREGATE LIABILITY TO YOU FOR ANY AND ALL CLAIMS ARISING OUT OF OR RELATING TO THESE TERMS OR YOUR ACCESS TO OR USE OF (OR YOUR INABILITY TO ACCESS OR USE) ANY PORTION OF THE SMART CONTRACTS, THE SITE, THE APP OR LIQUIDITY POOLS, WHETHER IN CONTRACT, TORT, STRICT LIABILITY, OR ANY OTHER LEGAL THEORY, IS LIMITED TO THE LOWER OF (A) THE AMOUNTS YOU ACTUALLY PAID US UNDER THESE TERMS IN THE 12 MONTH PERIOD PRECEDING THE DATE THE CLAIM AROSE, OR (B) US\$200. 3. YOU ACKNOWLEDGE AND AGREE THAT WE HAVE MADE THE SMART CONTRACTS, THE SITE, THE APP AND LIQUIDITY POOLS AVAILABLE TO YOU AND ENTERED INTO THESE TERMS IN RELIANCE UPON THE WARRANTY DISCLAIMERS AND LIMITATIONS OF LIABILITY SET FORTH HEREIN, WHICH REFLECT A REASONABLE AND FAIR ALLOCATION OF RISK BETWEEN THE PARTIES AND FORM AN ESSENTIAL BASIS OF THE BARGAIN BETWEEN US. WE WOULD NOT BE ABLE TO PROVIDE THE APP TO YOU WITHOUT THESE LIMITATIONS. 4. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, AND SOME JURISDICTIONS ALSO LIMIT DISCLAIMERS OR LIMITATIONS OF LIABILITY FOR PERSONAL INJURY FROM CONSUMER PRODUCTS, SO THE ABOVE LIMITATIONS MAY NOT APPLY TO PERSONAL INJURY CLAIMS. ## 11. Indemnity You agree to hold harmless and indemnify the Company and its subsidiaries, affiliates, officers, agents, employees, advertisers, licensors, suppliers or partners from and against any claim, liability, loss, damage (actual and consequential) of any kind or nature, suit, judgment, litigation cost, and attorneys' fees arising out of or in any way related to (a) your breach of these Terms, (b) your misuse of the Smart Contracts, the Site, the App or the Liquidity Pools, or (c) your violation of any applicable laws, rules or regulations in connection with your access to or use of the App. You agree that the Company will have control of the defence or settlement of any such claims. ## 12. Privacy Policy 1. Our [Privacy Policy](/legal/privacy-policy) describes the ways the Company collects, uses, stores and discloses your personal information, and is hereby incorporated by this reference into these Terms. You agree to the collection, use, storage, and disclosure of your data in accordance with the aforementioned Privacy Policy. 2. The Company will maintain certain data that you transmit to the Site and the App for the purpose of managing the performance of the Site and the App, as well as data relating to your use of the Site or the App. Although we perform regular routine backups of data, the Company is solely responsible for all data that you transmit or that release to any activity you have undertaken using the Site or the App. You agree that we shall have no liability to you for any loss or corruption of any such data, and you hereby waive any right of action against us arising from any such loss or corruption of such data. ## 13. Consent to Electronic Disclosures and Signatures 1. Because the Company operates only on the Internet, it is necessary for you to consent to transact business with us online and electronically. As part of doing business with us, therefore, we also need you to consent to our providing you certain disclosures electronically via the Site. By agreeing to these Terms, you agree to receive electronically all documents, communications, notices, contracts, and agreements arising from or relating to your use of the Site and Services. 2. By accepting these Terms or contacting us in any manner, you expressly consent to be contacted by us, our agents, representatives, affiliates, or anyone calling on our behalf for any and all purposes, in any way, including notifications, messages and/or calls delivered using automated systems. Notwithstanding the aforementioned, any form of communication from the Company will be provided to you electronically through the Site or (if applicable) via email to the email address provided. If you require paper copies of any agreements or disclosures, you may print such documents desired. 3. Your consent to receive disclosures and transact business electronically, and our agreement to do so, applies to any transactions to which such disclosures relate, whether between you and the Company or a third party by and through the Services. Your consent will remain in effect for so long as you are a user and, if you are no longer a user, will continue until such a time as all disclosures relevant to Services received through the Site. 4. You may withdraw your consent to receive agreements or disclosures electronically by contacting us at [meteora\_support@meteora.ag](mailto:meteora_support@meteora.ag). However, once you have withdrawn your consent you will not be able to access the Services or the Site. ## 14. Governing Law and Dispute Resolution 1. These Terms will be governed by and construed in accordance with the laws of the British Virgin Islands, without regard to conflict of law rules and principles (whether of the British Virgin Islands or any other jurisdiction) that would cause the application of the laws of any other jurisdiction. 2. All disputes arising out of or in connection with these Terms (including without limitation the enforceability of this Section 14 or any question regarding its existence, validity or termination, your access or use of the App, the Site, or the Smart Contracts, or to any products sold or distributed through the App, the Site, or the Smart Contracts) shall be referred to and finally resolved by arbitration administered by arbitration in accordance with the BVI IAC Arbitration Rules for the time being in force, which rules are deemed to be incorporated by reference in this Section 14. The place of arbitration shall be Road Town, Tortola, British Virgin Islands, unless the Parties agree otherwise. The number of arbitrators shall be one. The language to be used in the arbitral proceedings shall be English. The award of the arbitrator will be final and binding, and any judgment on the award rendered by the arbitrator may be entered in any court of competent jurisdiction. Each party will cover its own fees and costs associated with the arbitration proceedings. Notwithstanding the foregoing, the Company may seek and obtain injunctive relief in any jurisdiction in any court of competent jurisdiction, and you agree that these Terms are specifically enforceable by the Company through injunctive relief and other equitable remedies without proof of monetary damages. ## 15. Notices To give us notice under these Terms, the user must contact the Company by email at [meteora\_support@meteora.ag](mailto:meteora_support@meteora.ag) ## 16. Entire Agreement These Terms constitute the entire legal agreement between you and the Company, govern your access to and use of the Smart Contracts, the Site, the App or the Liquidity Pools, and completely replace any prior or contemporaneous agreements between the parties related to your access to or use of the Smart Contracts, the Site, the App or the Liquidity Pools, whether oral or written. ## 17. Force Majeure The Company shall not be liable for delays, failure in performance or interruption of service which result directly or indirectly from any cause or condition beyond its reasonable control, including but not limited to, significant market volatility, any delay or failure due to any act of God, act of civil or military authorities, act of terrorists, civil disturbance, war, strike or other labour dispute, fire, interruption in telecommunications or Internet services or network provider services, failure of equipment and/or software, other catastrophe or any other occurrence which is beyond its reasonable control, and shall not affect the validity and enforceability of any remaining provisions. ## 18. Third Party Rights There are no third party beneficiaries to these Terms. A person who is not a party under these Terms has no right under any applicable law to enforce or to enjoy the benefit of these Terms. ## 19. No Agency or Partnership Nothing in these Terms create any agency, partnership, joint venture or any similar relationship between the Company and you, nor cause the Company and you to be deemed acting in concert in any respect. ## 20. Interpretation The language in these Terms will be interpreted as to its fair meaning, and not strictly for or against any party. ## 21. Assignment You may not assign any or your rights or obligations under these Terms, whether by operation of law or otherwise, without our prior written consent. Notwithstanding anything contained herein, we may assign our rights and obligations under these Terms in our sole discretion (without your consent) to an affiliate for any reason, including without limitation any assignment or novation in connection with a reincorporation to change the Company's domicile. ## 22. Illegality Should any provision or part-provision of these Terms is or becomes invalid, illegal or unenforceable in any respect under any law of any jurisdiction, it shall be deemed modified to the minimum extent necessary to make it valid, legal and enforceable; if such modification is not possible, the relevant provision or part-provision shall be deemed deleted. Any modification to or deletion of a provision or part-provision pursuant to this Section 22 shall not affect or impair the validity and enforceability of the rest of these Terms, nor the validity and enforceability of such provision or part-provision under the law of any other jurisdiction. ## 23. Waiver Our failure to enforce any provision of these Terms will not be deemed a waiver of such provision, nor of the right to enforce such provision. ## 24. Severability If any provision of these Terms shall be determined to be invalid or unenforceable under any rule, law, or regulation of any local, state, or federal government agency, such provision will be changed and interpreted to accomplish the objectives of the provision to the greatest extent possible under any applicable law and the validity or enforceability of any other provision of these Terms shall not be affected. If such construction is not possible, the invalid or unenforceable portion will be severed from these Terms but the rest of these Terms will remain in full force and effect. ## 25. Survival The following provisions of these Terms shall survive termination of your use or access to the Site: Sections 5, 9, 10, 11, 14, and any other provision that by its terms survives termination of your use or access to the Site. ## 26. English Language Notwithstanding any other provision of these Terms, any translation of these Terms is provided for your convenience. The meanings of terms, conditions, and representations herein are subject to their definitions and interpretations in the English language. In the event of conflict or ambiguity between the English language version and translated versions of these terms, the English language version shall prevail. You acknowledge that you have read and understood the English language version of these Terms. # Airdrop Disclaimer Source: https://docs.meteora.ag/met/airdrop-disclaimer Important Disclaimers And Acknowledgement of Terms of Use for the Airdrop Checker **Please Read Carefully Before Checking Your Eligibility for the \$MET Airdrop** By clicking the "Accept" button below, and using the \$MET airdrop eligibility checker ("**Airdrop Checker**"), you acknowledge and agree to the following: *** ## Applicable Terms and Conditions Your access and use of the Airdrop Checker is governed by and subject to **(i)** the Airdrop Terms and **(ii)** the General Terms of Meteora's website. By clicking the "Accept" button below, you acknowledge and confirm that you have read and understood the Airdrop Terms and the General Terms, and that you agree to be bound by the Airdrop Terms and General Terms in respect of your access and use of the Airdrop Checker. For avoidance of doubt, the Meteora Foundation is not a party to the Airdrop Terms, and shall not be responsible for any matters relating to the Tokens, any Airdrop Round, Airdrop Terms, the Airdrop Programme and the Airdrop Site. *** ## Purpose and Limitations The Airdrop Checker is an informational tool provided solely to assist in assessing your preliminary eligibility for the \$MET airdrop programme. Results displayed by the Airdrop Checker do not guarantee final eligibility, participation, or any right to receive tokens or rewards. We reserve the right to disqualify participants who are suspected of fraudulent or illegal activities, bypassing eligibility checks, or failing to meet any eligibility criteria. We reserve the right to change our decisions (and accordingly, any results displayed by the Airdrop Checker) on or prior to the occurrence of the airdrop. Any acquisition of tokens through third parties (including but not limited to exchanges or other holders) shall not establish any relationship of any kind between you and Meteora Comet Limited and/or its affiliates (“we”, “us”) and we expressly disclaim any and all responsibility or liability arising from or in connection with such transfers. Any acquisition of tokens is strictly at your own risk and does not give rise to any rights against us. *** ## No Guarantees or Warranties The Airdrop Checker is provided “as is” without warranties, express or implied, regarding accuracy, completeness, or fitness for a particular purpose. We are not liable for any errors, omissions, or potential inaccuracies in the eligibility assessment provided by the Airdrop Checker, nor for any decisions or changes made on or prior to the occurrence of the airdrop that affect the results or accuracy of the eligibility assessment provided by the Airdrop Checker. *** ## Eligibility and Restrictions The \$MET Airdrop may be restricted in certain jurisdictions. If you are not legally permitted to receive digital tokens in your country or region, you must not participate. You confirm that you are not a citizen or resident of a jurisdiction subject to sanctions or prohibitions on token distribution, or a citizen or resident of any named prohibited jurisdiction set out in our Airdrop Terms. *** ## Privacy and Data Usage We may collect certain information when you use the Airdrop Checker, such as your wallet addresses or your past interactions with Meteora, to assess your eligibility for the token airdrop. For more information on how your data may be collected, used, disclosed and/or processed, please refer to our Privacy Policy. You hereby consent to the collection, usage, disclosure and processing of information relating to you, including without limitation, your personal data, in accordance with our Privacy Policy. *** ## User Responsibility and Security Please note that it is your responsibility to ensure the security of your wallets, private keys, and other credentials when using the Airdrop Checker. We will never request your private keys, wallet seed phrases, or sensitive account information. *** ## Assumption of Risk By using the Airdrop Checker, you assume all risks associated with its use and your reliance on its results. This tool is intended to provide general guidance only, and any actions you take based on its output are at your own risk. *** **If you do not accept any of these terms, you may not use the Airdrop Checker.** # Airdrop Terms and Conditions Source: https://docs.meteora.ag/met/airdrop-terms-and-conditions Terms and Conditions for $MET Airdrop Campaign The following Terms and Conditions (these "**Terms**") govern the participation of any person, individual or corporation eligible to participate ("**You**", "**Your**", "**Participant**") in the \$MET Airdrop Campaign launched by Meteora Comet Limited, a company incorporated in the British Virgin Islands ("**Company**"). Any person, individual or corporation which engages in any activity in connection with the \$MET Airdrop Campaign shall immediately be deemed a Participant and shall be deemed to have agreed to be bound by these Terms. These Terms shall be deemed entered into between the Participant and the Company each a "**Party**", collectively the "**Parties**". If You do not agree or You do not accept these Terms unreservedly, You may not participate in the \$MET Airdrop Campaign and will not qualify to receive any \$MET in the \$MET Airdrop Campaign. By accepting these Terms, You shall also be bound by any policies, instructions, schedules, guidelines, operating rules, supplementary terms and/or procedures which the Company may publish from time to time on the website at [https://met.meteora.ag/](https://met.meteora.ag/) and/or the Company's related social media channels (collectively the "**Public Channels**"), which are hereby expressly incorporated herein by reference. In accordance with Clause 7, the Company reserves all rights to disqualify Your participation. The Company may revise these Terms at any time with or without notice to You by publishing the updated Terms on any of the Public Channels. These changes shall take effect from the date of upload, and Your continued participation in the \$MET Airdrop Campaign from such date shall be deemed to constitute Your acceptance of such revised Terms. It shall be Your sole responsibility to check the Public Channels for such revisions from time to time. If you do not agree to these Terms, please do not participate in the \$MET Airdrop Campaign. \$MET is not intended to constitute securities of any form, units in a business trust, units in a collective investment scheme or any other form of investment in any jurisdiction. This document and these Terms do not constitute a prospectus or offer document of any sort and are not intended to constitute an offer of securities of any form, units in a business trust, units in a collective investment scheme or any other form of investment, or a solicitation for any form of investment in any jurisdiction. No regulatory authority has examined or approved of these Terms. No such action has been or will be taken by the Company under the laws, regulatory requirements or rules of any jurisdiction. The provision of these Terms to You does not imply that the Applicable Laws, regulatory requirements or rules have been complied with. In particular, \$MET: **(a)** is not a loan to the Company or any Affiliate; **(b)** does not provide the holder with any ownership or other interest in the Company or any Affiliate, or any other entity, enterprise or undertaking, or any kind of venture; **(c)** is not intended to be a representation of currency or money (whether fiat or virtual or any form of electronic money), security, commodity, bond, debt instrument, unit in a collective investment scheme or any other kind of financial instrument or investment; **(d)** is not intended to represent any rights under a contract for differences or under any other contract the purpose or pretended purpose of which is to secure a profit or avoid a loss; **(e)** is not a commodity or asset that any person is obliged to redeem or purchase; **(f)** is not any note, debenture, warrant or other certificate that entitles the holder to interest, dividend or any kind of return from any person; **(g)** is not intended to be a security, commodity, financial derivative, commercial paper or negotiable instrument, or any other kind of financial instrument between the relevant holder and any other person, nor is there any expectation of profit; and **(h)** is not an offer or solicitation in relation to gaming, gambling, betting, lotteries and/or similar services and products. *** ## Definitions The following definitions shall apply in the interpretation of these Terms: | Term | Definition | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **\$MET** | means the cryptographically-secure fungible protocol token of the Meteora protocol (as defined below), which is a transferable representation of attributed utility functions specified in the protocol/code of the Meteora protocol. | | **Applicable Laws** | means with respect to each Party and any person, any and all applicable laws to which such Party or person is subject, including any and all jurisdictions which may apply. | | **Affiliate** | means with respect to any person, any other person directly or indirectly controlling, controlled by or under common control with such person. | | **Digital Wallet** | means the digital asset wallet that is compatible with the Solana blockchain network that the Participant shall use for the purpose of participation in the \$MET Airdrop Campaign. | | **Indemnified Persons** | means the Company, the Company's group/affiliated entities as well as their respective past, present and future employees, officers, directors, contractors, consultants, equity holders, suppliers, vendors, service providers, parent companies, subsidiaries, Affiliates, agents, representatives, predecessors, successors and assigns. | | **Meteora protocol** | means the decentralised Dynamic Liquidity Market Maker protocol (DLMM), as more particularly described at [https://docs.meteora.ag/overview/home](https://docs.meteora.ag/overview/home). | *** **IT IS HEREBY AGREED:** *** ## 1. Participation in \$MET Airdrop Campaign **1.1.** The Company is launching the \$MET Airdrop Campaign solely for the purpose of increasing awareness of the Meteora protocol, and to encourage users to participate in the Meteora protocol. Participants which successfully participate in the \$MET Airdrop Campaign shall be eligible to receive \$MET in their respective Digital Wallet when the same is distributed at the Company's discretion. You agree and accept that the \$MET Airdrop Campaign shall in no way be construed as a sale of \$MET or any other digital asset. Participants are responsible for ensuring that the Digital Wallet utilised to participate in the \$MET Airdrop Campaign is a self-hosted digital wallet (do NOT utilise an address from an exchange or custodial wallet service as \$MET will be delivered to this address). **1.2.** The \$MET Airdrop Campaign shall run for a duration of approximately 68 weeks from **31 January 2024** to **30 June 2025**, or such other period as may be specified by the Company at its sole discretion ("**Campaign Duration**"). **1.3.** In order to be eligible for the \$MET Airdrop Campaign, by the last day of the Campaign Duration, Participants should have met any one of the following requirements, including any qualifying conditions as may be determined by the Company from time to time: **(a)** Qualify as a liquidity provider of the Meteora protocol in accordance with the "LP Stimulus Plan", including DLMM (Dynamic Liquidity Market Maker) beta users and long-term liquidity providers; **(b)** Qualify as an eligible "Bin Array Creator" for DLMM pools on the Meteora protocol; **(c)** Participate in the Launchpad / Launchpool ecosystem on the Meteora protocol, based on on-chain trading fees and points earned, as well as integrations with the Meteora protocol; **(d)** Qualify as a token creator who used Meteora's DBC (Dynamic Bonding Curve) technology; **(e)** Qualify as an expert or active contributor of the Meteora protocol, based on contributions to underlying software for the Meteora protocol, the Meteorites community, or key roles in the protocol's Discord channel; **(f)** Qualify as a "Mercurial Stakeholder" in accordance with the "Meteora Plan"; **(g)** Qualify as an "M3M3 Stakeholder" in accordance with the "Phoenix Rising Plan"; and **(h)** Qualify as a "JUP Staker" in accordance with the "Phoenix Rising Plan" **1.4.** The Company reserves the right to prescribe, at its sole discretion, such other qualifying conditions or restrictions on a user's participation in the \$MET Airdrop Campaign, modify the weightage allocated to any specific condition/task, or to disqualify or prohibit any person from participating or qualifying in any aspect of the \$MET Airdrop Campaign for any reason, including without limitation due to a user engaging in Disqualifying Conduct (defined below). **1.5.** There are limited numbers of \$MET available for distribution to Participants in the \$MET Airdrop Campaign, so it will be distributed on a "first-come-first-served" basis. **1.6.** The Participant acknowledges that the Company reserves the right to suspend, modify, restrict, cancel, withdraw or amend any aspect of the \$MET Airdrop Campaign at its sole discretion without liability to any person. **1.7.** Each Participant who enters or participates in any aspect of the \$MET Airdrop Campaign represents and acknowledges, without limitation or qualification, that all determinations or decisions made by the Company for the purposes of the \$MET Airdrop Campaign are final and binding. The Company shall not entertain any requests for appeal or review. In particular, the Participant acknowledges and accepts that despite any Participant satisfying all prescribed qualifying conditions / restrictions, the Company shall have the sole discretion to decline to deliver \$MET to such Participant for any reason whatsoever. *** ## 2. Claims Process **2.1.** Participants may claim awarded \$MET from the relevant underlying smart contract or technical service for \$MET Airdrop Campaign during the “Claim Period”, which starts from 23rd October 2025 until the expiry date on 23rd April 2026. The expiry date will be six (6) months after the start date of 23rd October 2025. Participants may claim \$MET by connecting their Digital Wallet enabling access to the Participant's Digital Wallet address as notified to the Company under 1.1, approving the relevant smart contract permissions as prompted, and calling a "Claim" function in accordance with the Company’s procedures. Any unclaimed \$MET Tokens after the aforementioned claim period shall no longer be available for claim, and shall be dealt with by the Company at its sole and absolute discretion. **2.2.** Each Participant shall pay for all blockchain network fees or "gas" which may be required to call a "Claim" function for \$MET, or otherwise interacting with any underlying smart contracts deployed on a blockchain network; such fees are typically payable each time a Participant initiates the request to claim \$MET. **2.3.** Participants are responsible for implementing all reasonable and appropriate measures for securing the Digital Wallet, vault or other storage mechanism that Participants use to store \$MET, including any requisite private key(s) or other credentials necessary to access such storage mechanism(s). If a Participant’s private key(s) or other access credentials are lost, such Participant may lose access to \$MET. The Company shall not be responsible for any security measures relating to the Participant’s receipt, possession, storage, transfer or potential future use of \$MET nor shall the Company be under any obligation to recover or return any such \$MET and the Company hereby excludes (to the fullest extent permitted under Applicable Laws) any and all liability for any security breaches or other acts or omissions which result in the Participant’s loss of (including loss of access to) \$MET airdropped to the Participant under these Terms. In the event of any loss, hack or theft of \$MET, each Participant acknowledges and confirms that it shall have no right(s), claim(s) or causes of action in any way whatsoever against the Company, its Affiliates, representatives, employees, directors and agents. *** ## 3. Representations, Warranties and Undertakings **3.1.** You, the Participant, agree, represent and warrant that: **(a)** You have read and understood the provisions of these Terms, including all relevant schedules and annexes that may be attached hereto; **(b)** You have full power and authority to enter into and give effect to Your obligations and undertakings under these Terms, and in the case where You are a corporation or acting on behalf of a corporation:
**(i)** the corporation is a duly organised and validly existing corporation in its place of incorporation and it is not in receivership or liquidation or judicial management or any analogous situation; and

**(ii)** the corporation has full power and authority to enter into and give effect to its obligations under these Terms and all corporate steps required to give effect to the entry of these Terms have been properly taken.
**(c)** these Terms constitute a legal and binding obligation and undertaking, and may be enforced to the full extent of the law; **(d)** where required, You have approved any approvals under any Applicable Laws for the participation in the \$MET Airdrop Campaign; **(e)** any expenses that the You may incur in observing these Terms shall be at Your own expense and cost; **(f)** You have not engaged in Disqualifying Conduct; **(g)** You understand that and no materials, commentary, content provided by the Company and/or the Indemnified Parties shall be considered financial advice, and any financial advice sought by the You in relation to Your participation in the \$MET Airdrop Campaign shall be at Your own costs and expense; **(h)** You are responsible and shall bear all expenses and costs involved (including but not limited to accountant fees) in determining the tax implications in Your participation of the \$MET Airdrop Campaign and the observance of these Terms; **(i)** You are responsible for ensuring that Your Digital Wallet is functional and the keys for such, secure, and that it is Your responsibility to contact the Company through the appropriate avenue to resolve any issue with the Digital Wallet; **(j)** You have a good understanding of the operation, functionality, usage, storage, transmission mechanisms and all material characteristics of cryptocurrencies, blockchain-based software systems, cryptocurrency wallets or other related token storage mechanisms, blockchain technology, smart contract technology, and staking mechanism, technology or services; **(k)** You or (if participating on behalf of a corporation) any of the corporation's related corporations, directors, officers, employees, agents or any person acting on the corporation's behalf is NOT an individual or entity that is or is owned or controlled by an individual or entity that ("**Sanctioned Persons**"):
**(i)** is listed by the \[British Virgin Islands Financial Services Commission] or the Monetary Authority of Singapore as "designated", "sanctioned", "prohibited" or "restricted" (or with other similar terminology) individuals or entities defined in the respective regulations promulgated under the Monetary Authority of Singapore Act (Chapter 186) of Singapore, the United Nations Act (Chapter 339) of Singapore or the Terrorism (Suppression of Financing) Act (Chapter 325) of Singapore or such other law, regulation or rule as may be prescribed by any relevant authority;

**(ii)** is currently the subject of any sanction administered by the United States Office of Foreign Assets Control of the United States Department of the Treasury ("**OFAC**") or any other United States government authority, is not designated as a "Specially Designated National" or "Blocked Person" by OFAC or subject to any similar sanctions or measures imposed or administered by the United Nations Security Council, the European Union, or similar sanctions administered or imposed by any other country (collectively, the "**Sanctions**");

**(iii)** is located, organised or resident in a country or territory that is the subject of such Sanctions (including, without limitation, the Democratic People's Republic of Korea, the Democratic Republic of Congo, Eritrea, Iran, Libya, Somalia, South Sudan, Sudan and Yemen); or

**(iv)** has engaged in and is not now engaged in any dealings or transactions with any government, person, entity or project targeted by, or located in any country or territory, that at the time of the dealing or transaction is or was the subject of any Sanctions.
**(l)** You are not a citizen, resident (tax or otherwise), domiciliary and/or green card holder or other similar certificate of residency of a country (i) where holding tokens, trading tokens, or participating in token sales or distribution, whether as a purchaser or a seller, is prohibited, restricted or unauthorised by applicable laws, decrees, regulations, treaties, or administrative acts, or (ii) where it is likely that the distribution of \$MET would be construed as the sale of a security (howsoever named), financial service or investment product (including without limitation the United States of America, Canada, the People's Republic of China, Democratic People's Republic of Korea, Cuba, Syria, Iran, Sudan, and the People's Republic of Crimea (each a **Restricted Territory**)), nor are you acquiring \$MET from any Restricted Territory, nor are you an entity (including but not limited to any corporation or partnership) incorporated, established or registered in or under the laws of a Restricted Territory, nor are you acquiring \$MET on behalf of any person or entity from a Restricted Territory. **3.2.** You are aware of and agrees that the \$MET Airdrop Campaign generally involves significant risk, and You hereby agree to accept the full consequences of all risks that may arise during, before, after and in connection to: **(a)** your participation in the \$MET Airdrop Campaign and the distribution of \$MET; **(b)** any loss of digital assets in your Digital Wallet; **(c)** the use of \$MET in Meteora protocol, any other blockchain network, or for any other purpose; **(d)** any potential delay, postponement, suspension, modification or abandonment of the \$MET Airdrop Campaign. **3.3.** The list under Clause 3.2 shall not be regarded as an exhaustive list of the potential risks associated with Your participation in the \$MET Airdrop Campaign and You agree to accept full responsibility for Your own knowledge of all risks that may arise. **3.4.** The Company does not take any responsibility for any circumstance or event that may prevent a person from participating in the \$MET Airdrop Campaign as a result of technical restrictions, issues, or other limitations such as force majeure, which include (but are not limited to) regulatory considerations, government directives, and government intervention of whatsoever nature. *** ## 4. Disclaimers of Warranties **4.1.** The Company hereby disclaims and does not provide a warranty of any kind, whether implied, express or statutory, including but not limited to the respect of the matters listed in Clause 4.2. Where the Applicable Laws does not allow the disclaimer or exclusion of such warranties, the defective disclaimer shall apply to the full extent as permitted by the Applicable Laws. **4.2.** You hereby and expressly agree that Your participation in the \$MET Airdrop Campaign is at Your sole risk and agree that in no event shall the Company be liable to You, or any corporation or entity You represent, for any of the following: **(a)** any interruption, error, defect, flaw or unavailability of the \$MET Airdrop Campaign; **(b)** any fraudulent or illegal use of Your Digital Wallet, or any loss of possession and destruction of Your private keys of any wallet; **(c)** Your inability to participate in the \$MET Airdrop Campaign or any transactions You may undertake in connection with the same; **(d)** any virus, malware, trojan or similar that may affect \$MET, Meteora protocol, or Your devices from use of any resources provided by the Company, despite the Company's best reasonable precautions in place to prevent as such; **(e)** any delay, postponement, suspension or abortion of the \$MET Airdrop Campaign; **(f)** the non-disclosure of information relating to the \$MET Airdrop Campaign; **(g)** Your disqualification for failing to recognise Yourself as a Sanctioned Person or the failure of the Company to recognise You as such; **(h)** any and all risks to You in Your participation in the \$MET Airdrop Campaign. **4.3.** You agree that the Company may, at any time and in its absolute discretion, delay, postpone, suspend or abort the \$MET Airdrop Campaign for any reasons, including regulatory concerns or change in business strategy or goals. You agree that, where such should occur, neither the Company nor the Indemnified Parties would be liable for any loss (including but not limited loss of use, revenue, income, profits, damages) in accordance with Clause 9. *** ## 5. Information Provided to the Company **5.1.** Each Participant shall ensure that any documents and information provided by such Participant in connection with its participation in the \$MET Airdrop Campaign is true, accurate and complete. **5.2.** Where it occurs any event that may render such provided information under Clause 5.1 false, misleading, incomplete or altered, Participants shall, at the earliest possible, take such acts necessary to notify the Company and/or their Indemnified Parties of the event and corresponding change. *** ## 6. Taxes The Parties shall seek their own advice on any tax that may be payable in connection with the performance of matter under these Terms. The Parties should be aware that this may include tax consequences including but not limited to tax reporting, income tax, transfer taxes and withholding tax. For the avoidance of doubt, the Company shall not be in any way reasonable for any claims, fines, penalties or other liabilities that any other party these Terms may incur. *** ## 7. Disqualification from Participating **7.1.** The Company reserves the right, in its absolute discretion, to disqualify any participant from participation in the \$MET Airdrop Campaign, neither Company nor the Indemnified Parties would be liable for any losses or damages that may arise for such disqualification and in accordance with Clause 9. **7.2.** Such situations of disqualification may include, but is not limited to, situations where such participant has encouraged, instigated and/or engaged in Disqualifying Conduct (defined below) that may be harmful to the Company. The Company reserves the right to take any action as necessary, including but not limited to legal proceedings, to protect the Company from the harm, losses, damage arising or connected to such conduct. **7.3.** "**Disqualifying Conduct**" refers to exploitative, abusive and excessive conduct, and shall include but is not limited to, at the sole and full discretion and judgement of the Company: **(a)** Acquiring, creating or controlling multiple user accounts, identities or Digital Wallet addresses in connection with participation in the \$MET Airdrop Campaign or any aspect of Meteora protocol, or otherwise participating in any Sybil attack or "farming" in connection with the \$MET Airdrop Campaign or Meteora protocol; **(b)** Introducing or using any malware, virus, trojan horses or other material that may alter or be harmful to technology in any way; **(c)** Gain and/or engage in unauthorised excess and use of any materials of the Company and its Indemnified Parties; **(d)** Interfering with the operation of \$MET Airdrop Campaign; **(e)** Impersonating the Company and/or the Indemnified Parties (such as but not limited to the use of e-mail or screen names); or **(f)** Using any materials produced for the \$MET Airdrop Campaign in a way that is inappropriate and violates any Applicable Laws. **7.4.** The Company reserves the right to implement the measures it deems necessary and fit to ensure that any Participant that has engaged in Disqualifying Conduct does not have access to the \$MET Airdrop Campaign. *** ## 8. Disclosure of Information **8.1.** The Company does not warrant the completeness and accuracy of any information relating to the Company, the \$MET Airdrop Campaign that is online, which may originate from but not limited to the following: **(a)** the website [https://www.meteora.ag/](https://www.meteora.ag/), [https://met.meteora.ag/](https://met.meteora.ag/) and all related sub-domains; **(b)** the X (prev Twitter) account [https://x.com/meteoraag](https://x.com/meteoraag); **(c)** the Discord channel [https://discord.gg/meteora](https://discord.gg/meteora); **(d)** any website or other social media channels directly or indirectly linked to the Company. **8.2.** You hereby agree that the Company and/or its Indemnified Parties shall be free of any liability arising from any reliance on such materials. **8.3.** In the event of any conflict or inconsistency between these Terms and any other information, social media posting, brochure, marketing or promotional material relating to the \$MET Airdrop Campaign, these Terms shall prevail. *** ## 9. Liability and Indemnity **9.1.** To the fullest extent permitted by law, the Company hereby expressly disclaims its liability for any loss incurred or suffered by You or any person in connection with the \$MET Airdrop Campaign, for: **(a)** any and all changes to the operations, management and organisation of the \$MET Airdrop Campaign including but not limited to any potential delay, postponement, suspension or abandonment of the \$MET Airdrop Campaign as well as calculation of airdrop amounts generally or in any specific case; **(b)** any mistake or error in delivery or in connection with \$MET due and any subsequent changes to the type or value of, or issues affecting, \$MET (if any); **(c)** failure, malfunction or breakdown of, or disruption to, the operations of the Company, the Meteora protocol, or any other technology (including but not limited to any smart contract technology), due to any reason, including but not limited to occurrences of hacks, mining attacks (including without limitation double-spend attacks, majority mining power attacks and "selfish-mining" attacks), cyber-attacks, distributed denials of service, errors, vulnerabilities, defects, flaws in programming or source code or otherwise, regardless of when such failure, malfunction, breakdown, or disruption occurs; **(d)** any virus, error, bug, flaw, defect or otherwise adversely affecting the \$MET Airdrop Campaign or your participation in \$MET Airdrop Campaign; **(e)** Your failure to disclose information relating to the \$MET Airdrop Campaign at the request of the Company; **(f)** any prohibition, restriction or regulation by any government or regulatory authority in any jurisdiction applicable to the \$MET Airdrop Campaign or Your participation in \$MET Airdrop Campaign; and **(g)** all risks, direct, indirect or ancillary, associated with your participation in the \$MET Airdrop Campaign, the Company and/or the Meteora protocol, whether or not expressly stated in these Terms. **9.2.** To the fullest extent permitted by Applicable Laws, You will indemnify, defend and hold harmless the Company and/or the Indemnified Parties from and against any and all claims, demands, actions, liabilities, costs, expenses for any type of loss (including but is not limited to damages, fines, punitive damages, personal injury, pain and suffering, emotional distress, revenue and profit loss, business and anticipated savings loss and data loss) that may arise in any kind (in tort, contract or otherwise), directly, indirectly, incidental or consequential, from or in connection with the matters dealt with and described in these Terms, including: **(a)** losses that may be incurred by actions taken by the Company and/or Indemnified Parties against participants engaged in Disqualifying Conduct under Clause 7.3; and **(b)** any loss that may be incurred as a result of the classification of the Participant as a Sanctioned Person as described under Clause 3.1(k). **9.3.** You hereby agree that You waive all rights to assert any claims against the Company and/or the Indemnified Parties under any Applicable Laws. This shall include the right to participate in any class action lawsuit or class wide arbitration against the Company, the Indemnified Parties and/or any other Participant and/or any companies related through common ownership or control at any point in time. *** ## 10. Intellectual Property **10.1.** You acknowledge and agree that save as otherwise indicated in writing, the Company (or, as applicable, its licensor(s)) owns all legal right, title and interest in and all intellectual property and all elements of \$MET and Meteora protocol, or any underlying websites in connection with the distribution and/or usage of \$MET and Meteora protocol, including, without limitation all art, designs, systems, methods, information, computer code, software, services, website design, "look and feel", organisation, compilation of the content, code, data and database, functionality, audio, video, text, photograph, graphics, and all other elements of the same (collectively, the "**Content**"). **10.2.** You acknowledge that the Content are protected by copyright, trade dress, patent, and trademark laws, international conventions, other relevant intellectual property and proprietary rights, and applicable laws. All Content are the copyrighted property of the Company (or, as applicable, its licensor(s), and all trademarks, service marks, and trade names associated with \$MET and Meteora protocol are proprietary to the Company or its licensor(s). Except as expressly set forth herein, your receipt or use of \$MET and Meteora protocol does not grant you ownership of or any other rights with respect to the aforesaid Content. **10.3.** The Company reserves all rights in and to the Content that are not expressly granted to you in these Terms. In particular, you understand and agree that: **(a)** your usage of \$MET and Meteora protocol does not give you any rights or licenses in or to the Content (including, without limitation, the Company's copyright in and to the associated art) other than those expressly contained in these Terms; **(b)** you do not have the right, except as otherwise set forth in these Terms, to reproduce, distribute, or otherwise commercialise any elements of the Content (including, without limitation, any art) without the Company's prior written consent in each case, which consent may be withheld at the Company's sole and absolute discretion; **(c)** you will not apply for, register, or otherwise use or attempt to use any \$MET or Meteora protocol trademarks or service marks, or any confusingly similar marks, anywhere in the world without the Company's prior written consent in each case, which consent may be withheld at the Company's and absolute discretion; and **(d)** \$MET and Meteora protocol may potentially include intellectual property elements provided by third parties that are subject to separate ownership and/or license terms, in which case those terms will govern such intellectual property rights. *** ## 11. Third Party Online Products and Services **11.1.** The Public Channels may contain links to third-party websites and services which are owned and operated by third parties ("**Third Party Online Products and Service(s)**"). These links are provided for Your information and convenience only, and are NOT an endorsement by the Company, its directors, officers, employees, agents, successors, and permitted assignees of the contents of such linked websites or third parties, over which none of the aforementioned entities have any control over. **11.2.** Your access to and use of any Third Party Online Products and Service(s) is governed by the terms, conditions, disclaimers and notices found on each such website or in connection with such Third Party Online Products and Service(s). The Company has not verified, will not, and is under no obligation to verify the accuracy, suitability or completeness of the contents on such Third Party Online Products and Service(s), and the Company does not control, endorse, warrant, promote, recommend or in any way assume responsibility or liability for any services or products that may be offered by or accessed through such Third Party Online Products and Service(s) or the operators of them, or the suitability or quality of any of such Third Party Online Products and Service(s). **11.3.** In addition, the Company does not warrant that such Third Party Online Products and Service(s) or the software, data or files contained in, accessed via or linked or referred to in, such Third Party Online Products and Service(s) are free of viruses (or other deleterious data or programs) or defects or that use of such Third Party Online Products and Service(s) will not cause harm or that they conform or will conform with any user expectations. Furthermore, the Company is not responsible for maintaining any materials referenced from another website, and makes no warranties for that website or service in such context. *** ## 12. Company's Remedies **12.1.** If any Participant breaches any provision in these Terms or is discovered or deemed to be ineligible or disqualified for the \$MET Airdrop Campaign for any reason, the Company is entitled at any time: **(a)** to withdraw, withhold, or require the forfeiture of any \$MET; or **(b)** where the \$MET has been delivered to the Participant, to reclaim such \$MET and/or claim liquidated damages from the Participant in an amount of two (2) times the market value of such \$MET. **12.2.** Upon the occurrence of the above, no person shall be entitled to any payment or compensation from the Company. *** ## 13. Assignment **13.1.** You may not assign or transfer all or part of its rights or obligations under these Terms without the prior written consent of the Company. The Company may refuse to recognise any such assignment, transfer or any other transaction resembling such. **13.2.** The Company may assign, as it sees fit and in its full discretion, any of its rights, obligations and duties under these Terms. *** ## 14. No Waiver **14.1.** The Company's failure or delay to exercise or enforce any right or provision of these Terms will not operate as a waiver of such right or provision, nor will any single or partial exercise of any right or remedy preclude any other or further exercise thereof or the exercise of any other right or remedy. **14.2.** Any provision in these Terms may be waived by written and signed consent of the Company. A waiver of any provision or terms shall not be deemed a waiver of any breach of the provision or term, or any other provision or term. For the avoidance of doubt, the Company may waive, by written and signed consent, any breach by any other Party to these Terms. *** ## 15. Governing Law and Dispute Resolution **15.1.** These Terms are governed by the laws of Singapore, without regard to conflict of law rules or principles (whether of Singapore or any other jurisdiction) that would cause the application of the laws of any other jurisdiction. **15.2.** Any dispute arising out of or related to these Terms, as well as any issue on its validity and existence, shall be referred to and finally resolved by confidential, arbitration administered in accordance with the BVI IAC Arbitration Rules for the time being in force, which rules are deemed to be incorporated by reference in this Clause 15. The place of arbitration shall be Road Town, Tortola, British Virgin Islands, unless the parties agree otherwise. The tribunal shall consist of 1 arbitrator agreed to by the parties within twenty (20) business days of receipt by the respondent of the request for arbitration or, in default thereof, appointed by the British Virgin Islands International Arbitration Centre in accordance with its prevailing rules. The arbitrator shall have exclusive authority to decide all issues relating to the interpretation, applicability, enforceability and scope of this arbitration agreement. The language of the arbitration shall be English. Each party irrevocably submits to the jurisdiction and venue of such tribunal. Judgment upon the award may be entered by any court having jurisdiction thereof or having jurisdiction over the relevant party or its assets. *** ## 16. Entire Agreement These Terms set forth the entire agreement and understanding between the Parties in connection with the matters dealt with and described herein, and supersedes all prior oral and written agreements, memoranda, understandings and undertakings between the Parties in connection with the matters dealt with and described herein. *** ## 17. Rights of Third Parties Save as expressly provided for in these Terms, a person who is not a party to these Terms has no right under any law of any jurisdiction to enforce or to enjoy the benefit of any term of these Terms. *** ## 18. Invalidity and Severance If any provision of these Terms shall be held to be illegal, void, invalid or unenforceable, the provision shall be deemed illegal, void, invalid or unenforceable to that extent. The remaining provisions of these Terms shall remain fully valid, legal and enforceable to the extent that they are unaffected by the defective provision, and the illegality, invalidity or unenforceability of the defective provision in one jurisdiction does not affect its legality, validity and enforceability under any other jurisdiction. The Parties agree to use all commercially reasonable efforts to explore other means of achieving the same result as if the provision had been entirely valid, legal and enforceable. # FAQ Source: https://docs.meteora.ag/met/faq Frequently asked questions about the Meteora Token Generation Event (TGE) ## Overview A Token Generation Event is when a project's token is first created on-chain and becomes claimable/tradable. It's the "go-live" for supply and distribution. 23rd October 2025. Exact time will be posted on Meteora's official socials. Solana. SPL token. Contract address will be posted only in our official channels at TGE. ## Eligibility Eligibility is based on points, LP activity, off chain contributions and more. Points are finalised. On Meteora's official claim page. Connect your wallet to view eligibility and allocation. Make sure to check the link properly. JUP Stakers will automatically be opted in for a Liquidity Distributor NFT position (3% of supply). The remaining 7% will go to other eligible users on a first come first serve basis, capping the total Liquidity Distributor NFT supply at 10%. ## Claim Process 1. Open the official TGE claim site from our announcements in discord or 𝕏 2. Connect a supported wallet (e.g. Phantom, Jup Mobile, Solflare…) 3. Review your allocation 4. Approve the on-chain transaction to claim. Typical Solana claim UX follows this pattern Phantom/Backpack/Jupiter/Solflare etc. Make sure to keep your wallet/app updated. You will need to manually select "Claim MET". Yes. Claiming your allocation is an on-chain process and gas fees are required (Typically \~0.02 SOL). A small amount of SOL is also required to create your token account for MET. ## Trading, Liquidity & Listing Initial liquidity will be on the Meteora DAMM v2 pool. Other listings, if any, will be announced separately. Early trading can be volatile. Confirm slippage settings, check pool TVL/depth, and beware price impact on large orders. ## Security & Official Links * Only use links from Discord Announcements, 𝕏 Page and our official website * Never DM seed phrases/private keys * Never click links in tweets from impersonator accounts * Be cautious of fake token/NFT's airdropped to your wallet * Confirm the exact token mint address from our channels before swapping ## Token Details Posted at TGE in announcements and on the claim page. Do not trust addresses posted elsewhere. ## Points / Airdrops Allocations are final. If you believe there’s a technical error on the UI, open a support ticket with wallet + tx links. (See [support policy](#support-policy) below.) If you're a JUP Staker, you'll automatically be opted in for a Liquidity Distributor NFT that can be withdrawn at any time when trading goes live. If you are another eligible airdrop recipient, you can decide to get your MET allocation or the NFT position value. The NFT supply is capped at 10% of total MET supply and on a first come first serve basis. ## Liquidity Distributor NFT & Launch Pool The Liquidity Distributor NFT represents your position in the DAMMv2 launch pool relative to the percentage of the total supply of MET you own. When you close your position from the initial launch DAMMv2 pool the NFT transfers out of your wallet in exchange for your percentage of liquidity within it. 10% of total MET supply. 3% of this supply will be auto opted in for JUP Stakers. The remaining 7% will be on a first come first serve basis. Within the DAMMv2 pool, a fee is charged based on swaps. Since the pool is single sided MET you will earn fees when someone swaps their USDC for MET. The pool fees start high and drastically decline overtime through a fee scheduler. All JUP Stakers are automatically opted in. The remaining 7% supply will be on a first come first serve basis prior to TGE. On the official TGE site [https://met.meteora.ag](https://met.meteora.ag). The date of claim will be announced on our official socials. No, you do not need to rush to claim nor will you miss out on fees claiming your NFT later than everyone. Your fees will still be generating in the pool even if you don't claim them immediately at launch. Unless you're a JUP Staker, that choice is ultimately yours. No. You can withdraw your position at any time once trading starts. No. Leave it for as long as you like. If you selected a Liquidity Position NFT before TGE, no further action is required. Your position will automatically be represented in the pool earning fees. Once you select claim NFT on the site, you are free to manage your position as you wish. You will receive your share of liquidity in the pool. This may be a mix of MET and USDC, or primarily MET, depending on pool activity. Yes. Once you've signed and confirmed your registration to switch your MET token allocation to MET liquidity Distributor NFT, you cannot change your choice. The allocation is capped at 10% of the total supply (100M). However, this limit may be slightly exceeded to accommodate the final deposit, as a minimal overflow is permitted for the last depositor. Until Sunday, 19 October, 23:00 UTC+8 The MET airdrop claim window closes on 23/01/2026 1 PM UTC. Make sure to claim your tokens before this deadline. ## Support Policy You can submit a ticket through our [Discord](https://discord.com/invite/meteora) channel. Include: * Wallet address * Transaction links (Solscan) * Device/wallet versions * Screenshots * A brief description of your issue During TGE volumes are high; we'll triage by severity. Please avoid duplicate tickets. ## Troubleshooting * Check that you’re on the correct wallet and network (Solana). * Ensure you have SOL for fees. * Refresh and retry; if it persists, open a ticket with your wallet + tx link. * For swaps, check slippage, pool TVL, and whether a token has transfer fees (some tokens do enable them). * Try switching to a different RPC. Add the token mint address manually or refresh assets. Try increasing the priority fee caps. If the default/attached priority fee is too low, validators may ignore the transaction during periods of network congestion. If that doesn't work, try switching the RPCs (this can be done by going to "settings"). In times of network congestion, the priority fee required to land the transaction may increase up to a limit set by the user. Set a priority fee cap that is within your budget. To avoid such failures, it is recommended to maintain at least 0.05 SOL in your wallet at all times. This buffer covers base fees and potential additional fees for most transactions. No, if a transaction fails, no funds will be deducted. It is possible that even if a transaction simulation fails, the actual transaction might still be successful. Check if the transaction went through on block scanners (e.g. [https://solscan.io/](https://solscan.io/)). ## Tokenomics Total supply: 1,000,000,000 tokens. Initial circulating supply: 480,000,000 tokens. 10% of total supply. The pool range where liquidity is added is from \$0.50 to \$7.50 (\$500M to \$7.5B FDV). ## Compromised Wallets If your wallet is compromised, you have the option to report your wallet and forfeit all MET allocations tied to the wallet. There is no option to submit a new address. # Protocol Revenues Source: https://docs.meteora.ag/met/protocol-revenues MET Protocol Revenues - How Meteora generates revenue Meteora earns a share of the trading fees generated on swaps routed through its pools. These fees constitute the protocol's revenue. The specific "Take Rate" (the percentage of the trading fee that goes to the protocol) varies depending on the pool type. # Fee Distribution logic Conceptually, the Total Swap Fee paid by a user is split between the liquidity providers (or launch partners) and the Meteora Protocol. ## DLMM + DAMM pools ``` Trading Fees = LP Fees + Protocol Revenues ``` ## DBC pools ``` Trading Fees = Launch Partner Fees + Token Creator Fees + Protocol Revenues ```
Pool Type Fee Model LP's Share Protocol Revenues
DAMM v1 Base Only 80% 20%
DAMM v2 Base + Dynamic 80% 20%
DLMM Base + Dynamic 95% 5%
DBC Base + Dynamic 80% (Launch Partner + Token Creator Share) 20%
It is important to understand that Meteora's revenues are not automatically converted to stablecoins (USDC) at the moment of collection. # Collection in Base or Quote Tokens Revenues are derived from swap fees, which are collected in the tokens currently being swapped. Therefore, Meteora accumulates a diverse basket of Base and Quote tokens (e.g., SOL, USDC, MET, etc.). # Tokenomics Source: https://docs.meteora.ag/met/tokenomics MET Tokenomics - Everything about $MET **MET SPL Address:** [METvsvVRapdj9cFLzq4Tr43xK4tAjQfwX76z3n6mWQL](https://solscan.io/token/METvsvVRapdj9cFLzq4Tr43xK4tAjQfwX76z3n6mWQL) * **TGE Date:** 23 October 2025 * **Total \$MET Supply:** 1,000,000,000 * **Circulating \$MET at TGE:** 480,000,000 (48% of total supply) \$MET’s current circulating supply can be found at [Coingecko](https://www.coingecko.com/en/coins/meteora), which includes any token burns conducted by token holders (i.e. not Meteora Team), and burns conducted by the Meteora Team. List of token burns conducted by Meteora Team:
Date/Time # of MET Tokens Context
17:01:37 Oct 25, 2025 2,261,990 [Link](https://x.com/realdezen/status/1982010180796817691?t=4klNX5UMieCQ4I5Ian6MqA\&s=19)
# Token Allocations and Vesting Schedule
Allocation % of Total Supply % of Total Supply Unlocked at TGE Cliff (Months) Vest (Months)
Mercurial Holders 15% 15% 0 0
Mercurial Reserve 5% 5% 0 0
LP Stimulus Plan 15% 15% 0 0
Launchpads & Launchpool Ecosystem 3% 3% 0 0
Offchain Contributors 2% 2% 0 0
Jupiter Stakers 3% 3% 0 0
M3M3 Plan 2% 2% 0 0
TGE Reserve 3% 3% 0 0
Team 18% 0% 1 72
Meteora Reserve 34% 0% 1 72
Allocation First Unlock Last Unlock
Team 23 Nov 2025 23 Oct 2031
Mercurial Reserve 23 Nov 2025 23 Oct 2031
# \$MET Token Transparency ## Wallets
Wallet Address Main Functions
Operations [EUBiwQD2quF7v65saSpG4BxpEfaWLgvs4hwyUiMNxYGJ](https://solscan.io/account/EUBiwQD2quF7v65saSpG4BxpEfaWLgvs4hwyUiMNxYGJ) CEX & MM tokens (3% of total supply) will be held here
Ecosystem [6HHtjZMR81LNAF5WFWE4xw72cybz3tPMQ3UJFy7FrvqH](https://solscan.io/account/6HHtjZMR81LNAF5WFWE4xw72cybz3tPMQ3UJFy7FrvqH) Tokens here will be used for TGE Airdrop, and hold the tokens for the Mercurial Reserve (45% of total supply)
Mercurial Reserve [DcHvzKHDpmBGxeRJh16K21EgeYuoLitZnk7MyDxSmr8N](https://solscan.io/account/6HHtjZMR81LNAF5WFWE4xw72cybz3tPMQ3UJFy7FrvqH) Locked Meteora Reserve Vault token allocations
Mercurial Reserve [HDXoxYngoXTziV7bGaPEXgUVRGsRuakagiKa9gA6rQzT](https://solscan.io/account/HDXoxYngoXTziV7bGaPEXgUVRGsRuakagiKa9gA6rQzT) Locked Team Vault token allocations
Read more regarding token distribution at TGE [here](https://meteoraag.medium.com/meteora-genesis-summary-21-october-2025-3a9d914c437f) # We Build Liquidity Pools Source: https://docs.meteora.ag/overview/home
Our mission at Meteora is to build the most dynamic liquidity pools for **liquidity providers**, **launchpads**, and **token launches**. We build **the best liquidity pools** for: Join the LP Army and earn the best fees and yield on your capital with Meteora's innovative liquidity solutions. Launch your project with confidence using Meteora's comprehensive launchpad infrastructure and tools. Discover and participate in exciting new token launches on Meteora. By using Meteora's DAMM v1/v2, DLMM, and DBC Pools, liquidity providers can earn the best fees and yield on their capital, driving sustainable, long-term liquidity to the platform. Follow our [developer updates on Telegram](https://t.me/meteora_dev)! # Product Overview ## Core products DLMM (Dynamic Liquidity Market Maker) gives LPs access to dynamic fees to capitalize on volatility, and precise liquidity concentration all in real-time, with the flexibility to select their preferred volatility strategy. DAMM v2 (Dynamic Automated Market Maker v2) is a constant-product AMM, with features that optimize transaction fees and provide greater flexibility for liquidity providing such as optional concentrated liquidity and usage of position NFTs. DAMM v2 is a new program, and not an upgrade of the Dynamic AMM v1 program. DAMM v1 (Dynamic Automated Market Maker v1) is a constant-product AMM that supports token prices from 0 to infinity. LPs can earn additional yield by utilizing lending sources alongside traditional swap fees, enhancing their returns. Dynamic Bonding Curve (DBC) is a fully customisable pricing curve that allows you to create and launch tokens with unique price dynamics. Tokens trade in a virtual bonding curve and graduate to a Meteora DAMM v1 or v2 pool when they hit the minimum quote threshold. By implementing these liquidity solutions, Meteora aims to foster a thriving ecosystem on Solana and establish Solana as the ultimate trading hub in DeFi. ## Other products Alpha Vaults are complimentary anti-bot mechanisms used together with a Launch Pool to deposit and purchase tokens before the pool starts trading. Presale Vault allows users to contribute using any SPL token and later claim their allocated presale tokens once the presale concludes. Stake2Earn Vaults allows you to fee share trading fees generated from DAMM v1/v2 pools with top token stakers. Dynamic Vaults optimize capital utilization by dynamically distributing assets to lending pools, generating yields for liquidity providers (LPs) on DAMM v1 and Memecoin Pools. Dynamic Fee Sharing is a program that allows you to dynamically configure sharing of fees to a handful of users. Zap is a wrapper program that provides utility functions that allow users to zap in/out from any AMMs or Jupiter. ## Why Liquidity and Liquidity Providers on Solana are Important ### **Liquidity Pools: The Foundation of DeFi** Liquidity pools are the backbone of decentralized finance. No matter what you're building—whether it's a new token, a DApp, or a DeFi service—it all starts with liquidity. For example, if you're launching a new token, you begin with nothing. You need to create a liquidity pool to enable swaps between your token and others. Moreover, deep liquidity for key tokens like SOL enables smooth liquidation and minimizes bad debt risks within the ecosystem. And deep liquidity for wrapped tokens (e.g., BTC, ETH) on Solana allows users to bridge assets across chains, attracting more users from other blockchain networks. Most users tend to focus only on the DeFi app experience, overlooking the liquidity that powers it. It's important to remember that behind every trade is a liquidity pool making it possible. ### **Endless Ways to Provide Liquidity** There are countless approaches to being a liquidity provider (LP). You can LP for: * New token launches * Memecoins or non-hyped assets * Market-making strategies * Major DeFi protocols or smaller experiments Being an LP isn't one-size-fits-all—it’s a spectrum with endless possibilities. ### **A Diverse Range of LPs** Being an LP can mean very different things depending on who you are and what your goals are. Liquidity provision comes from a wide array of contributors, such as: * Professional Market Makers * Developers who integrate liquidity pools into DApps * Creators who launch and bootstrap liquidity for new tokens * Launchpads that help migrate and establish liquidity for new projects * Everyday DeFi users who provide liquidity directly to earn yield or support projects they believe in ### **Liquidity Is the Fuel for Crypto’s Future** As DeFi continues to evolve, liquidity will become even more critical. The future of crypto doesn’t revolve around centralized exchanges—it lies in decentralized systems. We're heading toward a world where millions of people are launching billions of new tokens. **Liquidity Pools** will be central to that future. We’ll need new mechanisms for **creating, launching, distributing**, and **maintaining** these tokens—and all of them will depend on liquidity pools. For example **Liquidity Providers (LPs)** will be the people driving this ecosystem. They’re the ones who create, fund, and maintain the markets that make DeFi possible. **Launchpads** will play a vital role in this shift, offering platforms for new tokens to be created and launched. The launchpad ecosystem is just getting started—what we have today is only the beginning. # What's Dynamic Fee Sharing? Source: https://docs.meteora.ag/overview/other-products/dynamic-fee-sharing/what-is-dynamic-fee-sharing Dynamic Fee Sharing is a program that allows you to dynamically configure sharing of fees. The Dynamic Fee Sharing program allows for the creation of fee vaults where collected fees can be automatically distributed among multiple recipients based on predetermined share allocations. # Key Features On-chain fee collection and distribution with support for both SPL tokens and Token-2022 tokens. Features precise mathematical calculations with overflow protection and immutable share configurations after initialization. Support for 2-5 users per fee vault with configurable share allocations for each user. Includes individual claim tracking to prevent double claims and user-specific checkpoints for accurate fee distribution. Real-time fee accumulation with pro-rata distribution based on share percentages. Uses lazy evaluation for gas efficiency and supports partial funding and claiming. # Core Components 1. **Fee Vault**: The main account that stores user shares, accumulated fees, and distribution state 2. **Token Vault**: A PDA-controlled token account that holds the actual fee tokens 3. **Fee Vault Authority**: A PDA that controls the token vault for secure transfers # Algorithm to Find Optimal Yield Allocations Source: https://docs.meteora.ag/overview/other-products/dynamic-vault/algorithm-to-find-optimal-yield-allocations Hermes is our off-chain yield optimizer (keeper) program, designed to dynamically allocate liquidity across lending platforms for optimal yield while managing risk. Below, we break down its algorithmic approach and the rationale behind each step. *** # How Hermes Optimizes Yield **Hermes** continuously monitors lending pools and simulates allocations to maximize yield for vault depositors. ## Key Factors Affecting APR Higher utilization (more borrowed) increases APR for depositors. More deposits dilute the APR, as interest is shared among more depositors. Each platform’s model determines how APR changes with utilization. *** ## Step-by-Step: Optimal Allocation Algorithm Liquidity is split into small portions (e.g., 100+), configurable by admin. For each portion, simulate depositing it into every lending platform and calculate the resulting APR. Assign the portion to the platform offering the highest simulated APR. Update the simulated allocation and repeat until all liquidity is distributed. If the new allocation differs from the previous by more than 0.1%, trigger a rebalance. *** ## Pseudocode ``` #Off chain simulation portion ← x #x is minimally 100, set by admin deposit_amount ← vault.total_amount / portion last_allocation[] ← current allocation of vault.total_amount in each lending platform allocation[] ← track allocation after simulation to each lending platform FOR each portion FOR each platform Simulate deposit_amount to platform APR[platform] ← APR of platform after simulated deposit ENDFOR highest_APR_platform ← Select platform with the highest APR in APR[platform] allocation[highest_APR_platform] ← deposit_amount + allocation[highest_APR_platform] Update deposit_amount to platform ENDFOR #On Chain Rebalance crank IF diff(allocation[], last_allocation[]) > 0.1% THEN Send rebalance crank to allocate funds according to allocation[] ENDIF ``` # Design Goals Source: https://docs.meteora.ag/overview/other-products/dynamic-vault/design-goals The goal of Meteora Dynamic vaults is to solve the key challenges of optimizing funds for yield generation while keeping funds safe and accessible for users and protocols alike. In this section, we will discuss the design goals of our vaults. # Security and Safety of Principals * **Principals are always safe:** Funds can only be deposited into trusted and decentralized protocols for yield generation. * **Separation of concerns:** The keeper program only contains logic to find optimal yield allocations and to limit fund flows from the vaults to the protocols. It cannot access or claim principals. * **Decentralized governance:** We aim to upgrade authority for decisions around lending protocol integrations and allocations to a decentralized Autonomous Organization (DAO). *** # Full Liquidity at All Times * **Instant access:** Deposited assets remain liquid and accessible at all times, allowing users to withdraw funds at will. * **Liquidity checks:** The vault’s total deposit amount is always checked against the reserves left in the lending platform. * **Automatic withdrawals:** If the liquidity reserve in a pool drops below a predetermined threshold, the vault will withdraw from the pool to ensure sufficient liquidity for user withdrawals. *** # Optimized Yield Returns * **Dynamic allocation:** The vault program monitors and calculates yield variations across all connected lending platforms, dynamically allocating and rebalancing assets to those with the highest returns. * **APR awareness:** The annual percentage rate (APR) of a lending pool depends on factors such as borrowing amount, deposit amount, and the interest rate model. Deposit APR decreases as more is deposited, since borrowing interest is shared among depositors. * **Optimal allocation algorithm:** The algorithm must compare and find the best APR among platforms for a given deposit sum. *** # Ease of Integration and Usage * **User-friendly design:** Vaults and SDKs are designed to be straightforward and easy for any user or protocol to utilize and build applications on top of. * **Comprehensive resources:** We provide full guides, code examples, and an API to help anyone connect to the vaults and access all integrated lending reserves. * **Ecosystem vision:** Our goal is to make the vaults the yield infrastructure for all of Solana. *** # Event Monitoring and Tracking * **Continuous monitoring:** Lending pool APY, utilization rates, and reserve levels are continuously monitored for better yield opportunities and risk management. * **On-chain advantages:** Solana’s composability, speed, and low transaction fees enable on-chain event monitoring that surpasses other blockchains, helping us achieve these design principles. # Operation Fee Calculation Source: https://docs.meteora.ag/overview/other-products/dynamic-vault/operation-fee-calculation When an operator submits a `deposit_strategy` or `withdraw_strategy` transaction (i.e., when assets are rebalanced between lending protocols), we call this the **rebalance crank**. A fee is collected to the [fee\_vault](https://solscan.io/account/9kZeN47U2dubGbbzMrzzoRAUvpuxVLRcjW9XiFpYjUo4#splTransfers) every time the operator sends a rebalance crank. This fee is paid in vault LP SPL tokens and can be seen at the fee\_vault address. Currently, we charge **5% of profit** as the operation (performance) fee. *** # Variables **Before rebalance:** * `vault.total_amount`: $t_1$ * `lp_mint.total_supply`: $p_1$ * **Virtual price** (value of LP token): $v_1 = t_1 / p_1$ **After rebalance:** * `vault.total_amount`: $t_2$ * `lp_mint.total_supply`: $p_1$ * **Virtual price**: $v_2 = t_2 / p_1$ *** # Fee Calculation We charge an operation fee: ```math theme={"system"} fee = 0.05 \times (t_2 - t_1) ``` *** # Adjusting Virtual Price After Fee After deducting the fee, the virtual price becomes: ```math theme={"system"} v_{21} = (t_2 - fee) / p_1 ``` However, the vault does **not** send tokens directly to the treasury token account (since it may not have enough liquidity). Instead, the vault **mints additional LP tokens** for the fee\_vault. Let $\delta$ be the number of new LP tokens minted for the fee. The new virtual price is: ```math theme={"system"} v_{22} = t_2 / (p_1 + \delta) ``` We want the virtual price after fee to remain the same, so set $v_{21} = v_{22}$: ```math theme={"system"} (t_2 - fee) / p_1 = t_2 / (p_1 + \delta) ``` *** # Solving for $\delta$ Rearranging the equation above, we get: ```math theme={"system"} \delta = (p_1 \times fee) / (t_2 - fee) ``` Or, substituting $fee = 0.05 \times (t_2 - t_1)$: ```math theme={"system"} \delta = (p_1 \times 0.05 \times (t_2 - t_1)) / (t_2 - 0.05 \times (t_2 - t_1)) ``` Which simplifies to: ```math theme={"system"} \delta = (p_1 \times 0.05 \times (t_2 - t_1)) / (0.95 \times t_2 + 0.05 \times t_1) ``` *** **Summary:** * The operation fee is 5% of the profit from each rebalance crank. * The fee is paid by minting new LP tokens to the fee\_vault, not by transferring underlying assets. * The number of LP tokens minted is calculated to ensure the virtual price for LP holders remains consistent after the fee is taken. # Rebalance Crank Source: https://docs.meteora.ag/overview/other-products/dynamic-vault/rebalance-crank When an operator submits a `deposit_strategy` or `withdraw_strategy` transaction, we call this the **rebalance crank**. We define the state variables **before** the rebalance as: * `vault.total_amount`: $t_1$ * `token_vault.amount`: $a_1$ * `strategy.current_liquidity`: $c_1$ And the state variables **after** the rebalance as: * `vault.total_amount`: $t_2$ * `token_vault.amount`: $a_2$ * `strategy.current_liquidity`: $c_2$ The vault calculates the total accrued interest (profit) after rebalance as: ```math theme={"system"} \text{profit} = (c_2 + a_2) - (c_1 + a_1) ``` Then, the vault updates the total amount: ```math theme={"system"} t_2 = t_1 + \text{profit} ``` Or, equivalently: ```math theme={"system"} t_2 = t_1 + (c_2 + a_2) - (c_1 + a_1) ``` The immediate release of profit generated to the LPs can result in opportunities for a sandwich attack, as seen in the scenario below: An attacker is able to time their deposit before a rebalance and withdraw immediately after a rebalance in order to get the max profit. In the example above, the attacker is able to earn 10 tokens as a reward by executing the sandwich attack. # Sandwich Attack Prevention To prevent sandwich attacks, the system does **not** distribute 100% of the yield generated by lending platforms to LPs immediately after each rebalance. Instead, the yield is "dripped" (released gradually) to LPs over a pre-determined period. ## Key State Variables * **`total_amount`**:\ The total liquidity in the vault (vault balance + all strategy balances). * **`last_updated_locked_profit`**:\ The total profit that is currently locked, updated at every rebalance. * **`last_report`**:\ The timestamp of the last rebalance. * **`locked_profit_degradation`**:\ The rate at which locked profit is released, expressed as a percentage per second (e.g., 0.1% of locked profits released per second). *** # How Yield Unlocking Works When a user adds or removes liquidity, the system uses the **unlocked amount** (not the full `vault.total_amount`) to calculate how many LP tokens to mint or burn. This is done via the `get_unlock_amount` function. ## Calculation Steps 1. **Calculate Duration Since Last Rebalance:** ```math theme={"system"} \text{duration} = \text{currentTime} - \text{lastReport} ``` 2. **Calculate Locked Fund Ratio:** ```math theme={"system"} \text{lockedFundRatio} = 1 - (\text{duration} \times \text{lockedProfitDegradation}) ``` 3. **Calculate Unlocked Amount:** ```math theme={"system"} \text{unlockedAmount} = \text{totalAmount} - (\text{lastUpdatedLockedProfit} \times \text{lockedFundRatio}) ``` *** **In summary:**\ Only the unlocked portion of profits is available to LPs at any given time, mitigating the risk of sandwich attacks by preventing instant profit extraction after a rebalance. ## Example: Drip duration \~ 5 minutes As seen in the example above, the rebalancing at t = 2 mins will gain a total of 100 token as yield from the lending platforms. However, as we are using the unlocked amount value to calculate the withdrawal amount, the attacker will not get any of the yield gained if he were to withdraw his tokens immediately after rebalancing. He will also only gain a fraction of the total yield if he withdraws within the next few minutes. # Risk Management Source: https://docs.meteora.ag/overview/other-products/dynamic-vault/risk-management This section outlines the security measures implemented to mitigate various risk factors. In addition to executing the algorithm for optimal yield allocations, our keeper program must also assess and address certain risks before determining the final allocation. Risks are generally categorized into two main types: * **Operational Risk** * **Lending Risk** *** # Operation Risk Risks that are related to source code such as when a partner protocol or team has a program update, or when lending platforms are not well audited. In minor cases, the source code changes break the integration, users are unable to perform any vault withdrawals or deposits. In major cases, the vault program or lending protocols may be exploited, losing the tokens in the vaults. We implement a maximum allocation mechanism that the vault can deposit into each lending pool to mitigate this risk. All lending protocols' maximum allocation starts at 100%. We will assess them across a set of criteria which includes the existence of audits, open-source code, insurance funds, main token pools, program multi-sig / verified & non-updatable status as well as the length of integration with Meteora. This set of criteria will eventually be governed by the DAO. For every criterion not met, we will reduce the maximum allocation allowed to the protocol according to this matrix:
Criteria Maximum Allocation Reduction
Audit 20
Open-source 30
Official Insurance Funds? 20
Main Pool 10
Existing integration > 1 month 10
Program multi-sig / or Verified & Non-Updatable 20
**Example:** Lending Protocol Xyz (with Audited, Open-sourced, Main Pool, and Program multi-sig) The score for allocation will be 100-20 (No official insurance funds) - 10 (Existing integration \< 1 month) = 70. The maximum allocation for Xyz will be 70% of total liquidity. We also limit max allocation in each lending as 30% of total liquidity. Hermes is not allowed to withdraw funds from the lending protocols to external wallets. In the event that Hermes is hacked, the hackers will only be able to control the flow of funds to and from between the vaults and lending protocols; the principals are still safe in either of them. *** # Lending Risk This risk occurs when depositors are unable to withdraw their funds from the lending pools. This is caused when utilization rates of the reserves reach full capacity at 100% where borrowed amount equals the deposited amount, or when the amount of reserves remaining in the lending pools is less than the vault deposits. When this happens, depositors are unable to withdraw funds on demand. To avoid lending risks, we have developed the following mechanisms to protect principals: Allocations are stretched across multiple lending protocols to diversify and manage risk, reducing exposure to any single platform. Hermes continuously monitors the utilization rates of each lending pool. If utilization exceeds the 80% threshold, Hermes is ready to withdraw funds, ensuring a buffer for timely action even in high-demand pools. Vaults always maintain a buffer in the lending reserve, providing Hermes with additional time to react to liquidity movements and protect principal. # What's Dynamic Vault? Source: https://docs.meteora.ag/overview/other-products/dynamic-vault/what-is-dynamic-vault Dynamic Vault is DeFi's first dynamic yield infrastructure. Meteora's Dynamic Vaults are DeFi’s first dynamic yield infrastructure, where the vaults rebalance every minute across lending platforms to find the best possible yield while prioritizing keeping user funds as accessible as possible. Our off-chain yield optimizer keeper program will calculate the yield across all the lending platforms. Every few minutes, the off-chain keeper will constantly monitor the key metrics within each lending pool/protocol. The keeper will pick the highest APY based on the keeper calculation and deposit to the respective lending pools. As the lending pools fluctuate based on its usage, a rebalance would occur every few minutes if necessary. Key metrics include: Total Deposit, Deposit Limits, Pool Utilization Rate, APY, and more. Having a trusted capital allocation layer is important to help allocate liquidity to where it is needed the most, while mitigating risks that come along when depositing to these lending protocols. By providing a trusted and optimized way for users to participate in DeFi lending, we will attract more capital and participants to the ecosystem, driving innovation, and growth. The vaults prioritize safety by monitoring utilization rates and reserve levels, and withdrawing funds if thresholds are reached. To ensure secure yields, we have maximum allocation measures based on factors like audit, open-source code, and insurance coverage of lending platforms. These measures will be consistently refined with the community. # How does it work? Meteora Dynamic Vaults allow users and integrated protocols to deposit and/or withdraw assets from the vault program at any time. Deposited assets are distributed to various lending protocols like Solend and Tulip, with maximum allocation based on a combination of yield percentages and risk mitigation strategies around protocol audit, insurance coverage, and open source status. # Core Components ## Core Components ### 1. Vault Each Vault in the infrastructure layer stores single token assets (e.g., USDC or SOL), with the majority of assets allocated to various lending protocols to earn yield. Common tokens used across connecting protocols, AMMs, or wallets are stored in a single vault. For example, USDC from an AMM and wallet holdings are consolidated in the USDC vault. Users and protocols can deposit liquidity directly to each Vault through a simple interface. ### 2. Keeper - Hermes We've created an off-chain keeper called **Hermes** to manage complex logic and operations, including lending protocol monitoring and calculating optimal liquidity allocation across lending platforms. For now, there are **3 main operations** handled by Hermes: Hermes calculates the optimal liquidity allocation across lending platforms to generate the highest overall APY for the vault. The calculation requires key data from various lending platforms including deposit APY, utilization rate, and pool liquidity. This process repeats every few minutes, and if there's a delta between the new allocation and the current one, a rebalance crank is sent to the vault to trigger deposits and withdrawals to/from lending platforms. The tracker consistently monitors, tracks, and stores key data such as deposit APY and pool liquidity from lending platforms. This information is used for calculations and future references, and is also exposed to potential integrators for UI display or custom calculations. Hermes runs a risk monitoring service to track utilization rates and reserve levels of lending protocols, safeguarding user assets by withdrawing liquidity when thresholds are reached. For example, if a lending pool's utilization rate exceeds 80%, Hermes triggers a full liquidity withdrawal and stops deposits for 12 hours. ### 3. SDK Module - Integration APIs To facilitate easy integration for DApps and protocols like AMMs and wallets with our Dynamic Yield Layer, we've created a straightforward SDK and are building an entire library of pre-built modules and code samples for rapid app development and plug-and-play functionality. The liquidity in protocols can be deposited into or withdrawn from vaults directly via simple API calls. The vaults' yield can be distributed back to the LPs of integrated protocols. # What's Hermes? Source: https://docs.meteora.ag/overview/other-products/dynamic-vault/what-is-hermes Hermes - Our keeper program monitors the APY for each lending protocol every 1 hour, and sends rebalance cranks to re-distribute liquidity in the different platforms. There are factors that affect allocation in a platform: The annual percentage yield offered by each lending protocol. The total amount of assets currently deposited in the platform. The maximum amount of assets that can be deposited into the platform. The ratio of borrowed assets to total assets in the pool, indicating how much of the pool is being used. The amount of liquidity available in the pool's reserves. Rebalance cranks are sent every few minutes, so user will get yield just after few minutes depositing in vault Keeper can only deposit in predefined strategies, and cannot claim tokens. # What's Presale Vault? Source: https://docs.meteora.ag/overview/other-products/presale-vault/what-is-presale-vault Presale Vault allows users to contribute using any SPL token and later claim their allocated presale tokens once the presale concludes. This program is still in beta and is subject to breaking changes. # Overview Meteora Presale is a flexible and comprehensive token presale program that enables creators to launch tokens with multiple participation modes, customizable access control, and built-in token vesting. Whether you're launching a memecoin, utility token, or any SPL token, the presale program provides a secure and feature-rich solution that adapts to your launch strategy. # How does Meteora Presale work? The presale program creates a fair and transparent environment for token launches, allowing creators to configure every aspect of their presale while giving participants multiple ways to contribute and claim their tokens. Contributors deposit quote tokens (like SOL or USDC) during the presale period, and once the presale concludes successfully, they can claim their purchased tokens based on the presale mode and vesting schedule. ## Multiple Presale Modes for Every Launch Strategy Choose the presale mode that best fits your token launch goals: ### Fixed Price Presale Sell your tokens at a predetermined fixed price. This is the most straightforward approach where participants know exactly how many tokens they'll receive for their contribution. **Perfect for**: Projects that want price certainty and predictability for their community. ### First-Come, First-Serve (FCFS) The token price is dynamically determined based on total contributions. Early participants contribute first, and the presale ends once the maximum cap is reached. **Perfect for**: Creating urgency and rewarding early supporters who act quickly. ### Prorata (Fair Distribution) The token price is dynamically determined after the presale ends, and the presale can be oversubscribed. If the maximum cap is exceeded, tokens are distributed proportionally to all participants, and any excess contributions are automatically refunded. **Perfect for**: Ensuring fair distribution where everyone who participates gets an allocation, regardless of when they joined. ## Flexible Access Control Control who can participate in your presale with three access modes: ### Permissionless Anyone can participate in the presale without restrictions. This creates maximum accessibility and allows organic community growth. ### Permissioned with Authority Only whitelisted addresses approved by the creator can participate. This gives creators full control over who can join their presale, perfect for exclusive or private sales. ### Permissioned with Merkle Proof Use cryptographic Merkle proofs to whitelist participants efficiently. This approach scales to thousands of addresses while maintaining low on-chain costs. ## Multiple User Tiers (Registries) Create up to 5 different participation tiers, each with its own: * **Token allocation**: How many tokens are available for this tier * **Minimum deposit**: The minimum amount participants must contribute * **Maximum deposit**: The maximum amount participants can contribute * **Deposit fees**: Customizable fees for each tier **Example Use Cases:** * **Tiered Access**: VIP tier with higher caps, public tier with lower caps * **Different Fee Structures**: Zero fees for early supporters, small fees for public participants * **Allocation Management**: Reserve tokens for specific community segments ## Token Lock and Vesting Protect your launch with comprehensive locking and vesting mechanisms: **Partial Immediate Release**: Release a percentage of tokens immediately (e.g., 20% unlocked at TGE) **Lock Period**: Keep purchased tokens locked for a specified duration before vesting begins **Vesting Period**: Gradually release locked tokens over time, creating a smooth unlock schedule **Example:** * **Immediate Release**: 25% of tokens claimable right away * **Lock Duration**: 30 days where no additional tokens are released * **Vest Duration**: Remaining 75% unlocks gradually over 180 days This structure reduces sell pressure while rewarding participants over time. ## Real-Time Participation Tracking Participants can monitor their position in real-time: * **Deposit anytime**: Contribute during the presale period (respecting tier caps) * **Withdraw if needed**: Remove contributions before the presale ends (in most modes) * **Track allocation**: See your token allocation as the presale progresses * **Claim when ready**: Claim vested tokens as they unlock ## Automatic Refunds and Overflow Handling The program automatically handles edge cases: **Failed Presale**: If the minimum cap isn't reached, all contributions are fully refunded to participants **Oversubscribed Prorata**: Excess contributions are automatically refunded to maintain fair pricing **Unsold Tokens**: Configure whether unsold tokens are burned or returned to the creator # Benefits for Creators ## Launch Tokens Your Way Meteora Presale offers unmatched flexibility for token launches: **Key Benefits:** * **Multiple Revenue Streams**: Collect optional deposit fees while raising capital * **Risk Mitigation**: Built-in vesting and locking protect your token launch from day-one dumps * **Full Control**: Withdraw raised funds on your schedule, manage whitelist access, and configure every parameter ## Automated Presale Management Once configured, the presale runs automatically: * **Smart Cap Management**: Fixed Price and FCFS modes automatically end when the maximum cap is reached * **Vesting Distribution**: Tokens are released to participants according to the vesting schedule without manual intervention * **Refund Handling**: Failed presales and oversubscription refunds are processed automatically * **Fee Collection**: Deposit fees are collected and tracked automatically ## Support for Any SPL Token Accept contributions in any SPL token: * **SOL, USDC, USDT**: Common quote tokens * **SPL Token 2022**: Full support for next-generation token standard * **Custom Tokens**: Accept any SPL token as the quote token # Benefits for Launchpads ## Easy Integration and Customization Integrate Meteora Presale into your launchpad platform seamlessly: **Comprehensive SDK**: Use the official SDK for easy integration without dealing with raw program instructions **White-Label Ready**: Customize the presale experience to match your launchpad's branding and user flow **Multiple Launch Models**: Support different token launch strategies with a single integrated solution ## Attract Quality Projects Offer creators a professional presale solution: * **Feature-Rich Platform**: Multiple presale modes, tier systems, and vesting options attract serious projects * **Security First**: The presale program is fully audited and secure * **Proven Track Record**: Point to successful launches using the same infrastructure ## Configurable Fee Structure Monetize presales through deposit fees: * **Per-Tier Fees**: Set different fees for different participation tiers * **Up to 50% Maximum**: Flexible fee structure (0-50% in basis points) * **Transparent Collection**: Fees are collected automatically and can be withdrawn after presale completion * **Creator Incentives**: Share fee revenue with creators to attract more launches to your platform ## Permissioned Launch Support Offer exclusive launch opportunities: * **KYC Integration**: Use permissioned modes to gate access behind KYC verification * **Tiered Access**: Reward your platform's token holders or community members with special tiers * **Merkle Proof Whitelisting**: Efficiently manage large whitelists with cryptographic proofs * **Server Metadata**: Store server URLs for off-chain whitelist management and proof generation # Configuration Parameters Meteora Presale's extensive configurability adapts to any token launch strategy. Creators and launchpads can define parameters based on their specific requirements: ## Core Presale Parameters * **Quote Token**: The token accepted for contributions (SOL, USDC, etc.) * **Presale Token**: The token being sold * **Minimum Cap**: Minimum funds required for presale success (otherwise all contributions are refunded) * **Maximum Cap**: Maximum funds that can be raised * **Start Time**: When the presale begins accepting contributions * **End Time**: When the presale stops accepting contributions * **Presale Mode**: Choose Fixed Price, FCFS, or Prorata * **Access Control**: Permissionless, authority-based whitelist, or Merkle proof whitelist * **Unsold Token Action**: Burn or refund unsold tokens to creator ## Fixed Price Mode Parameters * **Token Price**: The fixed price ratio (quote tokens per presale token) * **Early Completion**: Automatically ends when maximum cap is reached ## Lock and Vesting Parameters * **Lock Duration**: How long tokens are locked after presale ends (up to 10 years) * **Vest Duration**: How long tokens vest after lock period ends (up to 10 years) * **Immediate Release**: Percentage of tokens released immediately (0-100%) * **Vesting Schedule**: Linear vesting over the vest duration ## Tier/Registry Parameters (Up to 5 Tiers) For each tier, configure: * **Token Allocation**: Total tokens allocated to this tier * **Minimum Deposit**: Minimum contribution amount per participant * **Maximum Deposit**: Maximum contribution amount per participant * **Deposit Fee**: Fee charged on deposits (0-50% in basis points) ## Whitelist Parameters * **Merkle Root**: For Merkle proof-based whitelisting * **Operator Addresses**: For authority-based whitelisting * **Server Metadata**: URL for off-chain whitelist verification or proof retrieval * **Personal Caps**: Individual deposit limits for whitelisted addresses ## Time Constraints * **Minimum Presale Duration**: 1 minute * **Maximum Presale Duration**: 30 days * **Maximum Time Until Start**: 30 days in advance * **Maximum Lock + Vest**: 10 years combined # What's Stake2Earn? Source: https://docs.meteora.ag/overview/other-products/stake2earn/what-is-stake2earn Stake2Earn allows you to fee share trading fees generated from DAMM v1 pools with top token stakers. # Overview Stake2Earn is a mechanism where top memecoin stakers compete to earn fee rewards from permanently-locked liquidity in the memecoin pool, transforming memecoins from a race to dump to a race to stake. # How does Stake2Earn work? Whether as a memecoin holder right from launch or a new holder just entering the game, Stake2Earn offers a unique opportunity to earn fee rewards through staking. Fee rewards are collected in the Stake2Earn fee vault for the pool, and distributed to top stakers. ## Top Stakers Earn Fee Rewards If you are going to hold the memecoin anyway, you can stake it to earn fee rewards. Only top memecoin stakers (configurable from 5 to 1000 stakers) are eligible to earn fee rewards from the associated liquidity pools. In addition, the **higher you stake**, **the larger your share of the fee rewards** generated by the permanently-locked liquidity. This competitive element incentivizes users to secure a ranked position and buy & stake more to increase and maximize their fee rewards. **Note**: The actual memecoin has to be staked and not an LP token, so there's no risk of IL (impermanent loss). ## Dynamic Competition for Fee Rewards If a staker falls out of the rankings (e.g. out of Top 100), they immediately stop earning fee rewards. This mechanic ensures that participants stay committed to staking in order to retain their fee rewards. As more participants seek to rank in the leaderboard, competition grows, driving a higher demand for the memecoin. ## Real-Time Earning — Stake More, Earn More! Stake2Earn operates in real-time. As you stake more, you instantly earn more fee rewards per block that you can manually claim later, providing an engaging experience for stakers who want to see returns on their stake. ## Claim Quote Token Rewards, Compound Memecoin Rewards For both token fee collection mode pools on DAMM v1, top stakers earn fee rewards in a combination of Quote Token and memecoins. **Example:** * **SOL rewards**: Can be manually claimed right away * **Memecoin rewards**: The memecoin portion of the claimed fee gets added to your stake, compounding earnings while mitigating sell pressure This dual reward structure — claiming SOL right away combined with restaking memecoin fee rewards makes it convenient for stakers to get rewarded without adding sell pressure to their holdings. ## Cooldown Period for Unstaking Staked memecoins must go through a cooldown period (customizable at Stake2Earn creation, minimum 6 hours) where the stakers must wait before they can withdraw their memecoins. Any memecoins undergoing this cooldown period do not count towards your staked memecoins and potential fee rewards. If users change their mind, they may cancel anytime and their memecoins will immediately count towards earning fee rewards if they are a top staker. # Benefits for Creators ## Automated Staking Mechanism Stake2Earn is a hassle-free solution that creators can use immediately to implement an automated staking mechanism for their memecoins. **Key Benefits:** * **No Extra Costs**: Rewards come entirely from trading fees on permanently-locked liquidity, not from tokenomics * **No Development Required**: There's no need to build a new program, design a UI, or handle any technical work * **Automated Reloading of Rewards**: Unlike traditional liquidity pool farms that require manual reloading of token incentives that also impact emissions, Stake2Earn automatically top up rewards from trading fees so creators do not have to do anything # Launchpad Integration ## Easy Integration and Customization Easily integrate Stake2Earn's staking mechanism and customize it according to your launchpad needs to support different token launch models: **Value-additive staking mechanism**: Stake2Earn offers a unique, value-additive staking mechanism for memecoins launching on your launchpad, without having to change your existing launch process. ## Highly Configurable Fee Structure Stake2Earn fees are highly configurable to be aligned with your launchpad goals and needs. A percentage of fees can be allocated towards different actions, for example: * Reward stakers and incentivize participation * Taken as a launchpad fee * Given to creators to attract more memecoin launches * Permanently-locked for deflationary purposes * Given to your launchpad users to incentivize any action you want # Configuration Parameters Stake2Earn's configurability adapts to all types of memecoins. Creators and launchpads can define key parameters based on their requirements: ## Key Parameters * **Fee allocation**: % of fee rewards from permanently-locked liquidity to allocate to top stakers vs keeping it solely for themselves * **Eligible stakers**: Number of stakers who will receive fee rewards (e.g. Top 100 stakers) * **Unstake cooldown**: Time period before staked memecoins can be withdrawn for users who unstaked (minimum 6 hours) * **Fee distribution duration**: Time period over which fee rewards are distributed (minimum 7 days) * **Fee unlock start time**: When fee rewards will start unlocking for stakers (immediate or at a custom time) # What's Zap? Source: https://docs.meteora.ag/overview/other-products/zap/what-is-zap Zap is a wrapper program that allows you to zap in/out of your position through Meteora AMMs or Jupiter. # Overview Zap is a wrapper program that allows you to zap in/out of your position through Meteora AMMs or Jupiter. # How does Zap work? The Zap program essentially allows you to immediately swap out of any token through Meteora AMMs or Jupiter. It is usually accompanied by a preceding action such as claiming token fee rewards, claiming position fees or removing liquidity. The program handles the account management and the payload to ensure that your swap goes through with ease. # Key Features Zap out of your position through Meteora AMMs or Jupiter. Zap in to your position through Meteora AMMs or Jupiter. # Core Components 1. **Smart Handling of Remaining Accounts**: The program handles the account management and the payload to ensure that your swap goes through with ease. 2. **Proper Payload Management**: The program handles the payload management to ensure that your swap goes through with ease. 3. **Flexible Swap Quotes**: The program integrates with Meteora AMMs and Jupiter allowing you to get the quotes of token you want to swap to/from and zap in/out through the best route to get the best price for your swap. # Additional Yield From Dynamic Vaults Source: https://docs.meteora.ag/overview/products/damm-v1/additional-yield-from-dynamic-vaults How DAMM v1 earns additional yield by deploying idle liquidity to Dynamic Vaults, which allocate capital across lending protocols to maximize returns. # What are Dynamic Vaults? [Dynamic Vaults](/overview/other-products/dynamic-vault/what-is-dynamic-vault) operate as a lending aggregator that allocates capital across multiple lending protocols on Solana. We utilize an off-chain keeper called [Hermes](/overview/other-products/dynamic-vault/what-is-hermes) which constantly monitors all lending pools every minute and rebalances allocations to optimize yields and reduce risk. While there is risk in lending, our Dynamic Vaults [mitigate that risk](/overview/other-products/dynamic-vault/risk-management) by constantly monitoring lending pool utilization rates and automatically withdrawing funds whenever risk thresholds are hit. Additionally, only a maximum of 30% is ever allocated to any single protocol. And our Dynamic Vaults have already been battle-tested with several real-life events: The USDC depeg in early March and the USDH exploit late last year. In both cases, Hermes was able to automatically detect and withdraw all funds safely. # Additional Yield For DAMM v1 Pools paired with USDC/SOL/USDT, a portion of unused USDC/SOL/USDT liquidity gets dynamically loaned out to external lending platforms (e.g. Kamino, Marginfi, Save (Solend)) to generate extra yield for LPs, via our Dynamic Vaults. This benefit applies to all Dynamic AMM Pools on Meteora that have USDC/SOL/USDT in the pair. * As such, a portion of USDC/SOL/USDT liquidity may be utilized in external lending platforms, while the rest remain in the Dynamic Vault Reserve to support sudden withdrawals by LPs. This can be viewed in the "Shared Vault Balance" of the pool account. * In an event where LPs have a liquidity position that is much larger than what is in the Dynamic Vault Reserve, and want to immediately withdraw all liquidity (that has USDC/SOL/USDT), they can withdraw liquidity in smaller sizes a few times or reach out to the team. * Yield earned from Dynamic Vaults is shown on the Dynamic AMM Pool UI as "24h Yield". # DAMM v1 Fee and APY Calculation Source: https://docs.meteora.ag/overview/products/damm-v1/damm-v1-fee-and-apy-calculation How trading fees and APY are calculated in DAMM v1 pools, including the contribution of vault yield on top of swap fee earnings. In order to enhance transparency for our LPs concerning the APY associated with their deposited assets, we compute and display various information, for example: Liquidity Provider Fee, Protocol Fee, 365d Yield/TVL, and LM rewards APR. # Total Trading Fee The amount of fees charged on each trade before the protocol fee is deducted. # Protocol Fee The amount of fees charged on each trade that goes to the protocol. Protocol Fee is a percentage of the total trading fee. ## Constant Product pools * **Standard Pools:** **20%** Protocol Fee, **80%** LP Fee (0.25% trade fee) * **Launch Pools:** **20%** Protocol Fee, **80%** LP Fee (customizable trade fee) ## Stable Swap pools * **0%** Protocol Fee, **100%** LP Fee (0.01% trade fee) ## Swaps Swap hosts can include a referral account in the swap transaction to receive a **Referral Fee** equal to **20%** of the protocol fee. # Base APY The base APY offered is subject to variation and is based on the prevailing trading activity and yield obtained from lending platforms. The calculation of APY is contingent on the increase in virtual price over a specific time period. ```math theme={"system"} \text{base APY} = \left(\left(\frac{\text{Virtual Price 2}}{\text{Virtual Price 1}}\right)^{\frac{1 \text{ year}}{\text{Timeframe}}} - 1\right) \times 100 ``` Where: * **Virtual Price 2**: Latest Virtual Price value * **Virtual Price 1**: Previous Virtual Price value in the last 24 Hours * **Timeframe**: Time difference between Virtual Price 1 and Virtual Price 2 (in seconds) > **Note**: The Virtual Price represents the value of your pool share and is determined by dividing the pool's total value by the number of LP tokens (VP = pool\_value / LP token). The pool's value rises as a result of a swap fee being charged on each trade or when assets deposited in lending pools generate lending yield. This increase in pool value corresponds to a rise in the Virtual Price. # 365d Yield/TVL The ratio of the aggregate swap fees accrued over a 1-year period to the total liquidity available in the pool represents the efficiency metric that informs LPs which pool generates the most trading fees. This data empowers LPs with valuable insights into pool performance. ```math theme={"system"} \text{1 year fee/TVL} = \frac{\text{24 hour fee} \times 365}{\text{Total Liquidity of pool}} ``` Where: * 24 hour fee: Swap fee generated in the last 24 hour in \$ * Total Liquidity of pool: Total value of the assets stored in the AMM pool in \$ # Liquidity Mining (LM) APR This refers to the APR that is calculated based on the rewards provided by the team or partner protocols through Liquidity Mining (LM), such as ABR, LDO rewards, etc. ```math theme={"system"} \text{LM APR} = \left(\left(1 + \frac{\text{Farm Reward per day}}{\text{Farm TVL}}\right)^{365} - 1\right) \times 100 ``` Where: * **Farm reward per day**: Token reward per day × token reward USD rate * **Farm TVL**: (Pool LP staked / Pool LP supply) × Pool TVL * **Pool TVL**: Pool token A × token A USD rate + Pool token B × token B USD rate # DAMM v1 Formulas Source: https://docs.meteora.ag/overview/products/damm-v1/damm-v1-formulas Mathematical formulas for the DAMM v1 constant-product AMM: price impact, liquidity provision, and fee calculations. DAMM v1 is a traditional full-range liquidity AMM with multiple curve support. # Constant Product Curve (xy = k) The constant product formula maintains liquidity invariance through the following relationships: ## Invariant Formula ```math theme={"system"} k = \text{token}_a \times \text{token}_b ``` ## Liquidity Invariant (D) ```math theme={"system"} D = \sqrt{\text{token}_a \times \text{token}_b} ``` ## Stable Swap Curve (StableSwap) Implements Curve Finance's StableSwap algorithm via Saber StableSwap. ## Core StableSwap Invariant ```math theme={"system"} A \cdot n^n \cdot \sum_{i} x_i + D = A \cdot n^n \cdot D + \frac{D^{n+1}}{n^n \cdot \prod_{i} x_i} ``` **Where:** * `A` = amplification coefficient * `n` = number of tokens (2 for pairs) * `x_i` = token amounts * `D` = invariant *** # Fee Calculation Formulas ## Trading Fees ### Base Trading Fee ```math theme={"system"} \text{fee} = \frac{\text{token\_amount} \times \text{fee\_numerator}}{\text{fee\_denominator}} ``` **Where:** * `fee_denominator` = 100,000 # LST Pools Source: https://docs.meteora.ag/overview/products/damm-v1/lst-pools Liquid Staking Token (LST) pools in DAMM v1 — purpose-built for SOL/LST pairs with stable pricing that accounts for the staking rate. With Dynamic LST Pools, we aim to greatly enhance the options for both LST creators, liquidity providers, and users to grow liquidity and promote the adoption of liquid staking tokens on Solana. Growing LST adoption has the potential to solve some of the major blockers in Solana DeFi. There is \~\$9.5B worth of capital (383M SOL) in directly staked SOL with less than 3% in LSTs. Growing LST adoption would help unlock that capital and put it to work in Solana DeFi dramatically increasing liquidity, volume, and the number of tradable assets. # What are DAMM v1 LST pools? The price of LSTs is constantly increasing with respect to the staked token as staking rewards get distributed every epoch. This price increase leads to impermanent loss (IL) for LPs in any xSOL/SOL pool. Our Dynamic LST pools are stable and mitigate IL from this price increase by continually tracking the price of an xSOL token directly from the LST’s on-chain program. By avoiding the use of price oracles, we remove a dependency and a potential exploit vector. # How does it work? For liquidity providers (LPs), this means you can deposit and withdraw at any time without having to worry about IL or whether the APY you are earning is enough to offset the IL. Additionally, our Dynamic LST Pools utilize the stable curve AMM model in order to concentrate the liquidity to offer low-slippage trades and increase the volume capture from swap aggregators like Jupiter. LPs benefit from the increased volume with better revenue from fees. And unlike concentrated liquidity automated market makers (CLMMs), an LP does not have to constantly manage their liquidity positions. A major problem for growing liquidity for any token is an overreliance on farming rewards. Often times it means having to utilize aggressive token emissions or maintain farming rewards over a longer period of time to maintain a certain level of liquidity. You generally see this if trading fees cannot support the liquidity depth in an AMM pool. Our Dynamic LST Pools utilize Meteora’s Dynamic Vaults to provide a more sustainable way to grow and retain liquidity by lending out the idle capital in the pool to earn an additional yield. This allows LPs to continuously earn lending yield even when trading volume dips or farming rewards end. # So what does this mean for liquid staking protocols? Our Dynamic LST Pools powered by [Dynamic Vaults](/overview/other-products/dynamic-vault/what-is-dynamic-vault) offer a more sustainable way to grow liquidity for your LST. You are less reliant on farming rewards to grow your liquidity and LPs are less likely to leave when your farming rewards end. Additionally, you’ll be able to support a deeper liquidity depth than your volume/fees may currently allow. This can be crucially important in the early days when you are looking to build up the trading volumes for your LST. We’ve been working hard to support our partners Marinade Finance, Jito Labs, and SolBlaze in helping them achieve their specific goals for their LST pools and will be providing that same level of support for any project that wants to launch a Dynamic LST Pool with us. # Pools with Farms Source: https://docs.meteora.ag/overview/products/damm-v1/pools-with-farms How farming works on DAMM v1 pools — LPs can stake their LP tokens to earn additional token rewards on top of swap fees and vault yield. Our farming program for Dynamic AMM (DAMM v1) Pools allows Liquidity Providers, who deposit in Meteora pools, to stake LP token to earn rewards. Rewards come from partners with a maximum of 2 reward tokens for a farming pool. There can be multiple farming pools for a Meteora pool. Farmers should notice on APR and Expiration before staking LP token to a farming pool. Here are steps to integrate with the farming program: Deposit into a Meteora pool to receive LP tokens, which represent your share in the pool. Then, stake your LP tokens in a farming pool to start earning rewards. If you have staked LP tokens in a farming pool, you can claim up to two different reward tokens provided by the pool at any time. To withdraw from a Meteora pool, first unstake your LP tokens from the farming pool. Once unstaked, you can withdraw your liquidity from the Meteora pool as usual. # How do I create a new farm? Farms are permissioned. Head to Meteora's [discord](https://discord.gg/meteora) and open a ticket. Provide the following information: * DAMM v1 pool address or Link to the pool you want to create a farm for * Reward A token mint address * Reward B token mint address (optional) * Reward Duration (in seconds) - We recommend 4 weeks Whenever you add rewards it resets the farm duration. Once rewards are added into the farm, they cannot be removed. Sometimes, at the end of the farm period, there could be spare rewards remaining due to 0 LP stakers in the farm during the farm period. These remaining rewards can be linearly distributed again if you extend the farm period. Head to our [rewards admin dashboard](https://meteora-admin.vercel.app/) to seed the pool with the rewards or seed the rewards via the [farming ts-sdk](/developer-guide/guides/damm-v1/farming-sdk/getting-started). # Stable Pools Source: https://docs.meteora.ag/overview/products/damm-v1/stable-pools DAMM v1 stable pools use a StableSwap invariant optimized for pegged assets (stablecoins, LSTs), offering lower slippage than constant-product pools. # How do DAMM v1 Stable Pools work? Meteora's Dynamic AMM Stable Pools are AMMs utilizing the stable curve that support token prices from 0 to infinity. Stable Pools are suitable if both of your tokens are stable coins i.e. USDC-USDT, USDS-USDC. Using a Stable Pool helps ensure that the liquidity ratio between the token pair remains at 1:1. Stable Pools also share similar benefits with the volatile Dynamic AMM Pools. For example, Stable Pools compose on top of [Dynamic Vaults](/overview/other-products/dynamic-vault/what-is-dynamic-vault) lending aggregator that rebalances funds (e.g. USDC/USDT/SOL) every minute across various external lending protocols e.g. Kamino, Save (Solend), and Marginfi to optimize yield and reduce risk. This added yield helps drive sustainable liquidity, as it is attractive for LPs to contribute liquidity in the pool even if trading fees are lower than usual or there is a lack of LM rewards. * Dynamic Stable Pools are concentrated, so they capture a lot more trading volume and fees. * Dynamic Stable Pools earn from lending the idle liquidity out to external lending protocols. * Dynamic Stable Pools do not require active LP management. You can set and forget it. Dynamic Stable Pools have the Stable tag on the UI. # Fees Stable Swap pools use a **0.01%** trade fee with **0%** Protocol Fee and **100%** LP Fee. See [DAMM v1 Fee and APY Calculation](/overview/products/damm-v1/damm-v1-fee-and-apy-calculation) for how protocol fees apply across pool types. # What is AMP in a DAMM v1 Stable Pool? The AMP (amplification) factor controls how concentrated the liquidity is in the stable pool, which relates to how far the ratio of 1:1 the assets will go before it starts to charge more for trades that further unbalance the ratio and charge less for trades that move the ratio of assets back to 1:1. # What's DAMM v1? Source: https://docs.meteora.ag/overview/products/damm-v1/what-is-damm-v1 DAMM v1 is Meteora's constant-product AMM (x·y=k) that earns LPs both swap fees and additional yield from idle liquidity deployed to lending protocols via Dynamic Vaults. Meteora's Dynamic AMM Pools are similar to constant product pools that support token prices from 0 to infinity. LPs on Dynamic AMM Pools earn both swap fees and yield from lending platforms. The price of your token in a Dynamic AMM (Volatile) Pool is based on the formula: ```math theme={"system"} x*y = k ``` * x and y are the quantities of the two tokens in the pool (e.g. MET and USDC). * k is a constant. As trades occur, the product of the amounts of the two tokens must remain the same. * If someone buys MET with USDC from your pool, the amount of MET in your pool decreases, and the amount of USDC increases. The DAMM v1 Pool adjusts the price based on the new token balances in the pool. # Earn additional yield by utilizing lending sources DAMM v1 Pools have a unique yield infrastructure where pools are built on top of the capital allocation layer. To the user, DAMM v1 Pools look similar to standard AMMs that uses the proven SPL-token swap. But underneath the hood, assets in the pools will be deposited directly into the Dynamic Vaults in the yield layer and USDC/SOL/USDT tokens get dynamically allocated to external lending protocols to generate yield and rewards, reducing the reliance on liquidity mining to attract liquidity. Overreliance on liquidity mining to attract LPs is unsustainable and can cause issues such as token inflation and short-term liquidity when LPs lose interest after the rewards end. Our Dynamic AMM Pools avoid this through effective capital allocation mechanisms of the idle assets to earn yield for the LPs. This allows LPs to receive yield from a few different places — the lending interest, the liquidity mining rewards collected from the platforms, the AMM trading fees, and Meteora liquidity mining rewards (when available). # Permanently lock liquidity and claim fees from locked liquidity Moreover, LPs can choose to permanently lock their liquidity on Dynamic AMM Pool to raise community confidence, while continuing to earn and claim fees from this locked liquidity. This helps to create a more sustainable and long-term liquidity provision for the ecosystem that prioritizes value creation and attracts committed LPs. To cater to memecoin launches, Memecoin Pools (a subset of Dynamic AMM Pools) have a dynamic fee, which ranges from 0.15%-15% and is set by the protocol. This fee may be changed by the protocol over time to optimize for different launches and market conditions. Memecoin Pool LPs also earn lending yield from the locked SOL and USDC liquidity in the pool. **Additional info:** Compare between DLMM, DAMM v1, and DAMM v2 [here](https://docs.google.com/spreadsheets/d/1-W2KE2PT18lmWKF6kB-7aolUBk2e5QvETL3D7g3F_VE/edit?usp=sharing). # Collect Fee Modes Source: https://docs.meteora.ag/overview/products/damm-v2/collect-fee-modes The three ways DAMM v2 pools can collect trading fees: BothToken (both tokens), OnlyB (quote only), and Compounding (auto-reinvest into liquidity). ## Overview Every DAMM v2 pool has a `collectFeeMode` that determines how trading fees flow to LPs. This is set at pool creation and cannot be changed. | Mode | Value | Fee Token(s) | Single-Sided | Price Range | | ------------- | ----- | ------------------------- | ------------ | --------------- | | `BothToken` | `0` | Token A + Token B | ✅ | Any | | `OnlyB` | `1` | Token B only | ✅ | Any | | `Compounding` | `2` | Token B (auto-reinvested) | ❌ | Full range only | *** ## BothToken (mode 0) Fees accumulate in the output token of each swap. When a trader swaps A→B, the fee is taken from the output (token B). When they swap B→A, the fee is taken from the output (token A). **LP fee claim:** Separate `claimPositionFee` instruction. Both `fee_a_pending` and `fee_b_pending` on the position are claimable. **Use when:** You want LPs to accumulate fees in both tokens — typical for symmetric liquidity provision. *** ## OnlyB (mode 1) All fees are collected in token B (the quote token), regardless of swap direction. For A→B swaps, the fee is taken from the output token (token B) directly. For B→A swaps, the fee is taken from the output token (token A) and then converted to the quote token (token B) internally. **LP fee claim:** Only `fee_b_pending` accumulates. `fee_a_pending` is always 0. **Use when:** LPs prefer a single, predictable fee token. Common for one-sided launches where token A is the new token and token B is SOL/USDC. *** ## Compounding (mode 2) The most distinctive mode. A configurable percentage of each trade's LP fee (`compoundingFeeBps`) is **automatically reinvested** back into the pool's reserves as token B rather than being held for claiming. The remainder is still claimable. ### How it works ``` Total Trading Fee ├── Protocol Fee (protocol_fee_percent % of total trading fee) └── LP Fee (remainder) ├── compoundingFeeBps / 10000 → added to pool token B reserves (grows pool liquidity) └── remainder → fee_b_pending (claimable by LP) ``` `compoundingFeeBps` is a u16 (0–10000). E.g., `5000` = 50% of LP fees compound, 50% claimable. ### Constraints * **Full range only** — Compounding pools use `MIN_SQRT_PRICE` to `MAX_SQRT_PRICE`. Custom price ranges are not supported. * **Balanced pools only** — Both `tokenAAmount` and `tokenBAmount` must be > 0. One-sided deposits cause a `DEAD_LIQUIDITY` error. * `compoundingFeeBps` must be > 0 when `collectFeeMode = 2` (`InvalidCompoundingFeeBps` error if zero). ### Swap result fields In compounding mode, the swap result exposes two separate fee fields: | Field | Description | | ---------------- | ------------------------------------- | | `claimingFee` | Portion the LP can claim later | | `compoundingFee` | Portion reinvested into pool reserves | For non-compounding modes, `compoundingFee = 0` and `claimingFee = tradingFee`. ### Reading from events The `EvtSwap2` event emits `collect_fee_mode` on every swap, so you can filter events by mode to track fee behaviour. *** ## Choosing a Mode Use **OnlyB (mode 1)**. Fees accumulate in your quote token (SOL/USDC), LPs get a clean single-token yield, and it works with one-sided deposits for a bootstrap launch. Use **BothToken (mode 0)**. LPs benefit from fee accumulation in the base token if it appreciates. Use **Compounding (mode 2)**. Pool depth increases with every trade. Best for mature, full-range pools with long-term LPs who prefer position growth over regular fee claims. # DAMM v2 Fee Calculation Source: https://docs.meteora.ag/overview/products/damm-v2/damm-v2-fee-calculation How trading fees are calculated and distributed in DAMM v2 pools, including base fee, dynamic fee, and compounding fee modes. DAMM v2 LPs earn a swap fee from traders when they perform a swap. The fees can be collected in three ways depending on the pool's `collectFeeMode`: * **BothToken (0)** — fees claimable in both base and quote tokens * **OnlyB (1)** — fees claimable in quote token only * **Compounding (2)** — a configurable percentage of fees is automatically reinvested back into the pool reserves; the remainder is claimable In BothToken and OnlyB modes, fees are not compounded into pool liquidity and can be claimed separately. In Compounding mode, a portion of fees is automatically reinvested — see [Compounding Fee Mode](#compounding-fee-mode) below. # Total Trading Fee The total swap fee ($f_s$) will have two components: 1. **A base fee** ($f_b$) 2. **A variable fee** ($f_v$) The **total swap fee** is calculated as: ```math theme={"system"} f_s = f_b + f_v ``` The variable fee ($f_v$) is a function of real-time price volatility. The fee rate will be applied to the swap amount in each liquidity bin and distributed proportionally to the LPs in that bin. LPs can claim these fees whenever they are available. ## Base Fee The base fee of a pool can be configured by the pool creator in the following ways: * **Fixed Base Fee**: A fixed fee that is applied to the swap amount. * **Fee Time Scheduler**: A fee decay mechanism that decays the fee from a high starting fee to an ending fixed base fee over a period of time. * **Fee Market Cap Scheduler**: A fee decay mechanism that decays the fee based on price movement rather than time. * **Rate Limiter**: A fee slope mechanism that increases the fee based on trade size. You can only choose one of the four options for the base fee. ### Fixed Base Fee Fixed base fee is a fixed fee that is applied to the swap amount. The fee can range from 0.01% to 50%. It is specified in the config key used for the pool creation. ### Fee Time Scheduler Fee Time Scheduler is a fee decay mechanism that decays the fee from a high starting fee to an ending base fee over time. The fee math calculation for the scheduler can be found [here](/anti-sniper-suite/fee-time-scheduler/fee-time-scheduler-math). ### Fee Market Cap Scheduler Fee Market Cap Scheduler is a fee decay mechanism that decays the fee based on price movement (market cap growth) rather than time. Fees reduce progressively as the token price increases from its starting point. The fee math calculation for the scheduler can be found [here](/anti-sniper-suite/fee-market-cap-scheduler/fee-market-cap-scheduler-math). ### Rate Limiter Rate Limiter is a fee slope mechanism that starts at a fixed base fee and increases the fee based on trade size. This helps deter large trades from manipulating the market during launch. The fee math calculation for the rate limiter can be found [here](/anti-sniper-suite/rate-limiter/rate-limiter-math). ## Dynamic Fee (Variable Fee) The variable fee is the core of the dynamic fee mechanism. It increases with market volatility. ```math theme={"system"} f_v = (v_a \times s)^2 \times C / 100000000000 ``` where: * **Volatility Accumulator** ($v_a$): A measure of recent price volatility * **Bin Step** ($s$): A parameter that defines the price granularity for measuring volatility * **Variable Fee Control** ($C$): A parameter to control the magnitude of the variable fee ### Volatility Accumulator The Volatility Accumulator tracks price movements. It's updated with every swap. ```math theme={"system"} v_a = \min(v_{max}, v_r + \Delta p \times 10000) ``` where: * **Max Volatility Accumulator** ($v_{max}$): A cap on the volatility measure to prevent fees from becoming excessively high * **Volatility Reference** ($v_r$): A decayed value of the volatility accumulator * **Price Change** ($\Delta p$): The price change since the last reference update, measured in "bins" #### Price Change The price change is calculated based on the change in the square root of the price. ```math theme={"system"} \Delta p = (\sqrt{p_c / p_r} - 1) / s \times 2 ``` where $p_c$ is current price and $p_r$ is reference price. #### Volatility Reference To ensure that the dynamic fee reflects recent volatility, the Volatility Reference decays over time. ```math theme={"system"} v_r = v_a \times R / 10000 ``` The decay mechanism is based on the time elapsed since the last significant trade: * If elapsed time \< filter period: No change. This ignores very high-frequency trades. * If filter period ≤ elapsed time \< decay period: The volatility reference is reduced. * If elapsed time ≥ decay period: The volatility reference is reset to 0. This happens if there are no significant trades for an extended period. # Max Dynamic Fee on DAMM v2 If you set the `useDynamicFee` to `true` in the config key when you deploy via [DAMM v2 Launch Pool](/developer-guide/quick-launch/damm-v2-launch-pool), the max dynamic fee on DAMM v2 will be less than or equals to 20% of the Base Fee. You can also choose to configure the dynamic fee manually based on the math formula above. **Example:** * Base Fee = 1% * Dynamic Fee = 0.2% * Total Trading/LP Fee = 1.2% # Compounding Fee Mode Compounding Fee Mode is a third fee collection option (`collect_fee_mode = 2`) where a configurable percentage of trading fees is automatically reinvested into the pool reserves, instead of being held for LP claiming. The rest of the fee is still claimable by LPs as normal. This mode is configured using the `compounding_fee_bps` parameter, which defines how many basis points of the LP fee are compounded. For example, a value of 5000 means 50% of the trading fee auto-compounds, and the remaining 50% is claimable. Pools using Compounding Fee Mode operate as a standard constant-product AMM with no concentrated price range. See [DAMM v2 Formulas](/overview/products/damm-v2/damm-v2-formulas) for details. ## Fee Split The protocol fee is first subtracted from the total trading fee. The compounding/claiming split then applies to the remaining LP fee: ```math theme={"system"} \text{protocol\_fee} = f_s \times \frac{\text{protocol\_fee\_percent}}{100} ``` ```math theme={"system"} \text{lp\_fee} = f_s - \text{protocol\_fee} ``` ```math theme={"system"} \text{compounding\_fee} = \text{lp\_fee} \times \frac{\text{compounding\_fee\_bps}}{10000} ``` ```math theme={"system"} \text{claiming\_fee} = \text{lp\_fee} - \text{compounding\_fee} ``` So: ```math theme={"system"} \text{lp\_fee} = \text{claiming\_fee} + \text{compounding\_fee} ``` **Example:** * Total trading fee ($f_s$) = 1% * Protocol fee = 20% of total → 0.2% * LP fee = 0.8% * `compounding_fee_bps` = 3000 (30%) * Compounding fee = 0.24% (auto-reinvested into pool reserves) * Claiming fee = 0.56% (claimable by LPs) # DAMM v2 Formulas Source: https://docs.meteora.ag/overview/products/damm-v2/damm-v2-formulas Mathematical formulas for liquidity addition/removal, pricing, and LP token calculation in DAMM v2 concentrated liquidity pools. DAMM v2 is a constant product AMM that operates between a `sqrt_min_price` and a `sqrt_max_price`. # Liquidity Addition / Removal When adding or removing liquidity, for a given liquidity delta `ΔL`, the required token amounts are calculated as: ```math theme={"system"} \Delta a = \Delta L \times \left(\frac{1}{\sqrt{P}} - \frac{1}{\sqrt{P_{\text{max}}}}\right) ``` ```math theme={"system"} \Delta b = \Delta L \times (\sqrt{P} - \sqrt{P_{\text{min}}}) ``` # LP Token Amount Example from token B: ```math theme={"system"} \text{Token B Amount} = \frac{\text{LP Token} × (\text{currentSqrtPrice} - \text{minSqrtPrice})}{2^{128}} ``` so you can reverse: ```math theme={"system"} \text{LP Token} = \frac{\text{Token B Amount} × 2^{128}}{\text{currentSqrtPrice} - \text{minSqrtPrice}} ``` # Farming Rewards The farming rewards are calculated as:
```math theme={"system"} \text{Reward per token} = \frac{\text{Elapsed Time} \times \text{Reward Rate} \times 2^{128}}{\text{Total Liquidity}} ```
```math theme={"system"} \text{User reward} = \text{Position Liquidity} \times (\text{Current Reward per Token} - \text{User Last Reward per Token}) \gg 192 ```
# Compounding Fee Mode When a pool uses Compounding Fee Mode (`collect_fee_mode = 2`), it operates as a standard constant-product AMM with no concentrated price range. The pool reserves grow over time as a portion of trading fees are automatically reinvested. ## Constant-Product Formula The pool maintains the invariant: ```math theme={"system"} \text{token\_a\_amount} \times \text{token\_b\_amount} = k ``` where $k$ is a constant. Unlike the standard DAMM v2 concentrated liquidity formula, there is no `sqrt_min_price` or `sqrt_max_price` bound — liquidity spans the full price range. Pools with `layout_version == 1` track `token_a_amount` and `token_b_amount` directly in the pool state, enabling accurate reserve accounting for the compounding mechanism. ## Fee Split Formulas The protocol fee is first subtracted from the total trading fee. The compounding/claiming split then applies to the LP fee (after protocol fee is removed): ```math theme={"system"} \text{protocol\_fee} = f_s \times \frac{\text{protocol\_fee\_percent}}{100} ``` ```math theme={"system"} \text{lp\_fee} = f_s - \text{protocol\_fee} ``` ```math theme={"system"} \text{compounding\_fee} = \text{lp\_fee} \times \frac{\text{compounding\_fee\_bps}}{10000} ``` ```math theme={"system"} \text{claiming\_fee} = \text{lp\_fee} - \text{compounding\_fee} ``` The compounding fee is added directly to the pool reserves, increasing $k$ over time and benefiting all LPs proportionally. # Price Impact The price impact for a swap can be calculated as: ```math theme={"system"} \text{Price Impact} = \frac{|\text{New Sqrt Price} - \text{Old Sqrt Price}|}{\text{Old Sqrt Price}} ``` # Farming Rewards Source: https://docs.meteora.ag/overview/products/damm-v2/farming-rewards How DAMM v2's built-in farming works — reward slots, pro-rata distribution, initializing rewards, funding, and claiming. No separate staking contract needed. ## Overview Every DAMM v2 pool has **two built-in reward slots** (`reward_infos[0]` and `reward_infos[1]`). Any SPL token (including Token 2022) can be used as a reward. LPs earn rewards proportional to their total position liquidity — including vested and permanently locked liquidity. No staking contract, no LP token wrapping. Positions earn rewards automatically while they hold liquidity. *** ## Reward Distribution Model Rewards use a **reward-per-token-stored** accumulator pattern (similar to Uniswap v3 staking): ``` reward_rate = total_funded_amount / reward_duration reward_per_token += reward_rate × elapsed_time / total_pool_liquidity pending_reward[position] = position_liquidity × (reward_per_token - checkpoint[position]) ``` | Field | Description | | ------------------------- | ------------------------------------------------------------------ | | `reward_per_token_stored` | Cumulative rewards per unit liquidity (U256, stored as `[u8; 32]`) | | `reward_rate` | Tokens emitted per second (or slot) | | `reward_duration_end` | When the current campaign ends | | `total_claimed_rewards` | Lifetime claimed by this position | ### Why U256? The accumulator uses 256-bit math to avoid overflow over long reward campaigns with small reward rates or large liquidity values. *** ## Lifecycle ### 1. Initialize a Reward The pool creator calls `initializeReward` to set up one of the two reward slots: ```typescript theme={"system"} const tx = await cpAmm.initializeReward({ pool: poolAddress, rewardMint: rewardTokenMint, funder: wallet.publicKey, rewardIndex: 0, // 0 or 1 rewardDuration: 30 * 24 * 3600, // 30 days in seconds }); ``` **Constraints:** * `reward_index` must be 0 or 1 (`InvalidRewardIndex` if out of range) * `reward_duration` must be between 86400 seconds (1 day) and 31536000 seconds (1 year) (`InvalidRewardDuration`) * Cannot re-initialize an already active slot (`RewardInitialized`) **Event emitted:** `EvtInitializeReward` *** ### 2. Fund the Reward Transfer reward tokens into the reward vault: ```typescript theme={"system"} const tx = await cpAmm.fundReward({ pool: poolAddress, rewardIndex: 0, amount: new BN(1_000_000_000_000), // total reward budget }); ``` Funding sets `reward_rate = amount / remaining_duration` and extends the campaign if called mid-campaign. **Events emitted:** `EvtFundReward` with `pre_reward_rate` and `post_reward_rate` *** ### 3. LPs Accrue Rewards Passively As time passes, `reward_per_token_stored` increases. Every time a position is touched (add/remove liquidity, claim fees, claim reward), the position's checkpoint is updated: ``` new_reward = position_liquidity × (reward_per_token_stored - checkpoint) pending += new_reward checkpoint = reward_per_token_stored ``` *** ### 4. Claim Rewards ```typescript theme={"system"} const tx = await cpAmm.claimReward({ owner: wallet.publicKey, position: positionAddress, pool: poolAddress, rewardIndex: 0, }); ``` This transfers all `reward_pendings[0]` to the owner and resets the pending amount. **Event emitted:** `EvtClaimReward` *** ## Updating a Reward Campaign | Action | Instruction | Notes | | ------------------- | -------------------------- | ------------------------------------------------------------ | | Change duration | `updateRewardDuration` | Can only extend, not shorten an active campaign | | Change funder | `updateRewardFunder` | New funder becomes responsible for future `fundReward` calls | | Withdraw ineligible | `withdrawIneligibleReward` | Reclaim tokens after campaign ends with unfunded remainder | *** ## Reward Constraints | Constraint | Details | | ------------------------------ | ----------------------------------------------------------------------------- | | Max reward slots | 2 per pool | | Reward during locked liquidity | ✅ Vested + permanent locked liquidity earns rewards | | Token 2022 rewards | ✅ Supported | | Native SOL rewards | ❌ (use wrapped SOL) | | Frozen vault | If reward vault is frozen, must skip reward (`RewardVaultFrozenSkipRequired`) | *** ## Reading Pending Rewards (TypeScript) ```typescript theme={"system"} const poolState = await cpAmm.fetchPoolState(poolAddress); const positionState = await cpAmm.fetchPositionState(positionAddress); // Update position reward checkpoints first (simulate on-chain update) const currentTime = Math.floor(Date.now() / 1000); for (let i = 0; i < 2; i++) { const rewardInfo = poolState.rewardInfos[i]; if (rewardInfo.initialized) { const pending = positionState.rewardInfos[i].rewardPendings; console.log(`Reward ${i} pending:`, pending.toString()); } } ``` # Fee Configuration Source: https://docs.meteora.ag/overview/products/damm-v2/fee-configuration All five base fee modes in DAMM v2 — time schedulers, market cap schedulers, and rate limiter — plus dynamic volatility fees and how the fee split works. ## Fee Structure Every DAMM v2 pool has a three-layer fee: ``` Gross Input Amount └── Trading Fee (base_fee + dynamic_fee, capped at 99%) ├── Protocol Fee (protocol_fee_percent % of trading fee) │ └── Referral Fee (portion of protocol fee if referral provided) └── LP Fee (remainder) └── [Compounding only] compoundingFeeBps / 10000 → pool reserves ``` All fee rates are stored as numerators over a fixed denominator (`FEE_DENOMINATOR = 1,000,000,000`), giving 9 decimal places of precision (e.g., fee rate of `2,500,000` = 0.25%). *** ## Base Fee Modes DAMM v2 supports five base fee modes. The mode is encoded in the `BaseFeeInfo` bytes of the pool config. ### 1. FeeTimeSchedulerLinear Fee decays linearly from a starting value over time: ``` fee = cliff_fee_numerator - (passed_period × reduction_factor) passed_period = (current_point - activation_point) / period_frequency ``` **Parameters:** | Field | Description | | --------------------- | ------------------------------------------------ | | `cliff_fee_numerator` | Starting fee rate (numerator over 1,000,000,000) | | `number_of_period` | How many periods to decay over | | `period_frequency` | Slots or seconds per period | | `reduction_factor` | How much to reduce per period | **Use when:** You want a high launch fee that smoothly steps down to a target fee over time (e.g., start at 5%, decay to 0.25% over 10 periods). *** ### 2. FeeTimeSchedulerExponential Fee decays exponentially from a starting value over time: ``` fee = cliff_fee_numerator × (1 - reduction_factor / 10_000) ^ passed_period passed_period = (current_point - activation_point) / period_frequency ``` **Use when:** You want a steep initial decay that flattens as the fee approaches the floor — more natural for launch mechanics. *** ### 3. FeeMarketCapSchedulerLinear Fee decays as the price moves (market-cap based). Instead of time, `passed_period` is computed from price movement: ``` fee = cliff_fee_numerator - (passed_period × reduction_factor) passed_period = (current_sqrt_price - init_sqrt_price) × 10_000 / init_sqrt_price / sqrt_price_step_bps ``` **Use when:** You want the fee to decay as the token price increases — rewarding price discovery with lower fees at higher market caps. *** ### 4. FeeMarketCapSchedulerExponential Same as linear market cap scheduler but with exponential decay: ``` fee = cliff_fee_numerator × (1 - reduction_factor / 10_000) ^ passed_period ``` **Use when:** Similar to linear market cap scheduler but with a smoother decay curve. *** ### 5. RateLimiter A rate limiter that enforces that only one swap can happen per transaction (CPI guard). Used to prevent sandwich attacks and MEV extraction on specific launch configurations. RateLimiter mode validates that exactly one swap instruction exists in the transaction. If more than one is detected, the transaction fails with `FailToValidateSingleSwapInstruction`. *** ## Dynamic Fee On top of the base fee, an optional **dynamic fee** component adjusts fee upward during periods of high price volatility: ``` total_fee = base_fee + dynamic_fee total_fee is capped at MAX_FEE_NUMERATOR (99%) ``` Dynamic fee uses a volatility accumulator (similar to DLMM's dynamic fee mechanism): | Parameter | Description | | ---------------------------- | --------------------------------------------- | | `bin_step` | Price sensitivity step (bps) | | `filter_period` | Time window for volatility averaging | | `decay_period` | How quickly the volatility accumulator decays | | `reduction_factor` | Rate of decay (0–10000) | | `max_volatility_accumulator` | Cap on accumulated volatility | | `variable_fee_control` | Scalar multiplier for the fee component | When `dynamicFeeEnabled = false`, the dynamic fee is always 0. *** ## Protocol & Referral Fee | Parameter | Description | | ---------------------- | --------------------------------------------------------------------- | | `protocol_fee_percent` | Percentage of trading fee that goes to the protocol (0–100) | | `referral_fee_percent` | Percentage of protocol fee that goes to the referral provider (0–100) | Standard pools and Launch Pools use **20%** Protocol Fee and **80%** LP Fee. Swap hosts that include a referral account receive a **Referral Fee** equal to **20%** of the protocol fee. Protocol fees are accumulated in the pool and claimed by the admin via `claimProtocolFee`. *** ## Fee Constraints | Constraint | Value | | ------------------------- | ----------------------------------------- | | Max total fee | 99% (`MAX_FEE_NUMERATOR = 990_000_000`) | | Fee denominator | `1_000_000_000` | | Min fee (floor) | Set by `get_min_fee_numerator()` per mode | | `compoundingFeeBps` range | 0–10000 (only for mode 2) | *** ## Updating Fees Pool fees can be updated post-creation via the `updatePoolFees` instruction (operator/admin only). The `EvtUpdatePoolFees` event is emitted on any fee update. Fee updates are restricted — only the operator or admin can call `updatePoolFees`. Certain constraints (e.g., cannot reduce dynamic fee if the volatility accumulator has pending state) apply. # Liquidity Locking Source: https://docs.meteora.ag/overview/products/damm-v2/liquidity-locking Lock DAMM v2 LP liquidity with cliff + linear vesting schedules or permanently. Two mechanisms: inner vesting (stored in position) and external vesting accounts. ## Overview DAMM v2 supports two types of liquidity locks, both of which move liquidity from `unlocked_liquidity` into restricted buckets on the position account: | Type | Bucket | Withdrawable? | | -------------- | ---------------------------- | ---------------- | | Vesting lock | `vested_liquidity` | Yes, on schedule | | Permanent lock | `permanent_locked_liquidity` | Never | Both types still earn trading fees and farming rewards at the normal rate — only withdrawal is restricted. *** ## Vesting Lock Vesting releases liquidity back to `unlocked_liquidity` on a **cliff + periodic** schedule. ### Schedule Parameters | Parameter | Description | | ------------------------ | ---------------------------------------------- | | `cliff_point` | Slot or timestamp when first unlock occurs | | `period_frequency` | Slots or seconds between each periodic release | | `cliff_unlock_liquidity` | How much liquidity unlocks at the cliff | | `liquidity_per_period` | How much unlocks per period after the cliff | | `number_of_period` | Total number of periods | ### Total locked amount ``` total_locked = cliff_unlock_liquidity + (liquidity_per_period × number_of_period) ``` ### Two vesting account types Vesting schedule stored directly in the position account. No extra account needed. ``` Position └── inner_vesting (InnerVesting) ├── cliff_point ├── period_frequency ├── cliff_unlock_liquidity ├── liquidity_per_period ├── number_of_period └── total_released_liquidity (tracks how much has unlocked so far) ``` **When to use:** Most use cases — simpler, single-account. **Limitation:** Only one vesting schedule per position. If you need multiple vesting tranches, split the position first. A separate `Vesting` account (PDA) holds the schedule. The position just references it. **When to use:** When you need multiple external vesting schedules on a position, or when the vesting schedule needs to be managed by a different authority. Positions with external vesting accounts cannot use `splitPosition` — you must use `validate_no_external_vesting()` first (`UnsupportPositionHasVestingLock` error if you try). ### Refreshing vested liquidity Vested liquidity doesn't auto-unlock. A transaction that calls any position interaction (add/remove liquidity, claim fees, etc.) triggers `refresh_inner_vesting`, which: 1. Calculates `released_liquidity` based on current slot/timestamp vs cliff/period schedule 2. Moves that amount from `vested_liquidity` → `unlocked_liquidity` 3. Clears the inner vesting struct when fully released **Event emitted on lock:** `EvtLockPosition` *** ## Permanent Lock Permanently locked liquidity cannot be withdrawn under any circumstances. It remains in the pool forever, providing a **liquidity floor guarantee**. This is used by token projects to demonstrate long-term commitment to liquidity: ```typescript theme={"system"} const tx = await cpAmm.permanentLockPosition({ owner: wallet.publicKey, position: positionAddress, pool: poolAddress, liquidityDelta: amountToLockPermanently, }); ``` **Event emitted:** `EvtPermanentLockPosition` with: * `lock_liquidity_amount` — amount just locked * `total_permanent_locked_liquidity` — new total permanently locked on this position *** ## Locked Liquidity Still Earns Both vesting and permanently locked liquidity contribute to fee and reward calculations: ```rust theme={"system"} pub fn get_total_liquidity(&self) -> Result { Ok(self.unlocked_liquidity .safe_add(self.vested_liquidity)? .safe_add(self.permanent_locked_liquidity)?) } ``` This total is used for: * Fee accrual (`fee_a_pending`, `fee_b_pending` checkpoints use total liquidity) * Farming reward accrual (both reward slots) *** ## Use Cases Lock founder LP for 12 months with a 6-month cliff and monthly releases: * `cliff_point` = launch\_timestamp + 6 months * `cliff_unlock_liquidity` = 25% of total * `liquidity_per_period` = 12.5% of total * `number_of_period` = 6 (monthly, for 6 months post-cliff) A DAO or protocol wanting to guarantee permanent liquidity depth can lock a portion permanently. The locked liquidity shows on-chain and is verifiable by anyone. Lock ecosystem-provided liquidity with a vesting schedule that aligns with token emission schedules, ensuring liquidity grows alongside token distribution. # Pool Types & Configuration Source: https://docs.meteora.ag/overview/products/damm-v2/pool-types How DAMM v2 pool configs work — static vs dynamic, price range parameters, activation types, and what gets set at pool creation vs config creation. ## Config Types DAMM v2 pools are created from a **config account** that pre-defines pool parameters. Two config types exist: Parameters are fixed when the config is created. All pools created from a static config inherit the same: * Fee structure (base fee mode, dynamic fee, protocol fee %) * `collect_fee_mode` (BothToken / OnlyB / Compounding) * `activation_type` (slot or timestamp) * Price range (`sqrt_min_price`, `sqrt_max_price`) **Best for:** Launchpads and protocols that want uniform pool settings across all their pools. Pool creators define custom parameters at pool creation time. Only available for **private configs** (permissioned via `pool_creator_authority`). Configurable per-pool: * Fee structure * `collect_fee_mode` * `activation_type` and `activation_point` * Price range * Alpha vault settings **Best for:** Protocols that need per-pool customization (Meteora Invent, custom launchpads). *** ## Activation Types Each pool can gate trading behind an activation point: | `activation_type` | Value | Description | | ----------------- | ----- | ---------------------------------------------- | | `Slot` | `0` | Trading opens at a specific Solana slot number | | `Timestamp` | `1` | Trading opens at a specific Unix timestamp | Before the activation point, swaps are disabled. Only whitelisted vault programs (Alpha Vault) can trade. Setting `activation_point: null` (or `0`) opens the pool for trading immediately. *** ## Price Range Every pool has a configured price range defined by: | Parameter | Type | Description | | --------------- | ------ | ------------------------------------------------- | | `sqrtMinPrice` | `u128` | Lower bound of the price range (as √price × 2^64) | | `sqrtMaxPrice` | `u128` | Upper bound of the price range (as √price × 2^64) | | `initSqrtPrice` | `u128` | Starting price at pool creation | ### Full Range vs Concentrated | Mode | `sqrtMinPrice` | `sqrtMaxPrice` | | ------------------ | ---------------- | ---------------- | | Full range (x·y=k) | `MIN_SQRT_PRICE` | `MAX_SQRT_PRICE` | | Concentrated | Custom lower | Custom upper | `CollectFeeMode.Compounding` (mode 2) **requires** full range. The SDK enforces `MIN_SQRT_PRICE` / `MAX_SQRT_PRICE` for compounding pools. ### Converting Price to √Price ``` sqrtPrice = √(tokenB_per_tokenA) × 2^64 ``` The TypeScript SDK provides `getSqrtPriceFromPrice(price, decimalsA, decimalsB)` for this conversion. *** ## Pool Creation Parameters When calling `createCustomPool`, the key parameters are: | Parameter | Type | Description | | ----------------- | ---------------- | --------------------------------------------------------- | | `tokenAMint` | `PublicKey` | Base token mint | | `tokenBMint` | `PublicKey` | Quote token mint (must be SOL or USDC for public configs) | | `tokenAAmount` | `BN` | Initial base token deposit | | `tokenBAmount` | `BN` | Initial quote token deposit (0 for one-sided) | | `sqrtMinPrice` | `BN` | Lower price bound | | `sqrtMaxPrice` | `BN` | Upper price bound | | `initSqrtPrice` | `BN` | Initial pool price | | `liquidityDelta` | `BN` | Initial liquidity (calculated from amounts) | | `collectFeeMode` | `CollectFeeMode` | 0 = BothToken, 1 = OnlyB, 2 = Compounding | | `activationType` | `ActivationType` | 0 = Slot, 1 = Timestamp | | `activationPoint` | `BN \| null` | When trading opens (null = immediate) | | `hasAlphaVault` | `boolean` | Whether an alpha vault is associated | | `poolFees` | `PoolFeesParams` | Full fee configuration | *** ## Pool State On-chain, a pool account stores: | Field | Type | Description | | -------------------- | ----------------- | ------------------------------------------- | | `liquidity` | `u128` | Current total liquidity in the active range | | `sqrtPrice` | `u128` | Current √price | | `sqrtMinPrice` | `u128` | Pool price range lower bound | | `sqrtMaxPrice` | `u128` | Pool price range upper bound | | `tokenAAmount` | `u64` | Token A reserves | | `tokenBAmount` | `u64` | Token B reserves | | `collectFeeMode` | `u8` | Fee collection mode | | `activationPoint` | `u64` | Trading activation point | | `poolStatus` | `u8` | Pool enabled/disabled status | | `poolType` | `u8` | 0 = Permissionless, 1 = Customizable | | `feeAPerTokenStored` | `[u8; 32]` | Cumulative fee A per unit liquidity (U256) | | `feeBPerTokenStored` | `[u8; 32]` | Cumulative fee B per unit liquidity (U256) | | `rewardInfos` | `[RewardInfo; 2]` | Farming reward state (2 slots) | | `metrics` | `PoolMetrics` | Cumulative swap/liquidity stats | # Position Management Source: https://docs.meteora.ag/overview/products/damm-v2/position-management How DAMM v2 positions work — NFT ownership, liquidity buckets, adding and removing liquidity, claiming fees, and closing positions. ## How Positions Work Every DAMM v2 LP position is an on-chain account paired with a **position NFT**. Whoever holds the NFT controls the position. This design enables positions to be: * Transferred between wallets (NFT transfer = position ownership transfer) * Traded on secondary markets * Used as collateral in future integrations ### Position Account Structure | Field | Type | Description | | ---------------------------- | --------------------- | ---------------------------------------------------- | | `pool` | `Pubkey` | The pool this position belongs to | | `nft_mint` | `Pubkey` | The position NFT mint address | | `unlocked_liquidity` | `u128` | Freely withdrawable liquidity | | `vested_liquidity` | `u128` | Liquidity releasing on a vesting schedule | | `permanent_locked_liquidity` | `u128` | Liquidity locked forever | | `fee_a_pending` | `u64` | Unclaimed token A fees | | `fee_b_pending` | `u64` | Unclaimed token B fees | | `fee_a_per_token_checkpoint` | `[u8; 32]` | Last fee-per-token snapshot (U256) | | `fee_b_per_token_checkpoint` | `[u8; 32]` | Last fee-per-token snapshot (U256) | | `reward_infos` | `[UserRewardInfo; 2]` | Per-position farming reward state | | `inner_vesting` | `InnerVesting` | Inline vesting schedule (no separate account needed) | | `metrics` | `PositionMetrics` | Cumulative claimed fee totals | *** ## Creating a Position A position is created when a pool is initialized via `createCustomPool`. The first position is created as part of pool setup. Additional positions can be created via `addLiquidity` / separate position creation instructions. **Required accounts:** * `payer` — who pays rent * `creator` — who receives protocol creation fee credit * `positionNft` — new Keypair whose public key becomes the NFT mint * `tokenAMint`, `tokenBMint` — pool tokens * Pool config account **Events emitted:** `EvtCreatePosition`, `EvtInitializePool` (on first creation), `EvtLiquidityChange` *** ## Adding Liquidity After a pool is live, any wallet can add liquidity to an existing position (if they own the position NFT) or create a new position. ### Calculating how much to deposit Use `getDepositQuote` on the SDK with the current pool state: ```typescript theme={"system"} const poolState = await cpAmm.fetchPoolState(poolAddress); const depositQuote = cpAmm.getDepositQuote({ inAmount: new BN(1_000_000_000), isTokenA: true, // true = specify token A amount, false = token B sqrtPrice: poolState.sqrtPrice, minSqrtPrice: poolState.sqrtMinPrice, maxSqrtPrice: poolState.sqrtMaxPrice, collectFeeMode: poolState.collectFeeMode, tokenAAmount: poolState.tokenAAmount, tokenBAmount: poolState.tokenBAmount, liquidity: poolState.liquidity, }); console.log("Token A to deposit:", depositQuote.tokenAAmount.toString()); console.log("Token B to deposit:", depositQuote.tokenBAmount.toString()); console.log("Liquidity delta:", depositQuote.liquidityDelta.toString()); ``` **Event emitted:** `EvtLiquidityChange` with `change_type: 0` *** ## Removing Liquidity To withdraw liquidity, pass the liquidity delta you want to remove. The program returns proportional token amounts from the pool's current reserves. ### Calculating withdraw amounts ```typescript theme={"system"} const withdrawQuote = cpAmm.getWithdrawQuote({ liquidityDelta: positionState.unlockedLiquidity, // withdraw all unlocked sqrtPrice: poolState.sqrtPrice, minSqrtPrice: poolState.sqrtMinPrice, maxSqrtPrice: poolState.sqrtMaxPrice, collectFeeMode: poolState.collectFeeMode, tokenAAmount: poolState.tokenAAmount, tokenBAmount: poolState.tokenBAmount, liquidity: poolState.liquidity, }); console.log("Token A out:", withdrawQuote.outAmountA.toString()); console.log("Token B out:", withdrawQuote.outAmountB.toString()); ``` Only `unlocked_liquidity` can be withdrawn. `vested_liquidity` and `permanent_locked_liquidity` cannot be removed (unless vesting releases them first). **Event emitted:** `EvtLiquidityChange` with `change_type: 1` *** ## Claiming Fees Fee claims are separate from liquidity removal. Accumulated fees sit in `fee_a_pending` and `fee_b_pending` until claimed. ```typescript theme={"system"} const tx = await cpAmm.claimPositionFee({ owner: wallet.publicKey, position: positionAddress, pool: poolAddress, }); ``` **Event emitted:** `EvtClaimPositionFee` with `fee_a_claimed` and `fee_b_claimed` amounts. In `CollectFeeMode.OnlyB` and `CollectFeeMode.Compounding` mode, `fee_a_claimed` is always 0. *** ## Splitting Positions A position can be split into two positions using `splitPosition`. This is useful for: * Separating vesting tranches * Transferring a portion of a position to a different wallet * LP token distribution events The split is specified as a numerator over `SPLIT_POSITION_DENOMINATOR` (1,000,000,000). E.g., `split_numerator = 500_000_000` splits the position 50/50. The split proportionally divides: * `unlocked_liquidity` * `permanent_locked_liquidity` * `fee_a_pending`, `fee_b_pending` * Reward pendings (both slots) * Inner vesting schedule (cliff amounts and per-period amounts) **Event emitted:** `EvtSplitPosition3` *** ## Closing a Position A position can be closed only when it is **empty**: * `get_total_liquidity() == 0` (all liquidity removed) * `fee_a_pending == 0`, `fee_b_pending == 0` (fees claimed) * All reward pendings == 0 (rewards claimed) Closing returns the rent to the payer and burns the position NFT. **Event emitted:** `EvtClosePosition` # Token 2022 Extensions Source: https://docs.meteora.ag/overview/products/damm-v2/token-2022-extensions DAMM v2 supports SPL Token 2022 mints and common extensions, with special handling for permissioned and unsupported extensions. ## Token 2022 Support DAMM v2 supports pools and positions using Token 2022 SPL tokens, including those with various Token 2022 extensions. The program automatically detects the mint's owner program and applies correct behaviors for Pool, Swap, and LP reward flows. ### Pool State: Token Program Flags * The `token_a_flag` and `token_b_flag` fields on the pool state indicate which token program each mint uses: * `0` = SPL Token Program (legacy) * `1` = SPL Token 2022 Program ### Permissionlessly Supported Extensions The following Token 2022 extensions are supported **permissionlessly** (no badge or special registration required): * **Transfer Fee (TransferFeeConfig)** * Trading and liquidity operations automatically calculate and adjust for transfer fees using both `transfer_fee_included` and `transfer_fee_excluded` logic. * Fees are validated across all swaps, deposits/withdrawals, and farming rewards. * **Metadata Pointer (MetadataPointer)** * Supported for proper metadata display and integration. * **Token Metadata (TokenMetadata)** * Token 2022 mints using Token Metadata extension are fully supported. ### Permissioned Extensions Mints with other Token 2022 extensions **require a token badge** to be supported in DAMM v2 pools. These include, but are not limited to: * Interest Bearing (InterestBearingConfig) * Permanent Delegate (PermanentDelegate) * Non-transferable * Memo Transfer, etc. To enable such tokens: To apply for a token badge, start by completing this [Google Form](https://forms.gle/59n3zDiGS2C6qMfd7) describing your token and any extensions in use. After submitting the form, open a ticket in the [Meteora Discord](https://discord.gg/meteo) to notify the team for review. ### Unsupported Extensions Some Token 2022 extensions are **not supported** or are only supported in limited form: * **Transfer Hook (TransferHook)**: Only supported if both the program ID and authority are `None` (no active hook). Otherwise, the mint is treated as unsupported. * **Token 2022 Native mint** (`So11111111111111111111111111111111111111112`) is **not supported** (`UnsupportNativeMintToken2022` error). If you try to create a pool or position with a Token 2022 mint that is not permissionlessly or permissionedly supported, pool creation will fail. # What is DAMM v2? Source: https://docs.meteora.ag/overview/products/damm-v2/what-is-damm-v2 DAMM v2 is Meteora's concentrated-liquidity constant-product AMM. It combines custom price ranges, flexible fee modes including auto-compounding, NFT-backed positions, built-in farming, and liquidity vesting — all in a single on-chain program. ## Overview DAMM v2 (Dynamic AMM v2) is Meteora's next-generation liquidity protocol on Solana. Built on the **cp-amm** program, it gives token creators and LPs fine-grained control over how pools are configured, how fees are collected, and how liquidity is locked and released. # Key Features DAMM v2 comes with the following features. LPs concentrate capital in a chosen price range to earn more fees per dollar deployed. Supports full-range (x·y=k) as a special case. **BothToken** — fees in both tokens. **OnlyB** — fees in quote token only. **Compounding** — a configurable share of fees auto-reinvests back into pool liquidity. Each LP position is tied to a position NFT. Positions track unlocked, vested, and permanently locked liquidity separately. Up to 2 reward tokens per pool. Rewards accrue pro-rata based on total position liquidity — no separate staking contract needed. Lock liquidity with cliff + linear vesting schedules, or lock permanently. Both inner vesting (single account) and external vesting accounts supported. A percentage of trading fees can be set to auto-compound directly into pool reserves via `compounding_fee_bps`. The pool operates as a standard constant-product AMM in this mode, with no concentrated price range. Set an activation point (by slot or timestamp) to delay trading. Pair with an Alpha Vault or presale vault for whitelisted early access. 5 base fee modes: time-decay linear/exponential, market-cap-based linear/exponential, and rate limiter. Combine with volatility-based dynamic fees. Permissionless and permissioned support for SPL Token 2022 with extensions. # Pool Creation Options DAMM v2 supports three ways to create a pool, each offering different levels of control: | Method | Description | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `initialize_pool` | Creates a pool using a pre-defined **static config** created by Meteora. Fee parameters are fixed. | | `initialize_pool_with_dynamic_config` | Creates a pool using a **dynamic config**. The pool creator defines all fee parameters during creation. | | `initialize_customizable_pool` | Creates a **fully customizable** pool where the pool creator sets all parameters including fee mode, dynamic fees, and compounding settings. | All three creation methods support `collect_fee_mode = 2` (Compounding) and `compounding_fee_bps` configuration. # Position Features Each liquidity position in DAMM v2 is represented by an NFT, making positions transferable between wallets. ## Liquidity Locking & Vesting Positions support three liquidity states: | State | Description | | ---------------------- | --------------------------------------------------------------------------------------------------- | | **Unlocked** | Can be withdrawn at any time by the position owner. | | **Vesting** | Time-locked liquidity that gradually becomes unlocked based on a cliff + periodic release schedule. | | **Permanently Locked** | Cannot be withdrawn ever, but still earns trading fees and farming rewards. | Use `lock_position` or `lock_inner_position` to vest liquidity directly within a position (no separate vesting account required). Use `permanent_lock_position` to permanently lock liquidity. Call `refresh_vesting` to release vested liquidity that has reached its unlock time. `lock_inner_position` stores vesting state inside the position itself, enabling better composability with other programs. ## Position Splitting Position owners can split a position into two using `split_position` or `split_position2`. The split proportionally divides: * Unlocked, vested, and permanently locked liquidity * Pending trading fees (both tokens) * Pending farming rewards * Inner vesting state This is useful for partially transferring or selling a portion of a position. # Swap Modes DAMM v2 supports two swap instructions: | Instruction | Modes | | ----------- | ------------------------------------------ | | `swap` | ExactIn only (deprecated) | | `swap2` | ExactIn (0), PartialFill (1), ExactOut (2) | The original `swap` instruction and the `EvtSwap`, `EvtRemoveLiquidity`, and `EvtAddLiquidity` events are deprecated. Use `swap2` and `EvtSwap2` / `EvtLiquidityChange` instead. For pools with Rate Limiter enabled (`baseFeeMode == 2`), the `SYSVAR_INSTRUCTIONS_PUBKEY` must be included in the remaining accounts of the swap instruction. # Farming Rewards DAMM v2 has a built-in farming mechanism (no separate farm program required). Each pool supports up to **2 reward tokens** simultaneously. * Pool creators can permissionlessly initialize the first reward (index 0) for their own pool * Rewards are distributed proportionally based on position liquidity (including unlocked, vesting, and permanently locked) * LPs claim rewards via `claim_reward` * The `skip_reward` parameter allows claiming even if a reward vault is frozen # Case Studies ## Program Address | Network | Address | | ------- | --------------------------------------------- | | Mainnet | `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` | | Devnet | `cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG` | *** ## Key Concepts ### Pool Types A DAMM v2 pool is always a **constant-product** pool (x·y=k within a price range). Two config types exist: * **Static Config** — Pool parameters (fee, price range, collect fee mode) are fixed at config creation. Pools inherit them. * **Dynamic Config** — Pool creator can specify custom parameters at pool creation time (private configs only). ### Positions Every LP position is an on-chain account backed by a **position NFT**. The NFT is the ownership token — whoever holds it can manage the position. A position tracks three liquidity buckets: | Bucket | Description | | ---------------------------- | --------------------------------------- | | `unlocked_liquidity` | Available to withdraw freely | | `vested_liquidity` | Released on a cliff + periodic schedule | | `permanent_locked_liquidity` | Never withdrawable | ### Activation & Trading Gating Pools can have an **activation point** (a future slot or timestamp) before which trading is disabled. This is used for: * Fair launch countdowns * Alpha Vault presale windows * Coordinated launch times across platforms *** ## Fee Architecture DAMM v2 fees have three layers: ``` Total Trading Fee ├── Protocol Fee (20%) │ └── Referral Fee (20% of protocol fee, if referral) └── LP Fee (80%) └── [Compounding only] compoundingFeeBps portion → back into pool reserves ``` See [Fee Configuration](/overview/products/damm-v2/fee-configuration) and [Collect Fee Modes](/overview/products/damm-v2/collect-fee-modes) for details. *** ## Quick Links Static vs dynamic config, price ranges, pool parameters BothToken, OnlyB, and Compounding explained Base fee modes, dynamic fee, protocol fee Creating positions, adding/removing liquidity Vesting schedules and permanent locks Setting up and claiming in-pool rewards # Bonding Curve Formulas Source: https://docs.meteora.ag/overview/products/dbc/bonding-curve-formulas Mathematical formulas behind DBC's multi-segment bonding curve: price calculation, token supply, and migration threshold. The Dynamic Bonding Curve is a customizable bonding curve that allows you to configure up to 16 curve segments to control the curve's shape and price action. Each curve segment follows a constant product formula: ```math theme={"system"} x \times y = k ``` # Mathematical Foundation A simple constant product formula can be expressed as: ```math theme={"system"} x \times y = \text{Virtual Base Reserve} \times \text{Virtual Curve Reserve} ``` This can also be represented as: ```math theme={"system"} x \times y = \text{Liquidity}^2 ``` Where: ```math theme={"system"} \text{Liquidity} = \sqrt{\,\text{Virtual Base Reserve} \times \text{Virtual Curve Reserve}\,} ``` With a constraint on `migration_quote_threshold`, this can be presented as a function of liquidity, minimum price, and maximum price. We denote: * `l` = liquidity * `pa` = minimum price * `pb` = maximum price Therefore: ```math theme={"system"} \text{Bonding Curve Constant Product} = f(l, p_a, p_b) ``` ## Example Configuration Consider a pool with the following configuration: ``` sqrt_start_price = 1 curve = [ (sqrt_price = 2, liquidity = 100), (sqrt_price = 4, liquidity = 500) ] ``` The bonding curve will function across 2 price ranges: * **Range 1**: `(l = 100, pa = 1, pb = 2)` * **Range 2**: `(l = 500, pa = 2, pb = 4)` These are just example values and are not real values in the actual curve. You will have to calculate the actual `sqrt_price` and `liquidity` values which will be much bigger. # Core Formulas Below are the core formulas used in the dynamic bonding curve program. We use the following notation: * Let $L_i$ = liquidity in $i$ index * Let $P_i$ = price at $i$ index * $P_{i-1}$ = price at the lower boundary of $i$ index *** ## 1. Bonding Curve Amount The total amount of base mint tokens in the bonding curve is given by: ```math theme={"system"} \text{Bonding Curve Amount} = \sum_{i} L_i \left( \frac{1}{P_{i-1}} - \frac{1}{P_i} \right) ``` *** ## 2. Migration Quote Threshold The migration quote threshold required for the pool to migrate is calculated as: ```math theme={"system"} \text{Migration Quote Threshold} = \sum_{i} L_i (P_i - P_{i-1}) ``` *** ## 3. Migration Price Calculation To determine the migration price squared ($p_\text{max}^2$) during migration, use: ```math theme={"system"} p_\text{max}^2 = \frac{\text{Migration Quote Threshold} \times (1 - \text{Migration Fee Percentage})}{\text{Migration Amount}} ``` Where: * `Migration Fee Percentage` is the fee (as a decimal, e.g., 0.01 for 1%) * `Migration Amount` is the total amount of base mint tokens being migrated *** These formulas allow you to compute swap amounts, migration thresholds, and price limits for any custom liquidity distribution along the bonding curve. # Fee Formulas The total swap fee ($f_s$) will have two components: 1. **A base fee** ($f_b$) 2. **A variable fee** ($f_v$) The **total swap fee** is calculated as: ```math theme={"system"} f_s = f_b + f_v ``` ## Pool Fee Interface ``` 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 } ``` Using the relevant parameters, you can calculate the base fee and variable fee for any given swap. * For **Fee Scheduler** you can refer to the [Fee Scheduler Formulas](/anti-sniper-suite/fee-time-scheduler/fee-time-scheduler-math). * For **Rate Limiter** you can refer to the [Rate Limiter Formulas](/anti-sniper-suite/rate-limiter/rate-limiter-math). * For **Dynamic Fees** you can refer to the [Dynamic Fee Formulas](/overview/products/dbc/trading-fees-calculation#dynamic-fee-variable-fee). # Migration Fee We introduced a new migration fee feature that allows users to collect a percentage of the `quote_min` from the `migration_quote_threshold` amount. ``` migrationFee: { // Optional migration fee (set as 0 for feePercentage and 0 for 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) } ``` ONLY if you are using the `buildCurveWithMarketCap` function from the DBC Typescript SDK, you will need to calculate the actual `initial_market_cap` value that you want based on the desired initial market cap. ## Formula ``` let D = desiredMarketCap and M = migrationMarketCap and f = migrationFee and I = initialMarketCap requiredRatio = sqrt(D / M) percentageSupplyOnMigration = (requiredRatio * (1 - f) * 100) / (1 + requiredRatio * (1 - f)) x = percentageSupplyOnMigration / ((100 - V - L) - percentageSupplyOnMigration) I = M * x² ``` ## Example ``` const curveConfig = buildCurveWithMarketCap({ token: { tokenType: TokenType.SPL, tokenBaseDecimal: TokenDecimal.SIX, tokenQuoteDecimal: TokenDecimal.NINE, tokenUpdateAuthority: TokenUpdateAuthorityOption.Immutable, totalTokenSupply: 1_000_000_000, leftover: 1, }, fee: { baseFeeParams: { baseFeeMode: BaseFeeMode.FeeSchedulerLinear, feeSchedulerParam: { startingFeeBps: 100, endingFeeBps: 100, numberOfPeriod: 0, totalDuration: 0, }, }, dynamicFeeEnabled: false, collectFeeMode: CollectFeeMode.QuoteToken, creatorTradingFeePercentage: 0, poolCreationFee: 0, enableFirstSwapWithMinFee: false, }, migration: { migrationOption: MigrationOption.MET_DAMM_V2, migrationFeeOption: MigrationFeeOption.FixedBps100, migrationFee: { feePercentage: 50, creatorFeePercentage: 0 }, }, liquidityDistribution: { partnerLiquidityPercentage: 0, partnerPermanentLockedLiquidityPercentage: 100, creatorLiquidityPercentage: 0, creatorPermanentLockedLiquidityPercentage: 0, }, lockedVesting: { totalLockedVestingAmount: 0, numberOfVestingPeriod: 0, cliffUnlockAmount: 0, totalVestingDuration: 0, cliffDurationFromMigrationTime: 0, }, activationType: ActivationType.Slot, initialMarketCap: 4000, migrationMarketCap: 69000, }) ``` A leftover value is needed to cover precision loss when you indicate a migration fee. # Curve Configuration Source: https://docs.meteora.ag/overview/products/dbc/curve-configuration How DBC's multi-segment bonding curve works — defining up to 16 price-liquidity points, understanding curve shape, and translating curves to PoolConfig parameters. ## The Multi-Segment Bonding Curve DBC uses a **piecewise concentrated-liquidity curve** with up to 16 segments. Each segment is defined by a `(sqrt_price, liquidity)` pair, creating a price path from the initial price to the migration price. The curve is stored as an array of `LiquidityDistributionConfig` points in the `PoolConfig` account: ```rust theme={"system"} pub struct LiquidityDistributionConfig { pub sqrt_price: u128, // upper bound √price of this segment pub liquidity: u128, // virtual liquidity in this segment } ``` Up to **16** price points (`MAX_CURVE_POINT`). *** ## How the Curve Works The curve defines how many quote tokens are needed to move the price through each segment: ``` Δquote = liquidity × (√P_upper - √P_lower) ``` A segment with **high liquidity** requires more quote tokens to traverse (flatter price movement). A segment with **low liquidity** is traversed quickly (steep price movement). ### Example: Two-Segment Curve ``` Segment 1: sqrt_price = X₁, liquidity = L₁ (steep launch phase) Segment 2: sqrt_price = X₂, liquidity = L₂ (flat mature phase) ↑ price X₂ --|----_________ (L₂: flat, needs many tokens to move price) X₁ --|-____ (L₁: steep, few tokens move price a lot) | initial_sqrt_price ``` *** ## Key Curve Parameters ### `sqrt_start_price` The initial price when the pool opens. Token price starts here and moves up as buyers purchase. ### `sqrt_price` per segment Each segment's `sqrt_price` is the **upper price bound** of that segment. When the current price reaches it, trading moves to the next segment. ### `migration_sqrt_price` The price at which the pool migrates. Derived from `migration_quote_threshold` and the total curve: ``` When: quote_reserve >= migration_quote_threshold → migrate ``` ### `swap_base_amount` Total base tokens available for sale through the curve: ``` swap_base_amount = Σ Δbase_per_segment ``` This is pre-calculated from the curve definition and stored in config. *** ## Token Supply Models Base tokens are minted on demand as buyers purchase. The total supply grows with each buy. * `fixed_token_supply_flag = 0` * Requires the `token_update_authority` to be set so the program can mint * Post-migration: minting authority is revoked **Best for:** Most meme coin / community launches. All tokens are pre-minted and deposited into the base vault. Leftover tokens (unsold at migration) are returned to `leftover_receiver`. * `fixed_token_supply_flag = 1` * Pre-migration supply = `pre_migration_token_supply` * Post-migration supply = `post_migration_token_supply` * Leftover = `pre_migration_token_supply - swap_base_amount - post_migration_token_supply` **Best for:** Projects with fixed total supply tokenomics. *** ## Visualizing Curve Shapes Different curve shapes serve different launch strategies: A steep early segment rewards early buyers with a lower average price, then the curve flattens as the supply enters wider distribution. Most DBC launches use this shape. ``` Segment 1: high liquidity → price barely moves per token sold Segment 2: low liquidity → price rises quickly at the end ``` Wait — actually it's the opposite: **low liquidity = steep price**, **high liquidity = flat price**. Correct shape for "cheap early, expensive later": * Segment 1: **low** liquidity (steep — small buys push price up a lot) * Last segment: **high** liquidity (flat — many tokens needed to move price) All segments at roughly equal liquidity creates a near-linear price path. Price discovery is gradual and predictable. Very low liquidity throughout → price spikes rapidly. Not recommended for broad distribution. *** ## Calculating Curve Parameters The TypeScript SDK provides helpers for building curve configurations: ```typescript theme={"system"} import { buildCurve, buildCurveAndCreateConfig, CurveType, } from "@meteora-ag/dynamic-bonding-curve-sdk"; // Build a standard launch curve const curveConfig = buildCurve({ totalTokenSupply: 1_000_000_000, // 1B tokens initialMarketCap: 30_000, // $30K initial market cap in USD migrationMarketCap: 500_000, // $500K migration market cap in USD migrationOption: MigrationOption.DammV2, tokenBaseDecimal: 6, tokenQuoteDecimal: 9, lockedVesting: { ... }, feeSchedulerMode: FeeSchedulerMode.Linear, }); ``` *** ## Constraints | Constraint | Value | | ----------------------------- | -------------------------- | | Max curve segments | 16 | | `sqrt_price` ordering | Must be strictly ascending | | Minimum liquidity per segment | > 0 | | `token_decimal` | 1–9 | # DBC Config Key Source: https://docs.meteora.ag/overview/products/dbc/dbc-config-key What a DBC config key is, how it controls curve parameters and fee settings, and how launchpads use it to customize token launch behaviour. # What is a DBC Config Key? A DBC Config Key is a unique configuration key that will dictate your curve structure and graduated pool fees structure. Here is an example of a [DBC Config Key](https://solscan.io/account/FbKf76ucsQssF7XZBuzScdJfugtsSKwZFYztKsMEhWZM#anchorData)

The quote mint that all baseMint tokens launched with this config will be paired to (e.g., SOL, USDC, MET)

  • Base Fees - Constant fee or Fee Scheduler with decay mechanism
  • Dynamic Fees - Variable fees based on market volatility (max 20% of base fee)

Determines fee collection: Only Quote tokens or Output token of each swap

Slot-based (400ms) or Timestamp-based (100ms) calculation for vesting and fee scheduler

Vesting schedule for baseMint tokens to pool creator after migration

  • Pre-migration - Fixed token supply before migration
  • Post-migration - Fixed token supply after migration
  • Dynamic - Optional null value for dynamic supply
  • DAMM Pool Option - DAMM V1 (0) or DAMM V2 (1)
  • Fee Config - Base fees for migrated pools (0.25%, 0.3%, 1%, 2%, 4% and 6%)
  • Migration Quote Threshold - Minimum quote amount for migration
  • Migration Fee - Collect a percentage of fees from the pool's quote reserve
  • Migrated Pool Base Fee Mode - Fee mode for the graduated DAMM v2 pool: FeeTimeSchedulerLinear (0), FeeTimeSchedulerExponential (1), RateLimiter (2), FeeMarketCapSchedulerLinear (3), or FeeMarketCapSchedulerExponential (4)
  • Market Cap Fee Scheduler Params - Configure fee reduction based on price movement for DAMM v2 pools (number of periods, sqrt price step, expiration duration)
  • First Swap with Min Fee - Allow the first swap to use minimum fee for creator bundled buys
  • Compounding Fee Mode - For DAMM v2 graduated pools, set collectFeeMode: 2 (Compounding) to reinvest trading fees back into the LP position. Requires compoundingFeeBps to be set to a non-zero value.
  • compoundingFeeBps - The fee rate (in basis points) applied when compounding fees back into the LP position. Must be non-zero when Compounding mode is active, and must be 0 for all other modes.

When your pool migrates to DAMM v2 and you use the Customizable fee option, you can set the migratedPoolFee struct with these options:

  • QuoteToken (0) - Fees collected in the quote token only (maps to DAMM v2 OnlyB mode)
  • OutputToken (1) - Fees collected in both tokens (maps to DAMM v2 BothToken mode)
  • Compounding (2) - Fees are automatically reinvested back into the liquidity position, growing LP value over time instead of accumulating as separate claimable fees
  • Creator Liquidity - Claimable LP percentage for pool creator (`creatorLiquidityPercentage`)
  • Partner Liquidity - Claimable LP percentage for config creator (`partnerLiquidityPercentage`)
  • Creator Permanently Locked Liquidity - Forever locked LP for creator fees (`creatorPermanentLockedLiquidityPercentage`)
  • Partner Permanently Locked Liquidity - Forever locked LP for partner fees (`partnerPermanentLockedLiquidityPercentage`)
  • LP Vesting (DAMM v2 only) - Optional vesting schedule for partner/creator LP (`partnerLiquidityVestingInfoParams`, `creatorLiquidityVestingInfoParams`)

Note: Minimum 10% liquidity must remain locked at day 1 post-migration. This can be achieved via permanent locked liquidity and/or vesting liquidity.

Percentage of trading fees shared with pool creators (default: 0% to partner only)

  • Token Type - SPL or Token2022
  • Token Decimal - 6 or 9 decimal places
  • SqrtStartPrice - Starting price in square root format
  • Curve - Up to 16 curve segments with sqrtPrice and liquidity

Partners can configure a pool creation fee in SOL lamports (`poolCreationFee`) that token creators must pay when creating pools with this config.

  • Fee Collection - Fee is collected from creators during `initializeVirtualPoolWithSplToken` or `initializeVirtualPoolWithToken2022`
  • Partner Claim - Partners can claim fees via `claimPartnerPoolCreationFee`
  • Protocol Share - Meteora receives 10% of collected pool creation fees
  • Config - Vanity address for the config key
  • Leftover Receiver - Claims leftover baseMint tokens after curve completion
  • Fee Claimer - Claims bonding curve fees
  • Payer - Pays for config key creation
# How to create a DBC Config Key? You can create a DBC Config Key by using the [DBC Typescript SDK](https://github.com/MeteoraAg/dynamic-bonding-curve-sdk) or via [launch.meteora.ag](https://launch.meteora.ag) # DBC Fee Calculation Source: https://docs.meteora.ag/overview/products/dbc/dbc-fee-calculation How trading fees are calculated and distributed in DBC pools, including base fee, dynamic fee, and the fee split between protocol and creator. DBC Pools earn a trading fee from traders when they perform a swap. The fees can be collected in two ways: * Quote only * Quote + Base DBC fees can be fee shared between the launchpad partner and the token pool creator. # Total Trading Fee The total swap fee ($f_s$) will have two components: 1. **A base fee** ($f_b$) 2. **A variable fee** ($f_v$) The **total swap fee** is calculated as: ```math theme={"system"} f_s = f_b + f_v ``` The variable fee ($f_v$) is a function of real-time price volatility. The fee rate will be applied to the swap amount in each liquidity bin and distributed proportionally to the LPs in that bin. LPs can claim these fees whenever they are available. ## Base Fee The base fee of a pool can be configured by the pool creator in the following ways: * **Fixed Base Fee**: A fixed fee that is applied to the swap amount. * **Fee Scheduler**: A fee decay mechanism that decays the fee from a high starting fee to an ending fixed base fee over a period of time. The ending fee will be the fixed base fee of the pool after the fee scheduler is finished. * **Rate Limiter**: A fee slope mechanism that starts at a fixed base fee and increases the fee depending on the buy amount. The fee after the rate limiter is finished will be the fixed base fee of the pool. You can only choose one of the three options for the base fee. ### Fixed Base Fee Fixed base fee is a fixed fee that is applied to the swap amount. The fee can range from 0.25% to 99%. It is specified in the config key used for the pool creation. ### Fee Scheduler Fee scheduler is a fee decay mechanism that decays the fee from starting fee to an ending base fee over a period of time. The fee math calculation for the scheduler can be found [here](/anti-sniper-suite/fee-time-scheduler/fee-time-scheduler-math). ### Rate Limiter Rate limiter is a fee slope mechanism that starts at a fixed base fee and increases the fee depending on the buy amount The fee math calculation for the rate limiter can be found [here](/anti-sniper-suite/rate-limiter/rate-limiter-math). ## Dynamic Fee (Variable Fee) The variable fee is the core of the dynamic fee mechanism. It increases with market volatility. ```math theme={"system"} f_v = (v_a \times s)^2 \times C / 100000000000 ``` where: * **Volatility Accumulator** ($v_a$): A measure of recent price volatility * **Bin Step** ($s$): A parameter that defines the price granularity for measuring volatility * **Variable Fee Control** ($C$): A parameter to control the magnitude of the variable fee ### Volatility Accumulator The Volatility Accumulator tracks price movements. It's updated with every swap. ```math theme={"system"} v_a = \min(v_{max}, v_r + \Delta p \times 10000) ``` where: * **Max Volatility Accumulator** ($v_{max}$): A cap on the volatility measure to prevent fees from becoming excessively high * **Volatility Reference** ($v_r$): A decayed value of the volatility accumulator * **Price Change** ($\Delta p$): The price change since the last reference update, measured in "bins" #### Price Change The price change is calculated based on the change in the square root of the price. ```math theme={"system"} \Delta p = (\sqrt{p_c / p_r} - 1) / s \times 2 ``` where $p_c$ is current price and $p_r$ is reference price. #### Volatility Decay To ensure that the dynamic fee reflects recent volatility, the Volatility Reference decays over time. ```math theme={"system"} v_r = v_a \times R / 10000 ``` The decay mechanism is based on the time elapsed since the last significant trade: * If elapsed time \< filter period: No change. This ignores very high-frequency trades. * If filter period ≤ elapsed time \< decay period: The volatility reference is reduced. * If elapsed time ≥ decay period: The volatility reference is reset to 0. This happens if there are no significant trades for an extended period. # Max Dynamic Fee on DBC for Typescript SDK Build Curve functions If you use any of the `buildCurve` helper functions in the DBC Typescript SDK, the max dynamic fee on DBC when toggled `true` is less than or equals to 20% of the Base Fee. Example: * Base Fee = 1% * Dynamic Fee = 0.2% * Total Trading/LP Fee = 1.2% # Protocol Fees Protocol Fee is a percentage of the Total Trading Fee (i.e. base + dynamic/variable fee). **Current Protocol Fees:** **20%** Protocol Fee and **80%** Trading Fee for virtual liquidity positions. Protocol fees are collected as either Quote token, or Quote + Both tokens, depending on each pool’s configuration. ## Swaps Swap hosts (such as Jupiter, Photon, or trading bots) can include a referral account in the swap transaction to receive a **Referral Fee** equal to **20%** of the protocol fee. # Protocol Migration Fee A fixed **0.2% (20 bps) protocol migration fee** is applied during migration from the DBC bonding curve to the graduated DAMM pool. This fee is deducted from the quote reserve during migration and is separate from any `migrationFee` configured by the partner. # Post-Migration Fee Modes (DAMM v2 Graduated Pools) When a DBC pool graduates and migrates to DAMM v2, the fee collection behavior is controlled by the `collectFeeMode` set in the `migratedPoolFee` config. There are three modes available: ## Mode 0 — QuoteToken (OnlyB) Fees from all trades are collected entirely in the quote token (e.g. SOL or USDC), regardless of trade direction. Maps to DAMM v2’s `OnlyB` collect fee mode. ## Mode 1 — OutputToken (BothToken) Fees are collected in the output token of each swap. For a buy (quote → base), the fee is in the base token. For a sell (base → quote), the fee is in the quote token. Maps to DAMM v2’s `BothToken` collect fee mode. ## Mode 2 — Compounding Fees are not distributed as claimable amounts. Instead, they are automatically reinvested back into the LP position, compounding the liquidity value over time. The compounding fee rate is specified in basis points via `compoundingFeeBps`: ```math theme={"system"} \text{compounded amount} = \text{fee collected} \times \frac{\text{compoundingFeeBps}}{10000} ``` When `collectFeeMode` is set to `2` (Compounding), `compoundingFeeBps` must be a non-zero value. When using any other mode, `compoundingFeeBps` must be `0`. ### DBC to DAMM v2 Fee Mode Mapping | DBC `collectFeeMode` | DAMM v2 mode | | -------------------- | --------------- | | 0 (QuoteToken) | 1 (OnlyB) | | 1 (OutputToken) | 0 (BothToken) | | 2 (Compounding) | 2 (Compounding) | # Dbc flow Source: https://docs.meteora.ag/overview/products/dbc/dbc-flow # Flow of DBC Pool -> DAMM v1/v2 Pool ## Concepts * **Pre-bonding**: DBC pool - where the newly minted token discovers its price. No need for an LP. * **Post-bonding**: DAMM v1/v2 pool - where the accumulated `quote_mint` tokens in the bonding curve + a portion of the `base_mint` tokens are migrated to form the liquidity pool of the new token * **Partner**: Launchpad * **Creator**: Token Pool Creator ## Flow Partner creates a DBC Config Key that consists of the curve shape, migrated pool fee, and many more. Creator creates a DBC Token Pool with the Partner's DBC Config Key. This action will mint the new token and initialise a DBC Pool. The DBC Token Pool is tradeable on all trading terminals and trading bots (including Jupiter Pro, Axiom, Photon, GMGN, BullX etc.) Once the DBC Token Pool has accumulated enough `quote_mint` tokens (`pool_state::quote_reserve >= pool_config::migration_quote_threshold`), our migrator keeper will automatically migrate the DBC pool to a DAMM Pool. The `migration_quote_threshold` and a portion of the `base_mint` tokens will form the liquidity pool of the DAMM Pool. The graduated DAMM v1/v2 Pool is also tradeable on all trading terminals and trading bots (including Jupiter Pro, Axiom, Photon, GMGN, BullX etc.) # Migration Source: https://docs.meteora.ag/overview/products/dbc/migration How a DBC virtual pool graduates to a DAMM v1 or DAMM v2 liquidity pool — triggers, liquidity distribution, vesting setup, and what happens on-chain. ## Overview When a DBC virtual pool's `quote_reserve` reaches `migration_quote_threshold`, the bonding curve phase ends and the pool **migrates** to a real AMM. This is automatic and permissionless — any caller can trigger the migration instruction once the threshold is hit. *** ## Migration Trigger ``` if virtual_pool.quote_reserve >= config.migration_quote_threshold → migrate ``` The `finish_curve_timestamp` is recorded on the `VirtualPool` when the threshold is first crossed. Migration can be called at any point after this. Trading is paused once the curve is complete (`PoolIsCompleted` error). Migration must happen before normal trading resumes. *** ## Migration Options | `migration_option` | Target Pool | | ------------------ | -------------------------------------------------- | | `MeteoraDamm` (0) | DAMM v1 (constant-product, supports stable pools) | | `DammV2` (1) | DAMM v2 (concentrated liquidity, custom fee modes) | *** ## Migration Steps (On-Chain) ### 1. PreBonding → LockedVesting (standard flow) ``` migrateMeteoraDammLockLpToken (for DAMM v1) migrateDammV2CreatePool + lockLp (for DAMM v2) ``` For most launches (no Jupiter lock): 1. `migration_progress = PreBondingCurve` 2. Threshold hit → caller invokes migrate instruction 3. Program creates DAMM pool with `migration_sqrt_price` and seeds liquidity 4. LP positions are distributed to partner, creator, and protocol 5. Vesting schedules are initialized on the LP positions 6. `migration_progress = LockedVesting` → `CreatedPool` ### 2. With Jupiter Lock (PostBonding flow) Some launches integrate with Jupiter's lock mechanism: 1. `PreBondingCurve` → threshold hit 2. `PostBondingCurve` (Jupiter lock processing) 3. `LockedVesting` → `CreatedPool` *** ## Liquidity Distribution at Migration The total migrated liquidity is split: ``` Total LP ├── Partner LP (partner_liquidity_percentage %) │ ├── Permanently locked (partner_permanent_locked_liquidity_percentage %) │ └── Vesting (partner_liquidity_vesting_info schedule) ├── Creator LP (creator_liquidity_percentage %) │ ├── Permanently locked (creator_permanent_locked_liquidity_percentage %) │ └── Vesting (creator_liquidity_vesting_info schedule) └── Protocol LP (remainder) ``` Vesting schedules use the same cliff + periodic model as DAMM v2 inner vesting: | Parameter | Description | | ------------------------------------ | ------------------------------------------- | | `cliff_duration_from_migration_time` | Seconds after migration before first unlock | | `frequency` | Seconds between each periodic release | | `number_of_period` | Total number of release periods | | `cliff_unlock_amount` | Amount released at the cliff | | `amount_per_period` | Amount released per period after the cliff | *** ## Migration Fee A one-time migration fee is taken from the migrated quote reserves: ``` migration_fee_amount = total_quote × migration_fee_bps / 10_000 ``` The `migration_fee_percentage` is the total fee percentage. This total fee is split between partner and creator: * Partner receives the portion not allocated to the creator * `creator_migration_fee_percentage %` → creator's share of the migration fee Both parties can claim their migration fee separately via `withdrawMigrationFee`. The `migration_fee_withdraw_status` bitmask tracks withdrawal status: * bit 1 (`0b010`) = creator has withdrawn * bit 2 (`0b100`) = partner has withdrawn *** ## Surplus Claims After migration, there may be surplus quote tokens beyond what's needed for the DAMM pool. These are claimable: | Claimant | Instruction | Condition | | -------- | ------------------------ | ----------------------------------------------------------- | | Protocol | `claimProtocolFee` | Protocol surplus claimed via the unified fee claim endpoint | | Partner | `withdrawPartnerSurplus` | `is_partner_withdraw_surplus = 0` | | Creator | `withdrawCreatorSurplus` | `is_creator_withdraw_surplus = 0` | The surplus split is determined by `PARTNER_AND_CREATOR_SURPLUS_SHARE` constant. *** ## Post-Migration: DAMM v2 Pool Parameters When `migration_option = DammV2`, the created DAMM pool uses: | DBC Config Field | Maps to DAMM v2 | | ----------------------------- | ------------------- | | `migration_sqrt_price` | `initSqrtPrice` | | `migrated_collect_fee_mode` | `collectFeeMode` | | `migrated_pool_fee_bps` | Base fee | | `migrated_pool_base_fee_mode` | `BaseFeeMode` | | `migrated_dynamic_fee` | Dynamic fee enabled | *** ## Fixed Supply Migration For fixed-supply tokens, leftover base tokens (unsold at migration) are returned to `leftover_receiver`: ``` leftover = pre_migration_token_supply - swap_base_amount - post_migration_token_supply ``` The `is_withdraw_leftover` flag on VirtualPool tracks whether this has happened. # DBC Pool Configuration Source: https://docs.meteora.ag/overview/products/dbc/pool-configuration Every parameter a DBC launch creator controls — token supply, fees, migration targets, LP distribution, vesting, and post-migration pool settings. ## Overview A DBC launch is configured via a `PoolConfig` account (the "config key"). The config is created once and can be used to launch many virtual pools from it. All parameters that determine how the launch behaves are set here. *** ## Token Configuration | Parameter | Description | | ----------------------------- | ----------------------------------------------------------- | | `token_decimal` | Base token decimals (1–9) | | `token_type` | `SplToken` (0) or `Token2022` (1) | | `token_update_authority` | Whether the creator retains update authority post-migration | | `fixed_token_supply_flag` | `0` = dynamic (mint on buy), `1` = fixed (pre-minted) | | `pre_migration_token_supply` | Only for fixed supply — total initial supply | | `post_migration_token_supply` | Tokens remaining after migration (for LP + locked) | | `leftover_receiver` | Address to receive leftover tokens (fixed supply only) | *** ## Fee Configuration ### Trading Fees Fees are collected in the quote token (`quote_token` mode) or the output token (`output_token` mode): | `collect_fee_mode` | Value | Description | | ------------------ | ----- | ------------------------------------------------- | | `QuoteToken` | `0` | Fees always in quote token (SOL/USDC) | | `OutputToken` | `1` | Fees in whichever token is received by the trader | DBC's `collect_fee_mode` has different values from DAMM v2. DBC: `0 = QuoteToken`, `1 = OutputToken`. DAMM v2: `0 = BothToken`, `1 = OnlyB`, `2 = Compounding`. ### Fee Split ``` Total Trading Fee ├── Protocol Fee (20%) └── Trading Fee share (80%, split between partner and creator) ``` | Parameter | Description | | -------------------------------- | ------------------------------------------------------------- | | `creator_trading_fee_percentage` | Percent of the trading fee share that goes to creator (0–100) | *** ## Migration Configuration ### Migration Target | `migration_option` | Value | Target | | ------------------ | ----- | ------------------ | | `MeteoraDamm` | `0` | Migrate to DAMM v1 | | `DammV2` | `1` | Migrate to DAMM v2 | ### Migration Thresholds | Parameter | Description | | --------------------------- | --------------------------------------------- | | `migration_quote_threshold` | Quote reserve level that triggers migration | | `migration_base_threshold` | Base tokens to add to the migrated pool | | `migration_sqrt_price` | Initial price of the post-migration DAMM pool | ### Migration Fee A one-time fee is deducted at migration. Options: | `MigrationFeeOption` | Fee | | -------------------- | --------------------------------------------------------- | | `FixedBps25` | 0.25% | | `FixedBps30` | 0.30% | | `FixedBps100` | 1.00% | | `FixedBps200` | 2.00% | | `FixedBps400` | 4.00% | | `FixedBps600` | 6.00% | | `Customizable` | Custom (set with a separate config for DAMM v2 migration) | The `migration_fee_percentage` is the total fee percentage taken from migration quote reserves. This total fee is then split between the partner and the creator: * Partner receives the portion not allocated to the creator * `creator_migration_fee_percentage` → creator's share of the migration fee *** ## LP Distribution After migration, the post-migration liquidity is distributed across: | Bucket | Parameter | Description | | ---------- | ------------------------------ | -------------------------------------- | | Partner LP | `partner_liquidity_percentage` | % of LP going to the partner/launchpad | | Creator LP | `creator_liquidity_percentage` | % of LP going to the creator | Additionally, a portion of each allocation can be **permanently locked**: | Parameter | Description | | ----------------------------------------------- | ------------------------------ | | `partner_permanent_locked_liquidity_percentage` | % of partner LP locked forever | | `creator_permanent_locked_liquidity_percentage` | % of creator LP locked forever | ### Vesting The remaining (non-permanently-locked) LP can vest on a schedule: ``` partner_liquidity_vesting_info: cliff_duration_from_migration_time: 0 // immediate cliff frequency: 86400 // daily releases number_of_period: 365 // over 1 year cliff_unlock_amount: amount_per_period: ``` ``` creator_liquidity_vesting_info: cliff_duration_from_migration_time: 2592000 // 30 days cliff frequency: 604800 // weekly releases number_of_period: 52 // over 1 year cliff_unlock_amount: amount_per_period: ``` *** ## Post-Migration Pool Settings (DAMM v2) When migrating to DAMM v2, additional parameters control the post-migration pool: | Parameter | Description | | ------------------------------ | ---------------------------------------------- | | `migrated_collect_fee_mode` | Collect fee mode for the DAMM v2 pool | | `migrated_dynamic_fee` | Whether dynamic fee is enabled on DAMM v2 pool | | `migrated_pool_fee_bps` | Base fee for the DAMM v2 pool | | `migrated_pool_base_fee_mode` | Base fee mode for DAMM v2 pool | | `migrated_pool_base_fee_bytes` | Encoded base fee params for the DAMM v2 pool | *** ## Activation Type | `activation_type` | Value | Description | | ----------------- | ----- | ---------------------------------- | | `Slot` | `0` | Pool opens at a specific slot | | `Timestamp` | `1` | Pool opens at a specific timestamp | Setting `activation_point` to a future slot/timestamp delays all trading until that point. *** ## Pool Creation Fee | Parameter | Description | | ------------------- | ---------------------------------------------------------- | | `pool_creation_fee` | Lamports charged to create a virtual pool from this config | This is collected from the pool creator at creation time and distributable via `claimPartnerPoolCreationFee`. # What is Dynamic Bonding Curve? Source: https://docs.meteora.ag/overview/products/dbc/what-is-dbc DBC is Meteora's permissionless token launch protocol. A configurable multi-segment bonding curve sells tokens until a migration threshold is hit, then automatically graduates the token to a DAMM v1 or DAMM v2 liquidity pool. ## Overview Dynamic Bonding Curve (DBC) lets anyone launch a token on Solana with a fully on-chain price discovery mechanism. The bonding curve defines a price schedule using up to **16 liquidity distribution points**, and trading happens directly against a virtual pool — no external AMM required until graduation. Up to 16 price-liquidity segments define the curve shape. Start steep for early price discovery, flatten out for later supply. Once the quote reserve hits `migration_quote_threshold`, the pool graduates to a DAMM v1 or DAMM v2 liquidity pool automatically. Configurable trading fees with protocol, partner, and creator fee splits. Optional fee scheduler for dynamic launch fees. Launch SPL tokens or Token 2022 tokens. Transfer fee and other extensions handled natively. Dynamic supply: tokens are minted as they're bought. Fixed supply: all tokens pre-minted, leftover returned after migration. Configure LP vesting, liquidity percentages, creator trading fees, and post-migration pool parameters per launch. *** ## Program Address | Network | Address | | ------- | --------------------------------------------- | | Mainnet | `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN` | | Devnet | `dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN` | *** ## How It Works ``` 1. Create config key → defines curve, fees, migration parameters 2. Create virtual pool → trading begins immediately (or after activation point) 3. Traders buy base token → price moves up the curve 4. Migration threshold hit → pool graduates to DAMM v1 or DAMM v2 5. Creator/partner claim surplus + LP positions ``` ### Virtual Pool vs Real Pool DBC uses a **virtual pool** (`VirtualPool` account) during the bonding phase: * No real AMM pool exists yet * Price is determined by the current position on the bonding curve * Both `base_vault` and `quote_vault` hold real tokens. Base tokens are either pre-minted (fixed supply) or minted on buy (dynamic supply). Quote tokens accumulate with each buy. * After migration, a real DAMM pool is created and all liquidity moves *** ## Virtual Pool State | Field | Description | | ------------------------ | -------------------------------------------------------- | | `config` | The `PoolConfig` this pool was created from | | `creator` | Who created this pool | | `base_mint` | The token being sold | | `base_vault` | Holds base tokens (or is empty for dynamic supply) | | `quote_vault` | Holds the accumulated quote token (SOL/USDC) | | `base_reserve` | Current base token reserve on the curve | | `quote_reserve` | Current quote token reserve (increases with each buy) | | `sqrt_price` | Current price on the curve | | `migration_progress` | `PreBonding → PostBonding → LockedVesting → CreatedPool` | | `finish_curve_timestamp` | When `quote_reserve >= migration_quote_threshold` | *** ## Migration Progress States ``` PreBondingCurve → Active trading, price moving up the curve ↓ PostBondingCurve → Migration threshold hit (Jupiter lock variant only) ↓ LockedVesting → LP positions being distributed, vesting set up ↓ CreatedPool → DAMM pool live, bonding phase complete ``` Most launches go directly `PreBonding → LockedVesting → CreatedPool`. The `PostBonding` state is only used for Jupiter-lock-integrated launches. *** ## Quick Links How to define curve segments with LiquidityDistributionParameters All the parameters a creator controls per launch How pools graduate to DAMM v1/v2 and LP is distributed Trading fees, protocol split, creator fee, migration fee # Anti-Sniper Features Timestamp-based fees, such as high fees at launch that decrease over time, help deter snipers and protect the pool during the most volatile periods. Amount-based fees that increases with a higher amount per swap, to deter snipers from sniping large amounts of tokens, while protecting smaller retail traders. # Other Features Supports SOL, USDC, JUP, and other quote tokens for maximum flexibility. Compatible with both SPL Token and Token2022 standards for broad token compatibility. Note: a 0.01 SOL pool creation fee applies for Token2022 pools using Output Token fee collection mode. Choose to collect fees only in the quote token or keep a percentage of all fees generated on the Dynamic Bonding Curve. Configure up to 16 price ranges with different liquidity curves for advanced pool customization. Partners can configure a SOL fee charged to token creators when creating pools. Partners can claim these fees via the SDK. Configure vesting schedules for partner and creator LP positions after migration to DAMM v2. **Minimum 10% Locked Liquidity Requirement** All DBC configs require at least 10% of liquidity to remain locked at day 1 (86400 seconds) post-migration. This can be achieved through permanent locked liquidity and/or LP vesting (DAMM v2 only). # Customizable Fees The Dynamic Bonding Curve (DBC) virtual pool collects a trading fee on every trade (buy or sell). * **Protocol Fee:**\ A portion of each trading fee is allocated to the DBC protocol (**20%** of the trading fee). * **Referral Fee:**\ Swap hosts (such as Jupiter, Photon, or trading bots) can include a referral account in the swap transaction to receive a referral fee, which is taken from the protocol fee (**20%** of the protocol fee). * **Fee Sharing in the Bonding Curve:** The remaining **80%** of the trading fee is split between the partner and the creator based on `creator_trading_fee_percentage`. For example, if `creator_trading_fee_percentage = 20%`, the partner gets 64% and the creator gets 16% of the total trading fee. * **Fee Distribution After Migration:** Once a token has graduated, the LP tokens are locked for both the partner and the token creator. The ratio of locked LP tokens is determined by the partner’s configuration. Both the partner and the token creator can claim fees from these locked LP tokens on Meteora DAMM v1 or DAMM v2. For DAMM v2 graduated pools, partners can also configure a **compounding fee mode** that reinvests trading fees back into the LP position instead of distributing them as separate claimable fees. # Migration ### Automatic Migration If the DBC pool reaches a pre-defined quote token or price threshold, the liquidity is automatically migrated to a DAMM v1 pool or DAMM v2 Pool on Meteora. We run 2 auto migrator keepers to migrate DBC pools. These 2 keepers have strict migration quote threshold requirements. Keeper addresses that we are running: 1. [CQdrEsYAxRqkwmpycuTwnMKggr3cr9fqY8Qma4J9TudY](https://solscan.io/account/CQdrEsYAxRqkwmpycuTwnMKggr3cr9fqY8Qma4J9TudY) * `pool_config.migration_quote_threshold` requirements: * 10 SOL * 750 USDC * 1500 JUP 2. [DeQ8dPv6ReZNQ45NfiWwS5CchWpB2BVq1QMyNV8L2uSW](https://solscan.io/account/DeQ8dPv6ReZNQ45NfiWwS5CchWpB2BVq1QMyNV8L2uSW) * `pool_config.migration_quote_threshold` requirements: * \>= 750 USD (`quote_mint` token) The Migration Keepers only runs on Mainnet. ### Manual Migration We have built a [manual migration user interface](https://migrator.meteora.ag/) for launchpads building on DBC to easily test the migration process. The Manual Migrator supports both Mainnet and Devnet. # DLMM Concepts Source: https://docs.meteora.ag/overview/products/dlmm/dlmm-concepts Core concepts behind DLMM: price bins, active bin, bin step, liquidity distribution, and how concentrated liquidity works in Meteora's DLMM. # Concentrated Liquidity With DLMM, LPs can provide liquidity within a specified price range, also known as concentrated liquidity. This is especially useful for token pairs where trades happen within a tight range, such as USDC/USDT where trades usually happen around \$0.99 - \$1.01. Often, liquidity outside of this range is untouched and LPs do not earn fees. By concentrating all liquidity within the price range of \$0.99 - \$1.01, LPs will be able to optimize their trading fees earned. All bins except for the active one contain just one type of token (X or Y) because they have been depleted or waiting to be used. Only the active bin earns trading fees. # DLMM Bin Structure ## Bin Price Liquidity is distributed across discrete bins with a fixed width and fixed price. Within each bin, liquidity can be exchanged at a fixed price using the formula $X + Y = k$ within each bin. Basically, you add X tokens and take out Y tokens (or vice versa), until there is only one type of token left. Each bin represents a single price point, and the difference between 2 consecutive bins is the **bin step**. Bin steps are calculated based on the basis points set by the pool creator. **Example:** Taking SOL/USDC, if the current price is \$20 and the bin step is 25 basis points (0.25%), then the consecutive bins would be: * Bin 1: \$20.00 * Bin 2: \$20.00 × 1.0025 = \$20.05 * Bin 3: \$20.05 × 1.0025 = \$20.10 * And so on... Liquidity pools are identified by their tuple of pooled assets: **(Token X, Token Y, Bin Step S)** ## Bin Liquidity Liquidity in each bin is calculated using the constant sum price variant: ```math theme={"system"} P \cdot x + y = L ``` Where: * **x** = quantity of token X * **y** = quantity of token Y * **L** = amount of liquidity in the bin * **P = Δy/Δx** = price constant unique to each pool **P** is defined as the rate of change of Y reserves per change in X reserves, and represents the price constant unique to each pool. ## Bin Composition **Key Points:** * All bins except for the active one contain just one type of token (X or Y) because they have been depleted or are waiting to be used * Only the active bin earns trading fees * **P** represents the slope of the line and remains consistently uniform within every bin In contrast to the constant product formula that you might be familiar with from other AMMs, the price is independent of the reserve amounts of both X and Y. In constant product AMMs, this relationship is calculated by $y = P/x$. Since the composition of reserves (x and y) are independent of both price and liquidity, an additional variable is used to describe the reserves available in the bin. This variable, **composition factor c**, is the percentage of bin liquidity composed of token Y: ```math theme={"system"} c = \frac{y}{L} ``` From this equation, we can derive x and y: ```math theme={"system"} y = c \cdot L ``` ```math theme={"system"} x = \frac{L}{P} \cdot (1 - c) ``` # Market Aggregation The constant sum curve intercepts both the x and y axes, meaning that the reserves of X or Y token can be depleted. When this happens, the current price moves to the next bin either on the left or right. ## Active Price Bin The **active price bin** is defined as the bin that contains reserves of both X and Y tokens. **Important:** There can only be one active bin at any point in time. * All bins to the **left** of the active bin contain only **token Y** * All bins to the **right** of the active bin contain only **token X** ## Practical Example Consider a SOL/USDC pool where: * Asset Y = USDC * Asset X = SOL * Price P = amount of USDC per SOL If we define the \$100 SOL bin as the active bin: * All bins to the left contain only USDC * All bins to the right contain only SOL * When there is significant demand for SOL, the active bin shifts to the right as the SOL reserves in the \$100 bin get exhausted # DLMM Farming Rewards Source: https://docs.meteora.ag/overview/products/dlmm/dlmm-farming-rewards How liquidity mining rewards work in DLMM: reward distribution, pro-rata share calculation, and how active bin participation affects earnings. DLMM farming rewards work differently from farms for Dynamic Pools. There are no LP tokens to stake into a farm. You start earning DLMM farming rewards once you deposit liquidity in a price range that covers the active bin. # How are rewards distributed? Rewards are distributed to the liquidity position in the active bin. But if swaps cause the price to move to a different active bin, rewards are distributed equally between bins crossed. For example, during a swap, active price moves from A -> C, but B is also within the range of active liquidity for the LP. Rewards will be equally distributed to the bins crossed for price points A, B, C. Your share of rewards: The proportion of rewards you get as an LP is based on your share of the liquidity position in the active bin and the bins crossed during swaps. The greater your share, the more rewards you get. Basically, only your liquidity that earns fees will earn farming rewards, so you won't get any rewards if your position is out of range and not active. No rewards will be distributed to the bin if it has 0 liquidity. # Is the rate of reward distribution linear? Yes, rewards are distributed at a fixed rate per second. For example, if there are 50,000 USDC in total farm rewards over 4 weeks (\~28 days), rewards are distributed at 0.020667 USDC per second. This is distributed to positions in the active bin and in bins crossed when the active bin changes. # What happens if there is no active liquidity? If there's no liquidity in the active bin, rewards will accumulate and not be distributed. Using the same example above (50,000 USDC in total rewards at 0.020667 USDC per second), if there's no active liquidity for 10 days, total undistributed farming rewards will be \~17,856.288 USDC. # How are rewards paid out? You'd have to claim farming rewards manually. # Do the rewards compound? No, rewards are not compounded. ## Example Let's walk through a step-by-step example of how DLMM farming rewards are distributed. **Total Rewards:** 50,000 USDC over 4 weeks (\~28 days)\ **Daily Rewards:** 1,785.71 USDC per day\ **Reward Rate:** 0.020667 USDC per second\ **Starting Active Bin:** 0 *** ### **Timeline**
| Time | Event | Bin 0 Supply | Bin 1 Supply | Notes | | ----- | ------------------------------------------------------------------------------------- | ------------ | ------------ | --------------------------------------------- | | 00:00 | **Position A** deposits **70** in bin 0 | 70 | 0 | | | 00:05 | **Position B** deposits **30** in bin 0
**Position C** deposits **100** in bin 1 | 100 | 100 | | | 00:10 | **Swap:** Active bin moves to bin 1 | 100 | 100 | Rewards are split
between bins 0 and 1 |
*** ### **Reward Calculations** #### **From 00:00 to 00:05 (5 seconds)** * **Accumulated Reward:**\ `0.020667 USDC/sec * 5 sec = 0.103335 USDC` * **Who earns?**\ Only **Position A** (bin 0) * **Distribution:** * Position A: **0.103335 USDC** #### **From 00:05 to 00:10 (5 seconds)** * **Accumulated Reward:**\ `0.020667 USDC/sec * 5 sec = 0.103335 USDC` * **Who earns?**\ Rewards are split equally between bins 0 and 1 (since the active bin moves during a swap) * **Reward per bin:**\ `0.103335 USDC / 2 = 0.0516675 USDC` per bin * **Bin 0 (Positions A & B):** * Position A: `0.0516675 * 70 / 100 = 0.03616725 USDC` * Position B: `0.0516675 * 30 / 100 = 0.01550025 USDC` * **Bin 1 (Position C):** * Position C: `0.0516675 * 100 / 100 = 0.0516675 USDC` *** ### **Summary**
| Position | 00:00 → 00:05 | 00:05 → 00:10 | **Total Reward** | | -------- | :-----------: | :-----------: | :--------------: | | **A** | 0.103335 | 0.03616725 | 0.13950225 | | **B** | — | 0.01550025 | 0.01550025 | | **C** | — | 0.0516675 | 0.0516675 |
*** **Key Points:** * Only active liquidity earns rewards. * When the active bin changes, rewards are split equally among all bins crossed, and then distributed proportionally to liquidity in each bin. * If a bin has no liquidity, it receives no rewards. # DLMM Fee Calculation Source: https://docs.meteora.ag/overview/products/dlmm/dlmm-fee-calculation How base fees and dynamic fees are calculated in DLMM pools, including the variable fee formula based on price volatility. # Total Trading Fee LPs earn a trading fee from traders when they perform a swap. The total trading fee ($f_s$) will have two components: 1. **A base fee** ($f_b$) 2. **A variable fee** ($f_v$) The **total swap fee** is calculated as:
$f_s = f_b + f_v$
The variable fee ($f_v$) is a function of real-time price volatility. The fee rate will be applied to the swap amount in each liquidity bin and distributed proportionally to the LPs in that bin. LPs can claim these fees whenever they are available. ## Base Fee The minimum fee charged per swap. Lower fee gets more volume but higher fee earns more per volume. Generally if you want a higher base fee, the higher the bin step. But a lower base fee than other DEXes might give more flexibility for dynamic fees to optimize for volume or fees given the market volatility. The base fee of a market is configured by the pool creator and determined by the base factor (B) and the bin step (s):
$f_b = B \cdot s \cdot 10 \cdot 10^{\text{base\_fee\_power\_factor}}$
Where: * **Base Factor** ($B$): An amplification to add to the bin step, to allow for adjustment of the pool base fees. * **Bin Step** ($s$): The price increment per bin, in basis points. * **Base Fee Power Factor**: An exponent that scales the base fee calculation. Default is 0 for most pools. Higher values increase the base fee exponentially. ## Variable Fee (Dynamic Fee) The variable fee depends on the volatility of the market where it is affected by swap frequencies as well as swaps that span across many bins. Fees are calculated and distributed on a **per bin** basis, to allow for a fair fee distribution to the LPs of each bin that is crossed. For large swaps that span across bins, fees are calculated iteratively. This means that if a large swap crosses $n$ bins, total swap fee is calculated per bin $k$ (such that $0 \leq k \leq n$), where $k$ is the difference in the bin IDs from the initial bin where the swap originated and the current bin in which it is being calculated. For example, let's use SOL/USDC. We also assume each bin step is \$1 for simplicity. Let us assume that the active bin (ID = 1000) before swap is \$100. A large buy order was made that pushed the price up to \$102. The value of $k$ for each bin is illustrated below:
| Bin Price | Bin ID | $k$ value | | :-------: | :----: | :-------: | | \$100 | 1000 | 0 | | \$101 | 1001 | 1 | | \$102 | 1002 | 2 |
Note that $k$ can also be negative if the price moves downwards. The variable fee for a bin $f_v(k)$ is calculated using: * **Variable fee control parameter** ($A$) * **Bin step** ($s$) * **Volatility accumulator** ($v_a(k)$) The formula is:
$f_v(k) = A(v_a(k) \cdot s)^2$
The on-chain computation uses ceiling division: it adds 99,999,999,999 before dividing by 100,000,000,000, ensuring the variable fee always rounds up. where: * **Volatility Accumulator** ($v_a(k)$): Captures instantaneous volatility * **Variable Fee Control Parameter** ($A$): Used to scale the variable fee component depending on the expected dynamics of the market ### Volatility Accumulator Volatility on the DLMM is derived from the number of bin changes that occur over time. Each bin change is a fixed price movement of the bin step. The **Volatility Accumulator** ($v_a(k)$) allows us to use bin crossovers as a measure of volatility beyond a single transaction. Think of the **Volatility Accumulator** ($v_a(k)$) as a witness of the current volatility of the token pair. Between each calculation step, this value will be kept in memory. It is calculated during a swap and depends on two factors: 1. **Volatility Reference** ($v_r$) from the previous swaps 2. **Introduced Volatility** ($|i_r - (activeID + k)|$) The Volatility Accumulator is calculated as:
$v_a(k) = v_r + |i_r - (activeID + k)|$
(Note: $activeID$ is the ID of the active bin **before** the swap is made.) #### Volatility Reference The **volatility reference** ($v_r$) depends on the time passed since the last transaction ($t$). We will define a window with an upper and lower bound. The lower bound of this window is defined as filter period ($t_f$), and upper bound as decay period ($t_d$). If $t$ is smaller than the **filter period** ($t_f$) (this indicates a high frequency of transactions occurring), then $v_r$ stays the same. If $t$ is greater than the **decay period** ($t_d$) (this indicates a low frequency of transactions occurring), then $v_r$ is reset to 0. If $t$ is within the **window bounded** by $t_f$ & $t_d$, then $v_r$ takes the previous value of $v_a$ decayed by a factor $R$ $$ v_r = \begin{cases} v_r, & t < t_f \\ R \cdot v_a, & t_f \leq t < t_d \\ 0, & t_d \leq t \end{cases} $$ High frequency trades will stack up volatility, while low frequency trades will slowly reduce the volatility. If a long time has passed without any trade, the volatility will reset to 0. We introduce a new variable, the **index reference** ($i_r$) to calculate the volatility introduced by the trade. In most cases, $i_r$ will be the ID of the active bin before the swap is made. In times of high frequency transactions, $i_r$ will keep its old value instead. Doing this will help prevent people from manipulating fees through making small lots of small transaction that increase and decrease price. $$ i_r = \begin{cases} i_r, & t < t_f \\ activeID, & t_f \leq t \end{cases} $$ The **volatility accumulated** $v_r$ for the bin $k$ will then be used to calculate the fees generated by swapping through this bin and be allocated to the liquidity providers of the bin. The final fee for the bin $k$ will be:
$fee = (swap\ amount)_k \cdot (f_b + f_v)_k$
### Example This example will show how the volatility accumulator will look as swaps are made. **Quick Recap:** * **Volatility Accumulator:** $v_a(k) = v_r + |i_r - (activeID + k)|$ * $t$ is time elapsed since last transaction * $t_f$ is filter period * $t_d$ is decay period * $R$ is the factor that decays $v_a$, the volatility accumulator ($R \cdot v_a$) when $t_f \leq t < t_d$ Let $t_f = 1$ sec, $t_d = 5$ secs, $R = 0.5$, and active bin ID is 100. #### **Swap 1** You make a trade that crosses +3 bins to 103. So $0 \leq k \leq 3$: $$ \begin{aligned} i_r &= 100 \\ v_r &= 0 \\ v_a(0) &= 0 + |100 - (100 + 0)| = 0 \\ v_a(1) &= 0 + |100 - (100 + 1)| = 1 \\ v_a(2) &= 0 + |100 - (100 + 2)| = 2 \\ v_a(3) &= 0 + |100 - (100 + 3)| = 3 \end{aligned} $$ At the end of swap 1, $v_a = 3$. #### **Swap 2** John makes a trade 4 seconds later that crosses +5 bins to 108. As $t = 4$, $v_r = R \cdot v_a$. So $0 \leq k \leq 5$: $$ \begin{aligned} i_r &= 103 \\ v_r &= 0.5 \cdot 3 = 1.5 \\ v_a(0) &= 1.5 + |103 - (103 + 0)| = 1.5 \\ v_a(1) &= 1.5 + |103 - (103 + 1)| = 2.5 \\ v_a(2) &= 1.5 + |103 - (103 + 2)| = 3.5 \\ \vdots \\ v_a(5) &= 1.5 + |103 - (103 + 5)| = 6.5 \end{aligned} $$ At the end of swap 2, $v_a = 6.5$. #### **Swap 3** Jane makes a trade 0.3 seconds later that crosses -2 bins to 106. As $t = 0.3 < t_f = 1$ second, $i_r$ and $v_r$ are not reset. The active bin before this swap is 108. So $-2 \leq k \leq 0$: $$ \begin{aligned} i_r &= 103 \\ v_r &= 1.5 \\ v_a(0) &= 1.5 + |103 - (108 + 0)| = 6.5 \\ v_a(-1) &= 1.5 + |103 - (108 - 1)| = 5.5 \\ v_a(-2) &= 1.5 + |103 - (108 - 2)| = 4.5 \end{aligned} $$ At the end of swap 3, $v_a = 4.5$. You can see that the volatility accumulator is decreasing despite high frequency of transactions, preventing people from manipulating fees by making lots of small transactions that increase/decrease prices. # DLMM Protocol Fees Protocol Fee is a percentage of the total swap fee (base + variable fee). ## Market-maker (MM) positions * **Standard Pools:** **10%** Protocol Fee, **90%** LP Fee * **Launch Pools:** **20%** Protocol Fee, **80%** LP Fee ## Limit orders * **50%** Protocol Fee, **50%** LO Fee ## Swaps Swap hosts (such as Jupiter, Photon, or trading bots) can include a referral account in the swap transaction to receive a **Host Fee** equal to **20%** of the protocol fee. Protocol fees are configured via the `protocol_share` parameter on each pool's preset parameters (measured in basis points of the total swap fee, max 2500 = 25%). **Breaking change in v0.11.0:** Bin state no longer stores `amount_x_in` and `amount_y_in` fields. The `reward_per_token_stored` fields have been renamed to `function_bytes`. Integrations that index bin state directly must update their deserialization logic. # DLMM Formulas Source: https://docs.meteora.ag/overview/products/dlmm/dlmm-formulas Mathematical formulas used in DLMM: bin price calculation, liquidity deposit/withdrawal, and fee accumulation. DLMM is a concentrated liquidity AMM that uses a dynamic fee mechanism to adjust liquidity based on market conditions. # Price Calculation Formulas ## Base Price Formula ```math theme={"system"} \text{price} = \left(1 + \frac{\text{bin\_step}}{\text{BASIS\_POINT\_MAX}}\right)^{\text{active\_id}} ``` **Where:** * `BASIS_POINT_MAX` = 10,000 * Uses Q64.64 fixed-point arithmetic * Example: For `bin_step = 10`, `price = (1.001)^active_id` ## Price Impact Formulas **Selling X for Y:** ```math theme={"system"} \text{min\_price} = \text{spot\_price} \times \frac{\text{BASIS\_POINT\_MAX} - \text{max\_price\_impact\_bps}}{\text{BASIS\_POINT\_MAX}} ``` **Selling Y for X:** ```math theme={"system"} \text{min\_price} = \text{spot\_price} \times \frac{\text{BASIS\_POINT\_MAX}}{\text{BASIS\_POINT\_MAX} - \text{max\_price\_impact\_bps}} ``` ## Fee Calculation Formulas ### Total Trading Fee ```math theme={"system"} \text{total\_fee\_rate} = \min(\text{base\_fee\_rate} + \text{variable\_fee\_rate}, \text{MAX\_FEE\_RATE}) ``` #### Base Fee Formula ```math theme={"system"} \text{base\_fee\_rate} = \text{base\_factor} \times \text{bin\_step} \times 10 \times 10^{\text{base\_fee\_power\_factor}} ``` #### Variable Fee Formula ```math theme={"system"} \text{variable\_fee\_rate} = \frac{(\text{volatility\_accumulator} \times \text{bin\_step})^2 \times \text{variable\_fee\_control} + \text{OFFSET}}{\text{SCALE}} ``` **Where:** * `OFFSET` = 99,999,999,999 * `SCALE` = 100,000,000,000 #### Composition Fee Formula ```math theme={"system"} \text{composition\_fee} = \frac{\text{swap\_amount} \times \text{total\_fee\_rate} \times (1 + \text{total\_fee\_rate})}{\text{FEE\_PRECISION}^2} ``` **Where:** * `MAX_FEE_RATE` = 100,000,000 ## Liquidity and Bin Math Formulas ### Liquidity Formula (Constant Sum) ```math theme={"system"} L = \text{price} \times x + y ``` **Where:** * `L` is liquidity * `x` and `y` are token amounts * Price is in Q64.64 format ### Liquidity Share Formula ```math theme={"system"} \text{liquidity\_share} = \frac{\text{in\_liquidity} \times \text{liquidity\_supply}}{\text{bin\_liquidity}} ``` # Strategies and Use Cases Source: https://docs.meteora.ag/overview/products/dlmm/strategies-and-use-cases LP strategies for DLMM: spot, curve, and bid-ask shapes — and when to use each based on your volatility outlook and capital efficiency goals. Through allocating different amounts of tokens at diverse price points, we are able to build a desired liquidity shape (volatility strategy) with the DLMM that best fits our LP goals. Provides a uniform distribution of liquidity that is flexible and suitable for any type of market and conditions. It is the most straightforward volatility strategy to deploy for new LPs who want to rebalance their position less frequently. This is similar to setting a CLMM price range. Ideal for a concentrated approach that aims to maximize capital efficiency by allocating capital mostly in the middle of your price range. This is great for stables or pairs where the price does not change very often. Bid-Ask is an inverse Curve distribution, where most of your capital is allocated towards both ends of the range. This strategy can be used to capture bigger volatility swings away from the current price. Bid-Ask is more complex than Spot and may require more frequent rebalancing to be effective, but has a high potential for fee capture during situations where prices fluctuate wildly around the current price. Bid-Ask can also be deployed single sided for a DCA in or out strategy. # Basic Strategies
Strategy Advantages Disadvantages Considerations
Curve
Curve
• Capital-efficient deployment of liquidity

• Ideal for calm markets
Increased risk of impermanent loss To achieve optimal effectiveness, it's necessary to consistently rebalance based on the current price.
Bid-Ask
Bid-Ask
• Captures market volatility

• Great for DCA in/out of positions
Riskier than other positions Requires rebalancing to remain efficient
Spot-Concentrated
Liquidity equally deposited between 1-3 bins
Spot-Concentrated
• Ideal for Stablecoin pairs

• Maximises assets efficiency
Highest risk of Impermanent Loss when price leaves the bin range If used in volatile pairs for capturing greatest amount of fees, make sure to monitor very closely as this strategy has highest risk of Impermanent Loss.
Spot-Spread
Liquidity equally deposited between 20-30 bins
Spot-Spread
• Very capital-efficient strategy

• Expect to stay in range for small intra-day volatility
High risk of Impermanent loss Make sure to monitor position at least on a daily basis.
Spot-Wide
Liquidity equally deposited between 50 bins
Spot-Wide
• Lower risk of impermanent loss

• Ideal for LPs who do not wish to regularly monitor price action
Reduced capital efficiency since capital is spread over a larger range Although capital-efficiency is lower than the other shapes above, in general, it is still better than x\*y=k exchanges
# What is Bin Step? Each bin represents a single price point, and the difference between 2 consecutive bins is the bin step. Bin steps are calculated based on the basis points set by the pool creator. Bin step is similar to tick size and a higher size means a larger jump from one price to the next. For example, if the current price for SOL/USDC is \$20 per SOL and the bin step is 25 basis points (0.25%), then the consecutive bins would be 20 x 1.0025 = 20.05, 20.05 \* 1.0025 = 20.10 and so on. Allows you to capture more volume, but your max price range per position is smaller. A general rule of thumb is smaller steps for stable pairs and larger steps for more volatile pairs. Allows you to set a wider price range per position, but at the cost of less volume, since there's a less continuous price range (harder for liquidity to be picked up for swaps). Important for highly volatile pairs where price swings can be huge. For highly volatile pairs, larger bin steps could also mean less errors, since with smaller bin steps a trade may jump between different binArrays frequently. Currently the max # of bins per position is 1400, so a larger bin step can be used if you need to widen your range for a single position. # How is Bin Step related to Base Fee? Base Fee is the minimum fee charged per swap. * Lower fee gets more volume but higher fee earns more per volume. * Generally if you want a higher base fee, the higher the bin step. * But a lower base fee than other DEXes might give more flexibility for dynamic fees to optimize for volume or fees given the market volatility. # Token 2022 Extensions Source: https://docs.meteora.ag/overview/products/dlmm/token-2022-extensions How DLMM handles Token 2022 extensions including transfer fees, interest-bearing tokens, and other SPL Token 2022 features. DLMM supports Token 2022 tokens with a variety of extensions, enabling tokens with enhanced functionality to be easily integrated into DLMM pools. These extensions that DLMM supports are categorized based on whether they require a `token_badge` from Meteora or can be used permissionlessly. ## Permissionless Extensions If your token is a Token 2022 with these extensions, you can use them permissionlessly without any additional setup or approval from Meteora. The following extensions can be used permissionlessly with DLMM: * `TransferFeeConfig` * `MetadataPointer` * `TokenMetadata` * `TransferHook` - Custom transfer logic. Only when both `hook_program` and `hook_authority` are revoked * `MemoTransfer` `MemoTransfer` is an account-level extension, not a mint extension. It is applied to individual token accounts rather than to the mint itself. *** ## Permissioned Extensions If your token requires any of the permissioned extensions that are listed below, you will need to get a `token_badge` from Meteora to use them seamlessly with DLMM. Start by completing this [Google Form](https://forms.gle/59n3zDiGS2C6qMfd7) indicating which extensions you require. After submitting it, open a Discord ticket to inform us so we can review your request. Getting a `token_badge` enables you to use these extensions seamlessly with DLMM: * `Uninitialized` * `TransferFeeConfig` * `TransferFeeAmount` * `MintCloseAuthority` * `ConfidentialTransferMint` * `ConfidentialTransferAccount` * `DefaultAccountState` - All new token accounts must be unfrozen by default * `ImmutableOwner` * `NonTransferable` * `InterestBearingConfig` * `CpiGuard` * `PermanentDelegate` * `NonTransferableAccount` * `TransferHook` * `TransferHookAccount` * `ConfidentialTransferFeeConfig` * `ConfidentialTransferFeeAmount` * `MetadataPointer` * `TokenMetadata` * `GroupPointer` * `TokenGroup` * `GroupMemberPointer` * `TokenGroupMember` * `ConfidentialMintBurn` * `ScaledUiAmount` * `Pausable` * `PausableAccount` # What's DLMM? Source: https://docs.meteora.ag/overview/products/dlmm/what-is-dlmm DLMM organizes liquidity into discrete price bins for zero-slippage swaps within each bin, dynamic fees during volatility, and precise capital concentration — ideal for token launches and active LP strategies. DLMM is designed with features that provide more flexibility for liquidity providers (LPs) and help LPs earn as much fees as possible with their capital. DLMM was inspired by Trader Joe's Liquidity Book and in our implementation, we organize the liquidity of an asset pair into discrete price bins. Token reserves deposited in a liquidity bin are made available for exchange at the price defined for that particular bin. Swaps that happen within the price bin itself would not suffer from slippage. The market for the asset pair is established by aggregating all the discrete liquidity bins. DLMM LPs earn fees for liquidity provision, dynamic fees during market volatility, and Liquidity Mining (LM) rewards where available. DLMM is also the fundamental system behind the **DLMM Launch Pool**. DLMM Launch Pool is a pool type designed for new token launches. It comes fundamentally equipped with a feature set that makes it optimal for bootstrapping liquidity for new tokens and making the tokens accessible on Jupiter and other trading integrations. # Features Higher capital efficiency and fees for LPs. DLMM can support high volume trading with low liquidity requirements through the concentrating of tokens at or around the current market value. Higher trading volume and fees due to zero slippage within each active bin that greatly reduces price impact. Greater flexibility and control for LPs when it comes to efficient liquidity distribution. LPs can build flexible liquidity distributions according to their volatility strategies. Unlocks more opportunities to capture higher fees based on market conditions and LP objectives / risk profile. LPs can also provide single-sided liquidity with only one token, unlike typical AMMs. Fees that increase or decrease depending on how volatile the market is, which in turn help offset losses that LPs may experience in volatile markets and enhance LP profitability. # How does it work? Users can select token pairs that they wish to provide liquidity for. For each token pair, they can choose a liquidity shape that best suits their strategies. ## Liquidity Shapes Provides a uniform distribution that is versatile and risk adjusted, suitable for any type of market and conditions. Ideal for a concentrated approach that aims to maximise efficiency while minimizing impact of volatility. An inverse Curve distribution, typically deployed single sided for a DCA in or out strategy. It can be used to capture volatility in a stable or pegged pair. Take note that it is **important for LPs to closely monitor their positions** and adjust accordingly to market conditions to manage the risk of impermanent loss. Unlike our Dynamic AMM pools, the DLMM is not connected to our Dynamic Vaults for lending yield. All liquidity is solely used for trading. # Dynamic Fees Dynamic Fees acts as a form of surge pricing based on market fluctuations and volatility. ## How do Dynamic Fees work? Since demand for tokens and price volatility are often the highest at launch, Dynamic Fee would also be high. This both mitigates against aggressive sniper bot purchases while capturing more fees for the token creator and LPs in the pool. The total swap fee consists of two components: a base fee and a variable fee. The base fee is configured by the pool creator and determined by the base factor and bin step. The variable fee is calculated based on real-time price volatility and is affected by swap frequencies and the number of bins crossed during a swap. These fees are calculated and distributed on a per-bin basis, ensuring fair distribution to LPs in each bin that is crossed. LPs can claim these fees whenever they are available. All DLMM Launch Pools have Dynamic Fees enabled by default. # Alpha Vault Source: https://docs.meteora.ag/resources/audits/alpha-vault # Offside Labs Download the Offside Labs v0.4.0 audit report. Download the Offside Labs v0.3.2 audit report. Download the Offside Labs May 2024 audit report. # DAMM v1 Source: https://docs.meteora.ag/resources/audits/damm-v1 # Offside Labs Download the Offside Labs v0.5.3 audit report. Download the Offside Labs v0.5.2 audit report. Download the Offside Labs v0.5.1 audit report. # Halborn Download the Halborn July 2022 audit report. # Oak Download the Oak October 2022 audit report. # DAMM v2 Source: https://docs.meteora.ag/resources/audits/damm-v2 # Zenith Download the Zenith v0.2.0 audit report. Download the Zenith v0.1.8 audit report. Download the Zenith v0.1.7 audit report. Download the Zenith v0.1.6 audit report. Download the Zenith v0.1.5 audit report. Download the Zenith v0.1.4 audit report. Download the Zenith v0.1.2 audit report. Download the Zenith June 2025 audit report \[1]. # Offside Labs Download the Offside Labs v0.2.0 audit report. Download the Offside Labs v0.1.8 audit report. Download the Offside Labs v0.1.7 audit report. Download the Offside Labs v0.1.6 audit report. Download the Offside Labs v0.1.5 audit report. Download the Offside Labs June 2025 audit report. # OtterSec Download the OtterSec v0.1.5 audit report. Download the OtterSec April 2025 audit report. # DBC Source: https://docs.meteora.ag/resources/audits/dbc # Offside Labs Download the Offside Labs v0.1.10 audit report. Download the Offside Labs v0.1.9 audit report. Download the Offside Labs v0.1.8 audit report. Download the Offside Labs v0.1.7 audit report. Download the Offside Labs v0.1.6 audit report. Download the Offside Labs v0.1.1 audit report. # OtterSec Download the OtterSec v0.1.3 audit report. # Zenith Download the Zenith v0.1.10 audit report. Download the Zenith v0.1.9 audit report. Download the Zenith v0.1.8 audit report. Download the Zenith v0.1.7 audit report. Download the Zenith v0.1.4 audit report. Download the Zenith v0.1.3 audit report. Download the Zenith v0.1.1 audit report. # DLMM Source: https://docs.meteora.ag/resources/audits/dlmm # Zenith Download the Zenith v0.11.0 audit report. Download the Zenith v0.10.1 audit report. # Offside Labs Download the Offside Labs v0.11.0 audit report. Download the Offside Labs v0.10.0 audit report. Download the Offside Labs v0.9.0 audit report. Download the Offside Labs v0.8.2 audit report. Download the Offside Labs January 2024 audit report. # OtterSec Download the OtterSec v0.8.5 audit report. Download the OtterSec February 2024 audit report. # Sec3 Download the Sec3 February 2024 audit report. # Dynamic Fee Sharing Source: https://docs.meteora.ag/resources/audits/dynamic-fee-sharing # Zenith Download the Zenith v0.1.1 audit report. # Dynamic Vault Source: https://docs.meteora.ag/resources/audits/dynamic-vault # Offside Labs Download the Offside Labs v0.9.4 audit report. Download the Offside Labs September 2024 audit report. # Sherlock Download the Sherlock v0.9.4 audit report. # Quantstamp Download the Quantstamp June 2022 audit report. # Halborn Download the Halborn July 2022 audit report. # Overview Source: https://docs.meteora.ag/resources/audits/overview Audit reports for DLMM Program Audit reports for DAMM v1 Program Audit reports for DAMM v2 Program Audit reports for Dynamic Bonding Curve Program Audit reports for Presale Vault Program Audit reports for Alpha Vault Program Audit reports for Dynamic Vault Program Audit reports for Stake2Earn Program Audit reports for Dynamic Fee Sharing Program Audit reports for Zap Program # Presale Vault Source: https://docs.meteora.ag/resources/audits/presale-vault # Sherlock Download the Sherlock v0.1.1 audit report. # Offside Labs Download the Offside Labs v0.1.1 audit report. Download the Offside Labs October 2025 audit report. # Stake2Earn Source: https://docs.meteora.ag/resources/audits/stake2earn # Offside Labs Download the Offside Labs October 2024 audit report. # Zap Source: https://docs.meteora.ag/resources/audits/zap # Offside Labs Download the Offside Labs v0.2.2 audit report. Download the Offside Labs v0.2.1 audit report. Download the Offside Labs v0.2.0 audit report. Download the Offside Labs October 2025 audit report. # Zenith Download the Zenith v0.2.2 audit report. Download the Zenith v0.2.1 audit report. Download the Zenith v0.2.0 audit report. # OtterSec Download the OtterSec October 2025 audit report. # Bug Bounty Source: https://docs.meteora.ag/resources/bug-bounty/overview Help us secure Meteora by responsibly disclosing vulnerabilities. We work with OOO Security to manage our bug bounty program. Meteora's bug bounty program is managed through [OOO Security](https://ooosec.com), covering vulnerabilities across our on-chain programs and protocol infrastructure. If you've found a security issue, please report it responsibly through the program — do not disclose publicly before it has been resolved. Report vulnerabilities and earn rewards for responsible disclosure. Covers DLMM, DAMM v1/v2, DBC, Alpha Vault, and other Meteora programs. # Dashboards Source: https://docs.meteora.ag/resources/community/dashboards Tokleo is a real-time analytics platform that provides enhanced tracking and insights for Meteora pools using comprehensive on-chain data. Created as a community hobby project, it helps users identify the best performing pools through customizable visualizations and automated data refreshing every 5 minutes. Looker Studio is a tool that allows you to track all all Meteora pools stats in one place. It provides a comprehensive overview of all pools, including performance metrics and analytics, helping you make informed decisions about your liquidity provisioning strategies. Hanyon Analytics is a data-driven platform born from a passion for analytics and storytelling in the DeFi space. The platform launches with two powerful tools specifically designed for the Meteora community: DAMMv2 User Analytics for tracking personal performance and monitoring top wallets, and the Top DAMMv2 Wallet Finder for discovering the most profitable wallets to copy or follow. DAMM v2 Searcher is a specialized search engine designed to eliminate the endless scrolling through Meteora's DAMM V2 pools by using smart analytics to identify high-yield liquidity opportunities. The platform automatically filters pools based on strict criteria (minimum $10 TVL, created within 2 days, 5%+ Fee/TVL ratio, and over $5 in 24h fees) to surface hidden gems with exceptional earning potential. DAMM v2 Analytics is a Dune dashboard that provides a comprehensive overview of Meteora's DAMM v2 pools. DBC Analytics is a Flipside dashboard that provides a comprehensive overview of Meteora's DBC pools. Meteorology AI Agent is a web-based onboarding assistant designed to help novice liquidity providers navigate the Meteora ecosystem. The platform operates in two intelligent modes: Chart-to-Strategy analysis that converts price chart screenshots into specific DLMM configurations (including range, bin-step, fee tier, and strategy recommendations), and Docs Q\&A that answers questions about Meteora, DLMM, AMM, and liquidity-providing risks using advanced retrieval-augmented generation. # Tools Source: https://docs.meteora.ag/resources/community/tools Meteora's ecosystem features a diverse collection of community-built tools that enhance the DeFi experience on Solana. These tools range from automated liquidity management platforms to analytics dashboards that provide real-time performance tracking. MetEngine lets you create and manage DLMM (Dynamic Liquidity Market Making) and DAMM positions on Meteora - instantly, from Telegram, Web App, and Farcaster MiniApp. You can LP with one click, mirror top-performing wallets and monitor everything in real time. Cleopetra is a seamless platform for liquidity provisioning on Solana DEXes, directly from Telegram. Enter a token, pick an LP strategy of your choice and create the position — the agent finds optimal pools and auto-rebalance positions when needed to maximise fees and reduce impermanent loss. Rocket Scan gives you the edge in the memecoin market with lightning-fast updates and real-time momentum tracking. Discover tokens early for DAMM V2 Pools and find the best entry points when trading in the trenches. Metlex is a specialized web dashboard for Meteora DLMM liquidity providers. It helps LPs monitor, analyze, and optimize their positions with features including PnL tracking, pool safety analysis, and top pair discovery across multiple DEXs. Built specifically for DLMM strategies, Metlex provides the essential tools needed to maximize liquidity provision returns. DLMM Profiler is a tool that allows you to analyze the performance of your DLMM positions on Meteora. Ultra LP is a tool that gives you real-time analytics and P\&L for all DLMM positions. As the LP Copilot on Meteora, you can track all your LP positions on Meteora with real-time and historical performance. Liquid Nova is an intelligent liquidity management platform that automates how you provide and manage liquidity in Meteora. Instead of constantly creating positions, monitoring prices, manually adjusting positions, and claiming fees, Liquid Nova executes your precise instructions automatically. UnifAI Network is a platform that enables AI agents to autonomously discover and use tools at runtime. It provides a unified API for agents to dynamically find services, execute tasks, and operate independently while maintaining security through client-side data control. The platform works with any LLM that supports function calling, allowing agents to adapt their capabilities on-demand rather than being limited to pre-configured tools. Starseed is an advanced, customizable Solana trading platform built to solve the inefficiency of traders juggling 10+ websites. It unifies essential tools onto a single dashboard where users can manage Meteora DLMM positions, swap tokens, and utilize advanced tools for automated position management. The platform's mission is to be Solana's one-stop-shop, offering a best-in-class experience where traders spend more time winning and less time juggling tabs. # Brand Kit Source: https://docs.meteora.ag/resources/miscellaneous/brand-kit Download the complete Meteora brand kit consisting of logos and symbols. # How to create a Liquidity Pool Source: https://docs.meteora.ag/user-guide/guides/how-to-create-a-pool User Guide ## DLMM ### Creating a New Pool Anyone can create a DLMM pool here: [https://app.meteora.ag/create](https://app.meteora.ag/create) * You can search by token ticker or by pasting the token contract address * We also display a list of tokens that you already hold in your wallet to help you select quickly * SOL or stables (e.g. USDC, USDT) are usually used as the Quote token, which represents the price used to trade the Base token * If you selected SOL, USDC, or USDT as your Base token, there will be a reminder that those tokens are usually used as the Quote token * Base Fee is the minimum % charged for every swap that occurs through a liquidity position * Each bin represents a single price point, and the difference between 2 consecutive bins is the bin step. Similar to tick size, a higher bin step means a larger jump from one price to the next. * **Smaller bin step**: Allows you to capture more volume, but your max range per position is smaller, with more limited base fee options. Generally, use smaller steps for more stable pairs and larger steps for more volatile pairs. * **Larger bin step**: Allows you to set a higher base fee and a wider price range per position, but at the cost of less volume, since there's a less continuous price range (harder for liquidity to be picked up for swaps). But useful for highly volatile pairs where price swings can be huge. You can select your Bin Step, only after you have selected your Base Fee %. And after you have created your pool with your selected Base Fee and Bin Step, you won't be able to change those parameters. * This would be the initial pool price for your token. In other words, it’s the amount of Quote Tokens needed to purchase 1 Base Token. Please verify that the price you input matches the current estimated market price, to avoid losing initial liquidity deposited due to arbitrage trades. * To help you, we provide the estimated market price based on Jupiter’s pricing. But please always verify and conduct your own due diligence. When creating a DLMM pool and setting the initial pool price, the eventual pool price may deviate slightly from your input; this is because if the bin price cannot be represented exactly by the program, the frontend will round up / down to the closest price. The deviation depends on the bin step the user selected. To prevent duplicate DLMM pools, for each token pair, there can only be one pool with a specific Bin Step and Base Fee % parameter combination on Meteora. If that pool already exists, you won’t be able to create a new pool with the same parameters. ## DAMM v1 or DAMM v2 ### Creating a New Pool Anyone can create a DAMM v2 pool here: [https://www.meteora.ag/create](https://www.meteora.ag/create) When you are on the Dynamic Pool Setup page, select “Create V2 pool” to start creating a DAMM v2 pool. You will be directed to the DAMM v2 pool creation page, where you can enter or select your preferred parameters for the pool. * You can search by token ticker or by pasting the token contract address * We also display a list of tokens that you already hold in your wallet to help you select quickly To support Token 2022 tokens and extensions at DAMM v2 pool creation, a token badge from the project team must be provided. However, some extensions (e.g. transfer hook) are presently unsupported. * SOL or stables (e.g. USDC, USDT) are usually used as the Quote token, which represents the price used to trade the Base token * If you selected SOL, USDC, or USDT as your Base token, there will be a reminder that those tokens are usually used as the Quote token * This would be the initial pool price for your token. In other words, it’s the amount of Quote Tokens needed to purchase 1 Base Token. Please verify that the price you input matches the current estimated market price, to avoid losing initial liquidity deposited due to arbitrage trades. * To help you, we provide the estimated market price based on Jupiter’s pricing. But please always verify and conduct your own due diligence. * Base Fee is the minimum % charged for every swap that occurs through a liquidity position. * **20%** of the fee charged goes to the protocol, and the remaining **80%** goes to liquidity providers in the pool. * By default, the pool would “Start Now”, meaning your pool would start trading immediately after you confirm the pool creation. * But you can also choose a “Custom” start time, picking from a future date and time (at 30 min intervals), such that your pool would start trading only from the selected date and time. * **Dynamic Fee**: If you choose “Yes”, your pool will charge slightly higher fees on top of your Base Fee, based on market volatility. If not, the pool fee will always be the Base Fee. * **Fee Collection Token**: If you select “Quote”, you will receive your fees earned only in the form of your Quote token (e.g. USDC of SOL). * Regarding how DAMM 2 collects fee only using the Quote token ("Token B"): * If a user swaps from A -> B, fee is charged on B; protocol takes some of the user's B * If a user swaps from B -> A, fee is charged on B before the swap is calculated; protocol takes some of the user's B before it gets swapped to A * Fee Scheduler is an anti-sniper mechanism. When enabled, fees charged on trades would start a % higher than the Base Fee, then drop over time until it reaches the Base Fee. * Exponential Fee Scheduler: * Fees start at 50%, then start dropping, but at a faster rate than Linear mode. This % applies to the Meteora user interface only. Pool creators or partners using the documentation to set up the pool programmatically may adjust their starting fee % and other parameters. * Linear Fee Scheduler: * Fees start at 50%, then start dropping, but at a slower rate than Exponential mode. This % applies to the Meteora user interface only. Pool creators or partners using our documentation to set up the pool programmatically may adjust their starting fee % and other parameters. If you select “Permanently lock my liquidity”, all tokens you deposit would be permanently locked and you would no longer be able to access or withdraw the underlying assets, forever. * Once you have entered and selected your preferred parameters, do another quick check. Click the “Create” button and your new pool will be created! To prevent duplicate DAMM v2 pools, for each token pair, there can only be one pool for a specific set of DAMM v2 parameter combinations (Base Fee, Dynamic Fee, Fee collection Token, Fee Scheduler Mode etc.) on Meteora. If that pool already exists, you won’t be able to create a new pool with the same parameters. # How to Swap Tokens on Meteora Source: https://docs.meteora.ag/user-guide/guides/how-to-swap-tokens User Guide If you find yourself in a position where you lack one or both of the tokens required to add liquidity to a pool, you can swap tokens on Meteora using one of these methods: ## Jupiter Terminal Meteora has integrated [Jupiter](https://jup.ag/) - the most popular DEX aggregator - to help you swap at the best rates. This is done through Jupiter Terminal, which is an open-sourced, lite version of Jupiter that provides end-to-end swap flow by linking it in a site's HTML. When you are navigating through Meteora, you can access Jupiter Terminal by selecting the Jupiter Terminal icon at the bottom left of the screen. You will see a pop-up where you can connect your wallet (this connects automatically if you're connected on Meteora), select your input and output tokens, and execute your swap. ## Swapping within the pool When you already possess one of the tokens in an asset pair for a pool, you can also swap some amounts of that token to the other directly using the existing pool liquidity. DLMM, DAMM v2, and DAMM v1, all have a “Swap” tab to swap tokens directly within the pool. For example, if you want to add liquidity to a SOL/USDC pool, but you only have SOL, you can simply select the "Swap" tab on the pool page to swap a portion your total SOL to an equivalent value of USDC (based on the current pool price of the token). Before you swap through that specific pool, please check that the pool has sufficient liquidity and the current pool price of the token is in sync with the market price. In addition, check that you are comfortable with the settings (e.g. transaction fees, your preferred slippage) of that pool, and check that the “Swap info” section is acceptable before you execute your transaction. ### How is "Price Impact" on the UI calculated for a swap that occurs through a pool? Price Impact is the % difference between the value of your input amount and the value of your output amount. On the Meteora user interface, Price Impact %: * Does not take slippage into account for the swap output amount, so you'll have to set slippage rate to 0 before calculating if you want a more precise %. * Does not take into account that the dollar value in the swap input box is sourced from Jupiter's price API, so it may not always be 100% accurate. For example: sometimes USDC will be worth \$0.9999 * Does not take into account the Swap fee that's charged on the swap. # How to use DAMM v2 Source: https://docs.meteora.ag/user-guide/guides/how-to-use-damm-v2 User Guide ## Navigating DAMM v2 pools DAMM v2, or Dynamic Automated Market Maker v2, builds upon the original DAMM, to provide a powerful, yet hassle-free way to add liquidity and earn fees on Solana. [DAMM v2](https://meteoraag.medium.com/dynamic-amm-v2-helping-lps-and-launches-win-c56128c883ad) allows you to deposit tokens into a pool, which are then used as liquidity for traders, bots, and aggregators to swap tokens, earning you fees with every trade. But it is much more configurable than your typical AMM, with features tailored for a wide variety of liquidity providers, token launches, and launchpads. **Features for LPs include:** Supports a wide range of SPL tokens and select Token 2022 extensions, letting you provide liquidity for more token types. Dynamic fees boost the fees you earn during periods of high market volatility, helping LPs maximize returns when trading activity increases. Advanced anti-sniper tools, such as the Fee Scheduler, start with higher fees to penalize snipers and gradually reduce fees over time for regular traders. **LPs also have:** Choose to receive your liquidity provider fees directly in a stable quote token like USDC, instead of the pool tokens. Lock your memecoin liquidity with a customizable vesting period or even permanently lock it, while still being able to claim your earned fees. Effortlessly transfer your liquidity position to another person by simply sending the NFT that represents your LP position. **Token creators can even:** Launch a new pool using just your token, without needing USDC or other stablecoins. Set a specific future time when pool trading should be enabled, allowing for launches, announcements, or fair trading starts. Open a pool with a fixed price range to provide higher capital efficiency, similar to Uniswap v3-style concentrated liquidity. On the Pool List page, once you’ve selected the token pair and DAMM v2 pool you’d like to add liquidity into, click on it and you would enter the specific pool’s detail page. To illustrate the various features of DAMM v2, we will be referring to a few pools in this guide, for example [SOL-USDC](https://app.meteora.ag/dammv2/8Pm2kZpnxD3hoMmt4bjStX2Pw2Z9abpbHzZxMPqxPmie), [URANUS-USDC](https://app.meteora.ag/dammv2/7ccKzmrXBpFHwyZGPqPuKL6bEyWAETSnHwnWe3jEneVc), [WLFI-USD1](https://app.meteora.ag/dammv2/F6L1RKAKwNuWwyCwweja6uxAkRv41XFTRWmg8tKGkn83), and [ICM-SOL](https://app.meteora.ag/dammv2/FLuXAxxqMbLkKHWHHCAiX2ub8qZuoC9bb35bSRDNDMo2). ### Total Value Locked At the top left of the pool detail page, you can vi ew the pool’s TVL (Total Value Locked). This is the total amount of token assets in the pool in terms of \$USD value (how much all the tokens currently in the pool are worth). DAMM v2 allows both permanent and non-permanent locking of liquidity, and the TVL section would show the following: * Vested Liquidity: % of liquidity non-permanently locked for at least 3 months (at this point in time) * Permanently Locked Liquidity: % of liquidity permanently locked in the pool Here's a screenshot of this example pool: [URANUS-USDC](https://app.meteora.ag/dammv2/7ccKzmrXBpFHwyZGPqPuKL6bEyWAETSnHwnWe3jEneVc) ### Price Range For most DAMM v2 pools created via the Meteora user interface (website), the price range supported is 0 to infinity. But for certain DAMM v2 pools created programmatically using our documentation, they could be configured to have a more concentrated price range with a specific min price and max price for higher capital efficiency. Once a pool is created, the price range for that specific pool is fixed and can never be adjusted again. Here’s a screenshot of the example pool: [SOL-USDC](https://app.meteora.ag/dammv2/8Pm2kZpnxD3hoMmt4bjStX2Pw2Z9abpbHzZxMPqxPmie), where the price range is concentrated at 70 - 440 USDC/SOL. ### Liquidity Allocation The TVL is further broken down into the amount of each token in the pool. In this screenshot of the example pool [ICM-SOL](https://app.meteora.ag/dammv2/FLuXAxxqMbLkKHWHHCAiX2ub8qZuoC9bb35bSRDNDMo2), \$820,815.85 in TVL is actually made up of 24,451,511 ICM and 2,064.47 SOL. To support Token 2022 tokens and extensions at DAMM v2 pool creation, a token badge from the project team must be provided. However, some extensions (e.g. transfer hook) are presently unsupported. In the Liquidity Allocation section, you can view a snippet of the token’s contract address. Click the icon next to it to access important quicklinks; to copy the token’s contract address, view the contract address on Solscan, check for token risks on Rugcheck.xyz, or analyze the token behaviour on Bubblemaps. You can also view the Jupiter Organic Score for the token and if the token has any risks. ### Pool Details #### Current Pool Price The Current Pool Price may not always be close to the general market price, especially when it was just created with a wrong initial price and has low liquidity. Check that the pool price is in sync with the market price prior to adding liquidity, to avoid incurring a loss due to arbitrage trades. #### 24h Volume Volume generated by the pool in 24h #### 24h Fee Total fees collected by the pool in 24h #### Base Fee Minimum trading fees earned when swaps occur through the pool #### Dynamic Fee Additional fee charged on each trade based on real-time price volatility #### Liquidity Provider Fee ```math theme={"system"} Base Fee + Dynamic Fee ``` #### Protocol Fee Amount of fees charged on each trade that goes to the protocol or integrations. For DAMM v2 pools, **20%** Protocol Fee and **80%** LP Fee apply to both standard and Launch Pools. #### Referral Fee Swap hosts can include a referral account in the swap transaction to receive a **Referral Fee** equal to **20%** of the protocol fee. #### Fee Collection Token * Pool creators can choose how LPs receive fees from the pool; whether in Base + Quote tokens, or Quote token only. * For example, in a URANUS-SOL pool, pool creators can set it such that LPs receive fees in both URANUS and SOL tokens (the typical AMM process), or receive fees only in SOL tokens. Once the pool is created, the selected Fee Collection Token cannot be changed. * As an LP, you can choose the specific DAMM v2 pool that has the Fee Collection Token that fits your requirements. #### Fee Scheduler * DAMM v2 supports Anti-Sniper mechanisms such as the Fee Scheduler, where fees start higher at launch then drop over time until it reaches the Base Fee. * Pool creators that enable the Fee Scheduler at pool creation, must also select their preferred mode; between the “Exponential” mode or “Linear” mode. * For pool creators who set up a Fee Scheduler using our Pool Creation UI on our website, the starting fee would be 50%. * For pool creators who set up a Fee Scheduler programmatically using our documentation (not via the Pool Creation UI), they can configure certain parameters, such as the starting fee %. * As an LP, you can choose the specific DAMM v2 pool that has the Fee Scheduler mode and parameters that fit your requirements. **Exponential Fee Scheduler** In this [ICM-SOL](https://app.meteora.ag/dammv2/FLuXAxxqMbLkKHWHHCAiX2ub8qZuoC9bb35bSRDNDMo2) pool example, Exponential mode is used. Fees started at 50% before dropping exponentially over time until it reached 1% after 60 seconds. **Linear Fee Scheduler** In this [WLFI-USD1](https://app.meteora.ag/dammv2/F6L1RKAKwNuWwyCwweja6uxAkRv41XFTRWmg8tKGkn83) pool example, Linear mode is used, and fees started at 10% before dropping linearly over time until it reached 0.25% after 3 minutes. #### Pool Address On each DAMM v2 pool detail page, you can also easily open up the pool address page on Solscan if required. #### Community Built-in Tools Meteora’s LP Army comprises many talented developers, who have over time built useful tools to improve LPing for everyone. The full list of tools can be found [here](https://www.lparmy.com/community-tools). #### Pool Chart Popular data analytics and charting tools with more granular data have integrated Meteora’s liquidity pools, including Birdeye, GeckoTerminal, DEXScreener, DEXTools, GMGN. We’ve provided buttons that link to the specific pool page for each of these tools. #### Supported Trading Platforms Popular trading platforms and bots have also integrated Meteora’s liquidity pools, including Axiom, Banana Gun, BONKbot, Fluxbot, Jupiter, MetaSolanaBot, Photon, and Trojan. We’ve provided buttons that link specifically to each of the trading platforms. Note: For pools without SOL as the quote token, BONKbot, Photon, and Axiom won’t be in the list. #### Total Positions By default, when you create a new DAMM v2 pool or you add liquidity to a pool, you would have one position in the pool. Even if you add more liquidity, it gets added to the same position. This position is represented by a unique liquidity position NFT that you hold in your wallet address. But DAMM v2 can support multiple individual liquidity positions, so if your friend has a separate position in the same pool, and sends his liquidity position NFT to your wallet address, you would then see that you now have 2 liquidity positions (your original position and the new position sent to you). The number of positions you see on the UI would correspond to the number of unique position NFTs you hold in your wallet. On the UI, you can only select and view the details for one liquidity position at a time. #### Total Deposits This represents the total \$ value of all your deposits in all your liquidity positions. #### Position Value This represents the \$ value of your deposits in the specific liquidity position selected. #### Fees from position This represents the \$ value of the accumulated fees for the specific liquidity position selected. For DAMM v2, fees earned by the LP do not auto-compound into the pool. They accumulate separately and have to be manually claimed by the LP. ## How to Add Liquidity Firstly, navigate to the “Deposit” tab. ### Enter Deposit Amount Under the “Deposit” tab, under “Enter deposit amount”, you can enter the amount of Base token or Quote token you’d like to deposit into the pool. The corresponding \$USD value will be shown at the bottom of your input. When you enter an amount for either the Base or Quote Token, Meteora automatically fills in the approximate amount of the other token based on the current liquidity allocation ratio. For example, if the SOL in the pool comprises 44.93% of liquidity, while USDC comprises 55.07%: When you enter 2 USDC, the SOL input field will automatically state approximately \~0.109525293 SOL, which is equivalent to (2 / 55.07) x 44.93 = \~\$1.63). The amount used may differ slightly from the expected token ratio because the token ratio within the active price bin is constantly changing as swaps occur. We’ve also provided a “Max” and a custom “%” button near the Base and Quote token fields. Clicking “Max” automatically enters your entire balance of the respective token, while clicking the custom % button automatically enters an amount based on the % indicated (e.g. 50%) After the Base token and Quote token input fields are filled, under “Deposit info”, you can check your deposit details before you confirm your transaction: * The estimated amount you will get * The Minimum Received * The Maximum Slippage %, which you can preset Once you have verified that the details are acceptable, click the “Deposit” button. ### Setting Liquidity Slippage You can adjust how much change to the pool price you're willing to accept and still add liquidity. If the pool price changes a lot while adding liquidity, your transaction may fail. Increase this slippage to improve your success rate. ## How to Withdraw Liquidity On the pool detail page, navigate to the “Withdraw” tab. Enter the amount of liquidity (LP tokens) to withdraw. In the “Withdraw Info” section, you will see a summary of how many Base tokens and Quote tokens you’d be getting: * The estimated amount you will get * The Minimum Received * The Maximum Slippage %, which you can preset Once you have verified that the details are acceptable, click the orange “Withdraw” button. ## How to Lock Liquidity If you have never added and locked liquidity on Meteora before, “My locks” would show “No locks found". ### Permanent Lock Liquidity Token teams, especially memecoins, can decide if they wish to permanently lock their liquidity on Meteora. Liquidity gets sent to a lock token account but fees will still be claimable. To do this, navigate to the “Permanent Lock” tab and enter the amount of LP tokens you’d like to lock permanently. You’d be able to see the total value you’re locking up, as well as the individual token amounts and their equivalent \$ value. When you’re ready, click the “Lock Liquidity” button. A pop-up would appear requesting confirmation. You would have to type in the text “permanently lock my liquidity never to get it back” as a way to confirm the transaction. If you had permanently-locked your assets, you would no longer be able to access or withdraw those underlying assets. ### Non-Permanent Lock Liquidity LPs also have the option to lock their liquidity in a “Non-permanent” manner, also known as a lock with vesting. This means that the liquidity is locked and released over a preset period of time. To begin, select the “Non-permanent” tab and enter the lock amount for the LP token. There are a few parameters that you’d have to decide based on your preferences and requirements, such as: * Vesting Start Date * Vesting Duration (Minute) * Cliff (Optional) (Minute) * Unlock Schedule (Minutely) Once these parameters are all filled up, you can proceed to click the “Lock Liquidity” button. ## FAQ ### Using DAMM v2 on the Meteora UI #### 1. When you deposit tokens into the pool, how is the LP token amount calculated? When you deposit the token amounts on Meteora FE, it will calculate and specify the lp\_token before it is sent to the program to execute. Example: * From token B: amount\_b = lp\_token (pool.current\_sqrt\_price - pool.min\_sqrt\_price) * So you can reverse: lp\_token = (pool.current\_sqrt\_price - pool.min\_sqrt\_price) / amount\_b How is the fee collected when the pool creator selects fee collection mode as Quote only? Regarding how DAMM 2 collects fee only using the Quote token ("Token B"): * If a user swaps from A -> B, fee is charged on B; protocol takes some of the user's B * If a user swaps from B -> A, fee is charged on B before the swap is calculated; protocol takes some of the user's B before it gets swapped to A ### Liquidity Position NFT #### 1. What does the position state of the NFT manage? The position state manages unlocked\_liquidity + locked\_liquidity + vested liquidity. User can interact with the following flows in the same, single position: * Permanently lock part of the liquidity * Create multiple vesting schedules * Add more liquidity (unlocked liquidity) #### 2. Can I transfer a position NFT (which represents a liquidity position)? Yes. For example, you already have a position in a pool, which is represented by a position NFT. Someone also has a position in that same pool and he sends you his position NFT. Now you would have 2 position NFTs (positions) for the same pool. ### Farming Farming user interface is coming soon. For DAMM V2, there is an in-built farming mechanism within the program. This is unlike DAMM v1, where there is a separate farming program. For DAMM v2, each specific pool can create farming rewards and the pool has its own unique reward vault. Each reward vault can have a maximum of 2 types of reward tokens. When the initialize\_reward program endpoint is used, a reward\_vault for the specific pool is created, and the initiator can specify the reward token (max 2 types) for the reward\_vault Rewards will be shared with all liquidity providers over the farming duration. Currently, in this beta stage, DAMM v2 Farming is not available on the Meteora UI. # DLMM Dynamic Terminal Source: https://docs.meteora.ag/user-guide/guides/how-to-use-dlmm/dynamic-terminal A unified command center for DLMM liquidity providers — featuring professional-grade TradingView charts, real-time position tracking, and streamlined position management. Meteora's **Dynamic Terminal** is the revamped DLMM pool interface, purpose-built to give liquidity providers everything they need in one place. It combines advanced charting, deep pool and token data, position management, and quick actions into a single, high-performance workspace. Dynamic Terminal for DLMM is live on [meteora.ag](https://meteora.ag). DAMM v2 support is coming soon. Meteora Dynamic Terminal *** ## Layout Overview The Dynamic Terminal is organized into four main areas: | Area | What's There | | ----------------- | ----------------------------------------- | | **Left panel** | Pool stats, token info, and risk data | | **Center top** | TradingView price chart | | **Center bottom** | Your open positions with real-time P\&L | | **Right panel** | Position creation and management controls | Each panel is resizable and collapsible — customize the layout to match your workflow. *** ## 1. Pool and Token Insights Panel (Left) The left panel consolidates everything you need to evaluate a pool before committing capital. **Pool statistics:** * Base Fee, Bin Step, Dynamic Fee * TVL and token ratio * Liquidity distribution chart * 24h Volume, Fees, and Fees/TVL **Token info and risk metrics:** * Token contract address and [Jupiter Organic Score](https://www.jup.ag) * Links to Solscan, RugCheck, and Bubblemaps * Token Age, Market Cap, FDV, Holders * % of supply held by Top 10 Holders and Top 10 Dev Wallets * Freeze Authority and Mint Authority status * Total Supply * Price change % in 5m / 1h / 12h / 24h **Pool performance:** * Historical fee performance * Links to popular LP community tools