import { Address, Hex } from 'viem'; declare enum OrderType$1 { Market = "market", Limit = "limit", Stop = "stop" } declare enum CancelOrderType { Limit = "limit", PendingOpen = "pendingOpen", PendingClose = "pendingClose" } interface OpenTradeParams { /** * Trading pair id — same value as `Pair.pairId` returned by `getPairs()`. * Accepts both the numeric string (e.g. `"0"`) and a plain `number`. */ pairId: string | number; /** true = long, false = short. */ buy: boolean; /** Entry price as a decimal string (e.g. "65000.50"). */ price: string; /** Collateral in USD as a decimal string (e.g. "100.00"). Fixed minimum is `MIN_OPEN_SIZE_USD` ($5). */ collateral: string; /** Leverage as a decimal string (e.g. "10" for 10×). Contract-side limits apply. */ leverage: string; /** Order type. */ type: OrderType$1; /** Take profit price as a decimal string. Optional. */ takeProfit?: string; /** Stop loss price as a decimal string. Optional. */ stopLoss?: string; /** Per-trade slippage override in basis points. Overrides client default. */ slippage?: number; /** * Mark the trade as a day trade. Must be `true` when the desired leverage * exceeds `pair.overnightMaxLeverage` (and `overnightMaxLeverage > 0`). * Day trades are automatically closed before market close if not manually * closed beforehand. Defaults to `false`. */ isDayTrade?: boolean; /** * Per-trade builder fee override. Each field falls back to the client-level * `builder` config when omitted. Pass `feeBps: 0` to open without a builder fee. */ builder?: { address?: Address; feeBps?: number; }; } interface CloseTradeParams { /** * Trading pair id — same value as `Position.pairId` returned by `getOpenPositions`. * Accepts both the numeric string (e.g. `"0"`) and a plain `number` for ergonomics. */ pairId: string | number; /** * Position index within the pair — same value as `Position.idx` returned by * `getOpenPositions`. Identifies which of the trader's open positions to close. */ idx: number; /** Current market price as a decimal string. */ price: string; /** Percentage to close (1–100). */ closePercent: number; /** Per-trade slippage override in basis points. */ slippage?: number; /** * When true, verifies USDC allowance covers the oracle fee before submitting. * Skip by default if you know allowance is sufficient. */ checkAllowance?: boolean; } /** * Cancel a pending limit order. */ interface CancelLimitOrderParams { type: CancelOrderType.Limit; /** * Trading pair id — same value as `OpenOrder.pairId` returned by `getOpenOrders`. * Accepts both the numeric string (e.g. `"0"`) and a plain `number`. */ pairId: string | number; /** * Limit order index within the pair — same value as `OpenOrder.idx` returned * by `getOpenOrders`. Identifies which limit order to cancel. */ idx: number; } /** * Cancel a timed-out market open order. */ interface CancelPendingOpenParams { type: CancelOrderType.PendingOpen; /** Market order ID from the original openTrade submission. */ orderId: number; } /** * Cancel a timed-out market close order. */ interface CancelPendingCloseParams { type: CancelOrderType.PendingClose; /** Market order ID from the original closeTrade submission. */ orderId: number; /** * If true, re-submits the close order after cancelling the timed-out one. * Defaults to false (cancel only, trade remains open). */ retry?: boolean; } type CancelOrderParams = CancelLimitOrderParams | CancelPendingOpenParams | CancelPendingCloseParams; interface ModifyOrderParams { /** * Trading pair id. * - Updating TP/SL on an open position → use `Position.pairId` from `getOpenPositions`. * - Updating a limit order's trigger price → use `OpenOrder.pairId` from `getOpenOrders`. * Accepts both the numeric string (e.g. `"0"`) and a plain `number`. */ pairId: string | number; /** * Slot index within the pair. * - Updating TP/SL on an open position → use `Position.idx`. * - Updating a limit order → use `OpenOrder.idx`. */ idx: number; /** New limit-order trigger price. Required when modifying a limit order's price. */ price?: string; /** New take profit price. */ takeProfit?: string; /** New stop loss price. */ stopLoss?: string; } interface UpdateCollateralParams { /** * Trading pair id — same value as `Position.pairId` returned by `getOpenPositions`. * Accepts both the numeric string (e.g. `"0"`) and a plain `number`. */ pairId: string | number; /** * Position index within the pair — same value as `Position.idx` returned by * `getOpenPositions`. Identifies which position to top up or partially withdraw from. */ idx: number; /** * Amount in USD as a decimal string. * Positive → add collateral (topUpCollateral). * Negative → remove collateral (removeCollateral). */ amount: string; } interface Balances { /** USDC balance as a decimal string (e.g. `"1234.567890"`). */ usdc: string; /** ETH balance as a decimal string (e.g. `"0.001234567890123456789"`). */ eth: string; /** USDC allowance granted to the TradingStorage contract as a decimal string. Max approval is preserved exactly. */ allowance: string; } interface AllowanceStatus { /** Current USDC allowance (6 decimals, raw bigint). */ current: bigint; /** Required USDC allowance (6 decimals, raw bigint). */ required: bigint; /** true if current >= required. */ sufficient: boolean; } interface SubmissionResult { txHash: Hex; /** Set for gasless submissions — the Safe smart account address that sent the UserOp. */ smartAccountAddress?: Address; } interface BuiltSafeTxCall { to: Address; data: Hex; value: bigint; } interface BuiltEoaTxRequest { kind: 'eoa'; to: Address; data: Hex; value: bigint; from: Address; traderAddress: Address; } interface BuiltSafeTxRequest { kind: 'safe'; safeAddress: Address; traderAddress: Address; calls: [BuiltSafeTxCall]; } type BuiltTxRequest = BuiltEoaTxRequest | BuiltSafeTxRequest; /** A single outstanding onboarding step, with the transaction that clears it. */ interface OnboardingStep { kind: 'approveUsdc' | 'setDelegate' | 'setupGaslessDelegation'; /** Human-readable description of what this step does. */ description: string; /** * The transaction to submit. Always sent from the trader's own account — * a delegate cannot approve USDC or register itself on the trader's behalf. */ tx: BuiltTxRequest; } /** * What still stands between a trader and their first trade. * * ```ts * const status = await client.getOnboardingStatus(); * if (!status.ready) { * for (const step of status.steps) { * console.log(step.description); // render a checklist * await wallet.sendTransaction(step.tx); * } * } * ``` */ interface OnboardingStatus { /** `true` when nothing is outstanding and the trader can actually open a position. */ ready: boolean; /** USDC allowance to TradingStorage is below `requiredUsd`. */ needsApproval: boolean; /** * USDC balance is below `requiredUsd`. No transaction can fix this — the * trader has to fund the account — so it produces no step, but it does keep * `ready` false. */ needsFunding: boolean; /** No delegate registered, or a different one than this client expects. */ needsDelegate: boolean; /** Self + Gasless only — the smart account has not been authorised yet. */ needsGaslessSetup: boolean; /** Outstanding steps, in the order they should be submitted. */ steps: OnboardingStep[]; /** Current USDC allowance to TradingStorage, as a decimal string. */ allowance: string; /** Trader's USDC balance, as a decimal string. */ usdcBalance: string; /** Trader's ETH balance, as a decimal string. Needed for gas in self-submit modes. */ ethBalance: string; /** Delegate currently registered on-chain, or `undefined` when none is set. */ currentDelegate?: Address; } type ClientMode = 'self-self' | 'self-gasless' | 'delegated-self' | 'delegated-gasless'; /** Shared optional settings available in every mode. */ interface CommonParams { /** Use Arbitrum Sepolia testnet. Defaults to false (mainnet). */ testnet?: boolean; /** Default slippage tolerance in basis points (e.g. 25 = 0.25%). Defaults to 25. */ slippageBps?: number; /** * Optional builder fee sharing. * `feeBps` in basis points (e.g. 10 = 10 bps / 0.1%, 2.55 = 2.55 bps). Max 50 (0.5%), step 0.01 bps. */ builder?: { address: Address; feeBps: number; }; /** * Override the Ostium subgraph endpoint used by built-in read methods * (`getPairs`, `getOpenPositions`, etc.). Defaults to the mainnet or testnet * subgraph based on `testnet`. */ subgraphUrl?: string; /** * Override the builder API base URL used for live prices, OHLC candles, and * the WebSocket stream. Defaults to `https://builder.prod.bedrock.ostium.io`. */ builderApiUrl?: string; /** * Alchemy API key used by account confirmation streams for Arbitrum contract * log overlays. Can be overridden per `streamAccountUpdates()` call. */ alchemyApiKey?: string; } interface SelfSelfSubmitParams extends CommonParams { /** Private key of the trader's EOA. This account holds USDC, owns all positions, and pays gas. */ traderPrivateKey: Hex; /** Arbitrum One (or Sepolia) RPC URL. */ rpcUrl: string; } interface SelfSelfBuildParams extends CommonParams { /** Trader EOA address. Used to build unsigned transactions without SDK submission. */ traderAddress: Address; /** Optional Arbitrum RPC URL for reads/simulation. Defaults to the chain public RPC. */ rpcUrl?: string; } /** * **Self + Self** — simplest mode. * * Your EOA is the trader: it holds USDC, owns all positions, and pays gas * for every transaction directly. */ type SelfSelfParams = SelfSelfSubmitParams | SelfSelfBuildParams; interface SelfGaslessSubmitParams extends CommonParams { /** Private key of the trader's EOA. This account holds USDC and owns all positions. A Safe is derived from this key to relay trades gaslessly. */ traderPrivateKey: Hex; /** * Known smart-account address for this key (from a previous client's * `getSmartAccountAddress()`). Skips the on-chain derivation call, making * construction network-free. The address is deterministic per key + chain. */ safeAddress?: Address; /** * ERC-4337 bundler/paymaster RPC URL. Defaults to Ostium's boost sponsorship * endpoint, `https://builder.prod.bedrock.ostium.io/v1/sponsor?chainId=42161`, * which sponsors the operation upstream. * * Point it at your own Pimlico project to sponsor through your own account * instead: the submitter then attaches a Pimlico paymaster, applies * `sponsorshipPolicyId`, and uses Pimlico's fee quote and gas estimation. * The flow is selected from the URL, so no extra flag is needed. */ pimlicoUrl?: string; /** Arbitrum RPC URL for reads/simulation. Defaults to public Arbitrum RPC when omitted. */ rpcUrl?: string; /** * Pimlico gas-sponsorship policy id. Applies only when `pimlicoUrl` points at * your own Pimlico project — Ostium's endpoint enforces policy upstream, so * setting both throws `INVALID_CONFIG` rather than dropping the value. */ sponsorshipPolicyId?: string; } interface SelfGaslessBuildParams extends CommonParams { /** Trader EOA address that owns USDC and positions. */ traderAddress: Address; /** Safe smart-account address that will submit delegated calls. */ safeAddress: Address; /** Optional Arbitrum RPC URL for reads/simulation. Defaults to the chain public RPC. */ rpcUrl?: string; } /** * **Self + Gasless** — your EOA owns everything; a Safe acts as a transparent gasless relay. * * Submit-capable clients derive the Safe from `traderPrivateKey`. Build-only * clients provide both `traderAddress` and `safeAddress`. */ type SelfGaslessParams = SelfGaslessSubmitParams | SelfGaslessBuildParams; interface DelegatedSelfSubmitParams extends CommonParams { /** Private key of the delegate EOA. This account signs and pays gas for all transactions. */ delegatePrivateKey: Hex; /** * Address of the trader this delegate acts for. * The trader must have called `setDelegate(delegateAddress)` on the trading contract. */ traderAddress: Address; /** Arbitrum One (or Sepolia) RPC URL. */ rpcUrl: string; } interface DelegatedSelfBuildParams extends CommonParams { /** Address of the trader this delegate acts for. */ traderAddress: Address; /** Delegate EOA address that will submit the transaction. */ delegateAddress: Address; /** Optional Arbitrum RPC URL for reads/simulation. Defaults to the chain public RPC. */ rpcUrl?: string; } /** * **Delegated + Self** — a dedicated delegate EOA signs and pays gas on behalf of a separate trader address. */ type DelegatedSelfParams = DelegatedSelfSubmitParams | DelegatedSelfBuildParams; interface DelegatedGaslessSubmitParams extends CommonParams { /** Private key of the delegate EOA. A Safe smart account is derived from this key and submits UserOperations via Pimlico. */ delegatePrivateKey: Hex; /** * Known smart-account address for the delegate key (from a previous client's * `getSmartAccountAddress()`). Skips the on-chain derivation call, making * construction network-free. The address is deterministic per key + chain. */ safeAddress?: Address; /** * Address of the trader this delegate acts for. * The trader must have called `setDelegate(safeAddress)` on the trading contract, * where `safeAddress` is the Safe derived from `delegatePrivateKey`. */ traderAddress: Address; /** * ERC-4337 bundler/paymaster RPC URL. Defaults to Ostium's boost sponsorship * endpoint, `https://builder.prod.bedrock.ostium.io/v1/sponsor?chainId=42161`, * which sponsors the operation upstream. * * Point it at your own Pimlico project to sponsor through your own account * instead: the submitter then attaches a Pimlico paymaster, applies * `sponsorshipPolicyId`, and uses Pimlico's fee quote and gas estimation. * The flow is selected from the URL, so no extra flag is needed. */ pimlicoUrl?: string; /** Arbitrum RPC URL for reads/simulation. Defaults to public Arbitrum RPC when omitted. */ rpcUrl?: string; /** * Pimlico gas-sponsorship policy id. Applies only when `pimlicoUrl` points at * your own Pimlico project — Ostium's endpoint enforces policy upstream, so * setting both throws `INVALID_CONFIG` rather than dropping the value. */ sponsorshipPolicyId?: string; } interface DelegatedGaslessBuildParams extends CommonParams { /** Address of the trader this delegate acts for. */ traderAddress: Address; /** Delegate EOA address that owns the Safe. */ delegateAddress: Address; /** Safe smart-account address that will submit delegated calls. */ safeAddress: Address; /** Optional Arbitrum RPC URL for reads/simulation. Defaults to the chain public RPC. */ rpcUrl?: string; } /** * **Delegated + Gasless** — a Safe derived from the delegate key submits sponsored UserOperations on behalf of the trader. */ type DelegatedGaslessParams = DelegatedGaslessSubmitParams | DelegatedGaslessBuildParams; interface OstiumClientConfig extends CommonParams { mode?: ClientMode; privateKey?: Hex; traderAddress?: Address; delegateAddress?: Address; safeAddress?: Address; rpcUrl?: string; pimlicoUrl?: string; /** * Pimlico gas-sponsorship policy id. Applies only when `pimlicoUrl` points at * your own Pimlico project — Ostium's endpoint enforces policy upstream, so * setting both throws `INVALID_CONFIG` rather than dropping the value. */ sponsorshipPolicyId?: string; } /** Mainnet (Arbitrum One) Ostium subgraph endpoint. */ declare const DEFAULT_SUBGRAPH_ENDPOINT = "https://builder.prod.bedrock.ostium.io/v1/subgraph/gn"; /** Testnet (Arbitrum Sepolia) Ostium subgraph endpoint. */ declare const DEFAULT_SUBGRAPH_ENDPOINT_TESTNET = "https://api.subgraph.ormilabs.com/api/public/67a599d5-c8d2-4cc4-9c4d-2975a97bc5d8/subgraphs/ost-sep/live/gn"; /** Default Ostium builder API base URL (prices, OHLC, WebSocket stream). */ declare const DEFAULT_BUILDER_API_URL = "https://builder.prod.bedrock.ostium.io"; /** * Configuration for {@link OstiumSubgraphClient}. * * All fields are optional — calling `OstiumSubgraphClient.create()` with no * arguments connects to the mainnet subgraph. * * ```ts * // Mainnet (default) * const client = OstiumSubgraphClient.create(); * * // Testnet (Arbitrum Sepolia) * const client = OstiumSubgraphClient.create({ testnet: true }); * * // Custom endpoints * const client = OstiumSubgraphClient.create({ * endpoint: 'https://my-subgraph.example.com/graphql', * builderApiUrl: 'https://my-builder-api.example.com', * }); * ``` */ interface OstiumSubgraphClientConfig { /** * Subgraph GraphQL endpoint. * When omitted, defaults to the mainnet or testnet subgraph based on `testnet`. */ endpoint?: string; /** * Use the Arbitrum Sepolia testnet subgraph. * Ignored when `endpoint` is set explicitly. Defaults to false (mainnet). */ testnet?: boolean; /** * Override the builder API base URL used for live prices, OHLC candles, and the * WebSocket stream. Defaults to `https://builder.prod.bedrock.ostium.io`. */ builderApiUrl?: string; /** * Alchemy API key used by `streamAccountUpdates()` for contract-log overlays. * Can be overridden per stream call. */ alchemyApiKey?: string; } interface Pair { /** Numeric string pair identifier (e.g. `"0"` for BTC/USD). Use this as `pairId` everywhere in the SDK. */ pairId: string; /** Normalized quote-asset display name (e.g. `"USD"`). */ pairTo: string; /** Normalized base-asset display name (e.g. `"BTC"`, `"WTI"` for raw `"CL"`). */ pairFrom: string; /** Minimum trade size in base-asset units (`5 / mid`). */ minSz: string; /** Max long size in base-asset units = `(maxOI − buyOI) / mid`. Zero when the long side is at capacity. */ maxBSz: string; /** Max short size in base-asset units = `(maxOI − sellOI) / mid`. Zero when the short side is at capacity. */ maxSSz: string; /** Minimum notional in USD — currently `"5.0"`. */ minNtl: string; /** Maximum leverage for this pair (takes the tighter of pair-level and group-level caps). */ maxLeverage: number; /** * Max leverage allowed for overnight positions. `0` means no overnight restriction. * When `overnightMaxLeverage > 0` and `trade.leverage > overnightMaxLeverage`, * the trade must set `isDayTrade: true` and will be auto-closed before market close. */ overnightMaxLeverage: number; /** Per-block rollover fee for this pair (formatted from `lastRolloverLongPure`). */ rolloverFeePerBlock: string; /** `buyOpenInterest + sellOpenInterest` (USD). */ openInterest: string; /** Current long open interest in USD. */ buyOpenInterest: string; /** Current short open interest in USD. */ sellOpenInterest: string; /** Maximum total open interest allowed for this pair per side in USD. */ maxOpenInterest: string; /** Group name (e.g. `"crypto"`, `"forex"`). */ category: string; /** 8-hour rollover rate as a percentage, separated by side. Negative = trader earns, positive = trader pays. */ rolloverRate: { long: string; short: string; }; /** Current mid price (average of bid and ask). */ midPx: string; /** Current ask price (long entries execute at or above this). */ askPx: string; /** Current bid price (short entries execute at or below this). */ bidPx: string; /** Whether the market is currently open for trading. */ isMarketOpen: boolean; /** Whether intra-day trading is currently closed for this pair. */ isDayTradingClosed: boolean; /** Seconds until `isDayTradingClosed` flips. `-1` when not applicable. */ secondsToToggleIsDayTradingClosed: number; /** Market hours for this pair. Omitted when the live price feed is unavailable. */ schedule?: PairSchedule; /** * Opening fee in basis points — pair taker fee (`takerFeeP / 10_000`) plus the * configured builder fee when set. */ openFee: number; /** Closing fee in basis points. Always `0`. */ closeFee: number; } /** Market-hours schedule for a pair, as reported by the live price feed. */ interface PairSchedule { /** Schedule identifier shared by pairs trading the same hours. */ id: number; /** True for markets that never close (e.g. crypto). */ alwaysOpen?: boolean; /** IANA timezone the opening hours are expressed in (e.g. `"America/New_York"`). */ timezone?: string; /** Opening hours per weekday range (e.g. `"Mo-Th 00:00-16:59,18:00-24:00"`). */ openingHours?: string[]; } interface PairsResponse { pairs: Pair[]; } /** Live price snapshot for a pair (bid/mid/ask as plain numbers). */ interface PriceData { mid: number; bid: number; ask: number; isMarketOpen: boolean; isDayTradingClosed: boolean; /** Seconds until `isDayTradingClosed` flips. `-1` when not applicable. */ secondsToToggleIsDayTradingClosed: number; /** Market hours for this pair, when reported by the feed. */ schedule?: PairSchedule; } interface AllPricesResponse { /** Live prices keyed by pair id (string). */ prices: Record; } interface Position { pairTo: string; pairFrom: string; pairId: string; /** Position id from the subgraph (numeric string — same as `Fill.pid`). */ pid: string; /** Trader address that owns this position. */ trader: string; /** * Position index — the trader's per-pair slot for this position. * * In `streamAccountUpdates()` fast overlays, this is only trustworthy once * `confirmationStatus` is `"executed"` or omitted on an indexed position. * `"optimistic"` and `"initiated"` overlays use `-1` because the on-chain * slot is not known yet. */ idx: number; /** `"B"` for LONG, `"S"` for SHORT. */ side: 'B' | 'S'; /** Position size in base-asset units (use `side` for direction). */ szi: string; /** Price at which the position was opened (USD). */ entryPx: string; /** Current effective leverage as a decimal string (e.g. `"10"`). */ leverage: string; /** Current notional in USD (`size × midPrice`). */ ntl: string; /** Net PnL after rollover, in USD. */ unrealizedPnl: string; /** `unrealizedPnl / collateralUsed`. */ returnOnEquity: string; /** Estimated price at which this position would be liquidated given current rollover. */ liquidationPx: string; /** Collateral locked in this position (USD). */ collateralUsed: string; /** Rollover fee accrued for this trade since it was opened, in USD. */ cumRollover: string; /** Take-profit price, when set on this position. */ tpPx?: string; /** Stop-loss price, when set on this position. */ slPx?: string; /** Open timestamp (Unix milliseconds). */ openTimestamp: number; /** Whether this position was opened as a day trade (auto-closes before market close). */ isDayTrade: boolean; /** Max leverage for the trade/pair/group **/ maxLeverage: string; /** Max collateral removable from this position without breaching min leverage, in USD. */ maxWithdrawable: string; /** Confirmation state for streamAccountUpdates overlays. Omitted for normal indexed reads. */ confirmationStatus?: 'optimistic' | 'initiated' | 'executed' | 'indexed'; /** On-chain market order id once known. */ orderId?: string; /** Transaction that initiated this market order, when known. */ initiatedTx?: string; /** Block that initiated this market order, when known. */ initiatedBlock?: string; } interface PairPosition { position: Position; } interface MarginSummary { /** Sum of `(collateral + netPnl)` across all open positions (USD). */ accountValue: string; /** Sum of collateral deposited across all open positions (USD). */ totalCollateralUsed: string; /** Sum of current notional values across all open positions (USD). */ totalNtlPos: string; /** Sum of unrealized PnL (after rollover) across all open positions (USD). */ totalRawPnlUsd: string; /** Sum of cumulative rollover across all open positions (USD, negative = trader pays). */ totalCumRollover: string; /** Sum of per-position max-removable collateral across all open positions (USD). */ totalWithdrawable: string; } interface OpenPositionsResponse { /** All open positions for the requested trader, sorted newest first. */ pairPositions: PairPosition[]; /** Aggregated margin metrics across all open positions. */ marginSummary: MarginSummary; /** Server time (Unix milliseconds). */ time: number; } /** Possible `orderAction` values returned by the subgraph for a fill. */ type OrderAction = 'Open' | 'Close' | 'Liquidation' | 'StopLoss' | 'TakeProfit' | 'RemoveCollateral' | 'TopUpCollateral' | 'CloseDayTrade'; /** Possible `orderType` values returned by the subgraph for a fill. */ type OrderType = 'Market' | 'Limit' | 'REMOVE_COLLATERAL' | 'TOP_UP_COLLATERAL'; interface FillFees { /** Opening fee (devFee + vaultFee) — only on `Open` actions, else `"0"`. */ opening: string; /** Rollover fee — on `Close`, `StopLoss`, `TakeProfit`, and `CloseDayTrade` actions, else `"0"`. */ rollover: string; /** Liquidation fee — only on `Liquidation` actions, else `"0"`. */ liquidation: string; /** Builder fee — when the order was routed via a builder. */ builder: string; /** Estimated price impact cost. */ priceImpact: string; } interface Fill { /** Normalized quote-asset display name (e.g. `"USD"`). */ pairTo: string; /** Normalized base-asset display name (e.g. `"BTC"`). */ pairFrom: string; /** Numeric string pair identifier — same as `Pair.pairId`. */ pairId: string; /** * On-chain keeper order id — the Trading contract's uint256 counter as a * base-10 numeric string (e.g. `"2162661"`). Identical for fast-overlay and * subgraph-indexed entries, so it is safe to correlate against the id * returned by `extractOrderIdFromReceipt()`. */ oid: string; /** Position id from the subgraph (numeric string — same as `Position.pid`). */ pid: string; /** Trader address that owns this fill. */ trader: string; /** `"B"` for LONG, `"S"` for SHORT. */ side: 'B' | 'S'; /** * Subgraph `orderAction` — passes through verbatim. Examples: `"Open"`, `"Close"`, * `"Liquidation"`, `"StopLoss"`, `"TakeProfit"`, `"RemoveCollateral"`, `"TopUpCollateral"`, `"CloseDayTrade"`. */ action: OrderAction; /** Subgraph `orderType` — passes through verbatim. Examples: `"Market"`, `"Limit"`, `"REMOVE_COLLATERAL"`, `"TOP_UP_COLLATERAL"`. */ type: OrderType; /** Execution price after dynamic spread impact. */ px: string; /** Trade size in base-asset units at the time of execution. */ szi: string; /** USD notional at the time of execution (`collateral × leverage`). */ ntl: string; /** Collateral on the underlying position at the time of the fill (USD). */ collateralUsed: string; /** Builder address associated with the order. May be the zero address when none is set. */ builder: string; fees: FillFees; /** * Net realized PnL in USD for close actions (`Close`, `StopLoss`, `TakeProfit`, * `CloseDayTrade`, `Liquidation`) after subtracting opening fee, oracle fee, and * rollover. `"0"` for `Open`, `RemoveCollateral`, and `TopUpCollateral` actions. */ closedPnl: string; /** Execution transaction hash. Empty string for pending orders. */ hash: string; /** Execution time (Unix seconds UTC). Same as `timestamp`. Subgraph `executedAt`. */ time: number; /** Execution time (Unix seconds UTC). Subgraph `executedAt`. */ timestamp: number; } /** * An order at any stage — pending, executed, or cancelled. Extends `Fill` with * initiation metadata and status flags. Poll with `getOrders({ initiatedTxHashes: * [txHash] })` using the hash from `SubmissionResult.txHash`, or with `orderIds`. */ interface Order extends Fill { /** Transaction that initiated this order. */ initiatedTx: string; /** Initiation time (Unix milliseconds). */ initiatedTime: number; /** True while the oracle callback has not yet been processed. */ isPending: boolean; /** True when the order was cancelled (timeout, slippage, or manual cancel). */ isCancelled: boolean; /** Reason for cancellation, when `isCancelled` is true. */ cancelReason?: string; /** Block that initiated this order, when known. */ initiatedBlock?: string; } interface OpenOrder { /** Normalized quote-asset display name (e.g. `"USD"`). */ pairTo: string; /** Normalized base-asset display name (e.g. `"BTC"`). */ pairFrom: string; /** Numeric string pair identifier — same as `Pair.pairId`. */ pairId: string; /** Trader address that owns this limit order. */ trader: string; /** * Limit-order slot index within the pair. Pass to `cancelOrder` / * `modifyOrder` together with `pairId` to target this limit on-chain. */ idx: number; /** `"B"` for LONG, `"S"` for SHORT. */ side: 'B' | 'S'; /** Trigger price — the order executes when the market reaches this level. */ limitPx: string; /** Order size in base-asset units. */ szi: string; /** USD notional for the order (`collateralUsed × leverage`). */ ntl: string; /** Collateral committed to this limit order, in USD. */ collateralUsed: string; /** Order leverage as a decimal string (e.g. `"10"`). */ leverage: string; /** Normalized order type: `"Limit"` | `"Stop"`. */ orderType: string; /** Take-profit price, when set on this limit order. */ tpPx?: string; /** Stop-loss price, when set on this limit order. */ slPx?: string; /** Initiation time (Unix milliseconds). */ timestamp: number; } interface CloseExecution { /** On-chain close order id. */ orderId: string; /** Open trade id / position id being closed. */ tradeId: string; /** Trader address that owns the position, when attributable. */ trader: string; /** Numeric string pair identifier, when known from the current position or subgraph tombstone. */ pairId?: string; /** Normalized quote-asset display name, when known. */ pairTo?: string; /** Normalized base-asset display name, when known. */ pairFrom?: string; /** Close action from the subgraph tombstone, when known. */ action?: OrderAction; /** Execution price from `MarketCloseExecutedV2.price` / subgraph close order. */ px: string; /** `MarketCloseExecutedV2.percentProfit`, normalized to a percent string. */ percentProfit: string; /** `MarketCloseExecutedV2.usdcSentToTrader`, normalized to USD. */ usdcSentToTrader: string; /** Closed percentage, normalized so a full close is `"100"`. */ percentageClosed: string; /** True for liquidations and 100% closes. */ isFullClose: boolean; /** Where this close execution was observed first. */ source: 'event' | 'subgraph'; /** Chain block for event-sourced closes, when available. */ blockNumber?: string; } interface AccountUpdatesForTrader { /** Open positions for this trader, formatted exactly like `getOpenPositions().pairPositions`. */ positions: PairPosition[]; /** Pending market orders only. */ orders: Order[]; /** Active limit and stop orders. */ limits: OpenOrder[]; /** Recent close executions observed before or during subgraph reconciliation. */ closeExecutions?: CloseExecution[]; } /** Account confirmation stream snapshot keyed by normalized trader address. */ type AccountUpdatesSnapshot = Record; interface StreamAccountUpdatesParams { /** * Trader addresses to stream. Pass one or more addresses to subscribe to * multiple accounts on one stream. Defaults to the connected trader on * `OstiumClient`. Required when using `OstiumSubgraphClient` directly or a * read-only client. Emitted snapshots are keyed by normalized trader address. */ user?: Address[]; /** * Alchemy API key for the Arbitrum contract-log WebSocket overlay. Defaults to * the key supplied when creating the client. */ alchemyApiKey?: string; /** * Subgraph polling interval in milliseconds. Defaults to `3000`. Event-driven * confirmations arrive sub-second regardless — this only paces reconciliation. */ pollIntervalMs?: number; } interface GetOrdersParams { /** * On-chain order ids to fetch. Mutually exclusive with `initiatedTxHashes`. */ orderIds?: Array; /** * Initiating transaction hashes (`orders.initiatedTx` on the subgraph). Use with * `SubmissionResult.txHash` to poll a trade you just submitted. Mutually exclusive * with `orderIds`. */ initiatedTxHashes?: readonly Hex[]; /** * Trader address. Pass `'ALL'` to fetch global orders without a trader filter. * On `OstiumClient`, defaults to the connected trader unless a builder filter is provided. */ user?: Address | AllTraders; /** Builder address to filter orders by. */ builder?: string; /** When provided, filters by the order's pending status. */ isPending?: boolean; /** When provided, filters by the order's cancelled status. */ isCanceled?: boolean; /** Alias for `isCanceled`. */ isCancelled?: boolean; /** Pair ids to filter by. Accepts numeric strings or numbers. */ pairIds?: Array; /** * Inclusive lower bound on execution time (Unix seconds UTC) — maps to * `executedAt_gte`. Only executed orders have an execution time, so combining * `start`/`end` with `isPending: true` matches nothing. */ start?: number; /** Inclusive upper bound on execution time (Unix seconds UTC) — maps to `executedAt_lte`. */ end?: number; /** Max orders to return. Defaults to `100`. */ limit?: number; } /** Params for {@link OstiumSubgraphClient.getBuilderOrders} / {@link OstiumClient.getBuilderOrders}. */ type GetBuilderOrdersParams = Omit; interface GetPairsParams { /** Optional list of pair ids to return. Accepts numeric strings or numbers. When omitted, all pairs are returned. */ pairIds?: Array; /** * Builder fee in bps added to each pair's `openFee`. On `OstiumClient`, defaults * to the configured builder fee when omitted. */ builderFeeBps?: number; } interface GetUserParams { user: Address; } interface GetOpenPositionsParams { /** * Trader address — pass `'ALL'` to fetch every trader's open positions * (no trader filter applied to the subgraph query). */ user: Address | AllTraders; /** Current Arbitrum block number — required for live PnL. Auto-fetched on `OstiumClient`. */ blockNumber?: bigint; /** * Maximum number of positions to return. Defaults to `Infinity` (all positions). */ limit?: number; /** * Number of positions to skip (for pagination). Defaults to `0`. */ skip?: number; } /** Sentinel value for read methods to fetch across every trader. */ type AllTraders = 'ALL'; interface GetFillsParams { /** * Trader address — pass `'ALL'` to fetch fills across every trader (no * trader filter). */ user: Address | AllTraders; /** * Optional pair filter — if provided, only fills on this pair are returned. * Accepts the numeric string (e.g. `"0"`) or a plain `number`. */ pairId?: string | number; /** * Maximum number of fills to return. Defaults to `1000`. * Pass `Infinity` (or any large number) to fetch every matching fill. */ limit?: number; } interface GetFillsByTimeParams extends GetFillsParams { /** Inclusive lower bound (Unix milliseconds). */ startTime: number; /** Inclusive upper bound (Unix milliseconds). Defaults to `Date.now()`. */ endTime?: number; } /** One simulated slippage row for a (pair, side, notional) tuple. */ interface SimSlippageRow { /** Notional echoed from the input (USD). */ ntl: string; /** Slippage as a percentage (e.g. `"0.5"` = 0.5 %). */ slippage: string; } /** Per-side simulated slippage for a single pair. */ interface SimSlippageForPair { /** Slippage for long entries — capped to the long side's remaining OI capacity. */ long: SimSlippageRow[]; /** Slippage for short entries — capped to the short side's remaining OI capacity. */ short: SimSlippageRow[]; } /** Simulated slippage results keyed by `pairId`. */ type SimSlippageByPairId = Record; interface GetSimSlippageParams { /** Pair ids to simulate (e.g. `[0, "1", "10"]`). Strings or numbers — both accepted. */ pairIds: Array; /** Notional amounts in USD as strings (e.g. `["1000", "5000"]`). */ ntls: string[]; } /** One synthetic orderbook level — matches Hyperliquid's L2 book level shape. */ interface SimOrderbookLevel { /** Fill price after dynamic spread impact. */ px: string; /** Size in base-asset units (`notional / px`). */ sz: string; /** Number of orders at this level — always `1` for simulated levels. */ n: number; } /** * Synthetic bid/ask orderbook — matches Hyperliquid's `L2Book` response shape. * * - `levels[0]` — bids (short entries), best bid first (highest px → lowest impact). * - `levels[1]` — asks (long entries), best ask first (lowest px → lowest impact). */ interface SimOrderbookResponse { pairId: string; pairFrom: string; pairTo: string; levels: [SimOrderbookLevel[], SimOrderbookLevel[]]; /** Response timestamp (Unix milliseconds). */ time: number; } interface GetSimOrderbookParams { /** Pair id to simulate. Accepts the numeric string (e.g. `"0"`) or a plain `number`. */ pairId: string | number; /** * Maximum number of levels per side. Capped at 20. Defaults to 20. * Notionals follow the `[1, 2, 3, 5] × 10ⁿ` exponential scale, stopping at * the side's remaining OI capacity. */ levels?: number; } /** Live price tick received from the builder API price stream. */ interface PriceTick { /** Numeric string pair identifier — same as `Pair.pairId`, when resolvable from the SDK cache. */ pairId?: string; /** Upstream feed identifier. */ feedId: string; /** Pair in `"BASE-QUOTE"` format (e.g. `"BTC-USD"`). */ pair: string; /** Base asset symbol (e.g. `"BTC"`). */ from: string; /** Quote asset symbol (e.g. `"USD"`). */ to: string; /** Best bid price (short entries execute at or below this). */ bid: number; /** Mid price (average of bid and ask). */ mid: number; /** Best ask price (long entries execute at or above this). */ ask: number; /** Whether the market is currently open for trading. */ isMarketOpen: boolean; /** Whether intra-day trading is currently closed for this pair. */ isDayTradingClosed: boolean; /** Seconds until `isDayTradingClosed` flips. `-1` when not applicable. */ secondsToToggleIsDayTradingClosed: number; /** Tick timestamp (Unix seconds). */ timestampSeconds: number; /** Market hours for this pair, when reported by the feed. */ schedule?: PairSchedule; } /** * Candle resolution for `getCandles`. * `"1"` = 1 min, `"5"` = 5 min, `"15"` = 15 min, `"60"` = 1 hr, `"240"` = 4 hr, `"1D"` = daily. */ type CandleResolution = '1' | '5' | '15' | '60' | '240' | '1D'; /** One OHLC candle returned by `getCandles`. */ interface Candle { /** Normalized base-asset display name (e.g. `"WTI"` for raw `"CL"`). */ pairFrom: string; /** Normalized quote-asset display name (e.g. `"USD"`). */ pairTo: string; /** Candle open time (Unix milliseconds). */ time: number; /** Opening price for the candle period (USD). */ open: number; /** Highest price reached during the candle period (USD). */ high: number; /** Lowest price reached during the candle period (USD). */ low: number; /** Closing price at the end of the candle period (USD). */ close: number; } interface GetCandlesParams { /** * Pair id — same as `Pair.pairId` from `getPairs()`. * Accepts both the numeric string (e.g. `"0"`) and a plain `number`. */ pairId: string | number; /** Start time (Unix milliseconds). */ from: number; /** End time (Unix milliseconds). Defaults to `Date.now()`. */ to?: number; /** Candle width — `"1"` (1 min) through `"1D"` (daily). See {@link CandleResolution}. */ resolution: CandleResolution; /** * Number of candle pages to fetch. Defaults to `1`. * * When greater than `1`, the SDK requests the next page using the previous * page's last candle timestamp and returns one flattened candle array. */ sets?: number; } /** Why a previewed trade would be rejected or needs the trader's attention. */ interface PreviewWarning { code: 'BELOW_MIN_COLLATERAL' | 'ABOVE_MAX_COLLATERAL' | 'LEVERAGE_ABOVE_MAX' | 'LEVERAGE_BELOW_MIN' | 'BELOW_MIN_POSITION_SIZE' | 'FEES_EXCEED_COLLATERAL' | 'ABOVE_EXPOSURE_LIMIT' | 'MARKET_CLOSED' | 'DAY_TRADING_CLOSED'; message: string; } /** Fee breakdown charged when the trade opens. All values in USDC. */ interface PreviewFees { /** Protocol opening fee. */ openFee: string; /** Flat oracle price-retrieval fee. */ oracleFee: string; /** Builder fee charged on notional, when a builder is configured. `"0"` otherwise. */ builderFee: string; /** Builder fee rate in basis points, as configured on the client. */ builderFeeBps: string; /** `openFee + oracleFee + builderFee` — deducted from collateral at open. */ total: string; /** Blended opening-fee rate actually applied, as a percentage. */ openFeePercent: string; takerFeePercent: string; makerFeePercent: string; /** Portion of the notional filled at the taker rate (USDC). */ takerNotional: string; /** Portion of the notional filled at the maker rate (USDC). */ makerNotional: string; } interface PreviewOpenTradeParams { pairId: string | number; isLong: boolean; /** Gross collateral in USDC, before fees. */ collateral: number; leverage: number; /** * Limit/stop trigger price. Omit for a market order, which prices off the * live bid/ask and pays the dynamic spread. */ limitPrice?: number; /** Day trades get the pair's higher intraday leverage cap. */ isDayTrade?: boolean; /** * Builder fee in basis points to include in the preview. On `OstiumClient` * this defaults to the fee configured at construction, so an order ticket * shows the fee the trade will actually pay. */ builderFeeBps?: number; } /** * Everything an order ticket needs before a trade is signed. Mirrors what * ostium.io shows, and is derived from `@ostium/formulae` — the same math the * contracts run. */ interface PreviewOpenTradeResult { pairId: string; pairFrom: string; pairTo: string; isLong: boolean; /** Live mid price. */ midPx: string; /** Reference price before impact — the side's bid/ask, or the limit price. */ refPx: string; /** Price the trade is expected to execute at, after dynamic spread. */ entryPx: string; /** Dynamic spread applied, as a percentage (`"0.5"` = 0.5%). Zero for limit orders. */ priceImpactP: string; /** Seconds until the current imbalance spread decays to zero. */ spreadDecaySeconds: number; fees: PreviewFees; /** Gross collateral supplied (USDC). */ collateral: string; /** Collateral actually backing the position after fees (USDC). */ collateralAtOpen: string; /** Notional exposure in USD (`collateralAtOpen × leverage`). */ exposure: string; /** Position size in base-asset units. */ positionSize: string; leverage: string; /** Liquidation price for the position as it would open. */ liquidationPx: string; /** Max leverage allowed, accounting for the day-trade cap. */ effectiveMaxLeverage: string; minLeverage: string; /** Minimum notional this pair accepts (USDC). */ minPositionSize: string; isDayTrade: boolean; /** * Whether the trade fits the pair's open-interest and group-collateral caps. * `undefined` when the vault balance could not be fetched. */ withinExposureLimit?: boolean; /** `true` when `warnings` is empty. */ isValid: boolean; warnings: PreviewWarning[]; } type TickHandler = (tick: PriceTick) => void; type SnapshotHandler = (ticks: PriceTick[]) => void; /** * WebSocket client for the Ostium live price stream. * * ```ts * // Via OstiumClient / OstiumSubgraphClient (recommended — pairIds resolved automatically): * const stream = client.streamPrices([0, 1]); // BTC and ETH by pairId * * stream.onSnapshot(ticks => console.log('snapshot:', ticks.length)); * stream.onTick(tick => console.log(tick.pair, tick.mid)); * * stream.subscribe([2]); // add pair 2 * stream.unsubscribe([0]); // remove pair 0 * stream.close(); * ``` * * The socket connects to `{builderApiUrl}/v1/prices/stream` — `https://` is * automatically rewritten to `wss://` (and `http://` to `ws://`). When * `streamPrices(pairIds)` is called with ids, the SDK sends * `{ type: "subscribe", pairs: ["FROM-TO", ...] }` on `open` (same wire format * as {@link OstiumPriceStream.subscribe}). * * `subscribe` / `unsubscribe` accept the same `pairId` values used everywhere * else in the SDK. `PriceTick.pair` / `.from` / `.to` use normalized display * names (e.g. `"UK100"` not `"FTSE"`). */ declare class OstiumPriceStream { private readonly ws; private readonly tickHandlers; private readonly snapshotHandlers; /** pairId (string) → raw "FROM-TO" name for the WS API. */ private readonly pairRawNameCache; /** raw "FROM-TO" name → pairId (string) for mapping incoming ticks back to SDK ids. */ private readonly rawNamePairIdCache; private constructor(); /** * Open a WebSocket connection to the live price stream. * * Uses the `ws` package which correctly handles case-insensitive `Connection` * header values (required for Cloudflare-proxied endpoints). * * @param builderApiUrl - Base URL (e.g. `"https://builder.prod.bedrock.ostium.io"`). The `http`/`https` * scheme is automatically converted to `ws`/`wss`. * @param rawPairs - Optional raw `"FROM-TO"` names (from * `OstiumSubgraphClient.streamPrices` pairIds). Sent as * `{ type: "subscribe", pairs }` after the socket opens. * @param pairRawNameCache - pairId → raw name map; passed in by the subgraph client so * `subscribe` / `unsubscribe` can accept pairIds. */ static connect(builderApiUrl: string, rawPairs?: string[], pairRawNameCache?: Map): OstiumPriceStream; /** * Register a callback that fires on every incoming price tick. * Returns an unsubscribe function. */ onTick(handler: TickHandler): () => void; /** * Register a callback that fires once with the full snapshot sent on connect. * Returns an unsubscribe function. */ onSnapshot(handler: SnapshotHandler): () => void; /** Register a one-time callback that fires when the connection is established. */ onOpen(handler: () => void): this; /** Register an error callback. */ onError(handler: (event: Error) => void): this; /** Register a callback that fires when the connection closes. */ onClose(handler: (code: number, reason: string) => void): this; /** * Add pairs to the active filter. Accepts the same `pairId` values used * throughout the SDK (numeric string or number). * Sends `{ type: "subscribe", pairs: [...rawNames] }` to the server. */ subscribe(pairIds: Array): this; /** * Remove pairs from the active filter. Accepts the same `pairId` values used * throughout the SDK. * Sends `{ type: "unsubscribe", pairs: [...rawNames] }` to the server. */ unsubscribe(pairIds: Array): this; /** Close the WebSocket connection. */ close(): void; /** Underlying WebSocket ready state (`0=CONNECTING`, `1=OPEN`, `2=CLOSING`, `3=CLOSED`). */ get readyState(): number; private resolveRawNames; private getPairIdForRawName; private send; } type UpdateHandler$1 = (positions: OpenPositionsResponse) => void; type TickSource = Pick; declare class OstiumPositionUpdatesStream { private readonly priceStream?; private readonly updateHandlers; private current; private readonly trackedPairIds; constructor(initial: OpenPositionsResponse, trackedPairIds: string[], priceStream?: TickSource); onUpdate(handler: UpdateHandler$1): () => void; onOpen(handler: () => void): this; onError(handler: (event: Error) => void): this; onClose(handler: (code: number, reason: string) => void): this; getCurrent(): OpenPositionsResponse; /** * Apply a single externally sourced price tick to the tracked positions. * * Use this when your app already has its own websocket connection and you want * the SDK to handle only the position recalculation logic. */ ingestTick(tick: PriceTick): void; /** * Apply a batch of externally sourced ticks, such as a websocket snapshot. */ ingestSnapshot(ticks: PriceTick[]): void; close(): void; private emit; } interface RawGroup { id: string; name: string; maxLeverage: string; minLeverage?: string; /** Group open-collateral totals + cap — inputs to `WithinExposureLimit`. */ longCollateral?: string; shortCollateral?: string; maxCollateralP?: string; } /** Per-pair fee config. Inputs to the open-trade preview. */ interface RawFee { /** Flat oracle fee charged at open, 6 decimals. */ oracleFee: string; /** Minimum leveraged position size, 6 decimals. */ minLevPos: string; } interface RawPair { id: string; from: string; to: string; maxLeverage: string; overnightMaxLeverage?: string; takerFeeP: string; makerFeeP?: string; makerMaxLeverage?: string; fee?: RawFee; maxOI: string; longOI: string; shortOI: string; group: RawGroup; lastUpdateTimestamp: string; buyVolume?: string; sellVolume?: string; decayRate?: string; netVolThreshold?: string; priceImpactK?: string; accRolloverLong?: string; accRolloverShort?: string; lastRolloverBlock?: string; lastRolloverLongPure?: string; brokerPremium?: string; isNegativeRolloverAllowed?: boolean; lastTradePrice: string; /** Half-spread × 1e10. Used by `getSimSpreadP` for static spread fallback. */ spreadP?: string; } interface RawTrade { id: string; tradeID: string; trader: string; pair: RawPair; isBuy: boolean; isDayTrade?: boolean; isOpen: boolean; index: string; tradeType: 'Market' | 'Limit'; collateral: string; notional: string; tradeNotional: string; leverage: string; highestLeverage: string; openPrice: string; closePrice?: string; stopLossPrice?: string; takeProfitPrice?: string; rollover: string; timestamp: string; closedAt?: string; } interface RawOrder { id: string; tradeID: string; limitID?: string; trader: string; pair: { id: string; from: string; to: string; group?: { id: string; name: string; }; }; orderAction: 'Open' | 'Close' | 'Liquidation' | 'StopLoss' | 'TakeProfit' | 'RemoveCollateral' | 'TopUpCollateral' | 'CloseDayTrade'; orderType: 'Market' | 'Limit' | 'REMOVE_COLLATERAL' | 'TOP_UP_COLLATERAL'; isBuy: boolean; isPending: boolean; isCancelled: boolean; cancelReason?: string; collateral: string; notional: string; tradeNotional: string; leverage: string; price: string; priceAfterImpact: string; priceImpactP: string; vaultFee: string; devFee: string; oracleFee: string; rolloverFee: string; liquidationFee: string; builder: string; builderFee: string; profitPercent: string; totalProfitPercent: string; amountSentToTrader: string; closePercent: string; initiatedTx: string; initiatedBlock: string; initiatedAt: string; executedTx?: string; executedBlock?: string; executedAt?: string; } interface RawLimit { id: string; uniqueId: string; orderId: string; trader: string; pair: { id: string; from: string; to: string; group?: { id: string; name: string; }; }; isBuy: boolean; limitType: 'LIMIT' | 'STOP'; isActive: boolean; executionStarted: boolean; collateral: string; notional: string; tradeNotional: string; leverage: string; openPrice: string; takeProfitPrice?: string; stopLossPrice?: string; block: string; initiatedAt: string; updatedAt: string; } /** * Resolves whether a pending market order is still registered on-chain. * `true` = registered (cancellable), `false` = ghost, `undefined` = unknown * (RPC failure — callers fail open and keep the order visible). */ type PendingOrderRegisteredReader = (orderId: string) => Promise; interface RawAccountUpdatesSnapshot { orders: RawOrder[]; limits: RawLimit[]; trades: RawTrade[]; /** * Recently executed close/liquidation orders. Used to tombstone fast overlay * entries whose on-chain close event was missed (e.g. during a WebSocket * reconnect) so a closed trade can never linger as a ghost position. */ closedOrders?: RawOrder[]; } interface ReceiptLogLike { topics?: readonly unknown[]; } interface TransactionReceiptLike { logs?: readonly ReceiptLogLike[]; receipt?: { logs?: readonly ReceiptLogLike[]; }; } type ReceiptOrderAction = 'any' | 'open' | 'close'; interface OstiumAccountUpdatesStreamOptions { /** One or more trader addresses to stream on this connection. Must be non-empty. */ users: Address[]; testnet: boolean; alchemyApiKey: string; pollIntervalMs?: number; fetchRawSnapshot: () => Promise; fetchRawPairs: () => Promise; fetchLivePrices: () => Promise>; openPriceStream: () => PriceStreamSource; getRawPairName: (pairId: string) => string | undefined; getRawPair: (pairId: string) => RawPair | undefined; initialRawPairs?: RawPair[]; /** * Override for the on-chain pending-order lookup used to drop ghost pending * market orders. Defaults to `reqID_pendingMarketOrder` on TradingStorage. */ isPendingMarketOrderRegistered?: PendingOrderRegisteredReader; } type UpdateHandler = (snapshot: AccountUpdatesSnapshot) => void; type ErrorHandler = (error: Error) => void; type PriceStreamSource = Pick; /** * Extract the keeper order id from a transaction receipt, reading the first * matching initiated-event log. * * @param receipt - A viem receipt, or any object with `logs` / `receipt.logs`. * @param trader - Restrict matching to logs whose indexed trader topic equals * this address. Supply it whenever the receipt may bundle more than one * trader's operations (an ERC-4337 `handleOps` receipt), otherwise the * first-match scan can return someone else's order id. * * **Only logs that carry an indexed trader topic can match.** The current * contracts' `MarketOpenOrderInitiated`, `MarketCloseOrderInitiated`, and * `MarketCloseOrderInitiatedV2` all qualify. The pre-V2 `PriceRequested` * carries no address, so it is skipped rather than assumed to match — parsing * an old `PriceRequested`-only receipt requires omitting this argument. * @param action - Scope the match to an open or a close order id, for receipts * that bundle both (e.g. a close and an open in one `handleOps`), where the * default first-match scan would return whichever the bundler ordered first. * Defaults to `'any'`, which preserves that first-match behavior. * * Scoping keys off `topic0` alone. `PriceRequested` carries no action, so it * matches only under `'any'`. * @returns The order id as a base-10 string, or `undefined` when no log * satisfies every supplied constraint. */ declare function extractOrderIdFromReceipt(receipt: TransactionReceiptLike | null | undefined, trader?: Address | string, action?: ReceiptOrderAction): string | undefined; declare class OstiumAccountUpdatesStream { private readonly options; private readonly updateHandlers; private readonly errorHandlers; private readonly logClient; private readonly blockClient; private readonly isPendingMarketOrderRegistered; private readonly priceStream; private readonly state; private readonly unwatchers; private readonly timer; /** Lower-cased set of subscribed trader addresses, for membership checks. */ private readonly normalizedUsers; /** First subscribed address — used as the attribution fallback when an event omits the trader. */ private readonly defaultUser; private readonly priceCache; private rawPairById; private rawPairsPromise; private latestBlockNumber; /** Chain head up to which missed-event backfill has run. */ private lastSweptBlock; private sweepInFlight; private optimisticOpenCounter; private inFlight; private consecutivePollFailures; private pollBackoffTicksRemaining; private pollBackoffUntilMs; private closed; constructor(options: OstiumAccountUpdatesStreamOptions); onUpdate(handler: UpdateHandler): () => void; onError(handler: ErrorHandler): this; getCurrent(): AccountUpdatesSnapshot; /** Trader addresses this stream is subscribed to, in the order supplied. */ get users(): Address[]; addOptimisticOpen(params: OpenTradeParams, submission?: SubmissionResult, user?: Address): string; attachOrderId(localId: string, orderId: string, metadata?: { initiatedTx?: string; initiatedBlock?: string; }): void; close(): void; private startPriceStream; private seedPrices; private startWatchers; private poll; /** * Refresh the cached chain tip, which feeds rollover projection in PnL and is * the starting point for `sweepMissedEvents()`. A failure keeps the previous * tip rather than clearing it — the tip is already served from a 30s cache, and * both consumers prefer a slightly stale tip to none at all. */ private trackChainTip; private shouldSkipPollForBackoff; private resetPollBackoff; private recordPollFailure; /** * Replay contract events the WebSocket may have dropped. viem reconnects a * failed socket and re-subscribes, but logs emitted during the gap are lost; * this sweep fetches the gap range over HTTP each poll so a flap degrades * confirmation latency to roughly one poll interval instead of losing the * event entirely. */ private sweepMissedEvents; private ingestPriceTicks; private mergePrices; private priceKeyFromTick; private priceKeyFromPairId; private handleMarketOpenInitiated; /** * Replace the placeholder direction/size of a fast pending order with the * real values decoded from the initiating transaction's calldata. Best * effort — undecodable calldata keeps the placeholder until the subgraph * indexes the order. */ private enrichPendingOrderFromTx; private handleMarketCloseExecuted; private closeExecutionFromMarketCloseExecuted; /** * Resolve which subscribed trader an optimistic open belongs to. When a single * address is streamed the choice is unambiguous; with multiple addresses the * caller must pass an explicit `user` that is part of the subscription. */ private resolveOptimisticUser; private optimisticTradeFromOpenParams; private handleMarketOpenExecuted; private rawTradeFromMarketOpenExecuted; private getRawPair; private loadRawPairs; private emit; private emitError; } declare class OstiumSubgraphClient { private readonly gql; private readonly builderApiUrl; private readonly testnet; private readonly alchemyApiKey?; /** Cached pair-name (`${from}/${to}`) → `pairId` map. Refreshed lazily. */ private pairIdCache; private pendingOrderReader; /** Cached `pairId` → `"FROM-TO"` in raw subgraph dash format (used for OHLC API). */ private pairRawNameCache; /** Cached `pairId` → full raw pair metadata for event overlays. */ private rawPairCache; private rawPairsMemo; private livePricesMemo; private vaultBalanceMemo; private constructor(); /** * Create a client connected to the Ostium subgraph. * * Construction is network-free: the pair-id cache used by `streamPrices`, * `getCandles`, and `getAllPrices` is fetched lazily on first use, so * build-only consumers (synchronous `get*Tx` encoders) never pay a subgraph * round-trip. * * ```ts * // Mainnet (default) * const client = await OstiumSubgraphClient.create(); * * // Testnet (Arbitrum Sepolia) * const client = await OstiumSubgraphClient.create({ testnet: true }); * ``` */ static create(config?: OstiumSubgraphClientConfig): Promise; /** * All trading pairs with computed `minSz`/`maxBSz`/`maxSSz`, live prices, and * market-status flags. Pass `pairIds` to restrict to a subset. */ getPairs(params?: GetPairsParams): Promise; /** Live mid/bid/ask prices keyed by `pairId`. */ getAllPrices(): Promise; /** * Open positions for a trader, sorted newest first, with margin summary. * * - Fetches live prices automatically. * - `blockNumber` is required for live PnL (rollover projection). When omitted, * PnL fields are zeroed. */ getOpenPositions(params: GetOpenPositionsParams): Promise; /** * Executed fills, sorted by `executedAt desc`. * * - `user`: pass an address to scope to a single trader, or `'ALL'` to fetch * fills across every trader (no trader filter). * - `pairId`: optional pair filter — when set, only fills on this pair are returned. */ getFills(params: GetFillsParams): Promise; /** Executed fills within an inclusive time range (Unix ms). Same filters as `getFills`. */ getFillsByTime(params: GetFillsByTimeParams): Promise; private fetchFills; /** Active limit orders for a trader, sorted by `updatedAt desc`. */ getOpenOrders({ user }: GetUserParams): Promise; /** * Fetch orders at any status — pending, executed, or cancelled. * * - Pass `initiatedTxHashes` (e.g. `[result.txHash]` from `openTrade` / `closeTrade`) * to poll by the subgraph `initiatedTx` field. * - Pass `orderIds` to look up by on-chain order id (mutually exclusive with * `initiatedTxHashes`). * - Pass `user: 'ALL'` to fetch global orders without a trader filter. * - Pass `builder`, `isPending`, `isCanceled`, `pairIds`, or `start` / `end` to filter the result set. */ getOrders(params?: GetOrdersParams): Promise; /** * Fetch orders routed through a builder, including sibling close orders on the * same positions. The subgraph only stores `builder` on open orders; this method * supplements phase-1 builder-tagged orders with phase-2 orders matched by `pid`. * * `limit` caps phase-1 builder-tagged orders only. Phase-2 sibling orders are * appended without a cap, so the merged result may exceed `limit`. Pass `start` * and/or `end` to filter both phases by execution time. */ getBuilderOrders(builder: Address, params?: GetBuilderOrdersParams): Promise; private fetchOrders; private pendingOrderRegisteredReader; private fetchOrdersByTradeIds; private buildOrderQueryVariables; /** * Simulate the dynamic-spread slippage a long and a short entry of each * notional would experience on the given pairs. Notionals exceeding the * side's remaining open-interest capacity (`maxOI − sideOI`) are dropped. * * Computed via `CalculateDynamicPriceImpact` from `@ostium/formulae` using * the pair's live OI / decay / threshold params + the current bid/mid/ask * from the live-prices feed (collateral = `ntl`, leverage = 1). * * ```ts * const sim = await client.getSimSlippage({ * pairIds: ['0', '1'], * ntls: ['10000', '100000', '1000000'], * }); * // → { '0': { long: [{ ntl, slippage }...], short: [...] }, '1': ... } * ``` */ getSimSlippage(params: GetSimSlippageParams): Promise; /** * Build a synthetic bid/ask orderbook for a single pair using the on-chain * dynamic-spread params. Each side gets up to `levels` (capped at 20) * exponentially-spaced notional levels (`[1, 2, 3, 5] × 10ⁿ`), stopping at * the side's remaining open-interest capacity. * * ```ts * const ob = await client.getSimOrderbook({ pairId: '0', levels: 20 }); * // ob.asks: long-entry levels (you'd buy at `px`) * // ob.bids: short-entry levels (you'd sell at `px`) * ``` */ getSimOrderbook(params: GetSimOrderbookParams): Promise; /** * Preview a trade before signing it: execution price after dynamic spread, * the fee breakdown, collateral left backing the position, resulting * liquidation price, and the validity checks that would otherwise revert * on-chain. * * Every number comes from `@ostium/formulae` — the same math the contracts * and ostium.io run — so an order ticket built on this agrees with what the * trader sees on the official frontend. * * ```ts * const preview = await client.previewOpenTrade({ * pairId: 0, isLong: true, collateral: 100, leverage: 10, * }); * * preview.entryPx; // '95234.12' — after spread * preview.fees.total; // '0.32' — deducted from collateral * preview.liquidationPx; // '86104.55' * preview.isValid; // false if `warnings` is non-empty * ``` * * Pass `limitPrice` to price a limit/stop order instead of a market order; * limit orders execute at their trigger, so they show no dynamic spread. */ previewOpenTrade(params: PreviewOpenTradeParams): Promise; /** * Protocol vault balance in USDC. This is the liquidity backing trader PnL, * and it caps how much open interest and group collateral a pair can take. */ getVaultBalance(): Promise; /** * `getVaultBalance` that swallows failures — the preview degrades to * skipping the exposure-limit check rather than failing outright. */ private fetchVaultBalanceSafe; /** * Fetch OHLC candles for a pair. * * `pairId` maps to the raw subgraph pair name internally (e.g. pair `0` → * `"BTC-USD"`). `from` / `to` are Unix milliseconds; `resolution` is one of * `"1"`, `"5"`, `"15"`, `"60"`, `"240"`, `"1D"`. Pass `sets` to fetch * multiple candle pages and return them as one flattened array. * * ```ts * const candles = await client.getCandles({ * pairId: 0, * from: Date.now() - 7 * 86_400_000, * resolution: '1D', * sets: 3, * }); * ``` */ getCandles(params: GetCandlesParams): Promise; /** * Open a WebSocket connection to the live price stream. * * Optionally filter to a subset of pairs by `pairId` — same values as returned by * `getPairs()`. When provided, the client sends `{ type: "subscribe", pairs }` on * `open` (no `?pairs=` query on the URL). Omit `pairIds` to receive the full feed. * * The returned `OstiumPriceStream` fires an initial `snapshot` event with all * cached ticks, then a `tick` event on every update. `PriceTick.from` / `.to` * are normalized display names (e.g. `"WTI"` not `"CL"`). * * ```ts * const stream = client.streamPrices([0, 1]); // BTC and ETH by pairId * * stream.onOpen(() => console.log('connected')); * stream.onSnapshot(ticks => console.log('snapshot', ticks.length)); * stream.onTick(tick => console.log(tick.pair, tick.mid)); * * // Dynamically add / remove by pairId: * stream.subscribe([2]); * stream.unsubscribe([0]); * stream.close(); * ``` * * Requires a runtime with native `WebSocket` (Node.js 18+, Bun, browsers). Bun’s * `WebSocket` may fail some `https://` upgrades (e.g. CloudFront); use Node if so. */ streamPrices(pairIds?: Array): OstiumPriceStream; /** * Stream price-driven updates for an existing `getOpenPositions()` response. * * The SDK subscribes only to the unique pairs present in `initial.pairPositions`, * recalculates price-sensitive fields for affected positions on each tick, and * emits the full updated response. * * Pass an existing `priceStream` to reuse a websocket connection your app has * already opened. Omit it to let the SDK open and manage a dedicated * connection for the tracked pair ids. */ streamPositionUpdates(initial: OpenPositionsResponse, priceStream?: OstiumPriceStream): OstiumPositionUpdatesStream; /** * Stream low-latency account confirmations. * * The stream polls the account-level subgraph snapshot for pending market * orders, active limit/stop orders, and open trades, then overlays Alchemy * contract logs so opens/closes appear before the subgraph catches up. */ streamAccountUpdates(params: StreamAccountUpdatesParams & { user: Address[]; }): OstiumAccountUpdatesStream; private fetchRawPairs; private fetchRawAccountUpdatesSnapshot; private refreshPairIdCache; private ensurePairIdCache; private ensurePairRawName; private fetchLivePricesCached; /** Wrapped `fetchLivePrices` that swallows network errors and returns `{}` by default. */ private fetchLivePricesSafe; private query; } declare class OstiumClient { private readonly builderApiUrl; private readonly signer?; private readonly submitter?; private readonly traderAddress?; private readonly effectiveSender?; private readonly contracts; private readonly publicClient; private readonly defaultSlippageBps; private readonly delegated; private readonly gasless; private readonly selfGasless; private readonly eoaSubmit?; private readonly builderAddress?; private readonly builderFeeBps?; /** Internal subgraph client backing all read methods (`getPairs`, `getOpenPositions`, …). */ readonly subgraph: OstiumSubgraphClient; private constructor(); /** * **Self + Self** — your EOA signs every transaction and pays gas directly. * * Use this when you want the simplest possible setup: one key, no smart accounts, * no delegation. Your EOA holds USDC and owns all positions. * * ```ts * const client = await OstiumClient.createSelfAndSelf({ * traderPrivateKey: '0x...', * rpcUrl: 'https://arb-mainnet.g.alchemy.com/v2/...', * }); * await client.openTrade({ ... }); * ``` */ static createSelfAndSelf(params: SelfSelfParams): Promise; /** * **Self + Gasless** — your EOA owns everything; a Safe relays trades for free. * * Your EOA holds USDC and owns all positions. A Safe smart account is derived * deterministically from your private key and registered as your on-chain delegate. * After a one-time setup (approve USDC + `setupGaslessDelegation()`), all trades * are submitted as sponsored UserOperations — no ETH required. * * ```ts * const client = await OstiumClient.createSelfAndGasless({ * traderPrivateKey: '0x...', * pimlicoUrl: 'https://builder.prod.bedrock.ostium.io/v1/sponsor?chainId=42161', * }); * // One-time setup — EOA pays gas once for each: * await client.approveUsdc('max'); * await client.setupGaslessDelegation(); * // All subsequent trading is gasless: * await client.openTrade({ ... }); * ``` */ static createSelfAndGasless(params: SelfGaslessParams): Promise; /** * **Delegated + Self** — a delegate EOA signs and pays gas on behalf of a trader address. * * The trader retains custody of USDC and positions. The delegate only needs ETH * for gas. Every trade is wrapped in `delegatedAction(traderAddress, callData)`. * The trader must call `setDelegate(delegateAddress)` once before this client * can submit trades. * * ```ts * const client = await OstiumClient.createDelegatedAndSelf({ * delegatePrivateKey: '0xDelegateKey', * traderAddress: '0xTraderAddress', * rpcUrl: 'https://arb-mainnet.g.alchemy.com/v2/...', * }); * await client.openTrade({ ... }); * ``` */ static createDelegatedAndSelf(params: DelegatedSelfParams): Promise; /** * **Delegated + Gasless** — a Safe derived from the delegate key submits sponsored * UserOperations on behalf of the trader. No ETH needed after setup. * * The trader retains custody of USDC and positions. The delegate's Safe submits * trades as UserOperations via Pimlico. The trader must call `setDelegate(safeAddress)` * once — use `client.getSmartAccountAddress()` to retrieve the Safe address. * * ```ts * const client = await OstiumClient.createDelegatedAndGasless({ * delegatePrivateKey: '0xDelegateKey', * traderAddress: '0xTraderAddress', * pimlicoUrl: 'https://builder.prod.bedrock.ostium.io/v1/sponsor?chainId=42161', * }); * await client.openTrade({ ... }); // gasless delegatedAction UserOp * ``` */ static createDelegatedAndGasless(params: DelegatedGaslessParams): Promise; /** * **Read-only client** — no signer, no submitter, no privateKey required. * * All read methods (`getPairs`, `getOpenPositions`, `getFills`, `getBalances`, …) * are available. Methods that take an optional `user` argument require it to be * passed explicitly. Calling any write method throws `INVALID_CONFIG`. * * ```ts * const reader = await OstiumClient.createReadOnly(); * const { pairs } = await reader.getPairs(); * const balances = await reader.getBalances('0xTrader...'); * const positions = await reader.getOpenPositions({ user: '0xTrader...' }); * ``` */ static createReadOnly(params?: { /** Arbitrum RPC URL. Defaults to the chain's public RPC. */ rpcUrl?: string; /** Use Arbitrum Sepolia testnet. Defaults to false (mainnet). */ testnet?: boolean; /** Override the subgraph endpoint. */ subgraphUrl?: string; /** Override the builder API base URL (prices, OHLC, WebSocket stream). */ builderApiUrl?: string; /** Alchemy API key used by `streamAccountUpdates()`. */ alchemyApiKey?: string; }): Promise; /** Internal factory shared by all public constructors. */ private static _fromConfig; /** * The on-chain address that owns trades and USDC allowances. * * - Self + Self / Delegated modes: trader's EOA or configured traderAddress. * - Self + Gasless: EOA derived from privateKey (NOT the Safe — USDC lives here). */ getTraderAddress(): Address; /** True when the client cannot submit transactions directly. */ isReadOnly(): boolean; /** True when the client can build mode-correct unsigned transaction requests. */ canBuildTransactions(): boolean; /** True when the client has the credentials needed for SDK-managed submission. */ canSubmitTransactions(): boolean; /** * Returns the Safe smart-account address used for gasless submission. * Returns undefined when not in gasless mode. * * - Self + Gasless: Safe that submits on behalf of the EOA (the delegate). * Pass this address to setupGaslessDelegation(). * - Delegated + Gasless: delegate's Safe address. * - Self + Self / Delegated + Self: returns undefined. */ getSmartAccountAddress(): Address | undefined; /** * One-time setup for Self + Gasless mode. * * Registers the Safe smart account as a delegate on the trading contract so * the Safe can submit gasless trades on behalf of your EOA. The EOA pays gas * for this single transaction; all subsequent trading is gasless. * * Only callable in Self + Gasless mode. Throws INVALID_CONFIG otherwise. * * @example * ```ts * const client = await OstiumClient.create({ privateKey: '0x...', pimlicoUrl: 'https://builder.prod.bedrock.ostium.io/v1/sponsor?chainId=42161' }); * await client.approveUsdc('max'); // EOA approves USDC (gas, one-time) * await client.setupGaslessDelegation(); // EOA sets Safe as delegate (gas, one-time) * // From here: all trading is gasless * await client.openTrade({ ... }); * ``` */ setupGaslessDelegation(): Promise; getSetupGaslessDelegationTx(): BuiltTxRequest; /** * Check whether the trader's USDC allowance covers the required amount. * The allowance is always checked against signer.traderAddress (the EOA in * Self + Gasless mode, the Safe in Delegated + Gasless). */ checkUsdcAllowance(requiredUsd: string): Promise; /** * USDC and ETH balances plus the USDC allowance to TradingStorage. * All three values are decimal strings so large values (e.g. max USDC approval) * are preserved exactly. Parse with `parseFloat` / `Number` only for display. * * In read-only mode, pass `user` explicitly. With a connected trader, omit it * to read the connected address. */ getBalances(user?: Address): Promise; /** * Approve USDC spending by the TradingStorage contract. * * - Self + Self: submitted gaslessly from EOA. * - Self + Gasless: submitted directly from EOA (the delegate cannot approve * on behalf of the trader). The EOA pays gas for this one-time operation. * - Delegated modes: throws — the trader must approve from their own account. * * @param amount USD amount as decimal string (e.g. "1000"), or "max" for MaxUint256. */ approveUsdc(amount: string): Promise; getApproveUsdcTx(amount: string): BuiltTxRequest; /** * What still stands between this trader and their first trade — USDC * approval, delegate registration, gasless setup — with the transaction * that clears each one. * * Onboarding is otherwise spread across three separate tx-builders and * three sections of BUILDER.md, with no way to ask "what is left?". This * answers that in one call, so a UI can render a checklist: * * ```ts * const status = await client.getOnboardingStatus({ requiredUsd: '1000' }); * for (const step of status.steps) { * console.log(step.description); * await wallet.sendTransaction(step.tx); // trader signs from their own account * } * ``` * * Every step is a transaction the **trader** must send themselves: a * delegate can neither approve USDC nor register itself. * * @param params.requiredUsd Collateral the trader intends to trade with. * Defaults to `"1"` — enough to prove an approval * exists at all. */ getOnboardingStatus(params?: { requiredUsd?: string; }): Promise; /** * Set a delegate on the trading contract. * * - Self + Self: EOA directly registers a delegate. * - Self + Gasless: NOT recommended — use setupGaslessDelegation() instead. * - Delegated modes: wrapped in delegatedAction so the existing delegate can * update the trader's delegation on their behalf. */ setDelegate(delegateAddress: Address): Promise; getSetDelegateTx(delegateAddress: Address): BuiltTxRequest; /** * Remove the current delegate on the trading contract. * Follows the same delegation-wrapping rules as setDelegate(). */ removeDelegate(): Promise; getRemoveDelegateTx(): BuiltTxRequest; /** * Open a new trade position. * * Call `approveUsdc()` (once) before the first trade — the contract will revert * on-chain if the USDC allowance is insufficient. Use `getBalances()` to check * the current allowance. */ openTrade(params: OpenTradeParams): Promise; getOpenTradeTx(params: OpenTradeParams): BuiltTxRequest; private resolveOpenTradeBuilder; private getOpenTradeEncoded; /** * Close an open position (full or partial). * * `pairId` and `idx` come straight from a `Position` returned by * `getOpenPositions` — pass them through directly: * * ```ts * const { pairPositions } = await client.getOpenPositions(); * const { pairId, idx } = pairPositions[0].position; * await client.closeTrade({ pairId, idx, price: '...', closePercent: 100 }); * ``` */ closeTrade(params: CloseTradeParams): Promise; getCloseTradeTx(params: CloseTradeParams): BuiltTxRequest; private getCloseTradeEncoded; /** * Cancel a pending order. * * TypeScript discriminates the params shape by `type` — required fields are * enforced at compile time. * * @example Cancel a pending limit order * ```ts * const [order] = await client.getOpenOrders(); * await client.cancelOrder({ type: CancelOrderType.Limit, pairId: order.pairId, idx: order.idx }); * ``` * @example Cancel a timed-out market open * ```ts * await client.cancelOrder({ type: CancelOrderType.PendingOpen, orderId: 123 }); * ``` * @example Cancel a timed-out market close (retry: true re-submits the close) * ```ts * await client.cancelOrder({ type: CancelOrderType.PendingClose, orderId: 456, retry: true }); * ``` */ cancelOrder(params: CancelOrderParams): Promise; getCancelOrderTx(params: CancelOrderParams): BuiltTxRequest; private getCancelOrderEncoded; /** * Modify an open trade or a pending limit order. * * `pairId` and `idx` come straight from `getOpenPositions` (for TP/SL on open * positions) or `getOpenOrders` (for limit-order edits): * * ```ts * // Update TP/SL on an open position * const { pairPositions } = await client.getOpenPositions(); * const { pairId, idx } = pairPositions[0].position; * await client.modifyOrder({ pairId, idx, takeProfit: '...', stopLoss: '...' }); * * // Re-price a pending limit order * const [order] = await client.getOpenOrders(); * await client.modifyOrder({ pairId: order.pairId, idx: order.idx, price: '...' }); * ``` * * - `price` provided → updates limit-order trigger price (with optional TP/SL). * - `takeProfit` only → calls updateTp on an open trade. * - `stopLoss` only → calls updateSl on an open trade. * - Both `takeProfit` and `stopLoss` without `price` → throws (send two calls). */ modifyOrder(params: ModifyOrderParams): Promise; getModifyOrderTx(params: ModifyOrderParams): BuiltTxRequest; private getModifyOrderEncoded; /** * Update collateral on an open position (isolated margin). * * `pairId` and `idx` come straight from a `Position` returned by `getOpenPositions`: * * ```ts * const { pairPositions } = await client.getOpenPositions(); * const { pairId, idx } = pairPositions[0].position; * await client.updateCollateral({ pairId, idx, amount: '50' }); // top up * await client.updateCollateral({ pairId, idx, amount: '-25' }); // remove * ``` * * Positive amount → topUpCollateral (adds margin, reduces effective leverage). * Negative amount → removeCollateral (removes margin, increases effective leverage). * * Checks USDC allowance before top-up operations. */ updateCollateral(params: UpdateCollateralParams): Promise; getUpdateCollateralTx(params: UpdateCollateralParams): Promise; private getUpdateCollateralEncoded; /** * All trading pairs with computed `minSz`/`maxBSz`/`maxSSz`, live prices, and * market-status flags. Pass `pairIds` to restrict to a subset. */ getPairs(params?: GetPairsParams): Promise; /** Live mid/bid/ask prices keyed by `pairId`. */ getAllPrices(): Promise; /** * Open positions + margin summary for a user. Defaults to the connected * trader. Live prices and the current block number are fetched automatically. * * - `user`: pass an address to scope to a single trader, or `'ALL'` to fetch * positions across every trader (no trader filter). * - `limit`: cap the number of positions returned (default: all). * - `skip`: offset into the result set for pagination (default: `0`). */ getOpenPositions(params?: Partial): Promise; /** * Executed fills, newest first. * * - `user` defaults to the connected trader. Pass `'ALL'` to fetch fills * across every trader (no trader filter). * - `pairId` (optional) — restricts to a single pair. * - `limit` (optional, default `1000`) — caps the result. Pass `Infinity` to * fetch every matching fill. */ getFills(params?: Partial): Promise; /** * Executed fills within a time range (Unix ms). Same filters as `getFills`, * including the default `limit: 1000`. */ getFillsByTime(params: Partial & { startTime: number; }): Promise; /** Active limit orders for a user. Defaults to the connected trader. */ getOpenOrders(params?: Partial): Promise; /** * Fetch orders at any status — pending, executed, or cancelled. * * Pass `initiatedTxHashes: [result.txHash]` to poll by the submission hash, or * `orderIds` by on-chain id. Without either, returns recent orders for the * connected trader unless `user: 'ALL'` or `builder` is provided. */ getOrders(params?: GetOrdersParams): Promise; /** * Fetch orders routed through a builder, including sibling close orders on the * same positions. See {@link OstiumSubgraphClient.getBuilderOrders}. */ getBuilderOrders(builder: Address, params?: GetBuilderOrdersParams): Promise; /** * Simulate per-side slippage for a list of pairs and notionals. * See {@link OstiumSubgraphClient.getSimSlippage} for full semantics. */ getSimSlippage(params: GetSimSlippageParams): Promise; /** * Build a synthetic bid/ask orderbook for one pair using exponentially-spaced * notional levels capped at each side's remaining OI capacity. * See {@link OstiumSubgraphClient.getSimOrderbook} for full semantics. */ getSimOrderbook(params: GetSimOrderbookParams): Promise; /** * Preview a trade before signing it — execution price after spread, fees, * resulting liquidation price, and the checks that would revert on-chain. * See {@link OstiumSubgraphClient.previewOpenTrade} for full semantics. * * ```ts * const preview = await client.previewOpenTrade({ * pairId: 0, isLong: true, collateral: 100, leverage: 10, * }); * if (!preview.isValid) console.warn(preview.warnings); * ``` */ previewOpenTrade(params: PreviewOpenTradeParams): Promise; /** * Protocol vault balance in USDC — the liquidity backing trader PnL. * See {@link OstiumSubgraphClient.getVaultBalance}. */ getVaultBalance(): Promise; /** * Fetch OHLC candles for a pair from the builder API. * * `from` / `to` are Unix milliseconds; `resolution` is one of * `"1"`, `"5"`, `"15"`, `"60"`, `"240"`, `"1D"`. Pass `sets` to fetch * multiple candle pages and return them as one flattened array. * * ```ts * const candles = await client.getCandles({ * pairId: 0, * from: Date.now() - 30 * 86_400_000, * resolution: '1D', * sets: 3, * }); * ``` */ getCandles(params: GetCandlesParams): Promise; /** * Open a WebSocket connection to the live price stream. * * Optionally filter to a subset of pairs by `pairId` — same values as returned by * `getPairs()`. When provided, the client sends `{ type: "subscribe", pairs }` on * `open` (no `?pairs=` query on the URL). Omit `pairIds` to receive the full feed. * * ```ts * const stream = client.streamPrices([0, 1]); // BTC and ETH by pairId * stream.onSnapshot(ticks => console.log(ticks)); * stream.onTick(tick => console.log(tick.pair, tick.mid)); * stream.subscribe([2]); // add pair * stream.unsubscribe([0]); // remove pair * stream.close(); * ``` * * Requires Node.js 18+, Bun, or a browser environment. Bun’s `WebSocket` may fail * some `https://` upgrades; use Node if the connection never reaches `open`. */ streamPrices(pairIds?: Array): OstiumPriceStream; /** * Stream price-driven updates for an existing `getOpenPositions()` response. * * Subscribes only to the unique pairs referenced by the response and emits the * full updated positions payload on each relevant price update. Pass an * existing `priceStream` to reuse a websocket your app already owns, or omit * it to let the SDK create a dedicated connection. */ streamPositionUpdates(initial: OpenPositionsResponse, priceStream?: OstiumPriceStream): OstiumPositionUpdatesStream; /** * Stream account confirmation snapshots for one or more traders. * * Emits full snapshots containing pending market orders, active limit/stop * orders, and open trades. Uses subgraph polling plus Alchemy contract logs so * market opens and full closes show up before subgraph indexing completes. * * Pass one or more addresses in `user` to subscribe to multiple accounts on a single * stream; defaults to the connected trader. Emitted snapshots are keyed by * normalized trader address, with `{ positions, orders, limits }` per trader. */ streamAccountUpdates(params?: StreamAccountUpdatesParams): OstiumAccountUpdatesStream; private getSetupGaslessDelegationEncoded; private getApproveUsdcEncoded; private getSetDelegateEncoded; private getRemoveDelegateEncoded; private prepareEncoded; private buildPreparedTx; private buildDirectEoaTx; private toBuiltTxRequest; private submitPrepared; /** Direct EOA submission — used only in Self + Gasless for approveUsdc and setupGaslessDelegation. */ private submitDirectEoa; private requireBuildCapability; private requireSubmitCapability; private resolveSlippage; } declare enum OstiumErrorCode { INVALID_CONFIG = "INVALID_CONFIG", VALIDATION_FAILED = "VALIDATION_FAILED", ALLOWANCE_INSUFFICIENT = "ALLOWANCE_INSUFFICIENT", SUBMISSION_FAILED = "SUBMISSION_FAILED", DELEGATION_FAILED = "DELEGATION_FAILED", CONTRACT_ERROR = "CONTRACT_ERROR", NETWORK_ERROR = "NETWORK_ERROR", /** * The operation was submitted but its outcome is unknown — do NOT resubmit. * See {@link OstiumSubmissionPendingError}. */ SUBMISSION_PENDING = "SUBMISSION_PENDING" } declare class OstiumError extends Error { readonly code: OstiumErrorCode; readonly cause?: unknown | undefined; constructor(message: string, code: OstiumErrorCode, cause?: unknown | undefined); } /** * Submitted, outcome unknown. * * A UserOperation that has been accepted by the bundler is not cancelled when * we stop waiting for its receipt — it can still land. Reporting that as a * plain failure invites the caller to retry and open the position twice, so it * gets its own type carrying the hash needed to reconcile. * * ```ts * catch (e) { * if (e instanceof OstiumSubmissionPendingError) { * // Poll the bundler for e.userOpHash, or reconcile against * // getOpenPositions() / getOrders(). Never resubmit blindly. * } * } * ``` */ declare class OstiumSubmissionPendingError extends OstiumError { /** Hash of the in-flight UserOperation. */ readonly userOpHash: `0x${string}`; constructor(message: string, /** Hash of the in-flight UserOperation. */ userOpHash: `0x${string}`, cause?: unknown); } /** * Decimal conversion utilities for trading precision * Critical: All values must be scaled correctly for smart contract calls */ /** * Parse a USDC amount string to bigint with 6 decimals * @param amount - Amount in USDC (e.g., "100.50" = 100.50 USDC) * @returns Bigint representation with 6 decimal precision */ declare function parseUsdc(amount: string | number): bigint; /** * Parse a price string to bigint with 18 decimals. * Uses string manipulation to avoid floating-point precision loss. * @param price - Price as string (e.g., "1900.50") * @returns Bigint representation with 18 decimal precision */ declare function parsePrice(price: string | number): bigint; /** * Parse leverage to contract format (leverage × 100). * @param leverage - Leverage as number (e.g., 20 for 20x) * @returns Bigint (e.g., 2000 for 20x) */ declare function parseLeverage(leverage: number): bigint; interface LiquidationPriceParams { /** Price the position opened at. */ entryPx: number; isLong: boolean; /** Collateral backing the position, in USDC. */ collateral: number; leverage: number; /** Max leverage allowed for the pair — sets the maintenance margin. */ maxLeverage: number; /** Rollover fee accrued so far, in USDC. Defaults to 0 (a fresh position). */ rollover?: number; /** Funding fee accrued so far, in USDC. Defaults to 0. */ funding?: number; } /** * Price at which a position is liquidated. * * Accrued fees push the liquidation price toward the entry price, so a * position held for a long time liquidates sooner than it did at open. * * ```ts * liquidationPrice({ * entryPx: 100_000, isLong: true, collateral: 1000, leverage: 10, maxLeverage: 100, * }); // → 90_500 * ``` */ declare function liquidationPrice(params: LiquidationPriceParams): number; interface PnLParams { entryPx: number; /** Current mark price. */ markPx: number; isLong: boolean; collateral: number; leverage: number; /** * Highest leverage the position has ever run at. Defaults to `leverage`. * Only differs after collateral has been added or removed. */ highestLeverage?: number; rollover?: number; funding?: number; } interface PnLResult { /** Net PnL in USDC, after rollover and funding. */ netPnl: number; /** Net PnL as a percentage of collateral. */ netPnlPercent: number; /** `collateral + netPnl` — what the position is worth if closed now. */ netValue: number; } /** * PnL for an open position at a given mark price. * * ```ts * pnl({ entryPx: 100_000, markPx: 105_000, isLong: true, collateral: 1000, leverage: 10 }); * // → { netPnl: 500, netPnlPercent: 50, netValue: 1500 } * ``` */ declare function pnl(params: PnLParams): PnLResult; /** * Precision constants for decimal conversions * Critical for trading calculations - all values must be scaled correctly */ declare const PRECISION_6 = 1000000n; declare const PRECISION_18 = 1000000000000000000n; declare const DEFAULT_SLIPPAGE_PERCENTAGE = 0.25; declare const MIN_OPEN_SIZE_USD = 5; declare const MIN_COLLATERAL_USD = 5; declare const MAX_COLLATERAL_USD = 2000000; declare enum OstiumSubgraphErrorCode { INVALID_CONFIG = "INVALID_CONFIG", INVALID_PARAMS = "INVALID_PARAMS", FETCH_FAILED = "FETCH_FAILED", NOT_FOUND = "NOT_FOUND", PARSE_ERROR = "PARSE_ERROR" } declare class OstiumSubgraphError extends Error { readonly code: OstiumSubgraphErrorCode; readonly cause?: unknown | undefined; constructor(message: string, code: OstiumSubgraphErrorCode, cause?: unknown | undefined); } export { type AccountUpdatesForTrader, type AccountUpdatesSnapshot, type AllPricesResponse, type AllTraders, type AllowanceStatus, type Balances, type BuiltEoaTxRequest, type BuiltSafeTxCall, type BuiltSafeTxRequest, type BuiltTxRequest, type CancelLimitOrderParams, type CancelOrderParams, CancelOrderType, type CancelPendingCloseParams, type CancelPendingOpenParams, type Candle, type CandleResolution, type ClientMode, type CloseExecution, type CloseTradeParams, DEFAULT_BUILDER_API_URL, DEFAULT_SLIPPAGE_PERCENTAGE, DEFAULT_SUBGRAPH_ENDPOINT, DEFAULT_SUBGRAPH_ENDPOINT_TESTNET, type DelegatedGaslessBuildParams, type DelegatedGaslessParams, type DelegatedGaslessSubmitParams, type DelegatedSelfBuildParams, type DelegatedSelfParams, type DelegatedSelfSubmitParams, type Fill, type FillFees, type OrderType as FillOrderType, type GetBuilderOrdersParams, type GetCandlesParams, type GetFillsByTimeParams, type GetFillsParams, type GetOpenPositionsParams, type GetOrdersParams, type GetPairsParams, type GetSimOrderbookParams, type GetSimSlippageParams, type GetUserParams, type LiquidationPriceParams, MAX_COLLATERAL_USD, MIN_COLLATERAL_USD, MIN_OPEN_SIZE_USD, type MarginSummary, type ModifyOrderParams, type OnboardingStatus, type OnboardingStep, type OpenOrder, type OpenPositionsResponse, type OpenTradeParams, type Order, type OrderAction, OrderType$1 as OrderType, OstiumAccountUpdatesStream, OstiumClient, type OstiumClientConfig, OstiumError, OstiumErrorCode, OstiumPositionUpdatesStream, OstiumPriceStream, OstiumSubgraphClient, type OstiumSubgraphClientConfig, OstiumSubgraphError, OstiumSubgraphErrorCode, OstiumSubmissionPendingError, PRECISION_18, PRECISION_6, type Pair, type PairPosition, type PairSchedule, type PairsResponse, type PnLParams, type PnLResult, type Position, type PreviewFees, type PreviewOpenTradeParams, type PreviewOpenTradeResult, type PreviewWarning, type PriceData, type PriceTick, type SelfGaslessBuildParams, type SelfGaslessParams, type SelfGaslessSubmitParams, type SelfSelfBuildParams, type SelfSelfParams, type SelfSelfSubmitParams, type SimOrderbookLevel, type SimOrderbookResponse, type SimSlippageByPairId, type SimSlippageForPair, type SimSlippageRow, type StreamAccountUpdatesParams, type SubmissionResult, type TransactionReceiptLike, type UpdateCollateralParams, extractOrderIdFromReceipt, liquidationPrice, parseLeverage, parsePrice, parseUsdc, pnl };