> For the complete documentation index, see [llms.txt](https://docs.ferra.ag/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ferra.ag/core-protocols/damm/technical-design.md).

# Technical Design

### Core Mechanism: AMM with Concentrated Liquidity

DAMM implements the constant-product formula **x \* y = k**, where `x` and `y` are the reserves of the two tokens and `k` is the invariant maintained across swaps (excluding fees).

Unlike traditional AMMs that spread liquidity uniformly across all prices, DAMM concentrates liquidity within a defined price range. Pool creators establish a lower tick (`T_L`) and upper tick (`T_U`) during initialization — all liquidity deposits operate within that band, improving capital efficiency.

Prices are discretized into **ticks**:

```
P(i) = 1.0001^i
```

The `tick_spacing` parameter controls granularity — smaller spacing allows finer price resolution but costs more gas per swap. Each fee tier maps to a specific tick spacing.

When the current price is within a position's range, that position's liquidity is **active** and earns fees. If the price moves outside the range, the position becomes inactive and holds only one token.

### Fee Architecture

DAMM implements a multi-layered fee system:

```
total_fee = base_fee + variable_fee
```

All fee calculations use **9-decimal precision** (denominator = 1,000,000,000).

#### Base Fee

A fixed percentage established at pool creation (e.g., 0.25%, 0.30%, 1%), applied to every swap. This is the minimum fee when no fee scheduler is active.

#### Dynamic Fee

The dynamic fee adjusts based on real-time market volatility. It adds a variable component on top of the base fee:

```
variable_fee = (volatility_accumulator × tick_spacing)² × variable_fee_control / 100
```

The `volatility_accumulator` tracks price movement per swap and decays over time via `filter_period`, `decay_period`, and `reduction_factor`. The mechanism is similar to the [*Volatility Accumulator*](/core-protocols/quickstart/dynamic-fee.md) which explained in DLMM's Dynamic Fee session. Higher volatility leads to increased fees to protect LPs; calm markets bring the variable fee back to zero.

#### Fee Caps

| Limit               | Value            |
| ------------------- | ---------------- |
| Max total fee       | 50%              |
| Max base fee rate   | 10%              |
| Min fee after decay | 0.01%            |
| Max protocol share  | 30% of total fee |

#### Anti-Sniper Fee Scheduler

The fee scheduler deters bots from sniping tokens during early trading by starting with high fees that decrease over time. It **overrides** the base fee with a decaying cliff fee (up to 50%).

**Linear decay:**

```
fee(t) = cliff_fee - (reduction_factor × periods_elapsed)
```

**Exponential decay:**

```
fee(t) = cliff_fee × (1 - reduction_factor / 10000) ^ periods_elapsed
```

**Example**:  A pool might launch with an initial fee of 10%, which decays gradually to 0.3% over a period of 24 hours or 1,000 slots. For highly volatile tokens, such as meme coins, the initial fee can be as high as 80% at launch to mitigate the risks of sudden price swings.

Once the scheduler completes all periods, the fee settles back to the static `fee_rate`

The **linear fee decay** from initial fee formular:  $$F(t) = F\_{\text{init}} - \left( \frac{F\_{\text{init}} - F\_{\text{final}}}{T} \right) \cdot t$$ &#x20;

Where:

* $$F(t)$$ : Fee at time (t)
* $$F\_{\text{init}}$$ : Initial fee, eg: 50%
* $$F\_{\text{final}}$$ : Final fee, eg: 0.3%
* T :  total decay duration
* &#x20;t :  elapsed time or slots

<figure><img src="/files/pbomLTWIiu1WrI6MNWTI" alt=""><figcaption><p>Linear decay function over the time (t)</p></figcaption></figure>

The **exponential fee decay** equation calculates the fee  $$F(t)$$ over time using a decay constant $${\lambda}$$, as described below:  $$F(t) = F\_{\text{final}} + (F\_{\text{init}} - F\_{\text{final}}) \cdot e^{-\lambda t}$$

<figure><img src="/files/elugzZPQNvWPtfYCc7ix" alt=""><figcaption><p>Exponential decay function over the time (t)</p></figcaption></figure>

The chart above shows that the fee is quite high at launch (e.g., 38% at 5 minutes after launch) but decreases to a normal rate once trading stabilizes (e.g., 0.54% at 50 minutes after launch).

#### Protocol Fee

A configurable share of the total fee is routed to the Ferra protocol. The remainder goes to LPs.

```
protocol_fee = total_fee_amount × protocol_fee_rate / 10000
lp_fee = total_fee_amount - protocol_fee
```

#### LP Fee Collect Mode

Pool creators choose how swap fees are collected:

| Mode       | Value | Behavior                                                  |
| ---------- | ----- | --------------------------------------------------------- |
| `ON_BOTH`  | 0     | Fee taken from the **input** token                        |
| `ON_QUOTE` | 1     | Fee taken from the **quote** asset (set via `is_quote_y`) |

`ON_QUOTE` ensures one specific token always accumulates as fee revenue — useful when the quote asset (e.g., USDC, SUI) is preferred.

### Swap Mechanics

#### Swap Flow

1. **Fee Calculation** — Aggregate base fee, dynamic fee, and anti-sniper fee into `total_fee_rate`
2. **Fee Deduction** — Deduct fee from input or output based on `collect_fee_mode`
3. **Price Calculation** — Compute output via constant-product formula:

   ```
   Δy = (y × Δx) / (x + Δx)
   ```
4. **Price Range Validation** — Swaps crossing tick boundaries iterate step by step through ticks
5. **Reserve Updates** — `x_new = x + Δx`, `y_new = y - Δy`, maintaining the invariant
6. **Fee Accumulation** — Split fee into LP fee and protocol fee, update `fee_growth_global`
7. **Volatility Update** — Update dynamic fee volatility parameters if enabled

**Example:** For a 100 SUI input with a 0.36% total fee, 0.36 SUI is deducted, leaving 99.64 SUI for the swap calculation.

#### Swap Result

Each swap emits a detailed breakdown:

```rust
struct SwapResult {
    amount_in: u64,
    amount_out: u64,
    fee_amount: u64,
    base_fee: u64,       // From fee scheduler or static fee_rate
    dynamic_fee: u64,    // From volatility engine
    steps: u64,          // Number of tick crossings
}
```

#### Pre-Swap Simulation

Use `calculate_swap_result` to simulate a swap off-chain without executing it — returns the same result structure including all fee breakdowns and step details.

#### Whitelist (Pre-Launch Access)

* Before `activation_timestamp`, only whitelisted addresses can swap
* After `activation_timestamp`, the pool is open to everyone
* Pool creator or `CONFIG_ROLE` manages the whitelist

### Liquidity Provision

#### Adding Liquidity

LPs deposit tokens into a pool and receive an **NFT position** representing their share. Deposits must be proportional to the current pool price within the established range.

For single-sided contributions, the contract calculates the equivalent based on the current pool price. Supported operations:

* **Open Position** — Create a new position at a tick range
* **Add Liquidity** — Increase liquidity by exact amount or by fixing one coin
* **Add Liquidity (Fix Coin)** — Specify one token amount; the contract computes the other

#### Removing Liquidity

LPs call `remove_liquidity` to withdraw tokens proportional to their pool share. Fee claims are separate from withdrawal — LPs must explicitly collect accumulated fees.

#### Collecting Fees & Rewards

* **Collect Fee** — Claim accumulated LP fees (non-auto-compounded)
* **Collect Reward** — Claim reward token emissions
* **Close Position** — Remove all liquidity + collect fees, then burn the NFT

#### Liquidity Locks

Positions support an on-chain `lock_until` timestamp (in milliseconds):

* While locked, liquidity **cannot** be decreased or removed
* Fee and reward collection **remain available** during lock
* Lock duration is immutable once set — cannot be shortened, no admin override
* `lock_until = 0` means unlocked
* Max lock: \~100 years

**Permanent locks** tokenize as tradeable NFTs, enabling governance participation or secondary market trading of locked positions.

#### Single-Sided Liquidity

DAMM supports depositing only one token when creating a pool. The contract initializes the pool with a starting price, allowing swaps to bootstrap the other side. This is ideal for token launches where the creator supplies only the launch token.

> Note: Single-sided LPs face higher impermanent loss risk due to price volatility during the bootstrapping phase.

### Pool Creation

#### Creation Flow

1. Verify system is not paused and package version is current
2. Check pool creation permission (open or `POOL_MANAGER_ROLE` required)
3. At least one coin type must be in the global token whitelist
4. Load fee scheduler and dynamic fee config from the `FeeTier` for the given `tick_spacing`
5. `activation_timestamp` must be >= current time
6. Generate deterministic pool key from coin types + tick spacing + feature flags
7. Create pool, open initial position, add initial liquidity
8. Share pool object on-chain
9. Return `(Position, remaining_Coin_A, remaining_Coin_B)`

#### Custom Pool Activation

Pool creators assign an `activation_timestamp` (Unix timestamp) controlling when swaps become available. Before this time, only whitelisted addresses can swap — enabling coordinated launches.
