import type { Address, PublicClient } from "viem"; import type { OpenOrder, BookTop } from "../orders.js"; import type { FillRow } from "../fills.js"; import type { RouterActionRecord } from "../router.js"; import { type BinaryPositionPnL } from "../derivedReads.js"; import type { BinaryMarketStatus } from "../store.js"; /** * A user's indexed YES/NO outcome-token balances in one binary market. Raw * outcome-token units (same decimals as the market's collateral); "0" when the * indexer has never seen the account touch that side. * * @category binary markets */ export type OutcomeBalances = { /** Raw YES balance ("0" if never held). */ yes: string; /** Raw NO balance ("0" if never held). */ no: string; }; /** * YES + NO indexed balances for a user in a binary market (0 if the indexer * hasn't seen them). Throws if the indexer request fails. */ export declare function getOutcomeBalances(account: string, marketAddress: string, indexerUrl: string): Promise; /** * A market context attached to portfolio rows (subset of {@link BinaryMarket}). * * @category binary markets */ export type PortfolioMarket = { /** * The market's bytes32 marketId (== `BinaryMarket.id`). Key positions by this, * never by `poolAddress` alone (a pool is recycled across markets). */ id: string; /** The BinaryMarket clone contract's address (lowercased). */ marketAddress: string; /** The pool serving the market (lowercased; a time-varying binding — see `id`). */ poolAddress: string; /** Underlying asset symbol (e.g. "BTC"). */ asset: string; /** Display question text. */ question: string; /** Lifecycle status (aliased from the indexer's `clobStatus`). */ status: BinaryMarketStatus; /** Last fill price (raw, ≈ YES probability × 10^quoteDecimals); null until first fill. */ lastPrice: string | null; /** Strike the question resolves against (raw, oracle price scale). */ strike: string; /** Timestamp (unix seconds) trading ends. */ expiry: string; /** Winning outcome (0 = YES, 1 = NO); null until Resolved / on a void. */ winningOutcome?: number | null; /** * True once the market voided. A void redeems against * {@link PortfolioMarket.payoutNumerators} — a half per side under the * `UNIFORM` void policy, `[p, D−p]` on a `CLOB_SNAPSHOT` void that captured * a two-sided close. */ voided: boolean; /** * Per-outcome payout numerators the market settled to (decimal strings); * what a void actually pays. Null until Resolved / on markets indexed before * the vector fields existed. */ payoutNumerators?: string[] | null; /** Denominator the numerators are scaled against (decimal string); null with them. */ payoutDenominator?: string | null; /** * Collateral decimals (per-market — collateral is per-venue, e.g. 6dp * TestUSDC vs 18dp USDso). Format prices/balances with this, never a * hard-coded 6. Outcome-token amounts mirror the same decimals. */ quoteDecimals: number; /** Series cadence in seconds, as the indexer derived it; null on legacy rows. */ intervalSec: string | null; /** * Compact series-cadence label ("15m" / "1h" / "4h" / "24h") — DERIVED by the * SDK from {@link PortfolioMarket.intervalSec}, so a positions/orders row can * show the contract duration without re-deriving it. `null` when unknown. */ interval: string | null; }; /** * One outcome-token position in a wallet's binary portfolio. * * @category binary markets */ export type PortfolioPosition = { /** The market the position is in. */ market: PortfolioMarket; /** 0 = YES, 1 = NO. */ outcomeIndex: number; /** ERC-6909 position id on the outcome-token singleton (decimal string). */ tokenId: string; /** Raw outcome-token balance. */ balance: string; }; /** * An open binary position joined with its reliable avg-cost PnL — the batched, * positions-list companion to `getBinaryPositionPnL` (which is per market). * `costBasis` / `avgCost` / `markValue` / `unrealizedPnl` / `realizedPnl` are * RAW collateral units; format with `market.quoteDecimals`. * * Those fields are BLENDED across both outcomes; the inherited `outcomes` pair * carries each book on its own. * * @category binary markets */ export type OpenPositionPnL = BinaryPositionPnL & { /** The market the position is in (id / addresses / quoteDecimals / status / …). */ market: PortfolioMarket; }; /** * Pure fold: group an account's open positions + its fills + router actions + * per-market top-of-book into one {@link OpenPositionPnL} per market, reusing the * same avg-cost engine ({@link pnlEventsFor} + {@link computePositionPnL}) as the * per-market `getBinaryPositionPnL`. Fills, router actions and balances all group * by MARKET ID — a binary pool is recycled across successive markets, so the pool * address does not identify which market a fill belongs to. No I/O — the client * method fetches the inputs (batched) and hands them here, which keeps this * unit-testable. */ export declare function computeOpenPositionsPnL(account: string, positions: PortfolioPosition[], fills: FillRow[], routerActions: RouterActionRecord[], bookTops: Record): OpenPositionPnL[]; /** * One currently-open order in a wallet's binary portfolio. * * @category binary markets */ export type PortfolioOrder = { /** Order id (`${pool}_${orderId}`). */ id: string; /** uint128 OrderId as a decimal string (pass to trader.cancelOrder). */ orderId: string; /** YES/NO classification of the order. */ side: OpenOrder["side"]; /** Limit price, raw quote units (YES-probability scale). */ price: string; /** Unfilled remainder, raw outcome units. */ quantityRemaining: string; /** Cumulative filled quantity, raw outcome units. */ filledQuantity: string; /** Original order size, raw outcome units. */ fullQuantity: string; /** Timestamp (unix seconds) the order was placed. */ placedAtTimestamp: string; /** Tx hash the order was placed in. */ placedTxHash: string; /** The market the order rests on. */ market: PortfolioMarket; }; /** * One recent fill the wallet participated in (binary portfolio view). * * @category binary markets */ export type PortfolioTrade = { /** Fill id (`${blockNumber}_${logIndex}`). */ id: string; /** Execution price, raw quote units (YES-probability scale). */ fillPrice: string; /** Outcome-token quantity filled, raw units. */ quantity: string; /** Timestamp (unix seconds) of the fill. */ timestamp: string; /** Tx hash the fill landed in. */ txHash: string; /** The queried account's side on this fill (maker or taker side), if known. */ side: OpenOrder["side"] | null; /** Whether the account was the maker (resting) on this fill. */ asMaker: boolean; /** The other party's address, if known. */ counterparty: string | null; /** Minimal market context for rendering the trade row. */ market: { /** The BinaryMarket clone contract's address (lowercased). */ marketAddress: string; /** Underlying asset symbol (e.g. "BTC"). */ asset: string; /** Collateral decimals — format `fillPrice`/`quantity` with this. */ quoteDecimals: number; /** Series cadence in seconds, as the indexer derived it; null on legacy rows. */ intervalSec: string | null; /** * Human timeframe label — `"15m"` / `"1h"` / `"4h"` / `"24h"` — DERIVED by * the SDK from `intervalSec` (falling back to `expiry − tradingStart`) and * snapped to its canonical unit. The "which timeframe was the trade for" * value. Null when no cadence is determinable. */ interval: string | null; /** Unix seconds trading opened; null on legacy rows. */ tradingStart: string | null; /** Unix seconds trading ends / the outcome is decided; null on legacy rows. */ expiry: string | null; }; }; /** * A wallet's binary portfolio — the shape {@link SomniaMarketsClient.getPortfolio} returns. * * @category binary markets */ export type Portfolio = { /** The queried account (lowercased). */ account: string; /** Non-zero outcome-token positions (up to 200, largest balance first). */ positions: PortfolioPosition[]; /** Currently-open binary orders, newest first. */ openOrders: PortfolioOrder[]; /** Recent binary fills the account participated in, newest first. */ trades: PortfolioTrade[]; /** * The read hit its `tradesLimit`, so fills older than the last entry in `trades` exist * and were NOT returned. Raise `tradesLimit` for the rest. * A total folded from a truncated `trades` covers part of the history only. * False when the page was short, and false for `tradesLimit: 0`, which asks for * no trades at all. */ tradesTruncated: boolean; /** * The lower time bound the trades leg was read with, unix seconds — `since` when * passed, otherwise now minus seven days (`DEFAULT_TRADES_SINCE_SEC`). Echoed so a UI can * label the list and a caller can page further back. Positions and orders are not windowed. */ tradesSince: number; }; /** * Default `tradesLimit` for every portfolio read. Shared so the returned * `tradesTruncated` flag cannot disagree with the limit that was used. */ export declare const DEFAULT_TRADES_LIMIT = 50; /** * Paging/window options shared by the portfolio queries * ({@link SomniaMarketsClient.getPortfolio} / {@link SomniaMarketsClient.getSpotPortfolio} / {@link SomniaMarketsClient.getPerpPortfolio}). * All optional. * * @category binary markets */ export type PortfolioOptions = { /** * Max open orders to fetch (default 200). * * On SPOT this ALSO bounds `pendingStopOrders`: the spot query binds one * limit variable to both sets, so a small value here shortens the stop-order * list too, not just the open orders you asked about. */ ordersLimit?: number; /** * Max recent trades to fetch (default 50). * * The reads page newest-first, so this cap drops the OLDEST fills. Check * `tradesTruncated` on the returned portfolio to see whether it did: the flag is * true when `trades.length` reaches this limit. */ tradesLimit?: number; /** * Only trades at/after this unix-seconds timestamp. Defaults to now minus seven * days (`DEFAULT_TRADES_SINCE_SEC`) — see that constant for why a bound is always * applied. The bound actually used comes back as `tradesSince`. */ since?: number; }; /** * Everything needed to render a wallet's binary portfolio: outcome-token * positions (non-zero balances), currently-open orders, and recent fills the * account participated in — matched on the indexed `maker` and `taker` columns. * One round-trip once the registry is warm. The type scope is resolved from a * memoized pool set (a minute's TTL per indexer), so a cold call sends that * look-up first — one extra request for SPOT and PERP, two for BINARY, which is * the complement of both. Throws on indexer failure. * * The taker seat used to be matched through the takerOrder relationship, on the * belief that `taker` was not denormalized onto a binary Fill. The indexer * stamps it for every pool type inside the fill's own transaction — see the * `participatedAs` note in `fills.ts` — so the join predicate selected exactly * the same rows while forcing a correlated `EXISTS` per row scanned. On the * development indexer that cost this read ~4.5s for a light wallet against * ~30ms. The takerOrder FIELDS are still selected: `side` and `owner` are what * a taker-seat row reads for its own side and its counterparty. */ export declare function getPortfolio(account: string, opts: PortfolioOptions | undefined, indexerUrl: string): Promise; /** * Identifies one owner's claimable balance in one pool vault — see {@link SomniaMarketsClient.getVaultBalance | client.getVaultBalance}. * * @category binary markets */ export interface GetVaultBalanceParams { /** The ERC20Vault address (the pool address). */ vault: Address; /** The balance's owner. */ owner: Address; /** The ERC-20 address (or the vault's native sentinel). */ token: Address; } /** * LIVE claimable balance an owner can withdraw from an ERC20Vault (a pool's * internal vault) for `token`, raw units — the current value behind the * append-only `VaultPayoutFallback` history. */ export declare function getVaultBalance(p: GetVaultBalanceParams, client: PublicClient): Promise; /** * Identifies one ERC-6909 outcome position — see `getOutcomeBalance`. * * @category binary markets */ export interface GetOutcomeBalanceParams { /** The outcome-token singleton address (from `MarketOnchain`). */ outcomeToken: Address; /** The balance's owner. */ account: Address; /** The position id — the market's `yesId`/`noId`. */ id: bigint; } /** * ERC-6909 outcome-token balance of `account` for position `id` on the shared * outcome-token singleton (raw). */ export declare function getOutcomeBalance(p: GetOutcomeBalanceParams, client: PublicClient): Promise; /** * A vault-credit fallback record (mirror of the indexer `VaultPayoutFallback` * entity) — an append-only history of payouts that could not be delivered to * the wallet and were credited to the owner's ERC20Vault balance instead. This * is the HISTORY layer; for the live claimable amount read * {@link SomniaMarketsClient.getVaultBalance | client.getVaultBalance}. Amounts are raw token units. * * @category binary markets */ export type VaultPayoutFallback = { /** Record id (`${blockNumber}_${logIndex}`). */ id: string; /** Credited owner (lowercased). */ owner: string; /** Credited token (lowercased). */ token: string; /** Amount credited to the vault balance (raw token units). */ amount: string; /** Market id the fallback was emitted for (lowercased). */ market: string; /** Timestamp (unix seconds) of the credit. */ timestamp: string; /** Tx hash the credit landed in. */ txHash: string; }; /** * An owner's vault-credit fallback history, newest first — optionally scoped to * one token, paginated. The live claimable balance is a chain read * ({@link SomniaMarketsClient.getVaultBalance | client.getVaultBalance}); this is the append-only credit log. */ export declare function getVaultPayoutFallbacks(owner: string, opts: { token?: string; limit?: number; offset?: number; } | undefined, indexerUrl: string): Promise;