@somnia-chain/markets-sdk


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

Interface: Trader

Defined in: packages/sdk/src/trade.ts:2313

The SDK's write tier — every pool/market transaction it can sign and send, bound to one signer. Built via client.createTrader(config) (see TraderConfig); shares that client's chain, addresses, and WebSocket.

Sending methods preserve ExecutorExecuteError, including missing executor transport as NotConfiguredError and a transaction whose receipt was not observed as TransactionOutcomeUnknownError.

Every write AWAITS its receipt before resolving — there is no bare-hash return to babysit. Order placements additionally resolve to the decoded order id + fills.

Properties

executor

readonly executor: Executor

Defined in: packages/sdk/src/trade.ts:2319

The executor this trader sends through — who signs, and the address the pools see as the caller (executor.actor). Read-only; build another trader to change it.

Methods

placeOrder()

placeOrder(params): Promise<PlaceOrderResult>

Defined in: packages/sdk/src/trade.ts:2348

Place a limit order (auto-approving the escrow token by default). Resolves once mined, with the resting order id and any fills.

Gotchas

  • Throws NotConfiguredError - the executor has no chain transport.
  • Throws InvalidInputError - price or quantity was not > 0.
  • Throws ContractRevertError - the pool rejected the order; errorName carries the protocol's own error (e.g. InsufficientBalance). Also thrown when the transaction mines with a reverted status — the SDK replays the call to recover the reason, so you get a name rather than a failed receipt.
  • Throws RpcError - a request did not complete, or the node refused the transaction.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.

Example (Placing a binary bid)

Bid 0.62 for 10 YES using an indexed binary market row market.

ts
const trader = client.createTrader({ privateKey });
const decimals = market.quoteDecimals;
const res = await trader.placeOrder({
  pool: market.poolAddress,
  side: "BUY_YES",
  price: probabilityToPrice(0.62, decimals),
  quantity: fromHuman(10, decimals),
});
console.log(res.orderId, res.fills.length); // resting id (if it rested) + immediate fills

Parameters

params

PlaceOrderParams

Returns

Promise<PlaceOrderResult>


cancelOrder()

cancelOrder(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2359

Cancel a resting order on its pool (works for spot + binary).

Gotchas

  • Throws NotConfiguredError - the executor has no chain transport.
  • Throws ContractRevertError - the cancel did not land (already filled, already canceled, not the owner — errorName distinguishes them).
  • Throws RpcError - a request did not complete, or the node refused the transaction.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.

Parameters

params

CancelOrderParams

Returns

Promise<TxResult>


reduceOrder()

reduceOrder(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2367

Shrink a resting order's remaining quantity in place, keeping its price-time queue priority (works for spot + binary). Reverts on-chain for an expired order — use Trader.cancelOrder there.

Parameters

params

ReduceOrderParams

Returns

Promise<TxResult>


cancelExpiredOrders()

cancelExpiredOrders(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2375

Permissionless keeper drain: clean an explicit list of expired resting orders on a pool, returning each order's escrow to its owner (best-effort; skips non-expired / stale ids).

Parameters

params

CancelExpiredOrdersParams

Returns

Promise<TxResult>


sweepExpiredAtLevel()

sweepExpiredAtLevel(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2382

Permissionless keeper drain: clean up to maxCount expired orders at one price level on a side.

Parameters

params

SweepExpiredAtLevelParams

Returns

Promise<TxResult>


captureClose()

captureClose(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2391

Permissionless closing-price capture on a BinaryPool (post-expiry): stores the closing mid and lifts the closing-book lock. Required before sweeping a pre-terminal closing book — a CloseNotCaptured revert on a cancel/sweep means "capture first, then retry".

Parameters

params

CaptureCloseParams

Returns

Promise<TxResult>


approveBuilder()

approveBuilder(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2409

Opt a routing/builder frontend in on a pool so orders the trader places with that builder code may charge up to maxFeeBpsTimes1k (0 revokes). Required before a non-zero builder/builderFeeBpsTimes1k on Trader.placeOrder, Trader.placeSpotOrder or Trader.placePerpOrder.

Binary, spot and perp pools each implement this interface, but the approval is stored PER POOL: approving a builder on one pool grants nothing on another. Call it once per pool the trader will place attributed orders on, or the placement reverts. Each pool declares the whole builder-error set; which one fires depends on the check that trips first. With NO approval at all that is BuilderNotApproved on a SpotPool (it guards approved > 0), BuilderFeeExceedsApproval on a PerpPool, and BuilderFeeExceedsCap on a BinaryPool — whose ceiling, unlike the other two, is frozen at init.

Parameters

params

ApproveBuilderParams

Returns

Promise<TxResult>


getBuilderApproval()

getBuilderApproval(ref): Promise<bigint>

Defined in: packages/sdk/src/trade.ts:2411

Read a trader's per-builder approval cap on a pool (pool bps×1000; 0 = none).

Parameters

ref

BuilderApprovalRef

Returns

Promise<bigint>


getEffectiveBuilderApproval()

getEffectiveBuilderApproval(ref): Promise<bigint>

Defined in: packages/sdk/src/trade.ts:2417

Effective builder approval on a pool: the trader's raw cap clamped by the pool's protocol-wide getMaxBuilderFeeBpsTimes1k ceiling — the actual enforced limit a builderFeeBpsTimes1k on any place-order verb must not exceed.

Parameters

ref

BuilderApprovalRef

Returns

Promise<bigint>


getMaxBuilderFeeBpsTimes1k()

getMaxBuilderFeeBpsTimes1k(pool): Promise<bigint>

Defined in: packages/sdk/src/trade.ts:2419

Read a pool's protocol-wide builder-fee ceiling (bps×1000).

Parameters

pool

`0x${string}`

Returns

Promise<bigint>


placeSpotOrder()

placeSpotOrder(params): Promise<PlaceOrderResult>

Defined in: packages/sdk/src/trade.ts:2432

Place a spot limit/market order on a SpotPool (auto-approves the escrow token, or sends native msg.value on a native-base sell).

An ERC-20 approval check uses requiredAmount, which is the pool's worst-case reserve including fee headroom. A native sell sends delta, which subtracts the owner's current vault balance from that reserve. The SDK reads the requirement once per uncached token/pool approval and on each native-base sell.

Parameters

params

PlaceSpotOrderParams

Returns

Promise<PlaceOrderResult>


placeSpotOrders()

placeSpotOrders(params): Promise<PlaceSpotOrdersResult>

Defined in: packages/sdk/src/trade.ts:2484

Place several orders on one SpotPool in a single transaction — a market maker's ladder in one tx instead of a loop of sends.

Gotchas

This write is NON-PAYABLE: unlike Trader.placeSpotOrder, it takes no msg.value. A native-base sell in a batch therefore funds from the pool's VAULT balance — pre-deposit native to the vault and auto-pull consumes it. ERC-20 auto-pull works normally per request, and the batch approves each escrow token once for the whole batch's total.

SPOT ONLY. A binary pool reverts UseBinaryPlacement on generic placement — the YES/NO kind must be explicit, so use Trader.placeOrder there.

A request that does not place is NOT an error: outcomes[i].success is false with no id for a PostOnly that would cross, an unfilled FillOrKill, an IOC that found no liquidity, an already-expired expiry, or a CancelTaker self-match. A hard validation error (bad lot size, insufficient funds) reverts the whole batch.

Outcome attribution matches each OrderPlaced event to its request on every field the event echoes (side, price, quantity, userData, expiry), in order. Two byte-identical adjacent requests with different outcomes are therefore indistinguishable from logs — the earlier index gets the credit. Tag rungs with distinct userData when exact attribution matters.

  • Throws NotConfiguredError - the executor has no chain transport.
  • Throws InvalidInputError - orders was empty, or a request had a non-positive price or quantity.
  • Throws ContractRevertError - the batch was rejected; errorName carries the protocol's error (EmptyBatch, UseBinaryPlacement on a binary pool, or a per-order validation failure).
  • Throws RpcError - a request did not complete, or the node refused the transaction.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.

Example (Placing a spot-order batch)

ts
// Place a three-rung sell ladder in one transaction.
const trader = client.createTrader({ privateKey });
const res = await trader.placeSpotOrders({
  pool,
  quoteToken,
  baseToken,
  orders: [1_010_000n, 1_020_000n, 1_030_000n].map((price) => ({
    isBid: false,
    price,
    quantity: 1_000_000n,
  })),
});
// Index-aligned with `orders`; a rung that did not place is success:false.
const ids = res.outcomes.flatMap((o) => (o.success ? [o.orderId!] : []));

Parameters

params

PlaceSpotOrdersParams

Returns

Promise<PlaceSpotOrdersResult>


cancelOrders()

cancelOrders(params): Promise<CancelOrdersResult>

Defined in: packages/sdk/src/trade.ts:2513

Cancel several resting orders on one pool in a single transaction — pull a whole ladder without leaving the remaining rungs exposed. Works on spot AND binary pools (cancel is inherited from the OrderBook base, not placement-gated).

Gotchas

BEST-EFFORT by design: an id that can no longer be cancelled (already filled, already cancelled, expired-and-swept, not owned by the signer) is SKIPPED on-chain instead of reverting the batch — which is the point in a fast market. Each outcomes[i].cancelled is inferred from whether the id emitted a cancel event, so a false does NOT tell you WHY: a benign fill race and a wrong id look identical here. Reconcile against the book if you need to know.

Example (Inspecting batch cancellations)

ts
const trader = client.createTrader({ privateKey });
const res = await trader.cancelOrders({ pool, orderIds: ladderIds });
const skipped = res.outcomes.filter((o) => !o.cancelled).map((o) => o.orderId);

Parameters

params

CancelOrdersParams

Returns

Promise<CancelOrdersResult>


cancelAllOrders()

cancelAllOrders(pool, opts?): Promise<CancelAllOrdersResult>

Defined in: packages/sdk/src/trade.ts:2571

Pull EVERY resting order the signer holds on one pool — the kill switch. Reads the ids and cancels them in one call. Works on spot AND binary pools.

When to use

Use it to stop quoting when the bot holds no local ids: after a restart, or after a send whose outcome is unknown. Trader.cancelOrders stays the right call when you already know which ids to pull.

Details

The default source: "chain" costs one eth_call plus the cancel transaction. source: "live" takes the ids from the live store instead, so the cancel is the only round trip — it needs an active market watch covering the pool.

Nothing resting is a SUCCESS, not an error: the result is then { sent: false, orderIds: [], outcomes: [] } and no transaction goes out. Branch on sent. When sent is true the result carries everything Trader.cancelOrders returns, per-id outcomes included.

Gotchas

An EXPIRED order that still rests is NOT cancelled on the default chain source. The pool's getOwnOpenOrders view filters expired orders out of the owner's own list, and expiry is lazy, so such an order keeps sitting on the book holding its funds while this read cannot see it. Clear that residue with Trader.cancelExpiredOrders or Trader.sweepExpiredAtLevel.

The two sources differ exactly here, and source: "live" is the stronger one. The live store marks an order expired only when it sees the pool's OrderExpired event, which lazy expiry does not emit until something touches the order — so a lapsed order still reads as resting and its id IS forwarded. On-chain the cancel then goes through: the pool gates a best-effort cancel on owner and id, not on expiry, so the order is removed from the book and its funds released. It emits OrderExpired rather than OrderCancelled, and both count as terminated, so the outcome reads cancelled: true. The live source therefore clears the residue that the chain source cannot even see.

A side filter is not supported yet. Pass the ids to Trader.cancelOrders when you must pull one side only.

  • Throws NotConfiguredError - the executor has no chain transport, or source: "live" without an active watch covering the pool. An unwatched store cannot tell an empty book from an unseen one, so it refuses rather than cancelling nothing.

  • Throws RpcError - the id read did not complete. A failed read never broadcasts.

  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.

  • Throws ContractRevertError - the cancel transaction reverted.

  • Throws InvalidInputError - the executor rejects the call.

Example (Pulling every quote after a restart)

ts
const trader = client.createTrader({ privateKey });
const res = await trader.cancelAllOrders(pool);
const pulled = res.sent ? res.outcomes.filter((o) => o.cancelled).length : 0;

Parameters

pool

`0x${string}`

opts?

CancelAllOrdersOptions

Returns

Promise<CancelAllOrdersResult>


reduceOrders()

reduceOrders(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2590

Shrink several resting orders in place in a single transaction, each keeping its price-time queue priority. Works on spot AND binary pools.

Gotchas

ATOMIC, unlike Trader.cancelOrders: the FIRST invalid reduction reverts the entire batch and no order changes. A reduction is invalid if the new quantity is not a lotSize multiple, is below minQuantity, is not strictly less than the current remaining, or the order has expired (cancel those instead). Size the batch accordingly — one stale id loses the whole tx.

Parameters

params

ReduceOrdersParams

Returns

Promise<TxResult>


placePerpOrder()

placePerpOrder(params): Promise<PlaceOrderResult>

Defined in: packages/sdk/src/trade.ts:2597

Place a perp limit/market order on a PerpPool. Margin is locked from the signer's MarginBank balance — Trader.depositMargin first.

Parameters

params

PlacePerpOrderParams

Returns

Promise<PlaceOrderResult>


amendOrder()

amendOrder(params): Promise<AmendOrderResult>

Defined in: packages/sdk/src/trade.ts:2644

Cancel ONE resting order and place its replacement atomically — the re-quote primitive, with no gap on the book.

When to use

Re-pricing a single quote. For a whole ladder use Trader.amendOrders, which cancels every old order before placing any replacement. To shrink an order without losing its place in the queue use Trader.reduceOrder — amend is not priority-preserving.

Details

Prefer this over Trader.amendOrders with a one-element array: this raises the replacement's own landing-time reason (PostOnlyWouldCross, SelfMatchCancelTaker, ImmediateOrCancelNoFill, FillOrKillNotFillable, OrderAlreadyExpired), where the batch wraps it as AmendReplacementRejected(requestIndex, reason) and leaves the caller unwrapping an index it already knew.

Gotchas

SpotPool and PerpPool only — a BinaryPool reverts UseBinaryPlacement, since binary placement is its own entry point. The replacement gets a NEW order id, so update local tracking. Non-payable: a native auto-pull amend reverts, because the cancel leg delivers the freed native to the wallet and the place leg cannot reach it — fund native replacements from a manual-vault balance.

  • Throws NotConfiguredError - the executor has no chain transport.
  • Throws InvalidInputError - price or quantity was not > 0.
  • Throws ContractRevertError - the old order was gone and alwaysPlace was not set (AmendOldOrderGone), it belongs to someone else (IncorrectSender), or the replacement did not rest or fill; errorName carries the protocol's error.
  • Throws RpcError - a request did not complete, or the node refused the transaction.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.

Example (Amending an order)

Re-quote one bid a tick lower, and keep the new id.

ts
const { newOrderId } = await trader.amendOrder({
  pool,
  oldOrderId: resting,
  newOrder: { isBid: true, price: 1_990_000n, quantity: 5_000_000n },
});

Parameters

params

AmendOrderParams

Returns

Promise<AmendOrderResult>


amendOrders()

amendOrders(params): Promise<AmendOrdersResult>

Defined in: packages/sdk/src/trade.ts:2651

Cancel N orders and place their replacements atomically. All-or-nothing, and it places — so the same BinaryPool restriction applies.

Parameters

params

AmendOrdersParams

Returns

Promise<AmendOrdersResult>


buildPlaceOrder()

buildPlaceOrder(params): Promise<UnsignedOrder>

Defined in: packages/sdk/src/trade.ts:2692

Build a binary placement WITHOUT sending it — the same inputs as Trader.placeOrder, handed back as unsigned calls.

When to use

Reach for this when the signing and the sending are not the same moment: to pre-sign an ERC-4337 UserOp while the user is still filling in the form, to batch the order into a multicall, to hand it to a relayer, or to simulate it. For ordinary "place this order now", use Trader.placeOrder — it is one call and it handles the approval for you.

Gotchas

The approval is RETURNED, not sent. placeOrder approves as a side effect; this cannot, because sending is exactly what it must not do. Send approval first when it is present, or the order reverts on-chain.

Still async: a binary placement reads the pool's market expiry when the caller does not pass expireTimestampNs, and resolves the pool's escrow tokens to work out which approval is needed. Pass expireTimestampNs, outcomeToken, yesId, noId, and collateral to keep it off the network.

No gas estimate and no nonce ride along — those belong to the signer, and pinning them here would stale the moment the call is cached.

Example (Building an unsigned order)

Pre-sign off the form, send on the click.

ts
const { order, approval } = await trader.buildPlaceOrder({
  pool, side: "BUY_YES", price: 620_000n, quantity: 10_000_000n,
});
if (approval) await walletClient.sendTransaction({ ...approval, account });
const signed = await account.signTransaction({ ...order, nonce, ...fees });

Parameters

params

PlaceOrderParams

Returns

Promise<UnsignedOrder>


buildPlaceSpotOrder()

buildPlaceSpotOrder(params): Promise<UnsignedOrder>

Defined in: packages/sdk/src/trade.ts:2716

Build a spot placement WITHOUT sending it — see Trader.buildPlaceOrder for when to reach for this and how the returned approval works.

A native-base sell pays via msg.value, so it comes back with no approval and a non-zero order.value: the pool's vault shortfall for this order, fee headroom included, as read when the call is built. A vault that gains funds before the send only shrinks the requirement (the pool refunds the overage); one that loses them makes the pool reject the call.

Gotchas

A spot placement that DEFAULTS its expiry pins it to ~50 years from now, so two builds a second apart differ in that one argument. Harmless against a 50-year horizon, but it means such a build is not byte-reproducible: sign and send the order you were handed rather than rebuilding and expecting the same bytes. Pass PlaceSpotOrderParams.expireTimestampNs explicitly and the build is reproducible, as binary and perp already are.

Parameters

params

PlaceSpotOrderParams

Returns

Promise<UnsignedOrder>


buildPlacePerpOrder()

buildPlacePerpOrder(params): Promise<UnsignedOrder>

Defined in: packages/sdk/src/trade.ts:2724

Build a perp placement WITHOUT sending it — see Trader.buildPlaceOrder for when to reach for this.

Never carries an approval: margin is locked from the MarginBank balance rather than escrowed per order (Trader.depositMargin first).

Parameters

params

PlacePerpOrderParams

Returns

Promise<UnsignedOrder>


depositMargin()

depositMargin(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2731

Deposit collateral into the MarginBank (auto-approving the collateral token to the bank by default). One cross-margin balance covers every perp pool.

Parameters

params

DepositMarginParams

Returns

Promise<TxResult>


withdrawMargin()

withdrawMargin(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2736

Withdraw free collateral from the MarginBank (margin-checked on-chain).

Parameters

params

WithdrawMarginParams

Returns

Promise<TxResult>


withdrawVault()

withdrawVault(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2746

Claim a payout that fell back to a pool's internal ERC20Vault (a PayoutFallbackToVault credit) back to the wallet. Read the claimable amount first with client.getVaultBalance({ vault, owner, token }).

Also how funds leave a manual-mode balance — see setManualVaultMode.

Parameters

params

WithdrawVaultParams

Returns

Promise<TxResult>


depositVault()

depositVault(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2755

Pre-fund an ERC-20 balance in a pool's internal vault (approves the pool when needed). Ordinary placement needs no deposit — auto-pull covers it; deposit when funding must precede the order. Native goes in via depositVaultNative.

Parameters

params

DepositVaultParams

Returns

Promise<TxResult>


depositVaultNative()

depositVaultNative(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2771

Pre-fund a native (SOMI) vault balance for the signer, or for another account when owner is set. The amount travels as msg.value.

A binary pool's vault takes exactly one token, so the SDK reads the pool's collateralToken() first and refuses a native deposit into a pool whose collateral is not native rather than spending a failed transaction. A pool without that view (a SpotPool) goes straight to the chain.

  • Throws NotConfiguredError - the executor has no chain transport.
  • Throws InvalidInputError - amount is not positive, or the pool is a binary pool whose collateral is not native.
  • Throws RpcError - the preflight read or the deposit did not complete. A failed preflight never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - the pool rejected the deposit (InvalidDepositOrWithdrawal when native is not one of its tokens).

Parameters

params

DepositVaultNativeParams

Returns

Promise<TxResult>


depositVaultNativeFor()

depositVaultNativeFor(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2778

Pre-fund ANOTHER account's native vault balance — depositVaultNative with owner required (an operator funding a bot wallet). Same errors.

Parameters

params

DepositVaultNativeParams & object

Returns

Promise<TxResult>


setManualVaultMode()

setManualVaultMode(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2786

Opt out of (or back into) wallet auto-pull on one SpotPool. While enabled, orders draw only on pre-deposited vault balance AND payouts stay as vault credit — claim them with withdrawVault. Scoped per user per pool.

Parameters

params

SetManualVaultModeParams

Returns

Promise<TxResult>


setOperatorApprovalForPool()

setOperatorApprovalForPool(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2794

Grant or revoke an operator on ONE SpotPool — the tighter way to let a bot trade for you. The signer is the granting owner; approved: false revokes. Read it back with SomniaMarketsClient.isApprovedForPool.

Parameters

params

SetOperatorApprovalForPoolParams

Returns

Promise<TxResult>


setOperatorApprovalGlobal()

setOperatorApprovalGlobal(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2802

Grant or revoke an operator across EVERY registered pool. Required for SpotRouter (not on any pool's allowlist); prefer setOperatorApprovalForPool for a single-venue bot.

Parameters

params

SetOperatorApprovalGlobalParams

Returns

Promise<TxResult>


setPerpLeverage()

setPerpLeverage(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2807

Set the signer's max leverage for one perp pool (caps position size vs margin).

Parameters

params

SetPerpLeverageParams

Returns

Promise<TxResult>


proposePerpWalletLink(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2828

Offer a child wallet a link to the signer as its main — the first half of the handshake that gives a perp sub-account access to the signer's wallet.

Isolated margin on perps is one wallet per position, so a trader running N isolated positions runs N wallets. Linking them lets each child's position-increasing order draw its shortfall from this main's wallet, so one funded treasury serves all N.

The signer is the MAIN and this moves no money. The child must send acceptPerpWalletLink next, and it is the only party that can: read the offer from client.listPerpWalletLinkEvents({ child }), which is the ONLY record of a pending proposal.

  • Throws InvalidInputError - registry is the zero address, or none of registry, marginBank and pool was passed.
  • Throws NotConfiguredError - the executor has no chain transport, or the bank holds no registry, so the rail is dormant on this deployment.
  • Throws RpcError - the registry or bank resolution read did not complete. A failed resolution never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - CannotLinkSelf, CallerIsChild (the signer is already someone's child), AlreadyLinked (child already has a main), NoStateChange (this offer already stands), or ZeroAddress.

Parameters

params

ProposePerpWalletLinkParams

Returns

Promise<TxResult>


acceptPerpWalletLink(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2843

Accept a main's standing offer, as the child — the second half of the handshake.

From here the signer's position-increasing orders pull their shortfall from main's wallet. Funding does not wait for link maturity; maturesAt gates ADL netting only.

  • Throws InvalidInputError - registry is the zero address, or none of registry, marginBank and pool was passed.
  • Throws NotConfiguredError - the executor has no chain transport, or the bank holds no registry, so the rail is dormant on this deployment.
  • Throws RpcError - the registry or bank resolution read did not complete. A failed resolution never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - NoProposalPending, CallerIsChild (main has itself become a child), CallerIsMain (the signer already has children), AlreadyLinked, or MaxChildrenReached.

Parameters

params

AcceptPerpWalletLinkParams

Returns

Promise<TxResult>


cancelPerpWalletLinkProposal()

cancelPerpWalletLinkProposal(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2854

Withdraw an offer the signer made and the child has not accepted. An ACCEPTED link comes down with unlinkPerpWallet instead.

  • Throws InvalidInputError - registry is the zero address, or none of registry, marginBank and pool was passed.
  • Throws NotConfiguredError - the executor has no chain transport, or the bank holds no registry, so the rail is dormant on this deployment.
  • Throws RpcError - the registry or bank resolution read did not complete. A failed resolution never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - NoProposalPending (nothing pending for this pair, including an offer already accepted).

Parameters

params

CancelPerpWalletLinkProposalParams

Returns

Promise<TxResult>


unlinkPerpWallet()

unlinkPerpWallet(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2868

Dissolve an accepted link, from either end — pass the other party.

Settles no money: a claim the main funded survives the unlink and still gates the child's withdrawals. PerpsUnlinkGuard vetoes it while the leaver holds open positions and is liquidatable.

  • Throws InvalidInputError - registry is the zero address, or none of registry, marginBank and pool was passed.
  • Throws NotConfiguredError - the executor has no chain transport, or the bank holds no registry, so the rail is dormant on this deployment.
  • Throws RpcError - the registry or bank resolution read did not complete. A failed resolution never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - NotLinked (the two are not a linked pair) or UnlinkBlockedByGuard (the leaver is liquidatable with open positions).

Parameters

params

UnlinkPerpWalletParams

Returns

Promise<TxResult>


repayPerpMainFunding()

repayPerpMainFunding(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2883

Return principal the signer's main funded, as the child.

Over-asking is clamped to min(amount, outstanding, balance) rather than rejected, so the outstanding figure from client.getPerpMainFunding cannot be stale-high. Repaying is what unlocks the child's own money: withdraw frees at most balance - outstanding.

  • Throws NotConfiguredError - the executor has no chain transport.
  • Throws InvalidInputError - amount is not positive, marginBank is the zero address, or neither marginBank nor pool was passed.
  • Throws RpcError - the bank resolution read did not complete. A failed resolution never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - NoFundedPrincipal (nothing outstanding), NothingToReturn (the clamp reached zero, so the balance is gone), or InsufficientMarginAfterWithdrawal.

Parameters

params

RepayPerpMainFundingParams

Returns

Promise<TxResult>


recallPerpMainFunding()

recallPerpMainFunding(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2897

Pull principal back out of a child, as the payer. The signer must be the payer the bank recorded at funding time.

Recovers principal, never winnings, and performs no unlink — the child can be funded again without a fresh handshake.

  • Throws NotConfiguredError - the executor has no chain transport.
  • Throws InvalidInputError - amount is not positive, marginBank is the zero address, or neither marginBank nor pool was passed.
  • Throws RpcError - the bank resolution read did not complete. A failed resolution never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - OnlyFundingPayer (the signer is not the recorded payer), NoFundedPrincipal, NothingToReturn, or InsufficientMarginAfterWithdrawal.

Parameters

params

RecallPerpMainFundingParams

Returns

Promise<TxResult>


claimPerpVoucher()

claimPerpVoucher(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2936

Claim the signer's one-time credit voucher: a grant of house money into its MarginBank balance.

The grant is non-withdrawable. The signer can trade with it, and can withdraw profit above it. Read client.getPerpVoucherEligibility first: a claim that fails still mines and costs gas, because not every executor simulates before it sends.

Gotchas

A claim is once per address for the distributor's life, not once per campaign.

While the grant remains, the bank confines the account's position increases: only allowlisted markets, at no more than the voucher leverage cap, and the account cannot change its own leverage setting. Reducing a position is never blocked. Builder fees are not charged on voucher accounts.

The account can still deposit its own collateral, and an order placed with an ERC-20 allowance to the bank can pull the wallet's collateral in. Both mix with the grant in one balance.

  • Throws InvalidInputError - distributor or marginBank is the zero address, or none of distributor, marginBank and pool was passed.
  • Throws NotConfiguredError - the executor has no chain transport, or the bank holds no credit granter, so the voucher programme is off on this deployment.
  • Throws RpcError - the distributor or bank resolution read did not complete. A failed resolution never broadcasts.
  • Throws TransactionOutcomeUnknownError - the transaction may have reached the node and its receipt was not observed. Look up hash before sending again.
  • Throws ContractRevertError - a pool or bank resolution read reverted (for example, pool is not a PerpPool or marginBank is not a MarginBank), and nothing was broadcast; or claim() reverted: CampaignInactive (outside the claim window), AlreadyClaimed, BudgetExhausted, ClaimantNotFlat (the signer holds a position or resting order), or ClaimantIsMainFunded (the signer carries principal from a linked main). The SDK's bundled error table does not name the last two yet, so they arrive with raw data and no errorName; client.getPerpVoucherEligibility reports them by name. Branch on functionName to tell a resolution revert (marginBank, getCreditGranter) from a claim revert (claim).

Parameters

params

ClaimPerpVoucherParams

Returns

Promise<TxResult>

Example

Checking eligibility, then claiming

ts
const eligibility = await markets.client.getPerpVoucherEligibility(marginBank, account);
if (eligibility.eligible) {
  await markets.trader.claimPerpVoucher({ marginBank });
} else if (eligibility.reason === "notFlat") {
  // Close every position and cancel every resting perp order first.
}

pokeFunding()

pokeFunding(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2938

Permissionlessly poke a perp pool's funding settlement (updateFunding).

Parameters

params
pool

`0x${string}`

gas?

bigint

Returns

Promise<TxResult>


placeSpotStopOrder()

placeSpotStopOrder(params): Promise<PlaceStopOrderResult>

Defined in: packages/sdk/src/trade.ts:2945

Place a spot stop-loss / take-profit pending order on a SpotStopOrderRegistry (funds the trigger via SOMI msg.value).

Parameters

params

PlaceSpotStopOrderParams

Returns

Promise<PlaceStopOrderResult>


cancelStopOrder()

cancelStopOrder(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2950

Cancel a pending stop order on its registry.

Parameters

params

CancelStopOrderParams

Returns

Promise<TxResult>


placePerpStopOrder()

placePerpStopOrder(params): Promise<PlacePerpStopOrderResult>

Defined in: packages/sdk/src/trade.ts:2963

Place a perp take-profit / stop-loss on a PerpStopOrderRegistry (funds the trigger via SOMI msg.value), granting the registry's one-time operator approval first if the signer has not already.

The single perp-stop create entry: pass pair for a linked one-cancels-other set, or intent: "opening" for a stop-entry. Both default off, so an existing call is an ordinary reduce-only stop and produces the same transaction it always did.

Parameters

params

PlacePerpStopOrderParams

Returns

Promise<PlacePerpStopOrderResult>


linkPerpStopOrders()

linkPerpStopOrders(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2970

Link two existing perp stops into a one-cancels-other pair — the after-the-fact form of placePerpStopOrder({ pair }), and how a survivor is re-paired.

Parameters

params

LinkPerpStopOrdersParams

Returns

Promise<TxResult>


cancelPerpStopOrder()

cancelPerpStopOrder(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2977

Cancel a pending perp stop. If it is one leg of a pair the other stays armed and is unlinked — use cancelPerpStopOrders to tear down both.

Parameters

params

CancelStopOrderParams

Returns

Promise<TxResult>


cancelPerpStopOrders()

cancelPerpStopOrders(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2982

Cancel several of the signer's pending perp stops in one tx, one refund transfer.

Parameters

params

CancelPerpStopOrdersParams

Returns

Promise<TxResult>


claimPerpStopSomi()

claimPerpStopSomi(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:2989

Claim SOMI the perp stop registry owes the signer — the refund path for an owner that cannot receive native. Reverts NothingToClaim on a zero balance.

Parameters

params

ClaimPerpStopSomiParams

Returns

Promise<TxResult>


buildPlacePerpStopOrder()

buildPlacePerpStopOrder(params): Promise<UnsignedPerpStopOrder>

Defined in: packages/sdk/src/trade.ts:3009

Build placePerpStopOrder without sending it — the stop-registry call plus, unless skipped, the operator grant the trigger needs first.

Recover the created ids from your own receipt with decodePerpStopOrderIds.

Parameters

params

PlacePerpStopOrderParams

Returns

Promise<UnsignedPerpStopOrder>


buildCancelOrders()

buildCancelOrders(params): UnsignedCall

Defined in: packages/sdk/src/trade.ts:3016

Build cancelOrders without sending it — so a ladder pull can ride in the same transaction as the replacement quotes.

Parameters

params

CancelOrdersParams

Returns

UnsignedCall


buildReduceOrders()

buildReduceOrders(params): UnsignedCall

Defined in: packages/sdk/src/trade.ts:3022

Build reduceOrders without sending it.

Parameters

params

ReduceOrdersParams

Returns

UnsignedCall


buildCancelPerpStopOrder()

buildCancelPerpStopOrder(params): UnsignedCall

Defined in: packages/sdk/src/trade.ts:3024

Build cancelPerpStopOrder without sending it.

Parameters

params

CancelStopOrderParams

Returns

UnsignedCall


buildCancelPerpStopOrders()

buildCancelPerpStopOrders(params): UnsignedCall

Defined in: packages/sdk/src/trade.ts:3026

Build cancelPerpStopOrders without sending it.

Parameters

params

CancelPerpStopOrdersParams

Returns

UnsignedCall


buildDepositMargin()

buildDepositMargin(params): Promise<UnsignedMarginDeposit>

Defined in: packages/sdk/src/trade.ts:3031

Build depositMargin without sending it — the deposit call plus, unless autoApprove: false, the ERC-20 approval the bank needs first.

Parameters

params

DepositMarginParams

Returns

Promise<UnsignedMarginDeposit>


buildWithdrawMargin()

buildWithdrawMargin(params): Promise<UnsignedCall>

Defined in: packages/sdk/src/trade.ts:3033

Build withdrawMargin without sending it. Nothing to approve.

Parameters

params

WithdrawMarginParams

Returns

Promise<UnsignedCall>


buildAcceptPerpWalletLink(params): Promise<UnsignedCall>

Defined in: packages/sdk/src/trade.ts:3043

Build acceptPerpWalletLink without sending it, so the accept and the child's first isolated placement go out as ONE transaction. The accept must execute first, or the placement finds no main.

  • Throws InvalidInputError - registry is the zero address, or none of registry, marginBank and pool was passed.
  • Throws NotConfiguredError - the bank holds no registry, so the rail is dormant on this deployment.
  • Throws RpcError - the registry or bank resolution read did not complete. A failed resolution never broadcasts.

Parameters

params

AcceptPerpWalletLinkParams

Returns

Promise<UnsignedCall>


buildRepayPerpMainFunding()

buildRepayPerpMainFunding(params): Promise<UnsignedCall>

Defined in: packages/sdk/src/trade.ts:3052

Build repayPerpMainFunding without sending it, so the repayment and the withdrawal it unlocks go out as ONE transaction. The repayment must execute first — the withdrawal's gate reads the claim it clears.

  • Throws InvalidInputError - amount is not positive, marginBank is the zero address, or neither marginBank nor pool was passed.
  • Throws RpcError - the bank resolution read did not complete.

Parameters

params

RepayPerpMainFundingParams

Returns

Promise<UnsignedCall>


buildClaimPerpVoucher()

buildClaimPerpVoucher(params): Promise<UnsignedCall>

Defined in: packages/sdk/src/trade.ts:3064

Build claimPerpVoucher without sending it, so the claim and the first order go out as ONE transaction. The claim must execute first. Otherwise the order finds no grant, and with an ERC-20 allowance to the bank it pulls the wallet's own collateral instead.

  • Throws InvalidInputError - distributor or marginBank is the zero address, or none of distributor, marginBank and pool was passed.
  • Throws NotConfiguredError - the bank holds no credit granter, so the voucher programme is off on this deployment.
  • Throws RpcError - the distributor or bank resolution read did not complete.
  • Throws ContractRevertError - a resolution read reverted, for example because marginBank is not a MarginBank.

Parameters

params

ClaimPerpVoucherParams

Returns

Promise<UnsignedCall>


mintSet()

mintSet(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3070

Mint a YES+NO set: deposit collateral, receive equal YES + NO.

Parameters

params

MintSetParams

Returns

Promise<TxResult>


burnSet()

burnSet(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3075

Burn a YES+NO set: surrender both halves, receive collateral back.

Parameters

params

BurnSetParams

Returns

Promise<TxResult>


redeem()

redeem(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3084

Burn winning outcome tokens for collateral (resolved/voided markets). Settlement-extraction v2: module-routed — the module pulls the caller's winning tokens, finalizes-if-needed, and redeems through BinarySettlement. Takes marketId (not a pool address — a pool serves successive markets).

Parameters

params

RedeemParams

Returns

Promise<TxResult>


signRedeemAuth()

signRedeemAuth(params): Promise<RedeemAuthorization>

Defined in: packages/sdk/src/trade.ts:3102

Produce an EIP-712 RedeemAuthorization the connected signer (the position owner) hands to a relayer, so the relayer can call Trader.redeemFor and pay the gas while the OWNER receives the payout. Signs over the module's REDEEM_AUTH_TYPEHASH in the SomniaMarkets domain; no transaction is sent.

  • Throws NotConfiguredError - no BinaryMarketsModule address is configured and none was passed.
  • Throws SignerRequiredError - this trader's executor cannot sign typed data as the actor: a safe or a session key (executor.signTypedData is absent). A private key or a wallet can.
  • Throws RpcError - the signer failed or refused (a wallet rejection, a custom signer's own error), preserved as cause.

The complete union is TraderSignRedeemAuthError.

Parameters

params

SignRedeemAuthParams

Returns

Promise<RedeemAuthorization>


redeemFor()

redeemFor(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3110

Relayer path: submit a position owner's pre-signed RedeemAuthorization (from Trader.signRedeemAuth). The caller pays gas; the module pays the OWNER the collateral (payout is hard-pinned to owner, never the relayer).

Parameters

params

RedeemForParams

Returns

Promise<TxResult>


redeemMany()

redeemMany(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3115

Claim winnings from many settled markets in one transaction (batch redeem).

Parameters

params

RedeemManyParams

Returns

Promise<TxResult>


redeemDirect()

redeemDirect(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3122

Low-level direct redemption against the BinarySettlement singleton (bypasses the module; no operator attribution). Takes the raw ERC-6909 outcomeId.

Parameters

params

RedeemDirectParams

Returns

Promise<TxResult>


claimOwed()

claimOwed(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3127

Claim an accrued push-fallback (owed) balance on the settlement singleton.

Parameters

params

ClaimOwedParams

Returns

Promise<TxResult>


pokeOracle()

pokeOracle(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3151

Permissionless oracle retry — the FIRST move when a market is past expiry with no resolution: ask the module to re-pull the answer for its oracle question.

When to use

Use before Trader.voidExpired. A poke that succeeds resolves the market normally (winners paid in full); voiding pays everyone 1/N instead, so it is the fallback, not the first resort.

Gotchas

Keyed by ORACLE QUESTION, not market: the module fans out to every market bound to that question and resolves the ones whose adapter answers. Unanswered adapters are skipped, so this can resolve some markets and leave others — a success is not "all bound markets resolved". Reverts OracleNotAnswered only when none answered, UnknownOracleQuestion when no market is bound; both decode as ContractRevertError, so a keeper loop can branch on errorName.

Parameters

params

PokeOracleParams

Returns

Promise<TxResult>


voidExpired()

voidExpired(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3179

Permissionless dead-oracle escape hatch: void a market whose oracle never answered, so both sides can redeem at 1/N collateral.

When to use

Use only after Trader.pokeOracle has failed and expiry + settlementWindow has elapsed — this is the funds-unstranding backstop, and it pays 1/N rather than the real outcome.

Gotchas

This writes to the MARKET contract, bypassing the module — so the oracle hub's earmark release never fires. Follow with Trader.syncSettlement, then Trader.finalizeMarket and Trader.releasePool, to leave the market fully reconciled.

Before sending, this reads the market's status, expiry, and settlement window and throws InvalidInputError naming the gate time if the window is still open — the on-chain SettlementWindowOpen revert carries no timestamp, and "when can I retry" is the operator's real question. The comparison uses the chain's block.timestamp, matching the contract, so a skewed local clock neither lets a doomed call through nor blocks a valid one. Pass skipPreflight to send blind and let the contract judge.

Parameters

params

VoidExpiredParams

Returns

Promise<TxResult>


finalizeMarket()

finalizeMarket(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3186

Permissionless keeper: finalize a settled market (sweep its pool's backing + resolution snapshot to the settlement singleton). No-op-guarded on repeat.

Parameters

params

FinalizeMarketParams

Returns

Promise<TxResult>


syncSettlement()

syncSettlement(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3194

Permissionless earmark reconcile: release the oracle earmark of a market voided via BinaryMarket.voidExpired() (which bypasses the module, so the hub's earmark release never fired). Idempotent; reverts MarketNotSettled while still live.

Parameters

params

SyncSettlementParams

Returns

Promise<TxResult>


releasePool()

releasePool(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3201

Permissionless keeper: release a finalized, drained pool back to its creator's free list for recycle onto the next market.

Parameters

params

ReleasePoolParams

Returns

Promise<TxResult>


getSettlement()

getSettlement(marketId, opts?): Promise<SettlementRecord | null>

Defined in: packages/sdk/src/trade.ts:3207

Read a market's settlement record from the BinarySettlement singleton (by bytes32 marketId — resolves the marketKey via the module's yesId). Returns null when the market has never been finalized.

Parameters

marketId

`0x${string}`

opts?
module?

`0x${string}`

settlement?

`0x${string}`

Returns

Promise<SettlementRecord | null>


getFreePools()

getFreePools(creator, collateral, opts?): Promise<`0x${string}`[]>

Defined in: packages/sdk/src/trade.ts:3209

Read a creator's free (finalized + released, reusable) pools for a collateral.

Parameters

creator

`0x${string}`

collateral

`0x${string}`

opts?
module?

`0x${string}`

Returns

Promise<`0x${string}`[]>


poolCreator()

poolCreator(pool, opts?): Promise<`0x${string}`>

Defined in: packages/sdk/src/trade.ts:3214

Read a pool's creator (its first-deploy creator — the only party that can reuse it).

Parameters

pool

`0x${string}`

opts?
module?

`0x${string}`

Returns

Promise<`0x${string}`>


mintSetNative()

mintSetNative(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3221

Mint a complete YES+NO set paying with NATIVE token via the CollateralRouter (wraps msg.value → wNative). The market's collateral must be wNative.

Parameters

params

MintSetNativeParams

Returns

Promise<TxResult>


mintSetPermit2()

mintSetPermit2(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3228

Mint a complete YES+NO set pulling collateral via a Permit2 signature through the CollateralRouter (no prior ERC-20 approve).

Parameters

params

MintSetPermit2Params

Returns

Promise<TxResult>


redeemNative()

redeemNative(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3235

Redeem winning outcome tokens for a NATIVE payout via the CollateralRouter (unwraps wNative → native). Approve the router for the winning outcome first.

Parameters

params

RedeemNativeParams

Returns

Promise<TxResult>


faucet()

faucet(params?): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3240

Mint TestUSDC from the faucet to the signer.

Parameters

params?

FaucetParams

Returns

Promise<TxResult>


resolve()

resolve(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3245

Resolve a market via the FakeOracle (demo resolver).

Parameters

params

ResolveParams

Returns

Promise<TxResult>


voidMarket()

voidMarket(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3250

Void a market via the FakeOracle (demo resolver).

Parameters

params

VoidMarketParams

Returns

Promise<TxResult>


poke()

poke(params): Promise<TxResult>

Defined in: packages/sdk/src/trade.ts:3252

Poke a market to advance its lifecycle. No-op since status is derived; kept for ABI stability.

Parameters

params
market

`0x${string}`

gas?

bigint

Returns

Promise<TxResult>


clearApprovalCache()

clearApprovalCache(token?, spender?): void

Defined in: packages/sdk/src/trade.ts:3258

Forget cached token approvals so the next escrowing write re-checks allowance. Pass a (token, spender) to clear one pair, or nothing to clear all. Rarely needed — maxUint256 approvals don't decrement.

Parameters

token?

`0x${string}`

spender?

`0x${string}`

Returns

void