pmxt-core 2.23.0 → 2.25.0
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/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
- package/dist/exchanges/polymarket/api-clob.js +1 -1
- package/dist/exchanges/polymarket/api-data.d.ts +1 -1
- package/dist/exchanges/polymarket/api-data.js +1 -1
- package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
- package/dist/exchanges/polymarket/api-gamma.js +1 -1
- package/dist/exchanges/polymarket/auth.js +42 -8
- package/dist/exchanges/polymarket/index.js +56 -19
- package/dist/exchanges/polymarket_us/config.d.ts +18 -0
- package/dist/exchanges/polymarket_us/config.js +22 -0
- package/dist/exchanges/polymarket_us/errors.d.ts +19 -0
- package/dist/exchanges/polymarket_us/errors.js +123 -0
- package/dist/exchanges/polymarket_us/errors.test.d.ts +1 -0
- package/dist/exchanges/polymarket_us/errors.test.js +54 -0
- package/dist/exchanges/polymarket_us/index.d.ts +90 -0
- package/dist/exchanges/polymarket_us/index.js +366 -0
- package/dist/exchanges/polymarket_us/index.test.d.ts +8 -0
- package/dist/exchanges/polymarket_us/index.test.js +237 -0
- package/dist/exchanges/polymarket_us/normalizer.d.ts +55 -0
- package/dist/exchanges/polymarket_us/normalizer.js +385 -0
- package/dist/exchanges/polymarket_us/normalizer.test.d.ts +1 -0
- package/dist/exchanges/polymarket_us/normalizer.test.js +224 -0
- package/dist/exchanges/polymarket_us/price.d.ts +94 -0
- package/dist/exchanges/polymarket_us/price.js +149 -0
- package/dist/exchanges/polymarket_us/price.test.d.ts +1 -0
- package/dist/exchanges/polymarket_us/price.test.js +131 -0
- package/dist/exchanges/polymarket_us/websocket.d.ts +39 -0
- package/dist/exchanges/polymarket_us/websocket.js +181 -0
- package/dist/exchanges/polymarket_us/websocket.test.d.ts +8 -0
- package/dist/exchanges/polymarket_us/websocket.test.js +162 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/smarkets/api.d.ts +8067 -0
- package/dist/exchanges/smarkets/api.js +10698 -0
- package/dist/exchanges/smarkets/auth.d.ts +56 -0
- package/dist/exchanges/smarkets/auth.js +105 -0
- package/dist/exchanges/smarkets/config.d.ts +41 -0
- package/dist/exchanges/smarkets/config.js +47 -0
- package/dist/exchanges/smarkets/errors.d.ts +31 -0
- package/dist/exchanges/smarkets/errors.js +186 -0
- package/dist/exchanges/smarkets/fetcher.d.ts +177 -0
- package/dist/exchanges/smarkets/fetcher.js +342 -0
- package/dist/exchanges/smarkets/index.d.ts +54 -0
- package/dist/exchanges/smarkets/index.js +285 -0
- package/dist/exchanges/smarkets/normalizer.d.ts +18 -0
- package/dist/exchanges/smarkets/normalizer.js +267 -0
- package/dist/exchanges/smarkets/price.d.ts +26 -0
- package/dist/exchanges/smarkets/price.js +44 -0
- package/dist/exchanges/smarkets/price.test.d.ts +1 -0
- package/dist/exchanges/smarkets/price.test.js +50 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -1
- package/dist/server/app.js +18 -2
- package/package.json +4 -3
|
@@ -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-04-
|
|
3
|
+
* Generated at: 2026-04-06T19:59:33.306Z
|
|
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-04-
|
|
6
|
+
* Generated at: 2026-04-06T19:59:33.306Z
|
|
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-04-
|
|
3
|
+
* Generated at: 2026-04-06T19:59:33.358Z
|
|
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-04-
|
|
6
|
+
* Generated at: 2026-04-06T19:59:33.358Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.limitlessApiSpec = {
|
|
@@ -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-04-
|
|
3
|
+
* Generated at: 2026-04-06T19:59:33.373Z
|
|
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-04-
|
|
6
|
+
* Generated at: 2026-04-06T19:59:33.373Z
|
|
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-04-
|
|
3
|
+
* Generated at: 2026-04-06T19:59:33.380Z
|
|
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-04-
|
|
6
|
+
* Generated at: 2026-04-06T19:59:33.380Z
|
|
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-04-
|
|
3
|
+
* Generated at: 2026-04-06T19:59:33.315Z
|
|
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-04-
|
|
6
|
+
* Generated at: 2026-04-06T19:59:33.315Z
|
|
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-04-
|
|
3
|
+
* Generated at: 2026-04-06T19:59:33.333Z
|
|
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-04-
|
|
6
|
+
* Generated at: 2026-04-06T19:59:33.333Z
|
|
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-04-
|
|
3
|
+
* Generated at: 2026-04-06T19:59:33.328Z
|
|
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-04-
|
|
6
|
+
* Generated at: 2026-04-06T19:59:33.328Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketGammaSpec = {
|
|
@@ -158,22 +158,56 @@ class PolymarketAuth {
|
|
|
158
158
|
if (this.clobClient) {
|
|
159
159
|
return this.clobClient;
|
|
160
160
|
}
|
|
161
|
-
// 1. Determine proxy and signature type early
|
|
161
|
+
// 1. Determine proxy and signature type early.
|
|
162
|
+
//
|
|
163
|
+
// Important: if signatureType is not provided we MUST run discovery
|
|
164
|
+
// even when funderAddress is provided. Previously this branch was
|
|
165
|
+
// skipped whenever funderAddress was set, which silently defaulted
|
|
166
|
+
// signatureType to 0 (EOA). For wallets whose funds live on a Gnosis
|
|
167
|
+
// Safe (the modern Polymarket onboarding default) the CLOB then
|
|
168
|
+
// reports balance "0" instead of the real value, with no error.
|
|
169
|
+
const sigTypeProvided = this.credentials.signatureType !== undefined && this.credentials.signatureType !== null;
|
|
162
170
|
let proxyAddress = this.credentials.funderAddress || undefined;
|
|
163
|
-
let signatureType =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
let signatureType = sigTypeProvided
|
|
172
|
+
? this.mapSignatureType(this.credentials.signatureType)
|
|
173
|
+
: undefined;
|
|
174
|
+
// Run discovery if either piece is missing. Note: discoverProxy()
|
|
175
|
+
// returns a synthetic { proxyAddress: signerEOA, signatureType: 0 }
|
|
176
|
+
// fallback when its HTTP call fails — that fallback should NOT be
|
|
177
|
+
// used to populate signatureType when funderAddress is already set,
|
|
178
|
+
// because it would silently assign EOA semantics to a Gnosis Safe.
|
|
179
|
+
let discoverySucceeded = false;
|
|
180
|
+
if (!proxyAddress || signatureType === undefined) {
|
|
181
|
+
try {
|
|
182
|
+
const discovered = await this.discoverProxy();
|
|
183
|
+
discoverySucceeded =
|
|
184
|
+
!!this.discoveredProxyAddress &&
|
|
185
|
+
this.discoveredSignatureType !== undefined;
|
|
186
|
+
if (!proxyAddress) {
|
|
187
|
+
proxyAddress = discovered.proxyAddress;
|
|
188
|
+
}
|
|
189
|
+
if (signatureType === undefined && discoverySucceeded) {
|
|
190
|
+
signatureType = discovered.signatureType;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// Discovery failure is handled by the heuristic below.
|
|
169
195
|
}
|
|
170
196
|
}
|
|
171
197
|
// Get API credentials (L1 auth)
|
|
172
|
-
// Pass signature type if we know it (some accounts need it for derivation?)
|
|
173
198
|
const apiCreds = await this.getApiCredentials();
|
|
174
199
|
// 3. Defaults
|
|
175
200
|
const signerAddress = this.signer.address;
|
|
176
201
|
const finalProxyAddress = (proxyAddress || signerAddress);
|
|
202
|
+
// If signature type is still unknown, infer from address relationship:
|
|
203
|
+
// when the funder differs from the signer EOA, the funder must be a
|
|
204
|
+
// proxy/safe — default to Gnosis Safe (2), which is what Polymarket
|
|
205
|
+
// has created for new accounts since 2023. Users on the legacy
|
|
206
|
+
// Polymarket Proxy (1) need to set signatureType explicitly.
|
|
207
|
+
if (signatureType === undefined) {
|
|
208
|
+
signatureType =
|
|
209
|
+
finalProxyAddress.toLowerCase() !== signerAddress.toLowerCase() ? 2 : 0;
|
|
210
|
+
}
|
|
177
211
|
const finalSignatureType = signatureType;
|
|
178
212
|
// Create L2-authenticated client
|
|
179
213
|
// console.log(`[PolymarketAuth] Initializing ClobClient | Signer: ${signerAddress} | Funder: ${finalProxyAddress} | SigType: ${finalSignatureType}`);
|
|
@@ -357,45 +357,82 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
357
357
|
const client = await auth.getClobClient();
|
|
358
358
|
// Polymarket relies strictly on USDC (Polygon)
|
|
359
359
|
const USDC_DECIMALS = 6;
|
|
360
|
-
// Try fetching from CLOB client first
|
|
360
|
+
// Try fetching from CLOB client first.
|
|
361
|
+
//
|
|
362
|
+
// Note on the bundled @polymarket/clob-client error model: its HTTP
|
|
363
|
+
// wrapper swallows axios errors and RETURNS an envelope shaped like
|
|
364
|
+
// { error, status } instead of throwing. We must therefore validate
|
|
365
|
+
// the shape of the result before using it, otherwise downstream
|
|
366
|
+
// parseFloat() yields NaN and the on-chain fallback never triggers.
|
|
361
367
|
let total = 0;
|
|
368
|
+
let clobBalanceAvailable = false;
|
|
362
369
|
try {
|
|
363
370
|
const balRes = await client.getBalanceAllowance({
|
|
364
371
|
asset_type: clob_client_1.AssetType.COLLATERAL,
|
|
365
372
|
});
|
|
366
|
-
|
|
367
|
-
|
|
373
|
+
if (balRes && typeof balRes.balance === 'string') {
|
|
374
|
+
const rawBalance = parseFloat(balRes.balance);
|
|
375
|
+
if (Number.isFinite(rawBalance)) {
|
|
376
|
+
total = rawBalance / Math.pow(10, USDC_DECIMALS);
|
|
377
|
+
clobBalanceAvailable = true;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// If balRes was an error envelope, fall through to on-chain.
|
|
368
381
|
}
|
|
369
382
|
catch (clobError) {
|
|
370
|
-
//
|
|
371
|
-
// but let's assume we proceed to on-chain check if total is 0
|
|
372
|
-
// or just do on-chain check always for robustness if possible.
|
|
373
|
-
// For now, let's trust CLOB but add On-Chain fallback if CLOB returns 0.
|
|
383
|
+
// Network/transport error — fall through to on-chain.
|
|
374
384
|
}
|
|
375
385
|
// On-Chain Fallback/Check (Robustness)
|
|
376
|
-
//
|
|
377
|
-
|
|
386
|
+
// Trigger when CLOB couldn't tell us, or reported a true zero (CLOB
|
|
387
|
+
// can lag or be confused about proxies for newly funded wallets).
|
|
388
|
+
if (!clobBalanceAvailable || total === 0) {
|
|
378
389
|
try {
|
|
379
390
|
const targetAddress = await auth.getEffectiveFunderAddress();
|
|
380
391
|
const balances = await this.getAddressOnChainBalance(targetAddress);
|
|
381
|
-
|
|
392
|
+
const onChain = balances[0]?.total ?? 0;
|
|
393
|
+
if (onChain > 0) {
|
|
394
|
+
total = onChain;
|
|
395
|
+
}
|
|
382
396
|
}
|
|
383
397
|
catch {
|
|
384
398
|
}
|
|
385
399
|
}
|
|
386
|
-
// 2. Fetch open orders to calculate locked funds
|
|
387
|
-
// We only care about BUY orders for USDC balance locking
|
|
388
|
-
|
|
400
|
+
// 2. Fetch open orders to calculate locked funds.
|
|
401
|
+
// We only care about BUY orders for USDC balance locking.
|
|
402
|
+
//
|
|
403
|
+
// The bundled @polymarket/clob-client throws "response.data is not
|
|
404
|
+
// iterable" from inside its getOpenOrders pagination loop whenever
|
|
405
|
+
// the CLOB API returns an HTTP error envelope (the library spreads
|
|
406
|
+
// response.data unconditionally). This is the root cause of #72:
|
|
407
|
+
// a wallet that has not completed Polymarket onboarding triggers an
|
|
408
|
+
// upstream auth/setup rejection that surfaces here as an opaque
|
|
409
|
+
// TypeError. Catch it and translate to a clear AuthenticationError.
|
|
389
410
|
let locked = 0;
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
411
|
+
try {
|
|
412
|
+
const openOrders = await client.getOpenOrders({});
|
|
413
|
+
if (Array.isArray(openOrders)) {
|
|
414
|
+
for (const order of openOrders) {
|
|
415
|
+
if (order.side === clob_client_1.Side.BUY) {
|
|
416
|
+
const remainingSize = parseFloat(order.original_size) - parseFloat(order.size_matched);
|
|
417
|
+
const price = parseFloat(order.price);
|
|
418
|
+
locked += remainingSize * price;
|
|
419
|
+
}
|
|
396
420
|
}
|
|
397
421
|
}
|
|
398
422
|
}
|
|
423
|
+
catch (ordersError) {
|
|
424
|
+
const msg = String(ordersError?.message ?? ordersError);
|
|
425
|
+
if (msg.includes('is not iterable')) {
|
|
426
|
+
throw new errors_1.AuthenticationError('Polymarket CLOB rejected the request to list open orders. ' +
|
|
427
|
+
'This usually means the wallet has not completed Polymarket ' +
|
|
428
|
+
'onboarding (no proxy/safe exists for this signer), or that ' +
|
|
429
|
+
'funderAddress / signatureType need to be passed explicitly. ' +
|
|
430
|
+
'Visit https://polymarket.com to complete account setup, or ' +
|
|
431
|
+
'pass funderAddress and signatureType in credentials.', 'Polymarket');
|
|
432
|
+
}
|
|
433
|
+
// Unexpected failure — surface through the standard mapper.
|
|
434
|
+
throw ordersError;
|
|
435
|
+
}
|
|
399
436
|
return [{
|
|
400
437
|
currency: 'USDC',
|
|
401
438
|
total: total,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polymarket US runtime configuration.
|
|
3
|
+
*
|
|
4
|
+
* Hand-authored single source of truth for base URLs and config factory
|
|
5
|
+
* for the Polymarket US exchange adapter (wraps the polymarket-us SDK).
|
|
6
|
+
*/
|
|
7
|
+
export declare const POLYMARKET_US_API_BASE_URL = "https://api.polymarket.us";
|
|
8
|
+
export declare const POLYMARKET_US_GATEWAY_BASE_URL = "https://gateway.polymarket.us";
|
|
9
|
+
export interface PolymarketUSConfig {
|
|
10
|
+
/** Base REST API URL */
|
|
11
|
+
apiUrl: string;
|
|
12
|
+
/** Gateway URL (used by the SDK for order signing / submission) */
|
|
13
|
+
gatewayUrl: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Return a typed config object for the Polymarket US API.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getPolymarketUSConfig(): PolymarketUSConfig;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Polymarket US runtime configuration.
|
|
4
|
+
*
|
|
5
|
+
* Hand-authored single source of truth for base URLs and config factory
|
|
6
|
+
* for the Polymarket US exchange adapter (wraps the polymarket-us SDK).
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.POLYMARKET_US_GATEWAY_BASE_URL = exports.POLYMARKET_US_API_BASE_URL = void 0;
|
|
10
|
+
exports.getPolymarketUSConfig = getPolymarketUSConfig;
|
|
11
|
+
// -- Base URL constants -------------------------------------------------------
|
|
12
|
+
exports.POLYMARKET_US_API_BASE_URL = "https://api.polymarket.us";
|
|
13
|
+
exports.POLYMARKET_US_GATEWAY_BASE_URL = "https://gateway.polymarket.us";
|
|
14
|
+
/**
|
|
15
|
+
* Return a typed config object for the Polymarket US API.
|
|
16
|
+
*/
|
|
17
|
+
function getPolymarketUSConfig() {
|
|
18
|
+
return {
|
|
19
|
+
apiUrl: exports.POLYMARKET_US_API_BASE_URL,
|
|
20
|
+
gatewayUrl: exports.POLYMARKET_US_GATEWAY_BASE_URL,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps polymarket-us SDK errors to PMXT unified error classes.
|
|
3
|
+
*
|
|
4
|
+
* The SDK exposes typed error subclasses (AuthenticationError,
|
|
5
|
+
* BadRequestError, NotFoundError, RateLimitError, InternalServerError,
|
|
6
|
+
* APIError, PolymarketUSError) so we can dispatch on instance rather
|
|
7
|
+
* than inspecting raw HTTP responses.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Polymarket US -> PMXT error mapper.
|
|
11
|
+
*/
|
|
12
|
+
export declare class PolymarketUSErrorMapper {
|
|
13
|
+
/**
|
|
14
|
+
* Map an unknown error thrown by the polymarket-us SDK (or any
|
|
15
|
+
* other source) to a PMXT error class instance.
|
|
16
|
+
*/
|
|
17
|
+
mapError(error: unknown): Error;
|
|
18
|
+
}
|
|
19
|
+
export declare const polymarketUSErrorMapper: PolymarketUSErrorMapper;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Maps polymarket-us SDK errors to PMXT unified error classes.
|
|
4
|
+
*
|
|
5
|
+
* The SDK exposes typed error subclasses (AuthenticationError,
|
|
6
|
+
* BadRequestError, NotFoundError, RateLimitError, InternalServerError,
|
|
7
|
+
* APIError, PolymarketUSError) so we can dispatch on instance rather
|
|
8
|
+
* than inspecting raw HTTP responses.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.polymarketUSErrorMapper = exports.PolymarketUSErrorMapper = void 0;
|
|
12
|
+
const polymarket_us_1 = require("polymarket-us");
|
|
13
|
+
const errors_1 = require("../../errors");
|
|
14
|
+
const EXCHANGE_NAME = 'PolymarketUS';
|
|
15
|
+
/**
|
|
16
|
+
* Construct a generic PMXT error for cases where no more specific
|
|
17
|
+
* mapping applies. Uses BaseError directly since the project does not
|
|
18
|
+
* yet expose an `ExchangeError` class.
|
|
19
|
+
*/
|
|
20
|
+
function genericExchangeError(message) {
|
|
21
|
+
return new errors_1.BaseError(message, 500, 'EXCHANGE_ERROR', false, EXCHANGE_NAME);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Polymarket US -> PMXT error mapper.
|
|
25
|
+
*/
|
|
26
|
+
class PolymarketUSErrorMapper {
|
|
27
|
+
/**
|
|
28
|
+
* Map an unknown error thrown by the polymarket-us SDK (or any
|
|
29
|
+
* other source) to a PMXT error class instance.
|
|
30
|
+
*/
|
|
31
|
+
mapError(error) {
|
|
32
|
+
// Already a PMXT error: pass through unchanged so callers can
|
|
33
|
+
// rely on `instanceof` checks (e.g. AuthenticationError thrown
|
|
34
|
+
// by `requireAuth` before any SDK call).
|
|
35
|
+
if (error instanceof errors_1.BaseError) {
|
|
36
|
+
return error;
|
|
37
|
+
}
|
|
38
|
+
// Authentication
|
|
39
|
+
if (error instanceof polymarket_us_1.AuthenticationError) {
|
|
40
|
+
return new errors_1.AuthenticationError(error.message, EXCHANGE_NAME);
|
|
41
|
+
}
|
|
42
|
+
// Rate limit
|
|
43
|
+
if (error instanceof polymarket_us_1.RateLimitError) {
|
|
44
|
+
return new errors_1.RateLimitExceeded(error.message, undefined, EXCHANGE_NAME);
|
|
45
|
+
}
|
|
46
|
+
// Not found - inspect message to discriminate order vs market
|
|
47
|
+
if (error instanceof polymarket_us_1.NotFoundError) {
|
|
48
|
+
const lower = (error.message || '').toLowerCase();
|
|
49
|
+
if (lower.includes('order')) {
|
|
50
|
+
return new errors_1.OrderNotFound(error.message, EXCHANGE_NAME);
|
|
51
|
+
}
|
|
52
|
+
if (lower.includes('market')) {
|
|
53
|
+
return new errors_1.MarketNotFound(error.message, EXCHANGE_NAME);
|
|
54
|
+
}
|
|
55
|
+
return genericExchangeError(error.message);
|
|
56
|
+
}
|
|
57
|
+
// Internal server error -> retryable unavailable
|
|
58
|
+
if (error instanceof polymarket_us_1.InternalServerError) {
|
|
59
|
+
return new errors_1.ExchangeNotAvailable(error.message, EXCHANGE_NAME);
|
|
60
|
+
}
|
|
61
|
+
// Bad request - inspect for known sub-categories
|
|
62
|
+
if (error instanceof polymarket_us_1.BadRequestError) {
|
|
63
|
+
return mapBadRequest(error.message);
|
|
64
|
+
}
|
|
65
|
+
// Generic API error - dispatch on status code
|
|
66
|
+
if (error instanceof polymarket_us_1.APIError) {
|
|
67
|
+
return mapByStatus(error.status, error.message);
|
|
68
|
+
}
|
|
69
|
+
// Catch-all SDK base class
|
|
70
|
+
if (error instanceof polymarket_us_1.PolymarketUSError) {
|
|
71
|
+
return genericExchangeError(error.message);
|
|
72
|
+
}
|
|
73
|
+
// Anything else
|
|
74
|
+
const message = String(error?.message ?? error);
|
|
75
|
+
return genericExchangeError(message);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.PolymarketUSErrorMapper = PolymarketUSErrorMapper;
|
|
79
|
+
function mapBadRequest(message) {
|
|
80
|
+
const lower = (message || '').toLowerCase();
|
|
81
|
+
if (lower.includes('insufficient') ||
|
|
82
|
+
lower.includes('buying power') ||
|
|
83
|
+
lower.includes('balance')) {
|
|
84
|
+
return new errors_1.InsufficientFunds(message, EXCHANGE_NAME);
|
|
85
|
+
}
|
|
86
|
+
if (lower.includes('invalid order') ||
|
|
87
|
+
lower.includes('price') ||
|
|
88
|
+
lower.includes('quantity') ||
|
|
89
|
+
lower.includes('tick') ||
|
|
90
|
+
lower.includes('self-match') ||
|
|
91
|
+
lower.includes('self_match')) {
|
|
92
|
+
return new errors_1.InvalidOrder(message, EXCHANGE_NAME);
|
|
93
|
+
}
|
|
94
|
+
if (lower.includes('market')) {
|
|
95
|
+
if (lower.includes('not found')) {
|
|
96
|
+
return new errors_1.MarketNotFound(message, EXCHANGE_NAME);
|
|
97
|
+
}
|
|
98
|
+
if (lower.includes('closed') ||
|
|
99
|
+
lower.includes('expired') ||
|
|
100
|
+
lower.includes('halted') ||
|
|
101
|
+
lower.includes('suspended')) {
|
|
102
|
+
return new errors_1.InvalidOrder(message, EXCHANGE_NAME);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return new errors_1.BadRequest(message, EXCHANGE_NAME);
|
|
106
|
+
}
|
|
107
|
+
function mapByStatus(status, message) {
|
|
108
|
+
if (status === 401) {
|
|
109
|
+
return new errors_1.AuthenticationError(message, EXCHANGE_NAME);
|
|
110
|
+
}
|
|
111
|
+
if (status === 404) {
|
|
112
|
+
return genericExchangeError(message);
|
|
113
|
+
}
|
|
114
|
+
if (status === 429) {
|
|
115
|
+
return new errors_1.RateLimitExceeded(message, undefined, EXCHANGE_NAME);
|
|
116
|
+
}
|
|
117
|
+
if (status >= 500 && status < 600) {
|
|
118
|
+
return new errors_1.ExchangeNotAvailable(message, EXCHANGE_NAME);
|
|
119
|
+
}
|
|
120
|
+
return new errors_1.BadRequest(message, EXCHANGE_NAME);
|
|
121
|
+
}
|
|
122
|
+
// Singleton instance for convenience
|
|
123
|
+
exports.polymarketUSErrorMapper = new PolymarketUSErrorMapper();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const errors_1 = require("./errors");
|
|
4
|
+
const polymarket_us_1 = require("polymarket-us");
|
|
5
|
+
const errors_2 = require("../../errors");
|
|
6
|
+
describe('PolymarketUSErrorMapper', () => {
|
|
7
|
+
const mapper = new errors_1.PolymarketUSErrorMapper();
|
|
8
|
+
test('maps SDK AuthenticationError -> PMXT AuthenticationError', () => {
|
|
9
|
+
const mapped = mapper.mapError(new polymarket_us_1.AuthenticationError('bad token'));
|
|
10
|
+
expect(mapped).toBeInstanceOf(errors_2.AuthenticationError);
|
|
11
|
+
expect(mapped.exchange).toBe('PolymarketUS');
|
|
12
|
+
});
|
|
13
|
+
test('maps BadRequestError("Insufficient buying power") -> InsufficientFunds', () => {
|
|
14
|
+
const mapped = mapper.mapError(new polymarket_us_1.BadRequestError('Insufficient buying power'));
|
|
15
|
+
expect(mapped).toBeInstanceOf(errors_2.InsufficientFunds);
|
|
16
|
+
});
|
|
17
|
+
test('maps BadRequestError("Invalid price tick") -> InvalidOrder', () => {
|
|
18
|
+
const mapped = mapper.mapError(new polymarket_us_1.BadRequestError('Invalid price tick'));
|
|
19
|
+
expect(mapped).toBeInstanceOf(errors_2.InvalidOrder);
|
|
20
|
+
});
|
|
21
|
+
test('maps BadRequestError("Self-match prevented") -> InvalidOrder', () => {
|
|
22
|
+
const mapped = mapper.mapError(new polymarket_us_1.BadRequestError('Self-match prevented'));
|
|
23
|
+
expect(mapped).toBeInstanceOf(errors_2.InvalidOrder);
|
|
24
|
+
});
|
|
25
|
+
test('maps NotFoundError("Order not found") -> OrderNotFound', () => {
|
|
26
|
+
const mapped = mapper.mapError(new polymarket_us_1.NotFoundError('Order not found'));
|
|
27
|
+
expect(mapped).toBeInstanceOf(errors_2.OrderNotFound);
|
|
28
|
+
});
|
|
29
|
+
test('maps NotFoundError("Market not found") -> MarketNotFound', () => {
|
|
30
|
+
const mapped = mapper.mapError(new polymarket_us_1.NotFoundError('Market not found'));
|
|
31
|
+
expect(mapped).toBeInstanceOf(errors_2.MarketNotFound);
|
|
32
|
+
});
|
|
33
|
+
test('maps RateLimitError -> RateLimitExceeded', () => {
|
|
34
|
+
const mapped = mapper.mapError(new polymarket_us_1.RateLimitError('slow down'));
|
|
35
|
+
expect(mapped).toBeInstanceOf(errors_2.RateLimitExceeded);
|
|
36
|
+
});
|
|
37
|
+
test('maps InternalServerError -> ExchangeNotAvailable', () => {
|
|
38
|
+
const mapped = mapper.mapError(new polymarket_us_1.InternalServerError('boom'));
|
|
39
|
+
expect(mapped).toBeInstanceOf(errors_2.ExchangeNotAvailable);
|
|
40
|
+
});
|
|
41
|
+
test('maps generic Error -> generic exchange BaseError', () => {
|
|
42
|
+
const mapped = mapper.mapError(new Error('something failed'));
|
|
43
|
+
expect(mapped).toBeInstanceOf(errors_2.BaseError);
|
|
44
|
+
expect(mapped.exchange).toBe('PolymarketUS');
|
|
45
|
+
expect(mapped.code).toBe('EXCHANGE_ERROR');
|
|
46
|
+
expect(mapped.message).toBe('something failed');
|
|
47
|
+
});
|
|
48
|
+
test('maps plain object -> generic exchange BaseError', () => {
|
|
49
|
+
const mapped = mapper.mapError({ message: 'plain object error' });
|
|
50
|
+
expect(mapped).toBeInstanceOf(errors_2.BaseError);
|
|
51
|
+
expect(mapped.exchange).toBe('PolymarketUS');
|
|
52
|
+
expect(mapped.message).toBe('plain object error');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polymarket US exchange adapter.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the official `polymarket-us` SDK to expose Polymarket US under the
|
|
5
|
+
* unified PMXT `PredictionMarketExchange` interface.
|
|
6
|
+
*
|
|
7
|
+
* Notes:
|
|
8
|
+
* - PMXT `marketId` corresponds to the Polymarket US market `slug`.
|
|
9
|
+
* - Outcomes are encoded as `${slug}:long` and `${slug}:short`.
|
|
10
|
+
* - Polymarket US books and orders are quoted in long-side prices; helpers
|
|
11
|
+
* in `./price` perform the side-aware conversion.
|
|
12
|
+
* - The SDK requires `marketSlug` in the cancel body, but PMXT
|
|
13
|
+
* `cancelOrder(orderId)` does not. We maintain an in-memory cache mapping
|
|
14
|
+
* orderId -> marketSlug populated whenever we observe an order.
|
|
15
|
+
*/
|
|
16
|
+
import { PredictionMarketExchange, ExchangeCredentials, MarketFetchParams, EventFetchParams, MyTradesParams } from '../../BaseExchange';
|
|
17
|
+
import { UnifiedMarket, UnifiedEvent, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams, BuiltOrder } from '../../types';
|
|
18
|
+
export * from './config';
|
|
19
|
+
export * from './price';
|
|
20
|
+
export * from './errors';
|
|
21
|
+
export { PolymarketUSNormalizer } from './normalizer';
|
|
22
|
+
export declare class PolymarketUSExchange extends PredictionMarketExchange {
|
|
23
|
+
readonly has: {
|
|
24
|
+
fetchMarkets: true;
|
|
25
|
+
fetchEvents: true;
|
|
26
|
+
fetchOHLCV: false;
|
|
27
|
+
fetchOrderBook: true;
|
|
28
|
+
fetchTrades: false;
|
|
29
|
+
createOrder: true;
|
|
30
|
+
cancelOrder: true;
|
|
31
|
+
fetchOrder: true;
|
|
32
|
+
fetchOpenOrders: true;
|
|
33
|
+
fetchPositions: true;
|
|
34
|
+
fetchBalance: true;
|
|
35
|
+
watchAddress: false;
|
|
36
|
+
unwatchAddress: false;
|
|
37
|
+
watchOrderBook: true;
|
|
38
|
+
watchTrades: true;
|
|
39
|
+
fetchMyTrades: true;
|
|
40
|
+
fetchClosedOrders: false;
|
|
41
|
+
fetchAllOrders: false;
|
|
42
|
+
buildOrder: true;
|
|
43
|
+
submitOrder: true;
|
|
44
|
+
};
|
|
45
|
+
private readonly client;
|
|
46
|
+
private readonly normalizer;
|
|
47
|
+
private readonly config;
|
|
48
|
+
/**
|
|
49
|
+
* Maps PMXT orderId -> Polymarket US marketSlug. Populated whenever we
|
|
50
|
+
* observe an order (create, fetch, list) so that `cancelOrder(orderId)`
|
|
51
|
+
* can supply the SDK-required `marketSlug` body field.
|
|
52
|
+
*/
|
|
53
|
+
private readonly orderSlugCache;
|
|
54
|
+
private wsWrapper?;
|
|
55
|
+
constructor(credentials?: ExchangeCredentials);
|
|
56
|
+
get name(): string;
|
|
57
|
+
private requireAuth;
|
|
58
|
+
/**
|
|
59
|
+
* Wrap any SDK call so SDK errors get translated to PMXT error classes.
|
|
60
|
+
*/
|
|
61
|
+
private run;
|
|
62
|
+
private cacheOrder;
|
|
63
|
+
/**
|
|
64
|
+
* Strip a trailing `:long` or `:short` suffix from a PMXT identifier
|
|
65
|
+
* to recover the bare Polymarket US market slug. If no suffix is
|
|
66
|
+
* present the input is returned unchanged.
|
|
67
|
+
*/
|
|
68
|
+
private slugFromId;
|
|
69
|
+
protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
70
|
+
protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
71
|
+
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
72
|
+
fetchBalance(_address?: string): Promise<Balance[]>;
|
|
73
|
+
fetchPositions(_address?: string): Promise<Position[]>;
|
|
74
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
75
|
+
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
76
|
+
fetchOrder(orderId: string): Promise<Order>;
|
|
77
|
+
buildOrder(params: CreateOrderParams): Promise<BuiltOrder>;
|
|
78
|
+
submitOrder(built: BuiltOrder): Promise<Order>;
|
|
79
|
+
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
80
|
+
cancelOrder(orderId: string): Promise<Order>;
|
|
81
|
+
/**
|
|
82
|
+
* Lazily construct the WebSocket wrapper. The underlying SDK factory
|
|
83
|
+
* requires credentials even for the public market socket, so this
|
|
84
|
+
* method calls `requireAuth()` up front.
|
|
85
|
+
*/
|
|
86
|
+
private ensureWs;
|
|
87
|
+
watchOrderBook(id: string, _limit?: number): Promise<OrderBook>;
|
|
88
|
+
watchTrades(id: string, _address?: string, _since?: number, _limit?: number): Promise<Trade[]>;
|
|
89
|
+
close(): Promise<void>;
|
|
90
|
+
}
|