Reading state and quotes

Read live program state over RPC before you act, and history and cached snapshots from the indexer.

Updated Nov 9, 2026

There are three ways to read Omnipair state, and they answer different questions.

RPC account reads and typed previews tell you what the program would do right now. The indexer tells you what has happened and serves cached snapshots the app can render at once. Mixing them up is the most common integration bug.

Accounts over RPC

dusk.get exposes typed account fetches and the PDA helpers for every account:

const [market] = dusk.get.pda.market(baseMint, quoteMint, paramsHash)
const account = await dusk.get.market(market)
 
const [position] = dusk.get.pda.borrowPosition(market, owner, positionId)
const borrow = await dusk.get.borrowPosition(position)
 
const proposal = await dusk.operator.proposal(proposalAddress)
const pending = await dusk.operator.pending(market)

Standalone helpers exist for every seed: deriveMarketAddress, deriveBorrowPositionAddress, deriveLeveragePositionAddress, deriveLeverageDelegationAddress, deriveYieldAccountAddress, deriveMarketReserveVaultAddress, deriveMarketCollateralVaultAddress, deriveLeverageCollateralVaultAddress, deriveMarketInterestVaultAddress, deriveFutarchyAuthorityAddress, deriveReferralPartnerAddress, deriveReferralAccrualAddress, deriveOperatorProposalAddress, deriveOperatorRevenueAddress, deriveEventAuthorityAddress and deriveTokenMetadataAddress. The accounts reference lists the seeds behind each.

A fetched Market is the state at the last checkpoint. Interest that has accrued since is not in it; previews are.

Typed previews

Previews are read-only instructions the SDK simulates and decodes. They run the program's own accounting, including lazy interest accrual, without persisting anything.

PreviewReturns
previewMarket(market)The accrued market: live reserves, utilization, rates, spot and EMA prices, hLP vault state
previewSwap(...)Output, fee components, price after, for an exact input
previewBorrowCapacity(...)For a collateral amount: maxDebtByHealth, maxDebtByCash, maxDebtByDailyLimit, maxDebt, maxBorrowAmount, maxCfBps, liquidationCfBps and the projected global-health terms
previewBorrowPosition(market, position)An existing position with accrued debt and health
previewBorrowPositionCapacity(...)For an existing position: additional borrow (capacityKind: "borrow") or collateral withdrawal ("withdraw") capacity, with borrowAllowed
previewHlpDepositCapacity(...)How much an hLP vault can admit right now and why not more
previewHlpOrderTrigger(...)The current NAV and funding average an hLP order would be judged against
const capacity = await dusk.get.previewBorrowPositionCapacity({
  capacityKind: "borrow",
  market,
  borrowPosition: position,
  collateralAssetMint: baseMint,
  debtAssetMint: quoteMint,
  collateralChange: new BN(0),
  projectedBorrowAmount: null, // maximum additional draw
})
 
capacity.existingDebtAmount
capacity.maxBorrowAmount
capacity.projectedDebtAmount
capacity.borrowAllowed

Use the position-aware preview for existing positions rather than adding their debt to previewBorrowCapacity; it accrues interest and replaces the position's own health contribution the way the instructions do. collateralChange is a signed raw delta: positive is the net credit after inbound transfer fees, negative is a vault debit. Capacity previews do not replace transaction-time checks for permissions, reduce-only, token accounts, referrals, slippage or deployment freshness.

The virtual order book

The app's depth view is a batch of swap previews. dusk.get.previewVirtualBook(market, { groupingBps, minContextSlot }) samples the curve into bid and ask levels with cumulative size, fees and surcharge, using confirmed banks; groupings are 5, 10, 25, 50 and 100 bps. Batches must agree on market, mint, authority state, epoch and start price within an eight-slot spread, and outputs include Token-2022 transfer fees at the simulated epoch.

The indexer

dusk.fetch wraps the REST routes: pools, poolActivity, userPortfolioSnapshots and the rest, plus dusk.fetch.request(path, options) for anything else. The REST API page lists the routes; the read API and streams page covers the native Dusk routes the app uses for live state.

Every native response carries a deployment envelope: cluster, program IDs, IDL hashes and protocol revision, plus the source slot, observation time and an expiry. Compare it with your pin and drop anything that does not match. A snapshot older than its expiresAt is stale; delivery and cache hits never renew it.

Which read for which job

You wantUse
A quote to show a user before they signpreviewSwap or the capacity previews
A position's current healthpreviewBorrowPosition, or the wallet payload stream for many at once
A market's reserves and rates for a dashboardpreviewMarket for exactness, markets/state for cached breadth
Trades, deposits, claims over timeThe indexer's history routes
To know when to refreshThe changes stream: hints only, never values
To decide whether to liquidate or fillRe-read the accounts over RPC at execution time, whatever the indexer said

Token-2022 amounts

Everything the SDK returns is raw atoms. Mints with the interest-bearing or scaled-UI-amount extensions display differently from atoms / 10^decimals; use the token program's AmountToUiAmount and UiAmountToAmount through simulation for display, never for accounting. Prices and price limits are quote per base in nine-decimal NAD units on fixed mint decimals, independent of UI multipliers.

Mutable transfer fees: keeper reads

The devnet SDK exposes fetchTransferFeeNotices, transferFeeNotice and transferFeeCredit, plus DuskLiquidations.transferFeeNotices. These distinguish effective transfer fees, conservative admission fees and final-notice liquidation fees.

A keeper reads both mints and Clock coherently and refreshes before signing. It must detect epoch changes without relying on mint or market updates.

A changed authority, schedule, cancellation or rescheduling invalidates its cached notice. The refreshKey and nextRecheckEpoch help integrations schedule that work; on-chain previews remain authoritative.

These are execution-side reads. Displayed protocol state in the webapp still comes from the indexer; do not add background frontend RPC polling to mirror the keeper monitor. See keeper operations.