@talismn/balances-react 0.0.0-pr587-20230301175306 → 0.0.0-pr589-20230302073822
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 +3 -7
- package/dist/declarations/src/hooks/index.d.ts +2 -3
- package/dist/declarations/src/hooks/useBalancesHydrate.d.ts +1 -1
- package/dist/declarations/src/hooks/useChainConnectors.d.ts +2 -2
- package/dist/declarations/src/hooks/useChaindata.d.ts +2 -2
- package/dist/declarations/src/hooks/useDbCache.d.ts +4 -1
- package/dist/declarations/src/hooks/useDbCacheSubscription.d.ts +5 -9
- package/dist/talismn-balances-react.cjs.dev.js +209 -290
- package/dist/talismn-balances-react.cjs.prod.js +209 -290
- package/dist/talismn-balances-react.esm.js +210 -288
- package/package.json +3 -4
- package/dist/declarations/src/hooks/useWithTestnets.d.ts +0 -8
- package/dist/declarations/src/util/useSharedSubscription.d.ts +0 -9
|
@@ -9,7 +9,6 @@ var tokenRates = require('@talismn/token-rates');
|
|
|
9
9
|
var dexieReactHooks = require('dexie-react-hooks');
|
|
10
10
|
var reactUse = require('react-use');
|
|
11
11
|
var chaindataProviderExtension = require('@talismn/chaindata-provider-extension');
|
|
12
|
-
var md5 = require('blueimp-md5');
|
|
13
12
|
var anylogger = require('anylogger');
|
|
14
13
|
var rxjs = require('rxjs');
|
|
15
14
|
var chainConnector = require('@talismn/chain-connector');
|
|
@@ -17,7 +16,6 @@ var chainConnectorEvm = require('@talismn/chain-connector-evm');
|
|
|
17
16
|
|
|
18
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
19
18
|
|
|
20
|
-
var md5__default = /*#__PURE__*/_interopDefault(md5);
|
|
21
19
|
var anylogger__default = /*#__PURE__*/_interopDefault(anylogger);
|
|
22
20
|
|
|
23
21
|
const provideContext = useProviderContext => {
|
|
@@ -54,15 +52,13 @@ const useBalanceModulesProvider = ({
|
|
|
54
52
|
const [BalanceModulesProvider, useBalanceModules] = provideContext(useBalanceModulesProvider);
|
|
55
53
|
|
|
56
54
|
function useChaindataProvider(options = {}) {
|
|
57
|
-
const [
|
|
58
|
-
|
|
59
|
-
// make sure we recreate provider only when the onfinalityApiKey changes
|
|
55
|
+
const [chaindata, setChaindata] = react.useState();
|
|
60
56
|
react.useEffect(() => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
57
|
+
setChaindata(new chaindataProviderExtension.ChaindataProviderExtension({
|
|
58
|
+
onfinalityApiKey: options.onfinalityApiKey
|
|
59
|
+
}));
|
|
60
|
+
}, [options.onfinalityApiKey]);
|
|
61
|
+
return chaindata;
|
|
66
62
|
}
|
|
67
63
|
const [ChaindataProvider, useChaindata] = provideContext(useChaindataProvider);
|
|
68
64
|
|
|
@@ -138,7 +134,9 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
|
|
|
138
134
|
balances
|
|
139
135
|
};
|
|
140
136
|
};
|
|
141
|
-
const useDbCacheProvider = (
|
|
137
|
+
const useDbCacheProvider = ({
|
|
138
|
+
useTestnets = false
|
|
139
|
+
}) => {
|
|
142
140
|
const chaindataProvider = useChaindata();
|
|
143
141
|
const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.chains(), [chaindataProvider]);
|
|
144
142
|
const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.evmNetworks(), [chaindataProvider]);
|
|
@@ -150,7 +148,7 @@ const useDbCacheProvider = () => {
|
|
|
150
148
|
// debounce every 500ms to prevent hammering UI with updates
|
|
151
149
|
reactUse.useDebounce(() => {
|
|
152
150
|
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
153
|
-
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates$1]);
|
|
151
|
+
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates$1, useTestnets]);
|
|
154
152
|
const refInitialized = react.useRef(false);
|
|
155
153
|
|
|
156
154
|
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
@@ -159,14 +157,14 @@ const useDbCacheProvider = () => {
|
|
|
159
157
|
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
160
158
|
refInitialized.current = true;
|
|
161
159
|
}
|
|
162
|
-
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates$1]);
|
|
160
|
+
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates$1, useTestnets]);
|
|
163
161
|
return dbData;
|
|
164
162
|
};
|
|
165
163
|
const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
166
164
|
|
|
167
165
|
var packageJson = {
|
|
168
166
|
name: "@talismn/balances-react",
|
|
169
|
-
version: "0.0.0-
|
|
167
|
+
version: "0.0.0-pr589-20230302073822",
|
|
170
168
|
author: "Talisman",
|
|
171
169
|
homepage: "https://talisman.xyz",
|
|
172
170
|
license: "UNLICENSED",
|
|
@@ -199,7 +197,6 @@ var packageJson = {
|
|
|
199
197
|
"@talismn/chaindata-provider-extension": "workspace:^",
|
|
200
198
|
"@talismn/token-rates": "workspace:^",
|
|
201
199
|
anylogger: "^1.0.11",
|
|
202
|
-
"blueimp-md5": "2.19.0",
|
|
203
200
|
dexie: "^3.2.3",
|
|
204
201
|
"dexie-react-hooks": "^1.1.1",
|
|
205
202
|
"react-use": "^17.4.0",
|
|
@@ -230,95 +227,6 @@ var packageJson = {
|
|
|
230
227
|
|
|
231
228
|
var log = anylogger__default["default"](packageJson.name);
|
|
232
229
|
|
|
233
|
-
// global data store containing all subscriptions
|
|
234
|
-
const subscriptions = {};
|
|
235
|
-
|
|
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
|
-
};
|
|
246
|
-
react.useEffect(() => {
|
|
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();
|
|
250
|
-
return () => {
|
|
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
|
-
}
|
|
264
|
-
};
|
|
265
|
-
}, [key]);
|
|
266
|
-
|
|
267
|
-
// Initialize subscription
|
|
268
|
-
react.useEffect(() => {
|
|
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
|
|
287
|
-
react.useEffect(() => {
|
|
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]);
|
|
305
|
-
}
|
|
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;
|
|
316
|
-
}
|
|
317
|
-
function useToken(tokenId, withTestnets) {
|
|
318
|
-
const tokens = useTokens(withTestnets);
|
|
319
|
-
return tokenId ? tokens[tokenId] : undefined;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
230
|
/**
|
|
323
231
|
* Creates a subscription function that can be used to subscribe to a multicast observable created from an upstream source.
|
|
324
232
|
*
|
|
@@ -360,191 +268,193 @@ const createMulticastSubscription = upstream => {
|
|
|
360
268
|
return subscribe;
|
|
361
269
|
};
|
|
362
270
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
271
|
+
function useChainConnectorsProvider(options) {
|
|
272
|
+
// chaindata dependency
|
|
273
|
+
const chaindata = useChaindata();
|
|
274
|
+
|
|
275
|
+
// substrate connector
|
|
276
|
+
const [substrate, setSubstrate] = react.useState();
|
|
277
|
+
react.useEffect(() => {
|
|
278
|
+
if (!chaindata) return;
|
|
279
|
+
setSubstrate(new chainConnector.ChainConnector(chaindata));
|
|
280
|
+
}, [chaindata]);
|
|
281
|
+
|
|
282
|
+
// evm connector
|
|
283
|
+
const [evm, setEvm] = react.useState();
|
|
284
|
+
react.useEffect(() => {
|
|
285
|
+
if (!chaindata) return;
|
|
286
|
+
setEvm(new chainConnectorEvm.ChainConnectorEvm(chaindata, {
|
|
287
|
+
onfinalityApiKey: options.onfinalityApiKey
|
|
288
|
+
}));
|
|
289
|
+
}, [chaindata, options.onfinalityApiKey]);
|
|
290
|
+
return react.useMemo(() => ({
|
|
291
|
+
substrate,
|
|
292
|
+
evm
|
|
293
|
+
}), [substrate, evm]);
|
|
294
|
+
}
|
|
295
|
+
const [ChainConnectorsProvider, useChainConnectors] = provideContext(useChainConnectorsProvider);
|
|
296
|
+
|
|
297
|
+
const useSubscriptionsProvider = () => [useSubscribeChaindataHydrate("chains"), useSubscribeChaindataHydrate("evmNetworks"), useSubscribeChaindataHydrate("tokens"), useSubscribeTokenRates(), useSubscribeBalances()];
|
|
298
|
+
const [SubscriptionsProvider, useSubscriptions] = provideContext(useSubscriptionsProvider);
|
|
371
299
|
|
|
372
300
|
/**
|
|
373
301
|
* This hook is responsible for fetching the data used for balances and inserting it into the db.
|
|
374
302
|
*/
|
|
375
303
|
const useDbCacheSubscription = subscribeTo => {
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
// can't handle balances & tokenRates here as they have other dependencies, it would trigger to many subscriptions
|
|
379
|
-
const subscribe = react.useCallback(() => {
|
|
304
|
+
const [subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances] = useSubscriptions();
|
|
305
|
+
react.useEffect(() => {
|
|
380
306
|
switch (subscribeTo) {
|
|
381
307
|
case "chains":
|
|
382
|
-
return
|
|
308
|
+
return subscribeHydrateChains();
|
|
383
309
|
case "evmNetworks":
|
|
384
|
-
return
|
|
310
|
+
return subscribeHydrateEvmNetworks();
|
|
385
311
|
case "tokens":
|
|
386
|
-
return
|
|
312
|
+
return subscribeHydrateTokens();
|
|
313
|
+
case "tokenRates":
|
|
314
|
+
return subscribeTokenRates();
|
|
315
|
+
case "balances":
|
|
316
|
+
return subscribeBalances();
|
|
387
317
|
}
|
|
388
|
-
}, [
|
|
389
|
-
useSharedSubscription(subscribeTo, subscribe);
|
|
318
|
+
}, [subscribeTo, subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances]);
|
|
390
319
|
};
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
320
|
+
function useSubscribeChaindataHydrate(type) {
|
|
321
|
+
const chaindata =
|
|
322
|
+
// cheeky hack to give us access to the hydrate methods
|
|
323
|
+
useChaindata();
|
|
324
|
+
const createSubscription = react.useCallback(() => {
|
|
325
|
+
if (!chaindata) return;
|
|
326
|
+
let active = true;
|
|
327
|
+
const interval = 300_000; // 300_000ms = 300s = 5 minutes
|
|
328
|
+
|
|
329
|
+
const hydrate = async () => {
|
|
330
|
+
if (!active) return;
|
|
331
|
+
try {
|
|
332
|
+
if (type === "chains") await chaindata.hydrateChains();
|
|
333
|
+
if (type === "evmNetworks") await chaindata.hydrateEvmNetworks();
|
|
334
|
+
if (type === "tokens") await chaindata.hydrateTokens();
|
|
335
|
+
setTimeout(hydrate, interval);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
const retryTimeout = 5_000; // 5_000ms = 5 seconds
|
|
338
|
+
log.error(`Failed to fetch chaindata, retrying in ${Math.round(retryTimeout / 1000)} seconds`, error);
|
|
339
|
+
setTimeout(hydrate, retryTimeout);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
hydrate();
|
|
343
|
+
return () => {
|
|
344
|
+
active = false;
|
|
345
|
+
};
|
|
346
|
+
}, [chaindata, type]);
|
|
347
|
+
const subscribe = useMulticastSubscription(createSubscription);
|
|
348
|
+
return subscribe;
|
|
413
349
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
350
|
+
function useSubscribeTokenRates() {
|
|
351
|
+
const chaindataProvider = useChaindata();
|
|
352
|
+
const tokens = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.tokens(), [chaindataProvider]);
|
|
353
|
+
const generationRef = react.useRef(0);
|
|
354
|
+
const createSubscription = react.useCallback(() => {
|
|
355
|
+
if (!chaindataProvider) return;
|
|
356
|
+
if (!tokens) return;
|
|
357
|
+
if (Object.keys(tokens).length < 1) return;
|
|
358
|
+
|
|
359
|
+
// when we make a new request, we want to ignore any old requests which haven't yet completed
|
|
360
|
+
// otherwise we risk replacing the most recent data with older data
|
|
361
|
+
const generation = (generationRef.current + 1) % Number.MAX_SAFE_INTEGER;
|
|
362
|
+
generationRef.current = generation;
|
|
363
|
+
let active = true;
|
|
364
|
+
const REFRESH_INTERVAL = 300_000; // 300_000ms = 5 minutes
|
|
365
|
+
const RETRY_INTERVAL = 5_000; // 5_000ms = 5 seconds
|
|
366
|
+
|
|
367
|
+
const hydrate = async () => {
|
|
368
|
+
if (!active) return;
|
|
369
|
+
if (generationRef.current !== generation) return;
|
|
370
|
+
try {
|
|
371
|
+
const tokenRates$1 = await tokenRates.fetchTokenRates(tokens);
|
|
372
|
+
if (!active) return;
|
|
373
|
+
if (generationRef.current !== generation) return;
|
|
374
|
+
const putTokenRates = Object.entries(tokenRates$1).map(([tokenId, rates]) => ({
|
|
375
|
+
tokenId,
|
|
376
|
+
rates
|
|
377
|
+
}));
|
|
378
|
+
tokenRates.db.transaction("rw", tokenRates.db.tokenRates, async () => await tokenRates.db.tokenRates.bulkPut(putTokenRates));
|
|
379
|
+
setTimeout(hydrate, REFRESH_INTERVAL);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
log.error(`Failed to fetch tokenRates, retrying in ${Math.round(RETRY_INTERVAL / 1000)} seconds`, error);
|
|
382
|
+
setTimeout(hydrate, RETRY_INTERVAL);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
hydrate();
|
|
386
|
+
return () => {
|
|
387
|
+
active = false;
|
|
388
|
+
};
|
|
389
|
+
}, [chaindataProvider, tokens]);
|
|
390
|
+
const subscribe = useMulticastSubscription(createSubscription);
|
|
391
|
+
return subscribe;
|
|
392
|
+
}
|
|
393
|
+
function useSubscribeBalances() {
|
|
422
394
|
const balanceModules = useBalanceModules();
|
|
423
395
|
const chaindataProvider = useChaindata();
|
|
424
396
|
const chainConnectors = useChainConnectors();
|
|
425
397
|
const [allAddresses] = useAllAddresses();
|
|
426
|
-
const tokens =
|
|
427
|
-
const
|
|
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
|
|
444
|
-
|
|
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);
|
|
456
|
-
}
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
// launch the loop
|
|
460
|
-
hydrate();
|
|
461
|
-
return () => {
|
|
462
|
-
if (timeout) clearTimeout(timeout);
|
|
463
|
-
};
|
|
464
|
-
};
|
|
465
|
-
const subscribeTokenRates = tokens => {
|
|
466
|
-
const REFRESH_INTERVAL = 300_000; // 6 minutes
|
|
467
|
-
const RETRY_INTERVAL = 5_000; // 5 sec
|
|
468
|
-
|
|
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
|
-
};
|
|
489
|
-
|
|
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(({
|
|
398
|
+
const tokens = dexieReactHooks.useLiveQuery(() => chaindataProvider === null || chaindataProvider === void 0 ? void 0 : chaindataProvider.tokens(), [chaindataProvider]);
|
|
399
|
+
const tokenIds = react.useMemo(() => Object.values(tokens ?? {}).map(({
|
|
498
400
|
id
|
|
499
|
-
}) => id);
|
|
500
|
-
const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId,
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
401
|
+
}) => id), [tokens]);
|
|
402
|
+
const addressesByToken = react.useMemo(() => Object.fromEntries(tokenIds.map(tokenId => [tokenId, allAddresses])), [allAddresses, tokenIds]);
|
|
403
|
+
const generationRef = react.useRef(0);
|
|
404
|
+
const createSubscription = react.useCallback(() => {
|
|
405
|
+
if (!chainConnectors.substrate) return;
|
|
406
|
+
if (!chainConnectors.evm) return;
|
|
407
|
+
if (!chaindataProvider) return;
|
|
408
|
+
const generation = (generationRef.current + 1) % Number.MAX_SAFE_INTEGER;
|
|
409
|
+
generationRef.current = generation;
|
|
410
|
+
const unsubs = balanceModules.map(balanceModule => {
|
|
411
|
+
// filter out tokens to only include those which this module knows how to fetch balances for
|
|
412
|
+
const moduleTokenIds = Object.values(tokens ?? {}).filter(({
|
|
413
|
+
type
|
|
414
|
+
}) => type === balanceModule.type).map(({
|
|
415
|
+
id
|
|
416
|
+
}) => id);
|
|
417
|
+
const addressesByModuleToken = Object.fromEntries(Object.entries(addressesByToken).filter(([tokenId]) => moduleTokenIds.includes(tokenId)));
|
|
418
|
+
const subscribe = createMulticastSubscription(next => {
|
|
419
|
+
const unsub = balances.balances(balanceModule, chainConnectors, chaindataProvider, addressesByModuleToken, (error, balances) => {
|
|
420
|
+
// log errors
|
|
421
|
+
if (error) return log.error(`Failed to fetch ${balanceModule.type} balances`, error);
|
|
422
|
+
// ignore empty balance responses
|
|
423
|
+
if (!balances) return;
|
|
424
|
+
// ignore balances from old subscriptions which are still in the process of unsubscribing
|
|
425
|
+
if (generationRef.current !== generation) return;
|
|
426
|
+
next(balances);
|
|
427
|
+
});
|
|
428
|
+
return () => {
|
|
429
|
+
// unsubscribe from upstream
|
|
430
|
+
unsub.then(unsubscribe => unsubscribe());
|
|
431
|
+
|
|
432
|
+
// set this subscription's balances in the store to status: cache
|
|
433
|
+
balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.filter(balance => {
|
|
434
|
+
if (balance.source !== balanceModule.type) return false;
|
|
435
|
+
if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
|
|
436
|
+
if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
|
|
437
|
+
return true;
|
|
438
|
+
}).modify({
|
|
439
|
+
status: "cache"
|
|
440
|
+
}));
|
|
441
|
+
};
|
|
442
|
+
});
|
|
443
|
+
const unsubscribe = subscribe(balances$1 => {
|
|
444
|
+
const putBalances = Object.entries(balances$1.toJSON()).map(([id, balance]) => ({
|
|
445
|
+
id,
|
|
446
|
+
...balance
|
|
447
|
+
}));
|
|
448
|
+
balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.bulkPut(putBalances));
|
|
449
|
+
});
|
|
450
|
+
return unsubscribe;
|
|
528
451
|
});
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
|
|
536
|
-
return true;
|
|
537
|
-
}).modify({
|
|
538
|
-
status: "cache"
|
|
539
|
-
}));
|
|
540
|
-
};
|
|
541
|
-
});
|
|
542
|
-
const unsubscribeAll = () => {
|
|
543
|
-
unsubscribed = true;
|
|
544
|
-
unsubs.forEach(unsub => unsub.then(unsubscribe => unsubscribe()));
|
|
545
|
-
};
|
|
546
|
-
return unsubscribeAll;
|
|
547
|
-
};
|
|
452
|
+
const unsubscribeAll = () => unsubs.forEach(unsub => unsub());
|
|
453
|
+
return unsubscribeAll;
|
|
454
|
+
}, [addressesByToken, balanceModules, chainConnectors, chaindataProvider, tokens]);
|
|
455
|
+
const subscribe = useMulticastSubscription(createSubscription);
|
|
456
|
+
return subscribe;
|
|
457
|
+
}
|
|
548
458
|
|
|
549
459
|
function useChains(withTestnets) {
|
|
550
460
|
// keep db data up to date
|
|
@@ -576,7 +486,7 @@ function useEvmNetwork(evmNetworkId, withTestnets) {
|
|
|
576
486
|
|
|
577
487
|
function useTokenRates() {
|
|
578
488
|
// keep db data up to date
|
|
579
|
-
|
|
489
|
+
useDbCacheSubscription("tokenRates");
|
|
580
490
|
const {
|
|
581
491
|
tokenRatesMap
|
|
582
492
|
} = useDbCache();
|
|
@@ -587,10 +497,21 @@ function useTokenRate(tokenId) {
|
|
|
587
497
|
return tokenId ? tokenRates[tokenId] : undefined;
|
|
588
498
|
}
|
|
589
499
|
|
|
590
|
-
|
|
500
|
+
function useTokens(withTestnets) {
|
|
501
|
+
// keep db data up to date
|
|
502
|
+
useDbCacheSubscription("tokens");
|
|
591
503
|
const {
|
|
592
|
-
|
|
593
|
-
|
|
504
|
+
tokensWithTestnetsMap,
|
|
505
|
+
tokensWithoutTestnetsMap
|
|
506
|
+
} = useDbCache();
|
|
507
|
+
return withTestnets ? tokensWithTestnetsMap : tokensWithoutTestnetsMap;
|
|
508
|
+
}
|
|
509
|
+
function useToken(tokenId, withTestnets) {
|
|
510
|
+
const tokens = useTokens(withTestnets);
|
|
511
|
+
return tokenId ? tokens[tokenId] : undefined;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const useBalancesHydrate = withTestnets => {
|
|
594
515
|
const chains = useChains(withTestnets);
|
|
595
516
|
const evmNetworks = useEvmNetworks(withTestnets);
|
|
596
517
|
const tokens = useTokens(withTestnets);
|
|
@@ -605,7 +526,7 @@ const useBalancesHydrate = () => {
|
|
|
605
526
|
|
|
606
527
|
function useBalances(addressesByToken) {
|
|
607
528
|
// keep db data up to date
|
|
608
|
-
|
|
529
|
+
useDbCacheSubscription("balances");
|
|
609
530
|
const balanceModules = useBalanceModules();
|
|
610
531
|
const {
|
|
611
532
|
balances: balances$1
|
|
@@ -636,18 +557,18 @@ function useBalances(addressesByToken) {
|
|
|
636
557
|
const BalancesProvider = ({
|
|
637
558
|
balanceModules,
|
|
638
559
|
onfinalityApiKey,
|
|
639
|
-
|
|
560
|
+
useTestnets,
|
|
640
561
|
children
|
|
641
|
-
}) => /*#__PURE__*/jsxRuntime.jsx(
|
|
642
|
-
|
|
643
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
562
|
+
}) => /*#__PURE__*/jsxRuntime.jsx(ChaindataProvider, {
|
|
563
|
+
onfinalityApiKey: onfinalityApiKey,
|
|
564
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ChainConnectorsProvider, {
|
|
644
565
|
onfinalityApiKey: onfinalityApiKey,
|
|
645
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
649
|
-
|
|
650
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
566
|
+
children: /*#__PURE__*/jsxRuntime.jsx(AllAddressesProvider, {
|
|
567
|
+
children: /*#__PURE__*/jsxRuntime.jsx(BalanceModulesProvider, {
|
|
568
|
+
balanceModules: balanceModules,
|
|
569
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DbCacheProvider, {
|
|
570
|
+
useTestnets: useTestnets,
|
|
571
|
+
children: /*#__PURE__*/jsxRuntime.jsx(SubscriptionsProvider, {
|
|
651
572
|
children: children
|
|
652
573
|
})
|
|
653
574
|
})
|
|
@@ -662,7 +583,7 @@ exports.BalancesProvider = BalancesProvider;
|
|
|
662
583
|
exports.ChainConnectorsProvider = ChainConnectorsProvider;
|
|
663
584
|
exports.ChaindataProvider = ChaindataProvider;
|
|
664
585
|
exports.DbCacheProvider = DbCacheProvider;
|
|
665
|
-
exports.
|
|
586
|
+
exports.SubscriptionsProvider = SubscriptionsProvider;
|
|
666
587
|
exports.createMulticastSubscription = createMulticastSubscription;
|
|
667
588
|
exports.provideContext = provideContext;
|
|
668
589
|
exports.useAllAddresses = useAllAddresses;
|
|
@@ -674,14 +595,12 @@ exports.useChainConnectors = useChainConnectors;
|
|
|
674
595
|
exports.useChaindata = useChaindata;
|
|
675
596
|
exports.useChains = useChains;
|
|
676
597
|
exports.useDbCache = useDbCache;
|
|
677
|
-
exports.useDbCacheBalancesSubscription = useDbCacheBalancesSubscription;
|
|
678
598
|
exports.useDbCacheSubscription = useDbCacheSubscription;
|
|
679
|
-
exports.useDbCacheTokenRatesSubscription = useDbCacheTokenRatesSubscription;
|
|
680
599
|
exports.useEvmNetwork = useEvmNetwork;
|
|
681
600
|
exports.useEvmNetworks = useEvmNetworks;
|
|
682
601
|
exports.useMulticastSubscription = useMulticastSubscription;
|
|
602
|
+
exports.useSubscriptions = useSubscriptions;
|
|
683
603
|
exports.useToken = useToken;
|
|
684
604
|
exports.useTokenRate = useTokenRate;
|
|
685
605
|
exports.useTokenRates = useTokenRates;
|
|
686
606
|
exports.useTokens = useTokens;
|
|
687
|
-
exports.useWithTestnets = useWithTestnets;
|