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
bondingCurveProgress = poolState.quoteReserve / poolConfigState.migration_quote_threshold
There are 2 ways you can get the quote reserve:
- From the
poolState.quoteReserve state in a DBC pool.
- From the
nextSqrtPrice in the swap CPI logs.
- Directly from
EvtSwap2 swap CPI logs.
1. Get Quote Reserve from Pool State
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
pub fn get_quote_token_from_sqrt_price(next_sqrt_price: u128, config: &PoolConfig) -> Result<U256> {
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 as it is the typescript version of the above function.
3. Directly from EvtSwap2 swap CPI logs
Example of an EvtSwap2 swap CPI logs:
{
"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.
// Example
baseFee: {
cliffFeeNumerator: <BN: 10000000>, // 1% flat fee
firstFactor: 0,
secondFactor: <BN: 0>,
thirdFactor: <BN: 0>,
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.
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
Here are some examples of how the Fee Scheduler works:
// Fee Scheduler: 50% reduce to 1% in 10 minutes linearly
baseFee: {
cliffFeeNumerator: <BN: 500000000>,
firstFactor: 60, // numberOfPeriods
secondFactor: <BN: 8166666>, // periodFrequency
thirdFactor: <BN: 10>, // reduction factor
baseFeeMode: 0
},
// Fee Scheduler: 50% reduce to 1% in 10 minutes exponentially
baseFee: {
cliffFeeNumerator: <BN: 500000000>,
firstFactor: 60, // numberOfPeriods
secondFactor: <BN: 631>, // periodFrequency
thirdFactor: <BN: 10>, // 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.
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
Here are some examples of how the Rate Limiter works:
// 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
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.
- You can also check the MigrationProgress from the DBC pool state via the
MigrationProgress parameter.
IsMigrated::NotMigrated // 0
IsMigrated::Migrated // 1
MigrationProgress::PreBondingCurve // 0
MigrationProgress::PostBondingCurve // 1
MigrationProgress::LockedVesting // 2
MigrationProgress::CreatedPool // 3
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.
- 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 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 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 happens on our Meteora DBC program as long as they were swapped through your trading terminal.
- For referral fees, simply add your referral token account within the swap instruction & you will receive 20% of the protocol fees for all swaps.