@lifi/perps-sdk-provider-hyperliquid 20.0.0 → 21.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +45 -0
  2. package/dist/cjs/HyperliquidProvider.d.ts.map +1 -1
  3. package/dist/cjs/HyperliquidProvider.js +2 -2
  4. package/dist/cjs/HyperliquidProvider.js.map +1 -1
  5. package/dist/cjs/services/getAccount.d.ts.map +1 -1
  6. package/dist/cjs/services/getAccount.js +5 -7
  7. package/dist/cjs/services/getAccount.js.map +1 -1
  8. package/dist/cjs/services/getActivity.d.ts.map +1 -1
  9. package/dist/cjs/services/getActivity.js +68 -44
  10. package/dist/cjs/services/getActivity.js.map +1 -1
  11. package/dist/cjs/services/getFills.d.ts.map +1 -1
  12. package/dist/cjs/services/getFills.js +30 -38
  13. package/dist/cjs/services/getFills.js.map +1 -1
  14. package/dist/cjs/services/getWithdrawableBalances.js +1 -1
  15. package/dist/cjs/services/getWithdrawableBalances.js.map +1 -1
  16. package/dist/cjs/services/historyPagination.d.ts +22 -0
  17. package/dist/cjs/services/historyPagination.d.ts.map +1 -0
  18. package/dist/cjs/services/historyPagination.js +125 -0
  19. package/dist/cjs/services/historyPagination.js.map +1 -0
  20. package/dist/cjs/utils/index.d.ts +1 -1
  21. package/dist/cjs/utils/index.d.ts.map +1 -1
  22. package/dist/cjs/utils/index.js +3 -3
  23. package/dist/cjs/utils/index.js.map +1 -1
  24. package/dist/cjs/utils/liquidation.js +1 -1
  25. package/dist/cjs/utils/liquidation.js.map +1 -1
  26. package/dist/cjs/utils/orderFormatting.d.ts +3 -2
  27. package/dist/cjs/utils/orderFormatting.d.ts.map +1 -1
  28. package/dist/cjs/utils/orderFormatting.js +4 -4
  29. package/dist/cjs/utils/orderFormatting.js.map +1 -1
  30. package/dist/cjs/utils/spotBalance.d.ts.map +1 -1
  31. package/dist/cjs/utils/spotBalance.js +2 -2
  32. package/dist/cjs/utils/spotBalance.js.map +1 -1
  33. package/dist/cjs/utils/withdrawableBalances.d.ts +1 -1
  34. package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -1
  35. package/dist/cjs/utils/withdrawableBalances.js +7 -4
  36. package/dist/cjs/utils/withdrawableBalances.js.map +1 -1
  37. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +6 -0
  38. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  39. package/dist/cjs/websocket/HyperliquidWsProvider.js +135 -37
  40. package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
  41. package/dist/esm/HyperliquidProvider.d.ts.map +1 -1
  42. package/dist/esm/HyperliquidProvider.js +3 -3
  43. package/dist/esm/HyperliquidProvider.js.map +1 -1
  44. package/dist/esm/services/getAccount.d.ts.map +1 -1
  45. package/dist/esm/services/getAccount.js +6 -5
  46. package/dist/esm/services/getAccount.js.map +1 -1
  47. package/dist/esm/services/getActivity.d.ts +3 -13
  48. package/dist/esm/services/getActivity.d.ts.map +1 -1
  49. package/dist/esm/services/getActivity.js +74 -64
  50. package/dist/esm/services/getActivity.js.map +1 -1
  51. package/dist/esm/services/getFills.d.ts +2 -14
  52. package/dist/esm/services/getFills.d.ts.map +1 -1
  53. package/dist/esm/services/getFills.js +32 -58
  54. package/dist/esm/services/getFills.js.map +1 -1
  55. package/dist/esm/services/getWithdrawableBalances.js +1 -1
  56. package/dist/esm/services/getWithdrawableBalances.js.map +1 -1
  57. package/dist/esm/services/historyPagination.d.ts +22 -0
  58. package/dist/esm/services/historyPagination.d.ts.map +1 -0
  59. package/dist/esm/services/historyPagination.js +121 -0
  60. package/dist/esm/services/historyPagination.js.map +1 -0
  61. package/dist/esm/utils/index.d.ts +1 -1
  62. package/dist/esm/utils/index.d.ts.map +1 -1
  63. package/dist/esm/utils/index.js +1 -1
  64. package/dist/esm/utils/index.js.map +1 -1
  65. package/dist/esm/utils/liquidation.js +2 -2
  66. package/dist/esm/utils/liquidation.js.map +1 -1
  67. package/dist/esm/utils/orderFormatting.d.ts +14 -12
  68. package/dist/esm/utils/orderFormatting.d.ts.map +1 -1
  69. package/dist/esm/utils/orderFormatting.js +14 -14
  70. package/dist/esm/utils/orderFormatting.js.map +1 -1
  71. package/dist/esm/utils/spotBalance.d.ts.map +1 -1
  72. package/dist/esm/utils/spotBalance.js +3 -3
  73. package/dist/esm/utils/spotBalance.js.map +1 -1
  74. package/dist/esm/utils/withdrawableBalances.d.ts +1 -1
  75. package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -1
  76. package/dist/esm/utils/withdrawableBalances.js +7 -4
  77. package/dist/esm/utils/withdrawableBalances.js.map +1 -1
  78. package/dist/esm/websocket/HyperliquidWsProvider.d.ts +6 -0
  79. package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  80. package/dist/esm/websocket/HyperliquidWsProvider.js +138 -50
  81. package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
  82. package/dist/types/HyperliquidProvider.d.ts.map +1 -1
  83. package/dist/types/services/getAccount.d.ts.map +1 -1
  84. package/dist/types/services/getActivity.d.ts +3 -13
  85. package/dist/types/services/getActivity.d.ts.map +1 -1
  86. package/dist/types/services/getFills.d.ts +2 -14
  87. package/dist/types/services/getFills.d.ts.map +1 -1
  88. package/dist/types/services/historyPagination.d.ts +22 -0
  89. package/dist/types/services/historyPagination.d.ts.map +1 -0
  90. package/dist/types/utils/index.d.ts +1 -1
  91. package/dist/types/utils/index.d.ts.map +1 -1
  92. package/dist/types/utils/orderFormatting.d.ts +14 -12
  93. package/dist/types/utils/orderFormatting.d.ts.map +1 -1
  94. package/dist/types/utils/spotBalance.d.ts.map +1 -1
  95. package/dist/types/utils/withdrawableBalances.d.ts +1 -1
  96. package/dist/types/utils/withdrawableBalances.d.ts.map +1 -1
  97. package/dist/types/websocket/HyperliquidWsProvider.d.ts +6 -0
  98. package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  99. package/package.json +3 -3
  100. package/src/HyperliquidProvider.ts +6 -5
  101. package/src/services/getAccount.ts +18 -18
  102. package/src/services/getActivity.ts +133 -104
  103. package/src/services/getFills.ts +42 -95
  104. package/src/services/getWithdrawableBalances.ts +1 -1
  105. package/src/services/historyPagination.ts +169 -0
  106. package/src/utils/index.ts +2 -2
  107. package/src/utils/liquidation.ts +2 -2
  108. package/src/utils/orderFormatting.ts +20 -16
  109. package/src/utils/spotBalance.ts +5 -3
  110. package/src/utils/withdrawableBalances.ts +12 -7
  111. package/src/websocket/HyperliquidWsProvider.ts +151 -63
@@ -0,0 +1,22 @@
1
+ type HistoryKey = string | number;
2
+ export declare const getHistoryLimit: (limit?: number) => number;
3
+ export declare function historyPage<T>(params: {
4
+ startTime?: number;
5
+ endTime?: number;
6
+ cursor?: string;
7
+ }, limit: number, fetchWindow: (startTime: number, endTime: number, snapshotEnd: number) => Promise<{
8
+ items: T[];
9
+ saturated: boolean;
10
+ }>, identify: (item: T) => {
11
+ time: number;
12
+ key: HistoryKey;
13
+ }, signal?: AbortSignal): Promise<{
14
+ items: T[];
15
+ pagination: {
16
+ limit: number;
17
+ hasMore: boolean;
18
+ cursor?: string;
19
+ };
20
+ }>;
21
+ export {};
22
+ //# sourceMappingURL=historyPagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyPagination.d.ts","sourceRoot":"","sources":["../../../src/services/historyPagination.ts"],"names":[],"mappings":"AAIA,KAAK,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA;AAiBjC,eAAO,MAAM,eAAe,GAAI,cAA6B,KAAG,MAQ/D,CAAA;AAmCD,wBAAsB,WAAW,CAAC,CAAC,EACjC,MAAM,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,CACX,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,EAChD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,UAAU,CAAA;CAAE,EACxD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IACT,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACjE,CAAC,CA2FD"}
@@ -12,7 +12,7 @@ export { mapMarketContext } from './mapMarketContext.js';
12
12
  export { type HlOrderLike, mapOrder, mapOrderStatus, mapOrderType, } from './mapOrder.js';
13
13
  export { isOpenAssetPosition, mapPosition } from './mapPosition.js';
14
14
  export { coinAsset, perpsDexNames } from './marketDisplay.js';
15
- export { formatOrderPrice, formatOrderSize, getMaxPriceDecimals, } from './orderFormatting.js';
15
+ export { getMaxPriceDecimals, snapOrderPrice, snapOrderSize, } from './orderFormatting.js';
16
16
  export { priceStepToAggregation } from './priceStepToAggregation.js';
17
17
  export { spotAssetFromToken, spotBalance, spotPriceById, } from './spotBalance.js';
18
18
  export { partitionSpotBalances, type SpotPartition } from './spotCollateral.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EACL,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,mBAAmB,GACpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EACL,KAAK,WAAW,EAChB,QAAQ,EACR,cAAc,EACd,YAAY,GACb,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,aAAa,GACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,qBAAqB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EACL,KAAK,gBAAgB,EACrB,WAAW,EACX,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EACL,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,mBAAmB,GACpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EACL,KAAK,WAAW,EAChB,QAAQ,EACR,cAAc,EACd,YAAY,GACb,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,aAAa,GACd,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,aAAa,GACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,qBAAqB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EACL,KAAK,gBAAgB,EACrB,WAAW,EACX,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAA"}
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Hyperliquid order size and price formatting for exchange submission.
2
+ * Hyperliquid order size and price snapping for exchange submission.
3
3
  *
4
- * These encode Hyperliquid-specific order submission rules. Getting size/price
5
- * formatting wrong causes rejected orders.
4
+ * These encode Hyperliquid-specific order submission rules. Snapping a size or
5
+ * a price onto the wrong grid causes rejected orders.
6
6
  *
7
7
  * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
8
8
  */
9
+ import type { DecimalString } from '@lifi/perps-types';
9
10
  /**
10
11
  * Derive the maximum number of price decimal places for a given asset.
11
12
  *
@@ -16,20 +17,20 @@
16
17
  */
17
18
  export declare function getMaxPriceDecimals(szDecimals: number, market?: string): number;
18
19
  /**
19
- * Format a size value for order submission.
20
+ * Snap a size onto the asset's lot grid for order submission.
20
21
  *
21
22
  * Per Hyperliquid docs (tick-and-lot-size):
22
23
  * - Size must be rounded to the asset's szDecimals
23
24
  * - Trailing zeroes must be removed for signing
24
25
  *
25
- * @param size - The size value to format
26
+ * @param size - The size to snap, as a decimal string
26
27
  * @param szDecimals - Number of decimal places allowed for this asset (from meta)
27
- * @returns Size as a string with correct precision, no trailing zeros
28
+ * @returns Size as a decimal string with correct precision, no trailing zeros
28
29
  * @public
29
30
  */
30
- export declare function formatOrderSize(size: number, szDecimals: number): string;
31
+ export declare function snapOrderSize(size: DecimalString, szDecimals: number): DecimalString;
31
32
  /**
32
- * Format a price value for order submission.
33
+ * Snap a price onto the asset's tick grid for order submission.
33
34
  *
34
35
  * Per Hyperliquid docs (tick-and-lot-size):
35
36
  * - Maximum 5 significant figures
@@ -38,13 +39,14 @@ export declare function formatOrderSize(size: number, szDecimals: number): strin
38
39
  * - Trailing zeroes must be removed for signing
39
40
  *
40
41
  * Rounding is half-up (away from zero at exact halfway) on the true decimal
41
- * value, not on the binary float — (1.005).toFixed(2) would give '1.00'.
42
+ * value, which is why the price arrives as a string: `(1.005).toFixed(2)`
43
+ * would give `'1.00'`.
42
44
  *
43
- * @param price - The price value to format
45
+ * @param price - The price to snap, as a decimal string
44
46
  * @param szDecimals - The asset's szDecimals (affects max price decimals)
45
47
  * @param market - Optional market type (e.g. 'spot'). Defaults to perps rules.
46
- * @returns Price as a string with correct precision, no trailing zeros
48
+ * @returns Price as a decimal string with correct precision, no trailing zeros
47
49
  * @public
48
50
  */
49
- export declare function formatOrderPrice(price: number, szDecimals: number, market?: string): string;
51
+ export declare function snapOrderPrice(price: DecimalString, szDecimals: number, market?: string): DecimalString;
50
52
  //# sourceMappingURL=orderFormatting.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"orderFormatting.d.ts","sourceRoot":"","sources":["../../../src/utils/orderFormatting.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAER;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAOxE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAYR"}
1
+ {"version":3,"file":"orderFormatting.d.ts","sourceRoot":"","sources":["../../../src/utils/orderFormatting.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AActD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAER;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,EACnB,UAAU,EAAE,MAAM,GACjB,aAAa,CAMf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,aAAa,CAYf"}
@@ -1 +1 @@
1
- {"version":3,"file":"spotBalance.d.ts","sourceRoot":"","sources":["../../../src/utils/spotBalance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAItD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,SAAS,SAAS,MAAM,EAAE,EAC1B,iBAAiB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KAC3C,GAAG,CAAC,MAAM,EAAE,MAAM,CAapB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,GAAG,aAAa,KAAG,KAIpD,CAAA;AAEF,qIAAqI;AACrI,eAAO,MAAM,WAAW,GACtB,OAAO,KAAK,EACZ,OAAO,MAAM,EACb,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,OAUF,CAAA"}
1
+ {"version":3,"file":"spotBalance.d.ts","sourceRoot":"","sources":["../../../src/utils/spotBalance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAItD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,SAAS,SAAS,MAAM,EAAE,EAC1B,iBAAiB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KAC3C,GAAG,CAAC,MAAM,EAAE,MAAM,CAapB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,GAAG,aAAa,KAAG,KAIpD,CAAA;AAEF,qIAAqI;AACrI,eAAO,MAAM,WAAW,GACtB,OAAO,KAAK,EACZ,OAAO,MAAM,EACb,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,OAYF,CAAA"}
@@ -1,4 +1,4 @@
1
- import type { ProviderWithdrawableBalance } from '@lifi/perps-sdk';
1
+ import { type ProviderWithdrawableBalance } from '@lifi/perps-sdk';
2
2
  import type { HlAbstractionMode, HlClearinghouseState, HlSpotClearinghouseState } from '../types/index.js';
3
3
  /**
4
4
  * Split a Hyperliquid account's venue figures into the routes a withdrawal
@@ -1 +1 @@
1
- {"version":3,"file":"withdrawableBalances.d.ts","sourceRoot":"","sources":["../../../src/utils/withdrawableBalances.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAA;AAClE,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,mBAAmB,CAAA;AAK1B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,+BAA+B,GAC1C,aAAa,iBAAiB,GAAG,IAAI,EACrC,OAAO,oBAAoB,EAC3B,WAAW,wBAAwB,EACnC,cAAc,MAAM,EACpB,gBAAgB,MAAM,KACrB,2BAA2B,EA4C7B,CAAA"}
1
+ {"version":3,"file":"withdrawableBalances.d.ts","sourceRoot":"","sources":["../../../src/utils/withdrawableBalances.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,mBAAmB,CAAA;AAK1B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,+BAA+B,GAC1C,aAAa,iBAAiB,GAAG,IAAI,EACrC,OAAO,oBAAoB,EAC3B,WAAW,wBAAwB,EACnC,cAAc,MAAM,EACpB,gBAAgB,MAAM,KACrB,2BAA2B,EA8C7B,CAAA"}
@@ -32,7 +32,12 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
32
32
  private readonly client;
33
33
  private readonly registry;
34
34
  private readonly abstractionByUser;
35
+ private readonly summaryUsers;
36
+ private readonly abstractionReadsByUser;
35
37
  private readonly spotRefs;
38
+ private spotWireEpoch;
39
+ private readonly latestSpotByUser;
40
+ private readonly revalueSpotBalances;
36
41
  private readonly unifiedSummaryByUser;
37
42
  private readonly latestPerpsByUser;
38
43
  private readonly heldSummaryByUser;
@@ -136,6 +141,7 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
136
141
  private fetchAbstractionMode;
137
142
  private handleActiveAssetData;
138
143
  private handleSpotState;
144
+ private emitSpotBalances;
139
145
  /** Read the venue buying power over REST when the spot frame omits it. */
140
146
  private fetchAvailableAfterMaintenance;
141
147
  }
@@ -1 +1 @@
1
- {"version":3,"file":"HyperliquidWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/HyperliquidWsProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HyperliquidWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/HyperliquidWsProvider.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/perps-sdk-provider-hyperliquid",
3
- "version": "20.0.0",
3
+ "version": "21.0.0",
4
4
  "description": "Hyperliquid provider plugin for @lifi/perps-sdk",
5
5
  "homepage": "https://github.com/lifinance/perps-sdk",
6
6
  "bugs": {
@@ -49,10 +49,10 @@
49
49
  "dependencies": {
50
50
  "big.js": "^7.0.1",
51
51
  "viem": "^2.55.18",
52
- "@lifi/perps-types": "^18.0.0"
52
+ "@lifi/perps-types": "^19.0.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "@lifi/perps-sdk": "^20.0.0"
55
+ "@lifi/perps-sdk": "^21.0.0"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public"
@@ -35,6 +35,7 @@ import {
35
35
  ActionType,
36
36
  type ActivitiesResponse,
37
37
  type AvailableToTrade,
38
+ type DecimalString,
38
39
  type FillsResponse,
39
40
  type Market,
40
41
  type MarketSettings,
@@ -80,7 +81,7 @@ import { hyperliquidSignActions } from './signers/signActions.js'
80
81
  import type { HlExtraAgents } from './types/index.js'
81
82
  import { hlInfoOptions, infoRequest } from './utils/infoClient.js'
82
83
  import { calculateLiquidationPrice } from './utils/liquidation.js'
83
- import { formatOrderPrice, formatOrderSize } from './utils/orderFormatting.js'
84
+ import { snapOrderPrice, snapOrderSize } from './utils/orderFormatting.js'
84
85
  import { positionRemovableMargin } from './utils/transferMargin.js'
85
86
 
86
87
  /**
@@ -465,15 +466,15 @@ export function hyperliquidProvider(
465
466
  positions: Position[]
466
467
  ): AccountSummary => getAccountSummary(account, positions),
467
468
 
468
- formatOrderPrice: (market: Market, price: number): string =>
469
- formatOrderPrice(
469
+ snapOrderPrice: (market: Market, price: DecimalString): DecimalString =>
470
+ snapOrderPrice(
470
471
  price,
471
472
  market.szDecimals,
472
473
  market.categoryId === SPOT_MARKET_ID ? 'spot' : undefined
473
474
  ),
474
475
 
475
- formatOrderSize: (market: Market, size: number): string =>
476
- formatOrderSize(size, market.szDecimals),
476
+ snapOrderSize: (market: Market, size: DecimalString): DecimalString =>
477
+ snapOrderSize(size, market.szDecimals),
477
478
 
478
479
  estimateLiquidationPrice: (
479
480
  market: PerpsMarket,
@@ -1,11 +1,10 @@
1
1
  import {
2
+ calculateTransferable,
2
3
  getMarketRegistry,
3
4
  getMarketsContext,
4
- maxOf,
5
- minOf,
6
5
  type ProviderGetAccountParams,
6
+ parseDecimal,
7
7
  type SDKRequestOptions,
8
- stringToFloat,
9
8
  toPerpsMarketDisplay,
10
9
  } from '@lifi/perps-sdk'
11
10
  import type {
@@ -16,7 +15,7 @@ import type {
16
15
  HyperliquidDexAccountState,
17
16
  Position,
18
17
  } from '@lifi/perps-types'
19
- import Big from 'big.js'
18
+ import type Big from 'big.js'
20
19
  import { PROVIDER_KEY } from '../constants.js'
21
20
  import type { HyperliquidContext } from '../context.js'
22
21
  import type {
@@ -83,13 +82,12 @@ const buildBalances = (
83
82
  const total = toWireBig(b.total, 'spotClearinghouseState.total')
84
83
  return {
85
84
  ...spotBalance(spotAssetFromToken(b), b.total, priceById),
86
- transferable: minOf(
87
- maxOf(
88
- total.minus(toWireBig(b.hold, 'spotClearinghouseState.hold')),
89
- new Big(0)
90
- ),
85
+ transferable: calculateTransferable(
91
86
  total
92
- ).toFixed(),
87
+ .minus(toWireBig(b.hold, 'spotClearinghouseState.hold'))
88
+ .toFixed(),
89
+ total.toFixed()
90
+ ),
93
91
  }
94
92
  }),
95
93
  quoteAssetIds
@@ -114,13 +112,13 @@ const buildBalances = (
114
112
  units: value.toFixed(),
115
113
  valueUsd: value.toFixed(),
116
114
  price: '1',
117
- transferable: minOf(
118
- maxOf(
119
- toWireBig(state.withdrawable, 'clearinghouseState.withdrawable'),
120
- new Big(0)
121
- ),
122
- value
123
- ).toFixed(),
115
+ transferable: calculateTransferable(
116
+ toWireBig(
117
+ state.withdrawable,
118
+ 'clearinghouseState.withdrawable'
119
+ ).toFixed(),
120
+ value.toFixed()
121
+ ),
124
122
  })
125
123
  }
126
124
  }
@@ -209,7 +207,9 @@ export const getAccount = async (
209
207
 
210
208
  const priceById = spotPriceById(
211
209
  markets,
212
- new Map(prices.map((p) => [p.marketId, stringToFloat(p.markPrice)]))
210
+ new Map(
211
+ prices.map((p) => [p.marketId, parseDecimal(p.markPrice) ?? Number.NaN])
212
+ )
213
213
  )
214
214
 
215
215
  const positions: Position[] = stateResults.flatMap((state) =>
@@ -2,6 +2,7 @@ import {
2
2
  type AssetRegistry,
3
3
  getAssetRegistry,
4
4
  getMarketRegistry,
5
+ PerpsError,
5
6
  type SDKRequestOptions,
6
7
  } from '@lifi/perps-sdk'
7
8
  import type {
@@ -10,13 +11,9 @@ import type {
10
11
  FundingActivity,
11
12
  MarketDisplay,
12
13
  } from '@lifi/perps-types'
13
- import { ActivityType } from '@lifi/perps-types'
14
+ import { ActivityType, PerpsErrorCode } from '@lifi/perps-types'
14
15
  import type { Address } from 'viem'
15
- import {
16
- DEFAULT_HISTORY_LIMIT,
17
- MAX_HISTORY_LIMIT,
18
- PROVIDER_KEY,
19
- } from '../constants.js'
16
+ import { PROVIDER_KEY } from '../constants.js'
20
17
  import type { HyperliquidContext } from '../context.js'
21
18
  import type {
22
19
  HlUserFills,
@@ -44,6 +41,7 @@ import {
44
41
  type InfoRequestOptions,
45
42
  infoRequest,
46
43
  } from '../utils/infoClient.js'
44
+ import { getHistoryLimit, historyPage } from './historyPagination.js'
47
45
 
48
46
  /**
49
47
  * Parameters for {@link getActivity}.
@@ -52,9 +50,9 @@ import {
52
50
  */
53
51
  export interface GetActivityParams {
54
52
  address: Address
55
- /** Maximum items returned; defaults to 50 and is capped at 200. */
53
+ /** Positive safe integer; defaults to 50 and is capped at 200. */
56
54
  limit?: number
57
- /** Millisecond timestamp cursor; rows strictly older than it are returned. */
55
+ /** Opaque cursor returned in the previous page's `pagination.cursor`. */
58
56
  cursor?: string
59
57
  /** Inclusive lower bound in milliseconds since epoch. */
60
58
  startTime?: number
@@ -78,23 +76,100 @@ const ASSET_BEARING_TYPES: ReadonlySet<ActivityType> = new Set([
78
76
  const needsMarkets = (typeFilter: ActivityType[] | undefined): boolean =>
79
77
  !typeFilter || typeFilter.some((t) => MARKET_BEARING_TYPES.has(t))
80
78
 
79
+ const fetchLiquidationHistory = async (
80
+ apiUrl: string,
81
+ user: Address,
82
+ startTime: number,
83
+ endTime: number,
84
+ resolveMarket: (coin: string) => MarketDisplay | undefined,
85
+ options?: InfoRequestOptions
86
+ ): Promise<ActivityItem[]> => {
87
+ const retained = new Map<number, HlUserFills[number]>()
88
+ while (startTime <= endTime) {
89
+ options?.signal?.throwIfAborted()
90
+ const fills = await infoRequest<HlUserFills>(
91
+ apiUrl,
92
+ { type: 'userFillsByTime', user, startTime, endTime },
93
+ options
94
+ )
95
+ options?.signal?.throwIfAborted()
96
+ let latest = startTime
97
+ for (const fill of fills) {
98
+ retained.set(fill.tid, fill)
99
+ latest = Math.max(latest, fill.time)
100
+ }
101
+ if (fills.length < 2000 || retained.size >= 10000) {
102
+ break
103
+ }
104
+ if (latest === startTime) {
105
+ throw new PerpsError(
106
+ PerpsErrorCode.ThirdPartyError,
107
+ 'Hyperliquid fills saturate a single millisecond; liquidation history cannot be paginated safely'
108
+ )
109
+ }
110
+ // Inclusive overlap retains all same-time fills at the venue page boundary.
111
+ startTime = latest
112
+ }
113
+ const queried = user.toLowerCase()
114
+ const fills = [...retained.values()].filter(
115
+ (fill) => fill.liquidation?.liquidatedUser.toLowerCase() === queried
116
+ )
117
+ if (fills.length === 0) {
118
+ return []
119
+ }
120
+ const hashes = new Set<string>()
121
+ let firstTime = Infinity
122
+ let lastTime = 0
123
+ for (const fill of fills) {
124
+ if (fill.hash !== undefined) {
125
+ hashes.add(fill.hash)
126
+ }
127
+ firstTime = Math.min(firstTime, fill.time)
128
+ lastTime = Math.max(lastTime, fill.time)
129
+ }
130
+ // Exclusions must cover the entire order, not the current SDK page's ledger window.
131
+ const ledger = await historyPage(
132
+ { startTime: firstTime, endTime: lastTime },
133
+ Number.MAX_SAFE_INTEGER,
134
+ async (startTime, endTime) => {
135
+ const updates = await infoRequest<HlUserNonFundingLedgerUpdates>(
136
+ apiUrl,
137
+ { type: 'userNonFundingLedgerUpdates', user, startTime, endTime },
138
+ options
139
+ )
140
+ return {
141
+ items: updates.filter(
142
+ (entry) => isLiquidationDelta(entry.delta) && hashes.has(entry.hash)
143
+ ),
144
+ saturated: updates.length >= 500,
145
+ }
146
+ },
147
+ (entry) => ({ time: entry.time, key: entry.hash }),
148
+ options?.signal
149
+ )
150
+ return mapLiquidationFills(
151
+ fills,
152
+ PROVIDER_KEY,
153
+ user,
154
+ resolveMarket,
155
+ new Set(ledger.items.map((entry) => entry.hash))
156
+ )
157
+ }
158
+
81
159
  const fetchActivityData = async (
82
160
  apiUrl: string,
83
161
  typeFilter: ActivityType[] | undefined,
84
- timeParams: { user: Address; startTime?: number; endTime?: number },
162
+ timeParams: { user: Address; startTime: number; endTime: number },
85
163
  assetRegistry: AssetRegistry,
86
164
  resolveMarket: (coin: string) => MarketDisplay | undefined,
165
+ liquidationHistory: Promise<ActivityItem[]> | undefined,
87
166
  options?: InfoRequestOptions
88
- ): Promise<ActivityItem[]> => {
167
+ ): Promise<{ items: ActivityItem[]; saturated: boolean }> => {
89
168
  const needLedger =
90
169
  !typeFilter || typeFilter.some((t) => t !== ActivityType.FUNDING)
91
170
  const needFunding = !typeFilter || typeFilter.includes(ActivityType.FUNDING)
92
- // A liquidation executed as a market order reaches the account as fills
93
- // with a `liquidation` field and never as a ledger `liquidation` delta.
94
- const needLiquidationFills =
95
- !typeFilter || typeFilter.includes(ActivityType.LIQUIDATION)
96
171
 
97
- const [ledgerUpdates, fundingUpdates, fills] = await Promise.all([
172
+ const [ledgerUpdates, fundingUpdates, liquidations] = await Promise.all([
98
173
  needLedger
99
174
  ? infoRequest<HlUserNonFundingLedgerUpdates>(
100
175
  apiUrl,
@@ -109,16 +184,11 @@ const fetchActivityData = async (
109
184
  options
110
185
  )
111
186
  : Promise.resolve([] as HlUserFunding),
112
- needLiquidationFills
113
- ? infoRequest<HlUserFills>(
114
- apiUrl,
115
- timeParams.startTime === undefined
116
- ? { type: 'userFills', user: timeParams.user }
117
- : { type: 'userFillsByTime', ...timeParams },
118
- options
119
- )
120
- : Promise.resolve([] as HlUserFills),
187
+ liquidationHistory,
121
188
  ])
189
+ if (ledgerUpdates.length >= 500 || fundingUpdates.length >= 500) {
190
+ return { items: [], saturated: true }
191
+ }
122
192
 
123
193
  const ledgerItems: ActivityItem[] = ledgerUpdates.flatMap(
124
194
  (entry): ActivityItem[] => {
@@ -156,46 +226,20 @@ const fetchActivityData = async (
156
226
  }
157
227
  )
158
228
 
159
- const ledgerLiquidationHashes = new Set(
160
- ledgerUpdates
161
- .filter((entry) => isLiquidationDelta(entry.delta))
162
- .map((entry) => entry.hash)
163
- )
164
- const liquidationItems = mapLiquidationFills(
165
- fills,
166
- PROVIDER_KEY,
167
- timeParams.user,
168
- resolveMarket,
169
- ledgerLiquidationHashes
170
- )
171
-
172
- const merged = [...ledgerItems, ...fundingItems, ...liquidationItems].sort(
173
- (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
174
- )
175
-
176
- if (!typeFilter) {
177
- return merged
178
- }
179
- const typeSet = new Set(typeFilter)
180
- return merged.filter((item) => typeSet.has(item.type))
229
+ const merged = [...ledgerItems, ...fundingItems, ...(liquidations ?? [])]
230
+ const items = typeFilter
231
+ ? merged.filter((item) => typeFilter.includes(item.type))
232
+ : merged
233
+ return { items, saturated: false }
181
234
  }
182
235
 
183
- /**
184
- * Fetch a chronological activity feed (deposits, withdrawals, transfers,
185
- * liquidations, funding) for `address`. Combines results from Hyperliquid's
186
- * `userNonFundingLedgerUpdates`, `userFunding`, and `userFills` endpoints,
187
- * sorted newest-first.
188
- *
189
- * Cursor-based pagination uses the ms-since-epoch timestamp of the last item
190
- * on the current page.
191
- * @throws {PerpsError} On Hyperliquid REST error, network, or parsing failures.
192
- * @public
193
- */
236
+ /** Fetch retained activity newest-first with opaque cursors across inclusive time ranges. */
194
237
  export const getActivity = async (
195
238
  { client, apiUrl }: HyperliquidContext,
196
239
  params: GetActivityParams,
197
240
  options?: SDKRequestOptions
198
241
  ): Promise<ActivitiesResponse> => {
242
+ const limit = getHistoryLimit(params.limit)
199
243
  const registry = getMarketRegistry(client, PROVIDER_KEY)
200
244
  // Only funding and liquidation rows carry a market, so a Ledger-only
201
245
  // request must not pull the market list.
@@ -211,53 +255,38 @@ export const getActivity = async (
211
255
  }
212
256
  const infoOpts = hlInfoOptions(client, options)
213
257
 
214
- const limit = Math.min(
215
- params.limit ?? DEFAULT_HISTORY_LIMIT,
216
- MAX_HISTORY_LIMIT
217
- )
218
- const timeParams = {
219
- user: params.address,
220
- ...(params.startTime !== undefined || params.endTime !== undefined
221
- ? { startTime: params.startTime ?? 0 }
222
- : {}),
223
- ...(params.endTime === undefined ? {} : { endTime: params.endTime }),
224
- }
225
-
226
- // `get`, not `require`: a coin the backend market list does not hold drops
227
- // only its own row instead of rejecting the whole feed. The registry warns
228
- // once per unresolved id. A delisted market still resolves, so its rows stay.
229
- const merged = await fetchActivityData(
230
- apiUrl,
231
- params.type,
232
- timeParams,
233
- assetRegistry,
234
- (coin) => registry.get(coin),
235
- infoOpts
236
- )
237
-
238
- // Drop boundary items so the next page does not return the cursor row twice.
239
- const filtered =
240
- params.cursor === undefined
241
- ? merged
242
- : merged.filter(
243
- (item) =>
244
- new Date(item.timestamp).getTime() <
245
- Number.parseInt(params.cursor!, 10)
258
+ const needLiquidationFills =
259
+ !params.type || params.type.includes(ActivityType.LIQUIDATION)
260
+ let liquidationHistory: Promise<ActivityItem[]> | undefined
261
+ const page = await historyPage(
262
+ params,
263
+ limit,
264
+ (startTime, endTime, snapshotEnd) => {
265
+ if (needLiquidationFills && liquidationHistory === undefined) {
266
+ liquidationHistory = fetchLiquidationHistory(
267
+ apiUrl,
268
+ params.address,
269
+ params.startTime ?? 0,
270
+ snapshotEnd,
271
+ (coin) => registry.get(coin),
272
+ infoOpts
246
273
  )
247
-
248
- const hasMore = filtered.length > limit
249
- const items = filtered.slice(0, limit)
250
-
251
- return {
252
- provider: PROVIDER_KEY,
253
- items,
254
- pagination: {
255
- limit,
256
- hasMore,
257
- cursor:
258
- items.length > 0
259
- ? String(new Date(items[items.length - 1].timestamp).getTime())
260
- : undefined,
274
+ }
275
+ return fetchActivityData(
276
+ apiUrl,
277
+ params.type,
278
+ { user: params.address, startTime, endTime },
279
+ assetRegistry,
280
+ (coin) => registry.get(coin),
281
+ liquidationHistory,
282
+ infoOpts
283
+ )
261
284
  },
262
- }
285
+ (item) => ({
286
+ time: new Date(item.timestamp).getTime(),
287
+ key: `${item.type}:${item.id}`,
288
+ }),
289
+ options?.signal
290
+ )
291
+ return { provider: PROVIDER_KEY, ...page }
263
292
  }