Docs

Hooks

Range order

A built-in hook that turns a pool into one owner's limit order, and holds the fill once the price has crossed it.

A concentrated-liquidity position that sits entirely on one side of the price is already a limit order: as the price crosses its range, it converts from one token to the other. The trouble is that it converts back if the price returns. The range-order hook fixes that. Once the order has filled, the pool refuses swaps that would move the price back into the range, until the owner takes the proceeds.

For the steps in the app, see Place a range order.

Configuration#

Fixed at pool creation:

FieldMeaning
ownerThe only wallet that may add or remove liquidity in the pool.
lower_tick, upper_tickThe order's range. Positions must use exactly this range.
sell_atrue sells token A as the price rises through the range; false sells token B as it falls.

Lifecycle#

StatusReached when
pendingThe pool is created. No order is in it yet.
activeThe owner deposits the order. The first deposit must be one-sided: the price below the range for sell-A, so the position holds only A, or at or above it for sell-B. The owner can add to the order while it is active.
filledSell-A: a B-to-A swap takes the price to or above upper_tick. Sell-B: an A-to-B swap takes it below lower_tick.
cancelledThe owner withdraws before the fill, withdraws all of it after the fill, or calls CancelOrder. The app shows this as Closed.

An order can't be rearmed. After it completes or is cancelled, the pool trades like an ordinary pool with whatever liquidity remains, and the next order needs a new pool.

The guard#

While the order is filled, every after-swap call checks where the swap left the price. A swap that ends inside the range or back across it fails with 7013 FilledOrderReentry, and the whole swap reverts.

The guard affects the whole pool, not just the order's liquidity. It stays until the owner withdraws all of the order's liquidity or cancels. A partial withdrawal keeps it. The hook never removes liquidity or sends proceeds by itself.

Cancelling#

CancelOrder takes the pool, the owner as signer and the writable hook state. It permanently releases the guard and leaves the ordinary withdrawal available. To finish a sale, withdraw in the same transaction as the cancellation. Any withdrawal before the fill, even a partial one, also cancels the order; the liquidity left behind trades on without a guard.

Errors#

CodeNameWhen
7009OrderOwnerMismatchSomeone other than the owner adds or removes liquidity.
7010OrderRangeMismatchA position doesn't use the order's exact range.
7011OrderMustBeOneSidedThe deposit isn't entirely on one side of the price.
7012OrderNotActiveLiquidity is added after the order filled or closed.
7013FilledOrderReentryA swap would move the price back into a filled order's range.

Permissions#

The hook needs both swap phases and both liquidity phases: mask 15.