Tick

Manages the discrete price points and liquidity distribution across the price curve.

Core Data Structures

TickManager

The main controller that organizes all ticks for a pool:

struct TickManager {
    tick_spacing: u32,           // Spacing between valid ticks
    ticks: SkipList<Tick>       // Ordered collection of ticks
}

Tick

Individual tick containing all relevant price point data:

struct Tick {
    index: I32,                          // Tick index (price level)
    sqrt_price: u128,                    // Square root price at this tick
    liquidity_net: I128,                 // Net liquidity change when crossing
    liquidity_gross: u128,               // Total liquidity at this tick
    fee_growth_outside_a: u128,          // Fee growth outside for token A
    fee_growth_outside_b: u128,          // Fee growth outside for token B
    points_growth_outside: u128,         // Points growth outside
    rewards_growth_outside: vector<u128> // Reward growth outside (per token)
}

Key Properties

Liquidity Net vs Gross

  • liquidity_net: Signed change in active liquidity when crossing this tick

    • Positive when tick is the lower bound of positions

    • Negative when tick is the upper bound of positions

  • liquidity_gross: Total amount of liquidity referencing this tick

    • Always positive

    • Used to determine if tick can be removed

Growth Outside Pattern

The "growth outside" pattern enables efficient fee and reward calculations:

  • Tracks accumulated growth outside the current active range

  • Allows O(1) calculation of growth within any range

  • Automatically updated when ticks are crossed during swaps

Core Functionality

Initialization

Creates a new tick manager with:

  • Specified tick spacing

  • Empty SkipList with randomized structure

  • 16 levels maximum for optimal performance

Liquidity Management

Adding Liquidity

Process:

  1. Tick Creation: Creates ticks if they don't exist

  2. Lower Tick Update: Increases liquidity_net (positive delta)

  3. Upper Tick Update: Decreases liquidity_net (negative delta)

  4. Growth Initialization: Sets appropriate "outside" growth values

Removing Liquidity

Process:

  1. Validation: Ensures ticks exist and have sufficient liquidity

  2. Liquidity Reduction: Decreases gross liquidity at both ticks

  3. Net Adjustment: Adjusts net liquidity appropriately

  4. Cleanup: Removes ticks if no liquidity remains

Swap Operations

Tick Crossing

When a swap crosses a tick:

  1. Liquidity Update: Applies liquidity_net to active liquidity

  2. Direction Handling: Negates delta for reverse direction (a2b)

  3. Growth Flipping: Updates "outside" growth values using wrapping subtraction

  4. Safety Checks: Validates liquidity doesn't overflow or underflow

Swap Navigation

Finds the next tick to process during swaps:

  • a2b (true): Finds previous tick (lower price)

  • b2a (false): Finds next tick (higher price)

  • Handles edge cases at minimum and maximum ticks

Returns current tick data and next tick ID for efficient swap iteration.

Range Calculations

Fee Growth in Range

Calculates accumulated fees within a position's range using the formula:

Where:

  • fee_below: Fee growth below the lower tick

  • fee_above: Fee growth above the upper tick

Points Growth in Range

Similar calculation for points (used in reward calculations).

Rewards Growth in Range

Calculates reward growth for multiple reward tokens within a range.

Advanced Features

Tick Discovery and Querying

Pagination Support

Efficiently retrieves ticks with pagination:

  • start: Optional starting tick index

  • limit: Maximum number of ticks to return

  • Returns ordered list for UI display

Tick Lookup

  • borrow_tick: Direct access (aborts if not found)

  • try_borrow_tick: Safe access returning Option

Data Access Functions

Tick Properties

Manager Properties

Reward Helpers

Safely accesses reward growth for a specific reward token index.

Internal Implementation

Tick Scoring System

Converts tick indices to SkipList scores:

  • Handles negative tick indices

  • Ensures proper ordering in SkipList

  • Maps to range [0, tick_bound * 2]

Default Tick Creation

Creates new tick with:

  • Calculated sqrt_price from tick_math

  • Zero liquidity values

  • Zero growth tracking values

  • Empty rewards vector

Liquidity Update Logic

Core logic for updating tick state:

  1. Gross Liquidity: Add/subtract amount based on is_increase

  2. Net Liquidity: Adjust based on is_upper flag

  3. Growth Initialization: Set "outside" values for new ticks based on current position

  4. Overflow Protection: Check for arithmetic overflows

  5. Return Remaining: Return remaining gross liquidity

Growth Initialization Logic

For new ticks:

  • Below current tick: Initialize outside growth to 0 (all growth is "above")

  • Above current tick: Initialize outside growth to global values (all growth is "below")

This ensures proper fee/reward calculations when the tick becomes active.

Error Codes

  • Error 0: Arithmetic overflow in liquidity calculations

  • Error 1: Insufficient liquidity for operation

  • Error 2: Invalid tick score (outside valid range)

  • Error 3: Tick not found when expected to exist

Mathematical Concepts

Price Calculation

Each tick represents a specific price:

Liquidity Net Calculation

When crossing tick from left to right:

For reverse direction (right to left):

Growth Outside Pattern

Fee growth inside a range [tickLower, tickUpper]:

Performance Characteristics

Time Complexity

  • Tick lookup: O(log n)

  • Tick insertion/deletion: O(log n)

  • Range queries: O(log n + k) where k is result size

  • Crossing tick: O(1)

  • Fee/reward calculation: O(1)

Space Complexity

  • Memory per tick: ~200 bytes + rewards vector

  • SkipList overhead: ~16 pointers per tick

  • Total for n ticks: O(n)

Gas Efficiency

  • Efficient sparse storage (only initialized ticks consume gas)

  • O(1) tick crossing operations

  • Batch operations for multiple tick updates

  • Optimized wrapping arithmetic for growth calculations

Best Practices

  1. Tick Spacing: Choose spacing based on gas costs vs. precision needs

  2. Batch Operations: Group multiple liquidity operations when possible

  3. Error Handling: Always check for tick existence before operations

  4. Memory Management: Clean up empty ticks to reduce storage costs

  5. Precision: Use appropriate decimal precision for price calculations

Security Considerations

  1. Overflow Protection: All arithmetic operations include overflow checks

  2. Tick Bounds: Validate tick indices are within valid range

  3. Liquidity Validation: Ensure sufficient liquidity before decreasing

  4. Growth Calculation: Use wrapping arithmetic to handle edge cases

  5. Access Control: Restrict dangerous operations to friend modules only

Last updated