Math Calculation

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.

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)
}

Using the getQuoteReserveFromNextSqrtPrice function in the DBC TypeScript SDK

getQuoteReserveFromNextSqrtPrice

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.

Flat Fee

// Example
baseFee: {
  cliffFeeNumerator: <BN: 10000000>, // 1% flat fee
  firstFactor: 0, 
  secondFactor: <BN: 0>, 
  thirdFactor: <BN: 0>, 
  baseFeeMode: 0
}

Fee Scheduler

type base_fee = {
    cliff_fee_numerator: BN
    first_factor: number // numberOfPeriod
    second_factor: BN // periodFrequency
    third_factor: BN // reductionFactor
    base_fee_mode: BaseFeeMode // 0 or 1
}
when in Linear (0) baseFeeMode: 
fee = cliff_fee_numerator - (period * reduction_factor)

when in Exponential (1) baseFeeMode:
fee = cliff_fee_numerator * (1 - reduction_factor/10_000)^period
// 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

type base_fee = {
    cliff_fee_numerator: BN
    first_factor: number //feeIncrementBps
    second_factor: BN // maxLimiterDuration
    third_factor: BN // referenceAmount
    base_fee_mode: BaseFeeMode // 2
}
when in RateLimiter (2) baseFeeMode:

For input_amount ≤ reference_amount:
fee = input_amount * cliff_fee_numerator

For input_amount > reference_amount:

-> Let x0 = reference_amount
-> Let c = cliff_fee_numerator
-> Let i = fee_increment
-> Let a = (input_amount - reference_amount) / reference_amount
-> Let b = (input_amount - reference_amount) % reference_amount

If a < max_index:
fee = x0 * (c + c*a + i*a*(a+1)/2) + b * (c + i*(a+1))

If a ≥ max_index:
fee = x0 * (c + c*max_index + i*max_index*(max_index+1)/2) + (d*x0 + b) * MAX_FEE

where:
-> d = a - max_index
-> MAX_FEE is the maximum allowed fee (99%)
Note: 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
// 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

Liquidity

liquidity = poolState.quoteReserve * quoteTokenPrice

FDV

fdv = poolConfigState.postMigrationTokenSupply * baseTokenPrice

Market Cap

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. The correct way is to fetch the Swap CPI logs from the Swap transaction.

Formula

marketCap = tokenPrice * circulatingTokenSupply

With DBC Pool Config State

// For poolConfig.feeCollectMode == 0 [QuoteToken] && tradeDirection == 1 [Quote to Base]
// quoteMint -> fee deducted from quoteMint
amountIn = actualAmountIn / tokenQuoteDecimal

// baseMint
amountOut = outputAmount / tokenBaseDecimal

tokenPrice = (amountIn * quoteMintPrice) / amountOut
// For poolConfig.feeCollectMode == 0 [QuoteToken] && tradeDirection == 0 [Base to Quote]
// baseMint
amountIn = actualAmountIn / tokenBaseDecimal

// quoteMint -> fee deducted from quoteMint
amountOut = (outputAmount + tradingFee + protocolFee + referralFee) / tokenQuoteDecimal

tokenPrice = (amountOut * quoteMintPrice) / amountIn
// For poolConfig.feeCollectMode == 1 [OutputToken] && tradeDirection == 1 [Quote to Base]
// quoteMint
amountIn = actualAmountIn / tokenQuoteDecimal

// baseMint -> fee deducted from baseMint
amountOut = (outputAmount + tradingFee + protocolFee + referralFee) / tokenBaseDecimal

tokenPrice = (amountIn * quoteMintPrice) / amountOut
// For poolConfig.feeCollectMode == 1 [OutputToken] && tradeDirection == 0 [Base to Quote]
// baseMint
amountIn = actualAmountIn / tokenBaseDecimal

// quoteMint -> fee deducted from quoteMint
amountOut = (outputAmount + tradingFee + protocolFee + referralFee) / tokenQuoteDecimal

tokenPrice = (amountOut * quoteMintPrice) / amountIn

With CPI Logs

Alternatively, if you don’t fetch poolConfig in your current code and are unable to get collectFeeMode, you can base it all on the CPI logs:
1. if actualInputAmount === amountIn: then amountIn <> outputAmount + tradingFee + protocolFee + referralFee
2. if actualInputAmount !== amountIn: then actualAmountIn <> outputAmount

Locked Vesting

total_vesting_amount = cliff_unlock_amount + (amount_per_period * number_of_period)

Trading Volume

Track from Swap CPI logs:
// Depending on Trade Direction:
trading_volume += amount_in * token_price

Migration

Migration Process

Once getPoolCurveProgress == 100%, then check migrationProgress and isMigrated status form the DBC pool state.
IsMigrated::NotMigrated  // 0
IsMigrated::Migrated // 1
MigrationProgress::PreBondingCurve  // 0
MigrationProgress::PostBondingCurve // 1
MigrationProgress::LockedVesting    // 2
MigrationProgress::CreatedPool      // 3

Current Auto Migrators Running

You can refer to the DBC Auto Migrator for the current auto migrators running.

How to Identify Launchpads Using DBC

We will provide a list of all DBC integrators.
You can ping us on Discord if you want to get access to the list.

Referral Account

DBC

For referral fees, simply add your referral token account within the swap instruction & you will receive 20% of the protocol fees for all trades.