@talismn/balances-react 0.0.0-pr640-20230321101310 → 0.0.0-pr640-20230322042757

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-pr640-20230322042757
4
4
 
5
5
  ### Minor Changes
6
6
 
@@ -8,18 +8,21 @@
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
18
  - 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
19
+ - @talismn/chain-connector@0.0.0-pr640-20230322042757
20
+ - @talismn/connection-meta@0.0.0-pr640-20230322042757
21
+ - @talismn/balances@0.0.0-pr640-20230322042757
22
+ - @talismn/token-rates@0.0.0-pr640-20230322042757
23
+ - @talismn/chaindata-provider-extension@0.0.0-pr640-20230322042757
24
+ - @talismn/chaindata-provider@0.0.0-pr640-20230322042757
25
+ - @talismn/chain-connector-evm@0.0.0-pr640-20230322042757
23
26
 
24
27
  ## 0.3.3
25
28
 
@@ -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, {
@@ -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-pr640-20230322042757",
203
204
  author: "Talisman",
204
205
  homepage: "https://talisman.xyz",
205
206
  license: "UNLICENSED",
@@ -230,11 +231,12 @@ 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",
236
238
  dexie: "^3.2.3",
237
- "dexie-react-hooks": "^1.1.1",
239
+ "dexie-react-hooks": "^1.1.3",
238
240
  "react-use": "^17.4.0",
239
241
  rxjs: "^7.8.0"
240
242
  },
@@ -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?.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,35 @@ 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 => b.chain?.name ?? b.chainId ?? "Unknown"))];
689
+
646
690
  const BalancesProvider = ({
647
691
  balanceModules,
648
692
  onfinalityApiKey,
@@ -674,11 +718,13 @@ exports.ChaindataProvider = ChaindataProvider;
674
718
  exports.DbCacheProvider = DbCacheProvider;
675
719
  exports.WithTestnetsProvider = WithTestnetsProvider;
676
720
  exports.createMulticastSubscription = createMulticastSubscription;
721
+ exports.getStaleChains = getStaleChains;
677
722
  exports.provideContext = provideContext;
678
723
  exports.useAllAddresses = useAllAddresses;
679
724
  exports.useBalanceModules = useBalanceModules;
680
725
  exports.useBalances = useBalances;
681
726
  exports.useBalancesHydrate = useBalancesHydrate;
727
+ exports.useBalancesStatus = useBalancesStatus;
682
728
  exports.useChain = useChain;
683
729
  exports.useChainConnectors = useChainConnectors;
684
730
  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, {
@@ -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-pr640-20230322042757",
203
204
  author: "Talisman",
204
205
  homepage: "https://talisman.xyz",
205
206
  license: "UNLICENSED",
@@ -230,11 +231,12 @@ 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",
236
238
  dexie: "^3.2.3",
237
- "dexie-react-hooks": "^1.1.1",
239
+ "dexie-react-hooks": "^1.1.3",
238
240
  "react-use": "^17.4.0",
239
241
  rxjs: "^7.8.0"
240
242
  },
@@ -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?.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,35 @@ 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 => b.chain?.name ?? b.chainId ?? "Unknown"))];
689
+
646
690
  const BalancesProvider = ({
647
691
  balanceModules,
648
692
  onfinalityApiKey,
@@ -674,11 +718,13 @@ exports.ChaindataProvider = ChaindataProvider;
674
718
  exports.DbCacheProvider = DbCacheProvider;
675
719
  exports.WithTestnetsProvider = WithTestnetsProvider;
676
720
  exports.createMulticastSubscription = createMulticastSubscription;
721
+ exports.getStaleChains = getStaleChains;
677
722
  exports.provideContext = provideContext;
678
723
  exports.useAllAddresses = useAllAddresses;
679
724
  exports.useBalanceModules = useBalanceModules;
680
725
  exports.useBalances = useBalances;
681
726
  exports.useBalancesHydrate = useBalancesHydrate;
727
+ exports.useBalancesStatus = useBalancesStatus;
682
728
  exports.useChain = useChain;
683
729
  exports.useChainConnectors = useChainConnectors;
684
730
  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, {
@@ -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-pr640-20230322042757",
194
195
  author: "Talisman",
195
196
  homepage: "https://talisman.xyz",
196
197
  license: "UNLICENSED",
@@ -221,11 +222,12 @@ 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",
227
229
  dexie: "^3.2.3",
228
- "dexie-react-hooks": "^1.1.1",
230
+ "dexie-react-hooks": "^1.1.3",
229
231
  "react-use": "^17.4.0",
230
232
  rxjs: "^7.8.0"
231
233
  },
@@ -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?.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,35 @@ 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 => b.chain?.name ?? b.chainId ?? "Unknown"))];
680
+
637
681
  const BalancesProvider = ({
638
682
  balanceModules,
639
683
  onfinalityApiKey,
@@ -657,4 +701,4 @@ const BalancesProvider = ({
657
701
  })
658
702
  });
659
703
 
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 };
704
+ 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-pr640-20230322042757",
4
4
  "author": "Talisman",
5
5
  "homepage": "https://talisman.xyz",
6
6
  "license": "UNLICENSED",
@@ -26,16 +26,17 @@
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-pr640-20230322042757",
30
+ "@talismn/chain-connector": "^0.0.0-pr640-20230322042757",
31
+ "@talismn/chain-connector-evm": "^0.0.0-pr640-20230322042757",
32
+ "@talismn/chaindata-provider": "^0.0.0-pr640-20230322042757",
33
+ "@talismn/chaindata-provider-extension": "^0.0.0-pr640-20230322042757",
34
+ "@talismn/connection-meta": "^0.0.0-pr640-20230322042757",
35
+ "@talismn/token-rates": "^0.0.0-pr640-20230322042757",
35
36
  "anylogger": "^1.0.11",
36
37
  "blueimp-md5": "2.19.0",
37
38
  "dexie": "^3.2.3",
38
- "dexie-react-hooks": "^1.1.1",
39
+ "dexie-react-hooks": "^1.1.3",
39
40
  "react-use": "^17.4.0",
40
41
  "rxjs": "^7.8.0"
41
42
  },