pmxt-core 2.48.6 → 2.49.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/gemini-titan/normalizer.js +9 -3
- package/dist/exchanges/gemini-titan/websocket.js +17 -5
- package/dist/exchanges/hyperliquid/normalizer.js +2 -0
- package/dist/exchanges/interfaces.d.ts +2 -2
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +2 -2
- package/dist/exchanges/kalshi/config.d.ts +6 -6
- package/dist/exchanges/kalshi/config.js +8 -8
- package/dist/exchanges/kalshi/fetcher.d.ts +2 -0
- package/dist/exchanges/kalshi/fetcher.js +6 -7
- package/dist/exchanges/kalshi/normalizer.js +6 -1
- package/dist/exchanges/kalshi/websocket.js +21 -9
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/client.js +2 -2
- package/dist/exchanges/limitless/config.d.ts +2 -0
- package/dist/exchanges/limitless/config.js +3 -1
- package/dist/exchanges/limitless/fetcher.d.ts +10 -0
- package/dist/exchanges/limitless/fetcher.js +2 -1
- package/dist/exchanges/limitless/index.js +1 -1
- package/dist/exchanges/limitless/utils.js +3 -3
- package/dist/exchanges/limitless/websocket.js +8 -11
- package/dist/exchanges/metaculus/utils.js +0 -1
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +17 -2
- package/dist/exchanges/myriad/normalizer.js +10 -5
- package/dist/exchanges/myriad/utils.js +2 -0
- package/dist/exchanges/opinion/api.d.ts +16 -1
- package/dist/exchanges/opinion/api.js +20 -1
- package/dist/exchanges/opinion/websocket.js +21 -14
- package/dist/exchanges/polymarket/api-clob.d.ts +13 -1
- package/dist/exchanges/polymarket/api-clob.js +26 -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 +3 -3
- package/dist/exchanges/polymarket/config.d.ts +1 -0
- package/dist/exchanges/polymarket/config.js +4 -0
- package/dist/exchanges/polymarket/index.js +2 -1
- package/dist/exchanges/polymarket_us/websocket.js +3 -2
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/auth.js +5 -4
- package/dist/exchanges/probable/config.d.ts +2 -0
- package/dist/exchanges/probable/config.js +5 -0
- package/dist/exchanges/probable/websocket.js +2 -1
- package/dist/exchanges/suibets/api.d.ts +1 -1
- package/dist/exchanges/suibets/api.js +1 -1
- package/dist/exchanges/suibets/config.d.ts +1 -1
- package/dist/exchanges/suibets/config.js +2 -2
- package/dist/exchanges/suibets/errors.js +9 -0
- package/dist/exchanges/suibets/fetcher.d.ts +22 -2
- package/dist/exchanges/suibets/fetcher.js +23 -5
- package/dist/exchanges/suibets/index.d.ts +1 -1
- package/dist/exchanges/suibets/index.js +1 -1
- package/dist/exchanges/suibets/normalizer.js +2 -22
- package/dist/feeds/binance/binance-feed.js +6 -3
- package/dist/feeds/chainlink/chainlink-feed.js +5 -2
- package/dist/server/openapi.yaml +2 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils/throttler.js +3 -5
- package/package.json +4 -4
|
@@ -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-06-
|
|
6
|
+
* Generated at: 2026-06-08T19:06:11.875Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.opinionApiSpec = {
|
|
@@ -150,6 +150,25 @@ exports.opinionApiSpec = {
|
|
|
150
150
|
]
|
|
151
151
|
}
|
|
152
152
|
},
|
|
153
|
+
"/market/slug/{slug}": {
|
|
154
|
+
"get": {
|
|
155
|
+
"tags": [
|
|
156
|
+
"Market"
|
|
157
|
+
],
|
|
158
|
+
"summary": "Get market detail by slug",
|
|
159
|
+
"operationId": "getMarketDetailBySlug",
|
|
160
|
+
"parameters": [
|
|
161
|
+
{
|
|
162
|
+
"name": "slug",
|
|
163
|
+
"in": "path",
|
|
164
|
+
"required": true,
|
|
165
|
+
"schema": {
|
|
166
|
+
"type": "string"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
},
|
|
153
172
|
"/market/categorical/{marketId}": {
|
|
154
173
|
"get": {
|
|
155
174
|
"tags": [
|
|
@@ -200,10 +200,7 @@ class OpinionWebSocket {
|
|
|
200
200
|
if (isNaN(price)) {
|
|
201
201
|
return;
|
|
202
202
|
}
|
|
203
|
-
const
|
|
204
|
-
const book = existing
|
|
205
|
-
? { ...existing }
|
|
206
|
-
: { bids: [], asks: [], timestamp: Date.now() };
|
|
203
|
+
const book = this.orderBooks.get(marketId) ?? { bids: [], asks: [], timestamp: Date.now() };
|
|
207
204
|
if (side === "bids") {
|
|
208
205
|
book.bids = applyLevelUpdate(book.bids, price, size, "desc");
|
|
209
206
|
}
|
|
@@ -280,8 +277,11 @@ class OpinionWebSocket {
|
|
|
280
277
|
this.subscribedDepthMarketIds.add(marketId);
|
|
281
278
|
}
|
|
282
279
|
if (!this.isConnected) {
|
|
283
|
-
this.connect().catch(() => {
|
|
284
|
-
|
|
280
|
+
this.connect().catch((err) => {
|
|
281
|
+
logger_1.logger.warn("Opinion WebSocket connect failed during watchOrderBook", { error: String(err) });
|
|
282
|
+
if (!this.isTerminated) {
|
|
283
|
+
this.scheduleReconnect();
|
|
284
|
+
}
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
287
|
else {
|
|
@@ -310,8 +310,11 @@ class OpinionWebSocket {
|
|
|
310
310
|
this.subscribedTradeMarketIds.add(marketId);
|
|
311
311
|
}
|
|
312
312
|
if (!this.isConnected) {
|
|
313
|
-
this.connect().catch(() => {
|
|
314
|
-
|
|
313
|
+
this.connect().catch((err) => {
|
|
314
|
+
logger_1.logger.warn("Opinion WebSocket connect failed during watchTrades", { error: String(err) });
|
|
315
|
+
if (!this.isTerminated) {
|
|
316
|
+
this.scheduleReconnect();
|
|
317
|
+
}
|
|
315
318
|
});
|
|
316
319
|
}
|
|
317
320
|
else {
|
|
@@ -378,20 +381,24 @@ exports.OpinionWebSocket = OpinionWebSocket;
|
|
|
378
381
|
// ---------------------------------------------------------------------------
|
|
379
382
|
/**
|
|
380
383
|
* Apply an absolute-size level update to one side of the book.
|
|
381
|
-
* A size of 0 (or NaN) removes the level.
|
|
384
|
+
* A size of 0 (or NaN) removes the level. Mutates the provided array in place
|
|
385
|
+
* and keeps it sorted.
|
|
382
386
|
*/
|
|
383
387
|
function applyLevelUpdate(levels, price, size, sortOrder) {
|
|
384
|
-
const
|
|
388
|
+
const idx = levels.findIndex((l) => l.price === price);
|
|
389
|
+
if (idx !== -1) {
|
|
390
|
+
levels.splice(idx, 1);
|
|
391
|
+
}
|
|
385
392
|
if (!isNaN(size) && size > 0) {
|
|
386
|
-
|
|
393
|
+
levels.push({ price, size });
|
|
387
394
|
}
|
|
388
395
|
if (sortOrder === "desc") {
|
|
389
|
-
|
|
396
|
+
levels.sort((a, b) => b.price - a.price);
|
|
390
397
|
}
|
|
391
398
|
else {
|
|
392
|
-
|
|
399
|
+
levels.sort((a, b) => a.price - b.price);
|
|
393
400
|
}
|
|
394
|
-
return
|
|
401
|
+
return levels;
|
|
395
402
|
}
|
|
396
403
|
/**
|
|
397
404
|
* Map Opinion's trade side string to our unified type.
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-08T19:06:11.828Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const polymarketClobSpec: {
|
|
@@ -243,6 +243,18 @@ export declare const polymarketClobSpec: {
|
|
|
243
243
|
}[];
|
|
244
244
|
};
|
|
245
245
|
};
|
|
246
|
+
"/v1/heartbeats": {
|
|
247
|
+
post: {
|
|
248
|
+
summary: string;
|
|
249
|
+
tags: string[];
|
|
250
|
+
security: {
|
|
251
|
+
L2Auth: never[];
|
|
252
|
+
}[];
|
|
253
|
+
parameters: {
|
|
254
|
+
$ref: string;
|
|
255
|
+
}[];
|
|
256
|
+
};
|
|
257
|
+
};
|
|
246
258
|
"/data/order/{id}": {
|
|
247
259
|
get: {
|
|
248
260
|
summary: string;
|
|
@@ -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-06-
|
|
6
|
+
* Generated at: 2026-06-08T19:06:11.828Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketClobSpec = {
|
|
@@ -349,6 +349,24 @@ exports.polymarketClobSpec = {
|
|
|
349
349
|
]
|
|
350
350
|
}
|
|
351
351
|
},
|
|
352
|
+
"/v1/heartbeats": {
|
|
353
|
+
"post": {
|
|
354
|
+
"summary": "Refresh authenticated session heartbeat",
|
|
355
|
+
"tags": [
|
|
356
|
+
"Orders"
|
|
357
|
+
],
|
|
358
|
+
"security": [
|
|
359
|
+
{
|
|
360
|
+
"L2Auth": []
|
|
361
|
+
}
|
|
362
|
+
],
|
|
363
|
+
"parameters": [
|
|
364
|
+
{
|
|
365
|
+
"$ref": "#/components/parameters/L2Headers"
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
}
|
|
369
|
+
},
|
|
352
370
|
"/data/order/{id}": {
|
|
353
371
|
"get": {
|
|
354
372
|
"summary": "Get Order",
|
|
@@ -410,6 +428,13 @@ exports.polymarketClobSpec = {
|
|
|
410
428
|
"schema": {
|
|
411
429
|
"type": "string"
|
|
412
430
|
}
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"name": "next_cursor",
|
|
434
|
+
"in": "query",
|
|
435
|
+
"schema": {
|
|
436
|
+
"type": "string"
|
|
437
|
+
}
|
|
413
438
|
}
|
|
414
439
|
]
|
|
415
440
|
}
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-08T19:06:11.840Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-08T19:06:11.840Z
|
|
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-06-
|
|
3
|
+
* Generated at: 2026-06-08T19:06:11.836Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-08T19:06:11.836Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketGammaSpec = {
|
|
@@ -10,9 +10,9 @@ const accounts_1 = require("viem/accounts");
|
|
|
10
10
|
const chains_1 = require("viem/chains");
|
|
11
11
|
const axios_1 = __importDefault(require("axios"));
|
|
12
12
|
const logger_1 = require("../../utils/logger");
|
|
13
|
+
const config_1 = require("./config");
|
|
13
14
|
const errors_1 = require("./errors");
|
|
14
15
|
const DEFAULT_POLYMARKET_HOST = process.env.POLYMARKET_CLOB_URL || 'https://clob.polymarket.com';
|
|
15
|
-
const POLYGON_CHAIN_ID = 137;
|
|
16
16
|
// Polymarket CLOB signature types — determines how the CLOB API
|
|
17
17
|
// resolves the on-chain address holding the user's funds.
|
|
18
18
|
const SIG_TYPE_EOA = 0;
|
|
@@ -83,7 +83,7 @@ class PolymarketAuth {
|
|
|
83
83
|
// Otherwise, derive/create them using L1 auth
|
|
84
84
|
const l1Client = new clob_client_v2_1.ClobClient({
|
|
85
85
|
host: this.host,
|
|
86
|
-
chain:
|
|
86
|
+
chain: config_1.POLYMARKET_CHAIN_ID,
|
|
87
87
|
signer: this.signer,
|
|
88
88
|
});
|
|
89
89
|
// Robust derivation strategy:
|
|
@@ -253,7 +253,7 @@ class PolymarketAuth {
|
|
|
253
253
|
// console.log(`[PolymarketAuth] Initializing ClobClient | Signer: ${signerAddress} | Funder: ${finalProxyAddress} | SigType: ${finalSignatureType}`);
|
|
254
254
|
this.clobClient = new clob_client_v2_1.ClobClient({
|
|
255
255
|
host: this.host,
|
|
256
|
-
chain:
|
|
256
|
+
chain: config_1.POLYMARKET_CHAIN_ID,
|
|
257
257
|
signer: this.signer,
|
|
258
258
|
creds: apiCreds,
|
|
259
259
|
signatureType: finalSignatureType,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const POLYMARKET_CHAIN_ID = 137;
|
|
@@ -14,6 +14,7 @@ const api_clob_1 = require("./api-clob");
|
|
|
14
14
|
const api_data_1 = require("./api-data");
|
|
15
15
|
const api_gamma_1 = require("./api-gamma");
|
|
16
16
|
const auth_1 = require("./auth");
|
|
17
|
+
const config_1 = require("./config");
|
|
17
18
|
const logger_1 = require("../../utils/logger");
|
|
18
19
|
const errors_2 = require("./errors");
|
|
19
20
|
const fetcher_1 = require("./fetcher");
|
|
@@ -629,7 +630,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
629
630
|
// Static network avoids ethers v5 auto-detect (eth_chainId), which can throw
|
|
630
631
|
// noNetwork / NETWORK_ERROR on flaky public RPCs (#92).
|
|
631
632
|
const provider = new ethers.providers.StaticJsonRpcProvider('https://polygon-rpc.com', {
|
|
632
|
-
chainId:
|
|
633
|
+
chainId: config_1.POLYMARKET_CHAIN_ID,
|
|
633
634
|
name: 'matic',
|
|
634
635
|
});
|
|
635
636
|
const pusdAddress = '0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB'; // pUSD (Polymarket USD)
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.PolymarketUSWebSocket = void 0;
|
|
19
|
+
const logger_1 = require("../../utils/logger");
|
|
19
20
|
const watch_timeout_1 = require("../../utils/watch-timeout");
|
|
20
21
|
const price_1 = require("./price");
|
|
21
22
|
function sideFromOrderSide(raw) {
|
|
@@ -96,8 +97,8 @@ class PolymarketUSWebSocket {
|
|
|
96
97
|
try {
|
|
97
98
|
this.socket.close();
|
|
98
99
|
}
|
|
99
|
-
catch {
|
|
100
|
-
|
|
100
|
+
catch (error) {
|
|
101
|
+
logger_1.logger.debug('[polymarket_us] error during socket close', { error: String(error) });
|
|
101
102
|
}
|
|
102
103
|
this.socket = null;
|
|
103
104
|
}
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-08T19:06:11.866Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-08T19:06:11.866Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.probableApiSpec = {
|
|
@@ -5,6 +5,7 @@ const clob_1 = require("@prob/clob");
|
|
|
5
5
|
const accounts_1 = require("viem/accounts");
|
|
6
6
|
const viem_1 = require("viem");
|
|
7
7
|
const chains_1 = require("viem/chains");
|
|
8
|
+
const config_1 = require("./config");
|
|
8
9
|
/**
|
|
9
10
|
* Manages Probable authentication and CLOB client initialization.
|
|
10
11
|
* Requires a privateKey and pre-generated API key triplet (apiKey, apiSecret, passphrase).
|
|
@@ -29,8 +30,8 @@ class ProbableAuth {
|
|
|
29
30
|
if (this.clobClient) {
|
|
30
31
|
return this.clobClient;
|
|
31
32
|
}
|
|
32
|
-
const chainId = parseInt(process.env.PROBABLE_CHAIN_ID ||
|
|
33
|
-
const chain = chainId ===
|
|
33
|
+
const chainId = parseInt(process.env.PROBABLE_CHAIN_ID || String(config_1.PROBABLE_CHAIN_ID), 10);
|
|
34
|
+
const chain = chainId === config_1.PROBABLE_TESTNET_CHAIN_ID ? chains_1.bscTestnet : chains_1.bsc;
|
|
34
35
|
const account = (0, accounts_1.privateKeyToAccount)(this.credentials.privateKey);
|
|
35
36
|
const wallet = (0, viem_1.createWalletClient)({
|
|
36
37
|
account,
|
|
@@ -45,9 +46,9 @@ class ProbableAuth {
|
|
|
45
46
|
// @prob/clob may resolve a different viem copy than this package; types then
|
|
46
47
|
// disagree on WalletClient. Runtime shape is identical.
|
|
47
48
|
const walletForClob = wallet;
|
|
48
|
-
if (chainId ===
|
|
49
|
+
if (chainId === config_1.PROBABLE_CHAIN_ID) {
|
|
49
50
|
this.clobClient = (0, clob_1.createClobClient)({
|
|
50
|
-
chainId:
|
|
51
|
+
chainId: config_1.PROBABLE_CHAIN_ID,
|
|
51
52
|
wallet: walletForClob,
|
|
52
53
|
credential,
|
|
53
54
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ProbableWebSocket = void 0;
|
|
4
4
|
const watch_timeout_1 = require("../../utils/watch-timeout");
|
|
5
|
+
const config_1 = require("./config");
|
|
5
6
|
/**
|
|
6
7
|
* Probable WebSocket implementation for real-time order book streaming.
|
|
7
8
|
* Uses the @prob/clob SDK's subscribePublicStream (no auth required).
|
|
@@ -19,7 +20,7 @@ class ProbableWebSocket {
|
|
|
19
20
|
async ensureClient() {
|
|
20
21
|
if (this.client)
|
|
21
22
|
return this.client;
|
|
22
|
-
const chainId = this.config.chainId || parseInt(process.env.PROBABLE_CHAIN_ID ||
|
|
23
|
+
const chainId = this.config.chainId || parseInt(process.env.PROBABLE_CHAIN_ID || String(config_1.PROBABLE_CHAIN_ID), 10);
|
|
23
24
|
const wsUrl = this.config.wsUrl || process.env.PROBABLE_WS_URL || 'wss://ws.probable.markets/public/api/v1';
|
|
24
25
|
const baseUrl = this.config.baseUrl || process.env.PROBABLE_BASE_URL || 'https://api.probable.markets/public/api/v1';
|
|
25
26
|
// Dynamically import @prob/clob using eval to bypass TS compilation to require()
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* It is NOT wired into defineImplicitApi — the fetcher calls these endpoints
|
|
6
6
|
* directly via FetcherContext.http (the rate-limited HTTP client).
|
|
7
7
|
*
|
|
8
|
-
* Base URL: https://suibets.
|
|
8
|
+
* Base URL: https://www.suibets.com
|
|
9
9
|
*
|
|
10
10
|
* Endpoints:
|
|
11
11
|
* GET /api/p2p/offers - List open P2P offers (status, matchId, sport, limit, offset)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* It is NOT wired into defineImplicitApi — the fetcher calls these endpoints
|
|
7
7
|
* directly via FetcherContext.http (the rate-limited HTTP client).
|
|
8
8
|
*
|
|
9
|
-
* Base URL: https://suibets.
|
|
9
|
+
* Base URL: https://www.suibets.com
|
|
10
10
|
*
|
|
11
11
|
* Endpoints:
|
|
12
12
|
* GET /api/p2p/offers - List open P2P offers (status, matchId, sport, limit, offset)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SUIBETS_BASE_URL = "https://suibets.
|
|
1
|
+
export declare const SUIBETS_BASE_URL = "https://www.suibets.com";
|
|
2
2
|
export declare const SUIBETS_PLATFORM_FEE = 0.02;
|
|
3
3
|
export declare const MIST_PER_SUI = 1000000000;
|
|
4
4
|
export declare const MIN_PRICE = 0.01;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ALLOWED_HOSTS = exports.RATE_LIMIT_MS = exports.MAX_PRICE = exports.MIN_PRICE = exports.MIST_PER_SUI = exports.SUIBETS_PLATFORM_FEE = exports.SUIBETS_BASE_URL = void 0;
|
|
4
4
|
exports.validateBaseUrl = validateBaseUrl;
|
|
5
5
|
exports.getSuibetsConfig = getSuibetsConfig;
|
|
6
|
-
exports.SUIBETS_BASE_URL = 'https://suibets.
|
|
6
|
+
exports.SUIBETS_BASE_URL = 'https://www.suibets.com';
|
|
7
7
|
// SuiBets is a P2P sports betting platform on Sui blockchain.
|
|
8
8
|
// Platform takes a 2% fee on settled markets.
|
|
9
9
|
exports.SUIBETS_PLATFORM_FEE = 0.02;
|
|
@@ -15,7 +15,7 @@ exports.MAX_PRICE = 0.99;
|
|
|
15
15
|
// Minimum delay between outbound requests (milliseconds)
|
|
16
16
|
exports.RATE_LIMIT_MS = 300;
|
|
17
17
|
// Allowlist of permitted hostnames for SSRF protection
|
|
18
|
-
exports.ALLOWED_HOSTS = ['suibets.
|
|
18
|
+
exports.ALLOWED_HOSTS = ['www.suibets.com'];
|
|
19
19
|
/**
|
|
20
20
|
* Validates that the given URL's hostname is in the ALLOWED_HOSTS allowlist.
|
|
21
21
|
* Throws if the hostname is not permitted, to prevent SSRF.
|
|
@@ -41,6 +41,15 @@ class SuibetsErrorMapper extends error_mapper_1.ErrorMapper {
|
|
|
41
41
|
mapError(error) {
|
|
42
42
|
if (axios_1.default.isAxiosError(error)) {
|
|
43
43
|
const status = error.response?.status;
|
|
44
|
+
// HTML body = hosting/gateway outage — not a missing resource.
|
|
45
|
+
// Return ExchangeNotAvailable so callers can distinguish
|
|
46
|
+
// "offer not found" from "upstream server is down".
|
|
47
|
+
const responseData = error.response?.data;
|
|
48
|
+
const isHtml = typeof responseData === 'string' &&
|
|
49
|
+
responseData.trimStart().startsWith('<');
|
|
50
|
+
if (isHtml) {
|
|
51
|
+
return new errors_1.ExchangeNotAvailable('SuiBets API is unavailable. Check https://www.suibets.com for service status.', this.exchangeName);
|
|
52
|
+
}
|
|
44
53
|
if (status === 429) {
|
|
45
54
|
const retryAfter = error.response?.headers?.['retry-after'];
|
|
46
55
|
const retryAfterSeconds = retryAfter ? parseInt(retryAfter, 10) : undefined;
|
|
@@ -33,7 +33,24 @@ export interface SuibetsRawEvent {
|
|
|
33
33
|
status: string;
|
|
34
34
|
offers?: SuibetsRawOffer[];
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Structured return type for fetchRawPositions.
|
|
38
|
+
* Keeps the three position-array types separate so each is normalised
|
|
39
|
+
* with the correct shape instead of being cast from unknown[].
|
|
40
|
+
*/
|
|
41
|
+
export interface SuibetsRawPositions {
|
|
42
|
+
createdOffers: SuibetsRawOffer[];
|
|
43
|
+
matchedBets: unknown[];
|
|
44
|
+
parlays: unknown[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Type guard: true only when the value has the core fields that
|
|
48
|
+
* SuibetsNormalizer.normalizePosition() reads (id, creatorOdds, creatorStake).
|
|
49
|
+
* Guards against silent garbage output when matchedBets or parlays
|
|
50
|
+
* are accidentally passed in as SuibetsRawOffer.
|
|
51
|
+
*/
|
|
52
|
+
export declare function isSuibetsRawOffer(value: unknown): value is SuibetsRawOffer;
|
|
53
|
+
export declare class SuibetsFetcher implements IExchangeFetcher<SuibetsRawOffer, SuibetsRawEvent, SuibetsRawPositions> {
|
|
37
54
|
private readonly ctx;
|
|
38
55
|
private readonly baseUrl;
|
|
39
56
|
constructor(ctx: FetcherContext, baseUrl: string);
|
|
@@ -59,6 +76,9 @@ export declare class SuibetsFetcher implements IExchangeFetcher<SuibetsRawOffer,
|
|
|
59
76
|
/**
|
|
60
77
|
* Fetches raw positions (created offers, matched bets, parlays) for a
|
|
61
78
|
* given Sui wallet address.
|
|
79
|
+
*
|
|
80
|
+
* Returns each array separately and typed so that normalisation uses
|
|
81
|
+
* the correct shape per position type rather than casting from unknown[].
|
|
62
82
|
*/
|
|
63
|
-
fetchRawPositions(walletAddress: string): Promise<
|
|
83
|
+
fetchRawPositions(walletAddress: string): Promise<SuibetsRawPositions>;
|
|
64
84
|
}
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SuibetsFetcher = void 0;
|
|
4
|
+
exports.isSuibetsRawOffer = isSuibetsRawOffer;
|
|
4
5
|
const errors_1 = require("./errors");
|
|
6
|
+
/**
|
|
7
|
+
* Type guard: true only when the value has the core fields that
|
|
8
|
+
* SuibetsNormalizer.normalizePosition() reads (id, creatorOdds, creatorStake).
|
|
9
|
+
* Guards against silent garbage output when matchedBets or parlays
|
|
10
|
+
* are accidentally passed in as SuibetsRawOffer.
|
|
11
|
+
*/
|
|
12
|
+
function isSuibetsRawOffer(value) {
|
|
13
|
+
if (typeof value !== 'object' || value === null)
|
|
14
|
+
return false;
|
|
15
|
+
const v = value;
|
|
16
|
+
return ((typeof v['id'] === 'string' || typeof v['id'] === 'number') &&
|
|
17
|
+
typeof v['creatorOdds'] === 'number' &&
|
|
18
|
+
typeof v['creatorStake'] === 'number');
|
|
19
|
+
}
|
|
5
20
|
class SuibetsFetcher {
|
|
6
21
|
ctx;
|
|
7
22
|
baseUrl;
|
|
@@ -115,14 +130,17 @@ class SuibetsFetcher {
|
|
|
115
130
|
/**
|
|
116
131
|
* Fetches raw positions (created offers, matched bets, parlays) for a
|
|
117
132
|
* given Sui wallet address.
|
|
133
|
+
*
|
|
134
|
+
* Returns each array separately and typed so that normalisation uses
|
|
135
|
+
* the correct shape per position type rather than casting from unknown[].
|
|
118
136
|
*/
|
|
119
137
|
async fetchRawPositions(walletAddress) {
|
|
120
138
|
const data = await this.get('/api/p2p/my', { wallet: walletAddress });
|
|
121
|
-
return
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
139
|
+
return {
|
|
140
|
+
createdOffers: (data.createdOffers ?? []).filter(isSuibetsRawOffer),
|
|
141
|
+
matchedBets: data.matchedBets ?? [],
|
|
142
|
+
parlays: data.parlays ?? [],
|
|
143
|
+
};
|
|
126
144
|
}
|
|
127
145
|
}
|
|
128
146
|
exports.SuibetsFetcher = SuibetsFetcher;
|
|
@@ -3,7 +3,7 @@ import { UnifiedMarket, UnifiedEvent, OrderBook, Position } from '../../types';
|
|
|
3
3
|
export interface SuibetsCredentials extends ExchangeCredentials {
|
|
4
4
|
/** Sui wallet address for fetching personal positions */
|
|
5
5
|
walletAddress?: string;
|
|
6
|
-
/** Override API base URL (default: https://suibets.
|
|
6
|
+
/** Override API base URL (default: https://www.suibets.com) */
|
|
7
7
|
baseUrl?: string;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
@@ -113,7 +113,7 @@ class SuiBetsExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
113
113
|
'Pass it via new SuiBetsExchange({ walletAddress: "0x..." }).', 'SuiBets');
|
|
114
114
|
}
|
|
115
115
|
const raw = await this.fetcher.fetchRawPositions(wallet);
|
|
116
|
-
return raw.map(r => this.normalizer.normalizePosition(r));
|
|
116
|
+
return raw.createdOffers.map(r => this.normalizer.normalizePosition(r));
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
exports.SuiBetsExchange = SuiBetsExchange;
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SuibetsNormalizer = void 0;
|
|
4
|
-
const metadata_1 = require("../../utils/metadata");
|
|
5
4
|
const utils_1 = require("./utils");
|
|
6
|
-
// Raw SuiBets offer fields already promoted to first-class UnifiedMarket columns.
|
|
7
|
-
// Omit these from sourceMetadata to capture only vendor-specific data not
|
|
8
|
-
// represented by the unified shape.
|
|
9
|
-
const SUIBETS_PROMOTED_OFFER_KEYS = [
|
|
10
|
-
'id', 'matchId', 'matchName', 'homeTeam', 'awayTeam',
|
|
11
|
-
'creatorOdds', 'creatorStake', 'remainingStake', 'totalMatched',
|
|
12
|
-
'matchDate', 'expiresAt', 'status', 'onchainOfferId',
|
|
13
|
-
'leagueName', 'sport', 'isOnchain',
|
|
14
|
-
];
|
|
15
|
-
// Raw SuiBets event fields already promoted to first-class UnifiedEvent columns.
|
|
16
|
-
const SUIBETS_PROMOTED_EVENT_KEYS = [
|
|
17
|
-
'id', 'name', 'homeTeam', 'awayTeam', 'sport', 'leagueName', 'offers',
|
|
18
|
-
];
|
|
19
5
|
function liquidity(offer) {
|
|
20
6
|
const remaining = offer.remainingStake ?? offer.creatorStake;
|
|
21
7
|
return (0, utils_1.mistToSui)(remaining);
|
|
@@ -64,16 +50,13 @@ class SuibetsNormalizer {
|
|
|
64
50
|
resolutionDate: new Date(dateSource),
|
|
65
51
|
volume24h,
|
|
66
52
|
liquidity: liq,
|
|
67
|
-
url: 'https://suibets.
|
|
53
|
+
url: 'https://www.suibets.com/p2p',
|
|
68
54
|
status: (0, utils_1.mapStatus)(raw.status),
|
|
69
55
|
category: 'Sports',
|
|
70
56
|
tags: ['Sports', 'P2P', raw.sport, raw.leagueName].filter((t) => Boolean(t)),
|
|
71
57
|
contractAddress: raw.onchainOfferId,
|
|
72
58
|
yes: creatorOutcome,
|
|
73
59
|
no: takerOutcome,
|
|
74
|
-
// Retains creatorWallet, creatorTeam, takerStake, currency \u2014 fields
|
|
75
|
-
// that are vendor-specific and not promoted to any unified column.
|
|
76
|
-
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, SUIBETS_PROMOTED_OFFER_KEYS),
|
|
77
60
|
};
|
|
78
61
|
return market;
|
|
79
62
|
}
|
|
@@ -98,12 +81,9 @@ class SuibetsNormalizer {
|
|
|
98
81
|
markets,
|
|
99
82
|
volume24h: totalVolume,
|
|
100
83
|
volume: totalVolume,
|
|
101
|
-
url: 'https://suibets.
|
|
84
|
+
url: 'https://www.suibets.com/p2p',
|
|
102
85
|
category: 'Sports',
|
|
103
86
|
tags: ['Sports', 'P2P', 'Sui', raw.sport, raw.leagueName].filter((t) => Boolean(t)),
|
|
104
|
-
// Retains matchDate and status \u2014 event-level fields not promoted to
|
|
105
|
-
// any first-class UnifiedEvent column.
|
|
106
|
-
sourceMetadata: (0, metadata_1.buildSourceMetadata)(raw, SUIBETS_PROMOTED_EVENT_KEYS),
|
|
107
87
|
};
|
|
108
88
|
}
|
|
109
89
|
normalizePosition(raw) {
|
|
@@ -115,7 +115,7 @@ class BinanceFeed extends base_feed_1.BaseDataFeed {
|
|
|
115
115
|
}
|
|
116
116
|
watchTickerImpl(symbol, callback) {
|
|
117
117
|
const sub = { symbol, callback };
|
|
118
|
-
this.subscriptions
|
|
118
|
+
this.subscriptions.push(sub);
|
|
119
119
|
this.ensureConnected().catch((err) => {
|
|
120
120
|
logger_1.logger.error('[BinanceFeed] initial connect failed in watchTickerImpl', {
|
|
121
121
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -185,14 +185,17 @@ class BinanceFeed extends base_feed_1.BaseDataFeed {
|
|
|
185
185
|
try {
|
|
186
186
|
msg = JSON.parse(text);
|
|
187
187
|
}
|
|
188
|
-
catch {
|
|
188
|
+
catch (error) {
|
|
189
|
+
logger_1.logger.debug('[BinanceFeed] failed to parse relay message', {
|
|
190
|
+
error: error instanceof Error ? error.message : String(error),
|
|
191
|
+
});
|
|
189
192
|
return;
|
|
190
193
|
}
|
|
191
194
|
if (msg.op !== 'event')
|
|
192
195
|
return;
|
|
193
196
|
const event = msg;
|
|
194
197
|
const ticker = (0, normalizer_1.normalizeTradeToTicker)(event);
|
|
195
|
-
this.latestTickers
|
|
198
|
+
this.latestTickers.set(ticker.symbol, ticker);
|
|
196
199
|
for (const sub of this.subscriptions) {
|
|
197
200
|
if (sub.symbol === ticker.symbol) {
|
|
198
201
|
sub.callback(ticker);
|