> 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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ferra.ag/core-protocols/damm/technical-design.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
