pmxt-core 2.4.0 → 2.6.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/BaseExchange.d.ts +55 -0
- package/dist/BaseExchange.js +65 -2
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +10 -1
- package/dist/exchanges/baozi/auth.d.ts +14 -0
- package/dist/exchanges/baozi/auth.js +33 -0
- package/dist/exchanges/baozi/errors.d.ts +11 -0
- package/dist/exchanges/baozi/errors.js +70 -0
- package/dist/exchanges/baozi/fetchEvents.d.ts +8 -0
- package/dist/exchanges/baozi/fetchEvents.js +34 -0
- package/dist/exchanges/baozi/fetchMarkets.d.ts +5 -0
- package/dist/exchanges/baozi/fetchMarkets.js +160 -0
- package/dist/exchanges/baozi/fetchOHLCV.d.ts +6 -0
- package/dist/exchanges/baozi/fetchOHLCV.js +10 -0
- package/dist/exchanges/baozi/fetchOrderBook.d.ts +12 -0
- package/dist/exchanges/baozi/fetchOrderBook.js +36 -0
- package/dist/exchanges/baozi/fetchTrades.d.ts +6 -0
- package/dist/exchanges/baozi/fetchTrades.js +10 -0
- package/dist/exchanges/baozi/index.d.ts +43 -0
- package/dist/exchanges/baozi/index.js +419 -0
- package/dist/exchanges/baozi/utils.d.ts +112 -0
- package/dist/exchanges/baozi/utils.js +446 -0
- package/dist/exchanges/baozi/websocket.d.ts +14 -0
- package/dist/exchanges/baozi/websocket.js +78 -0
- package/dist/exchanges/kalshi/fetchEvents.js +39 -0
- package/dist/exchanges/kalshi/fetchMarkets.js +13 -0
- package/dist/exchanges/kalshi/index.d.ts +15 -0
- package/dist/exchanges/kalshi/index.js +15 -0
- package/dist/exchanges/limitless/fetchEvents.js +69 -0
- package/dist/exchanges/limitless/fetchMarkets.js +13 -0
- package/dist/exchanges/limitless/index.d.ts +15 -0
- package/dist/exchanges/limitless/index.js +15 -0
- package/dist/exchanges/myriad/auth.d.ts +8 -0
- package/dist/exchanges/myriad/auth.js +25 -0
- package/dist/exchanges/myriad/errors.d.ts +8 -0
- package/dist/exchanges/myriad/errors.js +33 -0
- package/dist/exchanges/myriad/fetchEvents.d.ts +3 -0
- package/dist/exchanges/myriad/fetchEvents.js +48 -0
- package/dist/exchanges/myriad/fetchMarkets.d.ts +3 -0
- package/dist/exchanges/myriad/fetchMarkets.js +102 -0
- package/dist/exchanges/myriad/fetchOHLCV.d.ts +3 -0
- package/dist/exchanges/myriad/fetchOHLCV.js +91 -0
- package/dist/exchanges/myriad/fetchOrderBook.d.ts +2 -0
- package/dist/exchanges/myriad/fetchOrderBook.js +47 -0
- package/dist/exchanges/myriad/fetchTrades.d.ts +3 -0
- package/dist/exchanges/myriad/fetchTrades.js +62 -0
- package/dist/exchanges/myriad/index.d.ts +39 -0
- package/dist/exchanges/myriad/index.js +224 -0
- package/dist/exchanges/myriad/utils.d.ts +15 -0
- package/dist/exchanges/myriad/utils.js +99 -0
- package/dist/exchanges/myriad/websocket.d.ts +17 -0
- package/dist/exchanges/myriad/websocket.js +105 -0
- package/dist/exchanges/polymarket/fetchEvents.js +72 -3
- package/dist/exchanges/polymarket/fetchMarkets.js +52 -0
- package/dist/exchanges/polymarket/index.d.ts +15 -0
- package/dist/exchanges/polymarket/index.js +15 -0
- package/dist/exchanges/probable/fetchEvents.js +10 -0
- package/dist/exchanges/probable/fetchMarkets.js +33 -3
- package/dist/exchanges/probable/index.d.ts +15 -0
- package/dist/exchanges/probable/index.js +15 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +10 -2
- package/dist/server/app.js +28 -1
- package/dist/server/utils/lock-file.d.ts +1 -0
- package/dist/server/utils/lock-file.js +28 -8
- package/package.json +5 -3
package/dist/BaseExchange.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface MarketFilterParams {
|
|
|
8
8
|
searchIn?: 'title' | 'description' | 'both';
|
|
9
9
|
query?: string;
|
|
10
10
|
slug?: string;
|
|
11
|
+
marketId?: string;
|
|
12
|
+
outcomeId?: string;
|
|
13
|
+
eventId?: string;
|
|
11
14
|
page?: number;
|
|
12
15
|
similarityThreshold?: number;
|
|
13
16
|
}
|
|
@@ -19,6 +22,8 @@ export interface EventFetchParams {
|
|
|
19
22
|
offset?: number;
|
|
20
23
|
status?: 'active' | 'inactive' | 'closed' | 'all';
|
|
21
24
|
searchIn?: 'title' | 'description' | 'both';
|
|
25
|
+
eventId?: string;
|
|
26
|
+
slug?: string;
|
|
22
27
|
}
|
|
23
28
|
export interface HistoryFilterParams {
|
|
24
29
|
resolution?: CandleInterval;
|
|
@@ -89,6 +94,22 @@ export type EventFilterCriteria = {
|
|
|
89
94
|
};
|
|
90
95
|
};
|
|
91
96
|
export type EventFilterFunction = (event: UnifiedEvent) => boolean;
|
|
97
|
+
export type ExchangeCapability = true | false | 'emulated';
|
|
98
|
+
export interface ExchangeHas {
|
|
99
|
+
fetchMarkets: ExchangeCapability;
|
|
100
|
+
fetchEvents: ExchangeCapability;
|
|
101
|
+
fetchOHLCV: ExchangeCapability;
|
|
102
|
+
fetchOrderBook: ExchangeCapability;
|
|
103
|
+
fetchTrades: ExchangeCapability;
|
|
104
|
+
createOrder: ExchangeCapability;
|
|
105
|
+
cancelOrder: ExchangeCapability;
|
|
106
|
+
fetchOrder: ExchangeCapability;
|
|
107
|
+
fetchOpenOrders: ExchangeCapability;
|
|
108
|
+
fetchPositions: ExchangeCapability;
|
|
109
|
+
fetchBalance: ExchangeCapability;
|
|
110
|
+
watchOrderBook: ExchangeCapability;
|
|
111
|
+
watchTrades: ExchangeCapability;
|
|
112
|
+
}
|
|
92
113
|
export interface ExchangeCredentials {
|
|
93
114
|
apiKey?: string;
|
|
94
115
|
apiSecret?: string;
|
|
@@ -99,6 +120,7 @@ export interface ExchangeCredentials {
|
|
|
99
120
|
}
|
|
100
121
|
export declare abstract class PredictionMarketExchange {
|
|
101
122
|
protected credentials?: ExchangeCredentials;
|
|
123
|
+
readonly has: ExchangeHas;
|
|
102
124
|
constructor(credentials?: ExchangeCredentials);
|
|
103
125
|
abstract get name(): string;
|
|
104
126
|
/**
|
|
@@ -155,6 +177,39 @@ export declare abstract class PredictionMarketExchange {
|
|
|
155
177
|
* print(fed_event.title, len(fed_event.markets), 'markets')
|
|
156
178
|
*/
|
|
157
179
|
fetchEvents(params?: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
180
|
+
/**
|
|
181
|
+
* Fetch a single market by lookup parameters.
|
|
182
|
+
* Convenience wrapper around fetchMarkets() that returns a single result or throws MarketNotFound.
|
|
183
|
+
*
|
|
184
|
+
* @param params - Lookup parameters (marketId, outcomeId, slug, etc.)
|
|
185
|
+
* @returns A single unified market
|
|
186
|
+
* @throws MarketNotFound if no market matches the parameters
|
|
187
|
+
*
|
|
188
|
+
* @example-ts Fetch by market ID
|
|
189
|
+
* const market = await exchange.fetchMarket({ marketId: '663583' });
|
|
190
|
+
*
|
|
191
|
+
* @example-ts Fetch by outcome ID
|
|
192
|
+
* const market = await exchange.fetchMarket({ outcomeId: '10991849...' });
|
|
193
|
+
*
|
|
194
|
+
* @example-python Fetch by market ID
|
|
195
|
+
* market = exchange.fetch_market(market_id='663583')
|
|
196
|
+
*/
|
|
197
|
+
fetchMarket(params?: MarketFetchParams): Promise<UnifiedMarket>;
|
|
198
|
+
/**
|
|
199
|
+
* Fetch a single event by lookup parameters.
|
|
200
|
+
* Convenience wrapper around fetchEvents() that returns a single result or throws EventNotFound.
|
|
201
|
+
*
|
|
202
|
+
* @param params - Lookup parameters (eventId, slug, query)
|
|
203
|
+
* @returns A single unified event
|
|
204
|
+
* @throws EventNotFound if no event matches the parameters
|
|
205
|
+
*
|
|
206
|
+
* @example-ts Fetch by event ID
|
|
207
|
+
* const event = await exchange.fetchEvent({ eventId: 'TRUMP25DEC' });
|
|
208
|
+
*
|
|
209
|
+
* @example-python Fetch by event ID
|
|
210
|
+
* event = exchange.fetch_event(event_id='TRUMP25DEC')
|
|
211
|
+
*/
|
|
212
|
+
fetchEvent(params?: EventFetchParams): Promise<UnifiedEvent>;
|
|
158
213
|
/**
|
|
159
214
|
* @internal
|
|
160
215
|
* Implementation for fetching/searching markets.
|
package/dist/BaseExchange.js
CHANGED
|
@@ -2,11 +2,27 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PredictionMarketExchange = void 0;
|
|
4
4
|
const math_1 = require("./utils/math");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
5
6
|
// ----------------------------------------------------------------------------
|
|
6
7
|
// Base Exchange Class
|
|
7
8
|
// ----------------------------------------------------------------------------
|
|
8
9
|
class PredictionMarketExchange {
|
|
9
10
|
credentials;
|
|
11
|
+
has = {
|
|
12
|
+
fetchMarkets: false,
|
|
13
|
+
fetchEvents: false,
|
|
14
|
+
fetchOHLCV: false,
|
|
15
|
+
fetchOrderBook: false,
|
|
16
|
+
fetchTrades: false,
|
|
17
|
+
createOrder: false,
|
|
18
|
+
cancelOrder: false,
|
|
19
|
+
fetchOrder: false,
|
|
20
|
+
fetchOpenOrders: false,
|
|
21
|
+
fetchPositions: false,
|
|
22
|
+
fetchBalance: false,
|
|
23
|
+
watchOrderBook: false,
|
|
24
|
+
watchTrades: false,
|
|
25
|
+
};
|
|
10
26
|
constructor(credentials) {
|
|
11
27
|
this.credentials = credentials;
|
|
12
28
|
}
|
|
@@ -66,11 +82,58 @@ class PredictionMarketExchange {
|
|
|
66
82
|
* print(fed_event.title, len(fed_event.markets), 'markets')
|
|
67
83
|
*/
|
|
68
84
|
async fetchEvents(params) {
|
|
69
|
-
if (!params?.query) {
|
|
70
|
-
throw new Error("fetchEvents() requires a query parameter");
|
|
85
|
+
if (!params?.query && !params?.eventId && !params?.slug) {
|
|
86
|
+
throw new Error("fetchEvents() requires a query, eventId, or slug parameter");
|
|
71
87
|
}
|
|
72
88
|
return this.fetchEventsImpl(params);
|
|
73
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Fetch a single market by lookup parameters.
|
|
92
|
+
* Convenience wrapper around fetchMarkets() that returns a single result or throws MarketNotFound.
|
|
93
|
+
*
|
|
94
|
+
* @param params - Lookup parameters (marketId, outcomeId, slug, etc.)
|
|
95
|
+
* @returns A single unified market
|
|
96
|
+
* @throws MarketNotFound if no market matches the parameters
|
|
97
|
+
*
|
|
98
|
+
* @example-ts Fetch by market ID
|
|
99
|
+
* const market = await exchange.fetchMarket({ marketId: '663583' });
|
|
100
|
+
*
|
|
101
|
+
* @example-ts Fetch by outcome ID
|
|
102
|
+
* const market = await exchange.fetchMarket({ outcomeId: '10991849...' });
|
|
103
|
+
*
|
|
104
|
+
* @example-python Fetch by market ID
|
|
105
|
+
* market = exchange.fetch_market(market_id='663583')
|
|
106
|
+
*/
|
|
107
|
+
async fetchMarket(params) {
|
|
108
|
+
const markets = await this.fetchMarkets(params);
|
|
109
|
+
if (markets.length === 0) {
|
|
110
|
+
const identifier = params?.marketId || params?.outcomeId || params?.slug || params?.eventId || params?.query || 'unknown';
|
|
111
|
+
throw new errors_1.MarketNotFound(identifier, this.name);
|
|
112
|
+
}
|
|
113
|
+
return markets[0];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Fetch a single event by lookup parameters.
|
|
117
|
+
* Convenience wrapper around fetchEvents() that returns a single result or throws EventNotFound.
|
|
118
|
+
*
|
|
119
|
+
* @param params - Lookup parameters (eventId, slug, query)
|
|
120
|
+
* @returns A single unified event
|
|
121
|
+
* @throws EventNotFound if no event matches the parameters
|
|
122
|
+
*
|
|
123
|
+
* @example-ts Fetch by event ID
|
|
124
|
+
* const event = await exchange.fetchEvent({ eventId: 'TRUMP25DEC' });
|
|
125
|
+
*
|
|
126
|
+
* @example-python Fetch by event ID
|
|
127
|
+
* event = exchange.fetch_event(event_id='TRUMP25DEC')
|
|
128
|
+
*/
|
|
129
|
+
async fetchEvent(params) {
|
|
130
|
+
const events = await this.fetchEvents(params);
|
|
131
|
+
if (events.length === 0) {
|
|
132
|
+
const identifier = params?.eventId || params?.slug || params?.query || 'unknown';
|
|
133
|
+
throw new errors_1.EventNotFound(identifier, this.name);
|
|
134
|
+
}
|
|
135
|
+
return events[0];
|
|
136
|
+
}
|
|
74
137
|
// ----------------------------------------------------------------------------
|
|
75
138
|
// Implementation methods (to be overridden by exchanges)
|
|
76
139
|
// ----------------------------------------------------------------------------
|
package/dist/errors.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ export declare class OrderNotFound extends BaseError {
|
|
|
51
51
|
export declare class MarketNotFound extends BaseError {
|
|
52
52
|
constructor(marketId: string, exchange?: string);
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* 404 Not Found - The requested event doesn't exist
|
|
56
|
+
*/
|
|
57
|
+
export declare class EventNotFound extends BaseError {
|
|
58
|
+
constructor(identifier: string, exchange?: string);
|
|
59
|
+
}
|
|
54
60
|
/**
|
|
55
61
|
* 429 Too Many Requests - Rate limit exceeded
|
|
56
62
|
*/
|
package/dist/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ExchangeNotAvailable = exports.NetworkError = exports.ValidationError = exports.InsufficientFunds = exports.InvalidOrder = exports.RateLimitExceeded = exports.MarketNotFound = exports.OrderNotFound = exports.NotFound = exports.PermissionDenied = exports.AuthenticationError = exports.BadRequest = exports.BaseError = void 0;
|
|
3
|
+
exports.ExchangeNotAvailable = exports.NetworkError = exports.ValidationError = exports.InsufficientFunds = exports.InvalidOrder = exports.RateLimitExceeded = exports.EventNotFound = exports.MarketNotFound = exports.OrderNotFound = exports.NotFound = exports.PermissionDenied = exports.AuthenticationError = exports.BadRequest = exports.BaseError = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Base error class for all PMXT errors
|
|
6
6
|
*
|
|
@@ -87,6 +87,15 @@ class MarketNotFound extends BaseError {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
exports.MarketNotFound = MarketNotFound;
|
|
90
|
+
/**
|
|
91
|
+
* 404 Not Found - The requested event doesn't exist
|
|
92
|
+
*/
|
|
93
|
+
class EventNotFound extends BaseError {
|
|
94
|
+
constructor(identifier, exchange) {
|
|
95
|
+
super(`Event not found: ${identifier}`, 404, 'EVENT_NOT_FOUND', false, exchange);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.EventNotFound = EventNotFound;
|
|
90
99
|
/**
|
|
91
100
|
* 429 Too Many Requests - Rate limit exceeded
|
|
92
101
|
*/
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Keypair, PublicKey, Transaction } from '@solana/web3.js';
|
|
2
|
+
import { ExchangeCredentials } from '../../BaseExchange';
|
|
3
|
+
/**
|
|
4
|
+
* Manages Solana wallet authentication for Baozi.
|
|
5
|
+
* Read operations don't need auth (all on-chain data is public).
|
|
6
|
+
* Write operations (betting, claiming) require a Solana keypair.
|
|
7
|
+
*/
|
|
8
|
+
export declare class BaoziAuth {
|
|
9
|
+
private keypair;
|
|
10
|
+
constructor(credentials: ExchangeCredentials);
|
|
11
|
+
getPublicKey(): PublicKey;
|
|
12
|
+
getKeypair(): Keypair;
|
|
13
|
+
signTransaction(tx: Transaction): Transaction;
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BaoziAuth = void 0;
|
|
7
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
9
|
+
/**
|
|
10
|
+
* Manages Solana wallet authentication for Baozi.
|
|
11
|
+
* Read operations don't need auth (all on-chain data is public).
|
|
12
|
+
* Write operations (betting, claiming) require a Solana keypair.
|
|
13
|
+
*/
|
|
14
|
+
class BaoziAuth {
|
|
15
|
+
keypair;
|
|
16
|
+
constructor(credentials) {
|
|
17
|
+
if (!credentials.privateKey) {
|
|
18
|
+
throw new Error('Baozi requires a privateKey (base58-encoded Solana secret key) for trading operations');
|
|
19
|
+
}
|
|
20
|
+
this.keypair = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(credentials.privateKey));
|
|
21
|
+
}
|
|
22
|
+
getPublicKey() {
|
|
23
|
+
return this.keypair.publicKey;
|
|
24
|
+
}
|
|
25
|
+
getKeypair() {
|
|
26
|
+
return this.keypair;
|
|
27
|
+
}
|
|
28
|
+
signTransaction(tx) {
|
|
29
|
+
tx.sign(this.keypair);
|
|
30
|
+
return tx;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.BaoziAuth = BaoziAuth;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ErrorMapper } from '../../utils/error-mapper';
|
|
2
|
+
import { BaseError } from '../../errors';
|
|
3
|
+
/**
|
|
4
|
+
* Maps Solana/Anchor errors to pmxt unified error types.
|
|
5
|
+
*/
|
|
6
|
+
export declare class BaoziErrorMapper extends ErrorMapper {
|
|
7
|
+
constructor();
|
|
8
|
+
mapError(error: any): BaseError;
|
|
9
|
+
private extractAnchorError;
|
|
10
|
+
}
|
|
11
|
+
export declare const baoziErrorMapper: BaoziErrorMapper;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.baoziErrorMapper = exports.BaoziErrorMapper = void 0;
|
|
4
|
+
const error_mapper_1 = require("../../utils/error-mapper");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
// Anchor/Baozi program error codes
|
|
7
|
+
const PROGRAM_ERRORS = {
|
|
8
|
+
6000: { type: 'bad_request', message: 'Unauthorized' },
|
|
9
|
+
6001: { type: 'bad_request', message: 'Market not found' },
|
|
10
|
+
6015: { type: 'bad_request', message: 'Market is not open for betting' },
|
|
11
|
+
6018: { type: 'bad_request', message: 'Betting is closed' },
|
|
12
|
+
6020: { type: 'invalid_order', message: 'Bet amount too small' },
|
|
13
|
+
6040: { type: 'bad_request', message: 'Betting is frozen' },
|
|
14
|
+
6041: { type: 'invalid_order', message: 'Bet amount too large' },
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Maps Solana/Anchor errors to pmxt unified error types.
|
|
18
|
+
*/
|
|
19
|
+
class BaoziErrorMapper extends error_mapper_1.ErrorMapper {
|
|
20
|
+
constructor() {
|
|
21
|
+
super('Baozi');
|
|
22
|
+
}
|
|
23
|
+
mapError(error) {
|
|
24
|
+
// Handle Solana transaction errors
|
|
25
|
+
if (error?.message) {
|
|
26
|
+
const msg = error.message;
|
|
27
|
+
// Solana insufficient funds
|
|
28
|
+
if (msg.includes('Attempt to debit an account but found no record of a prior credit') ||
|
|
29
|
+
msg.includes('insufficient lamports') ||
|
|
30
|
+
msg.includes('insufficient funds')) {
|
|
31
|
+
return new errors_1.InsufficientFunds('Insufficient SOL balance', 'Baozi');
|
|
32
|
+
}
|
|
33
|
+
// Solana network errors
|
|
34
|
+
if (msg.includes('failed to send transaction') ||
|
|
35
|
+
msg.includes('Node is behind') ||
|
|
36
|
+
msg.includes('Transaction simulation failed')) {
|
|
37
|
+
// Try to extract Anchor error code
|
|
38
|
+
const anchorError = this.extractAnchorError(msg);
|
|
39
|
+
if (anchorError) {
|
|
40
|
+
return anchorError;
|
|
41
|
+
}
|
|
42
|
+
return new errors_1.NetworkError(`Solana RPC error: ${msg}`, 'Baozi');
|
|
43
|
+
}
|
|
44
|
+
// Connection errors
|
|
45
|
+
if (msg.includes('ECONNREFUSED') || msg.includes('ETIMEDOUT') || msg.includes('fetch failed')) {
|
|
46
|
+
return new errors_1.ExchangeNotAvailable('Solana RPC unreachable', 'Baozi');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return super.mapError(error);
|
|
50
|
+
}
|
|
51
|
+
extractAnchorError(message) {
|
|
52
|
+
// Anchor errors appear as "custom program error: 0x{hex}"
|
|
53
|
+
const match = message.match(/custom program error: 0x([0-9a-fA-F]+)/);
|
|
54
|
+
if (!match)
|
|
55
|
+
return null;
|
|
56
|
+
const code = parseInt(match[1], 16);
|
|
57
|
+
const knownError = PROGRAM_ERRORS[code];
|
|
58
|
+
if (!knownError) {
|
|
59
|
+
return new errors_1.BadRequest(`Baozi program error ${code}: ${message}`, 'Baozi');
|
|
60
|
+
}
|
|
61
|
+
switch (knownError.type) {
|
|
62
|
+
case 'invalid_order':
|
|
63
|
+
return new errors_1.InvalidOrder(knownError.message, 'Baozi');
|
|
64
|
+
default:
|
|
65
|
+
return new errors_1.BadRequest(knownError.message, 'Baozi');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.BaoziErrorMapper = BaoziErrorMapper;
|
|
70
|
+
exports.baoziErrorMapper = new BaoziErrorMapper();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Connection } from '@solana/web3.js';
|
|
2
|
+
import { EventFetchParams } from '../../BaseExchange';
|
|
3
|
+
import { UnifiedEvent } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* Baozi doesn't have Kalshi-style "events" (groups of related markets).
|
|
6
|
+
* Each market IS an event. Simple 1:1 mapping.
|
|
7
|
+
*/
|
|
8
|
+
export declare function fetchEvents(connection: Connection, params: EventFetchParams): Promise<UnifiedEvent[]>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchEvents = fetchEvents;
|
|
4
|
+
const fetchMarkets_1 = require("./fetchMarkets");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
/**
|
|
7
|
+
* Baozi doesn't have Kalshi-style "events" (groups of related markets).
|
|
8
|
+
* Each market IS an event. Simple 1:1 mapping.
|
|
9
|
+
*/
|
|
10
|
+
async function fetchEvents(connection, params) {
|
|
11
|
+
try {
|
|
12
|
+
const markets = await (0, fetchMarkets_1.fetchMarkets)(connection, {
|
|
13
|
+
query: params.query,
|
|
14
|
+
limit: params.limit,
|
|
15
|
+
offset: params.offset,
|
|
16
|
+
status: params.status,
|
|
17
|
+
searchIn: params.searchIn,
|
|
18
|
+
});
|
|
19
|
+
return markets.map(m => ({
|
|
20
|
+
id: m.marketId,
|
|
21
|
+
title: m.title,
|
|
22
|
+
description: m.description,
|
|
23
|
+
slug: m.marketId,
|
|
24
|
+
markets: [m],
|
|
25
|
+
url: m.url,
|
|
26
|
+
image: m.image,
|
|
27
|
+
category: m.category,
|
|
28
|
+
tags: m.tags,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw errors_1.baoziErrorMapper.mapError(error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Connection } from '@solana/web3.js';
|
|
2
|
+
import { MarketFetchParams } from '../../BaseExchange';
|
|
3
|
+
import { UnifiedMarket } from '../../types';
|
|
4
|
+
export declare function fetchMarkets(connection: Connection, params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
5
|
+
export declare function fetchSingleMarket(connection: Connection, pubkey: string): Promise<UnifiedMarket | null>;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.fetchMarkets = fetchMarkets;
|
|
37
|
+
exports.fetchSingleMarket = fetchSingleMarket;
|
|
38
|
+
const utils_1 = require("./utils");
|
|
39
|
+
const errors_1 = require("./errors");
|
|
40
|
+
const marketsCache = new utils_1.Cache(30_000); // 30s TTL
|
|
41
|
+
async function fetchMarkets(connection, params) {
|
|
42
|
+
try {
|
|
43
|
+
// Use cache for default (no-filter) fetches
|
|
44
|
+
if (!params?.query && !params?.slug) {
|
|
45
|
+
const cached = marketsCache.get();
|
|
46
|
+
if (cached) {
|
|
47
|
+
return applyFilters(cached, params);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Fetch boolean and race markets in parallel
|
|
51
|
+
const [booleanAccounts, raceAccounts] = await Promise.all([
|
|
52
|
+
connection.getProgramAccounts(utils_1.PROGRAM_ID, {
|
|
53
|
+
filters: [{ memcmp: { offset: 0, bytes: utils_1.MARKET_DISCRIMINATOR_BS58 } }],
|
|
54
|
+
}),
|
|
55
|
+
connection.getProgramAccounts(utils_1.PROGRAM_ID, {
|
|
56
|
+
filters: [{ memcmp: { offset: 0, bytes: utils_1.RACE_MARKET_DISCRIMINATOR_BS58 } }],
|
|
57
|
+
}),
|
|
58
|
+
]);
|
|
59
|
+
const markets = [];
|
|
60
|
+
// Parse boolean markets
|
|
61
|
+
for (const account of booleanAccounts) {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = (0, utils_1.parseMarket)(account.account.data);
|
|
64
|
+
markets.push((0, utils_1.mapBooleanToUnified)(parsed, account.pubkey.toString()));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Skip malformed accounts
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Parse race markets
|
|
71
|
+
for (const account of raceAccounts) {
|
|
72
|
+
try {
|
|
73
|
+
const parsed = (0, utils_1.parseRaceMarket)(account.account.data);
|
|
74
|
+
markets.push((0, utils_1.mapRaceToUnified)(parsed, account.pubkey.toString()));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Skip malformed accounts
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Cache results
|
|
81
|
+
marketsCache.set(markets);
|
|
82
|
+
return applyFilters(markets, params);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw errors_1.baoziErrorMapper.mapError(error);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function fetchSingleMarket(connection, pubkey) {
|
|
89
|
+
try {
|
|
90
|
+
const { PublicKey } = await Promise.resolve().then(() => __importStar(require('@solana/web3.js')));
|
|
91
|
+
const pk = new PublicKey(pubkey);
|
|
92
|
+
const accountInfo = await connection.getAccountInfo(pk);
|
|
93
|
+
if (!accountInfo)
|
|
94
|
+
return null;
|
|
95
|
+
const data = accountInfo.data;
|
|
96
|
+
const discriminator = data.subarray(0, 8);
|
|
97
|
+
// Check if it's a boolean market
|
|
98
|
+
if (Buffer.from(discriminator).equals(Buffer.from([219, 190, 213, 55, 0, 227, 198, 154]))) {
|
|
99
|
+
const parsed = (0, utils_1.parseMarket)(data);
|
|
100
|
+
return (0, utils_1.mapBooleanToUnified)(parsed, pubkey);
|
|
101
|
+
}
|
|
102
|
+
// Check if it's a race market
|
|
103
|
+
if (Buffer.from(discriminator).equals(Buffer.from([235, 196, 111, 75, 230, 113, 118, 238]))) {
|
|
104
|
+
const parsed = (0, utils_1.parseRaceMarket)(data);
|
|
105
|
+
return (0, utils_1.mapRaceToUnified)(parsed, pubkey);
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function applyFilters(markets, params) {
|
|
114
|
+
let result = [...markets];
|
|
115
|
+
// Status filter
|
|
116
|
+
const status = params?.status || 'active';
|
|
117
|
+
if (status !== 'all') {
|
|
118
|
+
const now = Date.now();
|
|
119
|
+
if (status === 'active') {
|
|
120
|
+
result = result.filter(m => m.resolutionDate.getTime() > now);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// 'inactive' / 'closed'
|
|
124
|
+
result = result.filter(m => m.resolutionDate.getTime() <= now);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Text search
|
|
128
|
+
if (params?.query) {
|
|
129
|
+
const lowerQuery = params.query.toLowerCase();
|
|
130
|
+
const searchIn = params.searchIn || 'title';
|
|
131
|
+
result = result.filter(m => {
|
|
132
|
+
const titleMatch = m.title.toLowerCase().includes(lowerQuery);
|
|
133
|
+
const descMatch = (m.description || '').toLowerCase().includes(lowerQuery);
|
|
134
|
+
if (searchIn === 'title')
|
|
135
|
+
return titleMatch;
|
|
136
|
+
if (searchIn === 'description')
|
|
137
|
+
return descMatch;
|
|
138
|
+
return titleMatch || descMatch; // 'both'
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// Sort
|
|
142
|
+
if (params?.sort === 'volume') {
|
|
143
|
+
result.sort((a, b) => (b.volume || 0) - (a.volume || 0));
|
|
144
|
+
}
|
|
145
|
+
else if (params?.sort === 'liquidity') {
|
|
146
|
+
result.sort((a, b) => b.liquidity - a.liquidity);
|
|
147
|
+
}
|
|
148
|
+
else if (params?.sort === 'newest') {
|
|
149
|
+
result.sort((a, b) => b.resolutionDate.getTime() - a.resolutionDate.getTime());
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Default: sort by volume
|
|
153
|
+
result.sort((a, b) => (b.volume || 0) - (a.volume || 0));
|
|
154
|
+
}
|
|
155
|
+
// Pagination
|
|
156
|
+
const offset = params?.offset || 0;
|
|
157
|
+
const limit = params?.limit || 10000;
|
|
158
|
+
result = result.slice(offset, offset + limit);
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchOHLCV = fetchOHLCV;
|
|
4
|
+
/**
|
|
5
|
+
* Baozi has no historical price/trade API without a custom indexer.
|
|
6
|
+
* Returns an empty array.
|
|
7
|
+
*/
|
|
8
|
+
async function fetchOHLCV() {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Connection } from '@solana/web3.js';
|
|
2
|
+
import { OrderBook } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Pari-mutuel markets don't have a real order book.
|
|
5
|
+
* We synthesize one that represents the current pool state:
|
|
6
|
+
* - bid = ask = implied probability from pool ratios
|
|
7
|
+
* - size = total pool in SOL
|
|
8
|
+
*
|
|
9
|
+
* This honestly represents pari-mutuel: there's one "price"
|
|
10
|
+
* (the implied probability) and you can bet any amount into it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function fetchOrderBook(connection: Connection, outcomeId: string): Promise<OrderBook>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchOrderBook = fetchOrderBook;
|
|
4
|
+
const fetchMarkets_1 = require("./fetchMarkets");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
/**
|
|
7
|
+
* Pari-mutuel markets don't have a real order book.
|
|
8
|
+
* We synthesize one that represents the current pool state:
|
|
9
|
+
* - bid = ask = implied probability from pool ratios
|
|
10
|
+
* - size = total pool in SOL
|
|
11
|
+
*
|
|
12
|
+
* This honestly represents pari-mutuel: there's one "price"
|
|
13
|
+
* (the implied probability) and you can bet any amount into it.
|
|
14
|
+
*/
|
|
15
|
+
async function fetchOrderBook(connection, outcomeId) {
|
|
16
|
+
try {
|
|
17
|
+
const marketPubkey = outcomeId.replace(/-YES$|-NO$|-\d+$/, '');
|
|
18
|
+
const market = await (0, fetchMarkets_1.fetchSingleMarket)(connection, marketPubkey);
|
|
19
|
+
if (!market) {
|
|
20
|
+
throw new Error(`Market not found: ${marketPubkey}`);
|
|
21
|
+
}
|
|
22
|
+
// Find the outcome matching the requested ID
|
|
23
|
+
const outcome = market.outcomes.find(o => o.outcomeId === outcomeId);
|
|
24
|
+
const price = outcome?.price ?? 0.5;
|
|
25
|
+
const totalLiquidity = market.liquidity;
|
|
26
|
+
// Single price level representing the entire pool
|
|
27
|
+
return {
|
|
28
|
+
bids: [{ price, size: totalLiquidity }],
|
|
29
|
+
asks: [{ price, size: totalLiquidity }],
|
|
30
|
+
timestamp: Date.now(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw errors_1.baoziErrorMapper.mapError(error);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchTrades = fetchTrades;
|
|
4
|
+
/**
|
|
5
|
+
* Baozi has no trade history API without a custom indexer.
|
|
6
|
+
* Returns an empty array.
|
|
7
|
+
*/
|
|
8
|
+
async function fetchTrades() {
|
|
9
|
+
return [];
|
|
10
|
+
}
|