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

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.
@@ -231,6 +231,12 @@ async function requireApiKey(
231
231
  * step (e.g. approve) having mined. A reverted leg throws and aborts the
232
232
  * remaining legs. Each step's `txParams` carries chainId, target, function
233
233
  * name, args, and a human-readable abi from the backend.
234
+ *
235
+ * The wallet MUST already be on the leg's `txParams.chainId`: this signer
236
+ * broadcasts on the wallet's active chain and never switches it (switching is
237
+ * the integrator's responsibility — the widget drives it before signing). A leg
238
+ * whose target chain differs from the wallet's chain throws before broadcasting,
239
+ * so a token approve/deposit can never land on an unintended chain.
234
240
  * @internal
235
241
  */
236
242
  export async function signEvmTxActions(
@@ -256,6 +262,16 @@ export async function signEvmTxActions(
256
262
  abi: readonly string[]
257
263
  }
258
264
 
265
+ if (walletSigner.chain?.id !== params.chainId) {
266
+ throw new PerpsError(
267
+ PerpsErrorCode.SDKError,
268
+ `EVM_TX leg '${step.action}' targets chain ${params.chainId}, but the ` +
269
+ `connected wallet is on chain ${walletSigner.chain?.id ?? 'unknown'}. ` +
270
+ `Switch the wallet to chain ${params.chainId} before signing — the ` +
271
+ "SDK broadcasts on the wallet's active chain and does not switch it."
272
+ )
273
+ }
274
+
259
275
  const txHash = await walletSigner.writeContract({
260
276
  address: params.to,
261
277
  abi: parseAbi(params.abi),
@@ -112,9 +112,19 @@ interface SubState {
112
112
  needsAuth: boolean
113
113
  }
114
114
 
115
+ /**
116
+ * A maintained book level, keyed in {@link OrderbookState} by its price string.
117
+ * `priceNum` is the price parsed once on insert so the emit-time sort orders by
118
+ * a cached number instead of re-parsing every price on every comparison.
119
+ */
120
+ interface BookLevel {
121
+ size: string
122
+ priceNum: number
123
+ }
124
+
115
125
  interface OrderbookState {
116
- bids: Map<string, string>
117
- asks: Map<string, string>
126
+ bids: Map<string, BookLevel>
127
+ asks: Map<string, BookLevel>
118
128
  assetId: string
119
129
  }
120
130
 
@@ -511,8 +521,7 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
511
521
  return
512
522
  }
513
523
  const raw = collectAuthChannelItems<LtOrder>(msg, 'orders')
514
- // A registry miss warns once and schedules a cooldown-gated refetch (the
515
- // id may have listed after the snapshot); the order is skipped.
524
+ // Unknown market id (absent from the synced snapshot); the order is skipped.
516
525
  const data = classifyAndMapOrders(raw, (marketIndex) =>
517
526
  this.registry?.get(String(marketIndex))
518
527
  )
@@ -665,14 +674,8 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
665
674
  data: {
666
675
  provider: this.providerKey,
667
676
  marketId: assetId,
668
- bids: mapToLevels(
669
- state.bids,
670
- (a, b) => Number(b.price) - Number(a.price)
671
- ),
672
- asks: mapToLevels(
673
- state.asks,
674
- (a, b) => Number(a.price) - Number(b.price)
675
- ),
677
+ bids: mapToLevels(state.bids, true),
678
+ asks: mapToLevels(state.asks, false),
676
679
  timestamp: Date.now(),
677
680
  },
678
681
  })
@@ -761,25 +764,34 @@ function isMarketStatsEntry(
761
764
  }
762
765
 
763
766
  function applyLevels(
764
- book: Map<string, string>,
767
+ book: Map<string, BookLevel>,
765
768
  levels: LtWsOrderBook['bids']
766
769
  ): void {
767
770
  for (const level of levels) {
768
771
  if (level.size === '0' || Number(level.size) === 0) {
769
772
  book.delete(level.price)
770
773
  } else {
771
- book.set(level.price, level.size)
774
+ const existing = book.get(level.price)
775
+ if (existing) {
776
+ existing.size = level.size
777
+ } else {
778
+ book.set(level.price, {
779
+ size: level.size,
780
+ priceNum: Number(level.price),
781
+ })
782
+ }
772
783
  }
773
784
  }
774
785
  }
775
786
 
776
787
  function mapToLevels(
777
- book: Map<string, string>,
778
- compare: (a: { price: string }, b: { price: string }) => number
788
+ book: Map<string, BookLevel>,
789
+ descending: boolean
779
790
  ): Array<{ price: string; size: string }> {
780
- const levels = [...book].map(([price, size]) => ({ price, size }))
781
- levels.sort(compare)
782
- return levels
791
+ const entries = [...book].sort(([, a], [, b]) =>
792
+ descending ? b.priceNum - a.priceNum : a.priceNum - b.priceNum
793
+ )
794
+ return entries.map(([price, { size }]) => ({ price, size }))
783
795
  }
784
796
 
785
797
  /**