Position Module

Manages liquidity position NFTs and their associated metadata.

Data Structures

Position

The main NFT struct representing position ownership:

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:

PositionManager

Central registry managing all positions:

PositionReward

Individual reward token tracking:

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:

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.

reset_fee

Collects accumulated fees and resets counters.

Position Lifecycle

1. Creation

2. Liquidity Addition

3. Fee Collection

4. Liquidity Removal

5. Position Closure

Fee and Reward Management

Fee Calculation

Fees are calculated using the formula:

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:

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:

Lock Validation

When decreasing liquidity, the system validates:

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

Batch Position Query Example

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.

Last updated