@talismn/balances-react 0.0.0-pr660-20230327112515 → 0.0.0-pr660-20230328111733
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @talismn/balances-react
|
|
2
2
|
|
|
3
|
-
## 0.0.0-pr660-
|
|
3
|
+
## 0.0.0-pr660-20230328111733
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
- Updated dependencies [79f6ccf6]
|
|
18
18
|
- Updated dependencies [6643a4e4]
|
|
19
19
|
- Updated dependencies [c24dc1fb]
|
|
20
|
-
- @talismn/chain-connector@0.0.0-pr660-
|
|
21
|
-
- @talismn/connection-meta@0.0.0-pr660-
|
|
22
|
-
- @talismn/balances@0.0.0-pr660-
|
|
23
|
-
- @talismn/token-rates@0.0.0-pr660-
|
|
24
|
-
- @talismn/chaindata-provider-extension@0.0.0-pr660-
|
|
25
|
-
- @talismn/chaindata-provider@0.0.0-pr660-
|
|
26
|
-
- @talismn/chain-connector-evm@0.0.0-pr660-
|
|
20
|
+
- @talismn/chain-connector@0.0.0-pr660-20230328111733
|
|
21
|
+
- @talismn/connection-meta@0.0.0-pr660-20230328111733
|
|
22
|
+
- @talismn/balances@0.0.0-pr660-20230328111733
|
|
23
|
+
- @talismn/token-rates@0.0.0-pr660-20230328111733
|
|
24
|
+
- @talismn/chaindata-provider-extension@0.0.0-pr660-20230328111733
|
|
25
|
+
- @talismn/chaindata-provider@0.0.0-pr660-20230328111733
|
|
26
|
+
- @talismn/chain-connector-evm@0.0.0-pr660-20230328111733
|
|
27
27
|
|
|
28
28
|
## 0.3.3
|
|
29
29
|
|
|
@@ -17,6 +17,9 @@ type DbCache = {
|
|
|
17
17
|
tokensWithoutTestnetsMap: Record<TokenId, Token>;
|
|
18
18
|
tokenRatesMap: Record<TokenId, TokenRates>;
|
|
19
19
|
balances: BalanceJson[];
|
|
20
|
+
balancesMeta: {
|
|
21
|
+
subscriptionId: string | undefined;
|
|
22
|
+
};
|
|
20
23
|
};
|
|
21
24
|
export declare const DbCacheProvider: import("react").FC<{
|
|
22
25
|
children?: import("react").ReactNode;
|
|
@@ -117,9 +117,12 @@ const DEFAULT_VALUE = {
|
|
|
117
117
|
tokensWithTestnetsMap: {},
|
|
118
118
|
tokensWithoutTestnetsMap: {},
|
|
119
119
|
tokenRatesMap: {},
|
|
120
|
-
balances: []
|
|
120
|
+
balances: [],
|
|
121
|
+
balancesMeta: {
|
|
122
|
+
subscriptionId: undefined
|
|
123
|
+
}
|
|
121
124
|
};
|
|
122
|
-
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
|
|
125
|
+
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances, meta) => {
|
|
123
126
|
if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
|
|
124
127
|
|
|
125
128
|
// BEGIN: temp hack to indicate that
|
|
@@ -155,6 +158,11 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
|
|
|
155
158
|
|
|
156
159
|
// return only balances for which we have a token
|
|
157
160
|
const balances = allBalances.filter(b => tokensWithTestnetsMap[b.tokenId]);
|
|
161
|
+
const balancesMeta = {
|
|
162
|
+
subscriptionId: meta?.find(({
|
|
163
|
+
id
|
|
164
|
+
}) => id === "subscriptionId")?.value
|
|
165
|
+
};
|
|
158
166
|
return {
|
|
159
167
|
chainsWithTestnets,
|
|
160
168
|
chainsWithoutTestnets,
|
|
@@ -169,7 +177,8 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
|
|
|
169
177
|
tokensWithTestnetsMap,
|
|
170
178
|
tokensWithoutTestnetsMap,
|
|
171
179
|
tokenRatesMap,
|
|
172
|
-
balances
|
|
180
|
+
balances,
|
|
181
|
+
balancesMeta
|
|
173
182
|
};
|
|
174
183
|
};
|
|
175
184
|
const useDbCacheProvider = () => {
|
|
@@ -179,28 +188,29 @@ const useDbCacheProvider = () => {
|
|
|
179
188
|
const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
|
|
180
189
|
const tokenRates$1 = dexieReactHooks.useLiveQuery(() => tokenRates.db.tokenRates.toArray(), []);
|
|
181
190
|
const rawBalances = dexieReactHooks.useLiveQuery(() => balances.db.balances.toArray(), []);
|
|
191
|
+
const meta = dexieReactHooks.useLiveQuery(() => balances.db.meta.toArray(), []);
|
|
182
192
|
const [dbData, setDbData] = react.useState(DEFAULT_VALUE);
|
|
183
193
|
|
|
184
194
|
// debounce every 500ms to prevent hammering UI with updates
|
|
185
195
|
reactUse.useDebounce(() => {
|
|
186
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
187
|
-
}, 500, [chainList, evmNetworkList, tokenList, rawBalances,
|
|
196
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta));
|
|
197
|
+
}, 500, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta]);
|
|
188
198
|
const refInitialized = react.useRef(false);
|
|
189
199
|
|
|
190
200
|
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
191
201
|
react.useEffect(() => {
|
|
192
|
-
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates$1 && rawBalances) {
|
|
193
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
202
|
+
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates$1 && rawBalances && meta) {
|
|
203
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta));
|
|
194
204
|
refInitialized.current = true;
|
|
195
205
|
}
|
|
196
|
-
}, [chainList, evmNetworkList,
|
|
206
|
+
}, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta]);
|
|
197
207
|
return dbData;
|
|
198
208
|
};
|
|
199
209
|
const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
200
210
|
|
|
201
211
|
var packageJson = {
|
|
202
212
|
name: "@talismn/balances-react",
|
|
203
|
-
version: "0.0.0-pr660-
|
|
213
|
+
version: "0.0.0-pr660-20230328111733",
|
|
204
214
|
author: "Talisman",
|
|
205
215
|
homepage: "https://talisman.xyz",
|
|
206
216
|
license: "UNLICENSED",
|
|
@@ -503,10 +513,29 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
503
513
|
id
|
|
504
514
|
}) => id);
|
|
505
515
|
const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId, addresses]));
|
|
516
|
+
const subscriptionId = Date.now().toString();
|
|
517
|
+
balances.db.meta.put({
|
|
518
|
+
id: "subscriptionId",
|
|
519
|
+
value: subscriptionId
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
// TODO: Create subscriptions in a service worker, where we can detect page closes
|
|
523
|
+
// and therefore reliably delete the subscriptionId when the user closes our dapp
|
|
524
|
+
//
|
|
525
|
+
// For more information, check out https://developer.chrome.com/blog/page-lifecycle-api/#faqs
|
|
526
|
+
// and scroll down to:
|
|
527
|
+
// - `What is the back/forward cache?`, and
|
|
528
|
+
// - `If I can't run asynchronous APIs in the frozen or terminated states, how can I save data to IndexedDB?
|
|
529
|
+
//
|
|
530
|
+
// For now, we'll just last-ditch remove the subscriptionId (it works surprisingly well!) in the beforeunload event
|
|
531
|
+
window.onbeforeunload = () => {
|
|
532
|
+
balances.db.meta.delete("subscriptionId");
|
|
533
|
+
};
|
|
506
534
|
const updateDb = balances$1 => {
|
|
507
535
|
const putBalances = Object.entries(balances$1.toJSON()).map(([id, balance]) => ({
|
|
508
536
|
id,
|
|
509
|
-
...balance
|
|
537
|
+
...balance,
|
|
538
|
+
status: balances.BalanceStatusLive(subscriptionId)
|
|
510
539
|
}));
|
|
511
540
|
balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.bulkPut(putBalances));
|
|
512
541
|
};
|
|
@@ -525,7 +554,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
525
554
|
const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances$1) => {
|
|
526
555
|
// log errors
|
|
527
556
|
if (error) {
|
|
528
|
-
if (error?.type === "STALE_RPC_ERROR") return balances.db.balances.where({
|
|
557
|
+
if (error?.type === "STALE_RPC_ERROR" || error?.type === "WEBSOCKET_ALLOCATION_EXHAUSTED_ERROR") return balances.db.balances.where({
|
|
529
558
|
source: balanceModule.type,
|
|
530
559
|
chainId: error.chainId
|
|
531
560
|
}).filter(balance => {
|
|
@@ -548,15 +577,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
548
577
|
unsub.then(unsubscribe => {
|
|
549
578
|
setTimeout(unsubscribe, 2_000);
|
|
550
579
|
});
|
|
551
|
-
balances.db.
|
|
552
|
-
source: balanceModule.type
|
|
553
|
-
}).filter(balance => {
|
|
554
|
-
if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
|
|
555
|
-
if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
|
|
556
|
-
return true;
|
|
557
|
-
}).modify({
|
|
558
|
-
status: "cache"
|
|
559
|
-
});
|
|
580
|
+
balances.db.meta.delete("subscriptionId");
|
|
560
581
|
};
|
|
561
582
|
});
|
|
562
583
|
const unsubscribeAll = () => {
|
|
@@ -642,10 +663,11 @@ function useBalances(addressesByToken) {
|
|
|
642
663
|
useDbCacheBalancesSubscription();
|
|
643
664
|
const balanceModules = useBalanceModules();
|
|
644
665
|
const {
|
|
645
|
-
balances: balances$1
|
|
666
|
+
balances: balances$1,
|
|
667
|
+
balancesMeta
|
|
646
668
|
} = useDbCache();
|
|
647
669
|
const hydrate = useBalancesHydrate();
|
|
648
|
-
return react.useMemo(() => new balances.Balances(balances$1.filter(balance => {
|
|
670
|
+
return react.useMemo(() => new balances.Balances(balances.deriveStatuses(balancesMeta.subscriptionId, balances$1.filter(balance => {
|
|
649
671
|
// check that this balance is included in our queried balance modules
|
|
650
672
|
if (!balanceModules.map(({
|
|
651
673
|
type
|
|
@@ -662,9 +684,9 @@ function useBalances(addressesByToken) {
|
|
|
662
684
|
|
|
663
685
|
// keep this balance
|
|
664
686
|
return true;
|
|
665
|
-
}),
|
|
687
|
+
})),
|
|
666
688
|
// hydrate balance chains, evmNetworks, tokens and tokenRates
|
|
667
|
-
hydrate), [balances$1, hydrate, balanceModules, addressesByToken]);
|
|
689
|
+
hydrate), [balancesMeta.subscriptionId, balances$1, hydrate, balanceModules, addressesByToken]);
|
|
668
690
|
}
|
|
669
691
|
|
|
670
692
|
/**
|
|
@@ -117,9 +117,12 @@ const DEFAULT_VALUE = {
|
|
|
117
117
|
tokensWithTestnetsMap: {},
|
|
118
118
|
tokensWithoutTestnetsMap: {},
|
|
119
119
|
tokenRatesMap: {},
|
|
120
|
-
balances: []
|
|
120
|
+
balances: [],
|
|
121
|
+
balancesMeta: {
|
|
122
|
+
subscriptionId: undefined
|
|
123
|
+
}
|
|
121
124
|
};
|
|
122
|
-
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
|
|
125
|
+
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances, meta) => {
|
|
123
126
|
if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
|
|
124
127
|
|
|
125
128
|
// BEGIN: temp hack to indicate that
|
|
@@ -155,6 +158,11 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
|
|
|
155
158
|
|
|
156
159
|
// return only balances for which we have a token
|
|
157
160
|
const balances = allBalances.filter(b => tokensWithTestnetsMap[b.tokenId]);
|
|
161
|
+
const balancesMeta = {
|
|
162
|
+
subscriptionId: meta?.find(({
|
|
163
|
+
id
|
|
164
|
+
}) => id === "subscriptionId")?.value
|
|
165
|
+
};
|
|
158
166
|
return {
|
|
159
167
|
chainsWithTestnets,
|
|
160
168
|
chainsWithoutTestnets,
|
|
@@ -169,7 +177,8 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
|
|
|
169
177
|
tokensWithTestnetsMap,
|
|
170
178
|
tokensWithoutTestnetsMap,
|
|
171
179
|
tokenRatesMap,
|
|
172
|
-
balances
|
|
180
|
+
balances,
|
|
181
|
+
balancesMeta
|
|
173
182
|
};
|
|
174
183
|
};
|
|
175
184
|
const useDbCacheProvider = () => {
|
|
@@ -179,28 +188,29 @@ const useDbCacheProvider = () => {
|
|
|
179
188
|
const tokenList = dexieReactHooks.useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
|
|
180
189
|
const tokenRates$1 = dexieReactHooks.useLiveQuery(() => tokenRates.db.tokenRates.toArray(), []);
|
|
181
190
|
const rawBalances = dexieReactHooks.useLiveQuery(() => balances.db.balances.toArray(), []);
|
|
191
|
+
const meta = dexieReactHooks.useLiveQuery(() => balances.db.meta.toArray(), []);
|
|
182
192
|
const [dbData, setDbData] = react.useState(DEFAULT_VALUE);
|
|
183
193
|
|
|
184
194
|
// debounce every 500ms to prevent hammering UI with updates
|
|
185
195
|
reactUse.useDebounce(() => {
|
|
186
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
187
|
-
}, 500, [chainList, evmNetworkList, tokenList, rawBalances,
|
|
196
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta));
|
|
197
|
+
}, 500, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta]);
|
|
188
198
|
const refInitialized = react.useRef(false);
|
|
189
199
|
|
|
190
200
|
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
191
201
|
react.useEffect(() => {
|
|
192
|
-
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates$1 && rawBalances) {
|
|
193
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances));
|
|
202
|
+
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates$1 && rawBalances && meta) {
|
|
203
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta));
|
|
194
204
|
refInitialized.current = true;
|
|
195
205
|
}
|
|
196
|
-
}, [chainList, evmNetworkList,
|
|
206
|
+
}, [chainList, evmNetworkList, tokenList, tokenRates$1, rawBalances, meta]);
|
|
197
207
|
return dbData;
|
|
198
208
|
};
|
|
199
209
|
const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
200
210
|
|
|
201
211
|
var packageJson = {
|
|
202
212
|
name: "@talismn/balances-react",
|
|
203
|
-
version: "0.0.0-pr660-
|
|
213
|
+
version: "0.0.0-pr660-20230328111733",
|
|
204
214
|
author: "Talisman",
|
|
205
215
|
homepage: "https://talisman.xyz",
|
|
206
216
|
license: "UNLICENSED",
|
|
@@ -503,10 +513,29 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
503
513
|
id
|
|
504
514
|
}) => id);
|
|
505
515
|
const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId, addresses]));
|
|
516
|
+
const subscriptionId = Date.now().toString();
|
|
517
|
+
balances.db.meta.put({
|
|
518
|
+
id: "subscriptionId",
|
|
519
|
+
value: subscriptionId
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
// TODO: Create subscriptions in a service worker, where we can detect page closes
|
|
523
|
+
// and therefore reliably delete the subscriptionId when the user closes our dapp
|
|
524
|
+
//
|
|
525
|
+
// For more information, check out https://developer.chrome.com/blog/page-lifecycle-api/#faqs
|
|
526
|
+
// and scroll down to:
|
|
527
|
+
// - `What is the back/forward cache?`, and
|
|
528
|
+
// - `If I can't run asynchronous APIs in the frozen or terminated states, how can I save data to IndexedDB?
|
|
529
|
+
//
|
|
530
|
+
// For now, we'll just last-ditch remove the subscriptionId (it works surprisingly well!) in the beforeunload event
|
|
531
|
+
window.onbeforeunload = () => {
|
|
532
|
+
balances.db.meta.delete("subscriptionId");
|
|
533
|
+
};
|
|
506
534
|
const updateDb = balances$1 => {
|
|
507
535
|
const putBalances = Object.entries(balances$1.toJSON()).map(([id, balance]) => ({
|
|
508
536
|
id,
|
|
509
|
-
...balance
|
|
537
|
+
...balance,
|
|
538
|
+
status: balances.BalanceStatusLive(subscriptionId)
|
|
510
539
|
}));
|
|
511
540
|
balances.db.transaction("rw", balances.db.balances, async () => await balances.db.balances.bulkPut(putBalances));
|
|
512
541
|
};
|
|
@@ -525,7 +554,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
525
554
|
const unsub = balances.balances(balanceModule, addressesByModuleToken, (error, balances$1) => {
|
|
526
555
|
// log errors
|
|
527
556
|
if (error) {
|
|
528
|
-
if (error?.type === "STALE_RPC_ERROR") return balances.db.balances.where({
|
|
557
|
+
if (error?.type === "STALE_RPC_ERROR" || error?.type === "WEBSOCKET_ALLOCATION_EXHAUSTED_ERROR") return balances.db.balances.where({
|
|
529
558
|
source: balanceModule.type,
|
|
530
559
|
chainId: error.chainId
|
|
531
560
|
}).filter(balance => {
|
|
@@ -548,15 +577,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
548
577
|
unsub.then(unsubscribe => {
|
|
549
578
|
setTimeout(unsubscribe, 2_000);
|
|
550
579
|
});
|
|
551
|
-
balances.db.
|
|
552
|
-
source: balanceModule.type
|
|
553
|
-
}).filter(balance => {
|
|
554
|
-
if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
|
|
555
|
-
if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
|
|
556
|
-
return true;
|
|
557
|
-
}).modify({
|
|
558
|
-
status: "cache"
|
|
559
|
-
});
|
|
580
|
+
balances.db.meta.delete("subscriptionId");
|
|
560
581
|
};
|
|
561
582
|
});
|
|
562
583
|
const unsubscribeAll = () => {
|
|
@@ -642,10 +663,11 @@ function useBalances(addressesByToken) {
|
|
|
642
663
|
useDbCacheBalancesSubscription();
|
|
643
664
|
const balanceModules = useBalanceModules();
|
|
644
665
|
const {
|
|
645
|
-
balances: balances$1
|
|
666
|
+
balances: balances$1,
|
|
667
|
+
balancesMeta
|
|
646
668
|
} = useDbCache();
|
|
647
669
|
const hydrate = useBalancesHydrate();
|
|
648
|
-
return react.useMemo(() => new balances.Balances(balances$1.filter(balance => {
|
|
670
|
+
return react.useMemo(() => new balances.Balances(balances.deriveStatuses(balancesMeta.subscriptionId, balances$1.filter(balance => {
|
|
649
671
|
// check that this balance is included in our queried balance modules
|
|
650
672
|
if (!balanceModules.map(({
|
|
651
673
|
type
|
|
@@ -662,9 +684,9 @@ function useBalances(addressesByToken) {
|
|
|
662
684
|
|
|
663
685
|
// keep this balance
|
|
664
686
|
return true;
|
|
665
|
-
}),
|
|
687
|
+
})),
|
|
666
688
|
// hydrate balance chains, evmNetworks, tokens and tokenRates
|
|
667
|
-
hydrate), [balances$1, hydrate, balanceModules, addressesByToken]);
|
|
689
|
+
hydrate), [balancesMeta.subscriptionId, balances$1, hydrate, balanceModules, addressesByToken]);
|
|
668
690
|
}
|
|
669
691
|
|
|
670
692
|
/**
|
|
@@ -4,7 +4,7 @@ import { ChainConnector } from '@talismn/chain-connector';
|
|
|
4
4
|
import { ChainConnectorEvm } from '@talismn/chain-connector-evm';
|
|
5
5
|
import { connectionMetaDb } from '@talismn/connection-meta';
|
|
6
6
|
import { ChaindataProviderExtension } from '@talismn/chaindata-provider-extension';
|
|
7
|
-
import { db as db$1, balances, Balances } from '@talismn/balances';
|
|
7
|
+
import { db as db$1, balances, BalanceStatusLive, Balances, deriveStatuses } from '@talismn/balances';
|
|
8
8
|
import { db, fetchTokenRates } from '@talismn/token-rates';
|
|
9
9
|
import { useLiveQuery } from 'dexie-react-hooks';
|
|
10
10
|
import { useDebounce } from 'react-use';
|
|
@@ -108,9 +108,12 @@ const DEFAULT_VALUE = {
|
|
|
108
108
|
tokensWithTestnetsMap: {},
|
|
109
109
|
tokensWithoutTestnetsMap: {},
|
|
110
110
|
tokenRatesMap: {},
|
|
111
|
-
balances: []
|
|
111
|
+
balances: [],
|
|
112
|
+
balancesMeta: {
|
|
113
|
+
subscriptionId: undefined
|
|
114
|
+
}
|
|
112
115
|
};
|
|
113
|
-
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances) => {
|
|
116
|
+
const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, allBalances, meta) => {
|
|
114
117
|
if (!chainsMap || !evmNetworksMap || !tokensMap || !tokenRates || !allBalances) return DEFAULT_VALUE;
|
|
115
118
|
|
|
116
119
|
// BEGIN: temp hack to indicate that
|
|
@@ -146,6 +149,11 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
|
|
|
146
149
|
|
|
147
150
|
// return only balances for which we have a token
|
|
148
151
|
const balances = allBalances.filter(b => tokensWithTestnetsMap[b.tokenId]);
|
|
152
|
+
const balancesMeta = {
|
|
153
|
+
subscriptionId: meta?.find(({
|
|
154
|
+
id
|
|
155
|
+
}) => id === "subscriptionId")?.value
|
|
156
|
+
};
|
|
149
157
|
return {
|
|
150
158
|
chainsWithTestnets,
|
|
151
159
|
chainsWithoutTestnets,
|
|
@@ -160,7 +168,8 @@ const consolidateDbCache = (chainsMap, evmNetworksMap, tokensMap, tokenRates, al
|
|
|
160
168
|
tokensWithTestnetsMap,
|
|
161
169
|
tokensWithoutTestnetsMap,
|
|
162
170
|
tokenRatesMap,
|
|
163
|
-
balances
|
|
171
|
+
balances,
|
|
172
|
+
balancesMeta
|
|
164
173
|
};
|
|
165
174
|
};
|
|
166
175
|
const useDbCacheProvider = () => {
|
|
@@ -170,28 +179,29 @@ const useDbCacheProvider = () => {
|
|
|
170
179
|
const tokenList = useLiveQuery(() => chaindataProvider?.tokens(), [chaindataProvider]);
|
|
171
180
|
const tokenRates = useLiveQuery(() => db.tokenRates.toArray(), []);
|
|
172
181
|
const rawBalances = useLiveQuery(() => db$1.balances.toArray(), []);
|
|
182
|
+
const meta = useLiveQuery(() => db$1.meta.toArray(), []);
|
|
173
183
|
const [dbData, setDbData] = useState(DEFAULT_VALUE);
|
|
174
184
|
|
|
175
185
|
// debounce every 500ms to prevent hammering UI with updates
|
|
176
186
|
useDebounce(() => {
|
|
177
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances));
|
|
178
|
-
}, 500, [chainList, evmNetworkList, tokenList, rawBalances,
|
|
187
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances, meta));
|
|
188
|
+
}, 500, [chainList, evmNetworkList, tokenList, tokenRates, rawBalances, meta]);
|
|
179
189
|
const refInitialized = useRef(false);
|
|
180
190
|
|
|
181
191
|
// force an update as soon as all datasources are fetched, so UI can display data ASAP
|
|
182
192
|
useEffect(() => {
|
|
183
|
-
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates && rawBalances) {
|
|
184
|
-
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances));
|
|
193
|
+
if (!refInitialized.current && chainList && evmNetworkList && tokenList && tokenRates && rawBalances && meta) {
|
|
194
|
+
setDbData(consolidateDbCache(chainList, evmNetworkList, tokenList, tokenRates, rawBalances, meta));
|
|
185
195
|
refInitialized.current = true;
|
|
186
196
|
}
|
|
187
|
-
}, [chainList, evmNetworkList,
|
|
197
|
+
}, [chainList, evmNetworkList, tokenList, tokenRates, rawBalances, meta]);
|
|
188
198
|
return dbData;
|
|
189
199
|
};
|
|
190
200
|
const [DbCacheProvider, useDbCache] = provideContext(useDbCacheProvider);
|
|
191
201
|
|
|
192
202
|
var packageJson = {
|
|
193
203
|
name: "@talismn/balances-react",
|
|
194
|
-
version: "0.0.0-pr660-
|
|
204
|
+
version: "0.0.0-pr660-20230328111733",
|
|
195
205
|
author: "Talisman",
|
|
196
206
|
homepage: "https://talisman.xyz",
|
|
197
207
|
license: "UNLICENSED",
|
|
@@ -494,10 +504,29 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
494
504
|
id
|
|
495
505
|
}) => id);
|
|
496
506
|
const addressesByToken = Object.fromEntries(tokenIds.map(tokenId => [tokenId, addresses]));
|
|
507
|
+
const subscriptionId = Date.now().toString();
|
|
508
|
+
db$1.meta.put({
|
|
509
|
+
id: "subscriptionId",
|
|
510
|
+
value: subscriptionId
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// TODO: Create subscriptions in a service worker, where we can detect page closes
|
|
514
|
+
// and therefore reliably delete the subscriptionId when the user closes our dapp
|
|
515
|
+
//
|
|
516
|
+
// For more information, check out https://developer.chrome.com/blog/page-lifecycle-api/#faqs
|
|
517
|
+
// and scroll down to:
|
|
518
|
+
// - `What is the back/forward cache?`, and
|
|
519
|
+
// - `If I can't run asynchronous APIs in the frozen or terminated states, how can I save data to IndexedDB?
|
|
520
|
+
//
|
|
521
|
+
// For now, we'll just last-ditch remove the subscriptionId (it works surprisingly well!) in the beforeunload event
|
|
522
|
+
window.onbeforeunload = () => {
|
|
523
|
+
db$1.meta.delete("subscriptionId");
|
|
524
|
+
};
|
|
497
525
|
const updateDb = balances => {
|
|
498
526
|
const putBalances = Object.entries(balances.toJSON()).map(([id, balance]) => ({
|
|
499
527
|
id,
|
|
500
|
-
...balance
|
|
528
|
+
...balance,
|
|
529
|
+
status: BalanceStatusLive(subscriptionId)
|
|
501
530
|
}));
|
|
502
531
|
db$1.transaction("rw", db$1.balances, async () => await db$1.balances.bulkPut(putBalances));
|
|
503
532
|
};
|
|
@@ -516,7 +545,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
516
545
|
const unsub = balances(balanceModule, addressesByModuleToken, (error, balances) => {
|
|
517
546
|
// log errors
|
|
518
547
|
if (error) {
|
|
519
|
-
if (error?.type === "STALE_RPC_ERROR") return db$1.balances.where({
|
|
548
|
+
if (error?.type === "STALE_RPC_ERROR" || error?.type === "WEBSOCKET_ALLOCATION_EXHAUSTED_ERROR") return db$1.balances.where({
|
|
520
549
|
source: balanceModule.type,
|
|
521
550
|
chainId: error.chainId
|
|
522
551
|
}).filter(balance => {
|
|
@@ -539,15 +568,7 @@ const subscribeBalances = (tokens, addresses, balanceModules) => {
|
|
|
539
568
|
unsub.then(unsubscribe => {
|
|
540
569
|
setTimeout(unsubscribe, 2_000);
|
|
541
570
|
});
|
|
542
|
-
db$1.
|
|
543
|
-
source: balanceModule.type
|
|
544
|
-
}).filter(balance => {
|
|
545
|
-
if (!Object.keys(addressesByModuleToken).includes(balance.tokenId)) return false;
|
|
546
|
-
if (!addressesByModuleToken[balance.tokenId].includes(balance.address)) return false;
|
|
547
|
-
return true;
|
|
548
|
-
}).modify({
|
|
549
|
-
status: "cache"
|
|
550
|
-
});
|
|
571
|
+
db$1.meta.delete("subscriptionId");
|
|
551
572
|
};
|
|
552
573
|
});
|
|
553
574
|
const unsubscribeAll = () => {
|
|
@@ -633,10 +654,11 @@ function useBalances(addressesByToken) {
|
|
|
633
654
|
useDbCacheBalancesSubscription();
|
|
634
655
|
const balanceModules = useBalanceModules();
|
|
635
656
|
const {
|
|
636
|
-
balances
|
|
657
|
+
balances,
|
|
658
|
+
balancesMeta
|
|
637
659
|
} = useDbCache();
|
|
638
660
|
const hydrate = useBalancesHydrate();
|
|
639
|
-
return useMemo(() => new Balances(balances.filter(balance => {
|
|
661
|
+
return useMemo(() => new Balances(deriveStatuses(balancesMeta.subscriptionId, balances.filter(balance => {
|
|
640
662
|
// check that this balance is included in our queried balance modules
|
|
641
663
|
if (!balanceModules.map(({
|
|
642
664
|
type
|
|
@@ -653,9 +675,9 @@ function useBalances(addressesByToken) {
|
|
|
653
675
|
|
|
654
676
|
// keep this balance
|
|
655
677
|
return true;
|
|
656
|
-
}),
|
|
678
|
+
})),
|
|
657
679
|
// hydrate balance chains, evmNetworks, tokens and tokenRates
|
|
658
|
-
hydrate), [balances, hydrate, balanceModules, addressesByToken]);
|
|
680
|
+
hydrate), [balancesMeta.subscriptionId, balances, hydrate, balanceModules, addressesByToken]);
|
|
659
681
|
}
|
|
660
682
|
|
|
661
683
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talismn/balances-react",
|
|
3
|
-
"version": "0.0.0-pr660-
|
|
3
|
+
"version": "0.0.0-pr660-20230328111733",
|
|
4
4
|
"author": "Talisman",
|
|
5
5
|
"homepage": "https://talisman.xyz",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"clean": "rm -rf dist && rm -rf .turbo rm -rf node_modules"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@talismn/balances": "^0.0.0-pr660-
|
|
30
|
-
"@talismn/chain-connector": "^0.0.0-pr660-
|
|
31
|
-
"@talismn/chain-connector-evm": "^0.0.0-pr660-
|
|
32
|
-
"@talismn/chaindata-provider": "^0.0.0-pr660-
|
|
33
|
-
"@talismn/chaindata-provider-extension": "^0.0.0-pr660-
|
|
34
|
-
"@talismn/connection-meta": "^0.0.0-pr660-
|
|
35
|
-
"@talismn/token-rates": "^0.0.0-pr660-
|
|
29
|
+
"@talismn/balances": "^0.0.0-pr660-20230328111733",
|
|
30
|
+
"@talismn/chain-connector": "^0.0.0-pr660-20230328111733",
|
|
31
|
+
"@talismn/chain-connector-evm": "^0.0.0-pr660-20230328111733",
|
|
32
|
+
"@talismn/chaindata-provider": "^0.0.0-pr660-20230328111733",
|
|
33
|
+
"@talismn/chaindata-provider-extension": "^0.0.0-pr660-20230328111733",
|
|
34
|
+
"@talismn/connection-meta": "^0.0.0-pr660-20230328111733",
|
|
35
|
+
"@talismn/token-rates": "^0.0.0-pr660-20230328111733",
|
|
36
36
|
"anylogger": "^1.0.11",
|
|
37
37
|
"blueimp-md5": "2.19.0",
|
|
38
38
|
"dexie": "^3.2.3",
|