From 148540f21466f5dfbad814f7e69118fb35614e98 Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 21 Nov 2024 18:42:32 +0330 Subject: [PATCH] refactor: using shared worker for fetching assets balances --- .../src/components/contexts.tsx | 4 +- .../accountDetails/components/AOC.tsx | 11 +- .../src/hooks/useAssetsBalances.ts | 268 ++++++++---------- .../src/hooks/useWorker.ts | 16 ++ .../src/util/workers/getAssetOnRelayChain.js | 141 --------- .../shared-helpers/getAssetOnAssetHub.js | 37 +++ .../getAssetOnMultiAssetChain.js | 48 +--- .../shared-helpers/getAssetOnRelayChain.js | 45 +++ .../getAssets.js} | 66 +---- .../workers/shared-helpers/getBalances.js | 46 +++ .../shared-helpers/getPooledBalance.js | 43 +++ .../src/util/workers/sharedWorker.js | 57 ++++ packages/extension-ui/src/Popup/index.tsx | 196 +++++++------ tsconfig.json | 2 +- 14 files changed, 483 insertions(+), 497 deletions(-) create mode 100644 packages/extension-polkagate/src/hooks/useWorker.ts delete mode 100644 packages/extension-polkagate/src/util/workers/getAssetOnRelayChain.js create mode 100644 packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnAssetHub.js rename packages/extension-polkagate/src/util/workers/{ => shared-helpers}/getAssetOnMultiAssetChain.js (52%) create mode 100644 packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnRelayChain.js rename packages/extension-polkagate/src/util/workers/{getAssetOnAssetHub.js => shared-helpers/getAssets.js} (50%) create mode 100644 packages/extension-polkagate/src/util/workers/shared-helpers/getBalances.js create mode 100644 packages/extension-polkagate/src/util/workers/shared-helpers/getPooledBalance.js create mode 100644 packages/extension-polkagate/src/util/workers/sharedWorker.js diff --git a/packages/extension-polkagate/src/components/contexts.tsx b/packages/extension-polkagate/src/components/contexts.tsx index f50455586..4a7a6223a 100644 --- a/packages/extension-polkagate/src/components/contexts.tsx +++ b/packages/extension-polkagate/src/components/contexts.tsx @@ -27,6 +27,7 @@ const ToastContext = React.createContext<({ show: (message: string) => void })>( const UserAddedChainContext = React.createContext({}); const GenesisHashOptionsContext = React.createContext([]); const AccountIconThemeContext = React.createContext({ accountIconTheme: undefined, setAccountIconTheme: noop }); +const WorkerContext = React.createContext(undefined); export { AccountContext, AccountIconThemeContext, @@ -44,4 +45,5 @@ export { AccountContext, SettingsContext, SigningReqContext, ToastContext, - UserAddedChainContext }; + UserAddedChainContext, + WorkerContext }; diff --git a/packages/extension-polkagate/src/fullscreen/accountDetails/components/AOC.tsx b/packages/extension-polkagate/src/fullscreen/accountDetails/components/AOC.tsx index 40c0cb779..ae99f5bad 100644 --- a/packages/extension-polkagate/src/fullscreen/accountDetails/components/AOC.tsx +++ b/packages/extension-polkagate/src/fullscreen/accountDetails/components/AOC.tsx @@ -14,7 +14,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { getValue } from '@polkadot/extension-polkagate/src/popup/account/util'; import { AssetLogo, FormatPrice, ShowBalance } from '../../../components'; -import { useApi, useNotifyOnChainChange, usePrices, useTranslation } from '../../../hooks'; +import { useApi, useNotifyOnChainChange, usePrices, useSelectedChains, useTranslation } from '../../../hooks'; import getLogo2 from '../../../util/getLogo2'; interface Props { @@ -120,6 +120,7 @@ function AOC ({ accountAssets, address, hideNumbers, mode = 'Detail', onclick, s const api = useApi(address); const pricesInCurrencies = usePrices(); + const selectedChains = useSelectedChains(); useNotifyOnChainChange(address); @@ -128,12 +129,14 @@ function AOC ({ accountAssets, address, hideNumbers, mode = 'Detail', onclick, s const toggleAssets = useCallback(() => setShowMore(!showMore), [showMore]); const assets = useMemo(() => { - if (accountAssets && accountAssets.length > 0) { - return accountAssets; + if (accountAssets && accountAssets.length > 0 && selectedChains) { + // filter non selected chains + + return accountAssets.filter(({ genesisHash }) => selectedChains.includes(genesisHash)); } else { return [undefined, undefined]; // two undefined to show two skeletons } - }, [accountAssets]); + }, [accountAssets, selectedChains]); const shouldShowCursor = useMemo(() => (mode === 'Detail' && accountAssets && accountAssets.length > 5) || (mode !== 'Detail' && accountAssets && accountAssets.length > 6), [accountAssets, mode]); diff --git a/packages/extension-polkagate/src/hooks/useAssetsBalances.ts b/packages/extension-polkagate/src/hooks/useAssetsBalances.ts index f558dc3f7..86f44bf79 100644 --- a/packages/extension-polkagate/src/hooks/useAssetsBalances.ts +++ b/packages/extension-polkagate/src/hooks/useAssetsBalances.ts @@ -10,7 +10,7 @@ import type { AlertType, DropdownOption, UserAddedChains } from '../util/types'; import { createAssets } from '@polkagate/apps-config/assets'; import { Chance } from 'chance'; -import { type Dispatch, type SetStateAction, useCallback, useEffect, useMemo, useState } from 'react'; +import { type Dispatch, type SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { BN, isObject } from '@polkadot/util'; @@ -24,7 +24,7 @@ import { TIME_TO_REMOVE_ALERT } from './useAlerts'; import useSelectedChains from './useSelectedChains'; import { useIsTestnetEnabled, useTranslation } from '.'; -type WorkerMessage = Record; +interface WorkerMessage { functionName?: string, metadata?: MetadataDef, results?: Record } type Assets = Record; type AssetsBalancesPerChain = Record; type AssetsBalancesPerAddress = Record; @@ -105,7 +105,7 @@ const BALANCE_VALIDITY_PERIOD = 1 * 1000 * 60; export const isUpToDate = (date?: number): boolean | undefined => date ? Date.now() - date < BALANCE_VALIDITY_PERIOD : undefined; -function allHexToBN (balances: object | string | undefined): BalancesDetails | {} { +function allHexToBN (balances: object | string | undefined): BalancesDetails | object { if (!balances) { return {}; } @@ -126,30 +126,32 @@ function allHexToBN (balances: object | string | undefined): BalancesDetails | { const assetsChains = createAssets(); +const FUNCTIONS = ['getAssetOnRelayChain', 'getAssetOnAssetHub', 'getAssetOnMultiAssetChain']; + /** * @description To fetch accounts assets on different selected chains * @param addresses a list of users accounts' addresses * @returns a list of assets balances on different selected chains and a fetching timestamp */ -export default function useAssetsBalances (accounts: AccountJson[] | null, setAlerts: Dispatch>, genesisOptions: DropdownOption[], userAddedEndpoints: UserAddedChains): SavedAssets | undefined | null { +export default function useAssetsBalances (accounts: AccountJson[] | null, setAlerts: Dispatch>, genesisOptions: DropdownOption[], userAddedEndpoints: UserAddedChains, worker?: Worker): SavedAssets | undefined | null { const { t } = useTranslation(); const isTestnetEnabled = useIsTestnetEnabled(); const selectedChains = useSelectedChains(); + const workerCallsCount = useRef(0); const random = useMemo(() => new Chance(), []); /** to limit calling of this heavy call on just home and account details */ - const SHOULD_FETCH_ASSETS = window.location.hash === '#/' || window.location.hash.startsWith('#/accountfs'); + const FETCH_PATHS = window.location.hash === '#/' || window.location.hash.startsWith('#/accountfs'); /** We need to trigger address change when a new address is added, without affecting other account fields. Therefore, we use the length of the accounts array as a dependency. */ // eslint-disable-next-line react-hooks/exhaustive-deps const addresses = useMemo(() => accounts?.map(({ address }) => address), [accounts?.length]); const [fetchedAssets, setFetchedAssets] = useState(); - const [isWorking, setIsWorking] = useState(false); - const [workersCalled, setWorkersCalled] = useState(); const [isUpdate, setIsUpdate] = useState(false); + const [roundDone, setRoundDone] = useState(false); const addAlert = useCallback(() => { const id = random.string({ length: 10 }); @@ -161,12 +163,12 @@ export default function useAssetsBalances (accounts: AccountJson[] | null, setAl }, [random, setAlerts, t]); useEffect(() => { - SHOULD_FETCH_ASSETS && getStorage(ASSETS_NAME_IN_STORAGE, true).then((savedAssets) => { + FETCH_PATHS && getStorage(ASSETS_NAME_IN_STORAGE, true).then((savedAssets) => { const _timeStamp = (savedAssets as SavedAssets)?.timeStamp; setIsUpdate(Boolean(isUpToDate(_timeStamp))); }).catch(console.error); - }, [SHOULD_FETCH_ASSETS]); + }, [FETCH_PATHS]); const removeZeroBalanceRecords = useCallback((toBeSavedAssets: SavedAssets): SavedAssets => { const _toBeSavedAssets = { ...toBeSavedAssets }; @@ -212,36 +214,32 @@ export default function useAssetsBalances (accounts: AccountJson[] | null, setAl setFetchedAssets(updatedAssetsToBeSaved); setStorage(ASSETS_NAME_IN_STORAGE, updatedAssetsToBeSaved, true).catch(console.error); - setWorkersCalled(undefined); setIsUpdate(true); }, [addresses, fetchedAssets, removeZeroBalanceRecords]); useEffect(() => { /** when one round fetch is done, we will save fetched assets in storage */ - if (addresses && workersCalled?.length === 0) { + if (addresses && roundDone) { + setRoundDone(false); handleAccountsSaving(); addAlert(); } - }, [addAlert, addresses, handleAccountsSaving, workersCalled?.length]); + }, [addAlert, addresses, handleAccountsSaving, roundDone]); useEffect(() => { /** chain list may have changed */ - isUpdate && !isWorking && selectedChains?.length && setIsUpdate(false); + isUpdate && !workerCallsCount.current && selectedChains?.length && setIsUpdate(false); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedChains]); useEffect(() => { - /** account list may have changed */ - isUpdate && !isWorking && addresses?.length && setIsUpdate(false); + /** accounts list may have changed */ + isUpdate && !workerCallsCount.current && addresses?.length && setIsUpdate(false); // eslint-disable-next-line react-hooks/exhaustive-deps }, [addresses]); useEffect(() => { - setIsWorking(!!workersCalled?.length); - }, [workersCalled?.length]); - - useEffect(() => { - if (!SHOULD_FETCH_ASSETS) { + if (!FETCH_PATHS) { return; } @@ -264,20 +262,18 @@ export default function useAssetsBalances (accounts: AccountJson[] | null, setAl return () => { unsubscribe(); }; - }, [SHOULD_FETCH_ASSETS, addresses]); + }, [FETCH_PATHS, addresses]); - const handleSetWorkersCall = useCallback((worker: Worker, terminate?: 'terminate') => { - terminate && worker.terminate(); + console.info('workerCallsCount.current', workerCallsCount.current); - setWorkersCalled((workersCalled) => { - terminate - ? workersCalled?.pop() - : !workersCalled - ? workersCalled = [worker] - : workersCalled.push(worker); + const handleRequestCount = useCallback((functionName: string) => { + if (FUNCTIONS.includes(functionName) && workerCallsCount.current) { + workerCallsCount.current--; - return workersCalled && [...workersCalled] as Worker[]; - }); + if (workerCallsCount.current === 0) { + setRoundDone(true); + } + } }, []); const combineAndSetAssets = useCallback((assets: Assets) => { @@ -307,168 +303,124 @@ export default function useAssetsBalances (accounts: AccountJson[] | null, setAl }); }, [addresses]); - const fetchAssetOnRelayChain = useCallback((_addresses: string[], chainName: string) => { - const worker: Worker = new Worker(new URL('../util/workers/getAssetOnRelayChain.js', import.meta.url)); - const _assets: Assets = {}; - - handleSetWorkersCall(worker); - - worker.postMessage({ addresses: _addresses, chainName, userAddedEndpoints }); - - worker.onerror = (err) => { - console.log(err); - }; + const handleWorkerMessages = useCallback(() => { + if (!worker) { + return; + } worker.onmessage = (e: MessageEvent) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const message = e.data; if (!message) { - console.info(`No assets found on ${chainName}`); - handleSetWorkersCall(worker, 'terminate'); - - return; + return; // may receive unknown messages! } - const parsedMessage = JSON.parse(message) as WorkerMessage; - - if ('metadata' in parsedMessage) { - const metadata = parsedMessage['metadata']; + const { functionName, metadata, results } = JSON.parse(message) as WorkerMessage; - updateMetadata(metadata as unknown as MetadataDef).catch(console.error); + if (metadata) { + updateMetadata(metadata).catch(console.error); return; } - Object.keys(parsedMessage).forEach((address) => { - /** We use index 0 because we consider each relay chain has only one asset */ - _assets[address] = [ - { - price: undefined, - ...parsedMessage[address][0], - ...allHexToBN(parsedMessage[address][0].balanceDetails) as BalancesDetails, - date: Date.now(), - decimal: Number(parsedMessage[address][0].decimal), - totalBalance: isHexToBn(parsedMessage[address][0].totalBalance) - }]; - - /** since balanceDetails is already converted all to BN, hence we can delete that field */ - delete _assets[address][0].balanceDetails; - }); - - combineAndSetAssets(_assets); - handleSetWorkersCall(worker, 'terminate'); - }; - }, [combineAndSetAssets, handleSetWorkersCall, userAddedEndpoints]); - - const fetchAssetOnAssetHubs = useCallback((_addresses: string[], chainName: string, assetsToBeFetched?: Asset[]) => { - const worker: Worker = new Worker(new URL('../util/workers/getAssetOnAssetHub.js', import.meta.url)); - const _assets: Assets = {}; - - handleSetWorkersCall(worker); - worker.postMessage({ addresses: _addresses, assetsToBeFetched, chainName, userAddedEndpoints }); - - worker.onerror = (err) => { - console.log(err); - }; - - worker.onmessage = (e: MessageEvent) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const message = e.data; - - if (!message) { - console.info(`No assets found on ${chainName}`); - handleSetWorkersCall(worker, 'terminate'); - + if (!functionName) { return; } - const parsedMessage = JSON.parse(message) as WorkerMessage; - - if ('metadata' in parsedMessage) { - const metadata = parsedMessage['metadata']; - - updateMetadata(metadata as unknown as MetadataDef).catch(console.error); + handleRequestCount(functionName); // need to count chains instead of workers since we are using shared worker + if (!results) { return; } - Object.keys(parsedMessage).forEach((address) => { - _assets[address] = parsedMessage[address] - .map((message) => { - const _asset = { - ...message, - ...allHexToBN(message.balanceDetails) as BalancesDetails, + const _assets: Assets = {}; + + if (functionName === 'getAssetOnRelayChain') { + Object.keys(results).forEach((address) => { + /** We use index 0 because we consider each relay chain has only one asset */ + _assets[address] = [ + { + price: undefined, + ...results[address][0], + ...allHexToBN(results[address][0].balanceDetails) as BalancesDetails, date: Date.now(), - decimal: Number(message.decimal), - totalBalance: isHexToBn(message.totalBalance) - }; + decimal: Number(results[address][0].decimal), + totalBalance: isHexToBn(results[address][0].totalBalance) + }]; - delete _asset.balanceDetails; + /** since balanceDetails is already converted all to BN, hence we can delete that field */ + delete _assets[address][0].balanceDetails; + }); + } - return _asset; - }); - }); + if (['getAssetOnAssetHub', 'getAssetOnMultiAssetChain'].includes(functionName)) { + Object.keys(results).forEach((address) => { + _assets[address] = results[address].map( + (message) => { + const temp = { + ...message, + ...allHexToBN(message.balanceDetails) as BalancesDetails, + date: Date.now(), + decimal: Number(message.decimal), + totalBalance: isHexToBn(message.totalBalance) + }; + + delete temp.balanceDetails; + + return temp; + }); + }); + } combineAndSetAssets(_assets); - handleSetWorkersCall(worker, 'terminate'); }; - }, [combineAndSetAssets, handleSetWorkersCall, userAddedEndpoints]); + }, [combineAndSetAssets, handleRequestCount, worker]); - const fetchAssetOnMultiAssetChain = useCallback((addresses: string[], chainName: string) => { - const worker: Worker = new Worker(new URL('../util/workers/getAssetOnMultiAssetChain.js', import.meta.url)); + const fetchAssetOnRelayChain = useCallback((_addresses: string[], chainName: string) => { + if (!worker) { + return; + } + + const functionName = 'getAssetOnRelayChain'; - handleSetWorkersCall(worker); - worker.postMessage({ addresses, chainName, userAddedEndpoints }); + worker.postMessage({ functionName, parameters: { address: _addresses, chainName, userAddedEndpoints } }); worker.onerror = (err) => { console.log(err); }; - worker.onmessage = (e: MessageEvent) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const message = e.data; - - if (!message) { - console.info(`No assets found on ${chainName}`); - handleSetWorkersCall(worker, 'terminate'); - - return; - } - - const parsedMessage = JSON.parse(message) as WorkerMessage; + handleWorkerMessages(); + }, [handleWorkerMessages, userAddedEndpoints, worker]); - if ('metadata' in parsedMessage) { - const metadata = parsedMessage['metadata']; + const fetchAssetOnAssetHubs = useCallback((_addresses: string[], chainName: string, assetsToBeFetched?: Asset[]) => { + if (!worker) { + return; + } - updateMetadata(metadata as unknown as MetadataDef).catch(console.error); + const functionName = 'getAssetOnAssetHub'; - return; - } + worker.postMessage({ functionName, parameters: { address: _addresses, assetsToBeFetched, chainName, userAddedEndpoints } }); - const _assets: Assets = {}; + worker.onerror = (err) => { + console.log(err); + }; + }, [userAddedEndpoints, worker]); - Object.keys(parsedMessage).forEach((address) => { - _assets[address] = parsedMessage[address].map( - (message) => { - const temp = { - ...message, - ...allHexToBN(message.balanceDetails) as BalancesDetails, - date: Date.now(), - decimal: Number(message.decimal), - totalBalance: isHexToBn(message.totalBalance) - }; + const fetchAssetOnMultiAssetChain = useCallback((addresses: string[], chainName: string) => { + if (!worker) { + return; + } - delete temp.balanceDetails; + const functionName = 'getAssetOnMultiAssetChain'; - return temp; - }); - }); + worker.postMessage({ functionName, parameters: { addresses, chainName, userAddedEndpoints } }); - combineAndSetAssets(_assets); - handleSetWorkersCall(worker, 'terminate'); + worker.onerror = (err) => { + console.log(err); }; - }, [combineAndSetAssets, handleSetWorkersCall, userAddedEndpoints]); + + handleWorkerMessages(); + }, [handleWorkerMessages, userAddedEndpoints, worker]); const fetchMultiAssetChainAssets = useCallback((chainName: string) => { return addresses && fetchAssetOnMultiAssetChain(addresses, chainName); @@ -486,7 +438,9 @@ export default function useAssetsBalances (accounts: AccountJson[] | null, setAl return; } - return chainName && fetchAssetOnRelayChain(addresses!, chainName); + workerCallsCount.current++; + + return fetchAssetOnRelayChain(addresses!, chainName); } if (ASSET_HUBS.includes(genesisHash)) { /** Checking assets balances on Asset Hub chains */ @@ -500,17 +454,21 @@ export default function useAssetsBalances (accounts: AccountJson[] | null, setAl const assetsToBeFetched = assetsChains[chainName]; /** we fetch asset hubs assets only if it is whitelisted via PolkaGate/apps-config */ + workerCallsCount.current++; + return fetchAssetOnAssetHubs(addresses!, chainName, assetsToBeFetched); } /** Checking assets balances on chains with more than one assets such as Acala, Hydration, etc, */ if (maybeMultiAssetChainName) { + workerCallsCount.current++; + fetchMultiAssetChainAssets(maybeMultiAssetChainName); } }, [addresses, fetchAssetOnAssetHubs, fetchAssetOnRelayChain, fetchMultiAssetChainAssets, genesisOptions]); useEffect(() => { - if (!SHOULD_FETCH_ASSETS || !addresses || addresses.length === 0 || isWorking || isUpdate || !selectedChains || isTestnetEnabled === undefined) { + if (!FETCH_PATHS || !worker || !addresses || addresses.length === 0 || workerCallsCount.current || isUpdate || !selectedChains || isTestnetEnabled === undefined) { return; } @@ -531,7 +489,7 @@ export default function useAssetsBalances (accounts: AccountJson[] | null, setAl fetchAssets(genesisHash, isSingleTokenChain, maybeMultiAssetChainName); }); - }, [SHOULD_FETCH_ASSETS, addresses, fetchAssets, isTestnetEnabled, isUpdate, isWorking, selectedChains, genesisOptions]); + }, [FETCH_PATHS, addresses, fetchAssets, worker, isTestnetEnabled, isUpdate, selectedChains, genesisOptions]); return fetchedAssets; } diff --git a/packages/extension-polkagate/src/hooks/useWorker.ts b/packages/extension-polkagate/src/hooks/useWorker.ts new file mode 100644 index 000000000..c0a0a34a9 --- /dev/null +++ b/packages/extension-polkagate/src/hooks/useWorker.ts @@ -0,0 +1,16 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { useContext } from 'react'; + +import { WorkerContext } from '../components'; + +export const useWorker = () => { + const worker = useContext(WorkerContext); + + if (worker === undefined) { + throw new Error('useWorker must be used within a WorkerProvider'); + } + + return worker; +}; diff --git a/packages/extension-polkagate/src/util/workers/getAssetOnRelayChain.js b/packages/extension-polkagate/src/util/workers/getAssetOnRelayChain.js deleted file mode 100644 index a4053e31a..000000000 --- a/packages/extension-polkagate/src/util/workers/getAssetOnRelayChain.js +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -// @ts-nocheck - -/* eslint-disable import-newlines/enforce */ -/* eslint-disable object-curly-newline */ - -import { BN, BN_ONE, BN_ZERO } from '@polkadot/util'; - -import { NATIVE_TOKEN_ASSET_ID, TEST_NETS } from '../constants'; -import getPoolAccounts from '../getPoolAccounts'; -import { getPriceIdByChainName } from '../utils'; -import { balancify, closeWebsockets, fastestEndpoint, getChainEndpoints, metadataFromApi } from './utils'; - -async function getPooledBalance (api, address) { - const response = await api.query['nominationPools']['poolMembers'](address); - const member = response?.unwrapOr(undefined); - - if (!member) { - return BN_ZERO; - } - - const poolId = member.poolId; - const accounts = poolId && getPoolAccounts(api, poolId); - - if (!accounts) { - return BN_ZERO; - } - - const [bondedPool, stashIdAccount, myClaimable] = await Promise.all([ - api.query['nominationPools']['bondedPools'](poolId), - api.derive.staking.account(accounts.stashId), - api.call['nominationPoolsApi']['pendingRewards'](address) - ]); - - const active = member.points.isZero() - ? BN_ZERO - : (new BN(String(member.points)).mul(new BN(String(stashIdAccount.stakingLedger.active)))).div(new BN(String(bondedPool.unwrap()?.points ?? BN_ONE))); - - const rewards = myClaimable; - let unlockingValue = BN_ZERO; - - member?.unbondingEras?.forEach((value) => { - unlockingValue = unlockingValue.add(value); - }); - - return active.add(rewards).add(unlockingValue); -} - -async function getBalances (chainName, addresses, userAddedEndpoints) { - const chainEndpoints = getChainEndpoints(chainName, userAddedEndpoints); - const { api, connections } = await fastestEndpoint(chainEndpoints); - - if (api.isConnected && api.derive.balances) { - const result = metadataFromApi(api); - - postMessage(JSON.stringify(result)); - - const requests = addresses.map(async (address) => { - const balances = await api.derive.balances.all(address); - const systemBalance = await api.query.system.account(address); - - balances.frozenBalance = systemBalance.frozen; - - let soloTotal = BN_ZERO; - let pooledBalance = BN_ZERO; - - if (api.query.nominationPools) { - pooledBalance = await getPooledBalance(api, address); - } - - if (api.query.staking?.ledger) { - const ledger = await api.query.staking.ledger(address); - - if (ledger.isSome) { - soloTotal = ledger?.unwrap()?.total?.toString(); - } - } - - return { address, balances, pooledBalance, soloTotal }; - }); - - return { api, balanceInfo: await Promise.all(requests), connectionsToBeClosed: connections }; - } -} - -async function getAssetOnRelayChain (addresses, chainName, userAddedEndpoints) { - const results = {}; - - await getBalances(chainName, addresses, userAddedEndpoints) - .then(({ api, balanceInfo, connectionsToBeClosed }) => { - balanceInfo.forEach(({ address, balances, pooledBalance, soloTotal }) => { - const totalBalance = balances.freeBalance.add(balances.reservedBalance).add(pooledBalance); - const genesisHash = api.genesisHash.toString(); - const priceId = TEST_NETS.includes(genesisHash) - ? undefined - : getPriceIdByChainName(chainName, userAddedEndpoints); - - results[address] = [{ // since some chains may have more than one asset hence we use an array here! even thought its not needed for relay chains but just to be as a general rule. - assetId: NATIVE_TOKEN_ASSET_ID, - balanceDetails: balancify({ ...balances, pooledBalance, soloTotal }), - chainName, - decimal: api.registry.chainDecimals[0], - genesisHash, - priceId, - token: api.registry.chainTokens[0], - totalBalance: String(totalBalance) - }]; - }); - - closeWebsockets(connectionsToBeClosed); - }) - .catch((error) => { - console.error(`getAssetOnRelayChain: Error fetching balances for ${chainName}:`, error); - }).finally(() => { - Object.keys(results).length ? postMessage(JSON.stringify(results)) : postMessage(undefined); - }); -} - -onmessage = async (e) => { - const { addresses, chainName, userAddedEndpoints } = e.data; - - let tryCount = 1; - - while (tryCount >= 1 && tryCount <= 5) { - try { - await getAssetOnRelayChain(addresses, chainName, userAddedEndpoints); - - tryCount = 0; - - return; - } catch (error) { - console.error(`Error while fetching assets on relay chains, ${5 - tryCount} times to retry`, error); - - tryCount === 5 && postMessage(undefined); - } - - tryCount++; - } -}; diff --git a/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnAssetHub.js b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnAssetHub.js new file mode 100644 index 000000000..07a37f654 --- /dev/null +++ b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnAssetHub.js @@ -0,0 +1,37 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { closeWebsockets, fastestEndpoint, getChainEndpoints, metadataFromApi, toGetNativeToken } from '../utils'; +import { getAssets } from './getAssets.js'; + +// @ts-ignore + +export async function getAssetOnAssetHub (addresses, assetsToBeFetched, chainName, userAddedEndpoints) { + const endpoints = getChainEndpoints(chainName, userAddedEndpoints); + const { api, connections } = await fastestEndpoint(endpoints); + + const { metadata } = metadataFromApi(api); + + postMessage(JSON.stringify({ functionName: 'getAssetOnAssetHub', metadata })); + + const results = await toGetNativeToken(addresses, api, chainName); + + // @ts-ignore + const nonNativeAssets = (assetsToBeFetched || []).filter((asset) => !asset.extras?.isNative); + + /** to calculate a new Foreign Token like MYTH asset id based on its XCM multi-location */ + // const allForeignAssets = await api.query.foreignAssets.asset.entries(); + // for (const [key, _others] of allForeignAssets) { + // const id = key.args[0]; + // const assetMetaData = await api.query.foreignAssets.metadata(id); + + // if (assetMetaData.toHuman().symbol === 'MYTH') { + // console.log('new foreign asset id:', encodeMultiLocation(id)); + // } + // } + + await getAssets(addresses, api, nonNativeAssets, chainName, results); + + postMessage(JSON.stringify({ functionName: 'getAssetOnAssetHub', results })); + closeWebsockets(connections); +} diff --git a/packages/extension-polkagate/src/util/workers/getAssetOnMultiAssetChain.js b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnMultiAssetChain.js similarity index 52% rename from packages/extension-polkagate/src/util/workers/getAssetOnMultiAssetChain.js rename to packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnMultiAssetChain.js index 8dca8583e..41891992c 100644 --- a/packages/extension-polkagate/src/util/workers/getAssetOnMultiAssetChain.js +++ b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnMultiAssetChain.js @@ -3,19 +3,17 @@ // @ts-nocheck -import { createAssets } from '@polkagate/apps-config/assets'; - -import { getSubstrateAddress } from '../utils'; +import { getSubstrateAddress } from '../../utils'; // eslint-disable-next-line import/extensions -import { balancifyAsset, closeWebsockets, fastestEndpoint, getChainEndpoints, metadataFromApi, toGetNativeToken } from './utils'; +import { balancifyAsset, closeWebsockets, fastestEndpoint, getChainEndpoints, metadataFromApi, toGetNativeToken } from '../utils'; -async function getAssets (addresses, assetsToBeFetched, chainName, userAddedEndpoints) { +export async function getAssetOnMultiAssetChain (assetsToBeFetched, addresses, chainName, userAddedEndpoints) { const endpoints = getChainEndpoints(chainName, userAddedEndpoints); const { api, connections } = await fastestEndpoint(endpoints); - const result = metadataFromApi(api); + const { metadata } = metadataFromApi(api); - postMessage(JSON.stringify(result)); + postMessage(JSON.stringify({ functionName: 'getAssetOnMultiAssetChain', metadata })); const results = await toGetNativeToken(addresses, api, chainName); @@ -56,42 +54,10 @@ async function getAssets (addresses, assetsToBeFetched, chainName, userAddedEndp results[address]?.push(asset) ?? (results[address] = [asset]); } else { - console.log(`NOTE: There is an asset on ${chainName} for ${formatted} which is not whitelisted. assetInfo`, storageKey, balance?.toHuman()); + console.info(`NOTE: There is an asset on ${chainName} for ${formatted} which is not whitelisted. assetInfo`, storageKey, balance?.toHuman()); } }); - postMessage(JSON.stringify(results)); + postMessage(JSON.stringify({ functionName: 'getAssetOnMultiAssetChain', results })); closeWebsockets(connections); } - -onmessage = async (e) => { - const { addresses, chainName, userAddedEndpoints } = e.data; - - const assetsChains = createAssets(); - const assetsToBeFetched = assetsChains[chainName]; - - /** if assetsToBeFetched === undefined then we don't fetch assets by default at first, but wil fetch them on-demand later in account details page*/ - if (!assetsToBeFetched) { - console.info(`getAssetOnMultiAssetChain: No assets to be fetched on ${chainName}`); - - return postMessage(undefined); // FIXME: if this happens, should be handled in caller - } - - let tryCount = 1; - - while (tryCount >= 1 && tryCount <= 5) { - try { - await getAssets(addresses, assetsToBeFetched, chainName, userAddedEndpoints); - - tryCount = 0; - - return; - } catch (error) { - console.error(`getAssetOnMultiAssetChain: Error while fetching assets on ${chainName}, ${5 - tryCount} times to retry`, error); - - tryCount === 5 && postMessage(undefined); - } - - tryCount++; - } -}; diff --git a/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnRelayChain.js b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnRelayChain.js new file mode 100644 index 000000000..1398801b4 --- /dev/null +++ b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnRelayChain.js @@ -0,0 +1,45 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +// @ts-nocheck + +import { NATIVE_TOKEN_ASSET_ID, TEST_NETS } from '../../constants'; +import { getPriceIdByChainName } from '../../utils'; +import { balancify, closeWebsockets } from '../utils'; +import { getBalances } from './getBalances.js'; + +export async function getAssetOnRelayChain (addresses, chainName, userAddedEndpoints) { + const results = {}; + + await getBalances(chainName, addresses, userAddedEndpoints) + .then(({ api, balanceInfo, connectionsToBeClosed }) => { + balanceInfo.forEach(({ address, balances, pooledBalance, soloTotal }) => { + const totalBalance = balances.freeBalance.add(balances.reservedBalance).add(pooledBalance); + const genesisHash = api.genesisHash.toString(); + + const priceId = TEST_NETS.includes(genesisHash) + ? undefined + : getPriceIdByChainName(chainName, userAddedEndpoints); + + results[address] = [{ // since some chains may have more than one asset hence we use an array here! even thought its not needed for relay chains but just to be as a general rule. + assetId: NATIVE_TOKEN_ASSET_ID, + balanceDetails: balancify({ ...balances, pooledBalance, soloTotal }), + chainName, + decimal: api.registry.chainDecimals[0], + genesisHash, + priceId, + token: api.registry.chainTokens[0], + totalBalance: String(totalBalance) + }]; + }); + + closeWebsockets(connectionsToBeClosed); + }) + .catch((error) => { + console.error(`getAssetOnRelayChain: Error fetching balances for ${chainName}:`, error); + }).finally(() => { + Object.keys(results).length + ? postMessage(JSON.stringify({ functionName: 'getAssetOnRelayChain', results })) + : postMessage({ functionName: 'getAssetOnRelayChain' }); + }); +} diff --git a/packages/extension-polkagate/src/util/workers/getAssetOnAssetHub.js b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssets.js similarity index 50% rename from packages/extension-polkagate/src/util/workers/getAssetOnAssetHub.js rename to packages/extension-polkagate/src/util/workers/shared-helpers/getAssets.js index 375091c18..5c5039545 100644 --- a/packages/extension-polkagate/src/util/workers/getAssetOnAssetHub.js +++ b/packages/extension-polkagate/src/util/workers/shared-helpers/getAssets.js @@ -3,11 +3,10 @@ import { BN_ZERO } from '@polkadot/util'; -import { decodeMultiLocation } from '../utils'; -import { closeWebsockets, fastestEndpoint, getChainEndpoints, metadataFromApi, toGetNativeToken } from './utils'; +import { decodeMultiLocation } from '../../utils'; //@ts-ignore -async function getAssets (addresses, api, assets, chainName, results) { +export async function getAssets (addresses, api, assets, chainName, results) { try { for (const asset of assets) { const isForeignAssets = asset.isForeign; @@ -59,65 +58,6 @@ async function getAssets (addresses, api, assets, chainName, results) { }); } } catch (e) { - console.error('Something went wrong while fetching assets', e); + console.error(`Something went wrong while fetching assets on ${chainName}`, e); } } - -// @ts-ignore -async function getAssetOnAssetHub (addresses, assetsToBeFetched, chainName, userAddedEndpoints) { - const endpoints = getChainEndpoints(chainName, userAddedEndpoints); - const { api, connections } = await fastestEndpoint(endpoints); - - const result = metadataFromApi(api); - - postMessage(JSON.stringify(result)); - - const results = await toGetNativeToken(addresses, api, chainName); - - // @ts-ignore - const nonNativeAssets = assetsToBeFetched.filter((asset) => !asset.extras?.isNative); - - /** to calculate a new Foreign Token like MYTH asset id based on its XCM multi-location */ - // const allForeignAssets = await api.query.foreignAssets.asset.entries(); - // for (const [key, _others] of allForeignAssets) { - // const id = key.args[0]; - // const assetMetaData = await api.query.foreignAssets.metadata(id); - - // if (assetMetaData.toHuman().symbol === 'MYTH') { - // console.log('new foreign asset id:', encodeMultiLocation(id)); - // } - // } - - await getAssets(addresses, api, nonNativeAssets, chainName, results); - - postMessage(JSON.stringify(results)); - closeWebsockets(connections); -} - -onmessage = async (e) => { - let { addresses, assetsToBeFetched, chainName, userAddedEndpoints } = e.data; - - if (!assetsToBeFetched) { - console.warn(`getAssetOnAssetHub: No assets to be fetched on ${chainName}, but just Native Token`); - - assetsToBeFetched = []; - } - - let tryCount = 1; - - while (tryCount >= 1 && tryCount <= 5) { - try { - await getAssetOnAssetHub(addresses, assetsToBeFetched, chainName, userAddedEndpoints); - - tryCount = 0; - - return; - } catch (error) { - console.error(`getAssetOnAssetHub: Error while fetching assets on asset hubs, ${5 - tryCount} times to retry`, error); - - tryCount === 5 && postMessage(undefined); - } - - tryCount++; - } -}; diff --git a/packages/extension-polkagate/src/util/workers/shared-helpers/getBalances.js b/packages/extension-polkagate/src/util/workers/shared-helpers/getBalances.js new file mode 100644 index 000000000..85716120a --- /dev/null +++ b/packages/extension-polkagate/src/util/workers/shared-helpers/getBalances.js @@ -0,0 +1,46 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +// @ts-nocheck + +import { BN_ZERO } from '@polkadot/util'; + +import { fastestEndpoint, getChainEndpoints, metadataFromApi } from '../utils'; +import { getPooledBalance } from './getPooledBalance.js'; + +export async function getBalances (chainName, addresses, userAddedEndpoints) { + const chainEndpoints = getChainEndpoints(chainName, userAddedEndpoints); + const { api, connections } = await fastestEndpoint(chainEndpoints); + + if (api.isConnected && api.derive.balances) { + const { metadata } = metadataFromApi(api); + + postMessage(JSON.stringify({ functionName: 'getAssetOnRelayChain', metadata })); + + const requests = addresses.map(async (address) => { + const balances = await api.derive.balances.all(address); + const systemBalance = await api.query.system.account(address); + + balances.frozenBalance = systemBalance.frozen; + + let soloTotal = BN_ZERO; + let pooledBalance = BN_ZERO; + + if (api.query.nominationPools) { + pooledBalance = await getPooledBalance(api, address); + } + + if (api.query.staking?.ledger) { + const ledger = await api.query.staking.ledger(address); + + if (ledger.isSome) { + soloTotal = ledger?.unwrap()?.total?.toString(); + } + } + + return { address, balances, pooledBalance, soloTotal }; + }); + + return { api, balanceInfo: await Promise.all(requests), connectionsToBeClosed: connections }; + } +} diff --git a/packages/extension-polkagate/src/util/workers/shared-helpers/getPooledBalance.js b/packages/extension-polkagate/src/util/workers/shared-helpers/getPooledBalance.js new file mode 100644 index 000000000..7b3ede14a --- /dev/null +++ b/packages/extension-polkagate/src/util/workers/shared-helpers/getPooledBalance.js @@ -0,0 +1,43 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +//@ts-nocheck + +import { BN, BN_ONE, BN_ZERO } from '@polkadot/util'; + +import getPoolAccounts from '../../getPoolAccounts'; + +export async function getPooledBalance (api, address) { + const response = await api.query.nominationPools.poolMembers(address); + const member = response?.unwrapOr(undefined); + + if (!member) { + return BN_ZERO; + } + + const poolId = member.poolId; + const accounts = poolId && getPoolAccounts(api, poolId); + + if (!accounts) { + return BN_ZERO; + } + + const [bondedPool, stashIdAccount, myClaimable] = await Promise.all([ + api.query.nominationPools.bondedPools(poolId), + api.derive.staking.account(accounts.stashId), + api.call.nominationPoolsApi.pendingRewards(address) + ]); + + const active = member.points.isZero() + ? BN_ZERO + : (new BN(String(member.points)).mul(new BN(String(stashIdAccount.stakingLedger.active)))).div(new BN(String(bondedPool.unwrap()?.points ?? BN_ONE))); + + const rewards = myClaimable; + let unlockingValue = BN_ZERO; + + member?.unbondingEras?.forEach((value) => { + unlockingValue = unlockingValue.add(value); + }); + + return active.add(rewards).add(unlockingValue); +} diff --git a/packages/extension-polkagate/src/util/workers/sharedWorker.js b/packages/extension-polkagate/src/util/workers/sharedWorker.js new file mode 100644 index 000000000..78b05d28e --- /dev/null +++ b/packages/extension-polkagate/src/util/workers/sharedWorker.js @@ -0,0 +1,57 @@ +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { createAssets } from '@polkagate/apps-config/assets'; + +import { getAssetOnAssetHub } from './shared-helpers/getAssetOnAssetHub.js'; +import { getAssetOnMultiAssetChain } from './shared-helpers/getAssetOnMultiAssetChain.js'; +import { getAssetOnRelayChain } from './shared-helpers/getAssetOnRelayChain.js'; + +const assetsChains = createAssets(); + +onmessage = (e) => { + const { functionName, parameters } = e.data; + + const params = Object.values(parameters); + + try { + switch (functionName) { + case 'getAssetOnRelayChain': + getAssetOnRelayChain(...params).catch(console.error); + break; + + case 'getAssetOnMultiAssetChain': + // eslint-disable-next-line no-case-declarations + const assetsToBeFetched = assetsChains[parameters.chainName]; + + /** if assetsToBeFetched === undefined then we don't fetch assets by default at first, but wil fetch them on-demand later in account details page*/ + if (!assetsToBeFetched) { + console.info(`getAssetOnMultiAssetChain: No assets to be fetched on ${parameters.chainName}`); + + return postMessage({ functionName }); // FIXME: if this happens, should be handled in caller + } + + getAssetOnMultiAssetChain(assetsToBeFetched, ...params).catch(console.error); + break; + + case 'getAssetOnAssetHub': + if (!parameters.assetsToBeFetched) { + console.warn('getAssetOnAssetHub: No assets to be fetched on, but just Native Token'); + + parameters.assetsToBeFetched = []; + } + + getAssetOnAssetHub(...params).catch(console.error); + break; + + default: + console.error('unknown function sent to shared worker!'); + + return postMessage({ functionName }); + } + } catch (error) { + console.error(`Error while shared worker probably running ${functionName}`, error); + + return postMessage({ functionName }); + } +}; diff --git a/packages/extension-ui/src/Popup/index.tsx b/packages/extension-ui/src/Popup/index.tsx index d0fbc8a85..f82b1bf15 100644 --- a/packages/extension-ui/src/Popup/index.tsx +++ b/packages/extension-ui/src/Popup/index.tsx @@ -14,7 +14,7 @@ import { Route, Switch, useLocation } from 'react-router'; import { PHISHING_PAGE_REDIRECT } from '@polkadot/extension-base/defaults'; import { canDerive } from '@polkadot/extension-base/utils'; import { ErrorBoundary, Loading } from '@polkadot/extension-polkagate/src/components'; -import { AccountContext, AccountIconThemeContext, AccountsAssetsContext, ActionContext, AlertContext, APIContext, AuthorizeReqContext, CurrencyContext, FetchingContext, GenesisHashOptionsContext, MediaContext, MetadataReqContext, ReferendaContext, SettingsContext, SigningReqContext, UserAddedChainContext } from '@polkadot/extension-polkagate/src/components/contexts'; +import { AccountContext, AccountIconThemeContext, AccountsAssetsContext, ActionContext, AlertContext, APIContext, AuthorizeReqContext, CurrencyContext, FetchingContext, GenesisHashOptionsContext, MediaContext, MetadataReqContext, ReferendaContext, SettingsContext, SigningReqContext, UserAddedChainContext, WorkerContext } from '@polkadot/extension-polkagate/src/components/contexts'; import { getStorage, type LoginInfo, setStorage, updateStorage, watchStorage } from '@polkadot/extension-polkagate/src/components/Loading'; import { ExtensionLockProvider } from '@polkadot/extension-polkagate/src/context/ExtensionLockContext'; import AccountFS from '@polkadot/extension-polkagate/src/fullscreen/accountDetails'; @@ -124,6 +124,7 @@ export default function Popup (): React.ReactElement { const isFetchingPricesRef = useRef(false); const isExtensionMode = useIsExtensionPopup(); const genesisHashOptionsCtx = useGenesisHashOptions(); + const workerRef = useRef(undefined); useLocation();// just to trigger component to fix forgot pass issue @@ -144,7 +145,7 @@ export default function Popup (): React.ReactElement { const [loginInfo, setLoginInfo] = useState(); const [alerts, setAlerts] = useState([]); - const assetsOnChains = useAssetsBalances(accounts, setAlerts, genesisHashOptionsCtx, userAddedChainCtx); + const assetsOnChains = useAssetsBalances(accounts, setAlerts, genesisHashOptionsCtx, userAddedChainCtx, workerRef.current); useNFT(accounts); @@ -162,6 +163,17 @@ export default function Popup (): React.ReactElement { } }, []); + useEffect(() => { + workerRef.current = new Worker(new URL('../../../extension-polkagate/src/util/workers/sharedWorker.js', import.meta.url)); + + return () => { + // Cleanup on unmount + if (workerRef.current) { + workerRef.current.terminate(); + } + }; + }, []); + useEffect(() => { getStorage('iconTheme') .then((maybeTheme) => setAccountIconTheme((maybeTheme as IconTheme | undefined) || DEFAULT_ACCOUNT_ICON_THEME)) @@ -313,95 +325,97 @@ export default function Popup (): React.ReactElement { - - - - - - - - - - - - - - {wrapWithErrorBoundary(, 'add-new-chain')} - {wrapWithErrorBoundary(, 'account')} - {wrapWithErrorBoundary(, 'account-creation')} - {wrapWithErrorBoundary(, 'export-all-address')} - {wrapWithErrorBoundary(, 'import-ledger')} - {wrapWithErrorBoundary(, 'import-seed')} - {wrapWithErrorBoundary(, 'import-raw-seed')} - {wrapWithErrorBoundary(, 'restore-json')} - {wrapWithErrorBoundary(, 'account')} - {wrapWithErrorBoundary(, 'auth-list')} - {wrapWithErrorBoundary(, 'crowdloans')} - {wrapWithErrorBoundary(, 'derived-address-locked')} - {wrapWithErrorBoundary(, 'derive-address')} - {wrapWithErrorBoundary(, 'fullscreen-account-derive')} - {wrapWithErrorBoundary(, 'export-address')} - {wrapWithErrorBoundary(, 'forget-address')} - {wrapWithErrorBoundary(, 'forgot-password')} - {wrapWithErrorBoundary(, 'reset-wallet')} - {wrapWithErrorBoundary(, 'fullscreen-proxy-management')} - {wrapWithErrorBoundary(, 'governance')} - {wrapWithErrorBoundary(, 'governance')} - {wrapWithErrorBoundary(, 'history')} - {wrapWithErrorBoundary(, 'import-add-watch-only')} - {wrapWithErrorBoundary(, 'import-add-watch-only-full-screen')} - {wrapWithErrorBoundary(, 'attach-qr')} - {wrapWithErrorBoundary(, 'attach-qr-full-screen')} - {wrapWithErrorBoundary(, 'import-proxied')} - {wrapWithErrorBoundary(, 'import-add-watch-only-full-screen')} - {wrapWithErrorBoundary(, 'manage-login-password')} - {wrapWithErrorBoundary(, 'manageProxies')} - {wrapWithErrorBoundary(, 'manage-identity')} - {wrapWithErrorBoundary(, 'manage-validators-fullscreen')} - {wrapWithErrorBoundary(, 'manage-validators-fullscreen')} - {wrapWithErrorBoundary(, 'nft-album')} - {wrapWithErrorBoundary(, 'onboarding')} - {wrapWithErrorBoundary(, 'pool-create')} - {wrapWithErrorBoundary(, 'pool-join')} - {wrapWithErrorBoundary(, 'pool-stake')} - {wrapWithErrorBoundary(, 'pool-poolInfromation')} - {wrapWithErrorBoundary(, 'pool-nominations')} - {wrapWithErrorBoundary(, 'pool-unstake')} - {wrapWithErrorBoundary(, 'pool-staking')} - {wrapWithErrorBoundary(, 'pool-staking-fullscreen')} - {wrapWithErrorBoundary(, 'rename')} - {wrapWithErrorBoundary(, 'receive')} - {wrapWithErrorBoundary(, 'send')} - {wrapWithErrorBoundary(, 'send')} - {wrapWithErrorBoundary(, 'stake')} - {wrapWithErrorBoundary(, 'social-recovery')} - {wrapWithErrorBoundary(, 'solo-fast-unstake')} - {wrapWithErrorBoundary(, 'solo-nominations')} - {wrapWithErrorBoundary(, 'solo-payout')} - {wrapWithErrorBoundary(, 'solo-restake')} - {wrapWithErrorBoundary(, 'solo-stake')} - {wrapWithErrorBoundary(, 'solo-unstake')} - {wrapWithErrorBoundary(, 'solo-staking')} - {wrapWithErrorBoundary(, 'solo-staking-fullscreen')} - {wrapWithErrorBoundary(, 'tuneup')} - {wrapWithErrorBoundary(, 'phishing-page-redirect')} - {Root} - - - - - - - - - - - - - + + + + + + + + + + + + + + + {wrapWithErrorBoundary(, 'add-new-chain')} + {wrapWithErrorBoundary(, 'account')} + {wrapWithErrorBoundary(, 'account-creation')} + {wrapWithErrorBoundary(, 'export-all-address')} + {wrapWithErrorBoundary(, 'import-ledger')} + {wrapWithErrorBoundary(, 'import-seed')} + {wrapWithErrorBoundary(, 'import-raw-seed')} + {wrapWithErrorBoundary(, 'restore-json')} + {wrapWithErrorBoundary(, 'account')} + {wrapWithErrorBoundary(, 'auth-list')} + {wrapWithErrorBoundary(, 'crowdloans')} + {wrapWithErrorBoundary(, 'derived-address-locked')} + {wrapWithErrorBoundary(, 'derive-address')} + {wrapWithErrorBoundary(, 'fullscreen-account-derive')} + {wrapWithErrorBoundary(, 'export-address')} + {wrapWithErrorBoundary(, 'forget-address')} + {wrapWithErrorBoundary(, 'forgot-password')} + {wrapWithErrorBoundary(, 'reset-wallet')} + {wrapWithErrorBoundary(, 'fullscreen-proxy-management')} + {wrapWithErrorBoundary(, 'governance')} + {wrapWithErrorBoundary(, 'governance')} + {wrapWithErrorBoundary(, 'history')} + {wrapWithErrorBoundary(, 'import-add-watch-only')} + {wrapWithErrorBoundary(, 'import-add-watch-only-full-screen')} + {wrapWithErrorBoundary(, 'attach-qr')} + {wrapWithErrorBoundary(, 'attach-qr-full-screen')} + {wrapWithErrorBoundary(, 'import-proxied')} + {wrapWithErrorBoundary(, 'import-add-watch-only-full-screen')} + {wrapWithErrorBoundary(, 'manage-login-password')} + {wrapWithErrorBoundary(, 'manageProxies')} + {wrapWithErrorBoundary(, 'manage-identity')} + {wrapWithErrorBoundary(, 'manage-validators-fullscreen')} + {wrapWithErrorBoundary(, 'manage-validators-fullscreen')} + {wrapWithErrorBoundary(, 'nft-album')} + {wrapWithErrorBoundary(, 'onboarding')} + {wrapWithErrorBoundary(, 'pool-create')} + {wrapWithErrorBoundary(, 'pool-join')} + {wrapWithErrorBoundary(, 'pool-stake')} + {wrapWithErrorBoundary(, 'pool-poolInfromation')} + {wrapWithErrorBoundary(, 'pool-nominations')} + {wrapWithErrorBoundary(, 'pool-unstake')} + {wrapWithErrorBoundary(, 'pool-staking')} + {wrapWithErrorBoundary(, 'pool-staking-fullscreen')} + {wrapWithErrorBoundary(, 'rename')} + {wrapWithErrorBoundary(, 'receive')} + {wrapWithErrorBoundary(, 'send')} + {wrapWithErrorBoundary(, 'send')} + {wrapWithErrorBoundary(, 'stake')} + {wrapWithErrorBoundary(, 'social-recovery')} + {wrapWithErrorBoundary(, 'solo-fast-unstake')} + {wrapWithErrorBoundary(, 'solo-nominations')} + {wrapWithErrorBoundary(, 'solo-payout')} + {wrapWithErrorBoundary(, 'solo-restake')} + {wrapWithErrorBoundary(, 'solo-stake')} + {wrapWithErrorBoundary(, 'solo-unstake')} + {wrapWithErrorBoundary(, 'solo-staking')} + {wrapWithErrorBoundary(, 'solo-staking-fullscreen')} + {wrapWithErrorBoundary(, 'tuneup')} + {wrapWithErrorBoundary(, 'phishing-page-redirect')} + {Root} + + + + + + + + + + + + + + diff --git a/tsconfig.json b/tsconfig.json index 8a4de3737..cacb7dd14 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ "packages/extension-polkagate/icons", "packages/extension-polkagate/src/components/themes.ts", "packages/extension/public/offscreen.js" - ], +, "packages/extension-polkagate/src/util/workers/shared-helpers/getAssetOnMultiAssetChain.js" ], "exclude": [ "**/node_modules/**/*" ]