@lifi/perps-sdk-provider-lighter 32.0.0 → 33.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.
@@ -1 +1 @@
1
- {"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"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"}
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,EAML,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAuFnC;;;;;;;;;;;;;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;AAyBD;;;;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,oBAAoB,CAGlC;IAEH,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;IA6DnE;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;cASP,OAAO,IAAI,IAAI;cAOlB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3B;;;;;;;OAOG;YACW,gBAAgB;IAsB9B,2FAA2F;YAC7E,mBAAmB;IAYjC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;YAyB5B,cAAc;YAwGd,mBAAmB;YAqBnB,iBAAiB;IAK/B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqB1C,OAAO,CAAC,QAAQ;IA0GhB,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,eAAe;IAyDvB,4EAA4E;IAC5E,OAAO,CAAC,gBAAgB;IAqCxB,qEAAqE;IACrE,OAAO,CAAC,kBAAkB;IAgD1B,OAAO,CAAC,oBAAoB;IAW5B,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/perps-sdk-provider-lighter",
3
- "version": "32.0.0",
3
+ "version": "33.0.0",
4
4
  "description": "Lighter provider plugin for @lifi/perps-sdk",
5
5
  "homepage": "https://github.com/lifinance/perps-sdk",
6
6
  "bugs": {
@@ -47,7 +47,7 @@
47
47
  "@lifi/perps-types": "^19.0.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "@lifi/perps-sdk": "^21.0.0"
50
+ "@lifi/perps-sdk": "^21.1.0"
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
@@ -275,10 +275,26 @@ interface ReadOnlyCreationBackoff {
275
275
  * 4. Fresh 1h create via this instance's WASM signer + the user's registered
276
276
  * API key
277
277
  *
278
- * When none of these yields a token the auth-gated reads degrade gracefully:
279
- * - `getOrders`, `getActivity` return empty results (mirrors backend behaviour)
280
- * - `getOrder` throws `Unauthorized`
281
- * - `getAccount` returns zero fee tier rather than failing
278
+ * Status reads report the account's state and do not throw for a missing
279
+ * credential: `getAccount` returns a zero fee tier and
280
+ * `apiKeyRegistered: false` when the wallet has no locally stored API key
281
+ * matching the key registered on Lighter; otherwise it reads the fee tier
282
+ * with the resolved token and throws `Unauthorized` if Lighter rejects it.
283
+ * `accountExists` and `getDepositFlow` need no token.
284
+ *
285
+ * Data reads throw `PerpsError`, one code per fact:
286
+ * - `SetupRequired` when none of these sources yields a token. The SDK
287
+ * sends no venue request. `getOrders`, `getOrder`, `getFills`,
288
+ * `getPortfolioHistory` and `getActivity` need a token.
289
+ * - `Unauthorized` when Lighter rejects the token that was sent. An
290
+ * SDK-owned read-only token that Lighter reports as revoked is replaced
291
+ * and the read retried once first.
292
+ * - `AccountNotFound` when the wallet has no Lighter account. This also
293
+ * applies to `getPositions`, `getWithdrawableBalances` and
294
+ * `getAvailableToTrade`, which need no token. `getAvailableToTrade`
295
+ * reads the fee tier through `getAccount`, so it also throws
296
+ * `Unauthorized` when a matching local key's token is rejected.
297
+ * An account with no rows resolves an empty list.
282
298
  *
283
299
  * @public
284
300
  */
@@ -328,8 +344,7 @@ export interface LighterPerpsProvider extends PerpsProviderPlugin {
328
344
  /**
329
345
  * Resolve a Lighter auth token for `address`, following the resolution order
330
346
  * documented on {@link LighterProviderOptions} (the per-call override does not
331
- * apply here). Returns `undefined` when no source can produce a token —
332
- * callers degrade gracefully.
347
+ * apply here). Returns `undefined` when no source can produce a token.
333
348
  */
334
349
  resolveAuthToken(address: Address): Promise<string | undefined>
335
350
  }
@@ -454,8 +469,7 @@ export const createLighterProvider = (
454
469
  * as the credential that authorises read-only token creation, and as
455
470
  * the fallback while creation is failing, bounded by the
456
471
  * creation-retry backoff.
457
- * Returns `undefined` when no source can produce a token — reads degrade
458
- * gracefully.
472
+ * Returns `undefined` when no source can produce a token.
459
473
  */
460
474
  const resolveAuthToken = async (
461
475
  opts: SDKRequestOptions | undefined,
@@ -549,6 +563,25 @@ export const createLighterProvider = (
549
563
  return attempt
550
564
  }
551
565
 
566
+ /** {@link resolveAuthToken}, throwing `SetupRequired` when no source yields a token. */
567
+ const requireAuthToken = async (
568
+ read: string,
569
+ opts: SDKRequestOptions | undefined,
570
+ address: Address,
571
+ knownApiKey?: LighterApiKey
572
+ ): Promise<string> => {
573
+ const token = await resolveAuthToken(opts, address, knownApiKey)
574
+ if (token === undefined) {
575
+ throw new PerpsError(
576
+ PerpsErrorCode.SetupRequired,
577
+ `Lighter ${read} requires an auth token. Pass \`authToken\` to ` +
578
+ 'lighterProvider, register an API key + signer for on-demand creation, or ' +
579
+ 'forward `options.lighterAuthToken` on the call.'
580
+ )
581
+ }
582
+ return token
583
+ }
584
+
552
585
  const replaceRevokedReadOnlyToken = async (
553
586
  address: Address,
554
587
  revokedToken: string
@@ -945,6 +978,7 @@ export const createLighterProvider = (
945
978
  localKey !== null &&
946
979
  normalizeLighterPublicKey(localKey.apiKeyPublicKey) ===
947
980
  normalizeLighterPublicKey(registeredKey.public_key)
981
+ // Status read: a missing or stale credential reports `apiKeyRegistered: false`, not a throw.
948
982
  const token = apiKeyRegistered
949
983
  ? await resolveAuthToken(opts, params.address, localKey)
950
984
  : undefined
@@ -1149,13 +1183,11 @@ export const createLighterProvider = (
1149
1183
  params: ProviderGetWithdrawableBalancesParams,
1150
1184
  opts?: SDKRequestOptions
1151
1185
  ): Promise<ProviderWithdrawableBalance[]> {
1152
- const account = await fetchAccountIfExists(
1186
+ const account = await fetchDetailedAccount(
1153
1187
  apiClient(opts),
1154
1188
  params.address
1155
1189
  )
1156
- return account === undefined
1157
- ? []
1158
- : lighterWithdrawableBalances(account, collateral.assetIndex)
1190
+ return lighterWithdrawableBalances(account, collateral.assetIndex)
1159
1191
  },
1160
1192
 
1161
1193
  async getPositions(
@@ -1165,16 +1197,9 @@ export const createLighterProvider = (
1165
1197
  const client = apiClient(opts)
1166
1198
  const registry = getMarketRegistry(requireClient(), providerKey)
1167
1199
  const [account] = await Promise.all([
1168
- fetchAccountIfExists(client, params.address),
1200
+ fetchDetailedAccount(client, params.address),
1169
1201
  registry.sync(),
1170
1202
  ])
1171
- if (account === undefined) {
1172
- return {
1173
- provider: providerKey,
1174
- positions: [],
1175
- pagination: { limit: params.limit ?? 0, hasMore: false },
1176
- }
1177
- }
1178
1203
 
1179
1204
  let positions: Position[] = mapOpenPositions(account.positions, (id) =>
1180
1205
  toPerpsMarketDisplay(registry.require(String(id)))
@@ -1279,10 +1304,7 @@ export const createLighterProvider = (
1279
1304
  if (statuses.size === 0) {
1280
1305
  return empty
1281
1306
  }
1282
- const token = await resolveAuthToken(opts, params.address)
1283
- if (token === undefined) {
1284
- return empty
1285
- }
1307
+ const token = await requireAuthToken('orders read', opts, params.address)
1286
1308
 
1287
1309
  const client = apiClient(opts)
1288
1310
  const registry = getMarketRegistry(requireClient(), providerKey)
@@ -1371,15 +1393,7 @@ export const createLighterProvider = (
1371
1393
  params: ProviderGetOrderParams,
1372
1394
  opts?: SDKRequestOptions
1373
1395
  ): Promise<Order> {
1374
- const token = await resolveAuthToken(opts, params.address)
1375
- if (token === undefined) {
1376
- throw new PerpsError(
1377
- PerpsErrorCode.SDKError,
1378
- 'Lighter order lookup requires an auth token. Pass `authToken` to ' +
1379
- 'lighterProvider, register an API key + signer for on-demand creation, or ' +
1380
- 'forward `options.lighterAuthToken` on the call.'
1381
- )
1382
- }
1396
+ const token = await requireAuthToken('order lookup', opts, params.address)
1383
1397
 
1384
1398
  const client = apiClient(opts)
1385
1399
  const registry = getMarketRegistry(requireClient(), providerKey)
@@ -1477,14 +1491,7 @@ export const createLighterProvider = (
1477
1491
  params: ProviderGetFillsParams,
1478
1492
  opts?: SDKRequestOptions
1479
1493
  ): Promise<FillsResponse> {
1480
- const token = await resolveAuthToken(opts, params.address)
1481
- if (token === undefined) {
1482
- return {
1483
- provider: providerKey,
1484
- items: [],
1485
- pagination: { limit: params.limit ?? 0, hasMore: false },
1486
- }
1487
- }
1494
+ const token = await requireAuthToken('fills read', opts, params.address)
1488
1495
 
1489
1496
  const client = apiClient(opts)
1490
1497
  const registry = getMarketRegistry(requireClient(), providerKey)
@@ -1541,14 +1548,12 @@ export const createLighterProvider = (
1541
1548
  const sdkOwnsToken =
1542
1549
  opts?.lighterAuthToken === undefined && authTokenSource === undefined
1543
1550
  const apiKey = sdkOwnsToken ? await keyStore.get(params.address) : null
1544
- const token = await resolveAuthToken(
1551
+ const token = await requireAuthToken(
1552
+ 'portfolio history read',
1545
1553
  opts,
1546
1554
  params.address,
1547
1555
  apiKey ?? undefined
1548
1556
  )
1549
- if (token === undefined) {
1550
- return { range: params.range, points: [] }
1551
- }
1552
1557
 
1553
1558
  const client = apiClient(opts)
1554
1559
  const account = await plugin.getAccount({ address: params.address }, opts)
@@ -1603,14 +1608,11 @@ export const createLighterProvider = (
1603
1608
  params: ProviderGetActivityParams,
1604
1609
  opts?: SDKRequestOptions
1605
1610
  ): Promise<ActivitiesResponse> {
1606
- const token = await resolveAuthToken(opts, params.address)
1607
- if (token === undefined) {
1608
- return {
1609
- provider: providerKey,
1610
- items: [],
1611
- pagination: { limit: params.limit ?? 0, hasMore: false },
1612
- }
1613
- }
1611
+ const token = await requireAuthToken(
1612
+ 'activity read',
1613
+ opts,
1614
+ params.address
1615
+ )
1614
1616
 
1615
1617
  const inputCursor = decodeActivityCursor(params.cursor)
1616
1618
  const client = apiClient(opts)
@@ -293,15 +293,6 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
293
293
 
294
294
  const wireChannels = await this.resolveChannel(sub)
295
295
 
296
- // Reject before any wire sub registers: a registered sub whose token can
297
- // never be resolved is retried on every reopen without the caller ever
298
- // seeing the failure.
299
- for (const { channel, needsAuth, address } of wireChannels) {
300
- if (needsAuth) {
301
- await this.requireAuthToken(channel, address)
302
- }
303
- }
304
-
305
296
  // Acquired before the wire subs register, so a rejected spot-mark open
306
297
  // leaves no `user_stats`/`account_all` entry behind for the next replay.
307
298
  const releaseSpotMarks =
@@ -392,8 +383,9 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
392
383
  * The auth token a gated channel's subscribe frame carries, or a throw when
393
384
  * no resolver is wired or the resolver yields none. Shared by the
394
385
  * subscribe-time guard and the per-send resolve so both report one message.
395
- * Throws {@link PerpsError} with `Unauthorized` so a caller branches on the
396
- * code, as it does for the Ondo and Lighter REST auth failures.
386
+ * Throws {@link PerpsError}: `SetupRequired` when the resolver yields no
387
+ * token, the code the REST reads throw for the same missing credential, and
388
+ * `SDKError` when no resolver is wired, which no account setup can fix.
397
389
  */
398
390
  private async requireAuthToken(
399
391
  channel: string,
@@ -402,7 +394,7 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
402
394
  const resolve = this.authTokenResolver()
403
395
  if (!resolve || !address) {
404
396
  throw new PerpsError(
405
- PerpsErrorCode.Unauthorized,
397
+ PerpsErrorCode.SDKError,
406
398
  `Lighter WS channel '${channel}' requires authentication but no auth-token resolver was available. ` +
407
399
  'Register `lighterProvider()` on the same client, or pass `resolveAuthToken` to `lighterWsProvider`.'
408
400
  )
@@ -410,7 +402,7 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
410
402
  const token = await resolve(address)
411
403
  if (!token) {
412
404
  throw new PerpsError(
413
- PerpsErrorCode.Unauthorized,
405
+ PerpsErrorCode.SetupRequired,
414
406
  `Lighter WS channel '${channel}' requires authentication but no token was available for ${address}.`
415
407
  )
416
408
  }
@@ -534,13 +526,18 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
534
526
  sub.channel === 'fills' ||
535
527
  sub.channel === 'positions'
536
528
  ) {
537
- const accountIndex = await this.resolveAccountIndex(sub.address)
538
529
  const lighterChannel = LIGHTER_AUTH_CHANNEL[sub.channel]
539
530
  // `account_all_trades` is publicly readable per the Lighter WS spec —
540
531
  // an auth token only filters events to the user's own account, which
541
532
  // we don't currently use to scope further. Skip the token here so a
542
533
  // user without a registered API key still gets their fill stream.
543
534
  const needsAuth = sub.channel !== 'fills'
535
+ // Before the account lookup and before registration: a registered sub
536
+ // with no token would fail on every reopen without the caller seeing it.
537
+ if (needsAuth) {
538
+ await this.requireAuthToken(lighterChannel, sub.address)
539
+ }
540
+ const accountIndex = await this.resolveAccountIndex(sub.address)
544
541
  return [
545
542
  {
546
543
  channel: `${lighterChannel}/${accountIndex}`,