@ostium/builder-sdk 0.1.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.js ADDED
@@ -0,0 +1,4988 @@
1
+ import { createPublicClient, http, createWalletClient, formatUnits, maxUint256, encodeFunctionData, getAddress, parseUnits } from 'viem';
2
+ import { privateKeyToAccount } from 'viem/accounts';
3
+ import { arbitrumSepolia, arbitrum } from 'viem/chains';
4
+ import { entryPoint07Address } from 'viem/account-abstraction';
5
+ import { createSmartAccountClient } from 'permissionless';
6
+ import { createPimlicoClient } from 'permissionless/clients/pimlico';
7
+ import { toSafeSmartAccount } from 'permissionless/accounts';
8
+ import { GraphQLClient } from 'graphql-request';
9
+ import { CurrentTradeProfitRaw, CurrentTotalProfitRaw, CurrentTotalProfitP, GetCurrentRolloverFee, GetTradeRolloverFee, GetEffectiveMaxLeverage, GetTradeLiquidationPrice, CalculateDynamicPriceImpact } from '@ostium/formulae';
10
+ import WS from 'ws';
11
+
12
+ // src/client.ts
13
+
14
+ // src/internal/erc20.ts
15
+ var ERC20_ABI = [
16
+ {
17
+ inputs: [
18
+ { internalType: "address", name: "owner", type: "address" },
19
+ { internalType: "address", name: "spender", type: "address" }
20
+ ],
21
+ name: "allowance",
22
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
23
+ stateMutability: "view",
24
+ type: "function"
25
+ },
26
+ {
27
+ inputs: [
28
+ { internalType: "address", name: "spender", type: "address" },
29
+ { internalType: "uint256", name: "amount", type: "uint256" }
30
+ ],
31
+ name: "approve",
32
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
33
+ stateMutability: "nonpayable",
34
+ type: "function"
35
+ },
36
+ {
37
+ inputs: [
38
+ { internalType: "address", name: "account", type: "address" }
39
+ ],
40
+ name: "balanceOf",
41
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
42
+ stateMutability: "view",
43
+ type: "function"
44
+ },
45
+ {
46
+ inputs: [
47
+ { internalType: "address", name: "to", type: "address" },
48
+ { internalType: "uint256", name: "amount", type: "uint256" }
49
+ ],
50
+ name: "transfer",
51
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
52
+ stateMutability: "nonpayable",
53
+ type: "function"
54
+ }
55
+ ];
56
+
57
+ // src/internal/decimal.ts
58
+ function parseUsdc(amount) {
59
+ const amountStr = typeof amount === "number" ? amount.toString() : amount;
60
+ if (!amountStr || amountStr === "0") return 0n;
61
+ if (!/^\d+(\.\d+)?$/.test(amountStr)) {
62
+ throw new Error(`Invalid USDC amount: ${amountStr}`);
63
+ }
64
+ const [intPart, decPart = ""] = amountStr.split(".");
65
+ const paddedDec = decPart.padEnd(6, "0").slice(0, 6);
66
+ return BigInt(intPart + paddedDec);
67
+ }
68
+ function parsePrice(price) {
69
+ const priceStr = typeof price === "number" ? price.toString() : price;
70
+ if (!priceStr || priceStr === "0") return 0n;
71
+ if (!/^-?\d+(\.\d+)?$/.test(priceStr)) {
72
+ throw new Error(`Invalid price: ${priceStr}`);
73
+ }
74
+ const isNegative = priceStr.startsWith("-");
75
+ const absStr = isNegative ? priceStr.slice(1) : priceStr;
76
+ const [intPart, decPart = ""] = absStr.split(".");
77
+ const paddedDec = decPart.padEnd(18, "0").slice(0, 18);
78
+ const result = BigInt(intPart + paddedDec);
79
+ return isNegative ? -result : result;
80
+ }
81
+ function parseLeverage(leverage) {
82
+ if (leverage <= 0 || !Number.isFinite(leverage)) {
83
+ throw new Error(`Invalid leverage: ${leverage}`);
84
+ }
85
+ return BigInt(Math.round(leverage * 100));
86
+ }
87
+
88
+ // src/internal/precision.ts
89
+ var PRECISION_6 = 1000000n;
90
+ var PRECISION_18 = 1000000000000000000n;
91
+ var DEFAULT_SLIPPAGE_PERCENTAGE = 0.25;
92
+ var MIN_COLLATERAL_USD = 5;
93
+ var MAX_COLLATERAL_USD = 2e6;
94
+ var ORDER_TYPE_MAP = {
95
+ "market": 0,
96
+ // OpenOrderType.MARKET
97
+ "limit": 1,
98
+ // OpenOrderType.LIMIT
99
+ "stop": 2
100
+ // OpenOrderType.STOP
101
+ };
102
+
103
+ // src/internal/validation.ts
104
+ var DECIMAL_RE = /^-?\d+(\.\d+)?$/;
105
+ function assertDecimal(value, label) {
106
+ if (!DECIMAL_RE.test(value)) {
107
+ throw new Error(`Invalid ${label}: "${value}" is not a valid decimal number`);
108
+ }
109
+ if (parseFloat(value) <= 0) {
110
+ throw new Error(`Invalid ${label}: must be greater than zero, got "${value}"`);
111
+ }
112
+ }
113
+ function assertNonNegativeDecimal(value, label) {
114
+ if (!DECIMAL_RE.test(value)) {
115
+ throw new Error(`Invalid ${label}: "${value}" is not a valid decimal number`);
116
+ }
117
+ if (parseFloat(value) < 0) {
118
+ throw new Error(`Invalid ${label}: must be non-negative, got "${value}"`);
119
+ }
120
+ }
121
+ function extractOpenType(open) {
122
+ return ORDER_TYPE_MAP[open.t];
123
+ }
124
+ function validateTpSlDirection(open, tp, sl, openPrice) {
125
+ if (open.b) {
126
+ if (tp > 0n && tp <= openPrice) {
127
+ throw new Error(`Take profit (${open.tp}) must be above open price (${open.p}) for long positions`);
128
+ }
129
+ if (sl > 0n && sl >= openPrice) {
130
+ throw new Error(`Stop loss (${open.sl}) must be below open price (${open.p}) for long positions`);
131
+ }
132
+ } else {
133
+ if (tp > 0n && tp >= openPrice) {
134
+ throw new Error(`Take profit (${open.tp}) must be below open price (${open.p}) for short positions`);
135
+ }
136
+ if (sl > 0n && sl <= openPrice) {
137
+ throw new Error(`Stop loss (${open.sl}) must be above open price (${open.p}) for short positions`);
138
+ }
139
+ }
140
+ }
141
+ function validateCloseParams(close) {
142
+ if (close.r < 1 || close.r > 100) {
143
+ throw new Error(`Close percentage must be 1\u2013100, got ${close.r}`);
144
+ }
145
+ assertDecimal(close.p, "close price");
146
+ }
147
+ function validateModifyParams(input) {
148
+ if (input.a < 0) {
149
+ throw new Error(`Invalid pair index: ${input.a}`);
150
+ }
151
+ if (input.i < 0) {
152
+ throw new Error(`Invalid trade/order index: ${input.i}`);
153
+ }
154
+ if (!input.p && !input.tp && !input.sl) {
155
+ throw new Error("At least one of price, takeProfit, or stopLoss must be provided");
156
+ }
157
+ if (input.p) {
158
+ assertDecimal(input.p, "price");
159
+ }
160
+ if (input.tp) {
161
+ assertNonNegativeDecimal(input.tp, "take profit");
162
+ }
163
+ if (input.sl) {
164
+ assertNonNegativeDecimal(input.sl, "stop loss");
165
+ }
166
+ }
167
+
168
+ // src/internal/open-builder.ts
169
+ var DEFAULT_CONFIG = {
170
+ defaultLeverage: 1,
171
+ maxLeverage: 100,
172
+ minOpenSize: MIN_COLLATERAL_USD
173
+ };
174
+ function buildTrade(open, traderAddress, config = {}) {
175
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
176
+ const collateralUsd = parseFloat(open.s);
177
+ if (collateralUsd < mergedConfig.minOpenSize) {
178
+ throw new Error(`Collateral ${open.s} below minimum ${mergedConfig.minOpenSize}`);
179
+ }
180
+ const leverageNum = parseFloat(open.l);
181
+ if (leverageNum > mergedConfig.maxLeverage) {
182
+ throw new Error(`Leverage ${open.l} exceeds maximum ${mergedConfig.maxLeverage}`);
183
+ }
184
+ const collateral = parseUsdc(open.s);
185
+ const openPrice = parsePrice(open.p);
186
+ const leverage = parseLeverage(leverageNum);
187
+ const tp = open.tp ? parsePrice(open.tp) : 0n;
188
+ const sl = open.sl ? parsePrice(open.sl) : 0n;
189
+ if (tp > 0n || sl > 0n) {
190
+ validateTpSlDirection(open, tp, sl, openPrice);
191
+ }
192
+ const trade = {
193
+ collateral,
194
+ openPrice,
195
+ tp,
196
+ sl,
197
+ trader: traderAddress,
198
+ leverage,
199
+ pairIndex: BigInt(open.a),
200
+ index: 0n,
201
+ buy: open.b,
202
+ isDayTrade: open.d ?? false
203
+ };
204
+ return { trade, orderType: extractOpenType(open) };
205
+ }
206
+ function buildBuilderFee(builder) {
207
+ if (!builder) {
208
+ return {
209
+ builder: "0x0000000000000000000000000000000000000000",
210
+ builderFee: 0n
211
+ };
212
+ }
213
+ return {
214
+ builder: builder.b,
215
+ builderFee: BigInt(builder.f)
216
+ };
217
+ }
218
+
219
+ // src/internal/contracts.ts
220
+ var ARBITRUM_MAINNET = {
221
+ chainId: 42161,
222
+ contracts: {
223
+ usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
224
+ trading: "0x6D0bA1f9996DBD8885827e1b2e8f6593e7702411",
225
+ tradingStorage: "0xcCd5891083A8acD2074690F65d3024E7D13d66E7"
226
+ }
227
+ };
228
+ var ARBITRUM_TESTNET = {
229
+ chainId: 421614,
230
+ contracts: {
231
+ usdc: "0xe73B11Fb1e3eeEe8AF2a23079A4410Fe1B370548",
232
+ trading: "0x2A9B9c988393f46a2537B0ff11E98c2C15a95afe",
233
+ tradingStorage: "0x0b9F5243B29938668c9Cfbd7557A389EC7Ef88b8"
234
+ }
235
+ };
236
+ function getNetworkConfig(isTestnet = false) {
237
+ return isTestnet ? ARBITRUM_TESTNET : ARBITRUM_MAINNET;
238
+ }
239
+
240
+ // src/types.ts
241
+ var OrderType = /* @__PURE__ */ ((OrderType2) => {
242
+ OrderType2["Market"] = "market";
243
+ OrderType2["Limit"] = "limit";
244
+ OrderType2["Stop"] = "stop";
245
+ return OrderType2;
246
+ })(OrderType || {});
247
+ var CancelOrderType = /* @__PURE__ */ ((CancelOrderType2) => {
248
+ CancelOrderType2["Limit"] = "limit";
249
+ CancelOrderType2["PendingOpen"] = "pendingOpen";
250
+ CancelOrderType2["PendingClose"] = "pendingClose";
251
+ return CancelOrderType2;
252
+ })(CancelOrderType || {});
253
+
254
+ // src/config.ts
255
+ var DEFAULT_PIMLICO_URL = "https://builder.ostium.io/v1/pimlico/sponsor?chainId=42161";
256
+ var DEFAULT_PIMLICO_URL_TESTNET = "https://builder.ostium.io/v1/pimlico/sponsor?chainId=421614";
257
+ function isGasless(config) {
258
+ return !!config.pimlicoUrl;
259
+ }
260
+ function isDelegated(config) {
261
+ return !!config.traderAddress;
262
+ }
263
+
264
+ // src/errors.ts
265
+ var OstiumErrorCode = /* @__PURE__ */ ((OstiumErrorCode2) => {
266
+ OstiumErrorCode2["INVALID_CONFIG"] = "INVALID_CONFIG";
267
+ OstiumErrorCode2["VALIDATION_FAILED"] = "VALIDATION_FAILED";
268
+ OstiumErrorCode2["ALLOWANCE_INSUFFICIENT"] = "ALLOWANCE_INSUFFICIENT";
269
+ OstiumErrorCode2["SUBMISSION_FAILED"] = "SUBMISSION_FAILED";
270
+ OstiumErrorCode2["DELEGATION_FAILED"] = "DELEGATION_FAILED";
271
+ OstiumErrorCode2["CONTRACT_ERROR"] = "CONTRACT_ERROR";
272
+ OstiumErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
273
+ return OstiumErrorCode2;
274
+ })(OstiumErrorCode || {});
275
+ var OstiumError = class extends Error {
276
+ constructor(message, code, cause) {
277
+ super(message);
278
+ this.code = code;
279
+ this.cause = cause;
280
+ this.name = "OstiumError";
281
+ }
282
+ code;
283
+ cause;
284
+ };
285
+
286
+ // src/signer/self.ts
287
+ var SelfSignerStrategy = class {
288
+ traderAddress;
289
+ constructor(traderAddress) {
290
+ this.traderAddress = traderAddress;
291
+ }
292
+ prepare(encoded) {
293
+ return encoded;
294
+ }
295
+ };
296
+
297
+ // src/internal/contract.ts
298
+ var TRADING_ABI = [
299
+ {
300
+ "inputs": [],
301
+ "stateMutability": "nonpayable",
302
+ "type": "constructor"
303
+ },
304
+ {
305
+ "inputs": [],
306
+ "name": "AboveMaxAllowedCollateral",
307
+ "type": "error"
308
+ },
309
+ {
310
+ "inputs": [
311
+ {
312
+ "internalType": "address",
313
+ "name": "trader",
314
+ "type": "address"
315
+ },
316
+ {
317
+ "internalType": "uint16",
318
+ "name": "pairIndex",
319
+ "type": "uint16"
320
+ },
321
+ {
322
+ "internalType": "uint8",
323
+ "name": "index",
324
+ "type": "uint8"
325
+ }
326
+ ],
327
+ "name": "AlreadyMarketClosed",
328
+ "type": "error"
329
+ },
330
+ {
331
+ "inputs": [],
332
+ "name": "BelowFees",
333
+ "type": "error"
334
+ },
335
+ {
336
+ "inputs": [],
337
+ "name": "BelowMinLevPos",
338
+ "type": "error"
339
+ },
340
+ {
341
+ "inputs": [],
342
+ "name": "DelegateForbidden",
343
+ "type": "error"
344
+ },
345
+ {
346
+ "inputs": [],
347
+ "name": "DelegateReentrant",
348
+ "type": "error"
349
+ },
350
+ {
351
+ "inputs": [],
352
+ "name": "DelegatedActionFailed",
353
+ "type": "error"
354
+ },
355
+ {
356
+ "inputs": [],
357
+ "name": "ExposureLimits",
358
+ "type": "error"
359
+ },
360
+ {
361
+ "inputs": [],
362
+ "name": "InvalidCallData",
363
+ "type": "error"
364
+ },
365
+ {
366
+ "inputs": [],
367
+ "name": "InvalidInitialization",
368
+ "type": "error"
369
+ },
370
+ {
371
+ "inputs": [],
372
+ "name": "InvalidNonce",
373
+ "type": "error"
374
+ },
375
+ {
376
+ "inputs": [],
377
+ "name": "InvalidSignature",
378
+ "type": "error"
379
+ },
380
+ {
381
+ "inputs": [
382
+ {
383
+ "internalType": "address",
384
+ "name": "a",
385
+ "type": "address"
386
+ }
387
+ ],
388
+ "name": "IsContract",
389
+ "type": "error"
390
+ },
391
+ {
392
+ "inputs": [],
393
+ "name": "IsDone",
394
+ "type": "error"
395
+ },
396
+ {
397
+ "inputs": [],
398
+ "name": "IsPaused",
399
+ "type": "error"
400
+ },
401
+ {
402
+ "inputs": [
403
+ {
404
+ "internalType": "address",
405
+ "name": "trader",
406
+ "type": "address"
407
+ }
408
+ ],
409
+ "name": "MaxPendingMarketOrdersReached",
410
+ "type": "error"
411
+ },
412
+ {
413
+ "inputs": [
414
+ {
415
+ "internalType": "address",
416
+ "name": "trader",
417
+ "type": "address"
418
+ },
419
+ {
420
+ "internalType": "uint16",
421
+ "name": "pairIndex",
422
+ "type": "uint16"
423
+ }
424
+ ],
425
+ "name": "MaxTradesPerPairReached",
426
+ "type": "error"
427
+ },
428
+ {
429
+ "inputs": [
430
+ {
431
+ "internalType": "address",
432
+ "name": "a",
433
+ "type": "address"
434
+ }
435
+ ],
436
+ "name": "NoDelegate",
437
+ "type": "error"
438
+ },
439
+ {
440
+ "inputs": [
441
+ {
442
+ "internalType": "address",
443
+ "name": "trader",
444
+ "type": "address"
445
+ },
446
+ {
447
+ "internalType": "uint16",
448
+ "name": "pairIndex",
449
+ "type": "uint16"
450
+ },
451
+ {
452
+ "internalType": "uint8",
453
+ "name": "index",
454
+ "type": "uint8"
455
+ }
456
+ ],
457
+ "name": "NoLimitFound",
458
+ "type": "error"
459
+ },
460
+ {
461
+ "inputs": [
462
+ {
463
+ "internalType": "address",
464
+ "name": "trader",
465
+ "type": "address"
466
+ },
467
+ {
468
+ "internalType": "uint16",
469
+ "name": "pairIndex",
470
+ "type": "uint16"
471
+ },
472
+ {
473
+ "internalType": "uint8",
474
+ "name": "index",
475
+ "type": "uint8"
476
+ }
477
+ ],
478
+ "name": "NoTradeFound",
479
+ "type": "error"
480
+ },
481
+ {
482
+ "inputs": [
483
+ {
484
+ "internalType": "uint256",
485
+ "name": "orderId",
486
+ "type": "uint256"
487
+ }
488
+ ],
489
+ "name": "NoTradeToTimeoutFound",
490
+ "type": "error"
491
+ },
492
+ {
493
+ "inputs": [
494
+ {
495
+ "internalType": "uint256",
496
+ "name": "orderId",
497
+ "type": "uint256"
498
+ }
499
+ ],
500
+ "name": "NotCloseMarketTimeoutOrder",
501
+ "type": "error"
502
+ },
503
+ {
504
+ "inputs": [
505
+ {
506
+ "internalType": "address",
507
+ "name": "trader",
508
+ "type": "address"
509
+ },
510
+ {
511
+ "internalType": "address",
512
+ "name": "caller",
513
+ "type": "address"
514
+ }
515
+ ],
516
+ "name": "NotDelegate",
517
+ "type": "error"
518
+ },
519
+ {
520
+ "inputs": [
521
+ {
522
+ "internalType": "address",
523
+ "name": "a",
524
+ "type": "address"
525
+ }
526
+ ],
527
+ "name": "NotGov",
528
+ "type": "error"
529
+ },
530
+ {
531
+ "inputs": [],
532
+ "name": "NotInitializing",
533
+ "type": "error"
534
+ },
535
+ {
536
+ "inputs": [
537
+ {
538
+ "internalType": "address",
539
+ "name": "a",
540
+ "type": "address"
541
+ }
542
+ ],
543
+ "name": "NotManager",
544
+ "type": "error"
545
+ },
546
+ {
547
+ "inputs": [
548
+ {
549
+ "internalType": "uint256",
550
+ "name": "orderId",
551
+ "type": "uint256"
552
+ }
553
+ ],
554
+ "name": "NotOpenMarketTimeoutOrder",
555
+ "type": "error"
556
+ },
557
+ {
558
+ "inputs": [
559
+ {
560
+ "internalType": "address",
561
+ "name": "a",
562
+ "type": "address"
563
+ }
564
+ ],
565
+ "name": "NotTradesUpKeep",
566
+ "type": "error"
567
+ },
568
+ {
569
+ "inputs": [
570
+ {
571
+ "internalType": "uint256",
572
+ "name": "orderId",
573
+ "type": "uint256"
574
+ },
575
+ {
576
+ "internalType": "address",
577
+ "name": "trader",
578
+ "type": "address"
579
+ }
580
+ ],
581
+ "name": "NotYourOrder",
582
+ "type": "error"
583
+ },
584
+ {
585
+ "inputs": [],
586
+ "name": "NullAddr",
587
+ "type": "error"
588
+ },
589
+ {
590
+ "inputs": [
591
+ {
592
+ "internalType": "uint16",
593
+ "name": "index",
594
+ "type": "uint16"
595
+ }
596
+ ],
597
+ "name": "PairNotListed",
598
+ "type": "error"
599
+ },
600
+ {
601
+ "inputs": [
602
+ {
603
+ "internalType": "uint8",
604
+ "name": "bits",
605
+ "type": "uint8"
606
+ },
607
+ {
608
+ "internalType": "uint256",
609
+ "name": "value",
610
+ "type": "uint256"
611
+ }
612
+ ],
613
+ "name": "SafeCastOverflowedUintDowncast",
614
+ "type": "error"
615
+ },
616
+ {
617
+ "inputs": [],
618
+ "name": "SignatureExpired",
619
+ "type": "error"
620
+ },
621
+ {
622
+ "inputs": [
623
+ {
624
+ "internalType": "address",
625
+ "name": "sender",
626
+ "type": "address"
627
+ },
628
+ {
629
+ "internalType": "uint16",
630
+ "name": "pairIndex",
631
+ "type": "uint16"
632
+ },
633
+ {
634
+ "internalType": "uint8",
635
+ "name": "index",
636
+ "type": "uint8"
637
+ }
638
+ ],
639
+ "name": "TriggerPending",
640
+ "type": "error"
641
+ },
642
+ {
643
+ "inputs": [
644
+ {
645
+ "internalType": "uint256",
646
+ "name": "orderId",
647
+ "type": "uint256"
648
+ }
649
+ ],
650
+ "name": "WaitTimeout",
651
+ "type": "error"
652
+ },
653
+ {
654
+ "inputs": [
655
+ {
656
+ "internalType": "uint32",
657
+ "name": "leverage",
658
+ "type": "uint32"
659
+ }
660
+ ],
661
+ "name": "WrongLeverage",
662
+ "type": "error"
663
+ },
664
+ {
665
+ "inputs": [],
666
+ "name": "WrongParams",
667
+ "type": "error"
668
+ },
669
+ {
670
+ "inputs": [],
671
+ "name": "WrongSL",
672
+ "type": "error"
673
+ },
674
+ {
675
+ "inputs": [],
676
+ "name": "WrongTP",
677
+ "type": "error"
678
+ },
679
+ {
680
+ "anonymous": false,
681
+ "inputs": [
682
+ {
683
+ "indexed": true,
684
+ "internalType": "uint256",
685
+ "name": "orderId",
686
+ "type": "uint256"
687
+ },
688
+ {
689
+ "indexed": true,
690
+ "internalType": "uint256",
691
+ "name": "tradeId",
692
+ "type": "uint256"
693
+ },
694
+ {
695
+ "indexed": true,
696
+ "internalType": "address",
697
+ "name": "trader",
698
+ "type": "address"
699
+ },
700
+ {
701
+ "indexed": false,
702
+ "internalType": "uint16",
703
+ "name": "pairIndex",
704
+ "type": "uint16"
705
+ },
706
+ {
707
+ "indexed": false,
708
+ "internalType": "enum IOstiumTradingStorage.LimitOrder",
709
+ "name": "",
710
+ "type": "uint8"
711
+ }
712
+ ],
713
+ "name": "AutomationCloseOrderInitiated",
714
+ "type": "event"
715
+ },
716
+ {
717
+ "anonymous": false,
718
+ "inputs": [
719
+ {
720
+ "indexed": true,
721
+ "internalType": "uint256",
722
+ "name": "orderId",
723
+ "type": "uint256"
724
+ },
725
+ {
726
+ "indexed": true,
727
+ "internalType": "address",
728
+ "name": "trader",
729
+ "type": "address"
730
+ },
731
+ {
732
+ "indexed": true,
733
+ "internalType": "uint16",
734
+ "name": "pairIndex",
735
+ "type": "uint16"
736
+ },
737
+ {
738
+ "indexed": false,
739
+ "internalType": "uint8",
740
+ "name": "index",
741
+ "type": "uint8"
742
+ }
743
+ ],
744
+ "name": "AutomationOpenOrderInitiated",
745
+ "type": "event"
746
+ },
747
+ {
748
+ "anonymous": false,
749
+ "inputs": [
750
+ {
751
+ "indexed": true,
752
+ "internalType": "address",
753
+ "name": "delegator",
754
+ "type": "address"
755
+ },
756
+ {
757
+ "indexed": true,
758
+ "internalType": "address",
759
+ "name": "delegate",
760
+ "type": "address"
761
+ }
762
+ ],
763
+ "name": "DelegateAdded",
764
+ "type": "event"
765
+ },
766
+ {
767
+ "anonymous": false,
768
+ "inputs": [
769
+ {
770
+ "indexed": true,
771
+ "internalType": "address",
772
+ "name": "delegator",
773
+ "type": "address"
774
+ },
775
+ {
776
+ "indexed": true,
777
+ "internalType": "address",
778
+ "name": "delegate",
779
+ "type": "address"
780
+ }
781
+ ],
782
+ "name": "DelegateRemoved",
783
+ "type": "event"
784
+ },
785
+ {
786
+ "anonymous": false,
787
+ "inputs": [
788
+ {
789
+ "indexed": false,
790
+ "internalType": "bool",
791
+ "name": "done",
792
+ "type": "bool"
793
+ }
794
+ ],
795
+ "name": "Done",
796
+ "type": "event"
797
+ },
798
+ {
799
+ "anonymous": false,
800
+ "inputs": [
801
+ {
802
+ "indexed": false,
803
+ "internalType": "uint64",
804
+ "name": "version",
805
+ "type": "uint64"
806
+ }
807
+ ],
808
+ "name": "Initialized",
809
+ "type": "event"
810
+ },
811
+ {
812
+ "anonymous": false,
813
+ "inputs": [
814
+ {
815
+ "indexed": true,
816
+ "internalType": "uint256",
817
+ "name": "tradeId",
818
+ "type": "uint256"
819
+ },
820
+ {
821
+ "indexed": true,
822
+ "internalType": "address",
823
+ "name": "trader",
824
+ "type": "address"
825
+ },
826
+ {
827
+ "indexed": true,
828
+ "internalType": "uint16",
829
+ "name": "pairIndex",
830
+ "type": "uint16"
831
+ }
832
+ ],
833
+ "name": "MarketCloseFailed",
834
+ "type": "event"
835
+ },
836
+ {
837
+ "anonymous": false,
838
+ "inputs": [
839
+ {
840
+ "indexed": true,
841
+ "internalType": "uint256",
842
+ "name": "orderId",
843
+ "type": "uint256"
844
+ },
845
+ {
846
+ "indexed": true,
847
+ "internalType": "uint256",
848
+ "name": "tradeId",
849
+ "type": "uint256"
850
+ },
851
+ {
852
+ "indexed": true,
853
+ "internalType": "address",
854
+ "name": "trader",
855
+ "type": "address"
856
+ },
857
+ {
858
+ "indexed": false,
859
+ "internalType": "uint16",
860
+ "name": "pairIndex",
861
+ "type": "uint16"
862
+ }
863
+ ],
864
+ "name": "MarketCloseOrderInitiated",
865
+ "type": "event"
866
+ },
867
+ {
868
+ "anonymous": false,
869
+ "inputs": [
870
+ {
871
+ "indexed": true,
872
+ "internalType": "uint256",
873
+ "name": "orderId",
874
+ "type": "uint256"
875
+ },
876
+ {
877
+ "indexed": true,
878
+ "internalType": "uint256",
879
+ "name": "tradeId",
880
+ "type": "uint256"
881
+ },
882
+ {
883
+ "indexed": true,
884
+ "internalType": "address",
885
+ "name": "trader",
886
+ "type": "address"
887
+ },
888
+ {
889
+ "indexed": false,
890
+ "internalType": "uint16",
891
+ "name": "pairIndex",
892
+ "type": "uint16"
893
+ },
894
+ {
895
+ "indexed": false,
896
+ "internalType": "uint16",
897
+ "name": "closePercentage",
898
+ "type": "uint16"
899
+ }
900
+ ],
901
+ "name": "MarketCloseOrderInitiatedV2",
902
+ "type": "event"
903
+ },
904
+ {
905
+ "anonymous": false,
906
+ "inputs": [
907
+ {
908
+ "indexed": true,
909
+ "internalType": "uint256",
910
+ "name": "orderId",
911
+ "type": "uint256"
912
+ },
913
+ {
914
+ "indexed": true,
915
+ "internalType": "uint256",
916
+ "name": "tradeId",
917
+ "type": "uint256"
918
+ },
919
+ {
920
+ "components": [
921
+ {
922
+ "internalType": "uint256",
923
+ "name": "block",
924
+ "type": "uint256"
925
+ },
926
+ {
927
+ "internalType": "uint192",
928
+ "name": "wantedPrice",
929
+ "type": "uint192"
930
+ },
931
+ {
932
+ "internalType": "uint32",
933
+ "name": "slippageP",
934
+ "type": "uint32"
935
+ },
936
+ {
937
+ "components": [
938
+ {
939
+ "internalType": "uint256",
940
+ "name": "collateral",
941
+ "type": "uint256"
942
+ },
943
+ {
944
+ "internalType": "uint192",
945
+ "name": "openPrice",
946
+ "type": "uint192"
947
+ },
948
+ {
949
+ "internalType": "uint192",
950
+ "name": "tp",
951
+ "type": "uint192"
952
+ },
953
+ {
954
+ "internalType": "uint192",
955
+ "name": "sl",
956
+ "type": "uint192"
957
+ },
958
+ {
959
+ "internalType": "address",
960
+ "name": "trader",
961
+ "type": "address"
962
+ },
963
+ {
964
+ "internalType": "uint32",
965
+ "name": "leverage",
966
+ "type": "uint32"
967
+ },
968
+ {
969
+ "internalType": "uint16",
970
+ "name": "pairIndex",
971
+ "type": "uint16"
972
+ },
973
+ {
974
+ "internalType": "uint8",
975
+ "name": "index",
976
+ "type": "uint8"
977
+ },
978
+ {
979
+ "internalType": "bool",
980
+ "name": "buy",
981
+ "type": "bool"
982
+ },
983
+ {
984
+ "internalType": "bool",
985
+ "name": "isDayTrade",
986
+ "type": "bool"
987
+ }
988
+ ],
989
+ "internalType": "struct IOstiumTradingStorage.Trade",
990
+ "name": "trade",
991
+ "type": "tuple"
992
+ }
993
+ ],
994
+ "indexed": false,
995
+ "internalType": "struct IOstiumTradingStorage.PendingMarketOrder",
996
+ "name": "order",
997
+ "type": "tuple"
998
+ }
999
+ ],
1000
+ "name": "MarketCloseTimeoutExecuted",
1001
+ "type": "event"
1002
+ },
1003
+ {
1004
+ "anonymous": false,
1005
+ "inputs": [
1006
+ {
1007
+ "indexed": true,
1008
+ "internalType": "uint256",
1009
+ "name": "orderId",
1010
+ "type": "uint256"
1011
+ },
1012
+ {
1013
+ "indexed": true,
1014
+ "internalType": "uint256",
1015
+ "name": "tradeId",
1016
+ "type": "uint256"
1017
+ },
1018
+ {
1019
+ "components": [
1020
+ {
1021
+ "internalType": "uint256",
1022
+ "name": "block",
1023
+ "type": "uint256"
1024
+ },
1025
+ {
1026
+ "internalType": "uint192",
1027
+ "name": "wantedPrice",
1028
+ "type": "uint192"
1029
+ },
1030
+ {
1031
+ "internalType": "uint32",
1032
+ "name": "slippageP",
1033
+ "type": "uint32"
1034
+ },
1035
+ {
1036
+ "components": [
1037
+ {
1038
+ "internalType": "uint256",
1039
+ "name": "collateral",
1040
+ "type": "uint256"
1041
+ },
1042
+ {
1043
+ "internalType": "uint192",
1044
+ "name": "openPrice",
1045
+ "type": "uint192"
1046
+ },
1047
+ {
1048
+ "internalType": "uint192",
1049
+ "name": "tp",
1050
+ "type": "uint192"
1051
+ },
1052
+ {
1053
+ "internalType": "uint192",
1054
+ "name": "sl",
1055
+ "type": "uint192"
1056
+ },
1057
+ {
1058
+ "internalType": "address",
1059
+ "name": "trader",
1060
+ "type": "address"
1061
+ },
1062
+ {
1063
+ "internalType": "uint32",
1064
+ "name": "leverage",
1065
+ "type": "uint32"
1066
+ },
1067
+ {
1068
+ "internalType": "uint16",
1069
+ "name": "pairIndex",
1070
+ "type": "uint16"
1071
+ },
1072
+ {
1073
+ "internalType": "uint8",
1074
+ "name": "index",
1075
+ "type": "uint8"
1076
+ },
1077
+ {
1078
+ "internalType": "bool",
1079
+ "name": "buy",
1080
+ "type": "bool"
1081
+ },
1082
+ {
1083
+ "internalType": "bool",
1084
+ "name": "isDayTrade",
1085
+ "type": "bool"
1086
+ }
1087
+ ],
1088
+ "internalType": "struct IOstiumTradingStorage.Trade",
1089
+ "name": "trade",
1090
+ "type": "tuple"
1091
+ },
1092
+ {
1093
+ "internalType": "uint16",
1094
+ "name": "percentage",
1095
+ "type": "uint16"
1096
+ }
1097
+ ],
1098
+ "indexed": false,
1099
+ "internalType": "struct IOstiumTradingStorage.PendingMarketOrderV2",
1100
+ "name": "order",
1101
+ "type": "tuple"
1102
+ }
1103
+ ],
1104
+ "name": "MarketCloseTimeoutExecutedV2",
1105
+ "type": "event"
1106
+ },
1107
+ {
1108
+ "anonymous": false,
1109
+ "inputs": [
1110
+ {
1111
+ "indexed": true,
1112
+ "internalType": "uint256",
1113
+ "name": "orderId",
1114
+ "type": "uint256"
1115
+ },
1116
+ {
1117
+ "indexed": true,
1118
+ "internalType": "address",
1119
+ "name": "trader",
1120
+ "type": "address"
1121
+ },
1122
+ {
1123
+ "indexed": true,
1124
+ "internalType": "uint16",
1125
+ "name": "pairIndex",
1126
+ "type": "uint16"
1127
+ }
1128
+ ],
1129
+ "name": "MarketOpenOrderInitiated",
1130
+ "type": "event"
1131
+ },
1132
+ {
1133
+ "anonymous": false,
1134
+ "inputs": [
1135
+ {
1136
+ "indexed": true,
1137
+ "internalType": "uint256",
1138
+ "name": "orderId",
1139
+ "type": "uint256"
1140
+ },
1141
+ {
1142
+ "components": [
1143
+ {
1144
+ "internalType": "uint256",
1145
+ "name": "block",
1146
+ "type": "uint256"
1147
+ },
1148
+ {
1149
+ "internalType": "uint192",
1150
+ "name": "wantedPrice",
1151
+ "type": "uint192"
1152
+ },
1153
+ {
1154
+ "internalType": "uint32",
1155
+ "name": "slippageP",
1156
+ "type": "uint32"
1157
+ },
1158
+ {
1159
+ "components": [
1160
+ {
1161
+ "internalType": "uint256",
1162
+ "name": "collateral",
1163
+ "type": "uint256"
1164
+ },
1165
+ {
1166
+ "internalType": "uint192",
1167
+ "name": "openPrice",
1168
+ "type": "uint192"
1169
+ },
1170
+ {
1171
+ "internalType": "uint192",
1172
+ "name": "tp",
1173
+ "type": "uint192"
1174
+ },
1175
+ {
1176
+ "internalType": "uint192",
1177
+ "name": "sl",
1178
+ "type": "uint192"
1179
+ },
1180
+ {
1181
+ "internalType": "address",
1182
+ "name": "trader",
1183
+ "type": "address"
1184
+ },
1185
+ {
1186
+ "internalType": "uint32",
1187
+ "name": "leverage",
1188
+ "type": "uint32"
1189
+ },
1190
+ {
1191
+ "internalType": "uint16",
1192
+ "name": "pairIndex",
1193
+ "type": "uint16"
1194
+ },
1195
+ {
1196
+ "internalType": "uint8",
1197
+ "name": "index",
1198
+ "type": "uint8"
1199
+ },
1200
+ {
1201
+ "internalType": "bool",
1202
+ "name": "buy",
1203
+ "type": "bool"
1204
+ },
1205
+ {
1206
+ "internalType": "bool",
1207
+ "name": "isDayTrade",
1208
+ "type": "bool"
1209
+ }
1210
+ ],
1211
+ "internalType": "struct IOstiumTradingStorage.Trade",
1212
+ "name": "trade",
1213
+ "type": "tuple"
1214
+ }
1215
+ ],
1216
+ "indexed": false,
1217
+ "internalType": "struct IOstiumTradingStorage.PendingMarketOrder",
1218
+ "name": "order",
1219
+ "type": "tuple"
1220
+ }
1221
+ ],
1222
+ "name": "MarketOpenTimeoutExecuted",
1223
+ "type": "event"
1224
+ },
1225
+ {
1226
+ "anonymous": false,
1227
+ "inputs": [
1228
+ {
1229
+ "indexed": true,
1230
+ "internalType": "uint256",
1231
+ "name": "orderId",
1232
+ "type": "uint256"
1233
+ },
1234
+ {
1235
+ "components": [
1236
+ {
1237
+ "internalType": "uint256",
1238
+ "name": "block",
1239
+ "type": "uint256"
1240
+ },
1241
+ {
1242
+ "internalType": "uint192",
1243
+ "name": "wantedPrice",
1244
+ "type": "uint192"
1245
+ },
1246
+ {
1247
+ "internalType": "uint32",
1248
+ "name": "slippageP",
1249
+ "type": "uint32"
1250
+ },
1251
+ {
1252
+ "components": [
1253
+ {
1254
+ "internalType": "uint256",
1255
+ "name": "collateral",
1256
+ "type": "uint256"
1257
+ },
1258
+ {
1259
+ "internalType": "uint192",
1260
+ "name": "openPrice",
1261
+ "type": "uint192"
1262
+ },
1263
+ {
1264
+ "internalType": "uint192",
1265
+ "name": "tp",
1266
+ "type": "uint192"
1267
+ },
1268
+ {
1269
+ "internalType": "uint192",
1270
+ "name": "sl",
1271
+ "type": "uint192"
1272
+ },
1273
+ {
1274
+ "internalType": "address",
1275
+ "name": "trader",
1276
+ "type": "address"
1277
+ },
1278
+ {
1279
+ "internalType": "uint32",
1280
+ "name": "leverage",
1281
+ "type": "uint32"
1282
+ },
1283
+ {
1284
+ "internalType": "uint16",
1285
+ "name": "pairIndex",
1286
+ "type": "uint16"
1287
+ },
1288
+ {
1289
+ "internalType": "uint8",
1290
+ "name": "index",
1291
+ "type": "uint8"
1292
+ },
1293
+ {
1294
+ "internalType": "bool",
1295
+ "name": "buy",
1296
+ "type": "bool"
1297
+ },
1298
+ {
1299
+ "internalType": "bool",
1300
+ "name": "isDayTrade",
1301
+ "type": "bool"
1302
+ }
1303
+ ],
1304
+ "internalType": "struct IOstiumTradingStorage.Trade",
1305
+ "name": "trade",
1306
+ "type": "tuple"
1307
+ },
1308
+ {
1309
+ "internalType": "uint16",
1310
+ "name": "percentage",
1311
+ "type": "uint16"
1312
+ }
1313
+ ],
1314
+ "indexed": false,
1315
+ "internalType": "struct IOstiumTradingStorage.PendingMarketOrderV2",
1316
+ "name": "order",
1317
+ "type": "tuple"
1318
+ }
1319
+ ],
1320
+ "name": "MarketOpenTimeoutExecutedV2",
1321
+ "type": "event"
1322
+ },
1323
+ {
1324
+ "anonymous": false,
1325
+ "inputs": [
1326
+ {
1327
+ "indexed": false,
1328
+ "internalType": "uint16",
1329
+ "name": "value",
1330
+ "type": "uint16"
1331
+ }
1332
+ ],
1333
+ "name": "MarketOrdersTimeoutUpdated",
1334
+ "type": "event"
1335
+ },
1336
+ {
1337
+ "anonymous": false,
1338
+ "inputs": [
1339
+ {
1340
+ "indexed": false,
1341
+ "internalType": "uint256",
1342
+ "name": "value",
1343
+ "type": "uint256"
1344
+ }
1345
+ ],
1346
+ "name": "MaxAllowedCollateralUpdated",
1347
+ "type": "event"
1348
+ },
1349
+ {
1350
+ "anonymous": false,
1351
+ "inputs": [
1352
+ {
1353
+ "indexed": true,
1354
+ "internalType": "address",
1355
+ "name": "trader",
1356
+ "type": "address"
1357
+ },
1358
+ {
1359
+ "indexed": true,
1360
+ "internalType": "uint16",
1361
+ "name": "pairIndex",
1362
+ "type": "uint16"
1363
+ },
1364
+ {
1365
+ "indexed": false,
1366
+ "internalType": "uint8",
1367
+ "name": "index",
1368
+ "type": "uint8"
1369
+ }
1370
+ ],
1371
+ "name": "OpenLimitCanceled",
1372
+ "type": "event"
1373
+ },
1374
+ {
1375
+ "anonymous": false,
1376
+ "inputs": [
1377
+ {
1378
+ "indexed": true,
1379
+ "internalType": "address",
1380
+ "name": "trader",
1381
+ "type": "address"
1382
+ },
1383
+ {
1384
+ "indexed": true,
1385
+ "internalType": "uint16",
1386
+ "name": "pairIndex",
1387
+ "type": "uint16"
1388
+ },
1389
+ {
1390
+ "indexed": false,
1391
+ "internalType": "uint8",
1392
+ "name": "index",
1393
+ "type": "uint8"
1394
+ }
1395
+ ],
1396
+ "name": "OpenLimitPlaced",
1397
+ "type": "event"
1398
+ },
1399
+ {
1400
+ "anonymous": false,
1401
+ "inputs": [
1402
+ {
1403
+ "indexed": true,
1404
+ "internalType": "address",
1405
+ "name": "trader",
1406
+ "type": "address"
1407
+ },
1408
+ {
1409
+ "indexed": true,
1410
+ "internalType": "uint16",
1411
+ "name": "pairIndex",
1412
+ "type": "uint16"
1413
+ },
1414
+ {
1415
+ "indexed": false,
1416
+ "internalType": "uint8",
1417
+ "name": "index",
1418
+ "type": "uint8"
1419
+ },
1420
+ {
1421
+ "components": [
1422
+ {
1423
+ "internalType": "uint256",
1424
+ "name": "collateral",
1425
+ "type": "uint256"
1426
+ },
1427
+ {
1428
+ "internalType": "uint192",
1429
+ "name": "openPrice",
1430
+ "type": "uint192"
1431
+ },
1432
+ {
1433
+ "internalType": "uint192",
1434
+ "name": "tp",
1435
+ "type": "uint192"
1436
+ },
1437
+ {
1438
+ "internalType": "uint192",
1439
+ "name": "sl",
1440
+ "type": "uint192"
1441
+ },
1442
+ {
1443
+ "internalType": "address",
1444
+ "name": "trader",
1445
+ "type": "address"
1446
+ },
1447
+ {
1448
+ "internalType": "uint32",
1449
+ "name": "leverage",
1450
+ "type": "uint32"
1451
+ },
1452
+ {
1453
+ "internalType": "uint16",
1454
+ "name": "pairIndex",
1455
+ "type": "uint16"
1456
+ },
1457
+ {
1458
+ "internalType": "uint8",
1459
+ "name": "index",
1460
+ "type": "uint8"
1461
+ },
1462
+ {
1463
+ "internalType": "bool",
1464
+ "name": "buy",
1465
+ "type": "bool"
1466
+ },
1467
+ {
1468
+ "internalType": "bool",
1469
+ "name": "isDayTrade",
1470
+ "type": "bool"
1471
+ }
1472
+ ],
1473
+ "indexed": false,
1474
+ "internalType": "struct IOstiumTradingStorage.Trade",
1475
+ "name": "trade",
1476
+ "type": "tuple"
1477
+ },
1478
+ {
1479
+ "indexed": false,
1480
+ "internalType": "enum IOstiumTradingStorage.OpenOrderType",
1481
+ "name": "orderType",
1482
+ "type": "uint8"
1483
+ },
1484
+ {
1485
+ "components": [
1486
+ {
1487
+ "internalType": "address",
1488
+ "name": "builder",
1489
+ "type": "address"
1490
+ },
1491
+ {
1492
+ "internalType": "uint32",
1493
+ "name": "builderFee",
1494
+ "type": "uint32"
1495
+ }
1496
+ ],
1497
+ "indexed": false,
1498
+ "internalType": "struct IOstiumTradingStorage.BuilderFee",
1499
+ "name": "builderFee",
1500
+ "type": "tuple"
1501
+ }
1502
+ ],
1503
+ "name": "OpenLimitPlacedV2",
1504
+ "type": "event"
1505
+ },
1506
+ {
1507
+ "anonymous": false,
1508
+ "inputs": [
1509
+ {
1510
+ "indexed": true,
1511
+ "internalType": "address",
1512
+ "name": "trader",
1513
+ "type": "address"
1514
+ },
1515
+ {
1516
+ "indexed": true,
1517
+ "internalType": "uint16",
1518
+ "name": "pairIndex",
1519
+ "type": "uint16"
1520
+ },
1521
+ {
1522
+ "indexed": false,
1523
+ "internalType": "uint8",
1524
+ "name": "index",
1525
+ "type": "uint8"
1526
+ },
1527
+ {
1528
+ "indexed": false,
1529
+ "internalType": "uint192",
1530
+ "name": "newPrice",
1531
+ "type": "uint192"
1532
+ },
1533
+ {
1534
+ "indexed": false,
1535
+ "internalType": "uint192",
1536
+ "name": "newTp",
1537
+ "type": "uint192"
1538
+ },
1539
+ {
1540
+ "indexed": false,
1541
+ "internalType": "uint192",
1542
+ "name": "newSl",
1543
+ "type": "uint192"
1544
+ }
1545
+ ],
1546
+ "name": "OpenLimitUpdated",
1547
+ "type": "event"
1548
+ },
1549
+ {
1550
+ "anonymous": false,
1551
+ "inputs": [
1552
+ {
1553
+ "indexed": true,
1554
+ "internalType": "uint256",
1555
+ "name": "tradeId",
1556
+ "type": "uint256"
1557
+ },
1558
+ {
1559
+ "indexed": true,
1560
+ "internalType": "address",
1561
+ "name": "trader",
1562
+ "type": "address"
1563
+ },
1564
+ {
1565
+ "indexed": false,
1566
+ "internalType": "uint16",
1567
+ "name": "pairIndex",
1568
+ "type": "uint16"
1569
+ },
1570
+ {
1571
+ "indexed": false,
1572
+ "internalType": "uint256",
1573
+ "name": "amount",
1574
+ "type": "uint256"
1575
+ }
1576
+ ],
1577
+ "name": "OracleFeeCharged",
1578
+ "type": "event"
1579
+ },
1580
+ {
1581
+ "anonymous": false,
1582
+ "inputs": [
1583
+ {
1584
+ "indexed": true,
1585
+ "internalType": "address",
1586
+ "name": "trader",
1587
+ "type": "address"
1588
+ },
1589
+ {
1590
+ "indexed": false,
1591
+ "internalType": "uint16",
1592
+ "name": "pairIndex",
1593
+ "type": "uint16"
1594
+ },
1595
+ {
1596
+ "indexed": false,
1597
+ "internalType": "uint256",
1598
+ "name": "amount",
1599
+ "type": "uint256"
1600
+ }
1601
+ ],
1602
+ "name": "OracleFeeChargedLimitCancelled",
1603
+ "type": "event"
1604
+ },
1605
+ {
1606
+ "anonymous": false,
1607
+ "inputs": [
1608
+ {
1609
+ "indexed": true,
1610
+ "internalType": "uint256",
1611
+ "name": "tradeId",
1612
+ "type": "uint256"
1613
+ },
1614
+ {
1615
+ "indexed": true,
1616
+ "internalType": "address",
1617
+ "name": "trader",
1618
+ "type": "address"
1619
+ },
1620
+ {
1621
+ "indexed": false,
1622
+ "internalType": "uint16",
1623
+ "name": "pairIndex",
1624
+ "type": "uint16"
1625
+ },
1626
+ {
1627
+ "indexed": false,
1628
+ "internalType": "uint256",
1629
+ "name": "amount",
1630
+ "type": "uint256"
1631
+ }
1632
+ ],
1633
+ "name": "OracleFeeRefunded",
1634
+ "type": "event"
1635
+ },
1636
+ {
1637
+ "anonymous": false,
1638
+ "inputs": [
1639
+ {
1640
+ "indexed": false,
1641
+ "internalType": "bool",
1642
+ "name": "paused",
1643
+ "type": "bool"
1644
+ }
1645
+ ],
1646
+ "name": "Paused",
1647
+ "type": "event"
1648
+ },
1649
+ {
1650
+ "anonymous": false,
1651
+ "inputs": [
1652
+ {
1653
+ "indexed": true,
1654
+ "internalType": "uint256",
1655
+ "name": "tradeId",
1656
+ "type": "uint256"
1657
+ },
1658
+ {
1659
+ "indexed": true,
1660
+ "internalType": "uint256",
1661
+ "name": "orderId",
1662
+ "type": "uint256"
1663
+ },
1664
+ {
1665
+ "indexed": true,
1666
+ "internalType": "address",
1667
+ "name": "trader",
1668
+ "type": "address"
1669
+ },
1670
+ {
1671
+ "indexed": false,
1672
+ "internalType": "uint16",
1673
+ "name": "pairIndex",
1674
+ "type": "uint16"
1675
+ },
1676
+ {
1677
+ "indexed": false,
1678
+ "internalType": "uint256",
1679
+ "name": "removeAmount",
1680
+ "type": "uint256"
1681
+ }
1682
+ ],
1683
+ "name": "RemoveCollateralInitiated",
1684
+ "type": "event"
1685
+ },
1686
+ {
1687
+ "anonymous": false,
1688
+ "inputs": [
1689
+ {
1690
+ "indexed": true,
1691
+ "internalType": "uint256",
1692
+ "name": "tradeId",
1693
+ "type": "uint256"
1694
+ },
1695
+ {
1696
+ "indexed": true,
1697
+ "internalType": "uint256",
1698
+ "name": "orderId",
1699
+ "type": "uint256"
1700
+ },
1701
+ {
1702
+ "indexed": true,
1703
+ "internalType": "address",
1704
+ "name": "trader",
1705
+ "type": "address"
1706
+ },
1707
+ {
1708
+ "indexed": false,
1709
+ "internalType": "uint16",
1710
+ "name": "pairIndex",
1711
+ "type": "uint16"
1712
+ },
1713
+ {
1714
+ "indexed": false,
1715
+ "internalType": "uint256",
1716
+ "name": "removeAmount",
1717
+ "type": "uint256"
1718
+ },
1719
+ {
1720
+ "indexed": false,
1721
+ "internalType": "string",
1722
+ "name": "reason",
1723
+ "type": "string"
1724
+ }
1725
+ ],
1726
+ "name": "RemoveCollateralRejected",
1727
+ "type": "event"
1728
+ },
1729
+ {
1730
+ "anonymous": false,
1731
+ "inputs": [
1732
+ {
1733
+ "indexed": true,
1734
+ "internalType": "uint256",
1735
+ "name": "tradeId",
1736
+ "type": "uint256"
1737
+ },
1738
+ {
1739
+ "indexed": true,
1740
+ "internalType": "address",
1741
+ "name": "trader",
1742
+ "type": "address"
1743
+ },
1744
+ {
1745
+ "indexed": true,
1746
+ "internalType": "uint16",
1747
+ "name": "pairIndex",
1748
+ "type": "uint16"
1749
+ },
1750
+ {
1751
+ "indexed": false,
1752
+ "internalType": "uint8",
1753
+ "name": "index",
1754
+ "type": "uint8"
1755
+ },
1756
+ {
1757
+ "indexed": false,
1758
+ "internalType": "uint192",
1759
+ "name": "newSl",
1760
+ "type": "uint192"
1761
+ }
1762
+ ],
1763
+ "name": "SlUpdated",
1764
+ "type": "event"
1765
+ },
1766
+ {
1767
+ "anonymous": false,
1768
+ "inputs": [
1769
+ {
1770
+ "indexed": true,
1771
+ "internalType": "uint256",
1772
+ "name": "tradeId",
1773
+ "type": "uint256"
1774
+ },
1775
+ {
1776
+ "indexed": true,
1777
+ "internalType": "address",
1778
+ "name": "trader",
1779
+ "type": "address"
1780
+ },
1781
+ {
1782
+ "indexed": true,
1783
+ "internalType": "uint16",
1784
+ "name": "pairIndex",
1785
+ "type": "uint16"
1786
+ },
1787
+ {
1788
+ "indexed": false,
1789
+ "internalType": "uint256",
1790
+ "name": "topUpAmount",
1791
+ "type": "uint256"
1792
+ },
1793
+ {
1794
+ "indexed": false,
1795
+ "internalType": "uint32",
1796
+ "name": "newLeverage",
1797
+ "type": "uint32"
1798
+ }
1799
+ ],
1800
+ "name": "TopUpCollateralExecuted",
1801
+ "type": "event"
1802
+ },
1803
+ {
1804
+ "anonymous": false,
1805
+ "inputs": [
1806
+ {
1807
+ "indexed": true,
1808
+ "internalType": "uint256",
1809
+ "name": "tradeId",
1810
+ "type": "uint256"
1811
+ },
1812
+ {
1813
+ "indexed": true,
1814
+ "internalType": "address",
1815
+ "name": "trader",
1816
+ "type": "address"
1817
+ },
1818
+ {
1819
+ "indexed": true,
1820
+ "internalType": "uint16",
1821
+ "name": "pairIndex",
1822
+ "type": "uint16"
1823
+ },
1824
+ {
1825
+ "indexed": false,
1826
+ "internalType": "uint8",
1827
+ "name": "index",
1828
+ "type": "uint8"
1829
+ },
1830
+ {
1831
+ "indexed": false,
1832
+ "internalType": "uint192",
1833
+ "name": "newTp",
1834
+ "type": "uint192"
1835
+ }
1836
+ ],
1837
+ "name": "TpUpdated",
1838
+ "type": "event"
1839
+ },
1840
+ {
1841
+ "anonymous": false,
1842
+ "inputs": [
1843
+ {
1844
+ "indexed": false,
1845
+ "internalType": "uint16",
1846
+ "name": "value",
1847
+ "type": "uint16"
1848
+ }
1849
+ ],
1850
+ "name": "TriggerTimeoutUpdated",
1851
+ "type": "event"
1852
+ },
1853
+ {
1854
+ "inputs": [],
1855
+ "name": "DELEGATION_TYPEHASH",
1856
+ "outputs": [
1857
+ {
1858
+ "internalType": "bytes32",
1859
+ "name": "",
1860
+ "type": "bytes32"
1861
+ }
1862
+ ],
1863
+ "stateMutability": "view",
1864
+ "type": "function"
1865
+ },
1866
+ {
1867
+ "inputs": [],
1868
+ "name": "DOMAIN_SEPARATOR",
1869
+ "outputs": [
1870
+ {
1871
+ "internalType": "bytes32",
1872
+ "name": "",
1873
+ "type": "bytes32"
1874
+ }
1875
+ ],
1876
+ "stateMutability": "view",
1877
+ "type": "function"
1878
+ },
1879
+ {
1880
+ "inputs": [],
1881
+ "name": "_msgSender",
1882
+ "outputs": [
1883
+ {
1884
+ "internalType": "address",
1885
+ "name": "",
1886
+ "type": "address"
1887
+ }
1888
+ ],
1889
+ "stateMutability": "view",
1890
+ "type": "function"
1891
+ },
1892
+ {
1893
+ "inputs": [
1894
+ {
1895
+ "internalType": "uint16",
1896
+ "name": "pairIndex",
1897
+ "type": "uint16"
1898
+ },
1899
+ {
1900
+ "internalType": "uint8",
1901
+ "name": "index",
1902
+ "type": "uint8"
1903
+ }
1904
+ ],
1905
+ "name": "cancelOpenLimitOrder",
1906
+ "outputs": [],
1907
+ "stateMutability": "nonpayable",
1908
+ "type": "function"
1909
+ },
1910
+ {
1911
+ "inputs": [
1912
+ {
1913
+ "internalType": "uint16",
1914
+ "name": "pairIndex",
1915
+ "type": "uint16"
1916
+ },
1917
+ {
1918
+ "internalType": "uint8",
1919
+ "name": "index",
1920
+ "type": "uint8"
1921
+ },
1922
+ {
1923
+ "internalType": "uint16",
1924
+ "name": "closePercentage",
1925
+ "type": "uint16"
1926
+ },
1927
+ {
1928
+ "internalType": "uint192",
1929
+ "name": "marketPrice",
1930
+ "type": "uint192"
1931
+ },
1932
+ {
1933
+ "internalType": "uint32",
1934
+ "name": "slippageP",
1935
+ "type": "uint32"
1936
+ }
1937
+ ],
1938
+ "name": "closeTradeMarket",
1939
+ "outputs": [],
1940
+ "stateMutability": "nonpayable",
1941
+ "type": "function"
1942
+ },
1943
+ {
1944
+ "inputs": [
1945
+ {
1946
+ "internalType": "uint256",
1947
+ "name": "_order",
1948
+ "type": "uint256"
1949
+ },
1950
+ {
1951
+ "internalType": "bool",
1952
+ "name": "retry",
1953
+ "type": "bool"
1954
+ }
1955
+ ],
1956
+ "name": "closeTradeMarketTimeout",
1957
+ "outputs": [],
1958
+ "stateMutability": "nonpayable",
1959
+ "type": "function"
1960
+ },
1961
+ {
1962
+ "inputs": [
1963
+ {
1964
+ "internalType": "address",
1965
+ "name": "",
1966
+ "type": "address"
1967
+ }
1968
+ ],
1969
+ "name": "delegatableNonces",
1970
+ "outputs": [
1971
+ {
1972
+ "internalType": "uint256",
1973
+ "name": "",
1974
+ "type": "uint256"
1975
+ }
1976
+ ],
1977
+ "stateMutability": "view",
1978
+ "type": "function"
1979
+ },
1980
+ {
1981
+ "inputs": [
1982
+ {
1983
+ "internalType": "address",
1984
+ "name": "trader",
1985
+ "type": "address"
1986
+ },
1987
+ {
1988
+ "internalType": "bytes",
1989
+ "name": "call_data",
1990
+ "type": "bytes"
1991
+ }
1992
+ ],
1993
+ "name": "delegatedAction",
1994
+ "outputs": [
1995
+ {
1996
+ "internalType": "bytes",
1997
+ "name": "",
1998
+ "type": "bytes"
1999
+ }
2000
+ ],
2001
+ "stateMutability": "nonpayable",
2002
+ "type": "function"
2003
+ },
2004
+ {
2005
+ "inputs": [
2006
+ {
2007
+ "internalType": "address",
2008
+ "name": "delegator",
2009
+ "type": "address"
2010
+ }
2011
+ ],
2012
+ "name": "delegations",
2013
+ "outputs": [
2014
+ {
2015
+ "internalType": "address",
2016
+ "name": "",
2017
+ "type": "address"
2018
+ }
2019
+ ],
2020
+ "stateMutability": "view",
2021
+ "type": "function"
2022
+ },
2023
+ {
2024
+ "inputs": [],
2025
+ "name": "done",
2026
+ "outputs": [],
2027
+ "stateMutability": "nonpayable",
2028
+ "type": "function"
2029
+ },
2030
+ {
2031
+ "inputs": [
2032
+ {
2033
+ "internalType": "enum IOstiumTradingStorage.LimitOrder",
2034
+ "name": "orderType",
2035
+ "type": "uint8"
2036
+ },
2037
+ {
2038
+ "internalType": "address",
2039
+ "name": "trader",
2040
+ "type": "address"
2041
+ },
2042
+ {
2043
+ "internalType": "uint16",
2044
+ "name": "pairIndex",
2045
+ "type": "uint16"
2046
+ },
2047
+ {
2048
+ "internalType": "uint8",
2049
+ "name": "index",
2050
+ "type": "uint8"
2051
+ },
2052
+ {
2053
+ "internalType": "uint256",
2054
+ "name": "priceTimestamp",
2055
+ "type": "uint256"
2056
+ }
2057
+ ],
2058
+ "name": "executeAutomationOrder",
2059
+ "outputs": [
2060
+ {
2061
+ "internalType": "enum IOstiumTrading.AutomationOrderStatus",
2062
+ "name": "",
2063
+ "type": "uint8"
2064
+ }
2065
+ ],
2066
+ "stateMutability": "nonpayable",
2067
+ "type": "function"
2068
+ },
2069
+ {
2070
+ "inputs": [
2071
+ {
2072
+ "internalType": "contract IOstiumRegistry",
2073
+ "name": "_registry",
2074
+ "type": "address"
2075
+ },
2076
+ {
2077
+ "internalType": "uint256",
2078
+ "name": "_maxAllowedCollateral",
2079
+ "type": "uint256"
2080
+ },
2081
+ {
2082
+ "internalType": "uint16",
2083
+ "name": "_marketOrdersTimeout",
2084
+ "type": "uint16"
2085
+ },
2086
+ {
2087
+ "internalType": "uint16",
2088
+ "name": "_triggerTimeout",
2089
+ "type": "uint16"
2090
+ }
2091
+ ],
2092
+ "name": "initialize",
2093
+ "outputs": [],
2094
+ "stateMutability": "nonpayable",
2095
+ "type": "function"
2096
+ },
2097
+ {
2098
+ "inputs": [],
2099
+ "name": "isDone",
2100
+ "outputs": [
2101
+ {
2102
+ "internalType": "bool",
2103
+ "name": "",
2104
+ "type": "bool"
2105
+ }
2106
+ ],
2107
+ "stateMutability": "view",
2108
+ "type": "function"
2109
+ },
2110
+ {
2111
+ "inputs": [],
2112
+ "name": "isPaused",
2113
+ "outputs": [
2114
+ {
2115
+ "internalType": "bool",
2116
+ "name": "",
2117
+ "type": "bool"
2118
+ }
2119
+ ],
2120
+ "stateMutability": "view",
2121
+ "type": "function"
2122
+ },
2123
+ {
2124
+ "inputs": [],
2125
+ "name": "marketOrdersTimeout",
2126
+ "outputs": [
2127
+ {
2128
+ "internalType": "uint16",
2129
+ "name": "",
2130
+ "type": "uint16"
2131
+ }
2132
+ ],
2133
+ "stateMutability": "view",
2134
+ "type": "function"
2135
+ },
2136
+ {
2137
+ "inputs": [],
2138
+ "name": "maxAllowedCollateral",
2139
+ "outputs": [
2140
+ {
2141
+ "internalType": "uint256",
2142
+ "name": "",
2143
+ "type": "uint256"
2144
+ }
2145
+ ],
2146
+ "stateMutability": "view",
2147
+ "type": "function"
2148
+ },
2149
+ {
2150
+ "inputs": [
2151
+ {
2152
+ "components": [
2153
+ {
2154
+ "internalType": "uint256",
2155
+ "name": "collateral",
2156
+ "type": "uint256"
2157
+ },
2158
+ {
2159
+ "internalType": "uint192",
2160
+ "name": "openPrice",
2161
+ "type": "uint192"
2162
+ },
2163
+ {
2164
+ "internalType": "uint192",
2165
+ "name": "tp",
2166
+ "type": "uint192"
2167
+ },
2168
+ {
2169
+ "internalType": "uint192",
2170
+ "name": "sl",
2171
+ "type": "uint192"
2172
+ },
2173
+ {
2174
+ "internalType": "address",
2175
+ "name": "trader",
2176
+ "type": "address"
2177
+ },
2178
+ {
2179
+ "internalType": "uint32",
2180
+ "name": "leverage",
2181
+ "type": "uint32"
2182
+ },
2183
+ {
2184
+ "internalType": "uint16",
2185
+ "name": "pairIndex",
2186
+ "type": "uint16"
2187
+ },
2188
+ {
2189
+ "internalType": "uint8",
2190
+ "name": "index",
2191
+ "type": "uint8"
2192
+ },
2193
+ {
2194
+ "internalType": "bool",
2195
+ "name": "buy",
2196
+ "type": "bool"
2197
+ },
2198
+ {
2199
+ "internalType": "bool",
2200
+ "name": "isDayTrade",
2201
+ "type": "bool"
2202
+ }
2203
+ ],
2204
+ "internalType": "struct IOstiumTradingStorage.Trade",
2205
+ "name": "t",
2206
+ "type": "tuple"
2207
+ },
2208
+ {
2209
+ "components": [
2210
+ {
2211
+ "internalType": "address",
2212
+ "name": "builder",
2213
+ "type": "address"
2214
+ },
2215
+ {
2216
+ "internalType": "uint32",
2217
+ "name": "builderFee",
2218
+ "type": "uint32"
2219
+ }
2220
+ ],
2221
+ "internalType": "struct IOstiumTradingStorage.BuilderFee",
2222
+ "name": "bf",
2223
+ "type": "tuple"
2224
+ },
2225
+ {
2226
+ "internalType": "enum IOstiumTradingStorage.OpenOrderType",
2227
+ "name": "orderType",
2228
+ "type": "uint8"
2229
+ },
2230
+ {
2231
+ "internalType": "uint256",
2232
+ "name": "slippageP",
2233
+ "type": "uint256"
2234
+ }
2235
+ ],
2236
+ "name": "openTrade",
2237
+ "outputs": [],
2238
+ "stateMutability": "nonpayable",
2239
+ "type": "function"
2240
+ },
2241
+ {
2242
+ "inputs": [
2243
+ {
2244
+ "internalType": "uint256",
2245
+ "name": "_order",
2246
+ "type": "uint256"
2247
+ }
2248
+ ],
2249
+ "name": "openTradeMarketTimeout",
2250
+ "outputs": [],
2251
+ "stateMutability": "nonpayable",
2252
+ "type": "function"
2253
+ },
2254
+ {
2255
+ "inputs": [],
2256
+ "name": "pause",
2257
+ "outputs": [],
2258
+ "stateMutability": "nonpayable",
2259
+ "type": "function"
2260
+ },
2261
+ {
2262
+ "inputs": [],
2263
+ "name": "registry",
2264
+ "outputs": [
2265
+ {
2266
+ "internalType": "contract IOstiumRegistry",
2267
+ "name": "",
2268
+ "type": "address"
2269
+ }
2270
+ ],
2271
+ "stateMutability": "view",
2272
+ "type": "function"
2273
+ },
2274
+ {
2275
+ "inputs": [
2276
+ {
2277
+ "internalType": "uint16",
2278
+ "name": "pairIndex",
2279
+ "type": "uint16"
2280
+ },
2281
+ {
2282
+ "internalType": "uint8",
2283
+ "name": "index",
2284
+ "type": "uint8"
2285
+ },
2286
+ {
2287
+ "internalType": "uint256",
2288
+ "name": "removeAmount",
2289
+ "type": "uint256"
2290
+ }
2291
+ ],
2292
+ "name": "removeCollateral",
2293
+ "outputs": [],
2294
+ "stateMutability": "nonpayable",
2295
+ "type": "function"
2296
+ },
2297
+ {
2298
+ "inputs": [],
2299
+ "name": "removeDelegate",
2300
+ "outputs": [],
2301
+ "stateMutability": "nonpayable",
2302
+ "type": "function"
2303
+ },
2304
+ {
2305
+ "inputs": [
2306
+ {
2307
+ "internalType": "address",
2308
+ "name": "delegate",
2309
+ "type": "address"
2310
+ }
2311
+ ],
2312
+ "name": "setDelegate",
2313
+ "outputs": [],
2314
+ "stateMutability": "nonpayable",
2315
+ "type": "function"
2316
+ },
2317
+ {
2318
+ "inputs": [
2319
+ {
2320
+ "internalType": "address",
2321
+ "name": "delegator",
2322
+ "type": "address"
2323
+ },
2324
+ {
2325
+ "internalType": "address",
2326
+ "name": "delegate",
2327
+ "type": "address"
2328
+ },
2329
+ {
2330
+ "internalType": "uint256",
2331
+ "name": "nonce",
2332
+ "type": "uint256"
2333
+ },
2334
+ {
2335
+ "internalType": "uint256",
2336
+ "name": "expiry",
2337
+ "type": "uint256"
2338
+ },
2339
+ {
2340
+ "internalType": "uint8",
2341
+ "name": "v",
2342
+ "type": "uint8"
2343
+ },
2344
+ {
2345
+ "internalType": "bytes32",
2346
+ "name": "r",
2347
+ "type": "bytes32"
2348
+ },
2349
+ {
2350
+ "internalType": "bytes32",
2351
+ "name": "s",
2352
+ "type": "bytes32"
2353
+ }
2354
+ ],
2355
+ "name": "setDelegateWithSignature",
2356
+ "outputs": [],
2357
+ "stateMutability": "nonpayable",
2358
+ "type": "function"
2359
+ },
2360
+ {
2361
+ "inputs": [
2362
+ {
2363
+ "internalType": "uint256",
2364
+ "name": "value",
2365
+ "type": "uint256"
2366
+ }
2367
+ ],
2368
+ "name": "setMarketOrdersTimeout",
2369
+ "outputs": [],
2370
+ "stateMutability": "nonpayable",
2371
+ "type": "function"
2372
+ },
2373
+ {
2374
+ "inputs": [
2375
+ {
2376
+ "internalType": "uint256",
2377
+ "name": "value",
2378
+ "type": "uint256"
2379
+ }
2380
+ ],
2381
+ "name": "setMaxAllowedCollateral",
2382
+ "outputs": [],
2383
+ "stateMutability": "nonpayable",
2384
+ "type": "function"
2385
+ },
2386
+ {
2387
+ "inputs": [
2388
+ {
2389
+ "internalType": "uint256",
2390
+ "name": "value",
2391
+ "type": "uint256"
2392
+ }
2393
+ ],
2394
+ "name": "setTriggerTimeout",
2395
+ "outputs": [],
2396
+ "stateMutability": "nonpayable",
2397
+ "type": "function"
2398
+ },
2399
+ {
2400
+ "inputs": [
2401
+ {
2402
+ "internalType": "uint16",
2403
+ "name": "pairIndex",
2404
+ "type": "uint16"
2405
+ },
2406
+ {
2407
+ "internalType": "uint8",
2408
+ "name": "index",
2409
+ "type": "uint8"
2410
+ },
2411
+ {
2412
+ "internalType": "uint256",
2413
+ "name": "topUpAmount",
2414
+ "type": "uint256"
2415
+ }
2416
+ ],
2417
+ "name": "topUpCollateral",
2418
+ "outputs": [],
2419
+ "stateMutability": "nonpayable",
2420
+ "type": "function"
2421
+ },
2422
+ {
2423
+ "inputs": [],
2424
+ "name": "triggerTimeout",
2425
+ "outputs": [
2426
+ {
2427
+ "internalType": "uint16",
2428
+ "name": "",
2429
+ "type": "uint16"
2430
+ }
2431
+ ],
2432
+ "stateMutability": "view",
2433
+ "type": "function"
2434
+ },
2435
+ {
2436
+ "inputs": [
2437
+ {
2438
+ "internalType": "uint16",
2439
+ "name": "pairIndex",
2440
+ "type": "uint16"
2441
+ },
2442
+ {
2443
+ "internalType": "uint8",
2444
+ "name": "index",
2445
+ "type": "uint8"
2446
+ },
2447
+ {
2448
+ "internalType": "uint192",
2449
+ "name": "price",
2450
+ "type": "uint192"
2451
+ },
2452
+ {
2453
+ "internalType": "uint192",
2454
+ "name": "tp",
2455
+ "type": "uint192"
2456
+ },
2457
+ {
2458
+ "internalType": "uint192",
2459
+ "name": "sl",
2460
+ "type": "uint192"
2461
+ }
2462
+ ],
2463
+ "name": "updateOpenLimitOrder",
2464
+ "outputs": [],
2465
+ "stateMutability": "nonpayable",
2466
+ "type": "function"
2467
+ },
2468
+ {
2469
+ "inputs": [
2470
+ {
2471
+ "internalType": "uint16",
2472
+ "name": "pairIndex",
2473
+ "type": "uint16"
2474
+ },
2475
+ {
2476
+ "internalType": "uint8",
2477
+ "name": "index",
2478
+ "type": "uint8"
2479
+ },
2480
+ {
2481
+ "internalType": "uint192",
2482
+ "name": "newSl",
2483
+ "type": "uint192"
2484
+ }
2485
+ ],
2486
+ "name": "updateSl",
2487
+ "outputs": [],
2488
+ "stateMutability": "nonpayable",
2489
+ "type": "function"
2490
+ },
2491
+ {
2492
+ "inputs": [
2493
+ {
2494
+ "internalType": "uint16",
2495
+ "name": "pairIndex",
2496
+ "type": "uint16"
2497
+ },
2498
+ {
2499
+ "internalType": "uint8",
2500
+ "name": "index",
2501
+ "type": "uint8"
2502
+ },
2503
+ {
2504
+ "internalType": "uint192",
2505
+ "name": "newTp",
2506
+ "type": "uint192"
2507
+ }
2508
+ ],
2509
+ "name": "updateTp",
2510
+ "outputs": [],
2511
+ "stateMutability": "nonpayable",
2512
+ "type": "function"
2513
+ }
2514
+ ];
2515
+
2516
+ // src/encoder.ts
2517
+ function tx(to, data) {
2518
+ return { to, data, value: 0n };
2519
+ }
2520
+ function encodeOpenTrade(trade, builderFee, orderType, slippageP, tradingAddress) {
2521
+ const data = encodeFunctionData({
2522
+ abi: TRADING_ABI,
2523
+ functionName: "openTrade",
2524
+ args: [
2525
+ {
2526
+ collateral: trade.collateral,
2527
+ openPrice: trade.openPrice,
2528
+ tp: trade.tp,
2529
+ sl: trade.sl,
2530
+ trader: trade.trader,
2531
+ leverage: Number(trade.leverage),
2532
+ pairIndex: Number(trade.pairIndex),
2533
+ index: Number(trade.index),
2534
+ buy: trade.buy,
2535
+ isDayTrade: trade.isDayTrade ?? false
2536
+ },
2537
+ {
2538
+ builder: builderFee.builder,
2539
+ builderFee: Number(builderFee.builderFee)
2540
+ },
2541
+ orderType,
2542
+ slippageP
2543
+ ]
2544
+ });
2545
+ return tx(tradingAddress, data);
2546
+ }
2547
+ function encodeCloseTradeMarket(pairIndex, index, closePercentage, marketPrice, slippageP, tradingAddress) {
2548
+ const data = encodeFunctionData({
2549
+ abi: TRADING_ABI,
2550
+ functionName: "closeTradeMarket",
2551
+ args: [Number(pairIndex), Number(index), Number(closePercentage), marketPrice, Number(slippageP)]
2552
+ });
2553
+ return tx(tradingAddress, data);
2554
+ }
2555
+ function encodeCancelLimitOrder(pairIndex, orderIndex, tradingAddress) {
2556
+ const data = encodeFunctionData({
2557
+ abi: TRADING_ABI,
2558
+ functionName: "cancelOpenLimitOrder",
2559
+ args: [Number(pairIndex), Number(orderIndex)]
2560
+ });
2561
+ return tx(tradingAddress, data);
2562
+ }
2563
+ function encodeCloseTradeMarketTimeout(orderId, retry, tradingAddress) {
2564
+ const data = encodeFunctionData({
2565
+ abi: TRADING_ABI,
2566
+ functionName: "closeTradeMarketTimeout",
2567
+ args: [orderId, retry]
2568
+ });
2569
+ return tx(tradingAddress, data);
2570
+ }
2571
+ function encodeOpenTradeMarketTimeout(orderId, tradingAddress) {
2572
+ const data = encodeFunctionData({
2573
+ abi: TRADING_ABI,
2574
+ functionName: "openTradeMarketTimeout",
2575
+ args: [orderId]
2576
+ });
2577
+ return tx(tradingAddress, data);
2578
+ }
2579
+ function encodeUpdateOpenLimitOrder(pairIndex, orderIndex, price, tp, sl, tradingAddress) {
2580
+ const data = encodeFunctionData({
2581
+ abi: TRADING_ABI,
2582
+ functionName: "updateOpenLimitOrder",
2583
+ args: [Number(pairIndex), Number(orderIndex), price, tp, sl]
2584
+ });
2585
+ return tx(tradingAddress, data);
2586
+ }
2587
+ function encodeUpdateTp(pairIndex, index, newTp, tradingAddress) {
2588
+ const data = encodeFunctionData({
2589
+ abi: TRADING_ABI,
2590
+ functionName: "updateTp",
2591
+ args: [Number(pairIndex), Number(index), newTp]
2592
+ });
2593
+ return tx(tradingAddress, data);
2594
+ }
2595
+ function encodeUpdateSl(pairIndex, index, newSl, tradingAddress) {
2596
+ const data = encodeFunctionData({
2597
+ abi: TRADING_ABI,
2598
+ functionName: "updateSl",
2599
+ args: [Number(pairIndex), Number(index), newSl]
2600
+ });
2601
+ return tx(tradingAddress, data);
2602
+ }
2603
+ function encodeTopUpCollateral(pairIndex, index, amount, tradingAddress) {
2604
+ const data = encodeFunctionData({
2605
+ abi: TRADING_ABI,
2606
+ functionName: "topUpCollateral",
2607
+ args: [Number(pairIndex), Number(index), amount]
2608
+ });
2609
+ return tx(tradingAddress, data);
2610
+ }
2611
+ function encodeRemoveCollateral(pairIndex, index, amount, tradingAddress) {
2612
+ const data = encodeFunctionData({
2613
+ abi: TRADING_ABI,
2614
+ functionName: "removeCollateral",
2615
+ args: [Number(pairIndex), Number(index), amount]
2616
+ });
2617
+ return tx(tradingAddress, data);
2618
+ }
2619
+ function encodeSetDelegate(delegateAddress, tradingAddress) {
2620
+ const data = encodeFunctionData({
2621
+ abi: TRADING_ABI,
2622
+ functionName: "setDelegate",
2623
+ args: [getAddress(delegateAddress)]
2624
+ });
2625
+ return tx(tradingAddress, data);
2626
+ }
2627
+ function encodeRemoveDelegate(tradingAddress) {
2628
+ const data = encodeFunctionData({
2629
+ abi: TRADING_ABI,
2630
+ functionName: "removeDelegate",
2631
+ args: []
2632
+ });
2633
+ return tx(tradingAddress, data);
2634
+ }
2635
+ function encodeDelegatedAction(traderAddress, callData, tradingAddress) {
2636
+ const data = encodeFunctionData({
2637
+ abi: TRADING_ABI,
2638
+ functionName: "delegatedAction",
2639
+ args: [getAddress(traderAddress), callData]
2640
+ });
2641
+ return tx(tradingAddress, data);
2642
+ }
2643
+ function encodeUsdcApprove(spender, amount, usdcAddress) {
2644
+ const data = encodeFunctionData({
2645
+ abi: ERC20_ABI,
2646
+ functionName: "approve",
2647
+ args: [getAddress(spender), amount]
2648
+ });
2649
+ return tx(usdcAddress, data);
2650
+ }
2651
+
2652
+ // src/signer/delegated.ts
2653
+ var DelegatedSignerStrategy = class {
2654
+ traderAddress;
2655
+ constructor(traderAddress) {
2656
+ this.traderAddress = traderAddress;
2657
+ }
2658
+ prepare(encoded) {
2659
+ return encodeDelegatedAction(this.traderAddress, encoded.data, encoded.to);
2660
+ }
2661
+ };
2662
+
2663
+ // src/signer/index.ts
2664
+ function createSigner(config, traderAddress, selfGasless = false) {
2665
+ if (isDelegated(config) || selfGasless) {
2666
+ return new DelegatedSignerStrategy(traderAddress);
2667
+ }
2668
+ return new SelfSignerStrategy(traderAddress);
2669
+ }
2670
+ function classifySubmitError(err) {
2671
+ const msg = err instanceof Error ? err.message : String(err);
2672
+ const lower = msg.toLowerCase();
2673
+ if (lower.includes("execution reverted") || lower.includes("reverted with reason") || lower.includes("contract function") || lower.includes("revert")) {
2674
+ return new OstiumError(`Contract reverted: ${msg}`, "CONTRACT_ERROR" /* CONTRACT_ERROR */, err);
2675
+ }
2676
+ if (lower.includes("fetch") || lower.includes("etimedout") || lower.includes("econnrefused") || lower.includes("enotfound") || lower.includes("network") || lower.includes("timeout") || lower.includes("connection")) {
2677
+ return new OstiumError(`Network error: ${msg}`, "NETWORK_ERROR" /* NETWORK_ERROR */, err);
2678
+ }
2679
+ return new OstiumError(
2680
+ `Transaction submission failed: ${msg}`,
2681
+ "SUBMISSION_FAILED" /* SUBMISSION_FAILED */,
2682
+ err
2683
+ );
2684
+ }
2685
+ var SelfSubmissionStrategy = class {
2686
+ effectiveSender;
2687
+ send;
2688
+ constructor(config, testnet) {
2689
+ if (!config.rpcUrl) {
2690
+ throw new OstiumError(
2691
+ "rpcUrl is required for self-submission mode",
2692
+ "INVALID_CONFIG" /* INVALID_CONFIG */
2693
+ );
2694
+ }
2695
+ const chain = testnet ? arbitrumSepolia : arbitrum;
2696
+ const account = privateKeyToAccount(config.privateKey);
2697
+ const walletClient = createWalletClient({ account, chain, transport: http(config.rpcUrl) });
2698
+ this.effectiveSender = account.address;
2699
+ this.send = (encoded) => walletClient.sendTransaction({ account, to: encoded.to, data: encoded.data, value: encoded.value });
2700
+ }
2701
+ async submit(encoded) {
2702
+ try {
2703
+ const txHash = await this.send(encoded);
2704
+ return { txHash };
2705
+ } catch (err) {
2706
+ throw classifySubmitError(err);
2707
+ }
2708
+ }
2709
+ };
2710
+ function classifyGaslessError(err) {
2711
+ const msg = err instanceof Error ? err.message : String(err);
2712
+ const lower = msg.toLowerCase();
2713
+ if (lower.includes("execution reverted") || lower.includes("reverted with reason") || lower.includes("revert") || lower.includes("userop reverted") || lower.includes("aa")) {
2714
+ return new OstiumError(`Contract reverted: ${msg}`, "CONTRACT_ERROR" /* CONTRACT_ERROR */, err);
2715
+ }
2716
+ if (lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests")) {
2717
+ return new OstiumError(
2718
+ `Pimlico rate limit exceeded \u2014 retry after 60 seconds. ${msg}`,
2719
+ "NETWORK_ERROR" /* NETWORK_ERROR */,
2720
+ err
2721
+ );
2722
+ }
2723
+ if (lower.includes("sponsorship") || lower.includes("policy")) {
2724
+ return new OstiumError(
2725
+ `Pimlico sponsorship policy error \u2014 check sponsorshipPolicyId config. ${msg}`,
2726
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
2727
+ err
2728
+ );
2729
+ }
2730
+ if (lower.includes("fetch") || lower.includes("etimedout") || lower.includes("econnrefused") || lower.includes("network") || lower.includes("timeout") || lower.includes("bundle") || lower.includes("connection")) {
2731
+ return new OstiumError(`Network error: ${msg}`, "NETWORK_ERROR" /* NETWORK_ERROR */, err);
2732
+ }
2733
+ return new OstiumError(
2734
+ `Gasless submission failed: ${msg}`,
2735
+ "SUBMISSION_FAILED" /* SUBMISSION_FAILED */,
2736
+ err
2737
+ );
2738
+ }
2739
+ var GaslessSubmissionStrategy = class _GaslessSubmissionStrategy {
2740
+ effectiveSender;
2741
+ testnet;
2742
+ pimlicoUrl;
2743
+ sponsorshipPolicyId;
2744
+ // Cached Safe account — derived once in create(), reused on every submit().
2745
+ safeAccount;
2746
+ constructor(testnet, pimlicoUrl, sponsorshipPolicyId, safeAccount) {
2747
+ this.testnet = testnet;
2748
+ this.pimlicoUrl = pimlicoUrl;
2749
+ this.sponsorshipPolicyId = sponsorshipPolicyId;
2750
+ this.safeAccount = safeAccount;
2751
+ this.effectiveSender = safeAccount.address;
2752
+ }
2753
+ static async create(config, testnet) {
2754
+ if (!config.pimlicoUrl) {
2755
+ throw new OstiumError(
2756
+ "pimlicoUrl is required for gasless mode",
2757
+ "INVALID_CONFIG" /* INVALID_CONFIG */
2758
+ );
2759
+ }
2760
+ const chain = testnet ? arbitrumSepolia : arbitrum;
2761
+ const pimlicoUrl = config.pimlicoUrl;
2762
+ const chainRpc = config.rpcUrl ?? (testnet ? "https://sepolia-rollup.arbitrum.io/rpc" : "https://arb1.arbitrum.io/rpc");
2763
+ const rpcTransport = http(chainRpc);
2764
+ const publicClient = createPublicClient({ chain, transport: rpcTransport });
2765
+ const owner = privateKeyToAccount(config.privateKey);
2766
+ try {
2767
+ const safeAccount = await toSafeSmartAccount({
2768
+ client: publicClient,
2769
+ owners: [owner],
2770
+ entryPoint: {
2771
+ address: entryPoint07Address,
2772
+ version: "0.7"
2773
+ },
2774
+ version: "1.4.1"
2775
+ });
2776
+ return new _GaslessSubmissionStrategy(testnet, pimlicoUrl, config.sponsorshipPolicyId, safeAccount);
2777
+ } catch (err) {
2778
+ throw new OstiumError(
2779
+ `Failed to derive Safe smart account address: ${err instanceof Error ? err.message : String(err)}`,
2780
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
2781
+ err
2782
+ );
2783
+ }
2784
+ }
2785
+ async submit(encoded) {
2786
+ const chain = this.testnet ? arbitrumSepolia : arbitrum;
2787
+ const pimlicoClient = createPimlicoClient({
2788
+ transport: http(this.pimlicoUrl),
2789
+ entryPoint: {
2790
+ address: entryPoint07Address,
2791
+ version: "0.7"
2792
+ }
2793
+ });
2794
+ try {
2795
+ const smartAccountClient = createSmartAccountClient({
2796
+ account: this.safeAccount,
2797
+ chain,
2798
+ bundlerTransport: http(this.pimlicoUrl),
2799
+ paymaster: pimlicoClient,
2800
+ userOperation: {
2801
+ estimateFeesPerGas: async () => (await pimlicoClient.getUserOperationGasPrice()).fast
2802
+ },
2803
+ ...this.sponsorshipPolicyId && {
2804
+ paymasterContext: {
2805
+ sponsorshipPolicyId: this.sponsorshipPolicyId
2806
+ }
2807
+ }
2808
+ });
2809
+ const txHash = await smartAccountClient.sendTransaction({
2810
+ to: encoded.to,
2811
+ data: encoded.data,
2812
+ value: encoded.value
2813
+ });
2814
+ return { txHash, smartAccountAddress: this.safeAccount.address };
2815
+ } catch (err) {
2816
+ throw classifyGaslessError(err);
2817
+ }
2818
+ }
2819
+ };
2820
+
2821
+ // src/submitter/index.ts
2822
+ async function createSubmitter(config, testnet) {
2823
+ if (isGasless(config)) {
2824
+ return GaslessSubmissionStrategy.create(config, testnet);
2825
+ }
2826
+ if (!config.rpcUrl) {
2827
+ throw new Error("rpcUrl is required for self-submission mode");
2828
+ }
2829
+ return new SelfSubmissionStrategy(config, testnet);
2830
+ }
2831
+
2832
+ // src/data/config.ts
2833
+ var DEFAULT_SUBGRAPH_ENDPOINT = "https://api.subgraph.ormilabs.com/api/public/67a599d5-c8d2-4cc4-9c4d-2975a97bc5d8/subgraphs/ost-prod/live/gn";
2834
+ var DEFAULT_SUBGRAPH_ENDPOINT_TESTNET = "https://api.subgraph.ormilabs.com/api/public/67a599d5-c8d2-4cc4-9c4d-2975a97bc5d8/subgraphs/ost-sep/live/gn";
2835
+ var DEFAULT_BUILDER_API_URL = "https://builder.ostium.io";
2836
+
2837
+ // src/data/errors.ts
2838
+ var OstiumSubgraphErrorCode = /* @__PURE__ */ ((OstiumSubgraphErrorCode2) => {
2839
+ OstiumSubgraphErrorCode2["INVALID_CONFIG"] = "INVALID_CONFIG";
2840
+ OstiumSubgraphErrorCode2["INVALID_PARAMS"] = "INVALID_PARAMS";
2841
+ OstiumSubgraphErrorCode2["FETCH_FAILED"] = "FETCH_FAILED";
2842
+ OstiumSubgraphErrorCode2["NOT_FOUND"] = "NOT_FOUND";
2843
+ OstiumSubgraphErrorCode2["PARSE_ERROR"] = "PARSE_ERROR";
2844
+ return OstiumSubgraphErrorCode2;
2845
+ })(OstiumSubgraphErrorCode || {});
2846
+ var OstiumSubgraphError = class extends Error {
2847
+ constructor(message, code, cause) {
2848
+ super(message);
2849
+ this.code = code;
2850
+ this.cause = cause;
2851
+ this.name = "OstiumSubgraphError";
2852
+ }
2853
+ code;
2854
+ cause;
2855
+ };
2856
+
2857
+ // src/data/queries.ts
2858
+ var PAIR_FIELDS = `
2859
+ id
2860
+ from
2861
+ to
2862
+ maxLeverage
2863
+ overnightMaxLeverage
2864
+ takerFeeP
2865
+ maxOI
2866
+ longOI
2867
+ shortOI
2868
+ group { id name maxLeverage }
2869
+ lastUpdateTimestamp
2870
+ buyVolume
2871
+ sellVolume
2872
+ decayRate
2873
+ netVolThreshold
2874
+ priceImpactK
2875
+ accRolloverLong
2876
+ accRolloverShort
2877
+ lastRolloverBlock
2878
+ lastRolloverLongPure
2879
+ brokerPremium
2880
+ isNegativeRolloverAllowed
2881
+ lastTradePrice
2882
+ spreadP`;
2883
+ var GetPairsAndGroupsQuery = `
2884
+ query GetPairsAndGroups {
2885
+ pairs(orderBy: id, orderDirection: asc, subgraphError: allow) {
2886
+ ${PAIR_FIELDS}
2887
+ }
2888
+ groups { id name maxLeverage }
2889
+ }`;
2890
+ var PAIR_FULL = `
2891
+ pair {
2892
+ id from to
2893
+ maxLeverage overnightMaxLeverage
2894
+ takerFeeP
2895
+ maxOI longOI shortOI
2896
+ group { id name maxLeverage }
2897
+ lastUpdateTimestamp
2898
+ buyVolume sellVolume decayRate netVolThreshold priceImpactK
2899
+ accRolloverLong accRolloverShort lastRolloverBlock lastRolloverLongPure
2900
+ brokerPremium isNegativeRolloverAllowed lastTradePrice
2901
+ }`;
2902
+ var TRADE_CORE = `
2903
+ id tradeID trader
2904
+ isOpen isBuy isDayTrade
2905
+ index tradeType
2906
+ collateral notional tradeNotional leverage highestLeverage
2907
+ openPrice stopLossPrice takeProfitPrice
2908
+ rollover timestamp`;
2909
+ var GetTraderOpenTradesQuery = `
2910
+ query GetTraderOpenTrades($trader: String!, $skip: Int!, $first: Int!) {
2911
+ trades(
2912
+ where: { isOpen: true, trader: $trader }
2913
+ skip: $skip first: $first
2914
+ orderBy: timestamp orderDirection: desc
2915
+ ) {
2916
+ ${TRADE_CORE}
2917
+ ${PAIR_FULL}
2918
+ }
2919
+ }`;
2920
+ var ORDER_FIELDS = `
2921
+ id tradeID limitID trader
2922
+ pair { id from to group { id name } }
2923
+ orderAction orderType isBuy
2924
+ isPending isCancelled cancelReason
2925
+ collateral notional tradeNotional leverage
2926
+ price priceAfterImpact priceImpactP
2927
+ vaultFee devFee oracleFee rolloverFee liquidationFee
2928
+ builder builderFee
2929
+ profitPercent totalProfitPercent amountSentToTrader
2930
+ closePercent
2931
+ initiatedTx initiatedBlock initiatedAt
2932
+ executedTx executedBlock executedAt`;
2933
+ function buildExecutedFillsQuery(opts) {
2934
+ const args = ["$skip: Int!", "$first: Int!"];
2935
+ const conditions = ["isPending: false", "isCancelled: false"];
2936
+ if (opts.hasTrader) {
2937
+ args.push("$trader: String!");
2938
+ conditions.push("trader: $trader");
2939
+ }
2940
+ if (opts.hasPairId) {
2941
+ args.push("$pairId: String!");
2942
+ conditions.push("pair: $pairId");
2943
+ }
2944
+ if (opts.hasTimeRange) {
2945
+ args.push("$startSec: BigInt!", "$endSec: BigInt!");
2946
+ conditions.push("executedAt_gte: $startSec", "executedAt_lte: $endSec");
2947
+ }
2948
+ return `
2949
+ query GetExecutedFills(${args.join(", ")}) {
2950
+ orders(
2951
+ where: { ${conditions.join(", ")} }
2952
+ skip: $skip first: $first
2953
+ orderBy: executedAt orderDirection: desc
2954
+ ) { ${ORDER_FIELDS} }
2955
+ }`;
2956
+ }
2957
+ function buildGetOrdersQuery(opts) {
2958
+ const args = ["$skip: Int!", "$first: Int!"];
2959
+ const conditions = [];
2960
+ if (opts.hasOrderIds) {
2961
+ args.push("$ids: [String!]!");
2962
+ conditions.push("id_in: $ids");
2963
+ }
2964
+ if (opts.hasInitiatedTxHashes) {
2965
+ args.push("$txHashes: [String!]!");
2966
+ conditions.push("initiatedTx_in: $txHashes");
2967
+ }
2968
+ if (opts.hasTrader) {
2969
+ args.push("$trader: String!");
2970
+ conditions.push("trader: $trader");
2971
+ }
2972
+ const where = conditions.length > 0 ? `where: { ${conditions.join(", ")} }` : "";
2973
+ return `
2974
+ query GetOrders(${args.join(", ")}) {
2975
+ orders(
2976
+ ${where}
2977
+ skip: $skip first: $first
2978
+ orderBy: initiatedAt orderDirection: desc
2979
+ ) { ${ORDER_FIELDS} }
2980
+ }`;
2981
+ }
2982
+ var LIMIT_FIELDS = `
2983
+ id uniqueId orderId trader
2984
+ pair { id from to group { id name } }
2985
+ isBuy limitType isActive executionStarted
2986
+ collateral notional tradeNotional leverage
2987
+ openPrice takeProfitPrice stopLossPrice
2988
+ block initiatedAt updatedAt`;
2989
+ var GetTraderActiveLimitsQuery = `
2990
+ query GetTraderActiveLimits($trader: String!, $skip: Int!, $first: Int!) {
2991
+ limits(
2992
+ where: { isActive: true, trader: $trader }
2993
+ skip: $skip first: $first
2994
+ orderBy: updatedAt orderDirection: desc
2995
+ ) { ${LIMIT_FIELDS} }
2996
+ }`;
2997
+
2998
+ // src/data/internal/pagination.ts
2999
+ async function paginateAll(fetcher, batchSize = 1e3, max = Infinity) {
3000
+ const results = [];
3001
+ let skip = 0;
3002
+ while (results.length < max) {
3003
+ const remaining = max - results.length;
3004
+ const fetchSize = Math.min(batchSize, remaining);
3005
+ const page = await fetcher(skip, fetchSize);
3006
+ results.push(...page);
3007
+ if (page.length < fetchSize) break;
3008
+ skip += fetchSize;
3009
+ }
3010
+ return results;
3011
+ }
3012
+
3013
+ // src/data/internal/precision.ts
3014
+ var USDC_DECIMALS = 6;
3015
+ var TOKEN_DECIMALS = 18;
3016
+ var LEVERAGE_DECIMALS = 2;
3017
+
3018
+ // src/data/internal/decimal.ts
3019
+ function formatUsdc(value) {
3020
+ if (value === void 0 || value === null) return 0;
3021
+ if (typeof value === "number") return value;
3022
+ if (typeof value === "string" && value.includes(".")) return parseFloat(value);
3023
+ return Number(formatUnits(BigInt(value), USDC_DECIMALS));
3024
+ }
3025
+ function formatTokens(value) {
3026
+ if (value === void 0 || value === null) return 0;
3027
+ if (typeof value === "number") return value;
3028
+ if (typeof value === "string" && value.includes(".")) return parseFloat(value);
3029
+ return Number(formatUnits(BigInt(value), TOKEN_DECIMALS));
3030
+ }
3031
+ function formatLeverage(value) {
3032
+ if (value === void 0 || value === null) return 0;
3033
+ if (typeof value === "number") return value;
3034
+ if (typeof value === "string" && value.includes(".")) return parseFloat(value);
3035
+ return Number(formatUnits(BigInt(value), LEVERAGE_DECIMALS));
3036
+ }
3037
+ function parseUsdc2(value) {
3038
+ return parseUnits(value.toString(), USDC_DECIMALS);
3039
+ }
3040
+ function parseTokens(value) {
3041
+ return parseUnits(value.toString(), TOKEN_DECIMALS);
3042
+ }
3043
+ function parseLeverage2(value) {
3044
+ return parseUnits(value.toString(), LEVERAGE_DECIMALS);
3045
+ }
3046
+ function getMaxLeverage(trade) {
3047
+ return trade.pair.maxLeverage && trade.pair.maxLeverage !== "0" ? trade.pair.maxLeverage : trade.pair.group?.maxLeverage ?? "1";
3048
+ }
3049
+ function timeElapsedSince(pair) {
3050
+ const now = Math.floor(Date.now() / 1e3);
3051
+ const last = parseInt(pair.lastUpdateTimestamp ?? "0") || parseInt(pair.lastFundingTime ?? "0");
3052
+ return (now - last).toString();
3053
+ }
3054
+
3055
+ // src/data/internal/calculations.ts
3056
+ var EMPTY_PNL = {
3057
+ pnl: 0,
3058
+ pnlPercent: 0,
3059
+ rollover: 0,
3060
+ netPnl: 0,
3061
+ netValue: 0,
3062
+ liquidationPrice: 0,
3063
+ priceAfterImpact: 0
3064
+ };
3065
+ function getRolloverAccumulator(pair, isBuy, blockNumber) {
3066
+ const accRollover = isBuy ? pair.accRolloverLong ?? "0" : pair.accRolloverShort ?? "0";
3067
+ return GetCurrentRolloverFee(
3068
+ accRollover,
3069
+ pair.lastRolloverBlock ?? "0",
3070
+ pair.brokerPremium ?? "0",
3071
+ pair.lastRolloverLongPure ?? "0",
3072
+ isBuy,
3073
+ pair.isNegativeRolloverAllowed ?? false,
3074
+ blockNumber.toString()
3075
+ );
3076
+ }
3077
+ function getTradeRolloverFeeRaw(trade, currentRolloverAccumulator) {
3078
+ return BigInt(
3079
+ GetTradeRolloverFee(
3080
+ trade.rollover,
3081
+ currentRolloverAccumulator,
3082
+ trade.collateral,
3083
+ trade.leverage
3084
+ )
3085
+ );
3086
+ }
3087
+ function getLiquidationPrice(trade, rolloverRaw) {
3088
+ if (!trade.leverage || trade.leverage === "0") return 0;
3089
+ if (!trade.openPrice || trade.openPrice === "0") return 0;
3090
+ if (!trade.collateral || trade.collateral === "0") return 0;
3091
+ try {
3092
+ const maxLeverage = GetEffectiveMaxLeverage(
3093
+ getMaxLeverage(trade),
3094
+ trade.pair.overnightMaxLeverage ?? "0",
3095
+ trade.isDayTrade ?? false
3096
+ );
3097
+ return formatTokens(
3098
+ GetTradeLiquidationPrice(
3099
+ trade.openPrice,
3100
+ trade.isBuy,
3101
+ trade.collateral,
3102
+ trade.leverage,
3103
+ rolloverRaw.toString(),
3104
+ "0",
3105
+ // funding excluded
3106
+ maxLeverage
3107
+ )
3108
+ );
3109
+ } catch {
3110
+ return 0;
3111
+ }
3112
+ }
3113
+ function getPriceImpact(marketPrice, isBuy, isOpen, pair, collateral, leverage) {
3114
+ if (!marketPrice.mid) return { priceImpactP: "0", priceAfterImpact: "0" };
3115
+ return CalculateDynamicPriceImpact(
3116
+ parseTokens(marketPrice.mid).toString(),
3117
+ parseTokens(marketPrice.ask).toString(),
3118
+ parseTokens(marketPrice.bid).toString(),
3119
+ isOpen,
3120
+ isBuy,
3121
+ parseUsdc2(collateral).toString(),
3122
+ parseLeverage2(leverage).toString(),
3123
+ pair.buyVolume ?? "0",
3124
+ pair.sellVolume ?? "0",
3125
+ pair.decayRate ?? "0",
3126
+ timeElapsedSince(pair),
3127
+ pair.netVolThreshold ?? "0",
3128
+ pair.priceImpactK ?? "0"
3129
+ );
3130
+ }
3131
+ function getTradePnL(trade, marketPrice, blockNumber) {
3132
+ if (!trade?.pair || !marketPrice?.mid || !blockNumber) return EMPTY_PNL;
3133
+ const rolloverAcc = getRolloverAccumulator(trade.pair, trade.isBuy, blockNumber);
3134
+ const rolloverRaw = getTradeRolloverFeeRaw(trade, rolloverAcc);
3135
+ const liquidationPrice = getLiquidationPrice(trade, rolloverRaw);
3136
+ const impactResult = getPriceImpact(
3137
+ marketPrice,
3138
+ trade.isBuy,
3139
+ false,
3140
+ trade.pair,
3141
+ formatUsdc(trade.collateral),
3142
+ formatLeverage(trade.leverage)
3143
+ );
3144
+ const priceForPnL = parseTokens(marketPrice.mid).toString();
3145
+ const pnlRaw = BigInt(
3146
+ CurrentTradeProfitRaw(
3147
+ trade.openPrice,
3148
+ priceForPnL,
3149
+ trade.isBuy,
3150
+ trade.leverage,
3151
+ trade.highestLeverage,
3152
+ trade.collateral
3153
+ )
3154
+ );
3155
+ const totalProfitRaw = BigInt(
3156
+ CurrentTotalProfitRaw(
3157
+ trade.openPrice,
3158
+ priceForPnL,
3159
+ trade.isBuy,
3160
+ trade.leverage,
3161
+ trade.highestLeverage,
3162
+ trade.collateral,
3163
+ rolloverRaw.toString(),
3164
+ "0"
3165
+ // funding excluded
3166
+ )
3167
+ );
3168
+ const pnlPercentRaw = BigInt(
3169
+ CurrentTotalProfitP(totalProfitRaw.toString(), trade.collateral)
3170
+ );
3171
+ return {
3172
+ pnl: formatUsdc(pnlRaw),
3173
+ pnlPercent: formatUsdc(pnlPercentRaw),
3174
+ rollover: formatUsdc(rolloverRaw),
3175
+ netPnl: formatUsdc(totalProfitRaw),
3176
+ netValue: formatUsdc(totalProfitRaw) + formatUsdc(trade.collateral),
3177
+ liquidationPrice,
3178
+ priceAfterImpact: formatTokens(impactResult.priceAfterImpact)
3179
+ };
3180
+ }
3181
+
3182
+ // src/data/internal/pair-names.ts
3183
+ var PAIR_NAME_MAP = {
3184
+ CL: "WTI",
3185
+ HG: "XCU",
3186
+ SPX: "US500",
3187
+ NDX: "US100",
3188
+ DJI: "US30",
3189
+ DAX: "GER40",
3190
+ FTSE: "UK100",
3191
+ HSI: "HK50",
3192
+ NIK: "JP225"
3193
+ };
3194
+ function normalizePairName(symbol) {
3195
+ return PAIR_NAME_MAP[symbol] ?? symbol;
3196
+ }
3197
+
3198
+ // src/data/internal/pricing.ts
3199
+ async function fetchLivePrices(builderApiUrl) {
3200
+ const res = await fetch(`${builderApiUrl}/v1/prices`);
3201
+ if (res.status === 503) return {};
3202
+ if (!res.ok) {
3203
+ throw new Error(`Live prices endpoint returned ${res.status} ${res.statusText}`);
3204
+ }
3205
+ const json = await res.json();
3206
+ if (!Array.isArray(json.prices)) {
3207
+ throw new Error("Live prices endpoint returned an unexpected payload");
3208
+ }
3209
+ const result = {};
3210
+ for (const item of json.prices) {
3211
+ if (!item.from || !item.to) continue;
3212
+ result[`${item.from}/${item.to}`] = {
3213
+ mid: item.mid,
3214
+ bid: item.bid,
3215
+ ask: item.ask,
3216
+ isMarketOpen: item.isMarketOpen ?? true,
3217
+ isDayTradingClosed: item.isDayTradingClosed ?? false,
3218
+ secondsToToggleIsDayTradingClosed: item.secondsToToggleIsDayTradingClosed ?? -1
3219
+ };
3220
+ }
3221
+ return result;
3222
+ }
3223
+ function rawTickToPublic(item) {
3224
+ const from = normalizePairName(item.from);
3225
+ const to = normalizePairName(item.to);
3226
+ return {
3227
+ feedId: item.feed_id,
3228
+ pair: `${from}-${to}`,
3229
+ from,
3230
+ to,
3231
+ bid: item.bid,
3232
+ mid: item.mid,
3233
+ ask: item.ask,
3234
+ isMarketOpen: item.isMarketOpen ?? true,
3235
+ isDayTradingClosed: item.isDayTradingClosed ?? false,
3236
+ secondsToToggleIsDayTradingClosed: item.secondsToToggleIsDayTradingClosed ?? -1,
3237
+ timestampSeconds: item.timestampSeconds
3238
+ };
3239
+ }
3240
+ async function fetchCandles(builderApiUrl, rawPair, fromMs, toMs, resolution) {
3241
+ const res = await fetch(`${builderApiUrl}/v1/ohlc`, {
3242
+ method: "POST",
3243
+ headers: { "Content-Type": "application/json" },
3244
+ body: JSON.stringify({
3245
+ pair: rawPair,
3246
+ fromTimestampSeconds: Math.floor(fromMs / 1e3),
3247
+ toTimestampSeconds: Math.floor(toMs / 1e3),
3248
+ resolution
3249
+ })
3250
+ });
3251
+ if (!res.ok) {
3252
+ throw new Error(`OHLC endpoint returned ${res.status} ${res.statusText}`);
3253
+ }
3254
+ const json = await res.json();
3255
+ return json.data.map((c) => ({
3256
+ pairFrom: normalizePairName(c.from),
3257
+ pairTo: normalizePairName(c.to),
3258
+ time: c.time,
3259
+ open: c.open,
3260
+ high: c.high,
3261
+ low: c.low,
3262
+ close: c.close
3263
+ }));
3264
+ }
3265
+ var OstiumPriceStream = class _OstiumPriceStream {
3266
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3267
+ ws;
3268
+ // ws.WebSocket — typed as any to stay compatible with both Node and Bun
3269
+ tickHandlers = /* @__PURE__ */ new Set();
3270
+ snapshotHandlers = /* @__PURE__ */ new Set();
3271
+ /** pairId (string) → raw "FROM-TO" name for the WS API. */
3272
+ pairRawNameCache;
3273
+ constructor(ws, pairRawNameCache, initialSubscribeRawPairs) {
3274
+ this.ws = ws;
3275
+ this.pairRawNameCache = pairRawNameCache;
3276
+ if (initialSubscribeRawPairs?.length) {
3277
+ ws.once("open", () => {
3278
+ ws.send(JSON.stringify({ type: "subscribe", pairs: initialSubscribeRawPairs }));
3279
+ });
3280
+ }
3281
+ ws.on("message", (data) => {
3282
+ let msg;
3283
+ try {
3284
+ msg = JSON.parse(typeof data === "string" ? data : data.toString());
3285
+ } catch {
3286
+ return;
3287
+ }
3288
+ if (msg.type === "snapshot" && Array.isArray(msg.data)) {
3289
+ const ticks = msg.data.map(rawTickToPublic);
3290
+ for (const h of this.snapshotHandlers) h(ticks);
3291
+ } else if (msg.type === "tick" && msg.data) {
3292
+ const tick = rawTickToPublic(msg.data);
3293
+ for (const h of this.tickHandlers) h(tick);
3294
+ }
3295
+ });
3296
+ }
3297
+ /**
3298
+ * Open a WebSocket connection to the live price stream.
3299
+ *
3300
+ * Uses the `ws` package which correctly handles case-insensitive `Connection`
3301
+ * header values (required for Cloudflare-proxied endpoints).
3302
+ *
3303
+ * @param builderApiUrl - Base URL (e.g. `"https://builder.ostium.io"`). The `http`/`https`
3304
+ * scheme is automatically converted to `ws`/`wss`.
3305
+ * @param rawPairs - Optional raw `"FROM-TO"` names (from
3306
+ * `OstiumSubgraphClient.streamPrices` pairIds). Sent as
3307
+ * `{ type: "subscribe", pairs }` after the socket opens.
3308
+ * @param pairRawNameCache - pairId → raw name map; passed in by the subgraph client so
3309
+ * `subscribe` / `unsubscribe` can accept pairIds.
3310
+ */
3311
+ static connect(builderApiUrl, rawPairs, pairRawNameCache = /* @__PURE__ */ new Map()) {
3312
+ const base = builderApiUrl.replace(/\/$/, "").replace(/^https?:\/\//, (match) => match === "https://" ? "wss://" : "ws://");
3313
+ const url = `${base}/v1/prices/stream`;
3314
+ const initial = rawPairs && rawPairs.length > 0 ? rawPairs : void 0;
3315
+ const ws = new WS(url, {
3316
+ headers: { "User-Agent": "ostium-sdk", "Accept": "*/*" }
3317
+ });
3318
+ return new _OstiumPriceStream(ws, pairRawNameCache, initial);
3319
+ }
3320
+ /**
3321
+ * Register a callback that fires on every incoming price tick.
3322
+ * Returns an unsubscribe function.
3323
+ */
3324
+ onTick(handler) {
3325
+ this.tickHandlers.add(handler);
3326
+ return () => {
3327
+ this.tickHandlers.delete(handler);
3328
+ };
3329
+ }
3330
+ /**
3331
+ * Register a callback that fires once with the full snapshot sent on connect.
3332
+ * Returns an unsubscribe function.
3333
+ */
3334
+ onSnapshot(handler) {
3335
+ this.snapshotHandlers.add(handler);
3336
+ return () => {
3337
+ this.snapshotHandlers.delete(handler);
3338
+ };
3339
+ }
3340
+ /** Register a one-time callback that fires when the connection is established. */
3341
+ onOpen(handler) {
3342
+ this.ws.once("open", handler);
3343
+ return this;
3344
+ }
3345
+ /** Register an error callback. */
3346
+ onError(handler) {
3347
+ this.ws.on("error", handler);
3348
+ return this;
3349
+ }
3350
+ /** Register a callback that fires when the connection closes. */
3351
+ onClose(handler) {
3352
+ this.ws.on("close", handler);
3353
+ return this;
3354
+ }
3355
+ /**
3356
+ * Add pairs to the active filter. Accepts the same `pairId` values used
3357
+ * throughout the SDK (numeric string or number).
3358
+ * Sends `{ type: "subscribe", pairs: [...rawNames] }` to the server.
3359
+ */
3360
+ subscribe(pairIds) {
3361
+ this.send({ type: "subscribe", pairs: this.resolveRawNames(pairIds) });
3362
+ return this;
3363
+ }
3364
+ /**
3365
+ * Remove pairs from the active filter. Accepts the same `pairId` values used
3366
+ * throughout the SDK.
3367
+ * Sends `{ type: "unsubscribe", pairs: [...rawNames] }` to the server.
3368
+ */
3369
+ unsubscribe(pairIds) {
3370
+ this.send({ type: "unsubscribe", pairs: this.resolveRawNames(pairIds) });
3371
+ return this;
3372
+ }
3373
+ /** Close the WebSocket connection. */
3374
+ close() {
3375
+ this.ws.close();
3376
+ }
3377
+ /** Underlying WebSocket ready state (`0=CONNECTING`, `1=OPEN`, `2=CLOSING`, `3=CLOSED`). */
3378
+ get readyState() {
3379
+ return this.ws.readyState;
3380
+ }
3381
+ resolveRawNames(pairIds) {
3382
+ return pairIds.map((id) => {
3383
+ const cached = this.pairRawNameCache.get(String(id));
3384
+ return cached ?? String(id);
3385
+ });
3386
+ }
3387
+ send(msg) {
3388
+ if (this.ws.readyState === WS.OPEN) {
3389
+ this.ws.send(JSON.stringify(msg));
3390
+ }
3391
+ }
3392
+ };
3393
+
3394
+ // src/data/internal/formatters.ts
3395
+ var MIN_NOTIONAL = "5.0";
3396
+ var MIN_NOTIONAL_NUM = 5;
3397
+ var BLOCKS_PER_SECOND_ARBITRUM = 4;
3398
+ var ROLLOVER_RATE_HOURS = 8;
3399
+ function lowerHex(value) {
3400
+ if (!value) return null;
3401
+ const lower = value.toLowerCase();
3402
+ return lower.startsWith("0x") ? lower : `0x${lower}`;
3403
+ }
3404
+ function pairMaxLeverage(pair) {
3405
+ const maxLevString = !pair.maxLeverage || pair.maxLeverage === "0" ? pair.group.maxLeverage ?? "0" : pair.maxLeverage;
3406
+ return formatLeverage(maxLevString);
3407
+ }
3408
+ function maxWithdrawForPosition(collateral, currentLeverage, maxLeverage) {
3409
+ if (collateral <= 0) return 0;
3410
+ if (currentLeverage <= 0) return 0;
3411
+ if (maxLeverage <= 0) return 0;
3412
+ if (currentLeverage >= maxLeverage) return 0;
3413
+ const max = collateral * (1 - currentLeverage / maxLeverage);
3414
+ if (max < 0) return 0;
3415
+ if (max > collateral) return collateral;
3416
+ return max;
3417
+ }
3418
+ function formatPair(raw, price) {
3419
+ const lastPrice = formatTokens(raw.lastTradePrice);
3420
+ const mid = price?.mid;
3421
+ const refPrice = mid && mid > 0 ? mid : lastPrice;
3422
+ const buyOI_usd = formatTokens(raw.longOI) * lastPrice;
3423
+ const sellOI_usd = formatTokens(raw.shortOI) * lastPrice;
3424
+ const maxOI_usd = formatUsdc(raw.maxOI);
3425
+ const minSz = refPrice > 0 ? MIN_NOTIONAL_NUM / refPrice : 0;
3426
+ const maxBSz = refPrice > 0 ? Math.max(0, (maxOI_usd - buyOI_usd) / refPrice) : 0;
3427
+ const maxSSz = refPrice > 0 ? Math.max(0, (maxOI_usd - sellOI_usd) / refPrice) : 0;
3428
+ const rolloverRate = getRolloverRateDisplay(raw);
3429
+ return {
3430
+ pairId: String(raw.id),
3431
+ pairTo: normalizePairName(raw.to),
3432
+ pairFrom: normalizePairName(raw.from),
3433
+ minSz: minSz.toString(),
3434
+ maxBSz: maxBSz.toString(),
3435
+ maxSSz: maxSSz.toString(),
3436
+ minNtl: MIN_NOTIONAL,
3437
+ maxLeverage: pairMaxLeverage(raw),
3438
+ overnightMaxLeverage: raw.overnightMaxLeverage ? formatLeverage(raw.overnightMaxLeverage) : 0,
3439
+ rolloverFeePerBlock: formatTokens(raw.lastRolloverLongPure ?? "0").toString(),
3440
+ openInterest: (buyOI_usd + sellOI_usd).toString(),
3441
+ buyOpenInterest: buyOI_usd.toString(),
3442
+ sellOpenInterest: sellOI_usd.toString(),
3443
+ maxOpenInterest: maxOI_usd.toString(),
3444
+ category: raw.group.name,
3445
+ rolloverRate,
3446
+ midPx: price ? price.mid.toString() : "0",
3447
+ askPx: price ? price.ask.toString() : "0",
3448
+ bidPx: price ? price.bid.toString() : "0",
3449
+ isMarketOpen: price?.isMarketOpen ?? true,
3450
+ isDayTradingClosed: price?.isDayTradingClosed ?? false,
3451
+ secondsToToggleIsDayTradingClosed: price?.secondsToToggleIsDayTradingClosed ?? -1
3452
+ };
3453
+ }
3454
+ function getRolloverRateDisplay(raw) {
3455
+ const longPure = formatTokens(raw.lastRolloverLongPure ?? "0");
3456
+ const premium = formatTokens(raw.brokerPremium ?? "0");
3457
+ let contractLong = longPure + premium;
3458
+ let contractShort = -longPure + premium;
3459
+ if (!raw.isNegativeRolloverAllowed) {
3460
+ contractLong = Math.max(contractLong, 0);
3461
+ contractShort = Math.max(contractShort, 0);
3462
+ }
3463
+ const displayPerBlockLong = -contractLong;
3464
+ const displayPerBlockShort = -contractShort;
3465
+ const blocksInPeriod = ROLLOVER_RATE_HOURS * 60 * 60 * BLOCKS_PER_SECOND_ARBITRUM;
3466
+ const periodMultiplier = blocksInPeriod * 100;
3467
+ return {
3468
+ long: (displayPerBlockLong * periodMultiplier).toString(),
3469
+ short: (displayPerBlockShort * periodMultiplier).toString()
3470
+ };
3471
+ }
3472
+ function formatPosition(raw, price, pnl, maxLeverage) {
3473
+ const collateral = formatUsdc(raw.collateral);
3474
+ const tradeNotional = formatTokens(raw.tradeNotional);
3475
+ const leverage = formatLeverage(raw.leverage);
3476
+ const mid = price?.mid ?? formatTokens(raw.pair.lastTradePrice);
3477
+ const ntl = tradeNotional * mid;
3478
+ const roe = collateral > 0 ? pnl.netPnl / collateral : 0;
3479
+ return {
3480
+ position: {
3481
+ pairTo: normalizePairName(raw.pair.to),
3482
+ pairFrom: normalizePairName(raw.pair.from),
3483
+ pairId: String(raw.pair.id),
3484
+ pid: raw.tradeID,
3485
+ idx: parseInt(raw.index || "0") || 0,
3486
+ side: raw.isBuy ? "B" : "S",
3487
+ szi: tradeNotional.toString(),
3488
+ entryPx: formatTokens(raw.openPrice).toString(),
3489
+ leverage: leverage.toString(),
3490
+ ntl: ntl.toString(),
3491
+ unrealizedPnl: pnl.netPnl.toString(),
3492
+ returnOnEquity: roe.toString(),
3493
+ liquidationPx: pnl.liquidationPrice.toString(),
3494
+ collateralUsed: collateral.toString(),
3495
+ cumRollover: pnl.rollover.toString(),
3496
+ ...raw.takeProfitPrice && raw.takeProfitPrice !== "0" ? { tpPx: formatTokens(raw.takeProfitPrice).toString() } : {},
3497
+ ...raw.stopLossPrice && raw.stopLossPrice !== "0" ? { slPx: formatTokens(raw.stopLossPrice).toString() } : {},
3498
+ openTimestamp: parseInt(raw.timestamp || "0") * 1e3,
3499
+ isDayTrade: raw.isDayTrade ?? false,
3500
+ maxLeverage: maxLeverage.toString()
3501
+ },
3502
+ maxWithdrawable: maxWithdrawForPosition(collateral, leverage, maxLeverage).toString()
3503
+ };
3504
+ }
3505
+ function formatFill(raw) {
3506
+ const collateral = formatUsdc(raw.collateral);
3507
+ const tradeNotional = formatTokens(raw.tradeNotional);
3508
+ const priceImpactP = formatTokens(raw.priceImpactP);
3509
+ const devFee = formatUsdc(raw.devFee);
3510
+ const vaultFee = formatUsdc(raw.vaultFee);
3511
+ const oracleFee = formatUsdc(raw.oracleFee);
3512
+ const rolloverFee = formatUsdc(raw.rolloverFee);
3513
+ const liquidation = formatUsdc(raw.liquidationFee);
3514
+ const builderFee = formatUsdc(raw.builderFee);
3515
+ const totalProfitPercent = formatUsdc(raw.totalProfitPercent);
3516
+ const action = raw.orderAction;
3517
+ const type = raw.orderType;
3518
+ const isClose = action === "Close" || action === "StopLoss" || action === "TakeProfit" || action === "CloseDayTrade";
3519
+ const opening = action === "Open" ? (devFee + vaultFee).toString() : "0";
3520
+ const rollover = isClose ? rolloverFee.toString() : "0";
3521
+ const liquidationFee = action === "Liquidation" ? liquidation.toString() : "0";
3522
+ const closedPnl = isClose || action === "Liquidation" ? (collateral * totalProfitPercent / 100 - devFee - vaultFee - oracleFee).toString() : "0";
3523
+ const px = formatTokens(raw.priceAfterImpact);
3524
+ const szi = tradeNotional;
3525
+ const pxBeforeImpact = raw.isBuy ? px / (1 + priceImpactP / 100) : px / (1 - priceImpactP / 100);
3526
+ const priceImpactFee = Math.abs((px - pxBeforeImpact) * szi);
3527
+ return {
3528
+ pairTo: normalizePairName(raw.pair.to),
3529
+ pairFrom: normalizePairName(raw.pair.from),
3530
+ pairId: String(raw.pair.id),
3531
+ oid: raw.id,
3532
+ pid: raw.tradeID,
3533
+ side: raw.isBuy ? "B" : "S",
3534
+ action,
3535
+ type,
3536
+ px: px.toString(),
3537
+ szi: szi.toString(),
3538
+ collateralUsed: collateral.toString(),
3539
+ fees: {
3540
+ opening,
3541
+ rollover,
3542
+ liquidation: liquidationFee,
3543
+ builder: builderFee.toString(),
3544
+ priceImpact: priceImpactFee.toString()
3545
+ },
3546
+ closedPnl,
3547
+ hash: lowerHex(raw.executedTx) ?? "",
3548
+ time: parseInt(raw.executedAt || "0") * 1e3
3549
+ };
3550
+ }
3551
+ function formatOrder(raw) {
3552
+ return {
3553
+ ...formatFill(raw),
3554
+ initiatedTx: lowerHex(raw.initiatedTx) ?? "",
3555
+ initiatedTime: parseInt(raw.initiatedAt || "0") * 1e3,
3556
+ isPending: raw.isPending,
3557
+ isCancelled: raw.isCancelled,
3558
+ ...raw.cancelReason ? { cancelReason: raw.cancelReason } : {}
3559
+ };
3560
+ }
3561
+ function formatOpenOrder(raw) {
3562
+ const tp = raw.takeProfitPrice && raw.takeProfitPrice !== "0" ? formatTokens(raw.takeProfitPrice) : null;
3563
+ const sl = raw.stopLossPrice && raw.stopLossPrice !== "0" ? formatTokens(raw.stopLossPrice) : null;
3564
+ const orderType = raw.limitType === "STOP" ? "Stop" : "Limit";
3565
+ return {
3566
+ pairTo: normalizePairName(raw.pair.to),
3567
+ pairFrom: normalizePairName(raw.pair.from),
3568
+ pairId: String(raw.pair.id),
3569
+ idx: parseInt(raw.orderId || "0") || 0,
3570
+ side: raw.isBuy ? "B" : "S",
3571
+ limitPx: formatTokens(raw.openPrice).toString(),
3572
+ szi: formatTokens(raw.tradeNotional).toString(),
3573
+ ...tp !== null ? { tpPx: tp.toString() } : {},
3574
+ ...sl !== null ? { slPx: sl.toString() } : {},
3575
+ orderType,
3576
+ timestamp: parseInt(raw.initiatedAt || "0") * 1e3
3577
+ };
3578
+ }
3579
+ var EMPTY_RESULT = { long: [], short: [] };
3580
+ var ORDERBOOK_MAX_LEVELS = 20;
3581
+ function generateLogSpacedNotionals(levels, capacity) {
3582
+ const n = Math.min(ORDERBOOK_MAX_LEVELS, Math.max(1, Math.floor(levels)));
3583
+ if (capacity <= 0) return [];
3584
+ if (n === 1) return [capacity];
3585
+ const minNtl = Math.max(1, capacity / 3300);
3586
+ if (minNtl >= capacity) return [capacity];
3587
+ const logMin = Math.log(minNtl);
3588
+ const logMax = Math.log(capacity);
3589
+ return Array.from({ length: n }, (_, i) => {
3590
+ if (i === n - 1) return capacity;
3591
+ const t = i / (n - 1);
3592
+ return Math.exp(logMin + t * (logMax - logMin));
3593
+ });
3594
+ }
3595
+ function buildPairContext(raw, price) {
3596
+ const maxOIUsd = formatUsdc(raw.maxOI);
3597
+ const longOIUsd = formatTokens(raw.longOI) * price.mid;
3598
+ const shortOIUsd = formatTokens(raw.shortOI) * price.mid;
3599
+ return {
3600
+ remLong: Math.max(0, maxOIUsd - longOIUsd),
3601
+ remShort: Math.max(0, maxOIUsd - shortOIUsd),
3602
+ midBN: parseTokens(price.mid).toString(),
3603
+ askBN: parseTokens(price.ask).toString(),
3604
+ bidBN: parseTokens(price.bid).toString(),
3605
+ timeElapsed: timeElapsedSince(raw)
3606
+ };
3607
+ }
3608
+ function priceImpactForLevel(raw, ctx, ntl, isBuy) {
3609
+ return CalculateDynamicPriceImpact(
3610
+ ctx.midBN,
3611
+ ctx.askBN,
3612
+ ctx.bidBN,
3613
+ true,
3614
+ // isOpen
3615
+ isBuy,
3616
+ parseUsdc2(ntl).toString(),
3617
+ parseLeverage2(1).toString(),
3618
+ raw.buyVolume ?? "0",
3619
+ raw.sellVolume ?? "0",
3620
+ raw.decayRate ?? "0",
3621
+ ctx.timeElapsed,
3622
+ raw.netVolThreshold ?? "0",
3623
+ raw.priceImpactK ?? "0"
3624
+ );
3625
+ }
3626
+ function simulateSlippageForPair(raw, ntls, price) {
3627
+ if (!price || !price.mid) return EMPTY_RESULT;
3628
+ const ctx = buildPairContext(raw, price);
3629
+ const compute = (isBuy, capacity) => ntls.filter((ntl) => {
3630
+ const n = Number(ntl);
3631
+ return Number.isFinite(n) && n > 0 && n <= capacity;
3632
+ }).map((ntl) => {
3633
+ const result = priceImpactForLevel(raw, ctx, Number(ntl), isBuy);
3634
+ return { ntl, slippage: formatTokens(result.priceImpactP).toString() };
3635
+ });
3636
+ return {
3637
+ long: compute(true, ctx.remLong),
3638
+ short: compute(false, ctx.remShort)
3639
+ };
3640
+ }
3641
+ function simulateOrderbookForPair(raw, price, levels) {
3642
+ const safeLevels = Math.min(ORDERBOOK_MAX_LEVELS, Math.max(1, Math.floor(levels)));
3643
+ const ctx = buildPairContext(raw, price);
3644
+ const askNtls = generateLogSpacedNotionals(safeLevels, ctx.remLong);
3645
+ const bidNtls = generateLogSpacedNotionals(safeLevels, ctx.remShort);
3646
+ const toLevel = (ntl, isBuy) => {
3647
+ const result = priceImpactForLevel(raw, ctx, ntl, isBuy);
3648
+ const px = formatTokens(result.priceAfterImpact);
3649
+ return {
3650
+ px: px.toString(),
3651
+ sz: (px > 0 ? ntl / px : 0).toString(),
3652
+ n: 1
3653
+ };
3654
+ };
3655
+ return {
3656
+ pairId: String(raw.id),
3657
+ pairFrom: normalizePairName(raw.from),
3658
+ pairTo: normalizePairName(raw.to),
3659
+ levels: [
3660
+ bidNtls.map((n) => toLevel(n, false)),
3661
+ // bids: short entries, best (closest to mid) first
3662
+ askNtls.map((n) => toLevel(n, true))
3663
+ // asks: long entries, best (closest to mid) first
3664
+ ],
3665
+ time: Date.now()
3666
+ };
3667
+ }
3668
+
3669
+ // src/data/client.ts
3670
+ var OstiumSubgraphClient = class _OstiumSubgraphClient {
3671
+ gql;
3672
+ builderApiUrl;
3673
+ /** Cached pair-name (`${from}/${to}`) → `pairId` map. Refreshed lazily. */
3674
+ pairIdCache = null;
3675
+ /** Cached `pairId` → `"FROM-TO"` in raw subgraph dash format (used for OHLC API). */
3676
+ pairRawNameCache = null;
3677
+ constructor(gql, builderApiUrl) {
3678
+ this.gql = gql;
3679
+ this.builderApiUrl = builderApiUrl;
3680
+ }
3681
+ /**
3682
+ * Create a client connected to the Ostium subgraph.
3683
+ *
3684
+ * Fetches the full pair list at startup so that `streamPrices`, `getCandles`,
3685
+ * and `getAllPrices` can resolve pair ids to raw names without an extra round-trip.
3686
+ *
3687
+ * ```ts
3688
+ * // Mainnet (default)
3689
+ * const client = await OstiumSubgraphClient.create();
3690
+ *
3691
+ * // Testnet (Arbitrum Sepolia)
3692
+ * const client = await OstiumSubgraphClient.create({ testnet: true });
3693
+ * ```
3694
+ */
3695
+ static async create(config = {}) {
3696
+ const endpoint = config.endpoint ?? (config.testnet ? DEFAULT_SUBGRAPH_ENDPOINT_TESTNET : DEFAULT_SUBGRAPH_ENDPOINT);
3697
+ if (!endpoint.startsWith("http")) {
3698
+ throw new OstiumSubgraphError(
3699
+ `Invalid subgraph endpoint: ${endpoint}`,
3700
+ "INVALID_CONFIG" /* INVALID_CONFIG */
3701
+ );
3702
+ }
3703
+ const client = new _OstiumSubgraphClient(
3704
+ new GraphQLClient(endpoint),
3705
+ config.builderApiUrl ?? DEFAULT_BUILDER_API_URL
3706
+ );
3707
+ await client.initPairCache();
3708
+ return client;
3709
+ }
3710
+ async initPairCache() {
3711
+ const rawPairs = await this.fetchRawPairs();
3712
+ this.refreshPairIdCache(rawPairs);
3713
+ }
3714
+ // ─────────────────────────────────────────────────────────────────────────
3715
+ // Pairs
3716
+ // ─────────────────────────────────────────────────────────────────────────
3717
+ /**
3718
+ * All trading pairs with computed `minSz`/`maxBSz`/`maxSSz`, live prices, and
3719
+ * market-status flags. Pass `pairIds` to restrict to a subset.
3720
+ */
3721
+ async getPairs(params) {
3722
+ const [rawPairs, prices] = await Promise.all([
3723
+ this.fetchRawPairs(),
3724
+ this.fetchLivePricesSafe()
3725
+ ]);
3726
+ this.refreshPairIdCache(rawPairs);
3727
+ let filtered = rawPairs;
3728
+ if (params?.pairIds && params.pairIds.length > 0) {
3729
+ const requested = new Set(params.pairIds.map(String));
3730
+ filtered = rawPairs.filter((p) => requested.has(String(p.id)));
3731
+ }
3732
+ return { pairs: filtered.map((p) => formatPair(p, prices[`${p.from}/${p.to}`])) };
3733
+ }
3734
+ /** Live mid/bid/ask prices keyed by `pairId`. */
3735
+ async getAllPrices() {
3736
+ const [pairIdMap, prices] = await Promise.all([
3737
+ this.ensurePairIdCache(),
3738
+ this.fetchLivePricesSafe()
3739
+ ]);
3740
+ const out = {};
3741
+ for (const [name, price] of Object.entries(prices)) {
3742
+ const id = pairIdMap.get(name);
3743
+ if (!id) continue;
3744
+ out[id] = {
3745
+ ask: price.ask.toString(),
3746
+ bid: price.bid.toString(),
3747
+ mid: price.mid.toString()
3748
+ };
3749
+ }
3750
+ return { prices: out };
3751
+ }
3752
+ // ─────────────────────────────────────────────────────────────────────────
3753
+ // Open positions
3754
+ // ─────────────────────────────────────────────────────────────────────────
3755
+ /**
3756
+ * Open positions for a trader, sorted newest first, with margin summary.
3757
+ *
3758
+ * - Fetches live prices automatically.
3759
+ * - `blockNumber` is required for live PnL (rollover projection). When omitted,
3760
+ * PnL fields are zeroed.
3761
+ */
3762
+ async getOpenPositions(params) {
3763
+ const { user, blockNumber } = params;
3764
+ const [trades, prices] = await Promise.all([
3765
+ paginateAll(async (skip, first) => {
3766
+ const data = await this.query(
3767
+ GetTraderOpenTradesQuery,
3768
+ { trader: user.toLowerCase(), skip, first }
3769
+ );
3770
+ return data.trades;
3771
+ }),
3772
+ this.fetchLivePricesSafe()
3773
+ ]);
3774
+ let totalWithdrawable = 0;
3775
+ const pairPositions = trades.map((trade) => {
3776
+ const price = prices[`${trade.pair.from}/${trade.pair.to}`];
3777
+ const pnl = price && blockNumber ? getTradePnL(trade, price, blockNumber) : EMPTY_PNL;
3778
+ const maxLev = trade.isDayTrade ? formatLeverage(trade.pair.overnightMaxLeverage) : pairMaxLeverage(trade.pair);
3779
+ const pairPos = formatPosition(trade, price, pnl, maxLev);
3780
+ totalWithdrawable += parseFloat(pairPos.maxWithdrawable);
3781
+ return pairPos;
3782
+ });
3783
+ const marginSummary = aggregateMarginSummary(pairPositions);
3784
+ return {
3785
+ pairPositions,
3786
+ marginSummary,
3787
+ withdrawable: totalWithdrawable.toString(),
3788
+ time: Date.now()
3789
+ };
3790
+ }
3791
+ // ─────────────────────────────────────────────────────────────────────────
3792
+ // Fills
3793
+ // ─────────────────────────────────────────────────────────────────────────
3794
+ /**
3795
+ * Executed fills, sorted by `executedAt desc`.
3796
+ *
3797
+ * - `user`: pass an address to scope to a single trader, or `'ALL'` to fetch
3798
+ * fills across every trader (no trader filter).
3799
+ * - `pairId`: optional pair filter — when set, only fills on this pair are returned.
3800
+ */
3801
+ async getFills(params) {
3802
+ return this.fetchFills(params, void 0);
3803
+ }
3804
+ /** Executed fills within an inclusive time range (Unix ms). Same filters as `getFills`. */
3805
+ async getFillsByTime(params) {
3806
+ const endTime = params.endTime ?? Date.now();
3807
+ return this.fetchFills(params, {
3808
+ startSec: Math.floor(params.startTime / 1e3).toString(),
3809
+ endSec: Math.floor(endTime / 1e3).toString()
3810
+ });
3811
+ }
3812
+ async fetchFills(filters, timeRange) {
3813
+ const hasTrader = filters.user !== "ALL";
3814
+ const hasPairId = filters.pairId !== void 0;
3815
+ const limit = filters.limit ?? 1e3;
3816
+ const document = buildExecutedFillsQuery({
3817
+ hasTrader,
3818
+ hasPairId,
3819
+ hasTimeRange: timeRange !== void 0
3820
+ });
3821
+ const orders = await paginateAll(
3822
+ async (skip, first) => {
3823
+ const variables = { skip, first };
3824
+ if (hasTrader) variables.trader = filters.user.toLowerCase();
3825
+ if (hasPairId) variables.pairId = String(filters.pairId);
3826
+ if (timeRange) {
3827
+ variables.startSec = timeRange.startSec;
3828
+ variables.endSec = timeRange.endSec;
3829
+ }
3830
+ const data = await this.query(document, variables);
3831
+ return data.orders;
3832
+ },
3833
+ 1e3,
3834
+ limit
3835
+ );
3836
+ return orders.map(formatFill);
3837
+ }
3838
+ // ─────────────────────────────────────────────────────────────────────────
3839
+ // Open limit orders
3840
+ // ─────────────────────────────────────────────────────────────────────────
3841
+ /** Active limit orders for a trader, sorted by `updatedAt desc`. */
3842
+ async getOpenOrders({ user }) {
3843
+ const limits = await paginateAll(async (skip, first) => {
3844
+ const data = await this.query(
3845
+ GetTraderActiveLimitsQuery,
3846
+ { trader: user.toLowerCase(), skip, first }
3847
+ );
3848
+ return data.limits;
3849
+ });
3850
+ return limits.map(formatOpenOrder);
3851
+ }
3852
+ // ─────────────────────────────────────────────────────────────────────────
3853
+ // Orders (any status)
3854
+ // ─────────────────────────────────────────────────────────────────────────
3855
+ /**
3856
+ * Fetch orders at any status — pending, executed, or cancelled.
3857
+ *
3858
+ * - Pass `initiatedTxHashes` (e.g. `[result.txHash]` from `openTrade` / `closeTrade`)
3859
+ * to poll by the subgraph `initiatedTx` field.
3860
+ * - Pass `orderIds` to look up by on-chain order id (mutually exclusive with
3861
+ * `initiatedTxHashes`).
3862
+ * - Pass only `user` (or omit on `OstiumClient`) to get recent orders for
3863
+ * a trader regardless of status.
3864
+ */
3865
+ async getOrders(params = {}) {
3866
+ const hasOrderIds = !!(params.orderIds && params.orderIds.length > 0);
3867
+ const hasInitiatedTxHashes = !!(params.initiatedTxHashes && params.initiatedTxHashes.length > 0);
3868
+ if (hasOrderIds && hasInitiatedTxHashes) {
3869
+ throw new OstiumSubgraphError(
3870
+ "getOrders: pass either orderIds or initiatedTxHashes, not both",
3871
+ "INVALID_PARAMS" /* INVALID_PARAMS */
3872
+ );
3873
+ }
3874
+ const hasTrader = !hasOrderIds && !hasInitiatedTxHashes && !!params.user;
3875
+ const limit = params.limit ?? 100;
3876
+ const document = buildGetOrdersQuery({
3877
+ hasOrderIds,
3878
+ hasInitiatedTxHashes,
3879
+ hasTrader
3880
+ });
3881
+ const orders = await paginateAll(
3882
+ async (skip, first) => {
3883
+ const variables = { skip, first };
3884
+ if (hasOrderIds) variables.ids = params.orderIds.map(String);
3885
+ if (hasInitiatedTxHashes) {
3886
+ variables.txHashes = params.initiatedTxHashes.map(
3887
+ (h) => typeof h === "string" ? h.toLowerCase() : h
3888
+ );
3889
+ }
3890
+ if (hasTrader) variables.trader = params.user.toLowerCase();
3891
+ const data = await this.query(document, variables);
3892
+ return data.orders;
3893
+ },
3894
+ 100,
3895
+ limit
3896
+ );
3897
+ return orders.map(formatOrder);
3898
+ }
3899
+ // ─────────────────────────────────────────────────────────────────────────
3900
+ // Simulated slippage
3901
+ // ─────────────────────────────────────────────────────────────────────────
3902
+ /**
3903
+ * Simulate the dynamic-spread slippage a long and a short entry of each
3904
+ * notional would experience on the given pairs. Notionals exceeding the
3905
+ * side's remaining open-interest capacity (`maxOI − sideOI`) are dropped.
3906
+ *
3907
+ * Computed via `CalculateDynamicPriceImpact` from `@ostium/formulae` using
3908
+ * the pair's live OI / decay / threshold params + the current bid/mid/ask
3909
+ * from the live-prices feed (collateral = `ntl`, leverage = 1).
3910
+ *
3911
+ * ```ts
3912
+ * const sim = await client.getSimSlippage({
3913
+ * pairIds: ['0', '1'],
3914
+ * ntls: ['10000', '100000', '1000000'],
3915
+ * });
3916
+ * // → { '0': { long: [{ ntl, slippage }...], short: [...] }, '1': ... }
3917
+ * ```
3918
+ */
3919
+ async getSimSlippage(params) {
3920
+ const [rawPairs, prices] = await Promise.all([
3921
+ this.fetchRawPairs(),
3922
+ this.fetchLivePricesSafe()
3923
+ ]);
3924
+ this.refreshPairIdCache(rawPairs);
3925
+ const requested = new Set(params.pairIds.map(String));
3926
+ const out = {};
3927
+ for (const pair of rawPairs) {
3928
+ const id = String(pair.id);
3929
+ if (!requested.has(id)) continue;
3930
+ const price = prices[`${pair.from}/${pair.to}`];
3931
+ out[id] = simulateSlippageForPair(pair, params.ntls, price);
3932
+ }
3933
+ return out;
3934
+ }
3935
+ /**
3936
+ * Build a synthetic bid/ask orderbook for a single pair using the on-chain
3937
+ * dynamic-spread params. Each side gets up to `levels` (capped at 20)
3938
+ * exponentially-spaced notional levels (`[1, 2, 3, 5] × 10ⁿ`), stopping at
3939
+ * the side's remaining open-interest capacity.
3940
+ *
3941
+ * ```ts
3942
+ * const ob = await client.getSimOrderbook({ pairId: '0', levels: 20 });
3943
+ * // ob.asks: long-entry levels (you'd buy at `px`)
3944
+ * // ob.bids: short-entry levels (you'd sell at `px`)
3945
+ * ```
3946
+ */
3947
+ async getSimOrderbook(params) {
3948
+ const targetId = String(params.pairId);
3949
+ const levels = params.levels ?? 20;
3950
+ const [rawPairs, prices] = await Promise.all([
3951
+ this.fetchRawPairs(),
3952
+ this.fetchLivePricesSafe()
3953
+ ]);
3954
+ this.refreshPairIdCache(rawPairs);
3955
+ const pair = rawPairs.find((p) => String(p.id) === targetId);
3956
+ if (!pair) {
3957
+ throw new OstiumSubgraphError(
3958
+ `Pair ${targetId} not found in subgraph response`,
3959
+ "NOT_FOUND" /* NOT_FOUND */
3960
+ );
3961
+ }
3962
+ const price = prices[`${pair.from}/${pair.to}`];
3963
+ if (!price || !price.mid) {
3964
+ throw new OstiumSubgraphError(
3965
+ `No live price available for ${pair.from}/${pair.to}`,
3966
+ "NOT_FOUND" /* NOT_FOUND */
3967
+ );
3968
+ }
3969
+ return simulateOrderbookForPair(pair, price, levels);
3970
+ }
3971
+ // ─────────────────────────────────────────────────────────────────────────
3972
+ // OHLC candles
3973
+ // ─────────────────────────────────────────────────────────────────────────
3974
+ /**
3975
+ * Fetch OHLC candles for a pair.
3976
+ *
3977
+ * `pairId` maps to the raw subgraph pair name internally (e.g. pair `0` →
3978
+ * `"BTC-USD"`). `from` / `to` are Unix milliseconds; `resolution` is one of
3979
+ * `"1"`, `"5"`, `"15"`, `"60"`, `"240"`, `"1D"`.
3980
+ *
3981
+ * ```ts
3982
+ * const candles = await client.getCandles({
3983
+ * pairId: 0,
3984
+ * from: Date.now() - 7 * 86_400_000,
3985
+ * resolution: '1D',
3986
+ * });
3987
+ * ```
3988
+ */
3989
+ async getCandles(params) {
3990
+ const rawPair = await this.ensurePairRawName(params.pairId);
3991
+ return fetchCandles(
3992
+ this.builderApiUrl,
3993
+ rawPair,
3994
+ params.from,
3995
+ params.to ?? Date.now(),
3996
+ params.resolution
3997
+ );
3998
+ }
3999
+ // ─────────────────────────────────────────────────────────────────────────
4000
+ // Live price stream (WebSocket)
4001
+ // ─────────────────────────────────────────────────────────────────────────
4002
+ /**
4003
+ * Open a WebSocket connection to the live price stream.
4004
+ *
4005
+ * Optionally filter to a subset of pairs by `pairId` — same values as returned by
4006
+ * `getPairs()`. When provided, the client sends `{ type: "subscribe", pairs }` on
4007
+ * `open` (no `?pairs=` query on the URL). Omit `pairIds` to receive the full feed.
4008
+ *
4009
+ * The returned `OstiumPriceStream` fires an initial `snapshot` event with all
4010
+ * cached ticks, then a `tick` event on every update. `PriceTick.from` / `.to`
4011
+ * are normalized display names (e.g. `"WTI"` not `"CL"`).
4012
+ *
4013
+ * ```ts
4014
+ * const stream = client.streamPrices([0, 1]); // BTC and ETH by pairId
4015
+ *
4016
+ * stream.onOpen(() => console.log('connected'));
4017
+ * stream.onSnapshot(ticks => console.log('snapshot', ticks.length));
4018
+ * stream.onTick(tick => console.log(tick.pair, tick.mid));
4019
+ *
4020
+ * // Dynamically add / remove by pairId:
4021
+ * stream.subscribe([2]);
4022
+ * stream.unsubscribe([0]);
4023
+ * stream.close();
4024
+ * ```
4025
+ *
4026
+ * Requires a runtime with native `WebSocket` (Node.js 18+, Bun, browsers). Bun’s
4027
+ * `WebSocket` may fail some `https://` upgrades (e.g. CloudFront); use Node if so.
4028
+ */
4029
+ streamPrices(pairIds) {
4030
+ const cache = this.pairRawNameCache ?? /* @__PURE__ */ new Map();
4031
+ const rawNames = pairIds?.map((id) => {
4032
+ const name = cache.get(String(id));
4033
+ if (!name) throw new OstiumSubgraphError(`Pair ${id} not found`, "NOT_FOUND" /* NOT_FOUND */);
4034
+ return name;
4035
+ });
4036
+ return OstiumPriceStream.connect(this.builderApiUrl, rawNames, cache);
4037
+ }
4038
+ // ─────────────────────────────────────────────────────────────────────────
4039
+ // Internal — fetchers, cache, query wrapper
4040
+ // ─────────────────────────────────────────────────────────────────────────
4041
+ async fetchRawPairs() {
4042
+ const data = await this.query(GetPairsAndGroupsQuery);
4043
+ return data.pairs;
4044
+ }
4045
+ refreshPairIdCache(rawPairs) {
4046
+ this.pairIdCache = new Map(rawPairs.map((p) => [`${p.from}/${p.to}`, String(p.id)]));
4047
+ this.pairRawNameCache = new Map(rawPairs.map((p) => [String(p.id), `${p.from}-${p.to}`]));
4048
+ }
4049
+ async ensurePairIdCache() {
4050
+ if (this.pairIdCache) return this.pairIdCache;
4051
+ this.refreshPairIdCache(await this.fetchRawPairs());
4052
+ return this.pairIdCache;
4053
+ }
4054
+ async ensurePairRawName(pairId) {
4055
+ if (!this.pairRawNameCache) {
4056
+ this.refreshPairIdCache(await this.fetchRawPairs());
4057
+ }
4058
+ const name = this.pairRawNameCache.get(String(pairId));
4059
+ if (!name) {
4060
+ throw new OstiumSubgraphError(
4061
+ `Pair ${pairId} not found`,
4062
+ "NOT_FOUND" /* NOT_FOUND */
4063
+ );
4064
+ }
4065
+ return name;
4066
+ }
4067
+ /** Wrapped `fetchLivePrices` that swallows network errors and returns `{}`. */
4068
+ async fetchLivePricesSafe() {
4069
+ try {
4070
+ return await fetchLivePrices(this.builderApiUrl);
4071
+ } catch {
4072
+ return {};
4073
+ }
4074
+ }
4075
+ async query(document, variables) {
4076
+ try {
4077
+ return await this.gql.request(document, variables);
4078
+ } catch (err) {
4079
+ const msg = err instanceof Error ? err.message : String(err);
4080
+ const lower = msg.toLowerCase();
4081
+ if (lower.includes("network") || lower.includes("timeout") || lower.includes("fetch")) {
4082
+ throw new OstiumSubgraphError(
4083
+ `Subgraph network error: ${msg}`,
4084
+ "FETCH_FAILED" /* FETCH_FAILED */,
4085
+ err
4086
+ );
4087
+ }
4088
+ throw new OstiumSubgraphError(
4089
+ `Subgraph query failed: ${msg}`,
4090
+ "FETCH_FAILED" /* FETCH_FAILED */,
4091
+ err
4092
+ );
4093
+ }
4094
+ }
4095
+ };
4096
+ function aggregateMarginSummary(pairPositions) {
4097
+ let accountValue = 0;
4098
+ let totalCollateralUsed = 0;
4099
+ let totalNtlPos = 0;
4100
+ let totalRawPnlUsd = 0;
4101
+ for (const { position } of pairPositions) {
4102
+ const collateral = parseFloat(position.collateralUsed) || 0;
4103
+ const ntl = parseFloat(position.ntl) || 0;
4104
+ const pnl = parseFloat(position.unrealizedPnl) || 0;
4105
+ accountValue += collateral + pnl;
4106
+ totalCollateralUsed += collateral;
4107
+ totalNtlPos += ntl;
4108
+ totalRawPnlUsd += pnl;
4109
+ }
4110
+ return {
4111
+ accountValue: accountValue.toString(),
4112
+ totalCollateralUsed: totalCollateralUsed.toString(),
4113
+ totalNtlPos: totalNtlPos.toString(),
4114
+ totalRawPnlUsd: totalRawPnlUsd.toString()
4115
+ };
4116
+ }
4117
+
4118
+ // src/client.ts
4119
+ var HEX64_RE = /^0x[0-9a-fA-F]{64}$/;
4120
+ var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
4121
+ function validateConfig(config) {
4122
+ if (!HEX64_RE.test(config.privateKey)) {
4123
+ throw new OstiumError(
4124
+ "privateKey must be a 64-character hex string prefixed with 0x",
4125
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4126
+ );
4127
+ }
4128
+ if (config.traderAddress && !ADDRESS_RE.test(config.traderAddress)) {
4129
+ throw new OstiumError(
4130
+ "traderAddress must be a valid 42-character Ethereum address (0x + 40 hex chars)",
4131
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4132
+ );
4133
+ }
4134
+ if (config.slippageBps !== void 0 && (config.slippageBps < 0 || config.slippageBps > 500)) {
4135
+ throw new OstiumError(
4136
+ "slippageBps must be between 0 and 500 (0%\u20135%)",
4137
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4138
+ );
4139
+ }
4140
+ if (config.builder !== void 0 && (config.builder.feeBps < 0 || config.builder.feeBps > 50)) {
4141
+ throw new OstiumError(
4142
+ "builder.feeBps must be between 0 and 50 (max 0.5%)",
4143
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4144
+ );
4145
+ }
4146
+ }
4147
+ var OstiumClient = class _OstiumClient {
4148
+ signer;
4149
+ submitter;
4150
+ contracts;
4151
+ publicClient;
4152
+ defaultSlippageBps;
4153
+ delegated;
4154
+ gasless;
4155
+ selfGasless;
4156
+ eoaSubmit;
4157
+ builderAddress;
4158
+ builderFeeBps;
4159
+ /** Internal subgraph client backing all read methods (`getPairs`, `getOpenPositions`, …). */
4160
+ subgraph;
4161
+ constructor(internals) {
4162
+ this.signer = internals.signer;
4163
+ this.submitter = internals.submitter;
4164
+ this.contracts = internals.contracts;
4165
+ this.publicClient = internals.publicClient;
4166
+ this.defaultSlippageBps = internals.defaultSlippageBps;
4167
+ this.delegated = internals.delegated;
4168
+ this.gasless = internals.gasless;
4169
+ this.selfGasless = internals.selfGasless;
4170
+ this.eoaSubmit = internals.eoaSubmit;
4171
+ this.builderAddress = internals.builderAddress;
4172
+ this.builderFeeBps = internals.builderFeeBps;
4173
+ this.subgraph = internals.subgraph;
4174
+ }
4175
+ /**
4176
+ * **Self + Self** — your EOA signs every transaction and pays gas directly.
4177
+ *
4178
+ * Use this when you want the simplest possible setup: one key, no smart accounts,
4179
+ * no delegation. Your EOA holds USDC and owns all positions.
4180
+ *
4181
+ * ```ts
4182
+ * const client = await OstiumClient.createSelfAndSelf({
4183
+ * traderPrivateKey: '0x...',
4184
+ * rpcUrl: 'https://arb-mainnet.g.alchemy.com/v2/...',
4185
+ * });
4186
+ * await client.openTrade({ ... });
4187
+ * ```
4188
+ */
4189
+ static async createSelfAndSelf(params) {
4190
+ return _OstiumClient._fromConfig({
4191
+ privateKey: params.traderPrivateKey,
4192
+ rpcUrl: params.rpcUrl,
4193
+ testnet: params.testnet,
4194
+ slippageBps: params.slippageBps,
4195
+ builder: params.builder,
4196
+ subgraphUrl: params.subgraphUrl,
4197
+ builderApiUrl: params.builderApiUrl
4198
+ });
4199
+ }
4200
+ /**
4201
+ * **Self + Gasless** — your EOA owns everything; a Safe relays trades for free.
4202
+ *
4203
+ * Your EOA holds USDC and owns all positions. A Safe smart account is derived
4204
+ * deterministically from your private key and registered as your on-chain delegate.
4205
+ * After a one-time setup (approve USDC + `setupGaslessDelegation()`), all trades
4206
+ * are submitted as sponsored UserOperations — no ETH required.
4207
+ *
4208
+ * ```ts
4209
+ * const client = await OstiumClient.createSelfAndGasless({
4210
+ * traderPrivateKey: '0x...',
4211
+ * pimlicoUrl: 'https://builder.ostium.io/v1/pimlico/sponsor?chainId=42161',
4212
+ * });
4213
+ * // One-time setup — EOA pays gas once for each:
4214
+ * await client.approveUsdc('max');
4215
+ * await client.setupGaslessDelegation();
4216
+ * // All subsequent trading is gasless:
4217
+ * await client.openTrade({ ... });
4218
+ * ```
4219
+ */
4220
+ static async createSelfAndGasless(params) {
4221
+ const defaultUrl = params.testnet ? DEFAULT_PIMLICO_URL_TESTNET : DEFAULT_PIMLICO_URL;
4222
+ return _OstiumClient._fromConfig({
4223
+ privateKey: params.traderPrivateKey,
4224
+ pimlicoUrl: params.pimlicoUrl ?? defaultUrl,
4225
+ rpcUrl: params.rpcUrl,
4226
+ sponsorshipPolicyId: params.sponsorshipPolicyId,
4227
+ testnet: params.testnet,
4228
+ slippageBps: params.slippageBps,
4229
+ builder: params.builder,
4230
+ subgraphUrl: params.subgraphUrl,
4231
+ builderApiUrl: params.builderApiUrl
4232
+ });
4233
+ }
4234
+ /**
4235
+ * **Delegated + Self** — a delegate EOA signs and pays gas on behalf of a trader address.
4236
+ *
4237
+ * The trader retains custody of USDC and positions. The delegate only needs ETH
4238
+ * for gas. Every trade is wrapped in `delegatedAction(traderAddress, callData)`.
4239
+ * The trader must call `setDelegate(delegateAddress)` once before this client
4240
+ * can submit trades.
4241
+ *
4242
+ * ```ts
4243
+ * const client = await OstiumClient.createDelegatedAndSelf({
4244
+ * delegatePrivateKey: '0xDelegateKey',
4245
+ * traderAddress: '0xTraderAddress',
4246
+ * rpcUrl: 'https://arb-mainnet.g.alchemy.com/v2/...',
4247
+ * });
4248
+ * await client.openTrade({ ... });
4249
+ * ```
4250
+ */
4251
+ static async createDelegatedAndSelf(params) {
4252
+ return _OstiumClient._fromConfig({
4253
+ privateKey: params.delegatePrivateKey,
4254
+ traderAddress: params.traderAddress,
4255
+ rpcUrl: params.rpcUrl,
4256
+ testnet: params.testnet,
4257
+ slippageBps: params.slippageBps,
4258
+ builder: params.builder,
4259
+ subgraphUrl: params.subgraphUrl,
4260
+ builderApiUrl: params.builderApiUrl
4261
+ });
4262
+ }
4263
+ /**
4264
+ * **Delegated + Gasless** — a Safe derived from the delegate key submits sponsored
4265
+ * UserOperations on behalf of the trader. No ETH needed after setup.
4266
+ *
4267
+ * The trader retains custody of USDC and positions. The delegate's Safe submits
4268
+ * trades as UserOperations via Pimlico. The trader must call `setDelegate(safeAddress)`
4269
+ * once — use `client.getSmartAccountAddress()` to retrieve the Safe address.
4270
+ *
4271
+ * ```ts
4272
+ * const client = await OstiumClient.createDelegatedAndGasless({
4273
+ * delegatePrivateKey: '0xDelegateKey',
4274
+ * traderAddress: '0xTraderAddress',
4275
+ * pimlicoUrl: 'https://builder.ostium.io/v1/pimlico/sponsor?chainId=42161',
4276
+ * });
4277
+ * await client.openTrade({ ... }); // gasless delegatedAction UserOp
4278
+ * ```
4279
+ */
4280
+ static async createDelegatedAndGasless(params) {
4281
+ const defaultUrl = params.testnet ? DEFAULT_PIMLICO_URL_TESTNET : DEFAULT_PIMLICO_URL;
4282
+ return _OstiumClient._fromConfig({
4283
+ privateKey: params.delegatePrivateKey,
4284
+ traderAddress: params.traderAddress,
4285
+ pimlicoUrl: params.pimlicoUrl ?? defaultUrl,
4286
+ rpcUrl: params.rpcUrl,
4287
+ sponsorshipPolicyId: params.sponsorshipPolicyId,
4288
+ testnet: params.testnet,
4289
+ slippageBps: params.slippageBps,
4290
+ builder: params.builder,
4291
+ subgraphUrl: params.subgraphUrl,
4292
+ builderApiUrl: params.builderApiUrl
4293
+ });
4294
+ }
4295
+ /**
4296
+ * **Read-only client** — no signer, no submitter, no privateKey required.
4297
+ *
4298
+ * All read methods (`getPairs`, `getOpenPositions`, `getFills`, `getBalances`, …)
4299
+ * are available. Methods that take an optional `user` argument require it to be
4300
+ * passed explicitly. Calling any write method throws `INVALID_CONFIG`.
4301
+ *
4302
+ * ```ts
4303
+ * const reader = await OstiumClient.createReadOnly();
4304
+ * const { pairs } = await reader.getPairs();
4305
+ * const balances = await reader.getBalances('0xTrader...');
4306
+ * const positions = await reader.getOpenPositions({ user: '0xTrader...' });
4307
+ * ```
4308
+ */
4309
+ static async createReadOnly(params = {}) {
4310
+ const testnet = params.testnet ?? false;
4311
+ const networkConfig = getNetworkConfig(testnet);
4312
+ const chain = testnet ? arbitrumSepolia : arbitrum;
4313
+ const rpcUrl = params.rpcUrl ?? chain.rpcUrls.default.http[0];
4314
+ const contracts = {
4315
+ trading: networkConfig.contracts.trading,
4316
+ tradingStorage: networkConfig.contracts.tradingStorage,
4317
+ usdc: networkConfig.contracts.usdc
4318
+ };
4319
+ const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
4320
+ const subgraph = await OstiumSubgraphClient.create({
4321
+ testnet,
4322
+ endpoint: params.subgraphUrl,
4323
+ builderApiUrl: params.builderApiUrl
4324
+ });
4325
+ return new _OstiumClient({
4326
+ contracts,
4327
+ publicClient,
4328
+ defaultSlippageBps: Math.round(DEFAULT_SLIPPAGE_PERCENTAGE * 100),
4329
+ delegated: false,
4330
+ gasless: false,
4331
+ selfGasless: false,
4332
+ subgraph
4333
+ });
4334
+ }
4335
+ /** Internal factory shared by all public constructors. */
4336
+ static async _fromConfig(config) {
4337
+ validateConfig(config);
4338
+ const testnet = config.testnet ?? false;
4339
+ const networkConfig = getNetworkConfig(testnet);
4340
+ const chain = testnet ? arbitrumSepolia : arbitrum;
4341
+ const defaultSlippageBps = config.slippageBps ?? Math.round(DEFAULT_SLIPPAGE_PERCENTAGE * 100);
4342
+ const contracts = {
4343
+ trading: networkConfig.contracts.trading,
4344
+ tradingStorage: networkConfig.contracts.tradingStorage,
4345
+ usdc: networkConfig.contracts.usdc
4346
+ };
4347
+ const selfGasless = isGasless(config) && !isDelegated(config);
4348
+ const submitter = await createSubmitter(config, testnet);
4349
+ let traderAddress;
4350
+ if (isDelegated(config)) {
4351
+ traderAddress = config.traderAddress;
4352
+ } else {
4353
+ traderAddress = privateKeyToAccount(config.privateKey).address;
4354
+ }
4355
+ const signer = createSigner(config, traderAddress, selfGasless);
4356
+ const publicRpc = testnet ? "https://sepolia-rollup.arbitrum.io/rpc" : "https://arb1.arbitrum.io/rpc";
4357
+ const rpcUrl = config.rpcUrl ?? (isGasless(config) ? publicRpc : void 0);
4358
+ if (!isGasless(config) && !config.rpcUrl) {
4359
+ throw new OstiumError(
4360
+ "rpcUrl is required for self-submission mode",
4361
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4362
+ );
4363
+ }
4364
+ const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
4365
+ let eoaSubmit;
4366
+ if (selfGasless) {
4367
+ const eoaAccount = privateKeyToAccount(config.privateKey);
4368
+ const eoaRpcUrl = config.rpcUrl ?? publicRpc;
4369
+ const eoaWalletClient = createWalletClient({ account: eoaAccount, chain, transport: http(eoaRpcUrl) });
4370
+ eoaSubmit = async (encoded) => {
4371
+ const txHash = await eoaWalletClient.sendTransaction({
4372
+ account: eoaAccount,
4373
+ to: encoded.to,
4374
+ data: encoded.data,
4375
+ value: encoded.value
4376
+ });
4377
+ return { txHash };
4378
+ };
4379
+ }
4380
+ const subgraph = await OstiumSubgraphClient.create({
4381
+ testnet,
4382
+ endpoint: config.subgraphUrl,
4383
+ builderApiUrl: config.builderApiUrl
4384
+ });
4385
+ return new _OstiumClient({
4386
+ signer,
4387
+ submitter,
4388
+ contracts,
4389
+ publicClient,
4390
+ defaultSlippageBps,
4391
+ delegated: isDelegated(config),
4392
+ gasless: isGasless(config),
4393
+ selfGasless,
4394
+ eoaSubmit,
4395
+ builderAddress: config.builder?.address,
4396
+ builderFeeBps: config.builder?.feeBps,
4397
+ subgraph
4398
+ });
4399
+ }
4400
+ // ─────────────────────────────────────────────────────────────────────────
4401
+ // Getters
4402
+ // ─────────────────────────────────────────────────────────────────────────
4403
+ /**
4404
+ * The on-chain address that owns trades and USDC allowances.
4405
+ *
4406
+ * - Self + Self / Delegated modes: trader's EOA or configured traderAddress.
4407
+ * - Self + Gasless: EOA derived from privateKey (NOT the Safe — USDC lives here).
4408
+ */
4409
+ getTraderAddress() {
4410
+ if (!this.signer) {
4411
+ throw new OstiumError(
4412
+ "No connected trader \u2014 pass `user` explicitly or use one of the createSelfAnd*/createDelegatedAnd* factories.",
4413
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4414
+ );
4415
+ }
4416
+ return this.signer.traderAddress;
4417
+ }
4418
+ /** True when the client was created via `createReadOnly` and cannot submit transactions. */
4419
+ isReadOnly() {
4420
+ return !this.signer || !this.submitter;
4421
+ }
4422
+ /**
4423
+ * Returns the Safe smart-account address used for gasless submission.
4424
+ * Returns undefined when not in gasless mode.
4425
+ *
4426
+ * - Self + Gasless: Safe that submits on behalf of the EOA (the delegate).
4427
+ * Pass this address to setupGaslessDelegation().
4428
+ * - Delegated + Gasless: delegate's Safe address.
4429
+ * - Self + Self / Delegated + Self: returns undefined.
4430
+ */
4431
+ getSmartAccountAddress() {
4432
+ return this.gasless && this.submitter ? this.submitter.effectiveSender : void 0;
4433
+ }
4434
+ // ─────────────────────────────────────────────────────────────────────────
4435
+ // Self + Gasless setup
4436
+ // ─────────────────────────────────────────────────────────────────────────
4437
+ /**
4438
+ * One-time setup for Self + Gasless mode.
4439
+ *
4440
+ * Registers the Safe smart account as a delegate on the trading contract so
4441
+ * the Safe can submit gasless trades on behalf of your EOA. The EOA pays gas
4442
+ * for this single transaction; all subsequent trading is gasless.
4443
+ *
4444
+ * Only callable in Self + Gasless mode. Throws INVALID_CONFIG otherwise.
4445
+ *
4446
+ * @example
4447
+ * ```ts
4448
+ * const client = await OstiumClient.create({ privateKey: '0x...', pimlicoUrl: 'https://builder.ostium.io/v1/pimlico/sponsor?chainId=42161' });
4449
+ * await client.approveUsdc('max'); // EOA approves USDC (gas, one-time)
4450
+ * await client.setupGaslessDelegation(); // EOA sets Safe as delegate (gas, one-time)
4451
+ * // From here: all trading is gasless
4452
+ * await client.openTrade({ ... });
4453
+ * ```
4454
+ */
4455
+ async setupGaslessDelegation() {
4456
+ if (!this.selfGasless || !this.eoaSubmit || !this.submitter) {
4457
+ throw new OstiumError(
4458
+ "setupGaslessDelegation() is only available in Self + Gasless mode. Create the client with pimlicoUrl but without traderAddress.",
4459
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4460
+ );
4461
+ }
4462
+ const safeAddress = this.submitter.effectiveSender;
4463
+ const encoded = encodeSetDelegate(safeAddress, this.contracts.trading);
4464
+ return this.submitDirectFromEoa(encoded);
4465
+ }
4466
+ // ─────────────────────────────────────────────────────────────────────────
4467
+ // USDC helpers
4468
+ // ─────────────────────────────────────────────────────────────────────────
4469
+ /**
4470
+ * Check whether the trader's USDC allowance covers the required amount.
4471
+ * The allowance is always checked against signer.traderAddress (the EOA in
4472
+ * Self + Gasless mode, the Safe in Delegated + Gasless).
4473
+ */
4474
+ async checkUsdcAllowance(requiredUsd) {
4475
+ const required = parseUsdc(requiredUsd);
4476
+ const current = await this.publicClient.readContract({
4477
+ address: this.contracts.usdc,
4478
+ abi: ERC20_ABI,
4479
+ functionName: "allowance",
4480
+ args: [this.getTraderAddress(), this.contracts.tradingStorage]
4481
+ });
4482
+ return { current, required, sufficient: current >= required };
4483
+ }
4484
+ /**
4485
+ * USDC and ETH balances plus the USDC allowance to TradingStorage.
4486
+ * All three values are decimal strings so large values (e.g. max USDC approval)
4487
+ * are preserved exactly. Parse with `parseFloat` / `Number` only for display.
4488
+ *
4489
+ * In read-only mode, pass `user` explicitly. With a connected trader, omit it
4490
+ * to read the connected address.
4491
+ */
4492
+ async getBalances(user) {
4493
+ const trader = user ?? this.getTraderAddress();
4494
+ const [usdcRaw, ethRaw, allowanceRaw] = await Promise.all([
4495
+ this.publicClient.readContract({
4496
+ address: this.contracts.usdc,
4497
+ abi: ERC20_ABI,
4498
+ functionName: "balanceOf",
4499
+ args: [trader]
4500
+ }),
4501
+ this.publicClient.getBalance({ address: trader }),
4502
+ this.publicClient.readContract({
4503
+ address: this.contracts.usdc,
4504
+ abi: ERC20_ABI,
4505
+ functionName: "allowance",
4506
+ args: [trader, this.contracts.tradingStorage]
4507
+ })
4508
+ ]);
4509
+ return {
4510
+ usdc: formatUnits(usdcRaw, 6),
4511
+ eth: formatUnits(ethRaw, 18),
4512
+ allowance: formatUnits(allowanceRaw, 6)
4513
+ };
4514
+ }
4515
+ /**
4516
+ * Approve USDC spending by the TradingStorage contract.
4517
+ *
4518
+ * - Self + Self: submitted gaslessly from EOA.
4519
+ * - Self + Gasless: submitted directly from EOA (the delegate cannot approve
4520
+ * on behalf of the trader). The EOA pays gas for this one-time operation.
4521
+ * - Delegated modes: throws — the trader must approve from their own account.
4522
+ *
4523
+ * @param amount USD amount as decimal string (e.g. "1000"), or "max" for MaxUint256.
4524
+ */
4525
+ async approveUsdc(amount) {
4526
+ if (this.delegated) {
4527
+ throw new OstiumError(
4528
+ "approveUsdc is not available in delegated mode. The trader must approve USDC directly from their own account.",
4529
+ "DELEGATION_FAILED" /* DELEGATION_FAILED */
4530
+ );
4531
+ }
4532
+ const rawAmount = amount === "max" ? maxUint256 : parseUsdc(amount);
4533
+ const encoded = encodeUsdcApprove(this.contracts.tradingStorage, rawAmount, this.contracts.usdc);
4534
+ if (this.selfGasless) {
4535
+ return this.submitDirectFromEoa(encoded);
4536
+ }
4537
+ return this.requireWriter().submitter.submit(encoded);
4538
+ }
4539
+ // ─────────────────────────────────────────────────────────────────────────
4540
+ // Delegation helpers
4541
+ // ─────────────────────────────────────────────────────────────────────────
4542
+ /**
4543
+ * Set a delegate on the trading contract.
4544
+ *
4545
+ * - Self + Self: EOA directly registers a delegate.
4546
+ * - Self + Gasless: NOT recommended — use setupGaslessDelegation() instead.
4547
+ * - Delegated modes: wrapped in delegatedAction so the existing delegate can
4548
+ * update the trader's delegation on their behalf.
4549
+ */
4550
+ async setDelegate(delegateAddress) {
4551
+ const encoded = encodeSetDelegate(delegateAddress, this.contracts.trading);
4552
+ return this.execute(encoded);
4553
+ }
4554
+ /**
4555
+ * Remove the current delegate on the trading contract.
4556
+ * Follows the same delegation-wrapping rules as setDelegate().
4557
+ */
4558
+ async removeDelegate() {
4559
+ const encoded = encodeRemoveDelegate(this.contracts.trading);
4560
+ return this.execute(encoded);
4561
+ }
4562
+ // ─────────────────────────────────────────────────────────────────────────
4563
+ // Core trading methods
4564
+ // ─────────────────────────────────────────────────────────────────────────
4565
+ /**
4566
+ * Open a new trade position.
4567
+ *
4568
+ * Call `approveUsdc()` (once) before the first trade — the contract will revert
4569
+ * on-chain if the USDC allowance is insufficient. Use `getBalances()` to check
4570
+ * the current allowance.
4571
+ */
4572
+ async openTrade(params) {
4573
+ const collateralNum = parseFloat(params.collateral);
4574
+ if (collateralNum > MAX_COLLATERAL_USD) {
4575
+ throw new OstiumError(
4576
+ `Collateral ${params.collateral} exceeds maximum ${MAX_COLLATERAL_USD}`,
4577
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */
4578
+ );
4579
+ }
4580
+ const apiOpen = {
4581
+ a: params.pairIndex,
4582
+ b: params.buy,
4583
+ p: params.price,
4584
+ s: params.collateral,
4585
+ l: params.leverage,
4586
+ t: params.type,
4587
+ tp: params.takeProfit,
4588
+ sl: params.stopLoss,
4589
+ d: params.isDayTrade
4590
+ };
4591
+ const apiBuilder = this.builderAddress !== void 0 && this.builderFeeBps !== void 0 ? { b: this.builderAddress, f: this.builderFeeBps } : void 0;
4592
+ let trade, orderType;
4593
+ try {
4594
+ ({ trade, orderType } = buildTrade(apiOpen, this.getTraderAddress()));
4595
+ } catch (err) {
4596
+ throw new OstiumError(
4597
+ `Trade validation failed: ${err instanceof Error ? err.message : String(err)}`,
4598
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */,
4599
+ err
4600
+ );
4601
+ }
4602
+ const builderFee = buildBuilderFee(apiBuilder);
4603
+ const slippageP = params.type === "market" /* Market */ ? BigInt(this.resolveSlippage(params.slippage)) : 0n;
4604
+ const encoded = encodeOpenTrade(trade, builderFee, orderType, slippageP, this.contracts.trading);
4605
+ return this.execute(encoded);
4606
+ }
4607
+ /**
4608
+ * Close an open position (full or partial).
4609
+ *
4610
+ * `pairId` and `idx` come straight from a `Position` returned by
4611
+ * `getOpenPositions` — pass them through directly:
4612
+ *
4613
+ * ```ts
4614
+ * const { pairPositions } = await client.getOpenPositions();
4615
+ * const { pairId, idx } = pairPositions[0].position;
4616
+ * await client.closeTrade({ pairId, idx, price: '...', closePercent: 100 });
4617
+ * ```
4618
+ */
4619
+ async closeTrade(params) {
4620
+ try {
4621
+ validateCloseParams({
4622
+ a: Number(params.pairId),
4623
+ t: params.idx,
4624
+ p: params.price,
4625
+ r: params.closePercent
4626
+ });
4627
+ } catch (err) {
4628
+ throw new OstiumError(
4629
+ `Close validation failed: ${err instanceof Error ? err.message : String(err)}`,
4630
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */,
4631
+ err
4632
+ );
4633
+ }
4634
+ const pairIndex = BigInt(params.pairId);
4635
+ const index = BigInt(params.idx);
4636
+ const closePercentage = BigInt(Math.round(params.closePercent * 100));
4637
+ const marketPrice = parsePrice(params.price);
4638
+ const slippageP = BigInt(this.resolveSlippage(params.slippage));
4639
+ const encoded = encodeCloseTradeMarket(
4640
+ pairIndex,
4641
+ index,
4642
+ closePercentage,
4643
+ marketPrice,
4644
+ slippageP,
4645
+ this.contracts.trading
4646
+ );
4647
+ return this.execute(encoded);
4648
+ }
4649
+ /**
4650
+ * Cancel a pending order.
4651
+ *
4652
+ * TypeScript discriminates the params shape by `type` — required fields are
4653
+ * enforced at compile time.
4654
+ *
4655
+ * @example Cancel a pending limit order
4656
+ * ```ts
4657
+ * const [order] = await client.getOpenOrders();
4658
+ * await client.cancelOrder({ type: CancelOrderType.Limit, pairId: order.pairId, idx: order.idx });
4659
+ * ```
4660
+ * @example Cancel a timed-out market open
4661
+ * ```ts
4662
+ * await client.cancelOrder({ type: CancelOrderType.PendingOpen, orderId: 123 });
4663
+ * ```
4664
+ * @example Cancel a timed-out market close (retry: true re-submits the close)
4665
+ * ```ts
4666
+ * await client.cancelOrder({ type: CancelOrderType.PendingClose, orderId: 456, retry: true });
4667
+ * ```
4668
+ */
4669
+ async cancelOrder(params) {
4670
+ let encoded;
4671
+ if (params.type === "limit" /* Limit */) {
4672
+ const pairIdNum = Number(params.pairId);
4673
+ const idxNum = Number(params.idx);
4674
+ if (!Number.isFinite(pairIdNum) || !Number.isInteger(pairIdNum) || pairIdNum < 0 || !Number.isFinite(idxNum) || !Number.isInteger(idxNum) || idxNum < 0) {
4675
+ throw new OstiumError(
4676
+ `Invalid pairId (${params.pairId}) or idx (${params.idx}) for limit cancel`,
4677
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */
4678
+ );
4679
+ }
4680
+ encoded = encodeCancelLimitOrder(
4681
+ BigInt(pairIdNum),
4682
+ BigInt(idxNum),
4683
+ this.contracts.trading
4684
+ );
4685
+ } else if (params.type === "pendingClose" /* PendingClose */) {
4686
+ if (params.orderId < 0) {
4687
+ throw new OstiumError(
4688
+ `Invalid orderId (${params.orderId}) for pending close cancel`,
4689
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */
4690
+ );
4691
+ }
4692
+ encoded = encodeCloseTradeMarketTimeout(
4693
+ BigInt(params.orderId),
4694
+ params.retry ?? false,
4695
+ this.contracts.trading
4696
+ );
4697
+ } else {
4698
+ if (params.orderId < 0) {
4699
+ throw new OstiumError(
4700
+ `Invalid orderId (${params.orderId}) for pending open cancel`,
4701
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */
4702
+ );
4703
+ }
4704
+ encoded = encodeOpenTradeMarketTimeout(BigInt(params.orderId), this.contracts.trading);
4705
+ }
4706
+ return this.execute(encoded);
4707
+ }
4708
+ /**
4709
+ * Modify an open trade or a pending limit order.
4710
+ *
4711
+ * `pairId` and `idx` come straight from `getOpenPositions` (for TP/SL on open
4712
+ * positions) or `getOpenOrders` (for limit-order edits):
4713
+ *
4714
+ * ```ts
4715
+ * // Update TP/SL on an open position
4716
+ * const { pairPositions } = await client.getOpenPositions();
4717
+ * const { pairId, idx } = pairPositions[0].position;
4718
+ * await client.modifyOrder({ pairId, idx, takeProfit: '...', stopLoss: '...' });
4719
+ *
4720
+ * // Re-price a pending limit order
4721
+ * const [order] = await client.getOpenOrders();
4722
+ * await client.modifyOrder({ pairId: order.pairId, idx: order.idx, price: '...' });
4723
+ * ```
4724
+ *
4725
+ * - `price` provided → updates limit-order trigger price (with optional TP/SL).
4726
+ * - `takeProfit` only → calls updateTp on an open trade.
4727
+ * - `stopLoss` only → calls updateSl on an open trade.
4728
+ * - Both `takeProfit` and `stopLoss` without `price` → throws (send two calls).
4729
+ */
4730
+ async modifyOrder(params) {
4731
+ try {
4732
+ validateModifyParams({
4733
+ a: Number(params.pairId),
4734
+ i: params.idx,
4735
+ p: params.price,
4736
+ tp: params.takeProfit,
4737
+ sl: params.stopLoss
4738
+ });
4739
+ } catch (err) {
4740
+ throw new OstiumError(
4741
+ `Modify validation failed: ${err instanceof Error ? err.message : String(err)}`,
4742
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */,
4743
+ err
4744
+ );
4745
+ }
4746
+ if (params.takeProfit && params.stopLoss && !params.price) {
4747
+ throw new OstiumError(
4748
+ "Cannot update both takeProfit and stopLoss simultaneously without a price. Send two separate modifyOrder calls.",
4749
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */
4750
+ );
4751
+ }
4752
+ const pairIndex = BigInt(params.pairId);
4753
+ const index = BigInt(params.idx);
4754
+ let encoded;
4755
+ if (params.price) {
4756
+ const price = parsePrice(params.price);
4757
+ const tp = params.takeProfit ? parsePrice(params.takeProfit) : 0n;
4758
+ const sl = params.stopLoss ? parsePrice(params.stopLoss) : 0n;
4759
+ encoded = encodeUpdateOpenLimitOrder(pairIndex, index, price, tp, sl, this.contracts.trading);
4760
+ } else if (params.takeProfit) {
4761
+ encoded = encodeUpdateTp(pairIndex, index, parsePrice(params.takeProfit), this.contracts.trading);
4762
+ } else if (params.stopLoss) {
4763
+ encoded = encodeUpdateSl(pairIndex, index, parsePrice(params.stopLoss), this.contracts.trading);
4764
+ } else {
4765
+ throw new OstiumError(
4766
+ "Either takeProfit or stopLoss must be provided when price is not specified",
4767
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */
4768
+ );
4769
+ }
4770
+ return this.execute(encoded);
4771
+ }
4772
+ /**
4773
+ * Update collateral on an open position (isolated margin).
4774
+ *
4775
+ * `pairId` and `idx` come straight from a `Position` returned by `getOpenPositions`:
4776
+ *
4777
+ * ```ts
4778
+ * const { pairPositions } = await client.getOpenPositions();
4779
+ * const { pairId, idx } = pairPositions[0].position;
4780
+ * await client.updateCollateral({ pairId, idx, amount: '50' }); // top up
4781
+ * await client.updateCollateral({ pairId, idx, amount: '-25' }); // remove
4782
+ * ```
4783
+ *
4784
+ * Positive amount → topUpCollateral (adds margin, reduces effective leverage).
4785
+ * Negative amount → removeCollateral (removes margin, increases effective leverage).
4786
+ *
4787
+ * Checks USDC allowance before top-up operations.
4788
+ */
4789
+ async updateCollateral(params) {
4790
+ const amount = parseFloat(params.amount);
4791
+ if (Number.isNaN(amount) || amount === 0) {
4792
+ throw new OstiumError(
4793
+ `Invalid collateral amount: ${params.amount}`,
4794
+ "VALIDATION_FAILED" /* VALIDATION_FAILED */
4795
+ );
4796
+ }
4797
+ const pairIndex = BigInt(params.pairId);
4798
+ const index = BigInt(params.idx);
4799
+ const absAmount = parseUsdc(Math.abs(amount).toString());
4800
+ let encoded;
4801
+ if (amount > 0) {
4802
+ const allowance = await this.checkUsdcAllowance(Math.abs(amount).toString());
4803
+ if (!allowance.sufficient) {
4804
+ throw new OstiumError(
4805
+ `Insufficient USDC allowance for collateral top-up. Current: ${allowance.current}, Required: ${allowance.required}. Call approveUsdc() first.`,
4806
+ "ALLOWANCE_INSUFFICIENT" /* ALLOWANCE_INSUFFICIENT */
4807
+ );
4808
+ }
4809
+ encoded = encodeTopUpCollateral(pairIndex, index, absAmount, this.contracts.trading);
4810
+ } else {
4811
+ encoded = encodeRemoveCollateral(pairIndex, index, absAmount, this.contracts.trading);
4812
+ }
4813
+ return this.execute(encoded);
4814
+ }
4815
+ // ─────────────────────────────────────────────────────────────────────────
4816
+ // Subgraph reads (Hyperliquid-style API)
4817
+ // ─────────────────────────────────────────────────────────────────────────
4818
+ /**
4819
+ * All trading pairs with computed `minSz`/`maxBSz`/`maxSSz`, live prices, and
4820
+ * market-status flags. Pass `pairIds` to restrict to a subset.
4821
+ */
4822
+ getPairs(params) {
4823
+ return this.subgraph.getPairs(params);
4824
+ }
4825
+ /** Live mid/bid/ask prices keyed by `pairId`. */
4826
+ getAllPrices() {
4827
+ return this.subgraph.getAllPrices();
4828
+ }
4829
+ /**
4830
+ * Open positions + margin summary for a user. Defaults to the connected
4831
+ * trader. Live prices and the current block number are fetched automatically.
4832
+ */
4833
+ async getOpenPositions(params) {
4834
+ return this.subgraph.getOpenPositions({
4835
+ user: params?.user ?? this.getTraderAddress(),
4836
+ blockNumber: params?.blockNumber ?? await this.publicClient.getBlockNumber()
4837
+ });
4838
+ }
4839
+ /**
4840
+ * Executed fills, newest first.
4841
+ *
4842
+ * - `user` defaults to the connected trader. Pass `'ALL'` to fetch fills
4843
+ * across every trader (no trader filter).
4844
+ * - `pairId` (optional) — restricts to a single pair.
4845
+ * - `limit` (optional, default `1000`) — caps the result. Pass `Infinity` to
4846
+ * fetch every matching fill.
4847
+ */
4848
+ getFills(params) {
4849
+ return this.subgraph.getFills({
4850
+ user: params?.user ?? this.getTraderAddress(),
4851
+ pairId: params?.pairId,
4852
+ limit: params?.limit
4853
+ });
4854
+ }
4855
+ /**
4856
+ * Executed fills within a time range (Unix ms). Same filters as `getFills`,
4857
+ * including the default `limit: 1000`.
4858
+ */
4859
+ getFillsByTime(params) {
4860
+ return this.subgraph.getFillsByTime({
4861
+ user: params.user ?? this.getTraderAddress(),
4862
+ pairId: params.pairId,
4863
+ limit: params.limit,
4864
+ startTime: params.startTime,
4865
+ endTime: params.endTime
4866
+ });
4867
+ }
4868
+ /** Active limit orders for a user. Defaults to the connected trader. */
4869
+ getOpenOrders(params) {
4870
+ return this.subgraph.getOpenOrders({ user: params?.user ?? this.getTraderAddress() });
4871
+ }
4872
+ /**
4873
+ * Fetch orders at any status — pending, executed, or cancelled.
4874
+ *
4875
+ * Pass `initiatedTxHashes: [result.txHash]` to poll by the submission hash, or
4876
+ * `orderIds` by on-chain id. Without either, returns recent orders for the
4877
+ * connected trader.
4878
+ */
4879
+ getOrders(params) {
4880
+ const byId = params?.orderIds?.length;
4881
+ const byTx = params?.initiatedTxHashes?.length;
4882
+ return this.subgraph.getOrders({
4883
+ ...params,
4884
+ user: params?.user ?? (byId || byTx ? void 0 : this.getTraderAddress())
4885
+ });
4886
+ }
4887
+ /**
4888
+ * Simulate per-side slippage for a list of pairs and notionals.
4889
+ * See {@link OstiumSubgraphClient.getSimSlippage} for full semantics.
4890
+ */
4891
+ getSimSlippage(params) {
4892
+ return this.subgraph.getSimSlippage(params);
4893
+ }
4894
+ /**
4895
+ * Build a synthetic bid/ask orderbook for one pair using exponentially-spaced
4896
+ * notional levels capped at each side's remaining OI capacity.
4897
+ * See {@link OstiumSubgraphClient.getSimOrderbook} for full semantics.
4898
+ */
4899
+ getSimOrderbook(params) {
4900
+ return this.subgraph.getSimOrderbook(params);
4901
+ }
4902
+ /**
4903
+ * Fetch OHLC candles for a pair from the builder API.
4904
+ *
4905
+ * `from` / `to` are Unix milliseconds; `resolution` is one of
4906
+ * `"1"`, `"5"`, `"15"`, `"60"`, `"240"`, `"1D"`.
4907
+ *
4908
+ * ```ts
4909
+ * const candles = await client.getCandles({
4910
+ * pairId: 0,
4911
+ * from: Date.now() - 30 * 86_400_000,
4912
+ * resolution: '1D',
4913
+ * });
4914
+ * ```
4915
+ */
4916
+ getCandles(params) {
4917
+ return this.subgraph.getCandles(params);
4918
+ }
4919
+ /**
4920
+ * Open a WebSocket connection to the live price stream.
4921
+ *
4922
+ * Optionally filter to a subset of pairs by `pairId` — same values as returned by
4923
+ * `getPairs()`. When provided, the client sends `{ type: "subscribe", pairs }` on
4924
+ * `open` (no `?pairs=` query on the URL). Omit `pairIds` to receive the full feed.
4925
+ *
4926
+ * ```ts
4927
+ * const stream = client.streamPrices([0, 1]); // BTC and ETH by pairId
4928
+ * stream.onSnapshot(ticks => console.log(ticks));
4929
+ * stream.onTick(tick => console.log(tick.pair, tick.mid));
4930
+ * stream.subscribe([2]); // add pair
4931
+ * stream.unsubscribe([0]); // remove pair
4932
+ * stream.close();
4933
+ * ```
4934
+ *
4935
+ * Requires Node.js 18+, Bun, or a browser environment. Bun’s `WebSocket` may fail
4936
+ * some `https://` upgrades; use Node if the connection never reaches `open`.
4937
+ */
4938
+ streamPrices(pairIds) {
4939
+ return this.subgraph.streamPrices(pairIds);
4940
+ }
4941
+ // ─────────────────────────────────────────────────────────────────────────
4942
+ // Internal helpers
4943
+ // ─────────────────────────────────────────────────────────────────────────
4944
+ /**
4945
+ * Core execution pipeline:
4946
+ * 1. signer.prepare() — optionally wraps in delegatedAction.
4947
+ * 2. submitter.submit() — sends via EOA walletClient or Pimlico UserOp.
4948
+ */
4949
+ async execute(encoded) {
4950
+ const { signer, submitter } = this.requireWriter();
4951
+ const prepared = signer.prepare(encoded);
4952
+ return submitter.submit(prepared);
4953
+ }
4954
+ /** Throws if the client is read-only; otherwise returns the signer + submitter. */
4955
+ requireWriter() {
4956
+ if (!this.signer || !this.submitter) {
4957
+ throw new OstiumError(
4958
+ "This client is read-only. Use one of the createSelfAnd*/createDelegatedAnd* factories to enable writes.",
4959
+ "INVALID_CONFIG" /* INVALID_CONFIG */
4960
+ );
4961
+ }
4962
+ return { signer: this.signer, submitter: this.submitter };
4963
+ }
4964
+ /** Direct EOA submission — used only in Self + Gasless for approveUsdc and setupGaslessDelegation. */
4965
+ async submitDirectFromEoa(encoded) {
4966
+ try {
4967
+ return await this.eoaSubmit(encoded);
4968
+ } catch (err) {
4969
+ if (err instanceof OstiumError) throw err;
4970
+ const msg = err instanceof Error ? err.message : String(err);
4971
+ const lower = msg.toLowerCase();
4972
+ if (lower.includes("revert")) {
4973
+ throw new OstiumError(`Contract reverted: ${msg}`, "CONTRACT_ERROR" /* CONTRACT_ERROR */, err);
4974
+ }
4975
+ if (lower.includes("network") || lower.includes("timeout") || lower.includes("fetch")) {
4976
+ throw new OstiumError(`Network error: ${msg}`, "NETWORK_ERROR" /* NETWORK_ERROR */, err);
4977
+ }
4978
+ throw new OstiumError(`Transaction failed: ${msg}`, "SUBMISSION_FAILED" /* SUBMISSION_FAILED */, err);
4979
+ }
4980
+ }
4981
+ resolveSlippage(override) {
4982
+ return override ?? this.defaultSlippageBps;
4983
+ }
4984
+ };
4985
+
4986
+ export { CancelOrderType, DEFAULT_BUILDER_API_URL, DEFAULT_SLIPPAGE_PERCENTAGE, DEFAULT_SUBGRAPH_ENDPOINT, DEFAULT_SUBGRAPH_ENDPOINT_TESTNET, MAX_COLLATERAL_USD, MIN_COLLATERAL_USD, OrderType, OstiumClient, OstiumError, OstiumErrorCode, OstiumPriceStream, OstiumSubgraphClient, OstiumSubgraphError, OstiumSubgraphErrorCode, PRECISION_18, PRECISION_6, parseLeverage, parsePrice, parseUsdc };
4987
+ //# sourceMappingURL=index.js.map
4988
+ //# sourceMappingURL=index.js.map