From d72ddfd5e35e1882e25f5865bf4c2f7546435e1f Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:57:04 +0700 Subject: [PATCH 01/14] [Issue-3132] feat: handle lastest chain, asset, multi-chain asset --- packages/extension-base/package.json | 1 + .../src/services/chain-service/index.ts | 246 ++++++++++++------ .../src/services/chain-service/utils/patch.ts | 17 +- yarn.lock | 8 + 4 files changed, 186 insertions(+), 86 deletions(-) diff --git a/packages/extension-base/package.json b/packages/extension-base/package.json index 48b6709c6d..24a6af4a63 100644 --- a/packages/extension-base/package.json +++ b/packages/extension-base/package.json @@ -93,6 +93,7 @@ "protobufjs": "^7.2.4", "rxjs": "^7.8.1", "sails-js": "^0.1.6", + "ts-md5": "^1.3.1", "tweetnacl": "^1.0.3", "uuid": "^9.0.0", "web3": "^1.10.0", diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index a2c8390c87..629a96655c 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -11,13 +11,14 @@ import { SubstrateChainHandler } from '@subwallet/extension-base/services/chain- import { TonChainHandler } from '@subwallet/extension-base/services/chain-service/handler/TonChainHandler'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainApiStatus, _ChainConnectionStatus, _ChainState, _CUSTOM_PREFIX, _DataMap, _EvmApi, _NetworkUpsertParams, _NFT_CONTRACT_STANDARDS, _SMART_CONTRACT_STANDARDS, _SmartContractTokenInfo, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse } from '@subwallet/extension-base/services/chain-service/types'; -import { _isAssetAutoEnable, _isAssetCanPayTxFee, _isAssetFungibleToken, _isChainEnabled, _isCustomAsset, _isCustomChain, _isCustomProvider, _isEqualContractAddress, _isEqualSmartContractAsset, _isLocalToken, _isMantaZkAsset, _isPureEvmChain, _isPureSubstrateChain, _parseAssetRefKey, fetchPatchData, randomizeProvider, updateLatestChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isAssetAutoEnable, _isAssetCanPayTxFee, _isAssetFungibleToken, _isChainEnabled, _isCustomAsset, _isCustomChain, _isCustomProvider, _isEqualContractAddress, _isEqualSmartContractAsset, _isLocalToken, _isMantaZkAsset, _isPureEvmChain, _isPureSubstrateChain, _parseAssetRefKey, fetchPatchData, PatchInfo, randomizeProvider, updateLatestChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { EventService } from '@subwallet/extension-base/services/event-service'; import { IChain, IMetadataItem } from '@subwallet/extension-base/services/storage-service/databases'; import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService'; import AssetSettingStore from '@subwallet/extension-base/stores/AssetSetting'; import { addLazy, calculateMetadataHash, fetchStaticData, filterAssetsByChainAndType, getShortMetadata, MODULE_SUPPORT } from '@subwallet/extension-base/utils'; import { BehaviorSubject, Subject } from 'rxjs'; +import { Md5 } from 'ts-md5'; import Web3 from 'web3'; import { logger as createLogger } from '@polkadot/util/logger'; @@ -108,8 +109,9 @@ export class ChainService { private assetLogoMapSubject = new BehaviorSubject>(AssetLogoMap); private chainLogoMapSubject = new BehaviorSubject>(ChainLogoMap); private ledgerGenericAllowChainsSubject = new BehaviorSubject([]); - private assetMapPatch: string = JSON.stringify({}); - private assetLogoPatch: string = JSON.stringify({}); + // private assetMapPatch: string = JSON.stringify({}); + // private assetLogoPatch: string = JSON.stringify({}); + private appliedPatchVersion = ''; // Todo: Update to new store indexed DB private store: AssetSettingStore = new AssetSettingStore(); @@ -698,73 +700,50 @@ export class ChainService { clearInterval(this.refreshLatestChainDataTimeOut); } - handleLatestChainData (latestChainInfo: _ChainInfo[]) { - try { - if (latestChainInfo && latestChainInfo.length > 0) { - const { needUpdateChainApiList, storedChainInfoList } = updateLatestChainInfo(this.dataMap, latestChainInfo); - - this.dbService.bulkUpdateChainStore(storedChainInfoList).catch(console.error); - this.updateChainSubscription(); + validatePatchWithHash (latestPatch: PatchInfo) { + const { ChainAsset, ChainAssetHashMap, ChainInfo, ChainInfoHashMap, MultiChainAsset, MultiChainAssetHashMap } = latestPatch; - needUpdateChainApiList.forEach((chainInfo) => { - console.log('Updating chain API for', chainInfo.slug); - this.initApiForChain(chainInfo).catch(console.error); - }); + for (const [chainSlug, chain] of Object.entries(ChainInfo)) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { chainStatus, providers, ...chainWithoutProvidersAndStatus } = chain; - this.logger.log('Finished updating latest RPC providers'); + if (Md5.hashStr(JSON.stringify(chainWithoutProvidersAndStatus)) !== ChainInfoHashMap[chainSlug]) { + return false; } - } catch (e) { - console.error('Error fetching latest chain data'); } - } - handleLatestAssetRef (latestBlockedAssetRefList: string[], latestAssetRefMap: Record | null) { - const updatedAssetRefMap: Record = { ...AssetRefMap }; - - if (latestAssetRefMap) { - for (const [assetRefKey, assetRef] of Object.entries(latestAssetRefMap)) { - updatedAssetRefMap[assetRefKey] = assetRef; + for (const [assetSlug, asset] of Object.entries(ChainAsset)) { + if (Md5.hashStr(JSON.stringify(asset)) !== ChainAssetHashMap[assetSlug]) { + return false; } } - latestBlockedAssetRefList.forEach((blockedAssetRef) => { - delete updatedAssetRefMap[blockedAssetRef]; - }); - - this.dataMap.assetRefMap = updatedAssetRefMap; - - this.xcmRefMapSubject.next(this.xcmRefMap); - this.swapRefMapSubject.next(this.swapRefMap); - this.logger.log('Finished updating latest asset ref'); - } - - handleLatestPriceId (latestPriceIds: Record) { - let isUpdated = false; - - Object.entries(latestPriceIds).forEach(([slug, priceId]) => { - if (this.dataMap.assetRegistry[slug] && this.dataMap.assetRegistry[slug].priceId !== priceId) { - isUpdated = true; - this.dataMap.assetRegistry[slug].priceId = priceId; + for (const [mAssetSlug, mAsset] of Object.entries(MultiChainAsset)) { + if (Md5.hashStr(JSON.stringify(mAsset)) !== MultiChainAssetHashMap[mAssetSlug]) { + return false; } - }); - - if (isUpdated) { - this.assetRegistrySubject.next(this.dataMap.assetRegistry); - this.eventService.emit('asset.updateState', ''); } - this.logger.log('Finished updating latest price IDs'); + return true; } - handleLatestAssetData (latestAssetInfo: Record | null, latestAssetLogoMap: Record | null) { + handleLatestPatch (latestPatch: PatchInfo) { try { - if (latestAssetInfo) { - const latestAssetPatch = JSON.stringify(latestAssetInfo); + const isSafePatch = this.validatePatchWithHash(latestPatch); + const { ChainAsset: latestAssetInfo, ChainInfo: latestChainInfo, MultiChainAsset: latestMultiChainAsset, appliedVersion } = latestPatch; + // todo: AssetLogoMap, ChainLogoMap + + if (isSafePatch && this.appliedPatchVersion !== appliedVersion) { + if (latestChainInfo && Object.keys(latestChainInfo).length > 0) { + const chainInfoMap = Object.assign({}, this.dataMap.chainInfoMap, latestChainInfo); + + this.dataMap.chainInfoMap = chainInfoMap; + this.chainInfoMapSubject.next(chainInfoMap); + } - if (this.assetMapPatch !== latestAssetPatch) { + if (latestAssetInfo && Object.keys(latestAssetInfo).length > 0) { const assetRegistry = filterAssetInfoMap(this.getChainInfoMap(), Object.assign({}, this.dataMap.assetRegistry, latestAssetInfo)); - this.assetMapPatch = latestAssetPatch; this.dataMap.assetRegistry = assetRegistry; this.assetRegistrySubject.next(assetRegistry); @@ -774,38 +753,121 @@ export class ChainService { }) .catch(console.error); } - } - - if (latestAssetLogoMap) { - const latestAssetLogoPatch = JSON.stringify(latestAssetLogoMap); - if (this.assetLogoPatch !== latestAssetLogoPatch) { - const logoMap = { ...AssetLogoMap, ...latestAssetLogoMap }; + if (latestMultiChainAsset && Object.keys(latestMultiChainAsset).length > 0) { + const multiChainAssetMap = { ...MultiChainAssetMap, ...latestMultiChainAsset }; - this.assetLogoPatch = latestAssetLogoPatch; - this.assetLogoMapSubject.next(logoMap); + this.multiChainAssetMapSubject.next(multiChainAssetMap); } + + this.appliedPatchVersion = appliedVersion; } + } catch (e) { + console.error('Error fetching latest patch data'); + } - if (latestAssetLogoMap) { - const latestAssetLogoPatch = JSON.stringify(latestAssetLogoMap); + this.eventService.emit('asset.online.ready', true); - if (this.assetLogoPatch !== latestAssetLogoPatch) { - const logoMap = { ...AssetLogoMap, ...latestAssetLogoMap }; + this.logger.log('Finished updating latest asset'); + } - this.assetLogoPatch = latestAssetLogoPatch; - this.assetLogoMapSubject.next(logoMap); - } + handleLatestChainData (latestChainInfo: _ChainInfo[]) { + try { + if (latestChainInfo && latestChainInfo.length > 0) { + const { needUpdateChainApiList, storedChainInfoList } = updateLatestChainInfo(this.dataMap, latestChainInfo); + + this.dbService.bulkUpdateChainStore(storedChainInfoList).catch(console.error); + this.updateChainSubscription(); + + needUpdateChainApiList.forEach((chainInfo) => { + console.log('Updating chain API for', chainInfo.slug); + this.initApiForChain(chainInfo).catch(console.error); + }); + + this.logger.log('Finished updating latest RPC providers'); } } catch (e) { - console.error('Error fetching latest asset data'); + console.error('Error fetching latest chain data'); } + } - this.eventService.emit('asset.online.ready', true); + // handleLatestAssetRef (latestBlockedAssetRefList: string[], latestAssetRefMap: Record | null) { + // const updatedAssetRefMap: Record = { ...AssetRefMap }; + // + // if (latestAssetRefMap) { + // for (const [assetRefKey, assetRef] of Object.entries(latestAssetRefMap)) { + // updatedAssetRefMap[assetRefKey] = assetRef; + // } + // } + // + // latestBlockedAssetRefList.forEach((blockedAssetRef) => { + // delete updatedAssetRefMap[blockedAssetRef]; + // }); + // + // this.dataMap.assetRefMap = updatedAssetRefMap; + // + // this.xcmRefMapSubject.next(this.xcmRefMap); + // this.swapRefMapSubject.next(this.swapRefMap); + // this.logger.log('Finished updating latest asset ref'); + // } - this.logger.log('Finished updating latest asset'); + handleLatestPriceId (latestPriceIds: Record) { + let isUpdated = false; + + Object.entries(latestPriceIds).forEach(([slug, priceId]) => { + if (this.dataMap.assetRegistry[slug] && this.dataMap.assetRegistry[slug].priceId !== priceId) { + isUpdated = true; + this.dataMap.assetRegistry[slug].priceId = priceId; + } + }); + + if (isUpdated) { + this.assetRegistrySubject.next(this.dataMap.assetRegistry); + this.eventService.emit('asset.updateState', ''); + } + + this.logger.log('Finished updating latest price IDs'); } + // handleLatestAssetData (latestAssetInfo: Record | null, latestAssetLogoMap: Record | null) { + // try { + // if (latestAssetInfo) { + // const latestAssetPatch = JSON.stringify(latestAssetInfo); + // + // if (this.assetMapPatch !== latestAssetPatch) { + // const assetRegistry = filterAssetInfoMap(this.getChainInfoMap(), Object.assign({}, this.dataMap.assetRegistry, latestAssetInfo)); + // + // this.assetMapPatch = latestAssetPatch; + // this.dataMap.assetRegistry = assetRegistry; + // this.assetRegistrySubject.next(assetRegistry); + // + // this.autoEnableTokens() + // .then(() => { + // this.eventService.emit('asset.updateState', ''); + // }) + // .catch(console.error); + // } + // } + // + // if (latestAssetLogoMap) { + // const latestAssetLogoPatch = JSON.stringify(latestAssetLogoMap); + // + // if (this.assetLogoPatch !== latestAssetLogoPatch) { + // const logoMap = { ...AssetLogoMap, ...latestAssetLogoMap }; + // + // this.assetLogoPatch = latestAssetLogoPatch; + // this.assetLogoMapSubject.next(logoMap); + // } + // } + // } catch (e) { + // console.error('Error fetching latest asset data'); + // } + // + // this.eventService.emit('asset.online.ready', true); + // + // this.logger.log('Finished updating latest asset'); + // } + async autoEnableTokens () { const autoEnableTokens = Object.values(this.dataMap.assetRegistry).filter((asset) => _isAssetAutoEnable(asset)); @@ -836,21 +898,31 @@ export class ChainService { } handleLatestData () { - this.fetchLatestAssetData().then(([latestAssetInfo, latestAssetLogoMap]) => { - this.eventService.waitAssetReady - .then(() => { - this.handleLatestAssetData(latestAssetInfo, latestAssetLogoMap); - }) - .catch(console.error); + // this.fetchLatestAssetData().then(([latestAssetInfo, latestAssetLogoMap]) => { + // this.eventService.waitAssetReady + // .then(() => { + // this.handleLatestAssetData(latestAssetInfo, latestAssetLogoMap); + // }) + // .catch(console.error); + // }).catch(console.error); + + this.fetchLatestPatchData().then((latestPatch) => { + if (latestPatch) { + this.eventService.waitAssetReady + .then(() => { + this.handleLatestPatch(latestPatch); + }) + .catch(console.error); + } }).catch(console.error); this.fetchLatestChainData().then((latestChainInfo) => { this.handleLatestChainData(latestChainInfo); }).catch(console.error); - this.fetchLatestAssetRef().then(([latestAssetRef, latestAssetRefMap]) => { - this.handleLatestAssetRef(latestAssetRef, latestAssetRefMap); - }).catch(console.error); + // this.fetchLatestAssetRef().then(([latestAssetRef, latestAssetRefMap]) => { + // this.handleLatestAssetRef(latestAssetRef, latestAssetRefMap); + // }).catch(console.error); this.fetchLatestPriceIdsData().then((latestPriceIds) => { this.handleLatestPriceId(latestPriceIds); @@ -1154,8 +1226,12 @@ export class ChainService { // } } - private async fetchLatestAssetData () { - return await Promise.all([fetchPatchData>('ChainAsset.json'), fetchPatchData>('AssetLogoMap.json')]); + // private async fetchLatestAssetData () { + // return await Promise.all([fetchPatchData>('ChainAsset.json'), fetchPatchData>('AssetLogoMap.json')]); // lastest logo also here. + // } + + private async fetchLatestPatchData () { + return await fetchPatchData('data.json'); } // @ts-ignore @@ -1163,9 +1239,9 @@ export class ChainService { return await fetchStaticData>('chain-assets/price-map'); } - private async fetchLatestAssetRef () { - return await Promise.all([fetchStaticData('chain-assets/disabled-xcm-channels'), fetchPatchData>('AssetRef.json')]); - } + // private async fetchLatestAssetRef () { + // return await Promise.all([fetchStaticData('chain-assets/disabled-xcm-channels'), fetchPatchData>('AssetRef.json')]); // + // } private async fetchLatestLedgerGenericAllowChains () { return await fetchStaticData('chains/ledger-generic-allow-chains') || []; diff --git a/packages/extension-base/src/services/chain-service/utils/patch.ts b/packages/extension-base/src/services/chain-service/utils/patch.ts index 9b83cd93de..d1d84c42f9 100644 --- a/packages/extension-base/src/services/chain-service/utils/patch.ts +++ b/packages/extension-base/src/services/chain-service/utils/patch.ts @@ -1,11 +1,26 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 +import { _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; + const PRODUCTION_BRANCHES = ['master', 'webapp', 'webapp-dev']; const branchName = process.env.BRANCH_NAME || 'subwallet-dev'; const fetchDomain = PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'https://chain-list-assets.subwallet.app' : 'https://dev.sw-chain-list-assets.pages.dev'; -const ChainListVersion = '0.2.62'; +const ChainListVersion = '0.2.92'; + +// todo: move this interface to chainlist +export interface PatchInfo { + patchVersion: string, + appliedVersion: string, + fetchedDate: string, + ChainInfo: Record, + ChainInfoHashMap: Record, + ChainAsset: Record, + ChainAssetHashMap: Record, + MultiChainAsset: Record, + MultiChainAssetHashMap: Record +} export async function fetchPatchData (slug: string) { try { diff --git a/yarn.lock b/yarn.lock index 9607b5d8b5..2e5fcbdbfc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6355,6 +6355,7 @@ __metadata: protobufjs: ^7.2.4 rxjs: ^7.8.1 sails-js: ^0.1.6 + ts-md5: ^1.3.1 tweetnacl: ^1.0.3 uuid: ^9.0.0 web3: ^1.10.0 @@ -27080,6 +27081,13 @@ __metadata: languageName: node linkType: hard +"ts-md5@npm:^1.3.1": + version: 1.3.1 + resolution: "ts-md5@npm:1.3.1" + checksum: 88fc4df837e17949fef92a8e71a0691b20e2f8b02a002876a162a102e7c9d364f1eb00cbd217f9578fec5fa07bb66ffa14ed054cdfe164486fab2173c8e9ea23 + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.10.1, tsconfig-paths@npm:^3.14.1": version: 3.14.1 resolution: "tsconfig-paths@npm:3.14.1" From b8087e03c871964c8116c4f6fccfc9951bdd345b Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:23:44 +0700 Subject: [PATCH 02/14] [Issue-3132] temp --- .../src/koni/background/handlers/State.ts | 5 + .../services/chain-online-service/index.ts | 170 ++++++++++++++++++ .../src/services/chain-service/index.ts | 101 ++--------- 3 files changed, 185 insertions(+), 91 deletions(-) create mode 100644 packages/extension-base/src/services/chain-online-service/index.ts diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index b79a3f7871..5849323bfc 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -14,6 +14,7 @@ import { BalanceService } from '@subwallet/extension-base/services/balance-servi import { ServiceStatus } from '@subwallet/extension-base/services/base/types'; import BuyService from '@subwallet/extension-base/services/buy-service'; import CampaignService from '@subwallet/extension-base/services/campaign-service'; +import { ChainOnlineService } from '@subwallet/extension-base/services/chain-online-service'; import { ChainService } from '@subwallet/extension-base/services/chain-service'; import { _DEFAULT_MANTA_ZK_CHAIN, _MANTA_ZK_CHAIN_GROUP, _PREDEFINED_SINGLE_MODES } from '@subwallet/extension-base/services/chain-service/constants'; import { _ChainState, _NetworkUpsertParams, _ValidateCustomAssetRequest } from '@subwallet/extension-base/services/chain-service/types'; @@ -132,6 +133,7 @@ export default class KoniState { readonly feeService: FeeService; readonly swapService: SwapService; readonly inappNotificationService: InappNotificationService; + readonly chainOnlineService: ChainOnlineService; // Handle the general status of the extension private generalStatus: ServiceStatus = ServiceStatus.INITIALIZING; @@ -165,6 +167,7 @@ export default class KoniState { this.feeService = new FeeService(this); this.swapService = new SwapService(this); this.inappNotificationService = new InappNotificationService(this.dbService, this.keyringService, this.eventService, this.chainService); + this.chainOnlineService = new ChainOnlineService(this.chainService, this.eventService); this.subscription = new KoniSubscription(this, this.dbService); this.cron = new KoniCron(this, this.subscription, this.dbService); @@ -303,6 +306,7 @@ export default class KoniState { await this.startSubscription(); this.chainService.checkLatestData(); + this.chainOnlineService.checkLatestData(); } public async initMantaPay (password: string) { @@ -1640,6 +1644,7 @@ export default class KoniState { this.afterChainServiceInit(); this.chainService.checkLatestData(); + this.chainOnlineService.checkLatestData(); } public async enableMantaPay (updateStore: boolean, address: string, password: string, seedPhrase?: string) { diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts new file mode 100644 index 0000000000..709aa34fa1 --- /dev/null +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -0,0 +1,170 @@ +// [object Object] +// SPDX-License-Identifier: Apache-2.0 + +import { MultiChainAssetMap } from '@subwallet/chain-list'; +import { _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; +import { ChainService, filterAssetInfoMap } from '@subwallet/extension-base/services/chain-service'; +import { LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; +import { fetchPatchData, PatchInfo } from '@subwallet/extension-base/services/chain-service/utils'; +import { EventService } from '@subwallet/extension-base/services/event-service'; +import { Md5 } from 'ts-md5'; + +export class ChainOnlineService { + private chainService: ChainService; + private eventService: EventService; + + refreshLatestChainDataTimeOut: NodeJS.Timer | undefined; + private patchVersion = ''; + + constructor (chainService: ChainService, eventService: EventService) { + this.chainService = chainService; + this.eventService = eventService; + } + + md5Hash (data: any) { + return Md5.hashStr(JSON.stringify(data)); + } + + validatePatchWithHash (latestPatch: PatchInfo) { + const { ChainAsset, ChainAssetHashMap, ChainInfo, ChainInfoHashMap, MultiChainAsset, MultiChainAssetHashMap } = latestPatch; + + for (const [chainSlug, chain] of Object.entries(ChainInfo)) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { chainStatus, providers, ...chainWithoutProvidersAndStatus } = chain; + + if (this.md5Hash(chainWithoutProvidersAndStatus) !== ChainInfoHashMap[chainSlug]) { + return false; + } + } + + for (const [assetSlug, asset] of Object.entries(ChainAsset)) { + if (this.md5Hash(asset) !== ChainAssetHashMap[assetSlug]) { + return false; + } + } + + for (const [mAssetSlug, mAsset] of Object.entries(MultiChainAsset)) { + if (this.md5Hash(mAsset) !== MultiChainAssetHashMap[mAssetSlug]) { + return false; + } + } + + return true; + } + + validatePatchBeforeStore (candidateChainInfoMap: Record, candidateAssetRegistry: Record, candidateMultiChainAssetMap: Record, latestPatch: PatchInfo) { + for (const [chainSlug, chainHash] of Object.entries(latestPatch.ChainInfoHashMap)) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { chainStatus, providers, ...chainWithoutProvidersAndStatus } = candidateChainInfoMap[chainSlug]; + + if (this.md5Hash(chainWithoutProvidersAndStatus) !== chainHash) { + return false; + } + } + + for (const [assetSlug, assetHash] of Object.entries(latestPatch.ChainAssetHashMap)) { + if (!candidateAssetRegistry[assetSlug]) { + if (latestPatch.) + } + + if (this.md5Hash(candidateAssetRegistry[assetSlug]) !== assetHash) { + return false; + } + } + + console.log('b'); + + for (const [mAssetSlug, mAssetHash] of Object.entries(latestPatch.MultiChainAssetHashMap)) { + if (this.md5Hash(candidateMultiChainAssetMap[mAssetSlug]) !== mAssetHash) { + return false; + } + } + + console.log('c'); + + return true; + } + + handleLatestPatch (latestPatch: PatchInfo) { + try { + // 1. validate fetch data with its hash + const isSafePatch = this.validatePatchWithHash(latestPatch); + const { ChainAsset: latestAssetInfo, ChainInfo: latestChainInfo, MultiChainAsset: latestMultiChainAsset, patchVersion } = latestPatch; + let chainInfoMap = {}; + let assetRegistry = {}; + let multiChainAssetMap = {}; + // todo: AssetLogoMap, ChainLogoMap + console.log('[i] isSafePatch', isSafePatch) + console.log('[i] latestPatch', latestPatch) + + if (isSafePatch && this.patchVersion !== patchVersion) { + // 2. merge data map + if (latestChainInfo && Object.keys(latestChainInfo).length > 0) { + chainInfoMap = Object.assign({}, this.chainService.getChainInfoMap(), latestChainInfo); + } + + console.log('[i] done chain') + + if (latestAssetInfo && Object.keys(latestAssetInfo).length > 0) { + assetRegistry = filterAssetInfoMap(this.chainService.getChainInfoMap(), Object.assign({}, this.chainService.getAssetRegistry(), latestAssetInfo)); + } + + console.log('[i] done asset') + + if (latestMultiChainAsset && Object.keys(latestMultiChainAsset).length > 0) { + multiChainAssetMap = { ...MultiChainAssetMap, ...latestMultiChainAsset }; + } + + console.log('[i] done multi asset') + + // 3. validate data before write + const isCorrectPatch = this.validatePatchBeforeStore(chainInfoMap, assetRegistry, multiChainAssetMap, latestPatch); + console.log('[i] isCorrectPatch', isCorrectPatch) + + // 4. write to subject + if (isCorrectPatch) { + this.chainService.setChainInfoMap(chainInfoMap); + this.chainService.subscribeChainInfoMap().next(chainInfoMap); + + this.chainService.setAssetRegistry(assetRegistry); + this.chainService.subscribeAssetRegistry().next(assetRegistry); + this.chainService.autoEnableTokens() + .then(() => { + this.eventService.emit('asset.updateState', ''); + }) + .catch(console.error); + + this.chainService.subscribeMultiChainAssetMap().next(multiChainAssetMap); + this.patchVersion = patchVersion; + } + } + } catch (e) { + console.error('Error fetching latest patch data'); + } + + this.eventService.emit('asset.online.ready', true); + } + + private async fetchLatestPatchData () { + return await fetchPatchData('data.json'); + } + + handleLatestData () { + this.fetchLatestPatchData().then((latestPatch) => { + if (latestPatch) { + this.eventService.waitAssetReady + .then(() => { + this.handleLatestPatch(latestPatch); + }) + .catch(console.error); + } + }).catch(console.error); + } + + checkLatestData () { + clearInterval(this.refreshLatestChainDataTimeOut); + this.handleLatestData(); + + this.refreshLatestChainDataTimeOut = setInterval(this.handleLatestData.bind(this), LATEST_CHAIN_DATA_FETCHING_INTERVAL); + } +} diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index 629a96655c..2568fd371c 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -11,14 +11,13 @@ import { SubstrateChainHandler } from '@subwallet/extension-base/services/chain- import { TonChainHandler } from '@subwallet/extension-base/services/chain-service/handler/TonChainHandler'; import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainApiStatus, _ChainConnectionStatus, _ChainState, _CUSTOM_PREFIX, _DataMap, _EvmApi, _NetworkUpsertParams, _NFT_CONTRACT_STANDARDS, _SMART_CONTRACT_STANDARDS, _SmartContractTokenInfo, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse } from '@subwallet/extension-base/services/chain-service/types'; -import { _isAssetAutoEnable, _isAssetCanPayTxFee, _isAssetFungibleToken, _isChainEnabled, _isCustomAsset, _isCustomChain, _isCustomProvider, _isEqualContractAddress, _isEqualSmartContractAsset, _isLocalToken, _isMantaZkAsset, _isPureEvmChain, _isPureSubstrateChain, _parseAssetRefKey, fetchPatchData, PatchInfo, randomizeProvider, updateLatestChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; +import { _isAssetAutoEnable, _isAssetCanPayTxFee, _isAssetFungibleToken, _isChainEnabled, _isCustomAsset, _isCustomChain, _isCustomProvider, _isEqualContractAddress, _isEqualSmartContractAsset, _isLocalToken, _isMantaZkAsset, _isPureEvmChain, _isPureSubstrateChain, _parseAssetRefKey, randomizeProvider, updateLatestChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { EventService } from '@subwallet/extension-base/services/event-service'; import { IChain, IMetadataItem } from '@subwallet/extension-base/services/storage-service/databases'; import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService'; import AssetSettingStore from '@subwallet/extension-base/stores/AssetSetting'; import { addLazy, calculateMetadataHash, fetchStaticData, filterAssetsByChainAndType, getShortMetadata, MODULE_SUPPORT } from '@subwallet/extension-base/utils'; import { BehaviorSubject, Subject } from 'rxjs'; -import { Md5 } from 'ts-md5'; import Web3 from 'web3'; import { logger as createLogger } from '@polkadot/util/logger'; @@ -51,7 +50,7 @@ const ignoredList = [ 'storyPartner_testnet' ]; -const filterAssetInfoMap = (chainInfo: Record, assets: Record): Record => { +export const filterAssetInfoMap = (chainInfo: Record, assets: Record): Record => { return Object.fromEntries( Object.entries(assets) .filter(([, info]) => chainInfo[info.originChain]) @@ -109,9 +108,6 @@ export class ChainService { private assetLogoMapSubject = new BehaviorSubject>(AssetLogoMap); private chainLogoMapSubject = new BehaviorSubject>(ChainLogoMap); private ledgerGenericAllowChainsSubject = new BehaviorSubject([]); - // private assetMapPatch: string = JSON.stringify({}); - // private assetLogoPatch: string = JSON.stringify({}); - private appliedPatchVersion = ''; // Todo: Update to new store indexed DB private store: AssetSettingStore = new AssetSettingStore(); @@ -253,6 +249,10 @@ export class ChainService { return this.dataMap.assetRegistry; } + public setAssetRegistry (assetRegistry: Record) { + this.dataMap.assetRegistry = assetRegistry; + } + public getMultiChainAssetMap () { return MultiChainAssetMap; } @@ -285,6 +285,10 @@ export class ChainService { return this.dataMap.chainInfoMap; } + public setChainInfoMap (chainInfoMap: Record) { + this.dataMap.chainInfoMap = chainInfoMap; + } + public getEvmChainInfoMap (): Record { const result: Record = {}; @@ -700,77 +704,6 @@ export class ChainService { clearInterval(this.refreshLatestChainDataTimeOut); } - validatePatchWithHash (latestPatch: PatchInfo) { - const { ChainAsset, ChainAssetHashMap, ChainInfo, ChainInfoHashMap, MultiChainAsset, MultiChainAssetHashMap } = latestPatch; - - for (const [chainSlug, chain] of Object.entries(ChainInfo)) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { chainStatus, providers, ...chainWithoutProvidersAndStatus } = chain; - - if (Md5.hashStr(JSON.stringify(chainWithoutProvidersAndStatus)) !== ChainInfoHashMap[chainSlug]) { - return false; - } - } - - for (const [assetSlug, asset] of Object.entries(ChainAsset)) { - if (Md5.hashStr(JSON.stringify(asset)) !== ChainAssetHashMap[assetSlug]) { - return false; - } - } - - for (const [mAssetSlug, mAsset] of Object.entries(MultiChainAsset)) { - if (Md5.hashStr(JSON.stringify(mAsset)) !== MultiChainAssetHashMap[mAssetSlug]) { - return false; - } - } - - return true; - } - - handleLatestPatch (latestPatch: PatchInfo) { - try { - const isSafePatch = this.validatePatchWithHash(latestPatch); - const { ChainAsset: latestAssetInfo, ChainInfo: latestChainInfo, MultiChainAsset: latestMultiChainAsset, appliedVersion } = latestPatch; - // todo: AssetLogoMap, ChainLogoMap - - if (isSafePatch && this.appliedPatchVersion !== appliedVersion) { - if (latestChainInfo && Object.keys(latestChainInfo).length > 0) { - const chainInfoMap = Object.assign({}, this.dataMap.chainInfoMap, latestChainInfo); - - this.dataMap.chainInfoMap = chainInfoMap; - this.chainInfoMapSubject.next(chainInfoMap); - } - - if (latestAssetInfo && Object.keys(latestAssetInfo).length > 0) { - const assetRegistry = filterAssetInfoMap(this.getChainInfoMap(), Object.assign({}, this.dataMap.assetRegistry, latestAssetInfo)); - - this.dataMap.assetRegistry = assetRegistry; - this.assetRegistrySubject.next(assetRegistry); - - this.autoEnableTokens() - .then(() => { - this.eventService.emit('asset.updateState', ''); - }) - .catch(console.error); - } - - if (latestMultiChainAsset && Object.keys(latestMultiChainAsset).length > 0) { - const multiChainAssetMap = { ...MultiChainAssetMap, ...latestMultiChainAsset }; - - this.multiChainAssetMapSubject.next(multiChainAssetMap); - } - - this.appliedPatchVersion = appliedVersion; - } - } catch (e) { - console.error('Error fetching latest patch data'); - } - - this.eventService.emit('asset.online.ready', true); - - this.logger.log('Finished updating latest asset'); - } - handleLatestChainData (latestChainInfo: _ChainInfo[]) { try { if (latestChainInfo && latestChainInfo.length > 0) { @@ -906,16 +839,6 @@ export class ChainService { // .catch(console.error); // }).catch(console.error); - this.fetchLatestPatchData().then((latestPatch) => { - if (latestPatch) { - this.eventService.waitAssetReady - .then(() => { - this.handleLatestPatch(latestPatch); - }) - .catch(console.error); - } - }).catch(console.error); - this.fetchLatestChainData().then((latestChainInfo) => { this.handleLatestChainData(latestChainInfo); }).catch(console.error); @@ -1230,10 +1153,6 @@ export class ChainService { // return await Promise.all([fetchPatchData>('ChainAsset.json'), fetchPatchData>('AssetLogoMap.json')]); // lastest logo also here. // } - private async fetchLatestPatchData () { - return await fetchPatchData('data.json'); - } - // @ts-ignore private async fetchLatestPriceIdsData () { return await fetchStaticData>('chain-assets/price-map'); From a47c54d8b0b720234787cc9c68dd329bd268399f Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:17:48 +0700 Subject: [PATCH 03/14] [Issue-3132] fix: fix validate deleted assets --- .../src/koni/background/handlers/State.ts | 2 ++ .../services/chain-online-service/index.ts | 21 ++++++------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index 5849323bfc..dc42442bc4 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -1006,6 +1006,8 @@ export default class KoniState { } async resumeAllNetworks () { + this.chainOnlineService.checkLatestData(); + return this.chainService.resumeAllChainApis(); } diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 709aa34fa1..5fb9a532a3 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -1,4 +1,4 @@ -// [object Object] +// Copyright 2019-2022 @subwallet/extension-koni authors & contributors // SPDX-License-Identifier: Apache-2.0 import { MultiChainAssetMap } from '@subwallet/chain-list'; @@ -64,7 +64,11 @@ export class ChainOnlineService { for (const [assetSlug, assetHash] of Object.entries(latestPatch.ChainAssetHashMap)) { if (!candidateAssetRegistry[assetSlug]) { - if (latestPatch.) + if (!latestPatch.ChainInfo[assetSlug]) { // assets are not existed in case chain is removed + continue; + } + + return false; } if (this.md5Hash(candidateAssetRegistry[assetSlug]) !== assetHash) { @@ -72,16 +76,12 @@ export class ChainOnlineService { } } - console.log('b'); - for (const [mAssetSlug, mAssetHash] of Object.entries(latestPatch.MultiChainAssetHashMap)) { if (this.md5Hash(candidateMultiChainAssetMap[mAssetSlug]) !== mAssetHash) { return false; } } - console.log('c'); - return true; } @@ -94,8 +94,6 @@ export class ChainOnlineService { let assetRegistry = {}; let multiChainAssetMap = {}; // todo: AssetLogoMap, ChainLogoMap - console.log('[i] isSafePatch', isSafePatch) - console.log('[i] latestPatch', latestPatch) if (isSafePatch && this.patchVersion !== patchVersion) { // 2. merge data map @@ -103,23 +101,16 @@ export class ChainOnlineService { chainInfoMap = Object.assign({}, this.chainService.getChainInfoMap(), latestChainInfo); } - console.log('[i] done chain') - if (latestAssetInfo && Object.keys(latestAssetInfo).length > 0) { assetRegistry = filterAssetInfoMap(this.chainService.getChainInfoMap(), Object.assign({}, this.chainService.getAssetRegistry(), latestAssetInfo)); } - console.log('[i] done asset') - if (latestMultiChainAsset && Object.keys(latestMultiChainAsset).length > 0) { multiChainAssetMap = { ...MultiChainAssetMap, ...latestMultiChainAsset }; } - console.log('[i] done multi asset') - // 3. validate data before write const isCorrectPatch = this.validatePatchBeforeStore(chainInfoMap, assetRegistry, multiChainAssetMap, latestPatch); - console.log('[i] isCorrectPatch', isCorrectPatch) // 4. write to subject if (isCorrectPatch) { From 93c093952ecded544ed319a49a911e52ec3aca02 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:12:11 +0700 Subject: [PATCH 04/14] [Issue-3132] fix: apply chain state for new chain --- .../src/koni/background/handlers/State.ts | 4 +-- .../services/chain-online-service/index.ts | 31 ++++++++++++++++--- .../src/services/chain-service/index.ts | 8 +++-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index dc42442bc4..652d97b83c 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -305,8 +305,8 @@ export default class KoniState { await this.startSubscription(); - this.chainService.checkLatestData(); this.chainOnlineService.checkLatestData(); + this.chainService.checkLatestData(); } public async initMantaPay (password: string) { @@ -1645,8 +1645,8 @@ export default class KoniState { await this.chainService.init(); this.afterChainServiceInit(); - this.chainService.checkLatestData(); this.chainOnlineService.checkLatestData(); + this.chainService.checkLatestData(); } public async enableMantaPay (updateStore: boolean, address: string, password: string, seedPhrase?: string) { diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 5fb9a532a3..7be334ef51 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -5,6 +5,7 @@ import { MultiChainAssetMap } from '@subwallet/chain-list'; import { _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { ChainService, filterAssetInfoMap } from '@subwallet/extension-base/services/chain-service'; import { LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; +import { _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { fetchPatchData, PatchInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { EventService } from '@subwallet/extension-base/services/event-service'; import { Md5 } from 'ts-md5'; @@ -90,19 +91,37 @@ export class ChainOnlineService { // 1. validate fetch data with its hash const isSafePatch = this.validatePatchWithHash(latestPatch); const { ChainAsset: latestAssetInfo, ChainInfo: latestChainInfo, MultiChainAsset: latestMultiChainAsset, patchVersion } = latestPatch; - let chainInfoMap = {}; - let assetRegistry = {}; - let multiChainAssetMap = {}; + let chainInfoMap: Record = {}; + let assetRegistry: Record = {}; + let multiChainAssetMap: Record = {}; + let currentChainState: Record = {}; + + let addedChain: string[] = []; // todo: AssetLogoMap, ChainLogoMap if (isSafePatch && this.patchVersion !== patchVersion) { // 2. merge data map if (latestChainInfo && Object.keys(latestChainInfo).length > 0) { chainInfoMap = Object.assign({}, this.chainService.getChainInfoMap(), latestChainInfo); + + currentChainState = this.chainService.getChainStateMap(); + const currentChainStateKey = Object.keys(currentChainState); + const newChainStateKey = Object.keys(chainInfoMap); + + addedChain = newChainStateKey.filter((chain) => !currentChainStateKey.includes(chain)); + + addedChain.forEach((key) => { + currentChainState[key] = { + active: false, + currentProvider: Object.keys(chainInfoMap[key].providers)[0], + manualTurnOff: false, + slug: key + }; + }); } if (latestAssetInfo && Object.keys(latestAssetInfo).length > 0) { - assetRegistry = filterAssetInfoMap(this.chainService.getChainInfoMap(), Object.assign({}, this.chainService.getAssetRegistry(), latestAssetInfo)); + assetRegistry = filterAssetInfoMap(this.chainService.getChainInfoMap(), Object.assign({}, this.chainService.getAssetRegistry(), latestAssetInfo), addedChain); } if (latestMultiChainAsset && Object.keys(latestMultiChainAsset).length > 0) { @@ -126,6 +145,10 @@ export class ChainOnlineService { .catch(console.error); this.chainService.subscribeMultiChainAssetMap().next(multiChainAssetMap); + + this.chainService.setChainStateMap(currentChainState); + this.chainService.subscribeChainStateMap().next(currentChainState); + this.patchVersion = patchVersion; } } diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index 2568fd371c..2be9e053b2 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -50,10 +50,10 @@ const ignoredList = [ 'storyPartner_testnet' ]; -export const filterAssetInfoMap = (chainInfo: Record, assets: Record): Record => { +export const filterAssetInfoMap = (chainInfo: Record, assets: Record, addedChains?: string[]): Record => { return Object.fromEntries( Object.entries(assets) - .filter(([, info]) => chainInfo[info.originChain]) + .filter(([, info]) => chainInfo[info.originChain] || addedChains?.includes(info.originChain)) ); }; @@ -359,6 +359,10 @@ export class ChainService { return this.dataMap.chainStateMap; } + public setChainStateMap (chainStateMap: Record) { + this.dataMap.chainStateMap = chainStateMap; + } + public getChainStateByKey (key: string) { return this.dataMap.chainStateMap[key]; } From 9534058db128a7e03a7643588e2c55a51273b6f8 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:53:25 +0700 Subject: [PATCH 05/14] [Issue-3132] feat: store patch version in local storage --- .../src/koni/background/handlers/State.ts | 2 +- .../services/chain-online-service/Chainlist.ts | 17 +++++++++++++++++ .../src/services/chain-online-service/index.ts | 14 +++++++++----- .../services/setting-service/SettingService.ts | 11 +++++++++++ .../extension-base/src/stores/ChainlistStore.ts | 15 +++++++++++++++ 5 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 packages/extension-base/src/services/chain-online-service/Chainlist.ts create mode 100644 packages/extension-base/src/stores/ChainlistStore.ts diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index 652d97b83c..4ab4b3176c 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -167,7 +167,7 @@ export default class KoniState { this.feeService = new FeeService(this); this.swapService = new SwapService(this); this.inappNotificationService = new InappNotificationService(this.dbService, this.keyringService, this.eventService, this.chainService); - this.chainOnlineService = new ChainOnlineService(this.chainService, this.eventService); + this.chainOnlineService = new ChainOnlineService(this.chainService, this.settingService, this.eventService); this.subscription = new KoniSubscription(this, this.dbService); this.cron = new KoniCron(this, this.subscription, this.dbService); diff --git a/packages/extension-base/src/services/chain-online-service/Chainlist.ts b/packages/extension-base/src/services/chain-online-service/Chainlist.ts new file mode 100644 index 0000000000..34d2f5cc16 --- /dev/null +++ b/packages/extension-base/src/services/chain-online-service/Chainlist.ts @@ -0,0 +1,17 @@ +// Copyright 2019-2022 @subwallet/extension-base +// SPDX-License-Identifier: Apache-2.0 + +import { StoreSubject } from '@subwallet/extension-base/services/keyring-service/context/stores/Base'; +import ChainlistStore from '@subwallet/extension-base/stores/ChainlistStore'; +import { BehaviorSubject } from 'rxjs'; + +interface ChainlistConfig { + patchVersion: string +} + +export class ChainlistStoreSubject extends StoreSubject { + store = new ChainlistStore(); + subject = new BehaviorSubject({ patchVersion: '' }); + key = 'Chainlist'; + defaultValue = { patchVersion: '' }; +} diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 7be334ef51..d490025eeb 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -8,17 +8,19 @@ import { LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/s import { _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { fetchPatchData, PatchInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { EventService } from '@subwallet/extension-base/services/event-service'; +import SettingService from '@subwallet/extension-base/services/setting-service/SettingService'; import { Md5 } from 'ts-md5'; export class ChainOnlineService { private chainService: ChainService; + private settingService: SettingService; private eventService: EventService; refreshLatestChainDataTimeOut: NodeJS.Timer | undefined; - private patchVersion = ''; - constructor (chainService: ChainService, eventService: EventService) { + constructor (chainService: ChainService, settingService: SettingService, eventService: EventService) { this.chainService = chainService; + this.settingService = settingService; this.eventService = eventService; } @@ -90,7 +92,9 @@ export class ChainOnlineService { try { // 1. validate fetch data with its hash const isSafePatch = this.validatePatchWithHash(latestPatch); - const { ChainAsset: latestAssetInfo, ChainInfo: latestChainInfo, MultiChainAsset: latestMultiChainAsset, patchVersion } = latestPatch; + const { ChainAsset: latestAssetInfo, ChainInfo: latestChainInfo, MultiChainAsset: latestMultiChainAsset, patchVersion: latestPatchVersion } = latestPatch; + const currentPatchVersion = this.settingService.getChainlistInfo().patchVersion; + let chainInfoMap: Record = {}; let assetRegistry: Record = {}; let multiChainAssetMap: Record = {}; @@ -99,7 +103,7 @@ export class ChainOnlineService { let addedChain: string[] = []; // todo: AssetLogoMap, ChainLogoMap - if (isSafePatch && this.patchVersion !== patchVersion) { + if (isSafePatch && currentPatchVersion !== latestPatchVersion) { // 2. merge data map if (latestChainInfo && Object.keys(latestChainInfo).length > 0) { chainInfoMap = Object.assign({}, this.chainService.getChainInfoMap(), latestChainInfo); @@ -149,7 +153,7 @@ export class ChainOnlineService { this.chainService.setChainStateMap(currentChainState); this.chainService.subscribeChainStateMap().next(currentChainState); - this.patchVersion = patchVersion; + this.settingService.setChainlist({ patchVersion: latestPatchVersion }); } } } catch (e) { diff --git a/packages/extension-base/src/services/setting-service/SettingService.ts b/packages/extension-base/src/services/setting-service/SettingService.ts index 91e757b7b9..fb523a026d 100644 --- a/packages/extension-base/src/services/setting-service/SettingService.ts +++ b/packages/extension-base/src/services/setting-service/SettingService.ts @@ -3,7 +3,9 @@ import { LanguageType, PassPhishing, RequestSettingsType, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; import { LANGUAGE } from '@subwallet/extension-base/constants'; +import { ChainlistStoreSubject } from '@subwallet/extension-base/services/chain-online-service/Chainlist'; import { SWStorage } from '@subwallet/extension-base/storage'; +import { ChainlistConfig } from '@subwallet/extension-base/stores/ChainlistStore'; import PassPhishingStore from '@subwallet/extension-base/stores/PassPhishingStore'; import SettingsStore from '@subwallet/extension-base/stores/Settings'; import { Subject } from 'rxjs'; @@ -14,6 +16,7 @@ import { DEFAULT_SETTING } from './constants'; export default class SettingService { private readonly settingsStore = new SettingsStore(); private readonly passPhishingStore = new PassPhishingStore(); + private readonly chainlistStore = new ChainlistStoreSubject(); constructor () { this.initSetting().catch(console.error); @@ -73,6 +76,14 @@ export default class SettingService { this.passPhishingStore.set('PassPhishing', data, callback); } + public getChainlistInfo (): ChainlistConfig { + return this.chainlistStore.subject.value; + } + + public setChainlist (data: ChainlistConfig): void { + this.chainlistStore.upsertData(data); + } + // Use for mobile only public get isAlwaysRequired (): Promise { return new Promise((resolve) => { diff --git a/packages/extension-base/src/stores/ChainlistStore.ts b/packages/extension-base/src/stores/ChainlistStore.ts new file mode 100644 index 0000000000..2b8b337966 --- /dev/null +++ b/packages/extension-base/src/stores/ChainlistStore.ts @@ -0,0 +1,15 @@ +// Copyright 2019-2022 @subwallet/extension-base +// SPDX-License-Identifier: Apache-2.0 + +import { EXTENSION_PREFIX } from '@subwallet/extension-base/defaults'; +import SubscribableStore from '@subwallet/extension-base/stores/SubscribableStore'; + +export interface ChainlistConfig { + patchVersion: string +} + +export default class ChainlistStore extends SubscribableStore { + constructor () { + super(EXTENSION_PREFIX ? `${EXTENSION_PREFIX}chainlist` : null); + } +} From 4ebb53e9328418e829034fb457113a91af44a8fd Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:15:31 +0700 Subject: [PATCH 06/14] [Issue-3132] feat: update chain logo & asset logo map --- .../services/chain-online-service/index.ts | 22 +++++++++++++++++-- .../src/services/chain-service/utils/patch.ts | 5 ++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index d490025eeb..12665b612c 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -1,7 +1,7 @@ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { MultiChainAssetMap } from '@subwallet/chain-list'; +import { AssetLogoMap, ChainLogoMap, MultiChainAssetMap } from '@subwallet/chain-list'; import { _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { ChainService, filterAssetInfoMap } from '@subwallet/extension-base/services/chain-service'; import { LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; @@ -92,7 +92,13 @@ export class ChainOnlineService { try { // 1. validate fetch data with its hash const isSafePatch = this.validatePatchWithHash(latestPatch); - const { ChainAsset: latestAssetInfo, ChainInfo: latestChainInfo, MultiChainAsset: latestMultiChainAsset, patchVersion: latestPatchVersion } = latestPatch; + const { AssetLogoMap: latestAssetLogoMap, + ChainAsset: latestAssetInfo, + ChainInfo: latestChainInfo, + ChainLogoMap: latestChainLogoMap, + MultiChainAsset: latestMultiChainAsset, + mAssetLogoMap: lastestMAssetLogoMap, + patchVersion: latestPatchVersion } = latestPatch; const currentPatchVersion = this.settingService.getChainlistInfo().patchVersion; let chainInfoMap: Record = {}; @@ -153,6 +159,18 @@ export class ChainOnlineService { this.chainService.setChainStateMap(currentChainState); this.chainService.subscribeChainStateMap().next(currentChainState); + if (latestChainLogoMap) { + const logoMap = Object.assign({}, ChainLogoMap, latestChainLogoMap); + + this.chainService.subscribeChainLogoMap().next(logoMap); + } + + if (latestAssetLogoMap) { + const logoMap = Object.assign({}, AssetLogoMap, latestAssetLogoMap, lastestMAssetLogoMap); + + this.chainService.subscribeAssetLogoMap().next(logoMap); + } + this.settingService.setChainlist({ patchVersion: latestPatchVersion }); } } diff --git a/packages/extension-base/src/services/chain-service/utils/patch.ts b/packages/extension-base/src/services/chain-service/utils/patch.ts index d1d84c42f9..cc55261def 100644 --- a/packages/extension-base/src/services/chain-service/utils/patch.ts +++ b/packages/extension-base/src/services/chain-service/utils/patch.ts @@ -19,7 +19,10 @@ export interface PatchInfo { ChainAsset: Record, ChainAssetHashMap: Record, MultiChainAsset: Record, - MultiChainAssetHashMap: Record + MultiChainAssetHashMap: Record, + ChainLogoMap: Record, + AssetLogoMap: Record, + mAssetLogoMap: Record } export async function fetchPatchData (slug: string) { From d830808868985305790d73d654945c5974d32ccf Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Tue, 5 Nov 2024 19:03:54 +0700 Subject: [PATCH 07/14] [Issue-3132] fix: fix chain list store --- .../src/koni/background/handlers/State.ts | 2 - .../chain-online-service/Chainlist.ts | 17 ---- .../services/chain-online-service/index.ts | 15 +-- .../src/services/chain-service/index.ts | 98 +------------------ .../setting-service/SettingService.ts | 13 ++- 5 files changed, 15 insertions(+), 130 deletions(-) delete mode 100644 packages/extension-base/src/services/chain-online-service/Chainlist.ts diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index 4ab4b3176c..42b7e85b1a 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -306,7 +306,6 @@ export default class KoniState { await this.startSubscription(); this.chainOnlineService.checkLatestData(); - this.chainService.checkLatestData(); } public async initMantaPay (password: string) { @@ -1646,7 +1645,6 @@ export default class KoniState { this.afterChainServiceInit(); this.chainOnlineService.checkLatestData(); - this.chainService.checkLatestData(); } public async enableMantaPay (updateStore: boolean, address: string, password: string, seedPhrase?: string) { diff --git a/packages/extension-base/src/services/chain-online-service/Chainlist.ts b/packages/extension-base/src/services/chain-online-service/Chainlist.ts deleted file mode 100644 index 34d2f5cc16..0000000000 --- a/packages/extension-base/src/services/chain-online-service/Chainlist.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2019-2022 @subwallet/extension-base -// SPDX-License-Identifier: Apache-2.0 - -import { StoreSubject } from '@subwallet/extension-base/services/keyring-service/context/stores/Base'; -import ChainlistStore from '@subwallet/extension-base/stores/ChainlistStore'; -import { BehaviorSubject } from 'rxjs'; - -interface ChainlistConfig { - patchVersion: string -} - -export class ChainlistStoreSubject extends StoreSubject { - store = new ChainlistStore(); - subject = new BehaviorSubject({ patchVersion: '' }); - key = 'Chainlist'; - defaultValue = { patchVersion: '' }; -} diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 12665b612c..36b78101ca 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -88,7 +88,7 @@ export class ChainOnlineService { return true; } - handleLatestPatch (latestPatch: PatchInfo) { + async handleLatestPatch (latestPatch: PatchInfo) { try { // 1. validate fetch data with its hash const isSafePatch = this.validatePatchWithHash(latestPatch); @@ -99,13 +99,12 @@ export class ChainOnlineService { MultiChainAsset: latestMultiChainAsset, mAssetLogoMap: lastestMAssetLogoMap, patchVersion: latestPatchVersion } = latestPatch; - const currentPatchVersion = this.settingService.getChainlistInfo().patchVersion; + const currentPatchVersion = (await this.settingService.getChainlistSetting())?.patchVersion || ''; let chainInfoMap: Record = {}; let assetRegistry: Record = {}; let multiChainAssetMap: Record = {}; let currentChainState: Record = {}; - let addedChain: string[] = []; // todo: AssetLogoMap, ChainLogoMap @@ -185,12 +184,13 @@ export class ChainOnlineService { return await fetchPatchData('data.json'); } - handleLatestData () { + handleLatestPatchData () { this.fetchLatestPatchData().then((latestPatch) => { if (latestPatch) { this.eventService.waitAssetReady .then(() => { - this.handleLatestPatch(latestPatch); + this.handleLatestPatch(latestPatch) + .catch(console.error); }) .catch(console.error); } @@ -199,8 +199,9 @@ export class ChainOnlineService { checkLatestData () { clearInterval(this.refreshLatestChainDataTimeOut); - this.handleLatestData(); + this.handleLatestPatchData(); + this.chainService.handleLatestData(); - this.refreshLatestChainDataTimeOut = setInterval(this.handleLatestData.bind(this), LATEST_CHAIN_DATA_FETCHING_INTERVAL); + this.refreshLatestChainDataTimeOut = setInterval(this.handleLatestPatchData.bind(this), LATEST_CHAIN_DATA_FETCHING_INTERVAL); } } diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index 2be9e053b2..e66c63e1bb 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -4,7 +4,7 @@ import { AssetLogoMap, AssetRefMap, ChainAssetMap, ChainInfoMap, ChainLogoMap, MultiChainAssetMap } from '@subwallet/chain-list'; import { _AssetRef, _AssetRefPath, _AssetType, _ChainAsset, _ChainInfo, _ChainStatus, _EvmInfo, _MultiChainAsset, _SubstrateChainType, _SubstrateInfo, _TonInfo } from '@subwallet/chain-list/types'; import { AssetSetting, ValidateNetworkResponse } from '@subwallet/extension-base/background/KoniTypes'; -import { _DEFAULT_ACTIVE_CHAINS, _ZK_ASSET_PREFIX, LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; +import { _DEFAULT_ACTIVE_CHAINS, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants'; import { EvmChainHandler } from '@subwallet/extension-base/services/chain-service/handler/EvmChainHandler'; import { MantaPrivateHandler } from '@subwallet/extension-base/services/chain-service/handler/manta/MantaPrivateHandler'; import { SubstrateChainHandler } from '@subwallet/extension-base/services/chain-service/handler/SubstrateChainHandler'; @@ -57,22 +57,6 @@ export const filterAssetInfoMap = (chainInfo: Record, assets ); }; -// const rawAssetRefMap = (assetRefMap: Record) => { -// const result: Record = {}; -// -// Object.entries(assetRefMap).forEach(([key, assetRef]) => { -// const originChainInfo = ChainInfoMap[assetRef.srcChain]; -// const destChainInfo = ChainInfoMap[assetRef.destChain]; -// const isSnowBridgeXcm = assetRef.path === _AssetRefPath.XCM && _isSnowBridgeXcm(originChainInfo, destChainInfo); -// -// if (!isSnowBridgeXcm) { -// result[key] = assetRef; -// } -// }); -// -// return result; -// }; - export class ChainService { private dataMap: _DataMap = { chainInfoMap: {}, @@ -697,13 +681,6 @@ export class ChainService { this.dataMap.assetRefMap = AssetRefMap; } - checkLatestData () { - clearInterval(this.refreshLatestChainDataTimeOut); - this.handleLatestData(); - - this.refreshLatestChainDataTimeOut = setInterval(this.handleLatestData.bind(this), LATEST_CHAIN_DATA_FETCHING_INTERVAL); - } - stopCheckLatestChainData () { clearInterval(this.refreshLatestChainDataTimeOut); } @@ -728,26 +705,6 @@ export class ChainService { } } - // handleLatestAssetRef (latestBlockedAssetRefList: string[], latestAssetRefMap: Record | null) { - // const updatedAssetRefMap: Record = { ...AssetRefMap }; - // - // if (latestAssetRefMap) { - // for (const [assetRefKey, assetRef] of Object.entries(latestAssetRefMap)) { - // updatedAssetRefMap[assetRefKey] = assetRef; - // } - // } - // - // latestBlockedAssetRefList.forEach((blockedAssetRef) => { - // delete updatedAssetRefMap[blockedAssetRef]; - // }); - // - // this.dataMap.assetRefMap = updatedAssetRefMap; - // - // this.xcmRefMapSubject.next(this.xcmRefMap); - // this.swapRefMapSubject.next(this.swapRefMap); - // this.logger.log('Finished updating latest asset ref'); - // } - handleLatestPriceId (latestPriceIds: Record) { let isUpdated = false; @@ -766,45 +723,6 @@ export class ChainService { this.logger.log('Finished updating latest price IDs'); } - // handleLatestAssetData (latestAssetInfo: Record | null, latestAssetLogoMap: Record | null) { - // try { - // if (latestAssetInfo) { - // const latestAssetPatch = JSON.stringify(latestAssetInfo); - // - // if (this.assetMapPatch !== latestAssetPatch) { - // const assetRegistry = filterAssetInfoMap(this.getChainInfoMap(), Object.assign({}, this.dataMap.assetRegistry, latestAssetInfo)); - // - // this.assetMapPatch = latestAssetPatch; - // this.dataMap.assetRegistry = assetRegistry; - // this.assetRegistrySubject.next(assetRegistry); - // - // this.autoEnableTokens() - // .then(() => { - // this.eventService.emit('asset.updateState', ''); - // }) - // .catch(console.error); - // } - // } - // - // if (latestAssetLogoMap) { - // const latestAssetLogoPatch = JSON.stringify(latestAssetLogoMap); - // - // if (this.assetLogoPatch !== latestAssetLogoPatch) { - // const logoMap = { ...AssetLogoMap, ...latestAssetLogoMap }; - // - // this.assetLogoPatch = latestAssetLogoPatch; - // this.assetLogoMapSubject.next(logoMap); - // } - // } - // } catch (e) { - // console.error('Error fetching latest asset data'); - // } - // - // this.eventService.emit('asset.online.ready', true); - // - // this.logger.log('Finished updating latest asset'); - // } - async autoEnableTokens () { const autoEnableTokens = Object.values(this.dataMap.assetRegistry).filter((asset) => _isAssetAutoEnable(asset)); @@ -835,22 +753,10 @@ export class ChainService { } handleLatestData () { - // this.fetchLatestAssetData().then(([latestAssetInfo, latestAssetLogoMap]) => { - // this.eventService.waitAssetReady - // .then(() => { - // this.handleLatestAssetData(latestAssetInfo, latestAssetLogoMap); - // }) - // .catch(console.error); - // }).catch(console.error); - this.fetchLatestChainData().then((latestChainInfo) => { this.handleLatestChainData(latestChainInfo); }).catch(console.error); - // this.fetchLatestAssetRef().then(([latestAssetRef, latestAssetRefMap]) => { - // this.handleLatestAssetRef(latestAssetRef, latestAssetRefMap); - // }).catch(console.error); - this.fetchLatestPriceIdsData().then((latestPriceIds) => { this.handleLatestPriceId(latestPriceIds); }).catch(console.error); @@ -1925,8 +1831,6 @@ export class ChainService { this.evmChainHandler.wakeUp(), this.tonChainHandler.wakeUp() ]); - - this.checkLatestData(); } public async initAssetSettings () { diff --git a/packages/extension-base/src/services/setting-service/SettingService.ts b/packages/extension-base/src/services/setting-service/SettingService.ts index fb523a026d..d4824cf951 100644 --- a/packages/extension-base/src/services/setting-service/SettingService.ts +++ b/packages/extension-base/src/services/setting-service/SettingService.ts @@ -3,9 +3,8 @@ import { LanguageType, PassPhishing, RequestSettingsType, UiSettings } from '@subwallet/extension-base/background/KoniTypes'; import { LANGUAGE } from '@subwallet/extension-base/constants'; -import { ChainlistStoreSubject } from '@subwallet/extension-base/services/chain-online-service/Chainlist'; import { SWStorage } from '@subwallet/extension-base/storage'; -import { ChainlistConfig } from '@subwallet/extension-base/stores/ChainlistStore'; +import ChainlistStore, { ChainlistConfig } from '@subwallet/extension-base/stores/ChainlistStore'; import PassPhishingStore from '@subwallet/extension-base/stores/PassPhishingStore'; import SettingsStore from '@subwallet/extension-base/stores/Settings'; import { Subject } from 'rxjs'; @@ -16,7 +15,7 @@ import { DEFAULT_SETTING } from './constants'; export default class SettingService { private readonly settingsStore = new SettingsStore(); private readonly passPhishingStore = new PassPhishingStore(); - private readonly chainlistStore = new ChainlistStoreSubject(); + private readonly chainlistStore = new ChainlistStore(); constructor () { this.initSetting().catch(console.error); @@ -76,12 +75,12 @@ export default class SettingService { this.passPhishingStore.set('PassPhishing', data, callback); } - public getChainlistInfo (): ChainlistConfig { - return this.chainlistStore.subject.value; + public getChainlistSetting () { + return this.chainlistStore.asyncGet('Chainlist'); } - public setChainlist (data: ChainlistConfig): void { - this.chainlistStore.upsertData(data); + public setChainlist (data: ChainlistConfig, callback?: () => void): void { + this.chainlistStore.set('Chainlist', data, callback); } // Use for mobile only From 514c1e3e7f0747b73f1eb967492274cb753c9fea Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:11:16 +0700 Subject: [PATCH 08/14] [Issue-3132] fix: fix chain list store --- .../services/chain-online-service/index.ts | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 36b78101ca..d1c1dcec74 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -5,7 +5,7 @@ import { AssetLogoMap, ChainLogoMap, MultiChainAssetMap } from '@subwallet/chain import { _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; import { ChainService, filterAssetInfoMap } from '@subwallet/extension-base/services/chain-service'; import { LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; -import { _ChainState } from '@subwallet/extension-base/services/chain-service/types'; +import { _ChainApiStatus, _ChainConnectionStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; import { fetchPatchData, PatchInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { EventService } from '@subwallet/extension-base/services/event-service'; import SettingService from '@subwallet/extension-base/services/setting-service/SettingService'; @@ -104,7 +104,8 @@ export class ChainOnlineService { let chainInfoMap: Record = {}; let assetRegistry: Record = {}; let multiChainAssetMap: Record = {}; - let currentChainState: Record = {}; + let currentChainStateMap: Record = {}; + let currentChainStatusMap: Record = {}; let addedChain: string[] = []; // todo: AssetLogoMap, ChainLogoMap @@ -113,19 +114,25 @@ export class ChainOnlineService { if (latestChainInfo && Object.keys(latestChainInfo).length > 0) { chainInfoMap = Object.assign({}, this.chainService.getChainInfoMap(), latestChainInfo); - currentChainState = this.chainService.getChainStateMap(); - const currentChainStateKey = Object.keys(currentChainState); - const newChainStateKey = Object.keys(chainInfoMap); + [currentChainStateMap, currentChainStatusMap] = [this.chainService.getChainStateMap(), this.chainService.getChainStatusMap()]; - addedChain = newChainStateKey.filter((chain) => !currentChainStateKey.includes(chain)); + const [currentChainStateKey, newChainKey] = [Object.keys(currentChainStateMap), Object.keys(chainInfoMap)]; + + addedChain = newChainKey.filter((chain) => !currentChainStateKey.includes(chain)); addedChain.forEach((key) => { - currentChainState[key] = { + currentChainStateMap[key] = { active: false, currentProvider: Object.keys(chainInfoMap[key].providers)[0], manualTurnOff: false, slug: key }; + + currentChainStatusMap[key] = { + slug: key, + connectionStatus: _ChainConnectionStatus.DISCONNECTED, + lastUpdated: Date.now() + }; }); } @@ -155,8 +162,8 @@ export class ChainOnlineService { this.chainService.subscribeMultiChainAssetMap().next(multiChainAssetMap); - this.chainService.setChainStateMap(currentChainState); - this.chainService.subscribeChainStateMap().next(currentChainState); + this.chainService.setChainStateMap(currentChainStateMap); + this.chainService.subscribeChainStateMap().next(currentChainStateMap); if (latestChainLogoMap) { const logoMap = Object.assign({}, ChainLogoMap, latestChainLogoMap); From 4c8a02850810909c1ebf883a89238ae0e5a84004 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:14:14 +0700 Subject: [PATCH 09/14] [Issue-3132] feat: update flow running latest patch and latest chain rpc --- .../src/koni/background/handlers/State.ts | 4 +- .../chain-online-service/constants.ts | 4 ++ .../services/chain-online-service/index.ts | 36 +++++++--- .../src/services/chain-service/index.ts | 66 +++++++++++++++---- 4 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 packages/extension-base/src/services/chain-online-service/constants.ts diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index 42b7e85b1a..19812c237a 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -167,7 +167,7 @@ export default class KoniState { this.feeService = new FeeService(this); this.swapService = new SwapService(this); this.inappNotificationService = new InappNotificationService(this.dbService, this.keyringService, this.eventService, this.chainService); - this.chainOnlineService = new ChainOnlineService(this.chainService, this.settingService, this.eventService); + this.chainOnlineService = new ChainOnlineService(this.chainService, this.settingService, this.eventService, this.dbService); this.subscription = new KoniSubscription(this, this.dbService); this.cron = new KoniCron(this, this.subscription, this.dbService); @@ -306,6 +306,7 @@ export default class KoniState { await this.startSubscription(); this.chainOnlineService.checkLatestData(); + this.chainService.checkLatestData(); } public async initMantaPay (password: string) { @@ -1645,6 +1646,7 @@ export default class KoniState { this.afterChainServiceInit(); this.chainOnlineService.checkLatestData(); + this.chainService.checkLatestData(); } public async enableMantaPay (updateStore: boolean, address: string, password: string, seedPhrase?: string) { diff --git a/packages/extension-base/src/services/chain-online-service/constants.ts b/packages/extension-base/src/services/chain-online-service/constants.ts new file mode 100644 index 0000000000..c99749eb0a --- /dev/null +++ b/packages/extension-base/src/services/chain-online-service/constants.ts @@ -0,0 +1,4 @@ +// Copyright 2019-2022 @subwallet/extension-koni authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export const LATEST_CHAIN_PATCH_FETCHING_INTERVAL = 180000; diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index d1c1dcec74..bc02f3277c 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -3,25 +3,29 @@ import { AssetLogoMap, ChainLogoMap, MultiChainAssetMap } from '@subwallet/chain-list'; import { _ChainAsset, _ChainInfo, _MultiChainAsset } from '@subwallet/chain-list/types'; +import { LATEST_CHAIN_PATCH_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-online-service/constants'; import { ChainService, filterAssetInfoMap } from '@subwallet/extension-base/services/chain-service'; -import { LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; import { _ChainApiStatus, _ChainConnectionStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; -import { fetchPatchData, PatchInfo } from '@subwallet/extension-base/services/chain-service/utils'; +import { fetchPatchData, PatchInfo, randomizeProvider } from '@subwallet/extension-base/services/chain-service/utils'; import { EventService } from '@subwallet/extension-base/services/event-service'; import SettingService from '@subwallet/extension-base/services/setting-service/SettingService'; +import { IChain } from '@subwallet/extension-base/services/storage-service/databases'; +import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService'; import { Md5 } from 'ts-md5'; export class ChainOnlineService { private chainService: ChainService; private settingService: SettingService; private eventService: EventService; + private dbService: DatabaseService; refreshLatestChainDataTimeOut: NodeJS.Timer | undefined; - constructor (chainService: ChainService, settingService: SettingService, eventService: EventService) { + constructor (chainService: ChainService, settingService: SettingService, eventService: EventService, dbService: DatabaseService) { this.chainService = chainService; this.settingService = settingService; this.eventService = eventService; + this.dbService = dbService; } md5Hash (data: any) { @@ -107,7 +111,6 @@ export class ChainOnlineService { let currentChainStateMap: Record = {}; let currentChainStatusMap: Record = {}; let addedChain: string[] = []; - // todo: AssetLogoMap, ChainLogoMap if (isSafePatch && currentPatchVersion !== latestPatchVersion) { // 2. merge data map @@ -123,7 +126,7 @@ export class ChainOnlineService { addedChain.forEach((key) => { currentChainStateMap[key] = { active: false, - currentProvider: Object.keys(chainInfoMap[key].providers)[0], + currentProvider: randomizeProvider(chainInfoMap[key].providers).providerKey, manualTurnOff: false, slug: key }; @@ -165,6 +168,17 @@ export class ChainOnlineService { this.chainService.setChainStateMap(currentChainStateMap); this.chainService.subscribeChainStateMap().next(currentChainStateMap); + this.chainService.subscribeChainStatusMap().next(currentChainStatusMap); + + const storedChainInfoList: IChain[] = Object.keys(chainInfoMap).map((chainSlug) => { + return { + ...chainInfoMap[chainSlug], + ...currentChainStateMap[chainSlug] + }; + }); + + await this.dbService.bulkUpdateChainStore(storedChainInfoList); + if (latestChainLogoMap) { const logoMap = Object.assign({}, ChainLogoMap, latestChainLogoMap); @@ -193,11 +207,16 @@ export class ChainOnlineService { handleLatestPatchData () { this.fetchLatestPatchData().then((latestPatch) => { - if (latestPatch) { + if (latestPatch && !this.chainService.getlockChainInfoMap()) { this.eventService.waitAssetReady .then(() => { + this.chainService.setLockChainInfoMap(true); this.handleLatestPatch(latestPatch) - .catch(console.error); + .then(() => this.chainService.setLockChainInfoMap(false)) + .catch((e) => { + this.chainService.setLockChainInfoMap(false); + console.error('Error update latest patch', e); + }); }) .catch(console.error); } @@ -207,8 +226,7 @@ export class ChainOnlineService { checkLatestData () { clearInterval(this.refreshLatestChainDataTimeOut); this.handleLatestPatchData(); - this.chainService.handleLatestData(); - this.refreshLatestChainDataTimeOut = setInterval(this.handleLatestPatchData.bind(this), LATEST_CHAIN_DATA_FETCHING_INTERVAL); + this.refreshLatestChainDataTimeOut = setInterval(this.handleLatestPatchData.bind(this), LATEST_CHAIN_PATCH_FETCHING_INTERVAL); } } diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index e66c63e1bb..9f62f64730 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -4,7 +4,7 @@ import { AssetLogoMap, AssetRefMap, ChainAssetMap, ChainInfoMap, ChainLogoMap, MultiChainAssetMap } from '@subwallet/chain-list'; import { _AssetRef, _AssetRefPath, _AssetType, _ChainAsset, _ChainInfo, _ChainStatus, _EvmInfo, _MultiChainAsset, _SubstrateChainType, _SubstrateInfo, _TonInfo } from '@subwallet/chain-list/types'; import { AssetSetting, ValidateNetworkResponse } from '@subwallet/extension-base/background/KoniTypes'; -import { _DEFAULT_ACTIVE_CHAINS, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants'; +import { _DEFAULT_ACTIVE_CHAINS, _ZK_ASSET_PREFIX, LATEST_CHAIN_DATA_FETCHING_INTERVAL } from '@subwallet/extension-base/services/chain-service/constants'; import { EvmChainHandler } from '@subwallet/extension-base/services/chain-service/handler/EvmChainHandler'; import { MantaPrivateHandler } from '@subwallet/extension-base/services/chain-service/handler/manta/MantaPrivateHandler'; import { SubstrateChainHandler } from '@subwallet/extension-base/services/chain-service/handler/SubstrateChainHandler'; @@ -170,6 +170,14 @@ export class ChainService { return result; } + public getlockChainInfoMap () { + return this.lockChainInfoMap; + } + + public setLockChainInfoMap (isLock: boolean) { + this.lockChainInfoMap = isLock; + } + public getEvmApi (slug: string) { return this.evmChainHandler.getEvmApiByChain(slug); } @@ -681,6 +689,13 @@ export class ChainService { this.dataMap.assetRefMap = AssetRefMap; } + checkLatestData () { + clearInterval(this.refreshLatestChainDataTimeOut); + this.handleLatestData(); + + this.refreshLatestChainDataTimeOut = setInterval(this.handleLatestData.bind(this), LATEST_CHAIN_DATA_FETCHING_INTERVAL); + } + stopCheckLatestChainData () { clearInterval(this.refreshLatestChainDataTimeOut); } @@ -754,8 +769,13 @@ export class ChainService { handleLatestData () { this.fetchLatestChainData().then((latestChainInfo) => { + this.lockChainInfoMap = true; // do not need to check current lockChainInfoMap because all remains action is fast enough and don't affect this feature. this.handleLatestChainData(latestChainInfo); - }).catch(console.error); + this.lockChainInfoMap = false; + }).catch((e) => { + this.lockChainInfoMap = false; + console.error('Error update latest chain data', e); + }); this.fetchLatestPriceIdsData().then((latestPriceIds) => { this.handleLatestPriceId(latestPriceIds); @@ -1059,19 +1079,11 @@ export class ChainService { // } } - // private async fetchLatestAssetData () { - // return await Promise.all([fetchPatchData>('ChainAsset.json'), fetchPatchData>('AssetLogoMap.json')]); // lastest logo also here. - // } - // @ts-ignore private async fetchLatestPriceIdsData () { return await fetchStaticData>('chain-assets/price-map'); } - // private async fetchLatestAssetRef () { - // return await Promise.all([fetchStaticData('chain-assets/disabled-xcm-channels'), fetchPatchData>('AssetRef.json')]); // - // } - private async fetchLatestLedgerGenericAllowChains () { return await fetchStaticData('chains/ledger-generic-allow-chains') || []; } @@ -1226,8 +1238,36 @@ export class ChainService { manualTurnOff }); } - } else { - // Todo: Remove chain from storage + } else { // added chain from patch + this.dataMap.chainStateMap[storedSlug] = { + currentProvider: storedChainInfo.currentProvider, + slug: storedSlug, + active: storedChainInfo.active, + manualTurnOff + }; + + this.updateChainConnectionStatus(storedSlug, _ChainConnectionStatus.DISCONNECTED); + + newStorageData.push({ + ...storedChainSettingMap[storedSlug], + active: storedChainInfo.active, + currentProvider: storedChainInfo.currentProvider, + manualTurnOff + }); + + mergedChainInfoMap[storedSlug] = { + slug: storedSlug, + name: storedChainInfo.name, + providers: storedChainInfo.providers, + evmInfo: storedChainInfo.evmInfo, + substrateInfo: storedChainInfo.substrateInfo, + bitcoinInfo: storedChainInfo.bitcoinInfo ?? null, + tonInfo: storedChainInfo.tonInfo, + isTestnet: storedChainInfo.isTestnet, + chainStatus: storedChainInfo.chainStatus, + icon: storedChainInfo.icon, + extraInfo: storedChainInfo.extraInfo + }; } } @@ -1831,6 +1871,8 @@ export class ChainService { this.evmChainHandler.wakeUp(), this.tonChainHandler.wakeUp() ]); + + this.checkLatestData(); } public async initAssetSettings () { From 62ec5eb2d4e0d5412ffad1e994d797589279623f Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:44:21 +0700 Subject: [PATCH 10/14] [Issue-3132] feat: restored patched assets --- .../src/services/chain-online-service/index.ts | 10 ++++++++++ .../extension-base/src/services/chain-service/index.ts | 2 ++ .../src/services/storage-service/DatabaseService.ts | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index bc02f3277c..5c88a36556 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -179,6 +179,16 @@ export class ChainOnlineService { await this.dbService.bulkUpdateChainStore(storedChainInfoList); + const addedAssets: _ChainAsset[] = []; + + Object.entries(assetRegistry).forEach(([slug, asset]) => { + if (addedChain.includes(asset.originChain)) { + addedAssets.push(asset); + } + }); + + await this.dbService.bulkUpdateAssetsStore(addedAssets); + if (latestChainLogoMap) { const logoMap = Object.assign({}, ChainLogoMap, latestChainLogoMap); diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index 9f62f64730..c6ddabe917 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -1268,6 +1268,8 @@ export class ChainService { icon: storedChainInfo.icon, extraInfo: storedChainInfo.extraInfo }; + + deprecatedChainMap[storedSlug] = storedSlug; // todo: set a better name } } diff --git a/packages/extension-base/src/services/storage-service/DatabaseService.ts b/packages/extension-base/src/services/storage-service/DatabaseService.ts index 16572b0aae..b0db514b1f 100644 --- a/packages/extension-base/src/services/storage-service/DatabaseService.ts +++ b/packages/extension-base/src/services/storage-service/DatabaseService.ts @@ -406,6 +406,10 @@ export default class DatabaseService { return this.stores.asset.upsert(item); } + async bulkUpdateAssetsStore (items: _ChainAsset[]) { + return this.stores.asset.bulkUpsert(items); + } + async getAllAssetStore () { return this.stores.asset.getAll(); } From 2aab0f3c04b2f7f5e90e697500fb92710749f8d7 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:46:49 +0700 Subject: [PATCH 11/14] [Issue-3132] fix: fix emit event after run handlelatestpatch --- .../src/services/chain-online-service/index.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 5c88a36556..81fc83e821 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -207,8 +207,6 @@ export class ChainOnlineService { } catch (e) { console.error('Error fetching latest patch data'); } - - this.eventService.emit('asset.online.ready', true); } private async fetchLatestPatchData () { @@ -228,9 +226,15 @@ export class ChainOnlineService { console.error('Error update latest patch', e); }); }) - .catch(console.error); + .catch((e) => { + console.error('Asset fail to ready', e); + }); } - }).catch(console.error); + }).catch((e) => { + console.error('Error get latest patch or data map is locking', e); + }); + + this.eventService.emit('asset.online.ready', true); } checkLatestData () { From 7ab992ac917f92a84b356023a9d3efa61dff4968 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:31:57 +0700 Subject: [PATCH 12/14] [Issue-3814] fix: handle default data map --- .../src/services/chain-online-service/index.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 81fc83e821..136c55889a 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -105,11 +105,11 @@ export class ChainOnlineService { patchVersion: latestPatchVersion } = latestPatch; const currentPatchVersion = (await this.settingService.getChainlistSetting())?.patchVersion || ''; - let chainInfoMap: Record = {}; - let assetRegistry: Record = {}; - let multiChainAssetMap: Record = {}; - let currentChainStateMap: Record = {}; - let currentChainStatusMap: Record = {}; + let chainInfoMap: Record = this.chainService.getChainInfoMap(); + let assetRegistry: Record = this.chainService.getAssetRegistry(); + let multiChainAssetMap: Record = MultiChainAssetMap; + let currentChainStateMap: Record = this.chainService.getChainStateMap(); + let currentChainStatusMap: Record = this.chainService.getChainStatusMap(); let addedChain: string[] = []; if (isSafePatch && currentPatchVersion !== latestPatchVersion) { @@ -143,7 +143,7 @@ export class ChainOnlineService { assetRegistry = filterAssetInfoMap(this.chainService.getChainInfoMap(), Object.assign({}, this.chainService.getAssetRegistry(), latestAssetInfo), addedChain); } - if (latestMultiChainAsset && Object.keys(latestMultiChainAsset).length > 0) { + if (latestMultiChainAsset && Object.keys(latestMultiChainAsset).length > 0) { // todo: currently not support update latest multichain-asset multiChainAssetMap = { ...MultiChainAssetMap, ...latestMultiChainAsset }; } From 0efd27d5ba5bedabe425d4f638e24d67057b7c52 Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:11:07 +0700 Subject: [PATCH 13/14] [Issue-3814] fix: fix subscanSlug --- .../src/koni/background/handlers/State.ts | 10 +++-- .../services/chain-online-service/index.ts | 45 +++++++++++-------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index 19812c237a..606de89fc0 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -285,7 +285,6 @@ export default class KoniState { public async init () { await this.eventService.waitCryptoReady; await this.chainService.init(); - this.afterChainServiceInit(); await this.migrationService.run(); this.campaignService.init(); this.mktCampaignService.init(); @@ -304,9 +303,11 @@ export default class KoniState { await this.dbService.stores.crowdloan.removeEndedCrowdloans(); await this.startSubscription(); - this.chainOnlineService.checkLatestData(); this.chainService.checkLatestData(); + this.chainService.subscribeChainInfoMap().subscribe(() => { + this.afterChainServiceInit(); + }); } public async initMantaPay (password: string) { @@ -1643,10 +1644,11 @@ export default class KoniState { await this.walletConnectService.resetWallet(resetAll); await this.chainService.init(); - this.afterChainServiceInit(); - this.chainOnlineService.checkLatestData(); this.chainService.checkLatestData(); + this.chainService.subscribeChainInfoMap().subscribe(() => { + this.afterChainServiceInit(); + }); } public async enableMantaPay (updateStore: boolean, address: string, password: string, seedPhrase?: string) { diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index 136c55889a..eab7849b1f 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -214,27 +214,34 @@ export class ChainOnlineService { } handleLatestPatchData () { - this.fetchLatestPatchData().then((latestPatch) => { - if (latestPatch && !this.chainService.getlockChainInfoMap()) { - this.eventService.waitAssetReady - .then(() => { - this.chainService.setLockChainInfoMap(true); - this.handleLatestPatch(latestPatch) - .then(() => this.chainService.setLockChainInfoMap(false)) + this.fetchLatestPatchData() + .then((latestPatch) => { + return new Promise((resolve) => { + if (latestPatch && !this.chainService.getlockChainInfoMap()) { + this.eventService.waitAssetReady + .then(() => { + this.chainService.setLockChainInfoMap(true); + this.handleLatestPatch(latestPatch) + .then(() => this.chainService.setLockChainInfoMap(false)) + .catch((e) => { + this.chainService.setLockChainInfoMap(false); + console.error('Error update latest patch', e); + }) + .finally(resolve); + }) .catch((e) => { - this.chainService.setLockChainInfoMap(false); - console.error('Error update latest patch', e); + console.error('Asset fail to ready', e); + resolve(); }); - }) - .catch((e) => { - console.error('Asset fail to ready', e); - }); - } - }).catch((e) => { - console.error('Error get latest patch or data map is locking', e); - }); - - this.eventService.emit('asset.online.ready', true); + } else { + resolve(); + } + }); + }).catch((e) => { + console.error('Error get latest patch or data map is locking', e); + }).finally(() => { + this.eventService.emit('asset.online.ready', true); + }); } checkLatestData () { From 222a14dc1a8585fe1c9e330ba82ed230d08d591e Mon Sep 17 00:00:00 2001 From: bluezdot <72647326+bluezdot@users.noreply.github.com> Date: Fri, 22 Nov 2024 09:30:28 +0700 Subject: [PATCH 14/14] [Issue-3814] minor update --- .../src/services/chain-online-service/index.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index eab7849b1f..f9236c81f6 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -105,11 +105,11 @@ export class ChainOnlineService { patchVersion: latestPatchVersion } = latestPatch; const currentPatchVersion = (await this.settingService.getChainlistSetting())?.patchVersion || ''; - let chainInfoMap: Record = this.chainService.getChainInfoMap(); - let assetRegistry: Record = this.chainService.getAssetRegistry(); - let multiChainAssetMap: Record = MultiChainAssetMap; - let currentChainStateMap: Record = this.chainService.getChainStateMap(); - let currentChainStatusMap: Record = this.chainService.getChainStatusMap(); + let chainInfoMap: Record = structuredClone(this.chainService.getChainInfoMap()); + let assetRegistry: Record = structuredClone(this.chainService.getAssetRegistry()); + let multiChainAssetMap: Record = structuredClone(MultiChainAssetMap); + let currentChainStateMap: Record = structuredClone(this.chainService.getChainStateMap()); + let currentChainStatusMap: Record = structuredClone(this.chainService.getChainStatusMap()); let addedChain: string[] = []; if (isSafePatch && currentPatchVersion !== latestPatchVersion) { @@ -117,7 +117,7 @@ export class ChainOnlineService { if (latestChainInfo && Object.keys(latestChainInfo).length > 0) { chainInfoMap = Object.assign({}, this.chainService.getChainInfoMap(), latestChainInfo); - [currentChainStateMap, currentChainStatusMap] = [this.chainService.getChainStateMap(), this.chainService.getChainStatusMap()]; + [currentChainStateMap, currentChainStatusMap] = [structuredClone(this.chainService.getChainStateMap()), structuredClone(this.chainService.getChainStatusMap())]; const [currentChainStateKey, newChainKey] = [Object.keys(currentChainStateMap), Object.keys(chainInfoMap)];