@talismn/balances-react 0.0.0-pr640-20230321101310 → 0.0.0-pr643-20230322031130

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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @talismn/balances-react
2
2
 
3
- ## 0.0.0-pr640-20230321101310
3
+ ## 0.0.0-pr643-20230322031130
4
4
 
5
5
  ### Minor Changes
6
6
 
@@ -8,18 +8,20 @@
8
8
 
9
9
  ### Patch Changes
10
10
 
11
+ - 3068bd6: feat: stale balances and exponential rpc backoff
11
12
  - 6643a4e: fix: tokenRates in @talismn/balances-react
12
13
  - 6643a4e: fix: ported useDbCache related perf fixes to @talismn/balances-react
14
+ - Updated dependencies [3068bd6]
13
15
  - Updated dependencies [6643a4e]
14
16
  - Updated dependencies [79f6ccf]
15
17
  - Updated dependencies [6643a4e]
16
- - Updated dependencies [c24dc1f]
17
- - @talismn/token-rates@0.0.0-pr640-20230321101310
18
- - @talismn/balances@0.0.0-pr640-20230321101310
19
- - @talismn/chaindata-provider-extension@0.0.0-pr640-20230321101310
20
- - @talismn/chaindata-provider@0.0.0-pr640-20230321101310
21
- - @talismn/chain-connector@0.0.0-pr640-20230321101310
22
- - @talismn/chain-connector-evm@0.0.0-pr640-20230321101310
18
+ - @talismn/chain-connector@0.0.0-pr643-20230322031130
19
+ - @talismn/connection-meta@0.0.0-pr643-20230322031130
20
+ - @talismn/balances@0.0.0-pr643-20230322031130
21
+ - @talismn/token-rates@0.0.0-pr643-20230322031130
22
+ - @talismn/chaindata-provider-extension@0.0.0-pr643-20230322031130
23
+ - @talismn/chaindata-provider@0.0.0-pr643-20230322031130
24
+ - @talismn/chain-connector-evm@0.0.0-pr643-20230322031130
23
25
 
24
26
  ## 0.3.3
25
27
 
@@ -2,6 +2,7 @@ export * from "./useAllAddresses";
2
2
  export * from "./useBalanceModules";
3
3
  export * from "./useBalances";
4
4
  export * from "./useBalancesHydrate";
5
+ export * from "./useBalancesStatus";
5
6
  export * from "./useChainConnectors";
6
7
  export * from "./useChaindata";
7
8
  export * from "./useChains";
@@ -0,0 +1,19 @@
1
+ import { Balances } from "@talismn/balances";
2
+ export type BalancesStatus = {
3
+ status: "live";
4
+ } | {
5
+ status: "fetching";
6
+ } | {
7
+ status: "stale";
8
+ staleChains: string[];
9
+ };
10
+ /**
11
+ * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
12
+ *
13
+ * @param balances The collection of balances to get the status from.
14
+ * @param isLoadingLocks Because the wallet currently fetches locks outside of the balances api, this param can be used to indicate that the locks are still loading, even if the `Balances` collection is not.
15
+ * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
16
+
17
+ */
18
+ export declare const useBalancesStatus: (balances: Balances, isLoadingLocks?: boolean) => BalancesStatus;
19
+ export declare const getStaleChains: (balances: Balances) => string[];
@@ -6,6 +6,7 @@ var react = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var chainConnector = require('@talismn/chain-connector');
8
8
  var chainConnectorEvm = require('@talismn/chain-connector-evm');
9
+ var connectionMeta = require('@talismn/connection-meta');
9
10
  var chaindataProviderExtension = require('@talismn/chaindata-provider-extension');
10
11
  var balances = require('@talismn/balances');
11
12
  var tokenRates = require('@talismn/token-rates');
@@ -73,7 +74,7 @@ function useChainConnectorsProvider(options) {
73
74
  const chaindata = useChaindata();
74
75
 
75
76
  // substrate connector
76
- const substrate = react.useMemo(() => new chainConnector.ChainConnector(chaindata), [chaindata]);
77
+ const substrate = react.useMemo(() => new chainConnector.ChainConnector(chaindata, connectionMeta.connectionMetaDb), [chaindata]);
77
78
 
78
79
  // evm connector
79
80
  const evm = react.useMemo(() => new chainConnectorEvm.ChainConnectorEvm(chaindata, {
@@ -173,9 +174,9 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
173
174
  };
174
175
  const useDbCacheProvider = () => {
175
176
  const chaindataProvider = useChaindata();
176
- const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.chains(), [chaindataProvider]);
177
- const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.evmNetworks(), [chaindataProvider]);
178
- const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
177
+ const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.chains(), [chaindataProvider]);
178
+ const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.evmNetworks(), [chaindataProvider]);
179
+ const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.tokens(), [chaindataProvider]);
179
180
  const tokenRates$1 = dexieReactHooks.useLiveQuery(() => tokenRates.db.tokenRates.toArray(), []);
180
181
  const rawBalances = dexieReactHooks.useLiveQuery(() => balances.db.balances.toArray(), []);
181
182
  const [dbData, setDbData] = react.useState(DEFAULT_VALUE);
@@ -199,7 +200,7 @@ const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
199
200
 
200
201
  var packageJson = {
201
202
  name: "@talismn/balances-react",
202
- version: "0.0.0-pr640-20230321101310",
203
+ version: "0.0.0-pr643-20230322031130",
203
204
  author: "Talisman",
204
205
  homepage: "https://talisman.xyz",
205
206
  license: "UNLICENSED",
@@ -217,7 +218,7 @@ var packageJson = {
217
218
  "/dist"
218
219
  ],
219
220
  engines: {
220
- node: ">=18"
221
+ node: ">=14"
221
222
  },
222
223
  scripts: {
223
224
  test: "jest",
@@ -230,6 +231,7 @@ var packageJson = {
230
231
  "@talismn/chain-connector-evm": "workspace:^",
231
232
  "@talismn/chaindata-provider": "workspace:^",
232
233
  "@talismn/chaindata-provider-extension": "workspace:^",
234
+ "@talismn/connection-meta": "workspace:^",
233
235
  "@talismn/token-rates": "workspace:^",
234
236
  anylogger: "^1.0.11",
235
237
  "blueimp-md5": "2.19.0",
@@ -442,8 +444,8 @@ function useDbCacheBalancesSubscription() {
442
444
  }, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
443
445
  const subscription = react.useCallback(() => {
444
446
  if (!Object.values(tokens ?? {}).length || !allAddresses.length) return () => {};
445
- return subscribeBalances(tokens ?? {}, allAddresses, chainConnectors, chaindataProvider, balanceModules);
446
- }, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
447
+ return subscribeBalances(tokens ?? {}, allAddresses, balanceModules);
448
+ }, [allAddresses, balanceModules, tokens]);
447
449
  useSharedSubscription(subscriptionKey, subscription);
448
450
  }
449
451
  const subscribeChainDataHydrate = (provider, type) => {
@@ -501,7 +503,7 @@ const subscribeTokenRates = tokens => {
501
503
  if (timeout) clearTimeout(timeout);
502
504
  };
503
505
  };
504
- const subscribeBalances = (tokens, addresses, chainConnectors, provider, balanceModules) => {
506
+ const subscribeBalances = (tokens, addresses, balanceModules) => {
505
507
  const tokenIds = Object.values(tokens).map(({
506
508
  id
507
509
  }) => id);
@@ -525,28 +527,41 @@ const subscribeBalances = (tokens, addresses, chainConnectors, provider, balance
525
527
  id
526
528
  }) => id);
527
529
  const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
528
- const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances) => {
530
+ const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances$1) => {
529
531
  // log errors
530
- if (error) return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
532
+ if (error) {
533
+ if ((error === null || error === void 0 ? void 0 : error.type) === "STALE_RPC_ERROR") return balances.db.balances.where({
534
+ source: balanceModule.type,
535
+ chainId: error.chainId
536
+ }).filter(balance => {
537
+ if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
538
+ if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
539
+ return true;
540
+ }).modify({
541
+ status: "stale"
542
+ });
543
+ return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
544
+ }
531
545
  // ignore empty balance responses
532
- if (!balances) return;
546
+ if (!balances$1) return;
533
547
  // ignore balances from old subscriptions which are still in the process of unsubscribing
534
548
  if (unsubscribed) return;
535
- updateDb(balances);
549
+ updateDb(balances$1);
536
550
  });
537
551
  return () => {
538
552
  // wait 2 seconds before actually unsubscribing, allowing for websocket to be reused
539
553
  unsub.then(unsubscribe => {
540
554
  setTimeout(unsubscribe, 2_000);
541
555
  });
542
- balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.filter(balance => {
543
- if (balance.source !== balanceModule.type) return false;
556
+ balances.db.balances.where({
557
+ source: balanceModule.type
558
+ }).filter(balance => {
544
559
  if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
545
560
  if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
546
561
  return true;
547
562
  }).modify({
548
563
  status: "cache"
549
- }));
564
+ });
550
565
  };
551
566
  });
552
567
  const unsubscribeAll = () => {
@@ -643,6 +658,38 @@ function useBalances(addressesByToken) {
643
658
  hydrate), [balances$1, hydrate, balanceModules, addressesByToken]);
644
659
  }
645
660
 
661
+ /**
662
+ * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
663
+ *
664
+ * @param balances The collection of balances to get the status from.
665
+ * @param isLoadingLocks Because the wallet currently fetches locks outside of the balances api, this param can be used to indicate that the locks are still loading, even if the `Balances` collection is not.
666
+ * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
667
+
668
+ */
669
+ const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
670
+ // stale
671
+ const staleChains = getStaleChains(balances);
672
+ if (staleChains.length > 0) return {
673
+ status: "stale",
674
+ staleChains
675
+ };
676
+
677
+ // fetching
678
+ const hasCachedBalances = balances.each.some(b => b.status === "cache");
679
+ if (hasCachedBalances || isLoadingLocks) return {
680
+ status: "fetching"
681
+ };
682
+
683
+ // live
684
+ return {
685
+ status: "live"
686
+ };
687
+ }, [balances, isLoadingLocks]);
688
+ const getStaleChains = balances => [...new Set(balances.sorted.filter(b => b.status === "stale").map(b => {
689
+ var _b$chain;
690
+ return ((_b$chain = b.chain) === null || _b$chain === void 0 ? void 0 : _b$chain.name) ?? b.chainId ?? "Unknown";
691
+ }))];
692
+
646
693
  const BalancesProvider = ({
647
694
  balanceModules,
648
695
  onfinalityApiKey,
@@ -674,11 +721,13 @@ exports.ChaindataProvider = ChaindataProvider;
674
721
  exports.DbCacheProvider = DbCacheProvider;
675
722
  exports.WithTestnetsProvider = WithTestnetsProvider;
676
723
  exports.createMulticastSubscription = createMulticastSubscription;
724
+ exports.getStaleChains = getStaleChains;
677
725
  exports.provideContext = provideContext;
678
726
  exports.useAllAddresses = useAllAddresses;
679
727
  exports.useBalanceModules = useBalanceModules;
680
728
  exports.useBalances = useBalances;
681
729
  exports.useBalancesHydrate = useBalancesHydrate;
730
+ exports.useBalancesStatus = useBalancesStatus;
682
731
  exports.useChain = useChain;
683
732
  exports.useChainConnectors = useChainConnectors;
684
733
  exports.useChaindata = useChaindata;
@@ -6,6 +6,7 @@ var react = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var chainConnector = require('@talismn/chain-connector');
8
8
  var chainConnectorEvm = require('@talismn/chain-connector-evm');
9
+ var connectionMeta = require('@talismn/connection-meta');
9
10
  var chaindataProviderExtension = require('@talismn/chaindata-provider-extension');
10
11
  var balances = require('@talismn/balances');
11
12
  var tokenRates = require('@talismn/token-rates');
@@ -73,7 +74,7 @@ function useChainConnectorsProvider(options) {
73
74
  const chaindata = useChaindata();
74
75
 
75
76
  // substrate connector
76
- const substrate = react.useMemo(() => new chainConnector.ChainConnector(chaindata), [chaindata]);
77
+ const substrate = react.useMemo(() => new chainConnector.ChainConnector(chaindata, connectionMeta.connectionMetaDb), [chaindata]);
77
78
 
78
79
  // evm connector
79
80
  const evm = react.useMemo(() => new chainConnectorEvm.ChainConnectorEvm(chaindata, {
@@ -173,9 +174,9 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
173
174
  };
174
175
  const useDbCacheProvider = () => {
175
176
  const chaindataProvider = useChaindata();
176
- const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.chains(), [chaindataProvider]);
177
- const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.evmNetworks(), [chaindataProvider]);
178
- const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
177
+ const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.chains(), [chaindataProvider]);
178
+ const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.evmNetworks(), [chaindataProvider]);
179
+ const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.tokens(), [chaindataProvider]);
179
180
  const tokenRates$1 = dexieReactHooks.useLiveQuery(() => tokenRates.db.tokenRates.toArray(), []);
180
181
  const rawBalances = dexieReactHooks.useLiveQuery(() => balances.db.balances.toArray(), []);
181
182
  const [dbData, setDbData] = react.useState(DEFAULT_VALUE);
@@ -199,7 +200,7 @@ const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
199
200
 
200
201
  var packageJson = {
201
202
  name: "@talismn/balances-react",
202
- version: "0.0.0-pr640-20230321101310",
203
+ version: "0.0.0-pr643-20230322031130",
203
204
  author: "Talisman",
204
205
  homepage: "https://talisman.xyz",
205
206
  license: "UNLICENSED",
@@ -217,7 +218,7 @@ var packageJson = {
217
218
  "/dist"
218
219
  ],
219
220
  engines: {
220
- node: ">=18"
221
+ node: ">=14"
221
222
  },
222
223
  scripts: {
223
224
  test: "jest",
@@ -230,6 +231,7 @@ var packageJson = {
230
231
  "@talismn/chain-connector-evm": "workspace:^",
231
232
  "@talismn/chaindata-provider": "workspace:^",
232
233
  "@talismn/chaindata-provider-extension": "workspace:^",
234
+ "@talismn/connection-meta": "workspace:^",
233
235
  "@talismn/token-rates": "workspace:^",
234
236
  anylogger: "^1.0.11",
235
237
  "blueimp-md5": "2.19.0",
@@ -442,8 +444,8 @@ function useDbCacheBalancesSubscription() {
442
444
  }, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
443
445
  const subscription = react.useCallback(() => {
444
446
  if (!Object.values(tokens ?? {}).length || !allAddresses.length) return () => {};
445
- return subscribeBalances(tokens ?? {}, allAddresses, chainConnectors, chaindataProvider, balanceModules);
446
- }, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
447
+ return subscribeBalances(tokens ?? {}, allAddresses, balanceModules);
448
+ }, [allAddresses, balanceModules, tokens]);
447
449
  useSharedSubscription(subscriptionKey, subscription);
448
450
  }
449
451
  const subscribeChainDataHydrate = (provider, type) => {
@@ -501,7 +503,7 @@ const subscribeTokenRates = tokens => {
501
503
  if (timeout) clearTimeout(timeout);
502
504
  };
503
505
  };
504
- const subscribeBalances = (tokens, addresses, chainConnectors, provider, balanceModules) => {
506
+ const subscribeBalances = (tokens, addresses, balanceModules) => {
505
507
  const tokenIds = Object.values(tokens).map(({
506
508
  id
507
509
  }) => id);
@@ -525,28 +527,41 @@ const subscribeBalances = (tokens, addresses, chainConnectors, provider, balance
525
527
  id
526
528
  }) => id);
527
529
  const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
528
- const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances) => {
530
+ const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances$1) => {
529
531
  // log errors
530
- if (error) return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
532
+ if (error) {
533
+ if ((error === null || error === void 0 ? void 0 : error.type) === "STALE_RPC_ERROR") return balances.db.balances.where({
534
+ source: balanceModule.type,
535
+ chainId: error.chainId
536
+ }).filter(balance => {
537
+ if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
538
+ if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
539
+ return true;
540
+ }).modify({
541
+ status: "stale"
542
+ });
543
+ return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
544
+ }
531
545
  // ignore empty balance responses
532
- if (!balances) return;
546
+ if (!balances$1) return;
533
547
  // ignore balances from old subscriptions which are still in the process of unsubscribing
534
548
  if (unsubscribed) return;
535
- updateDb(balances);
549
+ updateDb(balances$1);
536
550
  });
537
551
  return () => {
538
552
  // wait 2 seconds before actually unsubscribing, allowing for websocket to be reused
539
553
  unsub.then(unsubscribe => {
540
554
  setTimeout(unsubscribe, 2_000);
541
555
  });
542
- balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.filter(balance => {
543
- if (balance.source !== balanceModule.type) return false;
556
+ balances.db.balances.where({
557
+ source: balanceModule.type
558
+ }).filter(balance => {
544
559
  if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
545
560
  if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
546
561
  return true;
547
562
  }).modify({
548
563
  status: "cache"
549
- }));
564
+ });
550
565
  };
551
566
  });
552
567
  const unsubscribeAll = () => {
@@ -643,6 +658,38 @@ function useBalances(addressesByToken) {
643
658
  hydrate), [balances$1, hydrate, balanceModules, addressesByToken]);
644
659
  }
645
660
 
661
+ /**
662
+ * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
663
+ *
664
+ * @param balances The collection of balances to get the status from.
665
+ * @param isLoadingLocks Because the wallet currently fetches locks outside of the balances api, this param can be used to indicate that the locks are still loading, even if the `Balances` collection is not.
666
+ * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
667
+
668
+ */
669
+ const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
670
+ // stale
671
+ const staleChains = getStaleChains(balances);
672
+ if (staleChains.length > 0) return {
673
+ status: "stale",
674
+ staleChains
675
+ };
676
+
677
+ // fetching
678
+ const hasCachedBalances = balances.each.some(b => b.status === "cache");
679
+ if (hasCachedBalances || isLoadingLocks) return {
680
+ status: "fetching"
681
+ };
682
+
683
+ // live
684
+ return {
685
+ status: "live"
686
+ };
687
+ }, [balances, isLoadingLocks]);
688
+ const getStaleChains = balances => [...new Set(balances.sorted.filter(b => b.status === "stale").map(b => {
689
+ var _b$chain;
690
+ return ((_b$chain = b.chain) === null || _b$chain === void 0 ? void 0 : _b$chain.name) ?? b.chainId ?? "Unknown";
691
+ }))];
692
+
646
693
  const BalancesProvider = ({
647
694
  balanceModules,
648
695
  onfinalityApiKey,
@@ -674,11 +721,13 @@ exports.ChaindataProvider = ChaindataProvider;
674
721
  exports.DbCacheProvider = DbCacheProvider;
675
722
  exports.WithTestnetsProvider = WithTestnetsProvider;
676
723
  exports.createMulticastSubscription = createMulticastSubscription;
724
+ exports.getStaleChains = getStaleChains;
677
725
  exports.provideContext = provideContext;
678
726
  exports.useAllAddresses = useAllAddresses;
679
727
  exports.useBalanceModules = useBalanceModules;
680
728
  exports.useBalances = useBalances;
681
729
  exports.useBalancesHydrate = useBalancesHydrate;
730
+ exports.useBalancesStatus = useBalancesStatus;
682
731
  exports.useChain = useChain;
683
732
  exports.useChainConnectors = useChainConnectors;
684
733
  exports.useChaindata = useChaindata;
@@ -2,6 +2,7 @@ import { useContext, createContext, useState, useEffect, useMemo, useRef, useCal
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { ChainConnector } from '@talismn/chain-connector';
4
4
  import { ChainConnectorEvm } from '@talismn/chain-connector-evm';
5
+ import { connectionMetaDb } from '@talismn/connection-meta';
5
6
  import { ChaindataProviderExtension } from '@talismn/chaindata-provider-extension';
6
7
  import { db as db$1, balances, Balances } from '@talismn/balances';
7
8
  import { db, fetchTokenRates } from '@talismn/token-rates';
@@ -64,7 +65,7 @@ function useChainConnectorsProvider(options) {
64
65
  const chaindata = useChaindata();
65
66
 
66
67
  // substrate connector
67
- const substrate = useMemo(() => new ChainConnector(chaindata), [chaindata]);
68
+ const substrate = useMemo(() => new ChainConnector(chaindata, connectionMetaDb), [chaindata]);
68
69
 
69
70
  // evm connector
70
71
  const evm = useMemo(() => new ChainConnectorEvm(chaindata, {
@@ -164,9 +165,9 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
164
165
  };
165
166
  const useDbCacheProvider = () => {
166
167
  const chaindataProvider = useChaindata();
167
- const chainList = useLiveQuery(() => chaindataProvider?.chains(), [chaindataProvider]);
168
- const evmNetworkList = useLiveQuery(() => chaindataProvider?.evmNetworks(), [chaindataProvider]);
169
- const tokenList = useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
168
+ const chainList = useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.chains(), [chaindataProvider]);
169
+ const evmNetworkList = useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.evmNetworks(), [chaindataProvider]);
170
+ const tokenList = useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.tokens(), [chaindataProvider]);
170
171
  const tokenRates = useLiveQuery(() => db.tokenRates.toArray(), []);
171
172
  const rawBalances = useLiveQuery(() => db$1.balances.toArray(), []);
172
173
  const [dbData, setDbData] = useState(DEFAULT_VALUE);
@@ -190,7 +191,7 @@ const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
190
191
 
191
192
  var packageJson = {
192
193
  name: "@talismn/balances-react",
193
- version: "0.0.0-pr640-20230321101310",
194
+ version: "0.0.0-pr643-20230322031130",
194
195
  author: "Talisman",
195
196
  homepage: "https://talisman.xyz",
196
197
  license: "UNLICENSED",
@@ -208,7 +209,7 @@ var packageJson = {
208
209
  "/dist"
209
210
  ],
210
211
  engines: {
211
- node: ">=18"
212
+ node: ">=14"
212
213
  },
213
214
  scripts: {
214
215
  test: "jest",
@@ -221,6 +222,7 @@ var packageJson = {
221
222
  "@talismn/chain-connector-evm": "workspace:^",
222
223
  "@talismn/chaindata-provider": "workspace:^",
223
224
  "@talismn/chaindata-provider-extension": "workspace:^",
225
+ "@talismn/connection-meta": "workspace:^",
224
226
  "@talismn/token-rates": "workspace:^",
225
227
  anylogger: "^1.0.11",
226
228
  "blueimp-md5": "2.19.0",
@@ -433,8 +435,8 @@ function useDbCacheBalancesSubscription() {
433
435
  }, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
434
436
  const subscription = useCallback(() => {
435
437
  if (!Object.values(tokens ?? {}).length || !allAddresses.length) return () => {};
436
- return subscribeBalances(tokens ?? {}, allAddresses, chainConnectors, chaindataProvider, balanceModules);
437
- }, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
438
+ return subscribeBalances(tokens ?? {}, allAddresses, balanceModules);
439
+ }, [allAddresses, balanceModules, tokens]);
438
440
  useSharedSubscription(subscriptionKey, subscription);
439
441
  }
440
442
  const subscribeChainDataHydrate = (provider, type) => {
@@ -492,7 +494,7 @@ const subscribeTokenRates = tokens => {
492
494
  if (timeout) clearTimeout(timeout);
493
495
  };
494
496
  };
495
- const subscribeBalances = (tokens, addresses, chainConnectors, provider, balanceModules) => {
497
+ const subscribeBalances = (tokens, addresses, balanceModules) => {
496
498
  const tokenIds = Object.values(tokens).map(({
497
499
  id
498
500
  }) => id);
@@ -518,7 +520,19 @@ const subscribeBalances = (tokens, addresses, chainConnectors, provider, balance
518
520
  const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
519
521
  const unsub = balances(balanceModule, addressesByModuleToken, (error, balances) => {
520
522
  // log errors
521
- if (error) return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
523
+ if (error) {
524
+ if ((error === null || error === void 0 ? void 0 : error.type) === "STALE_RPC_ERROR") return db$1.balances.where({
525
+ source: balanceModule.type,
526
+ chainId: error.chainId
527
+ }).filter(balance => {
528
+ if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
529
+ if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
530
+ return true;
531
+ }).modify({
532
+ status: "stale"
533
+ });
534
+ return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
535
+ }
522
536
  // ignore empty balance responses
523
537
  if (!balances) return;
524
538
  // ignore balances from old subscriptions which are still in the process of unsubscribing
@@ -530,14 +544,15 @@ const subscribeBalances = (tokens, addresses, chainConnectors, provider, balance
530
544
  unsub.then(unsubscribe => {
531
545
  setTimeout(unsubscribe, 2_000);
532
546
  });
533
- db$1.transaction("rw", db$1.balances, async () => await db$1.balances.filter(balance => {
534
- if (balance.source !== balanceModule.type) return false;
547
+ db$1.balances.where({
548
+ source: balanceModule.type
549
+ }).filter(balance => {
535
550
  if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
536
551
  if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
537
552
  return true;
538
553
  }).modify({
539
554
  status: "cache"
540
- }));
555
+ });
541
556
  };
542
557
  });
543
558
  const unsubscribeAll = () => {
@@ -634,6 +649,38 @@ function useBalances(addressesByToken) {
634
649
  hydrate), [balances, hydrate, balanceModules, addressesByToken]);
635
650
  }
636
651
 
652
+ /**
653
+ * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
654
+ *
655
+ * @param balances The collection of balances to get the status from.
656
+ * @param isLoadingLocks Because the wallet currently fetches locks outside of the balances api, this param can be used to indicate that the locks are still loading, even if the `Balances` collection is not.
657
+ * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
658
+
659
+ */
660
+ const useBalancesStatus = (balances, isLoadingLocks) => useMemo(() => {
661
+ // stale
662
+ const staleChains = getStaleChains(balances);
663
+ if (staleChains.length > 0) return {
664
+ status: "stale",
665
+ staleChains
666
+ };
667
+
668
+ // fetching
669
+ const hasCachedBalances = balances.each.some(b => b.status === "cache");
670
+ if (hasCachedBalances || isLoadingLocks) return {
671
+ status: "fetching"
672
+ };
673
+
674
+ // live
675
+ return {
676
+ status: "live"
677
+ };
678
+ }, [balances, isLoadingLocks]);
679
+ const getStaleChains = balances => [...new Set(balances.sorted.filter(b => b.status === "stale").map(b => {
680
+ var _b$chain;
681
+ return ((_b$chain = b.chain) === null || _b$chain === void 0 ? void 0 : _b$chain.name) ?? b.chainId ?? "Unknown";
682
+ }))];
683
+
637
684
  const BalancesProvider = ({
638
685
  balanceModules,
639
686
  onfinalityApiKey,
@@ -657,4 +704,4 @@ const BalancesProvider = ({
657
704
  })
658
705
  });
659
706
 
660
- export { AllAddressesProvider, BalanceModulesProvider, BalancesProvider, ChainConnectorsProvider, ChaindataProvider, DbCacheProvider, WithTestnetsProvider, createMulticastSubscription, provideContext, useAllAddresses, useBalanceModules, useBalances, useBalancesHydrate, useChain, useChainConnectors, useChaindata, useChains, useDbCache, useDbCacheBalancesSubscription, useDbCacheSubscription, useDbCacheTokenRatesSubscription, useEvmNetwork, useEvmNetworks, useMulticastSubscription, useToken, useTokenRate, useTokenRates, useTokens, useWithTestnets };
707
+ export { AllAddressesProvider, BalanceModulesProvider, BalancesProvider, ChainConnectorsProvider, ChaindataProvider, DbCacheProvider, WithTestnetsProvider, createMulticastSubscription, getStaleChains, provideContext, useAllAddresses, useBalanceModules, useBalances, useBalancesHydrate, useBalancesStatus, useChain, useChainConnectors, useChaindata, useChains, useDbCache, useDbCacheBalancesSubscription, useDbCacheSubscription, useDbCacheTokenRatesSubscription, useEvmNetwork, useEvmNetworks, useMulticastSubscription, useToken, useTokenRate, useTokenRates, useTokens, useWithTestnets };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talismn/balances-react",
3
- "version": "0.0.0-pr640-20230321101310",
3
+ "version": "0.0.0-pr643-20230322031130",
4
4
  "author": "Talisman",
5
5
  "homepage": "https://talisman.xyz",
6
6
  "license": "UNLICENSED",
@@ -18,7 +18,7 @@
18
18
  "/dist"
19
19
  ],
20
20
  "engines": {
21
- "node": ">=18"
21
+ "node": ">=14"
22
22
  },
23
23
  "scripts": {
24
24
  "test": "jest",
@@ -26,12 +26,13 @@
26
26
  "clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
27
27
  },
28
28
  "dependencies": {
29
- "@talismn/balances": "^0.0.0-pr640-20230321101310",
30
- "@talismn/chain-connector": "^0.0.0-pr640-20230321101310",
31
- "@talismn/chain-connector-evm": "^0.0.0-pr640-20230321101310",
32
- "@talismn/chaindata-provider": "^0.0.0-pr640-20230321101310",
33
- "@talismn/chaindata-provider-extension": "^0.0.0-pr640-20230321101310",
34
- "@talismn/token-rates": "^0.0.0-pr640-20230321101310",
29
+ "@talismn/balances": "^0.0.0-pr643-20230322031130",
30
+ "@talismn/chain-connector": "^0.0.0-pr643-20230322031130",
31
+ "@talismn/chain-connector-evm": "^0.0.0-pr643-20230322031130",
32
+ "@talismn/chaindata-provider": "^0.0.0-pr643-20230322031130",
33
+ "@talismn/chaindata-provider-extension": "^0.0.0-pr643-20230322031130",
34
+ "@talismn/connection-meta": "^0.0.0-pr643-20230322031130",
35
+ "@talismn/token-rates": "^0.0.0-pr643-20230322031130",
35
36
  "anylogger": "^1.0.11",
36
37
  "blueimp-md5": "2.19.0",
37
38
  "dexie": "^3.2.3",