exchange.IO("lp.decrease", ...)
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
| Type | Description |
object / null value |
|
Arguments
| Name | Type | Required | Description |
k | string | Yes | Set to |
positionId | string | Yes | A position ID (the |
ratio | number | Yes | The share to withdraw, (0, 1], converted to basis points; 1 empties the position without closing it (close with |
options | object | No |
|
See Also
Jupiter exchange.IO exchange.IO("lp.remove") exchange.IO("lp.collect") exchange.IO("lp.positions") exchange.IO("lp.increase")
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_v2removes 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
| Field | Description |
|---|---|
receivedBase, receivedQuote | The two token amounts actually received (from the balances before and after) |
feesBase, feesQuote | The fee part of them (split off by the amounts claimable on chain before sending) |
principalBase, principalQuote | The principal part = received − fees |
rewards | Farm rewards collected, [{mint, symbol, amount}] (excluding the pool's two tokens) |
rentRefundSol | Rent returned by closing (SOL) |
feeSol | Network 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.