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), giving 6 decimal places of precision (e.g., fee rate of 2500 = 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) |
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) |
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) |
| Fee denominator | 1_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.