pmxt-core 2.37.8 → 2.37.10

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.
@@ -271,6 +271,7 @@ export interface ExchangeCredentials {
271
271
  privateKey?: string;
272
272
  signatureType?: number | string;
273
273
  funderAddress?: string;
274
+ walletAddress?: string;
274
275
  }
275
276
  export interface ExchangeOptions {
276
277
  /**
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
3
- * Generated at: 2026-05-05T12:47:28.371Z
3
+ * Generated at: 2026-05-08T14:38:32.269Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const kalshiApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.kalshiApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
6
- * Generated at: 2026-05-05T12:47:28.371Z
6
+ * Generated at: 2026-05-08T14:38:32.269Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.kalshiApiSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
3
- * Generated at: 2026-05-05T12:47:28.411Z
3
+ * Generated at: 2026-05-08T14:38:32.317Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const limitlessApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.limitlessApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
6
- * Generated at: 2026-05-05T12:47:28.411Z
6
+ * Generated at: 2026-05-08T14:38:32.317Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.limitlessApiSpec = {
@@ -1,40 +1,35 @@
1
1
  import { HttpClient } from '@limitless-exchange/sdk';
2
2
  import { Wallet } from 'ethers';
3
3
  import { ExchangeCredentials } from '../../BaseExchange';
4
+ export interface HMACCredentials {
5
+ tokenId: string;
6
+ secret: string;
7
+ }
4
8
  /**
5
- * Manages Limitless authentication using API keys.
6
- * Simplified from cookie-based to API key authentication.
9
+ * Manages Limitless authentication.
10
+ *
11
+ * Supports two modes:
12
+ * 1. API key + private key (individual signer — EIP-712 order signing)
13
+ * 2. HMAC credentials (partner/delegated signing — no private key needed)
7
14
  */
8
15
  export declare class LimitlessAuth {
9
16
  private credentials;
10
17
  private signer?;
11
18
  private httpClient?;
12
19
  private apiKey?;
20
+ private hmacCreds?;
13
21
  constructor(credentials: ExchangeCredentials);
14
- /**
15
- * Get the API key being used for authentication.
16
- */
17
22
  getApiKey(): string;
18
23
  /**
19
- * Get or create the HTTP client with API key authentication.
20
- * This client automatically includes the X-API-Key header in all requests.
24
+ * Get or create the HTTP client.
25
+ * Uses HMAC auth when credentials are available (delegated signing),
26
+ * otherwise falls back to the legacy X-API-Key header.
21
27
  */
22
28
  getHttpClient(): HttpClient;
23
- /**
24
- * Get the signer (wallet) for signing orders.
25
- * Required for placing orders via EIP-712 signatures.
26
- */
27
29
  getSigner(): Wallet;
28
- /**
29
- * Get the signer's address.
30
- */
31
30
  getAddress(): string;
32
- /**
33
- * Check if the auth has a signer available.
34
- */
35
31
  hasSigner(): boolean;
36
- /**
37
- * Reset cached client (useful for testing or credential rotation).
38
- */
32
+ /** True when HMAC credentials are present and no private key — delegated signing mode. */
33
+ isDelegatedSigning(): boolean;
39
34
  reset(): void;
40
35
  }
@@ -5,81 +5,86 @@ const sdk_1 = require("@limitless-exchange/sdk");
5
5
  const ethers_1 = require("ethers");
6
6
  const LIMITLESS_HOST = 'https://api.limitless.exchange';
7
7
  /**
8
- * Manages Limitless authentication using API keys.
9
- * Simplified from cookie-based to API key authentication.
8
+ * Manages Limitless authentication.
9
+ *
10
+ * Supports two modes:
11
+ * 1. API key + private key (individual signer — EIP-712 order signing)
12
+ * 2. HMAC credentials (partner/delegated signing — no private key needed)
10
13
  */
11
14
  class LimitlessAuth {
12
15
  credentials;
13
16
  signer;
14
17
  httpClient;
15
18
  apiKey;
19
+ hmacCreds;
16
20
  constructor(credentials) {
17
21
  this.credentials = credentials;
18
- // API key is required for authenticated endpoints
19
- // Can come from credentials or environment variable
22
+ // HMAC credentials for delegated signing (partner mode).
23
+ // apiSecret is the base64-encoded HMAC secret from the Limitless dashboard.
24
+ if (credentials.apiKey && credentials.apiSecret) {
25
+ this.hmacCreds = {
26
+ tokenId: credentials.apiKey,
27
+ secret: credentials.apiSecret,
28
+ };
29
+ }
30
+ // API key for legacy X-API-Key header auth.
20
31
  this.apiKey = credentials.apiKey || process.env.LIMITLESS_API_KEY;
21
- if (!this.apiKey) {
32
+ if (!this.apiKey && !this.hmacCreds) {
22
33
  throw new Error('Limitless requires an API key. Set LIMITLESS_API_KEY environment variable or provide apiKey in credentials.');
23
34
  }
24
- // Initialize signer if private key is provided (needed for order signing)
35
+ // Initialize signer if private key is provided (needed for EIP-712 order signing).
25
36
  if (credentials.privateKey) {
26
37
  let privateKey = credentials.privateKey;
27
- // Fix for common .env issue where newlines are escaped
28
38
  if (privateKey.includes('\\n')) {
29
39
  privateKey = privateKey.replace(/\\n/g, '\n');
30
40
  }
31
41
  this.signer = new ethers_1.Wallet(privateKey);
32
42
  }
33
43
  }
34
- /**
35
- * Get the API key being used for authentication.
36
- */
37
44
  getApiKey() {
38
45
  return this.apiKey;
39
46
  }
40
47
  /**
41
- * Get or create the HTTP client with API key authentication.
42
- * This client automatically includes the X-API-Key header in all requests.
48
+ * Get or create the HTTP client.
49
+ * Uses HMAC auth when credentials are available (delegated signing),
50
+ * otherwise falls back to the legacy X-API-Key header.
43
51
  */
44
52
  getHttpClient() {
45
53
  if (this.httpClient) {
46
54
  return this.httpClient;
47
55
  }
48
- this.httpClient = new sdk_1.HttpClient({
56
+ const config = {
49
57
  baseURL: LIMITLESS_HOST,
50
- apiKey: this.apiKey,
51
58
  timeout: 30000,
52
- });
59
+ };
60
+ if (this.hmacCreds) {
61
+ config.hmacCredentials = this.hmacCreds;
62
+ }
63
+ else if (this.apiKey) {
64
+ config.apiKey = this.apiKey;
65
+ }
66
+ this.httpClient = new sdk_1.HttpClient(config);
53
67
  return this.httpClient;
54
68
  }
55
- /**
56
- * Get the signer (wallet) for signing orders.
57
- * Required for placing orders via EIP-712 signatures.
58
- */
59
69
  getSigner() {
60
70
  if (!this.signer) {
61
71
  throw new Error('Wallet signer not available. Provide privateKey in credentials to sign orders.');
62
72
  }
63
73
  return this.signer;
64
74
  }
65
- /**
66
- * Get the signer's address.
67
- */
68
75
  getAddress() {
69
76
  if (!this.signer) {
70
77
  throw new Error('Signer not initialized. Provide privateKey in credentials.');
71
78
  }
72
79
  return this.signer.address;
73
80
  }
74
- /**
75
- * Check if the auth has a signer available.
76
- */
77
81
  hasSigner() {
78
82
  return !!this.signer;
79
83
  }
80
- /**
81
- * Reset cached client (useful for testing or credential rotation).
82
- */
84
+ /** True when HMAC credentials are present and no private key — delegated signing mode. */
85
+ isDelegatedSigning() {
86
+ return !!this.hmacCreds && !this.signer;
87
+ }
83
88
  reset() {
84
89
  this.httpClient = undefined;
85
90
  }
@@ -1,4 +1,5 @@
1
1
  import { HttpClient, OrderClient, MarketFetcher } from '@limitless-exchange/sdk';
2
+ import { Wallet } from 'ethers';
2
3
  export interface LimitlessOrderParams {
3
4
  marketSlug: string;
4
5
  outcomeId: string;
@@ -6,28 +7,71 @@ export interface LimitlessOrderParams {
6
7
  price: number;
7
8
  amount: number;
8
9
  type?: 'limit' | 'market';
10
+ onBehalfOf?: number;
11
+ }
12
+ export interface LimitlessClientConfig {
13
+ httpClient: HttpClient;
14
+ wallet?: Wallet;
15
+ isDelegated?: boolean;
16
+ /** Wallet address for profile lookup in delegated mode. */
17
+ walletAddress?: string;
9
18
  }
10
19
  /**
11
20
  * Wrapper client for Limitless Exchange using the official SDK.
12
- * Provides a simplified interface for market data and order operations.
21
+ *
22
+ * Two modes:
23
+ * - Individual: wallet + OrderClient (EIP-712 signing)
24
+ * - Delegated: no wallet, DelegatedOrderService (HMAC auth, server signs)
13
25
  */
14
26
  export declare class LimitlessClient {
15
27
  private httpClient;
16
- private orderClient;
28
+ private orderClient?;
17
29
  private marketFetcher;
18
- private signer;
30
+ private signer?;
31
+ private readonly isDelegated;
32
+ private walletAddress?;
33
+ private cachedProfileId?;
19
34
  private marketCache;
35
+ /** @deprecated Use the config-object constructor instead. */
20
36
  constructor(privateKey: string, apiKey: string);
37
+ constructor(config: LimitlessClientConfig);
21
38
  /**
22
39
  * Get market details by slug.
23
40
  * Results are cached to reduce API calls.
24
41
  */
25
42
  getMarket(slug: string): Promise<any>;
26
43
  /**
27
- * Create a limit order (GTC - Good Till Cancelled).
28
- * The SDK handles EIP-712 signing automatically.
44
+ * Create an order.
45
+ *
46
+ * - Individual mode: EIP-712 signed via OrderClient (requires private key).
47
+ * - Delegated mode: unsigned order via DelegatedOrderService (HMAC auth).
48
+ */
49
+ createOrder(params: LimitlessOrderParams): Promise<{
50
+ order: any;
51
+ id: any;
52
+ } | import("@limitless-exchange/sdk").OrderResponse>;
53
+ /**
54
+ * Create an order for a smart wallet account.
55
+ * maker = smart wallet address, signer = EOA address (our private key).
56
+ */
57
+ private createSmartWalletOrder;
58
+ /**
59
+ * Build and submit an unsigned order via the delegated signing flow.
60
+ * The Limitless server signs on behalf of the partner account.
61
+ * No private key required — uses HMAC-authenticated HTTP.
62
+ */
63
+ /**
64
+ * Resolve the Limitless profile ID for this account.
65
+ * Fetched once from the public profile endpoint, then cached.
66
+ */
67
+ private cachedProfile?;
68
+ private resolveProfile;
69
+ private resolveProfileId;
70
+ /**
71
+ * Build and submit an unsigned order via the delegated signing flow.
72
+ * The Limitless server signs on behalf of the account.
29
73
  */
30
- createOrder(params: LimitlessOrderParams): Promise<import("@limitless-exchange/sdk").OrderResponse>;
74
+ private createDelegatedOrder;
31
75
  /**
32
76
  * Cancel a specific order by ID.
33
77
  */
@@ -57,7 +101,7 @@ export declare class LimitlessClient {
57
101
  /**
58
102
  * Get the underlying OrderClient for advanced order operations.
59
103
  */
60
- getOrderClient(): OrderClient;
104
+ getOrderClient(): OrderClient | undefined;
61
105
  /**
62
106
  * Get the underlying MarketFetcher for advanced market queries.
63
107
  */
@@ -6,33 +6,66 @@ const ethers_1 = require("ethers");
6
6
  const LIMITLESS_API_URL = 'https://api.limitless.exchange';
7
7
  /**
8
8
  * Wrapper client for Limitless Exchange using the official SDK.
9
- * Provides a simplified interface for market data and order operations.
9
+ *
10
+ * Two modes:
11
+ * - Individual: wallet + OrderClient (EIP-712 signing)
12
+ * - Delegated: no wallet, DelegatedOrderService (HMAC auth, server signs)
10
13
  */
11
14
  class LimitlessClient {
12
15
  httpClient;
13
16
  orderClient;
14
17
  marketFetcher;
15
18
  signer;
19
+ isDelegated;
20
+ walletAddress;
21
+ cachedProfileId;
16
22
  marketCache = {};
17
- constructor(privateKey, apiKey) {
18
- // Fix for common .env issue where newlines are escaped
19
- if (privateKey.includes('\\n')) {
20
- privateKey = privateKey.replace(/\\n/g, '\n');
23
+ constructor(configOrKey, apiKey) {
24
+ if (typeof configOrKey === 'string') {
25
+ // Legacy positional constructor: (privateKey, apiKey)
26
+ let privateKey = configOrKey;
27
+ if (privateKey.includes('\\n')) {
28
+ privateKey = privateKey.replace(/\\n/g, '\n');
29
+ }
30
+ this.signer = new ethers_1.Wallet(privateKey);
31
+ this.isDelegated = false;
32
+ this.httpClient = new sdk_1.HttpClient({
33
+ baseURL: LIMITLESS_API_URL,
34
+ apiKey: apiKey,
35
+ timeout: 30000,
36
+ });
37
+ // ethers v5/v6 compat: SDK expects wallet.signTypedData (v6)
38
+ const wallet = this.signer;
39
+ if (!wallet.signTypedData && wallet._signTypedData) {
40
+ wallet.signTypedData = wallet._signTypedData;
41
+ }
42
+ this.orderClient = new sdk_1.OrderClient({
43
+ httpClient: this.httpClient,
44
+ wallet: wallet,
45
+ });
46
+ this.marketFetcher = new sdk_1.MarketFetcher(this.httpClient);
47
+ return;
21
48
  }
22
- this.signer = new ethers_1.Wallet(privateKey);
23
- // Initialize HTTP client with API key
24
- this.httpClient = new sdk_1.HttpClient({
25
- baseURL: LIMITLESS_API_URL,
26
- apiKey: apiKey,
27
- timeout: 30000,
28
- });
29
- // Initialize SDK clients
30
- // Note: SDK uses ethers v6, we use v5, so we cast to any
31
- this.orderClient = new sdk_1.OrderClient({
32
- httpClient: this.httpClient,
33
- wallet: this.signer,
34
- });
49
+ // New config-object constructor
50
+ const config = configOrKey;
51
+ this.httpClient = config.httpClient;
52
+ this.isDelegated = config.isDelegated ?? false;
53
+ this.walletAddress = config.walletAddress;
35
54
  this.marketFetcher = new sdk_1.MarketFetcher(this.httpClient);
55
+ if (!this.isDelegated && config.wallet) {
56
+ this.signer = config.wallet;
57
+ const wallet = this.signer;
58
+ if (!wallet.signTypedData && wallet._signTypedData) {
59
+ wallet.signTypedData = wallet._signTypedData;
60
+ }
61
+ this.orderClient = new sdk_1.OrderClient({
62
+ httpClient: this.httpClient,
63
+ wallet: wallet,
64
+ });
65
+ }
66
+ // In delegated mode without a wallet, createOrder uses a direct
67
+ // HTTP POST with an unsigned order payload (no SDK DelegatedOrderService
68
+ // required — compatible with all SDK versions).
36
69
  }
37
70
  /**
38
71
  * Get market details by slug.
@@ -50,33 +83,159 @@ class LimitlessClient {
50
83
  return market;
51
84
  }
52
85
  /**
53
- * Create a limit order (GTC - Good Till Cancelled).
54
- * The SDK handles EIP-712 signing automatically.
86
+ * Create an order.
87
+ *
88
+ * - Individual mode: EIP-712 signed via OrderClient (requires private key).
89
+ * - Delegated mode: unsigned order via DelegatedOrderService (HMAC auth).
55
90
  */
56
91
  async createOrder(params) {
57
92
  const market = await this.getMarket(params.marketSlug);
58
93
  if (!market.venue || !market.venue.exchange) {
59
94
  throw new Error(`Market ${params.marketSlug} has no venue exchange address`);
60
95
  }
61
- // Map BUY/SELL to SDK's Side enum
62
96
  const side = params.side === 'BUY' ? sdk_1.Side.BUY : sdk_1.Side.SELL;
63
- // Determine order type - default to GTC (limit orders)
64
- // FOK (Fill-or-Kill) can be used for market orders
65
97
  const orderType = params.type === 'market' ? sdk_1.OrderType.FOK : sdk_1.OrderType.GTC;
66
- // Create order using SDK
67
- // The SDK handles:
68
- // - EIP-712 signing
69
- // - Amount calculations (converting to proper decimals)
70
- // - API request formatting
71
- const order = await this.orderClient.createOrder({
72
- tokenId: params.outcomeId,
73
- price: params.price,
74
- size: params.amount,
75
- side: side,
76
- orderType: orderType,
77
- marketSlug: params.marketSlug,
98
+ if (this.isDelegated) {
99
+ return this.createDelegatedOrder(params, side, orderType);
100
+ }
101
+ if (!this.signer) {
102
+ throw new Error('No signer available. Provide a privateKey or use delegated signing.');
103
+ }
104
+ // For smart wallets: maker = smartWallet address, signer = EOA address.
105
+ // For EOA wallets: maker = signer = wallet address.
106
+ // The walletAddress credential indicates a smart wallet.
107
+ const signerAddress = this.signer.address;
108
+ const makerAddress = this.walletAddress ?? signerAddress;
109
+ const isSmartWallet = makerAddress.toLowerCase() !== signerAddress.toLowerCase();
110
+ if (!isSmartWallet && this.orderClient) {
111
+ // Standard EOA flow — use the SDK's OrderClient directly.
112
+ return this.orderClient.createOrder({
113
+ tokenId: params.outcomeId,
114
+ price: params.price,
115
+ size: params.amount,
116
+ side,
117
+ orderType,
118
+ marketSlug: params.marketSlug,
119
+ });
120
+ }
121
+ // Smart wallet flow: build the order with maker=smartWallet, signer=EOA,
122
+ // sign with the EOA key, and submit.
123
+ return this.createSmartWalletOrder(params, side, orderType, market, makerAddress, signerAddress);
124
+ }
125
+ /**
126
+ * Create an order for a smart wallet account.
127
+ * maker = smart wallet address, signer = EOA address (our private key).
128
+ */
129
+ async createSmartWalletOrder(params, side, orderType, market, makerAddress, signerAddress) {
130
+ if (!this.walletAddress) {
131
+ throw new Error('Smart wallet flow requires walletAddress in credentials.');
132
+ }
133
+ if (!this.signer) {
134
+ throw new Error('Smart wallet flow requires a privateKey for signing.');
135
+ }
136
+ const profile = await this.resolveProfile();
137
+ const feeRateBps = profile.feeRateBps ?? 100;
138
+ // Build unsigned order with maker = smart wallet address.
139
+ const builder = new sdk_1.OrderBuilder(makerAddress, feeRateBps);
140
+ const orderArgs = orderType === sdk_1.OrderType.FOK
141
+ ? { tokenId: params.outcomeId, makerAmount: params.price * params.amount, side }
142
+ : { tokenId: params.outcomeId, price: params.price, size: params.amount, side };
143
+ const unsignedOrder = builder.buildOrder(orderArgs);
144
+ // Override signer to the EOA (different from maker for smart wallets).
145
+ unsignedOrder.signer = signerAddress;
146
+ // ethers v5/v6 compat shim — SDK expects signTypedData (v6).
147
+ const wallet = this.signer;
148
+ if (!wallet.signTypedData && wallet._signTypedData) {
149
+ wallet.signTypedData = wallet._signTypedData;
150
+ }
151
+ // Sign with the EOA private key.
152
+ const orderSigner = new sdk_1.OrderSigner(wallet);
153
+ const signature = await orderSigner.signOrder(unsignedOrder, {
154
+ chainId: 8453,
155
+ contractAddress: market.venue.exchange,
78
156
  });
79
- return order;
157
+ // Submit with ownerId (required by Limitless API).
158
+ const payload = {
159
+ order: { ...unsignedOrder, signature },
160
+ orderType: orderType === sdk_1.OrderType.FOK ? 'FOK' : 'GTC',
161
+ marketSlug: params.marketSlug,
162
+ ownerId: profile.id,
163
+ };
164
+ const response = await this.httpClient.post('/orders', payload);
165
+ return {
166
+ order: response,
167
+ id: response?.order?.id ?? 'unknown',
168
+ };
169
+ }
170
+ /**
171
+ * Build and submit an unsigned order via the delegated signing flow.
172
+ * The Limitless server signs on behalf of the partner account.
173
+ * No private key required — uses HMAC-authenticated HTTP.
174
+ */
175
+ /**
176
+ * Resolve the Limitless profile ID for this account.
177
+ * Fetched once from the public profile endpoint, then cached.
178
+ */
179
+ cachedProfile;
180
+ async resolveProfile() {
181
+ if (this.cachedProfile)
182
+ return this.cachedProfile;
183
+ const addr = this.walletAddress ?? this.signer?.address;
184
+ if (!addr) {
185
+ throw new Error('No wallet address available for profile lookup.');
186
+ }
187
+ const profile = await this.httpClient.get(`/profiles/public/${addr}`);
188
+ const id = profile?.id;
189
+ if (!id || !Number.isFinite(id)) {
190
+ throw new Error(`Could not resolve Limitless profile ID for ${addr}`);
191
+ }
192
+ this.cachedProfile = {
193
+ id,
194
+ feeRateBps: profile?.rank?.feeRateBps ?? 100,
195
+ };
196
+ return this.cachedProfile;
197
+ }
198
+ async resolveProfileId() {
199
+ return (await this.resolveProfile()).id;
200
+ }
201
+ /**
202
+ * Build and submit an unsigned order via the delegated signing flow.
203
+ * The Limitless server signs on behalf of the account.
204
+ */
205
+ async createDelegatedOrder(params, side, orderType) {
206
+ const profileId = params.onBehalfOf ?? await this.resolveProfileId();
207
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
208
+ const USDC_DECIMALS = 6;
209
+ const price = Math.round(params.price * 1_000_000) / 1_000_000;
210
+ const size = params.amount;
211
+ const makerAmount = Math.round(price * size * Math.pow(10, USDC_DECIMALS));
212
+ const takerAmount = Math.round(size * Math.pow(10, USDC_DECIMALS));
213
+ const payload = {
214
+ order: {
215
+ salt: Date.now() * 1000 + Math.floor(Math.random() * 1000),
216
+ maker: ZERO_ADDRESS,
217
+ signer: ZERO_ADDRESS,
218
+ taker: ZERO_ADDRESS,
219
+ tokenId: params.outcomeId,
220
+ makerAmount: side === sdk_1.Side.BUY ? makerAmount : takerAmount,
221
+ takerAmount: side === sdk_1.Side.BUY ? takerAmount : makerAmount,
222
+ expiration: '0',
223
+ nonce: 0,
224
+ feeRateBps: 100,
225
+ side: side === sdk_1.Side.BUY ? 0 : 1,
226
+ signatureType: 0,
227
+ price,
228
+ },
229
+ orderType: orderType === sdk_1.OrderType.FOK ? 'FOK' : 'GTC',
230
+ marketSlug: params.marketSlug,
231
+ ownerId: profileId,
232
+ onBehalfOf: profileId,
233
+ };
234
+ const response = await this.httpClient.post('/orders', payload);
235
+ return {
236
+ order: response,
237
+ id: response?.order?.id ?? 'unknown',
238
+ };
80
239
  }
81
240
  /**
82
241
  * Cancel a specific order by ID.
@@ -109,7 +268,7 @@ class LimitlessClient {
109
268
  * Get the signer's wallet address.
110
269
  */
111
270
  getAddress() {
112
- return this.signer.address;
271
+ return this.signer?.address ?? '';
113
272
  }
114
273
  /**
115
274
  * Get the underlying HTTP client for direct API access.
@@ -53,10 +53,33 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
53
53
  if (credentials?.apiKey || credentials?.privateKey) {
54
54
  try {
55
55
  this.auth = new auth_1.LimitlessAuth(credentials);
56
- // Initialize client only if we have both privateKey and apiKey
57
56
  if (credentials.privateKey) {
58
- const apiKey = this.auth.getApiKey();
59
- this.client = new client_1.LimitlessClient(credentials.privateKey, apiKey);
57
+ // Signing mode: use the private key for EIP-712 signatures.
58
+ // When apiSecret is also present, use HMAC-authenticated HTTP
59
+ // (new-style tokens); otherwise legacy X-API-Key header.
60
+ if (credentials.apiSecret) {
61
+ let pk = credentials.privateKey;
62
+ if (!pk.startsWith('0x'))
63
+ pk = '0x' + pk;
64
+ const wallet = new (require('ethers').Wallet)(pk);
65
+ this.client = new client_1.LimitlessClient({
66
+ httpClient: this.auth.getHttpClient(),
67
+ wallet,
68
+ walletAddress: credentials.walletAddress,
69
+ });
70
+ }
71
+ else {
72
+ const apiKey = this.auth.getApiKey();
73
+ this.client = new client_1.LimitlessClient(credentials.privateKey, apiKey);
74
+ }
75
+ }
76
+ else if (this.auth.isDelegatedSigning()) {
77
+ // Delegated mode: HMAC auth, no private key, server signs
78
+ this.client = new client_1.LimitlessClient({
79
+ httpClient: this.auth.getHttpClient(),
80
+ isDelegated: true,
81
+ walletAddress: credentials.walletAddress,
82
+ });
60
83
  }
61
84
  }
62
85
  catch (error) {
@@ -197,6 +220,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
197
220
  price: price,
198
221
  amount: params.amount,
199
222
  type: params.type,
223
+ onBehalfOf: params.onBehalfOf,
200
224
  });
201
225
  // Map response to Order object
202
226
  // The SDK returns OrderResponse with order.id
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
3
- * Generated at: 2026-05-05T12:47:28.423Z
3
+ * Generated at: 2026-05-08T14:38:32.331Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const myriadApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.myriadApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
6
- * Generated at: 2026-05-05T12:47:28.423Z
6
+ * Generated at: 2026-05-08T14:38:32.331Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.myriadApiSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
3
- * Generated at: 2026-05-05T12:47:28.427Z
3
+ * Generated at: 2026-05-08T14:38:32.337Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const opinionApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.opinionApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
6
- * Generated at: 2026-05-05T12:47:28.427Z
6
+ * Generated at: 2026-05-08T14:38:32.337Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.opinionApiSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
3
- * Generated at: 2026-05-05T12:47:28.378Z
3
+ * Generated at: 2026-05-08T14:38:32.277Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketClobSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketClobSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
6
- * Generated at: 2026-05-05T12:47:28.378Z
6
+ * Generated at: 2026-05-08T14:38:32.277Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketClobSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
3
- * Generated at: 2026-05-05T12:47:28.393Z
3
+ * Generated at: 2026-05-08T14:38:32.294Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketDataSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketDataSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
6
- * Generated at: 2026-05-05T12:47:28.393Z
6
+ * Generated at: 2026-05-08T14:38:32.294Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketDataSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
3
- * Generated at: 2026-05-05T12:47:28.389Z
3
+ * Generated at: 2026-05-08T14:38:32.290Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketGammaSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketGammaSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
6
- * Generated at: 2026-05-05T12:47:28.389Z
6
+ * Generated at: 2026-05-08T14:38:32.290Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketGammaSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
3
- * Generated at: 2026-05-05T12:47:28.416Z
3
+ * Generated at: 2026-05-08T14:38:32.324Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const probableApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.probableApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
6
- * Generated at: 2026-05-05T12:47:28.416Z
6
+ * Generated at: 2026-05-08T14:38:32.324Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {
@@ -239,6 +239,16 @@ function createApp(options = {}) {
239
239
  });
240
240
  return;
241
241
  }
242
+ if (exchange.has &&
243
+ methodName in exchange.has &&
244
+ exchange.has[methodName] === false) {
245
+ res.status(501).json({
246
+ success: false,
247
+ error: `Method '${methodName}' is not supported by '${exchangeName}'. ` +
248
+ `Use exchange: "router" for cross-venue methods.`,
249
+ });
250
+ return;
251
+ }
242
252
  const result = await exchange[methodName](...args);
243
253
  res.json({ success: true, data: result });
244
254
  }
@@ -1561,7 +1561,14 @@ paths:
1561
1561
  summary: Market Matches
1562
1562
  operationId: fetchMarketMatches
1563
1563
  parameters:
1564
- - $ref: '#/components/parameters/ExchangeParam'
1564
+ - in: path
1565
+ name: exchange
1566
+ schema:
1567
+ type: string
1568
+ enum:
1569
+ - router
1570
+ required: true
1571
+ description: The prediction market exchange to target.
1565
1572
  - in: query
1566
1573
  name: query
1567
1574
  required: false
@@ -1663,7 +1670,14 @@ paths:
1663
1670
  summary: Event Matches
1664
1671
  operationId: fetchEventMatches
1665
1672
  parameters:
1666
- - $ref: '#/components/parameters/ExchangeParam'
1673
+ - in: path
1674
+ name: exchange
1675
+ schema:
1676
+ type: string
1677
+ enum:
1678
+ - router
1679
+ required: true
1680
+ description: The prediction market exchange to target.
1667
1681
  - in: query
1668
1682
  name: query
1669
1683
  required: false
@@ -1744,7 +1758,14 @@ paths:
1744
1758
  summary: Compare Prices Across Venues
1745
1759
  operationId: compareMarketPrices
1746
1760
  parameters:
1747
- - $ref: '#/components/parameters/ExchangeParam'
1761
+ - in: path
1762
+ name: exchange
1763
+ schema:
1764
+ type: string
1765
+ enum:
1766
+ - router
1767
+ required: true
1768
+ description: The prediction market exchange to target.
1748
1769
  requestBody:
1749
1770
  content:
1750
1771
  application/json:
@@ -1784,7 +1805,14 @@ paths:
1784
1805
  summary: Find Related Markets
1785
1806
  operationId: fetchRelatedMarkets
1786
1807
  parameters:
1787
- - $ref: '#/components/parameters/ExchangeParam'
1808
+ - in: path
1809
+ name: exchange
1810
+ schema:
1811
+ type: string
1812
+ enum:
1813
+ - router
1814
+ required: true
1815
+ description: The prediction market exchange to target.
1788
1816
  - in: query
1789
1817
  name: query
1790
1818
  required: false
@@ -1884,7 +1912,14 @@ paths:
1884
1912
  summary: Matched Markets
1885
1913
  operationId: fetchMatchedMarkets
1886
1914
  parameters:
1887
- - $ref: '#/components/parameters/ExchangeParam'
1915
+ - in: path
1916
+ name: exchange
1917
+ schema:
1918
+ type: string
1919
+ enum:
1920
+ - router
1921
+ required: true
1922
+ description: The prediction market exchange to target.
1888
1923
  - in: query
1889
1924
  name: minDifference
1890
1925
  required: false
@@ -1934,7 +1969,14 @@ paths:
1934
1969
  summary: Compare Matched Market Prices
1935
1970
  operationId: fetchMatchedPrices
1936
1971
  parameters:
1937
- - $ref: '#/components/parameters/ExchangeParam'
1972
+ - in: path
1973
+ name: exchange
1974
+ schema:
1975
+ type: string
1976
+ enum:
1977
+ - router
1978
+ required: true
1979
+ description: The prediction market exchange to target.
1938
1980
  - in: query
1939
1981
  name: minDifference
1940
1982
  required: false
@@ -1984,7 +2026,14 @@ paths:
1984
2026
  summary: Find Hedging Opportunities
1985
2027
  operationId: fetchHedges
1986
2028
  parameters:
1987
- - $ref: '#/components/parameters/ExchangeParam'
2029
+ - in: path
2030
+ name: exchange
2031
+ schema:
2032
+ type: string
2033
+ enum:
2034
+ - router
2035
+ required: true
2036
+ description: The prediction market exchange to target.
1988
2037
  - in: query
1989
2038
  name: query
1990
2039
  required: false
@@ -2082,7 +2131,14 @@ paths:
2082
2131
  summary: Find Arbitrage Opportunities
2083
2132
  operationId: fetchArbitrage
2084
2133
  parameters:
2085
- - $ref: '#/components/parameters/ExchangeParam'
2134
+ - in: path
2135
+ name: exchange
2136
+ schema:
2137
+ type: string
2138
+ enum:
2139
+ - router
2140
+ required: true
2141
+ description: The prediction market exchange to target.
2086
2142
  - in: query
2087
2143
  name: minSpread
2088
2144
  required: false
@@ -2843,6 +2899,9 @@ components:
2843
2899
  negRisk:
2844
2900
  type: boolean
2845
2901
  description: Optional override to skip neg-risk lookup (Polymarket)
2902
+ onBehalfOf:
2903
+ type: number
2904
+ description: 'Limitless delegated signing: profile ID to trade on behalf of'
2846
2905
  required:
2847
2906
  - marketId
2848
2907
  - outcomeId
@@ -3381,6 +3440,8 @@ components:
3381
3440
  funderAddress:
3382
3441
  type: string
3383
3442
  description: The address funding the trades (defaults to signer address)
3443
+ walletAddress:
3444
+ type: string
3384
3445
  x-sdk-constructors:
3385
3446
  polymarket:
3386
3447
  className: Polymarket
package/dist/types.d.ts CHANGED
@@ -206,6 +206,7 @@ export interface CreateOrderParams {
206
206
  fee?: number;
207
207
  tickSize?: number;
208
208
  negRisk?: boolean;
209
+ onBehalfOf?: number;
209
210
  }
210
211
  export interface BuiltOrder {
211
212
  /** The exchange name this order was built for. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxt-core",
3
- "version": "2.37.8",
3
+ "version": "2.37.10",
4
4
  "description": "pmxt is a unified prediction market data API. The ccxt for prediction markets.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,8 +29,8 @@
29
29
  "test": "jest -c jest.config.js",
30
30
  "server": "tsx watch src/server/index.ts",
31
31
  "server:prod": "node dist/server/index.js",
32
- "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.37.8,library=urllib3",
33
- "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.37.8,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
32
+ "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.37.10,library=urllib3",
33
+ "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.37.10,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
34
34
  "fetch:openapi": "node scripts/fetch-openapi-specs.js",
35
35
  "extract:jsdoc": "node ../scripts/extract-jsdoc.js",
36
36
  "generate:docs": "npm run extract:jsdoc && node ../scripts/generate-api-docs.js",
@@ -45,7 +45,7 @@
45
45
  "license": "MIT",
46
46
  "type": "commonjs",
47
47
  "dependencies": {
48
- "@limitless-exchange/sdk": "^1.0.2",
48
+ "@limitless-exchange/sdk": "^1.0.5",
49
49
  "@opinion-labs/opinion-clob-sdk": "^0.6.0",
50
50
  "@polymarket/clob-client-v2": "^1.0.0",
51
51
  "@prob/clob": "0.5.0",