@pear-protocol/symmio-client 0.3.12 → 0.3.14

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.
@@ -70,6 +70,9 @@ function toBinanceSymbol(symmSymbol) {
70
70
  // src/utils/binance-ws.ts
71
71
  var BINANCE_WS_URL = "wss://fstream.binance.com/market/ws";
72
72
  var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
73
+ var IDLE_CLOSE_DELAY_MS = 3e4;
74
+ var STALE_CONNECTION_MS = 3e4;
75
+ var STALE_CHECK_INTERVAL_MS = 1e4;
73
76
  var STABLE_QUOTES = ["USDT0", "USDT", "USDC", "USDE", "USDH", "USD"];
74
77
  function normalizeBaseSymbol(symbol) {
75
78
  const normalized = symbol.toUpperCase().trim();
@@ -119,8 +122,11 @@ var BinanceWsManager = class {
119
122
  streams = /* @__PURE__ */ new Map();
120
123
  reconnectAttempt = 0;
121
124
  reconnectTimer = null;
125
+ idleCloseTimer = null;
126
+ staleCheckTimer = null;
122
127
  intentionalClose = false;
123
- pendingSubscribes = [];
128
+ pendingSubscribes = /* @__PURE__ */ new Set();
129
+ lastMessageAt = 0;
124
130
  idCounter = 0;
125
131
  /**
126
132
  * Subscribe to a kline stream. Returns an unsubscribe function.
@@ -193,10 +199,10 @@ var BinanceWsManager = class {
193
199
  */
194
200
  destroy() {
195
201
  this.intentionalClose = true;
196
- if (this.reconnectTimer) {
197
- clearTimeout(this.reconnectTimer);
198
- this.reconnectTimer = null;
199
- }
202
+ this.clearReconnectTimer();
203
+ this.clearIdleCloseTimer();
204
+ this.clearStaleCheckTimer();
205
+ this.pendingSubscribes.clear();
200
206
  if (this.ws) {
201
207
  this.ws.close();
202
208
  this.ws = null;
@@ -216,6 +222,7 @@ var BinanceWsManager = class {
216
222
  }
217
223
  sub.callbacks.set(id, cb);
218
224
  if (isNew) {
225
+ this.clearIdleCloseTimer();
219
226
  this.ensureConnected();
220
227
  this.sendSubscribe([streamName]);
221
228
  }
@@ -227,18 +234,14 @@ var BinanceWsManager = class {
227
234
  if (sub.callbacks.size === 0) {
228
235
  this.streams.delete(streamName);
229
236
  this.sendUnsubscribe([streamName]);
230
- if (this.streams.size === 0 && this.ws) {
231
- this.intentionalClose = true;
232
- this.ws.close();
233
- this.ws = null;
234
- this.intentionalClose = false;
235
- }
237
+ this.scheduleIdleClose();
236
238
  }
237
239
  }
238
240
  ensureConnected() {
239
241
  if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
240
242
  return;
241
243
  }
244
+ this.clearReconnectTimer();
242
245
  this.connect();
243
246
  }
244
247
  connect() {
@@ -247,23 +250,27 @@ var BinanceWsManager = class {
247
250
  this.ws = new WebSocket(BINANCE_WS_URL);
248
251
  this.ws.onopen = () => {
249
252
  this.reconnectAttempt = 0;
250
- const activeStreams = Array.from(this.streams.keys());
253
+ this.lastMessageAt = Date.now();
254
+ this.startStaleCheck();
255
+ const activeStreams = Array.from(
256
+ /* @__PURE__ */ new Set([...this.streams.keys(), ...this.pendingSubscribes])
257
+ );
258
+ this.pendingSubscribes.clear();
251
259
  if (activeStreams.length > 0) {
252
260
  this.sendSubscribe(activeStreams);
253
261
  }
254
- if (this.pendingSubscribes.length > 0) {
255
- this.sendSubscribe(this.pendingSubscribes);
256
- this.pendingSubscribes = [];
257
- }
258
262
  };
259
263
  this.ws.onmessage = (event) => {
260
264
  try {
261
265
  const data = JSON.parse(event.data);
266
+ this.lastMessageAt = Date.now();
262
267
  this.handleMessage(data);
263
268
  } catch {
264
269
  }
265
270
  };
266
271
  this.ws.onclose = () => {
272
+ this.ws = null;
273
+ this.clearStaleCheckTimer();
267
274
  if (this.intentionalClose) return;
268
275
  this.scheduleReconnect();
269
276
  };
@@ -297,25 +304,27 @@ var BinanceWsManager = class {
297
304
  }
298
305
  sendSubscribe(streams) {
299
306
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
300
- this.pendingSubscribes.push(...streams);
307
+ streams.forEach((stream) => this.pendingSubscribes.add(stream));
301
308
  return;
302
309
  }
310
+ const params = Array.from(new Set(streams));
311
+ if (params.length === 0) return;
303
312
  this.ws.send(JSON.stringify({
304
313
  method: "SUBSCRIBE",
305
- params: streams,
314
+ params,
306
315
  id: Date.now()
307
316
  }));
308
317
  }
309
318
  sendUnsubscribe(streams) {
310
319
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
311
- this.pendingSubscribes = this.pendingSubscribes.filter(
312
- (s) => !streams.includes(s)
313
- );
320
+ streams.forEach((stream) => this.pendingSubscribes.delete(stream));
314
321
  return;
315
322
  }
323
+ const params = Array.from(new Set(streams));
324
+ if (params.length === 0) return;
316
325
  this.ws.send(JSON.stringify({
317
326
  method: "UNSUBSCRIBE",
318
- params: streams,
327
+ params,
319
328
  id: Date.now()
320
329
  }));
321
330
  }
@@ -329,6 +338,44 @@ var BinanceWsManager = class {
329
338
  this.connect();
330
339
  }, delay);
331
340
  }
341
+ scheduleIdleClose() {
342
+ if (this.streams.size > 0 || this.idleCloseTimer) return;
343
+ this.clearReconnectTimer();
344
+ if (!this.ws) return;
345
+ this.idleCloseTimer = setTimeout(() => {
346
+ this.idleCloseTimer = null;
347
+ if (this.streams.size > 0 || !this.ws) return;
348
+ this.intentionalClose = true;
349
+ this.ws.close();
350
+ this.ws = null;
351
+ this.intentionalClose = false;
352
+ this.clearStaleCheckTimer();
353
+ }, IDLE_CLOSE_DELAY_MS);
354
+ }
355
+ startStaleCheck() {
356
+ this.clearStaleCheckTimer();
357
+ this.staleCheckTimer = setInterval(() => {
358
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
359
+ if (this.streams.size === 0) return;
360
+ if (Date.now() - this.lastMessageAt < STALE_CONNECTION_MS) return;
361
+ this.ws.close();
362
+ }, STALE_CHECK_INTERVAL_MS);
363
+ }
364
+ clearReconnectTimer() {
365
+ if (!this.reconnectTimer) return;
366
+ clearTimeout(this.reconnectTimer);
367
+ this.reconnectTimer = null;
368
+ }
369
+ clearIdleCloseTimer() {
370
+ if (!this.idleCloseTimer) return;
371
+ clearTimeout(this.idleCloseTimer);
372
+ this.idleCloseTimer = null;
373
+ }
374
+ clearStaleCheckTimer() {
375
+ if (!this.staleCheckTimer) return;
376
+ clearInterval(this.staleCheckTimer);
377
+ this.staleCheckTimer = null;
378
+ }
332
379
  };
333
380
  var _instance = null;
334
381
  function getBinanceWsManager() {
@@ -359,6 +406,28 @@ function getNextRefCount(binanceSymbol) {
359
406
  function getPrevRefCount(binanceSymbol) {
360
407
  return Math.max(0, (refCounts.get(binanceSymbol) ?? 0) - 1);
361
408
  }
409
+ function addMappedSymbol(binanceSymbol, symmSymbol) {
410
+ const symbols = streamSymbols.get(binanceSymbol) ?? /* @__PURE__ */ new Map();
411
+ symbols.set(symmSymbol, (symbols.get(symmSymbol) ?? 0) + 1);
412
+ streamSymbols.set(binanceSymbol, symbols);
413
+ }
414
+ function removeMappedSymbol(binanceSymbol, symmSymbol) {
415
+ const symbols = streamSymbols.get(binanceSymbol);
416
+ if (!symbols) return false;
417
+ const currentCount = symbols.get(symmSymbol) ?? 0;
418
+ if (currentCount <= 0) return false;
419
+ if (currentCount === 1) {
420
+ symbols.delete(symmSymbol);
421
+ } else {
422
+ symbols.set(symmSymbol, currentCount - 1);
423
+ }
424
+ if (symbols.size === 0) {
425
+ streamSymbols.delete(binanceSymbol);
426
+ } else {
427
+ streamSymbols.set(binanceSymbol, symbols);
428
+ }
429
+ return true;
430
+ }
362
431
  var useBinanceMarkPriceStore = create((set) => ({
363
432
  markPrices: {},
364
433
  fundingRates: {},
@@ -367,9 +436,7 @@ var useBinanceMarkPriceStore = create((set) => ({
367
436
  const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
368
437
  const nextRefCount = getNextRefCount(binanceSymbol);
369
438
  refCounts.set(binanceSymbol, nextRefCount);
370
- const symbols = streamSymbols.get(binanceSymbol) ?? /* @__PURE__ */ new Set();
371
- symbols.add(symmSymbol);
372
- streamSymbols.set(binanceSymbol, symbols);
439
+ addMappedSymbol(binanceSymbol, symmSymbol);
373
440
  if (allMarkPricesRefCount === 0) {
374
441
  const wsManager = getBinanceWsManager();
375
442
  allMarkPricesUnsubscribe = wsManager.subscribeAllMarkPrices((entries) => {
@@ -384,7 +451,7 @@ var useBinanceMarkPriceStore = create((set) => ({
384
451
  nextMarkPrices ??= { ...state.markPrices };
385
452
  nextFundingRates ??= { ...state.fundingRates };
386
453
  nextFundingTimes ??= { ...state.nextFundingTimes };
387
- mappedSymbols.forEach((mappedSymbol) => {
454
+ mappedSymbols.forEach((_count, mappedSymbol) => {
388
455
  nextMarkPrices[mappedSymbol] = entry.markPrice;
389
456
  nextFundingRates[mappedSymbol] = entry.fundingRate;
390
457
  nextFundingTimes[mappedSymbol] = entry.nextFundingTime;
@@ -405,14 +472,9 @@ var useBinanceMarkPriceStore = create((set) => ({
405
472
  },
406
473
  unsubscribeSymbol: (symmSymbol, rawBinanceSymbol) => {
407
474
  const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
408
- const symbols = streamSymbols.get(binanceSymbol);
409
- if (symbols) {
410
- symbols.delete(symmSymbol);
411
- if (symbols.size === 0) {
412
- streamSymbols.delete(binanceSymbol);
413
- } else {
414
- streamSymbols.set(binanceSymbol, symbols);
415
- }
475
+ const removedSubscription = removeMappedSymbol(binanceSymbol, symmSymbol);
476
+ if (!removedSubscription) {
477
+ return;
416
478
  }
417
479
  const nextRefCount = getPrevRefCount(binanceSymbol);
418
480
  if (nextRefCount === 0) {
@@ -426,6 +488,10 @@ var useBinanceMarkPriceStore = create((set) => ({
426
488
  allMarkPricesUnsubscribe = null;
427
489
  }
428
490
  set((state) => {
491
+ const hasMappedSymbol = Boolean(streamSymbols.get(binanceSymbol)?.has(symmSymbol));
492
+ if (hasMappedSymbol) {
493
+ return state;
494
+ }
429
495
  if (state.markPrices[symmSymbol] == null && state.fundingRates[symmSymbol] == null && state.nextFundingTimes[symmSymbol] == null) {
430
496
  return state;
431
497
  }
@@ -510,7 +576,7 @@ var symmKeys = {
510
576
  signature: (address, chainId) => ["symm", "signature", address, chainId],
511
577
  auth: (accountAddress, chainId, signerAddress) => ["symm", "auth", accountAddress, chainId, signerAddress],
512
578
  approval: (owner, spender, chainId, token) => ["symm", "approval", owner, spender, chainId, token],
513
- balances: (address, chainId) => ["symm", "balances", address, chainId],
579
+ balances: (address, chainId, multiAccountAddress) => multiAccountAddress === void 0 ? ["symm", "balances", address, chainId] : ["symm", "balances", address, chainId, multiAccountAddress],
514
580
  positions: (params) => ["symm", "positions", params],
515
581
  openOrders: (params) => ["symm", "openOrders", params],
516
582
  tradeHistory: (params) => ["symm", "tradeHistory", params],
@@ -543,8 +609,33 @@ var useSymmWsStore = create((set) => ({
543
609
  }));
544
610
 
545
611
  // src/react/hooks/use-symm-ws.ts
546
- function asUnsubscribeFn(value) {
547
- return typeof value === "function" ? value : null;
612
+ var wsOwnerCounts = /* @__PURE__ */ new WeakMap();
613
+ var wsConnectPromises = /* @__PURE__ */ new WeakMap();
614
+ function addWsOwner(ws) {
615
+ wsOwnerCounts.set(ws, (wsOwnerCounts.get(ws) ?? 0) + 1);
616
+ }
617
+ function removeWsOwner(ws) {
618
+ const nextCount = Math.max(0, (wsOwnerCounts.get(ws) ?? 0) - 1);
619
+ if (nextCount === 0) {
620
+ wsOwnerCounts.delete(ws);
621
+ } else {
622
+ wsOwnerCounts.set(ws, nextCount);
623
+ }
624
+ return nextCount;
625
+ }
626
+ function connectShared(ws) {
627
+ if (ws.isConnected()) {
628
+ return Promise.resolve();
629
+ }
630
+ const existing = wsConnectPromises.get(ws);
631
+ if (existing) {
632
+ return existing;
633
+ }
634
+ const promise = ws.connect().finally(() => {
635
+ wsConnectPromises.delete(ws);
636
+ });
637
+ wsConnectPromises.set(ws, promise);
638
+ return promise;
548
639
  }
549
640
  function useSymmWs(params = {}) {
550
641
  const ctx = useContext(SymmContext);
@@ -561,114 +652,76 @@ function useSymmWs(params = {}) {
561
652
  }
562
653
  const ws = symmCoreClient.ws;
563
654
  const addr = accountAddress;
564
- const unsubscribers = [];
565
655
  let cancelled = false;
566
- const removeOnConnect = ws.onConnect(() => {
567
- setConnected(true);
656
+ addWsOwner(ws);
657
+ const removeOnConnect = ws.onConnect(() => setConnected(true));
658
+ const removeOnDisconnect = ws.onDisconnect(() => setConnected(false));
659
+ const subscriptions = [];
660
+ const addSubscription = (channel, handler) => {
661
+ ws.subscribe(channel, addr, chainId, handler);
662
+ subscriptions.push({ channel, handler });
663
+ };
664
+ addSubscription("positions", () => {
665
+ queryClient.invalidateQueries({ queryKey: symmKeys.positionsRoot });
568
666
  });
569
- const removeOnDisconnect = ws.onDisconnect(() => {
570
- setConnected(false);
667
+ addSubscription("open-orders", () => {
668
+ queryClient.invalidateQueries({ queryKey: symmKeys.openOrdersRoot });
571
669
  });
572
- const removeOnError = asUnsubscribeFn(ws.onError?.(() => {
573
- }));
574
- const removeOnWelcome = asUnsubscribeFn(ws.onWelcome?.(() => {
575
- }));
576
- unsubscribers.push(removeOnConnect, removeOnDisconnect);
577
- if (removeOnError) unsubscribers.push(removeOnError);
578
- if (removeOnWelcome) unsubscribers.push(removeOnWelcome);
579
- const positionsUnsub = asUnsubscribeFn(
580
- ws.subscribeToPositions(addr, chainId, () => {
581
- queryClient.invalidateQueries({
582
- queryKey: symmKeys.positionsRoot
583
- });
584
- })
585
- );
586
- if (positionsUnsub) unsubscribers.push(positionsUnsub);
587
- const openOrdersUnsub = asUnsubscribeFn(
588
- ws.subscribeToOpenOrders(addr, chainId, () => {
589
- queryClient.invalidateQueries({
590
- queryKey: symmKeys.openOrdersRoot
591
- });
592
- })
593
- );
594
- if (openOrdersUnsub) unsubscribers.push(openOrdersUnsub);
595
- const tradesUnsub = asUnsubscribeFn(
596
- ws.subscribeToTrades(addr, chainId, () => {
597
- queryClient.invalidateQueries({
598
- queryKey: symmKeys.tradeHistoryRoot
599
- });
600
- })
601
- );
602
- if (tradesUnsub) unsubscribers.push(tradesUnsub);
603
- const accountSummaryUnsub = asUnsubscribeFn(
604
- ws.subscribeToAccountSummary(addr, chainId, () => {
605
- queryClient.invalidateQueries({
606
- queryKey: symmKeys.balances(accountAddress, chainId)
607
- });
608
- queryClient.invalidateQueries({
609
- queryKey: symmKeys.accountSummary(accountAddress, chainId)
610
- });
611
- })
612
- );
613
- if (accountSummaryUnsub) unsubscribers.push(accountSummaryUnsub);
614
- const notificationsUnsub = asUnsubscribeFn(
615
- ws.subscribeToNotifications(addr, chainId, () => {
616
- queryClient.invalidateQueries({
617
- queryKey: symmKeys.notifications({ accountAddress, chainId })
618
- });
619
- queryClient.invalidateQueries({
620
- queryKey: symmKeys.unreadCount({ accountAddress, chainId })
621
- });
622
- })
623
- );
624
- if (notificationsUnsub) unsubscribers.push(notificationsUnsub);
625
- const tpslUnsub = asUnsubscribeFn(
626
- ws.subscribeToTpsl(addr, chainId, () => {
627
- queryClient.invalidateQueries({ queryKey: symmKeys.tpslOrdersRoot });
628
- queryClient.invalidateQueries({ queryKey: symmKeys.openOrdersRoot });
629
- })
630
- );
631
- if (tpslUnsub) unsubscribers.push(tpslUnsub);
632
- const twapUnsub = asUnsubscribeFn(
633
- ws.subscribeToTwapOrders(addr, chainId, () => {
634
- queryClient.invalidateQueries({ queryKey: symmKeys.twapOrdersRoot });
635
- queryClient.invalidateQueries({ queryKey: symmKeys.openOrdersRoot });
636
- })
637
- );
638
- if (twapUnsub) unsubscribers.push(twapUnsub);
639
- const triggerOrdersUnsub = asUnsubscribeFn(
640
- ws.subscribeToTriggerOrders(addr, chainId, () => {
641
- queryClient.invalidateQueries({ queryKey: symmKeys.triggerOrdersRoot });
642
- queryClient.invalidateQueries({ queryKey: symmKeys.openOrdersRoot });
643
- })
644
- );
645
- if (triggerOrdersUnsub) unsubscribers.push(triggerOrdersUnsub);
646
- const executionsUnsub = asUnsubscribeFn(
647
- ws.subscribeToExecutions(addr, chainId, () => {
648
- queryClient.invalidateQueries({
649
- queryKey: symmKeys.positionsRoot
650
- });
651
- queryClient.invalidateQueries({
652
- queryKey: symmKeys.portfolioRoot
653
- });
654
- })
655
- );
656
- if (executionsUnsub) unsubscribers.push(executionsUnsub);
657
- void ws.connect().then(() => {
658
- if (cancelled) {
659
- return;
670
+ addSubscription("trades", () => {
671
+ queryClient.invalidateQueries({ queryKey: symmKeys.tradeHistoryRoot });
672
+ });
673
+ addSubscription("account-summary", () => {
674
+ queryClient.invalidateQueries({
675
+ queryKey: symmKeys.balances(accountAddress, chainId)
676
+ });
677
+ queryClient.invalidateQueries({
678
+ queryKey: symmKeys.accountSummary(accountAddress, chainId)
679
+ });
680
+ });
681
+ addSubscription("notifications", () => {
682
+ queryClient.invalidateQueries({
683
+ queryKey: symmKeys.notifications({ accountAddress, chainId })
684
+ });
685
+ queryClient.invalidateQueries({
686
+ queryKey: symmKeys.unreadCount({ accountAddress, chainId })
687
+ });
688
+ });
689
+ addSubscription("tpsl", () => {
690
+ queryClient.invalidateQueries({ queryKey: symmKeys.tpslOrdersRoot });
691
+ queryClient.invalidateQueries({ queryKey: symmKeys.openOrdersRoot });
692
+ });
693
+ addSubscription("twap-orders", () => {
694
+ queryClient.invalidateQueries({ queryKey: symmKeys.twapOrdersRoot });
695
+ queryClient.invalidateQueries({ queryKey: symmKeys.openOrdersRoot });
696
+ });
697
+ addSubscription("trigger-orders", () => {
698
+ queryClient.invalidateQueries({ queryKey: symmKeys.triggerOrdersRoot });
699
+ queryClient.invalidateQueries({ queryKey: symmKeys.openOrdersRoot });
700
+ });
701
+ addSubscription("executions", () => {
702
+ queryClient.invalidateQueries({ queryKey: symmKeys.positionsRoot });
703
+ queryClient.invalidateQueries({ queryKey: symmKeys.portfolioRoot });
704
+ });
705
+ void connectShared(ws).then(() => {
706
+ if (cancelled) return;
707
+ if (ws.isConnected()) {
708
+ setConnected(true);
660
709
  }
661
710
  }).catch(() => {
662
- if (cancelled) {
663
- return;
664
- }
711
+ if (cancelled) return;
665
712
  setConnected(false);
666
713
  });
667
714
  return () => {
668
715
  cancelled = true;
669
- unsubscribers.forEach((unsubscribe) => unsubscribe());
670
- ws.disconnect();
671
- setConnected(false);
716
+ removeOnConnect();
717
+ removeOnDisconnect();
718
+ subscriptions.forEach(({ channel, handler }) => {
719
+ ws.unsubscribe(channel, addr, chainId, handler);
720
+ });
721
+ if (removeWsOwner(ws) === 0) {
722
+ ws.disconnect();
723
+ setConnected(false);
724
+ }
672
725
  };
673
726
  }, [symmCoreClient, accountAddress, chainId, queryClient, setConnected]);
674
727
  return { isConnected };
@@ -25587,7 +25640,7 @@ function useSymmBalances(params) {
25587
25640
  const internalEnabled = !!symmCoreClient && !!userAddress;
25588
25641
  return useQuery({
25589
25642
  ...params.query,
25590
- queryKey: symmKeys.balances(userAddress, chainId),
25643
+ queryKey: symmKeys.balances(userAddress, chainId, multiAccountAddress),
25591
25644
  queryFn: () => symmCoreClient.accounts.getBalanceInfo({
25592
25645
  userAddress,
25593
25646
  chainId,
@@ -25596,6 +25649,242 @@ function useSymmBalances(params) {
25596
25649
  enabled: internalEnabled && (params.query?.enabled ?? true)
25597
25650
  });
25598
25651
  }
25652
+
25653
+ // src/utils/account-overview.ts
25654
+ var BALANCE_INFO_KEYS = [
25655
+ "allocatedBalance",
25656
+ "allocated_balance",
25657
+ "cva",
25658
+ "lf",
25659
+ "partyAmm",
25660
+ "partyAMM",
25661
+ "party_a_mm",
25662
+ "mm",
25663
+ "lockedPartyAMM",
25664
+ "upnl"
25665
+ ];
25666
+ function isRecord(value) {
25667
+ return typeof value === "object" && value !== null;
25668
+ }
25669
+ function hasBalanceInfoShape(value) {
25670
+ return isRecord(value) && BALANCE_INFO_KEYS.some((key) => key in value);
25671
+ }
25672
+ function readValue(source, keys) {
25673
+ for (const key of keys) {
25674
+ if (key in source) {
25675
+ return source[key];
25676
+ }
25677
+ }
25678
+ return void 0;
25679
+ }
25680
+ function toNumber(value) {
25681
+ if (value === null || value === void 0 || value === "") {
25682
+ return 0;
25683
+ }
25684
+ if (typeof value === "bigint") {
25685
+ return Number(value);
25686
+ }
25687
+ const parsed = Number(value);
25688
+ return Number.isFinite(parsed) ? parsed : 0;
25689
+ }
25690
+ function toDisplayString(value) {
25691
+ if (Object.is(value, -0) || Math.abs(value) < Number.EPSILON) {
25692
+ return "0";
25693
+ }
25694
+ return String(value);
25695
+ }
25696
+ function readNumber(source, keys) {
25697
+ return toNumber(readValue(source, keys));
25698
+ }
25699
+ function readTimestamp(source) {
25700
+ const timestamp = readValue(source, ["timestamp"]);
25701
+ if (timestamp === void 0 || timestamp === null) {
25702
+ return void 0;
25703
+ }
25704
+ const parsed = Number(timestamp);
25705
+ return Number.isFinite(parsed) ? parsed : void 0;
25706
+ }
25707
+ function getBalanceInfoContainer(response) {
25708
+ if (!isRecord(response)) {
25709
+ return void 0;
25710
+ }
25711
+ if (hasBalanceInfoShape(response)) {
25712
+ return response;
25713
+ }
25714
+ const data = response.data;
25715
+ if (isRecord(data)) {
25716
+ return data;
25717
+ }
25718
+ return response;
25719
+ }
25720
+ function getSymmAccountBalanceInfo(response, accountAddress) {
25721
+ const container = getBalanceInfoContainer(response);
25722
+ if (!container) {
25723
+ return void 0;
25724
+ }
25725
+ if (hasBalanceInfoShape(container)) {
25726
+ return container;
25727
+ }
25728
+ if (accountAddress) {
25729
+ const normalizedAddress = accountAddress.toLowerCase();
25730
+ const direct = container[accountAddress] ?? container[normalizedAddress];
25731
+ if (isRecord(direct) && hasBalanceInfoShape(direct)) {
25732
+ return direct;
25733
+ }
25734
+ const matchingEntry = Object.entries(container).find(
25735
+ ([key]) => key.toLowerCase() === normalizedAddress
25736
+ );
25737
+ if (isRecord(matchingEntry?.[1]) && hasBalanceInfoShape(matchingEntry[1])) {
25738
+ return matchingEntry[1];
25739
+ }
25740
+ }
25741
+ const values = Object.values(container);
25742
+ if (values.length === 1 && isRecord(values[0]) && hasBalanceInfoShape(values[0])) {
25743
+ return values[0];
25744
+ }
25745
+ return void 0;
25746
+ }
25747
+ function computeSymmAccountOverview({
25748
+ balanceInfo,
25749
+ upnl: upnlOverride,
25750
+ netDeposited
25751
+ }) {
25752
+ const allocatedBalance = readNumber(balanceInfo, [
25753
+ "allocatedBalance",
25754
+ "allocated_balance"
25755
+ ]);
25756
+ const cva = readNumber(balanceInfo, ["cva", "lockedCVA", "locked_cva"]);
25757
+ const lf = readNumber(balanceInfo, ["lf", "lockedLF", "locked_lf"]);
25758
+ const partyAmm = readNumber(balanceInfo, [
25759
+ "partyAmm",
25760
+ "partyAMM",
25761
+ "party_a_mm",
25762
+ "mm",
25763
+ "lockedPartyAMM",
25764
+ "locked_party_a_mm"
25765
+ ]);
25766
+ const pendingCva = readNumber(balanceInfo, [
25767
+ "pendingCva",
25768
+ "pending_cva",
25769
+ "pendingLockedCVA",
25770
+ "pending_locked_cva"
25771
+ ]);
25772
+ const pendingLf = readNumber(balanceInfo, [
25773
+ "pendingLf",
25774
+ "pending_lf",
25775
+ "pendingLockedLF",
25776
+ "pending_locked_lf"
25777
+ ]);
25778
+ const pendingPartyAmm = readNumber(balanceInfo, [
25779
+ "pendingPartyAmm",
25780
+ "pendingPartyAMM",
25781
+ "pending_party_a_mm",
25782
+ "pendingMm",
25783
+ "pending_mm",
25784
+ "pendingLockedPartyAMM",
25785
+ "pending_locked_party_a_mm"
25786
+ ]);
25787
+ const upnl = upnlOverride === void 0 ? readNumber(balanceInfo, ["upnl"]) : toNumber(upnlOverride);
25788
+ const computedTotalLocked = cva + lf + partyAmm;
25789
+ const totalLocked = readValue(
25790
+ balanceInfo,
25791
+ ["totalLocked", "total_locked"]
25792
+ ) === void 0 ? computedTotalLocked : readNumber(balanceInfo, ["totalLocked", "total_locked"]);
25793
+ const totalPendingLocked = readValue(balanceInfo, [
25794
+ "totalPendingLocked",
25795
+ "total_pending_locked"
25796
+ ]) === void 0 ? pendingCva + pendingLf + pendingPartyAmm : readNumber(balanceInfo, ["totalPendingLocked", "total_pending_locked"]);
25797
+ const maintenanceMargin = cva + lf;
25798
+ const equity = allocatedBalance + upnl;
25799
+ const availableForOrder = upnl >= 0 ? allocatedBalance + upnl - totalLocked - totalPendingLocked : allocatedBalance - cva - lf - totalPendingLocked - Math.max(Math.abs(upnl), partyAmm);
25800
+ const availableBalance = readNumber(balanceInfo, [
25801
+ "availableBalance",
25802
+ "available_balance"
25803
+ ]);
25804
+ const notional = readNumber(balanceInfo, ["notional"]);
25805
+ return {
25806
+ allocatedBalance: toDisplayString(allocatedBalance),
25807
+ upnl: toDisplayString(upnl),
25808
+ equity: toDisplayString(equity),
25809
+ totalAccountValue: toDisplayString(equity),
25810
+ maintenanceMargin: toDisplayString(maintenanceMargin),
25811
+ totalLocked: toDisplayString(totalLocked),
25812
+ marginUsed: toDisplayString(computedTotalLocked),
25813
+ totalPendingLocked: toDisplayString(totalPendingLocked),
25814
+ availableForOrder: toDisplayString(availableForOrder),
25815
+ availableMargin: toDisplayString(availableForOrder),
25816
+ availableBalance: toDisplayString(availableBalance),
25817
+ netDeposited: toDisplayString(toNumber(netDeposited)),
25818
+ notional: toDisplayString(notional),
25819
+ timestamp: readTimestamp(balanceInfo)
25820
+ };
25821
+ }
25822
+ function computeSymmNetDeposited(totals, decimals = 6) {
25823
+ if (!totals) {
25824
+ return "0";
25825
+ }
25826
+ const deposit2 = parseRawCollateralUnits(totals.deposit);
25827
+ const withdraw2 = parseRawCollateralUnits(totals.withdraw);
25828
+ const value = deposit2 - withdraw2;
25829
+ const negative = value < 0n;
25830
+ const absolute = negative ? -value : value;
25831
+ const scale = 10n ** BigInt(decimals);
25832
+ const whole = absolute / scale;
25833
+ const fraction = absolute % scale;
25834
+ const fractionText = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
25835
+ const amount = fractionText ? `${whole}.${fractionText}` : whole.toString();
25836
+ return negative ? `-${amount}` : amount;
25837
+ }
25838
+ function parseRawCollateralUnits(value) {
25839
+ if (value === null || value === void 0 || value === "") {
25840
+ return 0n;
25841
+ }
25842
+ if (typeof value === "bigint") {
25843
+ return value;
25844
+ }
25845
+ if (typeof value === "number") {
25846
+ if (!Number.isSafeInteger(value)) {
25847
+ throw new Error("Raw collateral unit numbers must be safe integers");
25848
+ }
25849
+ return BigInt(value);
25850
+ }
25851
+ if (!/^-?\d+$/.test(value)) {
25852
+ throw new Error("Raw collateral unit strings must be base-10 integers");
25853
+ }
25854
+ return BigInt(value);
25855
+ }
25856
+
25857
+ // src/react/hooks/use-symm-account-overview.ts
25858
+ function useSymmAccountOverview(params) {
25859
+ const {
25860
+ userAddress,
25861
+ accountAddress,
25862
+ multiAccountAddress,
25863
+ upnl,
25864
+ netDeposited
25865
+ } = params;
25866
+ const query = useSymmBalances({
25867
+ userAddress,
25868
+ multiAccountAddress,
25869
+ chainId: params.chainId,
25870
+ query: params.query
25871
+ });
25872
+ const data = useMemo(() => {
25873
+ if (query.data === void 0) {
25874
+ return void 0;
25875
+ }
25876
+ const balanceInfo = getSymmAccountBalanceInfo(
25877
+ query.data,
25878
+ accountAddress ?? userAddress
25879
+ );
25880
+ return {
25881
+ response: query.data,
25882
+ balanceInfo,
25883
+ overview: balanceInfo ? computeSymmAccountOverview({ balanceInfo, upnl, netDeposited }) : void 0
25884
+ };
25885
+ }, [accountAddress, netDeposited, query.data, upnl, userAddress]);
25886
+ return { ...query, data };
25887
+ }
25599
25888
  function useSymmOpenBasketMutation(options) {
25600
25889
  const { symmCoreClient } = useSymmContext();
25601
25890
  const queryClient = useQueryClient();
@@ -27168,6 +27457,6 @@ function getSymmErrorMessage(error) {
27168
27457
  return "An unexpected error occurred.";
27169
27458
  }
27170
27459
 
27171
- export { SymmProvider, getSymmErrorMessage, symmKeys, useBinanceMarkPriceStore, useSymmAccountData, useSymmAccountSummary, useSymmAccountsApi, useSymmAccountsLength, useSymmAccountsQuery, useSymmAccountsWithPositions, useSymmAllocateCollateralMutation, useSymmApprovalQuery, useSymmApproveMutation, useSymmAuth, useSymmAvailableMargin, useSymmBalances, useSymmCancelClose, useSymmCancelOpenMutation, useSymmCancelTpslMutation, useSymmCancelTwapOrderMutation, useSymmChartCandles, useSymmChartSelection, useSymmClearTriggerConfigMutation, useSymmCloseAllPositionsMutation, useSymmCloseOrder, useSymmClosePositionMutation, useSymmContext, useSymmCoreClient, useSymmCreateAccountMutation, useSymmDeallocateCollateralMutation, useSymmDelegateAccessMutation, useSymmDelegation, useSymmDepositAndAllocateMutation, useSymmDepositMutation, useSymmEditAccountNameMutation, useSymmFunding, useSymmFundingHistory, useSymmFundingPayments, useSymmHedgerMarketById, useSymmHedgerMarketBySymbol, useSymmHedgerMarkets, useSymmInstantTradeEnsureReadyMutation, useSymmInstantTradeExecuteMutation, useSymmInternalTransferCollateralMutation, useSymmLockedParams, useSymmMarkReadNotificationMutation, useSymmMarkets, useSymmNotificationsQuery, useSymmOpenBasketMutation, useSymmOpenOrders, useSymmPendingIds, useSymmPendingInstantOpens, useSymmPerformanceOverlays, useSymmPortfolio, useSymmPositions, useSymmProposeRevokeDelegationMutation, useSymmRevokeDelegationMutation, useSymmSetTpslMutation, useSymmSetTriggerConfigMutation, useSymmSignTermsMutation, useSymmSignatureQuery, useSymmTokenMarkPrice, useSymmTokenSelectionMarkets, useSymmTokenSelectionMetadata, useSymmTpslOrders, useSymmTradeHistory, useSymmTriggerConfigQuery, useSymmTriggerOrders, useSymmTwapOrder, useSymmTwapOrdersQuery, useSymmUnreadCountQuery, useSymmUpdatePositionMutation, useSymmWithdraw, useSymmWsStore };
27460
+ export { SymmProvider, computeSymmAccountOverview, computeSymmNetDeposited, getSymmAccountBalanceInfo, getSymmErrorMessage, symmKeys, useBinanceMarkPriceStore, useSymmAccountData, useSymmAccountOverview, useSymmAccountSummary, useSymmAccountsApi, useSymmAccountsLength, useSymmAccountsQuery, useSymmAccountsWithPositions, useSymmAllocateCollateralMutation, useSymmApprovalQuery, useSymmApproveMutation, useSymmAuth, useSymmAvailableMargin, useSymmBalances, useSymmCancelClose, useSymmCancelOpenMutation, useSymmCancelTpslMutation, useSymmCancelTwapOrderMutation, useSymmChartCandles, useSymmChartSelection, useSymmClearTriggerConfigMutation, useSymmCloseAllPositionsMutation, useSymmCloseOrder, useSymmClosePositionMutation, useSymmContext, useSymmCoreClient, useSymmCreateAccountMutation, useSymmDeallocateCollateralMutation, useSymmDelegateAccessMutation, useSymmDelegation, useSymmDepositAndAllocateMutation, useSymmDepositMutation, useSymmEditAccountNameMutation, useSymmFunding, useSymmFundingHistory, useSymmFundingPayments, useSymmHedgerMarketById, useSymmHedgerMarketBySymbol, useSymmHedgerMarkets, useSymmInstantTradeEnsureReadyMutation, useSymmInstantTradeExecuteMutation, useSymmInternalTransferCollateralMutation, useSymmLockedParams, useSymmMarkReadNotificationMutation, useSymmMarkets, useSymmNotificationsQuery, useSymmOpenBasketMutation, useSymmOpenOrders, useSymmPendingIds, useSymmPendingInstantOpens, useSymmPerformanceOverlays, useSymmPortfolio, useSymmPositions, useSymmProposeRevokeDelegationMutation, useSymmRevokeDelegationMutation, useSymmSetTpslMutation, useSymmSetTriggerConfigMutation, useSymmSignTermsMutation, useSymmSignatureQuery, useSymmTokenMarkPrice, useSymmTokenSelectionMarkets, useSymmTokenSelectionMetadata, useSymmTpslOrders, useSymmTradeHistory, useSymmTriggerConfigQuery, useSymmTriggerOrders, useSymmTwapOrder, useSymmTwapOrdersQuery, useSymmUnreadCountQuery, useSymmUpdatePositionMutation, useSymmWithdraw, useSymmWsStore };
27172
27461
  //# sourceMappingURL=index.mjs.map
27173
27462
  //# sourceMappingURL=index.mjs.map