Type/to search
Built-in Functions
Structures
Built-in Variables and Constants
Conventions
Exchanges
Capability Matrix
Centralized Exchanges
Decentralized Exchanges (DEX)
Prediction Markets
Securities and Futures
On-chain & Custom

Withdraw a share of a position's liquidity and claim all fees and farm rewards; the position stays.

exchange.IO(k, positionId, ratio)
exchange.IO(k, positionId, ratio, options)

Examples

Withdraw half of each position that is out of range and sell back to USDC.

javascript
function main() { var list = exchange.IO("lp.positions", "SOL_USDC") if (!list) { Log("Query failed:", GetLastError()) return } list.forEach(function(p) { if (p.inRange) { return } var r = exchange.IO("lp.decrease", p.id, 0.5, {sell: true}) if (!r) { Log(p.id, "decrease failed:", GetLastError()) return } var row = r.positions[0] Log(p.id, "received", row.receivedBase, "SOL", row.receivedQuote, "USDC", "of which fees", row.feesBase, row.feesQuote, "sold", JSON.stringify(r.sells)) }) }

Returns

TypeDescription

object / null value

{txHash, txHashes, positions, sells}: txHash is the first transaction signature and txHashes all of them; each item of positions is one position's {id, symbol, txHashes, principalBase, principalQuote, feesBase, feesQuote, receivedBase, receivedQuote, rewards, rentRefundSol, feeSol}, and sells lists the swaps back to the quote token, see the remarks. A null value is returned when a position does not belong to this wallet, a simulation fails or a transaction fails.

Arguments

NameTypeRequiredDescription

k

string

Yes

Set to lp.decrease to reduce a position.

positionId

string

Yes

A position ID (the id of lp.positions, such as meteora:position address, raydium:NFT mint or orca:NFT mint; a bare address is accepted too). One position per call, which must belong to this wallet.

ratio

number

Yes

The share to withdraw, (0, 1], converted to basis points; 1 empties the position without closing it (close with lp.remove).

options

object

No

{sell}: with sell true the base token received is sold for the quote token with a Jupiter market order.

See Also

Remarks

How each protocol does it
  • Meteora DLMM: withdraws the ratio from every bin of the position that has liquidity (remove_liquidity_by_range2) and claims fees and rewards; positions wider than 70 bins are handled in transactions of 70 bins each. There is no minimum-output protection: what comes back is the position's share of each bin, so the amounts depend on the bins' composition at the time.
  • Raydium CLMM: one decrease_liquidity_v2 removes that share of the liquidity and claims the fees and all rewards, with minimum outputs of the amounts at the current price × 0.99.
  • Orca Whirlpools: one transaction decreases liquidity by the ratio (decrease_liquidity_v2, with a minimum for each token of the amount estimated at the current price less 1%; a price move beyond that makes the simulation fail and nothing is sent) and collects fees and rewards (collect_fees_v2, collect_reward_v2).

Position rows in the result
FieldDescription
receivedBase, receivedQuoteThe two token amounts actually received (from the balances before and after)
feesBase, feesQuoteThe fee part of them (split off by the amounts claimable on chain before sending)
principalBase, principalQuoteThe principal part = received − fees
rewardsFarm rewards collected, [{mint, symbol, amount}] (excluding the pool's two tokens)
rentRefundSolRent returned by closing (SOL)
feeSolNetwork fees paid by these transactions (SOL)

The orientation (base and quote) takes the stablecoin (then SOL) as the quote. Each item of sells is {symbol, qty, txHash}, or {symbol, qty, error} when the sale failed; sales are Jupiter market orders that wait for the broadcast only, so check them with exchange.IO("receipt").

Execution

Every transaction is simulated by the node before sending and is not sent when the simulation fails, with the reason reported (DLMM, Raydium CLMM and Orca Whirlpool error codes with their names); the compute-unit limit is the simulated usage plus headroom, and the priority fee is the 75th percentile of recent fees paid by transactions writing the same accounts, capped by exchange.IO("priorityFee"). The call returns after confirmation, with actual amounts from the balances before and after. When within 120 seconds the transaction is neither confirmed nor provably expired, the error says outcome is unknown with the signature: it may have landed, so check it with exchange.IO("receipt") before retrying.