@lifi/perps-sdk-provider-lighter 1.4.0 → 1.5.2

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 (53) hide show
  1. package/dist/cjs/LighterProvider.d.ts.map +1 -1
  2. package/dist/cjs/LighterProvider.js +1 -0
  3. package/dist/cjs/LighterProvider.js.map +1 -1
  4. package/dist/cjs/accountSummary.js +1 -1
  5. package/dist/cjs/accountSummary.js.map +1 -1
  6. package/dist/cjs/constants.d.ts +1 -0
  7. package/dist/cjs/constants.d.ts.map +1 -1
  8. package/dist/cjs/constants.js +2 -1
  9. package/dist/cjs/constants.js.map +1 -1
  10. package/dist/cjs/types/ws.d.ts +2 -2
  11. package/dist/cjs/types/ws.d.ts.map +1 -1
  12. package/dist/cjs/utils/apiClient.d.ts +1 -0
  13. package/dist/cjs/utils/apiClient.d.ts.map +1 -1
  14. package/dist/cjs/utils/apiClient.js +5 -4
  15. package/dist/cjs/utils/apiClient.js.map +1 -1
  16. package/dist/cjs/websocket/LighterWsProvider.d.ts.map +1 -1
  17. package/dist/cjs/websocket/LighterWsProvider.js +38 -6
  18. package/dist/cjs/websocket/LighterWsProvider.js.map +1 -1
  19. package/dist/esm/LighterProvider.d.ts.map +1 -1
  20. package/dist/esm/LighterProvider.js +1 -0
  21. package/dist/esm/LighterProvider.js.map +1 -1
  22. package/dist/esm/accountSummary.js +1 -1
  23. package/dist/esm/accountSummary.js.map +1 -1
  24. package/dist/esm/constants.d.ts +2 -1
  25. package/dist/esm/constants.d.ts.map +1 -1
  26. package/dist/esm/constants.js +2 -1
  27. package/dist/esm/constants.js.map +1 -1
  28. package/dist/esm/types/ws.d.ts +2 -2
  29. package/dist/esm/types/ws.d.ts.map +1 -1
  30. package/dist/esm/types/ws.js +2 -0
  31. package/dist/esm/types/ws.js.map +1 -1
  32. package/dist/esm/utils/apiClient.d.ts +6 -0
  33. package/dist/esm/utils/apiClient.d.ts.map +1 -1
  34. package/dist/esm/utils/apiClient.js +10 -4
  35. package/dist/esm/utils/apiClient.js.map +1 -1
  36. package/dist/esm/websocket/LighterWsProvider.d.ts.map +1 -1
  37. package/dist/esm/websocket/LighterWsProvider.js +41 -8
  38. package/dist/esm/websocket/LighterWsProvider.js.map +1 -1
  39. package/dist/types/LighterProvider.d.ts.map +1 -1
  40. package/dist/types/constants.d.ts +2 -1
  41. package/dist/types/constants.d.ts.map +1 -1
  42. package/dist/types/types/ws.d.ts +2 -2
  43. package/dist/types/types/ws.d.ts.map +1 -1
  44. package/dist/types/utils/apiClient.d.ts +6 -0
  45. package/dist/types/utils/apiClient.d.ts.map +1 -1
  46. package/dist/types/websocket/LighterWsProvider.d.ts.map +1 -1
  47. package/package.json +3 -3
  48. package/src/LighterProvider.ts +1 -0
  49. package/src/accountSummary.ts +1 -1
  50. package/src/constants.ts +2 -1
  51. package/src/types/ws.ts +4 -2
  52. package/src/utils/apiClient.ts +11 -7
  53. package/src/websocket/LighterWsProvider.ts +65 -7
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/utils/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAA;AAOxB,gBAAgB;AAChB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;AAejE;;;;;;GAMG;AACH,qBAAa,wBAAyB,SAAQ,UAAU;CAAG;AAO3D,gBAAgB;AAChB,eAAO,MAAM,sBAAsB,EAAE,mBAmBpC,CAAA;AAED,gBAAgB;AAChB,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,MAAM,CAAC,EAAE,mBAAmB,CAAA;IAC5B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;gBAExC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB;IAO9D,OAAO,CAAC,QAAQ;IAaV,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;IAI1D;;;;OAIG;IACG,SAAS,CAAC,CAAC,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,SAAc,GACrB,OAAO,CAAC,CAAC,CAAC;IAoBb;;;;OAIG;IACG,aAAa,CAAC,CAAC,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;YAWzB,UAAU;CAiBzB"}
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/utils/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAA;AAOxB,gBAAgB;AAChB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;AAejE;;;;;;GAMG;AACH,qBAAa,wBAAyB,SAAQ,UAAU;CAAG;AAO3D,gBAAgB;AAChB,eAAO,MAAM,sBAAsB,EAAE,mBAmBpC,CAAA;AAED,gBAAgB;AAChB,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,MAAM,CAAC,EAAE,mBAAmB,CAAA;IAC5B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;gBAExC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB;IAO9D,OAAO,CAAC,QAAQ;IAaV,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;IAI1D;;;;OAIG;IACG,SAAS,CAAC,CAAC,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,SAAc,GACrB,OAAO,CAAC,CAAC,CAAC;IAeb;;;;OAIG;IACG,aAAa,CAAC,CAAC,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;YAWzB,UAAU;IAMxB;;;;OAIG;IACH,OAAO,CAAC,QAAQ;CAejB"}
@@ -1 +1 @@
1
- {"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAIlB,cAAc,EACd,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAIV,YAAY,EACb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAuEnC;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAChC,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;AAQD;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAA;CACnC;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAC7D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,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,MAAuB,EAC9B,WAAW,SAAY,EACvB,OAAO,GAAE,wBAA6B,EACtC,MAAM,CAAC,EAAE,cAAc;IAsBnB,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;cA4ChD,OAAO,IAAI,IAAI;cAMlB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB3B,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;YAuB5B,cAAc;YA6Dd,mBAAmB;YAqBnB,iBAAiB;IAK/B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqB1C,OAAO,CAAC,QAAQ;IAoEhB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,sBAAsB;IAiC9B;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,mBAAmB;CAc5B;AA4FD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC3B,UAAU,wBAAwB,KAAG,iBAEmB,CAAA"}
1
+ {"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAIlB,cAAc,EACd,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAIV,YAAY,EACb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAyEnC;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAChC,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;AAQD;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAA;CACnC;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAC7D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,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,SAAY,EACvB,OAAO,GAAE,wBAA6B,EACtC,MAAM,CAAC,EAAE,cAAc;IAsBnB,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;cA4ChD,OAAO,IAAI,IAAI;cAMlB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB3B,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;YAyB5B,cAAc;YA2Ed,mBAAmB;YAqBnB,iBAAiB;IAK/B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqB1C,OAAO,CAAC,QAAQ;IA0EhB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,sBAAsB;IAiC9B;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,mBAAmB;CAc5B;AA2GD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC3B,UAAU,wBAAwB,KAAG,iBAEmB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/perps-sdk-provider-lighter",
3
- "version": "1.4.0",
3
+ "version": "1.5.2",
4
4
  "description": "Lighter provider plugin for @lifi/perps-sdk",
5
5
  "homepage": "https://github.com/lifinance/perps-sdk",
6
6
  "bugs": {
@@ -46,10 +46,10 @@
46
46
  "dependencies": {
47
47
  "big.js": "^7.0.1",
48
48
  "viem": "^2.48.8",
49
- "@lifi/perps-types": "^1.4.0"
49
+ "@lifi/perps-types": "^1.5.1"
50
50
  },
51
51
  "peerDependencies": {
52
- "@lifi/perps-sdk": "^1.4.0"
52
+ "@lifi/perps-sdk": "^1.5.2"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public"
@@ -679,6 +679,7 @@ export const lighterProvider = (
679
679
  address: params.address,
680
680
  balances,
681
681
  collateralBalances,
682
+ positions,
682
683
  marginUsed: totalMarginUsed.toString(),
683
684
  unrealizedPnl: totalUnrealizedPnl.toString(),
684
685
  feeTier:
@@ -18,5 +18,5 @@ export function getAccountSummary(
18
18
  account: AccountResponse,
19
19
  positions: Position[]
20
20
  ): AccountSummary {
21
- return summarizeAccount(account, positions, false)
21
+ return summarizeAccount(account, positions, 'free')
22
22
  }
package/src/constants.ts CHANGED
@@ -8,11 +8,12 @@ import type { FeeTier } from '@lifi/perps-types'
8
8
  export const LIGHTER_PROVIDER_KEY = 'lighter'
9
9
 
10
10
  /**
11
- * Default mainnet REST base URL for Lighter.
11
+ * Default mainnet REST and WS base URL for Lighter.
12
12
  *
13
13
  * @public
14
14
  */
15
15
  export const DEFAULT_LIGHTER_REST_URL = 'https://mainnet.zklighter.elliot.ai'
16
+ export const DEFAULT_LIGHTER_WS_URL = 'wss://mainnet.zklighter.elliot.ai/stream'
16
17
 
17
18
  /** @internal */
18
19
  export const DEFAULT_TRADES_LIMIT = 50
package/src/types/ws.ts CHANGED
@@ -5,7 +5,9 @@
5
5
  //
6
6
  // Channels we subscribe to:
7
7
  // - market_stats/all → context across all perp markets
8
+ // - market_stats/{id} → context for one perp market
8
9
  // - spot_market_stats/all → context across all spot markets
10
+ // - spot_market_stats/{id} → context for one spot market
9
11
  // - order_book/{market_id} → bids/asks per market (stateful with deltas)
10
12
 
11
13
  /** @public */
@@ -40,7 +42,7 @@ export type LtWsMarketStats = {
40
42
  */
41
43
  export type LtWsMarketStatsAllMessage = LtWsMessage & {
42
44
  type: 'subscribed/market_stats' | 'update/market_stats'
43
- market_stats?: Record<string, LtWsMarketStats>
45
+ market_stats?: LtWsMarketStats | Record<string, LtWsMarketStats>
44
46
  }
45
47
 
46
48
  /**
@@ -70,7 +72,7 @@ export type LtWsSpotMarketStats = {
70
72
  */
71
73
  export type LtWsSpotMarketStatsAllMessage = LtWsMessage & {
72
74
  type: 'subscribed/spot_market_stats' | 'update/spot_market_stats'
73
- spot_market_stats?: Record<string, LtWsSpotMarketStats>
75
+ spot_market_stats?: LtWsSpotMarketStats | Record<string, LtWsSpotMarketStats>
74
76
  }
75
77
 
76
78
  /** @public */
@@ -137,12 +137,7 @@ export class LighterApiClient {
137
137
  `Lighter rejected the auth token for ${path}`
138
138
  )
139
139
  }
140
- if (status < 200 || status >= 300) {
141
- throw new PerpsError(
142
- PerpsErrorCode.ThirdPartyError,
143
- `Lighter API request failed: ${status} — ${JSON.stringify(data).slice(0, 200)}`
144
- )
145
- }
140
+ this.assertOk(path, status, data)
146
141
  return data as T
147
142
  }
148
143
 
@@ -167,6 +162,16 @@ export class LighterApiClient {
167
162
 
168
163
  private async getChecked<T>(path: string, params?: ApiParams): Promise<T> {
169
164
  const { status, data } = await this.getWithStatus<unknown>(path, params)
165
+ this.assertOk(path, status, data)
166
+ return data as T
167
+ }
168
+
169
+ /**
170
+ * Post-parse validation shared by every checked read: rejects a non-2xx HTTP
171
+ * status and a 200 body carrying a non-success `code`. Callers that surface a
172
+ * distinct auth-rejection error must run that check before this one.
173
+ */
174
+ private assertOk(path: string, status: number, data: unknown): void {
170
175
  if (status < 200 || status >= 300) {
171
176
  throw new PerpsError(
172
177
  PerpsErrorCode.ThirdPartyError,
@@ -180,6 +185,5 @@ export class LighterApiClient {
180
185
  `Lighter API error for ${path}: code ${errorCode} — ${JSON.stringify(data).slice(0, 200)}`
181
186
  )
182
187
  }
183
- return data as T
184
188
  }
185
189
  }
@@ -21,6 +21,7 @@ import type {
21
21
  import type { Address } from 'viem'
22
22
  import {
23
23
  DEFAULT_LIGHTER_REST_URL,
24
+ DEFAULT_LIGHTER_WS_URL,
24
25
  LIGHTER_BASE_FEE_TIER,
25
26
  LIGHTER_PROVIDER_KEY,
26
27
  } from '../constants.js'
@@ -50,7 +51,8 @@ import {
50
51
  } from '../utils/index.js'
51
52
 
52
53
  // Public channels: `marketsContext` (market_stats/all + spot_market_stats/all),
53
- // `orderbook` (order_book/N), `trades` (trade/N).
54
+ // `marketContext` (market_stats/N or spot_market_stats/N), `orderbook`
55
+ // (order_book/N), `trades` (trade/N).
54
56
  // Authenticated channels (require an `authProvider` option):
55
57
  // - orderUpdates → account_all_orders/{account_index}
56
58
  // - fills → account_all_trades/{account_index}
@@ -74,7 +76,7 @@ import {
74
76
  // Orderbook is stateful: the first message is a full snapshot, subsequent
75
77
  // messages are deltas where size=0 deletes a level.
76
78
 
77
- const DEFAULT_WS_URL = 'wss://mainnet.zklighter.elliot.ai/stream'
79
+ const LIGHTER_SPOT_MARKET_ID_OFFSET = 2048
78
80
 
79
81
  const LIGHTER_AUTH_CHANNEL = {
80
82
  orderUpdates: 'account_all_orders',
@@ -160,7 +162,7 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
160
162
  private readonly accountIndexPromises = new Map<string, Promise<number>>()
161
163
 
162
164
  constructor(
163
- wsUrl: string = DEFAULT_WS_URL,
165
+ wsUrl: string = DEFAULT_LIGHTER_WS_URL,
164
166
  providerKey = 'lighter',
165
167
  options: LighterWsProviderOptions = {},
166
168
  client?: PerpsSDKClient
@@ -286,6 +288,8 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
286
288
  switch (sub.channel) {
287
289
  case 'marketsContext':
288
290
  return 'marketsContext'
291
+ case 'marketContext':
292
+ return `marketContext:${sub.marketId}`
289
293
  case 'orderbook':
290
294
  return `orderbook:${sub.marketId}`
291
295
  case 'trades':
@@ -321,6 +325,20 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
321
325
  { channel: 'spot_market_stats/all', needsAuth: false },
322
326
  ]
323
327
  }
328
+ if (sub.channel === 'marketContext') {
329
+ const id = Number(sub.marketId)
330
+ if (!Number.isFinite(id)) {
331
+ throw new Error(
332
+ `Lighter WS: unknown market for marketId '${sub.marketId}'. ` +
333
+ 'MarketId must be a numeric market_id string.'
334
+ )
335
+ }
336
+ const prefix =
337
+ id >= LIGHTER_SPOT_MARKET_ID_OFFSET
338
+ ? 'spot_market_stats'
339
+ : 'market_stats'
340
+ return [{ channel: `${prefix}/${id}`, needsAuth: false }]
341
+ }
324
342
  if (sub.channel === 'orderbook') {
325
343
  const id = Number(sub.marketId)
326
344
  if (!Number.isFinite(id)) {
@@ -423,7 +441,11 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
423
441
  msg.type === 'subscribed/market_stats' ||
424
442
  msg.type === 'update/market_stats'
425
443
  ) {
426
- this.handleMarketStats((msg as LtWsMarketStatsAllMessage).market_stats)
444
+ this.handleMarketStats(
445
+ (msg as LtWsMarketStatsAllMessage).market_stats,
446
+ msg.channel,
447
+ 'market_stats'
448
+ )
427
449
  return
428
450
  }
429
451
 
@@ -432,7 +454,9 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
432
454
  msg.type === 'update/spot_market_stats'
433
455
  ) {
434
456
  this.handleMarketStats(
435
- (msg as LtWsSpotMarketStatsAllMessage).spot_market_stats
457
+ (msg as LtWsSpotMarketStatsAllMessage).spot_market_stats,
458
+ msg.channel,
459
+ 'spot_market_stats'
436
460
  )
437
461
  return
438
462
  }
@@ -579,15 +603,34 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
579
603
  }
580
604
 
581
605
  private handleMarketStats(
582
- stats?: Record<string, LtWsMarketStats | LtWsSpotMarketStats>
606
+ stats:
607
+ | LtWsMarketStats
608
+ | LtWsSpotMarketStats
609
+ | Record<string, LtWsMarketStats | LtWsSpotMarketStats>
610
+ | undefined,
611
+ channel: string | undefined,
612
+ prefix: 'market_stats' | 'spot_market_stats'
583
613
  ): void {
584
614
  if (!stats) {
585
615
  return
586
616
  }
587
- const entries = Object.values(stats)
617
+ const entries = marketStatsEntries(stats)
588
618
  if (entries.length === 0) {
589
619
  return
590
620
  }
621
+ const channelMarketId = this.marketIdFromChannel(channel, prefix)
622
+ if (channelMarketId !== null) {
623
+ for (const entry of entries) {
624
+ const ctx = mapMarketContext(entry)
625
+ if (ctx.marketId === String(channelMarketId)) {
626
+ this.emit(`marketContext:${ctx.marketId}`, {
627
+ channel: 'marketContext',
628
+ data: ctx,
629
+ })
630
+ }
631
+ }
632
+ return
633
+ }
591
634
  for (const entry of entries) {
592
635
  const ctx = mapMarketContext(entry)
593
636
  this.marketsContext[ctx.marketId] = ctx
@@ -702,6 +745,21 @@ function isValidLighterFrame(msg: LtWsMessage): boolean {
702
745
  return true
703
746
  }
704
747
 
748
+ function marketStatsEntries(
749
+ stats:
750
+ | LtWsMarketStats
751
+ | LtWsSpotMarketStats
752
+ | Record<string, LtWsMarketStats | LtWsSpotMarketStats>
753
+ ): Array<LtWsMarketStats | LtWsSpotMarketStats> {
754
+ return isMarketStatsEntry(stats) ? [stats] : Object.values(stats)
755
+ }
756
+
757
+ function isMarketStatsEntry(
758
+ value: unknown
759
+ ): value is LtWsMarketStats | LtWsSpotMarketStats {
760
+ return isObject(value) && typeof value.market_id === 'number'
761
+ }
762
+
705
763
  function applyLevels(
706
764
  book: Map<string, string>,
707
765
  levels: LtWsOrderBook['bids']