context-markets 0.4.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/index.cjs ADDED
@@ -0,0 +1,1262 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ API_BASE: () => API_BASE,
24
+ CHAIN_ID: () => CHAIN_ID,
25
+ ContextApiError: () => ContextApiError,
26
+ ContextClient: () => ContextClient,
27
+ ContextConfigError: () => ContextConfigError,
28
+ ContextSigningError: () => ContextSigningError,
29
+ ENDPOINTS: () => ENDPOINTS,
30
+ HOLDINGS_ADDRESS: () => HOLDINGS_ADDRESS,
31
+ HOLDINGS_EIP712_DOMAIN: () => HOLDINGS_EIP712_DOMAIN,
32
+ PERMIT2_ADDRESS: () => PERMIT2_ADDRESS,
33
+ PERMIT2_EIP712_DOMAIN: () => PERMIT2_EIP712_DOMAIN,
34
+ SETTLEMENT_ADDRESS: () => SETTLEMENT_ADDRESS,
35
+ USDC_ADDRESS: () => USDC_ADDRESS,
36
+ calculateMaxFee: () => calculateMaxFee,
37
+ decodePriceCents: () => decodePriceCents,
38
+ decodeSize: () => decodeSize,
39
+ encodePriceCents: () => encodePriceCents,
40
+ encodeSize: () => encodeSize
41
+ });
42
+ module.exports = __toCommonJS(index_exports);
43
+
44
+ // src/config.ts
45
+ var API_BASE = "https://api-testnet.context.markets/v2";
46
+ var SETTLEMENT_ADDRESS = "0xD91935a82Af48ff79a68134d9Eab8fc9e5d3504D";
47
+ var HOLDINGS_ADDRESS = "0x0a6D61723E8AE8e34734A84075a1b58aB3eEca6a";
48
+ var USDC_ADDRESS = "0xBbee2756d3169CF7065e5E9C4A5EA9b1D1Fd415e";
49
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
50
+ var CHAIN_ID = 84532;
51
+ var EIP712_DOMAIN = {
52
+ name: "Settlement",
53
+ version: "1",
54
+ chainId: CHAIN_ID,
55
+ verifyingContract: SETTLEMENT_ADDRESS
56
+ };
57
+ var ORDER_TYPES = {
58
+ Order: [
59
+ { name: "marketId", type: "bytes32" },
60
+ { name: "trader", type: "address" },
61
+ { name: "price", type: "uint256" },
62
+ { name: "size", type: "uint256" },
63
+ { name: "outcomeIndex", type: "uint8" },
64
+ { name: "side", type: "uint8" },
65
+ { name: "nonce", type: "bytes32" },
66
+ { name: "expiry", type: "uint256" },
67
+ { name: "maxFee", type: "uint256" },
68
+ { name: "makerRoleConstraint", type: "uint8" },
69
+ { name: "inventoryModeConstraint", type: "uint8" }
70
+ ]
71
+ };
72
+ var MARKET_ORDER_INTENT_TYPES = {
73
+ MarketOrderIntent: [
74
+ { name: "marketId", type: "bytes32" },
75
+ { name: "trader", type: "address" },
76
+ { name: "maxSize", type: "uint256" },
77
+ { name: "maxPrice", type: "uint256" },
78
+ { name: "outcomeIndex", type: "uint8" },
79
+ { name: "side", type: "uint8" },
80
+ { name: "nonce", type: "bytes32" },
81
+ { name: "expiry", type: "uint256" },
82
+ { name: "maxFee", type: "uint256" }
83
+ ]
84
+ };
85
+ var CANCEL_TYPES = {
86
+ CancelNonce: [
87
+ { name: "trader", type: "address" },
88
+ { name: "nonce", type: "bytes32" }
89
+ ]
90
+ };
91
+ var HOLDINGS_EIP712_DOMAIN = {
92
+ name: "Holdings",
93
+ version: "1",
94
+ chainId: CHAIN_ID,
95
+ verifyingContract: HOLDINGS_ADDRESS
96
+ };
97
+ var PERMIT2_EIP712_DOMAIN = {
98
+ name: "Permit2",
99
+ chainId: CHAIN_ID,
100
+ verifyingContract: PERMIT2_ADDRESS
101
+ };
102
+ var OPERATOR_APPROVAL_TYPES = {
103
+ OperatorApproval: [
104
+ { name: "user", type: "address" },
105
+ { name: "operator", type: "address" },
106
+ { name: "approved", type: "bool" },
107
+ { name: "nonce", type: "uint256" },
108
+ { name: "deadline", type: "uint256" }
109
+ ]
110
+ };
111
+ var PERMIT_TRANSFER_FROM_TYPES = {
112
+ TokenPermissions: [
113
+ { name: "token", type: "address" },
114
+ { name: "amount", type: "uint256" }
115
+ ],
116
+ PermitTransferFrom: [
117
+ { name: "permitted", type: "TokenPermissions" },
118
+ { name: "spender", type: "address" },
119
+ { name: "nonce", type: "uint256" },
120
+ { name: "deadline", type: "uint256" }
121
+ ]
122
+ };
123
+ var ERC20_ABI = [
124
+ {
125
+ name: "approve",
126
+ type: "function",
127
+ stateMutability: "nonpayable",
128
+ inputs: [
129
+ { name: "spender", type: "address" },
130
+ { name: "amount", type: "uint256" }
131
+ ],
132
+ outputs: [{ name: "", type: "bool" }]
133
+ },
134
+ {
135
+ name: "allowance",
136
+ type: "function",
137
+ stateMutability: "view",
138
+ inputs: [
139
+ { name: "owner", type: "address" },
140
+ { name: "spender", type: "address" }
141
+ ],
142
+ outputs: [{ name: "", type: "uint256" }]
143
+ }
144
+ ];
145
+ var HOLDINGS_ABI = [
146
+ {
147
+ name: "balanceOf",
148
+ type: "function",
149
+ stateMutability: "view",
150
+ inputs: [
151
+ { name: "user", type: "address" },
152
+ { name: "token", type: "address" }
153
+ ],
154
+ outputs: [{ name: "", type: "uint256" }]
155
+ },
156
+ {
157
+ name: "setOperator",
158
+ type: "function",
159
+ stateMutability: "nonpayable",
160
+ inputs: [
161
+ { name: "operator", type: "address" },
162
+ { name: "approved", type: "bool" }
163
+ ],
164
+ outputs: []
165
+ },
166
+ {
167
+ name: "isOperatorFor",
168
+ type: "function",
169
+ stateMutability: "view",
170
+ inputs: [
171
+ { name: "owner", type: "address" },
172
+ { name: "operator", type: "address" }
173
+ ],
174
+ outputs: [{ name: "", type: "bool" }]
175
+ },
176
+ {
177
+ name: "deposit",
178
+ type: "function",
179
+ stateMutability: "nonpayable",
180
+ inputs: [
181
+ { name: "token", type: "address" },
182
+ { name: "amount", type: "uint256" }
183
+ ],
184
+ outputs: []
185
+ },
186
+ {
187
+ name: "withdraw",
188
+ type: "function",
189
+ stateMutability: "nonpayable",
190
+ inputs: [
191
+ { name: "token", type: "address" },
192
+ { name: "amount", type: "uint256" }
193
+ ],
194
+ outputs: []
195
+ }
196
+ ];
197
+ var SETTLEMENT_ABI = [
198
+ {
199
+ name: "mintCompleteSetsFromHoldings",
200
+ type: "function",
201
+ stateMutability: "nonpayable",
202
+ inputs: [
203
+ { name: "marketId", type: "bytes32" },
204
+ { name: "amount", type: "uint256" }
205
+ ],
206
+ outputs: []
207
+ },
208
+ {
209
+ name: "burnCompleteSetsFromHoldings",
210
+ type: "function",
211
+ stateMutability: "nonpayable",
212
+ inputs: [
213
+ { name: "marketId", type: "bytes32" },
214
+ { name: "amount", type: "uint256" },
215
+ { name: "recipient", type: "address" },
216
+ { name: "creditInternal", type: "bool" }
217
+ ],
218
+ outputs: []
219
+ }
220
+ ];
221
+ var OPERATOR_NONCE_ABI = [
222
+ {
223
+ name: "operatorNonce",
224
+ type: "function",
225
+ stateMutability: "view",
226
+ inputs: [{ name: "user", type: "address" }],
227
+ outputs: [{ name: "", type: "uint256" }]
228
+ }
229
+ ];
230
+
231
+ // src/errors.ts
232
+ var ContextApiError = class extends Error {
233
+ status;
234
+ body;
235
+ constructor(status, body) {
236
+ const message = typeof body === "object" && body !== null && "message" in body ? String(body.message) : `API request failed with status ${status}`;
237
+ super(message);
238
+ this.name = "ContextApiError";
239
+ this.status = status;
240
+ this.body = body;
241
+ }
242
+ };
243
+ var ContextSigningError = class extends Error {
244
+ constructor(message, cause) {
245
+ super(message);
246
+ this.name = "ContextSigningError";
247
+ if (cause) this.cause = cause;
248
+ }
249
+ };
250
+ var ContextConfigError = class extends Error {
251
+ constructor(message) {
252
+ super(message);
253
+ this.name = "ContextConfigError";
254
+ }
255
+ };
256
+
257
+ // src/http.ts
258
+ function createHttpClient(options = {}) {
259
+ const apiKey = options.apiKey;
260
+ const baseUrl = options.baseUrl ?? API_BASE;
261
+ const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
262
+ function headers() {
263
+ const h = {
264
+ "Content-Type": "application/json"
265
+ };
266
+ if (apiKey) {
267
+ h["Authorization"] = `Bearer ${apiKey}`;
268
+ }
269
+ return h;
270
+ }
271
+ async function request(method, url, body) {
272
+ const init = { method, headers: headers() };
273
+ if (body !== void 0) {
274
+ init.body = JSON.stringify(body);
275
+ }
276
+ const res = await fetchFn(url, init);
277
+ if (!res.ok) {
278
+ const respBody = await res.json().catch(() => null);
279
+ throw new ContextApiError(res.status, respBody);
280
+ }
281
+ return res.json();
282
+ }
283
+ return {
284
+ async get(path, params) {
285
+ let url = `${baseUrl}${path}`;
286
+ if (params) {
287
+ const searchParams = [];
288
+ for (const [k, v] of Object.entries(params)) {
289
+ if (v !== void 0) {
290
+ searchParams.push(
291
+ `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`
292
+ );
293
+ }
294
+ }
295
+ if (searchParams.length > 0) {
296
+ url += `?${searchParams.join("&")}`;
297
+ }
298
+ }
299
+ return request("GET", url);
300
+ },
301
+ async post(path, body) {
302
+ return request("POST", `${baseUrl}${path}`, body);
303
+ },
304
+ async delete(path, body) {
305
+ return request("DELETE", `${baseUrl}${path}`, body);
306
+ }
307
+ };
308
+ }
309
+
310
+ // src/signing/eip712.ts
311
+ var import_viem = require("viem");
312
+ var import_accounts = require("viem/accounts");
313
+ var import_chains = require("viem/chains");
314
+ function resolveSigner(input) {
315
+ if ("privateKey" in input) {
316
+ const account = (0, import_accounts.privateKeyToAccount)(input.privateKey);
317
+ const walletClient = (0, import_viem.createWalletClient)({
318
+ account,
319
+ chain: import_chains.baseSepolia,
320
+ transport: (0, import_viem.http)()
321
+ });
322
+ return { account, walletClient };
323
+ }
324
+ if ("account" in input) {
325
+ const walletClient = (0, import_viem.createWalletClient)({
326
+ account: input.account,
327
+ chain: import_chains.baseSepolia,
328
+ transport: (0, import_viem.http)()
329
+ });
330
+ return { account: input.account, walletClient };
331
+ }
332
+ if ("walletClient" in input) {
333
+ const account = input.walletClient.account;
334
+ if (!account) {
335
+ throw new ContextSigningError(
336
+ "WalletClient must have an account configured"
337
+ );
338
+ }
339
+ return { account, walletClient: input.walletClient };
340
+ }
341
+ throw new ContextSigningError("Invalid signer input");
342
+ }
343
+ function randomNonce() {
344
+ return (0, import_viem.keccak256)((0, import_viem.toBytes)(`${Date.now()}_${Math.random()}`));
345
+ }
346
+ async function signOrder(walletClient, account, order) {
347
+ try {
348
+ return await walletClient.signTypedData({
349
+ account,
350
+ domain: EIP712_DOMAIN,
351
+ types: ORDER_TYPES,
352
+ primaryType: "Order",
353
+ message: order
354
+ });
355
+ } catch (err) {
356
+ throw new ContextSigningError("Failed to sign order", err);
357
+ }
358
+ }
359
+ async function signMarketOrderIntent(walletClient, account, intent) {
360
+ try {
361
+ return await walletClient.signTypedData({
362
+ account,
363
+ domain: EIP712_DOMAIN,
364
+ types: MARKET_ORDER_INTENT_TYPES,
365
+ primaryType: "MarketOrderIntent",
366
+ message: intent
367
+ });
368
+ } catch (err) {
369
+ throw new ContextSigningError("Failed to sign market order intent", err);
370
+ }
371
+ }
372
+ async function signCancel(walletClient, account, trader, nonce) {
373
+ try {
374
+ return await walletClient.signTypedData({
375
+ account,
376
+ domain: EIP712_DOMAIN,
377
+ types: CANCEL_TYPES,
378
+ primaryType: "CancelNonce",
379
+ message: { trader, nonce }
380
+ });
381
+ } catch (err) {
382
+ throw new ContextSigningError("Failed to sign cancel", err);
383
+ }
384
+ }
385
+
386
+ // src/constants.ts
387
+ var PRICE_MULTIPLIER = 10000n;
388
+ var SIZE_MULTIPLIER = 1000000n;
389
+ var FEE_DIVISOR = 100n;
390
+ var DEFAULT_EXPIRY_SECONDS = 31536e3;
391
+
392
+ // src/order-builder/helpers.ts
393
+ function encodePriceCents(priceCents) {
394
+ if (!Number.isFinite(priceCents) || priceCents < 1 || priceCents > 99) {
395
+ throw new RangeError(`priceCents must be 1-99, got ${priceCents}`);
396
+ }
397
+ return BigInt(Math.round(priceCents * Number(PRICE_MULTIPLIER)));
398
+ }
399
+ function encodeSize(size) {
400
+ if (!Number.isFinite(size) || size < 0.01) {
401
+ throw new RangeError(`size must be >= 0.01, got ${size}`);
402
+ }
403
+ return BigInt(Math.round(size * Number(SIZE_MULTIPLIER)));
404
+ }
405
+ function calculateMaxFee(price, size) {
406
+ const fee = price * size / FEE_DIVISOR / SIZE_MULTIPLIER;
407
+ return fee < 1n ? 1n : fee;
408
+ }
409
+ function decodePriceCents(raw) {
410
+ return Number(raw) / Number(PRICE_MULTIPLIER);
411
+ }
412
+ function decodeSize(raw) {
413
+ return Number(raw) / Number(SIZE_MULTIPLIER);
414
+ }
415
+
416
+ // src/order-builder/builder.ts
417
+ var OrderBuilder = class {
418
+ constructor(walletClient, account) {
419
+ this.walletClient = walletClient;
420
+ this.account = account;
421
+ }
422
+ get address() {
423
+ return this.account.address;
424
+ }
425
+ async buildAndSign(req) {
426
+ const price = encodePriceCents(req.priceCents);
427
+ const size = encodeSize(req.size);
428
+ const maxFee = calculateMaxFee(price, size);
429
+ const nonce = randomNonce();
430
+ const expirySeconds = req.expirySeconds ?? DEFAULT_EXPIRY_SECONDS;
431
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + expirySeconds);
432
+ const order = {
433
+ marketId: req.marketId,
434
+ trader: this.address,
435
+ price,
436
+ size,
437
+ outcomeIndex: req.outcome === "yes" ? 1 : 0,
438
+ side: req.side === "buy" ? 0 : 1,
439
+ nonce,
440
+ expiry,
441
+ maxFee,
442
+ makerRoleConstraint: req.makerRoleConstraint ?? 0,
443
+ inventoryModeConstraint: req.inventoryModeConstraint ?? 0
444
+ };
445
+ const signature = await signOrder(this.walletClient, this.account, order);
446
+ return {
447
+ type: "limit",
448
+ ...order,
449
+ price: order.price.toString(),
450
+ size: order.size.toString(),
451
+ expiry: order.expiry.toString(),
452
+ maxFee: order.maxFee.toString(),
453
+ signature
454
+ };
455
+ }
456
+ async buildAndSignMarket(req) {
457
+ const maxPrice = encodePriceCents(req.maxPriceCents);
458
+ const maxSize = encodeSize(req.maxSize);
459
+ const maxFee = calculateMaxFee(maxPrice, maxSize);
460
+ const nonce = randomNonce();
461
+ const expirySeconds = req.expirySeconds ?? DEFAULT_EXPIRY_SECONDS;
462
+ const expiry = BigInt(Math.floor(Date.now() / 1e3) + expirySeconds);
463
+ const intent = {
464
+ marketId: req.marketId,
465
+ trader: this.address,
466
+ maxPrice,
467
+ maxSize,
468
+ outcomeIndex: req.outcome === "yes" ? 1 : 0,
469
+ side: req.side === "buy" ? 0 : 1,
470
+ nonce,
471
+ expiry,
472
+ maxFee
473
+ };
474
+ const signature = await signMarketOrderIntent(
475
+ this.walletClient,
476
+ this.account,
477
+ intent
478
+ );
479
+ return {
480
+ type: "market",
481
+ ...intent,
482
+ maxPrice: intent.maxPrice.toString(),
483
+ maxSize: intent.maxSize.toString(),
484
+ expiry: intent.expiry.toString(),
485
+ maxFee: intent.maxFee.toString(),
486
+ signature
487
+ };
488
+ }
489
+ async signCancel(nonce) {
490
+ return signCancel(
491
+ this.walletClient,
492
+ this.account,
493
+ this.address,
494
+ nonce
495
+ );
496
+ }
497
+ };
498
+
499
+ // src/generated/endpoints.ts
500
+ var ENDPOINTS = {
501
+ activity: {
502
+ global: "/activity"
503
+ },
504
+ markets: {
505
+ list: "/markets",
506
+ search: "/markets/search",
507
+ create: "/markets/create",
508
+ get: (id) => `/markets/${id}`,
509
+ activity: (id) => `/markets/${id}/activity`,
510
+ oracle: (id) => `/markets/${id}/oracle`,
511
+ oracleQuotes: (id) => `/markets/${id}/oracle/quotes`,
512
+ oracleQuotesLatest: (id) => `/markets/${id}/oracle/quotes/latest`,
513
+ orderbook: (id) => `/markets/${id}/orderbook`,
514
+ prices: (id) => `/markets/${id}/prices`,
515
+ quotes: (id) => `/markets/${id}/quotes`,
516
+ simulate: (id) => `/markets/${id}/simulate`
517
+ },
518
+ orders: {
519
+ create: "/orders",
520
+ recent: "/orders/recent",
521
+ get: (id) => `/orders/${id}`,
522
+ cancel: "/orders/cancel",
523
+ cancelReplace: "/orders/cancel-replace",
524
+ bulk: "/orders/bulk",
525
+ bulkCreate: "/orders/bulk/create",
526
+ bulkCancel: "/orders/bulk/cancel",
527
+ simulate: "/orders/simulate",
528
+ list: "/orders"
529
+ },
530
+ portfolio: {
531
+ get: (address) => `/portfolio/${address}`,
532
+ claimable: (address) => `/portfolio/${address}/claimable`,
533
+ positions: (address) => `/portfolio/${address}/positions`,
534
+ stats: (address) => `/portfolio/${address}/stats`
535
+ },
536
+ balance: {
537
+ mintTestUsdc: "/balance/mint-test-usdc",
538
+ tokenBalance: "/balance",
539
+ settlement: "/balance/settlement",
540
+ get: (address) => `/balance/${address}`
541
+ },
542
+ gasless: {
543
+ operator: "/gasless/operator",
544
+ depositWithPermit: "/gasless/deposit-with-permit"
545
+ },
546
+ questions: {
547
+ submit: "/questions",
548
+ agentSubmit: "/questions/agent-submit",
549
+ submission: (id) => `/questions/submissions/${id}`
550
+ }
551
+ };
552
+
553
+ // src/modules/markets.ts
554
+ var Markets = class {
555
+ constructor(http2) {
556
+ this.http = http2;
557
+ }
558
+ async list(params) {
559
+ return this.http.get(ENDPOINTS.markets.list, {
560
+ search: params?.query,
561
+ status: params?.status,
562
+ sortBy: params?.sortBy,
563
+ sort: params?.sort,
564
+ limit: params?.limit,
565
+ cursor: params?.cursor,
566
+ visibility: params?.visibility,
567
+ resolutionStatus: params?.resolutionStatus,
568
+ creator: params?.creator,
569
+ category: params?.category,
570
+ createdAfter: params?.createdAfter
571
+ });
572
+ }
573
+ async search(params) {
574
+ return this.http.get(ENDPOINTS.markets.search, {
575
+ q: params.q,
576
+ limit: params.limit,
577
+ offset: params.offset
578
+ });
579
+ }
580
+ async get(id) {
581
+ const res = await this.http.get(
582
+ ENDPOINTS.markets.get(id)
583
+ );
584
+ return res.market;
585
+ }
586
+ async quotes(marketId) {
587
+ return this.http.get(ENDPOINTS.markets.quotes(marketId));
588
+ }
589
+ async orderbook(marketId, params) {
590
+ return this.http.get(ENDPOINTS.markets.orderbook(marketId), {
591
+ depth: params?.depth,
592
+ outcomeIndex: params?.outcomeIndex
593
+ });
594
+ }
595
+ async fullOrderbook(marketId, params) {
596
+ const [no, yes] = await Promise.all([
597
+ this.orderbook(marketId, { ...params, outcomeIndex: 0 }),
598
+ this.orderbook(marketId, { ...params, outcomeIndex: 1 })
599
+ ]);
600
+ return {
601
+ marketId: yes.marketId,
602
+ yes: { bids: yes.bids, asks: yes.asks },
603
+ no: { bids: no.bids, asks: no.asks },
604
+ timestamp: yes.timestamp
605
+ };
606
+ }
607
+ async simulate(marketId, params) {
608
+ return this.http.post(
609
+ ENDPOINTS.markets.simulate(marketId),
610
+ {
611
+ side: params.side,
612
+ amount: params.amount,
613
+ amountType: params.amountType ?? "usd",
614
+ ...params.trader ? { trader: params.trader } : {}
615
+ }
616
+ );
617
+ }
618
+ async priceHistory(marketId, params) {
619
+ return this.http.get(ENDPOINTS.markets.prices(marketId), {
620
+ timeframe: params?.timeframe ?? params?.interval
621
+ });
622
+ }
623
+ async oracle(marketId) {
624
+ return this.http.get(ENDPOINTS.markets.oracle(marketId));
625
+ }
626
+ async oracleQuotes(marketId) {
627
+ return this.http.get(
628
+ ENDPOINTS.markets.oracleQuotes(marketId)
629
+ );
630
+ }
631
+ async latestOracleQuote(marketId) {
632
+ return this.http.get(
633
+ ENDPOINTS.markets.oracleQuotesLatest(marketId)
634
+ );
635
+ }
636
+ async requestOracleQuote(marketId) {
637
+ return this.http.post(
638
+ ENDPOINTS.markets.oracleQuotes(marketId),
639
+ {}
640
+ );
641
+ }
642
+ async activity(marketId, params) {
643
+ return this.http.get(
644
+ ENDPOINTS.markets.activity(marketId),
645
+ {
646
+ cursor: params?.cursor,
647
+ limit: params?.limit,
648
+ types: params?.types,
649
+ startTime: params?.startTime,
650
+ endTime: params?.endTime
651
+ }
652
+ );
653
+ }
654
+ async create(questionId) {
655
+ return this.http.post(ENDPOINTS.markets.create, {
656
+ questionId
657
+ });
658
+ }
659
+ async globalActivity(params) {
660
+ return this.http.get(ENDPOINTS.activity.global, {
661
+ cursor: params?.cursor,
662
+ limit: params?.limit,
663
+ types: params?.types,
664
+ startTime: params?.startTime,
665
+ endTime: params?.endTime
666
+ });
667
+ }
668
+ };
669
+
670
+ // src/modules/questions.ts
671
+ var DEFAULT_POLL_INTERVAL_MS = 2e3;
672
+ var DEFAULT_MAX_ATTEMPTS = 45;
673
+ var Questions = class {
674
+ constructor(http2) {
675
+ this.http = http2;
676
+ }
677
+ async submit(question) {
678
+ return this.http.post(ENDPOINTS.questions.submit, {
679
+ question
680
+ });
681
+ }
682
+ async agentSubmit(draft) {
683
+ return this.http.post(
684
+ ENDPOINTS.questions.agentSubmit,
685
+ draft
686
+ );
687
+ }
688
+ async agentSubmitAndWait(draft, options) {
689
+ const pollIntervalMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
690
+ const maxAttempts = options?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
691
+ const { submissionId } = await this.agentSubmit(draft);
692
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
693
+ const submission = await this.getSubmission(submissionId);
694
+ if (submission.status === "completed") {
695
+ return submission;
696
+ }
697
+ if (submission.status === "failed") {
698
+ throw new Error(
699
+ `Agent submission ${submissionId} failed`
700
+ );
701
+ }
702
+ if (attempt < maxAttempts) {
703
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
704
+ }
705
+ }
706
+ throw new Error(
707
+ `Agent submission ${submissionId} did not complete within ${maxAttempts} attempts`
708
+ );
709
+ }
710
+ async getSubmission(submissionId) {
711
+ return this.http.get(
712
+ ENDPOINTS.questions.submission(submissionId)
713
+ );
714
+ }
715
+ async submitAndWait(question, options) {
716
+ const pollIntervalMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
717
+ const maxAttempts = options?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
718
+ const { submissionId } = await this.submit(question);
719
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
720
+ const submission = await this.getSubmission(submissionId);
721
+ if (submission.status === "completed") {
722
+ return submission;
723
+ }
724
+ if (submission.status === "failed") {
725
+ throw new Error(
726
+ `Question submission ${submissionId} failed`
727
+ );
728
+ }
729
+ if (attempt < maxAttempts) {
730
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
731
+ }
732
+ }
733
+ throw new Error(
734
+ `Question submission ${submissionId} did not complete within ${maxAttempts} attempts`
735
+ );
736
+ }
737
+ };
738
+
739
+ // src/modules/orders.ts
740
+ var Orders = class {
741
+ constructor(http2, builder, address) {
742
+ this.http = http2;
743
+ this.builder = builder;
744
+ this.address = address;
745
+ }
746
+ requireSigner() {
747
+ if (!this.builder) {
748
+ throw new ContextConfigError(
749
+ "A signer is required for write operations. Pass a signer to ContextClient."
750
+ );
751
+ }
752
+ return this.builder;
753
+ }
754
+ requireAddress() {
755
+ if (!this.address) {
756
+ throw new ContextConfigError(
757
+ "A signer is required for this operation. Pass a signer to ContextClient."
758
+ );
759
+ }
760
+ return this.address;
761
+ }
762
+ // ─── Read ───
763
+ async list(params) {
764
+ return this.http.get(ENDPOINTS.orders.list, {
765
+ trader: params?.trader,
766
+ marketId: params?.marketId,
767
+ status: params?.status,
768
+ cursor: params?.cursor,
769
+ limit: params?.limit
770
+ });
771
+ }
772
+ async listAll(params) {
773
+ const allOrders = [];
774
+ let cursor;
775
+ do {
776
+ const res = await this.http.get(ENDPOINTS.orders.list, {
777
+ trader: params?.trader,
778
+ marketId: params?.marketId,
779
+ status: params?.status,
780
+ cursor
781
+ });
782
+ const orders = res.orders ?? [];
783
+ allOrders.push(...orders);
784
+ cursor = res.cursor ?? void 0;
785
+ if (orders.length === 0) break;
786
+ } while (cursor);
787
+ return allOrders;
788
+ }
789
+ async mine(marketId) {
790
+ return this.list({
791
+ trader: this.requireAddress(),
792
+ marketId
793
+ });
794
+ }
795
+ async allMine(marketId) {
796
+ return this.listAll({
797
+ trader: this.requireAddress(),
798
+ marketId
799
+ });
800
+ }
801
+ async get(id) {
802
+ const res = await this.http.get(
803
+ ENDPOINTS.orders.get(id)
804
+ );
805
+ return res.order;
806
+ }
807
+ async recent(params) {
808
+ return this.http.get(ENDPOINTS.orders.recent, {
809
+ trader: params?.trader,
810
+ marketId: params?.marketId,
811
+ status: params?.status,
812
+ limit: params?.limit,
813
+ windowSeconds: params?.windowSeconds
814
+ });
815
+ }
816
+ async simulate(params) {
817
+ return this.http.post(
818
+ ENDPOINTS.orders.simulate,
819
+ params
820
+ );
821
+ }
822
+ // ─── Write ───
823
+ async create(req) {
824
+ const builder = this.requireSigner();
825
+ const signed = await builder.buildAndSign(req);
826
+ return this.http.post(ENDPOINTS.orders.create, signed);
827
+ }
828
+ async createMarket(req) {
829
+ const builder = this.requireSigner();
830
+ const signed = await builder.buildAndSignMarket(req);
831
+ return this.http.post(ENDPOINTS.orders.create, signed);
832
+ }
833
+ async cancel(nonce) {
834
+ const builder = this.requireSigner();
835
+ const signature = await builder.signCancel(nonce);
836
+ return this.http.post(ENDPOINTS.orders.cancel, {
837
+ trader: builder.address,
838
+ nonce,
839
+ signature
840
+ });
841
+ }
842
+ async cancelReplace(cancelNonce, newOrder) {
843
+ const builder = this.requireSigner();
844
+ const cancelSig = await builder.signCancel(cancelNonce);
845
+ const signed = await builder.buildAndSign(newOrder);
846
+ return this.http.post(
847
+ ENDPOINTS.orders.cancelReplace,
848
+ {
849
+ cancel: {
850
+ trader: builder.address,
851
+ nonce: cancelNonce,
852
+ signature: cancelSig
853
+ },
854
+ create: signed
855
+ }
856
+ );
857
+ }
858
+ async bulkCreate(orders) {
859
+ const builder = this.requireSigner();
860
+ const signed = await Promise.all(
861
+ orders.map((req) => builder.buildAndSign(req))
862
+ );
863
+ const res = await this.http.post(
864
+ ENDPOINTS.orders.bulkCreate,
865
+ { orders: signed }
866
+ );
867
+ return res.results;
868
+ }
869
+ async bulkCancel(nonces) {
870
+ const builder = this.requireSigner();
871
+ const cancels = await Promise.all(
872
+ nonces.map(async (nonce) => {
873
+ const signature = await builder.signCancel(nonce);
874
+ return { trader: builder.address, nonce, signature };
875
+ })
876
+ );
877
+ const res = await this.http.post(
878
+ ENDPOINTS.orders.bulkCancel,
879
+ { cancels }
880
+ );
881
+ return res.results;
882
+ }
883
+ async bulk(creates, cancelNonces) {
884
+ const builder = this.requireSigner();
885
+ const createOps = await Promise.all(
886
+ creates.map(async (req) => ({
887
+ type: "create",
888
+ order: await builder.buildAndSign(req)
889
+ }))
890
+ );
891
+ const cancelOps = await Promise.all(
892
+ cancelNonces.map(async (nonce) => ({
893
+ type: "cancel",
894
+ cancel: {
895
+ trader: builder.address,
896
+ nonce,
897
+ signature: await builder.signCancel(nonce)
898
+ }
899
+ }))
900
+ );
901
+ return this.http.post(ENDPOINTS.orders.bulk, {
902
+ operations: [...createOps, ...cancelOps]
903
+ });
904
+ }
905
+ };
906
+
907
+ // src/modules/portfolio.ts
908
+ var PortfolioModule = class {
909
+ constructor(http2, defaultAddress) {
910
+ this.http = http2;
911
+ this.defaultAddress = defaultAddress;
912
+ }
913
+ resolveAddress(address) {
914
+ const resolved = address ?? this.defaultAddress;
915
+ if (!resolved) {
916
+ throw new Error(
917
+ "Address required. Either pass an address or configure a signer."
918
+ );
919
+ }
920
+ return resolved;
921
+ }
922
+ async get(address, params) {
923
+ return this.http.get(
924
+ ENDPOINTS.portfolio.get(this.resolveAddress(address)),
925
+ {
926
+ kind: params?.kind,
927
+ marketId: params?.marketId,
928
+ cursor: params?.cursor,
929
+ pageSize: params?.pageSize
930
+ }
931
+ );
932
+ }
933
+ async positions(address, params) {
934
+ return this.http.get(
935
+ ENDPOINTS.portfolio.positions(this.resolveAddress(address)),
936
+ {
937
+ marketId: params?.marketId,
938
+ status: params?.status,
939
+ search: params?.search,
940
+ cursor: params?.cursor,
941
+ limit: params?.limit
942
+ }
943
+ );
944
+ }
945
+ async claimable(address) {
946
+ return this.http.get(
947
+ ENDPOINTS.portfolio.claimable(this.resolveAddress(address))
948
+ );
949
+ }
950
+ async stats(address) {
951
+ return this.http.get(
952
+ ENDPOINTS.portfolio.stats(this.resolveAddress(address))
953
+ );
954
+ }
955
+ async balance(address) {
956
+ return this.http.get(
957
+ ENDPOINTS.balance.get(this.resolveAddress(address))
958
+ );
959
+ }
960
+ async tokenBalance(address, tokenAddress) {
961
+ return this.http.get(ENDPOINTS.balance.tokenBalance, {
962
+ address,
963
+ tokenAddress
964
+ });
965
+ }
966
+ async settlementBalance(address, tokenAddress) {
967
+ return this.http.get(ENDPOINTS.balance.settlement, {
968
+ address,
969
+ tokenAddress
970
+ });
971
+ }
972
+ };
973
+
974
+ // src/modules/account.ts
975
+ var import_viem2 = require("viem");
976
+ var import_chains2 = require("viem/chains");
977
+ var AccountModule = class {
978
+ constructor(http2, walletClient, account, rpcUrl) {
979
+ this.http = http2;
980
+ this.walletClient = walletClient;
981
+ this.account = account;
982
+ this.publicClient = (0, import_viem2.createPublicClient)({
983
+ chain: import_chains2.baseSepolia,
984
+ transport: (0, import_viem2.http)(rpcUrl)
985
+ });
986
+ }
987
+ publicClient;
988
+ get address() {
989
+ if (!this.account) {
990
+ throw new ContextConfigError(
991
+ "A signer is required for account operations."
992
+ );
993
+ }
994
+ return this.account.address;
995
+ }
996
+ requireWallet() {
997
+ if (!this.walletClient) {
998
+ throw new ContextConfigError(
999
+ "A signer is required for account operations."
1000
+ );
1001
+ }
1002
+ return this.walletClient;
1003
+ }
1004
+ requireAccount() {
1005
+ if (!this.account) {
1006
+ throw new ContextConfigError(
1007
+ "A signer is required for account operations."
1008
+ );
1009
+ }
1010
+ return this.account;
1011
+ }
1012
+ async status() {
1013
+ const addr = this.address;
1014
+ const [ethBalance, usdcAllowance, isOperatorApproved] = await Promise.all([
1015
+ this.publicClient.getBalance({ address: addr }),
1016
+ this.publicClient.readContract({
1017
+ address: USDC_ADDRESS,
1018
+ abi: ERC20_ABI,
1019
+ functionName: "allowance",
1020
+ args: [addr, HOLDINGS_ADDRESS]
1021
+ }),
1022
+ this.publicClient.readContract({
1023
+ address: HOLDINGS_ADDRESS,
1024
+ abi: HOLDINGS_ABI,
1025
+ functionName: "isOperatorFor",
1026
+ args: [addr, SETTLEMENT_ADDRESS]
1027
+ })
1028
+ ]);
1029
+ return {
1030
+ address: addr,
1031
+ ethBalance,
1032
+ usdcAllowance,
1033
+ isOperatorApproved,
1034
+ needsApprovals: usdcAllowance === 0n || !isOperatorApproved,
1035
+ needsGaslessSetup: !isOperatorApproved
1036
+ };
1037
+ }
1038
+ async setup() {
1039
+ const wallet = this.requireWallet();
1040
+ const account = this.requireAccount();
1041
+ const walletStatus = await this.status();
1042
+ let usdcApprovalTx = null;
1043
+ let operatorApprovalTx = null;
1044
+ if (walletStatus.usdcAllowance === 0n) {
1045
+ usdcApprovalTx = await wallet.writeContract({
1046
+ account,
1047
+ chain: import_chains2.baseSepolia,
1048
+ address: USDC_ADDRESS,
1049
+ abi: ERC20_ABI,
1050
+ functionName: "approve",
1051
+ args: [HOLDINGS_ADDRESS, import_viem2.maxUint256]
1052
+ });
1053
+ }
1054
+ if (!walletStatus.isOperatorApproved) {
1055
+ operatorApprovalTx = await wallet.writeContract({
1056
+ account,
1057
+ chain: import_chains2.baseSepolia,
1058
+ address: HOLDINGS_ADDRESS,
1059
+ abi: HOLDINGS_ABI,
1060
+ functionName: "setOperator",
1061
+ args: [SETTLEMENT_ADDRESS, true]
1062
+ });
1063
+ }
1064
+ return { usdcApprovalTx, operatorApprovalTx };
1065
+ }
1066
+ async mintTestUsdc(amount = 1e3) {
1067
+ return this.http.post(ENDPOINTS.balance.mintTestUsdc, {
1068
+ address: this.address,
1069
+ amount: amount.toString()
1070
+ });
1071
+ }
1072
+ async deposit(amount) {
1073
+ const wallet = this.requireWallet();
1074
+ const account = this.requireAccount();
1075
+ const amountRaw = (0, import_viem2.parseUnits)(amount.toString(), 6);
1076
+ const hash = await wallet.writeContract({
1077
+ account,
1078
+ chain: import_chains2.baseSepolia,
1079
+ address: HOLDINGS_ADDRESS,
1080
+ abi: HOLDINGS_ABI,
1081
+ functionName: "deposit",
1082
+ args: [USDC_ADDRESS, amountRaw]
1083
+ });
1084
+ await this.publicClient.waitForTransactionReceipt({ hash });
1085
+ return hash;
1086
+ }
1087
+ async withdraw(amount) {
1088
+ const wallet = this.requireWallet();
1089
+ const account = this.requireAccount();
1090
+ const amountRaw = (0, import_viem2.parseUnits)(amount.toString(), 6);
1091
+ const hash = await wallet.writeContract({
1092
+ account,
1093
+ chain: import_chains2.baseSepolia,
1094
+ address: HOLDINGS_ADDRESS,
1095
+ abi: HOLDINGS_ABI,
1096
+ functionName: "withdraw",
1097
+ args: [USDC_ADDRESS, amountRaw]
1098
+ });
1099
+ await this.publicClient.waitForTransactionReceipt({ hash });
1100
+ return hash;
1101
+ }
1102
+ async mintCompleteSets(marketId, amount) {
1103
+ const wallet = this.requireWallet();
1104
+ const account = this.requireAccount();
1105
+ const amountRaw = (0, import_viem2.parseUnits)(amount.toString(), 6);
1106
+ const hash = await wallet.writeContract({
1107
+ account,
1108
+ chain: import_chains2.baseSepolia,
1109
+ address: SETTLEMENT_ADDRESS,
1110
+ abi: SETTLEMENT_ABI,
1111
+ functionName: "mintCompleteSetsFromHoldings",
1112
+ args: [marketId, amountRaw]
1113
+ });
1114
+ await this.publicClient.waitForTransactionReceipt({ hash });
1115
+ return hash;
1116
+ }
1117
+ async burnCompleteSets(marketId, amount, creditInternal = true) {
1118
+ const wallet = this.requireWallet();
1119
+ const account = this.requireAccount();
1120
+ const amountRaw = (0, import_viem2.parseUnits)(amount.toString(), 6);
1121
+ const hash = await wallet.writeContract({
1122
+ account,
1123
+ chain: import_chains2.baseSepolia,
1124
+ address: SETTLEMENT_ADDRESS,
1125
+ abi: SETTLEMENT_ABI,
1126
+ functionName: "burnCompleteSetsFromHoldings",
1127
+ args: [marketId, amountRaw, this.address, creditInternal]
1128
+ });
1129
+ await this.publicClient.waitForTransactionReceipt({ hash });
1130
+ return hash;
1131
+ }
1132
+ // ─── Gasless (high-level: sign + relay) ───
1133
+ async gaslessSetup() {
1134
+ const wallet = this.requireWallet();
1135
+ const account = this.requireAccount();
1136
+ const nonce = await this.publicClient.readContract({
1137
+ address: HOLDINGS_ADDRESS,
1138
+ abi: OPERATOR_NONCE_ABI,
1139
+ functionName: "operatorNonce",
1140
+ args: [this.address]
1141
+ });
1142
+ const deadline = BigInt(Math.floor(Date.now() / 1e3) + 3600);
1143
+ const signature = await wallet.signTypedData({
1144
+ account,
1145
+ domain: HOLDINGS_EIP712_DOMAIN,
1146
+ types: OPERATOR_APPROVAL_TYPES,
1147
+ primaryType: "OperatorApproval",
1148
+ message: {
1149
+ user: this.address,
1150
+ operator: SETTLEMENT_ADDRESS,
1151
+ approved: true,
1152
+ nonce,
1153
+ deadline
1154
+ }
1155
+ });
1156
+ return this.relayOperatorApproval({
1157
+ user: this.address,
1158
+ approved: true,
1159
+ nonce: nonce.toString(),
1160
+ deadline: deadline.toString(),
1161
+ signature
1162
+ });
1163
+ }
1164
+ async gaslessDeposit(amount) {
1165
+ const wallet = this.requireWallet();
1166
+ const account = this.requireAccount();
1167
+ const amountRaw = (0, import_viem2.parseUnits)(amount.toString(), 6);
1168
+ const nonce = BigInt(Date.now());
1169
+ const deadline = BigInt(Math.floor(Date.now() / 1e3) + 3600);
1170
+ const signature = await wallet.signTypedData({
1171
+ account,
1172
+ domain: PERMIT2_EIP712_DOMAIN,
1173
+ types: PERMIT_TRANSFER_FROM_TYPES,
1174
+ primaryType: "PermitTransferFrom",
1175
+ message: {
1176
+ permitted: {
1177
+ token: USDC_ADDRESS,
1178
+ amount: amountRaw
1179
+ },
1180
+ spender: HOLDINGS_ADDRESS,
1181
+ nonce,
1182
+ deadline
1183
+ }
1184
+ });
1185
+ return this.relayDeposit({
1186
+ user: this.address,
1187
+ amount: amountRaw.toString(),
1188
+ nonce: nonce.toString(),
1189
+ deadline: deadline.toString(),
1190
+ signature
1191
+ });
1192
+ }
1193
+ // ─── Gasless Relay (low-level) ───
1194
+ async relayOperatorApproval(req) {
1195
+ return this.http.post(
1196
+ ENDPOINTS.gasless.operator,
1197
+ req
1198
+ );
1199
+ }
1200
+ async relayDeposit(req) {
1201
+ return this.http.post(
1202
+ ENDPOINTS.gasless.depositWithPermit,
1203
+ req
1204
+ );
1205
+ }
1206
+ };
1207
+
1208
+ // src/client.ts
1209
+ var ContextClient = class {
1210
+ markets;
1211
+ questions;
1212
+ orders;
1213
+ portfolio;
1214
+ account;
1215
+ /** The trader's on-chain address, or null if no signer was provided. */
1216
+ address;
1217
+ constructor(options = {}) {
1218
+ const http2 = createHttpClient({
1219
+ apiKey: options.apiKey,
1220
+ baseUrl: options.baseUrl
1221
+ });
1222
+ let builder = null;
1223
+ let address = null;
1224
+ let walletClient = null;
1225
+ let account = null;
1226
+ if (options.signer) {
1227
+ const resolved = resolveSigner(options.signer);
1228
+ walletClient = resolved.walletClient;
1229
+ account = resolved.account;
1230
+ address = resolved.account.address;
1231
+ builder = new OrderBuilder(walletClient, account);
1232
+ }
1233
+ this.address = address;
1234
+ this.markets = new Markets(http2);
1235
+ this.questions = new Questions(http2);
1236
+ this.orders = new Orders(http2, builder, address);
1237
+ this.portfolio = new PortfolioModule(http2, address);
1238
+ this.account = new AccountModule(http2, walletClient, account, options.rpcUrl);
1239
+ }
1240
+ };
1241
+ // Annotate the CommonJS export names for ESM import in node:
1242
+ 0 && (module.exports = {
1243
+ API_BASE,
1244
+ CHAIN_ID,
1245
+ ContextApiError,
1246
+ ContextClient,
1247
+ ContextConfigError,
1248
+ ContextSigningError,
1249
+ ENDPOINTS,
1250
+ HOLDINGS_ADDRESS,
1251
+ HOLDINGS_EIP712_DOMAIN,
1252
+ PERMIT2_ADDRESS,
1253
+ PERMIT2_EIP712_DOMAIN,
1254
+ SETTLEMENT_ADDRESS,
1255
+ USDC_ADDRESS,
1256
+ calculateMaxFee,
1257
+ decodePriceCents,
1258
+ decodeSize,
1259
+ encodePriceCents,
1260
+ encodeSize
1261
+ });
1262
+ //# sourceMappingURL=index.cjs.map