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