diff --git a/app/scripts/controllers/account-tracker-controller.ts b/app/scripts/controllers/account-tracker-controller.ts index 5f509a1901bf..d310d51cfb45 100644 --- a/app/scripts/controllers/account-tracker-controller.ts +++ b/app/scripts/controllers/account-tracker-controller.ts @@ -66,7 +66,7 @@ type Account = { export type AccountTrackerControllerState = { accounts: Record>; currentBlockGasLimit: string; - accountsByChainId: Record; + accountsByChainId: Record; currentBlockGasLimitByChainId: Record; }; diff --git a/app/scripts/controllers/app-state-controller.ts b/app/scripts/controllers/app-state-controller.ts index c506dc329e94..436abeaba1b3 100644 --- a/app/scripts/controllers/app-state-controller.ts +++ b/app/scripts/controllers/app-state-controller.ts @@ -60,7 +60,7 @@ export type AppStateControllerState = { // prior to Migration 92.3 where we split out the setting to support // multiple networks. hadAdvancedGasFeesSetPriorToMigration92_3: boolean; - qrHardware: Json; + qrHardware: Json & { sign: { request: unknown } }; nftsDropdownState: Json; surveyLinkLastClickedOrClosed: number | null; signatureSecurityAlertResponses: Record; diff --git a/ui/selectors/selectors.ts b/ui/selectors/selectors.ts index 60c7a4cb1439..343cc5dc28dc 100644 --- a/ui/selectors/selectors.ts +++ b/ui/selectors/selectors.ts @@ -4,13 +4,14 @@ import { stripSnapPrefix, getLocalizedSnapManifest, SnapStatus, + Snap, } from '@metamask/snaps-utils'; import { memoize } from 'lodash'; import semver from 'semver'; import { createSelector } from 'reselect'; import { NameType } from '@metamask/name-controller'; import { TransactionStatus } from '@metamask/transaction-controller'; -import { isEvmAccountType } from '@metamask/keyring-api'; +import { InternalAccount, isEvmAccountType } from '@metamask/keyring-api'; import { RpcEndpointType } from '@metamask/network-controller'; import { getCurrentChainId, @@ -126,45 +127,52 @@ import { } from './permissions'; import { getSelectedInternalAccount, getInternalAccounts } from './accounts'; import { getMultichainBalances, getMultichainNetwork } from './multichain'; +import { MetaMaskReduxState } from '../store/store'; +import { MultichainNetworks } from '../../shared/constants/multichain/networks'; +import { getKnownPropertyNames, Hex } from '@metamask/utils'; +import { Token } from '@metamask/assets-controllers'; +import { SnapId } from '@metamask/snaps-sdk'; -export function getNetworkIdentifier(state) { +export function getNetworkIdentifier(state: MetaMaskReduxState) { const { type, nickname, rpcUrl } = getProviderConfig(state); return nickname || rpcUrl || type; } -export function getMetaMetricsId(state) { +export function getMetaMetricsId(state: MetaMaskReduxState) { const { metaMetricsId } = state.metamask.MetaMetricsController; return metaMetricsId; } -export function isCurrentProviderCustom(state) { +export function isCurrentProviderCustom(state: MetaMaskReduxState) { const provider = getProviderConfig(state); return ( provider.type === NETWORK_TYPES.RPC && - !Object.values(CHAIN_IDS).includes(provider.chainId) + !Object.values(CHAIN_IDS).find((chainId) => chainId === provider.chainId) ); } -export function getCurrentQRHardwareState(state) { +export function getCurrentQRHardwareState(state: MetaMaskReduxState) { const { qrHardware } = state.metamask.AppStateController; - return qrHardware || {}; + return qrHardware ?? {}; } -export function getIsSigningQRHardwareTransaction(state) { +export function getIsSigningQRHardwareTransaction(state: MetaMaskReduxState) { return ( state.metamask.AppStateController.qrHardware?.sign?.request !== undefined ); } -export function getCurrentKeyring(state) { +export function getCurrentKeyring(state: MetaMaskReduxState) { const internalAccount = getSelectedInternalAccount(state); if (!internalAccount) { return null; } - return internalAccount.metadata.keyring; + return internalAccount.metadata.keyring as { + type: (typeof KeyringType)[keyof typeof KeyringType]; + }; } /** @@ -174,7 +182,10 @@ export function getCurrentKeyring(state) { * @param state * @param [networkClientId] - The optional network client ID to check network and account for EIP-1559 support */ -export function checkNetworkAndAccountSupports1559(state, networkClientId) { +export function checkNetworkAndAccountSupports1559( + state: MetaMaskReduxState, + networkClientId: string, +) { const networkSupports1559 = isEIP1559Network(state, networkClientId); return networkSupports1559; } @@ -185,7 +196,9 @@ export function checkNetworkAndAccountSupports1559(state, networkClientId) { * * @param state */ -export function checkNetworkOrAccountNotSupports1559(state) { +export function checkNetworkOrAccountNotSupports1559( + state: MetaMaskReduxState, +) { const networkNotSupports1559 = isNotEIP1559Network(state); return networkNotSupports1559; } @@ -196,7 +209,7 @@ export function checkNetworkOrAccountNotSupports1559(state) { * @param {object} state * @returns {boolean} */ -export function isHardwareWallet(state) { +export function isHardwareWallet(state: MetaMaskReduxState) { const keyring = getCurrentKeyring(state); return Boolean(keyring?.type?.includes('Hardware')); } @@ -207,7 +220,7 @@ export function isHardwareWallet(state) { * @param {object} state - The state object. * @returns {boolean} */ -export function accountSupportsSmartTx(state) { +export function accountSupportsSmartTx(state: MetaMaskReduxState) { const accountType = getAccountType(state); return Boolean(accountType !== 'snap'); } @@ -218,17 +231,19 @@ export function accountSupportsSmartTx(state) { * @param {object} state * @returns {string | undefined} */ -export function getHardwareWalletType(state) { +export function getHardwareWalletType(state: MetaMaskReduxState) { const keyring = getCurrentKeyring(state); - return isHardwareWallet(state) ? keyring.type : undefined; + return isHardwareWallet(state) ? keyring?.type : undefined; } -export function getAccountType(state) { +export function getAccountType(state: MetaMaskReduxState) { const currentKeyring = getCurrentKeyring(state); return getAccountTypeForKeyring(currentKeyring); } -export function getAccountTypeForKeyring(keyring) { +export function getAccountTypeForKeyring( + keyring: { type: (typeof KeyringType)[keyof typeof KeyringType] } | null, +) { if (!keyring) { return ''; } @@ -274,44 +289,46 @@ export const getMetaMaskAccounts = createSelector( multichainBalances, multichainNetwork, ) => - Object.values(internalAccounts).reduce((accounts, internalAccount) => { + Object.values(internalAccounts).reduce<{ + [address: string]: InternalAccount & { balance: string }; + }>((accounts, internalAccount) => { // TODO: mix in the identity state here as well, consolidating this // selector with `accountsWithSendEtherInfoSelector` - let account = internalAccount; + const account = { ...internalAccount, balance: '0x0' }; // TODO: `AccountTracker` balances are in hex and `MultichainBalance` are in number. // We should consolidate the format to either hex or number if (isEvmAccountType(internalAccount.type)) { if (balances?.[internalAccount.address]) { - account = { - ...account, + Object.assign(account, { ...balances[internalAccount.address], - }; + }); } } else { - account = { - ...account, + const assetName = getKnownPropertyNames(MultichainNetworks).filter( + (name) => MultichainNetworks[name] === multichainNetwork.chainId, + )[0]; + Object.assign(account, { balance: multichainBalances?.[internalAccount.id]?.[ - MultichainNativeAssets[multichainNetwork.chainId] + MultichainNativeAssets[assetName] ]?.amount ?? '0', - }; + }); } if (account.balance === null || account.balance === undefined) { - account = { - ...account, + Object.assign(account, { balance: (cachedBalances && cachedBalances[internalAccount.address]) ?? '0x0', - }; + }); } return { ...accounts, [internalAccount.address]: account, }; - }, {}), + }, {} as never), ); /** * Returns the address of the selected InternalAccount from the Metamask state. @@ -319,17 +336,20 @@ export const getMetaMaskAccounts = createSelector( * @param state - The Metamask state object. * @returns {string} The selected address. */ -export function getSelectedAddress(state) { +export function getSelectedAddress(state: MetaMaskReduxState) { return getSelectedInternalAccount(state)?.address; } -export function getInternalAccountByAddress(state, address) { +export function getInternalAccountByAddress( + state: MetaMaskReduxState, + address: string, +) { return Object.values( state.metamask.AccountsController.internalAccounts.accounts, ).find((account) => isEqualCaseInsensitive(account.address, address)); } -export function getMaybeSelectedInternalAccount(state) { +export function getMaybeSelectedInternalAccount(state: MetaMaskReduxState) { // Same as `getSelectedInternalAccount`, but might potentially be `undefined`: // - This might happen during the onboarding const accountId = @@ -339,12 +359,17 @@ export function getMaybeSelectedInternalAccount(state) { : undefined; } -export function checkIfMethodIsEnabled(state, methodName) { +export function checkIfMethodIsEnabled( + state: MetaMaskReduxState, + methodName: string, +) { const internalAccount = getSelectedInternalAccount(state); return Boolean(internalAccount.methods.includes(methodName)); } -export function getSelectedInternalAccountWithBalance(state) { +export function getSelectedInternalAccountWithBalance( + state: MetaMaskReduxState, +) { const selectedAccount = getSelectedInternalAccount(state); const rawAccount = getMetaMaskAccountBalances(state)[selectedAccount.address]; @@ -356,7 +381,10 @@ export function getSelectedInternalAccountWithBalance(state) { return selectedAccountWithBalance; } -export function getInternalAccount(state, accountId) { +export function getInternalAccount( + state: MetaMaskReduxState, + accountId: string, +) { return state.metamask.AccountsController.internalAccounts.accounts[accountId]; } @@ -400,12 +428,12 @@ export const getInternalAccountsSortedByKeyring = createSelector( }, ); -export function getNumberOfTokens(state) { +export function getNumberOfTokens(state: MetaMaskReduxState) { const { tokens } = state.metamask.TokensController; return tokens ? tokens.length : 0; } -export function getMetaMaskKeyrings(state) { +export function getMetaMaskKeyrings(state: MetaMaskReduxState) { return state.metamask.KeyringController.keyrings; } @@ -415,35 +443,37 @@ export function getMetaMaskKeyrings(state) { * @param {object} state - Redux state * @returns {object} A map of account addresses to account objects (which includes the account balance) */ -export function getMetaMaskAccountBalances(state) { +export function getMetaMaskAccountBalances(state: MetaMaskReduxState) { return state.metamask.AccountTracker.accounts; } -export function getMetaMaskCachedBalances(state) { +export function getMetaMaskCachedBalances(state: MetaMaskReduxState) { const chainId = getCurrentChainId(state); - - if (state.metamask.AccountTracker.accountsByChainId?.[chainId]) { - return Object.entries( - state.metamask.AccountTracker.accountsByChainId[chainId], - ).reduce((accumulator, [key, value]) => { - accumulator[key] = value.balance; - return accumulator; - }, {}); + const account = state.metamask.AccountTracker.accountsByChainId?.[chainId]; + if (account) { + return getKnownPropertyNames(account).reduce<{ [address: string]: string }>( + (accumulator, key) => { + accumulator[key] = account[key].balance ?? '0'; + return accumulator; + }, + {} as never, + ); } return {}; } -export function getCrossChainMetaMaskCachedBalances(state) { +export function getCrossChainMetaMaskCachedBalances(state: MetaMaskReduxState) { const allAccountsByChainId = state.metamask.AccountTracker.accountsByChainId; - return Object.keys(allAccountsByChainId).reduce((acc, topLevelKey) => { - acc[topLevelKey] = Object.keys(allAccountsByChainId[topLevelKey]).reduce( - (innerAcc, innerKey) => { - innerAcc[innerKey] = - allAccountsByChainId[topLevelKey][innerKey].balance; - return innerAcc; - }, - {}, - ); + return getKnownPropertyNames(allAccountsByChainId).reduce< + Record> + >((acc, topLevelKey) => { + acc[topLevelKey] = getKnownPropertyNames( + allAccountsByChainId[topLevelKey], + ).reduce>((innerAcc, innerKey) => { + innerAcc[innerKey] = + allAccountsByChainId[topLevelKey][innerKey].balance ?? '0'; + return innerAcc; + }, {}); return acc; }, {}); @@ -454,17 +484,20 @@ export function getCrossChainMetaMaskCachedBalances(state) { * @param {object} state - Redux state * @returns {object} An object of tokens with balances for the given account. Data relationship will be chainId => balance */ -export function getSelectedAccountNativeTokenCachedBalanceByChainId(state) { +export function getSelectedAccountNativeTokenCachedBalanceByChainId( + state: MetaMaskReduxState, +) { const { accountsByChainId } = state.metamask.AccountTracker; const { address: selectedAddress } = getSelectedInternalAccount(state); - const balancesByChainId = {}; - for (const [chainId, accounts] of Object.entries(accountsByChainId || {})) { - if (accounts[selectedAddress]) { - balancesByChainId[chainId] = accounts[selectedAddress].balance; - } - } - return balancesByChainId; + return getKnownPropertyNames(accountsByChainId).reduce>( + (balancesByChainId, chainId) => { + const accounts = accountsByChainId[chainId]; + balancesByChainId[chainId] = accounts[selectedAddress].balance ?? '0'; + return balancesByChainId; + }, + {}, + ); } /** @@ -474,7 +507,9 @@ export function getSelectedAccountNativeTokenCachedBalanceByChainId(state) { * @param {object} state - Redux state * @returns {object} An object mapping chain IDs to arrays of tokens (including native tokens) with balances. */ -export function getSelectedAccountTokensAcrossChains(state) { +export function getSelectedAccountTokensAcrossChains( + state: MetaMaskReduxState, +) { const { allTokens } = state.metamask.TokensController; const selectedAddress = getSelectedInternalAccount(state).address; @@ -484,8 +519,8 @@ export function getSelectedAccountTokensAcrossChains(state) { getSelectedAccountNativeTokenCachedBalanceByChainId(state); const chainIds = new Set([ - ...Object.keys(allTokens || {}), - ...Object.keys(nativeTokenBalancesByChainId || {}), + ...Object.keys(allTokens ?? {}), + ...Object.keys(nativeTokenBalancesByChainId ?? {}), ]); chainIds.forEach((chainId) => { @@ -524,7 +559,7 @@ export function getSelectedAccountTokensAcrossChains(state) { * @param {string} chainId - Chain ID * @returns {object} Native token information */ -function getNativeTokenInfo(state, chainId) { +function getNativeTokenInfo(state: MetaMaskReduxState, chainId: Hex) { const { networkConfigurationsByChainId } = state.metamask.NetworkController; const networkConfig = networkConfigurationsByChainId?.[chainId]; @@ -570,7 +605,7 @@ export const getMetaMaskAccountsConnected = createSelector( connectedAccounts.map(({ address }) => address.toLowerCase()), ); -export function isBalanceCached(state) { +export function isBalanceCached(state: MetaMaskReduxState) { const { address: selectedAddress } = getSelectedInternalAccount(state); const selectedAccountBalance = getMetaMaskAccountBalances(state)[selectedAddress]?.balance; @@ -579,14 +614,14 @@ export function isBalanceCached(state) { return Boolean(!selectedAccountBalance && cachedBalance); } -export function getSelectedAccountCachedBalance(state) { +export function getSelectedAccountCachedBalance(state: MetaMaskReduxState) { const cachedBalances = getMetaMaskCachedBalances(state); const { address: selectedAddress } = getSelectedInternalAccount(state); return cachedBalances?.[selectedAddress]; } -export function getAllTokens(state) { +export function getAllTokens(state: MetaMaskReduxState) { return state.metamask.TokensController.allTokens; } @@ -614,11 +649,11 @@ export const selectAllTokensFlat = createSelector( * @param state - Redux state object. * @returns Object - Installed Snaps. */ -export function getAllDomains(state) { +export function getAllDomains(state: MetaMaskReduxState) { return state.metamask.SelectedNetworkController.domains; } -export const getConfirmationExchangeRates = (state) => { +export const getConfirmationExchangeRates = (state: MetaMaskReduxState) => { return state.appState.confirmationExchangeRates; }; @@ -655,12 +690,15 @@ export const getWatchedToken = (transactionMeta) => }, ); -export function getTargetAccount(state, targetAddress) { +export function getTargetAccount( + state: MetaMaskReduxState, + targetAddress: string, +) { const accounts = getMetaMaskAccounts(state); return accounts[targetAddress]; } -export const getTokenExchangeRates = (state) => { +export const getTokenExchangeRates = (state: MetaMaskReduxState) => { const chainId = getCurrentChainId(state); const contractMarketData = state.metamask.TokenRatesController.marketData?.[chainId] ?? {}; @@ -673,7 +711,7 @@ export const getTokenExchangeRates = (state) => { ); }; -export const getCrossChainTokenExchangeRates = (state) => { +export const getCrossChainTokenExchangeRates = (state: MetaMaskReduxState) => { const contractMarketData = state.metamask.TokenRatesController.marketData ?? {}; @@ -696,16 +734,16 @@ export const getCrossChainTokenExchangeRates = (state) => { * @param state * @returns {Record} */ -export const getTokensMarketData = (state) => { +export const getTokensMarketData = (state: MetaMaskReduxState) => { const chainId = getCurrentChainId(state); return state.metamask.TokenRatesController.marketData?.[chainId]; }; -export const getMarketData = (state) => { +export const getMarketData = (state: MetaMaskReduxState) => { return state.metamask.TokenRatesController.marketData; }; -export function getAddressBook(state) { +export function getAddressBook(state: MetaMaskReduxState) { const chainId = getCurrentChainId(state); if (!state.metamask.AddressBookController.addressBook[chainId]) { return []; @@ -715,7 +753,10 @@ export function getAddressBook(state) { ); } -export function getEnsResolutionByAddress(state, address) { +export function getEnsResolutionByAddress( + state: MetaMaskReduxState, + address: string, +) { if (state.metamask.EnsController.ensResolutionsByAddress[address]) { return state.metamask.EnsController.ensResolutionsByAddress[address]; } @@ -724,10 +765,13 @@ export function getEnsResolutionByAddress(state, address) { getAddressBookEntry(state, address) || getInternalAccountByAddress(state, address); - return entry?.name || ''; + return entry?.name ?? ''; } -export function getAddressBookEntry(state, address) { +export function getAddressBookEntry( + state: MetaMaskReduxState, + address: string, +) { const addressBook = getAddressBook(state); const entry = addressBook.find((contact) => isEqualCaseInsensitive(contact.address, address), @@ -735,7 +779,10 @@ export function getAddressBookEntry(state, address) { return entry; } -export function getAddressBookEntryOrAccountName(state, address) { +export function getAddressBookEntryOrAccountName( + state: MetaMaskReduxState, + address: string, +) { const entry = getAddressBookEntry(state, address); if (entry && entry.name !== '') { return entry.name; @@ -748,14 +795,17 @@ export function getAddressBookEntryOrAccountName(state, address) { return internalAccount?.metadata.name || address; } -export function getAccountName(accounts, accountAddress) { +export function getAccountName( + accounts: InternalAccount[], + accountAddress: string, +) { const account = accounts.find((internalAccount) => isEqualCaseInsensitive(internalAccount.address, accountAddress), ); return account && account.metadata.name !== '' ? account.metadata.name : ''; } -export function accountsWithSendEtherInfoSelector(state) { +export function accountsWithSendEtherInfoSelector(state: MetaMaskReduxState) { const accounts = getMetaMaskAccounts(state); const internalAccounts = getInternalAccounts(state); @@ -771,7 +821,7 @@ export function accountsWithSendEtherInfoSelector(state) { return accountsWithSendEtherInfo; } -export function getAccountsWithLabels(state) { +export function getAccountsWithLabels(state: MetaMaskReduxState) { return getMetaMaskAccountsOrdered(state).map((account) => { const { address, @@ -791,28 +841,28 @@ export function getAccountsWithLabels(state) { }); } -export function getCurrentAccountWithSendEtherInfo(state) { +export function getCurrentAccountWithSendEtherInfo(state: MetaMaskReduxState) { const { address: currentAddress } = getSelectedInternalAccount(state); const accounts = accountsWithSendEtherInfoSelector(state); return getAccountByAddress(accounts, currentAddress); } -export function getTargetAccountWithSendEtherInfo(state, targetAddress) { +export function getTargetAccountWithSendEtherInfo( + state: MetaMaskReduxState, + targetAddress: string, +) { const accounts = accountsWithSendEtherInfoSelector(state); return getAccountByAddress(accounts, targetAddress); } -export function getCurrentEthBalance(state) { +export function getCurrentEthBalance(state: MetaMaskReduxState) { return getCurrentAccountWithSendEtherInfo(state)?.balance; } -export function getGasIsLoading(state) { - return state.appState.gasIsLoading; -} - export const getNetworkConfigurationIdByChainId = createDeepEqualSelector( - (state) => state.metamask.NetworkController.networkConfigurationsByChainId, + (state: MetaMaskReduxState) => + state.metamask.NetworkController.networkConfigurationsByChainId, (networkConfigurationsByChainId) => Object.entries(networkConfigurationsByChainId).reduce( (acc, [_chainId, network]) => { @@ -826,11 +876,11 @@ export const getNetworkConfigurationIdByChainId = createDeepEqualSelector( ); /** - * @type (state: any, chainId: string) => import('@metamask/network-controller').NetworkConfiguration + * @type (state: MetaMaskReduxState: any, chainId: string) => import('@metamask/network-controller').NetworkConfiguration */ export const selectNetworkConfigurationByChainId = createSelector( getNetworkConfigurationsByChainId, - (_state, chainId) => chainId, + (_state: MetaMaskReduxState, chainId: Hex) => chainId, (networkConfigurationsByChainId, chainId) => networkConfigurationsByChainId[chainId], ); @@ -848,11 +898,11 @@ export const selectDefaultRpcEndpointByChainId = createSelector( ); /** - * @type (state: any, chainId: string) => number | undefined + * @type (state: MetaMaskReduxState: any, chainId: string) => number | undefined */ export const selectConversionRateByChainId = createSelector( selectNetworkConfigurationByChainId, - (state) => state, + (state: MetaMaskReduxState) => state, (networkConfiguration, state) => { if (!networkConfiguration) { return undefined; @@ -866,8 +916,8 @@ export const selectConversionRateByChainId = createSelector( export const selectNftsByChainId = createSelector( getSelectedInternalAccount, - (state) => state.metamask.NftController.allNfts, - (_state, chainId) => chainId, + (state: MetaMaskReduxState) => state.metamask.NftController.allNfts, + (_state: MetaMaskReduxState, chainId: Hex) => chainId, (selectedAccount, nfts, chainId) => { return nfts?.[selectedAccount.address]?.[chainId] ?? []; }, @@ -875,8 +925,8 @@ export const selectNftsByChainId = createSelector( export const selectNftContractsByChainId = createSelector( getSelectedInternalAccount, - (state) => state.metamask.NftController.allNftContracts, - (_state, chainId) => chainId, + (state: MetaMaskReduxState) => state.metamask.NftController.allNftContracts, + (_state: MetaMaskReduxState, chainId: Hex) => chainId, (selectedAccount, nftContracts, chainId) => { return nftContracts?.[selectedAccount.address]?.[chainId] ?? []; }, @@ -893,7 +943,10 @@ export const selectNetworkIdentifierByChainId = createSelector( }, ); -export function getRequestingNetworkInfo(state, chainIds) { +export function getRequestingNetworkInfo( + state: MetaMaskReduxState, + chainIds: Hex[], +) { // If chainIds is undefined, set it to an empty array let processedChainIds = chainIds === undefined ? [] : chainIds; @@ -919,7 +972,7 @@ export function getRequestingNetworkInfo(state, chainIds) { * @param state - Redux state object. * @returns An object with information about the network with the given networkClientId */ -export function getSwitchedNetworkDetails(state) { +export function getSwitchedNetworkDetails(state: MetaMaskReduxState) { const { switchedNetworkDetails } = state.metamask.AppStateController; const networkConfigurations = getNetworkConfigurationsByChainId(state); @@ -942,33 +995,35 @@ export function getSwitchedNetworkDetails(state) { return null; } -export function getAppIsLoading(state) { +export function getAppIsLoading(state: MetaMaskReduxState) { return state.appState.isLoading; } -export function getNftIsStillFetchingIndication(state) { +export function getNftIsStillFetchingIndication(state: MetaMaskReduxState) { return state.appState.isNftStillFetchingIndication; } -export function getCurrentCurrency(state) { +export function getCurrentCurrency(state: MetaMaskReduxState) { return state.metamask.CurrencyController.currentCurrency; } -export function getTotalUnapprovedCount(state) { +export function getTotalUnapprovedCount(state: MetaMaskReduxState) { return state.metamask.ApprovalController.pendingApprovalCount ?? 0; } -export function getQueuedRequestCount(state) { +export function getQueuedRequestCount(state: MetaMaskReduxState) { return state.metamask.QueuedRequestController.queuedRequestCount ?? 0; } -export function getTotalUnapprovedMessagesCount(state) { - const { - unapprovedPersonalMsgCount = 0, - unapprovedDecryptMsgCount = 0, - unapprovedEncryptionPublicKeyMsgCount = 0, - unapprovedTypedMessagesCount = 0, - } = state.metamask.SignatureController; +export function getTotalUnapprovedMessagesCount(state: MetaMaskReduxState) { + const { unapprovedPersonalMsgCount = 0, unapprovedTypedMessagesCount = 0 } = + state.metamask.SignatureController; + + const { unapprovedDecryptMsgCount = 0 } = + state.metamask.DecryptMessageController; + + const { unapprovedEncryptionPublicKeyMsgCount = 0 } = + state.metamask.EncryptionPublicKeyController; return ( unapprovedPersonalMsgCount + @@ -978,24 +1033,27 @@ export function getTotalUnapprovedMessagesCount(state) { ); } -export function getTotalUnapprovedSignatureRequestCount(state) { +export function getTotalUnapprovedSignatureRequestCount( + state: MetaMaskReduxState, +) { const { unapprovedPersonalMsgCount = 0, unapprovedTypedMessagesCount = 0 } = state.metamask.SignatureController; return unapprovedPersonalMsgCount + unapprovedTypedMessagesCount; } -export function getUnapprovedTxCount(state) { +export function getUnapprovedTxCount(state: MetaMaskReduxState) { const unapprovedTxs = getUnapprovedTransactions(state); return Object.keys(unapprovedTxs).length; } export const getUnapprovedConfirmations = createDeepEqualSelector( - (state) => state.metamask.ApprovalController.pendingApprovals || {}, + (state: MetaMaskReduxState) => + state.metamask.ApprovalController.pendingApprovals ?? {}, (pendingApprovals) => Object.values(pendingApprovals), ); -export function getUnapprovedTemplatedConfirmations(state) { +export function getUnapprovedTemplatedConfirmations(state: MetaMaskReduxState) { const unapprovedConfirmations = getUnapprovedConfirmations(state); return unapprovedConfirmations.filter((approval) => TEMPLATED_CONFIRMATION_APPROVAL_TYPES.includes(approval.type), @@ -1010,7 +1068,7 @@ export const getPrioritizedUnapprovedTemplatedConfirmations = createSelector( ), ); -export function getSuggestedTokens(state) { +export function getSuggestedTokens(state: MetaMaskReduxState) { return ( getUnapprovedConfirmations(state)?.filter(({ type, requestData }) => { return ( @@ -1021,7 +1079,7 @@ export function getSuggestedTokens(state) { ); } -export function getSuggestedNfts(state) { +export function getSuggestedNfts(state: MetaMaskReduxState) { return ( getUnapprovedConfirmations(state)?.filter(({ requestData, type }) => { return ( @@ -1032,46 +1090,48 @@ export function getSuggestedNfts(state) { ); } -export function getIsMainnet(state) { +export function getIsMainnet(state: MetaMaskReduxState) { const chainId = getCurrentChainId(state); return chainId === CHAIN_IDS.MAINNET; } -export function getIsLineaMainnet(state) { +export function getIsLineaMainnet(state: MetaMaskReduxState) { const chainId = getCurrentChainId(state); return chainId === CHAIN_IDS.LINEA_MAINNET; } -export function getIsTestnet(state) { +export function getIsTestnet(state: MetaMaskReduxState) { const chainId = getCurrentChainId(state); return TEST_CHAINS.includes(chainId); } -export function getIsNonStandardEthChain(state) { +export function getIsNonStandardEthChain(state: MetaMaskReduxState) { return !(getIsMainnet(state) || getIsTestnet(state) || process.env.IN_TEST); } -export function getPreferences({ metamask }) { - return metamask.PreferencesController.preferences; +export function getPreferences(state: MetaMaskReduxState) { + return state.metamask.PreferencesController.preferences; } -export function getSendInputCurrencySwitched({ appState }) { - return appState.sendInputCurrencySwitched; +export function getSendInputCurrencySwitched(state: MetaMaskReduxState) { + return state.appState.sendInputCurrencySwitched; } -export function getShowTestNetworks(state) { +export function getShowTestNetworks(state: MetaMaskReduxState) { const { showTestNetworks } = getPreferences(state); return Boolean(showTestNetworks); } -export function getPetnamesEnabled(state) { +export function getPetnamesEnabled(state: MetaMaskReduxState) { const { petnamesEnabled = true } = getPreferences(state); return petnamesEnabled; } -export function getIsTokenNetworkFilterEqualCurrentNetwork(state) { +export function getIsTokenNetworkFilterEqualCurrentNetwork( + state: MetaMaskReduxState, +) { const chainId = getCurrentChainId(state); const { tokenNetworkFilter: tokenNetworkFilterValue } = getPreferences(state); - const tokenNetworkFilter = tokenNetworkFilterValue || {}; + const tokenNetworkFilter = tokenNetworkFilterValue ?? {}; if ( Object.keys(tokenNetworkFilter).length === 1 && Object.keys(tokenNetworkFilter)[0] === chainId @@ -1081,33 +1141,33 @@ export function getIsTokenNetworkFilterEqualCurrentNetwork(state) { return false; } -export function getUseTransactionSimulations(state) { +export function getUseTransactionSimulations(state: MetaMaskReduxState) { return Boolean( state.metamask.PreferencesController.useTransactionSimulations, ); } -export function getRedesignedConfirmationsEnabled(state) { +export function getRedesignedConfirmationsEnabled(state: MetaMaskReduxState) { const { redesignedConfirmationsEnabled } = getPreferences(state); return redesignedConfirmationsEnabled; } -export function getRedesignedTransactionsEnabled(state) { +export function getRedesignedTransactionsEnabled(state: MetaMaskReduxState) { const { redesignedTransactionsEnabled } = getPreferences(state); return redesignedTransactionsEnabled; } -export function getFeatureNotificationsEnabled(state) { +export function getFeatureNotificationsEnabled(state: MetaMaskReduxState) { const { featureNotificationsEnabled = false } = getPreferences(state); return featureNotificationsEnabled; } -export function getShowExtensionInFullSizeView(state) { +export function getShowExtensionInFullSizeView(state: MetaMaskReduxState) { const { showExtensionInFullSizeView } = getPreferences(state); return Boolean(showExtensionInFullSizeView); } -export function getTestNetworkBackgroundColor(state) { +export function getTestNetworkBackgroundColor(state: MetaMaskReduxState) { const currentNetwork = getProviderConfig(state).ticker; switch (true) { case currentNetwork?.includes(GOERLI_DISPLAY_NAME): @@ -1119,7 +1179,7 @@ export function getTestNetworkBackgroundColor(state) { } } -export function getShouldShowFiat(state) { +export function getShouldShowFiat(state: MetaMaskReduxState) { const currentChainId = getCurrentChainId(state); const isTestnet = TEST_NETWORK_IDS.includes(currentChainId); const { showFiatInTestnets } = getPreferences(state); @@ -1134,25 +1194,25 @@ export function getShouldShowFiat(state) { return isConvertibleToFiat; } -export function getShouldHideZeroBalanceTokens(state) { +export function getShouldHideZeroBalanceTokens(state: MetaMaskReduxState) { const { hideZeroBalanceTokens } = getPreferences(state); return hideZeroBalanceTokens; } -export function getAdvancedInlineGasShown(state) { +export function getAdvancedInlineGasShown(state: MetaMaskReduxState) { return Boolean( state.metamask.PreferencesController.featureFlags.advancedInlineGas, ); } -export function getUseNonceField(state) { +export function getUseNonceField(state: MetaMaskReduxState) { const isSmartTransaction = getIsSmartTransaction(state); return Boolean( !isSmartTransaction && state.metamask.PreferencesController.useNonceField, ); } -export function getCustomNonceValue(state) { +export function getCustomNonceValue(state: MetaMaskReduxState) { return String(state.appState.customNonceValue); } @@ -1164,7 +1224,10 @@ const getEmbeddableSvg = memoize( (svgString) => `data:image/svg+xml;utf8,${encodeURIComponent(svgString)}`, ); -export function getTargetSubjectMetadata(state, origin) { +export function getTargetSubjectMetadata( + state: MetaMaskReduxState, + origin: string, +) { const metadata = getSubjectMetadata(state)[origin]; if (metadata?.subjectType === SubjectType.Snap) { @@ -1187,7 +1250,7 @@ export function getTargetSubjectMetadata(state, origin) { * @param state - Redux state object. * @returns Object - Redux state object. */ -export const rawStateSelector = (state) => state; +export const rawStateSelector = (state: MetaMaskReduxState) => state; /** * Input selector used to retrieve Snaps that are added to Snaps Directory. @@ -1195,7 +1258,7 @@ export const rawStateSelector = (state) => state; * @param state - Redux state object. * @returns Object - Containing verified Snaps from the Directory. */ -const selectVerifiedSnapsRegistry = (state) => +const selectVerifiedSnapsRegistry = (state: MetaMaskReduxState) => state.metamask.SnapsRegistry.database?.verifiedSnaps; /** @@ -1205,7 +1268,7 @@ const selectVerifiedSnapsRegistry = (state) => * @param snapId - ID of a Snap. * @returns string - ID of a Snap that can be used as input selector. */ -const selectSnapId = (_state, snapId) => snapId; +const selectSnapId = (_state: MetaMaskReduxState, snapId: SnapId) => snapId; /** * Input selector for retrieving all installed Snaps. @@ -1213,7 +1276,7 @@ const selectSnapId = (_state, snapId) => snapId; * @param state - Redux state object. * @returns Object - Installed Snaps. */ -export const selectInstalledSnaps = (state) => +export const selectInstalledSnaps = (state: MetaMaskReduxState) => state.metamask.SnapController.snaps; /** @@ -1330,7 +1393,7 @@ export const getMemoizedUnapprovedTemplatedConfirmations = * @param state - Redux state object. * @returns the Snap interfaces. */ -const getInterfaces = (state) => +const getInterfaces = (state: MetaMaskReduxState) => state.metamask.SnapInterfaceController.interfaces; /** @@ -1340,7 +1403,8 @@ const getInterfaces = (state) => * @param interfaceId - ID of a Snap interface. * @returns ID of a Snap Interface that can be used as input selector. */ -const selectInterfaceId = (_state, interfaceId) => interfaceId; +const selectInterfaceId = (_state: MetaMaskReduxState, interfaceId: string) => + interfaceId; /** * Get a memoized version of the Snap interfaces. @@ -1400,7 +1464,7 @@ const selectOrigins = (_state, origins) => origins; */ export const getMultipleTargetsSubjectMetadata = createDeepEqualSelector( [rawStateSelector, selectOrigins], - (state, origins) => { + (state: MetaMaskReduxState, origins) => { return Object.keys(origins ?? {}).reduce((originsMetadata, origin) => { originsMetadata[origin] = getTargetSubjectMetadata(state, origin); return originsMetadata; @@ -1408,12 +1472,12 @@ export const getMultipleTargetsSubjectMetadata = createDeepEqualSelector( }, ); -export function getRpcPrefsForCurrentProvider(state) { +export function getRpcPrefsForCurrentProvider(state: MetaMaskReduxState) { const { rpcPrefs } = getProviderConfig(state); return rpcPrefs; } -export function getKnownMethodData(state, data) { +export function getKnownMethodData(state: MetaMaskReduxState, data: Hex) { const { knownMethodData, use4ByteResolution } = state.metamask.PreferencesController; @@ -1431,38 +1495,41 @@ export function getKnownMethodData(state, data) { return knownMethodData?.[fourBytePrefix] ?? null; } -export function getFeatureFlags(state) { +export function getFeatureFlags(state: MetaMaskReduxState) { return state.metamask.PreferencesController.featureFlags; } -export function getOriginOfCurrentTab(state) { +export function getOriginOfCurrentTab(state: MetaMaskReduxState) { return state.activeTab.origin; } -export function getDefaultHomeActiveTabName(state) { +export function getDefaultHomeActiveTabName(state: MetaMaskReduxState) { return state.metamask.AppStateController.defaultHomeActiveTabName; } -export function getIpfsGateway(state) { +export function getIpfsGateway(state: MetaMaskReduxState) { return state.metamask.PreferencesController.ipfsGateway; } -export function getUseExternalServices(state) { +export function getUseExternalServices(state: MetaMaskReduxState) { return state.metamask.PreferencesController.useExternalServices; } -export function getUSDConversionRate(state) { +export function getUSDConversionRate(state: MetaMaskReduxState) { return state.metamask.CurrencyController.currencyRates[ getProviderConfig(state).ticker ]?.usdConversionRate; } -export function getCurrencyRates(state) { +export function getCurrencyRates(state: MetaMaskReduxState) { return state.metamask.CurrencyController.currencyRates; } -export function getWeb3ShimUsageStateForOrigin(state, origin) { - return state.metamask.AlertController.web3ShimUsageOrigins[origin]; +export function getWeb3ShimUsageStateForOrigin( + state: MetaMaskReduxState, + origin: string, +) { + return state.metamask.AlertController.web3ShimUsageOrigins?.[origin]; } /** @@ -1500,7 +1567,10 @@ export function getWeb3ShimUsageStateForOrigin(state, origin) { * selected account's ETH balance, as expected by the Swaps API. */ -export function getSwapsDefaultToken(state, overrideChainId = null) { +export function getSwapsDefaultToken( + state: MetaMaskReduxState, + overrideChainId = null, +) { const selectedAccount = getSelectedAccount(state); const balance = selectedAccount?.balance; const currentChainId = getCurrentChainId(state); @@ -1519,7 +1589,10 @@ export function getSwapsDefaultToken(state, overrideChainId = null) { }; } -export function getIsSwapsChain(state, overrideChainId) { +export function getIsSwapsChain( + state: MetaMaskReduxState, + overrideChainId: Hex, +) { const currentChainId = getCurrentChainId(state); const chainId = overrideChainId ?? currentChainId; const isNotDevelopment = @@ -1530,13 +1603,16 @@ export function getIsSwapsChain(state, overrideChainId) { : ALLOWED_DEV_SWAPS_CHAIN_IDS.includes(chainId); } -export function getIsBridgeChain(state, overrideChainId) { +export function getIsBridgeChain( + state: MetaMaskReduxState, + overrideChainId: Hex, +) { const currentChainId = getCurrentChainId(state); const chainId = overrideChainId ?? currentChainId; return ALLOWED_BRIDGE_CHAIN_IDS.includes(chainId); } -function getBridgeFeatureFlags(state) { +function getBridgeFeatureFlags(state: MetaMaskReduxState) { return state.metamask.BridgeController.bridgeState?.bridgeFeatureFlags; } @@ -1551,7 +1627,7 @@ export const getIsBridgeEnabled = createSelector( }, ); -export function getNativeCurrencyImage(state) { +export function getNativeCurrencyImage(state: MetaMaskReduxState) { const chainId = getCurrentChainId(state); return CHAIN_ID_TOKEN_IMAGE_MAP[chainId]; } @@ -1560,15 +1636,15 @@ export function getNativeCurrencyForChain(chainId) { return CHAIN_ID_TOKEN_IMAGE_MAP[chainId] ?? undefined; } -export function getNextSuggestedNonce(state) { +export function getNextSuggestedNonce(state: MetaMaskReduxState) { return Number(state.appState.nextNonce); } -export function getShowWhatsNewPopup(state) { +export function getShowWhatsNewPopup(state: MetaMaskReduxState) { return state.appState.showWhatsNewPopup; } -export function getShowPermittedNetworkToastOpen(state) { +export function getShowPermittedNetworkToastOpen(state: MetaMaskReduxState) { return state.appState.showPermittedNetworkToastOpen; } @@ -1589,12 +1665,13 @@ export const getMemoizedAddressBook = createDeepEqualSelector( ); export const selectERC20TokensByChain = createDeepEqualSelector( - (state) => state.metamask.TokenListController.tokensChainsCache, + (state: MetaMaskReduxState) => + state.metamask.TokenListController.tokensChainsCache, (erc20TokensByChain) => erc20TokensByChain, ); export const selectERC20Tokens = createDeepEqualSelector( - (state) => state.metamask.TokenListController.tokenList, + (state: MetaMaskReduxState) => state.metamask.TokenListController.tokenList, (erc20Tokens) => erc20Tokens, ); @@ -1615,41 +1692,46 @@ export const getTokenList = createSelector( ); export const getMemoizedMetadataContract = createSelector( - (state, _address) => getTokenList(state), + (state: MetaMaskReduxState, _address: string) => getTokenList(state), (_state, address) => address, (tokenList, address) => tokenList[address?.toLowerCase()], ); /** - * @type (state: any, address: string) => string + * @type (state: MetaMaskReduxState: any, address: string) => string */ export const getMetadataContractName = createSelector( getMemoizedMetadataContract, (entry) => entry?.name ?? '', ); -export const getTxData = (state) => state.confirmTransaction.txData; +export const getTxData = (state: MetaMaskReduxState) => + state.confirmTransaction.txData; export const getUnapprovedTransaction = createDeepEqualSelector( - (state) => getUnapprovedTransactions(state), - (_, transactionId) => transactionId, + (state: MetaMaskReduxState) => getUnapprovedTransactions(state), + (_: MetaMaskReduxState, transactionId: Hex) => transactionId, (unapprovedTxs, transactionId) => Object.values(unapprovedTxs).find(({ id }) => id === transactionId), ); export const getTransaction = createDeepEqualSelector( - (state) => getCurrentNetworkTransactions(state), - (_, transactionId) => transactionId, + (state: MetaMaskReduxState) => getCurrentNetworkTransactions(state), + (_: MetaMaskReduxState, transactionId: Hex) => transactionId, (unapprovedTxs, transactionId) => { return ( - Object.values(unapprovedTxs).find(({ id }) => id === transactionId) || {} + Object.values(unapprovedTxs).find(({ id }) => id === transactionId) ?? {} ); }, ); export const getFullTxData = createDeepEqualSelector( getTxData, - (state, transactionId, status) => { + ( + state: MetaMaskReduxState, + transactionId: Hex, + status: TransactionStatus, + ) => { if (status === TransactionStatus.unapproved) { return getUnapprovedTransaction(state, transactionId) ?? {}; } @@ -1731,7 +1813,9 @@ export const getConnectedSitesList = createDeepEqualSelector( }, ); -export function getShouldShowAggregatedBalancePopover(state) { +export function getShouldShowAggregatedBalancePopover( + state: MetaMaskReduxState, +) { const { shouldShowAggregatedBalancePopover } = getPreferences(state); return shouldShowAggregatedBalancePopover; } @@ -1757,31 +1841,33 @@ export const getMemoizedCurrentChainId = createDeepEqualSelector( ); export const getMemoizedTxId = createDeepEqualSelector( - (state) => state.appState.txId, + (state: MetaMaskReduxState) => state.appState.txId, (txId) => txId, ); export const getMemoizedUnapprovedPersonalMessages = createDeepEqualSelector( - (state) => state.metamask.SignatureController.PersonalMsgs, + (state: MetaMaskReduxState) => + state.metamask.SignatureController.unapprovedPersonalMsgs, (unapprovedPersonalMsgs) => unapprovedPersonalMsgs, ); export const getMemoizedUnapprovedTypedMessages = createDeepEqualSelector( - (state) => state.metamask.SignatureController.TypedMessages, + (state: MetaMaskReduxState) => + state.metamask.SignatureController.unapprovedTypedMessages, (unapprovedTypedMessages) => unapprovedTypedMessages, ); -export function getSnaps(state) { +export function getSnaps(state: MetaMaskReduxState) { return state.metamask.SnapController.snaps; } -export function getLocale(state) { +export function getLocale(state: MetaMaskReduxState) { return state.metamask.PreferencesController.currentLocale; } export const getSnap = createDeepEqualSelector( getSnaps, - (_, snapId) => snapId, + (_: MetaMaskReduxState, snapId: SnapId) => snapId, (snaps, snapId) => { return snaps[snapId]; }, @@ -1827,7 +1913,7 @@ export const getSnapsMetadata = createDeepEqualSelector( */ export const getSnapMetadata = createDeepEqualSelector( getSnapsMetadata, - (_, snapId) => snapId, + (_: MetaMaskReduxState, snapId: SnapId) => snapId, (metadata, snapId) => { return ( metadata[snapId] ?? { @@ -1838,7 +1924,7 @@ export const getSnapMetadata = createDeepEqualSelector( ); export const getEnabledSnaps = createDeepEqualSelector(getSnaps, (snaps) => { - return Object.values(snaps).reduce((acc, cur) => { + return Object.values(snaps).reduce>((acc, cur) => { if (cur.enabled) { acc[cur.id] = cur; } @@ -1849,7 +1935,7 @@ export const getEnabledSnaps = createDeepEqualSelector(getSnaps, (snaps) => { export const getPreinstalledSnaps = createDeepEqualSelector( getSnaps, (snaps) => { - return Object.values(snaps).reduce((acc, snap) => { + return Object.values(snaps).reduce>((acc, snap) => { if (snap.preinstalled) { acc[snap.id] = snap; } @@ -1908,7 +1994,7 @@ export const getNotifySnaps = createDeepEqualSelector( }, ); -function getAllSnapInsights(state) { +function getAllSnapInsights(state: MetaMaskReduxState) { return state.metamask.SnapInsightsController.insights; } @@ -1924,7 +2010,7 @@ export const getSnapInsights = createDeepEqualSelector( * @param {object} state * @returns {object} */ -function getAllowedAnnouncementIds(state) { +function getAllowedAnnouncementIds(state: MetaMaskReduxState) { const currentKeyring = getCurrentKeyring(state); const currentKeyringIsLedger = currentKeyring?.type === KeyringType.ledger; const isFirefox = window.navigator.userAgent.includes('Firefox'); @@ -1952,7 +2038,7 @@ function getAllowedAnnouncementIds(state) { * @returns {Announcement[]} An array of announcements that can be shown to the user */ -export function getSortedAnnouncementsToShow(state) { +export function getSortedAnnouncementsToShow(state: MetaMaskReduxState) { const announcements = Object.values( state.metamask.AnnouncementController.announcements, ); @@ -1971,19 +2057,19 @@ export function getSortedAnnouncementsToShow(state) { * @param state * @returns {{networkId: string}[]} */ -export function getOrderedNetworksList(state) { +export function getOrderedNetworksList(state: MetaMaskReduxState) { return state.metamask.NetworkOrderController.orderedNetworkList; } -export function getPinnedAccountsList(state) { +export function getPinnedAccountsList(state: MetaMaskReduxState) { return state.metamask.AccountOrderController.pinnedAccountList; } -export function getHiddenAccountsList(state) { +export function getHiddenAccountsList(state: MetaMaskReduxState) { return state.metamask.AccountOrderController.hiddenAccountList; } -export function getShowRecoveryPhraseReminder(state) { +export function getShowRecoveryPhraseReminder(state: MetaMaskReduxState) { const { recoveryPhraseReminderLastShown, recoveryPhraseReminderHasBeenShown, @@ -2001,16 +2087,19 @@ export function getShowRecoveryPhraseReminder(state) { * @param state - Redux state object. * @returns Number of unapproved transactions */ -export function getNumberOfAllUnapprovedTransactionsAndMessages(state) { +export function getNumberOfAllUnapprovedTransactionsAndMessages( + state: MetaMaskReduxState, +) { const unapprovedTxs = getAllUnapprovedTransactions(state); const queuedRequestCount = getQueuedRequestCount(state); const allUnapprovedMessages = { ...unapprovedTxs, ...state.metamask.DecryptMessageController.unapprovedDecryptMsgs, - ...state.metamask.SignatureController.PersonalMsgs, - ...state.metamask.EncryptionPublicKeyController.EncryptionPublicKeyMsgs, - ...state.metamask.SignatureController.TypedMessages, + ...state.metamask.SignatureController.unapprovedPersonalMsgs, + ...state.metamask.EncryptionPublicKeyController + .unapprovedEncryptionPublicKeyMsgs, + ...state.metamask.SignatureController.unapprovedTypedMessages, }; const numUnapprovedMessages = Object.keys(allUnapprovedMessages).length; return numUnapprovedMessages + queuedRequestCount; @@ -2123,7 +2212,7 @@ export const getConnectedSitesListWithNetworkInfo = createDeepEqualSelector( * @param state - Redux state object. * @returns Network ID to switch to */ -export function getNetworkToAutomaticallySwitchTo(state) { +export function getNetworkToAutomaticallySwitchTo(state: MetaMaskReduxState) { const numberOfUnapprovedTx = getNumberOfAllUnapprovedTransactionsAndMessages(state); @@ -2156,7 +2245,7 @@ export function getNetworkToAutomaticallySwitchTo(state) { return null; } -export function getShowTermsOfUse(state) { +export function getShowTermsOfUse(state: MetaMaskReduxState) { const { termsOfUseLastAgreed } = state.metamask.AppStateController; if (!termsOfUseLastAgreed) { @@ -2168,11 +2257,11 @@ export function getShowTermsOfUse(state) { ); } -export function getLastViewedUserSurvey(state) { +export function getLastViewedUserSurvey(state: MetaMaskReduxState) { return state.metamask.AppStateController.lastViewedUserSurvey; } -export function getShowOutdatedBrowserWarning(state) { +export function getShowOutdatedBrowserWarning(state: MetaMaskReduxState) { const { outdatedBrowserWarningLastShown } = state.metamask.AppStateController; if (!outdatedBrowserWarningLastShown) { return true; @@ -2181,23 +2270,23 @@ export function getShowOutdatedBrowserWarning(state) { return currentTime - outdatedBrowserWarningLastShown >= DAY * 2; } -export function getOnboardingDate(state) { +export function getOnboardingDate(state: MetaMaskReduxState) { return state.metamask.AppStateController.onboardingDate; } -export function getShowBetaHeader(state) { +export function getShowBetaHeader(state: MetaMaskReduxState) { return state.metamask.AppStateController.showBetaHeader; } -export function getShowPermissionsTour(state) { +export function getShowPermissionsTour(state: MetaMaskReduxState) { return state.metamask.AppStateController.showPermissionsTour; } -export function getShowNetworkBanner(state) { +export function getShowNetworkBanner(state: MetaMaskReduxState) { return state.metamask.AppStateController.showNetworkBanner; } -export function getShowAccountBanner(state) { +export function getShowAccountBanner(state: MetaMaskReduxState) { return state.metamask.AppStateController.showAccountBanner; } /** @@ -2206,7 +2295,7 @@ export function getShowAccountBanner(state) { * @param {*} state * @returns Boolean */ -export function getUseTokenDetection(state) { +export function getUseTokenDetection(state: MetaMaskReduxState) { return Boolean(state.metamask.PreferencesController.useTokenDetection); } @@ -2216,7 +2305,7 @@ export function getUseTokenDetection(state) { * @param {*} state * @returns Boolean */ -export function getUseNftDetection(state) { +export function getUseNftDetection(state: MetaMaskReduxState) { return Boolean(state.metamask.PreferencesController.useNftDetection); } @@ -2226,7 +2315,7 @@ export function getUseNftDetection(state) { * @param {*} state * @returns Boolean */ -export function getUseBlockie(state) { +export function getUseBlockie(state: MetaMaskReduxState) { return Boolean(state.metamask.PreferencesController.useBlockie); } @@ -2236,7 +2325,7 @@ export function getUseBlockie(state) { * @param {*} state * @returns Boolean */ -export function getOpenSeaEnabled(state) { +export function getOpenSeaEnabled(state: MetaMaskReduxState) { return Boolean(state.metamask.PreferencesController.openSeaEnabled); } @@ -2246,11 +2335,14 @@ export function getOpenSeaEnabled(state) { * @param {*} state * @returns Boolean */ -export function getTheme(state) { +export function getTheme(state: MetaMaskReduxState) { return state.metamask.PreferencesController.theme; } -export function doesAddressRequireLedgerHidConnection(state, address) { +export function doesAddressRequireLedgerHidConnection( + state: MetaMaskReduxState, + address: string, +) { const addressIsLedger = isAddressLedger(state, address); const transportTypePreferenceIsWebHID = getLedgerTransportType(state) === LedgerTransportTypes.webhid; @@ -2267,11 +2359,11 @@ export function doesAddressRequireLedgerHidConnection(state, address) { ); } -export function getNewNftAddedMessage(state) { +export function getNewNftAddedMessage(state: MetaMaskReduxState) { return state.appState.newNftAddedMessage; } -export function getRemoveNftMessage(state) { +export function getRemoveNftMessage(state: MetaMaskReduxState) { return state.appState.removeNftMessage; } @@ -2281,7 +2373,7 @@ export function getRemoveNftMessage(state) { * @param {*} state * @returns string */ -export function getNewNetworkAdded(state) { +export function getNewNetworkAdded(state: MetaMaskReduxState) { return state.appState.newNetworkAddedName; } @@ -2289,19 +2381,21 @@ export function getNewNetworkAdded(state) { * @param state * @returns {{ chainId: import('@metamask/utils').Hex; nickname: string; editCompleted: boolean} | undefined} */ -export function getEditedNetwork(state) { +export function getEditedNetwork(state: MetaMaskReduxState) { return state.appState.editedNetwork; } -export function getIsAddingNewNetwork(state) { +export function getIsAddingNewNetwork(state: MetaMaskReduxState) { return state.appState.isAddingNewNetwork; } -export function getIsMultiRpcOnboarding(state) { +export function getIsMultiRpcOnboarding(state: MetaMaskReduxState) { return state.appState.isMultiRpcOnboarding; } -export function getNetworksTabSelectedNetworkConfigurationId(state) { +export function getNetworksTabSelectedNetworkConfigurationId( + state: MetaMaskReduxState, +) { return state.appState.selectedNetworkConfigurationId; } @@ -2420,7 +2514,7 @@ export const getNetworkClientIdsToPoll = createDeepEqualSelector( * @param {*} state * @returns {{maxBaseFee: string, priorityFee: string} | undefined} */ -export function getAdvancedGasFeeValues(state) { +export function getAdvancedGasFeeValues(state: MetaMaskReduxState) { // This will not work when we switch to supporting multi-chain. // There are four non-test files that use this selector. // advanced-gas-fee-defaults @@ -2448,7 +2542,9 @@ export function getAdvancedGasFeeValues(state) { * @param state * @returns string e.g. ethereum, bsc or polygon */ -export const getTokenDetectionSupportNetworkByChainId = (state) => { +export const getTokenDetectionSupportNetworkByChainId = ( + state: MetaMaskReduxState, +) => { const chainId = getCurrentChainId(state); switch (chainId) { case CHAIN_IDS.MAINNET: @@ -2497,28 +2593,30 @@ export const getTokenDetectionSupportNetworkByChainId = (state) => { * @param {*} state * @returns Boolean */ -export function getIsDynamicTokenListAvailable(state) { - const chainId = getCurrentChainId(state); - return [ - CHAIN_IDS.MAINNET, - CHAIN_IDS.BSC, - CHAIN_IDS.POLYGON, - CHAIN_IDS.AVALANCHE, - CHAIN_IDS.LINEA_GOERLI, - CHAIN_IDS.LINEA_SEPOLIA, - CHAIN_IDS.LINEA_MAINNET, - CHAIN_IDS.ARBITRUM, - CHAIN_IDS.OPTIMISM, - CHAIN_IDS.BASE, - CHAIN_IDS.ZKSYNC_ERA, - CHAIN_IDS.CRONOS, - CHAIN_IDS.CELO, - CHAIN_IDS.GNOSIS, - CHAIN_IDS.FANTOM, - CHAIN_IDS.POLYGON_ZKEVM, - CHAIN_IDS.MOONBEAM, - CHAIN_IDS.MOONRIVER, - ].includes(chainId); +export function getIsDynamicTokenListAvailable(state: MetaMaskReduxState) { + const currentChainId = getCurrentChainId(state); + return Boolean( + [ + CHAIN_IDS.MAINNET, + CHAIN_IDS.BSC, + CHAIN_IDS.POLYGON, + CHAIN_IDS.AVALANCHE, + CHAIN_IDS.LINEA_GOERLI, + CHAIN_IDS.LINEA_SEPOLIA, + CHAIN_IDS.LINEA_MAINNET, + CHAIN_IDS.ARBITRUM, + CHAIN_IDS.OPTIMISM, + CHAIN_IDS.BASE, + CHAIN_IDS.ZKSYNC_ERA, + CHAIN_IDS.CRONOS, + CHAIN_IDS.CELO, + CHAIN_IDS.GNOSIS, + CHAIN_IDS.FANTOM, + CHAIN_IDS.POLYGON_ZKEVM, + CHAIN_IDS.MOONBEAM, + CHAIN_IDS.MOONRIVER, + ].find((chainId) => chainId === currentChainId), + ); } /** @@ -2527,7 +2625,7 @@ export function getIsDynamicTokenListAvailable(state) { * @param {*} state * @returns list of token objects */ -export function getDetectedTokensInCurrentNetwork(state) { +export function getDetectedTokensInCurrentNetwork(state: MetaMaskReduxState) { const currentChainId = getCurrentChainId(state); const { address: selectedAddress } = getSelectedInternalAccount(state); return state.metamask.TokensController.allDetectedTokens?.[currentChainId]?.[ @@ -2535,7 +2633,7 @@ export function getDetectedTokensInCurrentNetwork(state) { ]; } -export function getAllDetectedTokens(state) { +export function getAllDetectedTokens(state: MetaMaskReduxState) { return state.metamask.TokensController.allDetectedTokens; } @@ -2545,7 +2643,9 @@ export function getAllDetectedTokens(state) { * @param {*} state * @returns list of token objects on all networks */ -export function getAllDetectedTokensForSelectedAddress(state) { +export function getAllDetectedTokensForSelectedAddress( + state: MetaMaskReduxState, +) { const completedOnboarding = getCompletedOnboarding(state); if (!completedOnboarding) { @@ -2553,10 +2653,11 @@ export function getAllDetectedTokensForSelectedAddress(state) { } const { address: selectedAddress } = getSelectedInternalAccount(state); - - const tokensByChainId = Object.entries( - state.metamask.TokensController.allDetectedTokens || {}, - ).reduce((acc, [chainId, chainTokens]) => { + const { allDetectedTokens } = state.metamask.TokensController ?? {}; + const tokensByChainId = getKnownPropertyNames(allDetectedTokens).reduce< + Record + >((acc, chainId) => { + const chainTokens = allDetectedTokens[chainId]; const tokensForAddress = chainTokens[selectedAddress]; if (tokensForAddress) { acc[chainId] = tokensForAddress.map((token) => ({ @@ -2576,11 +2677,11 @@ export function getAllDetectedTokensForSelectedAddress(state) { * @param {*} state * @returns */ -export function getNewTokensImported(state) { +export function getNewTokensImported(state: MetaMaskReduxState) { return state.appState.newTokensImported; } -export function getNewTokensImportedError(state) { +export function getNewTokensImportedError(state: MetaMaskReduxState) { return state.appState.newTokensImportedError; } @@ -2592,7 +2693,9 @@ export function getNewTokensImportedError(state) { * @param {*} state * @returns Boolean */ -export function getIsTokenDetectionInactiveOnMainnet(state) { +export function getIsTokenDetectionInactiveOnMainnet( + state: MetaMaskReduxState, +) { const isMainnet = getIsMainnet(state); const useTokenDetection = getUseTokenDetection(state); @@ -2606,7 +2709,7 @@ export function getIsTokenDetectionInactiveOnMainnet(state) { * @param {*} state * @returns Boolean */ -export function getIsTokenDetectionSupported(state) { +export function getIsTokenDetectionSupported(state: MetaMaskReduxState) { const useTokenDetection = getUseTokenDetection(state); const isDynamicTokenListAvailable = getIsDynamicTokenListAvailable(state); @@ -2620,7 +2723,9 @@ export function getIsTokenDetectionSupported(state) { * @param {*} state * @returns Boolean */ -export function getIstokenDetectionInactiveOnNonMainnetSupportedNetwork(state) { +export function getIstokenDetectionInactiveOnNonMainnetSupportedNetwork( + state: MetaMaskReduxState, +) { const useTokenDetection = getUseTokenDetection(state); const isMainnet = getIsMainnet(state); const isDynamicTokenListAvailable = getIsDynamicTokenListAvailable(state); @@ -2634,7 +2739,7 @@ export function getIstokenDetectionInactiveOnNonMainnetSupportedNetwork(state) { * @param {*} state * @returns Boolean */ -export function getUseRequestQueue(state) { +export function getUseRequestQueue(state: MetaMaskReduxState) { return state.metamask.PreferencesController.useRequestQueue; } @@ -2644,8 +2749,8 @@ export function getUseRequestQueue(state) { * @param {*} state * @returns Boolean */ -export function getIsSecurityAlertsEnabled(state) { - return state.metamask.PPOMController.securityAlertsEnabled; +export function getIsSecurityAlertsEnabled(state: MetaMaskReduxState) { + return state.metamask.PreferencesController.securityAlertsEnabled; } ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) @@ -2655,12 +2760,12 @@ export function getIsSecurityAlertsEnabled(state) { * @param {*} state * @returns The state of the `addSnapAccountEnabled` flag. */ -export function getIsAddSnapAccountEnabled(state) { +export function getIsAddSnapAccountEnabled(state: MetaMaskReduxState) { return state.metamask.PreferencesController.addSnapAccountEnabled; } ///: END:ONLY_INCLUDE_IF -export function getIsWatchEthereumAccountEnabled(state) { +export function getIsWatchEthereumAccountEnabled(state: MetaMaskReduxState) { return state.metamask.PreferencesController.watchEthereumAccountEnabled; } @@ -2670,7 +2775,7 @@ export function getIsWatchEthereumAccountEnabled(state) { * @param {*} state * @returns The state of the `bitcoinSupportEnabled` flag. */ -export function getIsBitcoinSupportEnabled(state) { +export function getIsBitcoinSupportEnabled(state: MetaMaskReduxState) { return state.metamask.PreferencesController.bitcoinSupportEnabled; } @@ -2681,7 +2786,7 @@ export function getIsBitcoinSupportEnabled(state) { * @param {*} state * @returns The state of the `solanaSupportEnabled` flag. */ -export function getIsSolanaSupportEnabled(state) { +export function getIsSolanaSupportEnabled(state: MetaMaskReduxState) { return state.metamask.PreferencesController.solanaSupportEnabled; } ///: END:ONLY_INCLUDE_IF @@ -2692,18 +2797,20 @@ export function getIsSolanaSupportEnabled(state) { * @param {*} state * @returns The state of the `bitcoinTestnetSupportEnabled` flag. */ -export function getIsBitcoinTestnetSupportEnabled(state) { +export function getIsBitcoinTestnetSupportEnabled(state: MetaMaskReduxState) { return state.metamask.PreferencesController.bitcoinTestnetSupportEnabled; } -export function getIsCustomNetwork(state) { - const chainId = getCurrentChainId(state); - - return !CHAIN_ID_TO_RPC_URL_MAP[chainId]; +export function getIsCustomNetwork(state: MetaMaskReduxState) { + return Boolean( + getKnownPropertyNames(CHAIN_ID_TO_RPC_URL_MAP).find( + (chainId) => chainId === getCurrentChainId(state), + ), + ); } export function getBlockExplorerLinkText( - state, + state: MetaMaskReduxState, accountDetailsModalComponent = false, ) { const isCustomNetwork = getIsCustomNetwork(state); @@ -2736,7 +2843,7 @@ export function getBlockExplorerLinkText( return blockExplorerLinkText; } -export function getAllAccountsOnNetworkAreEmpty(state) { +export function getAllAccountsOnNetworkAreEmpty(state: MetaMaskReduxState) { const balances = getMetaMaskCachedBalances(state) ?? {}; const hasNoNativeFundsOnAnyAccounts = Object.values(balances).every( (balance) => balance === '0x0' || balance === '0x00', @@ -2746,9 +2853,10 @@ export function getAllAccountsOnNetworkAreEmpty(state) { return hasNoNativeFundsOnAnyAccounts && hasNoTokens; } -export function getShouldShowSeedPhraseReminder(state) { - const { tokens, seedPhraseBackedUp, dismissSeedBackUpReminder } = - state.metamask; +export function getShouldShowSeedPhraseReminder(state: MetaMaskReduxState) { + const { seedPhraseBackedUp } = state.metamask.OnboardingController; + const { dismissSeedBackUpReminder } = state.metamask.PreferencesController; + const { tokens } = state.metamask.TokensController; // if there is no account, we don't need to show the seed phrase reminder const accountBalance = getSelectedInternalAccount(state) @@ -2762,11 +2870,14 @@ export function getShouldShowSeedPhraseReminder(state) { ); } -export function getCustomTokenAmount(state) { +export function getCustomTokenAmount(state: MetaMaskReduxState) { return state.appState.customTokenAmount; } -export function getUnconnectedAccounts(state, activeTab) { +export function getUnconnectedAccounts( + state: MetaMaskReduxState, + activeTab: MetaMaskReduxState['activeTab'], +) { const accounts = getMetaMaskAccountsOrdered(state); const connectedAccounts = getOrderedConnectedAccountsForConnectedDapp( state, @@ -2851,23 +2962,27 @@ export const getUpdatedAndSortedAccounts = createDeepEqualSelector( }, ); -export function getOnboardedInThisUISession(state) { +export function getOnboardedInThisUISession(state: MetaMaskReduxState) { return state.appState.onboardedInThisUISession; } -export function getShowBasicFunctionalityModal(state) { +export function getShowBasicFunctionalityModal(state: MetaMaskReduxState) { return state.appState.showBasicFunctionalityModal; } -export function getExternalServicesOnboardingToggleState(state) { +export function getExternalServicesOnboardingToggleState( + state: MetaMaskReduxState, +) { return state.appState.externalServicesOnboardingToggleState; } -export const useSafeChainsListValidationSelector = (state) => { +export const useSafeChainsListValidationSelector = ( + state: MetaMaskReduxState, +) => { return state.metamask.PreferencesController.useSafeChainsListValidation; }; -export function getShowFiatInTestnets(state) { +export function getShowFiatInTestnets(state: MetaMaskReduxState) { const { showFiatInTestnets } = getPreferences(state); return showFiatInTestnets; } @@ -2878,44 +2993,46 @@ export function getShowFiatInTestnets(state) { * @param {*} state * @returns Boolean */ -export function getUseCurrencyRateCheck(state) { +export function getUseCurrencyRateCheck(state: MetaMaskReduxState) { return Boolean(state.metamask.PreferencesController.useCurrencyRateCheck); } -export function getNames(state) { - return state.metamask.NameController.names || {}; +export function getNames(state: MetaMaskReduxState) { + return state.metamask.NameController.names ?? {}; } -export function getEthereumAddressNames(state) { - return state.metamask.NameController.names?.[NameType.ETHEREUM_ADDRESS] || {}; +export function getEthereumAddressNames(state: MetaMaskReduxState) { + return state.metamask.NameController.names?.[NameType.ETHEREUM_ADDRESS] ?? {}; } -export function getNameSources(state) { - return state.metamask.NameController.nameSources || {}; +export function getNameSources(state: MetaMaskReduxState) { + return state.metamask.NameController.nameSources ?? {}; } -export function getShowDeleteMetaMetricsDataModal(state) { +export function getShowDeleteMetaMetricsDataModal(state: MetaMaskReduxState) { return state.appState.showDeleteMetaMetricsDataModal; } -export function getShowDataDeletionErrorModal(state) { +export function getShowDataDeletionErrorModal(state: MetaMaskReduxState) { return state.appState.showDataDeletionErrorModal; } -export function getMetaMetricsDataDeletionId(state) { - return state.metamask.MetaMetricsDataDeletionController.Id; +export function getMetaMetricsDataDeletionId(state: MetaMaskReduxState) { + return state.metamask.MetaMetricsDataDeletionController + .metaMetricsDataDeletionId; } -export function getMetaMetricsDataDeletionTimestamp(state) { - return state.metamask.MetaMetricsDataDeletionController.Timestamp; +export function getMetaMetricsDataDeletionTimestamp(state: MetaMaskReduxState) { + return state.metamask.MetaMetricsDataDeletionController + .metaMetricsDataDeletionTimestamp; } -export function getMetaMetricsDataDeletionStatus(state) { +export function getMetaMetricsDataDeletionStatus(state: MetaMaskReduxState) { return state.metamask.MetaMetricsDataDeletionController .metaMetricsDataDeletionStatus; } -export function getRemoteFeatureFlags(state) { +export function getRemoteFeatureFlags(state: MetaMaskReduxState) { return state.metamask.RemoteFeatureFlagController.remoteFeatureFlags; } @@ -2925,7 +3042,7 @@ export function getRemoteFeatureFlags(state) { * @param {*} state * @returns Boolean */ -export function getSnapsList(state) { +export function getSnapsList(state: MetaMaskReduxState) { const snaps = getSnaps(state); return Object.entries(snaps) .filter(([_key, snap]) => { @@ -2960,7 +3077,7 @@ export function getSnapsList(state) { * @param state - Redux state object. * @returns True if popover has been shown, false otherwise. */ -export function getSnapsInstallPrivacyWarningShown(state) { +export function getSnapsInstallPrivacyWarningShown(state: MetaMaskReduxState) { const { snapsInstallPrivacyWarningShown } = state.metamask.AppStateController; if ( @@ -2974,19 +3091,21 @@ export function getSnapsInstallPrivacyWarningShown(state) { } ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) -export function getsnapsAddSnapAccountModalDismissed(state) { +export function getsnapsAddSnapAccountModalDismissed( + state: MetaMaskReduxState, +) { const { snapsAddSnapAccountModalDismissed } = state.metamask.PreferencesController; return snapsAddSnapAccountModalDismissed; } -export function getSnapRegistry(state) { +export function getSnapRegistry(state: MetaMaskReduxState) { const { snapRegistryList } = state.metamask.PreferencesController; return snapRegistryList; } -export function getKeyringSnapAccounts(state) { +export function getKeyringSnapAccounts(state: MetaMaskReduxState) { const internalAccounts = getInternalAccounts(state); const keyringAccounts = Object.values(internalAccounts).filter( @@ -2998,10 +3117,11 @@ export function getKeyringSnapAccounts(state) { return keyringAccounts; } -export function getKeyringSnapRemovalResult(state) { +export function getKeyringSnapRemovalResult(state: MetaMaskReduxState) { return state.appState.keyringRemovalSnapModal; } ///: END:ONLY_INCLUDE_IF -export const getPendingTokens = (state) => state.appState.pendingTokens; +export const getPendingTokens = (state: MetaMaskReduxState) => + state.appState.pendingTokens;