pmxt-core 2.37.7 → 2.37.9

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:19:53.152Z
3
+ * Generated at: 2026-05-07T05:14:50.177Z
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:19:53.152Z
6
+ * Generated at: 2026-05-07T05:14:50.177Z
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:19:53.192Z
3
+ * Generated at: 2026-05-07T05:14:50.217Z
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:19:53.192Z
6
+ * Generated at: 2026-05-07T05:14:50.217Z
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:19:53.204Z
3
+ * Generated at: 2026-05-07T05:14:50.228Z
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:19:53.204Z
6
+ * Generated at: 2026-05-07T05:14:50.228Z
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:19:53.207Z
3
+ * Generated at: 2026-05-07T05:14:50.231Z
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:19:53.207Z
6
+ * Generated at: 2026-05-07T05:14:50.231Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.opinionApiSpec = {
@@ -273,10 +273,15 @@ class OpinionNormalizer {
273
273
  label: child.noLabel || 'No',
274
274
  price: 0.5,
275
275
  };
276
+ const childTitle = child.marketTitle || '';
277
+ const parentTitle = parent.marketTitle || '';
278
+ const combinedTitle = parentTitle && childTitle
279
+ ? `${parentTitle} - ${childTitle}`
280
+ : parentTitle || childTitle;
276
281
  const market = {
277
282
  marketId,
278
283
  eventId: String(parent.marketId),
279
- title: child.marketTitle || '',
284
+ title: combinedTitle,
280
285
  description: child.rules || '',
281
286
  outcomes: [yesOutcome, noOutcome],
282
287
  resolutionDate: new Date((0, utils_1.toMillis)(child.cutoffAt)),
@@ -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:19:53.160Z
3
+ * Generated at: 2026-05-07T05:14:50.184Z
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:19:53.160Z
6
+ * Generated at: 2026-05-07T05:14:50.184Z
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:19:53.171Z
3
+ * Generated at: 2026-05-07T05:14:50.199Z
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:19:53.171Z
6
+ * Generated at: 2026-05-07T05:14:50.199Z
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:19:53.169Z
3
+ * Generated at: 2026-05-07T05:14:50.197Z
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:19:53.169Z
6
+ * Generated at: 2026-05-07T05:14:50.197Z
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:19:53.198Z
3
+ * Generated at: 2026-05-07T05:14:50.222Z
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:19:53.198Z
6
+ * Generated at: 2026-05-07T05:14:50.222Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {
@@ -2843,6 +2843,9 @@ components:
2843
2843
  negRisk:
2844
2844
  type: boolean
2845
2845
  description: Optional override to skip neg-risk lookup (Polymarket)
2846
+ onBehalfOf:
2847
+ type: number
2848
+ description: 'Limitless delegated signing: profile ID to trade on behalf of'
2846
2849
  required:
2847
2850
  - marketId
2848
2851
  - outcomeId
@@ -3381,6 +3384,8 @@ components:
3381
3384
  funderAddress:
3382
3385
  type: string
3383
3386
  description: The address funding the trades (defaults to signer address)
3387
+ walletAddress:
3388
+ type: string
3384
3389
  x-sdk-constructors:
3385
3390
  polymarket:
3386
3391
  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.7",
3
+ "version": "2.37.9",
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.7,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.7,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.9,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.9,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",