pmxt-core 2.0.0-b0 → 2.0.0-b10
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 +8 -35
- package/dist/BaseExchange.js +7 -59
- package/dist/exchanges/kalshi/fetchEvents.d.ts +3 -0
- package/dist/exchanges/kalshi/{searchEvents.js → fetchEvents.js} +4 -9
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +2 -2
- package/dist/exchanges/kalshi/fetchMarkets.js +71 -0
- package/dist/exchanges/kalshi/index.d.ts +2 -4
- package/dist/exchanges/kalshi/index.js +3 -11
- package/dist/exchanges/kalshi/utils.js +0 -2
- package/dist/exchanges/limitless/auth.d.ts +19 -15
- package/dist/exchanges/limitless/auth.js +43 -86
- package/dist/exchanges/limitless/client.d.ts +55 -9
- package/dist/exchanges/limitless/client.js +96 -143
- package/dist/exchanges/limitless/fetchEvents.d.ts +3 -0
- package/dist/exchanges/limitless/{searchEvents.js → fetchEvents.js} +6 -11
- package/dist/exchanges/limitless/fetchMarkets.d.ts +2 -2
- package/dist/exchanges/limitless/fetchMarkets.js +79 -15
- package/dist/exchanges/limitless/fetchOrderBook.js +13 -3
- package/dist/exchanges/limitless/index.d.ts +26 -5
- package/dist/exchanges/limitless/index.js +103 -53
- package/dist/exchanges/limitless/utils.js +0 -1
- package/dist/exchanges/limitless/websocket.d.ts +70 -8
- package/dist/exchanges/limitless/websocket.js +277 -10
- package/dist/exchanges/polymarket/fetchEvents.d.ts +3 -0
- package/dist/exchanges/polymarket/{searchEvents.js → fetchEvents.js} +6 -12
- package/dist/exchanges/polymarket/fetchMarkets.d.ts +2 -2
- package/dist/exchanges/polymarket/fetchMarkets.js +60 -0
- package/dist/exchanges/polymarket/index.d.ts +2 -4
- package/dist/exchanges/polymarket/index.js +3 -11
- package/dist/exchanges/polymarket/utils.js +0 -1
- package/dist/types.d.ts +0 -10
- package/dist/utils/validation.d.ts +2 -2
- package/dist/utils/validation.js +5 -6
- package/package.json +6 -5
- package/dist/exchanges/kalshi/getMarketsBySlug.d.ts +0 -7
- package/dist/exchanges/kalshi/getMarketsBySlug.js +0 -62
- package/dist/exchanges/kalshi/searchEvents.d.ts +0 -3
- package/dist/exchanges/kalshi/searchMarkets.d.ts +0 -3
- package/dist/exchanges/kalshi/searchMarkets.js +0 -28
- package/dist/exchanges/limitless/getMarketsBySlug.d.ts +0 -6
- package/dist/exchanges/limitless/getMarketsBySlug.js +0 -26
- package/dist/exchanges/limitless/searchEvents.d.ts +0 -3
- package/dist/exchanges/limitless/searchMarkets.d.ts +0 -3
- package/dist/exchanges/limitless/searchMarkets.js +0 -42
- package/dist/exchanges/polymarket/getMarketsBySlug.d.ts +0 -7
- package/dist/exchanges/polymarket/getMarketsBySlug.js +0 -39
- package/dist/exchanges/polymarket/searchEvents.d.ts +0 -3
- package/dist/exchanges/polymarket/searchMarkets.d.ts +0 -3
- package/dist/exchanges/polymarket/searchMarkets.js +0 -35
package/dist/BaseExchange.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ export interface MarketFilterParams {
|
|
|
5
5
|
offset?: number;
|
|
6
6
|
sort?: 'volume' | 'liquidity' | 'newest';
|
|
7
7
|
searchIn?: 'title' | 'description' | 'both';
|
|
8
|
-
}
|
|
9
|
-
export interface MarketFetchParams extends MarketFilterParams {
|
|
10
8
|
query?: string;
|
|
11
9
|
slug?: string;
|
|
10
|
+
page?: number;
|
|
11
|
+
similarityThreshold?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface MarketFetchParams extends MarketFilterParams {
|
|
12
14
|
}
|
|
13
15
|
export interface EventFetchParams {
|
|
14
16
|
query?: string;
|
|
@@ -126,44 +128,15 @@ export declare abstract class PredictionMarketExchange {
|
|
|
126
128
|
fetchEvents(params?: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
127
129
|
/**
|
|
128
130
|
* @internal
|
|
129
|
-
* Implementation for fetching
|
|
130
|
-
|
|
131
|
-
protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
132
|
-
/**
|
|
133
|
-
* @internal
|
|
134
|
-
* Implementation for searching markets by keyword.
|
|
135
|
-
*/
|
|
136
|
-
protected searchMarketsImpl(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
137
|
-
/**
|
|
138
|
-
* @internal
|
|
139
|
-
* Implementation for fetching markets by slug/ticker.
|
|
131
|
+
* Implementation for fetching/searching markets.
|
|
132
|
+
* Exchanges should handle query, slug, and plain fetch cases based on params.
|
|
140
133
|
*/
|
|
141
|
-
protected
|
|
134
|
+
protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
142
135
|
/**
|
|
143
136
|
* @internal
|
|
144
137
|
* Implementation for searching events by keyword.
|
|
145
138
|
*/
|
|
146
|
-
protected
|
|
147
|
-
/**
|
|
148
|
-
* @deprecated Use fetchMarkets({ query: '...' }) instead. Will be removed in v2.0
|
|
149
|
-
* Search for markets matching a keyword query.
|
|
150
|
-
* By default, searches only in market titles. Use params.searchIn to search descriptions or both.
|
|
151
|
-
*/
|
|
152
|
-
searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
153
|
-
/**
|
|
154
|
-
* @deprecated Use fetchMarkets({ slug: '...' }) instead. Will be removed in v2.0
|
|
155
|
-
* Fetch markets by URL slug (Polymarket) or ticker (Kalshi).
|
|
156
|
-
* @param slug - Market slug or ticker
|
|
157
|
-
*/
|
|
158
|
-
getMarketsBySlug(slug: string): Promise<UnifiedMarket[]>;
|
|
159
|
-
/**
|
|
160
|
-
* @deprecated Use fetchEvents({ query: '...' }) instead. Will be removed in v2.0
|
|
161
|
-
* Search for events matching a keyword query.
|
|
162
|
-
* Returns grouped events, each containing related markets.
|
|
163
|
-
* @param query - Search term
|
|
164
|
-
* @param params - Optional filter parameters
|
|
165
|
-
*/
|
|
166
|
-
searchEvents(query: string, params?: MarketFilterParams): Promise<UnifiedEvent[]>;
|
|
139
|
+
protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
167
140
|
/**
|
|
168
141
|
* Fetch historical price data for a specific market outcome.
|
|
169
142
|
* @param id - The Outcome ID (MarketOutcome.id). This should be the ID of the specific tradeable asset.
|
package/dist/BaseExchange.js
CHANGED
|
@@ -32,13 +32,6 @@ class PredictionMarketExchange {
|
|
|
32
32
|
* await exchange.fetchMarkets({ slug: 'will-trump-win' })
|
|
33
33
|
*/
|
|
34
34
|
async fetchMarkets(params) {
|
|
35
|
-
// Route based on params
|
|
36
|
-
if (params?.slug) {
|
|
37
|
-
return this.fetchMarketsBySlugImpl(params.slug);
|
|
38
|
-
}
|
|
39
|
-
if (params?.query) {
|
|
40
|
-
return this.searchMarketsImpl(params.query, params);
|
|
41
|
-
}
|
|
42
35
|
return this.fetchMarketsImpl(params);
|
|
43
36
|
}
|
|
44
37
|
/**
|
|
@@ -56,73 +49,28 @@ class PredictionMarketExchange {
|
|
|
56
49
|
* await exchange.fetchEvents({ query: 'Election' })
|
|
57
50
|
*/
|
|
58
51
|
async fetchEvents(params) {
|
|
59
|
-
if (params?.query) {
|
|
60
|
-
|
|
52
|
+
if (!params?.query) {
|
|
53
|
+
throw new Error("fetchEvents() requires a query parameter");
|
|
61
54
|
}
|
|
62
|
-
|
|
55
|
+
return this.fetchEventsImpl(params);
|
|
63
56
|
}
|
|
64
57
|
// ----------------------------------------------------------------------------
|
|
65
58
|
// Implementation methods (to be overridden by exchanges)
|
|
66
59
|
// ----------------------------------------------------------------------------
|
|
67
60
|
/**
|
|
68
61
|
* @internal
|
|
69
|
-
* Implementation for fetching
|
|
62
|
+
* Implementation for fetching/searching markets.
|
|
63
|
+
* Exchanges should handle query, slug, and plain fetch cases based on params.
|
|
70
64
|
*/
|
|
71
65
|
async fetchMarketsImpl(params) {
|
|
72
66
|
throw new Error("Method fetchMarketsImpl not implemented.");
|
|
73
67
|
}
|
|
74
|
-
/**
|
|
75
|
-
* @internal
|
|
76
|
-
* Implementation for searching markets by keyword.
|
|
77
|
-
*/
|
|
78
|
-
async searchMarketsImpl(query, params) {
|
|
79
|
-
throw new Error("Method searchMarketsImpl not implemented.");
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* @internal
|
|
83
|
-
* Implementation for fetching markets by slug/ticker.
|
|
84
|
-
*/
|
|
85
|
-
async fetchMarketsBySlugImpl(slug) {
|
|
86
|
-
throw new Error("Method fetchMarketsBySlugImpl not implemented.");
|
|
87
|
-
}
|
|
88
68
|
/**
|
|
89
69
|
* @internal
|
|
90
70
|
* Implementation for searching events by keyword.
|
|
91
71
|
*/
|
|
92
|
-
async
|
|
93
|
-
throw new Error("Method
|
|
94
|
-
}
|
|
95
|
-
// ----------------------------------------------------------------------------
|
|
96
|
-
// Deprecated methods (kept for backward compatibility)
|
|
97
|
-
// ----------------------------------------------------------------------------
|
|
98
|
-
/**
|
|
99
|
-
* @deprecated Use fetchMarkets({ query: '...' }) instead. Will be removed in v2.0
|
|
100
|
-
* Search for markets matching a keyword query.
|
|
101
|
-
* By default, searches only in market titles. Use params.searchIn to search descriptions or both.
|
|
102
|
-
*/
|
|
103
|
-
async searchMarkets(query, params) {
|
|
104
|
-
console.warn('⚠️ searchMarkets() is deprecated. Use fetchMarkets({ query: "..." }) instead.');
|
|
105
|
-
return this.fetchMarkets({ ...params, query });
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* @deprecated Use fetchMarkets({ slug: '...' }) instead. Will be removed in v2.0
|
|
109
|
-
* Fetch markets by URL slug (Polymarket) or ticker (Kalshi).
|
|
110
|
-
* @param slug - Market slug or ticker
|
|
111
|
-
*/
|
|
112
|
-
async getMarketsBySlug(slug) {
|
|
113
|
-
console.warn('⚠️ getMarketsBySlug() is deprecated. Use fetchMarkets({ slug: "..." }) instead.');
|
|
114
|
-
return this.fetchMarkets({ slug });
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* @deprecated Use fetchEvents({ query: '...' }) instead. Will be removed in v2.0
|
|
118
|
-
* Search for events matching a keyword query.
|
|
119
|
-
* Returns grouped events, each containing related markets.
|
|
120
|
-
* @param query - Search term
|
|
121
|
-
* @param params - Optional filter parameters
|
|
122
|
-
*/
|
|
123
|
-
async searchEvents(query, params) {
|
|
124
|
-
console.warn('⚠️ searchEvents() is deprecated. Use fetchEvents({ query: "..." }) instead.');
|
|
125
|
-
return this.fetchEvents({ ...params, query });
|
|
72
|
+
async fetchEventsImpl(params) {
|
|
73
|
+
throw new Error("Method fetchEventsImpl not implemented.");
|
|
126
74
|
}
|
|
127
75
|
/**
|
|
128
76
|
* Fetch historical price data for a specific market outcome.
|
|
@@ -3,11 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.fetchEvents = fetchEvents;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const utils_1 = require("./utils");
|
|
9
9
|
const errors_1 = require("./errors");
|
|
10
|
-
async function
|
|
10
|
+
async function fetchEvents(params) {
|
|
11
11
|
try {
|
|
12
12
|
const queryParams = {
|
|
13
13
|
limit: 200, // Reasonable batch for search
|
|
@@ -16,7 +16,7 @@ async function searchEvents(query, params) {
|
|
|
16
16
|
};
|
|
17
17
|
const response = await axios_1.default.get(utils_1.KALSHI_API_URL, { params: queryParams });
|
|
18
18
|
const events = response.data.events || [];
|
|
19
|
-
const lowerQuery = query.toLowerCase();
|
|
19
|
+
const lowerQuery = (params?.query || '').toLowerCase();
|
|
20
20
|
const filtered = events.filter((event) => {
|
|
21
21
|
return (event.title || '').toLowerCase().includes(lowerQuery);
|
|
22
22
|
});
|
|
@@ -39,12 +39,7 @@ async function searchEvents(query, params) {
|
|
|
39
39
|
url: `https://kalshi.com/events/${event.event_ticker}`,
|
|
40
40
|
image: event.image_url,
|
|
41
41
|
category: event.category,
|
|
42
|
-
tags: event.tags || []
|
|
43
|
-
searchMarkets: function (marketQuery) {
|
|
44
|
-
const lowerMarketQuery = marketQuery.toLowerCase();
|
|
45
|
-
return this.markets.filter(m => m.title.toLowerCase().includes(lowerMarketQuery) ||
|
|
46
|
-
m.outcomes.some(o => o.label.toLowerCase().includes(lowerMarketQuery)));
|
|
47
|
-
}
|
|
42
|
+
tags: event.tags || []
|
|
48
43
|
};
|
|
49
44
|
return unifiedEvent;
|
|
50
45
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MarketFetchParams } from '../../BaseExchange';
|
|
2
2
|
import { UnifiedMarket } from '../../types';
|
|
3
3
|
export declare function resetCache(): void;
|
|
4
|
-
export declare function fetchMarkets(params?:
|
|
4
|
+
export declare function fetchMarkets(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
@@ -84,6 +84,77 @@ function resetCache() {
|
|
|
84
84
|
lastCacheTime = 0;
|
|
85
85
|
}
|
|
86
86
|
async function fetchMarkets(params) {
|
|
87
|
+
try {
|
|
88
|
+
// Handle slug-based lookup (event ticker)
|
|
89
|
+
if (params?.slug) {
|
|
90
|
+
return await fetchMarketsBySlug(params.slug);
|
|
91
|
+
}
|
|
92
|
+
// Handle query-based search
|
|
93
|
+
if (params?.query) {
|
|
94
|
+
return await searchMarkets(params.query, params);
|
|
95
|
+
}
|
|
96
|
+
// Default: fetch markets
|
|
97
|
+
return await fetchMarketsDefault(params);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw errors_1.kalshiErrorMapper.mapError(error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function fetchMarketsBySlug(eventTicker) {
|
|
104
|
+
// Kalshi API expects uppercase tickers, but URLs use lowercase
|
|
105
|
+
const normalizedTicker = eventTicker.toUpperCase();
|
|
106
|
+
const url = `https://api.elections.kalshi.com/trade-api/v2/events/${normalizedTicker}`;
|
|
107
|
+
const response = await axios_1.default.get(url, {
|
|
108
|
+
params: { with_nested_markets: true }
|
|
109
|
+
});
|
|
110
|
+
const event = response.data.event;
|
|
111
|
+
if (!event)
|
|
112
|
+
return [];
|
|
113
|
+
// Enrichment: Fetch series tags if they exist
|
|
114
|
+
if (event.series_ticker) {
|
|
115
|
+
try {
|
|
116
|
+
const seriesUrl = `${utils_1.KALSHI_SERIES_URL}/${event.series_ticker}`;
|
|
117
|
+
const seriesResponse = await axios_1.default.get(seriesUrl);
|
|
118
|
+
const series = seriesResponse.data.series;
|
|
119
|
+
if (series && series.tags && series.tags.length > 0) {
|
|
120
|
+
if (!event.tags || event.tags.length === 0) {
|
|
121
|
+
event.tags = series.tags;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
// Ignore errors fetching series info - non-critical
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const unifiedMarkets = [];
|
|
130
|
+
const markets = event.markets || [];
|
|
131
|
+
for (const market of markets) {
|
|
132
|
+
const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market);
|
|
133
|
+
if (unifiedMarket) {
|
|
134
|
+
unifiedMarkets.push(unifiedMarket);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return unifiedMarkets;
|
|
138
|
+
}
|
|
139
|
+
async function searchMarkets(query, params) {
|
|
140
|
+
// We must fetch ALL markets to search them locally since we don't have server-side search
|
|
141
|
+
const searchLimit = 5000;
|
|
142
|
+
const markets = await fetchMarketsDefault({ ...params, limit: searchLimit });
|
|
143
|
+
const lowerQuery = query.toLowerCase();
|
|
144
|
+
const searchIn = params?.searchIn || 'title'; // Default to title-only search
|
|
145
|
+
const filtered = markets.filter(market => {
|
|
146
|
+
const titleMatch = (market.title || '').toLowerCase().includes(lowerQuery);
|
|
147
|
+
const descMatch = (market.description || '').toLowerCase().includes(lowerQuery);
|
|
148
|
+
if (searchIn === 'title')
|
|
149
|
+
return titleMatch;
|
|
150
|
+
if (searchIn === 'description')
|
|
151
|
+
return descMatch;
|
|
152
|
+
return titleMatch || descMatch; // 'both'
|
|
153
|
+
});
|
|
154
|
+
const limit = params?.limit || 20;
|
|
155
|
+
return filtered.slice(0, limit);
|
|
156
|
+
}
|
|
157
|
+
async function fetchMarketsDefault(params) {
|
|
87
158
|
const limit = params?.limit || 50;
|
|
88
159
|
const offset = params?.offset || 0;
|
|
89
160
|
const now = Date.now();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, ExchangeCredentials } from '../../BaseExchange';
|
|
1
|
+
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
|
|
2
2
|
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Balance, Order, Position, CreateOrderParams } from '../../types';
|
|
3
3
|
import { KalshiWebSocketConfig } from './websocket';
|
|
4
4
|
export { KalshiWebSocketConfig };
|
|
@@ -14,9 +14,7 @@ export declare class KalshiExchange extends PredictionMarketExchange {
|
|
|
14
14
|
private getBaseUrl;
|
|
15
15
|
private ensureAuth;
|
|
16
16
|
protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
17
|
-
protected
|
|
18
|
-
protected fetchMarketsBySlugImpl(slug: string): Promise<UnifiedMarket[]>;
|
|
19
|
-
protected searchEventsImpl(query: string, params?: MarketFilterParams): Promise<UnifiedEvent[]>;
|
|
17
|
+
protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
20
18
|
fetchOHLCV(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
|
|
21
19
|
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
22
20
|
fetchTrades(id: string, params: HistoryFilterParams): Promise<Trade[]>;
|
|
@@ -7,9 +7,7 @@ exports.KalshiExchange = void 0;
|
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const BaseExchange_1 = require("../../BaseExchange");
|
|
9
9
|
const fetchMarkets_1 = require("./fetchMarkets");
|
|
10
|
-
const
|
|
11
|
-
const searchEvents_1 = require("./searchEvents");
|
|
12
|
-
const getMarketsBySlug_1 = require("./getMarketsBySlug");
|
|
10
|
+
const fetchEvents_1 = require("./fetchEvents");
|
|
13
11
|
const fetchOHLCV_1 = require("./fetchOHLCV");
|
|
14
12
|
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
15
13
|
const fetchTrades_1 = require("./fetchTrades");
|
|
@@ -59,14 +57,8 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
59
57
|
async fetchMarketsImpl(params) {
|
|
60
58
|
return (0, fetchMarkets_1.fetchMarkets)(params);
|
|
61
59
|
}
|
|
62
|
-
async
|
|
63
|
-
return (0,
|
|
64
|
-
}
|
|
65
|
-
async fetchMarketsBySlugImpl(slug) {
|
|
66
|
-
return (0, getMarketsBySlug_1.getMarketsBySlug)(slug);
|
|
67
|
-
}
|
|
68
|
-
async searchEventsImpl(query, params) {
|
|
69
|
-
return (0, searchEvents_1.searchEvents)(query, params);
|
|
60
|
+
async fetchEventsImpl(params) {
|
|
61
|
+
return (0, fetchEvents_1.fetchEvents)(params);
|
|
70
62
|
}
|
|
71
63
|
async fetchOHLCV(id, params) {
|
|
72
64
|
return (0, fetchOHLCV_1.fetchOHLCV)(id, params);
|
|
@@ -32,14 +32,12 @@ function mapMarketToUnified(event, market) {
|
|
|
32
32
|
}
|
|
33
33
|
const outcomes = [
|
|
34
34
|
{
|
|
35
|
-
id: market.ticker, // The actual market ticker (primary tradeable)
|
|
36
35
|
outcomeId: market.ticker,
|
|
37
36
|
label: candidateName || 'Yes',
|
|
38
37
|
price: price,
|
|
39
38
|
priceChange24h: priceChange
|
|
40
39
|
},
|
|
41
40
|
{
|
|
42
|
-
id: `${market.ticker}-NO`, // Virtual ID for the No outcome
|
|
43
41
|
outcomeId: `${market.ticker}-NO`,
|
|
44
42
|
label: candidateName ? `Not ${candidateName}` : 'No',
|
|
45
43
|
price: 1 - price,
|
|
@@ -1,36 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { HttpClient } from '@limitless-exchange/sdk';
|
|
2
|
+
import { Wallet } from 'ethers';
|
|
3
3
|
import { ExchangeCredentials } from '../../BaseExchange';
|
|
4
4
|
/**
|
|
5
|
-
* Manages Limitless authentication
|
|
6
|
-
*
|
|
5
|
+
* Manages Limitless authentication using API keys.
|
|
6
|
+
* Simplified from cookie-based to API key authentication.
|
|
7
7
|
*/
|
|
8
8
|
export declare class LimitlessAuth {
|
|
9
9
|
private credentials;
|
|
10
10
|
private signer?;
|
|
11
|
-
private
|
|
12
|
-
private
|
|
11
|
+
private httpClient?;
|
|
12
|
+
private apiKey?;
|
|
13
13
|
constructor(credentials: ExchangeCredentials);
|
|
14
14
|
/**
|
|
15
|
-
* Get
|
|
16
|
-
* This uses the private key to derive/create API credentials.
|
|
15
|
+
* Get the API key being used for authentication.
|
|
17
16
|
*/
|
|
18
|
-
|
|
17
|
+
getApiKey(): string;
|
|
19
18
|
/**
|
|
20
|
-
*
|
|
19
|
+
* Get or create the HTTP client with API key authentication.
|
|
20
|
+
* This client automatically includes the X-API-Key header in all requests.
|
|
21
21
|
*/
|
|
22
|
-
|
|
22
|
+
getHttpClient(): HttpClient;
|
|
23
23
|
/**
|
|
24
|
-
* Get
|
|
25
|
-
*
|
|
24
|
+
* Get the signer (wallet) for signing orders.
|
|
25
|
+
* Required for placing orders via EIP-712 signatures.
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
getSigner(): Wallet;
|
|
28
28
|
/**
|
|
29
29
|
* Get the signer's address.
|
|
30
30
|
*/
|
|
31
31
|
getAddress(): string;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Check if the auth has a signer available.
|
|
34
|
+
*/
|
|
35
|
+
hasSigner(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Reset cached client (useful for testing or credential rotation).
|
|
34
38
|
*/
|
|
35
39
|
reset(): void;
|
|
36
40
|
}
|
|
@@ -1,121 +1,78 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LimitlessAuth = void 0;
|
|
4
|
-
const
|
|
4
|
+
const sdk_1 = require("@limitless-exchange/sdk");
|
|
5
5
|
const ethers_1 = require("ethers");
|
|
6
|
-
const errors_1 = require("./errors");
|
|
7
6
|
const LIMITLESS_HOST = 'https://api.limitless.exchange';
|
|
8
|
-
const BASE_CHAIN_ID = 8453;
|
|
9
7
|
/**
|
|
10
|
-
* Manages Limitless authentication
|
|
11
|
-
*
|
|
8
|
+
* Manages Limitless authentication using API keys.
|
|
9
|
+
* Simplified from cookie-based to API key authentication.
|
|
12
10
|
*/
|
|
13
11
|
class LimitlessAuth {
|
|
14
12
|
constructor(credentials) {
|
|
15
13
|
this.credentials = credentials;
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
// API key is required for authenticated endpoints
|
|
15
|
+
// Can come from credentials or environment variable
|
|
16
|
+
this.apiKey = credentials.apiKey || process.env.LIMITLESS_API_KEY;
|
|
17
|
+
if (!this.apiKey) {
|
|
18
|
+
throw new Error('Limitless requires an API key. Set LIMITLESS_API_KEY environment variable or provide apiKey in credentials.');
|
|
19
|
+
}
|
|
20
|
+
// Initialize signer if private key is provided (needed for order signing)
|
|
21
|
+
if (credentials.privateKey) {
|
|
22
|
+
this.signer = new ethers_1.Wallet(credentials.privateKey);
|
|
18
23
|
}
|
|
19
|
-
// Initialize the signer
|
|
20
|
-
this.signer = new ethers_1.Wallet(credentials.privateKey);
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
23
|
-
* Get
|
|
24
|
-
* This uses the private key to derive/create API credentials.
|
|
26
|
+
* Get the API key being used for authentication.
|
|
25
27
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (this.apiCreds) {
|
|
29
|
-
return this.apiCreds;
|
|
30
|
-
}
|
|
31
|
-
// If credentials were provided, use them
|
|
32
|
-
if (this.credentials.apiKey && this.credentials.apiSecret && this.credentials.passphrase) {
|
|
33
|
-
this.apiCreds = {
|
|
34
|
-
key: this.credentials.apiKey,
|
|
35
|
-
secret: this.credentials.apiSecret,
|
|
36
|
-
passphrase: this.credentials.passphrase,
|
|
37
|
-
};
|
|
38
|
-
return this.apiCreds;
|
|
39
|
-
}
|
|
40
|
-
// Otherwise, derive/create them using L1 auth
|
|
41
|
-
const l1Client = new clob_client_1.ClobClient(LIMITLESS_HOST, BASE_CHAIN_ID, this.signer);
|
|
42
|
-
// Robust derivation strategy:
|
|
43
|
-
// 1. Try to DERIVE existing credentials first (most common case).
|
|
44
|
-
// 2. If that fails (e.g. 404 or 400), try to CREATE new ones.
|
|
45
|
-
let creds;
|
|
46
|
-
try {
|
|
47
|
-
// console.log('Trying to derive existing API key...');
|
|
48
|
-
creds = await l1Client.deriveApiKey();
|
|
49
|
-
}
|
|
50
|
-
catch (deriveError) {
|
|
51
|
-
// console.log('Derivation failed, trying to create new API key...');
|
|
52
|
-
try {
|
|
53
|
-
creds = await l1Client.createApiKey();
|
|
54
|
-
}
|
|
55
|
-
catch (createError) {
|
|
56
|
-
throw errors_1.limitlessErrorMapper.mapError(createError);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if (!creds) {
|
|
60
|
-
throw new Error('Authentication failed: Credentials are empty.');
|
|
61
|
-
}
|
|
62
|
-
this.apiCreds = creds;
|
|
63
|
-
return creds;
|
|
28
|
+
getApiKey() {
|
|
29
|
+
return this.apiKey;
|
|
64
30
|
}
|
|
65
31
|
/**
|
|
66
|
-
*
|
|
32
|
+
* Get or create the HTTP client with API key authentication.
|
|
33
|
+
* This client automatically includes the X-API-Key header in all requests.
|
|
67
34
|
*/
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
return
|
|
71
|
-
if (typeof type === 'number')
|
|
72
|
-
return type;
|
|
73
|
-
const normalized = type.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
74
|
-
switch (normalized) {
|
|
75
|
-
case 'eoa':
|
|
76
|
-
return 0;
|
|
77
|
-
case 'polyproxy':
|
|
78
|
-
case 'polymarketproxy':
|
|
79
|
-
return 1;
|
|
80
|
-
case 'gnosissafe':
|
|
81
|
-
case 'safe':
|
|
82
|
-
return 2;
|
|
83
|
-
default:
|
|
84
|
-
const parsed = parseInt(normalized);
|
|
85
|
-
return isNaN(parsed) ? 0 : parsed;
|
|
35
|
+
getHttpClient() {
|
|
36
|
+
if (this.httpClient) {
|
|
37
|
+
return this.httpClient;
|
|
86
38
|
}
|
|
39
|
+
this.httpClient = new sdk_1.HttpClient({
|
|
40
|
+
baseURL: LIMITLESS_HOST,
|
|
41
|
+
apiKey: this.apiKey,
|
|
42
|
+
timeout: 30000,
|
|
43
|
+
});
|
|
44
|
+
return this.httpClient;
|
|
87
45
|
}
|
|
88
46
|
/**
|
|
89
|
-
* Get
|
|
90
|
-
*
|
|
47
|
+
* Get the signer (wallet) for signing orders.
|
|
48
|
+
* Required for placing orders via EIP-712 signatures.
|
|
91
49
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return this.clobClient;
|
|
50
|
+
getSigner() {
|
|
51
|
+
if (!this.signer) {
|
|
52
|
+
throw new Error('Wallet signer not available. Provide privateKey in credentials to sign orders.');
|
|
96
53
|
}
|
|
97
|
-
|
|
98
|
-
const apiCreds = await this.getApiCredentials();
|
|
99
|
-
// Determine signature type (default to EOA = 0)
|
|
100
|
-
const signatureType = this.mapSignatureType(this.credentials.signatureType);
|
|
101
|
-
// Determine funder address (defaults to signer's address)
|
|
102
|
-
const funderAddress = this.credentials.funderAddress ?? this.signer.address;
|
|
103
|
-
// Create L2-authenticated client
|
|
104
|
-
this.clobClient = new clob_client_1.ClobClient(LIMITLESS_HOST, BASE_CHAIN_ID, this.signer, apiCreds, signatureType, funderAddress);
|
|
105
|
-
return this.clobClient;
|
|
54
|
+
return this.signer;
|
|
106
55
|
}
|
|
107
56
|
/**
|
|
108
57
|
* Get the signer's address.
|
|
109
58
|
*/
|
|
110
59
|
getAddress() {
|
|
60
|
+
if (!this.signer) {
|
|
61
|
+
throw new Error('Signer not initialized. Provide privateKey in credentials.');
|
|
62
|
+
}
|
|
111
63
|
return this.signer.address;
|
|
112
64
|
}
|
|
113
65
|
/**
|
|
114
|
-
*
|
|
66
|
+
* Check if the auth has a signer available.
|
|
67
|
+
*/
|
|
68
|
+
hasSigner() {
|
|
69
|
+
return !!this.signer;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Reset cached client (useful for testing or credential rotation).
|
|
115
73
|
*/
|
|
116
74
|
reset() {
|
|
117
|
-
this.
|
|
118
|
-
this.clobClient = undefined;
|
|
75
|
+
this.httpClient = undefined;
|
|
119
76
|
}
|
|
120
77
|
}
|
|
121
78
|
exports.LimitlessAuth = LimitlessAuth;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HttpClient, OrderClient, MarketFetcher } from '@limitless-exchange/sdk';
|
|
1
2
|
export interface LimitlessOrderParams {
|
|
2
3
|
marketSlug: string;
|
|
3
4
|
outcomeId: string;
|
|
@@ -6,18 +7,63 @@ export interface LimitlessOrderParams {
|
|
|
6
7
|
amount: number;
|
|
7
8
|
type?: 'limit' | 'market';
|
|
8
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Wrapper client for Limitless Exchange using the official SDK.
|
|
12
|
+
* Provides a simplified interface for market data and order operations.
|
|
13
|
+
*/
|
|
9
14
|
export declare class LimitlessClient {
|
|
10
|
-
private
|
|
15
|
+
private httpClient;
|
|
16
|
+
private orderClient;
|
|
17
|
+
private marketFetcher;
|
|
11
18
|
private signer;
|
|
12
|
-
private sessionCookie?;
|
|
13
|
-
private userId?;
|
|
14
19
|
private marketCache;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
constructor(privateKey: string, apiKey: string);
|
|
21
|
+
/**
|
|
22
|
+
* Get market details by slug.
|
|
23
|
+
* Results are cached to reduce API calls.
|
|
24
|
+
*/
|
|
18
25
|
getMarket(slug: string): Promise<any>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Create a limit order (GTC - Good Till Cancelled).
|
|
28
|
+
* The SDK handles EIP-712 signing automatically.
|
|
29
|
+
*/
|
|
30
|
+
createOrder(params: LimitlessOrderParams): Promise<import("@limitless-exchange/sdk").OrderResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* Cancel a specific order by ID.
|
|
33
|
+
*/
|
|
34
|
+
cancelOrder(orderId: string): Promise<{
|
|
35
|
+
message: string;
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* Cancel all orders for a specific market.
|
|
39
|
+
*/
|
|
40
|
+
cancelAllOrders(marketSlug: string): Promise<{
|
|
41
|
+
message: string;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Get user orders for a specific market.
|
|
45
|
+
* @param marketSlug - The market slug
|
|
46
|
+
* @param statuses - Optional filter by order status
|
|
47
|
+
*/
|
|
22
48
|
getOrders(marketSlug: string, statuses?: ('LIVE' | 'MATCHED' | 'CANCELLED' | 'FILLED')[]): Promise<any>;
|
|
49
|
+
/**
|
|
50
|
+
* Get the signer's wallet address.
|
|
51
|
+
*/
|
|
52
|
+
getAddress(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Get the underlying HTTP client for direct API access.
|
|
55
|
+
*/
|
|
56
|
+
getHttpClient(): HttpClient;
|
|
57
|
+
/**
|
|
58
|
+
* Get the underlying OrderClient for advanced order operations.
|
|
59
|
+
*/
|
|
60
|
+
getOrderClient(): OrderClient;
|
|
61
|
+
/**
|
|
62
|
+
* Get the underlying MarketFetcher for advanced market queries.
|
|
63
|
+
*/
|
|
64
|
+
getMarketFetcher(): MarketFetcher;
|
|
65
|
+
/**
|
|
66
|
+
* Clear the market cache.
|
|
67
|
+
*/
|
|
68
|
+
clearMarketCache(): void;
|
|
23
69
|
}
|