Skip to main content

Predict Liquidity SDK

The liquidity functions move USDC into the Predict pool for PLP shares and move PLP shares back out for USDC, through requests that wait for the next pool flush. Vault explains the pool, its request queues, and the flush that fills them.

How a request fills

Neither request mints nor burns PLP in the transaction that makes it. tx.supplyPlp and tx.withdrawPlp each escrow an amount from your account custody into a queue, and both requests fill at the next pool flush, at the single mark that flush computes for the whole pool. The flush delivers each fill and each refund to your account rather than to the signer, so check the result with read.plpBalance or the account's USDC balance after the flush.

Each request takes an optional floor in its options object. The floor bounds the flush's mark for the whole request rather than naming a quantity to fill, and the flush measures it after the pool's supply or withdraw fee, so it bounds what your account actually receives:

RequestAmount you passFloorFloor units
tx.supplyPlpamountUsdc, a US dollar (USD) decimal as a number or stringminPlpOutRaw 6-decimal PLP shares as a bigint
tx.withdrawPlpshares, raw 6-decimal PLP shares as a bigintminUsdcOutA USD decimal as a number or string

A flush that quotes a request below its floor declines it instead of filling it smaller. At the deployed lp_request_limit_flush_attempts of 1, that first miss cancels the request and refunds the escrow to your account, so queue a new request to try again. The flush also refunds a request whose mark or quote is not executable at all, rather than aborting. A flush that has room for only part of a request fills that part at the same mark and keeps the remainder in the queue and rescales its floor. A request that you make after a flush has taken its snapshot waits for the flush after it.

The SDK does not check the per-request minimums. The contract aborts a supply below 10 USDC with EBelowMinSupplyRequest and a withdrawal below 1 PLP, which is 1_000_000n raw, with EBelowMinWithdrawRequest. The Vault page lists every queue rule and explains how a flush forms the mark.

caution

Both floors default to none. A request without minPlpOut or minUsdcOut fills at whatever mark the next flush computes, so set a floor at the price where you would rather take the refund than the fill.

Request functions

Each request builder derives your account wrapper ID from owner with no chain read and returns a fresh Transaction synchronously. Its first command generates the account Auth that its second command consumes, so the owner must sign the transaction. See how owner authority works.

tx.supplyPlp

Use tx.supplyPlp to queue a request that moves amountUsdc from your account's USDC custody into the supply queue. It returns a Transaction, and without minPlpOut the request accepts whatever mark the next flush computes.

It takes these parameters:

  • owner: The address that owns the account.
  • amountUsdc: The USDC to escrow, as a USD decimal number or string with at most 6 decimal places.
  • options: An optional PlpSupplyOptions object. It defaults to {}.

The SDK throws PredictInputError when amountUsdc is negative, is not a plain decimal, or has more than 6 decimal places.

PlpSupplyOptions has a single field:

  • minPlpOut: The fewest PLP, in raw 6-decimal shares as a bigint, that the flush's quote for the whole request must reach. It defaults to 0n, which sets no floor.

tx.withdrawPlp

Use tx.withdrawPlp to queue a request that moves shares of PLP from your account custody into the withdraw queue. It returns a Transaction, and without minUsdcOut the request accepts whatever mark the next flush computes.

The shares argument counts raw PLP shares, not USD and not PLP as a decimal: a value of 1_000_000n is 1 PLP. Read the balance to withdraw with read.plpBalance, which returns the same raw bigint, and pass it straight through.

It takes these parameters:

  • owner: The address that owns the account.
  • shares: The PLP to escrow, in raw 6-decimal shares as a bigint.
  • options: An optional PlpWithdrawOptions object. It defaults to {}.

The SDK throws PredictInputError when minUsdcOut is negative, is not a plain decimal, or has more than 6 decimal places.

PlpWithdrawOptions has a single field:

  • minUsdcOut: The least USDC, as a USD decimal number or string, that the flush's quote for the whole request must reach after the withdraw fee. When you omit it, the SDK sends 0, which sets no floor.

tx.cancelSupplyPlp and tx.cancelWithdrawPlp

Use tx.cancelSupplyPlp or tx.cancelWithdrawPlp to cancel a pending request by its queue index and refund the escrowed USDC or PLP to your account. Each returns a Transaction.

The supply and withdraw queues number their requests separately, so pass a supply request's index to tx.cancelSupplyPlp and a withdraw request's index to tx.cancelWithdrawPlp. The SDK has no read that lists your pending requests: keep the index from the request's receipt, which decode.plpRequest returns from the executed request transaction.

It takes these parameters:

  • owner: The address that owns the account that made the request.
  • index: The request's queue index, as a bigint.

A cancel works only while its request is still pending. The contract aborts with ERequestNotFound when no pending entry carries the index, with ENotRequestOwner when your account is not the request's recorded recipient, and with EValuationInProgress while a flush is in flight, so the current flush still fills a request inside its cutoff at that flush's mark.

The receipt's kind tells you which builder cancels the request:

import type { DecodableTransactionResult } from '@mysten/deepbook-v3/predict';
import type { Transaction } from '@mysten/sui/transactions';

// `client` is a Sui client extended with `predict`, and `result` is the
// executed request transaction with its events included.
function cancelRequest(owner: string, result: DecodableTransactionResult): Transaction {
const { kind, index } = client.predict.decode.plpRequest(result);
return kind === 'supply'
? client.predict.tx.cancelSupplyPlp(owner, index)
: client.predict.tx.cancelWithdrawPlp(owner, index);
}

Pool reads

Both pool reads run a simulated transaction through your Sui client's core API, with no indexer in the path. A failed simulation throws PredictMoveError when the chain returns a Move abort and a plain Error otherwise. See Errors for both types.

read.pool

Use read.pool to read the pool's PLP supply, idle USDC, and queue lengths in a single simulated transaction. It returns a Promise<PoolSummary>.

It takes no parameters.

PoolSummary has these fields:

  • plpTotalSupply: The total PLP supply in raw 6-decimal shares, as a bigint. It includes the permanently locked bootstrap shares, which no one can withdraw.
  • idleUsdc: The pool's idle USDC, as a USD decimal number.
  • supplyRequestsPending: The number of queued supply requests, not their total amount.
  • withdrawRequestsPending: The number of queued withdraw requests, not their total amount.

idleUsdc is a display value that passes through a JavaScript number, while plpTotalSupply stays exact. See Units for how the SDK converts amounts. PoolSummary carries no pool net asset value (NAV) or share price, because only a flush computes the mark. Each flush's FlushExecuted event records that mark as pool_value divided by total_supply, and the SDK does not decode it. See the pool events for its fields.

read.plpBalance

Use read.plpBalance to read the PLP shares in an account's custody. It returns a Promise<bigint> in raw 6-decimal shares, the unit tx.withdrawPlp takes.

It takes this parameter:

  • owner: The address that owns the account.

It reads the account balance accessor for the deployment's PLP coin type, client.predict.cfg.coinTypes.plp. That accessor counts stored balance plus funds that reach the account before it settles them, so shares from a filled supply appear without a separate settle. For the account's USDC, use read.balance. The read loads the owner's wrapper, so call it for an account that exists.

Decoder functions

The liquidity decoders parse an executed transaction's events locally and make no network call. Each expects exactly 1 matching event and throws PredictInputError otherwise, and neither has a plural form, so keep 1 request or 1 cancel per transaction when you intend to decode it. Include events when you execute the transaction, because an event with no Binary Canonical Serialization (BCS) payload also throws PredictInputError. See Decode transaction results for the result shape the decoders accept.

decode.plpRequest

Use decode.plpRequest to read the receipt of a tx.supplyPlp or tx.withdrawPlp transaction, including the queue index a cancel needs. It builds a PlpRequestReceipt from the transaction's SupplyRequested or WithdrawRequested event and returns it.

It takes this parameter:

  • r: The executed transaction result, a DecodableTransactionResult that includes its events.

PlpRequestReceipt has these fields:

  • kind: The queue the request joined, 'supply' or 'withdraw'.
  • vaultId: The PoolVault ID.
  • accountId: The ID of the requesting account.
  • recipient: The address the flush delivers the fill or refund to.
  • index: The request's queue index, as a bigint.
  • amount: The escrowed amount as a display decimal, in USDC for a supply and in PLP for a withdrawal.
  • raw: The exact escrowed amount as raw.amount, a bigint in 6-decimal units.

decode.plpCancel

Use decode.plpCancel to read the receipt of a tx.cancelSupplyPlp or tx.cancelWithdrawPlp transaction. It builds a PlpCancelReceipt from the transaction's RequestCancelled event and returns it.

It takes this parameter:

  • r: The executed transaction result, a DecodableTransactionResult that includes its events.

PlpCancelReceipt has these fields:

  • vaultId, accountId, recipient, and index: The same values the request's receipt carries.
  • isSupply: Whether the canceled request was a supply.
  • amount: The refund as a display decimal, in USDC for a supply and in PLP for a withdrawal.
  • raw: The exact refund as raw.amount, a bigint in 6-decimal units.

A flush that refunds your request emits the same event inside the flush transaction, with a reason that separates your own cancel (0) from a mark or quote the flush found not executable (1) and a missed floor (2). PlpCancelReceipt does not carry reason, and the pool events list its values.

Example

The examples import the shared client from the client setup, which selects its network from the examples' NETWORK constant. The following example queues a supply with an optional floor, reads the queue index from the executed result, and reads the pool:

import type {
DecodableTransactionResult,
PlpRequestReceipt,
PoolSummary,
} from '@mysten/deepbook-v3/predict';
import type { Transaction } from '@mysten/sui/transactions';
import { client } from './client.js';

// Supplying to the pool queues a request rather than minting PLP on the spot.
// This transaction returns no PLP: the request fills at the next pool flush, at
// the single NAV that flush computes. `minPlpOut` is a floor on that mark, in raw
// six-decimal shares: a flush quoting fewer shares declines rather than filling
// smaller, and at the deployed attempt count of one the first miss cancels and
// refunds the request. Omit it to accept whatever the next flush quotes.
export function queueSupply(
owner: string,
amountUsdc: number,
minPlpOut?: bigint,
): Transaction {
return client.predict.tx.supplyPlp(owner, amountUsdc, { minPlpOut });
}

// The queue index is the handle for cancelling a request before it fills, and it
// exists only in the receipt. Execute with events included and keep it.
export function supplyRequestIndex(result: DecodableTransactionResult): bigint {
// `kind` is 'supply' here, and `amount` is in quote units.
const receipt: PlpRequestReceipt = client.predict.decode.plpRequest(result);
return receipt.index;
}

// Pool state. `supplyRequestsPending` and `withdrawRequestsPending` are queue
// lengths rather than amounts, and `plpTotalSupply` is raw six-decimal shares.
export async function poolState(): Promise<PoolSummary> {
return client.predict.read.pool();
}

The following example queues a withdrawal of the whole PLP balance, checks the 1 PLP minimum before it builds, and cancels a queued withdrawal or supply by index:

import type { Transaction } from '@mysten/sui/transactions';
import { client } from './client.js';

// Withdrawing from the pool is queued exactly as a supply is, and it takes raw
// PLP shares rather than a USD amount. `read.plpBalance` returns those shares
// directly, so exiting the whole position needs no conversion. `minUsdcOut` is a
// floor on the USDC the flush pays for the whole request, measured after the
// withdraw fee: a flush quoting less declines and, at the deployed attempt count
// of one, cancels and refunds the request. Omit it to accept the next mark.
export async function queueWithdrawAll(
owner: string,
minUsdcOut?: number,
): Promise<Transaction> {
const shares = await client.predict.read.plpBalance(owner);
// The chain rejects a request below one whole PLP, which is 1_000_000 raw at
// six decimals. Check it here rather than letting a dust holder take a Move
// abort out of a helper whose job is exiting the whole position.
const MIN_WITHDRAW_RAW = 1_000_000n;
if (shares < MIN_WITHDRAW_RAW) {
throw new Error(
`${owner} holds ${shares} raw PLP shares; the minimum withdrawal request is ${MIN_WITHDRAW_RAW}.`,
);
}
return client.predict.tx.withdrawPlp(owner, shares, { minUsdcOut });
}

// A queued request can be cancelled up to the flush that would fill it. The
// index comes from the request receipt: `decode.plpRequest(result).index`.
export function cancelQueuedWithdraw(owner: string, index: bigint): Transaction {
return client.predict.tx.cancelWithdrawPlp(owner, index);
}

// A queued supply cancels the same way, through its own builder.
export function cancelQueuedSupply(owner: string, index: bigint): Transaction {
return client.predict.tx.cancelSupplyPlp(owner, index);
}