@lifi/perps-sdk-provider-hyperliquid 26.0.0 → 27.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 (121) hide show
  1. package/dist/cjs/services/getAccount.d.ts.map +1 -1
  2. package/dist/cjs/services/getAccount.js +2 -3
  3. package/dist/cjs/services/getAccount.js.map +1 -1
  4. package/dist/cjs/services/getOrders.d.ts.map +1 -1
  5. package/dist/cjs/services/getOrders.js +5 -27
  6. package/dist/cjs/services/getOrders.js.map +1 -1
  7. package/dist/cjs/services/getPortfolioHistory.d.ts.map +1 -1
  8. package/dist/cjs/services/getPortfolioHistory.js +3 -1
  9. package/dist/cjs/services/getPortfolioHistory.js.map +1 -1
  10. package/dist/cjs/utils/index.d.ts +1 -1
  11. package/dist/cjs/utils/index.d.ts.map +1 -1
  12. package/dist/cjs/utils/index.js +3 -1
  13. package/dist/cjs/utils/index.js.map +1 -1
  14. package/dist/cjs/utils/liquidation.d.ts +5 -2
  15. package/dist/cjs/utils/liquidation.d.ts.map +1 -1
  16. package/dist/cjs/utils/liquidation.js +9 -8
  17. package/dist/cjs/utils/liquidation.js.map +1 -1
  18. package/dist/cjs/utils/mapActivity.d.ts.map +1 -1
  19. package/dist/cjs/utils/mapActivity.js +9 -3
  20. package/dist/cjs/utils/mapActivity.js.map +1 -1
  21. package/dist/cjs/utils/mapFill.d.ts.map +1 -1
  22. package/dist/cjs/utils/mapFill.js +4 -1
  23. package/dist/cjs/utils/mapFill.js.map +1 -1
  24. package/dist/cjs/utils/mapMarket.d.ts.map +1 -1
  25. package/dist/cjs/utils/mapMarket.js +1 -1
  26. package/dist/cjs/utils/mapMarket.js.map +1 -1
  27. package/dist/cjs/utils/mapOrder.d.ts +2 -0
  28. package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
  29. package/dist/cjs/utils/mapOrder.js +31 -19
  30. package/dist/cjs/utils/mapOrder.js.map +1 -1
  31. package/dist/cjs/utils/mapPosition.d.ts.map +1 -1
  32. package/dist/cjs/utils/mapPosition.js +4 -4
  33. package/dist/cjs/utils/mapPosition.js.map +1 -1
  34. package/dist/cjs/utils/transferMargin.js +1 -1
  35. package/dist/cjs/utils/transferMargin.js.map +1 -1
  36. package/dist/cjs/utils/venueTotals.d.ts +0 -1
  37. package/dist/cjs/utils/venueTotals.d.ts.map +1 -1
  38. package/dist/cjs/utils/venueTotals.js +13 -4
  39. package/dist/cjs/utils/venueTotals.js.map +1 -1
  40. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +1 -0
  41. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  42. package/dist/cjs/websocket/HyperliquidWsProvider.js +60 -51
  43. package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
  44. package/dist/esm/services/getAccount.d.ts.map +1 -1
  45. package/dist/esm/services/getAccount.js +3 -4
  46. package/dist/esm/services/getAccount.js.map +1 -1
  47. package/dist/esm/services/getOrders.d.ts.map +1 -1
  48. package/dist/esm/services/getOrders.js +7 -35
  49. package/dist/esm/services/getOrders.js.map +1 -1
  50. package/dist/esm/services/getPortfolioHistory.d.ts.map +1 -1
  51. package/dist/esm/services/getPortfolioHistory.js +3 -1
  52. package/dist/esm/services/getPortfolioHistory.js.map +1 -1
  53. package/dist/esm/utils/index.d.ts +1 -1
  54. package/dist/esm/utils/index.d.ts.map +1 -1
  55. package/dist/esm/utils/index.js +1 -1
  56. package/dist/esm/utils/index.js.map +1 -1
  57. package/dist/esm/utils/liquidation.d.ts +23 -24
  58. package/dist/esm/utils/liquidation.d.ts.map +1 -1
  59. package/dist/esm/utils/liquidation.js +27 -31
  60. package/dist/esm/utils/liquidation.js.map +1 -1
  61. package/dist/esm/utils/mapActivity.d.ts.map +1 -1
  62. package/dist/esm/utils/mapActivity.js +9 -3
  63. package/dist/esm/utils/mapActivity.js.map +1 -1
  64. package/dist/esm/utils/mapFill.d.ts.map +1 -1
  65. package/dist/esm/utils/mapFill.js +4 -1
  66. package/dist/esm/utils/mapFill.js.map +1 -1
  67. package/dist/esm/utils/mapMarket.d.ts.map +1 -1
  68. package/dist/esm/utils/mapMarket.js +2 -2
  69. package/dist/esm/utils/mapMarket.js.map +1 -1
  70. package/dist/esm/utils/mapOrder.d.ts +7 -0
  71. package/dist/esm/utils/mapOrder.d.ts.map +1 -1
  72. package/dist/esm/utils/mapOrder.js +35 -19
  73. package/dist/esm/utils/mapOrder.js.map +1 -1
  74. package/dist/esm/utils/mapPosition.d.ts.map +1 -1
  75. package/dist/esm/utils/mapPosition.js +4 -4
  76. package/dist/esm/utils/mapPosition.js.map +1 -1
  77. package/dist/esm/utils/transferMargin.js +1 -1
  78. package/dist/esm/utils/transferMargin.js.map +1 -1
  79. package/dist/esm/utils/venueTotals.d.ts +2 -6
  80. package/dist/esm/utils/venueTotals.d.ts.map +1 -1
  81. package/dist/esm/utils/venueTotals.js +15 -8
  82. package/dist/esm/utils/venueTotals.js.map +1 -1
  83. package/dist/esm/utils/withdrawableBalances.d.ts +2 -2
  84. package/dist/esm/utils/withdrawableBalances.js +2 -2
  85. package/dist/esm/websocket/HyperliquidWsProvider.d.ts +2 -1
  86. package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  87. package/dist/esm/websocket/HyperliquidWsProvider.js +63 -54
  88. package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
  89. package/dist/types/services/getAccount.d.ts.map +1 -1
  90. package/dist/types/services/getOrders.d.ts.map +1 -1
  91. package/dist/types/services/getPortfolioHistory.d.ts.map +1 -1
  92. package/dist/types/utils/index.d.ts +1 -1
  93. package/dist/types/utils/index.d.ts.map +1 -1
  94. package/dist/types/utils/liquidation.d.ts +23 -24
  95. package/dist/types/utils/liquidation.d.ts.map +1 -1
  96. package/dist/types/utils/mapActivity.d.ts.map +1 -1
  97. package/dist/types/utils/mapFill.d.ts.map +1 -1
  98. package/dist/types/utils/mapMarket.d.ts.map +1 -1
  99. package/dist/types/utils/mapOrder.d.ts +7 -0
  100. package/dist/types/utils/mapOrder.d.ts.map +1 -1
  101. package/dist/types/utils/mapPosition.d.ts.map +1 -1
  102. package/dist/types/utils/venueTotals.d.ts +2 -6
  103. package/dist/types/utils/venueTotals.d.ts.map +1 -1
  104. package/dist/types/utils/withdrawableBalances.d.ts +2 -2
  105. package/dist/types/websocket/HyperliquidWsProvider.d.ts +2 -1
  106. package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  107. package/package.json +3 -3
  108. package/src/services/getAccount.ts +3 -3
  109. package/src/services/getOrders.ts +9 -44
  110. package/src/services/getPortfolioHistory.ts +3 -7
  111. package/src/utils/index.ts +2 -0
  112. package/src/utils/liquidation.ts +41 -35
  113. package/src/utils/mapActivity.ts +9 -3
  114. package/src/utils/mapFill.ts +4 -1
  115. package/src/utils/mapMarket.ts +4 -2
  116. package/src/utils/mapOrder.ts +46 -20
  117. package/src/utils/mapPosition.ts +8 -4
  118. package/src/utils/transferMargin.ts +1 -1
  119. package/src/utils/venueTotals.ts +21 -28
  120. package/src/utils/withdrawableBalances.ts +2 -2
  121. package/src/websocket/HyperliquidWsProvider.ts +95 -71
@@ -1,3 +1,4 @@
1
+ import { type MarketRegistry } from '@lifi/perps-sdk';
1
2
  import type { MarketDisplay, Order } from '@lifi/perps-types';
2
3
  import { OrderStatus, OrderType } from '@lifi/perps-types';
3
4
  import type { HlFrontendOpenOrder, HlOrderDetail, HlTwapHistoryEntry } from '../types/index.js';
@@ -7,6 +8,12 @@ export type HlOrderLike = HlFrontendOpenOrder | HlOrderDetail['order'];
7
8
  export declare const mapOrderType: (orderType: string) => Exclude<OrderType, OrderType.TWAP>;
8
9
  /** Translate venue lifecycle statuses; unknown statuses are errors. */
9
10
  export declare const mapOrderStatus: (status: string) => OrderStatus;
11
+ /**
12
+ * Map one venue row, or drop it. An outcome market identity, a coin the backend
13
+ * market list does not hold, and a row the mapper rejects each drop only their
14
+ * own row; each distinct mapper message warns once.
15
+ */
16
+ export declare const mapOrderRow: (coin: string, registry: MarketRegistry | undefined, map: (market: MarketDisplay) => Order | undefined) => Order | undefined;
10
17
  /**
11
18
  * Normalize regular, trigger, and TWAP rows through one lifecycle model. A row
12
19
  * whose filled or remaining size or timestamp cannot be derived gives `undefined`.
@@ -1 +1 @@
1
- {"version":3,"file":"mapOrder.d.ts","sourceRoot":"","sources":["../../../src/utils/mapOrder.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,aAAa,EACb,KAAK,EAGN,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAEL,WAAW,EACX,SAAS,EAGV,MAAM,mBAAmB,CAAA;AAE1B,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EACnB,MAAM,mBAAmB,CAAA;AAG1B,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;AAEtE,gFAAgF;AAChF,eAAO,MAAM,YAAY,GACvB,WAAW,MAAM,KAChB,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAiBnC,CAAA;AAED,uEAAuE;AACvE,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,KAAG,WAuC/C,CAAA;AAqBD;;;GAGG;AACH,eAAO,MAAM,QAAQ,GACnB,KAAK,WAAW,GAAG,aAAa,GAAG,kBAAkB,EACrD,QAAQ,aAAa,EACrB,gBAAgB,MAAM,KACrB,KAAK,GAAG,SAmKV,CAAA"}
1
+ {"version":3,"file":"mapOrder.d.ts","sourceRoot":"","sources":["../../../src/utils/mapOrder.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EAQpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EACV,aAAa,EACb,KAAK,EAGN,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAEL,WAAW,EACX,SAAS,EAGV,MAAM,mBAAmB,CAAA;AAE1B,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EACnB,MAAM,mBAAmB,CAAA;AAI1B,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;AAEtE,gFAAgF;AAChF,eAAO,MAAM,YAAY,GACvB,WAAW,MAAM,KAChB,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAiBnC,CAAA;AAED,uEAAuE;AACvE,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,KAAG,WAuC/C,CAAA;AAaD;;;;GAIG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,MAAM,EACZ,UAAU,cAAc,GAAG,SAAS,EACpC,KAAK,CAAC,MAAM,EAAE,aAAa,KAAK,KAAK,GAAG,SAAS,KAChD,KAAK,GAAG,SAkBV,CAAA;AAQD;;;GAGG;AACH,eAAO,MAAM,QAAQ,GACnB,KAAK,WAAW,GAAG,aAAa,GAAG,kBAAkB,EACrD,QAAQ,aAAa,EACrB,gBAAgB,MAAM,KACrB,KAAK,GAAG,SAgKV,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"mapPosition.d.ts","sourceRoot":"","sources":["../../../src/utils/mapPosition.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AASxD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,eAAe,KAAG,OACP,CAAA;AAEnD;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,GACtB,IAAI,eAAe,EACnB,QAAQ,kBAAkB,KACzB,QAAQ,GAAG,SAsDb,CAAA"}
1
+ {"version":3,"file":"mapPosition.d.ts","sourceRoot":"","sources":["../../../src/utils/mapPosition.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAaxD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,eAAe,KAAG,OACP,CAAA;AAEnD;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,GACtB,IAAI,eAAe,EACnB,QAAQ,kBAAkB,KACzB,QAAQ,GAAG,SAsDb,CAAA"}
@@ -19,13 +19,9 @@ export declare const perpsTotals: (dexStates: readonly DexMarginSummary[]) => {
19
19
  marginUsed: DecimalString;
20
20
  };
21
21
  /**
22
- * Sum the unrealized PnL of every position, in quote-asset units.
22
+ * Sum the unrealized PnL of every position, in quote-asset units. A term that
23
+ * does not match the decimal pattern adds nothing and warns once.
23
24
  * @public
24
25
  */
25
26
  export declare const sumUnrealizedPnl: (positions: readonly Position[]) => DecimalString;
26
- /**
27
- * Sum every term, or `undefined` with a warning when any term is not a
28
- * decimal string. A bad term never gives a partial sum.
29
- */
30
- export declare const safeSumDecimalStrings: (terms: readonly string[]) => DecimalString | undefined;
31
27
  //# sourceMappingURL=venueTotals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"venueTotals.d.ts","sourceRoot":"","sources":["../../../src/utils/venueTotals.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,aAAa,EACb,wBAAwB,EACxB,QAAQ,EACT,MAAM,mBAAmB,CAAA;AAG1B;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,wBAAwB,CAAA;CACzC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GACtB,WAAW,SAAS,gBAAgB,EAAE,KACrC;IAAE,YAAY,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAyB1D,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,WAAW,SAAS,QAAQ,EAAE,KAC7B,aAYA,CAAA;AAEH;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,SAAS,MAAM,EAAE,KACvB,aAAa,GAAG,SAKhB,CAAA"}
1
+ {"version":3,"file":"venueTotals.d.ts","sourceRoot":"","sources":["../../../src/utils/venueTotals.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,aAAa,EACb,wBAAwB,EACxB,QAAQ,EACT,MAAM,mBAAmB,CAAA;AAG1B;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,wBAAwB,CAAA;CACzC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GACtB,WAAW,SAAS,gBAAgB,EAAE,KACrC;IAAE,YAAY,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAyB1D,CAAA;AAID;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,WAAW,SAAS,QAAQ,EAAE,KAC7B,aAaF,CAAA"}
@@ -11,8 +11,8 @@ import type { HlAbstractionMode, HlClearinghouseState, HlSpotClearinghouseState
11
11
  * @param withdrawalFee - Flat venue fee in quote-asset units, set on every
12
12
  * quote-asset row. Hyperliquid deducts it from the requested amount. Absent
13
13
  * leaves every row without a fee.
14
- * @throws {PerpsError} `SDKError` when the fee or a venue figure is not a
15
- * decimal.
14
+ * @throws {PerpsError} `SDKError` when the fee or a venue figure does not match the
15
+ * decimal pattern.
16
16
  * @public
17
17
  */
18
18
  export declare const hyperliquidWithdrawableBalances: (abstraction: HlAbstractionMode | null, state: HlClearinghouseState, spotState: HlSpotClearinghouseState, quoteAssetId: string, withdrawalFee?: string) => ProviderWithdrawableBalance[];
@@ -115,7 +115,7 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
115
115
  private handleActiveSpotAssetCtx;
116
116
  /** Latest mid per `Market.id` across asset-context and fast feeds. */
117
117
  /** Latest mid per `Market.id` across asset-context and fast feeds; a mid
118
- * that is not a decimal string is left out. */
118
+ * that does not match the decimal pattern is left out. */
119
119
  private mergedMids;
120
120
  private orderbookReferencePrice;
121
121
  private handleL2Book;
@@ -125,6 +125,7 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
125
125
  private handleCandle;
126
126
  private handleTrades;
127
127
  private handleOrderUpdates;
128
+ private readOrderDetail;
128
129
  private handleUserFills;
129
130
  private handleAllDexsClearinghouseState;
130
131
  /** Whether the mode's collateral lives per-dex, making the perps-only
@@ -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":"AAAA,OAAO,EAYL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAGlB,KAAK,oBAAoB,EAazB,cAAc,EACd,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAQV,YAAY,EACb,MAAM,mBAAmB,CAAA;AA0E1B;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,QAAO,iBAKtC,CAAA;AAEH;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CAAC,MAAM,CAAC;IAC/D,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAmC;IAEvE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAG/B;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA4B;IACnE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuC;IACxE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAInC;IAID,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAQlC;IAGH,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAG/B;IACH,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAQ/B;IACH,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;IACD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAGhC;gBAEW,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc;IAYvE,OAAO,CAAC,mBAAmB;IAoBZ,SAAS,CACtB,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,oBAAoB,EAC9B,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,IAAI,CAAC;IAuBhB,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;IAqJnE;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,iBAAiB;IAmBzB;;;;OAIG;IACH,OAAO,CAAC,2BAA2B;IAWnC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,gBAAgB;cAcL,OAAO,IAAI,IAAI;IA0BlC,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAM9C,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;IA8B1C,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,WAAW;IAuDnB,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM;IAiFnC,OAAO,CAAC,sBAAsB;IAM9B,OAAO,CAAC,SAAS;IAUjB,oFAAoF;IACpF,OAAO,CAAC,wBAAwB;IAyBhC,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,oBAAoB;IAe5B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;IA8B5B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,wBAAwB;IAchC,sEAAsE;IACtE;8DAC0D;IAC1D,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,oBAAoB;IAqC5B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,kBAAkB;YA2DZ,eAAe;IAkC7B,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,+BAA+B;IA4CvC;0EACsE;IACtE,OAAO,CAAC,MAAM,CAAC,oBAAoB;YAOrB,eAAe;IA8C7B,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB;IA8B3B,OAAO,CAAC,kBAAkB;IAsC1B;2EACuE;IACvE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAEnD;;+BAE2B;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAM;IAEjD,OAAO,CAAC,uBAAuB;IA4C/B,OAAO,CAAC,oBAAoB;IAsD5B,OAAO,CAAC,qBAAqB;IAqB7B,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,gBAAgB;IAgDxB,0EAA0E;IAC1E,OAAO,CAAC,8BAA8B;CAsCvC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/perps-sdk-provider-hyperliquid",
3
- "version": "26.0.0",
3
+ "version": "27.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": "^21.0.0"
52
+ "@lifi/perps-types": "^22.0.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "@lifi/perps-sdk": "^24.0.0"
55
+ "@lifi/perps-sdk": "^25.0.0"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public"
@@ -5,6 +5,7 @@ import {
5
5
  isDecimalStringGreaterThan,
6
6
  type ProviderGetAccountParams,
7
7
  type SDKRequestOptions,
8
+ safeAddDecimalStrings,
8
9
  subtractDecimalString,
9
10
  toPerpsMarketDisplay,
10
11
  unknownToDecimalString,
@@ -38,7 +39,6 @@ import {
38
39
  } from '../utils/index.js'
39
40
  import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
40
41
  import { isOpenAssetPosition, mapPosition } from '../utils/mapPosition.js'
41
- import { safeSumDecimalStrings } from '../utils/venueTotals.js'
42
42
  import { requireAccountExists } from './getAccountExists.js'
43
43
 
44
44
  /**
@@ -274,12 +274,12 @@ export const getAccount = async (
274
274
  quoteAssetByCategory
275
275
  )
276
276
 
277
- const marginUsed = safeSumDecimalStrings(
277
+ const marginUsed = safeAddDecimalStrings(
278
278
  dexStates.flatMap(({ marginSummary }) =>
279
279
  marginSummary === undefined ? [] : [marginSummary.totalMarginUsed]
280
280
  )
281
281
  )
282
- const unrealizedPnl = safeSumDecimalStrings(
282
+ const unrealizedPnl = safeAddDecimalStrings(
283
283
  positions.map((position) => position.unrealizedPnl)
284
284
  )
285
285
 
@@ -1,14 +1,11 @@
1
1
  import {
2
2
  ACTIVE_ORDER_STATUSES,
3
- createWarnOnce,
4
3
  getMarketRegistry,
5
4
  isActiveOrderStatus,
6
- type MarketRegistry,
7
- PerpsError,
8
5
  type ProviderGetOrdersParams,
9
6
  type SDKRequestOptions,
10
7
  } from '@lifi/perps-sdk'
11
- import type { MarketDisplay, Order, OrdersResponse } from '@lifi/perps-types'
8
+ import type { Order, OrdersResponse } from '@lifi/perps-types'
12
9
  import { PROVIDER_KEY } from '../constants.js'
13
10
  import type { HyperliquidContext } from '../context.js'
14
11
  import type {
@@ -17,48 +14,14 @@ import type {
17
14
  HlTwapHistoryEntry,
18
15
  } from '../types/index.js'
19
16
  import { withExplorerLinks } from '../utils/explorer.js'
20
- import { assetIsOutcome, mapOrder, perpsDexNames } from '../utils/index.js'
17
+ import { mapOrder, perpsDexNames } from '../utils/index.js'
21
18
  import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
19
+ import { mapOrderRow } from '../utils/mapOrder.js'
22
20
  import { requireAccountExists } from './getAccountExists.js'
23
21
 
24
22
  /** Parameters for a lifecycle-filtered Hyperliquid order read. */
25
23
  export type GetOrdersParams = ProviderGetOrdersParams
26
24
 
27
- const warn = createWarnOnce()
28
-
29
- const warnOnce = (key: string): void => {
30
- warn(key, `[${PROVIDER_KEY}] ${key}`)
31
- }
32
-
33
- /**
34
- * Map one venue row, or drop it. An outcome market identity, a coin the backend
35
- * market list does not hold, and a row the mapper rejects each drop only their
36
- * own row instead of rejecting the whole page; each distinct mapper message
37
- * warns once.
38
- */
39
- const mapRow = (
40
- coin: string,
41
- registry: MarketRegistry,
42
- map: (market: MarketDisplay) => Order | undefined
43
- ): Order | undefined => {
44
- if (assetIsOutcome(coin)) {
45
- return undefined
46
- }
47
- const market = registry.get(coin)
48
- if (market === undefined) {
49
- return undefined
50
- }
51
- try {
52
- return map(market)
53
- } catch (error) {
54
- if (!(error instanceof PerpsError)) {
55
- throw error
56
- }
57
- warnOnce(`dropped order row: ${error.message}`)
58
- return undefined
59
- }
60
- }
61
-
62
25
  /** Read regular, trigger, and TWAP orders from the requested lifecycle feeds. */
63
26
  export const getOrders = async (
64
27
  { client, apiUrl }: HyperliquidContext,
@@ -127,7 +90,9 @@ export const getOrders = async (
127
90
  seenHistorical.add(key)
128
91
  keep(
129
92
  key,
130
- mapRow(detail.order.coin, registry, (market) => mapOrder(detail, market))
93
+ mapOrderRow(detail.order.coin, registry, (market) =>
94
+ mapOrder(detail, market)
95
+ )
131
96
  )
132
97
  }
133
98
  const raw = open.flat()
@@ -138,13 +103,13 @@ export const getOrders = async (
138
103
  if (!childIds.has(order.oid)) {
139
104
  keep(
140
105
  String(order.oid),
141
- mapRow(order.coin, registry, (market) => mapOrder(order, market))
106
+ mapOrderRow(order.coin, registry, (market) => mapOrder(order, market))
142
107
  )
143
108
  }
144
109
  for (const child of order.children ?? []) {
145
110
  keep(
146
111
  String(child.oid),
147
- mapRow(child.coin, registry, (market) =>
112
+ mapOrderRow(child.coin, registry, (market) =>
148
113
  mapOrder(child, market, String(order.oid))
149
114
  )
150
115
  )
@@ -154,7 +119,7 @@ export const getOrders = async (
154
119
  for (const twap of twaps) {
155
120
  keep(
156
121
  `twap:${twap.twapId}`,
157
- mapRow(twap.state.coin, registry, (market) => mapOrder(twap, market))
122
+ mapOrderRow(twap.state.coin, registry, (market) => mapOrder(twap, market))
158
123
  )
159
124
  }
160
125
  const matching = [...rows.values()].filter(
@@ -53,13 +53,9 @@ const validSamples = (
53
53
  ): [number, DecimalString][] =>
54
54
  samples.flatMap(([timestamp, value]): [number, DecimalString][] => {
55
55
  if (!Number.isFinite(timestamp)) {
56
- warnSkippedVenueRow(
57
- PROVIDER_KEY,
58
- row,
59
- 'timestamp',
60
- timestamp,
61
- 'timestamp'
62
- )
56
+ warnSkippedVenueRow(PROVIDER_KEY, row, 'timestamp', timestamp, {
57
+ expected: 'timestamp',
58
+ })
63
59
  return []
64
60
  }
65
61
  return [[timestamp, value]]
@@ -27,6 +27,8 @@ export { hlInfoOptions, infoRequest } from './infoClient.js'
27
27
  export {
28
28
  calculateLiquidationPrice,
29
29
  calculateMaintenanceMarginRate,
30
+ safeCalculateLiquidationPrice,
31
+ safeCalculateMaintenanceMarginRate,
30
32
  } from './liquidation.js'
31
33
  export {
32
34
  mapFundingActivity,
@@ -13,50 +13,56 @@
13
13
  */
14
14
 
15
15
  import {
16
+ createSafeFunction,
16
17
  divideDecimalString,
18
+ estimateLiquidationPrice,
17
19
  numberToDecimalString,
18
- safeEstimateLiquidationPrice,
20
+ PerpsError,
19
21
  } from '@lifi/perps-sdk'
22
+ import { type DecimalString, PerpsErrorCode } from '@lifi/perps-types'
20
23
 
21
24
  /**
22
- * Calculate the maintenance margin fraction for a Hyperliquid asset.
23
- *
24
- * Maintenance margin is half of the initial margin at max leverage.
25
+ * Maintenance margin fraction for a Hyperliquid asset: half of the initial
26
+ * margin at max leverage, `1 / (2 × maxLeverage)`.
25
27
  *
26
28
  * @param maxLeverage - Maximum leverage for the asset (e.g., 50 for BTC)
27
- * @returns Maintenance margin fraction (e.g., 0.01 for 50x max leverage),
28
- * or undefined if maxLeverage is zero
29
+ * @returns Maintenance margin fraction (`'0.01'` for 50x max leverage)
30
+ * @throws {PerpsError} `ValidationError` when `maxLeverage` is not a finite
31
+ * number above zero.
29
32
  * @public
30
33
  */
31
34
  export function calculateMaintenanceMarginRate(
32
35
  maxLeverage: number
33
- ): number | undefined {
34
- if (maxLeverage === 0) {
35
- return undefined
36
+ ): DecimalString {
37
+ if (!Number.isFinite(maxLeverage) || maxLeverage <= 0) {
38
+ throw new PerpsError(
39
+ PerpsErrorCode.ValidationError,
40
+ `\`maxLeverage\` must be a finite number above zero, got ${maxLeverage}.`
41
+ )
36
42
  }
37
- return 1 / (2 * maxLeverage)
43
+ return divideDecimalString('1', numberToDecimalString(2 * maxLeverage))
38
44
  }
39
45
 
46
+ /** @public */
47
+ export const safeCalculateMaintenanceMarginRate = createSafeFunction(
48
+ 'calculateMaintenanceMarginRate',
49
+ calculateMaintenanceMarginRate
50
+ )
51
+
40
52
  /**
41
- * Calculate liquidation price using the exact Hyperliquid formula.
42
- *
43
- * For isolated margin, new position prediction. For existing positions,
44
- * prefer Position.liquidationPrice from the API.
53
+ * Liquidation price of a new isolated position with the exact Hyperliquid
54
+ * formula. For an existing position, prefer `Position.liquidationPrice` from
55
+ * the API.
45
56
  *
46
57
  * Formula derivation (isolated margin, single position):
47
- * margin_per_unit = entryPrice / leverage
48
- * maintenance_per_unit = entryPrice * mmr
49
- * margin_available = margin_per_unit - maintenance_per_unit
50
- * liq_price = entryPrice - side * margin_available / (1 - mmr * side)
58
+ * margin_available = entryPrice × (1 / leverage - mmr)
59
+ * liq_price = entryPrice - side × margin_available / (1 - mmr × side)
51
60
  *
52
- * Where mmr = 1 / (2 * maxLeverage).
53
- *
54
- * @param entryPrice - Position entry price
55
- * @param leverage - User-selected leverage (e.g., 10)
56
- * @param isLong - True if long position, false if short
57
- * @param maxLeverage - Asset's maximum leverage (e.g., 50 for BTC). Determines
58
- * the maintenance margin rate: mmr = 1 / (2 * maxLeverage)
59
- * @returns Estimated liquidation price, or undefined if inputs are invalid
61
+ * @param leverage - User-selected leverage (e.g., `'10'`)
62
+ * @param maxLeverage - Asset's maximum leverage (e.g., 50 for BTC). Sets
63
+ * mmr = 1 / (2 × maxLeverage).
64
+ * @throws {PerpsError} `ValidationError` when `maxLeverage` is not a finite
65
+ * number above zero, or on an input that `estimateLiquidationPrice` rejects.
60
66
  * @public
61
67
  */
62
68
  export function calculateLiquidationPrice(
@@ -64,17 +70,17 @@ export function calculateLiquidationPrice(
64
70
  leverage: string,
65
71
  isLong: boolean,
66
72
  maxLeverage: number
67
- ): string | undefined {
68
- if (maxLeverage === 0) {
69
- return undefined
70
- }
71
- return safeEstimateLiquidationPrice({
73
+ ): string {
74
+ return estimateLiquidationPrice({
72
75
  entryPrice,
73
76
  leverage,
74
77
  isLong,
75
- maintenanceMarginRate: divideDecimalString(
76
- '1',
77
- numberToDecimalString(2 * maxLeverage)
78
- ),
78
+ maintenanceMarginRate: calculateMaintenanceMarginRate(maxLeverage),
79
79
  })
80
80
  }
81
+
82
+ /** @public */
83
+ export const safeCalculateLiquidationPrice = createSafeFunction(
84
+ 'calculateLiquidationPrice',
85
+ calculateLiquidationPrice
86
+ )
@@ -102,7 +102,9 @@ export const mapLedgerEntry = (
102
102
  const { delta } = entry
103
103
  const timestamp = rowTimestampToIsoStringOrUndefined(entry.time)
104
104
  if (timestamp === undefined) {
105
- warnSkippedVenueRow(providerKey, 'ledger', 'time', entry.time, 'timestamp')
105
+ warnSkippedVenueRow(providerKey, 'ledger', 'time', entry.time, {
106
+ expected: 'timestamp',
107
+ })
106
108
  return null
107
109
  }
108
110
  const base = { id: entry.hash, provider: providerKey, timestamp }
@@ -322,7 +324,9 @@ export const mapFundingActivity = (
322
324
  }
323
325
  const timestamp = rowTimestampToIsoStringOrUndefined(entry.time)
324
326
  if (timestamp === undefined) {
325
- warnSkippedVenueRow(providerKey, 'funding', 'time', entry.time, 'timestamp')
327
+ warnSkippedVenueRow(providerKey, 'funding', 'time', entry.time, {
328
+ expected: 'timestamp',
329
+ })
326
330
  return null
327
331
  }
328
332
  return {
@@ -387,7 +391,9 @@ export const mapLiquidationFills = (
387
391
  const time = Math.max(...group.map((fill) => fill.time))
388
392
  const timestamp = rowTimestampToIsoStringOrUndefined(time)
389
393
  if (timestamp === undefined) {
390
- warnSkippedVenueRow(providerKey, 'liquidation', 'time', time, 'timestamp')
394
+ warnSkippedVenueRow(providerKey, 'liquidation', 'time', time, {
395
+ expected: 'timestamp',
396
+ })
391
397
  return []
392
398
  }
393
399
  const closedSize =
@@ -31,7 +31,10 @@ export const mapFill = (
31
31
  const size = fill.sz
32
32
  const createdAt = rowTimestampToIsoStringOrUndefined(fill.time)
33
33
  if (createdAt === undefined) {
34
- warnSkippedVenueRow(PROVIDER_KEY, 'fill', 'time', fill.time, 'timestamp')
34
+ warnSkippedVenueRow(PROVIDER_KEY, 'fill', 'time', fill.time, {
35
+ marketId: market.id,
36
+ expected: 'timestamp',
37
+ })
35
38
  return undefined
36
39
  }
37
40
  // HL charges the builder portion in the same token as the total fee.
@@ -3,7 +3,7 @@ import type { PerpsMarket } from '@lifi/perps-types'
3
3
  import { PositionMarginAdjustment } from '@lifi/perps-types'
4
4
  import { PROVIDER_KEY } from '../constants.js'
5
5
  import type { HlMaxMarketOrderNtls, HlUniverseItem } from '../types/index.js'
6
- import { calculateMaintenanceMarginRate } from './liquidation.js'
6
+ import { safeCalculateMaintenanceMarginRate } from './liquidation.js'
7
7
  import { coinAsset } from './marketDisplay.js'
8
8
  import { getMaxPriceDecimals } from './orderFormatting.js'
9
9
 
@@ -72,5 +72,7 @@ export const mapMarket = (
72
72
  (universe.marginMode === undefined && universe.onlyIsolated !== true)
73
73
  ? PositionMarginAdjustment.ADD_AND_REMOVE
74
74
  : PositionMarginAdjustment.ADD_ONLY,
75
- maintenanceMarginRate: calculateMaintenanceMarginRate(universe.maxLeverage),
75
+ maintenanceMarginRate: safeCalculateMaintenanceMarginRate(
76
+ universe.maxLeverage
77
+ ),
76
78
  })
@@ -1,13 +1,14 @@
1
1
  import {
2
+ createWarnOnce,
3
+ isDecimalString,
2
4
  isDecimalStringGreaterThan,
5
+ type MarketRegistry,
3
6
  PerpsError,
4
7
  safeDivideDecimalString,
5
8
  safeIsDecimalStringGreaterThan,
6
9
  safeIsDecimalStringZero,
7
10
  safeSubtractDecimalString,
8
- subtractDecimalString,
9
11
  triggerConditionFor,
10
- unknownToDecimalString,
11
12
  warnSkippedVenueRow,
12
13
  } from '@lifi/perps-sdk'
13
14
  import type {
@@ -29,6 +30,7 @@ import type {
29
30
  HlOrderDetail,
30
31
  HlTwapHistoryEntry,
31
32
  } from '../types/index.js'
33
+ import { assetIsOutcome } from './assetId.js'
32
34
  import { rowTimestampToIsoStringOrUndefined } from './rowTimestamp.js'
33
35
 
34
36
  /** Order payload shared by frontend, historical, and single-order reads. */
@@ -98,15 +100,42 @@ export const mapOrderStatus = (status: string): OrderStatus => {
98
100
  }
99
101
  }
100
102
 
101
- const skipOrder = (field: string, value: unknown): undefined => {
102
- warnSkippedVenueRow(PROVIDER_KEY, 'order', field, value)
103
+ const skipOrder = (
104
+ marketId: string,
105
+ field: string,
106
+ value: unknown
107
+ ): undefined => {
108
+ warnSkippedVenueRow(PROVIDER_KEY, 'order', field, value, { marketId })
103
109
  return undefined
104
110
  }
105
111
 
106
- const venueDecimal = (value: unknown, field: string): string | undefined => {
112
+ const warnDroppedRowOnce = createWarnOnce()
113
+
114
+ /**
115
+ * Map one venue row, or drop it. An outcome market identity, a coin the backend
116
+ * market list does not hold, and a row the mapper rejects each drop only their
117
+ * own row; each distinct mapper message warns once.
118
+ */
119
+ export const mapOrderRow = (
120
+ coin: string,
121
+ registry: MarketRegistry | undefined,
122
+ map: (market: MarketDisplay) => Order | undefined
123
+ ): Order | undefined => {
124
+ if (assetIsOutcome(coin)) {
125
+ return undefined
126
+ }
127
+ const market = registry?.get(coin)
128
+ if (market === undefined) {
129
+ return undefined
130
+ }
107
131
  try {
108
- return unknownToDecimalString(value, field, PROVIDER_KEY)
109
- } catch {
132
+ return map(market)
133
+ } catch (error) {
134
+ if (!(error instanceof PerpsError)) {
135
+ throw error
136
+ }
137
+ const message = `[${PROVIDER_KEY}] dropped order row: ${error.message}`
138
+ warnDroppedRowOnce(message, message)
110
139
  return undefined
111
140
  }
112
141
  }
@@ -133,15 +162,15 @@ export const mapOrder = (
133
162
  const { state } = raw
134
163
  const remainingSize = safeSubtractDecimalString(state.sz, state.executedSz)
135
164
  if (remainingSize === undefined) {
136
- return skipOrder('executedSz', state.executedSz)
165
+ return skipOrder(market.id, 'executedSz', state.executedSz)
137
166
  }
138
167
  const createdAt = rowTimestampToIsoStringOrUndefined(state.timestamp)
139
168
  if (createdAt === undefined) {
140
- return skipOrder('timestamp', state.timestamp)
169
+ return skipOrder(market.id, 'timestamp', state.timestamp)
141
170
  }
142
171
  const updatedAt = rowTimestampToIsoStringOrUndefined(raw.time * 1000)
143
172
  if (updatedAt === undefined) {
144
- return skipOrder('time', raw.time)
173
+ return skipOrder(market.id, 'time', raw.time)
145
174
  }
146
175
  let status: OrderStatus
147
176
  switch (raw.status.status) {
@@ -195,23 +224,20 @@ export const mapOrder = (
195
224
  }
196
225
  const o = 'order' in raw ? raw.order : raw
197
226
  const venueStatus = 'order' in raw ? raw.status : 'open'
198
- const originalSize = venueDecimal(o.origSz, 'origSz')
199
- if (originalSize === undefined) {
200
- return skipOrder('origSz', o.origSz)
201
- }
202
- const remainingSize = venueDecimal(o.sz, 'sz')
203
- if (remainingSize === undefined) {
204
- return skipOrder('sz', o.sz)
227
+ const filledSize = safeSubtractDecimalString(o.origSz, o.sz)
228
+ if (filledSize === undefined) {
229
+ return isDecimalString(o.origSz)
230
+ ? skipOrder(market.id, 'sz', o.sz)
231
+ : skipOrder(market.id, 'origSz', o.origSz)
205
232
  }
206
- const filledSize = subtractDecimalString(originalSize, remainingSize)
207
233
  const createdAt = rowTimestampToIsoStringOrUndefined(o.timestamp)
208
234
  if (createdAt === undefined) {
209
- return skipOrder('timestamp', o.timestamp)
235
+ return skipOrder(market.id, 'timestamp', o.timestamp)
210
236
  }
211
237
  const statusTimestamp = 'order' in raw ? raw.statusTimestamp : o.timestamp
212
238
  const updatedAt = rowTimestampToIsoStringOrUndefined(statusTimestamp)
213
239
  if (updatedAt === undefined) {
214
- return skipOrder('statusTimestamp', statusTimestamp)
240
+ return skipOrder(market.id, 'statusTimestamp', statusTimestamp)
215
241
  }
216
242
  let status = mapOrderStatus(venueStatus)
217
243
  if (parentOrderId !== undefined && !('order' in raw)) {
@@ -18,8 +18,12 @@ import type { HlAssetPosition } from '../types/index.js'
18
18
 
19
19
  const warnNonPositiveLeverageOnce = createWarnOnce()
20
20
 
21
- const skipPosition = (field: string, value: unknown): undefined => {
22
- warnSkippedVenueRow(PROVIDER_KEY, 'position', field, value)
21
+ const skipPosition = (
22
+ marketId: string,
23
+ field: string,
24
+ value: unknown
25
+ ): undefined => {
26
+ warnSkippedVenueRow(PROVIDER_KEY, 'position', field, value, { marketId })
23
27
  return undefined
24
28
  }
25
29
 
@@ -48,7 +52,7 @@ export const mapPosition = (
48
52
  ): Position | undefined => {
49
53
  const pos = ap.position
50
54
  if (!isDecimalString(pos.szi)) {
51
- return skipPosition('szi', pos.szi)
55
+ return skipPosition(market.id, 'szi', pos.szi)
52
56
  }
53
57
  const size = absDecimalString(pos.szi)
54
58
  const positionValue = safeAbsDecimalString(pos.positionValue)
@@ -89,7 +93,7 @@ export const mapPosition = (
89
93
  size,
90
94
  entryPrice: pos.entryPx ?? '0',
91
95
  ...(markPrice === undefined ? {} : { markPrice }),
92
- liquidationPrice: pos.liquidationPx ?? '0',
96
+ liquidationPrice: pos.liquidationPx || '0',
93
97
  unrealizedPnl: pos.unrealizedPnl,
94
98
  ...(accruedFunding === undefined ? {} : { accruedFunding }),
95
99
  ...(leverage === undefined ? {} : { leverage }),
@@ -24,7 +24,7 @@ function requirePositionAmount(
24
24
  if (!isDecimalString(value)) {
25
25
  throw new PerpsError(
26
26
  PerpsErrorCode.ValidationError,
27
- `Invalid \`Position.${field}\`: '${value}' is not a decimal string.`
27
+ `Invalid \`Position.${field}\`: '${value}' does not match the decimal pattern.`
28
28
  )
29
29
  }
30
30
  return value