@pear-protocol/symmio-client 0.1.5 → 0.1.7

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.
@@ -29,6 +29,10 @@ var CLEARING_HOUSE_ADDRESS = {
29
29
  var SIGNATURE_STORE_ADDRESS = {
30
30
  [42161 /* ARBITRUM */]: "0x94eEa58De1C8945c342dB4bE9670301638E403e2"
31
31
  };
32
+ var DEFAULT_PARTY_B_ADDRESS = {
33
+ [42161 /* ARBITRUM */]: "0x00c069d68bc7420740460DBC3cc3fFF9b3742421",
34
+ [8453 /* BASE */]: "0x1EcAbF0Eba136920677C9575FAccee36f30592cf"
35
+ };
32
36
  function getAddress(addressMap, chainId, name) {
33
37
  const addr = addressMap[chainId];
34
38
  if (!addr || addr === "0x0000000000000000000000000000000000000000") {
@@ -23652,6 +23656,17 @@ async function revokeAccess(walletClient, publicClient, multiAccount, params) {
23652
23656
  chain: walletClient.chain
23653
23657
  });
23654
23658
  }
23659
+ async function hasDelegatedAccess(publicClient, multiAccount, params) {
23660
+ validateAddress(params.account, "subAccount");
23661
+ validateAddress(params.target, "target");
23662
+ const result = await publicClient.readContract({
23663
+ address: multiAccount,
23664
+ abi: MultiAccountABI,
23665
+ functionName: "delegatedAccesses",
23666
+ args: [params.account, params.target, params.selector]
23667
+ });
23668
+ return Boolean(result);
23669
+ }
23655
23670
 
23656
23671
  // src/abis/SignatureStore.ts
23657
23672
  var SignatureStoreABI = [
@@ -23956,6 +23971,51 @@ async function getOpenInstantCloses(chainId, account, accessToken) {
23956
23971
  return response.json();
23957
23972
  }
23958
23973
 
23974
+ // src/actions/stats.ts
23975
+ async function getPartyAStats(publicClient, symmioDiamond, partyA) {
23976
+ const result = await publicClient.readContract({
23977
+ address: symmioDiamond,
23978
+ abi: SymmioDiamondABI,
23979
+ functionName: "partyAStats",
23980
+ args: [partyA]
23981
+ });
23982
+ return {
23983
+ collateralBalance: result[1],
23984
+ allocatedBalance: result[2],
23985
+ availableBalance: result[3],
23986
+ lockedCVA: result[4],
23987
+ lockedLF: result[5],
23988
+ lockedPartyAMM: result[6],
23989
+ lockedPartyBMM: result[7],
23990
+ pendingLockedCVA: result[8],
23991
+ pendingLockedLF: result[9],
23992
+ pendingLockedPartyAMM: result[10],
23993
+ pendingLockedPartyBMM: result[11],
23994
+ positionsCount: Number(result[12]),
23995
+ pendingCount: Number(result[13]),
23996
+ nonces: 0
23997
+ };
23998
+ }
23999
+ function calculateAvailableForOrder(stats, upnl) {
24000
+ const {
24001
+ allocatedBalance,
24002
+ lockedCVA,
24003
+ lockedLF,
24004
+ lockedPartyAMM,
24005
+ pendingLockedCVA,
24006
+ pendingLockedLF,
24007
+ pendingLockedPartyAMM
24008
+ } = stats;
24009
+ const totalPendingLocked = pendingLockedCVA + pendingLockedLF + pendingLockedPartyAMM;
24010
+ if (upnl >= 0n) {
24011
+ const totalLocked = lockedCVA + lockedLF + lockedPartyAMM;
24012
+ return allocatedBalance + upnl - totalLocked - totalPendingLocked;
24013
+ }
24014
+ const absUpnl = -upnl;
24015
+ const consideringMm = absUpnl > lockedPartyAMM ? absUpnl : lockedPartyAMM;
24016
+ return allocatedBalance - lockedCVA - lockedLF - totalPendingLocked - consideringMm;
24017
+ }
24018
+
23959
24019
  // src/client.ts
23960
24020
  var SymmioSDK = class {
23961
24021
  chainId;
@@ -24102,7 +24162,9 @@ var SymmioSDK = class {
24102
24162
  /** Propose to revoke delegated access (starts cooldown). */
24103
24163
  proposeRevoke: (params) => proposeRevoke(wc, pc, ma, params),
24104
24164
  /** Revoke delegated access (after cooldown). */
24105
- revokeAccess: (params) => revokeAccess(wc, pc, ma, params)
24165
+ revokeAccess: (params) => revokeAccess(wc, pc, ma, params),
24166
+ /** Reads whether a selector is delegated to a target for a sub-account. */
24167
+ hasAccess: (params) => hasDelegatedAccess(pc, ma, params)
24106
24168
  };
24107
24169
  }
24108
24170
  // ─── Signature Module ──────────────────────────────────────────
@@ -24158,6 +24220,17 @@ var SymmioSDK = class {
24158
24220
  getOpenCloses: (account, accessToken) => getOpenInstantCloses(this.chainId, account, accessToken)
24159
24221
  };
24160
24222
  }
24223
+ // ─── Stats Module ───────────────────────────────────────────
24224
+ get stats() {
24225
+ const pc = this._publicClient;
24226
+ const sd = this._symmioDiamond;
24227
+ return {
24228
+ /** Reads partyA statistics (balances, locks) from the Diamond contract. */
24229
+ getPartyAStats: (partyA) => getPartyAStats(pc, sd, partyA),
24230
+ /** Calculates available margin for placing orders given uPNL. */
24231
+ calculateAvailableForOrder: (stats, upnl) => calculateAvailableForOrder(stats, upnl)
24232
+ };
24233
+ }
24161
24234
  // ─── Muon Signatures ──────────────────────────────────────────
24162
24235
  async getQuoteSig(partyA, symbolId) {
24163
24236
  return this.muon.getQuoteSig({
@@ -24332,8 +24405,8 @@ function SymmProvider({
24332
24405
  setAccessToken(null);
24333
24406
  return;
24334
24407
  }
24335
- setAccessToken(null);
24336
24408
  if (previousAddress && (addressChanged || chainChanged)) {
24409
+ setAccessToken(null);
24337
24410
  clearCachedToken(previousAddress, previousChainId);
24338
24411
  }
24339
24412
  }, [address, walletClient, chainId]);
@@ -24388,6 +24461,14 @@ function useSymmAuth() {
24388
24461
  };
24389
24462
  }
24390
24463
 
24464
+ // src/constants/selectors.ts
24465
+ var SEND_QUOTE_WITH_AFFILIATE_SELECTOR = "0x40f1310c";
24466
+ var CLOSE_QUOTE_SELECTOR = "0x501e891f";
24467
+ var ALL_TRADING_SELECTORS = [
24468
+ SEND_QUOTE_WITH_AFFILIATE_SELECTOR,
24469
+ CLOSE_QUOTE_SELECTOR
24470
+ ];
24471
+
24391
24472
  // src/react/query-keys.ts
24392
24473
  var symmKeys = {
24393
24474
  all: ["symm"],
@@ -24406,10 +24487,157 @@ var symmKeys = {
24406
24487
  fundingRates: (chainId) => ["symm", "fundingRates", chainId],
24407
24488
  portfolio: (address, chainId) => ["symm", "portfolio", address, chainId],
24408
24489
  notifications: (address, chainId) => ["symm", "notifications", address, chainId],
24409
- unreadCount: (address, chainId) => ["symm", "unreadCount", address, chainId]
24490
+ unreadCount: (address, chainId) => ["symm", "unreadCount", address, chainId],
24491
+ availableMargin: (address, chainId) => ["symm", "availableMargin", address, chainId],
24492
+ delegation: (account, target, selectors, chainId) => ["symm", "delegation", account, target, selectors, chainId],
24493
+ chartMetadata: (symbolsKey, positionKey) => ["symm", "chartMetadata", symbolsKey, positionKey]
24410
24494
  };
24411
24495
 
24412
- // src/react/hooks/use-symm-accounts.ts
24496
+ // src/react/hooks/use-symm-delegation.ts
24497
+ function useSymmDelegation(params) {
24498
+ const { symmioClient, chainId, address } = useSymmContext();
24499
+ const accountAddress = params?.accountAddress ?? address;
24500
+ const target = params?.target ?? DEFAULT_PARTY_B_ADDRESS[chainId];
24501
+ const selectors = params?.selectors ?? ALL_TRADING_SELECTORS;
24502
+ const enabled = (params?.enabled ?? true) && !!symmioClient && !!accountAddress && !!target && selectors.length > 0;
24503
+ return reactQuery.useQuery({
24504
+ queryKey: symmKeys.delegation(accountAddress, target, selectors, chainId),
24505
+ enabled,
24506
+ queryFn: async () => {
24507
+ if (!symmioClient) throw new Error("symmio client not available");
24508
+ if (!accountAddress) throw new Error("account address is required");
24509
+ if (!target) throw new Error("delegation target is not configured");
24510
+ const entries = await Promise.all(
24511
+ selectors.map(async (selector) => [
24512
+ selector,
24513
+ await symmioClient.delegation.hasAccess({
24514
+ account: accountAddress,
24515
+ target,
24516
+ selector
24517
+ })
24518
+ ])
24519
+ );
24520
+ const accessBySelector = Object.fromEntries(entries);
24521
+ return {
24522
+ hasAccess: selectors.every((selector) => accessBySelector[selector] === true),
24523
+ account: accountAddress,
24524
+ target,
24525
+ selectors,
24526
+ accessBySelector,
24527
+ openAccess: accessBySelector[SEND_QUOTE_WITH_AFFILIATE_SELECTOR] ?? void 0,
24528
+ closeAccess: accessBySelector[CLOSE_QUOTE_SELECTOR] ?? void 0
24529
+ };
24530
+ }
24531
+ });
24532
+ }
24533
+
24534
+ // src/react/cache.ts
24535
+ function invalidateBalances(qc) {
24536
+ qc.invalidateQueries({ queryKey: ["symm", "balances"] });
24537
+ qc.invalidateQueries({ queryKey: ["symm", "accountSummary"] });
24538
+ qc.invalidateQueries({ queryKey: ["symm", "portfolio"] });
24539
+ }
24540
+ function invalidatePositions(qc) {
24541
+ qc.invalidateQueries({ queryKey: ["symm", "positions"] });
24542
+ qc.invalidateQueries({ queryKey: ["symm", "openOrders"] });
24543
+ qc.invalidateQueries({ queryKey: ["symm", "tradeHistory"] });
24544
+ qc.invalidateQueries({ queryKey: ["symm", "portfolio"] });
24545
+ }
24546
+ function invalidateOrders(qc) {
24547
+ qc.invalidateQueries({ queryKey: ["symm", "openOrders"] });
24548
+ qc.invalidateQueries({ queryKey: ["symm", "tpslOrders"] });
24549
+ qc.invalidateQueries({ queryKey: ["symm", "twapOrders"] });
24550
+ }
24551
+
24552
+ // src/react/hooks/use-symm-instant-trade.ts
24553
+ function useSymmInstantTrade(params) {
24554
+ const {
24555
+ symmioClient,
24556
+ symmCoreClient,
24557
+ chainId,
24558
+ address,
24559
+ refreshAuth
24560
+ } = useSymmContext();
24561
+ const queryClient = reactQuery.useQueryClient();
24562
+ const defaultAccountAddress = params?.accountAddress ?? address;
24563
+ const defaultTarget = params?.target ?? DEFAULT_PARTY_B_ADDRESS[chainId];
24564
+ const defaultSelectors = params?.selectors ?? ALL_TRADING_SELECTORS;
24565
+ const delegation = useSymmDelegation({
24566
+ accountAddress: defaultAccountAddress,
24567
+ target: defaultTarget,
24568
+ selectors: defaultSelectors,
24569
+ enabled: params?.enabled
24570
+ });
24571
+ const ensureReady = reactQuery.useMutation({
24572
+ mutationFn: async (request) => {
24573
+ if (!symmioClient) throw new Error("symmio client not available");
24574
+ const accountAddress = request?.accountAddress ?? defaultAccountAddress;
24575
+ const target = request?.target ?? defaultTarget;
24576
+ const selectors = request?.selectors ?? defaultSelectors;
24577
+ if (!accountAddress) throw new Error("account address is required");
24578
+ if (!target) throw new Error("delegation target is not configured");
24579
+ if (selectors.length === 0) {
24580
+ throw new Error("at least one delegation selector is required");
24581
+ }
24582
+ const accessToken = await refreshAuth(accountAddress);
24583
+ if (!accessToken) {
24584
+ throw new Error("failed to refresh instant-trading auth");
24585
+ }
24586
+ const accessStates = await Promise.all(
24587
+ selectors.map(
24588
+ (selector) => symmioClient.delegation.hasAccess({
24589
+ account: accountAddress,
24590
+ target,
24591
+ selector
24592
+ })
24593
+ )
24594
+ );
24595
+ if (!accessStates.every(Boolean)) {
24596
+ await symmioClient.delegation.delegateAccess({
24597
+ account: accountAddress,
24598
+ target,
24599
+ selectors: [...selectors],
24600
+ activate: true
24601
+ });
24602
+ await queryClient.invalidateQueries({
24603
+ queryKey: symmKeys.delegation(accountAddress, target, selectors, chainId)
24604
+ });
24605
+ }
24606
+ return {
24607
+ accessToken,
24608
+ accountAddress,
24609
+ target,
24610
+ selectors
24611
+ };
24612
+ }
24613
+ });
24614
+ const execute = reactQuery.useMutation({
24615
+ mutationFn: async (request) => {
24616
+ if (!symmCoreClient) throw new Error("symm-core client not available");
24617
+ const setup = await ensureReady.mutateAsync({
24618
+ accountAddress: request.accountAddress,
24619
+ target: request.target,
24620
+ selectors: request.selectors
24621
+ });
24622
+ return request.action({
24623
+ symmCoreClient,
24624
+ accessToken: setup.accessToken,
24625
+ accountAddress: setup.accountAddress
24626
+ });
24627
+ },
24628
+ onSuccess: (_data, variables) => {
24629
+ if (variables.invalidatePositionsOnSuccess !== false) {
24630
+ invalidatePositions(queryClient);
24631
+ }
24632
+ }
24633
+ });
24634
+ return {
24635
+ delegation,
24636
+ ensureReady,
24637
+ execute
24638
+ };
24639
+ }
24640
+ var EMPTY_ACCOUNTS = [];
24413
24641
  function useSymmAccounts(userAddress) {
24414
24642
  const { symmioClient } = useSymmContext();
24415
24643
  const queryClient = reactQuery.useQueryClient();
@@ -24440,7 +24668,7 @@ function useSymmAccounts(userAddress) {
24440
24668
  }
24441
24669
  });
24442
24670
  return {
24443
- accounts: accountsQuery.data ?? [],
24671
+ accounts: accountsQuery.data ?? EMPTY_ACCOUNTS,
24444
24672
  count: accountsQuery.data?.length ?? 0,
24445
24673
  isLoading: accountsQuery.isLoading,
24446
24674
  error: accountsQuery.error,
@@ -24455,21 +24683,23 @@ function useSymmApproval(params) {
24455
24683
  const { owner, amount, spender, collateralToken } = params;
24456
24684
  const resolvedSpender = spender ?? symmioClient?.addresses.multiAccount;
24457
24685
  const resolvedToken = collateralToken ?? symmioClient?.addresses.collateral;
24686
+ const selectWithAmount = react.useCallback(
24687
+ (data) => ({
24688
+ ...data,
24689
+ state: data.allowance >= amount ? "APPROVED" /* APPROVED */ : "NOT_APPROVED" /* NOT_APPROVED */
24690
+ }),
24691
+ [amount]
24692
+ );
24458
24693
  const approvalQuery = reactQuery.useQuery({
24459
24694
  queryKey: symmKeys.approval(owner, resolvedSpender),
24460
24695
  queryFn: async () => {
24461
- const [state, allowance, balance] = await Promise.all([
24462
- symmioClient.approval.getState(
24463
- resolvedToken,
24464
- owner,
24465
- resolvedSpender,
24466
- amount
24467
- ),
24696
+ const [allowance, balance] = await Promise.all([
24468
24697
  symmioClient.approval.getAllowance(resolvedToken, owner, resolvedSpender),
24469
24698
  symmioClient.approval.getBalance(resolvedToken, owner)
24470
24699
  ]);
24471
- return { state, allowance, balance };
24700
+ return { allowance, balance };
24472
24701
  },
24702
+ select: selectWithAmount,
24473
24703
  enabled: !!symmioClient && !!owner && !!resolvedSpender && !!resolvedToken
24474
24704
  });
24475
24705
  const approve2 = reactQuery.useMutation({
@@ -24491,26 +24721,6 @@ function useSymmApproval(params) {
24491
24721
  approve: approve2
24492
24722
  };
24493
24723
  }
24494
-
24495
- // src/react/cache.ts
24496
- function invalidateBalances(qc) {
24497
- qc.invalidateQueries({ queryKey: ["symm", "balances"] });
24498
- qc.invalidateQueries({ queryKey: ["symm", "accountSummary"] });
24499
- qc.invalidateQueries({ queryKey: ["symm", "portfolio"] });
24500
- }
24501
- function invalidatePositions(qc) {
24502
- qc.invalidateQueries({ queryKey: ["symm", "positions"] });
24503
- qc.invalidateQueries({ queryKey: ["symm", "openOrders"] });
24504
- qc.invalidateQueries({ queryKey: ["symm", "tradeHistory"] });
24505
- qc.invalidateQueries({ queryKey: ["symm", "portfolio"] });
24506
- }
24507
- function invalidateOrders(qc) {
24508
- qc.invalidateQueries({ queryKey: ["symm", "openOrders"] });
24509
- qc.invalidateQueries({ queryKey: ["symm", "tpslOrders"] });
24510
- qc.invalidateQueries({ queryKey: ["symm", "twapOrders"] });
24511
- }
24512
-
24513
- // src/react/hooks/use-symm-deposit.ts
24514
24724
  function useSymmDeposit() {
24515
24725
  const { symmioClient } = useSymmContext();
24516
24726
  const queryClient = reactQuery.useQueryClient();
@@ -24630,6 +24840,32 @@ function useSymmSignature(userAddress) {
24630
24840
  signTerms
24631
24841
  };
24632
24842
  }
24843
+ function useSymmAvailableMargin(params) {
24844
+ const { symmioClient } = useSymmContext();
24845
+ const { accountAddress, upnl } = params;
24846
+ const resolvedUpnl = upnl ?? 0n;
24847
+ const selectWithUpnl = react.useCallback(
24848
+ (stats) => ({
24849
+ ...stats,
24850
+ upnl: resolvedUpnl,
24851
+ availableForOrder: calculateAvailableForOrder(stats, resolvedUpnl)
24852
+ }),
24853
+ [resolvedUpnl]
24854
+ );
24855
+ const query = reactQuery.useQuery({
24856
+ queryKey: symmKeys.availableMargin(accountAddress, symmioClient?.chainId),
24857
+ queryFn: () => symmioClient.stats.getPartyAStats(accountAddress),
24858
+ select: selectWithUpnl,
24859
+ enabled: !!symmioClient && !!accountAddress,
24860
+ staleTime: 1e4
24861
+ });
24862
+ return {
24863
+ availableForOrder: query.data?.availableForOrder ?? null,
24864
+ stats: query.data ?? null,
24865
+ isLoading: query.isLoading,
24866
+ refetch: query.refetch
24867
+ };
24868
+ }
24633
24869
  function useSymmBalances(params) {
24634
24870
  const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
24635
24871
  const { userAddress, multiAccountAddress } = params;
@@ -24839,37 +25075,37 @@ function useSymmMarkets(params) {
24839
25075
  refetch: query.refetch
24840
25076
  };
24841
25077
  }
25078
+ var EMPTY_MARKETS = [];
25079
+ var EMPTY_SYMBOLS = [];
25080
+ var EMPTY_MAP_BY_ID = /* @__PURE__ */ new Map();
25081
+ var EMPTY_MAP_BY_SYMBOL = /* @__PURE__ */ new Map();
24842
25082
  function useSymmHedgerMarkets(params) {
24843
25083
  const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
24844
25084
  const chainId = params?.chainId ?? ctxChainId;
24845
25085
  const searchText = params?.searchText?.trim();
24846
25086
  const isEnabled = params?.enabled ?? true;
25087
+ const { enabled: _, ...restParams } = params ?? {};
24847
25088
  const request = {
24848
- ...params,
25089
+ ...restParams,
24849
25090
  chainId,
24850
25091
  searchText: searchText || void 0
24851
25092
  };
24852
25093
  const query = reactQuery.useQuery({
24853
25094
  queryKey: symmKeys.hedgerMarkets(request),
24854
- queryFn: async () => {
24855
- const { enabled: _enabled, ...queryRequest } = request;
24856
- return symmCoreClient.markets.listSymmHedger(queryRequest);
24857
- },
25095
+ queryFn: () => symmCoreClient.markets.listSymmHedger(request),
24858
25096
  enabled: !!symmCoreClient && isEnabled,
24859
25097
  staleTime: 3e4
24860
25098
  });
24861
25099
  const data = query.data ?? null;
24862
- const emptyMap = /* @__PURE__ */ new Map();
24863
- const emptySymbolMap = /* @__PURE__ */ new Map();
24864
25100
  return {
24865
25101
  data,
24866
- markets: data?.markets ?? [],
24867
- rawMarkets: data?.rawMarkets ?? [],
24868
- filteredMarkets: data?.filteredMarkets ?? [],
24869
- allSymbols: data?.allSymbols ?? [],
24870
- filteredSymbols: data?.filteredSymbols ?? [],
24871
- marketsById: data?.marketsById ?? emptyMap,
24872
- marketsBySymbol: data?.marketsBySymbol ?? emptySymbolMap,
25102
+ markets: data?.markets ?? EMPTY_MARKETS,
25103
+ rawMarkets: data?.rawMarkets ?? EMPTY_MARKETS,
25104
+ filteredMarkets: data?.filteredMarkets ?? EMPTY_MARKETS,
25105
+ allSymbols: data?.allSymbols ?? EMPTY_SYMBOLS,
25106
+ filteredSymbols: data?.filteredSymbols ?? EMPTY_SYMBOLS,
25107
+ marketsById: data?.marketsById ?? EMPTY_MAP_BY_ID,
25108
+ marketsBySymbol: data?.marketsBySymbol ?? EMPTY_MAP_BY_SYMBOL,
24873
25109
  category: data?.category ?? params?.category ?? "all",
24874
25110
  resolvedSearchText: data?.searchText ?? searchText ?? "",
24875
25111
  isLoading: query.isLoading,
@@ -24961,13 +25197,15 @@ function useSymmNotifications(params) {
24961
25197
  refetch: notificationsQuery.refetch
24962
25198
  };
24963
25199
  }
25200
+ function asUnsubscribeFn(value) {
25201
+ return typeof value === "function" ? value : null;
25202
+ }
24964
25203
  function useSymmWs(params) {
24965
25204
  const { symmCoreClient, chainId: ctxChainId } = useSymmContext();
24966
25205
  const queryClient = reactQuery.useQueryClient();
24967
25206
  const { accountAddress } = params;
24968
25207
  const chainId = params.chainId ?? ctxChainId;
24969
25208
  const [isConnected, setIsConnected] = react.useState(false);
24970
- const cleanupRef = react.useRef([]);
24971
25209
  react.useEffect(() => {
24972
25210
  if (!symmCoreClient || !accountAddress) {
24973
25211
  setIsConnected(false);
@@ -24975,61 +25213,75 @@ function useSymmWs(params) {
24975
25213
  }
24976
25214
  const ws = symmCoreClient.ws;
24977
25215
  const addr = accountAddress;
25216
+ const unsubscribers = [];
24978
25217
  const removeOnConnect = ws.onConnect(() => setIsConnected(true));
24979
25218
  const removeOnDisconnect = ws.onDisconnect(() => setIsConnected(false));
24980
- ws.subscribeToPositions(addr, chainId, () => {
25219
+ unsubscribers.push(removeOnConnect, removeOnDisconnect);
25220
+ const positionsUnsub = asUnsubscribeFn(ws.subscribeToPositions(addr, chainId, () => {
24981
25221
  queryClient.invalidateQueries({
24982
25222
  queryKey: symmKeys.positions(accountAddress, chainId)
24983
25223
  });
24984
- });
24985
- ws.subscribeToOpenOrders(addr, chainId, () => {
25224
+ }));
25225
+ if (positionsUnsub) unsubscribers.push(positionsUnsub);
25226
+ const openOrdersUnsub = asUnsubscribeFn(ws.subscribeToOpenOrders(addr, chainId, () => {
24986
25227
  queryClient.invalidateQueries({
24987
25228
  queryKey: symmKeys.openOrders(accountAddress, chainId)
24988
25229
  });
24989
- });
24990
- ws.subscribeToTrades(addr, chainId, () => {
25230
+ }));
25231
+ if (openOrdersUnsub) unsubscribers.push(openOrdersUnsub);
25232
+ const tradesUnsub = asUnsubscribeFn(ws.subscribeToTrades(addr, chainId, () => {
24991
25233
  queryClient.invalidateQueries({
24992
25234
  queryKey: symmKeys.tradeHistory(accountAddress, chainId)
24993
25235
  });
24994
- });
24995
- ws.subscribeToAccountSummary(addr, chainId, () => {
25236
+ }));
25237
+ if (tradesUnsub) unsubscribers.push(tradesUnsub);
25238
+ const accountSummaryUnsub = asUnsubscribeFn(ws.subscribeToAccountSummary(addr, chainId, () => {
24996
25239
  queryClient.invalidateQueries({
24997
25240
  queryKey: symmKeys.balances(accountAddress, chainId)
24998
25241
  });
24999
25242
  queryClient.invalidateQueries({
25000
25243
  queryKey: symmKeys.accountSummary(accountAddress, chainId)
25001
25244
  });
25002
- });
25003
- ws.subscribeToNotifications(addr, chainId, () => {
25245
+ }));
25246
+ if (accountSummaryUnsub) unsubscribers.push(accountSummaryUnsub);
25247
+ const notificationsUnsub = asUnsubscribeFn(ws.subscribeToNotifications(addr, chainId, () => {
25004
25248
  queryClient.invalidateQueries({
25005
25249
  queryKey: symmKeys.notifications(accountAddress, chainId)
25006
25250
  });
25007
25251
  queryClient.invalidateQueries({
25008
25252
  queryKey: symmKeys.unreadCount(accountAddress, chainId)
25009
25253
  });
25010
- });
25011
- ws.subscribeToTpsl(addr, chainId, () => {
25254
+ }));
25255
+ if (notificationsUnsub) unsubscribers.push(notificationsUnsub);
25256
+ const tpslUnsub = asUnsubscribeFn(ws.subscribeToTpsl(addr, chainId, () => {
25012
25257
  queryClient.invalidateQueries({
25013
25258
  queryKey: symmKeys.tpslOrders(accountAddress, chainId)
25014
25259
  });
25015
- });
25016
- ws.subscribeToTwapOrders(addr, chainId, () => {
25260
+ }));
25261
+ if (tpslUnsub) unsubscribers.push(tpslUnsub);
25262
+ const twapUnsub = asUnsubscribeFn(ws.subscribeToTwapOrders(addr, chainId, () => {
25017
25263
  queryClient.invalidateQueries({
25018
25264
  queryKey: symmKeys.twapOrders(accountAddress, chainId)
25019
25265
  });
25020
- });
25021
- ws.subscribeToExecutions(addr, chainId, () => {
25266
+ }));
25267
+ if (twapUnsub) unsubscribers.push(twapUnsub);
25268
+ const executionsUnsub = asUnsubscribeFn(ws.subscribeToExecutions(addr, chainId, () => {
25022
25269
  queryClient.invalidateQueries({
25023
25270
  queryKey: symmKeys.positions(accountAddress, chainId)
25024
25271
  });
25025
25272
  queryClient.invalidateQueries({
25026
25273
  queryKey: symmKeys.portfolio(accountAddress, chainId)
25027
25274
  });
25028
- });
25029
- cleanupRef.current = [removeOnConnect, removeOnDisconnect];
25275
+ }));
25276
+ if (executionsUnsub) unsubscribers.push(executionsUnsub);
25030
25277
  return () => {
25031
- cleanupRef.current.forEach((fn) => fn());
25032
- ws.unsubscribeAll();
25278
+ if (unsubscribers.length > 2) {
25279
+ unsubscribers.forEach((unsubscribe) => unsubscribe());
25280
+ } else {
25281
+ removeOnConnect();
25282
+ removeOnDisconnect();
25283
+ ws.unsubscribeAll();
25284
+ }
25033
25285
  };
25034
25286
  }, [symmCoreClient, accountAddress, chainId, queryClient]);
25035
25287
  return { isConnected };
@@ -25356,8 +25608,12 @@ function useSymmTokenSelectionMetadata(selection) {
25356
25608
  const isUnsupported = unsupportedSymbols.length > 0;
25357
25609
  const unavailableReason = isUnsupported ? `Binance market data is unavailable for ${unsupportedSymbols.join(", ")}.` : null;
25358
25610
  const symbolsKey = [...selectedSymbols].sort().join(",");
25611
+ const positionKey = [
25612
+ longTokens.map((token) => `${token.symbol}:${token.weight}`).join("|"),
25613
+ shortTokens.map((token) => `${token.symbol}:${token.weight}`).join("|")
25614
+ ].join("::");
25359
25615
  const query = reactQuery.useQuery({
25360
- queryKey: ["symm", "chart-metadata", symbolsKey],
25616
+ queryKey: symmKeys.chartMetadata(symbolsKey, positionKey),
25361
25617
  queryFn: async () => {
25362
25618
  const allSymbols = [
25363
25619
  ...longTokens.map((t) => ({ symbol: t.symbol, side: "long" })),
@@ -25792,7 +26048,6 @@ function useSymmChartCandles(selection) {
25792
26048
  low: longValues.l * shortValues.l,
25793
26049
  close: longValues.c * shortValues.c
25794
26050
  };
25795
- if (!bar) return;
25796
26051
  listenersRef.current.forEach((cb) => {
25797
26052
  try {
25798
26053
  cb(bar);
@@ -25817,11 +26072,14 @@ function useSymmChartCandles(selection) {
25817
26072
  }
25818
26073
  }, [emitRealtimeBar, isUnsupported, selectedSymbols]);
25819
26074
  react.useEffect(() => {
26075
+ if (listenersRef.current.size > 0) {
26076
+ setupWsSubscriptions();
26077
+ }
25820
26078
  return () => {
25821
26079
  wsUnsubsRef.current.forEach((unsub) => unsub());
25822
26080
  wsUnsubsRef.current = [];
25823
26081
  };
25824
- }, [longTokens, shortTokens]);
26082
+ }, [setupWsSubscriptions]);
25825
26083
  const fetchBasketCandles = react.useCallback(
25826
26084
  async (start, end, interval) => {
25827
26085
  const longSymbol = longTokens[0]?.symbol;
@@ -25987,10 +26245,8 @@ function useSymmPerformanceOverlays(selection) {
25987
26245
  weight: -token.weight
25988
26246
  }))
25989
26247
  ], [longTokens, shortTokens]);
25990
- const generateOverlaySymbols = react.useCallback(() => {
25991
- return overlays.map((o) => o.symbol);
25992
- }, [overlays]);
25993
- return { overlays, generateOverlaySymbols };
26248
+ const overlaySymbols = react.useMemo(() => overlays.map((o) => o.symbol), [overlays]);
26249
+ return { overlays, overlaySymbols };
25994
26250
  }
25995
26251
  function getSymmErrorMessage(error) {
25996
26252
  if (error instanceof SymmioSDKError) return error.message;
@@ -26010,15 +26266,18 @@ exports.symmKeys = symmKeys;
26010
26266
  exports.useSymmAccounts = useSymmAccounts;
26011
26267
  exports.useSymmApproval = useSymmApproval;
26012
26268
  exports.useSymmAuth = useSymmAuth;
26269
+ exports.useSymmAvailableMargin = useSymmAvailableMargin;
26013
26270
  exports.useSymmBalances = useSymmBalances;
26014
26271
  exports.useSymmChartCandles = useSymmChartCandles;
26015
26272
  exports.useSymmChartSelection = useSymmChartSelection;
26016
26273
  exports.useSymmCollateral = useSymmCollateral;
26017
26274
  exports.useSymmContext = useSymmContext;
26018
26275
  exports.useSymmCoreClient = useSymmCoreClient;
26276
+ exports.useSymmDelegation = useSymmDelegation;
26019
26277
  exports.useSymmDeposit = useSymmDeposit;
26020
26278
  exports.useSymmFunding = useSymmFunding;
26021
26279
  exports.useSymmHedgerMarkets = useSymmHedgerMarkets;
26280
+ exports.useSymmInstantTrade = useSymmInstantTrade;
26022
26281
  exports.useSymmMarkets = useSymmMarkets;
26023
26282
  exports.useSymmNotifications = useSymmNotifications;
26024
26283
  exports.useSymmOpenOrders = useSymmOpenOrders;