@talismn/balances-react 0.0.0-pr595-20230306020834 → 0.0.0-pr596-20230306035406
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 +11 -8
- package/dist/declarations/src/hooks/index.d.ts +19 -0
- package/dist/declarations/src/hooks/useAllAddresses.d.ts +4 -0
- package/dist/declarations/src/hooks/useBalanceModules.d.ts +8 -0
- package/dist/declarations/src/hooks/useBalances.d.ts +3 -6
- package/dist/declarations/src/hooks/useBalancesHydrate.d.ts +2 -0
- package/dist/declarations/src/hooks/useChainConnectors.d.ts +12 -0
- package/dist/declarations/src/hooks/useChaindata.d.ts +6 -23
- package/dist/declarations/src/hooks/useChains.d.ts +3 -0
- package/dist/declarations/src/hooks/useDbCache.d.ts +24 -0
- package/dist/declarations/src/hooks/useDbCacheSubscription.d.ts +13 -0
- package/dist/declarations/src/hooks/useEvmNetworks.d.ts +3 -0
- package/dist/declarations/src/hooks/useTokenRates.d.ts +3 -3
- package/dist/declarations/src/hooks/useTokens.d.ts +3 -0
- package/dist/declarations/src/hooks/useWithTestnets.d.ts +8 -0
- package/dist/declarations/src/index.d.ts +1 -0
- package/dist/declarations/src/util/index.d.ts +2 -0
- package/dist/declarations/src/util/provideContext.d.ts +9 -0
- package/dist/declarations/src/util/useMulticastSubscription.d.ts +16 -0
- package/dist/declarations/src/util/useSharedSubscription.d.ts +9 -0
- package/dist/talismn-balances-react.cjs.dev.js +568 -252
- package/dist/talismn-balances-react.cjs.prod.js +568 -252
- package/dist/talismn-balances-react.esm.js +550 -255
- package/package.json +10 -8
|
@@ -2,23 +2,171 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
7
|
var balances = require('@talismn/balances');
|
|
6
|
-
var
|
|
7
|
-
var chainConnectorEvm = require('@talismn/chain-connector-evm');
|
|
8
|
+
var tokenRates = require('@talismn/token-rates');
|
|
8
9
|
var dexieReactHooks = require('dexie-react-hooks');
|
|
9
|
-
var react = require('react');
|
|
10
10
|
var reactUse = require('react-use');
|
|
11
|
-
var anylogger = require('anylogger');
|
|
12
11
|
var chaindataProviderExtension = require('@talismn/chaindata-provider-extension');
|
|
13
|
-
var
|
|
12
|
+
var md5 = require('blueimp-md5');
|
|
13
|
+
var anylogger = require('anylogger');
|
|
14
|
+
var rxjs = require('rxjs');
|
|
15
|
+
var chainConnector = require('@talismn/chain-connector');
|
|
16
|
+
var chainConnectorEvm = require('@talismn/chain-connector-evm');
|
|
14
17
|
|
|
15
18
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
16
19
|
|
|
20
|
+
var md5__default = /*#__PURE__*/_interopDefault(md5);
|
|
17
21
|
var anylogger__default = /*#__PURE__*/_interopDefault(anylogger);
|
|
18
22
|
|
|
23
|
+
const provideContext = useProviderContext => {
|
|
24
|
+
// automatic typing based on our hook's return type
|
|
25
|
+
|
|
26
|
+
const Context = /*#__PURE__*/react.createContext({
|
|
27
|
+
__provideContextInternalDefaultValue: true
|
|
28
|
+
});
|
|
29
|
+
const Provider = ({
|
|
30
|
+
children,
|
|
31
|
+
...props
|
|
32
|
+
}) => {
|
|
33
|
+
const ctx = useProviderContext(props);
|
|
34
|
+
return /*#__PURE__*/jsxRuntime.jsx(Context.Provider, {
|
|
35
|
+
value: ctx,
|
|
36
|
+
children: children
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
const useProvidedContext = () => {
|
|
40
|
+
const context = react.useContext(Context);
|
|
41
|
+
if (typeof context === "object" && context && "__provideContextInternalDefaultValue" in context) throw new Error("This hook requires a provider to be present above it in the tree");
|
|
42
|
+
return context;
|
|
43
|
+
};
|
|
44
|
+
const result = [Provider, useProvidedContext];
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const useAllAddressesProvider = () => react.useState([]);
|
|
49
|
+
const [AllAddressesProvider, useAllAddresses] = provideContext(useAllAddressesProvider);
|
|
50
|
+
|
|
51
|
+
const useBalanceModulesProvider = ({
|
|
52
|
+
balanceModules
|
|
53
|
+
}) => balanceModules;
|
|
54
|
+
const [BalanceModulesProvider, useBalanceModules] = provideContext(useBalanceModulesProvider);
|
|
55
|
+
|
|
56
|
+
function useChaindataProvider(options = {}) {
|
|
57
|
+
const [onfinalityApiKey, setOnfinalityApiKey] = react.useState(options.onfinalityApiKey);
|
|
58
|
+
|
|
59
|
+
// make sure we recreate provider only when the onfinalityApiKey changes
|
|
60
|
+
react.useEffect(() => {
|
|
61
|
+
if (options.onfinalityApiKey !== onfinalityApiKey) setOnfinalityApiKey(options.onfinalityApiKey);
|
|
62
|
+
}, [options.onfinalityApiKey, onfinalityApiKey]);
|
|
63
|
+
return react.useMemo(() => new chaindataProviderExtension.ChaindataProviderExtension({
|
|
64
|
+
onfinalityApiKey
|
|
65
|
+
}), [onfinalityApiKey]);
|
|
66
|
+
}
|
|
67
|
+
const [ChaindataProvider, useChaindata] = provideContext(useChaindataProvider);
|
|
68
|
+
|
|
69
|
+
const filterNoTestnet = ({
|
|
70
|
+
isTestnet
|
|
71
|
+
}) => isTestnet === false;
|
|
72
|
+
const DEFAULT_VALUE = {
|
|
73
|
+
chainsWithTestnets: [],
|
|
74
|
+
chainsWithoutTestnets: [],
|
|
75
|
+
evmNetworksWithTestnets: [],
|
|
76
|
+
evmNetworksWithoutTestnets: [],
|
|
77
|
+
tokensWithTestnets: [],
|
|
78
|
+
tokensWithoutTestnets: [],
|
|
79
|
+
chainsWithTestnetsMap: {},
|
|
80
|
+
chainsWithoutTestnetsMap: {},
|
|
81
|
+
evmNetworksWithTestnetsMap: {},
|
|
82
|
+
evmNetworksWithoutTestnetsMap: {},
|
|
83
|
+
tokensWithTestnetsMap: {},
|
|
84
|
+
tokensWithoutTestnetsMap: {},
|
|
85
|
+
tokenRatesMap: {},
|
|
86
|
+
balances: []
|
|
87
|
+
};
|
|
88
|
+
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
|
|
89
|
+
if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
|
|
90
|
+
|
|
91
|
+
// BEGIN: temp hack to indicate that
|
|
92
|
+
// - EVM GLMR is a mirror of substrate GLMR
|
|
93
|
+
// - EVM MOVR is a mirror of substrate MOVR
|
|
94
|
+
// - EVM DEV is a mirror of substrate DEV
|
|
95
|
+
// - EVM ACA is a mirror of substrate ACA
|
|
96
|
+
const mirrorTokenIds = {
|
|
97
|
+
"1284-evm-native-glmr": "moonbeam-substrate-native-glmr",
|
|
98
|
+
"1285-evm-native-movr": "moonriver-substrate-native-movr",
|
|
99
|
+
"1287-evm-native-dev": "moonbase-alpha-testnet-substrate-native-dev",
|
|
100
|
+
"787-evm-native-aca": "acala-substrate-native-aca"
|
|
101
|
+
};
|
|
102
|
+
Object.entries(mirrorTokenIds).filter(([mirrorToken]) => tokensMap[mirrorToken]).forEach(([mirrorToken, mirrorOf]) => tokensMap[mirrorToken].mirrorOf = mirrorOf);
|
|
103
|
+
// END: temp hack
|
|
104
|
+
|
|
105
|
+
const chainsWithTestnets = Object.values(chainsMap);
|
|
106
|
+
const chainsWithoutTestnets = chainsWithTestnets.filter(filterNoTestnet);
|
|
107
|
+
const chainsWithoutTestnetsMap = Object.fromEntries(chainsWithoutTestnets.map(network => [network.id, network]));
|
|
108
|
+
const evmNetworksWithTestnets = Object.values(evmNetworksMap);
|
|
109
|
+
const evmNetworksWithoutTestnets = evmNetworksWithTestnets.filter(filterNoTestnet);
|
|
110
|
+
const evmNetworksWithoutTestnetsMap = Object.fromEntries(evmNetworksWithoutTestnets.map(network => [network.id, network]));
|
|
111
|
+
|
|
112
|
+
// ensure that we have corresponding network for each token
|
|
113
|
+
const tokensWithTestnets = Object.values(tokensMap).filter(token => token.chain && chainsMap[token.chain.id] || token.evmNetwork && evmNetworksMap[token.evmNetwork.id]);
|
|
114
|
+
const tokensWithoutTestnets = tokensWithTestnets.filter(filterNoTestnet).filter(token => token.chain && chainsWithoutTestnetsMap[token.chain.id] || token.evmNetwork && evmNetworksWithoutTestnetsMap[token.evmNetwork.id]);
|
|
115
|
+
const tokensWithTestnetsMap = Object.fromEntries(tokensWithTestnets.map(token => [token.id, token]));
|
|
116
|
+
const tokensWithoutTestnetsMap = Object.fromEntries(tokensWithoutTestnets.map(token => [token.id, token]));
|
|
117
|
+
const tokenRatesMap = Object.fromEntries(tokenRates.map(({
|
|
118
|
+
tokenId,
|
|
119
|
+
rates
|
|
120
|
+
}) => [tokenId, rates]));
|
|
121
|
+
|
|
122
|
+
// return only balances for which we have a token
|
|
123
|
+
const balances = allBalances.filter(b => tokensWithTestnetsMap[b.tokenId]);
|
|
124
|
+
return {
|
|
125
|
+
chainsWithTestnets,
|
|
126
|
+
chainsWithoutTestnets,
|
|
127
|
+
evmNetworksWithTestnets,
|
|
128
|
+
evmNetworksWithoutTestnets,
|
|
129
|
+
tokensWithTestnets,
|
|
130
|
+
tokensWithoutTestnets,
|
|
131
|
+
chainsWithTestnetsMap: chainsMap,
|
|
132
|
+
chainsWithoutTestnetsMap,
|
|
133
|
+
evmNetworksWithTestnetsMap: evmNetworksMap,
|
|
134
|
+
evmNetworksWithoutTestnetsMap,
|
|
135
|
+
tokensWithTestnetsMap,
|
|
136
|
+
tokensWithoutTestnetsMap,
|
|
137
|
+
tokenRatesMap,
|
|
138
|
+
balances
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
const useDbCacheProvider = () => {
|
|
142
|
+
const chaindataProvider = useChaindata();
|
|
143
|
+
const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.chains(), [chaindataProvider]);
|
|
144
|
+
const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.evmNetworks(), [chaindataProvider]);
|
|
145
|
+
const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.tokens(), [chaindataProvider]);
|
|
146
|
+
const tokenRates$1 = dexieReactHooks.useLiveQuery(() => tokenRates.db.tokenRates.toArray(), []);
|
|
147
|
+
const rawBalances = dexieReactHooks.useLiveQuery(() => balances.db.balances.toArray(), []);
|
|
148
|
+
const [dbData, setDbData] = react.useState(DEFAULT_VALUE);
|
|
149
|
+
|
|
150
|
+
// debounce every 500ms to prevent hammering UI with updates
|
|
151
|
+
reactUse.useDebounce(() => {
|
|
152
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
153
|
+
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates$1]);
|
|
154
|
+
const refInitialized = react.useRef(false);
|
|
155
|
+
|
|
156
|
+
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
157
|
+
react.useEffect(() => {
|
|
158
|
+
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates$1 && rawBalances) {
|
|
159
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
160
|
+
refInitialized.current = true;
|
|
161
|
+
}
|
|
162
|
+
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates$1]);
|
|
163
|
+
return dbData;
|
|
164
|
+
};
|
|
165
|
+
const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
166
|
+
|
|
19
167
|
var packageJson = {
|
|
20
168
|
name: "@talismn/balances-react",
|
|
21
|
-
version: "0.0.0-
|
|
169
|
+
version: "0.0.0-pr596-20230306035406",
|
|
22
170
|
author: "Talisman",
|
|
23
171
|
homepage: "https://talisman.xyz",
|
|
24
172
|
license: "UNLICENSED",
|
|
@@ -51,9 +199,11 @@ var packageJson = {
|
|
|
51
199
|
"@talismn/chaindata-provider-extension": "workspace:^",
|
|
52
200
|
"@talismn/token-rates": "workspace:^",
|
|
53
201
|
anylogger: "^1.0.11",
|
|
202
|
+
"blueimp-md5": "2.19.0",
|
|
54
203
|
dexie: "^3.2.3",
|
|
55
204
|
"dexie-react-hooks": "^1.1.1",
|
|
56
|
-
"react-use": "^17.4.0"
|
|
205
|
+
"react-use": "^17.4.0",
|
|
206
|
+
rxjs: "^7.8.0"
|
|
57
207
|
},
|
|
58
208
|
devDependencies: {
|
|
59
209
|
"@talismn/eslint-config": "workspace:^",
|
|
@@ -80,294 +230,460 @@ var packageJson = {
|
|
|
80
230
|
|
|
81
231
|
var log = anylogger__default["default"](packageJson.name);
|
|
82
232
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
const [chaindataProvider, setChaindataProvider] = react.useState(null);
|
|
233
|
+
// global data store containing all subscriptions
|
|
234
|
+
const subscriptions = {};
|
|
86
235
|
|
|
87
|
-
|
|
88
|
-
|
|
236
|
+
/**
|
|
237
|
+
* This hook ensures a subscription is created only once, and unsubscribe automatically as soon as there is no consumer to the hook
|
|
238
|
+
* @param key key that is unique to the subscription's parameters
|
|
239
|
+
* @param subscribe // subscribe function that will be shared by all consumers of the key
|
|
240
|
+
*/
|
|
241
|
+
const useSharedSubscription = (key, subscribe) => {
|
|
242
|
+
// create the rxJS subject if it doesn't exist
|
|
243
|
+
if (!subscriptions[key]) subscriptions[key] = {
|
|
244
|
+
subject: new rxjs.Subject()
|
|
245
|
+
};
|
|
89
246
|
react.useEffect(() => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
let shouldHydrate = true;
|
|
94
|
-
const timer = 300_000; // 300_000ms = 300s = 5 minutes
|
|
95
|
-
const hydrate = async () => {
|
|
96
|
-
if (!shouldHydrate) return;
|
|
97
|
-
try {
|
|
98
|
-
const updated = await chaindataProvider.hydrate();
|
|
99
|
-
if (updated) setGeneration(generation => (generation + 1) % Number.MAX_SAFE_INTEGER);
|
|
100
|
-
setTimeout(hydrate, timer);
|
|
101
|
-
} catch (error) {
|
|
102
|
-
const retryTimeout = 5_000; // 5_000ms = 5 seconds
|
|
103
|
-
log.error(`Failed to fetch chaindata, retrying in ${Math.round(retryTimeout / 1000)} seconds`, error);
|
|
104
|
-
setTimeout(hydrate, retryTimeout);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
setChaindataProvider(chaindataProvider);
|
|
108
|
-
hydrate();
|
|
247
|
+
// subscribe to subject.
|
|
248
|
+
// it won't change but we need to count subscribers, to unsubscribe main subscription when no more observers
|
|
249
|
+
const s = subscriptions[key].subject.subscribe();
|
|
109
250
|
return () => {
|
|
110
|
-
|
|
251
|
+
// unsubscribe from our local observable updates to prevent memory leaks
|
|
252
|
+
s.unsubscribe();
|
|
253
|
+
const {
|
|
254
|
+
subject,
|
|
255
|
+
unsubscribe
|
|
256
|
+
} = subscriptions[key];
|
|
257
|
+
if (!subject.observed && unsubscribe) {
|
|
258
|
+
log.debug(`[useSharedSubscription] unsubscribing ${key}`);
|
|
259
|
+
|
|
260
|
+
// unsubscribe from backend updates to prevent unnecessary network connections
|
|
261
|
+
unsubscribe();
|
|
262
|
+
delete subscriptions[key].unsubscribe;
|
|
263
|
+
}
|
|
111
264
|
};
|
|
112
|
-
}, [
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
function useChains(chaindata) {
|
|
117
|
-
const [chains, setChains] = react.useState();
|
|
118
|
-
react.useEffect(() => {
|
|
119
|
-
if (!chaindata) return;
|
|
120
|
-
const thisGeneration = chaindata.generation;
|
|
121
|
-
chaindata.chains().then(chains => {
|
|
122
|
-
if (thisGeneration !== chaindata.generation) return;
|
|
123
|
-
setChains(chains);
|
|
124
|
-
});
|
|
125
|
-
}, [chaindata, chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
|
|
126
|
-
return chains || {};
|
|
127
|
-
}
|
|
128
|
-
function useChain(chaindata, chainId) {
|
|
129
|
-
const [chain, setChain] = react.useState();
|
|
130
|
-
react.useEffect(() => {
|
|
131
|
-
if (chaindata === null) return;
|
|
132
|
-
if (!chainId) return;
|
|
133
|
-
chaindata.getChain(chainId).then(setChain);
|
|
134
|
-
}, [chainId, chaindata, chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation]);
|
|
135
|
-
return chain;
|
|
136
|
-
}
|
|
137
|
-
function useEvmNetworks(chaindata) {
|
|
138
|
-
const [evmNetworks, setEvmNetworks] = react.useState();
|
|
265
|
+
}, [key]);
|
|
266
|
+
|
|
267
|
+
// Initialize subscription
|
|
139
268
|
react.useEffect(() => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
269
|
+
const {
|
|
270
|
+
unsubscribe
|
|
271
|
+
} = subscriptions[key];
|
|
272
|
+
// launch the subscription if it's a new key
|
|
273
|
+
if (!unsubscribe) {
|
|
274
|
+
const cb = subscribe();
|
|
275
|
+
log.debug(`[useSharedSubscription] subscribing ${key}`);
|
|
276
|
+
if (cb) subscriptions[key].unsubscribe = cb;
|
|
277
|
+
// this error should only happen when developping a new hook, let it bubble up
|
|
278
|
+
else throw new Error(`${key} subscribe did not return an unsubscribe callback`);
|
|
279
|
+
}
|
|
280
|
+
}, [key, subscribe]);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
function useChainConnectorsProvider(options) {
|
|
284
|
+
const [onfinalityApiKey, setOnfinalityApiKey] = react.useState(options.onfinalityApiKey);
|
|
285
|
+
|
|
286
|
+
// make sure we recreate provider only when the onfinalityApiKey changes
|
|
151
287
|
react.useEffect(() => {
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
288
|
+
if (options.onfinalityApiKey !== onfinalityApiKey) setOnfinalityApiKey(options.onfinalityApiKey);
|
|
289
|
+
}, [options.onfinalityApiKey, onfinalityApiKey]);
|
|
290
|
+
|
|
291
|
+
// chaindata dependency
|
|
292
|
+
const chaindata = useChaindata();
|
|
293
|
+
|
|
294
|
+
// substrate connector
|
|
295
|
+
const substrate = react.useMemo(() => new chainConnector.ChainConnector(chaindata), [chaindata]);
|
|
296
|
+
|
|
297
|
+
// evm connector
|
|
298
|
+
const evm = react.useMemo(() => new chainConnectorEvm.ChainConnectorEvm(chaindata, {
|
|
299
|
+
onfinalityApiKey
|
|
300
|
+
}), [chaindata, onfinalityApiKey]);
|
|
301
|
+
return react.useMemo(() => ({
|
|
302
|
+
substrate,
|
|
303
|
+
evm
|
|
304
|
+
}), [substrate, evm]);
|
|
157
305
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return tokens || {};
|
|
306
|
+
const [ChainConnectorsProvider, useChainConnectors] = provideContext(useChainConnectorsProvider);
|
|
307
|
+
|
|
308
|
+
function useTokens(withTestnets) {
|
|
309
|
+
// keep db data up to date
|
|
310
|
+
useDbCacheSubscription("tokens");
|
|
311
|
+
const {
|
|
312
|
+
tokensWithTestnetsMap,
|
|
313
|
+
tokensWithoutTestnetsMap
|
|
314
|
+
} = useDbCache();
|
|
315
|
+
return withTestnets ? tokensWithTestnetsMap : tokensWithoutTestnetsMap;
|
|
169
316
|
}
|
|
170
|
-
function useToken(
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
if (chaindata === null) return;
|
|
174
|
-
if (!tokenId) return;
|
|
175
|
-
chaindata.getToken(tokenId).then(setToken);
|
|
176
|
-
}, [chaindata, chaindata === null || chaindata === void 0 ? void 0 : chaindata.generation, tokenId]);
|
|
177
|
-
return token;
|
|
317
|
+
function useToken(tokenId, withTestnets) {
|
|
318
|
+
const tokens = useTokens(withTestnets);
|
|
319
|
+
return tokenId ? tokens[tokenId] : undefined;
|
|
178
320
|
}
|
|
179
321
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Creates a subscription function that can be used to subscribe to a multicast observable created from an upstream source.
|
|
324
|
+
*
|
|
325
|
+
* An example of when this is useful is when we want to subscribe to some data from multiple components, but we only want
|
|
326
|
+
* to actively keep that data hydrated when at least one component is subscribed to it.
|
|
327
|
+
*
|
|
328
|
+
* When the first component subscribes, the `upstream` function will be called. It should then set up a subscription and return a teardown function.
|
|
329
|
+
* When subsequent components subscribe, they will be added to the existing subscription.
|
|
330
|
+
* When the last component unsubscribes, the teardown function returned from the `upstream` function will be called.
|
|
331
|
+
*
|
|
332
|
+
* @param upstream A function that takes a "next" callback function as an argument, and returns either an unsubscribe function or void.
|
|
333
|
+
* @returns A subscription function that can be used to subscribe to the multicast observable.
|
|
334
|
+
*/
|
|
335
|
+
const useMulticastSubscription = upstream => {
|
|
336
|
+
const subscribe = react.useMemo(() => createMulticastSubscription(upstream), [upstream]);
|
|
337
|
+
return subscribe;
|
|
338
|
+
};
|
|
339
|
+
const createMulticastSubscription = upstream => {
|
|
340
|
+
// Create an upstream observable using the provided function.
|
|
341
|
+
const upstreamObservable = new rxjs.Observable(subscriber => {
|
|
342
|
+
const unsubscribe = upstream(val => subscriber.next(val));
|
|
343
|
+
return () => {
|
|
344
|
+
typeof unsubscribe === "function" && unsubscribe();
|
|
345
|
+
};
|
|
346
|
+
});
|
|
198
347
|
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// useCachedDb hook, which internally subscribes to all of the db tables
|
|
205
|
-
// for everything, and then filters the subscribed data based on what params
|
|
206
|
-
// the caller of useChains/useTokens/etc has provided.
|
|
207
|
-
function useBalances(
|
|
208
|
-
// TODO: Make this array of BalanceModules more type-safe
|
|
209
|
-
balanceModules, chaindataProvider, addressesByToken, options = {}) {
|
|
210
|
-
useBalancesSubscriptions(balanceModules, chaindataProvider, addressesByToken, options);
|
|
211
|
-
const chains = useChains(chaindataProvider);
|
|
212
|
-
const evmNetworks = useEvmNetworks(chaindataProvider);
|
|
213
|
-
const tokens = useTokens(chaindataProvider);
|
|
214
|
-
const tokenRates = useTokenRates(tokens);
|
|
215
|
-
const balances$1 = dexieReactHooks.useLiveQuery(async () => new balances.Balances(await balances.db.balances.filter(balance => {
|
|
216
|
-
// check that this balance is included in our queried balance modules
|
|
217
|
-
if (!balanceModules.map(({
|
|
218
|
-
type
|
|
219
|
-
}) => type).includes(balance.source)) return false;
|
|
348
|
+
// Create a multicast observable from the upstream observable, using the shareReplay operator.
|
|
349
|
+
const multicastObservable = rxjs.defer(() => upstreamObservable).pipe(rxjs.shareReplay({
|
|
350
|
+
bufferSize: 1,
|
|
351
|
+
refCount: true
|
|
352
|
+
}));
|
|
220
353
|
|
|
221
|
-
|
|
222
|
-
|
|
354
|
+
// Create a subscription function that subscribes to the multicast observable and returns an unsubscribe function.
|
|
355
|
+
const subscribe = callback => {
|
|
356
|
+
const subscription = multicastObservable.subscribe(callback);
|
|
357
|
+
const unsubscribe = () => subscription.unsubscribe();
|
|
358
|
+
return unsubscribe;
|
|
359
|
+
};
|
|
360
|
+
return subscribe;
|
|
361
|
+
};
|
|
223
362
|
|
|
224
|
-
|
|
225
|
-
|
|
363
|
+
const useWithTestnetsProvider = ({
|
|
364
|
+
withTestnets
|
|
365
|
+
}) => {
|
|
366
|
+
return {
|
|
367
|
+
withTestnets
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
const [WithTestnetsProvider, useWithTestnets] = provideContext(useWithTestnetsProvider);
|
|
226
371
|
|
|
227
|
-
|
|
228
|
-
|
|
372
|
+
/**
|
|
373
|
+
* This hook is responsible for fetching the data used for balances and inserting it into the db.
|
|
374
|
+
*/
|
|
375
|
+
const useDbCacheSubscription = subscribeTo => {
|
|
376
|
+
const provider = useChaindata();
|
|
229
377
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
378
|
+
// can't handle balances & tokenRates here as they have other dependencies, it would trigger to many subscriptions
|
|
379
|
+
const subscribe = react.useCallback(() => {
|
|
380
|
+
switch (subscribeTo) {
|
|
381
|
+
case "chains":
|
|
382
|
+
return subscribeChainDataHydrate(provider, "chains");
|
|
383
|
+
case "evmNetworks":
|
|
384
|
+
return subscribeChainDataHydrate(provider, "evmNetworks");
|
|
385
|
+
case "tokens":
|
|
386
|
+
return subscribeChainDataHydrate(provider, "tokens");
|
|
387
|
+
}
|
|
388
|
+
}, [provider, subscribeTo]);
|
|
389
|
+
useSharedSubscription(subscribeTo, subscribe);
|
|
390
|
+
};
|
|
240
391
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
392
|
+
/**
|
|
393
|
+
* This hook is responsible for fetching the data used for token rates and inserting it into the db.
|
|
394
|
+
*/
|
|
395
|
+
function useDbCacheTokenRatesSubscription() {
|
|
396
|
+
const {
|
|
397
|
+
withTestnets
|
|
398
|
+
} = useWithTestnets();
|
|
399
|
+
const tokens = useTokens(withTestnets);
|
|
400
|
+
const subscriptionKey = react.useMemo(
|
|
401
|
+
// not super sexy but we need key to change based on this stuff
|
|
402
|
+
() => {
|
|
403
|
+
const key = Object.values(tokens ?? {}).map(({
|
|
404
|
+
id
|
|
405
|
+
}) => id).sort().join();
|
|
406
|
+
return `tokenRates-${md5__default["default"](key)}`;
|
|
407
|
+
}, [tokens]);
|
|
408
|
+
const subscription = react.useCallback(() => {
|
|
409
|
+
if (!Object.values(tokens ?? {}).length) return () => {};
|
|
410
|
+
return subscribeTokenRates(tokens);
|
|
411
|
+
}, [tokens]);
|
|
412
|
+
useSharedSubscription(subscriptionKey, subscription);
|
|
245
413
|
}
|
|
246
414
|
|
|
247
|
-
|
|
248
|
-
|
|
415
|
+
/**
|
|
416
|
+
* This hook is responsible for fetching the data used for balances and inserting it into the db.
|
|
417
|
+
*/
|
|
418
|
+
function useDbCacheBalancesSubscription() {
|
|
419
|
+
const {
|
|
420
|
+
withTestnets
|
|
421
|
+
} = useWithTestnets();
|
|
422
|
+
const balanceModules = useBalanceModules();
|
|
423
|
+
const chaindataProvider = useChaindata();
|
|
424
|
+
const chainConnectors = useChainConnectors();
|
|
425
|
+
const [allAddresses] = useAllAddresses();
|
|
426
|
+
const tokens = useTokens(withTestnets);
|
|
427
|
+
const subscriptionKey = react.useMemo(
|
|
428
|
+
// not super sexy but we need key to change based on this stuff
|
|
429
|
+
() => {
|
|
430
|
+
const key = allAddresses.sort().join().concat(...Object.values(tokens ?? {}).map(({
|
|
431
|
+
id
|
|
432
|
+
}) => id).sort()).concat(`evm:${!!chainConnectors.evm}`, `sub:${!!chainConnectors.substrate}`, ...balanceModules.map(m => m.type).sort(), `cd:${!!chaindataProvider}`);
|
|
433
|
+
return `balances-${md5__default["default"](key)}`;
|
|
434
|
+
}, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
|
|
435
|
+
const subscription = react.useCallback(() => {
|
|
436
|
+
if (!Object.values(tokens ?? {}).length || !allAddresses.length) return () => {};
|
|
437
|
+
return subscribeBalances(tokens ?? {}, allAddresses, chainConnectors, chaindataProvider, balanceModules);
|
|
438
|
+
}, [allAddresses, balanceModules, chainConnectors, chaindataProvider, tokens]);
|
|
439
|
+
useSharedSubscription(subscriptionKey, subscription);
|
|
440
|
+
}
|
|
441
|
+
const subscribeChainDataHydrate = (provider, type) => {
|
|
442
|
+
const chaindata = provider;
|
|
443
|
+
const delay = 300_000; // 300_000ms = 300s = 5 minutes
|
|
249
444
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
// create subscription if it doesn't already exist
|
|
262
|
-
if (!subscriptions[key] || subscriptions[key].refcount === 0) {
|
|
263
|
-
var _subscriptions$key;
|
|
264
|
-
const generation = ((((_subscriptions$key = subscriptions[key]) === null || _subscriptions$key === void 0 ? void 0 : _subscriptions$key.generation) || 0) + 1) % Number.MAX_SAFE_INTEGER;
|
|
265
|
-
const unsub = balances.balances(balanceModule, chainConnectors, chaindataProvider, addressesByToken, (error, balances$1) => {
|
|
266
|
-
if (error) return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
|
|
267
|
-
if (!balances$1) return;
|
|
268
|
-
|
|
269
|
-
// ignore balances from old subscriptions which are still in the process of unsubscribing
|
|
270
|
-
if (subscriptions[key].generation !== generation) return;
|
|
271
|
-
const putBalances = Object.entries(balances$1.toJSON()).map(([id, balance]) => ({
|
|
272
|
-
id,
|
|
273
|
-
...balance
|
|
274
|
-
}));
|
|
275
|
-
balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.bulkPut(putBalances));
|
|
276
|
-
});
|
|
277
|
-
subscriptions[key] = {
|
|
278
|
-
unsub,
|
|
279
|
-
refcount: 0,
|
|
280
|
-
generation
|
|
281
|
-
};
|
|
445
|
+
let timeout = null;
|
|
446
|
+
const hydrate = async () => {
|
|
447
|
+
try {
|
|
448
|
+
if (type === "chains") await chaindata.hydrateChains();
|
|
449
|
+
if (type === "evmNetworks") await chaindata.hydrateEvmNetworks();
|
|
450
|
+
if (type === "tokens") await chaindata.hydrateTokens();
|
|
451
|
+
timeout = setTimeout(hydrate, delay);
|
|
452
|
+
} catch (error) {
|
|
453
|
+
const retryTimeout = 5_000; // 5_000ms = 5 seconds
|
|
454
|
+
log.error(`Failed to fetch chaindata, retrying in ${Math.round(retryTimeout / 1000)} seconds`, error);
|
|
455
|
+
timeout = setTimeout(hydrate, retryTimeout);
|
|
282
456
|
}
|
|
457
|
+
};
|
|
283
458
|
|
|
284
|
-
|
|
285
|
-
|
|
459
|
+
// launch the loop
|
|
460
|
+
hydrate();
|
|
461
|
+
return () => {
|
|
462
|
+
if (timeout) clearTimeout(timeout);
|
|
286
463
|
};
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
464
|
+
};
|
|
465
|
+
const subscribeTokenRates = tokens => {
|
|
466
|
+
const REFRESH_INTERVAL = 300_000; // 6 minutes
|
|
467
|
+
const RETRY_INTERVAL = 5_000; // 5 sec
|
|
290
468
|
|
|
291
|
-
|
|
292
|
-
|
|
469
|
+
let timeout = null;
|
|
470
|
+
const refreshTokenRates = async () => {
|
|
471
|
+
try {
|
|
472
|
+
if (timeout) clearTimeout(timeout);
|
|
473
|
+
const tokenRates$1 = await tokenRates.fetchTokenRates(tokens);
|
|
474
|
+
const putTokenRates = Object.entries(tokenRates$1).map(([tokenId, rates]) => ({
|
|
475
|
+
tokenId,
|
|
476
|
+
rates
|
|
477
|
+
}));
|
|
478
|
+
tokenRates.db.transaction("rw", tokenRates.db.tokenRates, async () => await tokenRates.db.tokenRates.bulkPut(putTokenRates));
|
|
479
|
+
timeout = setTimeout(() => {
|
|
480
|
+
refreshTokenRates();
|
|
481
|
+
}, REFRESH_INTERVAL);
|
|
482
|
+
} catch (error) {
|
|
483
|
+
log.error(`Failed to fetch tokenRates, retrying in ${Math.round(RETRY_INTERVAL / 1000)} seconds`, error);
|
|
484
|
+
setTimeout(async () => {
|
|
485
|
+
refreshTokenRates();
|
|
486
|
+
}, RETRY_INTERVAL);
|
|
487
|
+
}
|
|
488
|
+
};
|
|
293
489
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
490
|
+
// launch the loop
|
|
491
|
+
refreshTokenRates();
|
|
492
|
+
return () => {
|
|
493
|
+
if (timeout) clearTimeout(timeout);
|
|
494
|
+
};
|
|
495
|
+
};
|
|
496
|
+
const subscribeBalances = (tokens, addresses, chainConnectors, provider, balanceModules) => {
|
|
497
|
+
const tokenIds = Object.values(tokens).map(({
|
|
498
|
+
id
|
|
499
|
+
}) => id);
|
|
500
|
+
const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId, addresses]));
|
|
501
|
+
const updateDb = balances$1 => {
|
|
502
|
+
const putBalances = Object.entries(balances$1.toJSON()).map(([id, balance]) => ({
|
|
503
|
+
id,
|
|
504
|
+
...balance
|
|
505
|
+
}));
|
|
506
|
+
balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.bulkPut(putBalances));
|
|
507
|
+
};
|
|
508
|
+
let unsubscribed = false;
|
|
299
509
|
|
|
300
|
-
|
|
510
|
+
// eslint-disable-next-line no-console
|
|
511
|
+
log.log("subscribing to balance changes for %d tokens and %d addresses", tokenIds.length, addresses.length);
|
|
512
|
+
const unsubs = balanceModules.map(async balanceModule => {
|
|
513
|
+
// filter out tokens to only include those which this module knows how to fetch balances for
|
|
514
|
+
const moduleTokenIds = Object.values(tokens ?? {}).filter(({
|
|
515
|
+
type
|
|
516
|
+
}) => type === balanceModule.type).map(({
|
|
517
|
+
id
|
|
518
|
+
}) => id);
|
|
519
|
+
const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
|
|
520
|
+
const unsub = balances.balances(balanceModule, chainConnectors, provider, addressesByModuleToken, (error, balances) => {
|
|
521
|
+
// log errors
|
|
522
|
+
if (error) return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
|
|
523
|
+
// ignore empty balance responses
|
|
524
|
+
if (!balances) return;
|
|
525
|
+
// ignore balances from old subscriptions which are still in the process of unsubscribing
|
|
526
|
+
if (unsubscribed) return;
|
|
527
|
+
updateDb(balances);
|
|
528
|
+
});
|
|
529
|
+
return () => {
|
|
530
|
+
// wait 2 seconds before actually unsubscribing, allowing for websocket to be reused
|
|
531
|
+
unsub.then(unsubscribe => {
|
|
532
|
+
setTimeout(unsubscribe, 2_000);
|
|
533
|
+
});
|
|
301
534
|
balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.filter(balance => {
|
|
302
535
|
if (balance.source !== balanceModule.type) return false;
|
|
303
|
-
if (!Object.keys(
|
|
304
|
-
if (!
|
|
536
|
+
if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
|
|
537
|
+
if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
|
|
305
538
|
return true;
|
|
306
539
|
}).modify({
|
|
307
540
|
status: "cache"
|
|
308
541
|
}));
|
|
309
|
-
}
|
|
542
|
+
};
|
|
543
|
+
});
|
|
544
|
+
const unsubscribeAll = () => {
|
|
545
|
+
unsubscribed = true;
|
|
546
|
+
unsubs.forEach(unsub => unsub.then(unsubscribe => unsubscribe()));
|
|
310
547
|
};
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
id
|
|
327
|
-
}) => id);
|
|
328
|
-
const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
|
|
329
|
-
|
|
330
|
-
// add balance subscription for this module
|
|
331
|
-
addSubscription(subscriptionKey, balanceModule, {
|
|
332
|
-
substrate: chainConnector,
|
|
333
|
-
evm: chainConnectorEvm
|
|
334
|
-
}, chaindataProvider, addressesByModuleToken);
|
|
335
|
-
|
|
336
|
-
// return an unsub method, to be called when this effect unmounts
|
|
337
|
-
return () => removeSubscription(subscriptionKey, balanceModule, addressesByToken);
|
|
338
|
-
});
|
|
339
|
-
const unsubAll = () => unsubs.forEach(unsub => unsub());
|
|
340
|
-
return unsubAll;
|
|
341
|
-
}, [addressesByToken, balanceModules, chainConnector, chainConnectorEvm, chaindataProvider, tokens]);
|
|
548
|
+
return unsubscribeAll;
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
function useChains(withTestnets) {
|
|
552
|
+
// keep db data up to date
|
|
553
|
+
useDbCacheSubscription("chains");
|
|
554
|
+
const {
|
|
555
|
+
chainsWithTestnetsMap,
|
|
556
|
+
chainsWithoutTestnetsMap
|
|
557
|
+
} = useDbCache();
|
|
558
|
+
return withTestnets ? chainsWithTestnetsMap : chainsWithoutTestnetsMap;
|
|
559
|
+
}
|
|
560
|
+
function useChain(chainId, withTestnets) {
|
|
561
|
+
const chains = useChains(withTestnets);
|
|
562
|
+
return chainId ? chains[chainId] : undefined;
|
|
342
563
|
}
|
|
343
564
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
return
|
|
565
|
+
function useEvmNetworks(withTestnets) {
|
|
566
|
+
// keep db data up to date
|
|
567
|
+
useDbCacheSubscription("evmNetworks");
|
|
568
|
+
const {
|
|
569
|
+
evmNetworksWithTestnetsMap,
|
|
570
|
+
evmNetworksWithoutTestnetsMap
|
|
571
|
+
} = useDbCache();
|
|
572
|
+
return withTestnets ? evmNetworksWithTestnetsMap : evmNetworksWithoutTestnetsMap;
|
|
352
573
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
574
|
+
function useEvmNetwork(evmNetworkId, withTestnets) {
|
|
575
|
+
const evmNetworks = useEvmNetworks(withTestnets);
|
|
576
|
+
return evmNetworkId ? evmNetworks[evmNetworkId] : undefined;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function useTokenRates() {
|
|
580
|
+
// keep db data up to date
|
|
581
|
+
useDbCacheTokenRatesSubscription();
|
|
582
|
+
const {
|
|
583
|
+
tokenRatesMap
|
|
584
|
+
} = useDbCache();
|
|
585
|
+
return tokenRatesMap;
|
|
363
586
|
}
|
|
587
|
+
function useTokenRate(tokenId) {
|
|
588
|
+
const tokenRates = useTokenRates();
|
|
589
|
+
return tokenId ? tokenRates[tokenId] : undefined;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const useBalancesHydrate = () => {
|
|
593
|
+
const {
|
|
594
|
+
withTestnets
|
|
595
|
+
} = useWithTestnets();
|
|
596
|
+
const chains = useChains(withTestnets);
|
|
597
|
+
const evmNetworks = useEvmNetworks(withTestnets);
|
|
598
|
+
const tokens = useTokens(withTestnets);
|
|
599
|
+
const tokenRates = useTokenRates();
|
|
600
|
+
return react.useMemo(() => ({
|
|
601
|
+
chains,
|
|
602
|
+
evmNetworks,
|
|
603
|
+
tokens,
|
|
604
|
+
tokenRates
|
|
605
|
+
}), [chains, evmNetworks, tokens, tokenRates]);
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
function useBalances(addressesByToken) {
|
|
609
|
+
// keep db data up to date
|
|
610
|
+
useDbCacheBalancesSubscription();
|
|
611
|
+
const balanceModules = useBalanceModules();
|
|
612
|
+
const {
|
|
613
|
+
balances: balances$1
|
|
614
|
+
} = useDbCache();
|
|
615
|
+
const hydrate = useBalancesHydrate();
|
|
616
|
+
return react.useMemo(() => new balances.Balances(balances$1.filter(balance => {
|
|
617
|
+
// check that this balance is included in our queried balance modules
|
|
618
|
+
if (!balanceModules.map(({
|
|
619
|
+
type
|
|
620
|
+
}) => type).includes(balance.source)) return false;
|
|
621
|
+
|
|
622
|
+
// check that our query includes some tokens and addresses
|
|
623
|
+
if (!addressesByToken) return false;
|
|
624
|
+
|
|
625
|
+
// check that this balance is included in our queried tokens
|
|
626
|
+
if (!Object.keys(addressesByToken).includes(balance.tokenId)) return false;
|
|
627
|
+
|
|
628
|
+
// check that this balance is included in our queried addresses for this token
|
|
629
|
+
if (!addressesByToken[balance.tokenId].includes(balance.address)) return false;
|
|
630
|
+
|
|
631
|
+
// keep this balance
|
|
632
|
+
return true;
|
|
633
|
+
}),
|
|
634
|
+
// hydrate balance chains, evmNetworks, tokens and tokenRates
|
|
635
|
+
hydrate), [balances$1, hydrate, balanceModules, addressesByToken]);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
const BalancesProvider = ({
|
|
639
|
+
balanceModules,
|
|
640
|
+
onfinalityApiKey,
|
|
641
|
+
withTestnets,
|
|
642
|
+
children
|
|
643
|
+
}) => /*#__PURE__*/jsxRuntime.jsx(WithTestnetsProvider, {
|
|
644
|
+
withTestnets: withTestnets,
|
|
645
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ChaindataProvider, {
|
|
646
|
+
onfinalityApiKey: onfinalityApiKey,
|
|
647
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ChainConnectorsProvider, {
|
|
648
|
+
onfinalityApiKey: onfinalityApiKey,
|
|
649
|
+
children: /*#__PURE__*/jsxRuntime.jsx(AllAddressesProvider, {
|
|
650
|
+
children: /*#__PURE__*/jsxRuntime.jsx(BalanceModulesProvider, {
|
|
651
|
+
balanceModules: balanceModules,
|
|
652
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DbCacheProvider, {
|
|
653
|
+
children: children
|
|
654
|
+
})
|
|
655
|
+
})
|
|
656
|
+
})
|
|
657
|
+
})
|
|
658
|
+
})
|
|
659
|
+
});
|
|
364
660
|
|
|
661
|
+
exports.AllAddressesProvider = AllAddressesProvider;
|
|
662
|
+
exports.BalanceModulesProvider = BalanceModulesProvider;
|
|
663
|
+
exports.BalancesProvider = BalancesProvider;
|
|
664
|
+
exports.ChainConnectorsProvider = ChainConnectorsProvider;
|
|
665
|
+
exports.ChaindataProvider = ChaindataProvider;
|
|
666
|
+
exports.DbCacheProvider = DbCacheProvider;
|
|
667
|
+
exports.WithTestnetsProvider = WithTestnetsProvider;
|
|
668
|
+
exports.createMulticastSubscription = createMulticastSubscription;
|
|
669
|
+
exports.provideContext = provideContext;
|
|
670
|
+
exports.useAllAddresses = useAllAddresses;
|
|
671
|
+
exports.useBalanceModules = useBalanceModules;
|
|
365
672
|
exports.useBalances = useBalances;
|
|
673
|
+
exports.useBalancesHydrate = useBalancesHydrate;
|
|
366
674
|
exports.useChain = useChain;
|
|
675
|
+
exports.useChainConnectors = useChainConnectors;
|
|
367
676
|
exports.useChaindata = useChaindata;
|
|
368
677
|
exports.useChains = useChains;
|
|
678
|
+
exports.useDbCache = useDbCache;
|
|
679
|
+
exports.useDbCacheBalancesSubscription = useDbCacheBalancesSubscription;
|
|
680
|
+
exports.useDbCacheSubscription = useDbCacheSubscription;
|
|
681
|
+
exports.useDbCacheTokenRatesSubscription = useDbCacheTokenRatesSubscription;
|
|
369
682
|
exports.useEvmNetwork = useEvmNetwork;
|
|
370
683
|
exports.useEvmNetworks = useEvmNetworks;
|
|
684
|
+
exports.useMulticastSubscription = useMulticastSubscription;
|
|
371
685
|
exports.useToken = useToken;
|
|
686
|
+
exports.useTokenRate = useTokenRate;
|
|
372
687
|
exports.useTokenRates = useTokenRates;
|
|
373
688
|
exports.useTokens = useTokens;
|
|
689
|
+
exports.useWithTestnets = useWithTestnets;
|