@liberfi.io/react-predict 0.1.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/server.js ADDED
@@ -0,0 +1,795 @@
1
+ 'use strict';
2
+
3
+ require('@tanstack/react-query');
4
+ var react = require('react');
5
+ var utils = require('@liberfi.io/utils');
6
+
7
+ // src/hooks/predict/events.params.ts
8
+ var DEFAULT_PAGE_SIZE = 48;
9
+ function resolveTagSlug(selection) {
10
+ if (!selection) return void 0;
11
+ return selection.tagSlug ?? selection.categorySlug ?? void 0;
12
+ }
13
+ function resolveEventsParams(input = {}) {
14
+ const {
15
+ tagSlugSelection,
16
+ limit = DEFAULT_PAGE_SIZE,
17
+ status = "open",
18
+ with_markets = true,
19
+ source,
20
+ sort_by,
21
+ sort_asc
22
+ } = input;
23
+ const tag_slug = resolveTagSlug(tagSlugSelection);
24
+ return {
25
+ limit,
26
+ status,
27
+ with_markets,
28
+ ...source ? { source } : {},
29
+ ...tag_slug ? { tag_slug } : {},
30
+ ...sort_by ? { sort_by } : {},
31
+ ...sort_asc !== void 0 ? { sort_asc } : {}
32
+ };
33
+ }
34
+ function infiniteEventsQueryKey(params) {
35
+ return ["predict", "events-infinite", params];
36
+ }
37
+ async function fetchEventsPage(client, params) {
38
+ return client.listEvents(params);
39
+ }
40
+ function eventQueryKey(slug, source) {
41
+ return ["predict", "event", slug, source];
42
+ }
43
+ async function fetchEvent(client, slug, source) {
44
+ return client.getEvent(slug, source);
45
+ }
46
+ react.createContext(null);
47
+
48
+ // src/hooks/predict/useMarket.ts
49
+ function marketQueryKey(slug, source) {
50
+ return ["predict", "market", slug, source];
51
+ }
52
+ async function fetchMarket(client, slug, source) {
53
+ return client.getMarket(slug, source);
54
+ }
55
+ function buildQuery(params) {
56
+ const qs = new URLSearchParams();
57
+ for (const [key, value] of Object.entries(params)) {
58
+ if (value !== void 0 && value !== null) {
59
+ qs.set(key, String(value));
60
+ }
61
+ }
62
+ const str = qs.toString();
63
+ return str ? `?${str}` : "";
64
+ }
65
+ var PredictClient = class {
66
+ constructor(endpoint) {
67
+ this.endpoint = endpoint;
68
+ }
69
+ // -------------------------------------------------------------------------
70
+ // Events
71
+ // -------------------------------------------------------------------------
72
+ /**
73
+ * List prediction events with optional filtering, sorting, and pagination.
74
+ *
75
+ * Maps to `GET /api/v1/events`.
76
+ *
77
+ * @param params - Optional query parameters (filter, sort, pagination).
78
+ * @returns A paginated page of events.
79
+ */
80
+ async listEvents(params) {
81
+ const query = buildQuery(params ?? {});
82
+ const url = `${this.endpoint}/api/v1/events${query}`;
83
+ return await utils.httpGet(url);
84
+ }
85
+ /**
86
+ * Fetch a single prediction event by its slug.
87
+ *
88
+ * Maps to `GET /api/v1/events/:slug?source=...`.
89
+ *
90
+ * @param slug - Canonical event slug (e.g. "will-trump-win-2024" for Polymarket
91
+ * or "KXBTCD-25FEB-T68000" for DFlow).
92
+ * @param source - Upstream provider (`"dflow"` or `"polymarket"`).
93
+ * @returns The matching event.
94
+ * @throws When the server responds with 404 or any other non-2xx status.
95
+ */
96
+ async getEvent(slug, source) {
97
+ const query = source ? buildQuery({ source }) : "";
98
+ const url = `${this.endpoint}/api/v1/events/${encodeURIComponent(slug)}${query}`;
99
+ return await utils.httpGet(url);
100
+ }
101
+ /**
102
+ * Fetch events similar to the given slug.
103
+ *
104
+ * Maps to `GET /api/v1/events/:slug/similar?source=...`.
105
+ */
106
+ async getSimilarEvents(slug, source, params) {
107
+ const query = buildQuery({ source, ...params });
108
+ const url = `${this.endpoint}/api/v1/events/${encodeURIComponent(slug)}/similar${query}`;
109
+ return await utils.httpGet(url);
110
+ }
111
+ // -------------------------------------------------------------------------
112
+ // Markets
113
+ // -------------------------------------------------------------------------
114
+ /**
115
+ * Fetch a single prediction market by its slug.
116
+ *
117
+ * Maps to `GET /api/v1/markets/:slug?source=...`.
118
+ *
119
+ * @param slug - Canonical market slug.
120
+ * @param source - Upstream provider (`"dflow"` or `"polymarket"`).
121
+ * @returns The matching market.
122
+ * @throws When the server responds with 404 or any other non-2xx status.
123
+ */
124
+ async getMarket(slug, source) {
125
+ const query = source ? buildQuery({ source }) : "";
126
+ const url = `${this.endpoint}/api/v1/markets/${encodeURIComponent(slug)}${query}`;
127
+ return await utils.httpGet(url);
128
+ }
129
+ /** Maps to `GET /api/v1/markets/:slug/orderbook?source=...`. */
130
+ async getOrderbook(slug, source) {
131
+ const query = buildQuery({ source });
132
+ const url = `${this.endpoint}/api/v1/markets/${encodeURIComponent(slug)}/orderbook${query}`;
133
+ return await utils.httpGet(url);
134
+ }
135
+ /** Maps to `GET /api/v1/markets/:slug/trades?source=...`. */
136
+ async listMarketTrades(slug, params) {
137
+ const query = buildQuery(params);
138
+ const url = `${this.endpoint}/api/v1/markets/${encodeURIComponent(slug)}/trades${query}`;
139
+ return await utils.httpGet(url);
140
+ }
141
+ /** Maps to `GET /api/v1/markets/:slug/price-history?source=...&range=...`. */
142
+ async getPriceHistory(slug, source, range) {
143
+ const query = buildQuery({ source, range });
144
+ const url = `${this.endpoint}/api/v1/markets/${encodeURIComponent(slug)}/price-history${query}`;
145
+ return await utils.httpGet(url);
146
+ }
147
+ /** Maps to `GET /api/v1/markets/:slug/candlesticks?interval=...&limit=...`. */
148
+ async listCandlesticks(slug, params) {
149
+ const query = buildQuery(params ?? {});
150
+ const url = `${this.endpoint}/api/v1/markets/${encodeURIComponent(slug)}/candlesticks${query}`;
151
+ return await utils.httpGet(url);
152
+ }
153
+ // -------------------------------------------------------------------------
154
+ // Positions
155
+ // -------------------------------------------------------------------------
156
+ /**
157
+ * Maps to `GET /api/v1/positions?source=...&user=...`.
158
+ *
159
+ * @param user - Wallet address.
160
+ * @param source - Provider source. Omit to aggregate all providers.
161
+ */
162
+ async getPositions(user, source) {
163
+ const query = buildQuery({ source, user });
164
+ const url = `${this.endpoint}/api/v1/positions${query}`;
165
+ return await utils.httpGet(url);
166
+ }
167
+ // -------------------------------------------------------------------------
168
+ // Balance
169
+ // -------------------------------------------------------------------------
170
+ /**
171
+ * Get the on-chain USDC balance for a wallet.
172
+ *
173
+ * Maps to `GET /api/v1/balance?source=...&user=...`.
174
+ *
175
+ * @param source - Provider source (`"dflow"` for Solana, `"polymarket"` for Polygon).
176
+ * @param user - Wallet address.
177
+ */
178
+ async getBalance(source, user) {
179
+ const query = buildQuery({ source, user });
180
+ const url = `${this.endpoint}/api/v1/balance${query}`;
181
+ return await utils.httpGet(url);
182
+ }
183
+ // -------------------------------------------------------------------------
184
+ // Orders
185
+ // -------------------------------------------------------------------------
186
+ /** Maps to `GET /api/v1/orders?source=...&wallet_address=...`. */
187
+ async listOrders(params) {
188
+ const query = buildQuery(params);
189
+ const url = `${this.endpoint}/api/v1/orders${query}`;
190
+ return await utils.httpGet(url);
191
+ }
192
+ /** Maps to `GET /api/v1/orders/:id?source=...`. */
193
+ async getOrder(id, source) {
194
+ const query = buildQuery({ source });
195
+ const url = `${this.endpoint}/api/v1/orders/${encodeURIComponent(id)}${query}`;
196
+ return await utils.httpGet(url);
197
+ }
198
+ /** Maps to `DELETE /api/v1/orders/:id?source=...`. */
199
+ async cancelOrder(id, source) {
200
+ const query = buildQuery({ source });
201
+ const url = `${this.endpoint}/api/v1/orders/${encodeURIComponent(id)}${query}`;
202
+ return await utils.httpDelete(url);
203
+ }
204
+ // -------------------------------------------------------------------------
205
+ // Polymarket trading
206
+ // -------------------------------------------------------------------------
207
+ /**
208
+ * Create a Polymarket limit order via the prediction-server proxy.
209
+ *
210
+ * Maps to `POST /api/v1/orders/polymarket`.
211
+ *
212
+ * The caller must attach Polymarket CLOB authentication headers:
213
+ * - `POLY_ADDRESS` — the EVM wallet address.
214
+ * - `POLY_SIGNATURE` — L1 signature or L2 API key.
215
+ * - `POLY_TIMESTAMP` — Unix milliseconds string.
216
+ * - `POLY_NONCE` — credential nonce (use `"0"` for in-session derived creds).
217
+ *
218
+ * @param input - Order parameters.
219
+ * @param headers - Polymarket CLOB auth headers (`POLY_*`).
220
+ */
221
+ async createPolymarketOrder(input, headers) {
222
+ const url = `${this.endpoint}/api/v1/orders/polymarket`;
223
+ return await utils.httpPost(url, input, { headers });
224
+ }
225
+ // -------------------------------------------------------------------------
226
+ // DFlow trading
227
+ // -------------------------------------------------------------------------
228
+ /** Maps to `POST /api/v1/orders/dflow/quote`. */
229
+ async createDFlowQuote(body) {
230
+ const url = `${this.endpoint}/api/v1/orders/dflow/quote`;
231
+ return await utils.httpPost(url, body);
232
+ }
233
+ /** Maps to `POST /api/v1/orders/dflow/submit`. */
234
+ async submitDFlowTransaction(body) {
235
+ const url = `${this.endpoint}/api/v1/orders/dflow/submit`;
236
+ return await utils.httpPost(url, body);
237
+ }
238
+ // -------------------------------------------------------------------------
239
+ // Trades by wallet
240
+ // -------------------------------------------------------------------------
241
+ /** Maps to `GET /api/v1/trades?source=...&wallet=...`. */
242
+ async listTrades(params) {
243
+ const query = buildQuery(params);
244
+ const url = `${this.endpoint}/api/v1/trades${query}`;
245
+ return await utils.httpGet(url);
246
+ }
247
+ };
248
+ function createPredictClient(endpoint) {
249
+ return new PredictClient(endpoint);
250
+ }
251
+
252
+ // src/client/ws.ts
253
+ var DEFAULT_RECONNECT_BASE = 1e3;
254
+ var DEFAULT_RECONNECT_MAX = 3e4;
255
+ var DEFAULT_PING_INTERVAL = 2e4;
256
+ var DEFAULT_PONG_TIMEOUT = 1e4;
257
+ var PredictWsClient = class {
258
+ ws = null;
259
+ wsUrl;
260
+ autoReconnect;
261
+ reconnectBase;
262
+ reconnectMax;
263
+ pingMs;
264
+ pongTimeoutMs;
265
+ status = "disconnected";
266
+ reconnectAttempts = 0;
267
+ reconnectTimer = null;
268
+ pingTimer = null;
269
+ pongTimer = null;
270
+ shouldReconnect = true;
271
+ listeners = {
272
+ connect: [],
273
+ disconnect: [],
274
+ reconnecting: [],
275
+ error: [],
276
+ status: [],
277
+ subscribed: [],
278
+ orderbook: [],
279
+ prices: [],
280
+ trades: []
281
+ };
282
+ subs = {
283
+ channels: /* @__PURE__ */ new Map([
284
+ ["orderbook", /* @__PURE__ */ new Set()],
285
+ ["prices", /* @__PURE__ */ new Set()],
286
+ ["trades", /* @__PURE__ */ new Set()]
287
+ ])
288
+ };
289
+ constructor(config) {
290
+ this.wsUrl = config.wsUrl;
291
+ this.autoReconnect = config.autoReconnect ?? true;
292
+ this.reconnectBase = config.reconnectIntervalBase ?? DEFAULT_RECONNECT_BASE;
293
+ this.reconnectMax = config.reconnectMaxInterval ?? DEFAULT_RECONNECT_MAX;
294
+ this.pingMs = config.pingInterval ?? DEFAULT_PING_INTERVAL;
295
+ this.pongTimeoutMs = config.pongTimeout ?? DEFAULT_PONG_TIMEOUT;
296
+ if (config.autoConnect !== false) {
297
+ this.connect();
298
+ }
299
+ }
300
+ // -------------------------------------------------------------------------
301
+ // Connection management
302
+ // -------------------------------------------------------------------------
303
+ connect() {
304
+ if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
305
+ return;
306
+ }
307
+ this.shouldReconnect = true;
308
+ this.setStatus("connecting");
309
+ try {
310
+ this.ws = new WebSocket(this.wsUrl);
311
+ this.ws.onopen = () => {
312
+ this.reconnectAttempts = 0;
313
+ this.setStatus("connected");
314
+ this.emit("connect", void 0);
315
+ this.restoreSubscriptions();
316
+ this.startPing();
317
+ };
318
+ this.ws.onmessage = (event) => {
319
+ this.handleMessage(event.data);
320
+ };
321
+ this.ws.onerror = () => {
322
+ };
323
+ this.ws.onclose = (event) => {
324
+ this.stopPing();
325
+ this.setStatus("disconnected");
326
+ this.emit("disconnect", { code: event.code, reason: event.reason });
327
+ if (this.shouldReconnect && this.autoReconnect) {
328
+ this.scheduleReconnect();
329
+ }
330
+ };
331
+ } catch {
332
+ if (this.shouldReconnect && this.autoReconnect) {
333
+ this.scheduleReconnect();
334
+ }
335
+ }
336
+ }
337
+ disconnect() {
338
+ this.shouldReconnect = false;
339
+ this.stopPing();
340
+ this.clearReconnectTimer();
341
+ if (this.ws) {
342
+ this.ws.close();
343
+ this.ws = null;
344
+ }
345
+ this.setStatus("disconnected");
346
+ }
347
+ /** Disconnect and clear all subscription state and listeners. */
348
+ destroy() {
349
+ this.disconnect();
350
+ for (const ch of this.subs.channels.values()) ch.clear();
351
+ for (const key of Object.keys(this.listeners)) {
352
+ this.listeners[key].length = 0;
353
+ }
354
+ }
355
+ getStatus() {
356
+ return this.status;
357
+ }
358
+ isConnected() {
359
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
360
+ }
361
+ // -------------------------------------------------------------------------
362
+ // Subscription — low-level (multi-channel, multi-slug)
363
+ // -------------------------------------------------------------------------
364
+ /**
365
+ * Subscribe to one or more channels for the given market slugs.
366
+ * The server acknowledges with a `subscribed` message.
367
+ */
368
+ subscribe(channels, marketSlugs) {
369
+ for (const ch of channels) {
370
+ const set = this.subs.channels.get(ch);
371
+ for (const slug of marketSlugs) set.add(slug);
372
+ }
373
+ this.send({ type: "subscribe", channels, market_slugs: marketSlugs });
374
+ }
375
+ /**
376
+ * Unsubscribe from one or more channels for the given market slugs.
377
+ */
378
+ unsubscribe(channels, marketSlugs) {
379
+ for (const ch of channels) {
380
+ const set = this.subs.channels.get(ch);
381
+ for (const slug of marketSlugs) set.delete(slug);
382
+ }
383
+ this.send({ type: "unsubscribe", channels, market_slugs: marketSlugs });
384
+ }
385
+ // -------------------------------------------------------------------------
386
+ // Subscription — convenience (single channel)
387
+ // -------------------------------------------------------------------------
388
+ /**
389
+ * Subscribe to price updates for the given slugs.
390
+ * Returns an unsubscribe function.
391
+ */
392
+ subscribePrices(slugs, onUpdate) {
393
+ this.subscribe(["prices"], slugs);
394
+ const off = this.on("prices", onUpdate);
395
+ return () => {
396
+ off();
397
+ this.unsubscribe(["prices"], slugs);
398
+ };
399
+ }
400
+ /**
401
+ * Subscribe to orderbook snapshots for the given slugs.
402
+ * Returns an unsubscribe function.
403
+ */
404
+ subscribeOrderbook(slugs, onUpdate) {
405
+ this.subscribe(["orderbook"], slugs);
406
+ const off = this.on("orderbook", onUpdate);
407
+ return () => {
408
+ off();
409
+ this.unsubscribe(["orderbook"], slugs);
410
+ };
411
+ }
412
+ /**
413
+ * Subscribe to trade events for the given slugs.
414
+ * Returns an unsubscribe function.
415
+ */
416
+ subscribeTrades(slugs, onUpdate) {
417
+ this.subscribe(["trades"], slugs);
418
+ const off = this.on("trades", onUpdate);
419
+ return () => {
420
+ off();
421
+ this.unsubscribe(["trades"], slugs);
422
+ };
423
+ }
424
+ // -------------------------------------------------------------------------
425
+ // Status observation
426
+ // -------------------------------------------------------------------------
427
+ /** Register a callback for connection status changes. Returns unsubscribe. */
428
+ onStatusChange(cb) {
429
+ return this.on("status", cb);
430
+ }
431
+ /** Register a callback for server-sent errors. Returns unsubscribe. */
432
+ onError(cb) {
433
+ return this.on("error", cb);
434
+ }
435
+ // -------------------------------------------------------------------------
436
+ // Event emitter
437
+ // -------------------------------------------------------------------------
438
+ on(event, callback) {
439
+ const list = this.listeners[event];
440
+ list.push(callback);
441
+ return () => this.off(event, callback);
442
+ }
443
+ off(event, callback) {
444
+ const list = this.listeners[event];
445
+ const idx = list.indexOf(callback);
446
+ if (idx !== -1) list.splice(idx, 1);
447
+ }
448
+ // -------------------------------------------------------------------------
449
+ // Private
450
+ // -------------------------------------------------------------------------
451
+ emit(event, data) {
452
+ const list = this.listeners[event];
453
+ for (const cb of list) {
454
+ try {
455
+ cb(data);
456
+ } catch (e) {
457
+ }
458
+ }
459
+ }
460
+ send(msg) {
461
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;
462
+ try {
463
+ this.ws.send(JSON.stringify(msg));
464
+ return true;
465
+ } catch {
466
+ return false;
467
+ }
468
+ }
469
+ setStatus(next) {
470
+ if (this.status !== next) {
471
+ this.status = next;
472
+ this.emit("status", next);
473
+ }
474
+ }
475
+ handleMessage(raw) {
476
+ let msg;
477
+ try {
478
+ msg = JSON.parse(raw);
479
+ } catch {
480
+ return;
481
+ }
482
+ if (msg.type) {
483
+ switch (msg.type) {
484
+ case "pong":
485
+ this.clearPongTimer();
486
+ return;
487
+ case "subscribed":
488
+ this.emit("subscribed", {
489
+ channels: msg.channels,
490
+ market_slugs: msg.market_slugs
491
+ });
492
+ return;
493
+ case "error":
494
+ this.emit("error", {
495
+ code: msg.code,
496
+ message: msg.message
497
+ });
498
+ return;
499
+ }
500
+ }
501
+ if (msg.channel && msg.data) {
502
+ const dataMsg = msg;
503
+ switch (dataMsg.channel) {
504
+ case "orderbook":
505
+ this.emit("orderbook", dataMsg);
506
+ break;
507
+ case "prices":
508
+ this.emit("prices", dataMsg);
509
+ break;
510
+ case "trades":
511
+ this.emit("trades", dataMsg);
512
+ break;
513
+ }
514
+ }
515
+ }
516
+ scheduleReconnect() {
517
+ if (this.reconnectTimer) return;
518
+ const delay = Math.min(
519
+ this.reconnectBase * Math.pow(2, this.reconnectAttempts),
520
+ this.reconnectMax
521
+ );
522
+ this.setStatus("reconnecting");
523
+ this.emit("reconnecting", { attempt: this.reconnectAttempts + 1, delay });
524
+ this.reconnectTimer = setTimeout(() => {
525
+ this.reconnectTimer = null;
526
+ this.reconnectAttempts++;
527
+ this.connect();
528
+ }, delay);
529
+ }
530
+ clearReconnectTimer() {
531
+ if (this.reconnectTimer) {
532
+ clearTimeout(this.reconnectTimer);
533
+ this.reconnectTimer = null;
534
+ }
535
+ }
536
+ restoreSubscriptions() {
537
+ for (const [channel, slugs] of this.subs.channels.entries()) {
538
+ if (slugs.size > 0) {
539
+ this.send({
540
+ type: "subscribe",
541
+ channels: [channel],
542
+ market_slugs: Array.from(slugs)
543
+ });
544
+ }
545
+ }
546
+ }
547
+ startPing() {
548
+ this.stopPing();
549
+ this.pingTimer = setInterval(() => {
550
+ this.send({ type: "ping" });
551
+ this.armPongTimeout();
552
+ }, this.pingMs);
553
+ }
554
+ stopPing() {
555
+ if (this.pingTimer) {
556
+ clearInterval(this.pingTimer);
557
+ this.pingTimer = null;
558
+ }
559
+ this.clearPongTimer();
560
+ }
561
+ /**
562
+ * Start a timer that fires if the server does not reply with pong
563
+ * within `pongTimeoutMs`. On timeout the socket is closed so
564
+ * the normal reconnect flow kicks in.
565
+ */
566
+ armPongTimeout() {
567
+ this.clearPongTimer();
568
+ this.pongTimer = setTimeout(() => {
569
+ this.pongTimer = null;
570
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
571
+ this.ws.close(4e3, "pong timeout");
572
+ }
573
+ }, this.pongTimeoutMs);
574
+ }
575
+ clearPongTimer() {
576
+ if (this.pongTimer) {
577
+ clearTimeout(this.pongTimer);
578
+ this.pongTimer = null;
579
+ }
580
+ }
581
+ };
582
+ function createPredictWsClient(config) {
583
+ return new PredictWsClient(config);
584
+ }
585
+
586
+ // src/utils/polymarket-hmac.ts
587
+ function encode(str) {
588
+ return new TextEncoder().encode(str);
589
+ }
590
+ function base64ToBytes(b64) {
591
+ const binary = atob(b64);
592
+ const bytes = new Uint8Array(binary.length);
593
+ for (let i = 0; i < binary.length; i++) {
594
+ bytes[i] = binary.charCodeAt(i);
595
+ }
596
+ return bytes;
597
+ }
598
+ function bytesToBase64(bytes) {
599
+ let binary = "";
600
+ for (let i = 0; i < bytes.byteLength; i++) {
601
+ binary += String.fromCharCode(bytes[i]);
602
+ }
603
+ return btoa(binary);
604
+ }
605
+ async function hmacSha256Base64(secretBase64, message) {
606
+ const keyBytes = base64ToBytes(secretBase64);
607
+ const cryptoKey = await crypto.subtle.importKey(
608
+ "raw",
609
+ keyBytes.buffer,
610
+ { name: "HMAC", hash: "SHA-256" },
611
+ false,
612
+ ["sign"]
613
+ );
614
+ const msgBytes = encode(message);
615
+ const signature = await crypto.subtle.sign(
616
+ "HMAC",
617
+ cryptoKey,
618
+ msgBytes.buffer
619
+ );
620
+ return bytesToBase64(new Uint8Array(signature));
621
+ }
622
+ async function buildPolymarketL2Headers(address, input) {
623
+ const timestamp = Math.floor(Date.now() / 1e3).toString();
624
+ const body = input.body ?? "";
625
+ const message = `${timestamp}${input.method}${input.requestPath}${body}`;
626
+ const signature = await hmacSha256Base64(input.secret, message);
627
+ return {
628
+ POLY_ADDRESS: address,
629
+ POLY_SIGNATURE: signature,
630
+ POLY_TIMESTAMP: timestamp,
631
+ POLY_API_KEY: input.apiKey,
632
+ POLY_PASSPHRASE: input.passphrase
633
+ };
634
+ }
635
+ var CLOB_AUTH_DOMAIN = {
636
+ name: "ClobAuthDomain",
637
+ version: "1",
638
+ chainId: 137
639
+ };
640
+ var CLOB_AUTH_TYPES = {
641
+ ClobAuth: [
642
+ { name: "address", type: "address" },
643
+ { name: "timestamp", type: "string" },
644
+ { name: "nonce", type: "uint256" },
645
+ { name: "message", type: "string" }
646
+ ]
647
+ };
648
+ function buildClobAuthMessage(input) {
649
+ return {
650
+ address: input.address,
651
+ timestamp: input.timestamp,
652
+ nonce: input.nonce,
653
+ message: "This message attests that I control the given wallet"
654
+ };
655
+ }
656
+ async function derivePolymarketApiKey(address, signature, timestamp, nonce) {
657
+ const res = await fetch(
658
+ `https://clob.polymarket.com/auth/derive-api-key?nonce=${nonce}`,
659
+ {
660
+ method: "GET",
661
+ headers: {
662
+ "Content-Type": "application/json",
663
+ POLY_ADDRESS: address,
664
+ POLY_SIGNATURE: signature,
665
+ POLY_TIMESTAMP: timestamp,
666
+ POLY_NONCE: String(nonce)
667
+ }
668
+ }
669
+ );
670
+ if (!res.ok) {
671
+ const text = await res.text().catch(() => res.statusText);
672
+ throw new Error(
673
+ `Polymarket credential exchange failed (${res.status}): ${text}`
674
+ );
675
+ }
676
+ return res.json();
677
+ }
678
+
679
+ // src/utils/polymarket-order.ts
680
+ var CTF_EXCHANGE_ADDRESS = "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E";
681
+ var NEG_RISK_CTF_EXCHANGE_ADDRESS = "0xC5d563A36AE78145C45a50134d48A1215220f80a";
682
+ var USDC_ADDRESS = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
683
+ var POLYGON_CHAIN_ID = 137;
684
+ function buildCtfExchangeDomain(negRisk = false) {
685
+ return {
686
+ name: "CTFExchange",
687
+ version: "1",
688
+ chainId: POLYGON_CHAIN_ID,
689
+ verifyingContract: negRisk ? NEG_RISK_CTF_EXCHANGE_ADDRESS : CTF_EXCHANGE_ADDRESS
690
+ };
691
+ }
692
+ var CTF_ORDER_TYPES = {
693
+ Order: [
694
+ { name: "salt", type: "uint256" },
695
+ { name: "maker", type: "address" },
696
+ { name: "signer", type: "address" },
697
+ { name: "taker", type: "address" },
698
+ { name: "tokenId", type: "uint256" },
699
+ { name: "makerAmount", type: "uint256" },
700
+ { name: "takerAmount", type: "uint256" },
701
+ { name: "expiration", type: "uint256" },
702
+ { name: "nonce", type: "uint256" },
703
+ { name: "feeRateBps", type: "uint256" },
704
+ { name: "side", type: "uint8" },
705
+ { name: "signatureType", type: "uint8" }
706
+ ]
707
+ };
708
+ var ORDER_TYPE = {
709
+ GTC: 0,
710
+ // Good-Till-Cancelled
711
+ FOK: 1,
712
+ // Fill-Or-Kill
713
+ GTD: 2,
714
+ // Good-Till-Date
715
+ FAK: 3
716
+ // Fill-And-Kill
717
+ };
718
+ var SIDE = { BUY: 0, SELL: 1 };
719
+ var TICK_DECIMALS = {
720
+ "0.1": 1,
721
+ "0.01": 2,
722
+ "0.001": 3,
723
+ "0.0001": 4
724
+ };
725
+ function roundToTick(price, tickSize) {
726
+ const decimals = TICK_DECIMALS[tickSize] ?? 2;
727
+ return price.toFixed(decimals);
728
+ }
729
+ function toMicroUsdc(amount) {
730
+ return BigInt(Math.round(amount * 1e6));
731
+ }
732
+ function buildOrderMessage(input) {
733
+ const side = input.side === "BUY" ? SIDE.BUY : SIDE.SELL;
734
+ const priceStr = roundToTick(input.price, input.tickSize);
735
+ const priceNum = parseFloat(priceStr);
736
+ const sizeShares = toMicroUsdc(input.size);
737
+ const sizeUsdc = toMicroUsdc(input.size * priceNum);
738
+ const makerAmount = side === SIDE.BUY ? sizeUsdc.toString() : sizeShares.toString();
739
+ const takerAmount = side === SIDE.BUY ? sizeShares.toString() : sizeUsdc.toString();
740
+ const maker = input.funderAddress ?? input.signerAddress;
741
+ return {
742
+ salt: Math.floor(Math.random() * 1e15).toString(),
743
+ maker,
744
+ signer: input.signerAddress,
745
+ taker: "0x0000000000000000000000000000000000000000",
746
+ tokenId: input.tokenId,
747
+ makerAmount,
748
+ takerAmount,
749
+ expiration: String(input.expiration ?? 0),
750
+ nonce: "0",
751
+ feeRateBps: "0",
752
+ side,
753
+ signatureType: input.signatureType
754
+ };
755
+ }
756
+ function buildSignedOrder(input) {
757
+ const message = buildOrderMessage(input);
758
+ return {
759
+ ...message,
760
+ signature: input.signature,
761
+ orderType: input.orderType ?? "GTC"
762
+ };
763
+ }
764
+
765
+ exports.CLOB_AUTH_DOMAIN = CLOB_AUTH_DOMAIN;
766
+ exports.CLOB_AUTH_TYPES = CLOB_AUTH_TYPES;
767
+ exports.CTF_EXCHANGE_ADDRESS = CTF_EXCHANGE_ADDRESS;
768
+ exports.CTF_ORDER_TYPES = CTF_ORDER_TYPES;
769
+ exports.DEFAULT_PAGE_SIZE = DEFAULT_PAGE_SIZE;
770
+ exports.NEG_RISK_CTF_EXCHANGE_ADDRESS = NEG_RISK_CTF_EXCHANGE_ADDRESS;
771
+ exports.ORDER_TYPE = ORDER_TYPE;
772
+ exports.POLYGON_CHAIN_ID = POLYGON_CHAIN_ID;
773
+ exports.PredictClient = PredictClient;
774
+ exports.PredictWsClient = PredictWsClient;
775
+ exports.SIDE = SIDE;
776
+ exports.USDC_ADDRESS = USDC_ADDRESS;
777
+ exports.buildClobAuthMessage = buildClobAuthMessage;
778
+ exports.buildCtfExchangeDomain = buildCtfExchangeDomain;
779
+ exports.buildOrderMessage = buildOrderMessage;
780
+ exports.buildPolymarketL2Headers = buildPolymarketL2Headers;
781
+ exports.buildSignedOrder = buildSignedOrder;
782
+ exports.createPredictClient = createPredictClient;
783
+ exports.createPredictWsClient = createPredictWsClient;
784
+ exports.derivePolymarketApiKey = derivePolymarketApiKey;
785
+ exports.eventQueryKey = eventQueryKey;
786
+ exports.fetchEvent = fetchEvent;
787
+ exports.fetchEventsPage = fetchEventsPage;
788
+ exports.fetchMarket = fetchMarket;
789
+ exports.hmacSha256Base64 = hmacSha256Base64;
790
+ exports.infiniteEventsQueryKey = infiniteEventsQueryKey;
791
+ exports.marketQueryKey = marketQueryKey;
792
+ exports.resolveEventsParams = resolveEventsParams;
793
+ exports.resolveTagSlug = resolveTagSlug;
794
+ //# sourceMappingURL=server.js.map
795
+ //# sourceMappingURL=server.js.map