Skip to main content

Overview

DAMM v2 supports two types of liquidity locks, both of which move liquidity from unlocked_liquidity into restricted buckets on the position account:
TypeBucketWithdrawable?
Vesting lockvested_liquidityYes, on schedule
Permanent lockpermanent_locked_liquidityNever
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

ParameterDescription
cliff_pointSlot or timestamp when first unlock occurs
period_frequencySlots or seconds between each periodic release
cliff_unlock_liquidityHow much liquidity unlocks at the cliff
liquidity_per_periodHow much unlocks per period after the cliff
number_of_periodTotal 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.

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_liquidityunlocked_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:
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:
pub fn get_total_liquidity(&self) -> Result<u128> {
    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.