pmxt-core 2.19.6 → 2.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseExchange.d.ts +69 -30
- package/dist/BaseExchange.js +124 -82
- package/dist/exchanges/baozi/index.d.ts +2 -0
- package/dist/exchanges/baozi/index.js +2 -0
- package/dist/exchanges/baozi/price.d.ts +3 -0
- package/dist/exchanges/baozi/price.js +16 -0
- package/dist/exchanges/baozi/price.test.d.ts +1 -0
- package/dist/exchanges/baozi/price.test.js +33 -0
- package/dist/exchanges/baozi/utils.js +5 -9
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/fetchOHLCV.js +5 -4
- package/dist/exchanges/kalshi/fetchOrderBook.js +21 -21
- package/dist/exchanges/kalshi/fetchTrades.js +2 -1
- package/dist/exchanges/kalshi/index.d.ts +3 -1
- package/dist/exchanges/kalshi/index.js +19 -16
- package/dist/exchanges/kalshi/price.d.ts +3 -0
- package/dist/exchanges/kalshi/price.js +14 -0
- package/dist/exchanges/kalshi/price.test.d.ts +1 -0
- package/dist/exchanges/kalshi/price.test.js +24 -0
- package/dist/exchanges/kalshi/utils.js +5 -4
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/index.d.ts +58 -19
- package/dist/exchanges/limitless/index.js +169 -101
- package/dist/exchanges/limitless/websocket.d.ts +10 -3
- package/dist/exchanges/limitless/websocket.js +71 -52
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/index.d.ts +3 -1
- package/dist/exchanges/myriad/index.js +7 -4
- package/dist/exchanges/myriad/price.d.ts +1 -0
- package/dist/exchanges/myriad/price.js +7 -0
- package/dist/exchanges/myriad/price.test.d.ts +1 -0
- package/dist/exchanges/myriad/price.test.js +17 -0
- 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/index.d.ts +28 -15
- package/dist/exchanges/polymarket/index.js +217 -137
- package/dist/exchanges/polymarket/websocket.d.ts +11 -4
- package/dist/exchanges/polymarket/websocket.js +58 -36
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/index.d.ts +2 -0
- package/dist/exchanges/probable/index.js +2 -0
- package/dist/subscriber/base.d.ts +82 -0
- package/dist/subscriber/base.js +2 -0
- package/dist/subscriber/external/goldsky.d.ts +96 -0
- package/dist/subscriber/external/goldsky.js +412 -0
- package/dist/subscriber/watcher.d.ts +85 -0
- package/dist/subscriber/watcher.js +178 -0
- package/dist/types.d.ts +5 -0
- package/dist/utils/error-mapper.d.ts +8 -0
- package/dist/utils/error-mapper.js +58 -26
- package/package.json +3 -3
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LimitlessExchange = void 0;
|
|
3
|
+
exports.LimitlessExchange = exports.buildLimitlessBalanceActivity = exports.LIMITLESS_DEFAULT_SUBSCRIPTION = void 0;
|
|
4
|
+
const sdk_1 = require("@limitless-exchange/sdk");
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
4
6
|
const BaseExchange_1 = require("../../BaseExchange");
|
|
5
|
-
const
|
|
7
|
+
const errors_1 = require("../../errors");
|
|
8
|
+
const goldsky_1 = require("../../subscriber/external/goldsky");
|
|
9
|
+
Object.defineProperty(exports, "buildLimitlessBalanceActivity", { enumerable: true, get: function () { return goldsky_1.buildLimitlessBalanceActivity; } });
|
|
10
|
+
Object.defineProperty(exports, "LIMITLESS_DEFAULT_SUBSCRIPTION", { enumerable: true, get: function () { return goldsky_1.LIMITLESS_DEFAULT_SUBSCRIPTION; } });
|
|
11
|
+
const openapi_1 = require("../../utils/openapi");
|
|
12
|
+
const api_1 = require("./api");
|
|
13
|
+
const auth_1 = require("./auth");
|
|
14
|
+
const client_1 = require("./client");
|
|
15
|
+
const errors_2 = require("./errors");
|
|
6
16
|
const fetchEvents_1 = require("./fetchEvents");
|
|
17
|
+
const fetchMarkets_1 = require("./fetchMarkets");
|
|
7
18
|
const fetchOHLCV_1 = require("./fetchOHLCV");
|
|
8
19
|
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
9
20
|
const fetchTrades_1 = require("./fetchTrades");
|
|
10
|
-
const auth_1 = require("./auth");
|
|
11
|
-
const client_1 = require("./client");
|
|
12
21
|
const websocket_1 = require("./websocket");
|
|
13
|
-
const errors_1 = require("./errors");
|
|
14
|
-
const errors_2 = require("../../errors");
|
|
15
|
-
const sdk_1 = require("@limitless-exchange/sdk");
|
|
16
|
-
const ethers_1 = require("ethers");
|
|
17
|
-
const openapi_1 = require("../../utils/openapi");
|
|
18
|
-
const api_1 = require("./api");
|
|
19
22
|
class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
20
23
|
has = {
|
|
21
24
|
fetchMarkets: true,
|
|
@@ -29,6 +32,8 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
29
32
|
fetchOpenOrders: true,
|
|
30
33
|
fetchPositions: true,
|
|
31
34
|
fetchBalance: true,
|
|
35
|
+
watchAddress: true,
|
|
36
|
+
unwatchAddress: true,
|
|
32
37
|
watchOrderBook: true,
|
|
33
38
|
watchTrades: true,
|
|
34
39
|
fetchMyTrades: true,
|
|
@@ -40,6 +45,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
40
45
|
auth;
|
|
41
46
|
client;
|
|
42
47
|
wsConfig;
|
|
48
|
+
ws;
|
|
43
49
|
constructor(options) {
|
|
44
50
|
// Support both old signature (credentials only) and new signature (options object)
|
|
45
51
|
let credentials;
|
|
@@ -85,22 +91,8 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
85
91
|
return 'Limitless';
|
|
86
92
|
}
|
|
87
93
|
// ----------------------------------------------------------------------------
|
|
88
|
-
// Implicit API Error Mapping
|
|
89
|
-
// ----------------------------------------------------------------------------
|
|
90
|
-
mapImplicitApiError(error) {
|
|
91
|
-
throw errors_1.limitlessErrorMapper.mapError(error);
|
|
92
|
-
}
|
|
93
|
-
// ----------------------------------------------------------------------------
|
|
94
94
|
// Implementation methods for CCXT-style API
|
|
95
95
|
// ----------------------------------------------------------------------------
|
|
96
|
-
async fetchMarketsImpl(params) {
|
|
97
|
-
// Pass API key if available for authenticated requests
|
|
98
|
-
const apiKey = this.auth?.getApiKey();
|
|
99
|
-
return (0, fetchMarkets_1.fetchMarkets)(params, apiKey, this.callApi.bind(this));
|
|
100
|
-
}
|
|
101
|
-
async fetchEventsImpl(params) {
|
|
102
|
-
return (0, fetchEvents_1.fetchEvents)(params, this.callApi.bind(this), this.http);
|
|
103
|
-
}
|
|
104
96
|
async fetchOHLCV(id, params) {
|
|
105
97
|
return (0, fetchOHLCV_1.fetchOHLCV)(id, params, this.callApi.bind(this));
|
|
106
98
|
}
|
|
@@ -115,26 +107,6 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
115
107
|
}
|
|
116
108
|
return (0, fetchTrades_1.fetchTrades)(id, params, this.http);
|
|
117
109
|
}
|
|
118
|
-
// ----------------------------------------------------------------------------
|
|
119
|
-
// Trading Methods
|
|
120
|
-
// ----------------------------------------------------------------------------
|
|
121
|
-
ensureClient() {
|
|
122
|
-
if (!this.client) {
|
|
123
|
-
throw new Error('Trading operations require authentication. ' +
|
|
124
|
-
'Initialize LimitlessExchange with credentials: new LimitlessExchange({ privateKey: "0x...", apiKey: "lmts_..." })');
|
|
125
|
-
}
|
|
126
|
-
return this.client;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Ensure authentication is initialized before trading operations.
|
|
130
|
-
*/
|
|
131
|
-
ensureAuth() {
|
|
132
|
-
if (!this.auth) {
|
|
133
|
-
throw new errors_2.AuthenticationError('Trading operations require authentication. ' +
|
|
134
|
-
'Initialize LimitlessExchange with credentials: new LimitlessExchange({ privateKey: "0x...", apiKey: "lmts_..." })', 'Limitless');
|
|
135
|
-
}
|
|
136
|
-
return this.auth;
|
|
137
|
-
}
|
|
138
110
|
async createOrder(params) {
|
|
139
111
|
const client = this.ensureClient();
|
|
140
112
|
try {
|
|
@@ -172,9 +144,12 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
172
144
|
};
|
|
173
145
|
}
|
|
174
146
|
catch (error) {
|
|
175
|
-
throw
|
|
147
|
+
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
176
148
|
}
|
|
177
149
|
}
|
|
150
|
+
// ----------------------------------------------------------------------------
|
|
151
|
+
// Trading Methods
|
|
152
|
+
// ----------------------------------------------------------------------------
|
|
178
153
|
async cancelOrder(orderId) {
|
|
179
154
|
const client = this.ensureClient();
|
|
180
155
|
try {
|
|
@@ -193,7 +168,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
193
168
|
};
|
|
194
169
|
}
|
|
195
170
|
catch (error) {
|
|
196
|
-
throw
|
|
171
|
+
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
197
172
|
}
|
|
198
173
|
}
|
|
199
174
|
async fetchOrder(orderId) {
|
|
@@ -228,7 +203,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
228
203
|
}));
|
|
229
204
|
}
|
|
230
205
|
catch (error) {
|
|
231
|
-
throw
|
|
206
|
+
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
232
207
|
}
|
|
233
208
|
}
|
|
234
209
|
async fetchMyTrades(params) {
|
|
@@ -248,7 +223,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
248
223
|
}));
|
|
249
224
|
}
|
|
250
225
|
catch (error) {
|
|
251
|
-
throw
|
|
226
|
+
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
252
227
|
}
|
|
253
228
|
}
|
|
254
229
|
async fetchClosedOrders(params) {
|
|
@@ -293,10 +268,10 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
293
268
|
timestamp: o.createdAt ? new Date(o.createdAt).getTime() : Date.now(),
|
|
294
269
|
}));
|
|
295
270
|
}
|
|
296
|
-
async fetchPositions() {
|
|
297
|
-
|
|
298
|
-
const
|
|
299
|
-
const result = await this.callApi('PublicPortfolioController_getPositions', { account
|
|
271
|
+
async fetchPositions(address) {
|
|
272
|
+
// Public endpoint — no auth needed when an address is explicitly supplied.
|
|
273
|
+
const account = address ?? this.ensureAuth().getAddress();
|
|
274
|
+
const result = await this.callApi('PublicPortfolioController_getPositions', { account });
|
|
300
275
|
const data = result?.data || result || [];
|
|
301
276
|
return data.map((p) => ({
|
|
302
277
|
marketId: p.market?.slug || p.conditionId,
|
|
@@ -309,61 +284,25 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
309
284
|
realizedPnL: parseFloat(p.realizedPnl || '0'),
|
|
310
285
|
}));
|
|
311
286
|
}
|
|
312
|
-
async fetchBalance() {
|
|
313
|
-
const auth = this.ensureAuth();
|
|
287
|
+
async fetchBalance(address) {
|
|
314
288
|
try {
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const address = auth.getAddress();
|
|
319
|
-
// Get USDC contract address for Base
|
|
320
|
-
const usdcAddress = (0, sdk_1.getContractAddress)('USDC');
|
|
321
|
-
// USDC ERC20 ABI (balanceOf only)
|
|
322
|
-
const usdcContract = new ethers_1.Contract(usdcAddress, ['function balanceOf(address) view returns (uint256)'], provider);
|
|
323
|
-
// Query balance
|
|
324
|
-
const rawBalance = await usdcContract.balanceOf(address);
|
|
325
|
-
// USDC has 6 decimals
|
|
326
|
-
const USDC_DECIMALS = 6;
|
|
327
|
-
const total = parseFloat(rawBalance.toString()) / Math.pow(10, USDC_DECIMALS);
|
|
328
|
-
return [
|
|
329
|
-
{
|
|
330
|
-
currency: 'USDC',
|
|
331
|
-
total: total,
|
|
332
|
-
available: total, // On-chain balance is all available
|
|
333
|
-
locked: 0,
|
|
334
|
-
},
|
|
335
|
-
];
|
|
289
|
+
// When an external address is provided use on-chain RPC only — no auth required.
|
|
290
|
+
const targetAddress = address ?? this.ensureAuth().getAddress();
|
|
291
|
+
return await this.getAddressOnChainBalance(targetAddress);
|
|
336
292
|
}
|
|
337
293
|
catch (error) {
|
|
338
|
-
throw
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
// ----------------------------------------------------------------------------
|
|
342
|
-
// WebSocket Methods
|
|
343
|
-
// ----------------------------------------------------------------------------
|
|
344
|
-
ws;
|
|
345
|
-
/**
|
|
346
|
-
* Initialize WebSocket with API key if available.
|
|
347
|
-
*/
|
|
348
|
-
initWebSocket() {
|
|
349
|
-
if (!this.ws) {
|
|
350
|
-
const wsConfig = {
|
|
351
|
-
...this.wsConfig,
|
|
352
|
-
apiKey: this.auth?.getApiKey(),
|
|
353
|
-
};
|
|
354
|
-
this.ws = new websocket_1.LimitlessWebSocket(this.callApi.bind(this), wsConfig);
|
|
294
|
+
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
355
295
|
}
|
|
356
|
-
return this.ws;
|
|
357
296
|
}
|
|
358
297
|
async watchOrderBook(id, limit) {
|
|
359
|
-
const ws = this.
|
|
298
|
+
const ws = this.ensureWs();
|
|
360
299
|
// Return the snapshot immediately (this allows the script to proceed)
|
|
361
300
|
// Future versions could implement a more sophisticated queueing system
|
|
362
301
|
return ws.watchOrderBook(id);
|
|
363
302
|
}
|
|
364
|
-
async watchTrades(id, since, limit) {
|
|
365
|
-
const ws = this.
|
|
366
|
-
return ws.watchTrades(id);
|
|
303
|
+
async watchTrades(id, address, since, limit) {
|
|
304
|
+
const ws = this.ensureWs();
|
|
305
|
+
return ws.watchTrades(id, address);
|
|
367
306
|
}
|
|
368
307
|
/**
|
|
369
308
|
* Watch AMM price updates for a market address (Limitless only).
|
|
@@ -381,7 +320,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
381
320
|
* exchange.watch_prices(market_address, callback=lambda data: print('Price update:', data))
|
|
382
321
|
*/
|
|
383
322
|
async watchPrices(marketAddress, callback) {
|
|
384
|
-
const ws = this.
|
|
323
|
+
const ws = this.ensureWs();
|
|
385
324
|
return ws.watchPrices(marketAddress, callback);
|
|
386
325
|
}
|
|
387
326
|
/**
|
|
@@ -400,9 +339,12 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
400
339
|
*/
|
|
401
340
|
async watchUserPositions(callback) {
|
|
402
341
|
this.ensureAuth(); // Ensure API key is available
|
|
403
|
-
const ws = this.
|
|
342
|
+
const ws = this.ensureWs();
|
|
404
343
|
return ws.watchUserPositions(callback);
|
|
405
344
|
}
|
|
345
|
+
// ----------------------------------------------------------------------------
|
|
346
|
+
// WebSocket Methods
|
|
347
|
+
// ----------------------------------------------------------------------------
|
|
406
348
|
/**
|
|
407
349
|
* Watch user transactions in real-time (Limitless only).
|
|
408
350
|
* Requires API key authentication.
|
|
@@ -419,14 +361,140 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
419
361
|
*/
|
|
420
362
|
async watchUserTransactions(callback) {
|
|
421
363
|
this.ensureAuth(); // Ensure API key is available
|
|
422
|
-
const ws = this.
|
|
364
|
+
const ws = this.ensureWs();
|
|
423
365
|
return ws.watchUserTransactions(callback);
|
|
424
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Stream activity (positions, balances) for any public Base-chain wallet address.
|
|
369
|
+
*
|
|
370
|
+
* Uses polling of the Limitless public portfolio API (positions) and on-chain Base
|
|
371
|
+
* RPC calls (USDC balance). No credentials are required.
|
|
372
|
+
*
|
|
373
|
+
* Note: Limitless does not expose a public per-address trades endpoint, so the
|
|
374
|
+
* `'trades'` type returns an empty array when watching a public address.
|
|
375
|
+
*
|
|
376
|
+
* Follows the CCXT Pro streaming pattern: the first call returns the initial snapshot
|
|
377
|
+
* immediately; subsequent calls block until a change is detected.
|
|
378
|
+
*
|
|
379
|
+
* @param address - Any public Base-chain wallet address
|
|
380
|
+
* @param types - Activity types to watch (default: all)
|
|
381
|
+
*
|
|
382
|
+
* @example-ts
|
|
383
|
+
* while (true) {
|
|
384
|
+
* const activity = await exchange.watchAddress('0xabc...', ['positions', 'balances']);
|
|
385
|
+
* console.log(activity.positions, activity.balances);
|
|
386
|
+
* }
|
|
387
|
+
*/
|
|
388
|
+
async watchAddress(address, types = ['trades', 'positions', 'balances']) {
|
|
389
|
+
return this.ensureWs().watchAddress(address, types);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Stop watching an address and release polling resources.
|
|
393
|
+
* Any pending `watchAddress` promises for that address will be rejected.
|
|
394
|
+
*/
|
|
395
|
+
async unwatchAddress(address) {
|
|
396
|
+
return this.ensureWs().unwatchAddress(address);
|
|
397
|
+
}
|
|
425
398
|
async close() {
|
|
426
399
|
if (this.ws) {
|
|
427
|
-
this.ws.close();
|
|
400
|
+
await this.ws.close();
|
|
428
401
|
this.ws = undefined;
|
|
429
402
|
}
|
|
430
403
|
}
|
|
404
|
+
mapImplicitApiError(error) {
|
|
405
|
+
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
406
|
+
}
|
|
407
|
+
// ----------------------------------------------------------------------------
|
|
408
|
+
// Implicit API Error Mapping
|
|
409
|
+
// ----------------------------------------------------------------------------
|
|
410
|
+
async fetchMarketsImpl(params) {
|
|
411
|
+
// Pass API key if available for authenticated requests
|
|
412
|
+
const apiKey = this.auth?.getApiKey();
|
|
413
|
+
return (0, fetchMarkets_1.fetchMarkets)(params, apiKey, this.callApi.bind(this));
|
|
414
|
+
}
|
|
415
|
+
async fetchEventsImpl(params) {
|
|
416
|
+
return (0, fetchEvents_1.fetchEvents)(params, this.callApi.bind(this), this.http);
|
|
417
|
+
}
|
|
418
|
+
async getAddressOnChainBalance(targetAddress) {
|
|
419
|
+
// Query USDC balance directly from Base chain
|
|
420
|
+
const provider = new ethers_1.providers.JsonRpcProvider('https://mainnet.base.org');
|
|
421
|
+
// Get USDC contract address for Base
|
|
422
|
+
const usdcAddress = (0, sdk_1.getContractAddress)('USDC');
|
|
423
|
+
// USDC ERC20 ABI (balanceOf only)
|
|
424
|
+
const usdcContract = new ethers_1.Contract(usdcAddress, ['function balanceOf(address) view returns (uint256)'], provider);
|
|
425
|
+
const rawBalance = await usdcContract.balanceOf(targetAddress);
|
|
426
|
+
const USDC_DECIMALS = 6;
|
|
427
|
+
const total = parseFloat(rawBalance.toString()) / Math.pow(10, USDC_DECIMALS);
|
|
428
|
+
return [{
|
|
429
|
+
currency: 'USDC',
|
|
430
|
+
total,
|
|
431
|
+
available: total, // On-chain balance is all available
|
|
432
|
+
locked: 0,
|
|
433
|
+
}];
|
|
434
|
+
}
|
|
435
|
+
ensureClient() {
|
|
436
|
+
if (!this.client) {
|
|
437
|
+
throw new Error('Trading operations require authentication. ' +
|
|
438
|
+
'Initialize LimitlessExchange with credentials: new LimitlessExchange({ privateKey: "0x...", apiKey: "lmts_..." })');
|
|
439
|
+
}
|
|
440
|
+
return this.client;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Ensure authentication is initialized before trading operations.
|
|
444
|
+
*/
|
|
445
|
+
ensureAuth() {
|
|
446
|
+
if (!this.auth) {
|
|
447
|
+
throw new errors_1.AuthenticationError('Trading operations require authentication. ' +
|
|
448
|
+
'Initialize LimitlessExchange with credentials: new LimitlessExchange({ privateKey: "0x...", apiKey: "lmts_..." })', 'Limitless');
|
|
449
|
+
}
|
|
450
|
+
return this.auth;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Initialize WebSocket with API key if available.
|
|
454
|
+
*/
|
|
455
|
+
ensureWs() {
|
|
456
|
+
if (!this.ws) {
|
|
457
|
+
const wsConfig = {
|
|
458
|
+
...this.wsConfig,
|
|
459
|
+
apiKey: this.auth?.getApiKey(),
|
|
460
|
+
};
|
|
461
|
+
this.ws = new websocket_1.LimitlessWebSocket(this.callApi.bind(this), wsConfig);
|
|
462
|
+
}
|
|
463
|
+
return this.ws;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Fetch a composite activity snapshot for a Base-chain address from the Limitless
|
|
467
|
+
* public portfolio API and Base RPC. Used internally by the BaseSubscriber polling loop.
|
|
468
|
+
*/
|
|
469
|
+
async fetchWatchedAddressActivity(params) {
|
|
470
|
+
const address = params.address;
|
|
471
|
+
const types = params.types;
|
|
472
|
+
const result = { address, timestamp: Date.now() };
|
|
473
|
+
const fetches = [];
|
|
474
|
+
// Limitless has no public per-address trades endpoint; return empty.
|
|
475
|
+
if (types.includes('trades')) {
|
|
476
|
+
result.trades = [];
|
|
477
|
+
}
|
|
478
|
+
if (types.includes('positions')) {
|
|
479
|
+
fetches.push(this.fetchPositions(address)
|
|
480
|
+
.then((positions) => {
|
|
481
|
+
result.positions = positions;
|
|
482
|
+
})
|
|
483
|
+
.catch(() => {
|
|
484
|
+
result.positions = [];
|
|
485
|
+
}));
|
|
486
|
+
}
|
|
487
|
+
if (types.includes('balances')) {
|
|
488
|
+
fetches.push(this.getAddressOnChainBalance(address)
|
|
489
|
+
.then((balances) => {
|
|
490
|
+
result.balances = balances;
|
|
491
|
+
})
|
|
492
|
+
.catch(() => {
|
|
493
|
+
result.balances = [];
|
|
494
|
+
}));
|
|
495
|
+
}
|
|
496
|
+
await Promise.all(fetches);
|
|
497
|
+
return result;
|
|
498
|
+
}
|
|
431
499
|
}
|
|
432
500
|
exports.LimitlessExchange = LimitlessExchange;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { WebSocketClient, WebSocketConfig
|
|
1
|
+
import { ILogger, WebSocketClient, WebSocketConfig } from '@limitless-exchange/sdk';
|
|
2
|
+
import { SubscribedAddressSnapshot, SubscriptionOption } from "../../subscriber/base";
|
|
3
|
+
import { WatcherConfig } from "../../subscriber/watcher";
|
|
2
4
|
import { OrderBook, Trade } from '../../types';
|
|
3
5
|
export interface LimitlessWebSocketConfig extends Partial<WebSocketConfig> {
|
|
4
6
|
apiKey?: string;
|
|
@@ -7,6 +9,8 @@ export interface LimitlessWebSocketConfig extends Partial<WebSocketConfig> {
|
|
|
7
9
|
logger?: ILogger;
|
|
8
10
|
autoReconnect?: boolean;
|
|
9
11
|
reconnectDelay?: number;
|
|
12
|
+
/** Watcher subscription configurations */
|
|
13
|
+
watcherConfig?: WatcherConfig;
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
16
|
* Limitless WebSocket implementation using the official SDK.
|
|
@@ -18,6 +22,7 @@ export interface LimitlessWebSocketConfig extends Partial<WebSocketConfig> {
|
|
|
18
22
|
*/
|
|
19
23
|
export declare class LimitlessWebSocket {
|
|
20
24
|
private client;
|
|
25
|
+
private readonly watcher;
|
|
21
26
|
private config;
|
|
22
27
|
private callApi;
|
|
23
28
|
private orderbookCallbacks;
|
|
@@ -26,7 +31,6 @@ export declare class LimitlessWebSocket {
|
|
|
26
31
|
private orderbookBuffers;
|
|
27
32
|
private lastOrderbookTimestamps;
|
|
28
33
|
constructor(callApi: (operationId: string, params?: Record<string, any>) => Promise<any>, config?: LimitlessWebSocketConfig);
|
|
29
|
-
private setupEventHandlers;
|
|
30
34
|
/**
|
|
31
35
|
* Watch orderbook updates for a CLOB market.
|
|
32
36
|
*
|
|
@@ -58,11 +62,13 @@ export declare class LimitlessWebSocket {
|
|
|
58
62
|
/**
|
|
59
63
|
* Legacy method - watch trades (not directly supported, falls back to orderbook)
|
|
60
64
|
*/
|
|
61
|
-
watchTrades(marketSlug: string): Promise<Trade[]>;
|
|
65
|
+
watchTrades(marketSlug: string, address?: string): Promise<Trade[]>;
|
|
62
66
|
/**
|
|
63
67
|
* Unsubscribe from a market.
|
|
64
68
|
*/
|
|
65
69
|
unsubscribe(marketSlugOrAddress: string): Promise<void>;
|
|
70
|
+
watchAddress(address: string, types: SubscriptionOption[]): Promise<SubscribedAddressSnapshot>;
|
|
71
|
+
unwatchAddress(address: string): Promise<void>;
|
|
66
72
|
/**
|
|
67
73
|
* Close the WebSocket connection.
|
|
68
74
|
*/
|
|
@@ -75,6 +81,7 @@ export declare class LimitlessWebSocket {
|
|
|
75
81
|
* Get the underlying SDK WebSocket client for advanced usage.
|
|
76
82
|
*/
|
|
77
83
|
getClient(): WebSocketClient;
|
|
84
|
+
private setupEventHandlers;
|
|
78
85
|
private transformOrderbookData;
|
|
79
86
|
private getEmptyOrderbook;
|
|
80
87
|
}
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LimitlessWebSocket = void 0;
|
|
4
4
|
const sdk_1 = require("@limitless-exchange/sdk");
|
|
5
|
+
const goldsky_1 = require("../../subscriber/external/goldsky");
|
|
6
|
+
const watcher_1 = require("../../subscriber/watcher");
|
|
5
7
|
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
6
8
|
// Limitless uses USDC with 6 decimals
|
|
7
9
|
const USDC_DECIMALS = 6;
|
|
8
10
|
const USDC_SCALE = Math.pow(10, USDC_DECIMALS);
|
|
9
11
|
/**
|
|
10
|
-
* Convert raw orderbook size from smallest unit to human-readable USDC amount.
|
|
12
|
+
* Convert raw orderbook size from the smallest unit to human-readable USDC amount.
|
|
11
13
|
*/
|
|
12
14
|
function convertSize(rawSize) {
|
|
13
15
|
return rawSize / USDC_SCALE;
|
|
@@ -22,6 +24,7 @@ function convertSize(rawSize) {
|
|
|
22
24
|
*/
|
|
23
25
|
class LimitlessWebSocket {
|
|
24
26
|
client;
|
|
27
|
+
watcher;
|
|
25
28
|
config;
|
|
26
29
|
callApi;
|
|
27
30
|
orderbookCallbacks = new Map();
|
|
@@ -42,55 +45,14 @@ class LimitlessWebSocket {
|
|
|
42
45
|
this.client = new sdk_1.WebSocketClient(wsConfig, config.logger);
|
|
43
46
|
// Set up event handlers
|
|
44
47
|
this.setupEventHandlers();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const { marketSlug, orderbook } = data;
|
|
50
|
-
const pmxtOrderbook = this.transformOrderbookData(orderbook);
|
|
51
|
-
// Update timestamp for this market
|
|
52
|
-
this.lastOrderbookTimestamps.set(marketSlug, Date.now());
|
|
53
|
-
// Execute callback if registered
|
|
54
|
-
const callback = this.orderbookCallbacks.get(marketSlug);
|
|
55
|
-
if (callback) {
|
|
56
|
-
callback(pmxtOrderbook);
|
|
57
|
-
}
|
|
58
|
-
// Handle resolvers and buffers
|
|
59
|
-
const resolvers = this.orderbookResolvers.get(marketSlug) || [];
|
|
60
|
-
if (resolvers.length > 0) {
|
|
61
|
-
// If someone is waiting, give it to them immediately
|
|
62
|
-
const resolver = resolvers.shift();
|
|
63
|
-
resolver.resolve(pmxtOrderbook);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
// Otherwise, buffer it for the next call
|
|
67
|
-
if (!this.orderbookBuffers.has(marketSlug)) {
|
|
68
|
-
this.orderbookBuffers.set(marketSlug, []);
|
|
69
|
-
}
|
|
70
|
-
const buffer = this.orderbookBuffers.get(marketSlug);
|
|
71
|
-
buffer.push(pmxtOrderbook);
|
|
72
|
-
// Keep buffer size reasonable
|
|
73
|
-
if (buffer.length > 100)
|
|
74
|
-
buffer.shift();
|
|
75
|
-
}
|
|
48
|
+
const watcherConfig = this.config.watcherConfig;
|
|
49
|
+
const subscriber = new goldsky_1.GoldSkySubscriber({
|
|
50
|
+
...watcherConfig,
|
|
51
|
+
buildSubscription: goldsky_1.LIMITLESS_DEFAULT_SUBSCRIPTION,
|
|
76
52
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const callback = this.priceCallbacks.get(marketAddress);
|
|
81
|
-
if (callback) {
|
|
82
|
-
callback(data);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
// Handle connection events
|
|
86
|
-
this.client.on('connect', () => {
|
|
87
|
-
console.log('[LimitlessWS] Connected to WebSocket');
|
|
88
|
-
});
|
|
89
|
-
this.client.on('disconnect', (reason) => {
|
|
90
|
-
console.log(`[LimitlessWS] Disconnected from WebSocket: ${reason}`);
|
|
91
|
-
});
|
|
92
|
-
this.client.on('error', (error) => {
|
|
93
|
-
console.error('[LimitlessWS] WebSocket error:', error);
|
|
53
|
+
this.watcher = new watcher_1.AddressWatcher((address, types) => this.callApi("fetchWatchedAddressActivity", { address, types }), {
|
|
54
|
+
subscriber,
|
|
55
|
+
buildActivity: goldsky_1.buildLimitlessBalanceActivity,
|
|
94
56
|
});
|
|
95
57
|
}
|
|
96
58
|
/**
|
|
@@ -202,7 +164,7 @@ class LimitlessWebSocket {
|
|
|
202
164
|
if (!this.client.isConnected()) {
|
|
203
165
|
await this.client.connect();
|
|
204
166
|
}
|
|
205
|
-
await this.client.subscribe('orders'); // SDK uses 'orders' channel for user positional updates too?
|
|
167
|
+
await this.client.subscribe('orders'); // SDK uses 'orders' channel for user positional updates too?
|
|
206
168
|
// Actually, the channel type has 'subscribe_positions'. Let's check.
|
|
207
169
|
// Wait, I saw 'orders' in SubscriptionChannel.
|
|
208
170
|
// Let's use 'orders' as it's common for user data.
|
|
@@ -227,7 +189,7 @@ class LimitlessWebSocket {
|
|
|
227
189
|
/**
|
|
228
190
|
* Legacy method - watch trades (not directly supported, falls back to orderbook)
|
|
229
191
|
*/
|
|
230
|
-
async watchTrades(marketSlug) {
|
|
192
|
+
async watchTrades(marketSlug, address) {
|
|
231
193
|
console.warn('[LimitlessWS] watchTrades is not directly supported. ' +
|
|
232
194
|
'Use watchOrderBook() for real-time orderbook updates or fetchOHLCV() for historical data.');
|
|
233
195
|
return [];
|
|
@@ -246,13 +208,20 @@ class LimitlessWebSocket {
|
|
|
246
208
|
marketAddresses: [marketSlugOrAddress],
|
|
247
209
|
});
|
|
248
210
|
}
|
|
211
|
+
async watchAddress(address, types) {
|
|
212
|
+
return this.watcher.watch(address, types);
|
|
213
|
+
}
|
|
214
|
+
async unwatchAddress(address) {
|
|
215
|
+
return this.watcher.unwatch(address);
|
|
216
|
+
}
|
|
249
217
|
/**
|
|
250
218
|
* Close the WebSocket connection.
|
|
251
219
|
*/
|
|
252
220
|
async close() {
|
|
253
221
|
this.orderbookCallbacks.clear();
|
|
254
222
|
this.priceCallbacks.clear();
|
|
255
|
-
this.client.disconnect();
|
|
223
|
+
await this.client.disconnect();
|
|
224
|
+
this.watcher.close();
|
|
256
225
|
}
|
|
257
226
|
/**
|
|
258
227
|
* Check if connected.
|
|
@@ -266,6 +235,56 @@ class LimitlessWebSocket {
|
|
|
266
235
|
getClient() {
|
|
267
236
|
return this.client;
|
|
268
237
|
}
|
|
238
|
+
setupEventHandlers() {
|
|
239
|
+
// Handle orderbook updates
|
|
240
|
+
this.client.on('orderbookUpdate', (data) => {
|
|
241
|
+
const { marketSlug, orderbook } = data;
|
|
242
|
+
const pmxtOrderbook = this.transformOrderbookData(orderbook);
|
|
243
|
+
// Update timestamp for this market
|
|
244
|
+
this.lastOrderbookTimestamps.set(marketSlug, Date.now());
|
|
245
|
+
// Execute callback if registered
|
|
246
|
+
const callback = this.orderbookCallbacks.get(marketSlug);
|
|
247
|
+
if (callback) {
|
|
248
|
+
callback(pmxtOrderbook);
|
|
249
|
+
}
|
|
250
|
+
// Handle resolvers and buffers
|
|
251
|
+
const resolvers = this.orderbookResolvers.get(marketSlug) || [];
|
|
252
|
+
if (resolvers.length > 0) {
|
|
253
|
+
// If someone is waiting, give it to them immediately
|
|
254
|
+
const resolver = resolvers.shift();
|
|
255
|
+
resolver.resolve(pmxtOrderbook);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// Otherwise, buffer it for the next call
|
|
259
|
+
if (!this.orderbookBuffers.has(marketSlug)) {
|
|
260
|
+
this.orderbookBuffers.set(marketSlug, []);
|
|
261
|
+
}
|
|
262
|
+
const buffer = this.orderbookBuffers.get(marketSlug);
|
|
263
|
+
buffer.push(pmxtOrderbook);
|
|
264
|
+
// Keep buffer size reasonable
|
|
265
|
+
if (buffer.length > 100)
|
|
266
|
+
buffer.shift();
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
// Handle AMM price updates
|
|
270
|
+
this.client.on('newPriceData', (data) => {
|
|
271
|
+
const { marketAddress } = data;
|
|
272
|
+
const callback = this.priceCallbacks.get(marketAddress);
|
|
273
|
+
if (callback) {
|
|
274
|
+
callback(data);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
// Handle connection events
|
|
278
|
+
this.client.on('connect', () => {
|
|
279
|
+
console.log('[LimitlessWS] Connected to WebSocket');
|
|
280
|
+
});
|
|
281
|
+
this.client.on('disconnect', (reason) => {
|
|
282
|
+
console.log(`[LimitlessWS] Disconnected from WebSocket: ${reason}`);
|
|
283
|
+
});
|
|
284
|
+
this.client.on('error', (error) => {
|
|
285
|
+
console.error('[LimitlessWS] WebSocket error:', error);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
269
288
|
transformOrderbookData(orderbook) {
|
|
270
289
|
// Convert sizes from smallest unit to human-readable USDC amounts
|
|
271
290
|
const bids = (orderbook.bids || []).map((level) => ({
|
|
@@ -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-03-
|
|
3
|
+
* Generated at: 2026-03-14T16:40:09.282Z
|
|
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-03-
|
|
6
|
+
* Generated at: 2026-03-14T16:40:09.282Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.myriadApiSpec = {
|
|
@@ -13,6 +13,8 @@ export declare class MyriadExchange extends PredictionMarketExchange {
|
|
|
13
13
|
fetchOpenOrders: "emulated";
|
|
14
14
|
fetchPositions: true;
|
|
15
15
|
fetchBalance: "emulated";
|
|
16
|
+
watchAddress: false;
|
|
17
|
+
unwatchAddress: false;
|
|
16
18
|
watchOrderBook: "emulated";
|
|
17
19
|
watchTrades: "emulated";
|
|
18
20
|
fetchMyTrades: true;
|
|
@@ -42,6 +44,6 @@ export declare class MyriadExchange extends PredictionMarketExchange {
|
|
|
42
44
|
fetchPositions(): Promise<Position[]>;
|
|
43
45
|
fetchBalance(): Promise<Balance[]>;
|
|
44
46
|
watchOrderBook(id: string, _limit?: number): Promise<OrderBook>;
|
|
45
|
-
watchTrades(id: string, _since?: number, _limit?: number): Promise<Trade[]>;
|
|
47
|
+
watchTrades(id: string, address?: string, _since?: number, _limit?: number): Promise<Trade[]>;
|
|
46
48
|
close(): Promise<void>;
|
|
47
49
|
}
|