@talismn/balances-react 0.0.0-pr563-20230221230003 → 0.0.0-pr563-20230222052739
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 +5 -2
- package/dist/declarations/src/hooks/useDbCache.d.ts +1 -1
- package/dist/declarations/src/hooks/useDbCacheSubscription.d.ts +1 -1
- package/dist/declarations/src/hooks/useTokenRates.d.ts +3 -3
- package/dist/talismn-balances-react.cjs.dev.js +81 -49
- package/dist/talismn-balances-react.cjs.prod.js +81 -49
- package/dist/talismn-balances-react.esm.js +83 -52
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# @talismn/balances-react
|
|
2
2
|
|
|
3
|
-
## 0.0.0-pr563-
|
|
3
|
+
## 0.0.0-pr563-20230222052739
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
+
- 5ddeee95: fix: tokenRates in @talismn/balances-react
|
|
7
8
|
- 536eddb5: fix: ported useDbCache related perf fixes to @talismn/balances-react
|
|
9
|
+
- Updated dependencies [5ddeee95]
|
|
8
10
|
- Updated dependencies [536eddb5]
|
|
9
|
-
- @talismn/
|
|
11
|
+
- @talismn/token-rates@0.0.0-pr563-20230222052739
|
|
12
|
+
- @talismn/balances@0.0.0-pr563-20230222052739
|
|
10
13
|
|
|
11
14
|
## 0.3.3
|
|
12
15
|
|
|
@@ -15,8 +15,8 @@ type DbCache = {
|
|
|
15
15
|
evmNetworksWithoutTestnetsMap: Record<EvmNetworkId, EvmNetwork | CustomEvmNetwork>;
|
|
16
16
|
tokensWithTestnetsMap: Record<TokenId, Token>;
|
|
17
17
|
tokensWithoutTestnetsMap: Record<TokenId, Token>;
|
|
18
|
-
balances: BalanceJson[];
|
|
19
18
|
tokenRatesMap: Record<TokenId, TokenRates>;
|
|
19
|
+
balances: BalanceJson[];
|
|
20
20
|
};
|
|
21
21
|
type DbCacheProviderProps = {
|
|
22
22
|
useTestnets?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
export type DbEntityType = "chains" | "evmNetworks" | "tokens" | "balances";
|
|
2
|
+
export type DbEntityType = "chains" | "evmNetworks" | "tokens" | "tokenRates" | "balances";
|
|
3
3
|
export declare const SubscriptionsProvider: import("react").FC<{
|
|
4
4
|
children?: import("react").ReactNode;
|
|
5
5
|
}>, useSubscriptions: () => ((callback?: ((val: unknown) => void) | undefined) => import("../util").Unsubscribe)[];
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export declare function
|
|
1
|
+
import { TokenId } from "@talismn/chaindata-provider";
|
|
2
|
+
export declare function useTokenRates(): Record<string, import("@talismn/token-rates").TokenRates>;
|
|
3
|
+
export declare function useTokenRate(tokenId?: TokenId): import("@talismn/token-rates").TokenRates | undefined;
|
|
@@ -5,10 +5,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var balances = require('@talismn/balances');
|
|
8
|
+
var tokenRates = require('@talismn/token-rates');
|
|
8
9
|
var dexieReactHooks = require('dexie-react-hooks');
|
|
9
10
|
var reactUse = require('react-use');
|
|
10
11
|
var chaindataProviderExtension = require('@talismn/chaindata-provider-extension');
|
|
11
|
-
var tokenRates = require('@talismn/token-rates');
|
|
12
12
|
var anylogger = require('anylogger');
|
|
13
13
|
var rxjs = require('rxjs');
|
|
14
14
|
var chainConnector = require('@talismn/chain-connector');
|
|
@@ -62,25 +62,6 @@ function useChaindataProvider(options = {}) {
|
|
|
62
62
|
}
|
|
63
63
|
const [ChaindataProvider, useChaindata] = provideContext(useChaindataProvider);
|
|
64
64
|
|
|
65
|
-
function useTokenRates(tokens) {
|
|
66
|
-
const generation = react.useRef(0);
|
|
67
|
-
const [tokenRates$1, setTokenRates] = react.useState({});
|
|
68
|
-
react.useEffect(() => {
|
|
69
|
-
if (!tokens) return;
|
|
70
|
-
if (Object.keys(tokens).length < 1) return;
|
|
71
|
-
|
|
72
|
-
// when we make a new request, we want to ignore any old requests which haven't yet completed
|
|
73
|
-
// otherwise we risk replacing the most recent data with older data
|
|
74
|
-
generation.current = (generation.current + 1) % Number.MAX_SAFE_INTEGER;
|
|
75
|
-
const thisGeneration = generation.current;
|
|
76
|
-
tokenRates.fetchTokenRates(tokens).then(tokenRates => {
|
|
77
|
-
if (thisGeneration !== generation.current) return;
|
|
78
|
-
setTokenRates(tokenRates);
|
|
79
|
-
});
|
|
80
|
-
}, [tokens]);
|
|
81
|
-
return tokenRates$1;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
65
|
const filterNoTestnet = ({
|
|
85
66
|
isTestnet
|
|
86
67
|
}) => isTestnet === false;
|
|
@@ -97,13 +78,11 @@ const DEFAULT_VALUE = {
|
|
|
97
78
|
evmNetworksWithoutTestnetsMap: {},
|
|
98
79
|
tokensWithTestnetsMap: {},
|
|
99
80
|
tokensWithoutTestnetsMap: {},
|
|
100
|
-
|
|
101
|
-
|
|
81
|
+
tokenRatesMap: {},
|
|
82
|
+
balances: []
|
|
102
83
|
};
|
|
103
|
-
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap,
|
|
104
|
-
if (!chainsMap || !evmNetworksMap || !tokensMap || !allBalances
|
|
105
|
-
// TODO: Store tokenRates in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
106
|
-
/* || !tokenRates */) return DEFAULT_VALUE;
|
|
84
|
+
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
|
|
85
|
+
if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
|
|
107
86
|
|
|
108
87
|
// BEGIN: temp hack to indicate that
|
|
109
88
|
// - EVM GLMR is a mirror of substrate GLMR
|
|
@@ -131,6 +110,10 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, allBalances, t
|
|
|
131
110
|
const tokensWithoutTestnets = tokensWithTestnets.filter(filterNoTestnet).filter(token => token.chain && chainsWithoutTestnetsMap[token.chain.id] || token.evmNetwork && evmNetworksWithoutTestnetsMap[token.evmNetwork.id]);
|
|
132
111
|
const tokensWithTestnetsMap = Object.fromEntries(tokensWithTestnets.map(token => [token.id, token]));
|
|
133
112
|
const tokensWithoutTestnetsMap = Object.fromEntries(tokensWithoutTestnets.map(token => [token.id, token]));
|
|
113
|
+
const tokenRatesMap = Object.fromEntries(tokenRates.map(({
|
|
114
|
+
tokenId,
|
|
115
|
+
rates
|
|
116
|
+
}) => [tokenId, rates]));
|
|
134
117
|
|
|
135
118
|
// return only balances for which we have a token
|
|
136
119
|
const balances = allBalances.filter(b => tokensWithTestnetsMap[b.tokenId]);
|
|
@@ -147,8 +130,8 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, allBalances, t
|
|
|
147
130
|
evmNetworksWithoutTestnetsMap,
|
|
148
131
|
tokensWithTestnetsMap,
|
|
149
132
|
tokensWithoutTestnetsMap,
|
|
150
|
-
|
|
151
|
-
|
|
133
|
+
tokenRatesMap,
|
|
134
|
+
balances
|
|
152
135
|
};
|
|
153
136
|
};
|
|
154
137
|
const useDbCacheProvider = ({
|
|
@@ -158,35 +141,30 @@ const useDbCacheProvider = ({
|
|
|
158
141
|
const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.chains(), [chaindataProvider]);
|
|
159
142
|
const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.evmNetworks(), [chaindataProvider]);
|
|
160
143
|
const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
|
|
144
|
+
const tokenRates$1 = dexieReactHooks.useLiveQuery(() => tokenRates.db.tokenRates.toArray(), []);
|
|
161
145
|
const rawBalances = dexieReactHooks.useLiveQuery(() => balances.db.balances.toArray(), []);
|
|
162
|
-
|
|
163
|
-
// TODO: Store in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
164
|
-
const tokenRates = useTokenRates();
|
|
165
146
|
const [dbData, setDbData] = react.useState(DEFAULT_VALUE);
|
|
166
147
|
|
|
167
148
|
// debounce every 500ms to prevent hammering UI with updates
|
|
168
149
|
reactUse.useDebounce(() => {
|
|
169
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList,
|
|
170
|
-
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates, useTestnets]);
|
|
150
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
151
|
+
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates$1, useTestnets]);
|
|
171
152
|
const refInitialized = react.useRef(false);
|
|
172
153
|
|
|
173
154
|
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
174
155
|
react.useEffect(() => {
|
|
175
|
-
if (!refInitialized.current && chainList && evmNetworkList && tokenList && rawBalances
|
|
176
|
-
|
|
177
|
-
// && tokenRates
|
|
178
|
-
) {
|
|
179
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, rawBalances, tokenRates));
|
|
156
|
+
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates$1 && rawBalances) {
|
|
157
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
180
158
|
refInitialized.current = true;
|
|
181
159
|
}
|
|
182
|
-
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates, useTestnets]);
|
|
160
|
+
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates$1, useTestnets]);
|
|
183
161
|
return dbData;
|
|
184
162
|
};
|
|
185
163
|
const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
186
164
|
|
|
187
165
|
var packageJson = {
|
|
188
166
|
name: "@talismn/balances-react",
|
|
189
|
-
version: "0.0.0-pr563-
|
|
167
|
+
version: "0.0.0-pr563-20230222052739",
|
|
190
168
|
author: "Talisman",
|
|
191
169
|
homepage: "https://talisman.xyz",
|
|
192
170
|
license: "UNLICENSED",
|
|
@@ -316,14 +294,14 @@ function useChainConnectorsProvider(options) {
|
|
|
316
294
|
}
|
|
317
295
|
const [ChainConnectorsProvider, useChainConnectors] = provideContext(useChainConnectorsProvider);
|
|
318
296
|
|
|
319
|
-
const useSubscriptionsProvider = () => [useSubscribeChaindataHydrate("chains"), useSubscribeChaindataHydrate("evmNetworks"), useSubscribeChaindataHydrate("tokens"), useSubscribeBalances()];
|
|
297
|
+
const useSubscriptionsProvider = () => [useSubscribeChaindataHydrate("chains"), useSubscribeChaindataHydrate("evmNetworks"), useSubscribeChaindataHydrate("tokens"), useSubscribeTokenRates(), useSubscribeBalances()];
|
|
320
298
|
const [SubscriptionsProvider, useSubscriptions] = provideContext(useSubscriptionsProvider);
|
|
321
299
|
|
|
322
300
|
/**
|
|
323
301
|
* This hook is responsible for fetching the data used for balances and inserting it into the db.
|
|
324
302
|
*/
|
|
325
303
|
const useDbCacheSubscription = subscribeTo => {
|
|
326
|
-
const [subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeBalances] = useSubscriptions();
|
|
304
|
+
const [subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances] = useSubscriptions();
|
|
327
305
|
react.useEffect(() => {
|
|
328
306
|
switch (subscribeTo) {
|
|
329
307
|
case "chains":
|
|
@@ -332,10 +310,12 @@ const useDbCacheSubscription = subscribeTo => {
|
|
|
332
310
|
return subscribeHydrateEvmNetworks();
|
|
333
311
|
case "tokens":
|
|
334
312
|
return subscribeHydrateTokens();
|
|
313
|
+
case "tokenRates":
|
|
314
|
+
return subscribeTokenRates();
|
|
335
315
|
case "balances":
|
|
336
316
|
return subscribeBalances();
|
|
337
317
|
}
|
|
338
|
-
}, [
|
|
318
|
+
}, [subscribeTo, subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances]);
|
|
339
319
|
};
|
|
340
320
|
function useSubscribeChaindataHydrate(type) {
|
|
341
321
|
const chaindata =
|
|
@@ -367,6 +347,49 @@ function useSubscribeChaindataHydrate(type) {
|
|
|
367
347
|
const subscribe = useMulticastSubscription(createSubscription);
|
|
368
348
|
return subscribe;
|
|
369
349
|
}
|
|
350
|
+
function useSubscribeTokenRates() {
|
|
351
|
+
const chaindataProvider = useChaindata();
|
|
352
|
+
const tokens = dexieReactHooks.useLiveQuery(() => 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
|
+
}
|
|
370
393
|
function useSubscribeBalances() {
|
|
371
394
|
const balanceModules = useBalanceModules();
|
|
372
395
|
const chaindataProvider = useChaindata();
|
|
@@ -461,6 +484,19 @@ function useEvmNetwork(evmNetworkId, withTestnets) {
|
|
|
461
484
|
return evmNetworkId ? evmNetworks[evmNetworkId] : undefined;
|
|
462
485
|
}
|
|
463
486
|
|
|
487
|
+
function useTokenRates() {
|
|
488
|
+
// keep db data up to date
|
|
489
|
+
useDbCacheSubscription("tokenRates");
|
|
490
|
+
const {
|
|
491
|
+
tokenRatesMap
|
|
492
|
+
} = useDbCache();
|
|
493
|
+
return tokenRatesMap;
|
|
494
|
+
}
|
|
495
|
+
function useTokenRate(tokenId) {
|
|
496
|
+
const tokenRates = useTokenRates();
|
|
497
|
+
return tokenId ? tokenRates[tokenId] : undefined;
|
|
498
|
+
}
|
|
499
|
+
|
|
464
500
|
function useTokens(withTestnets) {
|
|
465
501
|
// keep db data up to date
|
|
466
502
|
useDbCacheSubscription("tokens");
|
|
@@ -479,12 +515,7 @@ const useBalancesHydrate = withTestnets => {
|
|
|
479
515
|
const chains = useChains(withTestnets);
|
|
480
516
|
const evmNetworks = useEvmNetworks(withTestnets);
|
|
481
517
|
const tokens = useTokens(withTestnets);
|
|
482
|
-
|
|
483
|
-
// TODO: Store in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
484
|
-
// useDbCacheSubscription("tokenRates")
|
|
485
|
-
const {
|
|
486
|
-
tokenRatesMap: tokenRates
|
|
487
|
-
} = useDbCache();
|
|
518
|
+
const tokenRates = useTokenRates();
|
|
488
519
|
return react.useMemo(() => ({
|
|
489
520
|
chains,
|
|
490
521
|
evmNetworks,
|
|
@@ -570,5 +601,6 @@ exports.useEvmNetworks = useEvmNetworks;
|
|
|
570
601
|
exports.useMulticastSubscription = useMulticastSubscription;
|
|
571
602
|
exports.useSubscriptions = useSubscriptions;
|
|
572
603
|
exports.useToken = useToken;
|
|
604
|
+
exports.useTokenRate = useTokenRate;
|
|
573
605
|
exports.useTokenRates = useTokenRates;
|
|
574
606
|
exports.useTokens = useTokens;
|
|
@@ -5,10 +5,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var balances = require('@talismn/balances');
|
|
8
|
+
var tokenRates = require('@talismn/token-rates');
|
|
8
9
|
var dexieReactHooks = require('dexie-react-hooks');
|
|
9
10
|
var reactUse = require('react-use');
|
|
10
11
|
var chaindataProviderExtension = require('@talismn/chaindata-provider-extension');
|
|
11
|
-
var tokenRates = require('@talismn/token-rates');
|
|
12
12
|
var anylogger = require('anylogger');
|
|
13
13
|
var rxjs = require('rxjs');
|
|
14
14
|
var chainConnector = require('@talismn/chain-connector');
|
|
@@ -62,25 +62,6 @@ function useChaindataProvider(options = {}) {
|
|
|
62
62
|
}
|
|
63
63
|
const [ChaindataProvider, useChaindata] = provideContext(useChaindataProvider);
|
|
64
64
|
|
|
65
|
-
function useTokenRates(tokens) {
|
|
66
|
-
const generation = react.useRef(0);
|
|
67
|
-
const [tokenRates$1, setTokenRates] = react.useState({});
|
|
68
|
-
react.useEffect(() => {
|
|
69
|
-
if (!tokens) return;
|
|
70
|
-
if (Object.keys(tokens).length < 1) return;
|
|
71
|
-
|
|
72
|
-
// when we make a new request, we want to ignore any old requests which haven't yet completed
|
|
73
|
-
// otherwise we risk replacing the most recent data with older data
|
|
74
|
-
generation.current = (generation.current + 1) % Number.MAX_SAFE_INTEGER;
|
|
75
|
-
const thisGeneration = generation.current;
|
|
76
|
-
tokenRates.fetchTokenRates(tokens).then(tokenRates => {
|
|
77
|
-
if (thisGeneration !== generation.current) return;
|
|
78
|
-
setTokenRates(tokenRates);
|
|
79
|
-
});
|
|
80
|
-
}, [tokens]);
|
|
81
|
-
return tokenRates$1;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
65
|
const filterNoTestnet = ({
|
|
85
66
|
isTestnet
|
|
86
67
|
}) => isTestnet === false;
|
|
@@ -97,13 +78,11 @@ const DEFAULT_VALUE = {
|
|
|
97
78
|
evmNetworksWithoutTestnetsMap: {},
|
|
98
79
|
tokensWithTestnetsMap: {},
|
|
99
80
|
tokensWithoutTestnetsMap: {},
|
|
100
|
-
|
|
101
|
-
|
|
81
|
+
tokenRatesMap: {},
|
|
82
|
+
balances: []
|
|
102
83
|
};
|
|
103
|
-
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap,
|
|
104
|
-
if (!chainsMap || !evmNetworksMap || !tokensMap || !allBalances
|
|
105
|
-
// TODO: Store tokenRates in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
106
|
-
/* || !tokenRates */) return DEFAULT_VALUE;
|
|
84
|
+
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
|
|
85
|
+
if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
|
|
107
86
|
|
|
108
87
|
// BEGIN: temp hack to indicate that
|
|
109
88
|
// - EVM GLMR is a mirror of substrate GLMR
|
|
@@ -131,6 +110,10 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, allBalances, t
|
|
|
131
110
|
const tokensWithoutTestnets = tokensWithTestnets.filter(filterNoTestnet).filter(token => token.chain && chainsWithoutTestnetsMap[token.chain.id] || token.evmNetwork && evmNetworksWithoutTestnetsMap[token.evmNetwork.id]);
|
|
132
111
|
const tokensWithTestnetsMap = Object.fromEntries(tokensWithTestnets.map(token => [token.id, token]));
|
|
133
112
|
const tokensWithoutTestnetsMap = Object.fromEntries(tokensWithoutTestnets.map(token => [token.id, token]));
|
|
113
|
+
const tokenRatesMap = Object.fromEntries(tokenRates.map(({
|
|
114
|
+
tokenId,
|
|
115
|
+
rates
|
|
116
|
+
}) => [tokenId, rates]));
|
|
134
117
|
|
|
135
118
|
// return only balances for which we have a token
|
|
136
119
|
const balances = allBalances.filter(b => tokensWithTestnetsMap[b.tokenId]);
|
|
@@ -147,8 +130,8 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, allBalances, t
|
|
|
147
130
|
evmNetworksWithoutTestnetsMap,
|
|
148
131
|
tokensWithTestnetsMap,
|
|
149
132
|
tokensWithoutTestnetsMap,
|
|
150
|
-
|
|
151
|
-
|
|
133
|
+
tokenRatesMap,
|
|
134
|
+
balances
|
|
152
135
|
};
|
|
153
136
|
};
|
|
154
137
|
const useDbCacheProvider = ({
|
|
@@ -158,35 +141,30 @@ const useDbCacheProvider = ({
|
|
|
158
141
|
const chainList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.chains(), [chaindataProvider]);
|
|
159
142
|
const evmNetworkList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.evmNetworks(), [chaindataProvider]);
|
|
160
143
|
const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
|
|
144
|
+
const tokenRates$1 = dexieReactHooks.useLiveQuery(() => tokenRates.db.tokenRates.toArray(), []);
|
|
161
145
|
const rawBalances = dexieReactHooks.useLiveQuery(() => balances.db.balances.toArray(), []);
|
|
162
|
-
|
|
163
|
-
// TODO: Store in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
164
|
-
const tokenRates = useTokenRates();
|
|
165
146
|
const [dbData, setDbData] = react.useState(DEFAULT_VALUE);
|
|
166
147
|
|
|
167
148
|
// debounce every 500ms to prevent hammering UI with updates
|
|
168
149
|
reactUse.useDebounce(() => {
|
|
169
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList,
|
|
170
|
-
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates, useTestnets]);
|
|
150
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
151
|
+
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates$1, useTestnets]);
|
|
171
152
|
const refInitialized = react.useRef(false);
|
|
172
153
|
|
|
173
154
|
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
174
155
|
react.useEffect(() => {
|
|
175
|
-
if (!refInitialized.current && chainList && evmNetworkList && tokenList && rawBalances
|
|
176
|
-
|
|
177
|
-
// && tokenRates
|
|
178
|
-
) {
|
|
179
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, rawBalances, tokenRates));
|
|
156
|
+
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates$1 && rawBalances) {
|
|
157
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
180
158
|
refInitialized.current = true;
|
|
181
159
|
}
|
|
182
|
-
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates, useTestnets]);
|
|
160
|
+
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates$1, useTestnets]);
|
|
183
161
|
return dbData;
|
|
184
162
|
};
|
|
185
163
|
const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
186
164
|
|
|
187
165
|
var packageJson = {
|
|
188
166
|
name: "@talismn/balances-react",
|
|
189
|
-
version: "0.0.0-pr563-
|
|
167
|
+
version: "0.0.0-pr563-20230222052739",
|
|
190
168
|
author: "Talisman",
|
|
191
169
|
homepage: "https://talisman.xyz",
|
|
192
170
|
license: "UNLICENSED",
|
|
@@ -316,14 +294,14 @@ function useChainConnectorsProvider(options) {
|
|
|
316
294
|
}
|
|
317
295
|
const [ChainConnectorsProvider, useChainConnectors] = provideContext(useChainConnectorsProvider);
|
|
318
296
|
|
|
319
|
-
const useSubscriptionsProvider = () => [useSubscribeChaindataHydrate("chains"), useSubscribeChaindataHydrate("evmNetworks"), useSubscribeChaindataHydrate("tokens"), useSubscribeBalances()];
|
|
297
|
+
const useSubscriptionsProvider = () => [useSubscribeChaindataHydrate("chains"), useSubscribeChaindataHydrate("evmNetworks"), useSubscribeChaindataHydrate("tokens"), useSubscribeTokenRates(), useSubscribeBalances()];
|
|
320
298
|
const [SubscriptionsProvider, useSubscriptions] = provideContext(useSubscriptionsProvider);
|
|
321
299
|
|
|
322
300
|
/**
|
|
323
301
|
* This hook is responsible for fetching the data used for balances and inserting it into the db.
|
|
324
302
|
*/
|
|
325
303
|
const useDbCacheSubscription = subscribeTo => {
|
|
326
|
-
const [subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeBalances] = useSubscriptions();
|
|
304
|
+
const [subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances] = useSubscriptions();
|
|
327
305
|
react.useEffect(() => {
|
|
328
306
|
switch (subscribeTo) {
|
|
329
307
|
case "chains":
|
|
@@ -332,10 +310,12 @@ const useDbCacheSubscription = subscribeTo => {
|
|
|
332
310
|
return subscribeHydrateEvmNetworks();
|
|
333
311
|
case "tokens":
|
|
334
312
|
return subscribeHydrateTokens();
|
|
313
|
+
case "tokenRates":
|
|
314
|
+
return subscribeTokenRates();
|
|
335
315
|
case "balances":
|
|
336
316
|
return subscribeBalances();
|
|
337
317
|
}
|
|
338
|
-
}, [
|
|
318
|
+
}, [subscribeTo, subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances]);
|
|
339
319
|
};
|
|
340
320
|
function useSubscribeChaindataHydrate(type) {
|
|
341
321
|
const chaindata =
|
|
@@ -367,6 +347,49 @@ function useSubscribeChaindataHydrate(type) {
|
|
|
367
347
|
const subscribe = useMulticastSubscription(createSubscription);
|
|
368
348
|
return subscribe;
|
|
369
349
|
}
|
|
350
|
+
function useSubscribeTokenRates() {
|
|
351
|
+
const chaindataProvider = useChaindata();
|
|
352
|
+
const tokens = dexieReactHooks.useLiveQuery(() => 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
|
+
}
|
|
370
393
|
function useSubscribeBalances() {
|
|
371
394
|
const balanceModules = useBalanceModules();
|
|
372
395
|
const chaindataProvider = useChaindata();
|
|
@@ -461,6 +484,19 @@ function useEvmNetwork(evmNetworkId, withTestnets) {
|
|
|
461
484
|
return evmNetworkId ? evmNetworks[evmNetworkId] : undefined;
|
|
462
485
|
}
|
|
463
486
|
|
|
487
|
+
function useTokenRates() {
|
|
488
|
+
// keep db data up to date
|
|
489
|
+
useDbCacheSubscription("tokenRates");
|
|
490
|
+
const {
|
|
491
|
+
tokenRatesMap
|
|
492
|
+
} = useDbCache();
|
|
493
|
+
return tokenRatesMap;
|
|
494
|
+
}
|
|
495
|
+
function useTokenRate(tokenId) {
|
|
496
|
+
const tokenRates = useTokenRates();
|
|
497
|
+
return tokenId ? tokenRates[tokenId] : undefined;
|
|
498
|
+
}
|
|
499
|
+
|
|
464
500
|
function useTokens(withTestnets) {
|
|
465
501
|
// keep db data up to date
|
|
466
502
|
useDbCacheSubscription("tokens");
|
|
@@ -479,12 +515,7 @@ const useBalancesHydrate = withTestnets => {
|
|
|
479
515
|
const chains = useChains(withTestnets);
|
|
480
516
|
const evmNetworks = useEvmNetworks(withTestnets);
|
|
481
517
|
const tokens = useTokens(withTestnets);
|
|
482
|
-
|
|
483
|
-
// TODO: Store in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
484
|
-
// useDbCacheSubscription("tokenRates")
|
|
485
|
-
const {
|
|
486
|
-
tokenRatesMap: tokenRates
|
|
487
|
-
} = useDbCache();
|
|
518
|
+
const tokenRates = useTokenRates();
|
|
488
519
|
return react.useMemo(() => ({
|
|
489
520
|
chains,
|
|
490
521
|
evmNetworks,
|
|
@@ -570,5 +601,6 @@ exports.useEvmNetworks = useEvmNetworks;
|
|
|
570
601
|
exports.useMulticastSubscription = useMulticastSubscription;
|
|
571
602
|
exports.useSubscriptions = useSubscriptions;
|
|
572
603
|
exports.useToken = useToken;
|
|
604
|
+
exports.useTokenRate = useTokenRate;
|
|
573
605
|
exports.useTokenRates = useTokenRates;
|
|
574
606
|
exports.useTokens = useTokens;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useContext, createContext, useState, useEffect, useRef, useMemo, useCallback } from 'react';
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { db, balances, Balances } from '@talismn/balances';
|
|
3
|
+
import { db as db$1, balances, Balances } from '@talismn/balances';
|
|
4
|
+
import { db, fetchTokenRates } from '@talismn/token-rates';
|
|
4
5
|
import { useLiveQuery } from 'dexie-react-hooks';
|
|
5
6
|
import { useDebounce } from 'react-use';
|
|
6
7
|
import { ChaindataProviderExtension } from '@talismn/chaindata-provider-extension';
|
|
7
|
-
import { fetchTokenRates } from '@talismn/token-rates';
|
|
8
8
|
import anylogger from 'anylogger';
|
|
9
9
|
import { Observable, defer, shareReplay } from 'rxjs';
|
|
10
10
|
import { ChainConnector } from '@talismn/chain-connector';
|
|
@@ -54,25 +54,6 @@ function useChaindataProvider(options = {}) {
|
|
|
54
54
|
}
|
|
55
55
|
const [ChaindataProvider, useChaindata] = provideContext(useChaindataProvider);
|
|
56
56
|
|
|
57
|
-
function useTokenRates(tokens) {
|
|
58
|
-
const generation = useRef(0);
|
|
59
|
-
const [tokenRates, setTokenRates] = useState({});
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (!tokens) return;
|
|
62
|
-
if (Object.keys(tokens).length < 1) return;
|
|
63
|
-
|
|
64
|
-
// when we make a new request, we want to ignore any old requests which haven't yet completed
|
|
65
|
-
// otherwise we risk replacing the most recent data with older data
|
|
66
|
-
generation.current = (generation.current + 1) % Number.MAX_SAFE_INTEGER;
|
|
67
|
-
const thisGeneration = generation.current;
|
|
68
|
-
fetchTokenRates(tokens).then(tokenRates => {
|
|
69
|
-
if (thisGeneration !== generation.current) return;
|
|
70
|
-
setTokenRates(tokenRates);
|
|
71
|
-
});
|
|
72
|
-
}, [tokens]);
|
|
73
|
-
return tokenRates;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
57
|
const filterNoTestnet = ({
|
|
77
58
|
isTestnet
|
|
78
59
|
}) => isTestnet === false;
|
|
@@ -89,13 +70,11 @@ const DEFAULT_VALUE = {
|
|
|
89
70
|
evmNetworksWithoutTestnetsMap: {},
|
|
90
71
|
tokensWithTestnetsMap: {},
|
|
91
72
|
tokensWithoutTestnetsMap: {},
|
|
92
|
-
|
|
93
|
-
|
|
73
|
+
tokenRatesMap: {},
|
|
74
|
+
balances: []
|
|
94
75
|
};
|
|
95
|
-
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap,
|
|
96
|
-
if (!chainsMap || !evmNetworksMap || !tokensMap || !allBalances
|
|
97
|
-
// TODO: Store tokenRates in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
98
|
-
/* || !tokenRates */) return DEFAULT_VALUE;
|
|
76
|
+
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
|
|
77
|
+
if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
|
|
99
78
|
|
|
100
79
|
// BEGIN: temp hack to indicate that
|
|
101
80
|
// - EVM GLMR is a mirror of substrate GLMR
|
|
@@ -123,6 +102,10 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, allBalances, t
|
|
|
123
102
|
const tokensWithoutTestnets = tokensWithTestnets.filter(filterNoTestnet).filter(token => token.chain && chainsWithoutTestnetsMap[token.chain.id] || token.evmNetwork && evmNetworksWithoutTestnetsMap[token.evmNetwork.id]);
|
|
124
103
|
const tokensWithTestnetsMap = Object.fromEntries(tokensWithTestnets.map(token => [token.id, token]));
|
|
125
104
|
const tokensWithoutTestnetsMap = Object.fromEntries(tokensWithoutTestnets.map(token => [token.id, token]));
|
|
105
|
+
const tokenRatesMap = Object.fromEntries(tokenRates.map(({
|
|
106
|
+
tokenId,
|
|
107
|
+
rates
|
|
108
|
+
}) => [tokenId, rates]));
|
|
126
109
|
|
|
127
110
|
// return only balances for which we have a token
|
|
128
111
|
const balances = allBalances.filter(b => tokensWithTestnetsMap[b.tokenId]);
|
|
@@ -139,8 +122,8 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, allBalances, t
|
|
|
139
122
|
evmNetworksWithoutTestnetsMap,
|
|
140
123
|
tokensWithTestnetsMap,
|
|
141
124
|
tokensWithoutTestnetsMap,
|
|
142
|
-
|
|
143
|
-
|
|
125
|
+
tokenRatesMap,
|
|
126
|
+
balances
|
|
144
127
|
};
|
|
145
128
|
};
|
|
146
129
|
const useDbCacheProvider = ({
|
|
@@ -150,25 +133,20 @@ const useDbCacheProvider = ({
|
|
|
150
133
|
const chainList = useLiveQuery(() => chaindataProvider?.chains(), [chaindataProvider]);
|
|
151
134
|
const evmNetworkList = useLiveQuery(() => chaindataProvider?.evmNetworks(), [chaindataProvider]);
|
|
152
135
|
const tokenList = useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
// TODO: Store in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
156
|
-
const tokenRates = useTokenRates();
|
|
136
|
+
const tokenRates = useLiveQuery(() => db.tokenRates.toArray(), []);
|
|
137
|
+
const rawBalances = useLiveQuery(() => db$1.balances.toArray(), []);
|
|
157
138
|
const [dbData, setDbData] = useState(DEFAULT_VALUE);
|
|
158
139
|
|
|
159
140
|
// debounce every 500ms to prevent hammering UI with updates
|
|
160
141
|
useDebounce(() => {
|
|
161
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList,
|
|
142
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances));
|
|
162
143
|
}, 500, [chainList, evmNetworkList, tokenList, rawBalances, tokenRates, useTestnets]);
|
|
163
144
|
const refInitialized = useRef(false);
|
|
164
145
|
|
|
165
146
|
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
166
147
|
useEffect(() => {
|
|
167
|
-
if (!refInitialized.current && chainList && evmNetworkList && tokenList && rawBalances
|
|
168
|
-
|
|
169
|
-
// && tokenRates
|
|
170
|
-
) {
|
|
171
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, rawBalances, tokenRates));
|
|
148
|
+
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates && rawBalances) {
|
|
149
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances));
|
|
172
150
|
refInitialized.current = true;
|
|
173
151
|
}
|
|
174
152
|
}, [chainList, evmNetworkList, rawBalances, tokenList, tokenRates, useTestnets]);
|
|
@@ -178,7 +156,7 @@ const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
|
178
156
|
|
|
179
157
|
var packageJson = {
|
|
180
158
|
name: "@talismn/balances-react",
|
|
181
|
-
version: "0.0.0-pr563-
|
|
159
|
+
version: "0.0.0-pr563-20230222052739",
|
|
182
160
|
author: "Talisman",
|
|
183
161
|
homepage: "https://talisman.xyz",
|
|
184
162
|
license: "UNLICENSED",
|
|
@@ -308,14 +286,14 @@ function useChainConnectorsProvider(options) {
|
|
|
308
286
|
}
|
|
309
287
|
const [ChainConnectorsProvider, useChainConnectors] = provideContext(useChainConnectorsProvider);
|
|
310
288
|
|
|
311
|
-
const useSubscriptionsProvider = () => [useSubscribeChaindataHydrate("chains"), useSubscribeChaindataHydrate("evmNetworks"), useSubscribeChaindataHydrate("tokens"), useSubscribeBalances()];
|
|
289
|
+
const useSubscriptionsProvider = () => [useSubscribeChaindataHydrate("chains"), useSubscribeChaindataHydrate("evmNetworks"), useSubscribeChaindataHydrate("tokens"), useSubscribeTokenRates(), useSubscribeBalances()];
|
|
312
290
|
const [SubscriptionsProvider, useSubscriptions] = provideContext(useSubscriptionsProvider);
|
|
313
291
|
|
|
314
292
|
/**
|
|
315
293
|
* This hook is responsible for fetching the data used for balances and inserting it into the db.
|
|
316
294
|
*/
|
|
317
295
|
const useDbCacheSubscription = subscribeTo => {
|
|
318
|
-
const [subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeBalances] = useSubscriptions();
|
|
296
|
+
const [subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances] = useSubscriptions();
|
|
319
297
|
useEffect(() => {
|
|
320
298
|
switch (subscribeTo) {
|
|
321
299
|
case "chains":
|
|
@@ -324,10 +302,12 @@ const useDbCacheSubscription = subscribeTo => {
|
|
|
324
302
|
return subscribeHydrateEvmNetworks();
|
|
325
303
|
case "tokens":
|
|
326
304
|
return subscribeHydrateTokens();
|
|
305
|
+
case "tokenRates":
|
|
306
|
+
return subscribeTokenRates();
|
|
327
307
|
case "balances":
|
|
328
308
|
return subscribeBalances();
|
|
329
309
|
}
|
|
330
|
-
}, [
|
|
310
|
+
}, [subscribeTo, subscribeHydrateChains, subscribeHydrateEvmNetworks, subscribeHydrateTokens, subscribeTokenRates, subscribeBalances]);
|
|
331
311
|
};
|
|
332
312
|
function useSubscribeChaindataHydrate(type) {
|
|
333
313
|
const chaindata =
|
|
@@ -359,6 +339,49 @@ function useSubscribeChaindataHydrate(type) {
|
|
|
359
339
|
const subscribe = useMulticastSubscription(createSubscription);
|
|
360
340
|
return subscribe;
|
|
361
341
|
}
|
|
342
|
+
function useSubscribeTokenRates() {
|
|
343
|
+
const chaindataProvider = useChaindata();
|
|
344
|
+
const tokens = useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
|
|
345
|
+
const generationRef = useRef(0);
|
|
346
|
+
const createSubscription = useCallback(() => {
|
|
347
|
+
if (!chaindataProvider) return;
|
|
348
|
+
if (!tokens) return;
|
|
349
|
+
if (Object.keys(tokens).length < 1) return;
|
|
350
|
+
|
|
351
|
+
// when we make a new request, we want to ignore any old requests which haven't yet completed
|
|
352
|
+
// otherwise we risk replacing the most recent data with older data
|
|
353
|
+
const generation = (generationRef.current + 1) % Number.MAX_SAFE_INTEGER;
|
|
354
|
+
generationRef.current = generation;
|
|
355
|
+
let active = true;
|
|
356
|
+
const REFRESH_INTERVAL = 300_000; // 300_000ms = 5 minutes
|
|
357
|
+
const RETRY_INTERVAL = 5_000; // 5_000ms = 5 seconds
|
|
358
|
+
|
|
359
|
+
const hydrate = async () => {
|
|
360
|
+
if (!active) return;
|
|
361
|
+
if (generationRef.current !== generation) return;
|
|
362
|
+
try {
|
|
363
|
+
const tokenRates = await fetchTokenRates(tokens);
|
|
364
|
+
if (!active) return;
|
|
365
|
+
if (generationRef.current !== generation) return;
|
|
366
|
+
const putTokenRates = Object.entries(tokenRates).map(([tokenId, rates]) => ({
|
|
367
|
+
tokenId,
|
|
368
|
+
rates
|
|
369
|
+
}));
|
|
370
|
+
db.transaction("rw", db.tokenRates, async () => await db.tokenRates.bulkPut(putTokenRates));
|
|
371
|
+
setTimeout(hydrate, REFRESH_INTERVAL);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
log.error(`Failed to fetch tokenRates, retrying in ${Math.round(RETRY_INTERVAL / 1000)} seconds`, error);
|
|
374
|
+
setTimeout(hydrate, RETRY_INTERVAL);
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
hydrate();
|
|
378
|
+
return () => {
|
|
379
|
+
active = false;
|
|
380
|
+
};
|
|
381
|
+
}, [chaindataProvider, tokens]);
|
|
382
|
+
const subscribe = useMulticastSubscription(createSubscription);
|
|
383
|
+
return subscribe;
|
|
384
|
+
}
|
|
362
385
|
function useSubscribeBalances() {
|
|
363
386
|
const balanceModules = useBalanceModules();
|
|
364
387
|
const chaindataProvider = useChaindata();
|
|
@@ -399,7 +422,7 @@ function useSubscribeBalances() {
|
|
|
399
422
|
unsub.then(unsubscribe => unsubscribe());
|
|
400
423
|
|
|
401
424
|
// set this subscription's balances in the store to status: cache
|
|
402
|
-
db.transaction("rw", db.balances, async () => await db.balances.filter(balance => {
|
|
425
|
+
db$1.transaction("rw", db$1.balances, async () => await db$1.balances.filter(balance => {
|
|
403
426
|
if (balance.source !== balanceModule.type) return false;
|
|
404
427
|
if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
|
|
405
428
|
if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
|
|
@@ -414,7 +437,7 @@ function useSubscribeBalances() {
|
|
|
414
437
|
id,
|
|
415
438
|
...balance
|
|
416
439
|
}));
|
|
417
|
-
db.transaction("rw", db.balances, async () => await db.balances.bulkPut(putBalances));
|
|
440
|
+
db$1.transaction("rw", db$1.balances, async () => await db$1.balances.bulkPut(putBalances));
|
|
418
441
|
});
|
|
419
442
|
return unsubscribe;
|
|
420
443
|
});
|
|
@@ -453,6 +476,19 @@ function useEvmNetwork(evmNetworkId, withTestnets) {
|
|
|
453
476
|
return evmNetworkId ? evmNetworks[evmNetworkId] : undefined;
|
|
454
477
|
}
|
|
455
478
|
|
|
479
|
+
function useTokenRates() {
|
|
480
|
+
// keep db data up to date
|
|
481
|
+
useDbCacheSubscription("tokenRates");
|
|
482
|
+
const {
|
|
483
|
+
tokenRatesMap
|
|
484
|
+
} = useDbCache();
|
|
485
|
+
return tokenRatesMap;
|
|
486
|
+
}
|
|
487
|
+
function useTokenRate(tokenId) {
|
|
488
|
+
const tokenRates = useTokenRates();
|
|
489
|
+
return tokenId ? tokenRates[tokenId] : undefined;
|
|
490
|
+
}
|
|
491
|
+
|
|
456
492
|
function useTokens(withTestnets) {
|
|
457
493
|
// keep db data up to date
|
|
458
494
|
useDbCacheSubscription("tokens");
|
|
@@ -471,12 +507,7 @@ const useBalancesHydrate = withTestnets => {
|
|
|
471
507
|
const chains = useChains(withTestnets);
|
|
472
508
|
const evmNetworks = useEvmNetworks(withTestnets);
|
|
473
509
|
const tokens = useTokens(withTestnets);
|
|
474
|
-
|
|
475
|
-
// TODO: Store in a DB so that we don't have to wait for tokens before we can begin to fetch tokenRates
|
|
476
|
-
// useDbCacheSubscription("tokenRates")
|
|
477
|
-
const {
|
|
478
|
-
tokenRatesMap: tokenRates
|
|
479
|
-
} = useDbCache();
|
|
510
|
+
const tokenRates = useTokenRates();
|
|
480
511
|
return useMemo(() => ({
|
|
481
512
|
chains,
|
|
482
513
|
evmNetworks,
|
|
@@ -538,4 +569,4 @@ const BalancesProvider = ({
|
|
|
538
569
|
})
|
|
539
570
|
});
|
|
540
571
|
|
|
541
|
-
export { AllAddressesProvider, BalanceModulesProvider, BalancesProvider, ChainConnectorsProvider, ChaindataProvider, DbCacheProvider, SubscriptionsProvider, createMulticastSubscription, provideContext, useAllAddresses, useBalanceModules, useBalances, useBalancesHydrate, useChain, useChainConnectors, useChaindata, useChains, useDbCache, useDbCacheSubscription, useEvmNetwork, useEvmNetworks, useMulticastSubscription, useSubscriptions, useToken, useTokenRates, useTokens };
|
|
572
|
+
export { AllAddressesProvider, BalanceModulesProvider, BalancesProvider, ChainConnectorsProvider, ChaindataProvider, DbCacheProvider, SubscriptionsProvider, createMulticastSubscription, provideContext, useAllAddresses, useBalanceModules, useBalances, useBalancesHydrate, useChain, useChainConnectors, useChaindata, useChains, useDbCache, useDbCacheSubscription, useEvmNetwork, useEvmNetworks, useMulticastSubscription, useSubscriptions, useToken, useTokenRate, useTokenRates, useTokens };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talismn/balances-react",
|
|
3
|
-
"version": "0.0.0-pr563-
|
|
3
|
+
"version": "0.0.0-pr563-20230222052739",
|
|
4
4
|
"author": "Talisman",
|
|
5
5
|
"homepage": "https://talisman.xyz",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@talismn/balances": "^0.0.0-pr563-
|
|
29
|
+
"@talismn/balances": "^0.0.0-pr563-20230222052739",
|
|
30
30
|
"@talismn/chain-connector": "^0.4.2",
|
|
31
31
|
"@talismn/chain-connector-evm": "^0.4.2",
|
|
32
32
|
"@talismn/chaindata-provider": "^0.4.2",
|
|
33
33
|
"@talismn/chaindata-provider-extension": "^0.4.2",
|
|
34
|
-
"@talismn/token-rates": "^0.
|
|
34
|
+
"@talismn/token-rates": "^0.0.0-pr563-20230222052739",
|
|
35
35
|
"anylogger": "^1.0.11",
|
|
36
36
|
"dexie": "^3.2.2",
|
|
37
37
|
"dexie-react-hooks": "^1.1.1",
|