pmxt-core 2.20.1 → 2.20.2

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.
Files changed (111) hide show
  1. package/dist/exchanges/baozi/fetcher.d.ts +40 -0
  2. package/dist/exchanges/baozi/fetcher.js +155 -0
  3. package/dist/exchanges/baozi/index.d.ts +2 -0
  4. package/dist/exchanges/baozi/index.js +60 -131
  5. package/dist/exchanges/baozi/normalizer.d.ts +14 -0
  6. package/dist/exchanges/baozi/normalizer.js +208 -0
  7. package/dist/exchanges/interfaces.d.ts +28 -0
  8. package/dist/exchanges/interfaces.js +2 -0
  9. package/dist/exchanges/kalshi/api.d.ts +1 -1
  10. package/dist/exchanges/kalshi/api.js +1 -1
  11. package/dist/exchanges/kalshi/fetcher.d.ts +126 -0
  12. package/dist/exchanges/kalshi/fetcher.js +313 -0
  13. package/dist/exchanges/kalshi/index.d.ts +6 -6
  14. package/dist/exchanges/kalshi/index.js +119 -202
  15. package/dist/exchanges/kalshi/normalizer.d.ts +25 -0
  16. package/dist/exchanges/kalshi/normalizer.js +294 -0
  17. package/dist/exchanges/limitless/api.d.ts +1 -1
  18. package/dist/exchanges/limitless/api.js +1 -1
  19. package/dist/exchanges/limitless/fetcher.d.ts +81 -0
  20. package/dist/exchanges/limitless/fetcher.js +238 -0
  21. package/dist/exchanges/limitless/index.d.ts +6 -9
  22. package/dist/exchanges/limitless/index.js +81 -79
  23. package/dist/exchanges/limitless/normalizer.d.ts +14 -0
  24. package/dist/exchanges/limitless/normalizer.js +117 -0
  25. package/dist/exchanges/limitless/websocket.d.ts +3 -0
  26. package/dist/exchanges/limitless/websocket.js +5 -4
  27. package/dist/exchanges/myriad/api.d.ts +1 -1
  28. package/dist/exchanges/myriad/api.js +1 -1
  29. package/dist/exchanges/myriad/fetcher.d.ts +73 -0
  30. package/dist/exchanges/myriad/fetcher.js +217 -0
  31. package/dist/exchanges/myriad/index.d.ts +2 -0
  32. package/dist/exchanges/myriad/index.js +40 -97
  33. package/dist/exchanges/myriad/normalizer.d.ts +14 -0
  34. package/dist/exchanges/myriad/normalizer.js +167 -0
  35. package/dist/exchanges/myriad/websocket.d.ts +3 -1
  36. package/dist/exchanges/myriad/websocket.js +4 -3
  37. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  38. package/dist/exchanges/polymarket/api-clob.js +1 -1
  39. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  40. package/dist/exchanges/polymarket/api-data.js +1 -1
  41. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  42. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  43. package/dist/exchanges/polymarket/fetcher.d.ts +99 -0
  44. package/dist/exchanges/polymarket/fetcher.js +335 -0
  45. package/dist/exchanges/polymarket/index.d.ts +2 -0
  46. package/dist/exchanges/polymarket/index.js +80 -66
  47. package/dist/exchanges/polymarket/normalizer.d.ts +18 -0
  48. package/dist/exchanges/polymarket/normalizer.js +126 -0
  49. package/dist/exchanges/probable/api.d.ts +1 -1
  50. package/dist/exchanges/probable/api.js +1 -1
  51. package/dist/exchanges/probable/fetcher.d.ts +106 -0
  52. package/dist/exchanges/probable/fetcher.js +357 -0
  53. package/dist/exchanges/probable/index.d.ts +3 -1
  54. package/dist/exchanges/probable/index.js +73 -105
  55. package/dist/exchanges/probable/normalizer.d.ts +14 -0
  56. package/dist/exchanges/probable/normalizer.js +109 -0
  57. package/package.json +3 -3
  58. package/dist/exchanges/baozi/fetchEvents.d.ts +0 -8
  59. package/dist/exchanges/baozi/fetchEvents.js +0 -39
  60. package/dist/exchanges/baozi/fetchMarkets.d.ts +0 -5
  61. package/dist/exchanges/baozi/fetchMarkets.js +0 -160
  62. package/dist/exchanges/baozi/fetchOHLCV.d.ts +0 -6
  63. package/dist/exchanges/baozi/fetchOHLCV.js +0 -10
  64. package/dist/exchanges/baozi/fetchOrderBook.d.ts +0 -12
  65. package/dist/exchanges/baozi/fetchOrderBook.js +0 -36
  66. package/dist/exchanges/baozi/fetchTrades.d.ts +0 -6
  67. package/dist/exchanges/baozi/fetchTrades.js +0 -10
  68. package/dist/exchanges/kalshi/fetchEvents.d.ts +0 -5
  69. package/dist/exchanges/kalshi/fetchEvents.js +0 -196
  70. package/dist/exchanges/kalshi/fetchMarkets.d.ts +0 -6
  71. package/dist/exchanges/kalshi/fetchMarkets.js +0 -247
  72. package/dist/exchanges/kalshi/fetchOHLCV.d.ts +0 -3
  73. package/dist/exchanges/kalshi/fetchOHLCV.js +0 -97
  74. package/dist/exchanges/kalshi/fetchOrderBook.d.ts +0 -2
  75. package/dist/exchanges/kalshi/fetchOrderBook.js +0 -60
  76. package/dist/exchanges/kalshi/fetchTrades.d.ts +0 -3
  77. package/dist/exchanges/kalshi/fetchTrades.js +0 -33
  78. package/dist/exchanges/limitless/fetchEvents.d.ts +0 -4
  79. package/dist/exchanges/limitless/fetchEvents.js +0 -173
  80. package/dist/exchanges/limitless/fetchMarkets.d.ts +0 -3
  81. package/dist/exchanges/limitless/fetchMarkets.js +0 -152
  82. package/dist/exchanges/limitless/fetchOHLCV.d.ts +0 -7
  83. package/dist/exchanges/limitless/fetchOHLCV.js +0 -49
  84. package/dist/exchanges/limitless/fetchOrderBook.d.ts +0 -6
  85. package/dist/exchanges/limitless/fetchOrderBook.js +0 -41
  86. package/dist/exchanges/limitless/fetchTrades.d.ts +0 -8
  87. package/dist/exchanges/limitless/fetchTrades.js +0 -27
  88. package/dist/exchanges/myriad/fetchEvents.d.ts +0 -4
  89. package/dist/exchanges/myriad/fetchEvents.js +0 -48
  90. package/dist/exchanges/myriad/fetchMarkets.d.ts +0 -4
  91. package/dist/exchanges/myriad/fetchMarkets.js +0 -102
  92. package/dist/exchanges/myriad/fetchOHLCV.d.ts +0 -3
  93. package/dist/exchanges/myriad/fetchOHLCV.js +0 -83
  94. package/dist/exchanges/myriad/fetchOrderBook.d.ts +0 -2
  95. package/dist/exchanges/myriad/fetchOrderBook.js +0 -39
  96. package/dist/exchanges/polymarket/fetchEvents.d.ts +0 -4
  97. package/dist/exchanges/polymarket/fetchEvents.js +0 -135
  98. package/dist/exchanges/polymarket/fetchMarkets.d.ts +0 -4
  99. package/dist/exchanges/polymarket/fetchMarkets.js +0 -214
  100. package/dist/exchanges/polymarket/fetchOHLCV.d.ts +0 -7
  101. package/dist/exchanges/polymarket/fetchOHLCV.js +0 -98
  102. package/dist/exchanges/polymarket/fetchOrderBook.d.ts +0 -6
  103. package/dist/exchanges/polymarket/fetchOrderBook.js +0 -33
  104. package/dist/exchanges/polymarket/fetchTrades.d.ts +0 -9
  105. package/dist/exchanges/polymarket/fetchTrades.js +0 -43
  106. package/dist/exchanges/probable/fetchEvents.d.ts +0 -6
  107. package/dist/exchanges/probable/fetchEvents.js +0 -151
  108. package/dist/exchanges/probable/fetchMarkets.d.ts +0 -4
  109. package/dist/exchanges/probable/fetchMarkets.js +0 -239
  110. package/dist/exchanges/probable/fetchTrades.d.ts +0 -10
  111. package/dist/exchanges/probable/fetchTrades.js +0 -40
@@ -0,0 +1,40 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ import { MarketFetchParams, EventFetchParams } from '../../BaseExchange';
3
+ import { IExchangeFetcher } from '../interfaces';
4
+ import { BaoziMarket, BaoziRaceMarket, BaoziUserPosition, BaoziRacePosition } from './utils';
5
+ export interface BaoziRawBooleanMarket {
6
+ pubkey: string;
7
+ parsed: BaoziMarket;
8
+ }
9
+ export interface BaoziRawRaceMarket {
10
+ pubkey: string;
11
+ parsed: BaoziRaceMarket;
12
+ }
13
+ export type BaoziRawMarket = BaoziRawBooleanMarket | BaoziRawRaceMarket;
14
+ export interface BaoziRawBooleanPosition {
15
+ pubkey: string;
16
+ parsed: BaoziUserPosition;
17
+ }
18
+ export interface BaoziRawRacePosition {
19
+ pubkey: string;
20
+ parsed: BaoziRacePosition;
21
+ }
22
+ export interface BaoziRawBalance {
23
+ lamports: number;
24
+ }
25
+ export declare function isRawBooleanMarket(raw: BaoziRawMarket): raw is BaoziRawBooleanMarket;
26
+ export declare function isRawRaceMarket(raw: BaoziRawMarket): raw is BaoziRawRaceMarket;
27
+ export declare class BaoziFetcher implements IExchangeFetcher<BaoziRawMarket, BaoziRawMarket> {
28
+ private readonly connection;
29
+ constructor(connection: Connection);
30
+ fetchRawMarkets(_params?: MarketFetchParams): Promise<BaoziRawMarket[]>;
31
+ fetchRawEvents(params: EventFetchParams): Promise<BaoziRawMarket[]>;
32
+ fetchRawSingleMarket(pubkey: string): Promise<BaoziRawMarket | null>;
33
+ fetchRawOrderBook(id: string): Promise<BaoziRawMarket | null>;
34
+ fetchRawUserPositions(walletAddress: PublicKey): Promise<{
35
+ booleanPositions: BaoziRawBooleanPosition[];
36
+ racePositions: BaoziRawRacePosition[];
37
+ }>;
38
+ fetchRawUserBalance(walletAddress: PublicKey): Promise<BaoziRawBalance>;
39
+ fetchRawMarketAccount(pubkey: PublicKey): Promise<BaoziRawMarket | null>;
40
+ }
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaoziFetcher = void 0;
4
+ exports.isRawBooleanMarket = isRawBooleanMarket;
5
+ exports.isRawRaceMarket = isRawRaceMarket;
6
+ const web3_js_1 = require("@solana/web3.js");
7
+ const utils_1 = require("./utils");
8
+ const errors_1 = require("./errors");
9
+ function isRawBooleanMarket(raw) {
10
+ return 'parsed' in raw && 'yesPool' in raw.parsed;
11
+ }
12
+ function isRawRaceMarket(raw) {
13
+ return 'parsed' in raw && 'outcomeCount' in raw.parsed;
14
+ }
15
+ // ---------------------------------------------------------------------------
16
+ // Fetcher
17
+ // ---------------------------------------------------------------------------
18
+ const marketsCache = new utils_1.Cache(30_000); // 30s TTL
19
+ class BaoziFetcher {
20
+ connection;
21
+ constructor(connection) {
22
+ this.connection = connection;
23
+ }
24
+ async fetchRawMarkets(_params) {
25
+ try {
26
+ const cached = marketsCache.get();
27
+ if (cached) {
28
+ return cached;
29
+ }
30
+ const [booleanAccounts, raceAccounts] = await Promise.all([
31
+ this.connection.getProgramAccounts(utils_1.PROGRAM_ID, {
32
+ filters: [{ memcmp: { offset: 0, bytes: utils_1.MARKET_DISCRIMINATOR_BS58 } }],
33
+ }),
34
+ this.connection.getProgramAccounts(utils_1.PROGRAM_ID, {
35
+ filters: [{ memcmp: { offset: 0, bytes: utils_1.RACE_MARKET_DISCRIMINATOR_BS58 } }],
36
+ }),
37
+ ]);
38
+ const markets = [];
39
+ for (const account of booleanAccounts) {
40
+ try {
41
+ const parsed = (0, utils_1.parseMarket)(account.account.data);
42
+ markets.push({ pubkey: account.pubkey.toString(), parsed });
43
+ }
44
+ catch {
45
+ // Skip malformed accounts
46
+ }
47
+ }
48
+ for (const account of raceAccounts) {
49
+ try {
50
+ const parsed = (0, utils_1.parseRaceMarket)(account.account.data);
51
+ markets.push({ pubkey: account.pubkey.toString(), parsed });
52
+ }
53
+ catch {
54
+ // Skip malformed accounts
55
+ }
56
+ }
57
+ marketsCache.set(markets);
58
+ return markets;
59
+ }
60
+ catch (error) {
61
+ throw errors_1.baoziErrorMapper.mapError(error);
62
+ }
63
+ }
64
+ async fetchRawEvents(params) {
65
+ // Baozi markets are 1:1 with events
66
+ return this.fetchRawMarkets({
67
+ query: params.query,
68
+ limit: params.limit,
69
+ offset: params.offset,
70
+ status: params.status,
71
+ searchIn: params.searchIn,
72
+ });
73
+ }
74
+ async fetchRawSingleMarket(pubkey) {
75
+ try {
76
+ const pk = new web3_js_1.PublicKey(pubkey);
77
+ const accountInfo = await this.connection.getAccountInfo(pk);
78
+ if (!accountInfo)
79
+ return null;
80
+ const data = accountInfo.data;
81
+ const discriminator = data.subarray(0, 8);
82
+ if (Buffer.from(discriminator).equals(utils_1.MARKET_DISCRIMINATOR)) {
83
+ const parsed = (0, utils_1.parseMarket)(data);
84
+ return { pubkey, parsed };
85
+ }
86
+ if (Buffer.from(discriminator).equals(utils_1.RACE_MARKET_DISCRIMINATOR)) {
87
+ const parsed = (0, utils_1.parseRaceMarket)(data);
88
+ return { pubkey, parsed };
89
+ }
90
+ return null;
91
+ }
92
+ catch {
93
+ return null;
94
+ }
95
+ }
96
+ async fetchRawOrderBook(id) {
97
+ const marketPubkey = id.replace(/-YES$|-NO$|-\d+$/, '');
98
+ return this.fetchRawSingleMarket(marketPubkey);
99
+ }
100
+ async fetchRawUserPositions(walletAddress) {
101
+ try {
102
+ const [booleanAccounts, raceAccounts] = await Promise.all([
103
+ this.connection.getProgramAccounts(utils_1.PROGRAM_ID, {
104
+ filters: [
105
+ { memcmp: { offset: 0, bytes: utils_1.USER_POSITION_DISCRIMINATOR_BS58 } },
106
+ { memcmp: { offset: 8, bytes: walletAddress.toBase58() } },
107
+ ],
108
+ }),
109
+ this.connection.getProgramAccounts(utils_1.PROGRAM_ID, {
110
+ filters: [
111
+ { memcmp: { offset: 0, bytes: utils_1.RACE_POSITION_DISCRIMINATOR_BS58 } },
112
+ { memcmp: { offset: 8, bytes: walletAddress.toBase58() } },
113
+ ],
114
+ }),
115
+ ]);
116
+ const booleanPositions = [];
117
+ for (const account of booleanAccounts) {
118
+ try {
119
+ const parsed = (0, utils_1.parseUserPosition)(account.account.data);
120
+ booleanPositions.push({ pubkey: account.pubkey.toString(), parsed });
121
+ }
122
+ catch {
123
+ // Skip malformed
124
+ }
125
+ }
126
+ const racePositions = [];
127
+ for (const account of raceAccounts) {
128
+ try {
129
+ const parsed = (0, utils_1.parseRacePosition)(account.account.data);
130
+ racePositions.push({ pubkey: account.pubkey.toString(), parsed });
131
+ }
132
+ catch {
133
+ // Skip malformed
134
+ }
135
+ }
136
+ return { booleanPositions, racePositions };
137
+ }
138
+ catch (error) {
139
+ throw errors_1.baoziErrorMapper.mapError(error);
140
+ }
141
+ }
142
+ async fetchRawUserBalance(walletAddress) {
143
+ try {
144
+ const lamports = await this.connection.getBalance(walletAddress);
145
+ return { lamports };
146
+ }
147
+ catch (error) {
148
+ throw errors_1.baoziErrorMapper.mapError(error);
149
+ }
150
+ }
151
+ async fetchRawMarketAccount(pubkey) {
152
+ return this.fetchRawSingleMarket(pubkey.toString());
153
+ }
154
+ }
155
+ exports.BaoziFetcher = BaoziFetcher;
@@ -30,6 +30,8 @@ export declare class BaoziExchange extends PredictionMarketExchange {
30
30
  private auth?;
31
31
  private connection;
32
32
  private ws?;
33
+ private readonly fetcher;
34
+ private readonly normalizer;
33
35
  constructor(options?: ExchangeCredentials | BaoziExchangeOptions);
34
36
  get name(): string;
35
37
  protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
@@ -4,14 +4,11 @@ exports.BaoziExchange = void 0;
4
4
  const web3_js_1 = require("@solana/web3.js");
5
5
  const BaseExchange_1 = require("../../BaseExchange");
6
6
  const errors_1 = require("../../errors");
7
- const fetchMarkets_1 = require("./fetchMarkets");
8
- const fetchEvents_1 = require("./fetchEvents");
9
- const fetchOHLCV_1 = require("./fetchOHLCV");
10
- const fetchOrderBook_1 = require("./fetchOrderBook");
11
- const fetchTrades_1 = require("./fetchTrades");
12
7
  const auth_1 = require("./auth");
13
8
  const websocket_1 = require("./websocket");
14
9
  const errors_2 = require("./errors");
10
+ const fetcher_1 = require("./fetcher");
11
+ const normalizer_1 = require("./normalizer");
15
12
  const utils_1 = require("./utils");
16
13
  class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
17
14
  has = {
@@ -39,6 +36,8 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
39
36
  auth;
40
37
  connection;
41
38
  ws;
39
+ fetcher;
40
+ normalizer;
42
41
  constructor(options) {
43
42
  let credentials;
44
43
  let rpcUrl;
@@ -59,163 +58,97 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
59
58
  if (credentials?.privateKey) {
60
59
  this.auth = new auth_1.BaoziAuth(credentials);
61
60
  }
61
+ this.fetcher = new fetcher_1.BaoziFetcher(this.connection);
62
+ this.normalizer = new normalizer_1.BaoziNormalizer();
62
63
  }
63
64
  get name() {
64
65
  return 'Baozi';
65
66
  }
66
67
  // -----------------------------------------------------------------------
67
- // Market Data
68
+ // Market Data (fetcher -> normalizer)
68
69
  // -----------------------------------------------------------------------
69
70
  async fetchMarketsImpl(params) {
70
- return (0, fetchMarkets_1.fetchMarkets)(this.connection, params);
71
+ const rawMarkets = await this.fetcher.fetchRawMarkets(params);
72
+ return this.normalizer.normalizeMarkets(rawMarkets, params);
71
73
  }
72
74
  async fetchEventsImpl(params) {
73
- return (0, fetchEvents_1.fetchEvents)(this.connection, params);
75
+ const rawMarkets = await this.fetcher.fetchRawEvents(params);
76
+ return this.normalizer.normalizeEvents(rawMarkets, {
77
+ query: params.query,
78
+ limit: params.limit,
79
+ offset: params.offset,
80
+ status: params.status,
81
+ searchIn: params.searchIn,
82
+ });
74
83
  }
75
84
  async fetchOHLCV() {
76
- return (0, fetchOHLCV_1.fetchOHLCV)();
85
+ // Baozi has no historical price/trade API without a custom indexer
86
+ return [];
77
87
  }
78
88
  async fetchOrderBook(id) {
79
- return (0, fetchOrderBook_1.fetchOrderBook)(this.connection, id);
89
+ const rawMarket = await this.fetcher.fetchRawOrderBook(id);
90
+ return this.normalizer.normalizeOrderBook(rawMarket, id);
80
91
  }
81
92
  async fetchTrades() {
82
- return (0, fetchTrades_1.fetchTrades)();
93
+ // Baozi has no trade history API without a custom indexer
94
+ return [];
83
95
  }
84
96
  // -----------------------------------------------------------------------
85
- // User Data
97
+ // User Data (fetcher -> normalizer)
86
98
  // -----------------------------------------------------------------------
87
99
  async fetchBalance() {
88
- try {
89
- const auth = this.ensureAuth();
90
- const lamports = await this.connection.getBalance(auth.getPublicKey());
91
- const solBalance = lamports / utils_1.LAMPORTS_PER_SOL;
92
- return [{
93
- currency: 'SOL',
94
- total: solBalance,
95
- available: solBalance,
96
- locked: 0,
97
- }];
98
- }
99
- catch (error) {
100
- throw errors_2.baoziErrorMapper.mapError(error);
101
- }
100
+ const auth = this.ensureAuth();
101
+ const rawBalance = await this.fetcher.fetchRawUserBalance(auth.getPublicKey());
102
+ return this.normalizer.normalizeBalance(rawBalance);
102
103
  }
103
104
  async fetchPositions() {
104
105
  try {
105
106
  const auth = this.ensureAuth();
106
107
  const userPubkey = auth.getPublicKey();
107
- // Fetch boolean and race positions in parallel
108
- const [booleanPositions, racePositions] = await Promise.all([
109
- this.connection.getProgramAccounts(utils_1.PROGRAM_ID, {
110
- filters: [
111
- { memcmp: { offset: 0, bytes: utils_1.USER_POSITION_DISCRIMINATOR_BS58 } },
112
- { memcmp: { offset: 8, bytes: userPubkey.toBase58() } },
113
- ],
114
- }),
115
- this.connection.getProgramAccounts(utils_1.PROGRAM_ID, {
116
- filters: [
117
- { memcmp: { offset: 0, bytes: utils_1.RACE_POSITION_DISCRIMINATOR_BS58 } },
118
- { memcmp: { offset: 8, bytes: userPubkey.toBase58() } },
119
- ],
120
- }),
121
- ]);
122
- const positions = [];
123
- // Process boolean positions
124
- for (const account of booleanPositions) {
125
- try {
126
- const pos = (0, utils_1.parseUserPosition)(account.account.data);
127
- if (pos.claimed)
128
- continue;
129
- // Try to fetch the market to get current prices
130
- const marketPda = (0, utils_1.deriveMarketPda)(pos.marketId);
131
- let currentYesPrice = 0;
132
- let currentNoPrice = 0;
133
- let marketTitle = `Market #${pos.marketId}`;
108
+ const { booleanPositions, racePositions } = await this.fetcher.fetchRawUserPositions(userPubkey);
109
+ // Build market lookup for current prices
110
+ const marketLookup = new Map();
111
+ for (const { parsed: pos } of booleanPositions) {
112
+ if (pos.claimed)
113
+ continue;
114
+ const marketPda = (0, utils_1.deriveMarketPda)(pos.marketId);
115
+ const marketPdaStr = marketPda.toString();
116
+ if (!marketLookup.has(marketPdaStr)) {
134
117
  try {
135
- const marketInfo = await this.connection.getAccountInfo(marketPda);
136
- if (marketInfo) {
137
- const market = (0, utils_1.parseMarket)(marketInfo.data);
138
- const unified = (0, utils_1.mapBooleanToUnified)(market, marketPda.toString());
139
- currentYesPrice = unified.yes?.price ?? 0;
140
- currentNoPrice = unified.no?.price ?? 0;
141
- marketTitle = market.question;
118
+ const rawMarket = await this.fetcher.fetchRawMarketAccount(marketPda);
119
+ if (rawMarket) {
120
+ const unified = this.normalizer.normalizeMarket(rawMarket);
121
+ if (unified)
122
+ marketLookup.set(marketPdaStr, unified);
142
123
  }
143
124
  }
144
125
  catch {
145
126
  // Use defaults if market fetch fails
146
127
  }
147
- const yesSOL = Number(pos.yesAmount) / utils_1.LAMPORTS_PER_SOL;
148
- const noSOL = Number(pos.noAmount) / utils_1.LAMPORTS_PER_SOL;
149
- if (yesSOL > 0) {
150
- positions.push({
151
- marketId: marketPda.toString(),
152
- outcomeId: `${marketPda.toString()}-YES`,
153
- outcomeLabel: 'Yes',
154
- size: yesSOL,
155
- entryPrice: 0, // Not tracked on-chain for pari-mutuel
156
- currentPrice: currentYesPrice,
157
- unrealizedPnL: 0, // Pari-mutuel doesn't have fixed unrealized P&L
158
- });
159
- }
160
- if (noSOL > 0) {
161
- positions.push({
162
- marketId: marketPda.toString(),
163
- outcomeId: `${marketPda.toString()}-NO`,
164
- outcomeLabel: 'No',
165
- size: noSOL,
166
- entryPrice: 0,
167
- currentPrice: currentNoPrice,
168
- unrealizedPnL: 0,
169
- });
170
- }
171
- }
172
- catch {
173
- // Skip malformed position accounts
174
128
  }
175
129
  }
176
- // Process race positions
177
- for (const account of racePositions) {
178
- try {
179
- const pos = (0, utils_1.parseRacePosition)(account.account.data);
180
- if (pos.claimed)
181
- continue;
182
- const racePda = (0, utils_1.deriveRaceMarketPda)(pos.marketId);
183
- const racePdaStr = racePda.toString();
184
- // Try to fetch the race market to get current prices and labels
185
- let outcomePrices = [];
186
- let outcomeLabels = [];
130
+ for (const { parsed: pos } of racePositions) {
131
+ if (pos.claimed)
132
+ continue;
133
+ const racePda = (0, utils_1.deriveRaceMarketPda)(pos.marketId);
134
+ const racePdaStr = racePda.toString();
135
+ if (!marketLookup.has(racePdaStr)) {
187
136
  try {
188
- const marketInfo = await this.connection.getAccountInfo(racePda);
189
- if (marketInfo) {
190
- const raceMarket = (0, utils_1.parseRaceMarket)(marketInfo.data);
191
- const unified = (0, utils_1.mapRaceToUnified)(raceMarket, racePdaStr);
192
- outcomePrices = unified.outcomes.map(o => o.price);
193
- outcomeLabels = unified.outcomes.map(o => o.label);
137
+ const rawMarket = await this.fetcher.fetchRawMarketAccount(racePda);
138
+ if (rawMarket) {
139
+ const unified = this.normalizer.normalizeMarket(rawMarket);
140
+ if (unified)
141
+ marketLookup.set(racePdaStr, unified);
194
142
  }
195
143
  }
196
144
  catch {
197
145
  // Use defaults if market fetch fails
198
146
  }
199
- for (let i = 0; i < pos.bets.length; i++) {
200
- const betSOL = Number(pos.bets[i]) / utils_1.LAMPORTS_PER_SOL;
201
- if (betSOL <= 0)
202
- continue;
203
- positions.push({
204
- marketId: racePdaStr,
205
- outcomeId: `${racePdaStr}-${i}`,
206
- outcomeLabel: outcomeLabels[i] || `Outcome ${i}`,
207
- size: betSOL,
208
- entryPrice: 0,
209
- currentPrice: outcomePrices[i] ?? 0,
210
- unrealizedPnL: 0,
211
- });
212
- }
213
- }
214
- catch {
215
- // Skip malformed position accounts
216
147
  }
217
148
  }
218
- return positions;
149
+ const boolPos = this.normalizer.normalizeBooleanPositions(booleanPositions, marketLookup);
150
+ const racePos = this.normalizer.normalizeRacePositions(racePositions, marketLookup);
151
+ return [...boolPos, ...racePos];
219
152
  }
220
153
  catch (error) {
221
154
  throw errors_2.baoziErrorMapper.mapError(error);
@@ -257,7 +190,7 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
257
190
  { pubkey: configPda, isSigner: false, isWritable: false },
258
191
  { pubkey: marketPubkey, isSigner: false, isWritable: true },
259
192
  { pubkey: positionPda, isSigner: false, isWritable: true },
260
- { pubkey: utils_1.PROGRAM_ID, isSigner: false, isWritable: false }, // whitelist (optional → pass program ID)
193
+ { pubkey: utils_1.PROGRAM_ID, isSigner: false, isWritable: false },
261
194
  { pubkey: keypair.publicKey, isSigner: true, isWritable: true },
262
195
  { pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
263
196
  ],
@@ -293,7 +226,7 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
293
226
  { pubkey: configPda, isSigner: false, isWritable: false },
294
227
  { pubkey: marketPubkey, isSigner: false, isWritable: true },
295
228
  { pubkey: racePositionPda, isSigner: false, isWritable: true },
296
- { pubkey: utils_1.PROGRAM_ID, isSigner: false, isWritable: false }, // whitelist (optional)
229
+ { pubkey: utils_1.PROGRAM_ID, isSigner: false, isWritable: false },
297
230
  { pubkey: keypair.publicKey, isSigner: true, isWritable: true },
298
231
  { pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
299
232
  ],
@@ -313,10 +246,10 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
313
246
  marketId: params.marketId,
314
247
  outcomeId: params.outcomeId,
315
248
  side: 'buy',
316
- type: 'market', // Pari-mutuel bets are always instant
249
+ type: 'market',
317
250
  price: undefined,
318
251
  amount: params.amount,
319
- status: 'filled', // Pari-mutuel bets fill instantly
252
+ status: 'filled',
320
253
  filled: params.amount,
321
254
  remaining: 0,
322
255
  timestamp: Date.now(),
@@ -330,8 +263,6 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
330
263
  throw new errors_1.InvalidOrder('Pari-mutuel bets are irrevocable and cannot be cancelled', 'Baozi');
331
264
  }
332
265
  async fetchOrder(orderId) {
333
- // In pari-mutuel, there are no pending orders. The "order" is the tx signature.
334
- // We can verify the transaction was confirmed and extract market info.
335
266
  try {
336
267
  const tx = await this.connection.getTransaction(orderId, {
337
268
  maxSupportedTransactionVersion: 0,
@@ -339,7 +270,6 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
339
270
  if (!tx) {
340
271
  throw new Error(`Transaction not found: ${orderId}`);
341
272
  }
342
- // Try to extract market/outcome from the transaction instruction
343
273
  let marketId = '';
344
274
  let outcomeId = '';
345
275
  let amount = 0;
@@ -357,7 +287,6 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
357
287
  const isRaceBet = discriminator.equals(utils_1.BET_ON_RACE_OUTCOME_SOL_DISCRIMINATOR);
358
288
  if (!isBooleanBet && !isRaceBet)
359
289
  continue;
360
- // Account keys[1] is the market PDA for both instruction types
361
290
  const marketKeyIndex = ix.accountKeyIndexes[1];
362
291
  const marketKey = message.staticAccountKeys[marketKeyIndex];
363
292
  marketId = marketKey.toString();
@@ -392,7 +321,7 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
392
321
  }
393
322
  }
394
323
  async fetchOpenOrders() {
395
- // Pari-mutuel bets execute instantly there are never open orders
324
+ // Pari-mutuel bets execute instantly -- there are never open orders
396
325
  return [];
397
326
  }
398
327
  // -----------------------------------------------------------------------
@@ -0,0 +1,14 @@
1
+ import { MarketFetchParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, OrderBook, Position, Balance } from '../../types';
3
+ import { IExchangeNormalizer } from '../interfaces';
4
+ import { BaoziRawMarket, BaoziRawBooleanPosition, BaoziRawRacePosition, BaoziRawBalance } from './fetcher';
5
+ export declare class BaoziNormalizer implements IExchangeNormalizer<BaoziRawMarket, BaoziRawMarket> {
6
+ normalizeMarket(raw: BaoziRawMarket): UnifiedMarket | null;
7
+ normalizeEvent(raw: BaoziRawMarket): UnifiedEvent | null;
8
+ normalizeMarkets(rawMarkets: BaoziRawMarket[], params?: MarketFetchParams): UnifiedMarket[];
9
+ normalizeEvents(rawMarkets: BaoziRawMarket[], params?: MarketFetchParams): UnifiedEvent[];
10
+ normalizeOrderBook(raw: BaoziRawMarket | null, outcomeId: string): OrderBook;
11
+ normalizeBooleanPositions(positions: BaoziRawBooleanPosition[], marketLookup: Map<string, UnifiedMarket>): Position[];
12
+ normalizeRacePositions(positions: BaoziRawRacePosition[], marketLookup: Map<string, UnifiedMarket>): Position[];
13
+ normalizeBalance(raw: BaoziRawBalance): Balance[];
14
+ }