> 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
