diff --git a/core/api-doc-config.generated.json b/core/api-doc-config.generated.json index 40aaff04..327ee5ce 100644 --- a/core/api-doc-config.generated.json +++ b/core/api-doc-config.generated.json @@ -1,5 +1,5 @@ { - "_generated": "Auto-generated by extract-jsdoc.js on 2026-07-10T06:40:05.097Z. Do not edit manually.", + "_generated": "Auto-generated by extract-jsdoc.js on 2026-08-06T18:56:58.173Z. Do not edit manually.", "methods": { "has": { "summary": "HTTP verb for the endpoint (e.g. GET, POST). */", @@ -9,17 +9,114 @@ "type": "ExchangeHas", "description": "Result" }, - "source": "BaseExchange.ts:42" + "source": "BaseExchange.ts:46" }, - "implicitApi": { + "getAuthNonce": { "summary": "Override in subclasses to force specific capability values.", - "description": "Use `'emulated'` for methods backed by a non-native mechanism,\nor `false` for methods that override the base only to throw a\nbetter error message (e.g. \"pari-mutuel bets cannot be cancelled\").\n/\n protected readonly capabilityOverrides: Partial> = {};\n\n protected credentials?: ExchangeCredentials;\n // Implicit API (merged across multiple defineImplicitApi calls)\n protected apiDescriptor?: ApiDescriptor;\n private _throttler: Throttler;\n // Snapshot state for cursor-based pagination\n private _snapshotTTL: number;\n private _snapshot?: { markets: UnifiedMarket[]; takenAt: number; id: string };\n private _eventSnapshot?: { events: UnifiedEvent[]; takenAt: number; id: string };\n private apiDescriptors: ApiDescriptor[] = [];\n\n constructor(credentials?: ExchangeCredentials, options?: ExchangeOptions) {\n this.credentials = credentials;\n this._snapshotTTL = options?.snapshotTTL ?? 0;\n this.http = axios.create({\n headers: {\n 'User-Agent': `pmxt (https://github.com/pmxt-dev/pmxt)`\n },\n paramsSerializer: {\n serialize: (params) => {\n const sp = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n if (Array.isArray(v)) v.forEach((x) => sp.append(k, String(x)));\n else sp.append(k, String(v));\n }\n return sp.toString();\n },\n },\n });\n this._throttler = new Throttler({\n refillRate: 1 / this._rateLimit,\n capacity: 1,\n delay: 1,\n });\n\n // Rate Limit Interceptor\n this.http.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {\n if (this.enableRateLimit) {\n await this._throttler.throttle();\n }\n return config;\n });\n\n // Request Interceptor\n this.http.interceptors.request.use((config: InternalAxiosRequestConfig) => {\n if (this.verbose) {\n logger.debug(`-> ${config.method?.toUpperCase()} ${config.url}`);\n if (config.params) logger.debug('params:', { params: config.params });\n if (config.data) logger.debug('body:', { body: config.data });\n }\n return config;\n });\n\n // Response Interceptor\n this.http.interceptors.response.use(\n (response: AxiosResponse) => {\n if (this.verbose) {\n logger.debug(`<- ${response.status} ${response.statusText} ${response.config.url}`);\n }\n return response;\n },\n (error: any) => {\n if (this.verbose) {\n logger.debug(`REQUEST FAILED: ${error.config?.url}`, {\n error: error.message,\n status: error.response?.status,\n data: error.response?.data,\n });\n }\n return Promise.reject(error);\n }\n );\n }\n\n private _rateLimit: number = 1000;\n\n get rateLimit(): number {\n return this._rateLimit;\n }\n\n set rateLimit(value: number) {\n this._rateLimit = value;\n this._throttler = new Throttler({\n refillRate: 1 / value,\n capacity: 1,\n delay: 1,\n });\n }\n\n abstract get name(): string;\n\n /**\nIntrospection getter: returns info about all implicit API methods.", + "description": "Use `'emulated'` for methods backed by a non-native mechanism,\nor `false` for methods that override the base only to throw a\nbetter error message (e.g. \"pari-mutuel bets cannot be cancelled\").\n/\n protected readonly capabilityOverrides: Partial> = {};\n\n protected credentials?: ExchangeCredentials;\n // Implicit API (merged across multiple defineImplicitApi calls)\n protected apiDescriptor?: ApiDescriptor;\n private _throttler: Throttler;\n // Snapshot state for cursor-based pagination\n private _snapshotTTL: number;\n private _snapshot?: { markets: UnifiedMarket[]; takenAt: number; id: string };\n private _eventSnapshot?: { events: UnifiedEvent[]; takenAt: number; id: string };\n private apiDescriptors: ApiDescriptor[] = [];\n protected _sessions: Map = new Map();\n\n constructor(credentials?: ExchangeCredentials, options?: ExchangeOptions) {\n this.credentials = credentials;\n this._snapshotTTL = options?.snapshotTTL ?? 0;\n this.http = axios.create({\n headers: {\n 'User-Agent': `pmxt (https://github.com/pmxt-dev/pmxt)`\n },\n paramsSerializer: {\n serialize: (params) => {\n const sp = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n if (Array.isArray(v)) v.forEach((x) => sp.append(k, String(x)));\n else sp.append(k, String(v));\n }\n return sp.toString();\n },\n },\n });\n this._throttler = new Throttler({\n refillRate: 1 / this._rateLimit,\n capacity: 1,\n delay: 1,\n });\n\n // Rate Limit Interceptor\n this.http.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {\n if (this.enableRateLimit) {\n await this._throttler.throttle();\n }\n return config;\n });\n\n // Request Interceptor\n this.http.interceptors.request.use((config: InternalAxiosRequestConfig) => {\n if (this.verbose) {\n logger.debug(`-> ${config.method?.toUpperCase()} ${config.url}`);\n if (config.params) logger.debug('params:', { params: config.params });\n if (config.data) logger.debug('body:', { body: config.data });\n }\n return config;\n });\n\n // Response Interceptor\n this.http.interceptors.response.use(\n (response: AxiosResponse) => {\n if (this.verbose) {\n logger.debug(`<- ${response.status} ${response.statusText} ${response.config.url}`);\n }\n return response;\n },\n (error: any) => {\n if (this.verbose) {\n logger.debug(`REQUEST FAILED: ${error.config?.url}`, {\n error: error.message,\n status: error.response?.status,\n data: error.response?.data,\n });\n }\n return Promise.reject(error);\n }\n );\n }\n\n private _rateLimit: number = 1000;\n\n get rateLimit(): number {\n return this._rateLimit;\n }\n\n set rateLimit(value: number) {\n this._rateLimit = value;\n this._throttler = new Throttler({\n refillRate: 1 / value,\n capacity: 1,\n delay: 1,\n });\n }\n\n abstract get name(): string;\n\n /**\nGet a cryptographic nonce for Web3 login.", + "params": [ + { + "name": "walletAddress", + "type": "string", + "optional": false, + "description": "The wallet address to authenticate" + } + ], + "returns": { + "type": "AuthNonceResponse", + "description": "Result" + }, + "source": "BaseExchange.ts:463" + }, + "loginWithSignature": { + "summary": "Login with a signed nonce to obtain session credentials.", + "description": "Login with a signed nonce to obtain session credentials.", + "params": [ + { + "name": "walletAddress", + "type": "string", + "optional": false, + "description": "The wallet address" + }, + { + "name": "signature", + "type": "string", + "optional": false, + "description": "The signature of the nonce message" + }, + { + "name": "nonce", + "type": "string", + "optional": false, + "description": "The nonce that was signed" + } + ], + "returns": { + "type": "AuthLoginResponse", + "description": "Result" + }, + "source": "BaseExchange.ts:571" + }, + "logout": { + "summary": "Logout and invalidate the current session.", + "description": "Logout and invalidate the current session.", + "params": [ + { + "name": "walletAddress", + "type": "string", + "optional": true, + "description": "The wallet address to logout (optional)" + } + ], + "returns": { + "type": "void", + "description": "Result" + }, + "source": "BaseExchange.ts:585" + }, + "isSessionActive": { + "summary": "Check if a session is active for the given wallet address.", + "description": "Check if a session is active for the given wallet address.", + "params": [ + { + "name": "walletAddress", + "type": "string", + "optional": false, + "description": "The wallet address to check" + } + ], + "returns": { + "type": "boolean", + "description": "Result" + }, + "source": "BaseExchange.ts:593" + }, + "getSession": { + "summary": "Get the stored session for a wallet address.", + "description": "SECURITY: This is an in-process helper only and is deliberately excluded\nfrom the HTTP/RPC server surface (see EXCLUDED_METHODS in\nscripts/generate-openapi.js). It returns session credentials (apiKey /\napiSecret / passphrase), so it must never be reachable over the network,\nwhere the wallet address — a public value — would otherwise let any caller\nretrieve another user's secrets.", + "params": [ + { + "name": "walletAddress", + "type": "string", + "optional": false, + "description": "The wallet address" + } + ], + "returns": { + "type": "AuthSession | undefined", + "description": "Result" + }, + "source": "BaseExchange.ts:607" + }, + "implicitApi": { + "summary": "Introspection getter: returns info about all implicit API methods.", + "description": "Introspection getter: returns info about all implicit API methods.", "params": [], "returns": { "type": "ImplicitApiMethodInfo[]", "description": "Result" }, - "source": "BaseExchange.ts:459" + "source": "BaseExchange.ts:657" }, "loadMarkets": { "summary": "Load and cache all markets from the exchange into `this.markets` and `this.marketsBySlug`.", @@ -36,7 +133,7 @@ "type": "Record", "description": "Dictionary of markets indexed by marketId" }, - "source": "BaseExchange.ts:572" + "source": "BaseExchange.ts:671" }, "fetchMarkets": { "summary": "Fetch markets with optional filtering, search, or slug lookup.", @@ -83,7 +180,7 @@ "ordering — exchanges may reorder or add markets between requests. For stable iteration\nacross pages, use `loadMarkets()` and paginate over `Object.values(exchange.markets)`.", "Some exchanges (like Limitless) may only support status 'active' for search results." ], - "source": "BaseExchange.ts:609" + "source": "BaseExchange.ts:708" }, "fetchMarketsPaginated": { "summary": "Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.", @@ -110,7 +207,7 @@ "type": "PaginatedMarketsResult", "description": "PaginatedMarketsResult with data, total, and optional nextCursor" }, - "source": "BaseExchange.ts:664" + "source": "BaseExchange.ts:763" }, "fetchEventsPaginated": { "summary": "Paginated variant of {@link fetchEvents}.", @@ -137,7 +234,7 @@ "type": "PaginatedEventsResult", "description": "PaginatedEventsResult with data, total, and optional nextCursor" }, - "source": "BaseExchange.ts:733" + "source": "BaseExchange.ts:832" }, "fetchEvents": { "summary": "Fetch events with optional keyword search.", @@ -175,7 +272,7 @@ "notes": [ "Some exchanges (like Limitless) may only support status 'active' for search results." ], - "source": "BaseExchange.ts:802" + "source": "BaseExchange.ts:901" }, "fetchSeries": { "summary": "Fetch the recurring series (fourth tier above Event -> Market -> Outcome)", @@ -192,7 +289,7 @@ "type": "UnifiedSeries[]", "description": "Array of unified series. Always an array, including the singular-lookup case." }, - "source": "BaseExchange.ts:841" + "source": "BaseExchange.ts:940" }, "fetchMarket": { "summary": "Fetch a single market by lookup parameters.", @@ -209,7 +306,7 @@ "type": "UnifiedMarket", "description": "A single unified market" }, - "source": "BaseExchange.ts:859" + "source": "BaseExchange.ts:958" }, "fetchEvent": { "summary": "Fetch a single event by lookup parameters.", @@ -226,7 +323,7 @@ "type": "UnifiedEvent", "description": "A single unified event" }, - "source": "BaseExchange.ts:959" + "source": "BaseExchange.ts:1058" }, "fetchEventMetadata": { "summary": "Fetch venue-native metadata for a specific event when the exchange", @@ -243,7 +340,7 @@ "type": "Record", "description": "Result" }, - "source": "BaseExchange.ts:976" + "source": "BaseExchange.ts:1075" }, "fetchOHLCV": { "summary": "Fetch historical OHLCV (candlestick) price data for a specific market outcome.", @@ -271,7 +368,7 @@ "Polymarket: outcomeId is the CLOB Token ID. Kalshi: outcomeId is the Market Ticker.", "Common resolutions: '1m' | '5m' | '15m' | '1h' | '6h' | '1d'. Arbitrary intervals (e.g. '30s', '120s', '3h') accepted by venues that support them." ], - "source": "BaseExchange.ts:987" + "source": "BaseExchange.ts:1086" }, "fetchOrderBook": { "summary": "Fetch the order book (bids/asks) for a specific outcome.", @@ -300,7 +397,7 @@ "type": "OrderBook", "description": "Order book with bids and asks. Returns OrderBook[] when" }, - "source": "BaseExchange.ts:1002" + "source": "BaseExchange.ts:1101" }, "fetchOrderBooks": { "summary": "Batch variant of {@link fetchOrderBook}. Fetches order books for", @@ -317,7 +414,7 @@ "type": "Record", "description": "A map keyed by the input id (preserving the caller's exact" }, - "source": "BaseExchange.ts:1030" + "source": "BaseExchange.ts:1129" }, "fetchTrades": { "summary": "Fetch raw trade history for a specific outcome.", @@ -343,7 +440,7 @@ "notes": [ "Polymarket requires an API key for trade history. Use fetchOHLCV for public historical data." ], - "source": "BaseExchange.ts:1043" + "source": "BaseExchange.ts:1142" }, "createOrder": { "summary": "Place a new order on the exchange.", @@ -360,7 +457,7 @@ "type": "Order", "description": "The created order" }, - "source": "BaseExchange.ts:1060" + "source": "BaseExchange.ts:1159" }, "buildOrder": { "summary": "Build an order payload without submitting it to the exchange.", @@ -377,7 +474,7 @@ "type": "BuiltOrder", "description": "A BuiltOrder containing the exchange-native payload" }, - "source": "BaseExchange.ts:1074" + "source": "BaseExchange.ts:1173" }, "submitOrder": { "summary": "Submit a pre-built order returned by buildOrder().", @@ -394,7 +491,7 @@ "type": "Order", "description": "The submitted order" }, - "source": "BaseExchange.ts:1086" + "source": "BaseExchange.ts:1185" }, "cancelOrder": { "summary": "Cancel an existing open order.", @@ -411,7 +508,7 @@ "type": "Order", "description": "The cancelled order" }, - "source": "BaseExchange.ts:1096" + "source": "BaseExchange.ts:1195" }, "fetchOrder": { "summary": "Fetch a specific order by ID.", @@ -428,7 +525,7 @@ "type": "Order", "description": "The order details" }, - "source": "BaseExchange.ts:1106" + "source": "BaseExchange.ts:1205" }, "fetchOpenOrders": { "summary": "Fetch all open orders, optionally filtered by market.", @@ -445,7 +542,7 @@ "type": "Order[]", "description": "Array of open orders" }, - "source": "BaseExchange.ts:1116" + "source": "BaseExchange.ts:1215" }, "fetchMyTrades": { "summary": "Fetch authenticated user trade history.", @@ -488,7 +585,7 @@ "type": "UserTrade[]", "description": "Array of user trades" }, - "source": "BaseExchange.ts:1126" + "source": "BaseExchange.ts:1225" }, "fetchClosedOrders": { "summary": "Fetch authenticated closed orders.", @@ -527,7 +624,7 @@ "type": "Order[]", "description": "Array of closed orders" }, - "source": "BaseExchange.ts:1142" + "source": "BaseExchange.ts:1241" }, "fetchAllOrders": { "summary": "Fetch authenticated order history across open and closed orders.", @@ -566,7 +663,7 @@ "type": "Order[]", "description": "Array of orders" }, - "source": "BaseExchange.ts:1157" + "source": "BaseExchange.ts:1256" }, "fetchPositions": { "summary": "Fetch current user positions across all markets.", @@ -583,7 +680,7 @@ "type": "Position[]", "description": "Array of user positions" }, - "source": "BaseExchange.ts:1172" + "source": "BaseExchange.ts:1271" }, "fetchBalance": { "summary": "Fetch account balances.", @@ -600,7 +697,7 @@ "type": "Balance[]", "description": "Array of account balances" }, - "source": "BaseExchange.ts:1182" + "source": "BaseExchange.ts:1281" }, "getExecutionPrice": { "summary": "Calculate the volume-weighted average execution price for a given order size.", @@ -629,7 +726,7 @@ "type": "number", "description": "Average execution price, or 0 if insufficient liquidity" }, - "source": "BaseExchange.ts:1192" + "source": "BaseExchange.ts:1291" }, "getExecutionPriceDetailed": { "summary": "Calculate detailed execution price information including partial fill data.", @@ -658,7 +755,7 @@ "type": "ExecutionPriceResult", "description": "Detailed execution result with price, filled amount, and fill status" }, - "source": "BaseExchange.ts:1205" + "source": "BaseExchange.ts:1304" }, "filterMarkets": { "summary": "Filter a list of markets by criteria.", @@ -681,7 +778,7 @@ "type": "UnifiedMarket[]", "description": "Filtered array of markets" }, - "source": "BaseExchange.ts:1221" + "source": "BaseExchange.ts:1320" }, "filterEvents": { "summary": "Filter a list of events by criteria.", @@ -704,7 +801,7 @@ "type": "UnifiedEvent[]", "description": "Filtered array of events" }, - "source": "BaseExchange.ts:1381" + "source": "BaseExchange.ts:1480" }, "watchOrderBook": { "summary": "Watch order book updates in real-time via WebSocket.", @@ -733,7 +830,7 @@ "type": "OrderBook", "description": "Promise that resolves with the current orderbook state" }, - "source": "BaseExchange.ts:1477" + "source": "BaseExchange.ts:1576" }, "watchOrderBooks": { "summary": "Watch multiple order books simultaneously via WebSocket.", @@ -762,7 +859,7 @@ "type": "Record", "description": "Promise that resolves with order books keyed by ID" }, - "source": "BaseExchange.ts:1490" + "source": "BaseExchange.ts:1589" }, "unwatchOrderBook": { "summary": "Unsubscribe from a previously watched order book stream.", @@ -779,7 +876,7 @@ "type": "void", "description": "Result" }, - "source": "BaseExchange.ts:1518" + "source": "BaseExchange.ts:1617" }, "watchTrades": { "summary": "Watch trade executions in real-time via WebSocket.", @@ -814,7 +911,7 @@ "type": "Trade[]", "description": "Promise that resolves with recent trades" }, - "source": "BaseExchange.ts:1531" + "source": "BaseExchange.ts:1630" }, "watchAddress": { "summary": "Stream activity for a public wallet address", @@ -837,7 +934,7 @@ "type": "SubscribedAddressSnapshot", "description": "Promise that resolves with the latest SubscribedAddressSnapshot snapshot" }, - "source": "BaseExchange.ts:1545" + "source": "BaseExchange.ts:1644" }, "unwatchAddress": { "summary": "Stop watching a previously registered wallet address and release its resource updates.", @@ -854,7 +951,7 @@ "type": "void", "description": "Result" }, - "source": "BaseExchange.ts:1558" + "source": "BaseExchange.ts:1657" }, "close": { "summary": "Close all WebSocket connections and clean up resources.", @@ -864,7 +961,7 @@ "type": "void", "description": "Result" }, - "source": "BaseExchange.ts:1567" + "source": "BaseExchange.ts:1666" }, "fetchMarketMatches": { "summary": "Find the same or related market on other venues. Two modes:", @@ -881,7 +978,7 @@ "type": "MatchResult[]", "description": "Array of matched markets with relation and confidence" }, - "source": "BaseExchange.ts:1581" + "source": "BaseExchange.ts:1680" }, "fetchMatches": { "summary": "fetchMatches", @@ -898,7 +995,7 @@ "type": "MatchResult[]", "description": "Result" }, - "source": "BaseExchange.ts:1597" + "source": "BaseExchange.ts:1696" }, "fetchEventMatches": { "summary": "Find the same or related event on other venues. Two modes:", @@ -915,7 +1012,7 @@ "type": "EventMatchResult[]", "description": "Array of matched events with market-level match details" }, - "source": "BaseExchange.ts:1605" + "source": "BaseExchange.ts:1704" }, "compareMarketPrices": { "summary": "Compare live prices for the same market across venues. Finds identity matches and returns side-by-side best bid/ask prices so you can spot price differences at a glance.", @@ -923,7 +1020,7 @@ "params": [ { "name": "params", - "type": "FetchMatchesParams", + "type": "CompareMarketPricesParams", "optional": false, "description": "Match filter parameters (uses relation: 'identity' internally)" } @@ -932,7 +1029,7 @@ "type": "PriceComparison[]", "description": "Array of price comparisons across venues" }, - "source": "BaseExchange.ts:1621" + "source": "BaseExchange.ts:1720" }, "fetchRelatedMarkets": { "summary": "Find related markets across venues. Discovers subset/superset market relationships", @@ -949,7 +1046,7 @@ "type": "PriceComparison[]", "description": "Array of subset/superset matches with live prices" }, - "source": "BaseExchange.ts:1631" + "source": "BaseExchange.ts:1730" }, "fetchMatchedMarkets": { "summary": "fetchMatchedMarkets", @@ -966,7 +1063,7 @@ "type": "MatchedMarketPair[]", "description": "Result" }, - "source": "BaseExchange.ts:1642" + "source": "BaseExchange.ts:1741" }, "fetchMatchedPrices": { "summary": "fetchMatchedPrices", @@ -983,7 +1080,7 @@ "type": "MatchedPricePair[]", "description": "Array of matched market pairs with prices from each venue" }, - "source": "BaseExchange.ts:1650" + "source": "BaseExchange.ts:1749" }, "fetchHedges": { "summary": "fetchHedges", @@ -1000,7 +1097,7 @@ "type": "PriceComparison[]", "description": "Array of subset/superset matches with live prices" }, - "source": "BaseExchange.ts:1661" + "source": "BaseExchange.ts:1760" }, "fetchArbitrage": { "summary": "fetchArbitrage", @@ -1017,7 +1114,7 @@ "type": "ArbitrageOpportunity[]", "description": "Array of arbitrage opportunities sorted by spread" }, - "source": "BaseExchange.ts:1671" + "source": "BaseExchange.ts:1770" }, "watchPrices": { "summary": "Watch AMM price updates for a market address (Limitless only).", @@ -1041,7 +1138,7 @@ "description": "Result" }, "exchangeOnly": "limitless", - "source": "index.ts:492" + "source": "index.ts:498" }, "watchUserPositions": { "summary": "Watch user positions in real-time (Limitless only).", @@ -1059,7 +1156,7 @@ "description": "Result" }, "exchangeOnly": "limitless", - "source": "index.ts:504" + "source": "index.ts:510" }, "watchUserTransactions": { "summary": "Watch user transactions in real-time (Limitless only).", @@ -1077,7 +1174,7 @@ "description": "Result" }, "exchangeOnly": "limitless", - "source": "index.ts:516" + "source": "index.ts:522" }, "initAuth": { "summary": "Initialize L2 API credentials for implicit API signing.", @@ -1124,7 +1221,7 @@ "description": "The UnifiedEvent, or null if not found" }, "exchangeOnly": "probable", - "source": "index.ts:152" + "source": "index.ts:197" }, "getEventBySlug": { "summary": "Fetch a single event by its URL slug (Probable only).", @@ -1142,7 +1239,7 @@ "description": "The UnifiedEvent, or null if not found" }, "exchangeOnly": "probable", - "source": "index.ts:171" + "source": "index.ts:216" }, "watchAllOrderBooks": { "summary": "Stream all orderbook updates across venues via the hosted WebSocket API.", @@ -1159,7 +1256,7 @@ "type": "FirehoseEvent", "description": "Next event with source, symbol, and orderbook" }, - "source": "client.ts:2057" + "source": "client.ts:2172" }, "firehose": { "summary": "Stream all orderbook updates across venues.", @@ -1176,7 +1273,7 @@ "type": "FirehoseEvent", "description": "Next event with source, symbol, and orderbook" }, - "source": "client.ts:2098" + "source": "client.ts:2213" } }, "workflowExample": { diff --git a/sdks/python/API_REFERENCE.md b/sdks/python/API_REFERENCE.md index eabcd275..2002e92b 100644 --- a/sdks/python/API_REFERENCE.md +++ b/sdks/python/API_REFERENCE.md @@ -127,6 +127,133 @@ exchange.has ``` +--- +### `get_auth_nonce` + +Override in subclasses to force specific capability values. + + +**Signature:** + +```python +def get_auth_nonce(wallet_address: str) -> AuthNonceResponse: +``` + +**Parameters:** + +- `wallet_address` (str): The wallet address to authenticate + +**Returns:** AuthNonceResponse - Result + +**Example:** + +```python +exchange.get_auth_nonce(wallet_address="...") +``` + + +--- +### `login_with_signature` + +Login with a signed nonce to obtain session credentials. + + +**Signature:** + +```python +def login_with_signature(wallet_address: str, signature: str, nonce: str) -> AuthLoginResponse: +``` + +**Parameters:** + +- `wallet_address` (str): The wallet address +- `signature` (str): The signature of the nonce message +- `nonce` (str): The nonce that was signed + +**Returns:** AuthLoginResponse - Result + +**Example:** + +```python +exchange.login_with_signature(wallet_address="...", signature="...", nonce="...") +``` + + +--- +### `logout` + +Logout and invalidate the current session. + + +**Signature:** + +```python +def logout(wallet_address: Optional[str] = None) -> None: +``` + +**Parameters:** + +- `wallet_address` (str) - **Optional**: The wallet address to logout (optional) + +**Returns:** None - Result + +**Example:** + +```python +exchange.logout(wallet_address="...") +``` + + +--- +### `is_session_active` + +Check if a session is active for the given wallet address. + + +**Signature:** + +```python +def is_session_active(wallet_address: str) -> bool: +``` + +**Parameters:** + +- `wallet_address` (str): The wallet address to check + +**Returns:** bool - Result + +**Example:** + +```python +exchange.is_session_active(wallet_address="...") +``` + + +--- +### `get_session` + +Get the stored session for a wallet address. + + +**Signature:** + +```python +def get_session(wallet_address: str) -> Optional[AuthSession]: +``` + +**Parameters:** + +- `wallet_address` (str): The wallet address + +**Returns:** Optional[AuthSession] - Result + +**Example:** + +```python +exchange.get_session(wallet_address="...") +``` + + --- ### `load_markets` @@ -1172,12 +1299,12 @@ Compare live prices for the same market across venues. Finds identity matches an **Signature:** ```python -def compare_market_prices(params: FetchMatchesParams) -> List[PriceComparison]: +def compare_market_prices(params: CompareMarketPricesParams) -> List[PriceComparison]: ``` **Parameters:** -- `params` (FetchMatchesParams): Match filter parameters (uses relation: 'identity' internally) +- `params` (CompareMarketPricesParams): Match filter parameters (uses relation: 'identity' internally) **Returns:** List[[PriceComparison](#pricecomparison)] - Array of price comparisons across venues diff --git a/sdks/python/pmxt/_exchanges.py b/sdks/python/pmxt/_exchanges.py index 2b1249c6..088863b8 100644 --- a/sdks/python/pmxt/_exchanges.py +++ b/sdks/python/pmxt/_exchanges.py @@ -593,6 +593,7 @@ def __init__( auto_start_server: Optional[bool] = None, pmxt_api_key: Optional[str] = None, wallet_address: Optional[str] = None, + api_base_url: Optional[str] = None, signer: Optional[object] = None, websocket: Optional[dict] = None, ) -> None: @@ -604,6 +605,10 @@ def __init__( auto_start_server: Automatically start server if not running (default: True) pmxt_api_key: Hosted PMXT API key (optional; enables hosted mode) wallet_address: Wallet address for hosted reads/writes (optional) + api_base_url: Base URL of the SuiBets exchange API itself (not the + sidecar — that is ``base_url``). Forwarded to the sidecar as the + ``baseUrl`` credential; falls back to the SUIBETS_BASE_URL env + var on the sidecar side when unset (optional) signer: Custom signer for hosted writes (optional) websocket: WebSocket transport configuration dict (optional) """ @@ -616,11 +621,14 @@ def __init__( signer=signer, websocket=websocket, ) + self.api_base_url = api_base_url def _get_credentials_dict(self) -> Optional[Dict[str, Any]]: creds = super()._get_credentials_dict() or {} if self.wallet_address: creds["walletAddress"] = self.wallet_address + if self.api_base_url: + creds["baseUrl"] = self.api_base_url return creds if creds else None diff --git a/sdks/python/pmxt/models.py b/sdks/python/pmxt/models.py index 96ad499c..9954e9b4 100644 --- a/sdks/python/pmxt/models.py +++ b/sdks/python/pmxt/models.py @@ -671,6 +671,7 @@ class PolymarketOptions(ExchangeOptions, total=False): class SuiBetsOptions(ExchangeOptions, total=False): """Constructor options for SuiBets clients.""" wallet_address: str + api_base_url: str class RouterOptions(TypedDict, total=False): diff --git a/sdks/python/tests/test_hosted_dispatch.py b/sdks/python/tests/test_hosted_dispatch.py index 85f9315a..7d0a0b4f 100644 --- a/sdks/python/tests/test_hosted_dispatch.py +++ b/sdks/python/tests/test_hosted_dispatch.py @@ -179,6 +179,25 @@ def test_suibets_constructor_accepts_wallet_address_for_hosted_mode() -> None: assert api._get_credentials_dict() == {"walletAddress": WALLET_ADDRESS} +def test_suibets_constructor_forwards_api_base_url_credential() -> None: + api = SuiBets( + wallet_address=WALLET_ADDRESS, + api_base_url="https://suibets.example", + auto_start_server=False, + ) + + assert api._get_credentials_dict() == { + "walletAddress": WALLET_ADDRESS, + "baseUrl": "https://suibets.example", + } + + +def test_suibets_api_base_url_alone_produces_credentials() -> None: + api = SuiBets(api_base_url="https://suibets.example", auto_start_server=False) + + assert api._get_credentials_dict() == {"baseUrl": "https://suibets.example"} + + # --------------------------------------------------------------------------- # # Read-method dispatch tests # --------------------------------------------------------------------------- # diff --git a/sdks/typescript/API_REFERENCE.md b/sdks/typescript/API_REFERENCE.md index bbe5a1fe..d2d3e6ab 100644 --- a/sdks/typescript/API_REFERENCE.md +++ b/sdks/typescript/API_REFERENCE.md @@ -129,6 +129,133 @@ exchange.has ``` +--- +### `getAuthNonce` + +Override in subclasses to force specific capability values. + + +**Signature:** + +```typescript +async getAuthNonce(walletAddress: string): Promise +``` + +**Parameters:** + +- `walletAddress` (string): The wallet address to authenticate + +**Returns:** Promise - Result + +**Example:** + +```typescript +await exchange.getAuthNonce("...") +``` + + +--- +### `loginWithSignature` + +Login with a signed nonce to obtain session credentials. + + +**Signature:** + +```typescript +async loginWithSignature(walletAddress: string, signature: string, nonce: string): Promise +``` + +**Parameters:** + +- `walletAddress` (string): The wallet address +- `signature` (string): The signature of the nonce message +- `nonce` (string): The nonce that was signed + +**Returns:** Promise - Result + +**Example:** + +```typescript +await exchange.loginWithSignature("...", "...", "...") +``` + + +--- +### `logout` + +Logout and invalidate the current session. + + +**Signature:** + +```typescript +async logout(walletAddress?: string): Promise +``` + +**Parameters:** + +- `walletAddress` (string) - **Optional**: The wallet address to logout (optional) + +**Returns:** Promise - Result + +**Example:** + +```typescript +await exchange.logout({ walletAddress: "..." }) +``` + + +--- +### `isSessionActive` + +Check if a session is active for the given wallet address. + + +**Signature:** + +```typescript +async isSessionActive(walletAddress: string): Promise +``` + +**Parameters:** + +- `walletAddress` (string): The wallet address to check + +**Returns:** Promise - Result + +**Example:** + +```typescript +await exchange.isSessionActive("...") +``` + + +--- +### `getSession` + +Get the stored session for a wallet address. + + +**Signature:** + +```typescript +async getSession(walletAddress: string): Promise +``` + +**Parameters:** + +- `walletAddress` (string): The wallet address + +**Returns:** Promise - Result + +**Example:** + +```typescript +await exchange.getSession("...") +``` + + --- ### `loadMarkets` @@ -1174,12 +1301,12 @@ Compare live prices for the same market across venues. Finds identity matches an **Signature:** ```typescript -async compareMarketPrices(params: FetchMatchesParams): Promise +async compareMarketPrices(params: CompareMarketPricesParams): Promise ``` **Parameters:** -- `params` (FetchMatchesParams): Match filter parameters (uses relation: 'identity' internally) +- `params` (CompareMarketPricesParams): Match filter parameters (uses relation: 'identity' internally) **Returns:** Promise<[PriceComparison](#pricecomparison)[]> - Array of price comparisons across venues diff --git a/sdks/typescript/pmxt/client.ts b/sdks/typescript/pmxt/client.ts index 04ddc27f..48769b03 100644 --- a/sdks/typescript/pmxt/client.ts +++ b/sdks/typescript/pmxt/client.ts @@ -3648,6 +3648,14 @@ export interface SuiBetsOptions extends ExchangeOptions { * SUIBETS_WALLET_ADDRESS environment variable on the sidecar. */ walletAddress?: string; + + /** + * Base URL of the SuiBets exchange API itself (not the PMXT sidecar — + * use `baseUrl` for that). Forwarded to the sidecar as the `baseUrl` + * credential. Can also be set via the SUIBETS_BASE_URL environment + * variable on the sidecar. + */ + apiBaseUrl?: string; } /** @@ -3669,25 +3677,29 @@ export interface SuiBetsOptions extends ExchangeOptions { */ export class SuiBets extends Exchange { private readonly _walletAddress?: string; + private readonly _apiBaseUrl?: string; constructor(options: SuiBetsOptions = {}) { super("suibets", options); this._walletAddress = options.walletAddress; + this._apiBaseUrl = options.apiBaseUrl; } /** * Includes walletAddress in the credentials sent to the sidecar so - * that fetchPositions() can reach the /api/p2p/my endpoint. - * Falls back to SUIBETS_WALLET_ADDRESS env var on the sidecar side - * when walletAddress is not set here. + * that fetchPositions() can reach the /api/p2p/my endpoint, and + * apiBaseUrl as the `baseUrl` credential controlling the SuiBets + * exchange API origin. Each falls back to the corresponding sidecar + * env var (SUIBETS_WALLET_ADDRESS / SUIBETS_BASE_URL) when unset. */ protected override getCredentials(): ExchangeCredentials | undefined { const base = super.getCredentials(); - if (!this._walletAddress) return base; + if (!this._walletAddress && !this._apiBaseUrl) return base; return { ...(base ?? {}), - walletAddress: this._walletAddress, - } as ExchangeCredentials & { walletAddress: string }; + ...(this._walletAddress ? { walletAddress: this._walletAddress } : {}), + ...(this._apiBaseUrl ? { baseUrl: this._apiBaseUrl } : {}), + } as ExchangeCredentials; } } diff --git a/sdks/typescript/tests/exchange-credentials.test.ts b/sdks/typescript/tests/exchange-credentials.test.ts index ce8f9899..ca7bc6e1 100644 --- a/sdks/typescript/tests/exchange-credentials.test.ts +++ b/sdks/typescript/tests/exchange-credentials.test.ts @@ -1,4 +1,4 @@ -import { Exchange, ExchangeOptions } from "../pmxt/client"; +import { Exchange, ExchangeOptions, SuiBets } from "../pmxt/client"; class TestExchange extends Exchange { public exposedCredentials() { @@ -6,6 +6,12 @@ class TestExchange extends Exchange { } } +class TestSuiBets extends SuiBets { + public exposedCredentials() { + return this.getCredentials(); + } +} + describe("exchange credentials", () => { it("accepts and forwards apiSecret with sidecar credentials", () => { const options = { @@ -23,4 +29,28 @@ describe("exchange credentials", () => { privateKey: "private-key", }); }); + + it("SuiBets forwards apiBaseUrl as the baseUrl credential", () => { + const exchange = new TestSuiBets({ + walletAddress: "0x" + "ab".repeat(32), + apiBaseUrl: "https://suibets.example", + autoStartServer: false, + }); + + expect(exchange.exposedCredentials()).toMatchObject({ + walletAddress: "0x" + "ab".repeat(32), + baseUrl: "https://suibets.example", + }); + }); + + it("SuiBets apiBaseUrl alone produces credentials", () => { + const exchange = new TestSuiBets({ + apiBaseUrl: "https://suibets.example", + autoStartServer: false, + }); + + expect(exchange.exposedCredentials()).toMatchObject({ + baseUrl: "https://suibets.example", + }); + }); });