@pear-protocol/hyperliquid-sdk 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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
  /**
@@ -94,7 +94,9 @@ class PearHyperliquidClient {
94
94
  */
95
95
  class PearMigrationSDK {
96
96
  constructor(client) {
97
- this.isSyncRunning = false;
97
+ this.isTradeHistorySyncRunning = false;
98
+ this.isOpenPositionsSyncRunning = false;
99
+ this.isOpenOrdersSyncRunning = false;
98
100
  this.client = client;
99
101
  }
100
102
  /**
@@ -103,16 +105,16 @@ class PearMigrationSDK {
103
105
  */
104
106
  async syncTradeHistory(payload) {
105
107
  // If sync is already running, return immediately
106
- if (this.isSyncRunning) {
108
+ if (this.isTradeHistorySyncRunning) {
107
109
  return null;
108
110
  }
109
111
  try {
110
- this.isSyncRunning = true;
112
+ this.isTradeHistorySyncRunning = true;
111
113
  const response = await this.client.syncTradeHistory(payload);
112
114
  return response;
113
115
  }
114
116
  finally {
115
- this.isSyncRunning = false;
117
+ this.isTradeHistorySyncRunning = false;
116
118
  }
117
119
  }
118
120
  /**
@@ -121,16 +123,16 @@ class PearMigrationSDK {
121
123
  */
122
124
  async syncOpenPositions(payload) {
123
125
  // If sync is already running, return immediately
124
- if (this.isSyncRunning) {
126
+ if (this.isOpenPositionsSyncRunning) {
125
127
  return null;
126
128
  }
127
129
  try {
128
- this.isSyncRunning = true;
130
+ this.isOpenPositionsSyncRunning = true;
129
131
  const response = await this.client.syncOpenPositions(payload);
130
132
  return response;
131
133
  }
132
134
  finally {
133
- this.isSyncRunning = false;
135
+ this.isOpenPositionsSyncRunning = false;
134
136
  }
135
137
  }
136
138
  /**
@@ -139,47 +141,2949 @@ class PearMigrationSDK {
139
141
  */
140
142
  async syncOpenOrders(payload) {
141
143
  // If sync is already running, return immediately
142
- if (this.isSyncRunning) {
144
+ if (this.isOpenOrdersSyncRunning) {
143
145
  return null;
144
146
  }
145
147
  try {
146
- this.isSyncRunning = true;
148
+ this.isOpenOrdersSyncRunning = true;
147
149
  const response = await this.client.syncOpenOrders(payload);
148
150
  return response;
149
151
  }
150
152
  finally {
151
- this.isSyncRunning = false;
153
+ this.isOpenOrdersSyncRunning = false;
152
154
  }
153
155
  }
154
156
  /**
155
- * Check if sync is currently running
157
+ * Check if any sync is currently running
156
158
  */
157
159
  isSyncInProgress() {
158
- return this.isSyncRunning;
160
+ return this.isTradeHistorySyncRunning || this.isOpenPositionsSyncRunning || this.isOpenOrdersSyncRunning;
161
+ }
162
+ /**
163
+ * Check if trade history sync is currently running
164
+ */
165
+ isTradeHistorySyncInProgress() {
166
+ return this.isTradeHistorySyncRunning;
167
+ }
168
+ /**
169
+ * Check if open positions sync is currently running
170
+ */
171
+ isOpenPositionsSyncInProgress() {
172
+ return this.isOpenPositionsSyncRunning;
173
+ }
174
+ /**
175
+ * Check if open orders sync is currently running
176
+ */
177
+ isOpenOrdersSyncInProgress() {
178
+ return this.isOpenOrdersSyncRunning;
159
179
  }
160
180
  /**
161
181
  * Get the underlying client instance
162
182
  */
163
- getClient() {
164
- return this.client;
183
+ getClient() {
184
+ return this.client;
185
+ }
186
+ /**
187
+ * Set authorization token on the client
188
+ */
189
+ setAuthToken(token) {
190
+ this.client.setAuthToken(token);
191
+ }
192
+ /**
193
+ * Set custom headers on the client
194
+ */
195
+ setHeaders(headers) {
196
+ this.client.setHeaders(headers);
197
+ }
198
+ /**
199
+ * Get base URL from client
200
+ */
201
+ getBaseUrl() {
202
+ return this.client.getBaseUrl();
203
+ }
204
+ }
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");
165
2361
  }
166
2362
  /**
167
- * Set authorization token on the client
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.
168
2365
  */
169
- setAuthToken(token) {
170
- this.client.setAuthToken(token);
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
+ }
171
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 {
172
2443
  /**
173
- * Set custom headers on the client
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.
174
2447
  */
175
- setHeaders(headers) {
176
- this.client.setHeaders(headers);
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";
177
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;
178
2523
  /**
179
- * Get base URL from client
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
180
2527
  */
181
- getBaseUrl() {
182
- return this.client.getBaseUrl();
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;
183
3087
  }
184
3088
  }
185
3089
 
@@ -2613,9 +5517,11 @@ const PearHyperliquidContext = createContext(undefined);
2613
5517
  /**
2614
5518
  * React Provider for PearHyperliquidClient
2615
5519
  */
2616
- 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, }) => {
2617
5521
  const client = useMemo(() => new PearHyperliquidClient(config), [config]);
2618
5522
  const migrationSDK = useMemo(() => new PearMigrationSDK(client), [client]);
5523
+ // Initialize Hyperliquid service
5524
+ const hyperliquidService = useMemo(() => new HyperliquidService(hyperliquidWsUrl), [hyperliquidWsUrl]);
2619
5525
  // Address state
2620
5526
  const [address, setAddress] = useState(null);
2621
5527
  // WebSocket data state
@@ -2712,10 +5618,16 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
2712
5618
  });
2713
5619
  }
2714
5620
  }, [isConnected, address, sendMessage]);
5621
+ // Handle address changes for Hyperliquid service
5622
+ useEffect(() => {
5623
+ hyperliquidService.updateUserAddress(address);
5624
+ }, [address, hyperliquidService]);
2715
5625
  const contextValue = useMemo(() => ({
2716
5626
  // Existing clients
2717
5627
  client,
2718
5628
  migrationSDK,
5629
+ // Enhanced services
5630
+ hyperliquidService,
2719
5631
  // Address management
2720
5632
  address,
2721
5633
  setAddress,
@@ -2725,7 +5637,7 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
2725
5637
  // WebSocket data
2726
5638
  data,
2727
5639
  lastError,
2728
- }), [client, migrationSDK, address, readyState, isConnected, data, lastError]);
5640
+ }), [client, migrationSDK, hyperliquidService, address, readyState, isConnected, data, lastError]);
2729
5641
  return (jsxRuntimeExports.jsx(PearHyperliquidContext.Provider, { value: contextValue, children: children }));
2730
5642
  };
2731
5643
  /**
@@ -2748,6 +5660,16 @@ const useMigrationSDK = () => {
2748
5660
  }
2749
5661
  return context.migrationSDK;
2750
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
+ };
2751
5673
 
2752
5674
  /**
2753
5675
  * Hook to manage address (login/logout functionality)
@@ -2776,14 +5698,74 @@ const useTradeHistories = () => {
2776
5698
  return context.data.tradeHistories;
2777
5699
  };
2778
5700
  /**
2779
- * Hook to access open positions
5701
+ * Hook to access open positions with enhanced real-time synchronization
2780
5702
  */
2781
5703
  const useOpenPositions = () => {
2782
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);
2783
5709
  if (!context) {
2784
5710
  throw new Error('useOpenPositions must be used within a PearHyperliquidProvider');
2785
5711
  }
2786
- 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
+ };
2787
5769
  };
2788
5770
  /**
2789
5771
  * Hook to access open orders
@@ -2796,15 +5778,85 @@ const useOpenOrders = () => {
2796
5778
  return context.data.openOrders;
2797
5779
  };
2798
5780
  /**
2799
- * Hook to access account summary
5781
+ * Hook to access account summary with enhanced real-time data from Hyperliquid
2800
5782
  */
2801
5783
  const useAccountSummary = () => {
2802
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);
2803
5789
  if (!context) {
2804
5790
  throw new Error('useAccountSummary must be used within a PearHyperliquidProvider');
2805
5791
  }
2806
- 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
+ };
2807
5859
  };
2808
5860
 
2809
- 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 };
2810
5862
  //# sourceMappingURL=index.esm.js.map