Skip to main content
CLMM pools are Uniswap V3-style: liquidity providers choose a price range (tickLower–tickUpper) and earn fees only while the price is inside it. Each pool is identified by a token pair plus a fee tier (configIndex). Prices are stored as sqrtPriceX96 = sqrt(token1/token0) × 2^96.

Guide: swap on CLMM

Guide: open & manage a position

Fee tiers (pool configs)

A fee tier is a PoolConfig contract registered in the factory, indexed from 0n. Every pool references exactly one.

Pool lookups

getPoolState(poolId)

object
Throws PoolNotFoundError if the pool doesn’t exist.

Other pool reads

Swaps

simulateSwap(params)

Runs the pool’s simulateSwap view method on the node (no transaction) and returns the liquidity curve the swap walks through. Feed the result to PoolUtils.offlineSwap to compute the output amount locally.
bigint
required
string
required
The pool’s tokens (any order, used to locate the pool).
boolean
required
true sells sorted token0 for token1 (price goes down).
bigint
required
Positive = exact-in, negative = exact-out.
string
Multi-hop path from buildSwapPath (optional).
string[]
Addresses of extra pools touched by a multi-hop path.
object

swap(params)

Executes a single-pool swap through the SwapWithoutAccount script (or SwapWithoutAccountWithFee when an integrator fee is set). The signer is both payer and recipient.
string
required
The input token (not necessarily the pool’s sorted token0).
string
required
The output token.
bigint
required
Amount specified: positive = exact-in, negative = exact-out (the negated desired output).
bigint
required
How much input token to attach. Exact-in: same as amount. Exact-out: your maximum input (simulate, then add slippage).
bigint
required
Basis points, converted to a sqrtPriceLimitX96.
bigint[]
required
Fee tiers to route through. Only routePlan[0] is used today.
bigint / string
Optional integrator fee, in the input token.
swap() always sends an empty multi-hop path, so it swaps in one pool only. For multi-hop, build the path with buildSwapPath and call the SwapWithoutAccount script from ClmmScripts directly.

swapTo(params)

Swaps until the pool reaches targetSqrtPriceX96, spending at most amountInMax of tokenIn. Fails on-chain (error code 106, InvalidSqrtPriceLimit) if the target is on the wrong side of the current price.

buildSwapPath(tokenId, configIndex)

Encodes one extra hop for simulateSwap({ data }): tokenId + configIndex as 4 hex characters.

Liquidity positions

A position is identified by pool + owner + tickLower + tickUpper. The position contract ID doubles as a position token ID. The owner holds one unit of it, and it is attached when modifying the position.

getPositionId(poolId, owner, tickLower, tickUpper)

Derives the position ID offline. Pass owner in normalized form for groupless addresses (see Groups and addresses). PoolUtils.getPositionId(poolAddress, owner, ...) normalizes for you.

createPool(...)

Creates a pool at price tick and mints the first position in [tickLower, tickUpper]. Tokens, their amounts, and the ticks are sorted internally. Attaches 6 × MINIMAL_CONTRACT_DEPOSIT ALPH for the new contracts.

addLiquidity(params)

string
required
Pool tokens. Pass them sorted (sortTokens) and match amount0 / amount1 to that order.
bigint
required
bigint
required
Multiples of the tier’s tickSpacing. Use TickUtils.getAlignedTick.
bigint
required
Desired amounts. The contract deposits the maximal balanced amounts up to these.
bigint
required
Basis points on price. Minimum amounts are derived from the price bounds.
string
Position owner. Defaults to the signer.
boolean
Set true when adding to a position you already own (attaches the position token). The signer must hold its position NFT, which the SDK attaches automatically.
The position’s deposit (dustAmount) is read on-chain via PositionManager.getSqrtPricesX96. Two-step variant: getAddLiquidityParams(p) returns [positionId, positionManager, params] without sending, and addLiquidityFromParams(positionId, positionManager, params) executes them. Use this to show a confirmation screen with the exact minimum amounts.

removeLiquidity(params)

Decreases the position’s liquidity and, in the same transaction, collects all accrued fees and rewards. Tokens go to the signer.
required
Identify the pool.
required
Identify the position.
bigint
required
Liquidity units to remove (read the position’s current liquidity, then take a fraction).
'token0' | 'token1'
required
Which side baseAmount refers to.
bigint
required
Minimum amount of the base token to receive.
bigint
required
Minimum amount of the other token to receive. Despite the name, it’s passed on-chain as a minimum.
Pass 0n for both minimums to disable the check.

collectTokens(params)

Collects accrued fees and rewards to recipient. It does not remove liquidity; use removeLiquidity for that.
required
Identify the position.
string
required
bigint
required
Caps on what to collect. Use U128_MAX-sized values (for example UNLIMITED_AMOUNT) to collect everything.

positionInfo(params)

Calls the pool’s positionInfo view and returns its result unchanged. fees holds three entries: token0, token1, and the pool’s reward token. The SDK passes the accumulator arguments (acc, iacc0, iacc1, t0, acct0) straight to the contract. See the Pool contract source for what they mean. To read a position’s raw liquidity, fetch the position contract:

Farming rewards

A pool can run up to three reward programs (MAX_REWARDS = 3), paying in token0, token1, or the pool’s extra reward token (token2). Programs are set up and funded by the Powfi team.
  • getPoolRewardState(poolId) returns the reward token and each program’s amount, openTime, and endTime (millisecond timestamps).
  • Rewards accrued by a position appear in positionInfo(...).fees: token0 rewards in fees[0], token1 rewards in fees[1], and rewards in any other token in fees[2]. They are paid out through collectTokens.

Referral (DEX) accounts

Powfi tracks referrals through per-user DexAccount contracts under a DexAccountRoot.

Configuration

Read the active config with getClmmConfig() and override it with setConfig(). getConfig() re-reads the bundled deployment.

Constants