@talismn/balances-react 0.0.0-pr587-20230302015709 → 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 -292
- package/dist/talismn-balances-react.cjs.prod.js +209 -292
- package/dist/talismn-balances-react.esm.js +210 -290
- 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,193 +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
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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
|
+
};
|
|
533
442
|
});
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
};
|
|
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;
|
|
451
|
+
});
|
|
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
|
+
}
|
|
550
458
|
|
|
551
459
|
function useChains(withTestnets) {
|
|
552
460
|
// keep db data up to date
|
|
@@ -578,7 +486,7 @@ function useEvmNetwork(evmNetworkId, withTestnets) {
|
|
|
578
486
|
|
|
579
487
|
function useTokenRates() {
|
|
580
488
|
// keep db data up to date
|
|
581
|
-
|
|
489
|
+
useDbCacheSubscription("tokenRates");
|
|
582
490
|
const {
|
|
583
491
|
tokenRatesMap
|
|
584
492
|
} = useDbCache();
|
|
@@ -589,10 +497,21 @@ function useTokenRate(tokenId) {
|
|
|
589
497
|
return tokenId ? tokenRates[tokenId] : undefined;
|
|
590
498
|
}
|
|
591
499
|
|
|
592
|
-
|
|
500
|
+
function useTokens(withTestnets) {
|
|
501
|
+
// keep db data up to date
|
|
502
|
+
useDbCacheSubscription("tokens");
|
|
593
503
|
const {
|
|
594
|
-
|
|
595
|
-
|
|
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 => {
|
|
596
515
|
const chains = useChains(withTestnets);
|
|
597
516
|
const evmNetworks = useEvmNetworks(withTestnets);
|
|
598
517
|
const tokens = useTokens(withTestnets);
|
|
@@ -607,7 +526,7 @@ const useBalancesHydrate = () => {
|
|
|
607
526
|
|
|
608
527
|
function useBalances(addressesByToken) {
|
|
609
528
|
// keep db data up to date
|
|
610
|
-
|
|
529
|
+
useDbCacheSubscription("balances");
|
|
611
530
|
const balanceModules = useBalanceModules();
|
|
612
531
|
const {
|
|
613
532
|
balances: balances$1
|
|
@@ -638,18 +557,18 @@ function useBalances(addressesByToken) {
|
|
|
638
557
|
const BalancesProvider = ({
|
|
639
558
|
balanceModules,
|
|
640
559
|
onfinalityApiKey,
|
|
641
|
-
|
|
560
|
+
useTestnets,
|
|
642
561
|
children
|
|
643
|
-
}) => /*#__PURE__*/jsxRuntime.jsx(
|
|
644
|
-
|
|
645
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
562
|
+
}) => /*#__PURE__*/jsxRuntime.jsx(ChaindataProvider, {
|
|
563
|
+
onfinalityApiKey: onfinalityApiKey,
|
|
564
|
+
children: /*#__PURE__*/jsxRuntime.jsx(ChainConnectorsProvider, {
|
|
646
565
|
onfinalityApiKey: onfinalityApiKey,
|
|
647
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
children: /*#__PURE__*/jsxRuntime.jsx(
|
|
651
|
-
|
|
652
|
-
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, {
|
|
653
572
|
children: children
|
|
654
573
|
})
|
|
655
574
|
})
|
|
@@ -664,7 +583,7 @@ exports.BalancesProvider = BalancesProvider;
|
|
|
664
583
|
exports.ChainConnectorsProvider = ChainConnectorsProvider;
|
|
665
584
|
exports.ChaindataProvider = ChaindataProvider;
|
|
666
585
|
exports.DbCacheProvider = DbCacheProvider;
|
|
667
|
-
exports.
|
|
586
|
+
exports.SubscriptionsProvider = SubscriptionsProvider;
|
|
668
587
|
exports.createMulticastSubscription = createMulticastSubscription;
|
|
669
588
|
exports.provideContext = provideContext;
|
|
670
589
|
exports.useAllAddresses = useAllAddresses;
|
|
@@ -676,14 +595,12 @@ exports.useChainConnectors = useChainConnectors;
|
|
|
676
595
|
exports.useChaindata = useChaindata;
|
|
677
596
|
exports.useChains = useChains;
|
|
678
597
|
exports.useDbCache = useDbCache;
|
|
679
|
-
exports.useDbCacheBalancesSubscription = useDbCacheBalancesSubscription;
|
|
680
598
|
exports.useDbCacheSubscription = useDbCacheSubscription;
|
|
681
|
-
exports.useDbCacheTokenRatesSubscription = useDbCacheTokenRatesSubscription;
|
|
682
599
|
exports.useEvmNetwork = useEvmNetwork;
|
|
683
600
|
exports.useEvmNetworks = useEvmNetworks;
|
|
684
601
|
exports.useMulticastSubscription = useMulticastSubscription;
|
|
602
|
+
exports.useSubscriptions = useSubscriptions;
|
|
685
603
|
exports.useToken = useToken;
|
|
686
604
|
exports.useTokenRate = useTokenRate;
|
|
687
605
|
exports.useTokenRates = useTokenRates;
|
|
688
606
|
exports.useTokens = useTokens;
|
|
689
|
-
exports.useWithTestnets = useWithTestnets;
|