@pear-protocol/symmio-client 0.3.14 → 0.3.16

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.
@@ -75,6 +75,7 @@ var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
75
75
  var IDLE_CLOSE_DELAY_MS = 3e4;
76
76
  var STALE_CONNECTION_MS = 3e4;
77
77
  var STALE_CHECK_INTERVAL_MS = 1e4;
78
+ var RECONNECT_RESET_MS = 6e4;
78
79
  var STABLE_QUOTES = ["USDT0", "USDT", "USDC", "USDE", "USDH", "USD"];
79
80
  function normalizeBaseSymbol(symbol) {
80
81
  const normalized = symbol.toUpperCase().trim();
@@ -126,6 +127,7 @@ var BinanceWsManager = class {
126
127
  reconnectTimer = null;
127
128
  idleCloseTimer = null;
128
129
  staleCheckTimer = null;
130
+ reconnectResetTimer = null;
129
131
  intentionalClose = false;
130
132
  pendingSubscribes = /* @__PURE__ */ new Set();
131
133
  lastMessageAt = 0;
@@ -164,6 +166,7 @@ var BinanceWsManager = class {
164
166
  const wrappedCb = (raw) => {
165
167
  cb({
166
168
  symbol: normalizeBaseSymbol(raw.s),
169
+ binanceSymbol: raw.s,
167
170
  markPrice: parseFloat(raw.p),
168
171
  indexPrice: parseFloat(raw.i),
169
172
  time: raw.E,
@@ -185,6 +188,7 @@ var BinanceWsManager = class {
185
188
  cb(
186
189
  extractTickers(raw).map((entry) => ({
187
190
  symbol: normalizeBaseSymbol(entry.s),
191
+ binanceSymbol: entry.s,
188
192
  markPrice: parseFloat(entry.p),
189
193
  indexPrice: parseFloat(entry.i),
190
194
  time: entry.E,
@@ -204,6 +208,7 @@ var BinanceWsManager = class {
204
208
  this.clearReconnectTimer();
205
209
  this.clearIdleCloseTimer();
206
210
  this.clearStaleCheckTimer();
211
+ this.clearReconnectResetTimer();
207
212
  this.pendingSubscribes.clear();
208
213
  if (this.ws) {
209
214
  this.ws.close();
@@ -240,20 +245,26 @@ var BinanceWsManager = class {
240
245
  }
241
246
  }
242
247
  ensureConnected() {
243
- if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
244
- return;
248
+ if (this.ws) {
249
+ const state = this.ws.readyState;
250
+ if (state === WebSocket.OPEN || state === WebSocket.CONNECTING || state === WebSocket.CLOSING) {
251
+ return;
252
+ }
245
253
  }
246
254
  this.clearReconnectTimer();
247
255
  this.connect();
248
256
  }
249
257
  connect() {
250
258
  if (typeof WebSocket === "undefined") return;
259
+ if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {
260
+ return;
261
+ }
251
262
  this.intentionalClose = false;
252
263
  this.ws = new WebSocket(BINANCE_WS_URL);
253
264
  this.ws.onopen = () => {
254
- this.reconnectAttempt = 0;
255
265
  this.lastMessageAt = Date.now();
256
266
  this.startStaleCheck();
267
+ this.scheduleReconnectReset();
257
268
  const activeStreams = Array.from(
258
269
  /* @__PURE__ */ new Set([...this.streams.keys(), ...this.pendingSubscribes])
259
270
  );
@@ -266,14 +277,24 @@ var BinanceWsManager = class {
266
277
  try {
267
278
  const data = JSON.parse(event.data);
268
279
  this.lastMessageAt = Date.now();
280
+ this.resetReconnectAttempt();
269
281
  this.handleMessage(data);
270
282
  } catch {
271
283
  }
272
284
  };
273
285
  this.ws.onclose = () => {
286
+ const wasIntentional = this.intentionalClose;
287
+ this.intentionalClose = false;
274
288
  this.ws = null;
275
289
  this.clearStaleCheckTimer();
276
- if (this.intentionalClose) return;
290
+ this.clearReconnectResetTimer();
291
+ if (this.streams.size === 0) {
292
+ return;
293
+ }
294
+ if (wasIntentional) {
295
+ this.connect();
296
+ return;
297
+ }
277
298
  this.scheduleReconnect();
278
299
  };
279
300
  this.ws.onerror = () => {
@@ -349,9 +370,6 @@ var BinanceWsManager = class {
349
370
  if (this.streams.size > 0 || !this.ws) return;
350
371
  this.intentionalClose = true;
351
372
  this.ws.close();
352
- this.ws = null;
353
- this.intentionalClose = false;
354
- this.clearStaleCheckTimer();
355
373
  }, IDLE_CLOSE_DELAY_MS);
356
374
  }
357
375
  startStaleCheck() {
@@ -363,6 +381,17 @@ var BinanceWsManager = class {
363
381
  this.ws.close();
364
382
  }, STALE_CHECK_INTERVAL_MS);
365
383
  }
384
+ scheduleReconnectReset() {
385
+ this.clearReconnectResetTimer();
386
+ this.reconnectResetTimer = setTimeout(() => {
387
+ this.reconnectResetTimer = null;
388
+ this.resetReconnectAttempt();
389
+ }, RECONNECT_RESET_MS);
390
+ }
391
+ resetReconnectAttempt() {
392
+ this.reconnectAttempt = 0;
393
+ this.clearReconnectResetTimer();
394
+ }
366
395
  clearReconnectTimer() {
367
396
  if (!this.reconnectTimer) return;
368
397
  clearTimeout(this.reconnectTimer);
@@ -378,13 +407,21 @@ var BinanceWsManager = class {
378
407
  clearInterval(this.staleCheckTimer);
379
408
  this.staleCheckTimer = null;
380
409
  }
410
+ clearReconnectResetTimer() {
411
+ if (!this.reconnectResetTimer) return;
412
+ clearTimeout(this.reconnectResetTimer);
413
+ this.reconnectResetTimer = null;
414
+ }
381
415
  };
382
- var _instance = null;
416
+ var BINANCE_WS_SINGLETON_KEY = "__pearBinanceWsManager__";
383
417
  function getBinanceWsManager() {
384
- if (!_instance) {
385
- _instance = new BinanceWsManager();
418
+ const g = globalThis;
419
+ let manager = g[BINANCE_WS_SINGLETON_KEY];
420
+ if (!manager) {
421
+ manager = new BinanceWsManager();
422
+ g[BINANCE_WS_SINGLETON_KEY] = manager;
386
423
  }
387
- return _instance;
424
+ return manager;
388
425
  }
389
426
 
390
427
  // src/react/stores/use-binance-mark-price-store.ts
@@ -392,15 +429,8 @@ var refCounts = /* @__PURE__ */ new Map();
392
429
  var streamSymbols = /* @__PURE__ */ new Map();
393
430
  var allMarkPricesRefCount = 0;
394
431
  var allMarkPricesUnsubscribe = null;
395
- var STABLE_QUOTES2 = ["USDT0", "USDT", "USDC", "USDE", "USDH", "USD"];
396
- function normalizeBinanceSymbol(symbol) {
397
- const normalized = symbol.toUpperCase().trim();
398
- for (const quote of STABLE_QUOTES2) {
399
- if (normalized.endsWith(quote) && normalized.length > quote.length) {
400
- return normalized.slice(0, -quote.length);
401
- }
402
- }
403
- return normalized;
432
+ function normalizeBinanceSymbolKey(symbol) {
433
+ return symbol.toUpperCase().trim();
404
434
  }
405
435
  function getNextRefCount(binanceSymbol) {
406
436
  return (refCounts.get(binanceSymbol) ?? 0) + 1;
@@ -435,7 +465,7 @@ var useBinanceMarkPriceStore = zustand.create((set) => ({
435
465
  fundingRates: {},
436
466
  nextFundingTimes: {},
437
467
  subscribeSymbol: (symmSymbol, rawBinanceSymbol) => {
438
- const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
468
+ const binanceSymbol = normalizeBinanceSymbolKey(rawBinanceSymbol);
439
469
  const nextRefCount = getNextRefCount(binanceSymbol);
440
470
  refCounts.set(binanceSymbol, nextRefCount);
441
471
  addMappedSymbol(binanceSymbol, symmSymbol);
@@ -447,8 +477,10 @@ var useBinanceMarkPriceStore = zustand.create((set) => ({
447
477
  let nextFundingRates = null;
448
478
  let nextFundingTimes = null;
449
479
  entries.forEach((entry) => {
450
- const canonicalSymbol = normalizeBinanceSymbol(entry.symbol);
451
- const mappedSymbols = streamSymbols.get(canonicalSymbol);
480
+ const binanceSymbolKey = normalizeBinanceSymbolKey(
481
+ entry.binanceSymbol ?? entry.symbol
482
+ );
483
+ const mappedSymbols = streamSymbols.get(binanceSymbolKey);
452
484
  if (!mappedSymbols || mappedSymbols.size === 0) return;
453
485
  nextMarkPrices ??= { ...state.markPrices };
454
486
  nextFundingRates ??= { ...state.fundingRates };
@@ -473,7 +505,7 @@ var useBinanceMarkPriceStore = zustand.create((set) => ({
473
505
  allMarkPricesRefCount += 1;
474
506
  },
475
507
  unsubscribeSymbol: (symmSymbol, rawBinanceSymbol) => {
476
- const binanceSymbol = normalizeBinanceSymbol(rawBinanceSymbol);
508
+ const binanceSymbol = normalizeBinanceSymbolKey(rawBinanceSymbol);
477
509
  const removedSubscription = removeMappedSymbol(binanceSymbol, symmSymbol);
478
510
  if (!removedSubscription) {
479
511
  return;
@@ -513,6 +545,7 @@ var useBinanceMarkPriceStore = zustand.create((set) => ({
513
545
  }));
514
546
 
515
547
  // src/react/hooks/use-binance-ws.ts
548
+ var BOOTSTRAP_RETRY_DELAYS_MS = [1e3, 2e3, 5e3];
516
549
  function useBinanceWs(params) {
517
550
  const { symmCoreClient, chainId } = params;
518
551
  const subscribeSymbol = useBinanceMarkPriceStore((state) => state.subscribeSymbol);
@@ -523,7 +556,8 @@ function useBinanceWs(params) {
523
556
  }
524
557
  let cancelled = false;
525
558
  let subscribedPairs = [];
526
- const run = async () => {
559
+ let retryTimer = null;
560
+ const run = async (attempt = 0) => {
527
561
  try {
528
562
  const result = await symmCoreClient.markets.listSymmHedger({ chainId });
529
563
  if (cancelled) {
@@ -543,11 +577,22 @@ function useBinanceWs(params) {
543
577
  subscribeSymbol(symbol, binanceSymbol);
544
578
  });
545
579
  } catch {
580
+ const delay = BOOTSTRAP_RETRY_DELAYS_MS[attempt];
581
+ if (cancelled || delay == null) {
582
+ return;
583
+ }
584
+ retryTimer = setTimeout(() => {
585
+ retryTimer = null;
586
+ void run(attempt + 1);
587
+ }, delay);
546
588
  }
547
589
  };
548
590
  void run();
549
591
  return () => {
550
592
  cancelled = true;
593
+ if (retryTimer) {
594
+ clearTimeout(retryTimer);
595
+ }
551
596
  subscribedPairs.forEach(([symbol, binanceSymbol]) => {
552
597
  unsubscribeSymbol(symbol, binanceSymbol);
553
598
  });
@@ -25635,21 +25680,196 @@ function useSymmAccountData(params) {
25635
25680
  enabled: internalEnabled && (params.query?.enabled ?? true)
25636
25681
  });
25637
25682
  }
25638
- function useSymmBalances(params) {
25683
+
25684
+ // src/utils/account-pnl.ts
25685
+ function toNumber(value) {
25686
+ if (value === null || value === void 0 || value === "") {
25687
+ return 0;
25688
+ }
25689
+ const parsed = Number(value);
25690
+ return Number.isFinite(parsed) ? parsed : 0;
25691
+ }
25692
+ function readOpenedPrice(leg) {
25693
+ return toNumber(leg.openedPrice ?? leg.opened_price);
25694
+ }
25695
+ function readCurrentPrice(leg) {
25696
+ const parsed = Number(leg.currentPrice ?? leg.current_price);
25697
+ return Number.isFinite(parsed) ? parsed : void 0;
25698
+ }
25699
+ function readMarkPrice(leg, markPrices) {
25700
+ const symbol = leg.symbol?.trim().toUpperCase();
25701
+ if (symbol) {
25702
+ const markPrice = Number(markPrices[symbol]);
25703
+ if (Number.isFinite(markPrice)) {
25704
+ return markPrice;
25705
+ }
25706
+ }
25707
+ return readCurrentPrice(leg);
25708
+ }
25709
+ function getSymbol(leg) {
25710
+ return leg.symbol?.trim().toUpperCase() || void 0;
25711
+ }
25712
+ function computeLegUpnl(leg, side, markPrices) {
25713
+ const markPrice = readMarkPrice(leg, markPrices);
25714
+ if (markPrice === void 0) {
25715
+ return { upnl: 0, missingSymbol: getSymbol(leg) };
25716
+ }
25717
+ const quantity = toNumber(leg.quantity);
25718
+ const openedPrice = readOpenedPrice(leg);
25719
+ const direction = side === "short" ? -1 : 1;
25720
+ return {
25721
+ upnl: quantity * (markPrice - openedPrice) * direction
25722
+ };
25723
+ }
25724
+ function computeSymmPositionUpnl(position, markPrices = {}) {
25725
+ const missingSymbols = /* @__PURE__ */ new Set();
25726
+ let upnl = 0;
25727
+ let legsCount = 0;
25728
+ for (const leg of position.longAssets ?? []) {
25729
+ legsCount += 1;
25730
+ const result = computeLegUpnl(leg, "long", markPrices);
25731
+ upnl += result.upnl;
25732
+ if (result.missingSymbol) missingSymbols.add(result.missingSymbol);
25733
+ }
25734
+ for (const leg of position.shortAssets ?? []) {
25735
+ legsCount += 1;
25736
+ const result = computeLegUpnl(leg, "short", markPrices);
25737
+ upnl += result.upnl;
25738
+ if (result.missingSymbol) missingSymbols.add(result.missingSymbol);
25739
+ }
25740
+ if (legsCount === 0) {
25741
+ return {
25742
+ upnl: toNumber(position.unrealizedPnl ?? position.unrealized_pnl),
25743
+ missingSymbols: [],
25744
+ positionsCount: 1,
25745
+ legsCount,
25746
+ usedFallbackPositions: 1
25747
+ };
25748
+ }
25749
+ return {
25750
+ upnl,
25751
+ missingSymbols: Array.from(missingSymbols),
25752
+ positionsCount: 1,
25753
+ legsCount,
25754
+ usedFallbackPositions: 0
25755
+ };
25756
+ }
25757
+ function computeSymmPositionsUpnl(positions = [], markPrices = {}) {
25758
+ const missingSymbols = /* @__PURE__ */ new Set();
25759
+ let upnl = 0;
25760
+ let legsCount = 0;
25761
+ let usedFallbackPositions = 0;
25762
+ for (const position of positions) {
25763
+ const result = computeSymmPositionUpnl(position, markPrices);
25764
+ upnl += result.upnl;
25765
+ legsCount += result.legsCount;
25766
+ usedFallbackPositions += result.usedFallbackPositions;
25767
+ result.missingSymbols.forEach((symbol) => missingSymbols.add(symbol));
25768
+ }
25769
+ return {
25770
+ upnl,
25771
+ missingSymbols: Array.from(missingSymbols),
25772
+ positionsCount: positions.length,
25773
+ legsCount,
25774
+ usedFallbackPositions
25775
+ };
25776
+ }
25777
+ function readMessageNumber(message, keys) {
25778
+ for (const key of keys) {
25779
+ if (key in message) {
25780
+ return toNumber(message[key]);
25781
+ }
25782
+ }
25783
+ return 0;
25784
+ }
25785
+ function normalizeSymmUpnlWebSocketMessage(raw) {
25786
+ if (typeof raw !== "object" || raw === null) {
25787
+ return void 0;
25788
+ }
25789
+ const message = raw;
25790
+ const timestamp = readMessageNumber(message, ["timestamp"]);
25791
+ return {
25792
+ upnl: readMessageNumber(message, ["upnl"]),
25793
+ timestamp: timestamp || void 0,
25794
+ availableBalance: readMessageNumber(message, [
25795
+ "availableBalance",
25796
+ "available_balance"
25797
+ ]),
25798
+ allocatedBalance: readMessageNumber(message, [
25799
+ "allocatedBalance",
25800
+ "allocated_balance"
25801
+ ]),
25802
+ cva: readMessageNumber(message, ["cva"]),
25803
+ lf: readMessageNumber(message, ["lf"]),
25804
+ partyAmm: readMessageNumber(message, ["partyAmm", "party_a_mm", "mm"]),
25805
+ pendingPartyAmm: readMessageNumber(message, [
25806
+ "pendingPartyAmm",
25807
+ "pending_party_a_mm",
25808
+ "pending_mm"
25809
+ ]),
25810
+ pendingCva: readMessageNumber(message, ["pendingCva", "pending_cva"]),
25811
+ pendingLf: readMessageNumber(message, ["pendingLf", "pending_lf"]),
25812
+ raw
25813
+ };
25814
+ }
25815
+ function useSymmPositions(params) {
25639
25816
  const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
25640
- const { userAddress, multiAccountAddress } = params;
25817
+ const { accountAddress, address } = params;
25818
+ const resolvedAddress = accountAddress ? void 0 : address;
25641
25819
  const chainId = params.chainId ?? ctxChainId;
25642
- const internalEnabled = !!symmCoreClient && !!userAddress;
25820
+ const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
25821
+ const enabled = internalEnabled && (params.query?.enabled ?? true);
25643
25822
  return reactQuery.useQuery({
25644
25823
  ...params.query,
25645
- queryKey: symmKeys.balances(userAddress, chainId, multiAccountAddress),
25646
- queryFn: () => symmCoreClient.accounts.getBalanceInfo({
25647
- userAddress,
25648
- chainId,
25649
- multiAccountAddress
25824
+ queryKey: symmKeys.positions({
25825
+ accountAddress,
25826
+ address: resolvedAddress,
25827
+ chainId
25650
25828
  }),
25651
- enabled: internalEnabled && (params.query?.enabled ?? true)
25829
+ queryFn: () => symmCoreClient.positions.getOpen({
25830
+ accountAddress,
25831
+ address: resolvedAddress,
25832
+ chainId
25833
+ }),
25834
+ enabled
25835
+ });
25836
+ }
25837
+
25838
+ // src/react/hooks/use-symm-account-current-pnl.ts
25839
+ function readPositions(response) {
25840
+ if (typeof response !== "object" || response === null) {
25841
+ return [];
25842
+ }
25843
+ const data = response.data;
25844
+ if (typeof data !== "object" || data === null) {
25845
+ return [];
25846
+ }
25847
+ const positions = data.positions;
25848
+ return Array.isArray(positions) ? positions : [];
25849
+ }
25850
+ function useSymmAccountCurrentPnl(params) {
25851
+ const { accountAddress, address, positions, query } = params;
25852
+ const liveMarkPrices = useBinanceMarkPriceStore((state) => state.markPrices);
25853
+ const positionsQuery = useSymmPositions({
25854
+ accountAddress,
25855
+ address,
25856
+ chainId: params.chainId,
25857
+ query: {
25858
+ ...query,
25859
+ enabled: positions === void 0 && (query?.enabled ?? true)
25860
+ }
25652
25861
  });
25862
+ const resolvedPositions = positions ?? readPositions(positionsQuery.data);
25863
+ const pnl = react.useMemo(
25864
+ () => computeSymmPositionsUpnl(resolvedPositions, liveMarkPrices),
25865
+ [liveMarkPrices, resolvedPositions]
25866
+ );
25867
+ return {
25868
+ ...pnl,
25869
+ value: pnl.upnl,
25870
+ positions: resolvedPositions,
25871
+ positionsQuery
25872
+ };
25653
25873
  }
25654
25874
 
25655
25875
  // src/utils/account-overview.ts
@@ -25679,7 +25899,7 @@ function readValue(source, keys) {
25679
25899
  }
25680
25900
  return void 0;
25681
25901
  }
25682
- function toNumber(value) {
25902
+ function toNumber2(value) {
25683
25903
  if (value === null || value === void 0 || value === "") {
25684
25904
  return 0;
25685
25905
  }
@@ -25696,7 +25916,7 @@ function toDisplayString(value) {
25696
25916
  return String(value);
25697
25917
  }
25698
25918
  function readNumber(source, keys) {
25699
- return toNumber(readValue(source, keys));
25919
+ return toNumber2(readValue(source, keys));
25700
25920
  }
25701
25921
  function readTimestamp(source) {
25702
25922
  const timestamp = readValue(source, ["timestamp"]);
@@ -25706,6 +25926,28 @@ function readTimestamp(source) {
25706
25926
  const parsed = Number(timestamp);
25707
25927
  return Number.isFinite(parsed) ? parsed : void 0;
25708
25928
  }
25929
+ function hasAccountDataShape(value) {
25930
+ return isRecord(value) && ("equity" in value || "maintenanceMargin" in value || "availableForOrder" in value || "totalLocked" in value);
25931
+ }
25932
+ function getSymmAccountData(response) {
25933
+ if (!isRecord(response)) {
25934
+ return void 0;
25935
+ }
25936
+ const data = response.data;
25937
+ if (isRecord(data)) {
25938
+ if (hasAccountDataShape(data.accountData)) {
25939
+ return data.accountData;
25940
+ }
25941
+ if (hasAccountDataShape(data)) {
25942
+ return data;
25943
+ }
25944
+ return void 0;
25945
+ }
25946
+ if (hasAccountDataShape(response)) {
25947
+ return response;
25948
+ }
25949
+ return void 0;
25950
+ }
25709
25951
  function getBalanceInfoContainer(response) {
25710
25952
  if (!isRecord(response)) {
25711
25953
  return void 0;
@@ -25786,7 +26028,7 @@ function computeSymmAccountOverview({
25786
26028
  "pendingLockedPartyAMM",
25787
26029
  "pending_locked_party_a_mm"
25788
26030
  ]);
25789
- const upnl = upnlOverride === void 0 ? readNumber(balanceInfo, ["upnl"]) : toNumber(upnlOverride);
26031
+ const upnl = upnlOverride === void 0 ? readNumber(balanceInfo, ["upnl"]) : toNumber2(upnlOverride);
25790
26032
  const computedTotalLocked = cva + lf + partyAmm;
25791
26033
  const totalLocked = readValue(
25792
26034
  balanceInfo,
@@ -25816,11 +26058,43 @@ function computeSymmAccountOverview({
25816
26058
  availableForOrder: toDisplayString(availableForOrder),
25817
26059
  availableMargin: toDisplayString(availableForOrder),
25818
26060
  availableBalance: toDisplayString(availableBalance),
25819
- netDeposited: toDisplayString(toNumber(netDeposited)),
26061
+ netDeposited: toDisplayString(toNumber2(netDeposited)),
25820
26062
  notional: toDisplayString(notional),
25821
26063
  timestamp: readTimestamp(balanceInfo)
25822
26064
  };
25823
26065
  }
26066
+ function computeSymmAccountOverviewFromData({
26067
+ accountData,
26068
+ upnl,
26069
+ netDeposited
26070
+ }) {
26071
+ const equity = readNumber(accountData, ["equity"]);
26072
+ const maintenanceMargin = readNumber(accountData, [
26073
+ "maintenanceMargin",
26074
+ "maintenance_margin"
26075
+ ]);
26076
+ const availableForOrder = readNumber(accountData, [
26077
+ "availableForOrder",
26078
+ "available_for_order"
26079
+ ]);
26080
+ const totalLocked = readNumber(accountData, ["totalLocked", "total_locked"]);
26081
+ return {
26082
+ allocatedBalance: "0",
26083
+ upnl: toDisplayString(toNumber2(upnl)),
26084
+ equity: toDisplayString(equity),
26085
+ totalAccountValue: toDisplayString(equity),
26086
+ maintenanceMargin: toDisplayString(maintenanceMargin),
26087
+ accountHealthData: accountData.accountHealthData,
26088
+ totalLocked: toDisplayString(totalLocked),
26089
+ marginUsed: toDisplayString(totalLocked),
26090
+ totalPendingLocked: "0",
26091
+ availableForOrder: toDisplayString(availableForOrder),
26092
+ availableMargin: toDisplayString(availableForOrder),
26093
+ availableBalance: toDisplayString(availableForOrder),
26094
+ netDeposited: toDisplayString(toNumber2(netDeposited)),
26095
+ notional: "0"
26096
+ };
26097
+ }
25824
26098
  function computeSymmNetDeposited(totals, decimals = 6) {
25825
26099
  if (!totals) {
25826
26100
  return "0";
@@ -25861,32 +26135,186 @@ function useSymmAccountOverview(params) {
25861
26135
  const {
25862
26136
  userAddress,
25863
26137
  accountAddress,
25864
- multiAccountAddress,
25865
26138
  upnl,
25866
- netDeposited
26139
+ netDeposited,
26140
+ positions,
26141
+ currentPnlQuery
25867
26142
  } = params;
25868
- const query = useSymmBalances({
25869
- userAddress,
25870
- multiAccountAddress,
26143
+ const address = accountAddress ?? userAddress;
26144
+ const shouldUseLocalPnl = upnl === void 0;
26145
+ const currentPnl = useSymmAccountCurrentPnl({
26146
+ accountAddress: address,
26147
+ positions,
25871
26148
  chainId: params.chainId,
25872
- query: params.query
26149
+ query: {
26150
+ ...currentPnlQuery,
26151
+ enabled: shouldUseLocalPnl && (currentPnlQuery?.enabled ?? true)
26152
+ }
26153
+ });
26154
+ const resolvedUpnl = shouldUseLocalPnl ? currentPnl.value : upnl;
26155
+ const upnlReady = !shouldUseLocalPnl || positions !== void 0 || currentPnl.positionsQuery.isSuccess;
26156
+ const query = useSymmAccountData({
26157
+ address,
26158
+ upnl: upnlReady ? String(resolvedUpnl ?? 0) : void 0,
26159
+ chainId: params.chainId,
26160
+ query: {
26161
+ ...params.query,
26162
+ enabled: upnlReady && (params.query?.enabled ?? true)
26163
+ }
25873
26164
  });
25874
26165
  const data = react.useMemo(() => {
25875
26166
  if (query.data === void 0) {
25876
26167
  return void 0;
25877
26168
  }
25878
- const balanceInfo = getSymmAccountBalanceInfo(
25879
- query.data,
25880
- accountAddress ?? userAddress
25881
- );
26169
+ const accountData = getSymmAccountData(query.data);
25882
26170
  return {
25883
26171
  response: query.data,
25884
- balanceInfo,
25885
- overview: balanceInfo ? computeSymmAccountOverview({ balanceInfo, upnl, netDeposited }) : void 0
26172
+ accountData,
26173
+ coreAccountData: accountData,
26174
+ currentPnl,
26175
+ overview: accountData ? computeSymmAccountOverviewFromData({
26176
+ accountData,
26177
+ upnl: resolvedUpnl,
26178
+ netDeposited
26179
+ }) : void 0
25886
26180
  };
25887
- }, [accountAddress, netDeposited, query.data, upnl, userAddress]);
26181
+ }, [currentPnl, netDeposited, query.data, resolvedUpnl]);
25888
26182
  return { ...query, data };
25889
26183
  }
26184
+ function parseMessageData(data) {
26185
+ if (typeof data !== "string") {
26186
+ return data;
26187
+ }
26188
+ try {
26189
+ return JSON.parse(data);
26190
+ } catch {
26191
+ return void 0;
26192
+ }
26193
+ }
26194
+ function toBalanceInfo(message) {
26195
+ return {
26196
+ allocatedBalance: message.allocatedBalance,
26197
+ cva: message.cva,
26198
+ lf: message.lf,
26199
+ partyAmm: message.partyAmm,
26200
+ pendingCva: message.pendingCva,
26201
+ pendingLf: message.pendingLf,
26202
+ pendingPartyAmm: message.pendingPartyAmm,
26203
+ upnl: message.upnl,
26204
+ availableBalance: message.availableBalance,
26205
+ timestamp: message.timestamp
26206
+ };
26207
+ }
26208
+ function useSymmUpnlWebSocket(params) {
26209
+ const {
26210
+ url,
26211
+ accountAddress,
26212
+ enabled = true,
26213
+ reconnectAttempts = 2,
26214
+ reconnectDelayMs = 1e3,
26215
+ webSocketFactory
26216
+ } = params;
26217
+ const [data, setData] = react.useState();
26218
+ const [status, setStatus] = react.useState("idle");
26219
+ const [error, setError] = react.useState();
26220
+ const socketRef = react.useRef(null);
26221
+ const sendAccountAddress = react.useCallback(() => {
26222
+ if (!accountAddress || socketRef.current?.readyState !== 1) {
26223
+ return;
26224
+ }
26225
+ socketRef.current.send(accountAddress);
26226
+ }, [accountAddress]);
26227
+ react.useEffect(() => {
26228
+ if (!enabled || !url || !accountAddress) {
26229
+ setStatus("idle");
26230
+ setData(void 0);
26231
+ setError(void 0);
26232
+ return;
26233
+ }
26234
+ const createSocket = webSocketFactory ?? ((wsUrl) => new WebSocket(wsUrl));
26235
+ let closedByHook = false;
26236
+ let reconnectCount = 0;
26237
+ let reconnectTimer;
26238
+ const connect = () => {
26239
+ setStatus("connecting");
26240
+ const socket = createSocket(url);
26241
+ socketRef.current = socket;
26242
+ socket.onopen = () => {
26243
+ reconnectCount = 0;
26244
+ setStatus("open");
26245
+ setError(void 0);
26246
+ socket.send(accountAddress);
26247
+ };
26248
+ socket.onmessage = (event) => {
26249
+ const parsed = parseMessageData(event.data);
26250
+ const nextMessage = normalizeSymmUpnlWebSocketMessage(parsed);
26251
+ if (nextMessage) {
26252
+ setData(nextMessage);
26253
+ }
26254
+ };
26255
+ socket.onerror = (event) => {
26256
+ setError(event);
26257
+ setStatus("error");
26258
+ };
26259
+ socket.onclose = () => {
26260
+ if (closedByHook) {
26261
+ setStatus("closed");
26262
+ return;
26263
+ }
26264
+ if (reconnectCount < reconnectAttempts) {
26265
+ reconnectCount += 1;
26266
+ reconnectTimer = setTimeout(connect, reconnectDelayMs);
26267
+ return;
26268
+ }
26269
+ setStatus("closed");
26270
+ };
26271
+ };
26272
+ connect();
26273
+ return () => {
26274
+ closedByHook = true;
26275
+ if (reconnectTimer) {
26276
+ clearTimeout(reconnectTimer);
26277
+ }
26278
+ socketRef.current?.close();
26279
+ socketRef.current = null;
26280
+ };
26281
+ }, [
26282
+ accountAddress,
26283
+ enabled,
26284
+ reconnectAttempts,
26285
+ reconnectDelayMs,
26286
+ url,
26287
+ webSocketFactory
26288
+ ]);
26289
+ const balanceInfo = react.useMemo(
26290
+ () => data ? toBalanceInfo(data) : void 0,
26291
+ [data]
26292
+ );
26293
+ return {
26294
+ data,
26295
+ upnl: data?.upnl,
26296
+ balanceInfo,
26297
+ status,
26298
+ error,
26299
+ sendAccountAddress
26300
+ };
26301
+ }
26302
+ function useSymmBalances(params) {
26303
+ const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
26304
+ const { userAddress, multiAccountAddress } = params;
26305
+ const chainId = params.chainId ?? ctxChainId;
26306
+ const internalEnabled = !!symmCoreClient && !!userAddress;
26307
+ return reactQuery.useQuery({
26308
+ ...params.query,
26309
+ queryKey: symmKeys.balances(userAddress, chainId, multiAccountAddress),
26310
+ queryFn: () => symmCoreClient.accounts.getBalanceInfo({
26311
+ userAddress,
26312
+ chainId,
26313
+ multiAccountAddress
26314
+ }),
26315
+ enabled: internalEnabled && (params.query?.enabled ?? true)
26316
+ });
26317
+ }
25890
26318
  function useSymmOpenBasketMutation(options) {
25891
26319
  const { symmCoreClient } = useSymmContext();
25892
26320
  const queryClient = reactQuery.useQueryClient();
@@ -26017,28 +26445,6 @@ function useSymmUpdatePositionMutation(paramsOrOptions, maybeOptions) {
26017
26445
  }
26018
26446
  });
26019
26447
  }
26020
- function useSymmPositions(params) {
26021
- const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
26022
- const { accountAddress, address } = params;
26023
- const resolvedAddress = accountAddress ? void 0 : address;
26024
- const chainId = params.chainId ?? ctxChainId;
26025
- const internalEnabled = !!symmCoreClient && !!(accountAddress || resolvedAddress);
26026
- const enabled = internalEnabled && (params.query?.enabled ?? true);
26027
- return reactQuery.useQuery({
26028
- ...params.query,
26029
- queryKey: symmKeys.positions({
26030
- accountAddress,
26031
- address: resolvedAddress,
26032
- chainId
26033
- }),
26034
- queryFn: () => symmCoreClient.positions.getOpen({
26035
- accountAddress,
26036
- address: resolvedAddress,
26037
- chainId
26038
- }),
26039
- enabled
26040
- });
26041
- }
26042
26448
  function useSymmOpenOrders(params) {
26043
26449
  const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
26044
26450
  const { accountAddress, address } = params;
@@ -27461,11 +27867,17 @@ function getSymmErrorMessage(error) {
27461
27867
 
27462
27868
  exports.SymmProvider = SymmProvider;
27463
27869
  exports.computeSymmAccountOverview = computeSymmAccountOverview;
27870
+ exports.computeSymmAccountOverviewFromData = computeSymmAccountOverviewFromData;
27464
27871
  exports.computeSymmNetDeposited = computeSymmNetDeposited;
27872
+ exports.computeSymmPositionUpnl = computeSymmPositionUpnl;
27873
+ exports.computeSymmPositionsUpnl = computeSymmPositionsUpnl;
27465
27874
  exports.getSymmAccountBalanceInfo = getSymmAccountBalanceInfo;
27875
+ exports.getSymmAccountData = getSymmAccountData;
27466
27876
  exports.getSymmErrorMessage = getSymmErrorMessage;
27877
+ exports.normalizeSymmUpnlWebSocketMessage = normalizeSymmUpnlWebSocketMessage;
27467
27878
  exports.symmKeys = symmKeys;
27468
27879
  exports.useBinanceMarkPriceStore = useBinanceMarkPriceStore;
27880
+ exports.useSymmAccountCurrentPnl = useSymmAccountCurrentPnl;
27469
27881
  exports.useSymmAccountData = useSymmAccountData;
27470
27882
  exports.useSymmAccountOverview = useSymmAccountOverview;
27471
27883
  exports.useSymmAccountSummary = useSymmAccountSummary;
@@ -27535,6 +27947,7 @@ exports.useSymmTwapOrder = useSymmTwapOrder;
27535
27947
  exports.useSymmTwapOrdersQuery = useSymmTwapOrdersQuery;
27536
27948
  exports.useSymmUnreadCountQuery = useSymmUnreadCountQuery;
27537
27949
  exports.useSymmUpdatePositionMutation = useSymmUpdatePositionMutation;
27950
+ exports.useSymmUpnlWebSocket = useSymmUpnlWebSocket;
27538
27951
  exports.useSymmWithdraw = useSymmWithdraw;
27539
27952
  exports.useSymmWsStore = useSymmWsStore;
27540
27953
  //# sourceMappingURL=index.js.map