@talismn/balances-react 0.4.0 → 0.4.1

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,5 +1,28 @@
1
1
  # @talismn/balances-react
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - fb8ee962: feat: proxy dapp websocket requests to talisman wallet backend when available
8
+ - f7aca48b: eslint rules
9
+ - 01bf239b: feat: crowdloan and nom pool balances
10
+ - 48f0222e: fix: removed some explicit `any`s
11
+ - 01bf239b: fix: packages publishing with incorrect interdependency versions
12
+ - Updated dependencies [fb8ee962]
13
+ - Updated dependencies [c898da98]
14
+ - Updated dependencies [f7aca48b]
15
+ - Updated dependencies [01bf239b]
16
+ - Updated dependencies [48f0222e]
17
+ - Updated dependencies [01bf239b]
18
+ - @talismn/balances@0.4.1
19
+ - @talismn/chain-connector@0.4.4
20
+ - @talismn/chaindata-provider-extension@0.4.4
21
+ - @talismn/chain-connector-evm@0.4.4
22
+ - @talismn/chaindata-provider@0.4.4
23
+ - @talismn/connection-meta@0.0.3
24
+ - @talismn/token-rates@0.1.16
25
+
3
26
  ## 0.4.0
4
27
 
5
28
  ### Minor Changes
@@ -12,10 +12,10 @@ export * from "./useEvmNetworks";
12
12
  export * from "./useTokenRates";
13
13
  export * from "./useTokens";
14
14
  export * from "./useWithTestnets";
15
- import { BalanceModule, Hydrate } from "@talismn/balances";
15
+ import { AnyBalanceModule, Hydrate } from "@talismn/balances";
16
16
  import { ReactNode } from "react";
17
17
  export type BalancesProviderProps = {
18
- balanceModules: Array<(hydrate: Hydrate) => BalanceModule<any, any, any, any, any>>;
18
+ balanceModules: Array<(hydrate: Hydrate) => AnyBalanceModule>;
19
19
  onfinalityApiKey?: string;
20
20
  withTestnets?: boolean;
21
21
  children?: ReactNode;
@@ -1,8 +1,8 @@
1
1
  /// <reference types="react" />
2
- import { BalanceModule, Hydrate } from "@talismn/balances";
2
+ import { AnyBalanceModule, Hydrate } from "@talismn/balances";
3
3
  export type BalanceModulesProviderOptions = {
4
- balanceModules: Array<(hydrate: Hydrate) => BalanceModule<any, any, any, any, any>>;
4
+ balanceModules: Array<(hydrate: Hydrate) => AnyBalanceModule>;
5
5
  };
6
6
  export declare const BalanceModulesProvider: import("react").FC<BalanceModulesProviderOptions & {
7
7
  children?: import("react").ReactNode;
8
- }>, useBalanceModules: () => BalanceModule<any, any, any, any, any>[];
8
+ }>, useBalanceModules: () => AnyBalanceModule[];
@@ -11,9 +11,8 @@ export type BalancesStatus = {
11
11
  * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
12
12
  *
13
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
14
  * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
16
15
 
17
16
  */
18
- export declare const useBalancesStatus: (balances: Balances, isLoadingLocks?: boolean) => BalancesStatus;
17
+ export declare const useBalancesStatus: (balances: Balances) => BalancesStatus;
19
18
  export declare const getStaleChains: (balances: Balances) => string[];
@@ -121,21 +121,6 @@ const DEFAULT_VALUE = {
121
121
  };
122
122
  const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
123
123
  if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
124
-
125
- // BEGIN: temp hack to indicate that
126
- // - EVM GLMR is a mirror of substrate GLMR
127
- // - EVM MOVR is a mirror of substrate MOVR
128
- // - EVM DEV is a mirror of substrate DEV
129
- // - EVM ACA is a mirror of substrate ACA
130
- const mirrorTokenIds = {
131
- "1284-evm-native-glmr": "moonbeam-substrate-native-glmr",
132
- "1285-evm-native-movr": "moonriver-substrate-native-movr",
133
- "1287-evm-native-dev": "moonbase-alpha-testnet-substrate-native-dev",
134
- "787-evm-native-aca": "acala-substrate-native-aca"
135
- };
136
- Object.entries(mirrorTokenIds).filter(([mirrorToken]) => tokensMap[mirrorToken]).forEach(([mirrorToken, mirrorOf]) => tokensMap[mirrorToken].mirrorOf = mirrorOf);
137
- // END: temp hack
138
-
139
124
  const chainsWithTestnets = Object.values(chainsMap);
140
125
  const chainsWithoutTestnets = chainsWithTestnets.filter(filterNoTestnet);
141
126
  const chainsWithoutTestnetsMap = Object.fromEntries(chainsWithoutTestnets.map(network => [network.id, network]));
@@ -184,7 +169,7 @@ const useDbCacheProvider = () => {
184
169
  // debounce every 500ms to prevent hammering UI with updates
185
170
  reactUse.useDebounce(() => {
186
171
  setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
187
- }, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates$1]);
172
+ }, 500, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances]);
188
173
  const refInitialized = react.useRef(false);
189
174
 
190
175
  // force an update as soon as all datasources are fetched, so UI can display data ASAP
@@ -193,14 +178,14 @@ const useDbCacheProvider = () => {
193
178
  setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
194
179
  refInitialized.current = true;
195
180
  }
196
- }, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates$1]);
181
+ }, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances]);
197
182
  return dbData;
198
183
  };
199
184
  const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
200
185
 
201
186
  var packageJson = {
202
187
  name: "@talismn/balances-react",
203
- version: "0.4.0",
188
+ version: "0.4.1",
204
189
  author: "Talisman",
205
190
  homepage: "https://talisman.xyz",
206
191
  license: "UNLICENSED",
@@ -222,27 +207,27 @@ var packageJson = {
222
207
  },
223
208
  scripts: {
224
209
  test: "jest",
225
- lint: "eslint . --max-warnings 0",
210
+ lint: "eslint src --max-warnings 0",
226
211
  clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
227
212
  },
228
213
  dependencies: {
229
- "@talismn/balances": "workspace:^",
230
- "@talismn/chain-connector": "workspace:^",
231
- "@talismn/chain-connector-evm": "workspace:^",
232
- "@talismn/chaindata-provider": "workspace:^",
233
- "@talismn/chaindata-provider-extension": "workspace:^",
234
- "@talismn/connection-meta": "workspace:^",
235
- "@talismn/token-rates": "workspace:^",
214
+ "@talismn/balances": "workspace:*",
215
+ "@talismn/chain-connector": "workspace:*",
216
+ "@talismn/chain-connector-evm": "workspace:*",
217
+ "@talismn/chaindata-provider": "workspace:*",
218
+ "@talismn/chaindata-provider-extension": "workspace:*",
219
+ "@talismn/connection-meta": "workspace:*",
220
+ "@talismn/token-rates": "workspace:*",
236
221
  anylogger: "^1.0.11",
237
222
  "blueimp-md5": "2.19.0",
238
223
  dexie: "^3.2.3",
239
224
  "dexie-react-hooks": "^1.1.3",
240
225
  "react-use": "^17.4.0",
241
- rxjs: "^7.8.0"
226
+ rxjs: "^7.8.1"
242
227
  },
243
228
  devDependencies: {
244
- "@talismn/eslint-config": "workspace:^",
245
- "@talismn/tsconfig": "workspace:^",
229
+ "@talismn/eslint-config": "workspace:*",
230
+ "@talismn/tsconfig": "workspace:*",
246
231
  "@types/jest": "^27.5.1",
247
232
  "@types/react": "^18.0.17",
248
233
  eslint: "^8.4.0",
@@ -503,10 +488,25 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
503
488
  id
504
489
  }) => id);
505
490
  const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId, addresses]));
491
+ const subscriptionId = balances.createSubscriptionId();
492
+
493
+ // TODO: Create subscriptions in a service worker, where we can detect page closes
494
+ // and therefore reliably delete the subscriptionId when the user closes our dapp
495
+ //
496
+ // For more information, check out https://developer.chrome.com/blog/page-lifecycle-api/#faqs
497
+ // and scroll down to:
498
+ // - `What is the back/forward cache?`, and
499
+ // - `If I can't run asynchronous APIs in the frozen or terminated states, how can I save data to IndexedDB?
500
+ //
501
+ // For now, we'll just last-ditch remove the subscriptionId (it works surprisingly well!) in the beforeunload event
502
+ window.onbeforeunload = () => {
503
+ balances.deleteSubscriptionId();
504
+ };
506
505
  const updateDb = balances$1 => {
507
506
  const putBalances = Object.entries(balances$1.toJSON()).map(([id, balance]) => ({
508
507
  id,
509
- ...balance
508
+ ...balance,
509
+ status: balances.BalanceStatusLive(subscriptionId)
510
510
  }));
511
511
  balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.bulkPut(putBalances));
512
512
  };
@@ -525,7 +525,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
525
525
  const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances$1) => {
526
526
  // log errors
527
527
  if (error) {
528
- if (error?.type === "STALE_RPC_ERROR") return balances.db.balances.where({
528
+ if (error?.type === "STALE_RPC_ERROR" || error?.type === "WEBSOCKET_ALLOCATION_EXHAUSTED_ERROR") return balances.db.balances.where({
529
529
  source: balanceModule.type,
530
530
  chainId: error.chainId
531
531
  }).filter(balance => {
@@ -548,15 +548,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
548
548
  unsub.then(unsubscribe => {
549
549
  setTimeout(unsubscribe, 2_000);
550
550
  });
551
- balances.db.balances.where({
552
- source: balanceModule.type
553
- }).filter(balance => {
554
- if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
555
- if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
556
- return true;
557
- }).modify({
558
- status: "cache"
559
- });
551
+ balances.deleteSubscriptionId();
560
552
  };
561
553
  });
562
554
  const unsubscribeAll = () => {
@@ -645,7 +637,7 @@ function useBalances(addressesByToken) {
645
637
  balances: balances$1
646
638
  } = useDbCache();
647
639
  const hydrate = useBalancesHydrate();
648
- return react.useMemo(() => new balances.Balances(balances$1.filter(balance => {
640
+ return react.useMemo(() => new balances.Balances(balances.deriveStatuses([...balances.getValidSubscriptionIds()], balances$1.filter(balance => {
649
641
  // check that this balance is included in our queried balance modules
650
642
  if (!balanceModules.map(({
651
643
  type
@@ -662,7 +654,7 @@ function useBalances(addressesByToken) {
662
654
 
663
655
  // keep this balance
664
656
  return true;
665
- }),
657
+ })),
666
658
  // hydrate balance chains, evmNetworks, tokens and tokenRates
667
659
  hydrate), [balances$1, hydrate, balanceModules, addressesByToken]);
668
660
  }
@@ -671,11 +663,10 @@ function useBalances(addressesByToken) {
671
663
  * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
672
664
  *
673
665
  * @param balances The collection of balances to get the status from.
674
- * @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.
675
666
  * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
676
667
 
677
668
  */
678
- const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
669
+ const useBalancesStatus = balances => react.useMemo(() => {
679
670
  // stale
680
671
  const staleChains = getStaleChains(balances);
681
672
  if (staleChains.length > 0) return {
@@ -685,7 +676,7 @@ const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
685
676
 
686
677
  // fetching
687
678
  const hasCachedBalances = balances.each.some(b => b.status === "cache");
688
- if (hasCachedBalances || isLoadingLocks) return {
679
+ if (hasCachedBalances) return {
689
680
  status: "fetching"
690
681
  };
691
682
 
@@ -693,7 +684,7 @@ const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
693
684
  return {
694
685
  status: "live"
695
686
  };
696
- }, [balances, isLoadingLocks]);
687
+ }, [balances]);
697
688
  const getStaleChains = balances => [...new Set(balances.sorted.filter(b => b.status === "stale").map(b => b.chain?.name ?? b.chainId ?? "Unknown"))];
698
689
 
699
690
  const BalancesProvider = ({
@@ -121,21 +121,6 @@ const DEFAULT_VALUE = {
121
121
  };
122
122
  const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
123
123
  if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
124
-
125
- // BEGIN: temp hack to indicate that
126
- // - EVM GLMR is a mirror of substrate GLMR
127
- // - EVM MOVR is a mirror of substrate MOVR
128
- // - EVM DEV is a mirror of substrate DEV
129
- // - EVM ACA is a mirror of substrate ACA
130
- const mirrorTokenIds = {
131
- "1284-evm-native-glmr": "moonbeam-substrate-native-glmr",
132
- "1285-evm-native-movr": "moonriver-substrate-native-movr",
133
- "1287-evm-native-dev": "moonbase-alpha-testnet-substrate-native-dev",
134
- "787-evm-native-aca": "acala-substrate-native-aca"
135
- };
136
- Object.entries(mirrorTokenIds).filter(([mirrorToken]) => tokensMap[mirrorToken]).forEach(([mirrorToken, mirrorOf]) => tokensMap[mirrorToken].mirrorOf = mirrorOf);
137
- // END: temp hack
138
-
139
124
  const chainsWithTestnets = Object.values(chainsMap);
140
125
  const chainsWithoutTestnets = chainsWithTestnets.filter(filterNoTestnet);
141
126
  const chainsWithoutTestnetsMap = Object.fromEntries(chainsWithoutTestnets.map(network => [network.id, network]));
@@ -184,7 +169,7 @@ const useDbCacheProvider = () => {
184
169
  // debounce every 500ms to prevent hammering UI with updates
185
170
  reactUse.useDebounce(() => {
186
171
  setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
187
- }, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates$1]);
172
+ }, 500, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances]);
188
173
  const refInitialized = react.useRef(false);
189
174
 
190
175
  // force an update as soon as all datasources are fetched, so UI can display data ASAP
@@ -193,14 +178,14 @@ const useDbCacheProvider = () => {
193
178
  setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
194
179
  refInitialized.current = true;
195
180
  }
196
- }, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates$1]);
181
+ }, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances]);
197
182
  return dbData;
198
183
  };
199
184
  const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
200
185
 
201
186
  var packageJson = {
202
187
  name: "@talismn/balances-react",
203
- version: "0.4.0",
188
+ version: "0.4.1",
204
189
  author: "Talisman",
205
190
  homepage: "https://talisman.xyz",
206
191
  license: "UNLICENSED",
@@ -222,27 +207,27 @@ var packageJson = {
222
207
  },
223
208
  scripts: {
224
209
  test: "jest",
225
- lint: "eslint . --max-warnings 0",
210
+ lint: "eslint src --max-warnings 0",
226
211
  clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
227
212
  },
228
213
  dependencies: {
229
- "@talismn/balances": "workspace:^",
230
- "@talismn/chain-connector": "workspace:^",
231
- "@talismn/chain-connector-evm": "workspace:^",
232
- "@talismn/chaindata-provider": "workspace:^",
233
- "@talismn/chaindata-provider-extension": "workspace:^",
234
- "@talismn/connection-meta": "workspace:^",
235
- "@talismn/token-rates": "workspace:^",
214
+ "@talismn/balances": "workspace:*",
215
+ "@talismn/chain-connector": "workspace:*",
216
+ "@talismn/chain-connector-evm": "workspace:*",
217
+ "@talismn/chaindata-provider": "workspace:*",
218
+ "@talismn/chaindata-provider-extension": "workspace:*",
219
+ "@talismn/connection-meta": "workspace:*",
220
+ "@talismn/token-rates": "workspace:*",
236
221
  anylogger: "^1.0.11",
237
222
  "blueimp-md5": "2.19.0",
238
223
  dexie: "^3.2.3",
239
224
  "dexie-react-hooks": "^1.1.3",
240
225
  "react-use": "^17.4.0",
241
- rxjs: "^7.8.0"
226
+ rxjs: "^7.8.1"
242
227
  },
243
228
  devDependencies: {
244
- "@talismn/eslint-config": "workspace:^",
245
- "@talismn/tsconfig": "workspace:^",
229
+ "@talismn/eslint-config": "workspace:*",
230
+ "@talismn/tsconfig": "workspace:*",
246
231
  "@types/jest": "^27.5.1",
247
232
  "@types/react": "^18.0.17",
248
233
  eslint: "^8.4.0",
@@ -503,10 +488,25 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
503
488
  id
504
489
  }) => id);
505
490
  const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId, addresses]));
491
+ const subscriptionId = balances.createSubscriptionId();
492
+
493
+ // TODO: Create subscriptions in a service worker, where we can detect page closes
494
+ // and therefore reliably delete the subscriptionId when the user closes our dapp
495
+ //
496
+ // For more information, check out https://developer.chrome.com/blog/page-lifecycle-api/#faqs
497
+ // and scroll down to:
498
+ // - `What is the back/forward cache?`, and
499
+ // - `If I can't run asynchronous APIs in the frozen or terminated states, how can I save data to IndexedDB?
500
+ //
501
+ // For now, we'll just last-ditch remove the subscriptionId (it works surprisingly well!) in the beforeunload event
502
+ window.onbeforeunload = () => {
503
+ balances.deleteSubscriptionId();
504
+ };
506
505
  const updateDb = balances$1 => {
507
506
  const putBalances = Object.entries(balances$1.toJSON()).map(([id, balance]) => ({
508
507
  id,
509
- ...balance
508
+ ...balance,
509
+ status: balances.BalanceStatusLive(subscriptionId)
510
510
  }));
511
511
  balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.bulkPut(putBalances));
512
512
  };
@@ -525,7 +525,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
525
525
  const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances$1) => {
526
526
  // log errors
527
527
  if (error) {
528
- if (error?.type === "STALE_RPC_ERROR") return balances.db.balances.where({
528
+ if (error?.type === "STALE_RPC_ERROR" || error?.type === "WEBSOCKET_ALLOCATION_EXHAUSTED_ERROR") return balances.db.balances.where({
529
529
  source: balanceModule.type,
530
530
  chainId: error.chainId
531
531
  }).filter(balance => {
@@ -548,15 +548,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
548
548
  unsub.then(unsubscribe => {
549
549
  setTimeout(unsubscribe, 2_000);
550
550
  });
551
- balances.db.balances.where({
552
- source: balanceModule.type
553
- }).filter(balance => {
554
- if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
555
- if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
556
- return true;
557
- }).modify({
558
- status: "cache"
559
- });
551
+ balances.deleteSubscriptionId();
560
552
  };
561
553
  });
562
554
  const unsubscribeAll = () => {
@@ -645,7 +637,7 @@ function useBalances(addressesByToken) {
645
637
  balances: balances$1
646
638
  } = useDbCache();
647
639
  const hydrate = useBalancesHydrate();
648
- return react.useMemo(() => new balances.Balances(balances$1.filter(balance => {
640
+ return react.useMemo(() => new balances.Balances(balances.deriveStatuses([...balances.getValidSubscriptionIds()], balances$1.filter(balance => {
649
641
  // check that this balance is included in our queried balance modules
650
642
  if (!balanceModules.map(({
651
643
  type
@@ -662,7 +654,7 @@ function useBalances(addressesByToken) {
662
654
 
663
655
  // keep this balance
664
656
  return true;
665
- }),
657
+ })),
666
658
  // hydrate balance chains, evmNetworks, tokens and tokenRates
667
659
  hydrate), [balances$1, hydrate, balanceModules, addressesByToken]);
668
660
  }
@@ -671,11 +663,10 @@ function useBalances(addressesByToken) {
671
663
  * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
672
664
  *
673
665
  * @param balances The collection of balances to get the status from.
674
- * @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.
675
666
  * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
676
667
 
677
668
  */
678
- const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
669
+ const useBalancesStatus = balances => react.useMemo(() => {
679
670
  // stale
680
671
  const staleChains = getStaleChains(balances);
681
672
  if (staleChains.length > 0) return {
@@ -685,7 +676,7 @@ const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
685
676
 
686
677
  // fetching
687
678
  const hasCachedBalances = balances.each.some(b => b.status === "cache");
688
- if (hasCachedBalances || isLoadingLocks) return {
679
+ if (hasCachedBalances) return {
689
680
  status: "fetching"
690
681
  };
691
682
 
@@ -693,7 +684,7 @@ const useBalancesStatus = (balances, isLoadingLocks) => react.useMemo(() => {
693
684
  return {
694
685
  status: "live"
695
686
  };
696
- }, [balances, isLoadingLocks]);
687
+ }, [balances]);
697
688
  const getStaleChains = balances => [...new Set(balances.sorted.filter(b => b.status === "stale").map(b => b.chain?.name ?? b.chainId ?? "Unknown"))];
698
689
 
699
690
  const BalancesProvider = ({
@@ -4,7 +4,7 @@ import { ChainConnector } from '@talismn/chain-connector';
4
4
  import { ChainConnectorEvm } from '@talismn/chain-connector-evm';
5
5
  import { connectionMetaDb } from '@talismn/connection-meta';
6
6
  import { ChaindataProviderExtension } from '@talismn/chaindata-provider-extension';
7
- import { db as db$1, balances, Balances } from '@talismn/balances';
7
+ import { db as db$1, createSubscriptionId, deleteSubscriptionId, balances, BalanceStatusLive, Balances, deriveStatuses, getValidSubscriptionIds } from '@talismn/balances';
8
8
  import { db, fetchTokenRates } from '@talismn/token-rates';
9
9
  import { useLiveQuery } from 'dexie-react-hooks';
10
10
  import { useDebounce } from 'react-use';
@@ -112,21 +112,6 @@ const DEFAULT_VALUE = {
112
112
  };
113
113
  const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
114
114
  if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
115
-
116
- // BEGIN: temp hack to indicate that
117
- // - EVM GLMR is a mirror of substrate GLMR
118
- // - EVM MOVR is a mirror of substrate MOVR
119
- // - EVM DEV is a mirror of substrate DEV
120
- // - EVM ACA is a mirror of substrate ACA
121
- const mirrorTokenIds = {
122
- "1284-evm-native-glmr": "moonbeam-substrate-native-glmr",
123
- "1285-evm-native-movr": "moonriver-substrate-native-movr",
124
- "1287-evm-native-dev": "moonbase-alpha-testnet-substrate-native-dev",
125
- "787-evm-native-aca": "acala-substrate-native-aca"
126
- };
127
- Object.entries(mirrorTokenIds).filter(([mirrorToken]) => tokensMap[mirrorToken]).forEach(([mirrorToken, mirrorOf]) => tokensMap[mirrorToken].mirrorOf = mirrorOf);
128
- // END: temp hack
129
-
130
115
  const chainsWithTestnets = Object.values(chainsMap);
131
116
  const chainsWithoutTestnets = chainsWithTestnets.filter(filterNoTestnet);
132
117
  const chainsWithoutTestnetsMap = Object.fromEntries(chainsWithoutTestnets.map(network => [network.id, network]));
@@ -175,7 +160,7 @@ const useDbCacheProvider = () => {
175
160
  // debounce every 500ms to prevent hammering UI with updates
176
161
  useDebounce(() => {
177
162
  setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances));
178
- }, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates]);
163
+ }, 500, [chainList, evmNetworkList, tokenList, tokenRates, rawBalances]);
179
164
  const refInitialized = useRef(false);
180
165
 
181
166
  // force an update as soon as all datasources are fetched, so UI can display data ASAP
@@ -184,14 +169,14 @@ const useDbCacheProvider = () => {
184
169
  setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances));
185
170
  refInitialized.current = true;
186
171
  }
187
- }, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates]);
172
+ }, [chainList, evmNetworkList, tokenList, tokenRates, rawBalances]);
188
173
  return dbData;
189
174
  };
190
175
  const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
191
176
 
192
177
  var packageJson = {
193
178
  name: "@talismn/balances-react",
194
- version: "0.4.0",
179
+ version: "0.4.1",
195
180
  author: "Talisman",
196
181
  homepage: "https://talisman.xyz",
197
182
  license: "UNLICENSED",
@@ -213,27 +198,27 @@ var packageJson = {
213
198
  },
214
199
  scripts: {
215
200
  test: "jest",
216
- lint: "eslint . --max-warnings 0",
201
+ lint: "eslint src --max-warnings 0",
217
202
  clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
218
203
  },
219
204
  dependencies: {
220
- "@talismn/balances": "workspace:^",
221
- "@talismn/chain-connector": "workspace:^",
222
- "@talismn/chain-connector-evm": "workspace:^",
223
- "@talismn/chaindata-provider": "workspace:^",
224
- "@talismn/chaindata-provider-extension": "workspace:^",
225
- "@talismn/connection-meta": "workspace:^",
226
- "@talismn/token-rates": "workspace:^",
205
+ "@talismn/balances": "workspace:*",
206
+ "@talismn/chain-connector": "workspace:*",
207
+ "@talismn/chain-connector-evm": "workspace:*",
208
+ "@talismn/chaindata-provider": "workspace:*",
209
+ "@talismn/chaindata-provider-extension": "workspace:*",
210
+ "@talismn/connection-meta": "workspace:*",
211
+ "@talismn/token-rates": "workspace:*",
227
212
  anylogger: "^1.0.11",
228
213
  "blueimp-md5": "2.19.0",
229
214
  dexie: "^3.2.3",
230
215
  "dexie-react-hooks": "^1.1.3",
231
216
  "react-use": "^17.4.0",
232
- rxjs: "^7.8.0"
217
+ rxjs: "^7.8.1"
233
218
  },
234
219
  devDependencies: {
235
- "@talismn/eslint-config": "workspace:^",
236
- "@talismn/tsconfig": "workspace:^",
220
+ "@talismn/eslint-config": "workspace:*",
221
+ "@talismn/tsconfig": "workspace:*",
237
222
  "@types/jest": "^27.5.1",
238
223
  "@types/react": "^18.0.17",
239
224
  eslint: "^8.4.0",
@@ -494,10 +479,25 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
494
479
  id
495
480
  }) => id);
496
481
  const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId, addresses]));
482
+ const subscriptionId = createSubscriptionId();
483
+
484
+ // TODO: Create subscriptions in a service worker, where we can detect page closes
485
+ // and therefore reliably delete the subscriptionId when the user closes our dapp
486
+ //
487
+ // For more information, check out https://developer.chrome.com/blog/page-lifecycle-api/#faqs
488
+ // and scroll down to:
489
+ // - `What is the back/forward cache?`, and
490
+ // - `If I can't run asynchronous APIs in the frozen or terminated states, how can I save data to IndexedDB?
491
+ //
492
+ // For now, we'll just last-ditch remove the subscriptionId (it works surprisingly well!) in the beforeunload event
493
+ window.onbeforeunload = () => {
494
+ deleteSubscriptionId();
495
+ };
497
496
  const updateDb = balances => {
498
497
  const putBalances = Object.entries(balances.toJSON()).map(([id, balance]) => ({
499
498
  id,
500
- ...balance
499
+ ...balance,
500
+ status: BalanceStatusLive(subscriptionId)
501
501
  }));
502
502
  db$1.transaction("rw", db$1.balances, async () => await db$1.balances.bulkPut(putBalances));
503
503
  };
@@ -516,7 +516,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
516
516
  const unsub = balances(balanceModule, addressesByModuleToken, (error, balances) => {
517
517
  // log errors
518
518
  if (error) {
519
- if (error?.type === "STALE_RPC_ERROR") return db$1.balances.where({
519
+ if (error?.type === "STALE_RPC_ERROR" || error?.type === "WEBSOCKET_ALLOCATION_EXHAUSTED_ERROR") return db$1.balances.where({
520
520
  source: balanceModule.type,
521
521
  chainId: error.chainId
522
522
  }).filter(balance => {
@@ -539,15 +539,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
539
539
  unsub.then(unsubscribe => {
540
540
  setTimeout(unsubscribe, 2_000);
541
541
  });
542
- db$1.balances.where({
543
- source: balanceModule.type
544
- }).filter(balance => {
545
- if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
546
- if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
547
- return true;
548
- }).modify({
549
- status: "cache"
550
- });
542
+ deleteSubscriptionId();
551
543
  };
552
544
  });
553
545
  const unsubscribeAll = () => {
@@ -636,7 +628,7 @@ function useBalances(addressesByToken) {
636
628
  balances
637
629
  } = useDbCache();
638
630
  const hydrate = useBalancesHydrate();
639
- return useMemo(() => new Balances(balances.filter(balance => {
631
+ return useMemo(() => new Balances(deriveStatuses([...getValidSubscriptionIds()], balances.filter(balance => {
640
632
  // check that this balance is included in our queried balance modules
641
633
  if (!balanceModules.map(({
642
634
  type
@@ -653,7 +645,7 @@ function useBalances(addressesByToken) {
653
645
 
654
646
  // keep this balance
655
647
  return true;
656
- }),
648
+ })),
657
649
  // hydrate balance chains, evmNetworks, tokens and tokenRates
658
650
  hydrate), [balances, hydrate, balanceModules, addressesByToken]);
659
651
  }
@@ -662,11 +654,10 @@ function useBalances(addressesByToken) {
662
654
  * Given a collection of `Balances`, this hook returns a `BalancesStatus` summary for the collection.
663
655
  *
664
656
  * @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
657
  * @returns An instance of `BalancesStatus` which represents the status of the balances collection.
667
658
 
668
659
  */
669
- const useBalancesStatus = (balances, isLoadingLocks) => useMemo(() => {
660
+ const useBalancesStatus = balances => useMemo(() => {
670
661
  // stale
671
662
  const staleChains = getStaleChains(balances);
672
663
  if (staleChains.length > 0) return {
@@ -676,7 +667,7 @@ const useBalancesStatus = (balances, isLoadingLocks) => useMemo(() => {
676
667
 
677
668
  // fetching
678
669
  const hasCachedBalances = balances.each.some(b => b.status === "cache");
679
- if (hasCachedBalances || isLoadingLocks) return {
670
+ if (hasCachedBalances) return {
680
671
  status: "fetching"
681
672
  };
682
673
 
@@ -684,7 +675,7 @@ const useBalancesStatus = (balances, isLoadingLocks) => useMemo(() => {
684
675
  return {
685
676
  status: "live"
686
677
  };
687
- }, [balances, isLoadingLocks]);
678
+ }, [balances]);
688
679
  const getStaleChains = balances => [...new Set(balances.sorted.filter(b => b.status === "stale").map(b => b.chain?.name ?? b.chainId ?? "Unknown"))];
689
680
 
690
681
  const BalancesProvider = ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talismn/balances-react",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "author": "Talisman",
5
5
  "homepage": "https://talisman.xyz",
6
6
  "license": "UNLICENSED",
@@ -22,27 +22,27 @@
22
22
  },
23
23
  "scripts": {
24
24
  "test": "jest",
25
- "lint": "eslint . --max-warnings 0",
25
+ "lint": "eslint src --max-warnings 0",
26
26
  "clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
27
27
  },
28
28
  "dependencies": {
29
- "@talismn/balances": "^0.4.0",
30
- "@talismn/chain-connector": "^0.4.3",
31
- "@talismn/chain-connector-evm": "^0.4.3",
32
- "@talismn/chaindata-provider": "^0.4.3",
33
- "@talismn/chaindata-provider-extension": "^0.4.3",
34
- "@talismn/connection-meta": "^0.0.2",
35
- "@talismn/token-rates": "^0.1.15",
29
+ "@talismn/balances": "0.4.1",
30
+ "@talismn/chain-connector": "0.4.4",
31
+ "@talismn/chain-connector-evm": "0.4.4",
32
+ "@talismn/chaindata-provider": "0.4.4",
33
+ "@talismn/chaindata-provider-extension": "0.4.4",
34
+ "@talismn/connection-meta": "0.0.3",
35
+ "@talismn/token-rates": "0.1.16",
36
36
  "anylogger": "^1.0.11",
37
37
  "blueimp-md5": "2.19.0",
38
38
  "dexie": "^3.2.3",
39
39
  "dexie-react-hooks": "^1.1.3",
40
40
  "react-use": "^17.4.0",
41
- "rxjs": "^7.8.0"
41
+ "rxjs": "^7.8.1"
42
42
  },
43
43
  "devDependencies": {
44
- "@talismn/eslint-config": "^0.0.1",
45
- "@talismn/tsconfig": "^0.0.2",
44
+ "@talismn/eslint-config": "0.0.2",
45
+ "@talismn/tsconfig": "0.0.2",
46
46
  "@types/jest": "^27.5.1",
47
47
  "@types/react": "^18.0.17",
48
48
  "eslint": "^8.4.0",