@lifi/perps-sdk-provider-hyperliquid 1.5.4 → 1.5.6

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.
Files changed (55) hide show
  1. package/dist/cjs/services/getFills.d.ts.map +1 -1
  2. package/dist/cjs/services/getFills.js +13 -6
  3. package/dist/cjs/services/getFills.js.map +1 -1
  4. package/dist/cjs/services/getOrders.js +1 -1
  5. package/dist/cjs/services/getOrders.js.map +1 -1
  6. package/dist/cjs/types/order.d.ts +1 -1
  7. package/dist/cjs/types/order.d.ts.map +1 -1
  8. package/dist/cjs/utils/decodeFastAssetCtxs.d.ts.map +1 -1
  9. package/dist/cjs/utils/decodeFastAssetCtxs.js +11 -6
  10. package/dist/cjs/utils/decodeFastAssetCtxs.js.map +1 -1
  11. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +7 -4
  12. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  13. package/dist/cjs/websocket/HyperliquidWsProvider.js +77 -62
  14. package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
  15. package/dist/cjs/websocket/decodeChain.d.ts +11 -0
  16. package/dist/cjs/websocket/decodeChain.d.ts.map +1 -0
  17. package/dist/cjs/websocket/decodeChain.js +37 -0
  18. package/dist/cjs/websocket/decodeChain.js.map +1 -0
  19. package/dist/esm/services/getFills.d.ts +4 -4
  20. package/dist/esm/services/getFills.d.ts.map +1 -1
  21. package/dist/esm/services/getFills.js +19 -9
  22. package/dist/esm/services/getFills.js.map +1 -1
  23. package/dist/esm/services/getOrders.js +1 -1
  24. package/dist/esm/services/getOrders.js.map +1 -1
  25. package/dist/esm/types/order.d.ts +1 -1
  26. package/dist/esm/types/order.d.ts.map +1 -1
  27. package/dist/esm/utils/decodeFastAssetCtxs.d.ts +1 -0
  28. package/dist/esm/utils/decodeFastAssetCtxs.d.ts.map +1 -1
  29. package/dist/esm/utils/decodeFastAssetCtxs.js +14 -6
  30. package/dist/esm/utils/decodeFastAssetCtxs.js.map +1 -1
  31. package/dist/esm/websocket/HyperliquidWsProvider.d.ts +20 -7
  32. package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  33. package/dist/esm/websocket/HyperliquidWsProvider.js +100 -71
  34. package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
  35. package/dist/esm/websocket/decodeChain.d.ts +30 -0
  36. package/dist/esm/websocket/decodeChain.d.ts.map +1 -0
  37. package/dist/esm/websocket/decodeChain.js +44 -0
  38. package/dist/esm/websocket/decodeChain.js.map +1 -0
  39. package/dist/types/services/getFills.d.ts +4 -4
  40. package/dist/types/services/getFills.d.ts.map +1 -1
  41. package/dist/types/types/order.d.ts +1 -1
  42. package/dist/types/types/order.d.ts.map +1 -1
  43. package/dist/types/utils/decodeFastAssetCtxs.d.ts +1 -0
  44. package/dist/types/utils/decodeFastAssetCtxs.d.ts.map +1 -1
  45. package/dist/types/websocket/HyperliquidWsProvider.d.ts +20 -7
  46. package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  47. package/dist/types/websocket/decodeChain.d.ts +30 -0
  48. package/dist/types/websocket/decodeChain.d.ts.map +1 -0
  49. package/package.json +3 -3
  50. package/src/services/getFills.ts +37 -11
  51. package/src/services/getOrders.ts +1 -1
  52. package/src/types/order.ts +1 -1
  53. package/src/utils/decodeFastAssetCtxs.ts +14 -6
  54. package/src/websocket/HyperliquidWsProvider.ts +136 -93
  55. package/src/websocket/decodeChain.ts +54 -0
@@ -10,7 +10,7 @@ import type { HyperliquidContext } from '../context.js';
10
10
  export interface GetFillsParams {
11
11
  address: Address;
12
12
  limit?: number;
13
- /** `tid` of the oldest fill to return (returned items have `tid < cursor`). */
13
+ /** Opaque pagination cursor from a previous page's `pagination.cursor`. */
14
14
  cursor?: string;
15
15
  /** Inclusive lower bound in ms-since-epoch — switches to the `userFillsByTime` endpoint. */
16
16
  startTime?: number;
@@ -24,9 +24,9 @@ export interface GetFillsParams {
24
24
  * list supplies the display fields; only the fills endpoint is read direct
25
25
  * from HL.
26
26
  *
27
- * Pagination is cursor-based on the fill's `tid`: results with
28
- * `tid < cursor` are kept and the last-page's tail `id` is returned as the
29
- * next cursor.
27
+ * The response is sorted (time desc, `tid` as tiebreaker) before pagination —
28
+ * see {@link compareFillsDesc}. The cursor encodes the last returned fill's
29
+ * `(time, tid)`; the next page keeps fills that sort strictly after it.
30
30
  * @throws {PerpsError} On Hyperliquid REST error, network, or parsing failures.
31
31
  * @public
32
32
  */
@@ -1 +1 @@
1
- {"version":3,"file":"getFills.d.ts","sourceRoot":"","sources":["../../../src/services/getFills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAMnC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAKvD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ,GACnB,oBAAoB,kBAAkB,EACtC,QAAQ,cAAc,EACtB,UAAU,iBAAiB,KAC1B,OAAO,CAAC,aAAa,CAiDvB,CAAA"}
1
+ {"version":3,"file":"getFills.d.ts","sourceRoot":"","sources":["../../../src/services/getFills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAMnC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AASvD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAoBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ,GACnB,oBAAoB,kBAAkB,EACtC,QAAQ,cAAc,EACtB,UAAU,iBAAiB,KAC1B,OAAO,CAAC,aAAa,CAqDvB,CAAA"}
@@ -2,6 +2,15 @@ import { getMarketRegistry } from '@lifi/perps-sdk';
2
2
  import { DEFAULT_HISTORY_LIMIT, MAX_HISTORY_LIMIT, PROVIDER_KEY, } from '../constants.js';
3
3
  import { mapFill } from '../utils/index.js';
4
4
  import { hlInfoOptions, infoRequest } from '../utils/infoClient.js';
5
+ // HL's docs specify neither newest-first ordering nor monotonic `tid` for
6
+ // `userFills`/`userFillsByTime`, so pagination can't rely on upstream order —
7
+ // it must impose its own (time desc, tid desc as tiebreaker for same-time fills).
8
+ const compareFillsDesc = (a, b) => b.time - a.time || b.tid - a.tid;
9
+ const encodeCursor = (fill) => `${fill.time}:${fill.tid}`;
10
+ const decodeCursor = (cursor) => {
11
+ const [time, tid] = cursor.split(':').map(Number);
12
+ return { time, tid };
13
+ };
5
14
  /**
6
15
  * Fetch the user's fills history. When `startTime` or `endTime` is provided,
7
16
  * Hyperliquid's `userFillsByTime` endpoint is used; otherwise the unbounded
@@ -9,9 +18,9 @@ import { hlInfoOptions, infoRequest } from '../utils/infoClient.js';
9
18
  * list supplies the display fields; only the fills endpoint is read direct
10
19
  * from HL.
11
20
  *
12
- * Pagination is cursor-based on the fill's `tid`: results with
13
- * `tid < cursor` are kept and the last-page's tail `id` is returned as the
14
- * next cursor.
21
+ * The response is sorted (time desc, `tid` as tiebreaker) before pagination —
22
+ * see {@link compareFillsDesc}. The cursor encodes the last returned fill's
23
+ * `(time, tid)`; the next page keeps fills that sort strictly after it.
15
24
  * @throws {PerpsError} On Hyperliquid REST error, network, or parsing failures.
16
25
  * @public
17
26
  */
@@ -29,20 +38,21 @@ export const getFills = async ({ client, apiUrl }, params, options) => {
29
38
  ...(params.endTime !== undefined ? { endTime: params.endTime } : {}),
30
39
  }, infoOpts)
31
40
  : await infoRequest(apiUrl, { type: 'userFills', user: params.address }, infoOpts);
41
+ const sorted = [...allFills].sort(compareFillsDesc);
32
42
  const filtered = params.cursor === undefined
33
- ? allFills
34
- : allFills.filter((f) => f.tid < Number.parseInt(params.cursor, 10));
43
+ ? sorted
44
+ : sorted.filter((f) => compareFillsDesc(f, decodeCursor(params.cursor)) > 0);
35
45
  const hasMore = filtered.length > limit;
36
- const items = filtered
37
- .slice(0, limit)
38
- .map((f) => mapFill(f, registry.require(f.coin)));
46
+ const page = filtered.slice(0, limit);
47
+ const items = page.map((f) => mapFill(f, registry.require(f.coin)));
48
+ const lastPageFill = page[page.length - 1];
39
49
  return {
40
50
  provider: PROVIDER_KEY,
41
51
  items,
42
52
  pagination: {
43
53
  limit,
44
54
  hasMore,
45
- cursor: items.length > 0 ? items[items.length - 1].id : undefined,
55
+ cursor: lastPageFill ? encodeCursor(lastPageFill) : undefined,
46
56
  },
47
57
  };
48
58
  };
@@ -1 +1 @@
1
- {"version":3,"file":"getFills.js","sourceRoot":"","sources":["../../../src/services/getFills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA0B,MAAM,iBAAiB,CAAA;AAG3E,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,GACb,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAkBnE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAC3B,EAAE,MAAM,EAAE,MAAM,EAAsB,EACtC,MAAsB,EACtB,OAA2B,EACH,EAAE;IAC1B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACxD,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IACrB,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,MAAM,CAAC,KAAK,IAAI,qBAAqB,EACrC,iBAAiB,CAClB,CAAA;IAED,MAAM,SAAS,GACb,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,CAAA;IAEhE,MAAM,QAAQ,GAAG,SAAS;QACxB,CAAC,CAAC,MAAM,WAAW,CACf,MAAM,EACN;YACE,IAAI,EAAE,iBAAiB;YACvB,IAAI,EAAE,MAAM,CAAC,OAAO;YACpB,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,CAAC;YAChC,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrE,EACD,QAAQ,CACT;QACH,CAAC,CAAC,MAAM,WAAW,CACf,MAAM,EACN,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,EAC3C,QAAQ,CACT,CAAA;IAEL,MAAM,QAAQ,GACZ,MAAM,CAAC,MAAM,KAAK,SAAS;QACzB,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAO,EAAE,EAAE,CAAC,CAAC,CAAA;IAEzE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAA;IACvC,MAAM,KAAK,GAAG,QAAQ;SACnB,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAEnD,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,KAAK;QACL,UAAU,EAAE;YACV,KAAK;YACL,OAAO;YACP,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;SAClE;KACF,CAAA;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"getFills.js","sourceRoot":"","sources":["../../../src/services/getFills.ts"],"names":[],"mappings":"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"}
@@ -24,7 +24,7 @@ export const getOrders = async ({ client, apiUrl }, params, options) => {
24
24
  const raw = ordersResults.flat();
25
25
  const childOids = new Set();
26
26
  for (const o of raw) {
27
- for (const child of o.children) {
27
+ for (const child of o.children ?? []) {
28
28
  childOids.add(child.oid);
29
29
  }
30
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"getOrders.js","sourceRoot":"","sources":["../../../src/services/getOrders.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"getOrders.js","sourceRoot":"","sources":["../../../src/services/getOrders.ts"],"names":[],"mappings":"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"}
@@ -13,7 +13,7 @@ export type HlFrontendOpenOrder = {
13
13
  isPositionTpsl: boolean;
14
14
  triggerCondition: string;
15
15
  triggerPx: string;
16
- children: HlFrontendOpenOrder[];
16
+ children?: HlFrontendOpenOrder[];
17
17
  tif: string | null;
18
18
  cloid: string | null;
19
19
  };
@@ -1 +1 @@
1
- {"version":3,"file":"order.d.ts","sourceRoot":"","sources":["../../../src/types/order.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,cAAc,EAAE,OAAO,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,mBAAmB,EAAE,CAAA;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB,CAAA;AAED,cAAc;AACd,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,EAAE,CAAA;AAExD,cAAc;AACd,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE;QACL,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,EAAE,EAAE,MAAM,CAAA;QACV,OAAO,EAAE,MAAM,CAAA;QACf,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,OAAO,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;QAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KACzB,CAAA;IACD,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,cAAc;AACd,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;CACrB,CAAA;AAED,cAAc;AACd,MAAM,MAAM,qBAAqB,GAC7B,kBAAkB,GAClB;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAAA"}
1
+ {"version":3,"file":"order.d.ts","sourceRoot":"","sources":["../../../src/types/order.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,cAAc,EAAE,OAAO,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAA;IAChC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB,CAAA;AAED,cAAc;AACd,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,EAAE,CAAA;AAExD,cAAc;AACd,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE;QACL,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,EAAE,EAAE,MAAM,CAAA;QACV,OAAO,EAAE,MAAM,CAAA;QACf,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,OAAO,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;QAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KACzB,CAAA;IACD,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,cAAc;AACd,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;CACrB,CAAA;AAED,cAAc;AACd,MAAM,MAAM,qBAAqB,GAC7B,kBAAkB,GAClB;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import type { HlWsFastAssetCtx } from '../types/index.js';
2
+ /** Decode a base64 + raw-DEFLATE (RFC 1951) payload into parsed JSON. */
2
3
  export declare function decodeCompressedJson<T>(base64: string): Promise<T>;
3
4
  /**
4
5
  * Decode a Hyperliquid `fastAssetCtxs` frame. HL sends the payload as a
@@ -1 +1 @@
1
- {"version":3,"file":"decodeFastAssetCtxs.d.ts","sourceRoot":"","sources":["../../../src/utils/decodeFastAssetCtxs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAOxE;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAE3C"}
1
+ {"version":3,"file":"decodeFastAssetCtxs.d.ts","sourceRoot":"","sources":["../../../src/utils/decodeFastAssetCtxs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,yEAAyE;AACzE,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAcxE;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAE3C"}
@@ -1,10 +1,18 @@
1
+ /** Decode a base64 + raw-DEFLATE (RFC 1951) payload into parsed JSON. */
1
2
  export async function decodeCompressedJson(base64) {
2
- const bytes = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
3
- const stream = new Blob([bytes])
4
- .stream()
5
- .pipeThrough(new DecompressionStream('deflate-raw'));
6
- const text = await new Response(stream).text();
7
- return JSON.parse(text);
3
+ const binary = atob(base64);
4
+ const bytes = new Uint8Array(binary.length);
5
+ for (let i = 0; i < binary.length; i++) {
6
+ bytes[i] = binary.charCodeAt(i);
7
+ }
8
+ const stream = new DecompressionStream('deflate-raw');
9
+ const text = new Response(stream.readable).text();
10
+ const writer = stream.writable.getWriter();
11
+ // Write-side failures (bad DEFLATE) also error the readable and reject
12
+ // `text`; detach these rejections to avoid unhandled duplicates.
13
+ writer.write(bytes).catch(() => undefined);
14
+ writer.close().catch(() => undefined);
15
+ return JSON.parse(await text);
8
16
  }
9
17
  /**
10
18
  * Decode a Hyperliquid `fastAssetCtxs` frame. HL sends the payload as a
@@ -1 +1 @@
1
- {"version":3,"file":"decodeFastAssetCtxs.js","sourceRoot":"","sources":["../../../src/utils/decodeFastAssetCtxs.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAI,MAAc;IAC1D,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IACnE,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;SAC7B,MAAM,EAAE;SACR,WAAW,CAAC,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAC,CAAA;IACtD,MAAM,IAAI,GAAG,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAA;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAA;AAC9B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc;IAEd,OAAO,oBAAoB,CAAmC,MAAM,CAAC,CAAA;AACvE,CAAC"}
1
+ {"version":3,"file":"decodeFastAssetCtxs.js","sourceRoot":"","sources":["../../../src/utils/decodeFastAssetCtxs.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAI,MAAc;IAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IACjC,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAA;IACrD,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAA;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAA;IAC1C,uEAAuE;IACvE,iEAAiE;IACjE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IAC1C,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAM,CAAA;AACpC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc;IAEd,OAAO,oBAAoB,CAAmC,MAAM,CAAC,CAAA;AACvE,CAAC"}
@@ -30,13 +30,15 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
30
30
  private readonly registry;
31
31
  private perpCtxBySubDex;
32
32
  private spotCtxByMarketId;
33
+ private marketsContextByMarketId;
33
34
  private orderbookKeysByMarketId;
34
35
  private latestOrderbookByMarketId;
35
36
  private fastCtxByMarketId;
36
- private fastDecodeChain;
37
- private pacDecodeChain;
38
- private sacDecodeChain;
39
- private orderbookDecodeChain;
37
+ private readonly reportDecodeFailure;
38
+ private readonly fastDecodeChain;
39
+ private readonly pacDecodeChain;
40
+ private readonly sacDecodeChain;
41
+ private readonly orderbookDecodeChain;
40
42
  constructor(wsUrl: string, providerKey: string, client?: PerpsSDKClient);
41
43
  subscribeQuote(params: ProviderGetQuoteParams, onQuote: QuoteListener): Promise<() => void>;
42
44
  protected openChannel(sub: Subscription): Promise<() => void>;
@@ -65,6 +67,7 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
65
67
  protected handleMessage(raw: string): void;
66
68
  private handleAllDexsAssetCtxs;
67
69
  private handlePac;
70
+ /** Merge perp asset contexts in place; returns the marketIds this frame touched. */
68
71
  private mergePerpAssetCtxEntries;
69
72
  private handleSac;
70
73
  private spotMarketIdBySacKey;
@@ -72,14 +75,24 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
72
75
  * Decode a `fastAssetCtxs` frame (base64 + raw-DEFLATE) and merge its changed
73
76
  * coins into the per-market fast-context store. Frames are incremental, so a
74
77
  * field absent from this frame keeps its prior value. Decodes are chained to
75
- * preserve arrival order across the async boundary.
78
+ * preserve arrival order across the async boundary; a backlog coalesces to
79
+ * its newest frame (see the chain's mode).
76
80
  */
77
81
  private handleFastAssetCtxs;
78
82
  /**
79
- * Build the all-markets context map from perp + spot asset contexts, with mid
80
- * + mark overlaid from `fastAssetCtxs`.
83
+ * Emit the all-markets context map, re-mapping only the markets the incoming
84
+ * frame touched. Each emission is a fresh snapshot object that carries
85
+ * untouched entries over by reference, so a listener holding an earlier
86
+ * snapshot never observes later-frame mutation.
81
87
  */
82
88
  private emitMarketsContext;
89
+ /**
90
+ * Context for one market from the cached feeds: spot asset context when it
91
+ * maps, else perp asset context with mid + mark overlaid from
92
+ * `fastAssetCtxs`, else the fast feed alone — each price standing in for the
93
+ * other where it carries only one of mid/mark.
94
+ */
95
+ private computeMarketContext;
83
96
  private handleActiveAssetCtx;
84
97
  private handleActiveSpotAssetCtx;
85
98
  /** Latest mid per `Market.id` across asset-context and fast feeds. */
@@ -1 +1 @@
1
- {"version":3,"file":"HyperliquidWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/HyperliquidWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAGlB,cAAc,EACd,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,mBAAmB,CAAA;AA6C1B;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,QAC5B,iBAEgD,CAAA;AAEtD;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CAAC,MAAM,CAAC;IAC/D,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,eAAe,CAAsD;IAC7E,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,uBAAuB,CAAiC;IAChE,OAAO,CAAC,yBAAyB,CAAuC;IAKxE,OAAO,CAAC,iBAAiB,CAAuC;IAGhE,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,oBAAoB,CAAmC;gBAEnD,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc;IASjE,cAAc,CAClB,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;cAkBN,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IA+DnE;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,iBAAiB;IAmBzB;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;IAWnC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,gBAAgB;cAcL,OAAO,IAAI,IAAI;IAalC,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAM9C,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;IA0B1C,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,WAAW;IA6CnB,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM;IA8EnC,OAAO,CAAC,sBAAsB;IAK9B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,oBAAoB;IAe5B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAgB3B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,wBAAwB;IAWhC,sEAAsE;IACtE,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,oBAAoB;IA2B5B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,kBAAkB;IA0D1B,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,+BAA+B;IAkBvC,OAAO,CAAC,eAAe;CAaxB"}
1
+ {"version":3,"file":"HyperliquidWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/HyperliquidWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAGlB,cAAc,EACd,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,mBAAmB,CAAA;AA8C1B;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,QAC5B,iBAEgD,CAAA;AAEtD;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CAAC,MAAM,CAAC;IAC/D,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,eAAe,CAAsD;IAC7E,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,wBAAwB,CAAoC;IACpE,OAAO,CAAC,uBAAuB,CAAiC;IAChE,OAAO,CAAC,yBAAyB,CAAuC;IAKxE,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CACW;IAM/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG/B;IACD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAG9B;IACD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAG9B;IACD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAGpC;gBAEW,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc;IASjE,cAAc,CAClB,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;cAkBN,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAgEnE;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,iBAAiB;IAmBzB;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;IAWnC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,gBAAgB;cAcL,OAAO,IAAI,IAAI;IAclC,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAM9C,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;IA0B1C,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,WAAW;IA6CnB,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM;IA8EnC,OAAO,CAAC,sBAAsB;IAM9B,OAAO,CAAC,SAAS;IAUjB,oFAAoF;IACpF,OAAO,CAAC,wBAAwB;IAyBhC,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,oBAAoB;IAe5B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IA6B5B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,wBAAwB;IAWhC,sEAAsE;IACtE,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,oBAAoB;IAmC5B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,kBAAkB;IAyD1B,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,+BAA+B;IAkBvC,OAAO,CAAC,eAAe;CAaxB"}
@@ -3,6 +3,7 @@ import { OrderSide, OrderType, } from '@lifi/perps-types';
3
3
  import Big from 'big.js';
4
4
  import { HYPERLIQUID_FEE_TIER_FALLBACK, SPOT_MARKET_ID } from '../constants.js';
5
5
  import { decodeCompressedJson, decodeFastAssetCtxs, isOpenAssetPosition, isTriggerOrder, mapFill, mapMarketContext, mapOrderStatus, mapOrderType, mapPosition, priceStepToAggregation, spotAssetFromToken, spotBalance, spotPriceById, } from '../utils/index.js';
6
+ import { DecodeChain } from './decodeChain.js';
6
7
  /** HL's compact `l2` snapshot carries 20 levels per side. */
7
8
  const HL_L2_BOOK_MAX_LEVELS_PER_SIDE = 20;
8
9
  /**
@@ -35,6 +36,7 @@ export class HyperliquidWsProvider extends WsProviderBase {
35
36
  registry;
36
37
  perpCtxBySubDex = new Map();
37
38
  spotCtxByMarketId = {};
39
+ marketsContextByMarketId = {};
38
40
  orderbookKeysByMarketId = new Map();
39
41
  latestOrderbookByMarketId = new Map();
40
42
  // Latest mid/mark per `Market.id` from the high-frequency `fastAssetCtxs`
@@ -42,12 +44,16 @@ export class HyperliquidWsProvider extends WsProviderBase {
42
44
  // frames carry only changed coins — and overlaid onto asset contexts that
43
45
  // carry oracle/funding/OI/metadata.
44
46
  fastCtxByMarketId = {};
45
- // `fastAssetCtxs` payloads are base64 + raw-DEFLATE; decode is async, so
46
- // chain decodes to apply incremental frames in arrival order.
47
- fastDecodeChain = Promise.resolve();
48
- pacDecodeChain = Promise.resolve();
49
- sacDecodeChain = Promise.resolve();
50
- orderbookDecodeChain = Promise.resolve();
47
+ reportDecodeFailure = (error) => wsLog.handlerFailure(this.providerKey, error);
48
+ // Compressed payloads (base64 + raw-DEFLATE) decode async, so each channel
49
+ // chains decodes to apply frames in arrival order. Only the fast feed
50
+ // coalesces a stall backlog to its newest frame: a coin's dropped tick is
51
+ // refreshed by its next one. pac/sac field-merges and l2 deltas depend on
52
+ // every frame, so they must not coalesce.
53
+ fastDecodeChain = new DecodeChain('latest', this.reportDecodeFailure);
54
+ pacDecodeChain = new DecodeChain('every', this.reportDecodeFailure);
55
+ sacDecodeChain = new DecodeChain('every', this.reportDecodeFailure);
56
+ orderbookDecodeChain = new DecodeChain('every', this.reportDecodeFailure);
51
57
  constructor(wsUrl, providerKey, client) {
52
58
  super(new ReconnectingWebSocket(wsUrl, { pingPayload: '{"method":"ping"}' }), providerKey);
53
59
  this.client = client;
@@ -84,6 +90,7 @@ export class HyperliquidWsProvider extends WsProviderBase {
84
90
  this.perpCtxBySubDex.clear();
85
91
  this.spotCtxByMarketId = {};
86
92
  this.fastCtxByMarketId = {};
93
+ this.marketsContextByMarketId = {};
87
94
  };
88
95
  }
89
96
  // All other channels: single WS subscription per key
@@ -179,12 +186,13 @@ export class HyperliquidWsProvider extends WsProviderBase {
179
186
  this.perpCtxBySubDex.clear();
180
187
  this.spotCtxByMarketId = {};
181
188
  this.fastCtxByMarketId = {};
189
+ this.marketsContextByMarketId = {};
182
190
  this.orderbookKeysByMarketId.clear();
183
191
  this.latestOrderbookByMarketId.clear();
184
- this.fastDecodeChain = Promise.resolve();
185
- this.pacDecodeChain = Promise.resolve();
186
- this.sacDecodeChain = Promise.resolve();
187
- this.orderbookDecodeChain = Promise.resolve();
192
+ this.fastDecodeChain.reset();
193
+ this.pacDecodeChain.reset();
194
+ this.sacDecodeChain.reset();
195
+ this.orderbookDecodeChain.reset();
188
196
  this.orderUpdatesKey = undefined;
189
197
  }
190
198
  sendSubscribe(payload) {
@@ -341,41 +349,41 @@ export class HyperliquidWsProvider extends WsProviderBase {
341
349
  }
342
350
  }
343
351
  handleAllDexsAssetCtxs(data) {
344
- this.mergePerpAssetCtxEntries(allDexsAssetCtxEntries(data));
345
- this.emitMarketsContext();
352
+ this.emitMarketsContext(this.mergePerpAssetCtxEntries(allDexsAssetCtxEntries(data)));
346
353
  }
347
354
  handlePac(base64) {
348
- this.pacDecodeChain = this.pacDecodeChain
349
- .then(async () => {
350
- this.mergePerpAssetCtxEntries(await decodeCompressedJson(base64));
351
- this.emitMarketsContext();
352
- })
353
- .catch((error) => wsLog.handlerFailure(this.providerKey, error));
355
+ this.pacDecodeChain.push(async () => {
356
+ this.emitMarketsContext(this.mergePerpAssetCtxEntries(await decodeCompressedJson(base64)));
357
+ });
354
358
  }
359
+ /** Merge perp asset contexts in place; returns the marketIds this frame touched. */
355
360
  mergePerpAssetCtxEntries(entries) {
361
+ const touched = new Set();
356
362
  for (const [dex, ctxs] of entries) {
357
- const previous = this.perpCtxBySubDex.get(dex || 'default');
358
- const byMarketId = {
359
- ...(previous ?? {}),
360
- };
363
+ let byMarketId = this.perpCtxBySubDex.get(dex || 'default');
364
+ if (byMarketId === undefined) {
365
+ byMarketId = {};
366
+ this.perpCtxBySubDex.set(dex || 'default', byMarketId);
367
+ }
361
368
  for (const ctx of ctxs) {
362
369
  const marketId = ctx.coin;
363
370
  if (marketId === undefined) {
364
371
  continue;
365
372
  }
366
- const merged = mergePerpAssetCtx(previous?.[marketId], marketId, ctx);
373
+ const merged = mergePerpAssetCtx(byMarketId[marketId], marketId, ctx);
367
374
  if (merged !== undefined) {
368
375
  byMarketId[marketId] = merged;
376
+ touched.add(marketId);
369
377
  }
370
378
  }
371
- this.perpCtxBySubDex.set(dex || 'default', byMarketId);
372
379
  }
380
+ return touched;
373
381
  }
374
382
  handleSac(base64) {
375
- this.sacDecodeChain = this.sacDecodeChain
376
- .then(async () => {
383
+ this.sacDecodeChain.push(async () => {
377
384
  const spotMarketIdBySacKey = this.spotMarketIdBySacKey();
378
385
  const ctxs = await decodeCompressedJson(base64);
386
+ const touched = new Set();
379
387
  for (const [sacKey, ctx] of Object.entries(ctxs)) {
380
388
  const marketId = spotMarketIdBySacKey.get(sacKey);
381
389
  if (marketId === undefined) {
@@ -385,10 +393,10 @@ export class HyperliquidWsProvider extends WsProviderBase {
385
393
  ...this.spotCtxByMarketId[marketId],
386
394
  ...ctx,
387
395
  };
396
+ touched.add(marketId);
388
397
  }
389
- this.emitMarketsContext();
390
- })
391
- .catch((error) => wsLog.handlerFailure(this.providerKey, error));
398
+ this.emitMarketsContext(touched);
399
+ });
392
400
  }
393
401
  spotMarketIdBySacKey() {
394
402
  const map = new Map();
@@ -405,11 +413,11 @@ export class HyperliquidWsProvider extends WsProviderBase {
405
413
  * Decode a `fastAssetCtxs` frame (base64 + raw-DEFLATE) and merge its changed
406
414
  * coins into the per-market fast-context store. Frames are incremental, so a
407
415
  * field absent from this frame keeps its prior value. Decodes are chained to
408
- * preserve arrival order across the async boundary.
416
+ * preserve arrival order across the async boundary; a backlog coalesces to
417
+ * its newest frame (see the chain's mode).
409
418
  */
410
419
  handleFastAssetCtxs(base64) {
411
- this.fastDecodeChain = this.fastDecodeChain
412
- .then(async () => {
420
+ this.fastDecodeChain.push(async () => {
413
421
  const ctxs = await decodeFastAssetCtxs(base64);
414
422
  for (const [marketId, ctx] of Object.entries(ctxs)) {
415
423
  const prev = this.fastCtxByMarketId[marketId];
@@ -418,48 +426,65 @@ export class HyperliquidWsProvider extends WsProviderBase {
418
426
  midPx: 'midPx' in ctx ? ctx.midPx : prev?.midPx,
419
427
  };
420
428
  }
421
- this.emitMarketsContext();
422
- })
423
- .catch((error) => wsLog.handlerFailure(this.providerKey, error));
429
+ this.emitMarketsContext(Object.keys(ctxs));
430
+ });
424
431
  }
425
432
  /**
426
- * Build the all-markets context map from perp + spot asset contexts, with mid
427
- * + mark overlaid from `fastAssetCtxs`.
433
+ * Emit the all-markets context map, re-mapping only the markets the incoming
434
+ * frame touched. Each emission is a fresh snapshot object that carries
435
+ * untouched entries over by reference, so a listener holding an earlier
436
+ * snapshot never observes later-frame mutation.
428
437
  */
429
- emitMarketsContext() {
430
- const data = {};
431
- for (const byMarketId of this.perpCtxBySubDex.values()) {
432
- for (const [marketId, ctx] of Object.entries(byMarketId)) {
433
- const base = mapMarketContext(marketId, ctx);
434
- const fast = this.fastCtxByMarketId[marketId];
435
- data[marketId] = {
436
- ...base,
437
- midPrice: fast?.midPx != null ? fast.midPx : base.midPrice,
438
- markPrice: fast?.markPx != null ? fast.markPx : base.markPrice,
439
- };
440
- }
441
- }
442
- for (const [marketId, ctx] of Object.entries(this.spotCtxByMarketId)) {
443
- const context = mapSpotMarketContext(marketId, ctx, this.fastCtxByMarketId[marketId]);
438
+ emitMarketsContext(touchedMarketIds) {
439
+ const data = {
440
+ ...this.marketsContextByMarketId,
441
+ };
442
+ for (const marketId of touchedMarketIds) {
443
+ const context = this.computeMarketContext(marketId);
444
444
  if (context === undefined) {
445
- continue;
446
- }
447
- data[marketId] = context;
448
- }
449
- for (const [marketId, fast] of Object.entries(this.fastCtxByMarketId)) {
450
- if (data[marketId] !== undefined) {
451
- continue;
445
+ delete data[marketId];
452
446
  }
453
- // No asset-context frame for this market yet — each price stands in for
454
- // the other where the fast feed carries only one of mid/mark.
455
- const midPrice = fast.midPx ?? fast.markPx;
456
- const markPrice = fast.markPx ?? fast.midPx;
457
- if (midPrice != null && markPrice != null) {
458
- data[marketId] = { marketId, midPrice, markPrice };
447
+ else {
448
+ data[marketId] = context;
459
449
  }
460
450
  }
451
+ this.marketsContextByMarketId = data;
461
452
  this.emit('marketsContext', { channel: 'marketsContext', data });
462
453
  }
454
+ /**
455
+ * Context for one market from the cached feeds: spot asset context when it
456
+ * maps, else perp asset context with mid + mark overlaid from
457
+ * `fastAssetCtxs`, else the fast feed alone — each price standing in for the
458
+ * other where it carries only one of mid/mark.
459
+ */
460
+ computeMarketContext(marketId) {
461
+ const fast = this.fastCtxByMarketId[marketId];
462
+ const spotCtx = this.spotCtxByMarketId[marketId];
463
+ if (spotCtx !== undefined) {
464
+ const context = mapSpotMarketContext(marketId, spotCtx, fast);
465
+ if (context !== undefined) {
466
+ return context;
467
+ }
468
+ }
469
+ let perpCtx;
470
+ for (const byMarketId of this.perpCtxBySubDex.values()) {
471
+ perpCtx = byMarketId[marketId] ?? perpCtx;
472
+ }
473
+ if (perpCtx !== undefined) {
474
+ const base = mapMarketContext(marketId, perpCtx);
475
+ return {
476
+ ...base,
477
+ midPrice: fast?.midPx != null ? fast.midPx : base.midPrice,
478
+ markPrice: fast?.markPx != null ? fast.markPx : base.markPrice,
479
+ };
480
+ }
481
+ const midPrice = fast?.midPx ?? fast?.markPx;
482
+ const markPrice = fast?.markPx ?? fast?.midPx;
483
+ if (midPrice != null && markPrice != null) {
484
+ return { marketId, midPrice, markPrice };
485
+ }
486
+ return undefined;
487
+ }
463
488
  handleActiveAssetCtx(data, raw) {
464
489
  const ctx = activePerpAssetCtx(data.coin, data.ctx);
465
490
  if (ctx === undefined) {
@@ -543,17 +568,22 @@ export class HyperliquidWsProvider extends WsProviderBase {
543
568
  return;
544
569
  }
545
570
  const compressed = data.c;
546
- this.orderbookDecodeChain = this.orderbookDecodeChain
547
- .then(async () => {
571
+ this.orderbookDecodeChain.push(async () => {
548
572
  this.handleCompactL2Delta(await decodeCompressedJson(compressed));
549
- })
550
- .catch((error) => wsLog.handlerFailure(this.providerKey, error));
573
+ });
551
574
  }
552
575
  handleCompactL2Delta(delta) {
553
576
  const previous = this.latestOrderbookByMarketId.get(delta.c);
554
577
  if (previous === undefined) {
555
578
  return;
556
579
  }
580
+ // Compact deltas decode asynchronously via `orderbookDecodeChain`, so one
581
+ // can resolve after a newer frame (sync snapshot/update, or a later delta)
582
+ // has already been applied. A delta no newer than the maintained book is
583
+ // stale; applying it would overwrite fresher state with older levels.
584
+ if (delta.t <= previous.timestamp) {
585
+ return;
586
+ }
557
587
  const book = {
558
588
  provider: this.providerKey,
559
589
  marketId: delta.c,
@@ -621,8 +651,7 @@ export class HyperliquidWsProvider extends WsProviderBase {
621
651
  continue;
622
652
  }
623
653
  const type = mapOrderType(o.orderType);
624
- // A miss warns once and schedules a cooldown-gated registry refetch
625
- // (the id may have listed after the snapshot); skip just this item.
654
+ // Unknown market id (absent from the synced snapshot); skip just this item.
626
655
  const market = this.registry?.get(o.coin);
627
656
  if (!market) {
628
657
  continue;