# Position Module

### Data Structures

#### Position

The main NFT struct representing position ownership:

```rust
struct Position has key, store {
    id: UID,                    // Unique identifier
    pool: ID,                   // Associated pool ID
    index: u64,                 // Position index number
    coin_type_a: TypeName,      // First token type
    coin_type_b: TypeName,      // Second token type
    name: String,               // Display name
    description: String,        // Description
    url: String,                // Icon URL
    tick_lower_index: I32,      // Lower tick bound
    tick_upper_index: I32,      // Upper tick bound
    liquidity: u128,            // Current liquidity amount
    lock_until: u64,            // Lock expiration timestamp
}
```

#### PositionInfo

The computational data for position calculations:

```rust
struct PositionInfo has copy, drop, store {
    position_id: ID,            // Corresponding Position NFT ID
    liquidity: u128,            // Active liquidity
    tick_lower_index: I32,      // Lower tick
    tick_upper_index: I32,      // Upper tick
    fee_growth_inside_a: u128,  // Fee growth for token A
    fee_growth_inside_b: u128,  // Fee growth for token B
    fee_owned_a: u64,          // Accumulated fees for token A
    fee_owned_b: u64,          // Accumulated fees for token B
    points_owned: u128,         // Accumulated points
    points_growth_inside: u128, // Points growth tracker
    rewards: vector<PositionReward>, // Multi-token rewards
}
```

#### PositionManager

Central registry managing all positions:

```rust
struct PositionManager has store {
    tick_spacing: u32,              // Tick spacing for the pool
    position_index: u64,            // Next position index
    positions: LinkedTable<ID, PositionInfo>, // Position data storage
}
```

#### PositionReward

Individual reward token tracking:

```rust
struct PositionReward has copy, drop, store {
    growth_inside: u128,    // Growth rate inside position range
    amount_owned: u64,      // Accumulated reward amount
}
```

### Core Functions

#### Position Creation

**`open_position<CoinTypeA, CoinTypeB>`**

Creates a new liquidity position NFT.

**Parameters:**

* `manager`: Mutable reference to PositionManager
* `pool_id`: ID of the target pool
* `pool_index`: Pool's index number
* `icon_url`: URL for position icon
* `tick_lower_index`: Lower bound of liquidity range
* `tick_upper_index`: Upper bound of liquidity range
* `lock_until`: Timestamp until position is locked
* `ctx`: Transaction context

**Returns:** New Position NFT

**Example:**

```rust
let position = position::open_position<USDC, ETH>(
    &mut manager,
    pool_id,
    1,
    string::utf8(b"https://example.com/icon.png"),
    i32::from(-1000),  // Lower tick
    i32::from(1000),   // Upper tick
    0,                 // No lock
    ctx
);
```

#### Liquidity Management

**`increase_liquidity`**

Adds liquidity to an existing position.

**Parameters:**

* `manager`: Mutable reference to PositionManager
* `position`: Mutable reference to Position NFT
* `delta_liquidity`: Amount of liquidity to add
* `fee_growth_inside_a`: Current fee growth for token A
* `fee_growth_inside_b`: Current fee growth for token B
* `points_growth_inside`: Current points growth
* `rewards_growth_inside`: Vector of current reward growth rates

**Returns:** New total liquidity amount

**`decrease_liquidity`**

Removes liquidity from a position.

**Parameters:** Similar to `increase_liquidity` but removes instead of adds **Additional Checks:**

* Validates position is not locked
* Ensures sufficient liquidity exists

#### Fee Management

**`update_fee`**

Updates accumulated fees for a position.

```rust
public(friend) fun update_fee(
    manager: &mut PositionManager,
    position_id: ID,
    fee_growth_a: u128,
    fee_growth_b: u128,
): (u64, u64)
```

**`reset_fee`**

Collects accumulated fees and resets counters.

```rust
public(friend) fun reset_fee(
    manager: &mut PositionManager,
    position_id: ID,
): (u64, u64)
```

### Position Lifecycle

#### 1. Creation

```rust
// Create new position
let position = open_position<TokenA, TokenB>(
    &mut manager, pool_id, pool_index, icon_url, 
    lower_tick, upper_tick, lock_until, ctx
);
```

#### 2. Liquidity Addition

```rust
// Add liquidity
let new_liquidity = increase_liquidity(
    &mut manager, &mut position, liquidity_amount,
    fee_growth_a, fee_growth_b, points_growth, rewards_growth
);
```

#### 3. Fee Collection

```rust
// Collect fees
let (fee_a, fee_b) = update_and_reset_fee(
    &mut manager, position_id, fee_growth_a, fee_growth_b
);
```

#### 4. Liquidity Removal

```rust
// Remove liquidity
let remaining_liquidity = decrease_liquidity(
    &mut manager, &mut position, liquidity_to_remove,
    fee_growth_a, fee_growth_b, points_growth, rewards_growth, clock
);
```

#### 5. Position Closure

```rust
// Close empty position
if (is_empty(&position_info)) {
    close_position(&mut manager, position);
}
```

### Fee and Reward Management

#### Fee Calculation

Fees are calculated using the formula:

```rust
delta_fee = liquidity × (current_growth - last_growth) / 2^64
```

The system tracks fee growth both globally and per position to calculate accumulated fees accurately.

#### Multi-token Rewards

The rewards system supports multiple reward tokens simultaneously:

```rust
// Each position can have multiple rewards
struct PositionReward {
    growth_inside: u128,    // Growth rate inside position's range
    amount_owned: u64,      // Accumulated reward amount
}
```

#### Reward Distribution

Rewards are distributed proportionally based on:

* Position liquidity amount
* Time in range
* Growth rates specific to the position's tick range

### Position Locking

#### Lock Mechanism

Positions can be locked until a specific timestamp to prevent premature liquidity removal:

```rust
// Lock position until timestamp
lock_position(&mut position, lock_until_timestamp);

// Check lock status
let lock_time = get_lock_until(&position);
```

#### Lock Validation

When decreasing liquidity, the system validates:

```rust
let current_time = clock::timestamp_ms(clock);
assert!(position.lock_until <= current_time, 11);
```

### API Reference

#### Query Functions

**Position Information**

* `liquidity(position: &Position): u128` - Get position liquidity
* `tick_range(position: &Position): (I32, I32)` - Get tick range
* `pool_id(position: &Position): ID` - Get associated pool ID
* `index(position: &Position): u64` - Get position index

**Position Info Queries**

* `info_liquidity(info: &PositionInfo): u128` - Get liquidity from info
* `info_fee_owned(info: &PositionInfo): (u64, u64)` - Get accumulated fees
* `info_points_owned(info: &PositionInfo): u128` - Get accumulated points
* `info_rewards(info: &PositionInfo): &vector<PositionReward>` - Get rewards

**Manager Queries**

* `is_position_exist(manager: &PositionManager, id: ID): bool` - Check if position exists
* `fetch_positions(manager: &PositionManager, start: vector<ID>, limit: u64): vector<PositionInfo>` - Get multiple positions

#### Validation Functions

**`check_position_tick_range`**

Validates tick range parameters:

* `tick_lower < tick_upper`
* Ticks within valid bounds
* Ticks align with tick spacing

**`is_empty`**

Checks if position can be closed:

* Zero liquidity
* No accumulated fees
* No pending rewards

### Examples

#### Complete Position Lifecycle Example

```rust
// 1. Create position manager
let manager = position::new(10, ctx); // 10 tick spacing

// 2. Open new position
let position = position::open_position<USDC, ETH>(
    &mut manager,
    pool_id,
    1,
    string::utf8(b"https://example.com/icon.png"),
    i32::from(-100),   // Lower tick
    i32::from(100),    // Upper tick
    0,                 // No lock
    ctx
);

// 3. Add liquidity
let liquidity_added = position::increase_liquidity(
    &mut manager,
    &mut position,
    1000000, // 1M liquidity units
    fee_growth_a,
    fee_growth_b,
    points_growth,
    rewards_growth
);

// 4. Later: collect fees
let (fee_a, fee_b) = position::update_and_reset_fee(
    &mut manager,
    object::id(&position),
    new_fee_growth_a,
    new_fee_growth_b
);

// 5. Remove some liquidity
let remaining = position::decrease_liquidity(
    &mut manager,
    &mut position,
    500000, // Remove 500K liquidity
    fee_growth_a,
    fee_growth_b,
    points_growth,
    rewards_growth,
    clock
);

// 6. Check if position can be closed
let position_info = position::borrow_position_info(
    &manager, 
    object::id(&position)
);
if (position::is_empty(position_info)) {
    position::close_position(&mut manager, position);
}
```

#### Batch Position Query Example

```rust
// Query multiple positions
let positions = position::fetch_positions(
    &manager,
    vector::empty<ID>(), // Start from beginning
    10                   // Limit to 10 positions
);

// Process each position
let i = 0;
while (i < vector::length(&positions)) {
    let pos_info = vector::borrow(&positions, i);
    let liquidity = position::info_liquidity(pos_info);
    let (fee_a, fee_b) = position::info_fee_owned(pos_info);
    // Process position data...
    i = i + 1;
}
```

### Best Practices

#### Position Management

1. **Always validate tick ranges** before creating positions
2. **Check lock status** before attempting to decrease liquidity
3. **Update fees and rewards** before liquidity changes
4. **Use batch queries** for efficient data retrieval

#### Error Handling

The module uses various assertion codes:

* `1`: Fee overflow in token A/B
* `2`: Reward overflow
* `3`: Points overflow
* `5`: Invalid tick range
* `6`: Position not found
* `7`: Cannot close non-empty position
* `8`: Liquidity addition overflow
* `9`: Insufficient liquidity to remove
* `10`: Invalid reward index
* `11`: Position is locked

#### Gas Optimization

* Use `fetch_positions` for batch operations
* Combine fee updates with liquidity changes
* Close empty positions to free storage

### Security Considerations

1. **Position Ownership**: Only the NFT holder can modify the position
2. **Tick Validation**: All tick ranges are validated for correctness
3. **Overflow Protection**: All arithmetic operations include overflow checks
4. **Lock Enforcement**: Locked positions cannot have liquidity decreased
5. **Access Control**: Critical functions are `friend`-only

This documentation provides a comprehensive guide to the Ferra CLMM Position Management system. For additional technical details, refer to the source code and inline comments.


---

# Agent Instructions: 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/integration/clmm/smart-contract/position-module.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.
