@lifi/perps-sdk-provider-lighter 30.0.0 → 31.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 (138) hide show
  1. package/dist/cjs/LighterProvider.d.ts.map +1 -1
  2. package/dist/cjs/LighterProvider.js +62 -54
  3. package/dist/cjs/LighterProvider.js.map +1 -1
  4. package/dist/cjs/accountSummary.d.ts +4 -1
  5. package/dist/cjs/accountSummary.d.ts.map +1 -1
  6. package/dist/cjs/accountSummary.js +8 -7
  7. package/dist/cjs/accountSummary.js.map +1 -1
  8. package/dist/cjs/availableToTrade.d.ts +2 -0
  9. package/dist/cjs/availableToTrade.d.ts.map +1 -1
  10. package/dist/cjs/availableToTrade.js +6 -7
  11. package/dist/cjs/availableToTrade.js.map +1 -1
  12. package/dist/cjs/types/pnl.d.ts.map +1 -1
  13. package/dist/cjs/types/ws.d.ts +5 -0
  14. package/dist/cjs/types/ws.d.ts.map +1 -1
  15. package/dist/cjs/utils/apiClient.d.ts +3 -2
  16. package/dist/cjs/utils/apiClient.d.ts.map +1 -1
  17. package/dist/cjs/utils/apiClient.js +5 -3
  18. package/dist/cjs/utils/apiClient.js.map +1 -1
  19. package/dist/cjs/utils/fetchDetailedAccount.d.ts +1 -1
  20. package/dist/cjs/utils/fetchDetailedAccount.d.ts.map +1 -1
  21. package/dist/cjs/utils/fetchDetailedAccount.js +2 -1
  22. package/dist/cjs/utils/fetchDetailedAccount.js.map +1 -1
  23. package/dist/cjs/utils/mapFill.d.ts.map +1 -1
  24. package/dist/cjs/utils/mapFill.js +1 -3
  25. package/dist/cjs/utils/mapFill.js.map +1 -1
  26. package/dist/cjs/utils/mapPortfolioHistory.d.ts +1 -1
  27. package/dist/cjs/utils/mapPortfolioHistory.d.ts.map +1 -1
  28. package/dist/cjs/utils/mapPortfolioHistory.js +36 -21
  29. package/dist/cjs/utils/mapPortfolioHistory.js.map +1 -1
  30. package/dist/cjs/utils/mapPosition.d.ts +1 -0
  31. package/dist/cjs/utils/mapPosition.d.ts.map +1 -1
  32. package/dist/cjs/utils/mapPosition.js +13 -1
  33. package/dist/cjs/utils/mapPosition.js.map +1 -1
  34. package/dist/cjs/utils/ohlcvInterval.d.ts.map +1 -1
  35. package/dist/cjs/utils/ohlcvInterval.js.map +1 -1
  36. package/dist/cjs/utils/spotPrice.d.ts +5 -1
  37. package/dist/cjs/utils/spotPrice.d.ts.map +1 -1
  38. package/dist/cjs/utils/spotPrice.js +14 -1
  39. package/dist/cjs/utils/spotPrice.js.map +1 -1
  40. package/dist/cjs/utils/withdrawableBalances.d.ts +3 -3
  41. package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -1
  42. package/dist/cjs/utils/withdrawableBalances.js +11 -3
  43. package/dist/cjs/utils/withdrawableBalances.js.map +1 -1
  44. package/dist/cjs/websocket/LighterWsProvider.d.ts +6 -0
  45. package/dist/cjs/websocket/LighterWsProvider.d.ts.map +1 -1
  46. package/dist/cjs/websocket/LighterWsProvider.js +120 -9
  47. package/dist/cjs/websocket/LighterWsProvider.js.map +1 -1
  48. package/dist/esm/LighterProvider.d.ts.map +1 -1
  49. package/dist/esm/LighterProvider.js +71 -61
  50. package/dist/esm/LighterProvider.js.map +1 -1
  51. package/dist/esm/accountSummary.d.ts +17 -3
  52. package/dist/esm/accountSummary.d.ts.map +1 -1
  53. package/dist/esm/accountSummary.js +18 -9
  54. package/dist/esm/accountSummary.js.map +1 -1
  55. package/dist/esm/availableToTrade.d.ts +2 -0
  56. package/dist/esm/availableToTrade.d.ts.map +1 -1
  57. package/dist/esm/availableToTrade.js +4 -6
  58. package/dist/esm/availableToTrade.js.map +1 -1
  59. package/dist/esm/types/pnl.d.ts +2 -3
  60. package/dist/esm/types/pnl.d.ts.map +1 -1
  61. package/dist/esm/types/ws.d.ts +13 -0
  62. package/dist/esm/types/ws.d.ts.map +1 -1
  63. package/dist/esm/types/ws.js +0 -11
  64. package/dist/esm/types/ws.js.map +1 -1
  65. package/dist/esm/utils/apiClient.d.ts +9 -2
  66. package/dist/esm/utils/apiClient.d.ts.map +1 -1
  67. package/dist/esm/utils/apiClient.js +9 -2
  68. package/dist/esm/utils/apiClient.js.map +1 -1
  69. package/dist/esm/utils/fetchDetailedAccount.d.ts +1 -1
  70. package/dist/esm/utils/fetchDetailedAccount.d.ts.map +1 -1
  71. package/dist/esm/utils/fetchDetailedAccount.js +2 -1
  72. package/dist/esm/utils/fetchDetailedAccount.js.map +1 -1
  73. package/dist/esm/utils/mapFill.d.ts.map +1 -1
  74. package/dist/esm/utils/mapFill.js +6 -10
  75. package/dist/esm/utils/mapFill.js.map +1 -1
  76. package/dist/esm/utils/mapPortfolioHistory.d.ts +3 -6
  77. package/dist/esm/utils/mapPortfolioHistory.d.ts.map +1 -1
  78. package/dist/esm/utils/mapPortfolioHistory.js +38 -26
  79. package/dist/esm/utils/mapPortfolioHistory.js.map +1 -1
  80. package/dist/esm/utils/mapPosition.d.ts +7 -0
  81. package/dist/esm/utils/mapPosition.d.ts.map +1 -1
  82. package/dist/esm/utils/mapPosition.js +17 -0
  83. package/dist/esm/utils/mapPosition.js.map +1 -1
  84. package/dist/esm/utils/ohlcvInterval.d.ts.map +1 -1
  85. package/dist/esm/utils/ohlcvInterval.js +5 -3
  86. package/dist/esm/utils/ohlcvInterval.js.map +1 -1
  87. package/dist/esm/utils/spotPrice.d.ts +10 -1
  88. package/dist/esm/utils/spotPrice.d.ts.map +1 -1
  89. package/dist/esm/utils/spotPrice.js +14 -0
  90. package/dist/esm/utils/spotPrice.js.map +1 -1
  91. package/dist/esm/utils/withdrawableBalances.d.ts +12 -5
  92. package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -1
  93. package/dist/esm/utils/withdrawableBalances.js +17 -5
  94. package/dist/esm/utils/withdrawableBalances.js.map +1 -1
  95. package/dist/esm/websocket/LighterWsProvider.d.ts +24 -0
  96. package/dist/esm/websocket/LighterWsProvider.d.ts.map +1 -1
  97. package/dist/esm/websocket/LighterWsProvider.js +153 -15
  98. package/dist/esm/websocket/LighterWsProvider.js.map +1 -1
  99. package/dist/types/LighterProvider.d.ts.map +1 -1
  100. package/dist/types/accountSummary.d.ts +17 -3
  101. package/dist/types/accountSummary.d.ts.map +1 -1
  102. package/dist/types/availableToTrade.d.ts +2 -0
  103. package/dist/types/availableToTrade.d.ts.map +1 -1
  104. package/dist/types/types/pnl.d.ts +2 -3
  105. package/dist/types/types/pnl.d.ts.map +1 -1
  106. package/dist/types/types/ws.d.ts +13 -0
  107. package/dist/types/types/ws.d.ts.map +1 -1
  108. package/dist/types/utils/apiClient.d.ts +9 -2
  109. package/dist/types/utils/apiClient.d.ts.map +1 -1
  110. package/dist/types/utils/fetchDetailedAccount.d.ts +1 -1
  111. package/dist/types/utils/fetchDetailedAccount.d.ts.map +1 -1
  112. package/dist/types/utils/mapFill.d.ts.map +1 -1
  113. package/dist/types/utils/mapPortfolioHistory.d.ts +3 -6
  114. package/dist/types/utils/mapPortfolioHistory.d.ts.map +1 -1
  115. package/dist/types/utils/mapPosition.d.ts +7 -0
  116. package/dist/types/utils/mapPosition.d.ts.map +1 -1
  117. package/dist/types/utils/ohlcvInterval.d.ts.map +1 -1
  118. package/dist/types/utils/spotPrice.d.ts +10 -1
  119. package/dist/types/utils/spotPrice.d.ts.map +1 -1
  120. package/dist/types/utils/withdrawableBalances.d.ts +12 -5
  121. package/dist/types/utils/withdrawableBalances.d.ts.map +1 -1
  122. package/dist/types/websocket/LighterWsProvider.d.ts +24 -0
  123. package/dist/types/websocket/LighterWsProvider.d.ts.map +1 -1
  124. package/package.json +3 -3
  125. package/src/LighterProvider.ts +119 -74
  126. package/src/accountSummary.ts +37 -14
  127. package/src/availableToTrade.ts +6 -10
  128. package/src/types/pnl.ts +2 -3
  129. package/src/types/ws.ts +23 -0
  130. package/src/utils/apiClient.ts +16 -7
  131. package/src/utils/fetchDetailedAccount.ts +2 -2
  132. package/src/utils/mapFill.ts +6 -13
  133. package/src/utils/mapPortfolioHistory.ts +42 -27
  134. package/src/utils/mapPosition.ts +17 -0
  135. package/src/utils/ohlcvInterval.ts +5 -3
  136. package/src/utils/spotPrice.ts +21 -1
  137. package/src/utils/withdrawableBalances.ts +26 -7
  138. package/src/websocket/LighterWsProvider.ts +222 -14
@@ -1 +1 @@
1
- {"version":3,"file":"spotPrice.d.ts","sourceRoot":"","sources":["../../../src/utils/spotPrice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAC9D,OAAO,KAAK,GAAG,MAAM,QAAQ,CAAA;AAG7B;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,SAAS,MAAM,EAAE,EAC1B,gBAAgB,MAAM,EACtB,UAAU,SAAS,aAAa,EAAE,EAClC,UAAU,WAAW,CAAC,MAAM,CAAC,KAC5B,GAAG,CAAC,MAAM,EAAE,GAAG,CAmBjB,CAAA"}
1
+ {"version":3,"file":"spotPrice.d.ts","sourceRoot":"","sources":["../../../src/utils/spotPrice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAC9D,OAAO,GAAG,MAAM,QAAQ,CAAA;AAGxB;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,SAAS,MAAM,EAAE,EAC1B,gBAAgB,MAAM,EACtB,UAAU,SAAS,aAAa,EAAE,EAClC,UAAU,WAAW,CAAC,MAAM,CAAC,KAC5B,GAAG,CAAC,MAAM,EAAE,GAAG,CAmBjB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,SAAS,MAAM,EACf,OAAO,MAAM,EACb,sBAAsB,MAAM,EAC5B,YAAY,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,KACnC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,CAAA;CAQjC,CAAA"}
@@ -1,12 +1,19 @@
1
- import type { ProviderWithdrawableBalance } from '@lifi/perps-sdk';
2
- import type { LtAccountAsset } from '../types/account.js';
1
+ import { type ProviderWithdrawableBalance } from '@lifi/perps-sdk';
2
+ import type { LtAccount } from '../types/account.js';
3
3
  /**
4
4
  * Split each held asset into the two routes a Lighter withdrawal can name:
5
5
  * spot draws on `balance` net of `locked_balance`, perps draws on
6
- * `margin_balance`. Routes with nothing left to draw are dropped; the
7
- * per-asset venue minimum is applied by the caller holding the asset registry.
6
+ * `margin_balance`. The settlement asset's perps route is also capped by the
7
+ * account `available_balance`, which excludes the margin open positions use.
8
+ * Every other asset's perps route reports its full `margin_balance`, uncapped,
9
+ * although `getAccount` reports `transferable: '0'` for it: a category
10
+ * transfer moves only the settlement asset. Routes with nothing left to draw
11
+ * are dropped; the per-asset venue minimum is applied by the caller holding
12
+ * the asset registry.
8
13
  *
14
+ * @param settlementAssetIndex - L2 asset index of the deployment's collateral
15
+ * asset, the only asset that `available_balance` is denominated in.
9
16
  * @public
10
17
  */
11
- export declare const lighterWithdrawableBalances: (assets: LtAccountAsset[]) => ProviderWithdrawableBalance[];
18
+ export declare const lighterWithdrawableBalances: (account: Pick<LtAccount, "assets" | "available_balance">, settlementAssetIndex: number) => ProviderWithdrawableBalance[];
12
19
  //# sourceMappingURL=withdrawableBalances.d.ts.map
@@ -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,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAGzD;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GACtC,QAAQ,cAAc,EAAE,KACvB,2BAA2B,EAgB7B,CAAA"}
1
+ {"version":3,"file":"withdrawableBalances.d.ts","sourceRoot":"","sources":["../../../src/utils/withdrawableBalances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,2BAA2B,EAAE,MAAM,iBAAiB,CAAA;AAEhF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAGpD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,2BAA2B,GACtC,SAAS,IAAI,CAAC,SAAS,EAAE,QAAQ,GAAG,mBAAmB,CAAC,EACxD,sBAAsB,MAAM,KAC3B,2BAA2B,EA0B7B,CAAA"}
@@ -59,6 +59,7 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
59
59
  * is a full open-position snapshot per the `PositionsEvent` contract.
60
60
  */
61
61
  private readonly positionsByAddress;
62
+ private readonly accountSummaryInputs;
62
63
  private readonly registry;
63
64
  private readonly accountIndexCache;
64
65
  private readonly accountIndexPromises;
@@ -77,6 +78,12 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
77
78
  */
78
79
  subscribeQuote(params: ProviderGetQuoteParams, onQuote: QuoteListener): Promise<() => void>;
79
80
  protected openChannel(sub: Subscription): Promise<() => void>;
81
+ /**
82
+ * Hold a `marketsContext` subscription for the spot marks that price the
83
+ * account's spot balances. The ref-counted base shares the wire channels
84
+ * with any consumer `marketsContext` subscription.
85
+ */
86
+ private subscribeSpotMarks;
80
87
  protected onClose(): void;
81
88
  protected sendSubscribe({ channel, needsAuth, address, }: SubState): Promise<void>;
82
89
  /**
@@ -87,6 +94,8 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
87
94
  * code, as it does for the Ondo and Lighter REST auth failures.
88
95
  */
89
96
  private requireAuthToken;
97
+ /** Whether a token resolves for the address; a resolver that throws counts as no token. */
98
+ private canResolveAuthToken;
90
99
  protected toKey(sub: Subscription): string;
91
100
  private resolveChannel;
92
101
  private resolveAccountIndex;
@@ -95,6 +104,21 @@ export declare class LighterWsProvider extends WsProviderBase<SubState> {
95
104
  private dispatch;
96
105
  private handleAccountOrders;
97
106
  private handleUserStats;
107
+ /**
108
+ * Replace the spot balances on a `subscribed/` frame and upsert them on an
109
+ * `update/` frame. An update before the first snapshot is dropped, so the
110
+ * map never holds a partial set. Balances parse here, so a non-decimal
111
+ * balance rejects its frame and never reaches the emit path.
112
+ */
113
+ private handleAccountAll;
114
+ /**
115
+ * Emit the account summary once both the `user_stats` figures and the spot
116
+ * balances are in. `portfolioValue` values the spot balances as REST
117
+ * `getAccount` does. `onlyOnChange` skips an emit whose `portfolioValue`
118
+ * equals the last one, so a mark tick on an unrelated market emits nothing.
119
+ */
120
+ private emitAccountSummary;
121
+ private settlementAssetIndex;
98
122
  private handleAccountTrades;
99
123
  private handleAccountPositions;
100
124
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAKlB,cAAc,EACd,KAAK,iBAAiB,EAGvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AA8EnC;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;AAEhC,UAAU,QAAQ;IAChB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yEAAyE;IACzE,SAAS,EAAE,OAAO,CAAA;CACnB;AAkBD;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAA;CAC5C;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAC7D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAE5B;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IAEnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,cAAc,CAAoC;IAE1D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2C;IAE9E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IAErD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqC;gBAGxE,KAAK,GAAE,MAA+B,EACtC,WAAW,GAAE,MAA6B,EAC1C,OAAO,GAAE,wBAA6B,EACtC,MAAM,CAAC,EAAE,cAAc;IAsBzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;;;OAKG;IACG,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;cA6ChD,OAAO,IAAI,IAAI;cAMlB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3B;;;;;;OAMG;YACW,gBAAgB;IAsB9B,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;YAyB5B,cAAc;YAyFd,mBAAmB;YAqBnB,iBAAiB;IAK/B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqB1C,OAAO,CAAC,QAAQ;IAkFhB,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,eAAe;IAuDvB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,sBAAsB;IAiC9B;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,mBAAmB;CAc5B;AAkID;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAU,wBAAwB,KACjC,iBAKA,CAAA"}
1
+ {"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/perps-sdk-provider-lighter",
3
- "version": "30.0.0",
3
+ "version": "31.0.0",
4
4
  "description": "Lighter provider plugin for @lifi/perps-sdk",
5
5
  "homepage": "https://github.com/lifinance/perps-sdk",
6
6
  "bugs": {
@@ -44,10 +44,10 @@
44
44
  "dependencies": {
45
45
  "big.js": "^7.0.1",
46
46
  "viem": "^2.55.18",
47
- "@lifi/perps-types": "^17.0.0"
47
+ "@lifi/perps-types": "^18.0.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "@lifi/perps-sdk": "^19.0.0"
50
+ "@lifi/perps-sdk": "^20.0.0"
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
@@ -9,6 +9,8 @@ import {
9
9
  getProviders,
10
10
  isActiveOrderStatus,
11
11
  localStorageAdapter,
12
+ maxOf,
13
+ minOf,
12
14
  PerpsError,
13
15
  type PerpsProviderPlugin,
14
16
  type PerpsSDKClient,
@@ -74,7 +76,7 @@ import {
74
76
  projectLighterConfigSettings,
75
77
  resolveAccountTier,
76
78
  } from './accountConfig.js'
77
- import { getAccountSummary } from './accountSummary.js'
79
+ import { getAccountSummary, lighterConfig } from './accountSummary.js'
78
80
  import { lighterAvailableToTrade } from './availableToTrade.js'
79
81
  import {
80
82
  DEFAULT_TRADES_LIMIT,
@@ -159,7 +161,7 @@ import {
159
161
  fetchRegisteredApiKey,
160
162
  normalizeLighterPublicKey,
161
163
  } from './utils/registeredApiKey.js'
162
- import { spotPriceByAssetId } from './utils/spotPrice.js'
164
+ import { spotPriceByAssetId, spotValuation } from './utils/spotPrice.js'
163
165
  import { isPlaceholderTxHash } from './utils/txHash.js'
164
166
  import { wireList } from './utils/wireList.js'
165
167
 
@@ -168,13 +170,6 @@ const ZERO_FEE_TIER = { maker: '0', taker: '0' }
168
170
  const tickToFeeString = (tick: number): string =>
169
171
  String(tick / LIGHTER_FEE_TICK_SCALE)
170
172
 
171
- const transferableWithin = (venueFigure: Big, units: Big): string => {
172
- if (venueFigure.lt(0)) {
173
- return '0'
174
- }
175
- return (venueFigure.gt(units) ? units : venueFigure).toFixed()
176
- }
177
-
178
173
  const projectFeeTier = (
179
174
  limits: LtAccountLimits
180
175
  ): { maker: string; taker: string } => ({
@@ -200,21 +195,21 @@ const CLIENT_ORDER_INDEX_PATTERN = /^\d+$/
200
195
  const INACTIVE_ORDERS_LOOKUP_LIMIT = 100
201
196
 
202
197
  interface PnlWindow {
203
- resolution: '1h' | '4h' | '1d'
204
- bucketMs: number
198
+ resolution: '1h' | '1d'
199
+ bucketSeconds: number
205
200
  countBack: number
206
201
  }
207
202
 
208
- const HOUR_MS = 60 * 60 * 1000
209
- const DAY_MS = 24 * HOUR_MS
203
+ const HOUR_SECONDS = 60 * 60
204
+ const DAY_SECONDS = 24 * HOUR_SECONDS
210
205
 
211
206
  // `all` has no natural bucket count; 1000 daily buckets reach back past the
212
207
  // venue's launch for every account.
213
208
  const PNL_WINDOWS: Record<PortfolioHistoryRange, PnlWindow> = {
214
- '24h': { resolution: '1h', bucketMs: HOUR_MS, countBack: 24 },
215
- '7d': { resolution: '4h', bucketMs: 4 * HOUR_MS, countBack: 42 },
216
- '30d': { resolution: '1d', bucketMs: DAY_MS, countBack: 30 },
217
- all: { resolution: '1d', bucketMs: DAY_MS, countBack: 1000 },
209
+ '24h': { resolution: '1h', bucketSeconds: HOUR_SECONDS, countBack: 24 },
210
+ '7d': { resolution: '1h', bucketSeconds: HOUR_SECONDS, countBack: 168 },
211
+ '30d': { resolution: '1d', bucketSeconds: DAY_SECONDS, countBack: 30 },
212
+ all: { resolution: '1d', bucketSeconds: DAY_SECONDS, countBack: 1000 },
218
213
  }
219
214
 
220
215
  /** Batches that get the pre-sign account tier check. */
@@ -789,24 +784,48 @@ export const createLighterProvider = (
789
784
  }
790
785
  }
791
786
 
792
- const resolveAccountExists = async (
793
- address: Address,
794
- opts?: SDKRequestOptions
795
- ): Promise<boolean> => {
787
+ /** The account, or `undefined` when Lighter has no account for the address. */
788
+ const fetchAccountIfExists = async (
789
+ client: LighterApiClient,
790
+ address: Address
791
+ ): Promise<LtAccount | undefined> => {
796
792
  try {
797
- await fetchDetailedAccount(apiClient(opts), address)
798
- return true
793
+ return await fetchDetailedAccount(client, address)
799
794
  } catch (err) {
800
795
  if (
801
796
  err instanceof PerpsError &&
802
797
  err.code === PerpsErrorCode.AccountNotFound
803
798
  ) {
804
- return false
799
+ return undefined
805
800
  }
806
801
  throw err
807
802
  }
808
803
  }
809
804
 
805
+ /** The venue default for a market: its backend `defaultLeverage`, with cross margin. */
806
+ const resolveDefaultMarketSettings = async (
807
+ marketId: string
808
+ ): Promise<MarketSettings> => {
809
+ const registry = getMarketRegistry(requireClient(), providerKey)
810
+ await registry.sync()
811
+ const market = registry.require(marketId)
812
+ const leverage =
813
+ 'maxLeverage' in market ? market.defaultLeverage : undefined
814
+ if (leverage === undefined || !(leverage > 0)) {
815
+ throw new PerpsError(
816
+ PerpsErrorCode.SDKError,
817
+ `The backend market '${marketId}' carries no positive Lighter default leverage`
818
+ )
819
+ }
820
+ return { marginMode: MarginMode.CROSS, leverage }
821
+ }
822
+
823
+ const resolveAccountExists = async (
824
+ address: Address,
825
+ opts?: SDKRequestOptions
826
+ ): Promise<boolean> =>
827
+ (await fetchAccountIfExists(apiClient(opts), address)) !== undefined
828
+
810
829
  let setupPromise: Promise<SetupAction[]> | undefined
811
830
 
812
831
  /** The venue's own `Provider.setup` descriptor for an action, if declared. */
@@ -963,9 +982,6 @@ export const createLighterProvider = (
963
982
  const instanceMeta = providers.find((p) => p.key === providerKey)
964
983
  const categories = instanceMeta?.categories ?? []
965
984
  const perpsCategory = categories.find((c) => c.quoteAsset !== null)
966
- const spotCategoryId =
967
- categories.find((c) => c.quoteAsset === null)?.id ??
968
- LIGHTER_SPOT_CATEGORY_ID
969
985
 
970
986
  const availableBalance = toRequiredBig(
971
987
  account.available_balance,
@@ -982,7 +998,7 @@ export const createLighterProvider = (
982
998
  )
983
999
  const spotPrices = spotPriceByAssetId(
984
1000
  registry.markets,
985
- spotCategoryId,
1001
+ LIGHTER_SPOT_CATEGORY_ID,
986
1002
  prices,
987
1003
  new Set(
988
1004
  [...heldAssets, ...marginAssets]
@@ -996,16 +1012,17 @@ export const createLighterProvider = (
996
1012
  asset: Asset,
997
1013
  units: string
998
1014
  ): Balance => {
999
- const price =
1000
- a.asset_id === collateral.assetIndex
1001
- ? new Big(1)
1002
- : spotPrices.get(String(a.asset_id))
1015
+ const { valueUsd, price } = spotValuation(
1016
+ a.asset_id,
1017
+ units,
1018
+ collateral.assetIndex,
1019
+ spotPrices
1020
+ )
1003
1021
  return {
1004
1022
  categoryId,
1005
1023
  asset,
1006
1024
  units,
1007
- valueUsd:
1008
- price === undefined ? '0' : new Big(units).times(price).toFixed(),
1025
+ valueUsd,
1009
1026
  ...(price === undefined ? {} : { price: price.toFixed() }),
1010
1027
  }
1011
1028
  }
@@ -1033,13 +1050,31 @@ export const createLighterProvider = (
1033
1050
  a.margin_balance
1034
1051
  ),
1035
1052
  transferable: isSettlement
1036
- ? transferableWithin(availableBalance, new Big(a.margin_balance))
1053
+ ? minOf(
1054
+ maxOf(availableBalance, new Big(0)),
1055
+ new Big(a.margin_balance)
1056
+ ).toFixed()
1037
1057
  : '0',
1038
1058
  }
1039
1059
  })
1040
- const balances: Balance[] = heldAssets.map((a) =>
1041
- toBalance(a, spotCategoryId, registryAsset(a), a.balance)
1042
- )
1060
+ const balances: Balance[] = heldAssets.map((a) => {
1061
+ const balance = new Big(a.balance)
1062
+ return {
1063
+ ...toBalance(
1064
+ a,
1065
+ LIGHTER_SPOT_CATEGORY_ID,
1066
+ registryAsset(a),
1067
+ a.balance
1068
+ ),
1069
+ transferable: minOf(
1070
+ maxOf(
1071
+ balance.minus(toRequiredBig(a.locked_balance, 'locked_balance')),
1072
+ new Big(0)
1073
+ ),
1074
+ balance
1075
+ ).toFixed(),
1076
+ }
1077
+ })
1043
1078
 
1044
1079
  const assetCollateral = account.assets.flatMap((a) =>
1045
1080
  a.margin_mode === undefined
@@ -1059,6 +1094,8 @@ export const createLighterProvider = (
1059
1094
  apiKeyRegistered,
1060
1095
  accountType: account.account_type,
1061
1096
  availableBalance: account.available_balance,
1097
+ crossAssetValue: account.cross_asset_value,
1098
+ crossInitialMarginRequirement: account.cross_initial_margin_requirement,
1062
1099
  totalAssetValue: account.total_asset_value,
1063
1100
  userTierName: limitsResult?.user_tier_name,
1064
1101
  accountTradingMode:
@@ -1112,11 +1149,13 @@ export const createLighterProvider = (
1112
1149
  params: ProviderGetWithdrawableBalancesParams,
1113
1150
  opts?: SDKRequestOptions
1114
1151
  ): Promise<ProviderWithdrawableBalance[]> {
1115
- const account = await fetchDetailedAccount(
1152
+ const account = await fetchAccountIfExists(
1116
1153
  apiClient(opts),
1117
1154
  params.address
1118
1155
  )
1119
- return lighterWithdrawableBalances(account.assets)
1156
+ return account === undefined
1157
+ ? []
1158
+ : lighterWithdrawableBalances(account, collateral.assetIndex)
1120
1159
  },
1121
1160
 
1122
1161
  async getPositions(
@@ -1126,9 +1165,16 @@ export const createLighterProvider = (
1126
1165
  const client = apiClient(opts)
1127
1166
  const registry = getMarketRegistry(requireClient(), providerKey)
1128
1167
  const [account] = await Promise.all([
1129
- fetchDetailedAccount(client, params.address),
1168
+ fetchAccountIfExists(client, params.address),
1130
1169
  registry.sync(),
1131
1170
  ])
1171
+ if (account === undefined) {
1172
+ return {
1173
+ provider: providerKey,
1174
+ positions: [],
1175
+ pagination: { limit: params.limit ?? 0, hasMore: false },
1176
+ }
1177
+ }
1132
1178
 
1133
1179
  let positions: Position[] = mapOpenPositions(account.positions, (id) =>
1134
1180
  toPerpsMarketDisplay(registry.require(String(id)))
@@ -1165,39 +1211,38 @@ export const createLighterProvider = (
1165
1211
  },
1166
1212
 
1167
1213
  /**
1168
- * Lighter reports a market's margin mode and leverage only on the
1169
- * account's position row, so a market the account never touched (or a
1170
- * missing account) resolves `undefined` rather than a venue default.
1214
+ * Lighter reports a market's margin mode and leverage on the account's
1215
+ * position row. Without a row carrying a positive IMF (or without an
1216
+ * account), the venue applies the market's default leverage with cross margin.
1171
1217
  */
1172
1218
  async getMarketSettings(
1173
1219
  params: ProviderGetMarketSettingsParams,
1174
1220
  opts?: SDKRequestOptions
1175
- ): Promise<MarketSettings | undefined> {
1176
- // Spot markets carry no margin mode or leverage.
1177
- if (params.market.categoryId === LIGHTER_SPOT_CATEGORY_ID) {
1178
- return undefined
1179
- }
1180
- let account: LtAccount
1181
- try {
1182
- account = await fetchDetailedAccount(apiClient(opts), params.address)
1183
- } catch (err) {
1184
- if (
1185
- err instanceof PerpsError &&
1186
- err.code === PerpsErrorCode.AccountNotFound
1187
- ) {
1188
- return undefined
1189
- }
1190
- throw err
1221
+ ): Promise<MarketSettings> {
1222
+ const { marketId, categoryId } = params.market
1223
+ if (categoryId === LIGHTER_SPOT_CATEGORY_ID) {
1224
+ throw new PerpsError(
1225
+ PerpsErrorCode.ValidationError,
1226
+ `Lighter market '${marketId}' is a spot market and carries no leverage setting`
1227
+ )
1191
1228
  }
1192
- const row = account.positions.find(
1193
- (p) => String(p.market_id) === params.market.marketId
1229
+ const client = apiClient(opts)
1230
+ const account = await fetchAccountIfExists(client, params.address)
1231
+ const row = account?.positions.find(
1232
+ (p) => String(p.market_id) === marketId
1194
1233
  )
1195
- if (!row) {
1196
- return undefined
1197
- }
1198
- const leverage = leverageFromImf(row.initial_margin_fraction)
1199
- if (leverage === undefined) {
1200
- return undefined
1234
+ // An unparsable IMF throws; a non-positive one means no stored setting.
1235
+ const leverage =
1236
+ row === undefined
1237
+ ? undefined
1238
+ : leverageFromImf(
1239
+ toRequiredBig(
1240
+ row.initial_margin_fraction,
1241
+ 'initial_margin_fraction'
1242
+ ).toFixed()
1243
+ )
1244
+ if (row === undefined || leverage === undefined) {
1245
+ return resolveDefaultMarketSettings(marketId)
1201
1246
  }
1202
1247
  return {
1203
1248
  marginMode:
@@ -1493,18 +1538,18 @@ export const createLighterProvider = (
1493
1538
  }
1494
1539
 
1495
1540
  const client = apiClient(opts)
1496
- const account = await fetchDetailedAccount(client, params.address)
1541
+ const account = await plugin.getAccount({ address: params.address }, opts)
1497
1542
  const window = PNL_WINDOWS[params.range]
1498
- const endTimestamp = Date.now()
1543
+ const endTimestampSeconds = Math.floor(Date.now() / 1_000)
1499
1544
  const queryParams: Record<string, string | number | boolean> = {
1500
1545
  by: 'index',
1501
- value: String(account.index),
1546
+ value: String(lighterConfig(account).accountIndex),
1502
1547
  resolution: window.resolution,
1503
1548
  start_timestamp:
1504
1549
  params.range === 'all'
1505
1550
  ? 0
1506
- : endTimestamp - window.countBack * window.bucketMs,
1507
- end_timestamp: endTimestamp,
1551
+ : endTimestampSeconds - window.countBack * window.bucketSeconds,
1552
+ end_timestamp: endTimestampSeconds,
1508
1553
  count_back: window.countBack,
1509
1554
  ignore_transfers: false,
1510
1555
  }
@@ -1537,7 +1582,7 @@ export const createLighterProvider = (
1537
1582
  return mapPortfolioHistory(
1538
1583
  params.range,
1539
1584
  wireList(response.pnl),
1540
- toRequiredBig(account.total_asset_value, 'total_asset_value')
1585
+ new Big(getAccountSummary(account, account.positions).portfolioValue)
1541
1586
  )
1542
1587
  },
1543
1588
 
@@ -7,10 +7,18 @@ import type {
7
7
  } from '@lifi/perps-types'
8
8
  import { PerpsErrorCode } from '@lifi/perps-types'
9
9
  import Big from 'big.js'
10
+ import { atLeastZero } from './availableToTrade.js'
10
11
  import { LIGHTER_PROVIDER_KEY, LIGHTER_RH_PROVIDER_KEY } from './constants.js'
11
12
  import { toRequiredBig } from './utils/decimal.js'
12
13
 
13
- const lighterConfig = (account: AccountResponse): LighterAccountConfig => {
14
+ /**
15
+ * The Lighter arm of `account.config`.
16
+ *
17
+ * @throws {PerpsError} `SDKError` when the account is not a Lighter one.
18
+ */
19
+ export const lighterConfig = (
20
+ account: AccountResponse
21
+ ): LighterAccountConfig => {
14
22
  const { config } = account
15
23
  if (
16
24
  config.provider !== LIGHTER_PROVIDER_KEY &&
@@ -24,12 +32,27 @@ const lighterConfig = (account: AccountResponse): LighterAccountConfig => {
24
32
  return config
25
33
  }
26
34
 
35
+ /**
36
+ * Lighter portfolio value: the perps-route equity (`total_asset_value`) plus
37
+ * the USD value of every spot-route holding, settlement asset included.
38
+ */
39
+ export const lighterPortfolioValue = (
40
+ perpsEquity: Big,
41
+ spotValuesUsd: readonly string[]
42
+ ): Big =>
43
+ spotValuesUsd.reduce(
44
+ (sum, valueUsd) => sum.plus(toRequiredBig(valueUsd, 'valueUsd')),
45
+ perpsEquity
46
+ )
47
+
27
48
  /**
28
49
  * Roll a Lighter account up into an {@link AccountSummary}. `totalAssetValue`
29
50
  * is perps-route equity and excludes the spot route, so `portfolioValue` adds
30
51
  * every spot `balances` row, settlement included; the `collateralBalances` rows
31
- * are the perps-route holding already inside `totalAssetValue`. The positions
32
- * supply only the margin and PnL breakdown.
52
+ * are the perps-route holding already inside `totalAssetValue`.
53
+ * `availableMargin` is the cross free collateral, floored at 0: an isolated
54
+ * position's equity stays with that position until the user removes it. The
55
+ * positions supply only the margin and PnL breakdown.
33
56
  *
34
57
  * @throws {PerpsError} `SDKError` when the account is not a Lighter one.
35
58
  * @public
@@ -47,18 +70,18 @@ export function getAccountSummary(
47
70
  unrealizedPnl = unrealizedPnl.plus(position.unrealizedPnl)
48
71
  }
49
72
 
50
- let portfolioValue = toRequiredBig(config.totalAssetValue, 'totalAssetValue')
51
- for (const balance of account.balances) {
52
- portfolioValue = portfolioValue.plus(
53
- toRequiredBig(balance.valueUsd, 'valueUsd')
54
- )
55
- }
56
-
57
73
  return {
58
- portfolioValue: portfolioValue.toFixed(),
59
- availableMargin: toRequiredBig(
60
- config.availableBalance,
61
- 'availableBalance'
74
+ portfolioValue: lighterPortfolioValue(
75
+ toRequiredBig(config.totalAssetValue, 'totalAssetValue'),
76
+ account.balances.map((balance) => balance.valueUsd)
77
+ ).toFixed(),
78
+ availableMargin: atLeastZero(
79
+ toRequiredBig(config.crossAssetValue, 'crossAssetValue').minus(
80
+ toRequiredBig(
81
+ config.crossInitialMarginRequirement,
82
+ 'crossInitialMarginRequirement'
83
+ )
84
+ )
62
85
  ).toFixed(),
63
86
  marginUsed: marginUsed.toFixed(),
64
87
  unrealizedPnl: unrealizedPnl.toFixed(),
@@ -4,23 +4,19 @@ import { MarginMode, PositionSide } from '@lifi/perps-types'
4
4
  import Big from 'big.js'
5
5
  import { toRequiredBig } from './utils/decimal.js'
6
6
 
7
- const atLeastZero = (value: Big): Big => (value.lt(0) ? new Big(0) : value)
7
+ export const atLeastZero = (value: Big): Big =>
8
+ value.lt(0) ? new Big(0) : value
8
9
 
9
- // Lighter's `available_balance` already nets cross unrealized PnL and counts
10
- // an isolated position's equity above its IMR, so only the rest is released.
10
+ // `availableMargin` is the cross free collateral and holds nothing of an
11
+ // isolated position, so closing one releases its whole equity.
11
12
  const releasedOnClose = (position: Position): Big => {
12
13
  const marginUsed = toRequiredBig(position.marginUsed, 'marginUsed')
13
14
  if (position.marginMode !== MarginMode.ISOLATED) {
14
15
  return marginUsed
15
16
  }
16
- const equity = marginUsed.plus(
17
- toRequiredBig(position.unrealizedPnl, 'unrealizedPnl')
17
+ return atLeastZero(
18
+ marginUsed.plus(toRequiredBig(position.unrealizedPnl, 'unrealizedPnl'))
18
19
  )
19
- const imr = toRequiredBig(
20
- position.initialMarginRequirement,
21
- 'initialMarginRequirement'
22
- )
23
- return equity.lt(imr) ? equity : imr
24
20
  }
25
21
 
26
22
  /**
package/src/types/pnl.ts CHANGED
@@ -2,9 +2,8 @@
2
2
  // Lighter serializes an empty list as JSON `null`, so list members are nullable.
3
3
 
4
4
  /**
5
- * One PnL bucket. `timestamp` is Unix milliseconds. Every other field is a
6
- * JSON number in USD for that bucket alone; the endpoint reports no account
7
- * value.
5
+ * One cumulative PnL snapshot. `timestamp` is Unix seconds; PnL, flow, and
6
+ * volume fields are cumulative totals as of that timestamp.
8
7
  *
9
8
  * @public
10
9
  */
package/src/types/ws.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { LtAccountAsset } from './account.js'
2
+
1
3
  // The Lighter stream server sends JSON messages of shape:
2
4
  // { type: 'subscribed/<channel>' | 'update/<channel>' | 'ping',
3
5
  // channel: '<channel>/<id>',
@@ -9,6 +11,7 @@
9
11
  // - spot_market_stats/all → context across all spot markets
10
12
  // - spot_market_stats/{id} → context for one spot market
11
13
  // - order_book/{market_id} → bids/asks per market (stateful with deltas)
14
+ // - account_all/{account} → per-asset spot-route balances
12
15
 
13
16
  /**
14
17
  * Common envelope fields on every Lighter WebSocket frame.
@@ -211,6 +214,26 @@ export type LtWsUserStatsMessage = LtWsMessage & {
211
214
  }
212
215
  }
213
216
 
217
+ /**
218
+ * `account_all/{account_index}` or `account_all_assets/{account_index}` frame,
219
+ * read for its `assets` map only. The `subscribed/` frame carries every asset
220
+ * keyed by asset index; an `update/` frame carries the changed assets, or
221
+ * `null` when no balance changed. `balance` is the spot-route balance in asset
222
+ * units.
223
+ * @public
224
+ */
225
+ export type LtWsAccountAllMessage = LtWsMessage & {
226
+ type:
227
+ | 'subscribed/account_all'
228
+ | 'update/account_all'
229
+ | 'subscribed/account_all_assets'
230
+ | 'update/account_all_assets'
231
+ assets?: Record<
232
+ string,
233
+ Pick<LtAccountAsset, 'symbol' | 'asset_id' | 'balance' | 'locked_balance'>
234
+ > | null
235
+ }
236
+
214
237
  /**
215
238
  * Authenticated account-position frame. Position and funding maps are keyed
216
239
  * by Lighter market index; the provider normalizes the payload before emitting