> 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/integration/damm/smart-contract/factory-module.md).

# Factory Module

### Overview

The Ferra DAMM Factory module handles:

* Pool creation with fee scheduler and dynamic fee configuration
* Pool registry management via linked table
* Deterministic pool key generation
* Initial liquidity provision

#### Key Features

* **Singleton Pool Registry**: Maintains a centralized registry of all created pools
* **Deterministic Pool Keys**: Generates unique pool identifiers based on coin types, tick spacing, and fee configuration
* **Access Control**: Supports whitelisting and role-based pool creation
* **Initial Liquidity**: Automatically creates initial liquidity positions when creating pools
* **Advanced Fee Configuration**: Supports fee scheduler and dynamic fee setup at pool creation

### Data Structures

#### Pools

```move
struct Pools has key, store {
    id: UID,
    list: LinkedTable<ID, PoolSimpleInfo>,
    index: u64,
}
```

The `Pools` struct is a singleton object that manages all pools in the system:

* `id`: Unique identifier for the pools registry
* `list`: Linked table containing pool information indexed by pool keys
* `index`: Sequential counter for pool creation order

#### PoolSimpleInfo

```move
struct PoolSimpleInfo has copy, drop, store {
    pool_id: ID,
    pool_key: ID,
    coin_type_a: TypeName,
    coin_type_b: TypeName,
    tick_spacing: u32,
}
```

Contains essential information about each pool:

* `pool_id`: Unique identifier of the actual pool object
* `pool_key`: Deterministic key generated from coin types and configuration
* `coin_type_a/coin_type_b`: The two token types in the pool (ordered lexicographically)
* `tick_spacing`: The spacing between usable ticks in the pool

### Main Functions

#### create\_pool

```move
public fun create_pool<CoinTypeA, CoinTypeB>(
    global_config: &GlobalConfig,
    pools: &mut Pools,
    tick_spacing: u32,
    initialize_price: u128,
    tick_lower: u32,
    tick_upper: u32,
    url: String,
    coin_a: Coin<CoinTypeA>,
    coin_b: Coin<CoinTypeB>,
    is_fixed_a: bool,
    collect_fee_mode: u8,
    is_quote_y: bool,
    fee_scheduler_mode: u8,
    enable_fee_scheduler: bool,
    enable_dynamic_fee: bool,
    activation_timestamp: u64,
    clock: &Clock,
    ctx: &mut TxContext,
): (Position, Coin<CoinTypeA>, Coin<CoinTypeB>)
```

Creates a new liquidity pool with initial liquidity provision and DAMM-specific configuration.

**Parameters:**

| Parameter              | Type              | Description                                    |
| ---------------------- | ----------------- | ---------------------------------------------- |
| `global_config`        | `&GlobalConfig`   | Global configuration object for the protocol   |
| `pools`                | `&mut Pools`      | Mutable reference to the pools registry        |
| `tick_spacing`         | `u32`             | The spacing between usable ticks               |
| `initialize_price`     | `u128`            | Initial sqrt price of the pool                 |
| `tick_lower`           | `u32`             | Lower tick for initial liquidity position      |
| `tick_upper`           | `u32`             | Upper tick for initial liquidity position      |
| `url`                  | `String`          | URL for pool/position metadata                 |
| `coin_a`               | `Coin<CoinTypeA>` | Initial token A to provide as liquidity        |
| `coin_b`               | `Coin<CoinTypeB>` | Initial token B to provide as liquidity        |
| `is_fixed_a`           | `bool`            | Whether to fix the amount of coin A            |
| `collect_fee_mode`     | `u8`              | Fee collection mode (0: both, 1: quote only)   |
| `is_quote_y`           | `bool`            | Whether CoinTypeB is the quote token           |
| `fee_scheduler_mode`   | `u8`              | Fee scheduler mode (0: linear, 1: exponential) |
| `enable_fee_scheduler` | `bool`            | Enable time-based fee reduction                |
| `enable_dynamic_fee`   | `bool`            | Enable volatility-based fee adjustment         |
| `activation_timestamp` | `u64`             | Pool activation time (0 for immediate)         |
| `clock`                | `&Clock`          | Clock object for time-based operations         |
| `ctx`                  | `&mut TxContext`  | Transaction context                            |

**Returns:**

* `Position`: The created liquidity position NFT
* `Coin<CoinTypeA>`: Remaining coin A after liquidity provision
* `Coin<CoinTypeB>`: Remaining coin B after liquidity provision

**Access Control:**

* Checks if pair creation is globally allowed
* Validates creator permissions if pair creation is restricted
* Requires at least one coin type to be whitelisted

#### new\_pool\_key

```move
public fun new_pool_key<CoinTypeA, CoinTypeB>(
    tick_spacing: u32,
    collect_fee_mode: u8,
    fee_scheduler_mode: u8,
    enable_fee_scheduler: bool,
    enable_dynamic_fee: bool
): ID
```

Generates a deterministic pool key based on coin types and configuration.

**Algorithm:**

1. Get string representations of both coin types
2. Ensure CoinTypeA is lexicographically greater than CoinTypeB
3. Concatenate type names, tick spacing, and fee configuration
4. Generate ID using Blake2b256 hash

**Important:** The function enforces that CoinTypeA must be the "bigger" type in string order, ensuring consistent pool keys regardless of the order types are provided.

#### fetch\_pools

```move
public fun fetch_pools(
    pools: &Pools,
    start: vector<ID>,
    limit: u64
): vector<PoolSimpleInfo>
```

Retrieves a paginated list of pools from the registry.

**Parameters:**

* `start`: Optional starting point for pagination (empty vector starts from beginning)
* `limit`: Maximum number of pools to return

**Returns:** Vector of `PoolSimpleInfo` objects

#### Utility Functions

```move
// Get pools index (total count)
public fun index(pools: &Pools): u64

// Get coin types from pool info
public fun coin_types(pool_info: &PoolSimpleInfo): (TypeName, TypeName)

// Get pool ID from pool info
public fun pool_id(pool_info: &PoolSimpleInfo): ID

// Get pool key from pool info
public fun pool_key(pool_info: &PoolSimpleInfo): ID

// Get tick spacing from pool info
public fun tick_spacing(pool_info: &PoolSimpleInfo): u32

// Borrow pool simple info by key
public fun pool_simple_info(pools: &Pools, key: ID): &PoolSimpleInfo
```

### Events

#### InitFactoryEvent

```move
struct InitFactoryEvent has copy, drop {
    pools_id: ID,
}
```

Emitted when the factory is initialized, providing the ID of the pools registry.

#### CreatePoolEvent

```move
struct CreatePoolEvent has copy, drop {
    pool_id: ID,
    coin_type_a: String,
    coin_type_b: String,
    tick_spacing: u32,
    initialize_price: u128,
    fee_scheduler_enabled: bool,
    fee_scheduler_mode: Option<u8>,
    dynamic_fee_enabled: bool,
    activation_timestamp: u64,
    collect_fee_mode: u8,
    is_quote_y: bool,
}
```

Emitted when a new pool is created, containing all essential pool configuration.

### Error Codes

| Code | Constant                    | Description                                    |
| ---- | --------------------------- | ---------------------------------------------- |
| 301  | `E_NOT_IN_WHITELIST`        | Neither token is whitelisted                   |
| 302  | `E_INVALID_PRICE_RANGE`     | Initialize price out of valid range            |
| 303  | `E_SAME_COIN_TYPES`         | Cannot create pool with same coin types        |
| 304  | `E_INSUFFICIENT_COIN_B`     | Not enough coin B for liquidity                |
| 305  | `E_INSUFFICIENT_COIN_A`     | Not enough coin A for liquidity                |
| 306  | `E_INVALID_COIN_TYPE_ORDER` | Coin types are identical                       |
| 307  | `E_POOL_ALREADY_EXISTS`     | Pool with same key already exists              |
| 308  | `E_INVALID_AMOUNT`          | Invalid liquidity amount                       |
| 309  | `E_GLOBAL_PAUSED`           | Protocol is globally paused                    |
| 310  | `E_INVALID_PARAMS`          | Invalid fee scheduler or activation parameters |

### Usage Examples

#### Creating a Pool with Fee Scheduler

```move
// Create pool with linear fee scheduler
let (position, remaining_a, remaining_b) = factory::create_pool<USDC, TOKEN>(
    &global_config,
    &mut pools,
    60,                          // tick_spacing
    initial_sqrt_price,          // initialize_price
    tick_lower,                  // lower tick
    tick_upper,                  // upper tick
    string::utf8(b""),           // url (default)
    coin_a,                      // initial USDC
    coin_b,                      // initial TOKEN
    true,                        // fix amount A
    0,                           // collect fee on both
    true,                        // TOKEN (Y) is quote
    0,                           // linear fee scheduler
    true,                        // enable fee scheduler
    true,                        // enable dynamic fee
    activation_time,             // future activation
    &clock,
    ctx
);
```

#### Querying Pools

```move
// Get first 10 pools
let pools_list = factory::fetch_pools(&pools, vector::empty(), 10);

// Get next page
let next_page = factory::fetch_pools(
    &pools, 
    vector::singleton(last_pool_key), 
    10
);
```

### Fee Scheduler Modes

#### Linear Mode (0)

Fee decreases linearly from cliff fee to base fee:

```
current_fee = max(base_fee, cliff_fee - (periods × reduction_per_period))
```

#### Exponential Mode (1)

Fee decreases exponentially:

```
current_fee = max(base_fee, cliff_fee × (1 - reduction_factor)^periods)
```

### Best Practices

1. **Token Ordering**: The factory automatically handles token ordering, but be aware that `CoinTypeA` will always be the lexicographically larger type
2. **Initial Liquidity**: Provide sufficient initial liquidity to establish a meaningful price range
3. **Fee Configuration**: Consider market conditions when choosing fee scheduler mode and parameters
4. **Activation Timing**: Use activation timestamp for fair launch scenarios
5. **Whitelist Setup**: Configure whitelist before activation for pre-launch access


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.ferra.ag/integration/damm/smart-contract/factory-module.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
