@talismn/balances-react 0.0.0-pr2120-20250805025334 → 0.0.0-pr2127-20250806071759
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/dist/declarations/src/atoms/tokenRates.d.ts +3 -1
- package/dist/declarations/src/hooks/useTokenRates.d.ts +3 -1
- package/dist/declarations/src/util/dexieToRxjs.d.ts +6 -0
- package/dist/talismn-balances-react.cjs.dev.js +38 -13
- package/dist/talismn-balances-react.cjs.prod.js +38 -13
- package/dist/talismn-balances-react.esm.js +40 -15
- package/package.json +10 -8
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { TokenId } from "@talismn/chaindata-provider";
|
|
2
|
-
export declare const useTokenRates: () =>
|
|
2
|
+
export declare const useTokenRates: () => {
|
|
3
|
+
[k: string]: import("@talismn/token-rates").TokenRates;
|
|
4
|
+
};
|
|
3
5
|
export declare const useTokenRate: (tokenId?: TokenId) => import("@talismn/token-rates").TokenRates;
|
|
@@ -14,6 +14,7 @@ var connectionMeta = require('@talismn/connection-meta');
|
|
|
14
14
|
var util = require('@talismn/util');
|
|
15
15
|
var utils = require('jotai/utils');
|
|
16
16
|
var rxjs = require('rxjs');
|
|
17
|
+
var dexie = require('dexie');
|
|
17
18
|
var anylogger = require('anylogger');
|
|
18
19
|
var utilCrypto = require('@polkadot/util-crypto');
|
|
19
20
|
|
|
@@ -33,9 +34,7 @@ const enabledTokensAtom = jotai.atom(undefined);
|
|
|
33
34
|
const allAddressesAtom = jotai.atom([]);
|
|
34
35
|
|
|
35
36
|
const chaindataProviderAtom = jotai.atom(() => {
|
|
36
|
-
return new chaindataProvider.ChaindataProvider({
|
|
37
|
-
// TODO pass persistedStorage
|
|
38
|
-
});
|
|
37
|
+
return new chaindataProvider.ChaindataProvider({});
|
|
39
38
|
});
|
|
40
39
|
|
|
41
40
|
const chainConnectorsAtom = jotai.atom(get => {
|
|
@@ -86,17 +85,32 @@ var packageJson = {
|
|
|
86
85
|
|
|
87
86
|
var log = anylogger__default.default(packageJson.name);
|
|
88
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Converts a dexie Observable into an rxjs Observable.
|
|
90
|
+
*/
|
|
91
|
+
function dexieToRxjs(o) {
|
|
92
|
+
return new rxjs.Observable(observer => {
|
|
93
|
+
const subscription = o.subscribe({
|
|
94
|
+
next: value => observer.next(value),
|
|
95
|
+
error: error => observer.error(error)
|
|
96
|
+
});
|
|
97
|
+
return () => subscription.unsubscribe();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
const tokenRatesAtom = jotai.atom(async get => {
|
|
90
102
|
// runs a timer to keep tokenRates up to date
|
|
91
103
|
get(tokenRatesFetcherAtomEffect);
|
|
92
|
-
return
|
|
104
|
+
return await get(tokenRatesDbAtom);
|
|
93
105
|
});
|
|
94
|
-
|
|
95
|
-
// TODO: Persist to storage
|
|
96
|
-
const tokenRates$ = new rxjs.ReplaySubject(1);
|
|
97
106
|
const tokenRatesDbAtom = utils.atomWithObservable(() => {
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
const dbRatesToMap = dbRates => Object.fromEntries(dbRates.map(({
|
|
108
|
+
tokenId,
|
|
109
|
+
rates
|
|
110
|
+
}) => [tokenId, rates]));
|
|
111
|
+
|
|
112
|
+
// retrieve fetched tokenRates from the db
|
|
113
|
+
return dexieToRxjs(dexie.liveQuery(() => tokenRates.db.tokenRates.toArray())).pipe(rxjs.map(dbRatesToMap));
|
|
100
114
|
});
|
|
101
115
|
const tokenRatesFetcherAtomEffect = jotaiEffect.atomEffect(get => {
|
|
102
116
|
// lets us tear down the existing timer when the effect is restarted
|
|
@@ -107,6 +121,7 @@ const tokenRatesFetcherAtomEffect = jotaiEffect.atomEffect(get => {
|
|
|
107
121
|
const tokensPromise = get(tokensAtom);
|
|
108
122
|
(async () => {
|
|
109
123
|
const tokensById = lodashEs.keyBy(await tokensPromise, "id");
|
|
124
|
+
const tokenIds = Object.keys(tokensById);
|
|
110
125
|
const loopMs = 300_000; // 300_000ms = 300s = 5 minutes
|
|
111
126
|
const retryTimeout = 5_000; // 5_000ms = 5 seconds
|
|
112
127
|
|
|
@@ -114,11 +129,21 @@ const tokenRatesFetcherAtomEffect = jotaiEffect.atomEffect(get => {
|
|
|
114
129
|
try {
|
|
115
130
|
if (abort.signal.aborted) return; // don't fetch if aborted
|
|
116
131
|
const tokenRates$1 = await tokenRates.fetchTokenRates(tokensById, tokenRates.ALL_CURRENCY_IDS, coinsApiConfig);
|
|
117
|
-
const putTokenRates = {
|
|
118
|
-
|
|
119
|
-
|
|
132
|
+
const putTokenRates = Object.entries(tokenRates$1).map(([tokenId, rates]) => ({
|
|
133
|
+
tokenId,
|
|
134
|
+
rates
|
|
135
|
+
}));
|
|
120
136
|
if (abort.signal.aborted) return; // don't insert into db if aborted
|
|
121
|
-
tokenRates
|
|
137
|
+
await tokenRates.db.transaction("rw", tokenRates.db.tokenRates, async () => {
|
|
138
|
+
// override all tokenRates
|
|
139
|
+
await tokenRates.db.tokenRates.bulkPut(putTokenRates);
|
|
140
|
+
|
|
141
|
+
// delete tokenRates for tokens which no longer exist
|
|
142
|
+
const validTokenIds = new Set(tokenIds);
|
|
143
|
+
const tokenRatesIds = await tokenRates.db.tokenRates.toCollection().primaryKeys();
|
|
144
|
+
const deleteIds = tokenRatesIds.filter(id => !validTokenIds.has(id));
|
|
145
|
+
if (deleteIds.length > 0) await tokenRates.db.tokenRates.bulkDelete(deleteIds);
|
|
146
|
+
});
|
|
122
147
|
if (abort.signal.aborted) return; // don't schedule next loop if aborted
|
|
123
148
|
setTimeout(hydrate, loopMs);
|
|
124
149
|
} catch (error) {
|
|
@@ -14,6 +14,7 @@ var connectionMeta = require('@talismn/connection-meta');
|
|
|
14
14
|
var util = require('@talismn/util');
|
|
15
15
|
var utils = require('jotai/utils');
|
|
16
16
|
var rxjs = require('rxjs');
|
|
17
|
+
var dexie = require('dexie');
|
|
17
18
|
var anylogger = require('anylogger');
|
|
18
19
|
var utilCrypto = require('@polkadot/util-crypto');
|
|
19
20
|
|
|
@@ -33,9 +34,7 @@ const enabledTokensAtom = jotai.atom(undefined);
|
|
|
33
34
|
const allAddressesAtom = jotai.atom([]);
|
|
34
35
|
|
|
35
36
|
const chaindataProviderAtom = jotai.atom(() => {
|
|
36
|
-
return new chaindataProvider.ChaindataProvider({
|
|
37
|
-
// TODO pass persistedStorage
|
|
38
|
-
});
|
|
37
|
+
return new chaindataProvider.ChaindataProvider({});
|
|
39
38
|
});
|
|
40
39
|
|
|
41
40
|
const chainConnectorsAtom = jotai.atom(get => {
|
|
@@ -86,17 +85,32 @@ var packageJson = {
|
|
|
86
85
|
|
|
87
86
|
var log = anylogger__default.default(packageJson.name);
|
|
88
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Converts a dexie Observable into an rxjs Observable.
|
|
90
|
+
*/
|
|
91
|
+
function dexieToRxjs(o) {
|
|
92
|
+
return new rxjs.Observable(observer => {
|
|
93
|
+
const subscription = o.subscribe({
|
|
94
|
+
next: value => observer.next(value),
|
|
95
|
+
error: error => observer.error(error)
|
|
96
|
+
});
|
|
97
|
+
return () => subscription.unsubscribe();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
const tokenRatesAtom = jotai.atom(async get => {
|
|
90
102
|
// runs a timer to keep tokenRates up to date
|
|
91
103
|
get(tokenRatesFetcherAtomEffect);
|
|
92
|
-
return
|
|
104
|
+
return await get(tokenRatesDbAtom);
|
|
93
105
|
});
|
|
94
|
-
|
|
95
|
-
// TODO: Persist to storage
|
|
96
|
-
const tokenRates$ = new rxjs.ReplaySubject(1);
|
|
97
106
|
const tokenRatesDbAtom = utils.atomWithObservable(() => {
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
const dbRatesToMap = dbRates => Object.fromEntries(dbRates.map(({
|
|
108
|
+
tokenId,
|
|
109
|
+
rates
|
|
110
|
+
}) => [tokenId, rates]));
|
|
111
|
+
|
|
112
|
+
// retrieve fetched tokenRates from the db
|
|
113
|
+
return dexieToRxjs(dexie.liveQuery(() => tokenRates.db.tokenRates.toArray())).pipe(rxjs.map(dbRatesToMap));
|
|
100
114
|
});
|
|
101
115
|
const tokenRatesFetcherAtomEffect = jotaiEffect.atomEffect(get => {
|
|
102
116
|
// lets us tear down the existing timer when the effect is restarted
|
|
@@ -107,6 +121,7 @@ const tokenRatesFetcherAtomEffect = jotaiEffect.atomEffect(get => {
|
|
|
107
121
|
const tokensPromise = get(tokensAtom);
|
|
108
122
|
(async () => {
|
|
109
123
|
const tokensById = lodashEs.keyBy(await tokensPromise, "id");
|
|
124
|
+
const tokenIds = Object.keys(tokensById);
|
|
110
125
|
const loopMs = 300_000; // 300_000ms = 300s = 5 minutes
|
|
111
126
|
const retryTimeout = 5_000; // 5_000ms = 5 seconds
|
|
112
127
|
|
|
@@ -114,11 +129,21 @@ const tokenRatesFetcherAtomEffect = jotaiEffect.atomEffect(get => {
|
|
|
114
129
|
try {
|
|
115
130
|
if (abort.signal.aborted) return; // don't fetch if aborted
|
|
116
131
|
const tokenRates$1 = await tokenRates.fetchTokenRates(tokensById, tokenRates.ALL_CURRENCY_IDS, coinsApiConfig);
|
|
117
|
-
const putTokenRates = {
|
|
118
|
-
|
|
119
|
-
|
|
132
|
+
const putTokenRates = Object.entries(tokenRates$1).map(([tokenId, rates]) => ({
|
|
133
|
+
tokenId,
|
|
134
|
+
rates
|
|
135
|
+
}));
|
|
120
136
|
if (abort.signal.aborted) return; // don't insert into db if aborted
|
|
121
|
-
tokenRates
|
|
137
|
+
await tokenRates.db.transaction("rw", tokenRates.db.tokenRates, async () => {
|
|
138
|
+
// override all tokenRates
|
|
139
|
+
await tokenRates.db.tokenRates.bulkPut(putTokenRates);
|
|
140
|
+
|
|
141
|
+
// delete tokenRates for tokens which no longer exist
|
|
142
|
+
const validTokenIds = new Set(tokenIds);
|
|
143
|
+
const tokenRatesIds = await tokenRates.db.tokenRates.toCollection().primaryKeys();
|
|
144
|
+
const deleteIds = tokenRatesIds.filter(id => !validTokenIds.has(id));
|
|
145
|
+
if (deleteIds.length > 0) await tokenRates.db.tokenRates.bulkDelete(deleteIds);
|
|
146
|
+
});
|
|
122
147
|
if (abort.signal.aborted) return; // don't schedule next loop if aborted
|
|
123
148
|
setTimeout(hydrate, loopMs);
|
|
124
149
|
} catch (error) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { atom, useSetAtom, useAtomValue } from 'jotai';
|
|
2
2
|
import { useMemo, useEffect } from 'react';
|
|
3
|
-
import { DEFAULT_COINSAPI_CONFIG,
|
|
3
|
+
import { DEFAULT_COINSAPI_CONFIG, db, fetchTokenRates, ALL_CURRENCY_IDS } from '@talismn/token-rates';
|
|
4
4
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { ChaindataProvider } from '@talismn/chaindata-provider';
|
|
6
6
|
export { evmErc20TokenId, evmNativeTokenId, subAssetTokenId, subNativeTokenId, subPsp22TokenId, subTokensTokenId } from '@talismn/chaindata-provider';
|
|
@@ -12,7 +12,8 @@ import { ChainConnectorEvm } from '@talismn/chain-connector-evm';
|
|
|
12
12
|
import { connectionMetaDb } from '@talismn/connection-meta';
|
|
13
13
|
import { firstThenDebounce, isTruthy, isAbortError } from '@talismn/util';
|
|
14
14
|
import { atomWithObservable } from 'jotai/utils';
|
|
15
|
-
import { combineLatest,
|
|
15
|
+
import { combineLatest, Observable, map } from 'rxjs';
|
|
16
|
+
import { liveQuery } from 'dexie';
|
|
16
17
|
import anylogger from 'anylogger';
|
|
17
18
|
import { cryptoWaitReady } from '@polkadot/util-crypto';
|
|
18
19
|
|
|
@@ -28,9 +29,7 @@ const enabledTokensAtom = atom(undefined);
|
|
|
28
29
|
const allAddressesAtom = atom([]);
|
|
29
30
|
|
|
30
31
|
const chaindataProviderAtom = atom(() => {
|
|
31
|
-
return new ChaindataProvider({
|
|
32
|
-
// TODO pass persistedStorage
|
|
33
|
-
});
|
|
32
|
+
return new ChaindataProvider({});
|
|
34
33
|
});
|
|
35
34
|
|
|
36
35
|
const chainConnectorsAtom = atom(get => {
|
|
@@ -81,17 +80,32 @@ var packageJson = {
|
|
|
81
80
|
|
|
82
81
|
var log = anylogger(packageJson.name);
|
|
83
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Converts a dexie Observable into an rxjs Observable.
|
|
85
|
+
*/
|
|
86
|
+
function dexieToRxjs(o) {
|
|
87
|
+
return new Observable(observer => {
|
|
88
|
+
const subscription = o.subscribe({
|
|
89
|
+
next: value => observer.next(value),
|
|
90
|
+
error: error => observer.error(error)
|
|
91
|
+
});
|
|
92
|
+
return () => subscription.unsubscribe();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
84
96
|
const tokenRatesAtom = atom(async get => {
|
|
85
97
|
// runs a timer to keep tokenRates up to date
|
|
86
98
|
get(tokenRatesFetcherAtomEffect);
|
|
87
|
-
return
|
|
99
|
+
return await get(tokenRatesDbAtom);
|
|
88
100
|
});
|
|
89
|
-
|
|
90
|
-
// TODO: Persist to storage
|
|
91
|
-
const tokenRates$ = new ReplaySubject(1);
|
|
92
101
|
const tokenRatesDbAtom = atomWithObservable(() => {
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
const dbRatesToMap = dbRates => Object.fromEntries(dbRates.map(({
|
|
103
|
+
tokenId,
|
|
104
|
+
rates
|
|
105
|
+
}) => [tokenId, rates]));
|
|
106
|
+
|
|
107
|
+
// retrieve fetched tokenRates from the db
|
|
108
|
+
return dexieToRxjs(liveQuery(() => db.tokenRates.toArray())).pipe(map(dbRatesToMap));
|
|
95
109
|
});
|
|
96
110
|
const tokenRatesFetcherAtomEffect = atomEffect(get => {
|
|
97
111
|
// lets us tear down the existing timer when the effect is restarted
|
|
@@ -102,6 +116,7 @@ const tokenRatesFetcherAtomEffect = atomEffect(get => {
|
|
|
102
116
|
const tokensPromise = get(tokensAtom);
|
|
103
117
|
(async () => {
|
|
104
118
|
const tokensById = keyBy(await tokensPromise, "id");
|
|
119
|
+
const tokenIds = Object.keys(tokensById);
|
|
105
120
|
const loopMs = 300_000; // 300_000ms = 300s = 5 minutes
|
|
106
121
|
const retryTimeout = 5_000; // 5_000ms = 5 seconds
|
|
107
122
|
|
|
@@ -109,11 +124,21 @@ const tokenRatesFetcherAtomEffect = atomEffect(get => {
|
|
|
109
124
|
try {
|
|
110
125
|
if (abort.signal.aborted) return; // don't fetch if aborted
|
|
111
126
|
const tokenRates = await fetchTokenRates(tokensById, ALL_CURRENCY_IDS, coinsApiConfig);
|
|
112
|
-
const putTokenRates = {
|
|
113
|
-
|
|
114
|
-
|
|
127
|
+
const putTokenRates = Object.entries(tokenRates).map(([tokenId, rates]) => ({
|
|
128
|
+
tokenId,
|
|
129
|
+
rates
|
|
130
|
+
}));
|
|
115
131
|
if (abort.signal.aborted) return; // don't insert into db if aborted
|
|
116
|
-
tokenRates
|
|
132
|
+
await db.transaction("rw", db.tokenRates, async () => {
|
|
133
|
+
// override all tokenRates
|
|
134
|
+
await db.tokenRates.bulkPut(putTokenRates);
|
|
135
|
+
|
|
136
|
+
// delete tokenRates for tokens which no longer exist
|
|
137
|
+
const validTokenIds = new Set(tokenIds);
|
|
138
|
+
const tokenRatesIds = await db.tokenRates.toCollection().primaryKeys();
|
|
139
|
+
const deleteIds = tokenRatesIds.filter(id => !validTokenIds.has(id));
|
|
140
|
+
if (deleteIds.length > 0) await db.tokenRates.bulkDelete(deleteIds);
|
|
141
|
+
});
|
|
117
142
|
if (abort.signal.aborted) return; // don't schedule next loop if aborted
|
|
118
143
|
setTimeout(hydrate, loopMs);
|
|
119
144
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talismn/balances-react",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-pr2127-20250806071759",
|
|
4
4
|
"author": "Talisman",
|
|
5
5
|
"homepage": "https://talisman.xyz",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -23,19 +23,21 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"anylogger": "^1.0.11",
|
|
25
25
|
"blueimp-md5": "2.19.0",
|
|
26
|
+
"dexie": "^4.0.9",
|
|
27
|
+
"dexie-react-hooks": "^1.1.7",
|
|
26
28
|
"jotai": "~2",
|
|
27
29
|
"jotai-effect": "~1",
|
|
28
30
|
"lodash-es": "4.17.21",
|
|
29
31
|
"react-use": "^17.5.1",
|
|
30
32
|
"rxjs": "^7.8.1",
|
|
31
|
-
"@talismn/
|
|
32
|
-
"@talismn/chain-connector": "0.0.0-
|
|
33
|
-
"@talismn/
|
|
34
|
-
"@talismn/
|
|
33
|
+
"@talismn/chain-connector-evm": "0.0.0-pr2127-20250806071759",
|
|
34
|
+
"@talismn/chain-connector": "0.0.0-pr2127-20250806071759",
|
|
35
|
+
"@talismn/balances": "0.0.0-pr2127-20250806071759",
|
|
36
|
+
"@talismn/connection-meta": "0.0.0-pr2127-20250806071759",
|
|
37
|
+
"@talismn/chaindata-provider": "0.0.0-pr2127-20250806071759",
|
|
35
38
|
"@talismn/scale": "0.2.0",
|
|
36
|
-
"@talismn/token-rates": "0.0.0-
|
|
37
|
-
"@talismn/
|
|
38
|
-
"@talismn/util": "0.0.0-pr2120-20250805025334"
|
|
39
|
+
"@talismn/token-rates": "0.0.0-pr2127-20250806071759",
|
|
40
|
+
"@talismn/util": "0.5.0"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@types/jest": "^29.5.14",
|