@subwallet/extension-base 1.1.51-1 → 1.1.52-0

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.
Files changed (75) hide show
  1. package/background/KoniTypes.d.ts +1 -0
  2. package/cjs/koni/api/tokens/evm/balance.js +1 -2
  3. package/cjs/koni/api/tokens/evm/transfer.js +3 -5
  4. package/cjs/koni/api/tokens/evm/web3.js +3 -3
  5. package/cjs/koni/background/handlers/Extension.js +5 -4
  6. package/cjs/koni/background/handlers/State.js +21 -122
  7. package/cjs/koni/background/subscription.js +3 -63
  8. package/cjs/packageInfo.js +1 -1
  9. package/cjs/services/balance-service/BalanceMapImpl.js +2 -2
  10. package/cjs/services/balance-service/helpers/index.js +27 -0
  11. package/cjs/services/balance-service/helpers/subscribe/evm.js +33 -15
  12. package/cjs/services/balance-service/helpers/subscribe/{balance.js → index.js} +46 -29
  13. package/cjs/services/balance-service/helpers/subscribe/substrate/equilibrium.js +34 -15
  14. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +156 -72
  15. package/cjs/services/balance-service/index.js +371 -44
  16. package/cjs/services/chain-service/constants.js +2 -1
  17. package/cjs/services/chain-service/health-check/utils/asset-info.js +1 -3
  18. package/cjs/services/chain-service/index.js +60 -26
  19. package/cjs/services/chain-service/utils/index.js +10 -2
  20. package/cjs/services/chain-service/utils/patch.js +1 -1
  21. package/cjs/services/earning-service/handlers/liquid-staking/stella-swap.js +2 -2
  22. package/cjs/services/earning-service/handlers/native-staking/para-chain.js +1 -1
  23. package/cjs/services/migration-service/scripts/AutoEnableChainsTokens.js +1 -1
  24. package/cjs/services/storage-service/DatabaseService.js +10 -1
  25. package/cjs/stores/DetectAccountBalance.js +18 -0
  26. package/cjs/utils/asset.js +19 -0
  27. package/cjs/utils/index.js +12 -0
  28. package/koni/api/tokens/evm/balance.d.ts +1 -1
  29. package/koni/api/tokens/evm/balance.js +1 -2
  30. package/koni/api/tokens/evm/transfer.d.ts +2 -2
  31. package/koni/api/tokens/evm/transfer.js +3 -5
  32. package/koni/api/tokens/evm/web3.d.ts +1 -1
  33. package/koni/api/tokens/evm/web3.js +2 -2
  34. package/koni/background/handlers/Extension.js +5 -4
  35. package/koni/background/handlers/State.d.ts +2 -13
  36. package/koni/background/handlers/State.js +21 -121
  37. package/koni/background/subscription.d.ts +1 -5
  38. package/koni/background/subscription.js +1 -60
  39. package/package.json +28 -13
  40. package/packageInfo.js +1 -1
  41. package/services/balance-service/BalanceMapImpl.js +1 -1
  42. package/services/balance-service/helpers/index.d.ts +2 -0
  43. package/services/balance-service/helpers/index.js +5 -0
  44. package/services/balance-service/helpers/subscribe/evm.d.ts +3 -5
  45. package/services/balance-service/helpers/subscribe/evm.js +31 -14
  46. package/services/balance-service/helpers/subscribe/{balance.d.ts → index.d.ts} +2 -2
  47. package/services/balance-service/helpers/subscribe/{balance.js → index.js} +41 -28
  48. package/services/balance-service/helpers/subscribe/substrate/equilibrium.d.ts +3 -4
  49. package/services/balance-service/helpers/subscribe/substrate/equilibrium.js +29 -13
  50. package/services/balance-service/helpers/subscribe/substrate/index.d.ts +2 -2
  51. package/services/balance-service/helpers/subscribe/substrate/index.js +143 -67
  52. package/services/balance-service/index.d.ts +71 -4
  53. package/services/balance-service/index.js +372 -46
  54. package/services/chain-service/constants.js +2 -1
  55. package/services/chain-service/health-check/utils/asset-info.js +1 -3
  56. package/services/chain-service/index.d.ts +2 -1
  57. package/services/chain-service/index.js +61 -27
  58. package/services/chain-service/types.d.ts +1 -0
  59. package/services/chain-service/utils/index.js +10 -2
  60. package/services/chain-service/utils/patch.js +1 -1
  61. package/services/earning-service/handlers/liquid-staking/stella-swap.js +2 -2
  62. package/services/earning-service/handlers/native-staking/para-chain.js +1 -1
  63. package/services/migration-service/scripts/AutoEnableChainsTokens.js +1 -1
  64. package/services/storage-service/DatabaseService.js +7 -1
  65. package/services/storage-service/databases/index.d.ts +1 -0
  66. package/stores/DetectAccountBalance.d.ts +5 -0
  67. package/stores/DetectAccountBalance.js +10 -0
  68. package/types/{balance.d.ts → balance/index.d.ts} +16 -0
  69. package/types/index.js +1 -1
  70. package/utils/asset.d.ts +2 -0
  71. package/utils/asset.js +12 -0
  72. package/utils/index.d.ts +1 -0
  73. package/utils/index.js +1 -0
  74. /package/cjs/types/{balance.js → balance/index.js} +0 -0
  75. /package/types/{balance.js → balance/index.js} +0 -0
@@ -1,17 +1,50 @@
1
- import { AmountData } from '@subwallet/extension-base/background/KoniTypes';
1
+ import { AmountData, DetectBalanceCache } from '@subwallet/extension-base/background/KoniTypes';
2
2
  import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
3
- import { BalanceItem } from '@subwallet/extension-base/types';
3
+ import { ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
4
+ import { EventItem, EventType } from '@subwallet/extension-base/services/event-service/types';
5
+ import { BalanceItem, BalanceJson } from '@subwallet/extension-base/types';
6
+ import { PromiseHandler } from '@subwallet/extension-base/utils';
7
+ import { BehaviorSubject } from 'rxjs';
4
8
  /**
5
9
  * Balance service
6
10
  * @class
7
11
  */
8
- export declare class BalanceService {
12
+ export declare class BalanceService implements StoppableServiceInterface {
9
13
  private state;
14
+ private balanceMap;
15
+ private balanceUpdateCache;
16
+ startPromiseHandler: PromiseHandler<void>;
17
+ stopPromiseHandler: PromiseHandler<void>;
18
+ status: ServiceStatus;
19
+ private isReload;
20
+ private readonly detectAccountBalanceStore;
21
+ private readonly balanceDetectSubject;
22
+ private readonly intervalTime;
23
+ private readonly cacheTime;
10
24
  /**
11
25
  * @constructor
12
26
  * @param {KoniState} state - The state of extension.
13
27
  */
14
28
  constructor(state: KoniState);
29
+ /** Init service */
30
+ init(): Promise<void>;
31
+ /** Restore balance map */
32
+ loadData(): Promise<void>;
33
+ /** Start service */
34
+ start(): Promise<void>;
35
+ /** Stop service */
36
+ stop(): Promise<void>;
37
+ /** Wait service start */
38
+ waitForStarted(): Promise<void>;
39
+ /** Wait service stop */
40
+ waitForStopped(): Promise<void>;
41
+ /**
42
+ * Handle when data change
43
+ * */
44
+ handleEvents(events: EventItem<EventType>[], eventTypes: EventType[]): void;
45
+ getBalanceDetectCache(update: (value: DetectBalanceCache) => void): void;
46
+ setBalanceDetectCache(addresses: string[]): void;
47
+ /** Subscribe token free balance of a address on chain */
15
48
  subscribeTokenFreeBalance(address: string, chain: string, tokenSlug: string | undefined, callback?: (rs: AmountData) => void): Promise<[() => void, AmountData]>;
16
49
  /**
17
50
  * @public
@@ -24,5 +57,39 @@ export declare class BalanceService {
24
57
  * @return {Promise<AmountData>} - Free token balance of address on chain
25
58
  */
26
59
  getTokenFreeBalance(address: string, chain: string, tokenSlug?: string): Promise<AmountData>;
27
- subscribeBalance(addresses: string[], chains: string[] | null, _callback: (rs: BalanceItem) => void): () => void;
60
+ /** Remove balance from the subject object by addresses */
61
+ removeBalanceByAddresses(addresses: string[]): void;
62
+ /** Remove inactive asset from the balance map */
63
+ removeInactiveChainBalances(): Promise<void>;
64
+ getBalance(reset?: boolean): Promise<BalanceJson>;
65
+ /** Get stored balance from db */
66
+ getStoredBalance(address: string): Promise<BalanceItem[]>;
67
+ handleResetBalance(forceRefresh?: boolean): Promise<void>;
68
+ /**
69
+ * Update value for balance map
70
+ * Note: items must be same tokenSlug */
71
+ setBalanceItem(items: BalanceItem[]): void;
72
+ /**
73
+ * Store balance map to db
74
+ * */
75
+ private updateBalanceStore;
76
+ /**
77
+ * Subscribe balance map with subject object
78
+ * */
79
+ subscribeBalanceMap(): BehaviorSubject<import("@subwallet/extension-base/types").BalanceMap>;
80
+ /** Subscribe area */
81
+ private _unsubscribeBalance;
82
+ /** Subscribe balance subscription */
83
+ runSubscribeBalances(): Promise<void>;
84
+ /** Unsubscribe balance subscription */
85
+ runUnsubscribeBalances(): void;
86
+ /** Reload balance subscription */
87
+ reloadBalance(): Promise<void>;
88
+ /** Subscribe area */
89
+ autoEnableChains(addresses: string[]): Promise<void>;
90
+ private _intervalScan;
91
+ private _unsubscribeBalanceDetectCache;
92
+ private startBalanceDetectCache;
93
+ private startScanBalance;
94
+ private stopScanBalance;
28
95
  }
@@ -3,36 +3,163 @@
3
3
 
4
4
  import { BalanceError } from '@subwallet/extension-base/background/errors/BalanceError';
5
5
  import { BalanceErrorType } from '@subwallet/extension-base/background/KoniTypes';
6
- import { groupBalance } from '@subwallet/extension-base/services/balance-service/helpers/group';
7
- import { subscribeEVMBalance } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/evm';
8
- import { subscribeSubstrateBalance } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/substrate';
9
- import { _PURE_EVM_CHAINS } from '@subwallet/extension-base/services/chain-service/constants';
10
- import { _getChainNativeTokenSlug, _isChainEvmCompatible, _isPureEvmChain } from '@subwallet/extension-base/services/chain-service/utils';
11
- import { categoryAddresses } from '@subwallet/extension-base/utils';
6
+ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
7
+ import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
8
+ import { _getChainNativeTokenSlug } from '@subwallet/extension-base/services/chain-service/utils';
9
+ import DetectAccountBalanceStore from '@subwallet/extension-base/stores/DetectAccountBalance';
10
+ import { addLazy, createPromiseHandler, isAccountAll, waitTimeout } from '@subwallet/extension-base/utils';
11
+ import keyring from '@subwallet/ui-keyring';
12
12
  import { t } from 'i18next';
13
+ import { BehaviorSubject } from 'rxjs';
14
+ import { noop } from '@polkadot/util';
15
+ import { BalanceMapImpl } from "./BalanceMapImpl.js";
16
+ import { subscribeBalance } from "./helpers/index.js";
13
17
 
14
18
  /**
15
19
  * Balance service
16
20
  * @class
17
21
  */
18
22
  export class BalanceService {
23
+ balanceUpdateCache = [];
24
+ startPromiseHandler = createPromiseHandler();
25
+ stopPromiseHandler = createPromiseHandler();
26
+ status = ServiceStatus.NOT_INITIALIZED;
27
+ isReload = false;
28
+ detectAccountBalanceStore = new DetectAccountBalanceStore();
29
+ balanceDetectSubject = new BehaviorSubject({});
30
+ intervalTime = 3 * 60 * 1000;
31
+ cacheTime = 15 * 60 * 1000;
32
+
19
33
  /**
20
34
  * @constructor
21
35
  * @param {KoniState} state - The state of extension.
22
36
  */
23
37
  constructor(state) {
24
38
  this.state = state;
25
- // Todo: Load data from db to balanceSubject
26
- // Todo: Start subscribe balance and data
27
- // Todo: Listen change and apply to balanceSubject
28
- // Todo: Active/Chain
29
- // Todo: Add/remove account
30
- // Todo: Add new account
31
- // Todo: Optimize get balance for single account and chain with cache
32
- // Todo: Move everything of fetching balance to this service
39
+ this.balanceMap = new BalanceMapImpl();
40
+ }
41
+
42
+ /** Init service */
43
+ async init() {
44
+ this.status = ServiceStatus.INITIALIZING;
45
+ await this.state.eventService.waitChainReady;
46
+ await this.state.eventService.waitAccountReady;
47
+
48
+ // Load data from db to balanceSubject
49
+ await this.loadData();
50
+ this.status = ServiceStatus.INITIALIZED;
51
+
52
+ // Start service
53
+ await this.start();
54
+
55
+ // Handle events
56
+ this.state.eventService.onLazy(this.handleEvents.bind(this));
57
+ }
58
+
59
+ /** Restore balance map */
60
+ async loadData() {
61
+ const backupBalanceData = await this.state.dbService.getStoredBalance();
62
+ this.balanceMap.updateBalanceItems(backupBalanceData, true);
63
+ }
64
+
65
+ /** Start service */
66
+ async start() {
67
+ if (this.status === ServiceStatus.STOPPING) {
68
+ await this.waitForStopped();
69
+ }
70
+ if (this.status === ServiceStatus.STARTED || this.status === ServiceStatus.STARTING) {
71
+ return await this.waitForStarted();
72
+ }
73
+ this.status = ServiceStatus.STARTING;
74
+ await this.startScanBalance();
75
+
76
+ // Run subscribe balance
77
+ await this.runSubscribeBalances();
78
+
79
+ // Update status
80
+ this.stopPromiseHandler = createPromiseHandler();
81
+ this.status = ServiceStatus.STARTED;
82
+ this.startPromiseHandler.resolve();
83
+ }
84
+
85
+ /** Stop service */
86
+ async stop() {
87
+ if (this.status === ServiceStatus.STARTING) {
88
+ await this.waitForStarted();
89
+ }
90
+ if (this.status === ServiceStatus.STOPPED || this.status === ServiceStatus.STOPPING) {
91
+ return await this.waitForStopped();
92
+ }
93
+ this.runUnsubscribeBalances();
94
+ this.stopScanBalance();
95
+
96
+ // Update status
97
+ this.startPromiseHandler = createPromiseHandler();
98
+ this.status = ServiceStatus.STOPPING;
99
+ this.stopPromiseHandler.resolve();
100
+ }
101
+
102
+ /** Wait service start */
103
+ waitForStarted() {
104
+ return this.startPromiseHandler.promise;
105
+ }
106
+
107
+ /** Wait service stop */
108
+ waitForStopped() {
109
+ return this.stopPromiseHandler.promise;
110
+ }
111
+
112
+ /**
113
+ * Handle when data change
114
+ * */
115
+ handleEvents(events, eventTypes) {
116
+ const removedAddresses = [];
117
+ let needReload = false;
118
+ let lazyTime = 2000;
119
+
120
+ // Account changed or chain changed (active or inactive)
121
+ if (eventTypes.includes('account.updateCurrent') || eventTypes.includes('account.add') || eventTypes.includes('chain.updateState') || eventTypes.includes('asset.updateState')) {
122
+ needReload = true;
123
+ if (eventTypes.includes('account.updateCurrent')) {
124
+ lazyTime = 1000;
125
+ }
126
+ }
127
+ events.forEach(event => {
128
+ if (event.type === 'account.remove') {
129
+ removedAddresses.push(event.data[0]);
130
+ lazyTime = 1000;
131
+ }
132
+ });
133
+ if (removedAddresses.length > 0) {
134
+ this.balanceMap.removeBalanceItems([...removedAddresses, ALL_ACCOUNT_KEY]); // Add all account key to recalculate all account balances
135
+ needReload = true;
136
+ }
137
+ if (needReload) {
138
+ addLazy('reloadBalanceByEvents', () => {
139
+ if (!this.isReload) {
140
+ this.runSubscribeBalances().catch(console.error);
141
+ }
142
+ }, lazyTime, undefined, true);
143
+ }
144
+ }
145
+ getBalanceDetectCache(update) {
146
+ this.detectAccountBalanceStore.get('DetectBalanceCache', value => {
147
+ update(value);
148
+ });
149
+ }
150
+ setBalanceDetectCache(addresses) {
151
+ this.detectAccountBalanceStore.get('DetectBalanceCache', value => {
152
+ const rs = {
153
+ ...value
154
+ };
155
+ for (const address of addresses) {
156
+ rs[address] = Date.now();
157
+ }
158
+ this.detectAccountBalanceStore.set('DetectBalanceCache', rs);
159
+ });
33
160
  }
34
161
 
35
- /* Subscribe token free balance on chain */
162
+ /** Subscribe token free balance of a address on chain */
36
163
  async subscribeTokenFreeBalance(address, chain, tokenSlug, callback) {
37
164
  const chainInfo = this.state.chainService.getChainInfoByKey(chain);
38
165
  const chainState = this.state.chainService.getChainStateByKey(chain);
@@ -54,7 +181,12 @@ export class BalanceService {
54
181
  }
55
182
  return new Promise((resolve, reject) => {
56
183
  let hasError = true;
57
- const unsub = this.subscribeBalance([address], [chain], rs => {
184
+ const assetMap = this.state.chainService.getAssetRegistry();
185
+ const chainInfoMap = this.state.chainService.getChainInfoMap();
186
+ const evmApiMap = this.state.chainService.getEvmApiMap();
187
+ const substrateApiMap = this.state.chainService.getSubstrateApiMap();
188
+ const unsub = subscribeBalance([address], [chain], [tSlug], assetMap, chainInfoMap, substrateApiMap, evmApiMap, result => {
189
+ const rs = result[0];
58
190
  if (rs.tokenSlug === tSlug) {
59
191
  hasError = false;
60
192
  const balance = {
@@ -94,43 +226,237 @@ export class BalanceService {
94
226
  const [, balance] = await this.subscribeTokenFreeBalance(address, chain, tokenSlug);
95
227
  return balance;
96
228
  }
97
- subscribeBalance(addresses, chains, _callback) {
98
- const [substrateAddresses, evmAddresses] = categoryAddresses(addresses);
229
+
230
+ /** Remove balance from the subject object by addresses */
231
+ removeBalanceByAddresses(addresses) {
232
+ this.balanceMap.removeBalanceItems([...addresses, ALL_ACCOUNT_KEY]);
233
+ }
234
+
235
+ /** Remove inactive asset from the balance map */
236
+ async removeInactiveChainBalances() {
237
+ const assetSettings = await this.state.chainService.getAssetSettings();
238
+ this.balanceMap.removeBalanceItemByFilter(item => {
239
+ return !assetSettings[item.tokenSlug];
240
+ });
241
+ }
242
+ async getBalance(reset) {
243
+ await this.removeInactiveChainBalances();
244
+ return {
245
+ details: this.balanceMap.map,
246
+ reset
247
+ };
248
+ }
249
+
250
+ /** Get stored balance from db */
251
+ async getStoredBalance(address) {
252
+ return await this.state.dbService.stores.balance.getBalanceMapByAddresses(address);
253
+ }
254
+ async handleResetBalance(forceRefresh) {
255
+ if (forceRefresh) {
256
+ this.balanceMap.setData({});
257
+ await this.state.dbService.stores.balance.clear();
258
+ } else {
259
+ await Promise.all([this.removeInactiveChainBalances()]);
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Update value for balance map
265
+ * Note: items must be same tokenSlug */
266
+ setBalanceItem(items) {
267
+ if (items.length) {
268
+ const nowTime = new Date().getTime();
269
+ for (const item of items) {
270
+ const balance = {
271
+ timestamp: nowTime,
272
+ ...item
273
+ };
274
+ this.balanceUpdateCache.push(balance);
275
+ }
276
+ addLazy('updateBalanceStore', () => {
277
+ const isAllAccount = isAccountAll(this.state.keyringService.currentAccount.address);
278
+ this.balanceMap.updateBalanceItems(this.balanceUpdateCache, isAllAccount);
279
+ if (isAllAccount) {
280
+ this.balanceUpdateCache = [...this.balanceUpdateCache, ...Object.values(this.balanceMap.map[ALL_ACCOUNT_KEY])];
281
+ }
282
+ this.updateBalanceStore(this.balanceUpdateCache);
283
+ this.balanceUpdateCache = [];
284
+ }, 300, 1800);
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Store balance map to db
290
+ * */
291
+ updateBalanceStore(items) {
292
+ this.state.dbService.updateBulkBalanceStore(items).catch(console.warn);
293
+ }
294
+
295
+ /**
296
+ * Subscribe balance map with subject object
297
+ * */
298
+ subscribeBalanceMap() {
299
+ return this.balanceMap.mapSubject;
300
+ }
301
+
302
+ /** Subscribe area */
303
+
304
+ /** Subscribe balance subscription */
305
+ async runSubscribeBalances() {
306
+ await Promise.all([this.state.eventService.waitKeyringReady, this.state.eventService.waitChainReady]);
307
+ this.runUnsubscribeBalances();
308
+ const addresses = this.state.getDecodedAddresses();
309
+ if (!addresses.length) {
310
+ return;
311
+ }
312
+
313
+ // Reset balance before subscribe
314
+ await this.handleResetBalance();
315
+ let cancel = false;
316
+ const assetMap = this.state.chainService.getAssetRegistry();
99
317
  const chainInfoMap = this.state.chainService.getChainInfoMap();
100
- const chainStateMap = this.state.chainService.getChainStateMap();
101
- const substrateApiMap = this.state.chainService.getSubstrateApiMap();
102
318
  const evmApiMap = this.state.chainService.getEvmApiMap();
319
+ const substrateApiMap = this.state.chainService.getSubstrateApiMap();
320
+ const activeChainSlugs = Object.keys(this.state.getActiveChainInfoMap());
321
+ const assetState = this.state.chainService.subscribeAssetSettings().value;
322
+ const assets = Object.values(assetMap).filter(asset => {
323
+ var _assetState$asset$slu;
324
+ return activeChainSlugs.includes(asset.originChain) && ((_assetState$asset$slu = assetState[asset.slug]) === null || _assetState$asset$slu === void 0 ? void 0 : _assetState$asset$slu.visible);
325
+ }).map(asset => asset.slug);
326
+ const unsub = subscribeBalance(addresses, activeChainSlugs, assets, assetMap, chainInfoMap, substrateApiMap, evmApiMap, result => {
327
+ !cancel && this.setBalanceItem(result);
328
+ });
329
+ const unsub2 = this.state.subscribeMantaPayBalance();
330
+ this._unsubscribeBalance = () => {
331
+ cancel = true;
332
+ unsub && unsub();
333
+ unsub2 && unsub2();
334
+ };
335
+ }
336
+
337
+ /** Unsubscribe balance subscription */
338
+ runUnsubscribeBalances() {
339
+ this._unsubscribeBalance && this._unsubscribeBalance();
340
+ this._unsubscribeBalance = undefined;
341
+ }
342
+
343
+ /** Reload balance subscription */
344
+ async reloadBalance() {
345
+ this.isReload = true;
346
+ await this.handleResetBalance(true);
347
+ await this.runSubscribeBalances();
348
+ await waitTimeout(1800);
349
+ this.isReload = false;
350
+ }
103
351
 
104
- // Get data from chain or all chains
105
- const chainList = chains || Object.keys(chainInfoMap);
106
- // Filter active chain only
107
- const useChainInfos = chainList.filter(c => chainStateMap[c] && chainStateMap[c].active).map(c => chainInfoMap[c]);
108
- const callback = items => {
109
- if (items.length) {
110
- _callback(groupBalance(items, 'GROUPED', items[0].tokenSlug));
352
+ /** Subscribe area */
353
+
354
+ async autoEnableChains(addresses) {
355
+ this.setBalanceDetectCache(addresses);
356
+ const assetMap = this.state.chainService.getAssetRegistry();
357
+ const promiseList = addresses.map(address => {
358
+ return this.state.subscanService.getMultiChainBalance(address).catch(e => {
359
+ console.error(e);
360
+ return null;
361
+ });
362
+ });
363
+ const needEnableChains = [];
364
+ const needActiveTokens = [];
365
+ const balanceDataList = await Promise.all(promiseList);
366
+ const currentAssetSettings = await this.state.chainService.getAssetSettings();
367
+ const chainInfoMap = this.state.chainService.getChainInfoMap();
368
+ const detectBalanceChainSlugMap = this.state.chainService.detectBalanceChainSlugMap;
369
+ for (const balanceData of balanceDataList) {
370
+ if (balanceData) {
371
+ for (const balanceDatum of balanceData) {
372
+ var _currentAssetSettings;
373
+ const {
374
+ balance,
375
+ bonded,
376
+ category,
377
+ locked,
378
+ network,
379
+ symbol
380
+ } = balanceDatum;
381
+ const chain = detectBalanceChainSlugMap[network];
382
+ const chainInfo = chain ? chainInfoMap[chain] : null;
383
+ const chainState = this.state.chainService.getChainStateByKey(chain);
384
+ const balanceIsEmpty = (!balance || balance === '0') && (!locked || locked === '0') && (!bonded || bonded === '0');
385
+ const tokenKey = `${chain}-${category === 'native' ? 'NATIVE' : 'LOCAL'}-${symbol.toUpperCase()}`;
386
+ const existedKey = Object.keys(assetMap).find(v => v.toLowerCase() === tokenKey.toLowerCase());
387
+
388
+ // Cancel if chain is not supported or is testnet
389
+ if (!chainInfo || chainInfo.isTestnet) {
390
+ continue;
391
+ }
392
+
393
+ // Cancel is balance is 0
394
+ if (balanceIsEmpty) {
395
+ continue;
396
+ }
397
+
398
+ // Cancel is chain is turned off by user
399
+ if (chainState && chainState.manualTurnOff) {
400
+ continue;
401
+ }
402
+
403
+ // const a = this.state.chainService.getChainStateByKey(chain);
404
+
405
+ if (existedKey && !((_currentAssetSettings = currentAssetSettings[existedKey]) !== null && _currentAssetSettings !== void 0 && _currentAssetSettings.visible)) {
406
+ needEnableChains.push(chain);
407
+ needActiveTokens.push(existedKey);
408
+ currentAssetSettings[existedKey] = {
409
+ visible: true
410
+ };
411
+ }
412
+ }
111
413
  }
414
+ }
415
+ if (needActiveTokens.length) {
416
+ await this.state.chainService.enableChains(needEnableChains);
417
+ this.state.chainService.setAssetSettings({
418
+ ...currentAssetSettings
419
+ });
420
+ }
421
+ }
422
+ async startScanBalance() {
423
+ var _this$startBalanceDet2;
424
+ await Promise.all([this.state.eventService.waitAccountReady, this.state.eventService.waitChainReady]);
425
+ this.stopScanBalance();
426
+ this.startBalanceDetectCache = createPromiseHandler();
427
+ const updateBalanceDetectCache = value => {
428
+ var _this$startBalanceDet;
429
+ (_this$startBalanceDet = this.startBalanceDetectCache) === null || _this$startBalanceDet === void 0 ? void 0 : _this$startBalanceDet.resolve();
430
+ this.balanceDetectSubject.next(value || {});
112
431
  };
113
-
114
- // Looping over each chain
115
- const unsubList = useChainInfos.map(async chainInfo => {
116
- const chainSlug = chainInfo.slug;
117
- const useAddresses = _isChainEvmCompatible(chainInfo) ? evmAddresses : substrateAddresses;
118
- if (_isPureEvmChain(chainInfo)) {
119
- const nativeTokenInfo = this.state.getNativeTokenInfo(chainSlug);
120
- return subscribeEVMBalance(chainSlug, useAddresses, evmApiMap, callback, nativeTokenInfo);
432
+ this.getBalanceDetectCache(updateBalanceDetectCache);
433
+ const subscription = this.detectAccountBalanceStore.getSubject().subscribe({
434
+ next: updateBalanceDetectCache
435
+ });
436
+ this._unsubscribeBalanceDetectCache = subscription.unsubscribe;
437
+ const scanBalance = () => {
438
+ const addresses = keyring.getPairs().map(account => account.address);
439
+ const cache = this.balanceDetectSubject.value;
440
+ const now = Date.now();
441
+ const needDetectAddresses = [];
442
+ for (const address of addresses) {
443
+ if (!cache[address] || now - cache[address] > this.cacheTime) {
444
+ needDetectAddresses.push(address);
445
+ }
121
446
  }
122
- if (!useAddresses || useAddresses.length === 0 || _PURE_EVM_CHAINS.indexOf(chainSlug) > -1) {
123
- return undefined;
447
+ if (needDetectAddresses.length) {
448
+ this.autoEnableChains(needDetectAddresses).finally(noop);
124
449
  }
125
- const networkAPI = await substrateApiMap[chainSlug].isReady;
126
- return subscribeSubstrateBalance(useAddresses, chainInfo, chainSlug, networkAPI, evmApiMap, callback);
127
- });
128
- return () => {
129
- unsubList.forEach(subProm => {
130
- subProm.then(unsub => {
131
- unsub && unsub();
132
- }).catch(console.error);
133
- });
134
450
  };
451
+ await ((_this$startBalanceDet2 = this.startBalanceDetectCache) === null || _this$startBalanceDet2 === void 0 ? void 0 : _this$startBalanceDet2.promise);
452
+ scanBalance();
453
+ this._intervalScan = setInterval(scanBalance, this.intervalTime);
454
+ }
455
+ stopScanBalance() {
456
+ this._intervalScan && clearInterval(this._intervalScan);
457
+ this._unsubscribeBalanceDetectCache && this._unsubscribeBalanceDetectCache();
458
+ this._intervalScan = undefined;
459
+ this._unsubscribeBalanceDetectCache = undefined;
460
+ this.startBalanceDetectCache = undefined;
135
461
  }
136
462
  }
@@ -240,7 +240,8 @@ export const _DEFAULT_ACTIVE_CHAINS = [..._DEFAULT_CHAINS, 'vara_network'];
240
240
  export const EVM_PASS_CONNECT_STATUS = {
241
241
  arbitrum_one: ['*'],
242
242
  okxTest: ['*'],
243
- astarZkEvm: ['*']
243
+ astarZkEvm: ['*'],
244
+ xlayer: ['*']
244
245
  };
245
246
  export const EVM_REFORMAT_DECIMALS = {
246
247
  acala: ['acala_evm', 'karura_evm']
@@ -216,9 +216,7 @@ export const getEvmNativeInfo = async api => {
216
216
  };
217
217
  export const getErc20AssetInfo = async (asset, api) => {
218
218
  const contractAddress = _getContractAddressOfToken(asset);
219
- const tokenContract = getERC20Contract('chain', contractAddress, {
220
- chain: api
221
- });
219
+ const tokenContract = getERC20Contract(contractAddress, api);
222
220
  const [_decimals, _symbol, _name] = await Promise.all([
223
221
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
224
222
  tokenContract.methods.decimals().call(),
@@ -83,7 +83,7 @@ export declare class ChainService {
83
83
  initAssetRefMap(): void;
84
84
  checkLatestData(): void;
85
85
  stopCheckLatestChainData(): void;
86
- handleLatestProviderData(latestChainInfo: _ChainInfo[]): void;
86
+ handleLatestChainData(latestChainInfo: _ChainInfo[]): void;
87
87
  handleLatestAssetRef(latestBlockedAssetRefList: string[], latestAssetRefMap: Record<string, _AssetRef> | null): void;
88
88
  handleLatestPriceId(latestPriceIds: Record<string, string | null>): void;
89
89
  handleLatestAssetData(latestAssetInfo: Record<string, _ChainAsset> | null, latestAssetLogoMap: Record<string, string> | null): void;
@@ -138,4 +138,5 @@ export declare class ChainService {
138
138
  upsertMetadata(chain: string, metadata: IMetadataItem): import("dexie").PromiseExtended<unknown>;
139
139
  getMetadataByHash(hash: string): import("dexie").PromiseExtended<IMetadataItem | undefined>;
140
140
  getSubscanChainMap(reverse?: boolean): Record<string, string>;
141
+ get detectBalanceChainSlugMap(): Record<string, string>;
141
142
  }