@somnia-chain/markets-sdk


@somnia-chain/markets-sdk / index / SomniaMarkets

Class: SomniaMarkets

Defined in: packages/sdk/src/unified/exchange.ts:154

The exchange — the SDK's single entry point. One instance per chain; wraps the native engine (watches, local books, one-round-trip writes) behind symbols, fetch*/watch* verbs, and human-unit structs — the idioms every exchange bot already speaks (ccxt users will feel at home, down to the field names).

When to use

Use as the entry point for strategy and display code — numbers are human units, which is what that code wants. Reach past it to the native engine at SomniaMarkets.client (bigint-exact reads) and SomniaMarkets.trader (raw writes) for everything the unified surface doesn't cover.

Details

Verb conventions:

  • fetch* — one-shot (a chain or indexer round-trip).
  • watch* — streaming: each await resolves on the NEXT update of that channel, served from the zero-round-trip local store (the first call hydrates the ref-counted market watch).
  • create* / cancel* — writes (fixed fees, one-round-trip confirm).

Every struct carries the raw native payload under info for exact math.

Each instance is fully isolated — its own config, live store, and lazily opened WebSocket (an indexer-only exchange never opens one) — so one process can run several: a bot per chain, per-request servers, parallel tests.

Gotchas

Call SomniaMarkets.close to release the watches when done. The native engine is not separately constructible — it is only reachable through an exchange instance.

Example

Load the market registry, stream a book, place a limit order.

ts
import { SomniaMarkets } from "@somnia-chain/markets-sdk";

const exchange = new SomniaMarkets({
  chain,        // a viem Chain
  wsRpcUrl,     // wss:// RPC of that chain
  indexerUrl,   // the Envio/Hasura GraphQL endpoint
  addresses,    // contract addresses (e.g. from @somnia-chain/deployments)
  privateKey,   // optional — only createOrder & friends need a signer
});
await exchange.loadMarkets();

const book  = await exchange.watchOrderBook("BTC-95000-31DEC26/USDC#YES"); // live, zero RTT
const order = await exchange.createOrder("BTC-95000-31DEC26/USDC#YES", "limit", "buy", 10, 0.62);
await exchange.close();

Constructors

Constructor

new SomniaMarkets(config): SomniaMarkets

Defined in: packages/sdk/src/unified/exchange.ts:232

Parameters

config

SomniaMarketsConfig

Returns

SomniaMarkets

Properties

client

readonly client: SomniaMarketsClient

Defined in: packages/sdk/src/unified/exchange.ts:156

The native engine — bigint-exact, address-keyed. The escape hatch.


markets

markets: Record<string, UnifiedMarket> = {}

Defined in: packages/sdk/src/unified/exchange.ts:158

Unified markets keyed by MARKET symbol (populated by loadMarkets).


symbols

symbols: string[] = []

Defined in: packages/sdk/src/unified/exchange.ts:160

All market symbols (populated by loadMarkets).


has

readonly has: object

Defined in: packages/sdk/src/unified/exchange.ts:166

Capability map — which unified verbs this venue supports (the ccxt exchange.has convention, for capability-probing bot code). Every listed verb is implemented here, so every flag is true.

fetchMarkets

readonly fetchMarkets: true = true

SomniaMarkets.fetchMarkets

fetchOrderBook

readonly fetchOrderBook: true = true

SomniaMarkets.fetchOrderBook

fetchTrades

readonly fetchTrades: true = true

SomniaMarkets.fetchTrades

fetchOHLCV

readonly fetchOHLCV: true = true

SomniaMarkets.fetchOHLCV

fetchBalance

readonly fetchBalance: true = true

SomniaMarkets.fetchBalance

fetchOpenOrders

readonly fetchOpenOrders: true = true

SomniaMarkets.fetchOpenOrders

fetchMyTrades

readonly fetchMyTrades: true = true

SomniaMarkets.fetchMyTrades

fetchStatus

readonly fetchStatus: true = true

SomniaMarkets.fetchStatus

createOrder

readonly createOrder: true = true

SomniaMarkets.createOrder

cancelOrder

readonly cancelOrder: true = true

SomniaMarkets.cancelOrder

watchOrderBook

readonly watchOrderBook: true = true

SomniaMarkets.watchOrderBook

watchTrades

readonly watchTrades: true = true

SomniaMarkets.watchTrades

watchOrders

readonly watchOrders: true = true

SomniaMarkets.watchOrders

watchMyTrades

readonly watchMyTrades: true = true

SomniaMarkets.watchMyTrades

fetchPositions

readonly fetchPositions: true = true

SomniaMarkets.fetchPositions

fetchFundingRate

readonly fetchFundingRate: true = true

SomniaMarkets.fetchFundingRate

fetchFundingRateHistory

readonly fetchFundingRateHistory: true = true

SomniaMarkets.fetchFundingRateHistory — the key did not previously exist in this map, so it had to be ADDED rather than flipped.

watchPrice

readonly watchPrice: true = true

SomniaMarkets.watchPrice

fetchPrice

readonly fetchPrice: true = true

SomniaMarkets.fetchPrice

fetchPriceOHLCV

readonly fetchPriceOHLCV: true = true

SomniaMarkets.fetchPriceOHLCV

Accessors

trader

Get Signature

get trader(): Trader

Defined in: packages/sdk/src/unified/exchange.ts:249

The raw write tier bound to this exchange's signer — bigint-exact placeOrder/mintSet/faucet/… for anything the unified verbs don't cover.

Gotchas

Built lazily; throws if no signer was configured.

Returns

Trader


walletAddress

Get Signature

get walletAddress(): `0x${string}` | undefined

Defined in: packages/sdk/src/unified/exchange.ts:274

The authenticated wallet address, if a signer was configured.

Returns

`0x${string}` | undefined

Methods

setSigner()

setSigner(signer): void

Defined in: packages/sdk/src/unified/exchange.ts:262

Bind (or replace) the exchange's signer after construction. Browser apps construct the exchange at boot for public reads, then call this when the user's wallet connects — and again with {} on disconnect, which returns the exchange to unauthenticated reads. Replaces the trader every authenticated verb and walletAddress resolve against; live watches and market data are unaffected.

Parameters

signer

Pick<TraderConfig, "privateKey" | "account" | "walletClient">

Returns

void


loadMarkets()

loadMarkets(reload?): Promise<Record<string, UnifiedMarket>>

Defined in: packages/sdk/src/unified/exchange.ts:301

Load (or reload) the market registry: every market as a unified, symbol-keyed market object. Call once before anything symbol-based.

Parameters

reload?

boolean = false

Returns

Promise<Record<string, UnifiedMarket>>


market()

market(ref): Tradable

Defined in: packages/sdk/src/unified/exchange.ts:452

Resolve any handle (symbol, tradable symbol, pool/market address, market id) to its tradable. Requires loadMarkets().

Parameters

ref

string

Returns

Tradable


priceToPrecision()

priceToPrecision(ref, price): number

Defined in: packages/sdk/src/unified/exchange.ts:472

Snap a price to the market's tick grid (rounds down; binary prices are also clamped inside (0, 1)).

When to use

Use before createOrder with computed prices.

Spot/perp ticks come from the market row; binary ticks come from the pool, read once by loadMarkets — so a pool recycled mid-session keeps the grid captured at load time until loadMarkets(true) refreshes it.

Parameters

ref

string

price

number

Returns

number

Throws

InvalidInputError if the market is binary and its pool's parameters could not be read — quantizing against a guessed grid is what produced off-tick rejections, so this fails loudly instead.


amountToPrecision()

amountToPrecision(ref, amount): number

Defined in: packages/sdk/src/unified/exchange.ts:493

Snap an amount to the market's lot grid (rounds down).

Spot/perp lots come from the market row; binary lots come from the pool, read once by loadMarkets — so a pool recycled mid-session keeps the grid captured at load time until loadMarkets(true) refreshes it.

Parameters

ref

string

amount

number

Returns

number

Throws

InvalidInputError if the market is binary and its pool's parameters could not be read. Previously such a market fell back to a one-whole-token lot, silently flooring every sub-token amount to 0.


fetchMarkets()

fetchMarkets(): Promise<UnifiedMarket[]>

Defined in: packages/sdk/src/unified/exchange.ts:510

Every market as an array — loadMarkets (called if needed), minus the symbol keying.

When to use

Use as the ccxt-shaped sibling for list-style consumers.

Returns

Promise<UnifiedMarket[]>


fetchOrderBook()

fetchOrderBook(ref, limit?): Promise<UnifiedOrderBook>

Defined in: packages/sdk/src/unified/exchange.ts:638

One-shot book read from the contract (head-fresh; no watch needed).

When to use

Use when one book snapshot is enough. For a continuously-current zero-round-trip book, use watchOrderBook.

Parameters

ref

string

limit?

number = 10

Returns

Promise<UnifiedOrderBook>


fetchTrades()

fetchTrades(ref, since?, limit?): Promise<UnifiedTrade[]>

Defined in: packages/sdk/src/unified/exchange.ts:648

Recent public trades (indexer, newest first).

Parameters

ref

string

since?

number

limit?

number = 50

Returns

Promise<UnifiedTrade[]>


fetchOHLCV()

fetchOHLCV(ref, timeframe?, since?, limit?): Promise<UnifiedOHLCV[]>

Defined in: packages/sdk/src/unified/exchange.ts:679

OHLCV candles (indexer), oldest first as [ms,o,h,l,c,vol] rows. Timeframes: 1m 5m 15m 1h 4h 1d.

Parameters

ref

string

timeframe?

string = "5m"

since?

number

limit?

number = 500

Returns

Promise<UnifiedOHLCV[]>

Example

The last 24 hourly candles, destructured per row.

ts
const candles = await exchange.fetchOHLCV("SOMI/USDC", "1h", undefined, 24);
for (const [ts, open, high, low, close, volume] of candles) {
  console.log(new Date(ts).toISOString(), open, high, low, close, volume);
}

fetchTicker()

fetchTicker(ref): Promise<UnifiedTicker>

Defined in: packages/sdk/src/unified/exchange.ts:706

Rolling 24h ticker (indexer): OHLC + base/quote volume folded from the hourly candles, last from the freshest fill. NO-outcome tradables view prices through the 1−p lens like every other read.

Parameters

ref

string

Returns

Promise<UnifiedTicker>

Example

Drive a price strip off one call.

ts
const tk = await exchange.fetchTicker("SOMI/USDC");
console.log(tk.last, tk.percentage, tk.baseVolume);

fetchBalance()

fetchBalance(): Promise<UnifiedBalances>

Defined in: packages/sdk/src/unified/exchange.ts:812

Wallet balances for every currency the loaded markets use (+ native).

Gotchas

free === total: funds escrowed in resting orders live in the pools, not the wallet, so they simply don't appear here.

Returns

Promise<UnifiedBalances>

Example

ERC-20s key by currency code; binary outcome holdings key by TRADABLE symbol.

ts
const bal = await exchange.fetchBalance();
console.log(bal.USDC?.total);                              // collateral in the wallet
console.log(bal["BTC-95000-31DEC26/USDC#YES"]?.total);     // YES shares held

Throws

SignerRequiredError - balances are per-account, so this needs a signer (or an account) even though it only reads.

Throws

IndexerError - loadMarkets() needed the indexer and it was unreachable. Distinct from an empty result: no balances is {}, not a throw.

Throws

RpcError - a chain balance read did not complete.


fetchOpenOrders()

fetchOpenOrders(ref?): Promise<UnifiedOrder[]>

Defined in: packages/sdk/src/unified/exchange.ts:863

Open orders (indexer view).

When to use

Use for an occasional snapshot; a trading loop should prefer watchOrders.

Gotchas

The indexer view lags the chain slightly.

Parameters

ref?

string

Returns

Promise<UnifiedOrder[]>


fetchOrders()

fetchOrders(ref?, since?, limit?, params?): Promise<UnifiedOrder[]>

Defined in: packages/sdk/src/unified/exchange.ts:894

The wallet's orders across every lifecycle status (indexer), newest first — the history counterpart to fetchOpenOrders. Scope to one tradable with ref; page with limit/params.offset.

Parameters

ref?

string

since?

number

limit?

number = 100

params?
offset?

number

Returns

Promise<UnifiedOrder[]>

Example

The last 50 orders on one book, whatever became of them.

ts
const orders = await exchange.fetchOrders("SOMI/USDC", undefined, 50);
for (const o of orders) console.log(o.status, o.side, o.amount, o.txHash);

fetchPortfolioAnalytics()

fetchPortfolioAnalytics(timeframe, params?): Promise<PortfolioAnalytics>

Defined in: packages/sdk/src/unified/exchange.ts:1017

The wallet's portfolio metrics plane over a timeframe: equity curve (cumulative realized + unrealized PnL), per-bucket PnL, money-weighted return, volume, and fees saved versus a comparison taker rate. Computed client-side from the wallet's indexed fills (avg-cost basis) marked to candle closes — no server aggregate involved.

SPOT-scoped today: binary outcomes settle rather than mark, and the perp account plane (funding, margin) joins the fold as new event kinds when perp analytics land. Fills are paged to exhaustion — truncating would drop the OLDEST fills and silently corrupt the carried-in cost basis, not just undercount volume. Fills whose taker direction the indexer has not resolved (takerIsBid null), or where the wallet's role (maker vs taker) is unknowable, are skipped rather than guessed.

Parameters

timeframe

PortfolioTimeframe

params?
sessionSince?

number

cexRateBps?

number

Returns

Promise<PortfolioAnalytics>

Example

ts
const p = await exchange.fetchPortfolioAnalytics("7d");
console.log(p.pnl.totalUsd, p.mwrr.return, p.equity.length);

fetchMyTrades()

fetchMyTrades(ref?, since?, limit?): Promise<UnifiedTrade[]>

Defined in: packages/sdk/src/unified/exchange.ts:1106

My historical trades (indexer portfolios).

Parameters

ref?

string

since?

number

limit?

number = 50

Returns

Promise<UnifiedTrade[]>


fetchStatus()

fetchStatus(): Promise<{ status: "error" | "ok" | "connecting"; updated: number; info: TailStatus; }>

Defined in: packages/sdk/src/unified/exchange.ts:1160

Exchange health.

Details

"ok" unless a live watch is missing its socket — "connecting" while the first WS handshake is still in flight (~1s after a watch opens), "error" once a previously-live socket is lost.

Returns

Promise<{ status: "error" | "ok" | "connecting"; updated: number; info: TailStatus; }>


watchOrderBook()

watchOrderBook(ref, limit?): Promise<UnifiedOrderBook>

Defined in: packages/sdk/src/unified/exchange.ts:1263

Streaming book off the local store: zero round-trips, current to the last block; each await resolves on the next book change.

Parameters

ref

string

limit?

number = 10

Returns

Promise<UnifiedOrderBook>

Example

A quoting loop: wake on every book change, read the touch.

ts
while (true) {
  const book = await exchange.watchOrderBook("SOMI/USDC", 5);
  const [bestBid] = book.bids[0] ?? [];
  const [bestAsk] = book.asks[0] ?? [];
  console.log(`bid ${bestBid} / ask ${bestAsk}`);
}

watchTrades()

watchTrades(ref, limit?): Promise<UnifiedTrade[]>

Defined in: packages/sdk/src/unified/exchange.ts:1288

Streaming public trades (the live tape), newest first.

Parameters

ref

string

limit?

number = 50

Returns

Promise<UnifiedTrade[]>

Example

Print each fill as it lands ([0] is always the latest).

ts
while (true) {
  const [latest] = await exchange.watchTrades("SOMI/USDC", 1);
  if (latest) console.log(`${latest.side ?? "?"} ${latest.amount} @ ${latest.price}`);
}

watchOrders()

watchOrders(ref, limit?): Promise<UnifiedOrder[]>

Defined in: packages/sdk/src/unified/exchange.ts:1333

Streaming view of MY orders on this tradable (authenticated).

When to use

Use to learn that a resting order filled: its status flips to "closed".

Parameters

ref

string

limit?

number = 100

Returns

Promise<UnifiedOrder[]>

Example

Place a limit order, then block until it fully fills (or dies).

ts
const placed = await exchange.createOrder(symbol, "limit", "buy", 10, 0.62);
while (placed.status === "open") {
  const orders = await exchange.watchOrders(symbol); // resolves on the next change
  const mine = orders.find((o) => o.id === placed.id);
  if (!mine || mine.status !== "open") break; // filled, canceled, or expired
}

watchMyTrades()

watchMyTrades(ref, limit?): Promise<UnifiedTrade[]>

Defined in: packages/sdk/src/unified/exchange.ts:1370

Streaming view of MY fills on this tradable (authenticated).

Parameters

ref

string

limit?

number = 50

Returns

Promise<UnifiedTrade[]>


watchPrice()

watchPrice(asset): Promise<UnifiedPrice>

Defined in: packages/sdk/src/unified/exchange.ts:1416

Streaming price off the local price store: zero round-trips, current to the last pushed tick; each await resolves on the next price change.

Details

First call hydrates the ref-counted feed watch.

Gotchas

Requires config.priceFeed to be set.

Parameters

asset

string

Returns

Promise<UnifiedPrice>


fetchPrice()

fetchPrice(asset): Promise<UnifiedPrice | null>

Defined in: packages/sdk/src/unified/exchange.ts:1430

One-shot current price (indexer HTTP read; no watch needed), or null if the feed has no observations yet.

Parameters

asset

string

Returns

Promise<UnifiedPrice | null>


fetchPriceOHLCV()

fetchPriceOHLCV(asset, timeframe?, since?, limit?): Promise<UnifiedOHLCV[]>

Defined in: packages/sdk/src/unified/exchange.ts:1446

OHLC price candles (EMA oracle), oldest first as [ms,o,h,l,c,vol] rows.

Details

Timeframes: 1m 1h 1d (aliases for the feed's M1/H1/D1).

Gotchas

vol is the oracle update count for the bucket (NOT trade volume).

Parameters

asset

string

timeframe?

string = "1m"

since?

number

limit?

number = 500

Returns

Promise<UnifiedOHLCV[]>


createOrder()

createOrder(ref, type, side, amount, price?, params?): Promise<UnifiedOrder>

Defined in: packages/sdk/src/unified/exchange.ts:1512

Place an order.

Details

Works identically for every market kind: the tradable symbol carries the outcome, side is plain buy/sell, prices and amounts are human units in the tradable's own terms. type: "market" computes a crossing limit from the best opposite level ± params.slippage (default 1%) and sends it IOC. Resolves once mined, with fills decoded from the same round-trip.

Gotchas

A NO price is the NO probability — the YES-terms complement is handled internally.

The price and quantity are ALIGNED to the market's tick and lot grids before they are sent, because the pool rejects an off-grid value outright. Alignment never moves a value against you: a buy price rounds down, a sell price rounds up, and a quantity always rounds down, so the order is never larger or worse priced than you asked for. The returned UnifiedOrder carries what was actually placed, which may differ from the arguments by up to one tick or lot — read price and amount back from it rather than assuming your inputs. Pre-aligning with priceToPrecision / amountToPrecision makes this a no-op, since aligning an aligned value changes nothing.

Note priceToPrecision always rounds DOWN, for either side; this path is side-aware instead, so for a sell the two can differ by one tick.

A quantity below one whole lot throws InvalidInputError rather than silently placing a zero-quantity order.

Parameters

ref

string

type

"market" | "limit"

side

"buy" | "sell"

amount

number

price?

number

params?

CreateOrderParams = {}

Returns

Promise<UnifiedOrder>

Example

Rest a bid at 62% on YES, then take the NO book at market.

ts
const rested = await exchange.createOrder("BTC-95000-31DEC26/USDC#YES", "limit", "buy", 25, 0.62);
console.log(rested.status, rested.filled); // "open" 0 — or "closed" if it crossed

const taken = await exchange.createOrder("BTC-95000-31DEC26/USDC#NO", "market", "sell", 10, undefined, {
  slippage: 0.02, // accept up to 2% past the best bid
});

Throws

SignerRequiredError - the exchange was built without a privateKey / account / walletClient.

Throws

InvalidInputError - unknown symbol (call loadMarkets() first), a "limit" order with no price, or a "market" order whose opposite book side is empty so no crossing price exists.

Throws

ContractRevertError - the chain rejected the order. Branch on errorName for the protocol's own reason (e.g. InsufficientBalance, ExpiredOrderMustBeCancelled).

Throws

RpcError - the send never got an answer from the node.

Throws

IndexerError - a symbol lookup needed the indexer and it was unreachable.


cancelOrder()

cancelOrder(id, ref): Promise<{ id: string; symbol: string; status: "canceled"; info: unknown; }>

Defined in: packages/sdk/src/unified/exchange.ts:1687

Cancel a resting order by id (from createOrder / watchOrders).

Parameters

id

string

ref

string

Returns

Promise<{ id: string; symbol: string; status: "canceled"; info: unknown; }>

Example

ts
const placed = await exchange.createOrder("SOMI/USDC", "limit", "buy", 10, 0.55);
if (placed.status === "open") await exchange.cancelOrder(placed.id, "SOMI/USDC");

Throws

SignerRequiredError - no signer on this exchange.

Throws

InvalidInputError - unknown symbol.

Throws

ContractRevertError - the cancel did not land; errorName says why (an already-filled or already-canceled order reverts).

Throws

RpcError - the send never got an answer from the node.


createStopOrder()

createStopOrder(ref, type, side, amount, triggerPrice, price?, params?): Promise<UnifiedStopOrder>

Defined in: packages/sdk/src/unified/exchange.ts:1747

Place a stop / take-profit order: rests OFF the book on the market's stop registry and fires as a market or limit order when the pool's mark price crosses triggerPrice. The trigger direction is inferred from which side of the current mark the trigger sits on; pass params.triggerDirection to pin it explicitly.

Gotchas

The trigger, limit price and quantity are aligned to the market's grids, and the trigger aligns AWAY from the mark so it cannot land on it (a trigger equal to the mark fires the instant it is armed). The limit price aligns like any order price — a buy down, a sell up — so it never becomes worse than stated.

Those two rules are independent, so a limit set exactly EQUAL to the trigger can end up one tick inside it: a buy stop at trigger 0.5004, limit 0.5004 on a 0.001 grid arms at 0.501 and rests a 0.500 bid, which may not fill. That is deliberate — pulling the limit up to meet the trigger would make you pay more than you asked. Set the limit a tick or two past the trigger when you want the triggered order to cross.

Parameters

ref

string

type

"market" | "limit"

side

"buy" | "sell"

amount

number

triggerPrice

number

price?

number

params?
triggerDirection?

"above" | "below"

Returns

Promise<UnifiedStopOrder>

Example

A stop-loss: sell 5 if the mark drops to 1.10.

ts
const stop = await exchange.createStopOrder("SOMI/USDC", "market", "sell", 5, 1.10);
// …later: await exchange.cancelStopOrder(stop.id, "SOMI/USDC");

fetchOpenStopOrders()

fetchOpenStopOrders(ref?): Promise<UnifiedStopOrder[]>

Defined in: packages/sdk/src/unified/exchange.ts:1863

The wallet's pending (armed, untriggered) stop orders, newest first. Scope to one tradable with ref.

Parameters

ref?

string

Returns

Promise<UnifiedStopOrder[]>


cancelStopOrder()

cancelStopOrder(id, ref): Promise<{ id: string; symbol: string; status: "canceled"; info: unknown; }>

Defined in: packages/sdk/src/unified/exchange.ts:1899

Cancel a pending stop order on its registry (refunds the keeper payment). id comes from fetchOpenStopOrders.

Parameters

id

string

ref

string

Returns

Promise<{ id: string; symbol: string; status: "canceled"; info: unknown; }>


fetchFundingRate()

fetchFundingRate(ref): Promise<UnifiedFundingRate>

Defined in: packages/sdk/src/unified/exchange.ts:1917

Live funding-rate + mark/index snapshot for a perp market (chain read).

Parameters

ref

string

Returns

Promise<UnifiedFundingRate>


fetchFundingRateHistory()

fetchFundingRateHistory(ref, since?, limit?): Promise<UnifiedFundingRate[]>

Defined in: packages/sdk/src/unified/exchange.ts:1983

Historical funding rates for a perp market, oldest first (ccxt-standard shape).

Reads the INDEXED series rather than the chain: only one funding value is readable on chain at a time. Positional (symbol, since, limit) follows the ccxt convention set by fetchOHLCV, unlike the object-options readers on the client.

fundingRate is normalized to a per-8h fraction using each row's own fundingWindowSec, so the series stays consistent across a parameter change. The raw indexed row is on info for anything more specific — including spanStart / spanEnd, which matter because a row's accrual reaches BACKWARDS from its timestamp and a lazily-settled one can cover hours.

since is a CURSOR, not just a window bound: passing it walks FORWARD from that point, so the ccxt pagination idiom terminates.

ts
let since = startOfHistory;
for (;;) {
  const page = await exchange.fetchFundingRateHistory("BTC/USDSO:USDSO", since, 100);
  if (page.length === 0) break;
  consume(page);
  since = page[page.length - 1].timestamp + 1;   // advances
}

Without the forward ordering this loop spins: the underlying read pages newest-first, so narrowing the window from below still returns the newest N and since never gets past the tail. Omitting since keeps the newest-first behaviour, which is what a "latest funding" read wants — fetchOHLCV has the same split.

Parameters

ref

string

market symbol or pool address

since?

number

unix MILLISECONDS (ccxt convention), inclusive; acts as a forward cursor

limit?

number

max rows (default 100)

Returns

Promise<UnifiedFundingRate[]>


fetchPositions()

fetchPositions(refs?): Promise<UnifiedPosition[]>

Defined in: packages/sdk/src/unified/exchange.ts:2019

Open perp positions (authenticated; on-chain MarginBank reads). Pass symbols to scope; defaults to every loaded perp market.

Parameters

refs?

string[]

Returns

Promise<UnifiedPosition[]>


depositMargin()

depositMargin(ref, amount): Promise<{ hash: string; info: unknown; }>

Defined in: packages/sdk/src/unified/exchange.ts:2084

Deposit collateral into the perp MarginBank (human quote units, e.g. USDso). One cross-margin balance covers every perp market.

Parameters

ref

string

amount

number

Returns

Promise<{ hash: string; info: unknown; }>


withdrawMargin()

withdrawMargin(ref, amount): Promise<{ hash: string; info: unknown; }>

Defined in: packages/sdk/src/unified/exchange.ts:2100

Withdraw free collateral from the perp MarginBank (human quote units).

Parameters

ref

string

amount

number

Returns

Promise<{ hash: string; info: unknown; }>


mintSet()

mintSet(ref, amount): Promise<{ hash: string; info: unknown; }>

Defined in: packages/sdk/src/unified/exchange.ts:2135

Mint complete sets: amount collateral → amount of EVERY outcome.

Parameters

ref

string

amount

number

Returns

Promise<{ hash: string; info: unknown; }>

Example

Mint 100 sets (100 USDC → 100 YES + 100 NO), then sell the side you don't want.

ts
await exchange.mintSet("BTC-95000-31DEC26/USDC", 100);
await exchange.createOrder("BTC-95000-31DEC26/USDC#NO", "limit", "sell", 100, 0.38);

burnSet()

burnSet(ref, amount): Promise<{ hash: string; info: unknown; }>

Defined in: packages/sdk/src/unified/exchange.ts:2147

Burn complete sets back to collateral.

Parameters

ref

string

amount

number

Returns

Promise<{ hash: string; info: unknown; }>


redeem()

redeem(ref, amount): Promise<{ hash: string; info: unknown; }>

Defined in: packages/sdk/src/unified/exchange.ts:2171

Redeem winning outcome tokens for collateral (post-resolution). Settlement- extraction v2: module-routed by marketId (the winning outcome is read off the BinaryMarket contract when not resolved yet in the indexed row).

Parameters

ref

string

amount

number

Returns

Promise<{ hash: string; info: unknown; }>

Example

After resolution, redeem the winning side found in the balance map.

ts
const bal = await exchange.fetchBalance();
const winning = bal["BTC-95000-31DEC26/USDC#YES"]?.total ?? 0;
if (winning > 0) await exchange.redeem("BTC-95000-31DEC26/USDC", winning);

close()

close(): Promise<void>

Defined in: packages/sdk/src/unified/exchange.ts:2207

Release every watch + channel this exchange holds and stop the client's live machinery.

Details

The instance stays usable for one-shot fetch calls.

Returns

Promise<void>