@limitless-exchange/sdk 0.0.2 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,8 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  APIError: () => APIError,
34
- AuthenticatedClient: () => AuthenticatedClient,
35
- Authenticator: () => Authenticator,
34
+ AuthenticationError: () => AuthenticationError,
36
35
  BASE_SEPOLIA_CHAIN_ID: () => BASE_SEPOLIA_CHAIN_ID,
37
36
  CONTRACT_ADDRESSES: () => CONTRACT_ADDRESSES,
38
37
  ConsoleLogger: () => ConsoleLogger,
@@ -40,15 +39,16 @@ __export(index_exports, {
40
39
  DEFAULT_CHAIN_ID: () => DEFAULT_CHAIN_ID,
41
40
  DEFAULT_WS_URL: () => DEFAULT_WS_URL,
42
41
  HttpClient: () => HttpClient,
42
+ Market: () => Market,
43
43
  MarketFetcher: () => MarketFetcher,
44
- MarketType: () => MarketType,
45
- MessageSigner: () => MessageSigner,
46
44
  NoOpLogger: () => NoOpLogger,
47
45
  OrderBuilder: () => OrderBuilder,
48
46
  OrderClient: () => OrderClient,
49
47
  OrderSigner: () => OrderSigner,
50
48
  OrderType: () => OrderType,
49
+ OrderValidationError: () => OrderValidationError,
51
50
  PortfolioFetcher: () => PortfolioFetcher,
51
+ RateLimitError: () => RateLimitError,
52
52
  RetryConfig: () => RetryConfig,
53
53
  RetryableClient: () => RetryableClient,
54
54
  SIGNING_MESSAGE_TEMPLATE: () => SIGNING_MESSAGE_TEMPLATE,
@@ -115,16 +115,11 @@ var Side = /* @__PURE__ */ ((Side2) => {
115
115
  Side2[Side2["SELL"] = 1] = "SELL";
116
116
  return Side2;
117
117
  })(Side || {});
118
- var OrderType = /* @__PURE__ */ ((OrderType3) => {
119
- OrderType3["FOK"] = "FOK";
120
- OrderType3["GTC"] = "GTC";
121
- return OrderType3;
118
+ var OrderType = /* @__PURE__ */ ((OrderType2) => {
119
+ OrderType2["FOK"] = "FOK";
120
+ OrderType2["GTC"] = "GTC";
121
+ return OrderType2;
122
122
  })(OrderType || {});
123
- var MarketType = /* @__PURE__ */ ((MarketType3) => {
124
- MarketType3["CLOB"] = "CLOB";
125
- MarketType3["NEGRISK"] = "NEGRISK";
126
- return MarketType3;
127
- })(MarketType || {});
128
123
  var SignatureType = /* @__PURE__ */ ((SignatureType2) => {
129
124
  SignatureType2[SignatureType2["EOA"] = 0] = "EOA";
130
125
  SignatureType2[SignatureType2["POLY_PROXY"] = 1] = "POLY_PROXY";
@@ -142,250 +137,92 @@ var WebSocketState = /* @__PURE__ */ ((WebSocketState2) => {
142
137
  return WebSocketState2;
143
138
  })(WebSocketState || {});
144
139
 
145
- // src/auth/signer.ts
146
- var import_ethers = require("ethers");
147
- var MessageSigner = class {
148
- /**
149
- * Creates a new message signer instance.
150
- *
151
- * @param wallet - Ethers wallet instance for signing
152
- */
153
- constructor(wallet) {
154
- this.wallet = wallet;
155
- }
156
- /**
157
- * Creates authentication headers for API requests.
158
- *
159
- * @param signingMessage - Message to sign from the API
160
- * @returns Promise resolving to signature headers
161
- *
162
- * @example
163
- * ```typescript
164
- * const signer = new MessageSigner(wallet);
165
- * const headers = await signer.createAuthHeaders(message);
166
- * ```
167
- */
168
- async createAuthHeaders(signingMessage) {
169
- const hexMessage = this.stringToHex(signingMessage);
170
- const signature = await this.wallet.signMessage(signingMessage);
171
- const address = this.wallet.address;
172
- const recoveredAddress = import_ethers.ethers.verifyMessage(signingMessage, signature);
173
- if (address.toLowerCase() !== recoveredAddress.toLowerCase()) {
174
- throw new Error("Signature verification failed: address mismatch");
175
- }
176
- return {
177
- "x-account": address,
178
- "x-signing-message": hexMessage,
179
- "x-signature": signature
180
- };
181
- }
182
- /**
183
- * Signs EIP-712 typed data.
184
- *
185
- * @param domain - EIP-712 domain
186
- * @param types - EIP-712 types
187
- * @param value - Value to sign
188
- * @returns Promise resolving to signature string
189
- *
190
- * @example
191
- * ```typescript
192
- * const signature = await signer.signTypedData(domain, types, order);
193
- * ```
194
- */
195
- async signTypedData(domain, types, value) {
196
- return await this.wallet.signTypedData(domain, types, value);
197
- }
198
- /**
199
- * Gets the wallet address.
200
- *
201
- * @returns Ethereum address
202
- */
203
- getAddress() {
204
- return this.wallet.address;
205
- }
206
- /**
207
- * Converts a string to hex format.
208
- *
209
- * @param text - String to convert
210
- * @returns Hex string with 0x prefix
211
- * @internal
212
- */
213
- stringToHex(text) {
214
- return import_ethers.ethers.hexlify(import_ethers.ethers.toUtf8Bytes(text));
215
- }
216
- };
217
-
218
- // src/auth/authenticator.ts
219
- var Authenticator = class {
140
+ // src/types/market-class.ts
141
+ var Market = class _Market {
220
142
  /**
221
- * Creates a new authenticator instance.
222
- *
223
- * @param httpClient - HTTP client for API requests
224
- * @param signer - Message signer for wallet operations
225
- * @param logger - Optional logger for debugging and monitoring (default: no logging)
143
+ * Creates a Market instance.
226
144
  *
227
- * @example
228
- * ```typescript
229
- * // Without logging (default)
230
- * const authenticator = new Authenticator(httpClient, signer);
231
- *
232
- * // With logging
233
- * import { ConsoleLogger } from '@limitless-exchange/sdk';
234
- * const logger = new ConsoleLogger('debug');
235
- * const authenticator = new Authenticator(httpClient, signer, logger);
236
- * ```
145
+ * @param data - Market data from API
146
+ * @param httpClient - HTTP client for making requests
237
147
  */
238
- constructor(httpClient, signer, logger) {
148
+ constructor(data, httpClient) {
149
+ Object.assign(this, data);
239
150
  this.httpClient = httpClient;
240
- this.signer = signer;
241
- this.logger = logger || new NoOpLogger();
151
+ if (data.markets && Array.isArray(data.markets)) {
152
+ this.markets = data.markets.map((m) => new _Market(m, httpClient));
153
+ }
242
154
  }
243
155
  /**
244
- * Gets a signing message from the API.
245
- *
246
- * @returns Promise resolving to signing message string
247
- * @throws Error if API request fails
156
+ * Get user's orders for this market.
248
157
  *
249
- * @example
250
- * ```typescript
251
- * const message = await authenticator.getSigningMessage();
252
- * console.log(message);
253
- * ```
254
- */
255
- async getSigningMessage() {
256
- this.logger.debug("Requesting signing message from API");
257
- const message = await this.httpClient.get("/auth/signing-message");
258
- this.logger.debug("Received signing message", { length: message.length });
259
- return message;
260
- }
261
- /**
262
- * Authenticates with the API and obtains session cookie.
158
+ * @remarks
159
+ * Fetches all orders placed by the authenticated user for this specific market.
160
+ * Uses the http_client from the MarketFetcher that created this Market instance.
263
161
  *
264
- * @param options - Login options including client type and smart wallet
265
- * @returns Promise resolving to authentication result
266
- * @throws Error if authentication fails or smart wallet is required but not provided
162
+ * @returns Promise resolving to array of user orders
163
+ * @throws Error if market wasn't fetched via MarketFetcher
267
164
  *
268
165
  * @example
269
166
  * ```typescript
270
- * // EOA authentication
271
- * const result = await authenticator.authenticate({ client: 'eoa' });
272
- *
273
- * // ETHERSPOT with smart wallet
274
- * const result = await authenticator.authenticate({
275
- * client: 'etherspot',
276
- * smartWallet: '0x...'
277
- * });
167
+ * // Clean fluent API
168
+ * const market = await marketFetcher.getMarket("bitcoin-2024");
169
+ * const orders = await market.getUserOrders();
170
+ * console.log(`You have ${orders.length} orders in ${market.title}`);
278
171
  * ```
279
172
  */
280
- async authenticate(options = {}) {
281
- const client = options.client || "eoa";
282
- this.logger.info("Starting authentication", {
283
- client,
284
- hasSmartWallet: !!options.smartWallet
285
- });
286
- if (client === "etherspot" && !options.smartWallet) {
287
- this.logger.error("Smart wallet address required for ETHERSPOT client");
288
- throw new Error("Smart wallet address is required for ETHERSPOT client");
289
- }
290
- try {
291
- const signingMessage = await this.getSigningMessage();
292
- this.logger.debug("Creating signature headers");
293
- const headers = await this.signer.createAuthHeaders(signingMessage);
294
- this.logger.debug("Sending authentication request", { client });
295
- const response = await this.httpClient.postWithResponse(
296
- "/auth/login",
297
- { client, smartWallet: options.smartWallet },
298
- {
299
- headers,
300
- validateStatus: (status) => status < 500
301
- }
173
+ async getUserOrders() {
174
+ if (!this.httpClient) {
175
+ throw new Error(
176
+ "This Market instance has no httpClient attached. Make sure to fetch the market via MarketFetcher.getMarket() to use this method."
302
177
  );
303
- this.logger.debug("Extracting session cookie from response");
304
- const cookies = this.httpClient.extractCookies(response);
305
- const sessionCookie = cookies["limitless_session"];
306
- if (!sessionCookie) {
307
- this.logger.error("Session cookie not found in response headers");
308
- throw new Error("Failed to obtain session cookie from response");
309
- }
310
- this.httpClient.setSessionCookie(sessionCookie);
311
- this.logger.info("Authentication successful", {
312
- account: response.data.account,
313
- client: response.data.client
314
- });
315
- return {
316
- sessionCookie,
317
- profile: response.data
318
- };
319
- } catch (error) {
320
- this.logger.error("Authentication failed", error, {
321
- client
322
- });
323
- throw error;
324
- }
325
- }
326
- /**
327
- * Verifies the current authentication status.
328
- *
329
- * @param sessionCookie - Session cookie to verify
330
- * @returns Promise resolving to user's Ethereum address
331
- * @throws Error if session is invalid
332
- *
333
- * @example
334
- * ```typescript
335
- * const address = await authenticator.verifyAuth(sessionCookie);
336
- * console.log(`Authenticated as: ${address}`);
337
- * ```
338
- */
339
- async verifyAuth(sessionCookie) {
340
- this.logger.debug("Verifying authentication session");
341
- const originalCookie = this.httpClient["sessionCookie"];
342
- this.httpClient.setSessionCookie(sessionCookie);
343
- try {
344
- const address = await this.httpClient.get("/auth/verify-auth");
345
- this.logger.info("Session verified", { address });
346
- return address;
347
- } catch (error) {
348
- this.logger.error("Session verification failed", error);
349
- throw error;
350
- } finally {
351
- if (originalCookie) {
352
- this.httpClient.setSessionCookie(originalCookie);
353
- } else {
354
- this.httpClient.clearSessionCookie();
355
- }
356
178
  }
179
+ const response = await this.httpClient.get(`/markets/${this.slug}/user-orders`);
180
+ const orders = Array.isArray(response) ? response : response.orders || [];
181
+ return orders;
357
182
  }
358
- /**
359
- * Logs out and clears the session.
360
- *
361
- * @param sessionCookie - Session cookie to invalidate
362
- * @throws Error if logout request fails
363
- *
364
- * @example
365
- * ```typescript
366
- * await authenticator.logout(sessionCookie);
367
- * console.log('Logged out successfully');
368
- * ```
369
- */
370
- async logout(sessionCookie) {
371
- this.logger.debug("Logging out session");
372
- const originalCookie = this.httpClient["sessionCookie"];
373
- this.httpClient.setSessionCookie(sessionCookie);
374
- try {
375
- await this.httpClient.post("/auth/logout", {});
376
- this.logger.info("Logout successful");
377
- } catch (error) {
378
- this.logger.error("Logout failed", error);
379
- throw error;
380
- } finally {
381
- if (originalCookie) {
382
- this.httpClient.setSessionCookie(originalCookie);
383
- } else {
384
- this.httpClient.clearSessionCookie();
385
- }
386
- }
183
+ };
184
+
185
+ // src/api/http.ts
186
+ var import_axios = __toESM(require("axios"));
187
+ var import_http = __toESM(require("http"));
188
+ var import_https = __toESM(require("https"));
189
+
190
+ // src/utils/constants.ts
191
+ var DEFAULT_API_URL = "https://api.limitless.exchange";
192
+ var DEFAULT_WS_URL = "wss://ws.limitless.exchange";
193
+ var DEFAULT_CHAIN_ID = 8453;
194
+ var BASE_SEPOLIA_CHAIN_ID = 84532;
195
+ var SIGNING_MESSAGE_TEMPLATE = "Welcome to Limitless.exchange! Please sign this message to verify your identity.\n\nNonce: {NONCE}";
196
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
197
+ var CONTRACT_ADDRESSES = {
198
+ // Base mainnet (chainId: 8453)
199
+ 8453: {
200
+ USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
201
+ // Native USDC on Base
202
+ CTF: "0xC9c98965297Bc527861c898329Ee280632B76e18"
203
+ // Conditional Token Framework
204
+ },
205
+ // Base Sepolia testnet (chainId: 84532)
206
+ 84532: {
207
+ USDC: "0x...",
208
+ CTF: "0x..."
387
209
  }
388
210
  };
211
+ function getContractAddress(contractType, chainId = DEFAULT_CHAIN_ID) {
212
+ const addresses = CONTRACT_ADDRESSES[chainId];
213
+ if (!addresses) {
214
+ throw new Error(
215
+ `No contract addresses configured for chainId ${chainId}. Supported chains: ${Object.keys(CONTRACT_ADDRESSES).join(", ")}`
216
+ );
217
+ }
218
+ const address = addresses[contractType];
219
+ if (!address || address === "0x...") {
220
+ throw new Error(
221
+ `Contract address for ${contractType} not available on chainId ${chainId}. Please configure the address in constants.ts or use environment variables.`
222
+ );
223
+ }
224
+ return address;
225
+ }
389
226
 
390
227
  // src/api/errors.ts
391
228
  var APIError = class _APIError extends Error {
@@ -431,111 +268,33 @@ var APIError = class _APIError extends Error {
431
268
  return this.status === 401 || this.status === 403;
432
269
  }
433
270
  };
434
-
435
- // src/auth/authenticated-client.ts
436
- var AuthenticatedClient = class {
437
- /**
438
- * Creates a new authenticated client with auto-retry capability.
439
- *
440
- * @param config - Configuration for authenticated client
441
- */
442
- constructor(config) {
443
- this.httpClient = config.httpClient;
444
- this.authenticator = config.authenticator;
445
- this.client = config.client;
446
- this.smartWallet = config.smartWallet;
447
- this.logger = config.logger || new NoOpLogger();
448
- this.maxRetries = config.maxRetries ?? 1;
449
- }
450
- /**
451
- * Executes a function with automatic retry on authentication errors.
452
- *
453
- * @param fn - Function to execute with auth retry
454
- * @returns Promise resolving to the function result
455
- * @throws Error if max retries exceeded or non-auth error occurs
456
- *
457
- * @example
458
- * ```typescript
459
- * // Automatic retry on 401/403
460
- * const positions = await authClient.withRetry(() =>
461
- * portfolioFetcher.getPositions()
462
- * );
463
- *
464
- * // Works with any async operation
465
- * const order = await authClient.withRetry(() =>
466
- * orderClient.createOrder({ ... })
467
- * );
468
- * ```
469
- */
470
- async withRetry(fn) {
471
- let attempts = 0;
472
- while (attempts <= this.maxRetries) {
473
- try {
474
- return await fn();
475
- } catch (error) {
476
- if (error instanceof APIError && error.isAuthError() && attempts < this.maxRetries) {
477
- this.logger.info("Authentication expired, re-authenticating...", {
478
- attempt: attempts + 1,
479
- maxRetries: this.maxRetries
480
- });
481
- await this.reauthenticate();
482
- attempts++;
483
- continue;
484
- }
485
- throw error;
486
- }
271
+ var RateLimitError = class _RateLimitError extends APIError {
272
+ constructor(message = "Rate limit exceeded", status = 429, data = null, url, method) {
273
+ super(message, status, data, url, method);
274
+ this.name = "RateLimitError";
275
+ if (Error.captureStackTrace) {
276
+ Error.captureStackTrace(this, _RateLimitError);
487
277
  }
488
- throw new Error("Unexpected error: exceeded max retries");
489
- }
490
- /**
491
- * Re-authenticates with the API.
492
- *
493
- * @internal
494
- */
495
- async reauthenticate() {
496
- this.logger.debug("Re-authenticating with API");
497
- await this.authenticator.authenticate({
498
- client: this.client,
499
- smartWallet: this.smartWallet
500
- });
501
- this.logger.info("Re-authentication successful");
502
278
  }
503
279
  };
504
-
505
- // src/api/http.ts
506
- var import_axios = __toESM(require("axios"));
507
- var import_http = __toESM(require("http"));
508
- var import_https = __toESM(require("https"));
509
-
510
- // src/utils/constants.ts
511
- var DEFAULT_API_URL = "https://api.limitless.exchange";
512
- var DEFAULT_WS_URL = "wss://ws.limitless.exchange";
513
- var DEFAULT_CHAIN_ID = 8453;
514
- var BASE_SEPOLIA_CHAIN_ID = 84532;
515
- var SIGNING_MESSAGE_TEMPLATE = "Welcome to Limitless.exchange! Please sign this message to verify your identity.\n\nNonce: {NONCE}";
516
- var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
517
- var CONTRACT_ADDRESSES = {
518
- // Base mainnet (chainId: 8453)
519
- 8453: {
520
- CLOB: "0xa4409D988CA2218d956BeEFD3874100F444f0DC3",
521
- NEGRISK: "0x5a38afc17F7E97ad8d6C547ddb837E40B4aEDfC6"
522
- },
523
- // Base Sepolia testnet (chainId: 84532)
524
- 84532: {
525
- CLOB: "0x...",
526
- // Add testnet addresses when available
527
- NEGRISK: "0x..."
280
+ var AuthenticationError = class _AuthenticationError extends APIError {
281
+ constructor(message = "Authentication failed", status = 401, data = null, url, method) {
282
+ super(message, status, data, url, method);
283
+ this.name = "AuthenticationError";
284
+ if (Error.captureStackTrace) {
285
+ Error.captureStackTrace(this, _AuthenticationError);
286
+ }
528
287
  }
529
288
  };
530
- function getContractAddress(marketType, chainId = DEFAULT_CHAIN_ID) {
531
- const addresses = CONTRACT_ADDRESSES[chainId];
532
- if (!addresses) {
533
- throw new Error(
534
- `No contract addresses configured for chainId ${chainId}. Supported chains: ${Object.keys(CONTRACT_ADDRESSES).join(", ")}`
535
- );
289
+ var ValidationError = class _ValidationError extends APIError {
290
+ constructor(message, status = 400, data = null, url, method) {
291
+ super(message, status, data, url, method);
292
+ this.name = "ValidationError";
293
+ if (Error.captureStackTrace) {
294
+ Error.captureStackTrace(this, _ValidationError);
295
+ }
536
296
  }
537
- return addresses[marketType];
538
- }
297
+ };
539
298
 
540
299
  // src/api/http.ts
541
300
  var HttpClient = class {
@@ -545,8 +304,13 @@ var HttpClient = class {
545
304
  * @param config - Configuration options for the HTTP client
546
305
  */
547
306
  constructor(config = {}) {
548
- this.sessionCookie = config.sessionCookie;
307
+ this.apiKey = config.apiKey || process.env.LIMITLESS_API_KEY;
549
308
  this.logger = config.logger || new NoOpLogger();
309
+ if (!this.apiKey) {
310
+ this.logger.warn(
311
+ "API key not set. Authenticated endpoints will fail. Set LIMITLESS_API_KEY environment variable or pass apiKey parameter."
312
+ );
313
+ }
550
314
  const keepAlive = config.keepAlive !== false;
551
315
  const maxSockets = config.maxSockets || 50;
552
316
  const maxFreeSockets = config.maxFreeSockets || 10;
@@ -589,13 +353,17 @@ var HttpClient = class {
589
353
  setupInterceptors() {
590
354
  this.client.interceptors.request.use(
591
355
  (config) => {
592
- if (this.sessionCookie) {
593
- config.headers["Cookie"] = `limitless_session=${this.sessionCookie}`;
356
+ if (this.apiKey) {
357
+ config.headers["X-API-Key"] = this.apiKey;
594
358
  }
595
359
  const fullUrl = `${config.baseURL || ""}${config.url || ""}`;
596
360
  const method = config.method?.toUpperCase() || "GET";
361
+ const logHeaders = { ...config.headers };
362
+ if (logHeaders["X-API-Key"]) {
363
+ logHeaders["X-API-Key"] = "***";
364
+ }
597
365
  this.logger.debug(`\u2192 ${method} ${fullUrl}`, {
598
- headers: config.headers,
366
+ headers: logHeaders,
599
367
  body: config.data
600
368
  });
601
369
  return config;
@@ -636,7 +404,15 @@ var HttpClient = class {
636
404
  message = String(data);
637
405
  }
638
406
  }
639
- throw new APIError(message, status, data, url, method);
407
+ if (status === 429) {
408
+ throw new RateLimitError(message, status, data, url, method);
409
+ } else if (status === 401 || status === 403) {
410
+ throw new AuthenticationError(message, status, data, url, method);
411
+ } else if (status === 400) {
412
+ throw new ValidationError(message, status, data, url, method);
413
+ } else {
414
+ throw new APIError(message, status, data, url, method);
415
+ }
640
416
  } else if (error.request) {
641
417
  throw new Error("No response received from API");
642
418
  } else {
@@ -646,18 +422,18 @@ var HttpClient = class {
646
422
  );
647
423
  }
648
424
  /**
649
- * Sets the session cookie for authenticated requests.
425
+ * Sets the API key for authenticated requests.
650
426
  *
651
- * @param cookie - Session cookie value
427
+ * @param apiKey - API key value
652
428
  */
653
- setSessionCookie(cookie) {
654
- this.sessionCookie = cookie;
429
+ setApiKey(apiKey) {
430
+ this.apiKey = apiKey;
655
431
  }
656
432
  /**
657
- * Clears the session cookie.
433
+ * Clears the API key.
658
434
  */
659
- clearSessionCookie() {
660
- this.sessionCookie = void 0;
435
+ clearApiKey() {
436
+ this.apiKey = void 0;
661
437
  }
662
438
  /**
663
439
  * Performs a GET request.
@@ -682,19 +458,6 @@ var HttpClient = class {
682
458
  const response = await this.client.post(url, data, config);
683
459
  return response.data;
684
460
  }
685
- /**
686
- * Performs a POST request and returns the full response object.
687
- * Useful when you need access to response headers (e.g., for cookie extraction).
688
- *
689
- * @param url - Request URL
690
- * @param data - Request body data
691
- * @param config - Additional request configuration
692
- * @returns Promise resolving to the full AxiosResponse object
693
- * @internal
694
- */
695
- async postWithResponse(url, data, config) {
696
- return await this.client.post(url, data, config);
697
- }
698
461
  /**
699
462
  * Performs a DELETE request.
700
463
  *
@@ -717,26 +480,6 @@ var HttpClient = class {
717
480
  const response = await this.client.delete(url, deleteConfig);
718
481
  return response.data;
719
482
  }
720
- /**
721
- * Extracts cookies from response headers.
722
- *
723
- * @param response - Axios response object
724
- * @returns Object containing parsed cookies
725
- * @internal
726
- */
727
- extractCookies(response) {
728
- const setCookie = response.headers["set-cookie"];
729
- if (!setCookie) return {};
730
- const cookies = {};
731
- const cookieStrings = Array.isArray(setCookie) ? setCookie : [setCookie];
732
- for (const cookieString of cookieStrings) {
733
- const parts = cookieString.split(";")[0].split("=");
734
- if (parts.length === 2) {
735
- cookies[parts[0].trim()] = parts[1].trim();
736
- }
737
- }
738
- return cookies;
739
- }
740
483
  };
741
484
 
742
485
  // src/api/retry.ts
@@ -921,7 +664,7 @@ var RetryableClient = class {
921
664
  };
922
665
 
923
666
  // src/orders/builder.ts
924
- var import_ethers2 = require("ethers");
667
+ var import_ethers = require("ethers");
925
668
  var ZERO_ADDRESS2 = "0x0000000000000000000000000000000000000000";
926
669
  var DEFAULT_PRICE_TICK = 1e-3;
927
670
  var OrderBuilder = class {
@@ -960,8 +703,7 @@ var OrderBuilder = class {
960
703
  * const fokOrder = builder.buildOrder({
961
704
  * tokenId: '123456',
962
705
  * makerAmount: 50, // 50 USDC to spend
963
- * side: Side.BUY,
964
- * marketType: MarketType.CLOB
706
+ * side: Side.BUY
965
707
  * });
966
708
  *
967
709
  * // GTC order (price + size)
@@ -969,8 +711,7 @@ var OrderBuilder = class {
969
711
  * tokenId: '123456',
970
712
  * price: 0.38,
971
713
  * size: 22.123, // Will be rounded to tick-aligned: 22.123 shares
972
- * side: Side.BUY,
973
- * marketType: MarketType.CLOB
714
+ * side: Side.BUY
974
715
  * });
975
716
  * ```
976
717
  */
@@ -1005,7 +746,7 @@ var OrderBuilder = class {
1005
746
  * @internal
1006
747
  */
1007
748
  isFOKOrder(args) {
1008
- return "amount" in args;
749
+ return "makerAmount" in args;
1009
750
  }
1010
751
  /**
1011
752
  * Generates a unique salt using timestamp + nano-offset pattern.
@@ -1159,7 +900,7 @@ var OrderBuilder = class {
1159
900
  }
1160
901
  }
1161
902
  const amountFormatted = makerAmount.toFixed(DECIMALS);
1162
- const amountScaled = import_ethers2.ethers.parseUnits(amountFormatted, DECIMALS);
903
+ const amountScaled = import_ethers.ethers.parseUnits(amountFormatted, DECIMALS);
1163
904
  const collateralAmount = Number(amountScaled);
1164
905
  return {
1165
906
  makerAmount: collateralAmount,
@@ -1179,7 +920,7 @@ var OrderBuilder = class {
1179
920
  if (!args.tokenId || args.tokenId === "0") {
1180
921
  throw new Error("Invalid tokenId: tokenId is required.");
1181
922
  }
1182
- if (args.taker && !import_ethers2.ethers.isAddress(args.taker)) {
923
+ if (args.taker && !import_ethers.ethers.isAddress(args.taker)) {
1183
924
  throw new Error(`Invalid taker address: ${args.taker}`);
1184
925
  }
1185
926
  if (this.isFOKOrder(args)) {
@@ -1190,7 +931,7 @@ var OrderBuilder = class {
1190
931
  throw new Error(`Invalid makerAmount: ${args.makerAmount}. Maker amount must be positive.`);
1191
932
  }
1192
933
  } else {
1193
- if (args.price < 0 || args.price > 1) {
934
+ if (args.price == null || args.price < 0 || args.price > 1) {
1194
935
  throw new Error(`Invalid price: ${args.price}. Price must be between 0 and 1.`);
1195
936
  }
1196
937
  if (args.size <= 0) {
@@ -1245,8 +986,7 @@ var OrderSigner = class {
1245
986
  * ```typescript
1246
987
  * const signature = await signer.signOrder(unsignedOrder, {
1247
988
  * chainId: 8453,
1248
- * contractAddress: '0x...',
1249
- * marketType: MarketType.CLOB
989
+ * contractAddress: '0x...'
1250
990
  * });
1251
991
  * ```
1252
992
  */
@@ -1254,7 +994,7 @@ var OrderSigner = class {
1254
994
  this.logger.debug("Signing order with EIP-712", {
1255
995
  tokenId: order.tokenId,
1256
996
  side: order.side,
1257
- marketType: config.marketType
997
+ verifyingContract: config.contractAddress
1258
998
  });
1259
999
  const walletAddress = await this.wallet.getAddress();
1260
1000
  if (walletAddress.toLowerCase() !== order.signer.toLowerCase()) {
@@ -1280,11 +1020,11 @@ var OrderSigner = class {
1280
1020
  signatureType: order.signatureType
1281
1021
  };
1282
1022
  this.logger.debug("EIP-712 Order Value", orderValue);
1283
- console.log("[OrderSigner] Full signing payload:", JSON.stringify({
1023
+ this.logger.debug("Full signing payload", {
1284
1024
  domain,
1285
1025
  types: this.getTypes(),
1286
1026
  value: orderValue
1287
- }, null, 2));
1027
+ });
1288
1028
  try {
1289
1029
  const signature = await this.wallet.signTypedData(domain, types, orderValue);
1290
1030
  this.logger.info("Successfully generated EIP-712 signature", {
@@ -1344,11 +1084,11 @@ var OrderSigner = class {
1344
1084
  };
1345
1085
 
1346
1086
  // src/orders/validator.ts
1347
- var import_ethers3 = require("ethers");
1348
- var ValidationError = class extends Error {
1087
+ var import_ethers2 = require("ethers");
1088
+ var OrderValidationError = class extends Error {
1349
1089
  constructor(message) {
1350
1090
  super(message);
1351
- this.name = "ValidationError";
1091
+ this.name = "OrderValidationError";
1352
1092
  }
1353
1093
  };
1354
1094
  function isFOKOrder(args) {
@@ -1356,418 +1096,149 @@ function isFOKOrder(args) {
1356
1096
  }
1357
1097
  function validateOrderArgs(args) {
1358
1098
  if (!args.tokenId) {
1359
- throw new ValidationError("TokenId is required");
1099
+ throw new OrderValidationError("TokenId is required");
1360
1100
  }
1361
1101
  if (args.tokenId === "0") {
1362
- throw new ValidationError("TokenId cannot be zero");
1102
+ throw new OrderValidationError("TokenId cannot be zero");
1363
1103
  }
1364
1104
  if (!/^\d+$/.test(args.tokenId)) {
1365
- throw new ValidationError(`Invalid tokenId format: ${args.tokenId}`);
1105
+ throw new OrderValidationError(`Invalid tokenId format: ${args.tokenId}`);
1366
1106
  }
1367
- if (args.taker && !import_ethers3.ethers.isAddress(args.taker)) {
1368
- throw new ValidationError(`Invalid taker address: ${args.taker}`);
1107
+ if (args.taker && !import_ethers2.ethers.isAddress(args.taker)) {
1108
+ throw new OrderValidationError(`Invalid taker address: ${args.taker}`);
1369
1109
  }
1370
1110
  if (args.expiration !== void 0) {
1371
1111
  if (!/^\d+$/.test(args.expiration)) {
1372
- throw new ValidationError(`Invalid expiration format: ${args.expiration}`);
1112
+ throw new OrderValidationError(`Invalid expiration format: ${args.expiration}`);
1373
1113
  }
1374
1114
  }
1375
1115
  if (args.nonce !== void 0) {
1376
1116
  if (!Number.isInteger(args.nonce) || args.nonce < 0) {
1377
- throw new ValidationError(`Invalid nonce: ${args.nonce}`);
1117
+ throw new OrderValidationError(`Invalid nonce: ${args.nonce}`);
1378
1118
  }
1379
1119
  }
1380
1120
  if (isFOKOrder(args)) {
1381
1121
  if (typeof args.makerAmount !== "number" || isNaN(args.makerAmount)) {
1382
- throw new ValidationError("Amount must be a valid number");
1122
+ throw new OrderValidationError("Amount must be a valid number");
1383
1123
  }
1384
1124
  if (args.makerAmount <= 0) {
1385
- throw new ValidationError(`Amount must be positive, got: ${args.makerAmount}`);
1125
+ throw new OrderValidationError(`Amount must be positive, got: ${args.makerAmount}`);
1386
1126
  }
1387
1127
  const amountStr = args.makerAmount.toString();
1388
1128
  const decimalIndex = amountStr.indexOf(".");
1389
1129
  if (decimalIndex !== -1) {
1390
1130
  const decimalPlaces = amountStr.length - decimalIndex - 1;
1391
1131
  if (decimalPlaces > 2) {
1392
- throw new ValidationError(
1132
+ throw new OrderValidationError(
1393
1133
  `Amount must have max 2 decimal places, got: ${args.makerAmount} (${decimalPlaces} decimals)`
1394
1134
  );
1395
1135
  }
1396
1136
  }
1397
1137
  } else {
1398
1138
  if (typeof args.price !== "number" || isNaN(args.price)) {
1399
- throw new ValidationError("Price must be a valid number");
1139
+ throw new OrderValidationError("Price must be a valid number");
1400
1140
  }
1401
1141
  if (args.price < 0 || args.price > 1) {
1402
- throw new ValidationError(`Price must be between 0 and 1, got: ${args.price}`);
1142
+ throw new OrderValidationError(`Price must be between 0 and 1, got: ${args.price}`);
1403
1143
  }
1404
1144
  if (typeof args.size !== "number" || isNaN(args.size)) {
1405
- throw new ValidationError("Size must be a valid number");
1145
+ throw new OrderValidationError("Size must be a valid number");
1406
1146
  }
1407
1147
  if (args.size <= 0) {
1408
- throw new ValidationError(`Size must be positive, got: ${args.size}`);
1148
+ throw new OrderValidationError(`Size must be positive, got: ${args.size}`);
1409
1149
  }
1410
1150
  }
1411
1151
  }
1412
1152
  function validateUnsignedOrder(order) {
1413
- if (!import_ethers3.ethers.isAddress(order.maker)) {
1414
- throw new ValidationError(`Invalid maker address: ${order.maker}`);
1153
+ if (!import_ethers2.ethers.isAddress(order.maker)) {
1154
+ throw new OrderValidationError(`Invalid maker address: ${order.maker}`);
1415
1155
  }
1416
- if (!import_ethers3.ethers.isAddress(order.signer)) {
1417
- throw new ValidationError(`Invalid signer address: ${order.signer}`);
1156
+ if (!import_ethers2.ethers.isAddress(order.signer)) {
1157
+ throw new OrderValidationError(`Invalid signer address: ${order.signer}`);
1418
1158
  }
1419
- if (!import_ethers3.ethers.isAddress(order.taker)) {
1420
- throw new ValidationError(`Invalid taker address: ${order.taker}`);
1159
+ if (!import_ethers2.ethers.isAddress(order.taker)) {
1160
+ throw new OrderValidationError(`Invalid taker address: ${order.taker}`);
1421
1161
  }
1422
1162
  if (!order.makerAmount || order.makerAmount === 0) {
1423
- throw new ValidationError("MakerAmount must be greater than zero");
1163
+ throw new OrderValidationError("MakerAmount must be greater than zero");
1424
1164
  }
1425
1165
  if (!order.takerAmount || order.takerAmount === 0) {
1426
- throw new ValidationError("TakerAmount must be greater than zero");
1166
+ throw new OrderValidationError("TakerAmount must be greater than zero");
1427
1167
  }
1428
1168
  if (typeof order.makerAmount !== "number" || order.makerAmount <= 0) {
1429
- throw new ValidationError(`Invalid makerAmount: ${order.makerAmount}`);
1169
+ throw new OrderValidationError(`Invalid makerAmount: ${order.makerAmount}`);
1430
1170
  }
1431
1171
  if (typeof order.takerAmount !== "number" || order.takerAmount <= 0) {
1432
- throw new ValidationError(`Invalid takerAmount: ${order.takerAmount}`);
1172
+ throw new OrderValidationError(`Invalid takerAmount: ${order.takerAmount}`);
1433
1173
  }
1434
1174
  if (!/^\d+$/.test(order.tokenId)) {
1435
- throw new ValidationError(`Invalid tokenId format: ${order.tokenId}`);
1175
+ throw new OrderValidationError(`Invalid tokenId format: ${order.tokenId}`);
1436
1176
  }
1437
1177
  if (!/^\d+$/.test(order.expiration)) {
1438
- throw new ValidationError(`Invalid expiration format: ${order.expiration}`);
1178
+ throw new OrderValidationError(`Invalid expiration format: ${order.expiration}`);
1439
1179
  }
1440
1180
  if (!Number.isInteger(order.salt) || order.salt <= 0) {
1441
- throw new ValidationError(`Invalid salt: ${order.salt}`);
1181
+ throw new OrderValidationError(`Invalid salt: ${order.salt}`);
1442
1182
  }
1443
1183
  if (!Number.isInteger(order.nonce) || order.nonce < 0) {
1444
- throw new ValidationError(`Invalid nonce: ${order.nonce}`);
1184
+ throw new OrderValidationError(`Invalid nonce: ${order.nonce}`);
1445
1185
  }
1446
1186
  if (!Number.isInteger(order.feeRateBps) || order.feeRateBps < 0) {
1447
- throw new ValidationError(`Invalid feeRateBps: ${order.feeRateBps}`);
1187
+ throw new OrderValidationError(`Invalid feeRateBps: ${order.feeRateBps}`);
1448
1188
  }
1449
1189
  if (order.side !== 0 && order.side !== 1) {
1450
- throw new ValidationError(`Invalid side: ${order.side}. Must be 0 (BUY) or 1 (SELL)`);
1190
+ throw new OrderValidationError(`Invalid side: ${order.side}. Must be 0 (BUY) or 1 (SELL)`);
1451
1191
  }
1452
1192
  if (!Number.isInteger(order.signatureType) || order.signatureType < 0) {
1453
- throw new ValidationError(`Invalid signatureType: ${order.signatureType}`);
1193
+ throw new OrderValidationError(`Invalid signatureType: ${order.signatureType}`);
1454
1194
  }
1455
1195
  if (order.price !== void 0) {
1456
1196
  if (typeof order.price !== "number" || isNaN(order.price)) {
1457
- throw new ValidationError("Price must be a valid number");
1197
+ throw new OrderValidationError("Price must be a valid number");
1458
1198
  }
1459
1199
  if (order.price < 0 || order.price > 1) {
1460
- throw new ValidationError(`Price must be between 0 and 1, got: ${order.price}`);
1200
+ throw new OrderValidationError(`Price must be between 0 and 1, got: ${order.price}`);
1461
1201
  }
1462
1202
  }
1463
1203
  }
1464
1204
  function validateSignedOrder(order) {
1465
1205
  validateUnsignedOrder(order);
1466
1206
  if (!order.signature) {
1467
- throw new ValidationError("Signature is required");
1207
+ throw new OrderValidationError("Signature is required");
1468
1208
  }
1469
1209
  if (!order.signature.startsWith("0x")) {
1470
- throw new ValidationError("Signature must start with 0x");
1210
+ throw new OrderValidationError("Signature must start with 0x");
1471
1211
  }
1472
1212
  if (order.signature.length !== 132) {
1473
- throw new ValidationError(
1213
+ throw new OrderValidationError(
1474
1214
  `Invalid signature length: ${order.signature.length}. Expected 132 characters.`
1475
1215
  );
1476
1216
  }
1477
1217
  if (!/^0x[0-9a-fA-F]{130}$/.test(order.signature)) {
1478
- throw new ValidationError("Signature must be valid hex string");
1218
+ throw new OrderValidationError("Signature must be valid hex string");
1479
1219
  }
1480
1220
  }
1481
1221
 
1482
- // src/orders/client.ts
1483
- var OrderClient = class {
1222
+ // src/markets/fetcher.ts
1223
+ var MarketFetcher = class {
1484
1224
  /**
1485
- * Creates a new order client instance.
1225
+ * Creates a new market fetcher instance.
1486
1226
  *
1487
- * @param config - Order client configuration
1227
+ * @param httpClient - HTTP client for API requests
1228
+ * @param logger - Optional logger for debugging (default: no logging)
1488
1229
  *
1489
- * @throws Error if neither marketType nor signingConfig is provided
1230
+ * @example
1231
+ * ```typescript
1232
+ * const fetcher = new MarketFetcher(httpClient);
1233
+ * ```
1490
1234
  */
1491
- constructor(config) {
1492
- this.httpClient = config.httpClient;
1493
- this.logger = config.logger || new NoOpLogger();
1494
- this.ownerId = config.userData.userId;
1495
- const feeRateBps = config.userData.feeRateBps;
1496
- this.orderBuilder = new OrderBuilder(config.wallet.address, feeRateBps, 1e-3);
1497
- this.orderSigner = new OrderSigner(config.wallet, this.logger);
1498
- if (config.signingConfig) {
1499
- this.signingConfig = config.signingConfig;
1500
- } else if (config.marketType) {
1501
- const chainId = parseInt(process.env.CHAIN_ID || "8453");
1502
- const contractAddress = config.marketType === "NEGRISK" /* NEGRISK */ ? process.env.NEGRISK_CONTRACT_ADDRESS || getContractAddress("NEGRISK", chainId) : process.env.CLOB_CONTRACT_ADDRESS || getContractAddress("CLOB", chainId);
1503
- this.signingConfig = {
1504
- chainId,
1505
- contractAddress,
1506
- marketType: config.marketType
1507
- };
1508
- this.logger.info("Auto-configured signing", {
1509
- chainId,
1510
- contractAddress,
1511
- marketType: config.marketType
1512
- });
1513
- } else {
1514
- const chainId = parseInt(process.env.CHAIN_ID || "8453");
1515
- const contractAddress = process.env.CLOB_CONTRACT_ADDRESS || getContractAddress("CLOB", chainId);
1516
- this.signingConfig = {
1517
- chainId,
1518
- contractAddress,
1519
- marketType: "CLOB" /* CLOB */
1520
- };
1521
- this.logger.debug("Using default CLOB configuration", {
1522
- chainId,
1523
- contractAddress
1524
- });
1525
- }
1235
+ constructor(httpClient, logger) {
1236
+ this.httpClient = httpClient;
1237
+ this.logger = logger || new NoOpLogger();
1238
+ this.venueCache = /* @__PURE__ */ new Map();
1526
1239
  }
1527
1240
  /**
1528
- * Creates and submits a new order.
1529
- *
1530
- * @remarks
1531
- * This method handles the complete order creation flow:
1532
- * 1. Build unsigned order
1533
- * 2. Sign with EIP-712
1534
- * 3. Submit to API
1535
- *
1536
- * @param params - Order parameters
1537
- * @returns Promise resolving to order response
1538
- *
1539
- * @throws Error if order creation fails
1540
- *
1541
- * @example
1542
- * ```typescript
1543
- * const order = await orderClient.createOrder({
1544
- * tokenId: '123456',
1545
- * price: 0.65,
1546
- * size: 100,
1547
- * side: Side.BUY,
1548
- * orderType: OrderType.GTC,
1549
- * marketSlug: 'market-slug'
1550
- * });
1551
- *
1552
- * console.log(`Order created: ${order.order.id}`);
1553
- * ```
1554
- */
1555
- async createOrder(params) {
1556
- this.logger.info("Creating order", {
1557
- side: params.side,
1558
- orderType: params.orderType,
1559
- marketSlug: params.marketSlug
1560
- });
1561
- const unsignedOrder = this.orderBuilder.buildOrder(params);
1562
- this.logger.debug("Built unsigned order", {
1563
- salt: unsignedOrder.salt,
1564
- makerAmount: unsignedOrder.makerAmount,
1565
- takerAmount: unsignedOrder.takerAmount
1566
- });
1567
- const signature = await this.orderSigner.signOrder(
1568
- unsignedOrder,
1569
- this.signingConfig
1570
- );
1571
- const payload = {
1572
- order: {
1573
- ...unsignedOrder,
1574
- signature
1575
- },
1576
- orderType: params.orderType,
1577
- marketSlug: params.marketSlug,
1578
- ownerId: this.ownerId
1579
- };
1580
- this.logger.debug("Submitting order to API");
1581
- console.log("[OrderClient] Full API request payload:", JSON.stringify(payload, null, 2));
1582
- const apiResponse = await this.httpClient.post(
1583
- "/orders",
1584
- payload
1585
- );
1586
- this.logger.info("Order created successfully", {
1587
- orderId: apiResponse.order.id
1588
- });
1589
- return this.transformOrderResponse(apiResponse);
1590
- }
1591
- /**
1592
- * Transforms raw API response to clean OrderResponse DTO.
1593
- *
1594
- * @param apiResponse - Raw API response with nested objects
1595
- * @returns Clean OrderResponse with only essential fields
1596
- *
1597
- * @internal
1598
- */
1599
- transformOrderResponse(apiResponse) {
1600
- const cleanOrder = {
1601
- order: {
1602
- id: apiResponse.order.id,
1603
- createdAt: apiResponse.order.createdAt,
1604
- makerAmount: apiResponse.order.makerAmount,
1605
- takerAmount: apiResponse.order.takerAmount,
1606
- expiration: apiResponse.order.expiration,
1607
- signatureType: apiResponse.order.signatureType,
1608
- salt: apiResponse.order.salt,
1609
- maker: apiResponse.order.maker,
1610
- signer: apiResponse.order.signer,
1611
- taker: apiResponse.order.taker,
1612
- tokenId: apiResponse.order.tokenId,
1613
- side: apiResponse.order.side,
1614
- feeRateBps: apiResponse.order.feeRateBps,
1615
- nonce: apiResponse.order.nonce,
1616
- signature: apiResponse.order.signature,
1617
- orderType: apiResponse.order.orderType,
1618
- price: apiResponse.order.price,
1619
- marketId: apiResponse.order.marketId
1620
- }
1621
- };
1622
- if (apiResponse.makerMatches && apiResponse.makerMatches.length > 0) {
1623
- cleanOrder.makerMatches = apiResponse.makerMatches.map((match) => ({
1624
- id: match.id,
1625
- createdAt: match.createdAt,
1626
- matchedSize: match.matchedSize,
1627
- orderId: match.orderId
1628
- }));
1629
- }
1630
- return cleanOrder;
1631
- }
1632
- /**
1633
- * Cancels an existing order by ID.
1634
- *
1635
- * @param orderId - Order ID to cancel
1636
- * @returns Promise resolving to cancellation message
1637
- *
1638
- * @throws Error if cancellation fails
1639
- *
1640
- * @example
1641
- * ```typescript
1642
- * const result = await orderClient.cancel('order-id-123');
1643
- * console.log(result.message); // "Order canceled successfully"
1644
- * ```
1645
- */
1646
- async cancel(orderId) {
1647
- this.logger.info("Cancelling order", { orderId });
1648
- const response = await this.httpClient.delete(
1649
- `/orders/${orderId}`
1650
- );
1651
- this.logger.info("Order cancellation response", {
1652
- orderId,
1653
- message: response.message
1654
- });
1655
- return response;
1656
- }
1657
- /**
1658
- * Cancels all orders for a specific market.
1659
- *
1660
- * @param marketSlug - Market slug to cancel all orders for
1661
- * @returns Promise resolving to cancellation message
1662
- *
1663
- * @throws Error if cancellation fails
1664
- *
1665
- * @example
1666
- * ```typescript
1667
- * const result = await orderClient.cancelAll('market-slug-123');
1668
- * console.log(result.message); // "Orders canceled successfully"
1669
- * ```
1670
- */
1671
- async cancelAll(marketSlug) {
1672
- this.logger.info("Cancelling all orders for market", { marketSlug });
1673
- const response = await this.httpClient.delete(
1674
- `/orders/all/${marketSlug}`
1675
- );
1676
- this.logger.info("All orders cancellation response", {
1677
- marketSlug,
1678
- message: response.message
1679
- });
1680
- return response;
1681
- }
1682
- /**
1683
- * @deprecated Use `cancel()` instead
1684
- */
1685
- async cancelOrder(orderId) {
1686
- await this.cancel(orderId);
1687
- }
1688
- /**
1689
- * Gets an order by ID.
1690
- *
1691
- * @param orderId - Order ID to fetch
1692
- * @returns Promise resolving to order details
1693
- *
1694
- * @throws Error if order not found
1695
- *
1696
- * @example
1697
- * ```typescript
1698
- * const order = await orderClient.getOrder('order-id-123');
1699
- * console.log(order.order.side);
1700
- * ```
1701
- */
1702
- async getOrder(orderId) {
1703
- this.logger.debug("Fetching order", { orderId });
1704
- const response = await this.httpClient.get(
1705
- `/orders/${orderId}`
1706
- );
1707
- return response;
1708
- }
1709
- /**
1710
- * Builds an unsigned order without submitting.
1711
- *
1712
- * @remarks
1713
- * Useful for advanced use cases where you need the unsigned order
1714
- * before signing and submission.
1715
- *
1716
- * @param params - Order parameters
1717
- * @returns Unsigned order
1718
- *
1719
- * @example
1720
- * ```typescript
1721
- * const unsignedOrder = orderClient.buildUnsignedOrder({
1722
- * tokenId: '123456',
1723
- * price: 0.65,
1724
- * size: 100,
1725
- * side: Side.BUY
1726
- * });
1727
- * ```
1728
- */
1729
- buildUnsignedOrder(params) {
1730
- return this.orderBuilder.buildOrder(params);
1731
- }
1732
- /**
1733
- * Signs an unsigned order without submitting.
1734
- *
1735
- * @remarks
1736
- * Useful for advanced use cases where you need to inspect
1737
- * the signature before submission.
1738
- *
1739
- * @param order - Unsigned order to sign
1740
- * @returns Promise resolving to signature
1741
- *
1742
- * @example
1743
- * ```typescript
1744
- * const signature = await orderClient.signOrder(unsignedOrder);
1745
- * ```
1746
- */
1747
- async signOrder(order) {
1748
- return await this.orderSigner.signOrder(order, this.signingConfig);
1749
- }
1750
- };
1751
-
1752
- // src/markets/fetcher.ts
1753
- var MarketFetcher = class {
1754
- /**
1755
- * Creates a new market fetcher instance.
1756
- *
1757
- * @param httpClient - HTTP client for API requests
1758
- * @param logger - Optional logger for debugging (default: no logging)
1759
- *
1760
- * @example
1761
- * ```typescript
1762
- * const fetcher = new MarketFetcher(httpClient);
1763
- * ```
1764
- */
1765
- constructor(httpClient, logger) {
1766
- this.httpClient = httpClient;
1767
- this.logger = logger || new NoOpLogger();
1768
- }
1769
- /**
1770
- * Gets active markets with query parameters and pagination support.
1241
+ * Gets active markets with query parameters and pagination support.
1771
1242
  *
1772
1243
  * @param params - Query parameters for filtering and pagination
1773
1244
  * @returns Promise resolving to active markets response
@@ -1806,13 +1277,18 @@ var MarketFetcher = class {
1806
1277
  this.logger.debug("Fetching active markets", { params });
1807
1278
  try {
1808
1279
  const response = await this.httpClient.get(endpoint);
1280
+ const markets = response.data.map((marketData) => new Market(marketData, this.httpClient));
1281
+ const result = {
1282
+ data: markets,
1283
+ totalMarketsCount: response.totalMarketsCount
1284
+ };
1809
1285
  this.logger.info("Active markets fetched successfully", {
1810
- count: response.data.length,
1286
+ count: markets.length,
1811
1287
  total: response.totalMarketsCount,
1812
1288
  sortBy: params?.sortBy,
1813
1289
  page: params?.page
1814
1290
  });
1815
- return response;
1291
+ return result;
1816
1292
  } catch (error) {
1817
1293
  this.logger.error("Failed to fetch active markets", error, { params });
1818
1294
  throw error;
@@ -1821,20 +1297,48 @@ var MarketFetcher = class {
1821
1297
  /**
1822
1298
  * Gets a single market by slug.
1823
1299
  *
1300
+ * @remarks
1301
+ * Automatically caches venue information for efficient order signing.
1302
+ * Always call this method before creating orders to ensure venue data
1303
+ * is available and avoid additional API requests.
1304
+ *
1824
1305
  * @param slug - Market slug identifier
1825
1306
  * @returns Promise resolving to market details
1826
1307
  * @throws Error if API request fails or market not found
1827
1308
  *
1828
1309
  * @example
1829
1310
  * ```typescript
1311
+ * // Get market
1830
1312
  * const market = await fetcher.getMarket('bitcoin-price-2024');
1831
1313
  * console.log(`Market: ${market.title}`);
1314
+ *
1315
+ * // Fluent API - get user orders for this market (clean!)
1316
+ * const orders = await market.getUserOrders();
1317
+ * console.log(`You have ${orders.length} orders`);
1318
+ *
1319
+ * // Venue is now cached for order signing
1320
+ * await orderClient.createOrder({
1321
+ * marketSlug: 'bitcoin-price-2024',
1322
+ * ...
1323
+ * });
1832
1324
  * ```
1833
1325
  */
1834
1326
  async getMarket(slug) {
1835
1327
  this.logger.debug("Fetching market", { slug });
1836
1328
  try {
1837
- const market = await this.httpClient.get(`/markets/${slug}`);
1329
+ const response = await this.httpClient.get(`/markets/${slug}`);
1330
+ const market = new Market(response, this.httpClient);
1331
+ if (market.venue) {
1332
+ this.venueCache.set(slug, market.venue);
1333
+ this.logger.debug("Venue cached for order signing", {
1334
+ slug,
1335
+ exchange: market.venue.exchange,
1336
+ adapter: market.venue.adapter,
1337
+ cacheSize: this.venueCache.size
1338
+ });
1339
+ } else {
1340
+ this.logger.warn("Market has no venue data", { slug });
1341
+ }
1838
1342
  this.logger.info("Market fetched successfully", {
1839
1343
  slug,
1840
1344
  title: market.title
@@ -1845,6 +1349,36 @@ var MarketFetcher = class {
1845
1349
  throw error;
1846
1350
  }
1847
1351
  }
1352
+ /**
1353
+ * Gets cached venue information for a market.
1354
+ *
1355
+ * @remarks
1356
+ * Returns venue data previously cached by getMarket() call.
1357
+ * Used internally by OrderClient for efficient order signing.
1358
+ *
1359
+ * @param slug - Market slug identifier
1360
+ * @returns Cached venue information, or undefined if not in cache
1361
+ *
1362
+ * @example
1363
+ * ```typescript
1364
+ * const venue = fetcher.getVenue('bitcoin-price-2024');
1365
+ * if (venue) {
1366
+ * console.log(`Exchange: ${venue.exchange}`);
1367
+ * }
1368
+ * ```
1369
+ */
1370
+ getVenue(slug) {
1371
+ const venue = this.venueCache.get(slug);
1372
+ if (venue) {
1373
+ this.logger.debug("Venue cache hit", {
1374
+ slug,
1375
+ exchange: venue.exchange
1376
+ });
1377
+ } else {
1378
+ this.logger.debug("Venue cache miss", { slug });
1379
+ }
1380
+ return venue;
1381
+ }
1848
1382
  /**
1849
1383
  * Gets the orderbook for a CLOB market.
1850
1384
  *
@@ -1876,335 +1410,473 @@ var MarketFetcher = class {
1876
1410
  throw error;
1877
1411
  }
1878
1412
  }
1413
+ };
1414
+
1415
+ // src/portfolio/fetcher.ts
1416
+ var PortfolioFetcher = class {
1417
+ /**
1418
+ * Creates a new portfolio fetcher instance.
1419
+ *
1420
+ * @param httpClient - Authenticated HTTP client for API requests
1421
+ * @param logger - Optional logger for debugging (default: no logging)
1422
+ *
1423
+ * @example
1424
+ * ```typescript
1425
+ * // Create authenticated client
1426
+ * const httpClient = new HttpClient({ baseURL: API_URL });
1427
+ * await authenticator.authenticate({ client: 'eoa' });
1428
+ *
1429
+ * // Create portfolio fetcher
1430
+ * const portfolioFetcher = new PortfolioFetcher(httpClient);
1431
+ * ```
1432
+ */
1433
+ constructor(httpClient, logger) {
1434
+ this.httpClient = httpClient;
1435
+ this.logger = logger || new NoOpLogger();
1436
+ }
1437
+ /**
1438
+ * Gets user profile for a specific wallet address.
1439
+ *
1440
+ * @remarks
1441
+ * Returns user profile data including user ID and fee rate.
1442
+ * Used internally by OrderClient to fetch user data.
1443
+ *
1444
+ * @param address - Wallet address to fetch profile for
1445
+ * @returns Promise resolving to user profile data
1446
+ * @throws Error if API request fails or user is not authenticated
1447
+ *
1448
+ * @example
1449
+ * ```typescript
1450
+ * const profile = await portfolioFetcher.getProfile('0x1234...');
1451
+ * console.log(`User ID: ${profile.id}`);
1452
+ * console.log(`Account: ${profile.account}`);
1453
+ * console.log(`Fee Rate: ${profile.rank?.feeRateBps}`);
1454
+ * ```
1455
+ */
1456
+ async getProfile(address) {
1457
+ this.logger.debug("Fetching user profile", { address });
1458
+ try {
1459
+ const response = await this.httpClient.get(`/profiles/${address}`);
1460
+ this.logger.info("User profile fetched successfully", { address });
1461
+ return response;
1462
+ } catch (error) {
1463
+ this.logger.error("Failed to fetch user profile", error, { address });
1464
+ throw error;
1465
+ }
1466
+ }
1467
+ /**
1468
+ * Gets raw portfolio positions response from API.
1469
+ *
1470
+ * @returns Promise resolving to portfolio positions response with CLOB and AMM positions
1471
+ * @throws Error if API request fails or user is not authenticated
1472
+ *
1473
+ * @example
1474
+ * ```typescript
1475
+ * const response = await portfolioFetcher.getPositions();
1476
+ * console.log(`CLOB positions: ${response.clob.length}`);
1477
+ * console.log(`AMM positions: ${response.amm.length}`);
1478
+ * console.log(`Total points: ${response.accumulativePoints}`);
1479
+ * ```
1480
+ */
1481
+ async getPositions() {
1482
+ this.logger.debug("Fetching user positions");
1483
+ try {
1484
+ const response = await this.httpClient.get("/portfolio/positions");
1485
+ this.logger.info("Positions fetched successfully", {
1486
+ clobCount: response.clob?.length || 0,
1487
+ ammCount: response.amm?.length || 0
1488
+ });
1489
+ return response;
1490
+ } catch (error) {
1491
+ this.logger.error("Failed to fetch positions", error);
1492
+ throw error;
1493
+ }
1494
+ }
1495
+ /**
1496
+ * Gets CLOB positions only.
1497
+ *
1498
+ * @returns Promise resolving to array of CLOB positions
1499
+ * @throws Error if API request fails
1500
+ *
1501
+ * @example
1502
+ * ```typescript
1503
+ * const clobPositions = await portfolioFetcher.getCLOBPositions();
1504
+ * clobPositions.forEach(pos => {
1505
+ * console.log(`${pos.market.title}: YES ${pos.positions.yes.unrealizedPnl} P&L`);
1506
+ * });
1507
+ * ```
1508
+ */
1509
+ async getCLOBPositions() {
1510
+ const response = await this.getPositions();
1511
+ return response.clob || [];
1512
+ }
1513
+ /**
1514
+ * Gets AMM positions only.
1515
+ *
1516
+ * @returns Promise resolving to array of AMM positions
1517
+ * @throws Error if API request fails
1518
+ *
1519
+ * @example
1520
+ * ```typescript
1521
+ * const ammPositions = await portfolioFetcher.getAMMPositions();
1522
+ * ammPositions.forEach(pos => {
1523
+ * console.log(`${pos.market.title}: ${pos.unrealizedPnl} P&L`);
1524
+ * });
1525
+ * ```
1526
+ */
1527
+ async getAMMPositions() {
1528
+ const response = await this.getPositions();
1529
+ return response.amm || [];
1530
+ }
1531
+ /**
1532
+ * Gets paginated history of user actions.
1533
+ *
1534
+ * Includes AMM trades, CLOB trades, Negrisk trades & conversions.
1535
+ *
1536
+ * @param page - Page number (starts at 1)
1537
+ * @param limit - Number of items per page
1538
+ * @returns Promise resolving to paginated history response
1539
+ * @throws Error if API request fails or user is not authenticated
1540
+ *
1541
+ * @example
1542
+ * ```typescript
1543
+ * // Get first page
1544
+ * const response = await portfolioFetcher.getUserHistory(1, 20);
1545
+ * console.log(`Found ${response.data.length} of ${response.totalCount} entries`);
1546
+ *
1547
+ * // Process history entries
1548
+ * for (const entry of response.data) {
1549
+ * console.log(`Type: ${entry.type}`);
1550
+ * console.log(`Market: ${entry.marketSlug}`);
1551
+ * }
1552
+ *
1553
+ * // Get next page
1554
+ * const page2 = await portfolioFetcher.getUserHistory(2, 20);
1555
+ * ```
1556
+ */
1557
+ async getUserHistory(page = 1, limit = 10) {
1558
+ this.logger.debug("Fetching user history", { page, limit });
1559
+ try {
1560
+ const params = new URLSearchParams({
1561
+ page: page.toString(),
1562
+ limit: limit.toString()
1563
+ });
1564
+ const response = await this.httpClient.get(
1565
+ `/portfolio/history?${params.toString()}`
1566
+ );
1567
+ this.logger.info("User history fetched successfully");
1568
+ return response;
1569
+ } catch (error) {
1570
+ this.logger.error("Failed to fetch user history", error, { page, limit });
1571
+ throw error;
1572
+ }
1573
+ }
1574
+ };
1575
+
1576
+ // src/orders/client.ts
1577
+ var OrderClient = class {
1879
1578
  /**
1880
- * Gets the current price for a token.
1579
+ * Creates a new order client instance.
1580
+ *
1581
+ * @param config - Order client configuration
1582
+ */
1583
+ constructor(config) {
1584
+ this.httpClient = config.httpClient;
1585
+ this.wallet = config.wallet;
1586
+ this.logger = config.logger || new NoOpLogger();
1587
+ this.orderSigner = new OrderSigner(config.wallet, this.logger);
1588
+ this.marketFetcher = config.marketFetcher || new MarketFetcher(config.httpClient, this.logger);
1589
+ if (config.signingConfig) {
1590
+ this.signingConfig = config.signingConfig;
1591
+ } else {
1592
+ const chainId = parseInt(process.env.CHAIN_ID || "8453");
1593
+ const contractAddress = ZERO_ADDRESS;
1594
+ this.signingConfig = {
1595
+ chainId,
1596
+ contractAddress
1597
+ };
1598
+ this.logger.info("Auto-configured signing (contract address from venue)", {
1599
+ chainId
1600
+ });
1601
+ }
1602
+ }
1603
+ /**
1604
+ * Ensures user data is loaded and cached.
1605
+ * Fetches from profile API on first call, then caches for subsequent calls.
1606
+ *
1607
+ * @returns Promise resolving to cached user data
1608
+ * @internal
1609
+ */
1610
+ async ensureUserData() {
1611
+ if (!this.cachedUserData) {
1612
+ this.logger.info("Fetching user profile for order client initialization...", {
1613
+ walletAddress: this.wallet.address
1614
+ });
1615
+ const portfolioFetcher = new PortfolioFetcher(this.httpClient);
1616
+ const profile = await portfolioFetcher.getProfile(this.wallet.address);
1617
+ this.cachedUserData = {
1618
+ userId: profile.id,
1619
+ feeRateBps: profile.rank?.feeRateBps || 300
1620
+ };
1621
+ this.orderBuilder = new OrderBuilder(
1622
+ this.wallet.address,
1623
+ this.cachedUserData.feeRateBps,
1624
+ 1e-3
1625
+ );
1626
+ this.logger.info("Order Client initialized", {
1627
+ walletAddress: profile.account,
1628
+ userId: this.cachedUserData.userId,
1629
+ feeRate: `${this.cachedUserData.feeRateBps / 100}%`
1630
+ });
1631
+ }
1632
+ return this.cachedUserData;
1633
+ }
1634
+ /**
1635
+ * Creates and submits a new order.
1636
+ *
1637
+ * @remarks
1638
+ * This method handles the complete order creation flow:
1639
+ * 1. Resolve venue address (from cache or API)
1640
+ * 2. Build unsigned order
1641
+ * 3. Sign with EIP-712 using venue.exchange as verifyingContract
1642
+ * 4. Submit to API
1881
1643
  *
1882
- * @param tokenId - Token ID
1883
- * @returns Promise resolving to price information
1884
- * @throws Error if API request fails
1644
+ * Performance best practice: Always call marketFetcher.getMarket(marketSlug)
1645
+ * before createOrder() to cache venue data and avoid additional API requests.
1646
+ *
1647
+ * @param params - Order parameters
1648
+ * @returns Promise resolving to order response
1649
+ *
1650
+ * @throws Error if order creation fails or venue not found
1885
1651
  *
1886
1652
  * @example
1887
1653
  * ```typescript
1888
- * const price = await fetcher.getPrice('123456');
1889
- * console.log(`Current price: ${price.price}`);
1654
+ * // Best practice: fetch market first to cache venue
1655
+ * const market = await marketFetcher.getMarket('bitcoin-2024');
1656
+ *
1657
+ * const order = await orderClient.createOrder({
1658
+ * tokenId: market.tokens.yes,
1659
+ * price: 0.65,
1660
+ * size: 100,
1661
+ * side: Side.BUY,
1662
+ * orderType: OrderType.GTC,
1663
+ * marketSlug: 'bitcoin-2024'
1664
+ * });
1665
+ *
1666
+ * console.log(`Order created: ${order.order.id}`);
1890
1667
  * ```
1891
1668
  */
1892
- async getPrice(tokenId) {
1893
- this.logger.debug("Fetching price", { tokenId });
1894
- try {
1895
- const price = await this.httpClient.get(`/prices/${tokenId}`);
1896
- this.logger.info("Price fetched successfully", {
1897
- tokenId,
1898
- price: price.price
1899
- });
1900
- return price;
1901
- } catch (error) {
1902
- this.logger.error("Failed to fetch price", error, { tokenId });
1903
- throw error;
1669
+ async createOrder(params) {
1670
+ const userData = await this.ensureUserData();
1671
+ this.logger.info("Creating order", {
1672
+ side: params.side,
1673
+ orderType: params.orderType,
1674
+ marketSlug: params.marketSlug
1675
+ });
1676
+ let venue = this.marketFetcher.getVenue(params.marketSlug);
1677
+ if (!venue) {
1678
+ this.logger.warn(
1679
+ "Venue not cached, fetching market details. For better performance, call marketFetcher.getMarket() before createOrder().",
1680
+ { marketSlug: params.marketSlug }
1681
+ );
1682
+ const market = await this.marketFetcher.getMarket(params.marketSlug);
1683
+ if (!market.venue) {
1684
+ throw new Error(
1685
+ `Market ${params.marketSlug} does not have venue information. Venue data is required for order signing.`
1686
+ );
1687
+ }
1688
+ venue = market.venue;
1904
1689
  }
1690
+ const dynamicSigningConfig = {
1691
+ ...this.signingConfig,
1692
+ contractAddress: venue.exchange
1693
+ };
1694
+ this.logger.debug("Using venue for order signing", {
1695
+ marketSlug: params.marketSlug,
1696
+ exchange: venue.exchange,
1697
+ adapter: venue.adapter
1698
+ });
1699
+ const unsignedOrder = this.orderBuilder.buildOrder(params);
1700
+ this.logger.debug("Built unsigned order", {
1701
+ salt: unsignedOrder.salt,
1702
+ makerAmount: unsignedOrder.makerAmount,
1703
+ takerAmount: unsignedOrder.takerAmount
1704
+ });
1705
+ const signature = await this.orderSigner.signOrder(unsignedOrder, dynamicSigningConfig);
1706
+ const payload = {
1707
+ order: {
1708
+ ...unsignedOrder,
1709
+ signature
1710
+ },
1711
+ orderType: params.orderType,
1712
+ marketSlug: params.marketSlug,
1713
+ ownerId: userData.userId
1714
+ };
1715
+ this.logger.debug("Submitting order to API", payload);
1716
+ const apiResponse = await this.httpClient.post("/orders", payload);
1717
+ this.logger.info("Order created successfully", {
1718
+ orderId: apiResponse.order.id
1719
+ });
1720
+ return this.transformOrderResponse(apiResponse);
1905
1721
  }
1906
- };
1907
-
1908
- // src/portfolio/fetcher.ts
1909
- var PortfolioFetcher = class {
1910
1722
  /**
1911
- * Creates a new portfolio fetcher instance.
1912
- *
1913
- * @param httpClient - Authenticated HTTP client for API requests
1914
- * @param logger - Optional logger for debugging (default: no logging)
1723
+ * Transforms raw API response to clean OrderResponse DTO.
1915
1724
  *
1916
- * @example
1917
- * ```typescript
1918
- * // Create authenticated client
1919
- * const httpClient = new HttpClient({ baseURL: API_URL });
1920
- * await authenticator.authenticate({ client: 'eoa' });
1725
+ * @param apiResponse - Raw API response with nested objects
1726
+ * @returns Clean OrderResponse with only essential fields
1921
1727
  *
1922
- * // Create portfolio fetcher
1923
- * const portfolioFetcher = new PortfolioFetcher(httpClient);
1924
- * ```
1728
+ * @internal
1925
1729
  */
1926
- constructor(httpClient, logger) {
1927
- this.httpClient = httpClient;
1928
- this.logger = logger || new NoOpLogger();
1730
+ transformOrderResponse(apiResponse) {
1731
+ const cleanOrder = {
1732
+ order: {
1733
+ id: apiResponse.order.id,
1734
+ createdAt: apiResponse.order.createdAt,
1735
+ makerAmount: apiResponse.order.makerAmount,
1736
+ takerAmount: apiResponse.order.takerAmount,
1737
+ expiration: apiResponse.order.expiration,
1738
+ signatureType: apiResponse.order.signatureType,
1739
+ salt: apiResponse.order.salt,
1740
+ maker: apiResponse.order.maker,
1741
+ signer: apiResponse.order.signer,
1742
+ taker: apiResponse.order.taker,
1743
+ tokenId: apiResponse.order.tokenId,
1744
+ side: apiResponse.order.side,
1745
+ feeRateBps: apiResponse.order.feeRateBps,
1746
+ nonce: apiResponse.order.nonce,
1747
+ signature: apiResponse.order.signature,
1748
+ orderType: apiResponse.order.orderType,
1749
+ price: apiResponse.order.price,
1750
+ marketId: apiResponse.order.marketId
1751
+ }
1752
+ };
1753
+ if (apiResponse.makerMatches && apiResponse.makerMatches.length > 0) {
1754
+ cleanOrder.makerMatches = apiResponse.makerMatches.map((match) => ({
1755
+ id: match.id,
1756
+ createdAt: match.createdAt,
1757
+ matchedSize: match.matchedSize,
1758
+ orderId: match.orderId
1759
+ }));
1760
+ }
1761
+ return cleanOrder;
1929
1762
  }
1930
1763
  /**
1931
- * Gets raw portfolio positions response from API.
1764
+ * Cancels an existing order by ID.
1932
1765
  *
1933
- * @returns Promise resolving to portfolio positions response with CLOB and AMM positions
1934
- * @throws Error if API request fails or user is not authenticated
1766
+ * @param orderId - Order ID to cancel
1767
+ * @returns Promise resolving to cancellation message
1768
+ *
1769
+ * @throws Error if cancellation fails
1935
1770
  *
1936
1771
  * @example
1937
1772
  * ```typescript
1938
- * const response = await portfolioFetcher.getPositions();
1939
- * console.log(`CLOB positions: ${response.clob.length}`);
1940
- * console.log(`AMM positions: ${response.amm.length}`);
1941
- * console.log(`Total points: ${response.accumulativePoints}`);
1773
+ * const result = await orderClient.cancel('order-id-123');
1774
+ * console.log(result.message); // "Order canceled successfully"
1942
1775
  * ```
1943
1776
  */
1944
- async getPositions() {
1945
- this.logger.debug("Fetching user positions");
1946
- try {
1947
- const response = await this.httpClient.get(
1948
- "/portfolio/positions"
1949
- );
1950
- this.logger.info("Positions fetched successfully", {
1951
- clobCount: response.clob?.length || 0,
1952
- ammCount: response.amm?.length || 0
1953
- });
1954
- return response;
1955
- } catch (error) {
1956
- this.logger.error("Failed to fetch positions", error);
1957
- throw error;
1958
- }
1777
+ async cancel(orderId) {
1778
+ this.logger.info("Cancelling order", { orderId });
1779
+ const response = await this.httpClient.delete(`/orders/${orderId}`);
1780
+ this.logger.info("Order cancellation response", {
1781
+ orderId,
1782
+ message: response.message
1783
+ });
1784
+ return response;
1959
1785
  }
1960
1786
  /**
1961
- * Gets CLOB positions only.
1787
+ * Cancels all orders for a specific market.
1962
1788
  *
1963
- * @returns Promise resolving to array of CLOB positions
1964
- * @throws Error if API request fails
1789
+ * @param marketSlug - Market slug to cancel all orders for
1790
+ * @returns Promise resolving to cancellation message
1791
+ *
1792
+ * @throws Error if cancellation fails
1965
1793
  *
1966
1794
  * @example
1967
1795
  * ```typescript
1968
- * const clobPositions = await portfolioFetcher.getCLOBPositions();
1969
- * clobPositions.forEach(pos => {
1970
- * console.log(`${pos.market.title}: YES ${pos.positions.yes.unrealizedPnl} P&L`);
1971
- * });
1796
+ * const result = await orderClient.cancelAll('market-slug-123');
1797
+ * console.log(result.message); // "Orders canceled successfully"
1972
1798
  * ```
1973
1799
  */
1974
- async getCLOBPositions() {
1975
- const response = await this.getPositions();
1976
- return response.clob || [];
1800
+ async cancelAll(marketSlug) {
1801
+ this.logger.info("Cancelling all orders for market", { marketSlug });
1802
+ const response = await this.httpClient.delete(`/orders/all/${marketSlug}`);
1803
+ this.logger.info("All orders cancellation response", {
1804
+ marketSlug,
1805
+ message: response.message
1806
+ });
1807
+ return response;
1977
1808
  }
1978
1809
  /**
1979
- * Gets AMM positions only.
1810
+ * Builds an unsigned order without submitting.
1980
1811
  *
1981
- * @returns Promise resolving to array of AMM positions
1982
- * @throws Error if API request fails
1812
+ * @remarks
1813
+ * Useful for advanced use cases where you need the unsigned order
1814
+ * before signing and submission.
1815
+ *
1816
+ * @param params - Order parameters
1817
+ * @returns Promise resolving to unsigned order
1983
1818
  *
1984
1819
  * @example
1985
1820
  * ```typescript
1986
- * const ammPositions = await portfolioFetcher.getAMMPositions();
1987
- * ammPositions.forEach(pos => {
1988
- * console.log(`${pos.market.title}: ${pos.unrealizedPnl} P&L`);
1821
+ * const unsignedOrder = await orderClient.buildUnsignedOrder({
1822
+ * tokenId: '123456',
1823
+ * price: 0.65,
1824
+ * size: 100,
1825
+ * side: Side.BUY
1989
1826
  * });
1990
1827
  * ```
1991
1828
  */
1992
- async getAMMPositions() {
1993
- const response = await this.getPositions();
1994
- return response.amm || [];
1829
+ async buildUnsignedOrder(params) {
1830
+ await this.ensureUserData();
1831
+ return this.orderBuilder.buildOrder(params);
1995
1832
  }
1996
1833
  /**
1997
- * Flattens positions into a unified format for easier consumption.
1834
+ * Signs an unsigned order without submitting.
1998
1835
  *
1999
1836
  * @remarks
2000
- * Converts CLOB positions (which have YES/NO sides) and AMM positions
2001
- * into a unified Position array. Only includes positions with non-zero values.
1837
+ * Useful for advanced use cases where you need to inspect
1838
+ * the signature before submission.
2002
1839
  *
2003
- * @returns Promise resolving to array of flattened positions
2004
- * @throws Error if API request fails
1840
+ * @param order - Unsigned order to sign
1841
+ * @returns Promise resolving to signature
2005
1842
  *
2006
1843
  * @example
2007
1844
  * ```typescript
2008
- * const positions = await portfolioFetcher.getFlattenedPositions();
2009
- * positions.forEach(pos => {
2010
- * const pnlPercent = (pos.unrealizedPnl / pos.costBasis) * 100;
2011
- * console.log(`${pos.market.title} (${pos.side}): ${pnlPercent.toFixed(2)}% P&L`);
2012
- * });
1845
+ * const signature = await orderClient.signOrder(unsignedOrder);
2013
1846
  * ```
2014
1847
  */
2015
- async getFlattenedPositions() {
2016
- const response = await this.getPositions();
2017
- const positions = [];
2018
- for (const clobPos of response.clob || []) {
2019
- const yesCost = parseFloat(clobPos.positions.yes.cost);
2020
- const yesValue = parseFloat(clobPos.positions.yes.marketValue);
2021
- if (yesCost > 0 || yesValue > 0) {
2022
- positions.push({
2023
- type: "CLOB",
2024
- market: clobPos.market,
2025
- side: "YES",
2026
- costBasis: yesCost,
2027
- marketValue: yesValue,
2028
- unrealizedPnl: parseFloat(clobPos.positions.yes.unrealizedPnl),
2029
- realizedPnl: parseFloat(clobPos.positions.yes.realisedPnl),
2030
- currentPrice: clobPos.latestTrade?.latestYesPrice ?? 0,
2031
- avgPrice: yesCost > 0 ? parseFloat(clobPos.positions.yes.fillPrice) / 1e6 : 0,
2032
- tokenBalance: parseFloat(clobPos.tokensBalance.yes)
2033
- });
2034
- }
2035
- const noCost = parseFloat(clobPos.positions.no.cost);
2036
- const noValue = parseFloat(clobPos.positions.no.marketValue);
2037
- if (noCost > 0 || noValue > 0) {
2038
- positions.push({
2039
- type: "CLOB",
2040
- market: clobPos.market,
2041
- side: "NO",
2042
- costBasis: noCost,
2043
- marketValue: noValue,
2044
- unrealizedPnl: parseFloat(clobPos.positions.no.unrealizedPnl),
2045
- realizedPnl: parseFloat(clobPos.positions.no.realisedPnl),
2046
- currentPrice: clobPos.latestTrade?.latestNoPrice ?? 0,
2047
- avgPrice: noCost > 0 ? parseFloat(clobPos.positions.no.fillPrice) / 1e6 : 0,
2048
- tokenBalance: parseFloat(clobPos.tokensBalance.no)
2049
- });
2050
- }
2051
- }
2052
- for (const ammPos of response.amm || []) {
2053
- const cost = parseFloat(ammPos.totalBuysCost);
2054
- const value = parseFloat(ammPos.collateralAmount);
2055
- if (cost > 0 || value > 0) {
2056
- positions.push({
2057
- type: "AMM",
2058
- market: ammPos.market,
2059
- side: ammPos.outcomeIndex === 0 ? "YES" : "NO",
2060
- costBasis: cost,
2061
- marketValue: value,
2062
- unrealizedPnl: parseFloat(ammPos.unrealizedPnl),
2063
- realizedPnl: parseFloat(ammPos.realizedPnl),
2064
- currentPrice: ammPos.latestTrade ? parseFloat(ammPos.latestTrade.outcomeTokenPrice) : 0,
2065
- avgPrice: parseFloat(ammPos.averageFillPrice),
2066
- tokenBalance: parseFloat(ammPos.outcomeTokenAmount)
2067
- });
2068
- }
2069
- }
2070
- this.logger.debug("Flattened positions", { count: positions.length });
2071
- return positions;
1848
+ async signOrder(order) {
1849
+ return await this.orderSigner.signOrder(order, this.signingConfig);
2072
1850
  }
2073
1851
  /**
2074
- * Calculates portfolio summary statistics from raw API response.
1852
+ * Gets the wallet address.
2075
1853
  *
2076
- * @param response - Portfolio positions response from API
2077
- * @returns Portfolio summary with totals and statistics
1854
+ * @returns Ethereum address of the wallet
2078
1855
  *
2079
1856
  * @example
2080
1857
  * ```typescript
2081
- * const response = await portfolioFetcher.getPositions();
2082
- * const summary = portfolioFetcher.calculateSummary(response);
2083
- *
2084
- * console.log(`Total Portfolio Value: $${(summary.totalValue / 1e6).toFixed(2)}`);
2085
- * console.log(`Total P&L: ${summary.totalUnrealizedPnlPercent.toFixed(2)}%`);
2086
- * console.log(`CLOB Positions: ${summary.breakdown.clob.positions}`);
2087
- * console.log(`AMM Positions: ${summary.breakdown.amm.positions}`);
1858
+ * const address = orderClient.walletAddress;
1859
+ * console.log(`Wallet: ${address}`);
2088
1860
  * ```
2089
1861
  */
2090
- calculateSummary(response) {
2091
- this.logger.debug("Calculating portfolio summary", {
2092
- clobCount: response.clob?.length || 0,
2093
- ammCount: response.amm?.length || 0
2094
- });
2095
- let totalValue = 0;
2096
- let totalCostBasis = 0;
2097
- let totalUnrealizedPnl = 0;
2098
- let totalRealizedPnl = 0;
2099
- let clobPositions = 0;
2100
- let clobValue = 0;
2101
- let clobPnl = 0;
2102
- let ammPositions = 0;
2103
- let ammValue = 0;
2104
- let ammPnl = 0;
2105
- for (const clobPos of response.clob || []) {
2106
- const yesCost = parseFloat(clobPos.positions.yes.cost);
2107
- const yesValue = parseFloat(clobPos.positions.yes.marketValue);
2108
- const yesUnrealizedPnl = parseFloat(clobPos.positions.yes.unrealizedPnl);
2109
- const yesRealizedPnl = parseFloat(clobPos.positions.yes.realisedPnl);
2110
- if (yesCost > 0 || yesValue > 0) {
2111
- clobPositions++;
2112
- totalCostBasis += yesCost;
2113
- totalValue += yesValue;
2114
- totalUnrealizedPnl += yesUnrealizedPnl;
2115
- totalRealizedPnl += yesRealizedPnl;
2116
- clobValue += yesValue;
2117
- clobPnl += yesUnrealizedPnl;
2118
- }
2119
- const noCost = parseFloat(clobPos.positions.no.cost);
2120
- const noValue = parseFloat(clobPos.positions.no.marketValue);
2121
- const noUnrealizedPnl = parseFloat(clobPos.positions.no.unrealizedPnl);
2122
- const noRealizedPnl = parseFloat(clobPos.positions.no.realisedPnl);
2123
- if (noCost > 0 || noValue > 0) {
2124
- clobPositions++;
2125
- totalCostBasis += noCost;
2126
- totalValue += noValue;
2127
- totalUnrealizedPnl += noUnrealizedPnl;
2128
- totalRealizedPnl += noRealizedPnl;
2129
- clobValue += noValue;
2130
- clobPnl += noUnrealizedPnl;
2131
- }
2132
- }
2133
- for (const ammPos of response.amm || []) {
2134
- const cost = parseFloat(ammPos.totalBuysCost);
2135
- const value = parseFloat(ammPos.collateralAmount);
2136
- const unrealizedPnl = parseFloat(ammPos.unrealizedPnl);
2137
- const realizedPnl = parseFloat(ammPos.realizedPnl);
2138
- if (cost > 0 || value > 0) {
2139
- ammPositions++;
2140
- totalCostBasis += cost;
2141
- totalValue += value;
2142
- totalUnrealizedPnl += unrealizedPnl;
2143
- totalRealizedPnl += realizedPnl;
2144
- ammValue += value;
2145
- ammPnl += unrealizedPnl;
2146
- }
2147
- }
2148
- const totalUnrealizedPnlPercent = totalCostBasis > 0 ? totalUnrealizedPnl / totalCostBasis * 100 : 0;
2149
- const uniqueMarkets = /* @__PURE__ */ new Set();
2150
- for (const pos of response.clob || []) {
2151
- uniqueMarkets.add(pos.market.id);
2152
- }
2153
- for (const pos of response.amm || []) {
2154
- uniqueMarkets.add(pos.market.id);
2155
- }
2156
- const summary = {
2157
- totalValue,
2158
- totalCostBasis,
2159
- totalUnrealizedPnl,
2160
- totalRealizedPnl,
2161
- totalUnrealizedPnlPercent,
2162
- positionCount: clobPositions + ammPositions,
2163
- marketCount: uniqueMarkets.size,
2164
- breakdown: {
2165
- clob: {
2166
- positions: clobPositions,
2167
- value: clobValue,
2168
- pnl: clobPnl
2169
- },
2170
- amm: {
2171
- positions: ammPositions,
2172
- value: ammValue,
2173
- pnl: ammPnl
2174
- }
2175
- }
2176
- };
2177
- this.logger.debug("Portfolio summary calculated", summary);
2178
- return summary;
1862
+ get walletAddress() {
1863
+ return this.wallet.address;
2179
1864
  }
2180
1865
  /**
2181
- * Gets positions and calculates summary in a single call.
1866
+ * Gets the owner ID (user ID from profile).
2182
1867
  *
2183
- * @returns Promise resolving to response and summary
2184
- * @throws Error if API request fails or user is not authenticated
1868
+ * @returns Owner ID from user profile, or undefined if not yet loaded
2185
1869
  *
2186
1870
  * @example
2187
1871
  * ```typescript
2188
- * const { response, summary } = await portfolioFetcher.getPortfolio();
2189
- *
2190
- * console.log('Portfolio Summary:');
2191
- * console.log(` Total Value: $${(summary.totalValue / 1e6).toFixed(2)}`);
2192
- * console.log(` Total P&L: $${(summary.totalUnrealizedPnl / 1e6).toFixed(2)}`);
2193
- * console.log(` P&L %: ${summary.totalUnrealizedPnlPercent.toFixed(2)}%`);
2194
- * console.log(`\nCLOB Positions: ${response.clob.length}`);
2195
- * console.log(`AMM Positions: ${response.amm.length}`);
1872
+ * const ownerId = orderClient.ownerId;
1873
+ * if (ownerId) {
1874
+ * console.log(`Owner ID: ${ownerId}`);
1875
+ * }
2196
1876
  * ```
2197
1877
  */
2198
- async getPortfolio() {
2199
- this.logger.debug("Fetching portfolio with summary");
2200
- const response = await this.getPositions();
2201
- const summary = this.calculateSummary(response);
2202
- this.logger.info("Portfolio fetched with summary", {
2203
- positionCount: summary.positionCount,
2204
- totalValueUSDC: summary.totalValue / 1e6,
2205
- pnlPercent: summary.totalUnrealizedPnlPercent
2206
- });
2207
- return { response, summary };
1878
+ get ownerId() {
1879
+ return this.cachedUserData?.userId;
2208
1880
  }
2209
1881
  };
2210
1882
 
@@ -2225,7 +1897,7 @@ var WebSocketClient = class {
2225
1897
  this.pendingListeners = [];
2226
1898
  this.config = {
2227
1899
  url: config.url || DEFAULT_WS_URL,
2228
- sessionCookie: config.sessionCookie || "",
1900
+ apiKey: config.apiKey || process.env.LIMITLESS_API_KEY || "",
2229
1901
  autoReconnect: config.autoReconnect ?? true,
2230
1902
  reconnectDelay: config.reconnectDelay || 1e3,
2231
1903
  maxReconnectAttempts: config.maxReconnectAttempts || Infinity,
@@ -2250,18 +1922,29 @@ var WebSocketClient = class {
2250
1922
  return this.state === "connected" /* CONNECTED */ && this.socket?.connected === true;
2251
1923
  }
2252
1924
  /**
2253
- * Sets the session cookie for authentication.
1925
+ * Sets the API key for authentication.
2254
1926
  *
2255
- * @param sessionCookie - Session cookie value
1927
+ * @param apiKey - API key value
1928
+ *
1929
+ * @remarks
1930
+ * API key is required for authenticated subscriptions (positions, transactions).
1931
+ * If already connected, this will trigger a reconnection with the new API key.
2256
1932
  */
2257
- setSessionCookie(sessionCookie) {
2258
- this.config.sessionCookie = sessionCookie;
1933
+ setApiKey(apiKey) {
1934
+ this.config.apiKey = apiKey;
2259
1935
  if (this.socket?.connected) {
2260
- this.logger.info("Session cookie updated, reconnecting...");
2261
- this.disconnect();
2262
- this.connect();
1936
+ this.logger.info("API key updated, reconnecting...");
1937
+ this.reconnectWithNewAuth();
2263
1938
  }
2264
1939
  }
1940
+ /**
1941
+ * Reconnects with new authentication credentials.
1942
+ * @internal
1943
+ */
1944
+ async reconnectWithNewAuth() {
1945
+ await this.disconnect();
1946
+ await this.connect();
1947
+ }
2265
1948
  /**
2266
1949
  * Connects to the WebSocket server.
2267
1950
  *
@@ -2275,8 +1958,8 @@ var WebSocketClient = class {
2275
1958
  * ```
2276
1959
  */
2277
1960
  async connect() {
2278
- if (this.socket?.connected) {
2279
- this.logger.info("Already connected");
1961
+ if (this.socket?.connected || this.state === "connecting" /* CONNECTING */) {
1962
+ this.logger.info("Already connected or connecting");
2280
1963
  return;
2281
1964
  }
2282
1965
  this.logger.info("Connecting to WebSocket", { url: this.config.url });
@@ -2285,18 +1968,26 @@ var WebSocketClient = class {
2285
1968
  const timeout = setTimeout(() => {
2286
1969
  reject(new Error(`Connection timeout after ${this.config.timeout}ms`));
2287
1970
  }, this.config.timeout);
2288
- const wsUrl = this.config.url.endsWith("/markets") ? this.config.url : `${this.config.url}/markets`;
2289
- this.socket = (0, import_socket.io)(wsUrl, {
1971
+ const wsUrl = this.config.url;
1972
+ const socketOptions = {
2290
1973
  transports: ["websocket"],
2291
1974
  // Use WebSocket transport only
2292
- extraHeaders: {
2293
- cookie: `limitless_session=${this.config.sessionCookie}`
2294
- },
2295
1975
  reconnection: this.config.autoReconnect,
2296
1976
  reconnectionDelay: this.config.reconnectDelay,
2297
- reconnectionAttempts: this.config.maxReconnectAttempts,
1977
+ reconnectionDelayMax: Math.min(this.config.reconnectDelay * 32, 6e4),
1978
+ // Max 60s
1979
+ reconnectionAttempts: this.config.maxReconnectAttempts === Infinity ? 0 : this.config.maxReconnectAttempts,
1980
+ // 0 = infinite
1981
+ randomizationFactor: 0.2,
1982
+ // Add jitter to prevent thundering herd
2298
1983
  timeout: this.config.timeout
2299
- });
1984
+ };
1985
+ if (this.config.apiKey) {
1986
+ socketOptions.extraHeaders = {
1987
+ "X-API-Key": this.config.apiKey
1988
+ };
1989
+ }
1990
+ this.socket = (0, import_socket.io)(wsUrl + "/markets", socketOptions);
2300
1991
  this.attachPendingListeners();
2301
1992
  this.setupEventHandlers();
2302
1993
  this.socket.once("connect", () => {
@@ -2318,12 +2009,14 @@ var WebSocketClient = class {
2318
2009
  /**
2319
2010
  * Disconnects from the WebSocket server.
2320
2011
  *
2012
+ * @returns Promise that resolves when disconnected
2013
+ *
2321
2014
  * @example
2322
2015
  * ```typescript
2323
- * wsClient.disconnect();
2016
+ * await wsClient.disconnect();
2324
2017
  * ```
2325
2018
  */
2326
- disconnect() {
2019
+ async disconnect() {
2327
2020
  if (!this.socket) {
2328
2021
  return;
2329
2022
  }
@@ -2338,13 +2031,13 @@ var WebSocketClient = class {
2338
2031
  *
2339
2032
  * @param channel - Channel to subscribe to
2340
2033
  * @param options - Subscription options
2341
- * @returns Promise that resolves when subscribed
2034
+ * @returns Promise that resolves immediately (kept async for API compatibility)
2342
2035
  * @throws Error if not connected
2343
2036
  *
2344
2037
  * @example
2345
2038
  * ```typescript
2346
2039
  * // Subscribe to orderbook for a specific market
2347
- * await wsClient.subscribe('orderbook', { marketSlug: 'market-123' });
2040
+ * await wsClient.subscribe('orderbook', { marketSlugs: ['market-123'] });
2348
2041
  *
2349
2042
  * // Subscribe to all trades
2350
2043
  * await wsClient.subscribe('trades');
@@ -2357,21 +2050,20 @@ var WebSocketClient = class {
2357
2050
  if (!this.isConnected()) {
2358
2051
  throw new Error("WebSocket not connected. Call connect() first.");
2359
2052
  }
2053
+ const authenticatedChannels = [
2054
+ "subscribe_positions",
2055
+ "subscribe_transactions"
2056
+ ];
2057
+ if (authenticatedChannels.includes(channel) && !this.config.apiKey) {
2058
+ throw new Error(
2059
+ `API key is required for '${channel}' subscription. Please provide an API key in the constructor or set LIMITLESS_API_KEY environment variable. You can generate an API key at https://limitless.exchange`
2060
+ );
2061
+ }
2360
2062
  const subscriptionKey = this.getSubscriptionKey(channel, options);
2361
2063
  this.subscriptions.set(subscriptionKey, options);
2362
2064
  this.logger.info("Subscribing to channel", { channel, options });
2363
- return new Promise((resolve, reject) => {
2364
- this.socket.emit(channel, options, (response) => {
2365
- if (response?.error) {
2366
- this.logger.error("Subscription failed", response.error);
2367
- this.subscriptions.delete(subscriptionKey);
2368
- reject(new Error(response.error));
2369
- } else {
2370
- this.logger.info("Subscribed successfully", { channel, options });
2371
- resolve();
2372
- }
2373
- });
2374
- });
2065
+ this.socket.emit(channel, options);
2066
+ this.logger.info("Subscription request sent", { channel, options });
2375
2067
  }
2376
2068
  /**
2377
2069
  * Unsubscribes from a channel.
@@ -2379,10 +2071,11 @@ var WebSocketClient = class {
2379
2071
  * @param channel - Channel to unsubscribe from
2380
2072
  * @param options - Subscription options (must match subscribe call)
2381
2073
  * @returns Promise that resolves when unsubscribed
2074
+ * @throws Error if not connected or unsubscribe fails
2382
2075
  *
2383
2076
  * @example
2384
2077
  * ```typescript
2385
- * await wsClient.unsubscribe('orderbook', { marketSlug: 'market-123' });
2078
+ * await wsClient.unsubscribe('orderbook', { marketSlugs: ['market-123'] });
2386
2079
  * ```
2387
2080
  */
2388
2081
  async unsubscribe(channel, options = {}) {
@@ -2392,17 +2085,19 @@ var WebSocketClient = class {
2392
2085
  const subscriptionKey = this.getSubscriptionKey(channel, options);
2393
2086
  this.subscriptions.delete(subscriptionKey);
2394
2087
  this.logger.info("Unsubscribing from channel", { channel, options });
2395
- return new Promise((resolve, reject) => {
2396
- this.socket.emit("unsubscribe", { channel, ...options }, (response) => {
2397
- if (response?.error) {
2398
- this.logger.error("Unsubscribe failed", response.error);
2399
- reject(new Error(response.error));
2400
- } else {
2401
- this.logger.info("Unsubscribed successfully", { channel, options });
2402
- resolve();
2403
- }
2404
- });
2405
- });
2088
+ try {
2089
+ const unsubscribeData = { channel, ...options };
2090
+ const response = await this.socket.timeout(5e3).emitWithAck("unsubscribe", unsubscribeData);
2091
+ if (response && typeof response === "object" && "error" in response) {
2092
+ const errorMsg = response.error;
2093
+ this.logger.error("Unsubscribe failed", new Error(errorMsg), { error: errorMsg });
2094
+ throw new Error(`Unsubscribe failed: ${errorMsg}`);
2095
+ }
2096
+ this.logger.info("Unsubscribed successfully", { channel, options });
2097
+ } catch (error) {
2098
+ this.logger.error("Unsubscribe error", error, { channel });
2099
+ throw error;
2100
+ }
2406
2101
  }
2407
2102
  /**
2408
2103
  * Registers an event listener.
@@ -2445,14 +2140,27 @@ var WebSocketClient = class {
2445
2140
  * Removes an event listener.
2446
2141
  *
2447
2142
  * @param event - Event name
2448
- * @param handler - Event handler to remove
2143
+ * @param handler - Event handler to remove (if undefined, removes all handlers for event)
2449
2144
  * @returns This client for chaining
2145
+ *
2146
+ * @example
2147
+ * ```typescript
2148
+ * // Remove specific handler
2149
+ * wsClient.off('orderbookUpdate', myHandler);
2150
+ *
2151
+ * // Remove all handlers for event
2152
+ * wsClient.off('orderbookUpdate');
2153
+ * ```
2450
2154
  */
2451
2155
  off(event, handler) {
2452
2156
  if (!this.socket) {
2453
2157
  return this;
2454
2158
  }
2455
- this.socket.off(event, handler);
2159
+ if (handler === void 0) {
2160
+ this.socket.removeAllListeners(event);
2161
+ } else {
2162
+ this.socket.off(event, handler);
2163
+ }
2456
2164
  return this;
2457
2165
  }
2458
2166
  /**
@@ -2545,8 +2253,7 @@ var WebSocketClient = class {
2545
2253
  // Annotate the CommonJS export names for ESM import in node:
2546
2254
  0 && (module.exports = {
2547
2255
  APIError,
2548
- AuthenticatedClient,
2549
- Authenticator,
2256
+ AuthenticationError,
2550
2257
  BASE_SEPOLIA_CHAIN_ID,
2551
2258
  CONTRACT_ADDRESSES,
2552
2259
  ConsoleLogger,
@@ -2554,15 +2261,16 @@ var WebSocketClient = class {
2554
2261
  DEFAULT_CHAIN_ID,
2555
2262
  DEFAULT_WS_URL,
2556
2263
  HttpClient,
2264
+ Market,
2557
2265
  MarketFetcher,
2558
- MarketType,
2559
- MessageSigner,
2560
2266
  NoOpLogger,
2561
2267
  OrderBuilder,
2562
2268
  OrderClient,
2563
2269
  OrderSigner,
2564
2270
  OrderType,
2271
+ OrderValidationError,
2565
2272
  PortfolioFetcher,
2273
+ RateLimitError,
2566
2274
  RetryConfig,
2567
2275
  RetryableClient,
2568
2276
  SIGNING_MESSAGE_TEMPLATE,