Skip to content

The LP lifecycle

Follow principal, position liquidity, fee claims, and ownership from entry to exit.

The current core exposes position opening, signed liquidity changes, fee collection, and closure. This page maps those operations to user-visible state. Use the matching IDL for account order and argument encoding.

flowchart TD
Empty[Open empty position] --> Fund[Add liquidity with token limits]
Fund --> Hold[Active or out of range]
Hold --> Collect[Collect earned fees]
Collect --> Hold
Hold --> Remove[Remove some or all liquidity]
Remove --> Claims[Collect remaining fees]
Claims --> Close[Close only when liquidity and debts are zero]

1. Choose the range and budget

Validate ordered ticks, spacing, mint order, price units, and the current pool policy. Use the range math to calculate both token obligations. At the relevant edge or outside the range a position may need only one asset; strictly inside it needs both.

An LP interface should show the required A/B amounts, maximum deposit amounts, price snapshot, range, fee policy, and whether the range is currently active. A one-token budget is not a promise that an arbitrary range can be funded.

2. Open the position

open_position creates an owner-bound record with zero liquidity and fee debt. Creating that record does not transfer principal, establish an LP share token, or earn fees. Ownership is stored in the Position; position transfer is not a current instruction.

3. Fund or add liquidity

modify_liquidity with positive liquidity_delta calculates the A/B deposit with rounding up. limit_a and limit_b are maximum debits on this path. It updates the position, boundary ticks, applicable active liquidity, and fee checkpoints, then settles tokens. Enabled add-liquidity hooks can reject the operation.

Adding later must crystallize fees earned by the previous liquidity before changing L. New liquidity must not receive historical fees. The current code performs this accounting in instructions/positions/accounting.rs.

4. Hold and observe

An out-of-range position can hold principal but earn no swap fees until its liquidity is active. Token composition changes with price; L is not a stable token balance or a constant currency valuation. Activity elsewhere in the pool does not imply that this position earned fees.

Show principal A/B, current range status, accrued fee claims, and valuation separately. The principal estimate uses current price and removal rounding. The fee estimate must include growth since the stored checkpoint, not only fees_owed_a/b already crystallized.

5. Collect fees

collect_position_fees crystallizes current inside growth, clears owed amounts as part of the transaction, and pays the owner's token accounts. It leaves liquidity unchanged. A failed transfer must roll back both debt clearing and token movement.

Collection is a movement of an existing claim, not a second earning event. Performance calculations count fees earned once, whether they remain owed or have already been collected.

6. Reinvest explicitly

Automatic compounding is not implemented. Reinvestment would collect, obtain the range's required token composition, and add liquidity with new limits. Conversion fees, slippage, network costs, and time out of range affect the outcome. A displayed APY must state that it assumes this future reinvestment behavior.

7. Remove liquidity

Use a negative liquidity_delta. The magnitude must fit the owned liquidity; i128::MIN is rejected. The core calculates principal with rounding down, and limit_a/b are minimum receipts on removal. Removal crystallizes prior fees and updates boundary liquidity.

A full removal can leave fee debts on a zero-liquidity position. Those claims remain collectible. A partial removal preserves the remaining range and liquidity; it does not create a new owner.

8. Close the empty account

close_position requires liquidity, A fee debt, and B fee debt all to be zero. It returns the account rent to the owner. This is distinct from withdrawing principal or collecting fees.

See APR and APY, instruction reference, and integration validation for the full sequence and rejected transitions.