@pear-protocol/hyperliquid-sdk 0.0.3 → 0.0.5

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 CHANGED
@@ -98,7 +98,9 @@ class PearHyperliquidClient {
98
98
  */
99
99
  class PearMigrationSDK {
100
100
  constructor(client) {
101
- this.isSyncRunning = false;
101
+ this.isTradeHistorySyncRunning = false;
102
+ this.isOpenPositionsSyncRunning = false;
103
+ this.isOpenOrdersSyncRunning = false;
102
104
  this.client = client;
103
105
  }
104
106
  /**
@@ -107,16 +109,16 @@ class PearMigrationSDK {
107
109
  */
108
110
  async syncTradeHistory(payload) {
109
111
  // If sync is already running, return immediately
110
- if (this.isSyncRunning) {
112
+ if (this.isTradeHistorySyncRunning) {
111
113
  return null;
112
114
  }
113
115
  try {
114
- this.isSyncRunning = true;
116
+ this.isTradeHistorySyncRunning = true;
115
117
  const response = await this.client.syncTradeHistory(payload);
116
118
  return response;
117
119
  }
118
120
  finally {
119
- this.isSyncRunning = false;
121
+ this.isTradeHistorySyncRunning = false;
120
122
  }
121
123
  }
122
124
  /**
@@ -125,16 +127,16 @@ class PearMigrationSDK {
125
127
  */
126
128
  async syncOpenPositions(payload) {
127
129
  // If sync is already running, return immediately
128
- if (this.isSyncRunning) {
130
+ if (this.isOpenPositionsSyncRunning) {
129
131
  return null;
130
132
  }
131
133
  try {
132
- this.isSyncRunning = true;
134
+ this.isOpenPositionsSyncRunning = true;
133
135
  const response = await this.client.syncOpenPositions(payload);
134
136
  return response;
135
137
  }
136
138
  finally {
137
- this.isSyncRunning = false;
139
+ this.isOpenPositionsSyncRunning = false;
138
140
  }
139
141
  }
140
142
  /**
@@ -143,47 +145,2949 @@ class PearMigrationSDK {
143
145
  */
144
146
  async syncOpenOrders(payload) {
145
147
  // If sync is already running, return immediately
146
- if (this.isSyncRunning) {
148
+ if (this.isOpenOrdersSyncRunning) {
147
149
  return null;
148
150
  }
149
151
  try {
150
- this.isSyncRunning = true;
152
+ this.isOpenOrdersSyncRunning = true;
151
153
  const response = await this.client.syncOpenOrders(payload);
152
154
  return response;
153
155
  }
154
156
  finally {
155
- this.isSyncRunning = false;
157
+ this.isOpenOrdersSyncRunning = false;
156
158
  }
157
159
  }
158
160
  /**
159
- * Check if sync is currently running
161
+ * Check if any sync is currently running
160
162
  */
161
163
  isSyncInProgress() {
162
- return this.isSyncRunning;
164
+ return this.isTradeHistorySyncRunning || this.isOpenPositionsSyncRunning || this.isOpenOrdersSyncRunning;
165
+ }
166
+ /**
167
+ * Check if trade history sync is currently running
168
+ */
169
+ isTradeHistorySyncInProgress() {
170
+ return this.isTradeHistorySyncRunning;
171
+ }
172
+ /**
173
+ * Check if open positions sync is currently running
174
+ */
175
+ isOpenPositionsSyncInProgress() {
176
+ return this.isOpenPositionsSyncRunning;
177
+ }
178
+ /**
179
+ * Check if open orders sync is currently running
180
+ */
181
+ isOpenOrdersSyncInProgress() {
182
+ return this.isOpenOrdersSyncRunning;
163
183
  }
164
184
  /**
165
185
  * Get the underlying client instance
166
186
  */
167
- getClient() {
168
- return this.client;
187
+ getClient() {
188
+ return this.client;
189
+ }
190
+ /**
191
+ * Set authorization token on the client
192
+ */
193
+ setAuthToken(token) {
194
+ this.client.setAuthToken(token);
195
+ }
196
+ /**
197
+ * Set custom headers on the client
198
+ */
199
+ setHeaders(headers) {
200
+ this.client.setHeaders(headers);
201
+ }
202
+ /**
203
+ * Get base URL from client
204
+ */
205
+ getBaseUrl() {
206
+ return this.client.getBaseUrl();
207
+ }
208
+ }
209
+
210
+ /** Base error class for all SDK errors. */
211
+ class HyperliquidError extends Error {
212
+ constructor(message) {
213
+ super(message);
214
+ this.name = "HyperliquidError";
215
+ }
216
+ }
217
+
218
+ /** Base class for all transport-related errors. */
219
+ class TransportError extends HyperliquidError {
220
+ constructor(message) {
221
+ super(message);
222
+ this.name = "TransportError";
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Info client for interacting with the Hyperliquid API.
228
+ * @typeParam T The type of transport used to connect to the Hyperliquid API.
229
+ */
230
+ class InfoClient {
231
+ transport;
232
+ /**
233
+ * Initialises a new instance.
234
+ * @param args - The arguments for initialisation.
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * import * as hl from "@nktkas/hyperliquid";
239
+ *
240
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
241
+ * const infoClient = new hl.InfoClient({ transport });
242
+ * ```
243
+ */
244
+ constructor(args) {
245
+ this.transport = args.transport;
246
+ }
247
+ allMids(args_or_signal, maybeSignal) {
248
+ const args = args_or_signal instanceof AbortSignal ? {} : args_or_signal;
249
+ const signal = args_or_signal instanceof AbortSignal ? args_or_signal : maybeSignal;
250
+ const request = {
251
+ type: "allMids",
252
+ ...args,
253
+ };
254
+ return this.transport.request("info", request, signal);
255
+ }
256
+ /**
257
+ * Block details by block height.
258
+ * @param args - The parameters for the request.
259
+ * @param signal - An optional abort signal.
260
+ * @returns Block details response.
261
+ *
262
+ * @see null - no documentation
263
+ * @example
264
+ * ```ts
265
+ * import * as hl from "@nktkas/hyperliquid";
266
+ *
267
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
268
+ * const infoClient = new hl.InfoClient({ transport });
269
+ *
270
+ * const data = await infoClient.blockDetails({ height: 123 });
271
+ * ```
272
+ */
273
+ async blockDetails(args, signal) {
274
+ const request = {
275
+ type: "blockDetails",
276
+ ...args,
277
+ };
278
+ const { blockDetails } = await this.transport.request("explorer", request, signal);
279
+ return blockDetails;
280
+ }
281
+ /**
282
+ * Request candlestick snapshots.
283
+ * @param args - The parameters for the request.
284
+ * @param signal - An optional abort signal.
285
+ * @returns Array of candlestick data points.
286
+ *
287
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#candle-snapshot
288
+ * @example
289
+ * ```ts
290
+ * import * as hl from "@nktkas/hyperliquid";
291
+ *
292
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
293
+ * const infoClient = new hl.InfoClient({ transport });
294
+ *
295
+ * const data = await infoClient.candleSnapshot({
296
+ * coin: "ETH",
297
+ * interval: "1h",
298
+ * startTime: Date.now() - 1000 * 60 * 60 * 24
299
+ * });
300
+ * ```
301
+ */
302
+ candleSnapshot(args, signal) {
303
+ const request = {
304
+ type: "candleSnapshot",
305
+ req: args,
306
+ };
307
+ return this.transport.request("info", request, signal);
308
+ }
309
+ /**
310
+ * Request clearinghouse state.
311
+ * @param args - The parameters for the request.
312
+ * @param signal - An optional abort signal.
313
+ * @returns Account summary for perpetual trading.
314
+ *
315
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-users-perpetuals-account-summary
316
+ * @example
317
+ * ```ts
318
+ * import * as hl from "@nktkas/hyperliquid";
319
+ *
320
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
321
+ * const infoClient = new hl.InfoClient({ transport });
322
+ *
323
+ * const data = await infoClient.clearinghouseState({ user: "0x..." });
324
+ * ```
325
+ */
326
+ clearinghouseState(args, signal) {
327
+ const request = {
328
+ type: "clearinghouseState",
329
+ ...args,
330
+ };
331
+ return this.transport.request("info", request, signal);
332
+ }
333
+ /**
334
+ * Request user staking delegations.
335
+ * @param args - The parameters for the request.
336
+ * @param signal - An optional abort signal.
337
+ * @returns Array of user's delegations to validators.
338
+ *
339
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-staking-delegations
340
+ * @example
341
+ * ```ts
342
+ * import * as hl from "@nktkas/hyperliquid";
343
+ *
344
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
345
+ * const infoClient = new hl.InfoClient({ transport });
346
+ *
347
+ * const data = await infoClient.delegations({ user: "0x..." });
348
+ * ```
349
+ */
350
+ delegations(args, signal) {
351
+ const request = {
352
+ type: "delegations",
353
+ ...args,
354
+ };
355
+ return this.transport.request("info", request, signal);
356
+ }
357
+ /**
358
+ * Request user staking history.
359
+ * @param args - The parameters for the request.
360
+ * @param signal - An optional abort signal.
361
+ * @returns Array of user's staking updates.
362
+ *
363
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-staking-history
364
+ * @example
365
+ * ```ts
366
+ * import * as hl from "@nktkas/hyperliquid";
367
+ *
368
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
369
+ * const infoClient = new hl.InfoClient({ transport });
370
+ *
371
+ * const data = await infoClient.delegatorHistory({ user: "0x..." });
372
+ * ```
373
+ */
374
+ delegatorHistory(args, signal) {
375
+ const request = {
376
+ type: "delegatorHistory",
377
+ ...args,
378
+ };
379
+ return this.transport.request("info", request, signal);
380
+ }
381
+ /**
382
+ * Request user staking rewards.
383
+ * @param args - The parameters for the request.
384
+ * @param signal - An optional abort signal.
385
+ * @returns Array of user's staking rewards.
386
+ *
387
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-staking-rewards
388
+ * @example
389
+ * ```ts
390
+ * import * as hl from "@nktkas/hyperliquid";
391
+ *
392
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
393
+ * const infoClient = new hl.InfoClient({ transport });
394
+ *
395
+ * const data = await infoClient.delegatorRewards({ user: "0x..." });
396
+ * ```
397
+ */
398
+ delegatorRewards(args, signal) {
399
+ const request = {
400
+ type: "delegatorRewards",
401
+ ...args,
402
+ };
403
+ return this.transport.request("info", request, signal);
404
+ }
405
+ /**
406
+ * Request user staking summary.
407
+ * @param args - The parameters for the request.
408
+ * @param signal - An optional abort signal.
409
+ * @returns Summary of a user's staking delegations.
410
+ *
411
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-staking-summary
412
+ * @example
413
+ * ```ts
414
+ * import * as hl from "@nktkas/hyperliquid";
415
+ *
416
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
417
+ * const infoClient = new hl.InfoClient({ transport });
418
+ *
419
+ * const data = await infoClient.delegatorSummary({ user: "0x..." });
420
+ * ```
421
+ */
422
+ delegatorSummary(args, signal) {
423
+ const request = {
424
+ type: "delegatorSummary",
425
+ ...args,
426
+ };
427
+ return this.transport.request("info", request, signal);
428
+ }
429
+ /**
430
+ * Request user's extra agents.
431
+ * @param args - The parameters for the request.
432
+ * @param signal - An optional abort signal.
433
+ * @returns User's extra agents.
434
+ *
435
+ * @see null - no documentation
436
+ * @example
437
+ * ```ts
438
+ * import * as hl from "@nktkas/hyperliquid";
439
+ *
440
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
441
+ * const infoClient = new hl.InfoClient({ transport });
442
+ *
443
+ * const data = await infoClient.extraAgents({ user: "0x..." });
444
+ * ```
445
+ */
446
+ extraAgents(args, signal) {
447
+ const request = {
448
+ type: "extraAgents",
449
+ ...args,
450
+ };
451
+ return this.transport.request("info", request, signal);
452
+ }
453
+ /**
454
+ * Request frontend open orders.
455
+ * @param args - The parameters for the request.
456
+ * @param signal - An optional abort signal.
457
+ * @returns Array of open orders with additional frontend information.
458
+ *
459
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-open-orders-with-additional-frontend-info
460
+ * @example
461
+ * ```ts
462
+ * import * as hl from "@nktkas/hyperliquid";
463
+ *
464
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
465
+ * const infoClient = new hl.InfoClient({ transport });
466
+ *
467
+ * const data = await infoClient.frontendOpenOrders({ user: "0x..." });
468
+ * ```
469
+ */
470
+ frontendOpenOrders(args, signal) {
471
+ const request = {
472
+ type: "frontendOpenOrders",
473
+ ...args,
474
+ };
475
+ return this.transport.request("info", request, signal);
476
+ }
477
+ /**
478
+ * Request funding history.
479
+ * @param args - The parameters for the request.
480
+ * @param signal - An optional abort signal.
481
+ * @returns Array of historical funding rate data for an asset.
482
+ *
483
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-historical-funding-rates
484
+ * @example
485
+ * ```ts
486
+ * import * as hl from "@nktkas/hyperliquid";
487
+ *
488
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
489
+ * const infoClient = new hl.InfoClient({ transport });
490
+ *
491
+ * const data = await infoClient.fundingHistory({
492
+ * coin: "ETH",
493
+ * startTime: Date.now() - 1000 * 60 * 60 * 24
494
+ * });
495
+ * ```
496
+ */
497
+ fundingHistory(args, signal) {
498
+ const request = {
499
+ type: "fundingHistory",
500
+ ...args,
501
+ };
502
+ return this.transport.request("info", request, signal);
503
+ }
504
+ /**
505
+ * Request user's historical orders.
506
+ * @param args - The parameters for the request.
507
+ * @param signal - An optional abort signal.
508
+ * @returns Array of user's historical orders.
509
+ *
510
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-historical-orders
511
+ * @example
512
+ * ```ts
513
+ * import * as hl from "@nktkas/hyperliquid";
514
+ *
515
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
516
+ * const infoClient = new hl.InfoClient({ transport });
517
+ *
518
+ * const data = await infoClient.historicalOrders({ user: "0x..." });
519
+ * ```
520
+ */
521
+ historicalOrders(args, signal) {
522
+ const request = {
523
+ type: "historicalOrders",
524
+ ...args,
525
+ };
526
+ return this.transport.request("info", request, signal);
527
+ }
528
+ /**
529
+ * Request to check if a user is a VIP.
530
+ * @param args - The parameters for the request.
531
+ * @param signal - An optional abort signal.
532
+ * @returns Boolean indicating user's VIP status.
533
+ *
534
+ * @see null - no documentation
535
+ * @example
536
+ * ```ts
537
+ * import * as hl from "@nktkas/hyperliquid";
538
+ *
539
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
540
+ * const infoClient = new hl.InfoClient({ transport });
541
+ *
542
+ * const data = await infoClient.isVip({ user: "0x..." });
543
+ * ```
544
+ */
545
+ isVip(args, signal) {
546
+ const request = {
547
+ type: "isVip",
548
+ ...args,
549
+ };
550
+ return this.transport.request("info", request, signal);
551
+ }
552
+ /**
553
+ * Request L2 order book.
554
+ * @param args - The parameters for the request.
555
+ * @param signal - An optional abort signal.
556
+ * @returns L2 order book snapshot.
557
+ *
558
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#l2-book-snapshot
559
+ * @example
560
+ * ```ts
561
+ * import * as hl from "@nktkas/hyperliquid";
562
+ *
563
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
564
+ * const infoClient = new hl.InfoClient({ transport });
565
+ *
566
+ * const data = await infoClient.l2Book({ coin: "ETH", nSigFigs: 2 });
567
+ * ```
568
+ */
569
+ l2Book(args, signal) {
570
+ const request = {
571
+ type: "l2Book",
572
+ ...args,
573
+ };
574
+ return this.transport.request("info", request, signal);
575
+ }
576
+ /**
577
+ * Request legal verification status of a user.
578
+ * @param args - The parameters for the request.
579
+ * @param signal - An optional abort signal.
580
+ * @returns Legal verification status for a user.
581
+ *
582
+ * @see null - no documentation
583
+ * @example
584
+ * ```ts
585
+ * import * as hl from "@nktkas/hyperliquid";
586
+ *
587
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
588
+ * const infoClient = new hl.InfoClient({ transport });
589
+ *
590
+ * const data = await infoClient.legalCheck({ user: "0x..." });
591
+ * ```
592
+ */
593
+ legalCheck(args, signal) {
594
+ const request = {
595
+ type: "legalCheck",
596
+ ...args,
597
+ };
598
+ return this.transport.request("info", request, signal);
599
+ }
600
+ /**
601
+ * Request builder fee approval.
602
+ * @param args - The parameters for the request.
603
+ * @param signal - An optional abort signal.
604
+ * @returns Maximum builder fee approval.
605
+ *
606
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#check-builder-fee-approval
607
+ * @example
608
+ * ```ts
609
+ * import * as hl from "@nktkas/hyperliquid";
610
+ *
611
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
612
+ * const infoClient = new hl.InfoClient({ transport });
613
+ *
614
+ * const data = await infoClient.maxBuilderFee({ user: "0x...", builder: "0x..." });
615
+ * ```
616
+ */
617
+ maxBuilderFee(args, signal) {
618
+ const request = {
619
+ type: "maxBuilderFee",
620
+ ...args,
621
+ };
622
+ return this.transport.request("info", request, signal);
623
+ }
624
+ meta(args_or_signal, maybeSignal) {
625
+ const args = args_or_signal instanceof AbortSignal ? {} : args_or_signal;
626
+ const signal = args_or_signal instanceof AbortSignal ? args_or_signal : maybeSignal;
627
+ const request = {
628
+ type: "meta",
629
+ ...args,
630
+ };
631
+ return this.transport.request("info", request, signal);
632
+ }
633
+ /**
634
+ * Request metadata and asset contexts.
635
+ * @param signal - An optional abort signal.
636
+ * @returns Metadata and context information for each perpetual asset.
637
+ *
638
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
639
+ * @example
640
+ * ```ts
641
+ * import * as hl from "@nktkas/hyperliquid";
642
+ *
643
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
644
+ * const infoClient = new hl.InfoClient({ transport });
645
+ *
646
+ * const data = await infoClient.metaAndAssetCtxs();
647
+ * ```
648
+ */
649
+ metaAndAssetCtxs(signal) {
650
+ const request = {
651
+ type: "metaAndAssetCtxs",
652
+ };
653
+ return this.transport.request("info", request, signal);
654
+ }
655
+ /**
656
+ * Request open orders.
657
+ * @param args - The parameters for the request.
658
+ * @param signal - An optional abort signal.
659
+ * @returns Array of open order.
660
+ *
661
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-open-orders
662
+ * @example
663
+ * ```ts
664
+ * import * as hl from "@nktkas/hyperliquid";
665
+ *
666
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
667
+ * const infoClient = new hl.InfoClient({ transport });
668
+ *
669
+ * const data = await infoClient.openOrders({ user: "0x..." });
670
+ * ```
671
+ */
672
+ openOrders(args, signal) {
673
+ const request = {
674
+ type: "openOrders",
675
+ ...args,
676
+ };
677
+ return this.transport.request("info", request, signal);
678
+ }
679
+ /**
680
+ * Request order status.
681
+ * @param args - The parameters for the request.
682
+ * @param signal - An optional abort signal.
683
+ * @returns Result of an order status lookup.
684
+ *
685
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-order-status-by-oid-or-cloid
686
+ * @example
687
+ * ```ts
688
+ * import * as hl from "@nktkas/hyperliquid";
689
+ *
690
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
691
+ * const infoClient = new hl.InfoClient({ transport });
692
+ *
693
+ * const data = await infoClient.orderStatus({ user: "0x...", oid: 12345 });
694
+ * ```
695
+ */
696
+ orderStatus(args, signal) {
697
+ const request = {
698
+ type: "orderStatus",
699
+ ...args,
700
+ };
701
+ return this.transport.request("info", request, signal);
702
+ }
703
+ /**
704
+ * Request for the status of the perpetual deploy auction.
705
+ * @param signal - An optional abort signal.
706
+ * @returns Status of the perpetual deploy auction.
707
+ *
708
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-information-about-the-perp-deploy-auction
709
+ * @example
710
+ * ```ts
711
+ * import * as hl from "@nktkas/hyperliquid";
712
+ *
713
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
714
+ * const infoClient = new hl.InfoClient({ transport });
715
+ *
716
+ * const data = await infoClient.perpDeployAuctionStatus();
717
+ * ```
718
+ */
719
+ perpDeployAuctionStatus(signal) {
720
+ const request = {
721
+ type: "perpDeployAuctionStatus",
722
+ };
723
+ return this.transport.request("info", request, signal);
724
+ }
725
+ /**
726
+ * Request all perpetual dexs.
727
+ * @param signal - An optional abort signal.
728
+ * @returns Array of perpetual dexes.
729
+ *
730
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-all-perpetual-dexs
731
+ * @example
732
+ * ```ts
733
+ * import * as hl from "@nktkas/hyperliquid";
734
+ *
735
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
736
+ * const infoClient = new hl.InfoClient({ transport });
737
+ *
738
+ * const data = await infoClient.perpDexs();
739
+ * ```
740
+ */
741
+ perpDexs(signal) {
742
+ const request = {
743
+ type: "perpDexs",
744
+ };
745
+ return this.transport.request("info", request, signal);
746
+ }
747
+ /**
748
+ * Request perpetuals at open interest cap.
749
+ * @param args - The parameters for the request.
750
+ * @param signal - An optional abort signal.
751
+ * @returns Array of perpetuals at open interest caps.
752
+ *
753
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#query-perps-at-open-interest-caps
754
+ * @example
755
+ * ```ts
756
+ * import * as hl from "@nktkas/hyperliquid";
757
+ *
758
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
759
+ * const infoClient = new hl.InfoClient({ transport });
760
+ *
761
+ * const data = await infoClient.perpsAtOpenInterestCap();
762
+ * ```
763
+ */
764
+ perpsAtOpenInterestCap(signal) {
765
+ const request = {
766
+ type: "perpsAtOpenInterestCap",
767
+ };
768
+ return this.transport.request("info", request, signal);
769
+ }
770
+ /**
771
+ * Request portfolio.
772
+ * @param args - The parameters for the request.
773
+ * @param signal - An optional abort signal.
774
+ * @returns Portfolio of a user.
775
+ *
776
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-portfolio
777
+ * @example
778
+ * ```ts
779
+ * import * as hl from "@nktkas/hyperliquid";
780
+ *
781
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
782
+ * const infoClient = new hl.InfoClient({ transport });
783
+ *
784
+ * const data = await infoClient.portfolio({ user: "0x..." });
785
+ * ```
786
+ */
787
+ portfolio(args, signal) {
788
+ const request = {
789
+ type: "portfolio",
790
+ ...args,
791
+ };
792
+ return this.transport.request("info", request, signal);
793
+ }
794
+ /**
795
+ * Request predicted funding rates.
796
+ * @param signal - An optional abort signal.
797
+ * @returns Array of predicted funding rates.
798
+ *
799
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-predicted-funding-rates-for-different-venues
800
+ * @example
801
+ * ```ts
802
+ * import * as hl from "@nktkas/hyperliquid";
803
+ *
804
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
805
+ * const infoClient = new hl.InfoClient({ transport });
806
+ *
807
+ * const data = await infoClient.predictedFundings();
808
+ * ```
809
+ */
810
+ predictedFundings(signal) {
811
+ const request = {
812
+ type: "predictedFundings",
813
+ };
814
+ return this.transport.request("info", request, signal);
815
+ }
816
+ /**
817
+ * Request user's existence check before transfer.
818
+ * @param args - The parameters for the request.
819
+ * @param signal - An optional abort signal.
820
+ * @returns Pre-transfer user existence check result.
821
+ *
822
+ * @see null - no documentation
823
+ * @example
824
+ * ```ts
825
+ * import * as hl from "@nktkas/hyperliquid";
826
+ *
827
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
828
+ * const infoClient = new hl.InfoClient({ transport });
829
+ *
830
+ * const data = await infoClient.preTransferCheck({ user: "0x...", source: "0x..." });
831
+ * ```
832
+ */
833
+ preTransferCheck(args, signal) {
834
+ const request = {
835
+ type: "preTransferCheck",
836
+ ...args,
837
+ };
838
+ return this.transport.request("info", request, signal);
839
+ }
840
+ /**
841
+ * Request user referral.
842
+ * @param args - The parameters for the request.
843
+ * @param signal - An optional abort signal.
844
+ * @returns Referral information for a user.
845
+ *
846
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-referral-information
847
+ * @example
848
+ * ```ts
849
+ * import * as hl from "@nktkas/hyperliquid";
850
+ *
851
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
852
+ * const infoClient = new hl.InfoClient({ transport });
853
+ *
854
+ * const data = await infoClient.referral({ user: "0x..." });
855
+ * ```
856
+ */
857
+ referral(args, signal) {
858
+ const request = {
859
+ type: "referral",
860
+ ...args,
861
+ };
862
+ return this.transport.request("info", request, signal);
863
+ }
864
+ /**
865
+ * Request spot clearinghouse state.
866
+ * @param args - The parameters for the request.
867
+ * @param signal - An optional abort signal.
868
+ * @returns Balances for spot tokens.
869
+ *
870
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-a-users-token-balances
871
+ * @example
872
+ * ```ts
873
+ * import * as hl from "@nktkas/hyperliquid";
874
+ *
875
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
876
+ * const infoClient = new hl.InfoClient({ transport });
877
+ *
878
+ * const data = await infoClient.spotClearinghouseState({ user: "0x..." });
879
+ * ```
880
+ */
881
+ spotClearinghouseState(args, signal) {
882
+ const request = {
883
+ type: "spotClearinghouseState",
884
+ ...args,
885
+ };
886
+ return this.transport.request("info", request, signal);
887
+ }
888
+ /**
889
+ * Request spot deploy state.
890
+ * @param args - The parameters for the request.
891
+ * @param signal - An optional abort signal.
892
+ * @returns The deploy state of a user.
893
+ *
894
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-information-about-the-spot-deploy-auction
895
+ * @example
896
+ * ```ts
897
+ * import * as hl from "@nktkas/hyperliquid";
898
+ *
899
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
900
+ * const infoClient = new hl.InfoClient({ transport });
901
+ *
902
+ * const data = await infoClient.spotDeployState({ user: "0x..." });
903
+ * ```
904
+ */
905
+ spotDeployState(args, signal) {
906
+ const request = {
907
+ type: "spotDeployState",
908
+ ...args,
909
+ };
910
+ return this.transport.request("info", request, signal);
911
+ }
912
+ /**
913
+ * Request spot trading metadata.
914
+ * @param signal - An optional abort signal.
915
+ * @returns Metadata for spot assets.
916
+ *
917
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-metadata
918
+ * @example
919
+ * ```ts
920
+ * import * as hl from "@nktkas/hyperliquid";
921
+ *
922
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
923
+ * const infoClient = new hl.InfoClient({ transport });
924
+ *
925
+ * const data = await infoClient.spotMeta();
926
+ * ```
927
+ */
928
+ spotMeta(signal) {
929
+ const request = {
930
+ type: "spotMeta",
931
+ };
932
+ return this.transport.request("info", request, signal);
933
+ }
934
+ /**
935
+ * Request spot metadata and asset contexts.
936
+ * @param signal - An optional abort signal.
937
+ * @returns Metadata and context information for each spot asset.
938
+ *
939
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-asset-contexts
940
+ * @example
941
+ * ```ts
942
+ * import * as hl from "@nktkas/hyperliquid";
943
+ *
944
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
945
+ * const infoClient = new hl.InfoClient({ transport });
946
+ *
947
+ * const data = await infoClient.spotMetaAndAssetCtxs();
948
+ * ```
949
+ */
950
+ spotMetaAndAssetCtxs(signal) {
951
+ const request = {
952
+ type: "spotMetaAndAssetCtxs",
953
+ };
954
+ return this.transport.request("info", request, signal);
955
+ }
956
+ /**
957
+ * Request user sub-accounts.
958
+ * @param args - The parameters for the request.
959
+ * @param signal - An optional abort signal.
960
+ * @returns Array of user sub-account or null if the user does not have any sub-accounts.
961
+ *
962
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-subaccounts
963
+ * @example
964
+ * ```ts
965
+ * import * as hl from "@nktkas/hyperliquid";
966
+ *
967
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
968
+ * const infoClient = new hl.InfoClient({ transport });
969
+ *
970
+ * const data = await infoClient.subAccounts({ user: "0x..." });
971
+ * ```
972
+ */
973
+ subAccounts(args, signal) {
974
+ const request = {
975
+ type: "subAccounts",
976
+ ...args,
977
+ };
978
+ return this.transport.request("info", request, signal);
979
+ }
980
+ /**
981
+ * Request token details.
982
+ * @param args - The parameters for the request.
983
+ * @param signal - An optional abort signal.
984
+ * @returns The details of a token.
985
+ *
986
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-information-about-a-token
987
+ * @example
988
+ * ```ts
989
+ * import * as hl from "@nktkas/hyperliquid";
990
+ *
991
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
992
+ * const infoClient = new hl.InfoClient({ transport });
993
+ *
994
+ * const data = await infoClient.tokenDetails({ tokenId: "0x..." });
995
+ * ```
996
+ */
997
+ tokenDetails(args, signal) {
998
+ const request = {
999
+ type: "tokenDetails",
1000
+ ...args,
1001
+ };
1002
+ return this.transport.request("info", request, signal);
1003
+ }
1004
+ /**
1005
+ * Request twap history of a user.
1006
+ * @param args - The parameters for the request.
1007
+ * @param signal - An optional abort signal.
1008
+ * @returns The twap history of a user.
1009
+ *
1010
+ * @see null - no documentation
1011
+ * @example
1012
+ * ```ts
1013
+ * import * as hl from "@nktkas/hyperliquid";
1014
+ *
1015
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1016
+ * const infoClient = new hl.InfoClient({ transport });
1017
+ *
1018
+ * const data = await infoClient.twapHistory({ user: "0x..." });
1019
+ * ```
1020
+ */
1021
+ twapHistory(args, signal) {
1022
+ const request = {
1023
+ type: "twapHistory",
1024
+ ...args,
1025
+ };
1026
+ return this.transport.request("info", request, signal);
1027
+ }
1028
+ /**
1029
+ * Transaction details by transaction hash.
1030
+ * @param args - The parameters for the request.
1031
+ * @param signal - An optional abort signal.
1032
+ * @returns Transaction details response.
1033
+ *
1034
+ * @see null - no documentation
1035
+ * @example
1036
+ * ```ts
1037
+ * import * as hl from "@nktkas/hyperliquid";
1038
+ *
1039
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1040
+ * const infoClient = new hl.InfoClient({ transport });
1041
+ *
1042
+ * const data = await infoClient.txDetails({ hash: "0x..." });
1043
+ * ```
1044
+ */
1045
+ async txDetails(args, signal) {
1046
+ const request = {
1047
+ type: "txDetails",
1048
+ ...args,
1049
+ };
1050
+ const { tx } = await this.transport.request("explorer", request, signal);
1051
+ return tx;
1052
+ }
1053
+ /**
1054
+ * User details by user's address.
1055
+ * @param args - The parameters for the request.
1056
+ * @param signal - An optional abort signal.
1057
+ * @returns User details response.
1058
+ *
1059
+ * @see null - no documentation
1060
+ * @example
1061
+ * ```ts
1062
+ * import * as hl from "@nktkas/hyperliquid";
1063
+ *
1064
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1065
+ * const infoClient = new hl.InfoClient({ transport });
1066
+ *
1067
+ * const data = await infoClient.userDetails({ user: "0x..." });
1068
+ * ```
1069
+ */
1070
+ async userDetails(args, signal) {
1071
+ const request = {
1072
+ type: "userDetails",
1073
+ ...args,
1074
+ };
1075
+ const { txs } = await this.transport.request("explorer", request, signal);
1076
+ return txs;
1077
+ }
1078
+ /**
1079
+ * Request user fees.
1080
+ * @param args - The parameters for the request.
1081
+ * @param signal - An optional abort signal.
1082
+ * @returns User fees.
1083
+ *
1084
+ * @see null - no documentation
1085
+ * @example
1086
+ * ```ts
1087
+ * import * as hl from "@nktkas/hyperliquid";
1088
+ *
1089
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1090
+ * const infoClient = new hl.InfoClient({ transport });
1091
+ *
1092
+ * const data = await infoClient.userFees({ user: "0x..." });
1093
+ * ```
1094
+ */
1095
+ userFees(args, signal) {
1096
+ const request = {
1097
+ type: "userFees",
1098
+ ...args,
1099
+ };
1100
+ return this.transport.request("info", request, signal);
1101
+ }
1102
+ /**
1103
+ * Request user fills.
1104
+ * @param args - The parameters for the request.
1105
+ * @param signal - An optional abort signal.
1106
+ * @returns Array of user's trade fill.
1107
+ *
1108
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills
1109
+ * @example
1110
+ * ```ts
1111
+ * import * as hl from "@nktkas/hyperliquid";
1112
+ *
1113
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1114
+ * const infoClient = new hl.InfoClient({ transport });
1115
+ *
1116
+ * const data = await infoClient.userFills({ user: "0x..." });
1117
+ * ```
1118
+ */
1119
+ userFills(args, signal) {
1120
+ const request = {
1121
+ type: "userFills",
1122
+ ...args,
1123
+ };
1124
+ return this.transport.request("info", request, signal);
1125
+ }
1126
+ /**
1127
+ * Request user fills by time.
1128
+ * @param args - The parameters for the request.
1129
+ * @param signal - An optional abort signal.
1130
+ * @returns Array of user's trade fill.
1131
+ *
1132
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills-by-time
1133
+ * @example
1134
+ * ```ts
1135
+ * import * as hl from "@nktkas/hyperliquid";
1136
+ *
1137
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1138
+ * const infoClient = new hl.InfoClient({ transport });
1139
+ *
1140
+ * const data = await infoClient.userFillsByTime({
1141
+ * user: "0x...",
1142
+ * startTime: Date.now() - 1000 * 60 * 60 * 24
1143
+ * });
1144
+ * ```
1145
+ */
1146
+ userFillsByTime(args, signal) {
1147
+ const request = {
1148
+ type: "userFillsByTime",
1149
+ ...args,
1150
+ };
1151
+ return this.transport.request("info", request, signal);
1152
+ }
1153
+ /**
1154
+ * Request user funding.
1155
+ * @param args - The parameters for the request.
1156
+ * @param signal - An optional abort signal.
1157
+ * @returns Array of user's funding ledger update.
1158
+ *
1159
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-a-users-funding-history-or-non-funding-ledger-updates
1160
+ * @example
1161
+ * ```ts
1162
+ * import * as hl from "@nktkas/hyperliquid";
1163
+ *
1164
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1165
+ * const infoClient = new hl.InfoClient({ transport });
1166
+ *
1167
+ * const data = await infoClient.userFunding({
1168
+ * user: "0x...",
1169
+ * startTime: Date.now() - 1000 * 60 * 60 * 24
1170
+ * });
1171
+ * ```
1172
+ */
1173
+ userFunding(args, signal) {
1174
+ const request = {
1175
+ type: "userFunding",
1176
+ ...args,
1177
+ };
1178
+ return this.transport.request("info", request, signal);
1179
+ }
1180
+ /**
1181
+ * Request user non-funding ledger updates.
1182
+ * @param args - The parameters for the request.
1183
+ * @param signal - An optional abort signal.
1184
+ * @returns Array of user's non-funding ledger update.
1185
+ *
1186
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-a-users-funding-history-or-non-funding-ledger-updates
1187
+ * @example
1188
+ * ```ts
1189
+ * import * as hl from "@nktkas/hyperliquid";
1190
+ *
1191
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1192
+ * const infoClient = new hl.InfoClient({ transport });
1193
+ *
1194
+ * const data = await infoClient.userNonFundingLedgerUpdates({
1195
+ * user: "0x...",
1196
+ * startTime: Date.now() - 1000 * 60 * 60 * 24
1197
+ * });
1198
+ * ```
1199
+ */
1200
+ userNonFundingLedgerUpdates(args, signal) {
1201
+ const request = {
1202
+ type: "userNonFundingLedgerUpdates",
1203
+ ...args,
1204
+ };
1205
+ return this.transport.request("info", request, signal);
1206
+ }
1207
+ /**
1208
+ * Request user rate limits.
1209
+ * @param args - The parameters for the request.
1210
+ * @param signal - An optional abort signal.
1211
+ * @returns User's rate limits.
1212
+ *
1213
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-user-rate-limits
1214
+ * @example
1215
+ * ```ts
1216
+ * import * as hl from "@nktkas/hyperliquid";
1217
+ *
1218
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1219
+ * const infoClient = new hl.InfoClient({ transport });
1220
+ *
1221
+ * const data = await infoClient.userRateLimit({ user: "0x..." });
1222
+ * ```
1223
+ */
1224
+ userRateLimit(args, signal) {
1225
+ const request = {
1226
+ type: "userRateLimit",
1227
+ ...args,
1228
+ };
1229
+ return this.transport.request("info", request, signal);
1230
+ }
1231
+ /**
1232
+ * Request user role.
1233
+ * @param args - The parameters for the request.
1234
+ * @param signal - An optional abort signal.
1235
+ * @returns User's role.
1236
+ *
1237
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-role
1238
+ * @example
1239
+ * ```ts
1240
+ * import * as hl from "@nktkas/hyperliquid";
1241
+ *
1242
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1243
+ * const infoClient = new hl.InfoClient({ transport });
1244
+ *
1245
+ * const data = await infoClient.userRole({ user: "0x..." });
1246
+ * ```
1247
+ */
1248
+ userRole(args, signal) {
1249
+ const request = {
1250
+ type: "userRole",
1251
+ ...args,
1252
+ };
1253
+ return this.transport.request("info", request, signal);
1254
+ }
1255
+ /**
1256
+ * Request multi-sig signers for a user.
1257
+ * @param args - The parameters for the request.
1258
+ * @param signal - An optional abort signal.
1259
+ * @returns Multi-sig signers for a user or null if the user does not have any multi-sig signers.
1260
+ *
1261
+ * @see null - no documentation
1262
+ * @example
1263
+ * ```ts
1264
+ * import * as hl from "@nktkas/hyperliquid";
1265
+ *
1266
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1267
+ * const infoClient = new hl.InfoClient({ transport });
1268
+ *
1269
+ * const data = await infoClient.userToMultiSigSigners({ user: "0x..." });
1270
+ * ```
1271
+ */
1272
+ userToMultiSigSigners(args, signal) {
1273
+ const request = {
1274
+ type: "userToMultiSigSigners",
1275
+ ...args,
1276
+ };
1277
+ return this.transport.request("info", request, signal);
1278
+ }
1279
+ /**
1280
+ * Request user twap slice fills.
1281
+ * @param args - The parameters for the request.
1282
+ * @param signal - An optional abort signal.
1283
+ * @returns Array of user's twap slice fill.
1284
+ *
1285
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-twap-slice-fills
1286
+ * @example
1287
+ * ```ts
1288
+ * import * as hl from "@nktkas/hyperliquid";
1289
+ *
1290
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1291
+ * const infoClient = new hl.InfoClient({ transport });
1292
+ *
1293
+ * const data = await infoClient.userTwapSliceFills({ user: "0x..." });
1294
+ * ```
1295
+ */
1296
+ userTwapSliceFills(args, signal) {
1297
+ const request = {
1298
+ type: "userTwapSliceFills",
1299
+ ...args,
1300
+ };
1301
+ return this.transport.request("info", request, signal);
1302
+ }
1303
+ /**
1304
+ * Request user twap slice fills by time.
1305
+ * @param args - The parameters for the request.
1306
+ * @param signal - An optional abort signal.
1307
+ * @returns Array of user's twap slice fill.
1308
+ *
1309
+ * @see null - no documentation
1310
+ * @example
1311
+ * ```ts
1312
+ * import * as hl from "@nktkas/hyperliquid";
1313
+ *
1314
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1315
+ * const infoClient = new hl.InfoClient({ transport });
1316
+ *
1317
+ * const data = await infoClient.userTwapSliceFillsByTime({
1318
+ * user: "0x...",
1319
+ * startTime: Date.now() - 1000 * 60 * 60 * 24
1320
+ * });
1321
+ * ```
1322
+ */
1323
+ userTwapSliceFillsByTime(args, signal) {
1324
+ const request = {
1325
+ type: "userTwapSliceFillsByTime",
1326
+ ...args,
1327
+ };
1328
+ return this.transport.request("info", request, signal);
1329
+ }
1330
+ /**
1331
+ * Request user vault deposits.
1332
+ * @param args - The parameters for the request.
1333
+ * @param signal - An optional abort signal.
1334
+ * @returns Array of user's vault deposits.
1335
+ *
1336
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-vault-deposits
1337
+ * @example
1338
+ * ```ts
1339
+ * import * as hl from "@nktkas/hyperliquid";
1340
+ *
1341
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1342
+ * const infoClient = new hl.InfoClient({ transport });
1343
+ *
1344
+ * const data = await infoClient.userVaultDeposits({ user: "0x..." });
1345
+ * ```
1346
+ */
1347
+ userVaultEquities(args, signal) {
1348
+ const request = {
1349
+ type: "userVaultEquities",
1350
+ ...args,
1351
+ };
1352
+ return this.transport.request("info", request, signal);
1353
+ }
1354
+ /**
1355
+ * Request validator summaries.
1356
+ * @param args - The parameters for the request.
1357
+ * @returns Array of validator summaries.
1358
+ *
1359
+ * @see null - no documentation
1360
+ * @example
1361
+ * ```ts
1362
+ * import * as hl from "@nktkas/hyperliquid";
1363
+ *
1364
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1365
+ * const infoClient = new hl.InfoClient({ transport });
1366
+ *
1367
+ * const data = await infoClient.validatorSummaries();
1368
+ * ```
1369
+ */
1370
+ validatorSummaries(signal) {
1371
+ const request = {
1372
+ type: "validatorSummaries",
1373
+ };
1374
+ return this.transport.request("info", request, signal);
1375
+ }
1376
+ /**
1377
+ * Request details of a vault.
1378
+ * @param args - The parameters for the request.
1379
+ * @param signal - An optional abort signal.
1380
+ * @returns Details of a vault or null if the vault does not exist.
1381
+ *
1382
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-details-for-a-vault
1383
+ * @example
1384
+ * ```ts
1385
+ * import * as hl from "@nktkas/hyperliquid";
1386
+ *
1387
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1388
+ * const infoClient = new hl.InfoClient({ transport });
1389
+ *
1390
+ * const data = await infoClient.vaultDetails({ vaultAddress: "0x..." });
1391
+ * ```
1392
+ */
1393
+ vaultDetails(args, signal) {
1394
+ const request = {
1395
+ type: "vaultDetails",
1396
+ ...args,
1397
+ };
1398
+ return this.transport.request("info", request, signal);
1399
+ }
1400
+ /**
1401
+ * Request a list of vaults less than 2 hours old.
1402
+ * @param args - The parameters for the request.
1403
+ * @param signal - An optional abort signal.
1404
+ * @returns Array of vault summaries.
1405
+ *
1406
+ * @see null - no documentation
1407
+ * @example
1408
+ * ```ts
1409
+ * import * as hl from "@nktkas/hyperliquid";
1410
+ *
1411
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1412
+ * const infoClient = new hl.InfoClient({ transport });
1413
+ *
1414
+ * const data = await infoClient.vaultSummaries();
1415
+ * ```
1416
+ */
1417
+ vaultSummaries(signal) {
1418
+ const request = {
1419
+ type: "vaultSummaries",
1420
+ };
1421
+ return this.transport.request("info", request, signal);
1422
+ }
1423
+ async [Symbol.asyncDispose]() {
1424
+ await this.transport[Symbol.asyncDispose]?.();
1425
+ }
1426
+ }
1427
+
1428
+ /**
1429
+ * Subscription client for subscribing to various Hyperliquid events.
1430
+ * @typeParam T The type of transport used to connect to the Hyperliquid Websocket API.
1431
+ */
1432
+ class SubscriptionClient {
1433
+ transport;
1434
+ /**
1435
+ * Initialises a new instance.
1436
+ * @param args - The arguments for initialisation.
1437
+ *
1438
+ * @example
1439
+ * ```ts
1440
+ * import * as hl from "@nktkas/hyperliquid";
1441
+ *
1442
+ * const transport = new hl.WebSocketTransport();
1443
+ * const subsClient = new hl.SubscriptionClient({ transport });
1444
+ * ```
1445
+ */
1446
+ constructor(args) {
1447
+ this.transport = args.transport;
1448
+ }
1449
+ /**
1450
+ * Subscribe to context updates for a specific perpetual asset.
1451
+ * @param args - The parameters for the subscription.
1452
+ * @param listener - The callback function to be called when the event is received.
1453
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1454
+ *
1455
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1456
+ * @example
1457
+ * ```ts
1458
+ * import * as hl from "@nktkas/hyperliquid";
1459
+ *
1460
+ * const transport = new hl.WebSocketTransport();
1461
+ * const subsClient = new hl.SubscriptionClient({ transport });
1462
+ *
1463
+ * const sub = await subsClient.activeAssetCtx({ coin: "BTC" }, (data) => {
1464
+ * console.log(data);
1465
+ * });
1466
+ * ```
1467
+ */
1468
+ activeAssetCtx(args, listener) {
1469
+ const channel = args.coin.startsWith("@") ? "activeSpotAssetCtx" : "activeAssetCtx";
1470
+ const payload = {
1471
+ type: "activeAssetCtx",
1472
+ coin: args.coin,
1473
+ };
1474
+ return this.transport.subscribe(channel, payload, (e) => {
1475
+ if (e.detail.coin === args.coin) {
1476
+ listener(e.detail);
1477
+ }
1478
+ });
1479
+ }
1480
+ /**
1481
+ * Subscribe to trading data updates for a specific asset and user.
1482
+ * @param args - The parameters for the subscription.
1483
+ * @param listener - The callback function to be called when the event is received.
1484
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1485
+ *
1486
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1487
+ * @example
1488
+ * ```ts
1489
+ * import * as hl from "@nktkas/hyperliquid";
1490
+ *
1491
+ * const transport = new hl.WebSocketTransport();
1492
+ * const subsClient = new hl.SubscriptionClient({ transport });
1493
+ *
1494
+ * const sub = await subsClient.activeAssetData({ coin: "BTC", user: "0x..." }, (data) => {
1495
+ * console.log(data);
1496
+ * });
1497
+ * ```
1498
+ */
1499
+ activeAssetData(args, listener) {
1500
+ const payload = {
1501
+ type: "activeAssetData",
1502
+ coin: args.coin,
1503
+ user: args.user,
1504
+ };
1505
+ return this.transport.subscribe(payload.type, payload, (e) => {
1506
+ if (e.detail.coin === args.coin && e.detail.user === args.user.toLowerCase()) {
1507
+ listener(e.detail);
1508
+ }
1509
+ });
1510
+ }
1511
+ allMids(args_or_listener, maybeListener) {
1512
+ const args = typeof args_or_listener === "function" ? {} : args_or_listener;
1513
+ const listener = typeof args_or_listener === "function" ? args_or_listener : maybeListener;
1514
+ const payload = {
1515
+ type: "allMids",
1516
+ dex: args.dex,
1517
+ };
1518
+ return this.transport.subscribe(payload.type, payload, (e) => {
1519
+ listener(e.detail);
1520
+ });
1521
+ }
1522
+ /**
1523
+ * Subscribe to best bid and offer updates for a specific asset.
1524
+ * @param args - The parameters for the subscription.
1525
+ * @param listener - The callback function to be called when the event is received.
1526
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1527
+ *
1528
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1529
+ * @example
1530
+ * ```ts
1531
+ * import * as hl from "@nktkas/hyperliquid";
1532
+ *
1533
+ * const transport = new hl.WebSocketTransport();
1534
+ * const subsClient = new hl.SubscriptionClient({ transport });
1535
+ *
1536
+ * const sub = await subsClient.bbo({ coin: "BTC" }, (data) => {
1537
+ * console.log(data);
1538
+ * });
1539
+ * ```
1540
+ */
1541
+ bbo(args, listener) {
1542
+ const payload = {
1543
+ type: "bbo",
1544
+ coin: args.coin,
1545
+ };
1546
+ return this.transport.subscribe(payload.type, payload, (e) => {
1547
+ if (e.detail.coin === args.coin) {
1548
+ listener(e.detail);
1549
+ }
1550
+ });
1551
+ }
1552
+ /**
1553
+ * Subscribe to candlestick data updates for a specific asset.
1554
+ * @param args - The parameters for the subscription.
1555
+ * @param listener - The callback function to be called when the event is received.
1556
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1557
+ *
1558
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1559
+ * @example
1560
+ * ```ts
1561
+ * import * as hl from "@nktkas/hyperliquid";
1562
+ *
1563
+ * const transport = new hl.WebSocketTransport();
1564
+ * const subsClient = new hl.SubscriptionClient({ transport });
1565
+ *
1566
+ * const sub = await subsClient.candle({ coin: "BTC", interval: "1h" }, (data) => {
1567
+ * console.log(data);
1568
+ * });
1569
+ * ```
1570
+ */
1571
+ candle(args, listener) {
1572
+ const payload = {
1573
+ type: "candle",
1574
+ coin: args.coin,
1575
+ interval: args.interval,
1576
+ };
1577
+ return this.transport.subscribe(payload.type, payload, (e) => {
1578
+ if (e.detail.s === args.coin && e.detail.i === args.interval) {
1579
+ listener(e.detail);
1580
+ }
1581
+ });
1582
+ }
1583
+ /**
1584
+ * Subscribe to explorer block updates.
1585
+ * @param listener - The callback function to be called when the event is received.
1586
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1587
+ * @note Make sure the endpoint in the {@link transport} supports this method.
1588
+ *
1589
+ * @see null - no documentation
1590
+ * @example
1591
+ * ```ts
1592
+ * import * as hl from "@nktkas/hyperliquid";
1593
+ *
1594
+ * const transport = new hl.WebSocketTransport();
1595
+ * const subsClient = new hl.SubscriptionClient({ transport });
1596
+ *
1597
+ * const sub = await subsClient.explorerBlock((data) => {
1598
+ * console.log(data);
1599
+ * });
1600
+ * ```
1601
+ */
1602
+ explorerBlock(listener) {
1603
+ const payload = {
1604
+ type: "explorerBlock",
1605
+ };
1606
+ return this.transport.subscribe("_explorerBlock", payload, (e) => {
1607
+ listener(e.detail);
1608
+ });
1609
+ }
1610
+ /**
1611
+ * Subscribe to explorer transaction updates.
1612
+ * @param listener - The callback function to be called when the event is received.
1613
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1614
+ * @note Make sure the endpoint in the {@link transport} supports this method.
1615
+ *
1616
+ * @see null - no documentation
1617
+ * @example
1618
+ * ```ts
1619
+ * import * as hl from "@nktkas/hyperliquid";
1620
+ *
1621
+ * const transport = new hl.WebSocketTransport();
1622
+ * const subsClient = new hl.SubscriptionClient({ transport });
1623
+ *
1624
+ * const sub = await subsClient.explorerTxs((data) => {
1625
+ * console.log(data);
1626
+ * });
1627
+ * ```
1628
+ */
1629
+ explorerTxs(listener) {
1630
+ const payload = {
1631
+ type: "explorerTxs",
1632
+ };
1633
+ return this.transport.subscribe("_explorerTxs", payload, (e) => {
1634
+ listener(e.detail);
1635
+ });
1636
+ }
1637
+ /**
1638
+ * Subscribe to L2 order book updates for a specific asset.
1639
+ * @param args - The parameters for the subscription.
1640
+ * @param listener - The callback function to be called when the event is received.
1641
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1642
+ *
1643
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1644
+ * @example
1645
+ * ```ts
1646
+ * import * as hl from "@nktkas/hyperliquid";
1647
+ *
1648
+ * const transport = new hl.WebSocketTransport();
1649
+ * const subsClient = new hl.SubscriptionClient({ transport });
1650
+ *
1651
+ * const sub = await subsClient.l2Book({ coin: "BTC" }, (data) => {
1652
+ * console.log(data);
1653
+ * });
1654
+ * ```
1655
+ */
1656
+ l2Book(args, listener) {
1657
+ const payload = {
1658
+ type: "l2Book",
1659
+ coin: args.coin,
1660
+ nSigFigs: args.nSigFigs ?? null,
1661
+ mantissa: args.mantissa ?? null,
1662
+ };
1663
+ return this.transport.subscribe(payload.type, payload, (e) => {
1664
+ if (e.detail.coin === args.coin) {
1665
+ listener(e.detail);
1666
+ }
1667
+ });
1668
+ }
1669
+ /**
1670
+ * Subscribe to notification updates for a specific user.
1671
+ * @param args - The parameters for the subscription.
1672
+ * @param listener - The callback function to be called when the event is received.
1673
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1674
+ *
1675
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1676
+ * @example
1677
+ * ```ts
1678
+ * import * as hl from "@nktkas/hyperliquid";
1679
+ *
1680
+ * const transport = new hl.WebSocketTransport();
1681
+ * const subsClient = new hl.SubscriptionClient({ transport });
1682
+ *
1683
+ * const sub = await subsClient.notification({ user: "0x..." }, (data) => {
1684
+ * console.log(data);
1685
+ * });
1686
+ * ```
1687
+ */
1688
+ notification(args, listener) {
1689
+ const payload = {
1690
+ type: "notification",
1691
+ user: args.user,
1692
+ };
1693
+ return this.transport.subscribe(payload.type, payload, (e) => {
1694
+ listener(e.detail);
1695
+ });
1696
+ }
1697
+ /**
1698
+ * Subscribe to order status updates for a specific user.
1699
+ * @param args - The parameters for the subscription.
1700
+ * @param listener - The callback function to be called when the event is received.
1701
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1702
+ *
1703
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1704
+ * @example
1705
+ * ```ts
1706
+ * import * as hl from "@nktkas/hyperliquid";
1707
+ *
1708
+ * const transport = new hl.WebSocketTransport();
1709
+ * const subsClient = new hl.SubscriptionClient({ transport });
1710
+ *
1711
+ * const sub = await subsClient.orderUpdates({ user: "0x..." }, (data) => {
1712
+ * console.log(data);
1713
+ * });
1714
+ * ```
1715
+ */
1716
+ orderUpdates(args, listener) {
1717
+ const payload = {
1718
+ type: "orderUpdates",
1719
+ user: args.user,
1720
+ };
1721
+ return this.transport.subscribe(payload.type, payload, (e) => {
1722
+ listener(e.detail);
1723
+ });
1724
+ }
1725
+ /**
1726
+ * Subscribe to real-time trade updates for a specific asset.
1727
+ * @param args - The parameters for the subscription.
1728
+ * @param listener - The callback function to be called when the event is received.
1729
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1730
+ *
1731
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1732
+ * @example
1733
+ * ```ts
1734
+ * import * as hl from "@nktkas/hyperliquid";
1735
+ *
1736
+ * const transport = new hl.WebSocketTransport();
1737
+ * const subsClient = new hl.SubscriptionClient({ transport });
1738
+ *
1739
+ * const sub = await subsClient.trades({ coin: "BTC" }, (data) => {
1740
+ * console.log(data);
1741
+ * });
1742
+ * ```
1743
+ */
1744
+ trades(args, listener) {
1745
+ const payload = {
1746
+ type: "trades",
1747
+ coin: args.coin,
1748
+ };
1749
+ return this.transport.subscribe(payload.type, payload, (e) => {
1750
+ if (e.detail[0]?.coin === args.coin) {
1751
+ listener(e.detail);
1752
+ }
1753
+ });
1754
+ }
1755
+ /**
1756
+ * Subscribe to non-order events for a specific user.
1757
+ * @param args - The parameters for the subscription.
1758
+ * @param listener - The callback function to be called when the event is received.
1759
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1760
+ *
1761
+ * @note Different subscriptions cannot be distinguished from each other.
1762
+ *
1763
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1764
+ * @example
1765
+ * ```ts
1766
+ * import * as hl from "@nktkas/hyperliquid";
1767
+ *
1768
+ * const transport = new hl.WebSocketTransport();
1769
+ * const subsClient = new hl.SubscriptionClient({ transport });
1770
+ *
1771
+ * const sub = await subsClient.userEvents({ user: "0x..." }, (data) => {
1772
+ * console.log(data);
1773
+ * });
1774
+ * ```
1775
+ */
1776
+ userEvents(args, listener) {
1777
+ const payload = {
1778
+ type: "userEvents",
1779
+ user: args.user,
1780
+ };
1781
+ return this.transport.subscribe("user", payload, (e) => {
1782
+ listener(e.detail);
1783
+ });
1784
+ }
1785
+ /**
1786
+ * Subscribe to trade fill updates for a specific user.
1787
+ * @param args - The parameters for the subscription.
1788
+ * @param listener - The callback function to be called when the event is received.
1789
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1790
+ *
1791
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1792
+ * @example
1793
+ * ```ts
1794
+ * import * as hl from "@nktkas/hyperliquid";
1795
+ *
1796
+ * const transport = new hl.WebSocketTransport();
1797
+ * const subsClient = new hl.SubscriptionClient({ transport });
1798
+ *
1799
+ * const sub = await subsClient.userFills({ user: "0x..." }, (data) => {
1800
+ * console.log(data);
1801
+ * });
1802
+ * ```
1803
+ */
1804
+ userFills(args, listener) {
1805
+ const payload = {
1806
+ type: "userFills",
1807
+ user: args.user,
1808
+ aggregateByTime: args.aggregateByTime ?? false,
1809
+ };
1810
+ return this.transport.subscribe(payload.type, payload, (e) => {
1811
+ if (e.detail.user === args.user.toLowerCase()) {
1812
+ listener(e.detail);
1813
+ }
1814
+ });
1815
+ }
1816
+ /**
1817
+ * Subscribe to funding payment updates for a specific user.
1818
+ * @param args - The parameters for the subscription.
1819
+ * @param listener - The callback function to be called when the event is received.
1820
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1821
+ *
1822
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1823
+ * @example
1824
+ * ```ts
1825
+ * import * as hl from "@nktkas/hyperliquid";
1826
+ *
1827
+ * const transport = new hl.WebSocketTransport();
1828
+ * const subsClient = new hl.SubscriptionClient({ transport });
1829
+ *
1830
+ * const sub = await subsClient.userFundings({ user: "0x..." }, (data) => {
1831
+ * console.log(data);
1832
+ * });
1833
+ * ```
1834
+ */
1835
+ userFundings(args, listener) {
1836
+ const payload = {
1837
+ type: "userFundings",
1838
+ user: args.user,
1839
+ };
1840
+ return this.transport.subscribe(payload.type, payload, (e) => {
1841
+ if (e.detail.user === args.user.toLowerCase()) {
1842
+ listener(e.detail);
1843
+ }
1844
+ });
1845
+ }
1846
+ /**
1847
+ * Subscribe to non-funding ledger updates for a specific user.
1848
+ * @param args - The parameters for the subscription.
1849
+ * @param listener - The callback function to be called when the event is received.
1850
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1851
+ *
1852
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1853
+ * @example
1854
+ * ```ts
1855
+ * import * as hl from "@nktkas/hyperliquid";
1856
+ *
1857
+ * const transport = new hl.WebSocketTransport();
1858
+ * const subsClient = new hl.SubscriptionClient({ transport });
1859
+ *
1860
+ * const sub = await subsClient.userNonFundingLedgerUpdates({ user: "0x..." }, (data) => {
1861
+ * console.log(data);
1862
+ * });
1863
+ * ```
1864
+ */
1865
+ userNonFundingLedgerUpdates(args, listener) {
1866
+ const payload = {
1867
+ type: "userNonFundingLedgerUpdates",
1868
+ user: args.user,
1869
+ };
1870
+ return this.transport.subscribe(payload.type, payload, (e) => {
1871
+ if (e.detail.user === args.user.toLowerCase()) {
1872
+ listener(e.detail);
1873
+ }
1874
+ });
1875
+ }
1876
+ /**
1877
+ * Subscribe to TWAP order history updates for a specific user.
1878
+ * @param args - The parameters for the subscription.
1879
+ * @param listener - The callback function to be called when the event is received.
1880
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1881
+ *
1882
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1883
+ * @example
1884
+ * ```ts
1885
+ * import * as hl from "@nktkas/hyperliquid";
1886
+ *
1887
+ * const transport = new hl.WebSocketTransport();
1888
+ * const subsClient = new hl.SubscriptionClient({ transport });
1889
+ *
1890
+ * const sub = await subsClient.userTwapHistory({ user: "0x..." }, (data) => {
1891
+ * console.log(data);
1892
+ * });
1893
+ * ```
1894
+ */
1895
+ userTwapHistory(args, listener) {
1896
+ const payload = {
1897
+ type: "userTwapHistory",
1898
+ user: args.user,
1899
+ };
1900
+ return this.transport.subscribe(payload.type, payload, (e) => {
1901
+ if (e.detail.user === args.user.toLowerCase()) {
1902
+ listener(e.detail);
1903
+ }
1904
+ });
1905
+ }
1906
+ /**
1907
+ * Subscribe to TWAP execution updates for a specific user.
1908
+ * @param args - The parameters for the subscription.
1909
+ * @param listener - The callback function to be called when the event is received.
1910
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1911
+ *
1912
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1913
+ * @example
1914
+ * ```ts
1915
+ * import * as hl from "@nktkas/hyperliquid";
1916
+ *
1917
+ * const transport = new hl.WebSocketTransport();
1918
+ * const subsClient = new hl.SubscriptionClient({ transport });
1919
+ *
1920
+ * const sub = await subsClient.userTwapSliceFills({ user: "0x..." }, (data) => {
1921
+ * console.log(data);
1922
+ * });
1923
+ * ```
1924
+ */
1925
+ userTwapSliceFills(args, listener) {
1926
+ const payload = {
1927
+ type: "userTwapSliceFills",
1928
+ user: args.user,
1929
+ };
1930
+ return this.transport.subscribe(payload.type, payload, (e) => {
1931
+ if (e.detail.user === args.user.toLowerCase()) {
1932
+ listener(e.detail);
1933
+ }
1934
+ });
1935
+ }
1936
+ /**
1937
+ * Subscribe to comprehensive user and market data updates.
1938
+ * @param args - The parameters for the subscription.
1939
+ * @param listener - The callback function to be called when the event is received.
1940
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
1941
+ *
1942
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
1943
+ * @example
1944
+ * ```ts
1945
+ * import * as hl from "@nktkas/hyperliquid";
1946
+ *
1947
+ * const transport = new hl.WebSocketTransport();
1948
+ * const subsClient = new hl.SubscriptionClient({ transport });
1949
+ *
1950
+ * const sub = await subsClient.webData2({ user: "0x..." }, (data) => {
1951
+ * console.log(data);
1952
+ * });
1953
+ * ```
1954
+ */
1955
+ webData2(args, listener) {
1956
+ const payload = {
1957
+ type: "webData2",
1958
+ user: args.user,
1959
+ };
1960
+ return this.transport.subscribe(payload.type, payload, (e) => {
1961
+ if (e.detail.user === args.user.toLowerCase()) {
1962
+ listener(e.detail);
1963
+ }
1964
+ });
1965
+ }
1966
+ async [Symbol.asyncDispose]() {
1967
+ await this.transport[Symbol.asyncDispose]?.();
1968
+ }
1969
+ }
1970
+
1971
+ /**
1972
+ * Error thrown when an HTTP response is deemed invalid:
1973
+ * - Non-200 status code
1974
+ * - Unexpected content type
1975
+ */
1976
+ class HttpRequestError extends TransportError {
1977
+ response;
1978
+ responseBody;
1979
+ /**
1980
+ * Creates a new HTTP request error.
1981
+ * @param response - The failed HTTP response.
1982
+ * @param responseBody - The raw response body content, if available.
1983
+ */
1984
+ constructor(response, responseBody) {
1985
+ let message = `HTTP request failed: status ${response.status}`;
1986
+ if (responseBody)
1987
+ message += `, body "${responseBody}"`;
1988
+ super(message);
1989
+ this.response = response;
1990
+ this.responseBody = responseBody;
1991
+ this.name = "HttpRequestError";
1992
+ }
1993
+ }
1994
+ /** HTTP implementation of the REST transport interface. */
1995
+ class HttpTransport {
1996
+ isTestnet;
1997
+ timeout;
1998
+ server;
1999
+ fetchOptions;
2000
+ onRequest;
2001
+ onResponse;
2002
+ /**
2003
+ * Creates a new HTTP transport instance.
2004
+ * @param options - Configuration options for the HTTP transport layer.
2005
+ */
2006
+ constructor(options) {
2007
+ this.isTestnet = options?.isTestnet ?? false;
2008
+ this.timeout = options?.timeout === undefined ? 10_000 : options.timeout;
2009
+ this.server = {
2010
+ mainnet: {
2011
+ api: options?.server?.mainnet?.api ?? "https://api.hyperliquid.xyz",
2012
+ rpc: options?.server?.mainnet?.rpc ?? "https://rpc.hyperliquid.xyz",
2013
+ },
2014
+ testnet: {
2015
+ api: options?.server?.testnet?.api ?? "https://api.hyperliquid-testnet.xyz",
2016
+ rpc: options?.server?.testnet?.rpc ?? "https://rpc.hyperliquid-testnet.xyz",
2017
+ },
2018
+ };
2019
+ this.fetchOptions = options?.fetchOptions ?? {};
2020
+ this.onRequest = options?.onRequest;
2021
+ this.onResponse = options?.onResponse;
2022
+ }
2023
+ /**
2024
+ * Sends a request to the Hyperliquid API via fetch.
2025
+ * @param endpoint - The API endpoint to send the request to.
2026
+ * @param payload - The payload to send with the request.
2027
+ * @param signal - An optional abort signal.
2028
+ * @returns A promise that resolves with parsed JSON response body.
2029
+ * @throws {HttpRequestError} - Thrown when an HTTP response is deemed invalid.
2030
+ * @throws May throw {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch#exceptions | fetch errors}.
2031
+ */
2032
+ async request(endpoint, payload, signal) {
2033
+ // Construct a Request
2034
+ const url = new URL(endpoint, this.server[this.isTestnet ? "testnet" : "mainnet"][endpoint === "explorer" ? "rpc" : "api"]);
2035
+ const init = mergeRequestInit({
2036
+ body: JSON.stringify(payload),
2037
+ headers: {
2038
+ "Accept-Encoding": "gzip, deflate, br, zstd",
2039
+ "Content-Type": "application/json",
2040
+ },
2041
+ keepalive: true,
2042
+ method: "POST",
2043
+ signal: this.timeout ? AbortSignal.timeout(this.timeout) : undefined,
2044
+ }, this.fetchOptions, { signal });
2045
+ let request = new Request(url, init);
2046
+ // Call the onRequest callback, if provided
2047
+ if (this.onRequest) {
2048
+ const customRequest = await this.onRequest(request);
2049
+ if (customRequest instanceof Request)
2050
+ request = customRequest;
2051
+ }
2052
+ // Send the Request and wait for a Response
2053
+ let response = await fetch(request);
2054
+ // Call the onResponse callback, if provided
2055
+ if (this.onResponse) {
2056
+ const customResponse = await this.onResponse(response);
2057
+ if (customResponse instanceof Response)
2058
+ response = customResponse;
2059
+ }
2060
+ // Validate the Response
2061
+ if (!response.ok || !response.headers.get("Content-Type")?.includes("application/json")) {
2062
+ // Unload the response body to prevent memory leaks
2063
+ const body = await response.text().catch(() => undefined);
2064
+ throw new HttpRequestError(response, body);
2065
+ }
2066
+ // Parse the response body
2067
+ const body = await response.json();
2068
+ // Check if the response is an error
2069
+ if (body?.type === "error") {
2070
+ throw new HttpRequestError(response, body?.message);
2071
+ }
2072
+ // Return the response body
2073
+ return body;
2074
+ }
2075
+ }
2076
+ /** Merges multiple {@linkcode HeadersInit} into one {@linkcode Headers}. */
2077
+ function mergeHeadersInit(...inits) {
2078
+ if (inits.length === 0 || inits.length === 1) {
2079
+ return new Headers(inits[0]);
2080
+ }
2081
+ const merged = new Headers();
2082
+ for (const headers of inits) {
2083
+ const iterator = Symbol.iterator in headers ? headers : Object.entries(headers);
2084
+ for (const [key, value] of iterator) {
2085
+ merged.set(key, value);
2086
+ }
2087
+ }
2088
+ return merged;
2089
+ }
2090
+ /** Merges multiple {@linkcode RequestInit} into one {@linkcode RequestInit}. */
2091
+ function mergeRequestInit(...inits) {
2092
+ const merged = inits.reduce((acc, init) => ({ ...acc, ...init }), {});
2093
+ const headersList = inits.map((init) => init.headers)
2094
+ .filter((headers) => typeof headers === "object");
2095
+ if (headersList.length > 0) {
2096
+ merged.headers = mergeHeadersInit(...headersList);
2097
+ }
2098
+ const signals = inits.map((init) => init.signal)
2099
+ .filter((signal) => signal instanceof AbortSignal);
2100
+ if (signals.length > 0) {
2101
+ merged.signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
2102
+ }
2103
+ return merged;
2104
+ }
2105
+
2106
+ // Copyright 2018-2025 the Deno authors. MIT license.
2107
+ // This module is browser compatible.
2108
+ /**
2109
+ * Resolve a {@linkcode Promise} after a given amount of milliseconds.
2110
+ *
2111
+ * @throws {DOMException} If the optional signal is aborted before the delay
2112
+ * duration, and `signal.reason` is undefined.
2113
+ * @param ms Duration in milliseconds for how long the delay should last.
2114
+ * @param options Additional options.
2115
+ *
2116
+ * @example Basic usage
2117
+ * ```ts no-assert
2118
+ * import { delay } from "@std/async/delay";
2119
+ *
2120
+ * // ...
2121
+ * const delayedPromise = delay(100);
2122
+ * const result = await delayedPromise;
2123
+ * // ...
2124
+ * ```
2125
+ *
2126
+ * @example Disable persistence
2127
+ *
2128
+ * Setting `persistent` to `false` will allow the process to continue to run as
2129
+ * long as the timer exists.
2130
+ *
2131
+ * ```ts no-assert ignore
2132
+ * import { delay } from "@std/async/delay";
2133
+ *
2134
+ * // ...
2135
+ * await delay(100, { persistent: false });
2136
+ * // ...
2137
+ * ```
2138
+ */
2139
+ function delay(ms, options = {}) {
2140
+ const { signal, persistent = true } = options;
2141
+ if (signal?.aborted)
2142
+ return Promise.reject(signal.reason);
2143
+ return new Promise((resolve, reject) => {
2144
+ const abort = () => {
2145
+ clearTimeout(i);
2146
+ reject(signal?.reason);
2147
+ };
2148
+ const done = () => {
2149
+ signal?.removeEventListener("abort", abort);
2150
+ resolve();
2151
+ };
2152
+ const i = setTimeout(done, ms);
2153
+ signal?.addEventListener("abort", abort, { once: true });
2154
+ if (persistent === false) {
2155
+ try {
2156
+ // @ts-ignore For browser compatibility
2157
+ Deno.unrefTimer(i);
2158
+ }
2159
+ catch (error) {
2160
+ if (!(error instanceof ReferenceError)) {
2161
+ throw error;
2162
+ }
2163
+ // deno-lint-ignore no-console
2164
+ console.error("`persistent` option is only available in Deno");
2165
+ }
2166
+ }
2167
+ });
2168
+ }
2169
+
2170
+ // deno-lint-ignore-file no-explicit-any
2171
+ /** Simple FIFO (First In, First Out) buffer implementation. */
2172
+ class FIFOMessageBuffer {
2173
+ queue = [];
2174
+ push(data, signal) {
2175
+ this.queue.push({ data, signal });
2176
+ }
2177
+ *[Symbol.iterator]() {
2178
+ while (this.queue.length > 0) {
2179
+ const { data, signal } = this.queue.shift();
2180
+ if (signal?.aborted)
2181
+ continue;
2182
+ yield data;
2183
+ }
2184
+ }
2185
+ }
2186
+ /** Error thrown when reconnection problems occur. */
2187
+ class ReconnectingWebSocketError extends TransportError {
2188
+ code;
2189
+ constructor(code, cause) {
2190
+ super(`Error when reconnecting WebSocket: ${code}`);
2191
+ this.code = code;
2192
+ this.name = "ReconnectingWebSocketError";
2193
+ this.cause = cause;
2194
+ }
2195
+ }
2196
+ /**
2197
+ * A WebSocket that automatically reconnects when disconnected.
2198
+ * Fully compatible with standard WebSocket API.
2199
+ */
2200
+ class ReconnectingWebSocket {
2201
+ _socket;
2202
+ _protocols;
2203
+ _listeners = [];
2204
+ _attempt = 0;
2205
+ reconnectOptions;
2206
+ reconnectAbortController = new AbortController();
2207
+ constructor(url, protocols, options) {
2208
+ this.reconnectOptions = {
2209
+ maxRetries: options?.maxRetries ?? 3,
2210
+ connectionTimeout: options?.connectionTimeout === undefined ? 10_000 : options.connectionTimeout,
2211
+ connectionDelay: options?.connectionDelay ?? ((n) => Math.min(~~(1 << n) * 150, 10_000)),
2212
+ shouldReconnect: options?.shouldReconnect ?? (() => true),
2213
+ messageBuffer: options?.messageBuffer ?? new FIFOMessageBuffer(),
2214
+ };
2215
+ this._socket = this._createSocket(url, protocols);
2216
+ this._protocols = protocols;
2217
+ this._setupEventListeners();
2218
+ }
2219
+ _createSocket(url, protocols) {
2220
+ const socket = new WebSocket(url, protocols);
2221
+ if (this.reconnectOptions.connectionTimeout === null)
2222
+ return socket;
2223
+ const timeoutId = setTimeout(() => {
2224
+ socket.removeEventListener("open", openHandler);
2225
+ socket.removeEventListener("close", closeHandler);
2226
+ socket.close(3008, "Timeout"); // https://www.iana.org/assignments/websocket/websocket.xml#close-code-number
2227
+ }, this.reconnectOptions.connectionTimeout);
2228
+ const openHandler = () => {
2229
+ socket.removeEventListener("close", closeHandler);
2230
+ clearTimeout(timeoutId);
2231
+ };
2232
+ const closeHandler = () => {
2233
+ socket.removeEventListener("open", openHandler);
2234
+ clearTimeout(timeoutId);
2235
+ };
2236
+ socket.addEventListener("open", openHandler, { once: true });
2237
+ socket.addEventListener("close", closeHandler, { once: true });
2238
+ return socket;
2239
+ }
2240
+ /** Initializes the internal event listeners for the socket. */
2241
+ _setupEventListeners() {
2242
+ this._socket.addEventListener("open", this._open, { once: true });
2243
+ this._socket.addEventListener("close", this._close, { once: true });
2244
+ }
2245
+ _open = () => {
2246
+ // Reset the attempt counter
2247
+ this._attempt = 0;
2248
+ // Send all buffered messages
2249
+ for (const message of this.reconnectOptions.messageBuffer) {
2250
+ this._socket.send(message);
2251
+ }
2252
+ };
2253
+ _close = async (event) => {
2254
+ try {
2255
+ // If the event was triggered but the socket is not closing, ignore it
2256
+ if (this._socket.readyState !== ReconnectingWebSocket.CLOSING &&
2257
+ this._socket.readyState !== ReconnectingWebSocket.CLOSED)
2258
+ return;
2259
+ // If the instance is terminated, do not attempt to reconnect
2260
+ if (this.reconnectAbortController.signal.aborted)
2261
+ return;
2262
+ // Check if reconnection should be attempted
2263
+ if (++this._attempt > this.reconnectOptions.maxRetries) {
2264
+ this._cleanup("RECONNECTION_LIMIT_REACHED");
2265
+ return;
2266
+ }
2267
+ const userDecision = await this.reconnectOptions.shouldReconnect(event, this.reconnectAbortController.signal);
2268
+ if (this.reconnectAbortController.signal.aborted)
2269
+ return;
2270
+ if (!userDecision) {
2271
+ this._cleanup("RECONNECTION_STOPPED_BY_USER");
2272
+ return;
2273
+ }
2274
+ // Delay before reconnecting
2275
+ const reconnectDelay = typeof this.reconnectOptions.connectionDelay === "number"
2276
+ ? this.reconnectOptions.connectionDelay
2277
+ : await this.reconnectOptions.connectionDelay(this._attempt, this.reconnectAbortController.signal);
2278
+ if (this.reconnectAbortController.signal.aborted)
2279
+ return;
2280
+ await delay(reconnectDelay, { signal: this.reconnectAbortController.signal });
2281
+ // Create a new WebSocket instance
2282
+ const { onclose, onerror, onmessage, onopen } = this._socket;
2283
+ this._socket = this._createSocket(this._socket.url, this._protocols);
2284
+ // Reconnect all listeners
2285
+ this._setupEventListeners();
2286
+ this._listeners.forEach(({ type, listenerProxy, options }) => {
2287
+ this._socket.addEventListener(type, listenerProxy, options);
2288
+ });
2289
+ this._socket.onclose = onclose;
2290
+ this._socket.onerror = onerror;
2291
+ this._socket.onmessage = onmessage;
2292
+ this._socket.onopen = onopen;
2293
+ }
2294
+ catch (error) {
2295
+ this._cleanup("UNKNOWN_ERROR", error);
2296
+ }
2297
+ };
2298
+ /** Clean up internal resources. */
2299
+ _cleanup(code, cause) {
2300
+ this.reconnectAbortController.abort(new ReconnectingWebSocketError(code, cause));
2301
+ this._listeners = [];
2302
+ this._socket.close();
2303
+ }
2304
+ // WebSocket property implementations
2305
+ get url() {
2306
+ return this._socket.url;
2307
+ }
2308
+ get readyState() {
2309
+ return this._socket.readyState;
2310
+ }
2311
+ get bufferedAmount() {
2312
+ return this._socket.bufferedAmount;
2313
+ }
2314
+ get extensions() {
2315
+ return this._socket.extensions;
2316
+ }
2317
+ get protocol() {
2318
+ return this._socket.protocol;
2319
+ }
2320
+ get binaryType() {
2321
+ return this._socket.binaryType;
2322
+ }
2323
+ set binaryType(value) {
2324
+ this._socket.binaryType = value;
2325
+ }
2326
+ CONNECTING = 0;
2327
+ OPEN = 1;
2328
+ CLOSING = 2;
2329
+ CLOSED = 3;
2330
+ static CONNECTING = 0;
2331
+ static OPEN = 1;
2332
+ static CLOSING = 2;
2333
+ static CLOSED = 3;
2334
+ get onclose() {
2335
+ return this._socket.onclose;
2336
+ }
2337
+ set onclose(value) {
2338
+ this._socket.onclose = value;
2339
+ }
2340
+ get onerror() {
2341
+ return this._socket.onerror;
2342
+ }
2343
+ set onerror(value) {
2344
+ this._socket.onerror = value;
2345
+ }
2346
+ get onmessage() {
2347
+ return this._socket.onmessage;
2348
+ }
2349
+ set onmessage(value) {
2350
+ this._socket.onmessage = value;
2351
+ }
2352
+ get onopen() {
2353
+ return this._socket.onopen;
2354
+ }
2355
+ set onopen(value) {
2356
+ this._socket.onopen = value;
2357
+ }
2358
+ /**
2359
+ * @param permanently - If `true`, the connection will be permanently closed. Default is `true`.
2360
+ */
2361
+ close(code, reason, permanently = true) {
2362
+ this._socket.close(code, reason);
2363
+ if (permanently)
2364
+ this._cleanup("USER_INITIATED_CLOSE");
169
2365
  }
170
2366
  /**
171
- * Set authorization token on the client
2367
+ * @param signal - `AbortSignal` to cancel sending a message if it was in the buffer.
2368
+ * @note If the connection is not open, the data will be buffered and sent when the connection is established.
172
2369
  */
173
- setAuthToken(token) {
174
- this.client.setAuthToken(token);
2370
+ send(data, signal) {
2371
+ if (signal?.aborted)
2372
+ return;
2373
+ if (this._socket.readyState !== ReconnectingWebSocket.OPEN && !this.reconnectAbortController.signal.aborted) {
2374
+ this.reconnectOptions.messageBuffer.push(data, signal);
2375
+ }
2376
+ else {
2377
+ this._socket.send(data);
2378
+ }
2379
+ }
2380
+ addEventListener(type, listener, options) {
2381
+ // Wrap the listener to handle reconnection
2382
+ let listenerProxy;
2383
+ if (this.reconnectAbortController.signal.aborted) {
2384
+ // If the instance is terminated, use the original listener
2385
+ listenerProxy = listener;
2386
+ }
2387
+ else {
2388
+ // Check if the listener is already registered
2389
+ const index = this._listeners.findIndex((e) => listenersMatch(e, { type, listener, options }));
2390
+ if (index !== -1) {
2391
+ // Use the existing listener proxy
2392
+ listenerProxy = this._listeners[index].listenerProxy;
2393
+ }
2394
+ else {
2395
+ // Wrap the original listener to follow the once option when reconnecting
2396
+ listenerProxy = (event) => {
2397
+ try {
2398
+ if (typeof listener === "function") {
2399
+ listener.call(this, event);
2400
+ }
2401
+ else {
2402
+ listener.handleEvent(event);
2403
+ }
2404
+ }
2405
+ finally {
2406
+ // If the listener is marked as once, remove it after the first invocation
2407
+ if (typeof options === "object" && options.once === true) {
2408
+ const index = this._listeners.findIndex((e) => listenersMatch(e, { type, listener, options }));
2409
+ if (index !== -1) {
2410
+ this._listeners.splice(index, 1);
2411
+ }
2412
+ }
2413
+ }
2414
+ };
2415
+ this._listeners.push({ type, listener, options, listenerProxy });
2416
+ }
2417
+ }
2418
+ // Add the wrapped (or original) listener
2419
+ this._socket.addEventListener(type, listenerProxy, options);
2420
+ }
2421
+ removeEventListener(type, listener, options) {
2422
+ // Remove a wrapped listener, not an original listener
2423
+ const index = this._listeners.findIndex((e) => listenersMatch(e, { type, listener, options }));
2424
+ if (index !== -1) {
2425
+ const { listenerProxy } = this._listeners[index];
2426
+ this._socket.removeEventListener(type, listenerProxy, options);
2427
+ this._listeners.splice(index, 1);
2428
+ }
2429
+ else {
2430
+ // If the wrapped listener is not found, remove the original listener
2431
+ this._socket.removeEventListener(type, listener, options);
2432
+ }
175
2433
  }
2434
+ dispatchEvent(event) {
2435
+ return this._socket.dispatchEvent(event);
2436
+ }
2437
+ }
2438
+ /** Check if two event listeners are the same (just like EventTarget). */
2439
+ function listenersMatch(a, b) {
2440
+ // EventTarget only compares capture in options, even if one is an object and the other is boolean
2441
+ const aCapture = Boolean(typeof a.options === "object" ? a.options.capture : a.options);
2442
+ const bCapture = Boolean(typeof b.options === "object" ? b.options.capture : b.options);
2443
+ return a.type === b.type && a.listener === b.listener && aCapture === bCapture;
2444
+ }
2445
+
2446
+ class TypedEventTarget extends EventTarget {
176
2447
  /**
177
- * Set custom headers on the client
2448
+ * Dispatches a synthetic event event to target and returns true if either
2449
+ * event's cancelable attribute value is false or its preventDefault() method
2450
+ * was not invoked, and false otherwise.
178
2451
  */
179
- setHeaders(headers) {
180
- this.client.setHeaders(headers);
2452
+ dispatchTypedEvent(_type, event) {
2453
+ return super.dispatchEvent(event);
2454
+ }
2455
+ }
2456
+
2457
+ /** Listens for WebSocket messages and sends them as Hyperliquid typed events. */
2458
+ class HyperliquidEventTarget extends TypedEventTarget {
2459
+ constructor(socket) {
2460
+ super();
2461
+ socket.addEventListener("message", (event) => {
2462
+ try {
2463
+ const msg = JSON.parse(event.data);
2464
+ if (isHyperliquidMsg(msg)) {
2465
+ this.dispatchEvent(new CustomEvent(msg.channel, { detail: msg.data }));
2466
+ }
2467
+ else if (isExplorerBlockMsg(msg)) {
2468
+ this.dispatchEvent(new CustomEvent("_explorerBlock", { detail: msg }));
2469
+ }
2470
+ else if (isExplorerTxsMsg(msg)) {
2471
+ this.dispatchEvent(new CustomEvent("_explorerTxs", { detail: msg }));
2472
+ }
2473
+ }
2474
+ catch {
2475
+ // Ignore JSON parsing errors
2476
+ }
2477
+ });
2478
+ }
2479
+ }
2480
+ /** Type guard for Hyperliquid messages. */
2481
+ function isHyperliquidMsg(value) {
2482
+ return typeof value === "object" && value !== null &&
2483
+ "channel" in value && typeof value.channel === "string";
2484
+ }
2485
+ /** Type guard for explorer block messages. */
2486
+ function isExplorerBlockMsg(value) {
2487
+ return Array.isArray(value) && value.length > 0 &&
2488
+ (typeof value[0] === "object" && value[0] !== null && !Array.isArray(value[0]) &&
2489
+ "height" in value[0] && typeof value[0].height === "number" &&
2490
+ "blockTime" in value[0] && typeof value[0].blockTime === "number" &&
2491
+ "hash" in value[0] && typeof value[0].hash === "string" &&
2492
+ "proposer" in value[0] && typeof value[0].proposer === "string" &&
2493
+ "numTxs" in value[0] && typeof value[0].numTxs === "number");
2494
+ }
2495
+ /** Type guard for explorer transactions messages. */
2496
+ function isExplorerTxsMsg(value) {
2497
+ return Array.isArray(value) && value.length > 0 &&
2498
+ (typeof value[0] === "object" && value[0] !== null && !Array.isArray(value[0]) &&
2499
+ "action" in value[0] && typeof value[0].action === "object" && value[0].action !== null &&
2500
+ "block" in value[0] && typeof value[0].block === "number" &&
2501
+ "error" in value[0] && (typeof value[0].error === "string" || value[0].error === null) &&
2502
+ "hash" in value[0] && typeof value[0].hash === "string" &&
2503
+ "time" in value[0] && typeof value[0].time === "number" &&
2504
+ "user" in value[0] && typeof value[0].user === "string");
2505
+ }
2506
+
2507
+ /**
2508
+ * Error thrown when a WebSocket request fails:
2509
+ * - When the WebSocket connection is closed
2510
+ * - When the server responds with an error message
2511
+ */
2512
+ class WebSocketRequestError extends TransportError {
2513
+ constructor(message) {
2514
+ super(message);
2515
+ this.name = "WebSocketRequestError";
181
2516
  }
2517
+ }
2518
+ /**
2519
+ * Manages WebSocket requests to the Hyperliquid API.
2520
+ * Handles request creation, sending, and mapping responses to their corresponding requests.
2521
+ */
2522
+ class WebSocketAsyncRequest {
2523
+ socket;
2524
+ lastId = 0;
2525
+ queue = [];
2526
+ lastRequestTime = 0;
182
2527
  /**
183
- * Get base URL from client
2528
+ * Creates a new WebSocket async request handler.
2529
+ * @param socket - WebSocket connection instance for sending requests to the Hyperliquid WebSocket API
2530
+ * @param hlEvents - Used to recognize Hyperliquid responses and match them with sent requests
184
2531
  */
185
- getBaseUrl() {
186
- return this.client.getBaseUrl();
2532
+ constructor(socket, hlEvents) {
2533
+ this.socket = socket;
2534
+ // Monitor responses and match the pending request
2535
+ hlEvents.addEventListener("subscriptionResponse", (event) => {
2536
+ // Use a stringified request as an id
2537
+ const id = WebSocketAsyncRequest.requestToId(event.detail);
2538
+ this.queue.findLast((item) => item.id === id)?.resolve(event.detail);
2539
+ });
2540
+ hlEvents.addEventListener("post", (event) => {
2541
+ const data = event.detail.response.type === "info"
2542
+ ? event.detail.response.payload.data
2543
+ : event.detail.response.payload;
2544
+ this.queue.findLast((item) => item.id === event.detail.id)?.resolve(data);
2545
+ });
2546
+ hlEvents.addEventListener("pong", () => {
2547
+ this.queue.findLast((item) => item.id === "ping")?.resolve();
2548
+ });
2549
+ hlEvents.addEventListener("error", (event) => {
2550
+ try {
2551
+ // Error event doesn't have an id, use original request to match
2552
+ const request = event.detail.match(/{.*}/)?.[0];
2553
+ if (!request)
2554
+ return;
2555
+ const parsedRequest = JSON.parse(request);
2556
+ // For `post` requests
2557
+ if ("id" in parsedRequest && typeof parsedRequest.id === "number") {
2558
+ this.queue.findLast((item) => item.id === parsedRequest.id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
2559
+ return;
2560
+ }
2561
+ // For `subscribe` and `unsubscribe` requests
2562
+ if ("subscription" in parsedRequest &&
2563
+ typeof parsedRequest.subscription === "object" && parsedRequest.subscription !== null) {
2564
+ const id = WebSocketAsyncRequest.requestToId(parsedRequest);
2565
+ this.queue.findLast((item) => item.id === id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
2566
+ return;
2567
+ }
2568
+ // For already/invalid subscribed requests
2569
+ if (event.detail.startsWith("Already subscribed") || event.detail.startsWith("Invalid subscription")) {
2570
+ const id = WebSocketAsyncRequest.requestToId({
2571
+ method: "subscribe",
2572
+ subscription: parsedRequest,
2573
+ });
2574
+ this.queue.findLast((item) => item.id === id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
2575
+ return;
2576
+ }
2577
+ // For already unsubscribed requests
2578
+ if (event.detail.startsWith("Already unsubscribed")) {
2579
+ const id = WebSocketAsyncRequest.requestToId({
2580
+ method: "unsubscribe",
2581
+ subscription: parsedRequest,
2582
+ });
2583
+ this.queue.findLast((item) => item.id === id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
2584
+ return;
2585
+ }
2586
+ // For unknown requests
2587
+ const id = WebSocketAsyncRequest.requestToId(parsedRequest);
2588
+ this.queue.findLast((item) => item.id === id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
2589
+ }
2590
+ catch {
2591
+ // Ignore JSON parsing errors
2592
+ }
2593
+ });
2594
+ // Throws all pending requests if the connection is dropped
2595
+ socket.addEventListener("close", () => {
2596
+ this.queue.forEach(({ reject }) => {
2597
+ reject(new WebSocketRequestError("Cannot complete WebSocket request: connection is closed"));
2598
+ });
2599
+ this.queue = [];
2600
+ });
2601
+ }
2602
+ async request(method, payload_or_signal, maybeSignal) {
2603
+ const payload = payload_or_signal instanceof AbortSignal ? undefined : payload_or_signal;
2604
+ const signal = payload_or_signal instanceof AbortSignal ? payload_or_signal : maybeSignal;
2605
+ // Reject the request if the signal is aborted
2606
+ if (signal?.aborted)
2607
+ return Promise.reject(signal.reason);
2608
+ // Create a request
2609
+ let id;
2610
+ let request;
2611
+ if (method === "post") {
2612
+ id = ++this.lastId;
2613
+ request = { method, id, request: payload };
2614
+ }
2615
+ else if (method === "ping") {
2616
+ id = "ping";
2617
+ request = { method };
2618
+ }
2619
+ else {
2620
+ request = { method, subscription: payload };
2621
+ id = WebSocketAsyncRequest.requestToId(request);
2622
+ }
2623
+ // Send the request
2624
+ this.socket.send(JSON.stringify(request), signal);
2625
+ this.lastRequestTime = Date.now();
2626
+ // Wait for a response
2627
+ const { promise, resolve, reject } = Promise.withResolvers();
2628
+ this.queue.push({ id, resolve, reject });
2629
+ const onAbort = () => reject(signal?.reason);
2630
+ signal?.addEventListener("abort", onAbort, { once: true });
2631
+ return await promise.finally(() => {
2632
+ const index = this.queue.findLastIndex((item) => item.id === id);
2633
+ if (index !== -1)
2634
+ this.queue.splice(index, 1);
2635
+ signal?.removeEventListener("abort", onAbort);
2636
+ });
2637
+ }
2638
+ /** Normalizes an object and then converts it to a string. */
2639
+ static requestToId(value) {
2640
+ const lowerHex = containsUppercaseHex(value) ? deepLowerHex(value) : value;
2641
+ const sorted = deepSortKeys(lowerHex);
2642
+ return JSON.stringify(sorted); // Also removes undefined
2643
+ }
2644
+ }
2645
+ /** Deeply converts hexadecimal strings in an object/array to lowercase. */
2646
+ function deepLowerHex(obj) {
2647
+ if (typeof obj === "string") {
2648
+ return /^(0X[0-9a-fA-F]*|0x[0-9a-fA-F]*[A-F][0-9a-fA-F]*)$/.test(obj) ? obj.toLowerCase() : obj;
2649
+ }
2650
+ if (Array.isArray(obj)) {
2651
+ return obj.map(deepLowerHex);
2652
+ }
2653
+ if (typeof obj === "object" && obj !== null) {
2654
+ const result = {};
2655
+ const entries = Object.entries(obj);
2656
+ for (const [key, value] of entries) {
2657
+ result[key] = deepLowerHex(value);
2658
+ }
2659
+ return result;
2660
+ }
2661
+ return obj;
2662
+ }
2663
+ /** Check if an object contains uppercase hexadecimal strings. */
2664
+ function containsUppercaseHex(obj) {
2665
+ const str = JSON.stringify(obj);
2666
+ return /0X[0-9a-fA-F]*|0x[0-9a-fA-F]*[A-F][0-9a-fA-F]*/.test(str);
2667
+ }
2668
+ /** Deeply sort the keys of an object. */
2669
+ function deepSortKeys(obj) {
2670
+ if (typeof obj !== "object" || obj === null) {
2671
+ return obj;
2672
+ }
2673
+ if (Array.isArray(obj)) {
2674
+ return obj.map(deepSortKeys);
2675
+ }
2676
+ const result = {};
2677
+ const keys = Object.keys(obj).sort();
2678
+ for (const key of keys) {
2679
+ result[key] = deepSortKeys(obj[key]);
2680
+ }
2681
+ return result;
2682
+ }
2683
+
2684
+ /** WebSocket implementation of the REST and Subscription transport interfaces. */
2685
+ class WebSocketTransport {
2686
+ _wsRequester;
2687
+ _hlEvents;
2688
+ _keepAliveTimeout = null;
2689
+ _subscriptions = new Map();
2690
+ _isReconnecting = false;
2691
+ /**
2692
+ * Request timeout in ms.
2693
+ * Set to `null` to disable.
2694
+ */
2695
+ timeout;
2696
+ /** Keep-alive configuration. */
2697
+ keepAlive;
2698
+ /** Enable automatic resubscription after reconnection. */
2699
+ autoResubscribe;
2700
+ /** The WebSocket that is used for communication. */
2701
+ socket;
2702
+ /**
2703
+ * Creates a new WebSocket transport instance.
2704
+ * @param options - Configuration options for the WebSocket transport layer.
2705
+ */
2706
+ constructor(options) {
2707
+ this.socket = new ReconnectingWebSocket(options?.url ?? "wss://api.hyperliquid.xyz/ws", undefined, options?.reconnect);
2708
+ this._hlEvents = new HyperliquidEventTarget(this.socket);
2709
+ this._wsRequester = new WebSocketAsyncRequest(this.socket, this._hlEvents);
2710
+ this.timeout = options?.timeout === undefined ? 10_000 : options.timeout;
2711
+ this.keepAlive = {
2712
+ interval: options?.keepAlive?.interval === undefined ? 30_000 : options.keepAlive?.interval,
2713
+ timeout: options?.keepAlive?.timeout === undefined ? this.timeout : options.keepAlive?.timeout,
2714
+ };
2715
+ this.autoResubscribe = options?.autoResubscribe ?? true;
2716
+ // Initialize listeners
2717
+ this.socket.addEventListener("open", () => {
2718
+ this._keepAliveStart();
2719
+ this._resubscribeStart();
2720
+ });
2721
+ this.socket.addEventListener("close", () => {
2722
+ this._keepAliveStop();
2723
+ this._resubscribeStop();
2724
+ this._isReconnecting = true;
2725
+ });
2726
+ }
2727
+ /**
2728
+ * Sends a request to the Hyperliquid API via WebSocket.
2729
+ *
2730
+ * Note: Explorer requests are not supported in the Hyperliquid WebSocket API.
2731
+ *
2732
+ * @param endpoint - The API endpoint to send the request to (`explorer` requests are not supported).
2733
+ * @param payload - The payload to send with the request.
2734
+ * @param signal - An optional abort signal.
2735
+ * @returns A promise that resolves with parsed JSON response body.
2736
+ * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
2737
+ */
2738
+ request(type, payload, signal) {
2739
+ const timeoutSignal = this.timeout ? AbortSignal.timeout(this.timeout) : undefined;
2740
+ const combinedSignal = signal && timeoutSignal
2741
+ ? AbortSignal.any([signal, timeoutSignal])
2742
+ : signal ?? timeoutSignal;
2743
+ return this._wsRequester.request("post", {
2744
+ type: type === "exchange" ? "action" : type,
2745
+ payload,
2746
+ }, combinedSignal);
2747
+ }
2748
+ /**
2749
+ * Subscribes to a Hyperliquid event channel.
2750
+ *
2751
+ * Sends a subscription request to the server and listens for events.
2752
+ *
2753
+ * @param channel - The event channel to listen to.
2754
+ * @param payload - A payload to send with the subscription request.
2755
+ * @param listener - A function to call when the event is dispatched.
2756
+ * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
2757
+ * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
2758
+ */
2759
+ async subscribe(channel, payload, listener) {
2760
+ // Create a unique identifier for the subscription
2761
+ const id = WebSocketAsyncRequest.requestToId(payload);
2762
+ // Initialize new subscription, if it doesn't exist
2763
+ let subscription = this._subscriptions.get(id);
2764
+ if (!subscription) {
2765
+ // Send subscription request
2766
+ const promise = this._wsRequester.request("subscribe", payload);
2767
+ // Cache subscription info
2768
+ subscription = {
2769
+ listeners: new Map(),
2770
+ promise,
2771
+ resubscribeAbortController: new AbortController(),
2772
+ };
2773
+ this._subscriptions.set(id, subscription);
2774
+ }
2775
+ // Initialize new listener, if it doesn't exist
2776
+ let unsubscribe = subscription.listeners.get(listener);
2777
+ if (!unsubscribe) {
2778
+ // Create new unsubscribe function
2779
+ unsubscribe = async () => {
2780
+ // Remove listener and cleanup
2781
+ this._hlEvents.removeEventListener(channel, listener);
2782
+ const subscription = this._subscriptions.get(id);
2783
+ subscription?.listeners.delete(listener);
2784
+ // If no listeners remain, remove subscription entirely
2785
+ if (subscription?.listeners.size === 0) {
2786
+ // Cleanup subscription
2787
+ this._subscriptions.delete(id);
2788
+ // If the socket is open, send unsubscription request
2789
+ if (this.socket.readyState === ReconnectingWebSocket.OPEN) {
2790
+ await this._wsRequester.request("unsubscribe", payload);
2791
+ }
2792
+ }
2793
+ };
2794
+ // Add listener and cache unsubscribe function
2795
+ this._hlEvents.addEventListener(channel, listener);
2796
+ subscription.listeners.set(listener, unsubscribe);
2797
+ }
2798
+ // Wait for the initial subscription request to complete
2799
+ await subscription.promise;
2800
+ // Return subscription control object
2801
+ return {
2802
+ unsubscribe,
2803
+ resubscribeSignal: subscription.resubscribeAbortController?.signal,
2804
+ };
2805
+ }
2806
+ /**
2807
+ * Waits until the WebSocket connection is ready.
2808
+ * @param signal - An optional abort signal.
2809
+ * @returns A promise that resolves when the connection is ready.
2810
+ */
2811
+ ready(signal) {
2812
+ return new Promise((resolve, reject) => {
2813
+ const combinedSignal = signal
2814
+ ? AbortSignal.any([this.socket.reconnectAbortController.signal, signal])
2815
+ : this.socket.reconnectAbortController.signal;
2816
+ if (combinedSignal.aborted)
2817
+ return reject(combinedSignal.reason);
2818
+ if (this.socket.readyState === ReconnectingWebSocket.OPEN)
2819
+ return resolve();
2820
+ const handleOpen = () => {
2821
+ combinedSignal.removeEventListener("abort", handleAbort);
2822
+ resolve();
2823
+ };
2824
+ const handleAbort = () => {
2825
+ this.socket.removeEventListener("open", handleOpen);
2826
+ reject(combinedSignal.reason);
2827
+ };
2828
+ this.socket.addEventListener("open", handleOpen, { once: true });
2829
+ combinedSignal.addEventListener("abort", handleAbort, { once: true });
2830
+ });
2831
+ }
2832
+ /**
2833
+ * Closes the WebSocket connection and waits until it is fully closed.
2834
+ * @param signal - An optional abort signal.
2835
+ * @returns A promise that resolves when the connection is fully closed.
2836
+ */
2837
+ close(signal) {
2838
+ return new Promise((resolve, reject) => {
2839
+ if (signal?.aborted)
2840
+ return reject(signal.reason);
2841
+ if (this.socket.readyState === ReconnectingWebSocket.CLOSED)
2842
+ return resolve();
2843
+ const handleClose = () => {
2844
+ signal?.removeEventListener("abort", handleAbort);
2845
+ resolve();
2846
+ };
2847
+ const handleAbort = () => {
2848
+ this.socket.removeEventListener("close", handleClose);
2849
+ reject(signal?.reason);
2850
+ };
2851
+ this.socket.addEventListener("close", handleClose, { once: true });
2852
+ signal?.addEventListener("abort", handleAbort, { once: true });
2853
+ this.socket.close();
2854
+ });
2855
+ }
2856
+ /** Keep the connection alive. Sends ping only when necessary. */
2857
+ _keepAliveStart() {
2858
+ if (this.keepAlive.interval === null || this._keepAliveTimeout)
2859
+ return;
2860
+ const tick = async () => {
2861
+ if (this.socket.readyState !== ReconnectingWebSocket.OPEN || !this._keepAliveTimeout ||
2862
+ this.keepAlive.interval === null)
2863
+ return;
2864
+ // Check if the last request was sent more than the keep-alive interval ago
2865
+ if (Date.now() - this._wsRequester.lastRequestTime >= this.keepAlive.interval) {
2866
+ const timeoutSignal = this.keepAlive.timeout ? AbortSignal.timeout(this.keepAlive.timeout) : undefined;
2867
+ await this._wsRequester.request("ping", timeoutSignal)
2868
+ .catch(() => undefined); // Ignore errors
2869
+ }
2870
+ // Schedule the next ping
2871
+ if (this.socket.readyState === ReconnectingWebSocket.OPEN && this._keepAliveTimeout &&
2872
+ this.keepAlive.interval !== null) {
2873
+ const nextDelay = this.keepAlive.interval - (Date.now() - this._wsRequester.lastRequestTime);
2874
+ this._keepAliveTimeout = setTimeout(tick, nextDelay);
2875
+ }
2876
+ };
2877
+ this._keepAliveTimeout = setTimeout(tick, this.keepAlive.interval);
2878
+ }
2879
+ _keepAliveStop() {
2880
+ if (this._keepAliveTimeout !== null) {
2881
+ clearTimeout(this._keepAliveTimeout);
2882
+ this._keepAliveTimeout = null;
2883
+ }
2884
+ }
2885
+ /** Resubscribe to all existing subscriptions if auto-resubscribe is enabled. */
2886
+ _resubscribeStart() {
2887
+ if (this.autoResubscribe && this._isReconnecting) {
2888
+ for (const [id, subscriptionInfo] of this._subscriptions.entries()) {
2889
+ subscriptionInfo.promise = this._wsRequester.request("subscribe", JSON.parse(id))
2890
+ .catch((error) => {
2891
+ subscriptionInfo.resubscribeAbortController?.abort(error);
2892
+ });
2893
+ }
2894
+ }
2895
+ }
2896
+ _resubscribeStop() {
2897
+ if (!this.autoResubscribe || this.socket.reconnectAbortController.signal.aborted) {
2898
+ for (const subscriptionInfo of this._subscriptions.values()) {
2899
+ for (const [_, unsubscribe] of subscriptionInfo.listeners) {
2900
+ unsubscribe(); // does not cause an error if used when the connection is closed
2901
+ }
2902
+ }
2903
+ }
2904
+ }
2905
+ async [Symbol.asyncDispose]() {
2906
+ await this.close();
2907
+ }
2908
+ }
2909
+
2910
+ /**
2911
+ * Hyperliquid service client for direct API communication
2912
+ */
2913
+ class HyperliquidService {
2914
+ constructor(wsUrl = 'wss://api.hyperliquid.xyz/ws', isTestnet = false) {
2915
+ // Market data
2916
+ this.allMidsData = null;
2917
+ this.webData2 = null;
2918
+ // Optimized caches
2919
+ this.assetBySymbol = new Map();
2920
+ this.allAssetsCache = null;
2921
+ // Initialize HTTP client
2922
+ this.infoClient = new InfoClient({
2923
+ transport: new HttpTransport(),
2924
+ });
2925
+ // Initialize WebSocket if URL provided
2926
+ if (wsUrl) {
2927
+ this.initializeWebSocket(wsUrl);
2928
+ }
2929
+ }
2930
+ initializeWebSocket(wsUrl) {
2931
+ this.wsTransport = new WebSocketTransport({
2932
+ url: wsUrl,
2933
+ });
2934
+ this.subsClient = new SubscriptionClient({ transport: this.wsTransport });
2935
+ // Subscribe to all mids for real-time price data
2936
+ this.subsClient.allMids((data) => {
2937
+ this.allMidsData = data;
2938
+ });
2939
+ // Subscribe to web data for asset information
2940
+ // Will be updated when address is set via updateUserAddress method
2941
+ }
2942
+ /**
2943
+ * Refresh asset cache when webData2 updates
2944
+ */
2945
+ refreshAssetCache() {
2946
+ var _a, _b;
2947
+ if (!((_a = this.webData2) === null || _a === void 0 ? void 0 : _a.meta.universe) || !((_b = this.webData2) === null || _b === void 0 ? void 0 : _b.assetCtxs))
2948
+ return;
2949
+ this.assetBySymbol.clear();
2950
+ this.allAssetsCache = null;
2951
+ // Build optimized lookup map
2952
+ this.webData2.meta.universe.forEach((universe, index) => {
2953
+ const assetCtx = this.webData2.assetCtxs[index];
2954
+ if (assetCtx) {
2955
+ this.assetBySymbol.set(universe.name, {
2956
+ universe,
2957
+ assetCtx,
2958
+ index
2959
+ });
2960
+ }
2961
+ });
2962
+ }
2963
+ /**
2964
+ * Get asset information by symbol - O(1) lookup
2965
+ */
2966
+ getAssetInfo(symbol) {
2967
+ var _a;
2968
+ return ((_a = this.assetBySymbol.get(symbol)) === null || _a === void 0 ? void 0 : _a.universe) || null;
2969
+ }
2970
+ /**
2971
+ * Get asset context by symbol - O(1) lookup
2972
+ */
2973
+ getAssetCtx(symbol) {
2974
+ var _a;
2975
+ return ((_a = this.assetBySymbol.get(symbol)) === null || _a === void 0 ? void 0 : _a.assetCtx) || null;
2976
+ }
2977
+ /**
2978
+ * Get asset index by symbol - O(1) lookup
2979
+ */
2980
+ getAssetIndex(symbol) {
2981
+ const data = this.assetBySymbol.get(symbol);
2982
+ return data ? data.index : null;
2983
+ }
2984
+ /**
2985
+ * Get all assets with caching
2986
+ */
2987
+ getAllAssets() {
2988
+ if (this.allAssetsCache) {
2989
+ return this.allAssetsCache;
2990
+ }
2991
+ this.allAssetsCache = Array.from(this.assetBySymbol.values()).map(data => ({
2992
+ universe: data.universe,
2993
+ assetsCtx: data.assetCtx,
2994
+ }));
2995
+ return this.allAssetsCache;
2996
+ }
2997
+ /**
2998
+ * Get current market price for an asset
2999
+ */
3000
+ getMarketPrice(symbol) {
3001
+ var _a;
3002
+ return parseFloat(((_a = this.allMidsData) === null || _a === void 0 ? void 0 : _a.mids[symbol]) || '0');
3003
+ }
3004
+ /**
3005
+ * Get optimal decimal places for an asset
3006
+ */
3007
+ getOptimalDecimal(symbol) {
3008
+ const asset = this.getAssetInfo(symbol);
3009
+ return asset ? asset.szDecimals : 8;
3010
+ }
3011
+ /**
3012
+ * Get user's open positions from Hyperliquid
3013
+ */
3014
+ async getUserPositions(address) {
3015
+ try {
3016
+ const state = await this.infoClient.clearinghouseState({
3017
+ user: address
3018
+ });
3019
+ return state.assetPositions || [];
3020
+ }
3021
+ catch (error) {
3022
+ console.error('Failed to get user positions:', error);
3023
+ return [];
3024
+ }
3025
+ }
3026
+ /**
3027
+ * Get user's account summary from Hyperliquid
3028
+ */
3029
+ async getAccountSummary(address) {
3030
+ try {
3031
+ return await this.infoClient.clearinghouseState({
3032
+ user: address
3033
+ });
3034
+ }
3035
+ catch (error) {
3036
+ console.error('Failed to get account summary:', error);
3037
+ return null;
3038
+ }
3039
+ }
3040
+ /**
3041
+ * Get user's open orders from Hyperliquid
3042
+ */
3043
+ async getUserOrders(address) {
3044
+ try {
3045
+ return await this.infoClient.openOrders({
3046
+ user: address
3047
+ });
3048
+ }
3049
+ catch (error) {
3050
+ console.error('Failed to get user orders:', error);
3051
+ return [];
3052
+ }
3053
+ }
3054
+ /**
3055
+ * Update the user address for webData2 subscription
3056
+ */
3057
+ updateUserAddress(address) {
3058
+ if (this.subsClient && address) {
3059
+ // Subscribe to webData2 with the new address
3060
+ this.subsClient.webData2({
3061
+ user: address,
3062
+ }, (data) => {
3063
+ this.webData2 = data;
3064
+ this.refreshAssetCache();
3065
+ });
3066
+ }
3067
+ }
3068
+ /**
3069
+ * Get the info client instance
3070
+ */
3071
+ getInfoClient() {
3072
+ return this.infoClient;
3073
+ }
3074
+ /**
3075
+ * Check if WebSocket is connected
3076
+ */
3077
+ isWebSocketConnected() {
3078
+ return !!this.subsClient && !!this.wsTransport;
3079
+ }
3080
+ /**
3081
+ * Clean up resources
3082
+ */
3083
+ async cleanup() {
3084
+ if (this.wsTransport && this.wsTransport.close) {
3085
+ await this.wsTransport.close();
3086
+ }
3087
+ this.assetBySymbol.clear();
3088
+ this.allAssetsCache = null;
3089
+ this.allMidsData = null;
3090
+ this.webData2 = null;
187
3091
  }
188
3092
  }
189
3093
 
@@ -2617,9 +5521,11 @@ const PearHyperliquidContext = require$$0.createContext(undefined);
2617
5521
  /**
2618
5522
  * React Provider for PearHyperliquidClient
2619
5523
  */
2620
- const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/ws', children, }) => {
5524
+ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/ws', hyperliquidWsUrl = 'wss://api.hyperliquid.xyz/ws', children, }) => {
2621
5525
  const client = require$$0.useMemo(() => new PearHyperliquidClient(config), [config]);
2622
5526
  const migrationSDK = require$$0.useMemo(() => new PearMigrationSDK(client), [client]);
5527
+ // Initialize Hyperliquid service
5528
+ const hyperliquidService = require$$0.useMemo(() => new HyperliquidService(hyperliquidWsUrl), [hyperliquidWsUrl]);
2623
5529
  // Address state
2624
5530
  const [address, setAddress] = require$$0.useState(null);
2625
5531
  // WebSocket data state
@@ -2716,10 +5622,16 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
2716
5622
  });
2717
5623
  }
2718
5624
  }, [isConnected, address, sendMessage]);
5625
+ // Handle address changes for Hyperliquid service
5626
+ require$$0.useEffect(() => {
5627
+ hyperliquidService.updateUserAddress(address);
5628
+ }, [address, hyperliquidService]);
2719
5629
  const contextValue = require$$0.useMemo(() => ({
2720
5630
  // Existing clients
2721
5631
  client,
2722
5632
  migrationSDK,
5633
+ // Enhanced services
5634
+ hyperliquidService,
2723
5635
  // Address management
2724
5636
  address,
2725
5637
  setAddress,
@@ -2729,7 +5641,7 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
2729
5641
  // WebSocket data
2730
5642
  data,
2731
5643
  lastError,
2732
- }), [client, migrationSDK, address, readyState, isConnected, data, lastError]);
5644
+ }), [client, migrationSDK, hyperliquidService, address, readyState, isConnected, data, lastError]);
2733
5645
  return (jsxRuntimeExports.jsx(PearHyperliquidContext.Provider, { value: contextValue, children: children }));
2734
5646
  };
2735
5647
  /**
@@ -2752,6 +5664,16 @@ const useMigrationSDK = () => {
2752
5664
  }
2753
5665
  return context.migrationSDK;
2754
5666
  };
5667
+ /**
5668
+ * Hook to use Hyperliquid service from context
5669
+ */
5670
+ const useHyperliquidService = () => {
5671
+ const context = require$$0.useContext(PearHyperliquidContext);
5672
+ if (!context) {
5673
+ throw new Error('useHyperliquidService must be used within a PearHyperliquidProvider');
5674
+ }
5675
+ return context.hyperliquidService;
5676
+ };
2755
5677
 
2756
5678
  /**
2757
5679
  * Hook to manage address (login/logout functionality)
@@ -2780,14 +5702,74 @@ const useTradeHistories = () => {
2780
5702
  return context.data.tradeHistories;
2781
5703
  };
2782
5704
  /**
2783
- * Hook to access open positions
5705
+ * Hook to access open positions with enhanced real-time synchronization
2784
5706
  */
2785
5707
  const useOpenPositions = () => {
2786
5708
  const context = require$$0.useContext(PearHyperliquidContext);
5709
+ const hyperliquidService = useHyperliquidService();
5710
+ const [enhancedPositions, setEnhancedPositions] = require$$0.useState([]);
5711
+ const [isLoading, setIsLoading] = require$$0.useState(false);
5712
+ const [lastSyncTime, setLastSyncTime] = require$$0.useState(null);
2787
5713
  if (!context) {
2788
5714
  throw new Error('useOpenPositions must be used within a PearHyperliquidProvider');
2789
5715
  }
2790
- return context.data.openPositions;
5716
+ // Get base positions from WebSocket
5717
+ const wsPositions = context.data.openPositions;
5718
+ // Enhance positions with real-time Hyperliquid data
5719
+ const syncPositions = require$$0.useCallback(async () => {
5720
+ if (!wsPositions || wsPositions.length === 0) {
5721
+ setEnhancedPositions([]);
5722
+ return;
5723
+ }
5724
+ setIsLoading(true);
5725
+ try {
5726
+ // Enhanced positions with real-time market prices from Hyperliquid
5727
+ const enhancedPositionsData = wsPositions.map(wsPos => {
5728
+ // Calculate updated position values using current market prices
5729
+ const enhancedLongAssets = wsPos.longAssets.map(asset => ({
5730
+ ...asset,
5731
+ positionValue: asset.platformSize * hyperliquidService.getMarketPrice(asset.coin),
5732
+ }));
5733
+ const enhancedShortAssets = wsPos.shortAssets.map(asset => ({
5734
+ ...asset,
5735
+ positionValue: asset.platformSize * hyperliquidService.getMarketPrice(asset.coin),
5736
+ }));
5737
+ // Calculate updated position value and mark ratio
5738
+ const totalPositionValue = enhancedLongAssets.reduce((sum, asset) => sum + asset.positionValue, 0) +
5739
+ enhancedShortAssets.reduce((sum, asset) => sum + asset.positionValue, 0);
5740
+ return {
5741
+ ...wsPos,
5742
+ longAssets: enhancedLongAssets,
5743
+ shortAssets: enhancedShortAssets,
5744
+ positionValue: totalPositionValue,
5745
+ // Add timestamp for when we enhanced with Hyperliquid data
5746
+ lastSyncAt: new Date().toISOString(),
5747
+ };
5748
+ });
5749
+ setEnhancedPositions(enhancedPositionsData);
5750
+ setLastSyncTime(new Date());
5751
+ }
5752
+ catch (error) {
5753
+ console.error('Failed to enhance positions with Hyperliquid data:', error);
5754
+ // Fall back to WebSocket data if enhancement fails
5755
+ setEnhancedPositions(wsPositions || []);
5756
+ }
5757
+ finally {
5758
+ setIsLoading(false);
5759
+ }
5760
+ }, [wsPositions, hyperliquidService]);
5761
+ // Sync positions whenever WebSocket data changes
5762
+ require$$0.useEffect(() => {
5763
+ syncPositions();
5764
+ }, [syncPositions]);
5765
+ // Real-time updates are handled automatically through webData2 subscription
5766
+ return {
5767
+ positions: enhancedPositions, // Returns OpenPositionDto[] - fully backward compatible
5768
+ isLoading,
5769
+ lastSyncTime,
5770
+ rawWsPositions: wsPositions, // Expose raw WebSocket data for debugging
5771
+ resync: syncPositions // Manual resync function
5772
+ };
2791
5773
  };
2792
5774
  /**
2793
5775
  * Hook to access open orders
@@ -2800,22 +5782,94 @@ const useOpenOrders = () => {
2800
5782
  return context.data.openOrders;
2801
5783
  };
2802
5784
  /**
2803
- * Hook to access account summary
5785
+ * Hook to access account summary with enhanced real-time data from Hyperliquid
2804
5786
  */
2805
5787
  const useAccountSummary = () => {
2806
5788
  const context = require$$0.useContext(PearHyperliquidContext);
5789
+ const hyperliquidService = useHyperliquidService();
5790
+ const [enhancedSummary, setEnhancedSummary] = require$$0.useState(null);
5791
+ const [isLoading, setIsLoading] = require$$0.useState(false);
5792
+ const [lastSyncTime, setLastSyncTime] = require$$0.useState(null);
2807
5793
  if (!context) {
2808
5794
  throw new Error('useAccountSummary must be used within a PearHyperliquidProvider');
2809
5795
  }
2810
- return context.data.accountSummary;
5796
+ // Get base summary from WebSocket (your backend data)
5797
+ const wsSummary = context.data.accountSummary;
5798
+ // Enhance account summary with fresh Hyperliquid data
5799
+ const syncAccountSummary = require$$0.useCallback(async () => {
5800
+ var _a, _b, _c, _d, _e, _f, _g, _h;
5801
+ if (!context.address || !wsSummary) {
5802
+ setEnhancedSummary(wsSummary);
5803
+ return;
5804
+ }
5805
+ setIsLoading(true);
5806
+ try {
5807
+ // Get fresh data from Hyperliquid (like your backend does)
5808
+ const hlAccountSummary = await hyperliquidService.getAccountSummary(context.address);
5809
+ if (hlAccountSummary) {
5810
+ // Enhance your backend data with fresh Hyperliquid data
5811
+ const enhancedSummaryData = {
5812
+ balanceSummary: {
5813
+ // Use fresh Hyperliquid data for real-time accuracy
5814
+ crossMaintenanceMarginUsed: hlAccountSummary.crossMaintenanceMarginUsed || wsSummary.balanceSummary.crossMaintenanceMarginUsed,
5815
+ crossMarginSummary: {
5816
+ accountValue: ((_a = hlAccountSummary.crossMarginSummary) === null || _a === void 0 ? void 0 : _a.accountValue) || wsSummary.balanceSummary.crossMarginSummary.accountValue,
5817
+ totalMarginUsed: ((_b = hlAccountSummary.crossMarginSummary) === null || _b === void 0 ? void 0 : _b.totalMarginUsed) || wsSummary.balanceSummary.crossMarginSummary.totalMarginUsed,
5818
+ totalNtlPos: ((_c = hlAccountSummary.crossMarginSummary) === null || _c === void 0 ? void 0 : _c.totalNtlPos) || wsSummary.balanceSummary.crossMarginSummary.totalNtlPos,
5819
+ totalRawUsd: ((_d = hlAccountSummary.crossMarginSummary) === null || _d === void 0 ? void 0 : _d.totalRawUsd) || wsSummary.balanceSummary.crossMarginSummary.totalRawUsd
5820
+ },
5821
+ marginSummary: {
5822
+ accountValue: ((_e = hlAccountSummary.marginSummary) === null || _e === void 0 ? void 0 : _e.accountValue) || wsSummary.balanceSummary.marginSummary.accountValue,
5823
+ totalMarginUsed: ((_f = hlAccountSummary.marginSummary) === null || _f === void 0 ? void 0 : _f.totalMarginUsed) || wsSummary.balanceSummary.marginSummary.totalMarginUsed,
5824
+ totalNtlPos: ((_g = hlAccountSummary.marginSummary) === null || _g === void 0 ? void 0 : _g.totalNtlPos) || wsSummary.balanceSummary.marginSummary.totalNtlPos,
5825
+ totalRawUsd: ((_h = hlAccountSummary.marginSummary) === null || _h === void 0 ? void 0 : _h.totalRawUsd) || wsSummary.balanceSummary.marginSummary.totalRawUsd
5826
+ },
5827
+ time: Date.now(), // Current timestamp
5828
+ // Keep your backend's calculated withdrawable (includes order deductions)
5829
+ withdrawable: wsSummary.balanceSummary.withdrawable
5830
+ },
5831
+ // Keep your backend's agent wallet data
5832
+ agentWallet: wsSummary.agentWallet
5833
+ };
5834
+ setEnhancedSummary(enhancedSummaryData);
5835
+ }
5836
+ else {
5837
+ // Fallback to WebSocket data if Hyperliquid fails
5838
+ setEnhancedSummary(wsSummary);
5839
+ }
5840
+ setLastSyncTime(new Date());
5841
+ }
5842
+ catch (error) {
5843
+ console.error('Failed to enhance account summary with Hyperliquid:', error);
5844
+ // Fall back to WebSocket data if enhancement fails
5845
+ setEnhancedSummary(wsSummary);
5846
+ }
5847
+ finally {
5848
+ setIsLoading(false);
5849
+ }
5850
+ }, [context.address, wsSummary, hyperliquidService]);
5851
+ // Sync account summary whenever WebSocket data changes
5852
+ require$$0.useEffect(() => {
5853
+ syncAccountSummary();
5854
+ }, [syncAccountSummary]);
5855
+ // Real-time updates are handled automatically through webData2 subscription
5856
+ return {
5857
+ summary: enhancedSummary, // Returns AccountSummaryResponseDto - fully backward compatible
5858
+ isLoading,
5859
+ lastSyncTime,
5860
+ rawWsSummary: wsSummary, // Expose raw WebSocket data for debugging
5861
+ resync: syncAccountSummary // Manual resync function
5862
+ };
2811
5863
  };
2812
5864
 
5865
+ exports.HyperliquidService = HyperliquidService;
2813
5866
  exports.PearHyperliquidClient = PearHyperliquidClient;
2814
5867
  exports.PearHyperliquidProvider = PearHyperliquidProvider;
2815
5868
  exports.PearMigrationSDK = PearMigrationSDK;
2816
5869
  exports.default = PearHyperliquidClient;
2817
5870
  exports.useAccountSummary = useAccountSummary;
2818
5871
  exports.useAddress = useAddress;
5872
+ exports.useHyperliquidService = useHyperliquidService;
2819
5873
  exports.useMigrationSDK = useMigrationSDK;
2820
5874
  exports.useOpenOrders = useOpenOrders;
2821
5875
  exports.useOpenPositions = useOpenPositions;