Skip to main content

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_optionTarget 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 = LockedVestingCreatedPool

2. With Jupiter Lock (PostBonding flow)

Some launches integrate with Jupiter’s lock mechanism:
  1. PreBondingCurve → threshold hit
  2. PostBondingCurve (Jupiter lock processing)
  3. LockedVestingCreatedPool

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:
ParameterDescription
cliff_duration_from_migration_timeSeconds after migration before first unlock
frequencySeconds between each periodic release
number_of_periodTotal number of release periods
cliff_unlock_amountAmount released at the cliff
amount_per_periodAmount 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
Split between protocol and creator:
  • migration_fee_percentage % → protocol
  • creator_migration_fee_percentage % → creator
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:
ClaimantInstructionCondition
ProtocolwithdrawProtocolSurplusis_protocol_withdraw_surplus = 0
PartnerwithdrawPartnerSurplusis_partner_withdraw_surplus = 0
CreatorwithdrawCreatorSurplusis_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 FieldMaps to DAMM v2
migration_sqrt_priceinitSqrtPrice
migrated_collect_fee_modecollectFeeMode
migrated_pool_fee_bpsBase fee
migrated_pool_base_fee_modeBaseFeeMode
migrated_dynamic_feeDynamic 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.