@talismn/balances-react 0.2.3 → 0.3.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.
@@ -0,0 +1,353 @@
1
+ import { Balances, db, balances } from '@talismn/balances';
2
+ import { ChainConnector } from '@talismn/chain-connector';
3
+ import { ChainConnectorEvm } from '@talismn/chain-connector-evm';
4
+ import { useLiveQuery } from 'dexie-react-hooks';
5
+ import { useState, useEffect, useRef } from 'react';
6
+ import { useDebounce } from 'react-use';
7
+ import anylogger from 'anylogger';
8
+ import { ChaindataProviderExtension } from '@talismn/chaindata-provider-extension';
9
+ import { fetchTokenRates } from '@talismn/token-rates';
10
+
11
+ var packageJson = {
12
+ name: "@talismn/balances-react",
13
+ version: "0.3.1",
14
+ author: "Talisman",
15
+ homepage: "https://talisman.xyz",
16
+ license: "UNLICENSED",
17
+ publishConfig: {
18
+ access: "public"
19
+ },
20
+ repository: {
21
+ directory: "packages/balances-react",
22
+ type: "git",
23
+ url: "https://github.com/talismansociety/talisman.git"
24
+ },
25
+ main: "dist/talismn-balances-react.cjs.js",
26
+ module: "dist/talismn-balances-react.esm.js",
27
+ files: [
28
+ "/dist"
29
+ ],
30
+ engines: {
31
+ node: ">=14"
32
+ },
33
+ scripts: {
34
+ test: "jest",
35
+ lint: "eslint . --max-warnings 0",
36
+ clean: "rm -rf dist && rm -rf .turbo rm -rf node_modules"
37
+ },
38
+ dependencies: {
39
+ "@talismn/balances": "workspace:^",
40
+ "@talismn/chain-connector": "workspace:^",
41
+ "@talismn/chain-connector-evm": "workspace:^",
42
+ "@talismn/chaindata-provider": "workspace:^",
43
+ "@talismn/chaindata-provider-extension": "workspace:^",
44
+ "@talismn/token-rates": "workspace:^",
45
+ anylogger: "^1.0.11",
46
+ dexie: "^3.2.2",
47
+ "dexie-react-hooks": "^1.1.1",
48
+ "react-use": "^17.4.0"
49
+ },
50
+ devDependencies: {
51
+ "@talismn/eslint-config": "workspace:^",
52
+ "@talismn/tsconfig": "workspace:^",
53
+ "@types/jest": "^27.5.1",
54
+ "@types/react": "^18.0.17",
55
+ eslint: "^8.4.0",
56
+ jest: "^28.1.0",
57
+ react: "^18.2.0",
58
+ "ts-jest": "^28.0.2",
59
+ typescript: "^4.6.4"
60
+ },
61
+ peerDependencies: {
62
+ react: "*",
63
+ "react-dom": "*"
64
+ },
65
+ eslintConfig: {
66
+ root: true,
67
+ "extends": [
68
+ "@talismn/eslint-config/react"
69
+ ]
70
+ }
71
+ };
72
+
73
+ var log = anylogger(packageJson.name);
74
+
75
+ // TODO: Allow user to call useChaindata from multiple places
76
+
77
+ function useChaindata() {
78
+ const [chaindataProvider, setChaindataProvider] = useState(null);
79
+
80
+ // this number is incremented each time the chaindataProvider has fetched new data
81
+ const [generation, setGeneration] = useState(0);
82
+ useEffect(() => {
83
+ const chaindataProvider = new ChaindataProviderExtension();
84
+ let shouldHydrate = true;
85
+ const timer = 300_000; // 300_000ms = 300s = 5 minutes
86
+ const hydrate = async () => {
87
+ if (!shouldHydrate) return;
88
+ try {
89
+ const updated = await chaindataProvider.hydrate();
90
+ if (updated) setGeneration(generation => (generation + 1) % Number.MAX_SAFE_INTEGER);
91
+ setTimeout(hydrate, timer);
92
+ } catch (error) {
93
+ const retryTimeout = 5_000; // 5_000ms = 5 seconds
94
+ log.error(`Failed to fetch chaindata, retrying in ${Math.round(retryTimeout / 1000)} seconds`, error);
95
+ setTimeout(hydrate, retryTimeout);
96
+ }
97
+ };
98
+ setChaindataProvider(chaindataProvider);
99
+ hydrate();
100
+ return () => {
101
+ shouldHydrate = false;
102
+ };
103
+ }, []);
104
+ if (chaindataProvider) chaindataProvider.generation = generation;
105
+ return chaindataProvider;
106
+ }
107
+ function useChains(chaindata) {
108
+ const [chains, setChains] = useState();
109
+ useEffect(() => {
110
+ if (!chaindata) return;
111
+ const thisGeneration = chaindata.generation;
112
+ chaindata.chains().then(chains => {
113
+ if (thisGeneration !== chaindata.generation) return;
114
+ setChains(chains);
115
+ });
116
+ }, [chaindata?.generation]);
117
+ return chains || {};
118
+ }
119
+ function useChain(chaindata, chainId) {
120
+ const [chain, setChain] = useState();
121
+ useEffect(() => {
122
+ if (chaindata === null) return;
123
+ if (!chainId) return;
124
+ chaindata.getChain(chainId).then(setChain);
125
+ }, [chaindata?.generation]);
126
+ return chain;
127
+ }
128
+ function useEvmNetworks(chaindata) {
129
+ const [evmNetworks, setEvmNetworks] = useState();
130
+ useEffect(() => {
131
+ if (!chaindata) return;
132
+ const thisGeneration = chaindata.generation;
133
+ chaindata.evmNetworks().then(evmNetworks => {
134
+ if (thisGeneration !== chaindata.generation) return;
135
+ setEvmNetworks(evmNetworks);
136
+ });
137
+ }, [chaindata?.generation]);
138
+ return evmNetworks || {};
139
+ }
140
+ function useEvmNetwork(chaindata, evmNetworkId) {
141
+ const [evmNetwork, setEvmNetwork] = useState();
142
+ useEffect(() => {
143
+ if (chaindata === null) return;
144
+ if (!evmNetworkId) return;
145
+ chaindata.getEvmNetwork(evmNetworkId).then(setEvmNetwork);
146
+ }, [chaindata?.generation]);
147
+ return evmNetwork;
148
+ }
149
+ function useTokens(chaindata) {
150
+ const [tokens, setTokens] = useState();
151
+ useEffect(() => {
152
+ if (!chaindata) return;
153
+ const thisGeneration = chaindata.generation;
154
+ chaindata.tokens().then(tokens => {
155
+ if (thisGeneration !== chaindata.generation) return;
156
+ setTokens(tokens);
157
+ });
158
+ }, [chaindata?.generation]);
159
+ return tokens || {};
160
+ }
161
+ function useToken(chaindata, tokenId) {
162
+ const [token, setToken] = useState();
163
+ useEffect(() => {
164
+ if (chaindata === null) return;
165
+ if (!tokenId) return;
166
+ chaindata.getToken(tokenId).then(setToken);
167
+ }, [chaindata?.generation]);
168
+ return token;
169
+ }
170
+
171
+ function useTokenRates(tokens) {
172
+ const generation = useRef(0);
173
+ const [tokenRates, setTokenRates] = useState();
174
+ useEffect(() => {
175
+ if (!tokens) return;
176
+ if (Object.keys(tokens).length < 1) return;
177
+
178
+ // when we make a new request, we want to ignore any old requests which haven't yet completed
179
+ // otherwise we risk replacing the most recent data with older data
180
+ generation.current = (generation.current + 1) % Number.MAX_SAFE_INTEGER;
181
+ const thisGeneration = generation.current;
182
+ fetchTokenRates(tokens).then(tokenRates => {
183
+ if (thisGeneration !== generation.current) return;
184
+ setTokenRates(tokenRates);
185
+ });
186
+ }, [tokens]);
187
+ return tokenRates || {};
188
+ }
189
+
190
+ // TODO: Add the equivalent functionalty of `useDbCache` directly to this library.
191
+ //
192
+ // How it will work:
193
+ //
194
+ // useChains/useEvmNetworks/useTokens/useTokenRates will all make use of a
195
+ // useCachedDb hook, which internally subscribes to all of the db tables
196
+ // for everything, and then filters the subscribed data based on what params
197
+ // the caller of useChains/useTokens/etc has provided.
198
+ function useBalances(
199
+ // TODO: Make this array of BalanceModules more type-safe
200
+ balanceModules, chaindataProvider, addressesByToken) {
201
+ useBalancesSubscriptions(balanceModules, chaindataProvider, addressesByToken);
202
+ const chains = useChains(chaindataProvider);
203
+ const evmNetworks = useEvmNetworks(chaindataProvider);
204
+ const tokens = useTokens(chaindataProvider);
205
+ const tokenRates = useTokenRates(tokens);
206
+ const balances = useLiveQuery(async () => new Balances(await db.balances.filter(balance => {
207
+ // check that this balance is included in our queried balance modules
208
+ if (!balanceModules.map(({
209
+ type
210
+ }) => type).includes(balance.source)) return false;
211
+
212
+ // check that our query includes some tokens and addresses
213
+ if (!addressesByToken) return false;
214
+
215
+ // check that this balance is included in our queried tokens
216
+ if (!Object.keys(addressesByToken).includes(balance.tokenId)) return false;
217
+
218
+ // check that this balance is included in our queried addresses for this token
219
+ if (!addressesByToken[balance.tokenId].includes(balance.address)) return false;
220
+
221
+ // keep this balance
222
+ return true;
223
+ }).toArray(),
224
+ // hydrate balance chains, evmNetworks, tokens and tokenRates
225
+ {
226
+ chains,
227
+ evmNetworks,
228
+ tokens,
229
+ tokenRates
230
+ }), [balanceModules, addressesByToken, chains, evmNetworks, tokens, tokenRates]);
231
+
232
+ // debounce every 100ms to prevent hammering UI with updates
233
+ const [debouncedBalances, setDebouncedBalances] = useState(balances);
234
+ useDebounce(() => balances && setDebouncedBalances(balances), 100, [balances]);
235
+ return debouncedBalances;
236
+ }
237
+
238
+ // TODO: Turn into react context
239
+ const subscriptions = {};
240
+
241
+ // This hook is responsible for allowing us to call useBalances
242
+ // from multiple components, without setting up unnecessary
243
+ // balance subscriptions
244
+ function useBalancesSubscriptions(
245
+ // TODO: Make this array of BalanceModules more type-safe
246
+ balanceModules, chaindataProvider, addressesByToken) {
247
+ // const subscriptions = useRef<
248
+ // Record<string, { unsub: Promise<() => void>; refcount: number; generation: number }>
249
+ // >({})
250
+
251
+ const addSubscription = (key, balanceModule, chainConnectors, chaindataProvider, addressesByToken) => {
252
+ // create subscription if it doesn't already exist
253
+ if (!subscriptions[key] || subscriptions[key].refcount === 0) {
254
+ const generation = ((subscriptions[key]?.generation || 0) + 1) % Number.MAX_SAFE_INTEGER;
255
+ const unsub = balances(balanceModule, chainConnectors, chaindataProvider, addressesByToken, (error, balances) => {
256
+ if (error) return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
257
+ if (!balances) return;
258
+
259
+ // ignore balances from old subscriptions which are still in the process of unsubscribing
260
+ if (subscriptions[key].generation !== generation) return;
261
+ const putBalances = Object.entries(balances.toJSON()).map(([id, balance]) => ({
262
+ id,
263
+ ...balance
264
+ }));
265
+ db.transaction("rw", db.balances, async () => await db.balances.bulkPut(putBalances));
266
+ });
267
+ subscriptions[key] = {
268
+ unsub,
269
+ refcount: 0,
270
+ generation
271
+ };
272
+ }
273
+
274
+ // bump up the refcount by 1
275
+ subscriptions[key].refcount += 1;
276
+ };
277
+ const removeSubscription = (key, balanceModule, addressesByToken) => {
278
+ // ignore dead subscriptions
279
+ if (!subscriptions[key] || subscriptions[key].refcount === 0) return;
280
+
281
+ // drop the refcount by one
282
+ subscriptions[key].refcount -= 1;
283
+
284
+ // unsubscribe if refcount is now 0 (nobody wants this subcription anymore)
285
+ if (subscriptions[key].refcount < 1) {
286
+ // remove subscription
287
+ subscriptions[key].unsub.then(unsub => unsub());
288
+ delete subscriptions[key];
289
+
290
+ // set this subscription's balances in the store to status: cache
291
+ db.transaction("rw", db.balances, async () => await db.balances.filter(balance => {
292
+ if (balance.source !== balanceModule.type) return false;
293
+ if (!Object.keys(addressesByToken).includes(balance.tokenId)) return false;
294
+ if (!addressesByToken[balance.tokenId].includes(balance.address)) return false;
295
+ return true;
296
+ }).modify({
297
+ status: "cache"
298
+ }));
299
+ }
300
+ };
301
+ const chainConnector = useChainConnector(chaindataProvider);
302
+ const chainConnectorEvm = useChainConnectorEvm(chaindataProvider);
303
+ const tokens = useTokens(chaindataProvider);
304
+ useEffect(() => {
305
+ if (chainConnector === null) return;
306
+ if (chainConnectorEvm === null) return;
307
+ if (chaindataProvider === null) return;
308
+ if (addressesByToken === null) return;
309
+ const unsubs = balanceModules.map(balanceModule => {
310
+ const subscriptionKey = `${balanceModule.type}-${JSON.stringify(addressesByToken)}`;
311
+
312
+ // filter out tokens to only include those which this module knows how to fetch balances for
313
+ const moduleTokenIds = Object.values(tokens).filter(({
314
+ type
315
+ }) => type === balanceModule.type).map(({
316
+ id
317
+ }) => id);
318
+ const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
319
+
320
+ // add balance subscription for this module
321
+ addSubscription(subscriptionKey, balanceModule, {
322
+ substrate: chainConnector,
323
+ evm: chainConnectorEvm
324
+ }, chaindataProvider, addressesByModuleToken);
325
+
326
+ // return an unsub method, to be called when this effect unmounts
327
+ return () => removeSubscription(subscriptionKey, balanceModule, addressesByToken);
328
+ });
329
+ const unsubAll = () => unsubs.forEach(unsub => unsub());
330
+ return unsubAll;
331
+ }, [addressesByToken, chainConnector, chainConnectorEvm, chaindataProvider, tokens]);
332
+ }
333
+
334
+ // TODO: Allow advanced users of this library to provide their own chain connector
335
+ function useChainConnector(chaindataProvider) {
336
+ const [chainConnector, setChainConnector] = useState(null);
337
+ useEffect(() => {
338
+ if (chaindataProvider === null) return;
339
+ setChainConnector(new ChainConnector(chaindataProvider));
340
+ }, [chaindataProvider]);
341
+ return chainConnector;
342
+ }
343
+ // TODO: Allow advanced users of this library to provide their own chain connector
344
+ function useChainConnectorEvm(chaindataProvider) {
345
+ const [chainConnectorEvm, setChainConnectorEvm] = useState(null);
346
+ useEffect(() => {
347
+ if (chaindataProvider === null) return;
348
+ setChainConnectorEvm(new ChainConnectorEvm(chaindataProvider));
349
+ }, [chaindataProvider]);
350
+ return chainConnectorEvm;
351
+ }
352
+
353
+ export { useBalances, useChain, useChaindata, useChains, useEvmNetwork, useEvmNetworks, useToken, useTokenRates, useTokens };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talismn/balances-react",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "author": "Talisman",
5
5
  "homepage": "https://talisman.xyz",
6
6
  "license": "UNLICENSED",
@@ -12,8 +12,8 @@
12
12
  "type": "git",
13
13
  "url": "https://github.com/talismansociety/talisman.git"
14
14
  },
15
- "main": "dist/index.js",
16
- "types": "dist/index.d.ts",
15
+ "main": "dist/talismn-balances-react.cjs.js",
16
+ "module": "dist/talismn-balances-react.esm.js",
17
17
  "files": [
18
18
  "/dist"
19
19
  ],
@@ -21,29 +21,25 @@
21
21
  "node": ">=14"
22
22
  },
23
23
  "scripts": {
24
- "dev": "tsc --watch --declarationMap",
25
- "build": "tsc --declarationMap",
26
- "build:packages:prod": "rm -rf dist && tsc",
27
- "prepack": "yarn build:packages:prod",
28
24
  "test": "jest",
29
25
  "lint": "eslint . --max-warnings 0",
30
26
  "clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
31
27
  },
32
28
  "dependencies": {
33
- "@talismn/balances": "^0.2.3",
34
- "@talismn/chain-connector": "^0.2.0",
35
- "@talismn/chain-connector-evm": "^0.3.0",
36
- "@talismn/chaindata-provider": "^0.2.0",
37
- "@talismn/chaindata-provider-extension": "^0.2.0",
38
- "@talismn/token-rates": "^0.1.11",
29
+ "@talismn/balances": "^0.3.1",
30
+ "@talismn/chain-connector": "^0.4.1",
31
+ "@talismn/chain-connector-evm": "^0.4.1",
32
+ "@talismn/chaindata-provider": "^0.4.1",
33
+ "@talismn/chaindata-provider-extension": "^0.4.1",
34
+ "@talismn/token-rates": "^0.1.13",
39
35
  "anylogger": "^1.0.11",
40
36
  "dexie": "^3.2.2",
41
37
  "dexie-react-hooks": "^1.1.1",
42
38
  "react-use": "^17.4.0"
43
39
  },
44
40
  "devDependencies": {
45
- "@talismn/eslint-config": "^0.0.0",
46
- "@talismn/tsconfig": "^0.0.1",
41
+ "@talismn/eslint-config": "^0.0.1",
42
+ "@talismn/tsconfig": "^0.0.2",
47
43
  "@types/jest": "^27.5.1",
48
44
  "@types/react": "^18.0.17",
49
45
  "eslint": "^8.4.0",
@@ -59,7 +55,7 @@
59
55
  "eslintConfig": {
60
56
  "root": true,
61
57
  "extends": [
62
- "@talismn/eslint-config"
58
+ "@talismn/eslint-config/react"
63
59
  ]
64
60
  }
65
61
  }
@@ -1,3 +0,0 @@
1
- export * from "./useBalances";
2
- export * from "./useChaindata";
3
- export * from "./useTokenRates";
@@ -1,158 +0,0 @@
1
- import { Balances, balances as balancesFn, } from "@talismn/balances";
2
- import { db } from "@talismn/balances";
3
- import { ChainConnector } from "@talismn/chain-connector";
4
- import { ChainConnectorEvm } from "@talismn/chain-connector-evm";
5
- import { useLiveQuery } from "dexie-react-hooks";
6
- import { useEffect, useState } from "react";
7
- import { useDebounce } from "react-use";
8
- import log from "../log";
9
- import { useChains, useEvmNetworks, useTokens } from "./useChaindata";
10
- import { useTokenRates } from "./useTokenRates";
11
- // TODO: Add the equivalent functionalty of `useDbCache` directly to this library.
12
- //
13
- // How it will work:
14
- //
15
- // useChains/useEvmNetworks/useTokens/useTokenRates will all make use of a
16
- // useCachedDb hook, which internally subscribes to all of the db tables
17
- // for everything, and then filters the subscribed data based on what params
18
- // the caller of useChains/useTokens/etc has provided.
19
- export function useBalances(
20
- // TODO: Make this array of BalanceModules more type-safe
21
- balanceModules, chaindataProvider, addressesByToken) {
22
- useBalancesSubscriptions(balanceModules, chaindataProvider, addressesByToken);
23
- const chains = useChains(chaindataProvider);
24
- const evmNetworks = useEvmNetworks(chaindataProvider);
25
- const tokens = useTokens(chaindataProvider);
26
- const tokenRates = useTokenRates(tokens);
27
- const balances = useLiveQuery(async () => new Balances(await db.balances
28
- .filter((balance) => {
29
- // check that this balance is included in our queried balance modules
30
- if (!balanceModules.map(({ type }) => type).includes(balance.source))
31
- return false;
32
- // check that our query includes some tokens and addresses
33
- if (!addressesByToken)
34
- return false;
35
- // check that this balance is included in our queried tokens
36
- if (!Object.keys(addressesByToken).includes(balance.tokenId))
37
- return false;
38
- // check that this balance is included in our queried addresses for this token
39
- if (!addressesByToken[balance.tokenId].includes(balance.address))
40
- return false;
41
- // keep this balance
42
- return true;
43
- })
44
- .toArray(),
45
- // hydrate balance chains, evmNetworks, tokens and tokenRates
46
- { chains, evmNetworks, tokens, tokenRates }), [balanceModules, addressesByToken, chains, evmNetworks, tokens, tokenRates]);
47
- // debounce every 100ms to prevent hammering UI with updates
48
- const [debouncedBalances, setDebouncedBalances] = useState(balances);
49
- useDebounce(() => balances && setDebouncedBalances(balances), 100, [balances]);
50
- return debouncedBalances;
51
- }
52
- // TODO: Turn into react context
53
- const subscriptions = {};
54
- // This hook is responsible for allowing us to call useBalances
55
- // from multiple components, without setting up unnecessary
56
- // balance subscriptions
57
- function useBalancesSubscriptions(
58
- // TODO: Make this array of BalanceModules more type-safe
59
- balanceModules, chaindataProvider, addressesByToken) {
60
- // const subscriptions = useRef<
61
- // Record<string, { unsub: Promise<() => void>; refcount: number; generation: number }>
62
- // >({})
63
- const addSubscription = (key, balanceModule, chainConnectors, chaindataProvider, addressesByToken) => {
64
- // create subscription if it doesn't already exist
65
- if (!subscriptions[key] || subscriptions[key].refcount === 0) {
66
- const generation = ((subscriptions[key]?.generation || 0) + 1) % Number.MAX_SAFE_INTEGER;
67
- const unsub = balancesFn(balanceModule, chainConnectors, chaindataProvider, addressesByToken, (error, balances) => {
68
- if (error)
69
- return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
70
- if (!balances)
71
- return;
72
- // ignore balances from old subscriptions which are still in the process of unsubscribing
73
- if (subscriptions[key].generation !== generation)
74
- return;
75
- const putBalances = Object.entries(balances.toJSON()).map(([id, balance]) => ({
76
- id,
77
- ...balance,
78
- }));
79
- db.transaction("rw", db.balances, async () => await db.balances.bulkPut(putBalances));
80
- });
81
- subscriptions[key] = { unsub, refcount: 0, generation };
82
- }
83
- // bump up the refcount by 1
84
- subscriptions[key].refcount += 1;
85
- };
86
- const removeSubscription = (key, balanceModule, addressesByToken) => {
87
- // ignore dead subscriptions
88
- if (!subscriptions[key] || subscriptions[key].refcount === 0)
89
- return;
90
- // drop the refcount by one
91
- subscriptions[key].refcount -= 1;
92
- // unsubscribe if refcount is now 0 (nobody wants this subcription anymore)
93
- if (subscriptions[key].refcount < 1) {
94
- // remove subscription
95
- subscriptions[key].unsub.then((unsub) => unsub());
96
- delete subscriptions[key];
97
- // set this subscription's balances in the store to status: cache
98
- db.transaction("rw", db.balances, async () => await db.balances
99
- .filter((balance) => {
100
- if (balance.source !== balanceModule.type)
101
- return false;
102
- if (!Object.keys(addressesByToken).includes(balance.tokenId))
103
- return false;
104
- if (!addressesByToken[balance.tokenId].includes(balance.address))
105
- return false;
106
- return true;
107
- })
108
- .modify({ status: "cache" }));
109
- }
110
- };
111
- const chainConnector = useChainConnector(chaindataProvider);
112
- const chainConnectorEvm = useChainConnectorEvm(chaindataProvider);
113
- const tokens = useTokens(chaindataProvider);
114
- useEffect(() => {
115
- if (chainConnector === null)
116
- return;
117
- if (chainConnectorEvm === null)
118
- return;
119
- if (chaindataProvider === null)
120
- return;
121
- if (addressesByToken === null)
122
- return;
123
- const unsubs = balanceModules.map((balanceModule) => {
124
- const subscriptionKey = `${balanceModule.type}-${JSON.stringify(addressesByToken)}`;
125
- // filter out tokens to only include those which this module knows how to fetch balances for
126
- const moduleTokenIds = Object.values(tokens)
127
- .filter(({ type }) => type === balanceModule.type)
128
- .map(({ id }) => id);
129
- const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
130
- // add balance subscription for this module
131
- addSubscription(subscriptionKey, balanceModule, { substrate: chainConnector, evm: chainConnectorEvm }, chaindataProvider, addressesByModuleToken);
132
- // return an unsub method, to be called when this effect unmounts
133
- return () => removeSubscription(subscriptionKey, balanceModule, addressesByToken);
134
- });
135
- const unsubAll = () => unsubs.forEach((unsub) => unsub());
136
- return unsubAll;
137
- }, [addressesByToken, chainConnector, chainConnectorEvm, chaindataProvider, tokens]);
138
- }
139
- // TODO: Allow advanced users of this library to provide their own chain connector
140
- function useChainConnector(chaindataProvider) {
141
- const [chainConnector, setChainConnector] = useState(null);
142
- useEffect(() => {
143
- if (chaindataProvider === null)
144
- return;
145
- setChainConnector(new ChainConnector(chaindataProvider));
146
- }, [chaindataProvider]);
147
- return chainConnector;
148
- }
149
- // TODO: Allow advanced users of this library to provide their own chain connector
150
- function useChainConnectorEvm(chaindataProvider) {
151
- const [chainConnectorEvm, setChainConnectorEvm] = useState(null);
152
- useEffect(() => {
153
- if (chaindataProvider === null)
154
- return;
155
- setChainConnectorEvm(new ChainConnectorEvm(chaindataProvider));
156
- }, [chaindataProvider]);
157
- return chainConnectorEvm;
158
- }