From 68b0a52c882baf31a6d988a937b62dcebb036ef6 Mon Sep 17 00:00:00 2001 From: Jongsun Suh Date: Thu, 30 Jan 2025 12:48:23 -0500 Subject: [PATCH] stash --- .../controllers/metametrics-controller.ts | 179 ++---- app/scripts/metamask-controller.js | 2 +- ui/ducks/background/background.ts | 597 +----------------- ui/ducks/background/constants.ts | 230 +++---- 4 files changed, 176 insertions(+), 832 deletions(-) diff --git a/app/scripts/controllers/metametrics-controller.ts b/app/scripts/controllers/metametrics-controller.ts index 9668a9f25b09..093b95000bce 100644 --- a/app/scripts/controllers/metametrics-controller.ts +++ b/app/scripts/controllers/metametrics-controller.ts @@ -10,8 +10,7 @@ import { } from 'lodash'; import { bufferToHex, keccak } from 'ethereumjs-util'; import { v4 as uuidv4 } from 'uuid'; -import { NameControllerState, NameType } from '@metamask/name-controller'; -import { AccountsControllerState } from '@metamask/accounts-controller'; +import { NameType } from '@metamask/name-controller'; import { getErrorMessage, Hex, @@ -23,14 +22,9 @@ import { NetworkControllerGetNetworkClientByIdAction, NetworkControllerGetStateAction, NetworkControllerNetworkDidChangeEvent, - NetworkState, } from '@metamask/network-controller'; import { Browser } from 'webextension-polyfill'; -import { - Nft, - NftControllerState, - TokensControllerState, -} from '@metamask/assets-controllers'; +import { Nft } from '@metamask/assets-controllers'; import { captureException as sentryCaptureException } from '@sentry/browser'; import { BaseController, @@ -38,7 +32,6 @@ import { ControllerStateChangeEvent, RestrictedControllerMessenger, } from '@metamask/base-controller'; -import { AddressBookControllerState } from '@metamask/address-book-controller'; import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app'; import { METAMETRICS_ANONYMOUS_ID, @@ -65,13 +58,13 @@ import { AnonymousTransactionMetaMetricsEvent, TransactionMetaMetricsEvent, } from '../../../shared/constants/transaction'; -import { LedgerTransportTypes } from '../../../shared/constants/hardware-wallets'; import Analytics from '../lib/segment/analytics'; ///: BEGIN:ONLY_INCLUDE_IF(build-main) import { ENVIRONMENT } from '../../../development/build/constants'; ///: END:ONLY_INCLUDE_IF +import { BackgroundStateProxy } from '../../../shared/types/background'; import type { PreferencesControllerState, PreferencesControllerGetStateAction, @@ -144,39 +137,6 @@ const exceptionsToFilter: Record = { */ type SegmentEventType = 'identify' | 'track' | 'page'; -// TODO: Complete MetaMaskState by adding the full state definition and relocate it after the background is converted to TypeScript. -export type MetaMaskState = { - ledgerTransportType: LedgerTransportTypes; - networkConfigurationsByChainId: NetworkState['networkConfigurationsByChainId']; - internalAccounts: AccountsControllerState['internalAccounts']; - allNfts: NftControllerState['allNfts']; - allTokens: TokensControllerState['allTokens']; - theme: string; - participateInMetaMetrics: boolean; - dataCollectionForMarketing: boolean; - ShowNativeTokenAsMainBalance: boolean; - useNftDetection: PreferencesControllerState['useNftDetection']; - openSeaEnabled: PreferencesControllerState['openSeaEnabled']; - securityAlertsEnabled: PreferencesControllerState['securityAlertsEnabled']; - useTokenDetection: PreferencesControllerState['useTokenDetection']; - tokenSortConfig: PreferencesControllerState['preferences']['tokenSortConfig']; - names: NameControllerState['names']; - security_providers: string[]; - addressBook: AddressBookControllerState['addressBook']; - currentCurrency: string; - preferences: { - privacyMode: PreferencesControllerState['preferences']['privacyMode']; - tokenNetworkFilter: string[]; - }; - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - custodyAccountDetails: { - [address: string]: { - custodianName: string; - }; - }; - ///: END:ONLY_INCLUDE_IF -}; - /** * {@link MetaMetricsController}'s metadata. * @@ -358,10 +318,6 @@ export default class MetaMetricsController extends BaseController< #environment: MetaMetricsControllerOptions['environment']; - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - #selectedAddress: PreferencesControllerState['selectedAddress']; - ///: END:ONLY_INCLUDE_IF - #segment: MetaMetricsControllerOptions['segment']; /** @@ -412,10 +368,6 @@ export default class MetaMetricsController extends BaseController< this.#extension = extension; this.#environment = environment; - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - this.#selectedAddress = preferencesControllerState.selectedAddress; - ///: END:ONLY_INCLUDE_IF - const abandonedFragments = omitBy(state.fragments, 'persist'); this.messagingSystem.subscribe( @@ -584,6 +536,7 @@ export default class MetaMetricsController extends BaseController< : {}; this.update((state) => { + // @ts-expect-error TODO: Fix `Type instantiation is excessively deep and possibly infinite.ts(2589)` state.fragments[id] = merge({}, additionalFragmentProps, fragment); }); @@ -1004,7 +957,7 @@ export default class MetaMetricsController extends BaseController< } } - handleMetaMaskStateUpdate(newState: MetaMaskState): void { + handleMetaMaskStateUpdate(newState: BackgroundStateProxy): void { const userTraits = this._buildUserTraitsObject(newState); if (userTraits) { this.identify(userTraits); @@ -1067,23 +1020,10 @@ export default class MetaMetricsController extends BaseController< referrer: MetaMetricsContext['referrer'], page: MetaMetricsContext['page'] = METAMETRICS_BACKGROUND_PAGE_OBJECT, ): MetaMetricsContext { - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - const mmiProps: { - extensionId?: string; - } = {}; - - if (this.#extension?.runtime?.id) { - mmiProps.extensionId = this.#extension.runtime.id; - } - ///: END:ONLY_INCLUDE_IF - return { app: { name: 'MetaMask Extension', version: this.version, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - ...mmiProps, - ///: END:ONLY_INCLUDE_IF }, userAgent: window.navigator.userAgent, page, @@ -1115,21 +1055,6 @@ export default class MetaMetricsController extends BaseController< environmentType = ENVIRONMENT_TYPE_BACKGROUND, } = rawPayload; - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - const mmiProps: { - extensionId?: string; - accountAddress?: string; - } = {}; - - if (this.#extension?.runtime?.id) { - mmiProps.extensionId = this.#extension.runtime.id; - } - - if (this.#selectedAddress) { - mmiProps.accountAddress = this.#selectedAddress; - } - ///: END:ONLY_INCLUDE_IF - return { event, messageId: buildUniqueMessageId(rawPayload), @@ -1153,9 +1078,6 @@ export default class MetaMetricsController extends BaseController< ? properties.chain_id : this.chainId, environment_type: environmentType, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - ...mmiProps, - ///: END:ONLY_INCLUDE_IF }, context: this.#buildContext(referrer, page), }; @@ -1169,73 +1091,73 @@ export default class MetaMetricsController extends BaseController< * @returns traits that have changed since last update */ _buildUserTraitsObject( - metamaskState: MetaMaskState, + metamaskState: BackgroundStateProxy, ): Partial | null { - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - const mmiAccountAddress = - metamaskState.custodyAccountDetails && - Object.keys(metamaskState.custodyAccountDetails).length - ? Object.keys(metamaskState.custodyAccountDetails)[0] - : null; - ///: END:ONLY_INCLUDE_IF const { traits, previousUserTraits } = this.state; const currentTraits = { [MetaMetricsUserTrait.AddressBookEntries]: sum( - Object.values(metamaskState.addressBook).map(size), + Object.values(metamaskState.AddressBookController.addressBook).map( + size, + ), ), [MetaMetricsUserTrait.InstallDateExt]: traits[MetaMetricsUserTrait.InstallDateExt] || '', [MetaMetricsUserTrait.LedgerConnectionType]: - metamaskState.ledgerTransportType, + metamaskState.PreferencesController.ledgerTransportType, [MetaMetricsUserTrait.NetworksAdded]: Object.values( - metamaskState.networkConfigurationsByChainId, + metamaskState.NetworkController.networkConfigurationsByChainId, ).map((networkConfiguration) => networkConfiguration.chainId), [MetaMetricsUserTrait.NetworksWithoutTicker]: Object.values( - metamaskState.networkConfigurationsByChainId, + metamaskState.NetworkController.networkConfigurationsByChainId, ) .filter(({ nativeCurrency }) => !nativeCurrency) .map(({ chainId }) => chainId), [MetaMetricsUserTrait.NftAutodetectionEnabled]: - metamaskState.useNftDetection, + metamaskState.PreferencesController.useNftDetection, [MetaMetricsUserTrait.NumberOfAccounts]: Object.values( - metamaskState.internalAccounts.accounts, + metamaskState.AccountsController.internalAccounts.accounts, ).length, [MetaMetricsUserTrait.NumberOfNftCollections]: - this.#getAllUniqueNFTAddressesLength(metamaskState.allNfts), + this.#getAllUniqueNFTAddressesLength( + metamaskState.NftController.allNfts, + ), [MetaMetricsUserTrait.NumberOfNfts]: this.#getAllNFTsFlattened( - metamaskState.allNfts, + metamaskState.NftController.allNfts, ).length, [MetaMetricsUserTrait.NumberOfTokens]: this.#getNumberOfTokens( - metamaskState.allTokens, + metamaskState.TokensController.allTokens, ), - [MetaMetricsUserTrait.OpenSeaApiEnabled]: metamaskState.openSeaEnabled, + [MetaMetricsUserTrait.OpenSeaApiEnabled]: + metamaskState.PreferencesController.openSeaEnabled, [MetaMetricsUserTrait.ThreeBoxEnabled]: false, // deprecated, hard-coded as false - [MetaMetricsUserTrait.Theme]: metamaskState.theme || 'default', + [MetaMetricsUserTrait.Theme]: + metamaskState.PreferencesController.theme || 'default', [MetaMetricsUserTrait.TokenDetectionEnabled]: - metamaskState.useTokenDetection, + metamaskState.PreferencesController.useTokenDetection, [MetaMetricsUserTrait.ShowNativeTokenAsMainBalance]: - metamaskState.ShowNativeTokenAsMainBalance, - [MetaMetricsUserTrait.CurrentCurrency]: metamaskState.currentCurrency, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - [MetaMetricsUserTrait.MmiExtensionId]: this.#extension?.runtime?.id, - [MetaMetricsUserTrait.MmiAccountAddress]: mmiAccountAddress ?? null, - [MetaMetricsUserTrait.MmiIsCustodian]: Boolean(mmiAccountAddress), - ///: END:ONLY_INCLUDE_IF - [MetaMetricsUserTrait.SecurityProviders]: - metamaskState.securityAlertsEnabled ? ['blockaid'] : [], + metamaskState.PreferencesController.preferences + ?.showNativeTokenAsMainBalance, + [MetaMetricsUserTrait.CurrentCurrency]: + metamaskState.CurrencyController.currentCurrency, + [MetaMetricsUserTrait.SecurityProviders]: metamaskState + .PreferencesController.securityAlertsEnabled + ? ['blockaid'] + : [], [MetaMetricsUserTrait.PetnameAddressCount]: this.#getPetnameAddressCount(metamaskState), [MetaMetricsUserTrait.IsMetricsOptedIn]: - metamaskState.participateInMetaMetrics, + metamaskState.MetaMetricsController.participateInMetaMetrics, [MetaMetricsUserTrait.HasMarketingConsent]: - metamaskState.dataCollectionForMarketing, + metamaskState.MetaMetricsController.dataCollectionForMarketing, [MetaMetricsUserTrait.TokenSortPreference]: - metamaskState.tokenSortConfig?.key || '', + metamaskState.PreferencesController.preferences?.tokenSortConfig?.key || + '', [MetaMetricsUserTrait.PrivacyModeEnabled]: - metamaskState.preferences.privacyMode, + metamaskState.PreferencesController.preferences?.privacyMode, [MetaMetricsUserTrait.NetworkFilterPreference]: Object.keys( - metamaskState.preferences.tokenNetworkFilter || {}, + metamaskState.PreferencesController.preferences?.tokenNetworkFilter || + {}, ), }; @@ -1299,11 +1221,13 @@ export default class MetaMetricsController extends BaseController< * * @param allNfts */ - #getAllNFTsFlattened = memoize((allNfts: MetaMaskState['allNfts'] = {}) => { - return Object.values(allNfts).reduce((result: Nft[], chainNFTs) => { - return result.concat(...Object.values(chainNFTs)); - }, []); - }); + #getAllNFTsFlattened = memoize( + (allNfts: BackgroundStateProxy['NftController']['allNfts'] = {}) => { + return Object.values(allNfts).reduce((result: Nft[], chainNFTs) => { + return result.concat(...Object.values(chainNFTs)); + }, []); + }, + ); /** * Returns the number of unique NFT addresses the user @@ -1312,7 +1236,7 @@ export default class MetaMetricsController extends BaseController< * @param allNfts */ #getAllUniqueNFTAddressesLength( - allNfts: MetaMaskState['allNfts'] = {}, + allNfts: BackgroundStateProxy['NftController']['allNfts'] = {}, ): number { const allNFTAddresses = this.#getAllNFTsFlattened(allNfts).map( (nft) => nft.address, @@ -1325,7 +1249,9 @@ export default class MetaMetricsController extends BaseController< * @param allTokens * @returns number of unique token addresses */ - #getNumberOfTokens(allTokens: MetaMaskState['allTokens']): number { + #getNumberOfTokens( + allTokens: BackgroundStateProxy['TokensController']['allTokens'], + ): number { return Object.values(allTokens).reduce((result, accountsByChain) => { return result + sum(Object.values(accountsByChain).map(size)); }, 0); @@ -1549,8 +1475,9 @@ export default class MetaMetricsController extends BaseController< * * @param metamaskState */ - #getPetnameAddressCount(metamaskState: MetaMaskState): number { - const addressNames = metamaskState.names?.[NameType.ETHEREUM_ADDRESS] ?? {}; + #getPetnameAddressCount(metamaskState: BackgroundStateProxy): number { + const addressNames = + metamaskState.NameController.names?.[NameType.ETHEREUM_ADDRESS] ?? {}; return Object.keys(addressNames).reduce((totalCount, address) => { const addressEntry = addressNames[address]; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index afc60f585b57..8b293f4fdab4 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3279,7 +3279,7 @@ export default class MetamaskController extends EventEmitter { const updatePublicConfigStore = async (memState) => { const networkStatus = - memState.networksMetadata[memState.selectedNetworkClientId]?.status; + memState.networksMetadata?.[memState.selectedNetworkClientId]?.status; if (networkStatus === NetworkStatus.Available) { publicConfigStore.putState(await selectPublicState(memState)); } diff --git a/ui/ducks/background/background.ts b/ui/ducks/background/background.ts index c92c29eba076..c3fea8cbd856 100644 --- a/ui/ducks/background/background.ts +++ b/ui/ducks/background/background.ts @@ -1,41 +1,11 @@ /* eslint-disable jsdoc/require-param */ -import { addHexPrefix, isHexString } from 'ethereumjs-util'; -import type { AnyAction, Dispatch } from 'redux'; -import { createSelector } from 'reselect'; -import { - mergeGasFeeEstimates, - TransactionMeta, - TransactionParams, -} from '@metamask/transaction-controller'; -import { Hex } from '@metamask/utils'; -import { AlertTypes } from '../../../shared/constants/alerts'; -import { - GasEstimateTypes, - NetworkCongestionThresholds, -} from '../../../shared/constants/gas'; -import { KeyringType } from '../../../shared/constants/keyring'; -import { decGWEIToHexWEI } from '../../../shared/modules/conversion.utils'; -import { stripHexPrefix } from '../../../shared/modules/hexstring-utils'; -import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; -import { - accountsWithSendEtherInfoSelector, - checkNetworkAndAccountSupports1559, - getAddressBook, -} from '../../selectors/selectors'; -import { - getProviderConfig, - getSelectedNetworkClientId, -} from '../../../shared/modules/selectors/networks'; -import { getSelectedInternalAccount } from '../../selectors/accounts'; +import type { AnyAction } from 'redux'; import * as actionConstants from '../../store/actionConstants'; -import { updateTransactionGasFees } from '../../store/actions'; -import { setCustomGasLimit, setCustomGasPrice } from '../gas/gas.duck'; -import { MetaMaskReduxState } from '../../store/store'; import { BackgroundStateProxy } from '../../../shared/types/background'; import { initialBackgroundState } from './constants'; export type BackgroundSliceState = { - background: BackgroundStateProxy + background: BackgroundStateProxy; }; /** @@ -47,571 +17,18 @@ export type BackgroundSliceState = { * @returns */ export default function reduceBackground( - state: BackgroundSliceState, + state: BackgroundSliceState['background'], action: AnyAction, ): BackgroundStateProxy { - // I don't think we should be spreading initialMetamaskState into this. Once the - // state tree has begun by way of the first reduce call the initialMetamaskState is - // set. The only time it should be used again is if we reset the state with a - // deliberate action. However, our tests are *relying upon the initialState - // tree above to be spread into the reducer as a way of hydrating the state - // for this slice*. I attempted to remove this and it caused nearly 40 test - // failures. We are going to refactor this slice anyways, possibly removing - // it so we will fix this issue when that time comes. - const backgroundState = { ...initialBackgroundState, ...state.background }; + const backgroundState = { + ...initialBackgroundState, + ...state, + }; switch (action.type) { case actionConstants.UPDATE_METAMASK_STATE: return { ...backgroundState, ...action.value }; - case actionConstants.LOCK_METAMASK: - return { - ...backgroundState, - KeyringController: { - ...backgroundState.KeyringController, - isUnlocked: false, - }, - }; - - case actionConstants.SET_ACCOUNT_LABEL: { - const { account } = action.value; - const name = action.value.label; - const accountToUpdate = Object.values( - backgroundState.AccountsController.internalAccounts.accounts, - ).find((internalAccount) => { - return internalAccount.address.toLowerCase() === account.toLowerCase(); - }); - if (!accountToUpdate) { - return backgroundState; - } - - const internalAccounts = { - ...backgroundState.AccountsController.internalAccounts, - accounts: { - ...backgroundState.AccountsController.internalAccounts.accounts, - [accountToUpdate.id]: { - ...accountToUpdate, - metadata: { - ...accountToUpdate.metadata, - name, - }, - }, - }, - }; - return Object.assign(backgroundState, { internalAccounts }); - } - - case actionConstants.UPDATE_TRANSACTION_PARAMS: { - const { id: txId, value } = action; - let { transactions } = backgroundState.TxController ?? {}; - transactions = transactions?.map((tx) => { - if (tx.id === txId) { - const newTx = { ...tx }; - newTx.txParams = value; - return newTx; - } - return tx; - }); - - return { - ...backgroundState, - TxController: { ...backgroundState.TxController, transactions }, - }; - } - - case actionConstants.SET_PARTICIPATE_IN_METAMETRICS: - return { - ...backgroundState, - MetaMetricsController: { - ...backgroundState.MetaMetricsController, - participateInMetaMetrics: action.value, - }, - }; - - case actionConstants.SET_DATA_COLLECTION_FOR_MARKETING: - return { - ...backgroundState, - MetaMetricsController: { - ...backgroundState.MetaMetricsController, - dataCollectionForMarketing: action.value, - }, - }; - - case actionConstants.COMPLETE_ONBOARDING: { - return { - ...backgroundState, - OnboardingController: { - ...backgroundState.OnboardingController, - completedOnboarding: true, - }, - }; - } - - case actionConstants.RESET_ONBOARDING: { - return { - ...backgroundState, - isInitialized: false, - OnboardingController: { - ...backgroundState.OnboardingController, - completedOnboarding: false, - firstTimeFlowType: null, - onboardingTabs: {}, - seedPhraseBackedUp: null, - }, - KeyringController: { - ...backgroundState.KeyringController, - isUnlocked: false, - }, - }; - } - - case actionConstants.SET_FIRST_TIME_FLOW_TYPE: { - return { - ...backgroundState, - OnboardingController: { - ...backgroundState.OnboardingController, - firstTimeFlowType: action.value, - }, - }; - } - default: return backgroundState; } } - -const toHexWei = (value: string, expectHexWei: boolean) => { - return addHexPrefix(expectHexWei ? value : decGWEIToHexWEI(value)); -}; - -type UpdateGasFeeOptions = Required< - Pick< - TransactionParams, - 'gasPrice' | 'gasLimit' | 'maxPriorityFeePerGas' | 'maxFeePerGas' - > -> & { - transaction: TransactionMeta; - expectHexWei: boolean; -}; - -// Action Creators -export function updateGasFees({ - gasPrice, - gasLimit, - maxPriorityFeePerGas, - maxFeePerGas, - transaction, - expectHexWei = false, -}: UpdateGasFeeOptions) { - return async (dispatch: Dispatch) => { - const txParamsCopy = { ...transaction.txParams, gas: gasLimit }; - if (gasPrice && txParamsCopy.gasPrice) { - dispatch( - setCustomGasPrice(toHexWei(txParamsCopy.gasPrice, expectHexWei)), - ); - txParamsCopy.gasPrice = toHexWei(gasPrice, expectHexWei); - } else if (maxFeePerGas && maxPriorityFeePerGas) { - txParamsCopy.maxFeePerGas = toHexWei(maxFeePerGas, expectHexWei); - txParamsCopy.maxPriorityFeePerGas = addHexPrefix( - decGWEIToHexWEI(maxPriorityFeePerGas), - ); - } - const updatedTx = { - ...transaction, - txParams: txParamsCopy, - }; - - const customGasLimit = isHexString(addHexPrefix(gasLimit)) - ? addHexPrefix(gasLimit) - : addHexPrefix(gasLimit.toString()); - dispatch(setCustomGasLimit(customGasLimit)); - await dispatch( - // TODO: Fix type for ThunkAction involving async background update - updateTransactionGasFees(updatedTx.id, updatedTx) as unknown as AnyAction, - ); - }; -} - -// Selectors - -export const getAlertEnabledness = (state: BackgroundSliceState) => - state.background.AlertController.alertEnabledness; - -export const getUnconnectedAccountAlertEnabledness = ( - state: BackgroundSliceState, -) => getAlertEnabledness(state)[AlertTypes.unconnectedAccount]; - -export const getWeb3ShimUsageAlertEnabledness = (state: BackgroundSliceState) => - getAlertEnabledness(state)[AlertTypes.web3ShimUsage]; - -export const getUnconnectedAccountAlertShown = (state: BackgroundSliceState) => - state.background.AlertController.unconnectedAccountAlertShownOrigins; - -export const getTokens = (state: BackgroundSliceState) => - state.background.TokensController.tokens; - -export function getNftsDropdownState(state: BackgroundSliceState) { - return state.background.AppStateController.nftsDropdownState; -} - -export const getNfts = (state: BackgroundSliceState) => { - const { - background: { - NftController: { allNfts }, - }, - } = state; - const { address: selectedAddress } = getSelectedInternalAccount(state); - - const { chainId } = getProviderConfig(state); - - return allNfts?.[selectedAddress]?.[chainId] ?? []; -}; - -export const getNFTsByChainId = (state: BackgroundSliceState, chainId: Hex) => { - const { - background: { - NftController: { allNfts }, - }, - } = state; - const { address: selectedAddress } = getSelectedInternalAccount(state); - - return allNfts?.[selectedAddress]?.[chainId] ?? []; -}; - -export const getNftContracts = (state: BackgroundSliceState) => { - const { - background: { - NftController: { allNftContracts }, - }, - } = state; - const { address: selectedAddress } = getSelectedInternalAccount(state); - const { chainId } = getProviderConfig(state); - return allNftContracts?.[selectedAddress]?.[chainId]; -}; - -export function getBlockGasLimit(state: BackgroundSliceState) { - return state.background.AccountTracker.currentBlockGasLimit; -} - -export function getNativeCurrency(state: BackgroundSliceState) { - return getProviderConfig(state).ticker; -} - -export function getConversionRate(state: BackgroundSliceState) { - return state.background.CurrencyController.currencyRates[ - getProviderConfig(state).ticker - ]?.conversionRate; -} - -export function getCurrencyRates(state: BackgroundSliceState) { - return state.background.CurrencyController.currencyRates; -} - -export function getSendHexDataFeatureFlagState(state: BackgroundSliceState) { - return state.background.PreferencesController.featureFlags.sendHexData; -} - -export function getSendToAccounts(state: BackgroundSliceState) { - const fromAccounts = accountsWithSendEtherInfoSelector(state); - const addressBookAccounts = getAddressBook(state); - return [...fromAccounts, ...addressBookAccounts]; -} - -/** - * Function returns true if network details are fetched and it is found to not support EIP-1559 - * - * @param state - */ -export function isNotEIP1559Network(state: BackgroundSliceState) { - const selectedNetworkClientId = getSelectedNetworkClientId(state); - return ( - state.background.NetworkController.networksMetadata[selectedNetworkClientId] - .EIPS[1559] === false - ); -} - -/** - * Function returns true if network details are fetched and it is found to support EIP-1559 - * - * @param state - * @param networkClientId - The optional network client ID to check for EIP-1559 support. Defaults to the currently selected network. - */ -export function isEIP1559Network( - state: BackgroundSliceState, - networkClientId: string, -) { - const selectedNetworkClientId = getSelectedNetworkClientId(state); - - return ( - state.background.NetworkController.networksMetadata?.[ - networkClientId ?? selectedNetworkClientId - ]?.EIPS[1559] === true - ); -} - -function getGasFeeControllerEstimateType(state: BackgroundSliceState) { - return state.background.GasFeeController.gasEstimateType; -} - -function getGasFeeControllerEstimateTypeByChainId( - state: BackgroundSliceState, - chainId: Hex, -) { - return state.background.GasFeeController.gasFeeEstimatesByChainId?.[chainId] - ?.gasEstimateType; -} - -function getGasFeeControllerEstimates(state: BackgroundSliceState) { - return state.background.GasFeeController.gasFeeEstimates; -} - -function getGasFeeControllerEstimatesByChainId( - state: BackgroundSliceState, - chainId: Hex, -) { - return ( - state.background.GasFeeController.gasFeeEstimatesByChainId?.[chainId] - ?.gasFeeEstimates ?? {} - ); -} - -function getTransactionGasFeeEstimates( - state: BackgroundSliceState & Pick, -) { - const transactionMetadata = state.confirmTransaction?.txData; - return transactionMetadata?.gasFeeEstimates; -} - -function getTransactionGasFeeEstimatesByChainId( - state: BackgroundSliceState & Pick, - chainId: Hex, -) { - const transactionMetadata = state.confirmTransaction?.txData; - const transactionChainId = transactionMetadata?.chainId; - - if (transactionChainId !== chainId) { - return undefined; - } - - return transactionMetadata?.gasFeeEstimates; -} - -const getTransactionGasFeeEstimateType = createSelector( - getTransactionGasFeeEstimates, - (transactionGasFeeEstimates) => transactionGasFeeEstimates?.type, -); - -const getTransactionGasFeeEstimateTypeByChainId = createSelector( - getTransactionGasFeeEstimatesByChainId, - (transactionGasFeeEstimates) => transactionGasFeeEstimates?.type, -); - -export const getGasEstimateType = createSelector( - getGasFeeControllerEstimateType, - getTransactionGasFeeEstimateType, - (gasFeeControllerEstimateType, transactionGasFeeEstimateType) => { - return transactionGasFeeEstimateType ?? gasFeeControllerEstimateType; - }, -); - -export const getGasEstimateTypeByChainId = createSelector( - getGasFeeControllerEstimateTypeByChainId, - getTransactionGasFeeEstimateTypeByChainId, - (gasFeeControllerEstimateType, transactionGasFeeEstimateType) => { - return transactionGasFeeEstimateType ?? gasFeeControllerEstimateType; - }, -); - -/** - * @param state - * @returns The balances of imported and detected tokens across all accounts and chains. - */ -export function getTokenBalances(state: BackgroundSliceState) { - return state.background.TokenBalancesController.tokenBalances; -} - -export const getGasFeeEstimatesByChainId = createSelector( - getGasFeeControllerEstimatesByChainId, - getTransactionGasFeeEstimatesByChainId, - (gasFeeControllerEstimates, transactionGasFeeEstimates) => { - if (transactionGasFeeEstimates) { - return mergeGasFeeEstimates({ - // TODO: Explicitly handle case where there are no gas fee estimates. - gasFeeControllerEstimates: gasFeeControllerEstimates as Exclude< - ReturnType, - Record - >, - transactionGasFeeEstimates, - }); - } - - return gasFeeControllerEstimates; - }, -); - -export const getGasFeeEstimates = createSelector( - getGasFeeControllerEstimates, - getTransactionGasFeeEstimates, - (gasFeeControllerEstimates, transactionGasFeeEstimates) => { - if (transactionGasFeeEstimates) { - return mergeGasFeeEstimates({ - // TODO: Explicitly handle case where there are no gas fee estimates. - gasFeeControllerEstimates: gasFeeControllerEstimates as Exclude< - ReturnType, - Record - >, - transactionGasFeeEstimates, - }); - } - - return gasFeeControllerEstimates; - }, -); - -export function getEstimatedGasFeeTimeBounds(state: BackgroundSliceState) { - return state.background.GasFeeController.estimatedGasFeeTimeBounds; -} - -export function getEstimatedGasFeeTimeBoundsByChainId( - state: BackgroundSliceState, - chainId: Hex, -) { - return state.background.GasFeeController.gasFeeEstimatesByChainId?.[chainId] - ?.estimatedGasFeeTimeBounds; -} - -export function getIsGasEstimatesLoading( - state: BackgroundSliceState & Pick, -) { - const networkAndAccountSupports1559 = - checkNetworkAndAccountSupports1559(state); - const gasEstimateType = getGasEstimateType(state); - - // We consider the gas estimate to be loading if the gasEstimateType is - // 'NONE' or if the current gasEstimateType cannot be supported by the current - // network - const isEIP1559TolerableEstimateType = - gasEstimateType === GasEstimateTypes.feeMarket || - gasEstimateType === GasEstimateTypes.ethGasPrice; - const isGasEstimatesLoading = - gasEstimateType === GasEstimateTypes.none || - (networkAndAccountSupports1559 && !isEIP1559TolerableEstimateType) || - (!networkAndAccountSupports1559 && - gasEstimateType === GasEstimateTypes.feeMarket); - - return isGasEstimatesLoading; -} - -export function getIsGasEstimatesLoadingByChainId( - state: BackgroundSliceState & Pick, - { chainId, networkClientId }: { chainId: Hex; networkClientId: string }, -) { - const networkAndAccountSupports1559 = checkNetworkAndAccountSupports1559( - state, - networkClientId, - ); - const gasEstimateType = getGasEstimateTypeByChainId(state, chainId); - - // We consider the gas estimate to be loading if the gasEstimateType is - // 'NONE' or if the current gasEstimateType cannot be supported by the current - // network - const isEIP1559TolerableEstimateType = - gasEstimateType === GasEstimateTypes.feeMarket || - gasEstimateType === GasEstimateTypes.ethGasPrice; - const isGasEstimatesLoading = - gasEstimateType === GasEstimateTypes.none || - (networkAndAccountSupports1559 && !isEIP1559TolerableEstimateType) || - (!networkAndAccountSupports1559 && - gasEstimateType === GasEstimateTypes.feeMarket); - - return isGasEstimatesLoading; -} - -export function getIsNetworkBusyByChainId( - state: BackgroundSliceState & Pick, - chainId: Hex, -) { - const gasFeeEstimates = getGasFeeEstimatesByChainId(state, chainId); - return 'networkCongestion' in gasFeeEstimates - ? (gasFeeEstimates?.networkCongestion ?? 0) >= - NetworkCongestionThresholds.busy - : false; -} - -export function getCompletedOnboarding(state: BackgroundSliceState) { - return state.background.OnboardingController.completedOnboarding; -} -export function getIsInitialized(state: BackgroundSliceState) { - return state.background.isInitialized; -} - -export function getIsUnlocked(state: BackgroundSliceState) { - return state.background.KeyringController.isUnlocked; -} - -export function getSeedPhraseBackedUp(state: BackgroundSliceState) { - return state.background.OnboardingController.seedPhraseBackedUp; -} - -/** - * Given the redux state object and an address, finds a keyring that contains that address, if one exists - * - * @param state - the redux state object - * @param address - the address to search for among the keyring addresses - * @returns The keyring which contains the passed address, or undefined - */ -export function findKeyringForAddress( - state: BackgroundSliceState, - address: string, -) { - const keyring = state.background.KeyringController.keyrings.find((kr) => { - return kr.accounts.some((account) => { - return ( - isEqualCaseInsensitive(account, addHexPrefix(address)) || - isEqualCaseInsensitive(account, stripHexPrefix(address)) - ); - }); - }); - - return keyring; -} - -/** - * Given the redux state object, returns the users preferred ledger transport type - * - * @param state - the redux state object - * @returns The user's preferred ledger transport type as a string. One of 'webhid' on chrome or 'u2f' on firefox - */ -export function getLedgerTransportType(state: BackgroundSliceState) { - return state.background.PreferencesController.ledgerTransportType; -} - -/** - * Given the redux state object and an address, returns a boolean indicating whether the passed address is part of a Ledger keyring - * - * @param state - the redux state object - * @param address - the address to search for among all keyring addresses - * @returns 'true' if the passed address is part of a ledger keyring, and 'false' otherwise - */ -export function isAddressLedger(state: BackgroundSliceState, address: string) { - const keyring = findKeyringForAddress(state, address); - - return keyring?.type === KeyringType.ledger; -} - -/** - * Given the redux state object, returns a boolean indicating whether the user has any Ledger accounts added to MetaMask (i.e. Ledger keyrings - * in state) - * - * @param state - the redux state object - * @param state.background - * @returns true if the user has a Ledger account and false otherwise - */ -export function doesUserHaveALedgerAccount(state: BackgroundSliceState) { - return state.background.KeyringController.keyrings.some((kr) => { - return kr.type === KeyringType.ledger; - }); -} - -export function getCurrentCurrency(state) { - return state.background.currentCurrency; -} diff --git a/ui/ducks/background/constants.ts b/ui/ducks/background/constants.ts index 7fafa3845f72..a2a97546acb2 100644 --- a/ui/ducks/background/constants.ts +++ b/ui/ducks/background/constants.ts @@ -1,16 +1,16 @@ -import { NameType } from '@metamask/name-controller'; +// import { NameType } from '@metamask/name-controller'; // TODO: Replace with import from `@metamask/preferences-controller` once migration to core repo is complete. // eslint-disable-next-line import/no-restricted-paths -import { getDefaultPreferencesControllerState } from '../../../app/scripts/controllers/preferences-controller'; +// import { getDefaultPreferencesControllerState } from '../../../app/scripts/controllers/preferences-controller'; import type { BackgroundStateProxy, MemStoreControllersComposedState, } from '../../../shared/types/background'; -import { - DEFAULT_AUTO_LOCK_TIME_LIMIT, - ThemeType, -} from '../../../shared/constants/preferences'; -import { LedgerTransportTypes } from '../../../shared/constants/hardware-wallets'; +// import { +// DEFAULT_AUTO_LOCK_TIME_LIMIT, +// ThemeType, +// } from '../../../shared/constants/preferences'; +// import { LedgerTransportTypes } from '../../../shared/constants/hardware-wallets'; export const initialBackgroundState: Omit< BackgroundStateProxy, @@ -22,112 +22,112 @@ export const initialBackgroundState: Omit< >; }> = { isInitialized: false, - KeyringController: { - isUnlocked: false, - keyrings: [], - }, - AccountsController: { - internalAccounts: { accounts: {}, selectedAccount: '' }, - }, - AccountTracker: { - currentBlockGasLimit: '', - currentBlockGasLimitByChainId: {}, - }, - AddressBookController: { - addressBook: {}, - }, - ApprovalController: { - pendingApprovals: {}, - approvalFlows: [], - }, - CurrencyController: { - currentCurrency: 'usd', - currencyRates: { - ETH: { - conversionRate: null, - conversionDate: 0, - usdConversionRate: null, - }, - }, - }, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - CustodyController: { - custodyAccountDetails: {}, - }, - ///: END:ONLY_INCLUDE_IF - DecryptMessageController: { - unapprovedDecryptMsgs: {}, - }, - GasFeeController: { - gasFeeEstimates: {}, - gasEstimateType: 'none', - }, - MetaMetricsController: { - participateInMetaMetrics: null, - dataCollectionForMarketing: null, - }, - NameController: { - names: { - [NameType.ETHEREUM_ADDRESS]: {}, - }, - }, - NetworkController: { - selectedNetworkClientId: '', - networkConfigurationsByChainId: {}, - networksMetadata: {}, - }, - NftController: { - allNfts: {}, - }, - OnboardingController: { - firstTimeFlowType: null, - completedOnboarding: false, - }, - PreferencesController: { - ...getDefaultPreferencesControllerState(), - theme: ThemeType.os, - useBlockie: false, - use4ByteResolution: true, - useNftDetection: true, - useTokenDetection: true, - openSeaEnabled: true, - securityAlertsEnabled: true, - featureFlags: {}, - currentLocale: '', - knownMethodData: {}, - // Ledger transport type is deprecated. We currently only support webhid - // on chrome, and u2f on firefox. - ledgerTransportType: window.navigator.hid - ? LedgerTransportTypes.webhid - : LedgerTransportTypes.u2f, - preferences: { - ...getDefaultPreferencesControllerState().preferences, - autoLockTimeLimit: DEFAULT_AUTO_LOCK_TIME_LIMIT, - showExtensionInFullSizeView: false, - showFiatInTestnets: false, - showNativeTokenAsMainBalance: true, - showTestNetworks: false, - smartTransactionsOptInStatus: true, - petnamesEnabled: true, - featureNotificationsEnabled: false, - privacyMode: false, - showMultiRpcModal: false, - tokenSortConfig: { - key: 'tokenFiatAmount', - order: 'dsc', - sortCallback: 'stringNumeric', - }, - tokenNetworkFilter: {}, - }, - }, - SignatureController: { - unapprovedPersonalMsgs: {}, - unapprovedTypedMessages: {}, - }, - TokensController: { - allTokens: {}, - }, - TxController: { - transactions: [], - }, + // KeyringController: { + // isUnlocked: false, + // keyrings: [], + // }, + // AccountsController: { + // internalAccounts: { accounts: {}, selectedAccount: '' }, + // }, + // AccountTracker: { + // currentBlockGasLimit: '', + // currentBlockGasLimitByChainId: {}, + // }, + // AddressBookController: { + // addressBook: {}, + // }, + // ApprovalController: { + // pendingApprovals: {}, + // approvalFlows: [], + // }, + // CurrencyController: { + // currentCurrency: 'usd', + // currencyRates: { + // ETH: { + // conversionRate: null, + // conversionDate: 0, + // usdConversionRate: null, + // }, + // }, + // }, + // ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + // CustodyController: { + // custodyAccountDetails: {}, + // }, + // ///: END:ONLY_INCLUDE_IF + // DecryptMessageController: { + // unapprovedDecryptMsgs: {}, + // }, + // GasFeeController: { + // gasFeeEstimates: {}, + // gasEstimateType: 'none', + // }, + // MetaMetricsController: { + // participateInMetaMetrics: null, + // dataCollectionForMarketing: null, + // }, + // NameController: { + // names: { + // [NameType.ETHEREUM_ADDRESS]: {}, + // }, + // }, + // NetworkController: { + // selectedNetworkClientId: '', + // networkConfigurationsByChainId: {}, + // networksMetadata: {}, + // }, + // NftController: { + // allNfts: {}, + // }, + // OnboardingController: { + // firstTimeFlowType: null, + // completedOnboarding: false, + // }, + // PreferencesController: { + // ...getDefaultPreferencesControllerState(), + // theme: ThemeType.os, + // useBlockie: false, + // use4ByteResolution: true, + // useNftDetection: true, + // useTokenDetection: true, + // openSeaEnabled: true, + // securityAlertsEnabled: true, + // featureFlags: {}, + // currentLocale: '', + // knownMethodData: {}, + // // Ledger transport type is deprecated. We currently only support webhid + // // on chrome, and u2f on firefox. + // ledgerTransportType: window.navigator.hid + // ? LedgerTransportTypes.webhid + // : LedgerTransportTypes.u2f, + // preferences: { + // ...getDefaultPreferencesControllerState().preferences, + // autoLockTimeLimit: DEFAULT_AUTO_LOCK_TIME_LIMIT, + // showExtensionInFullSizeView: false, + // showFiatInTestnets: false, + // showNativeTokenAsMainBalance: true, + // showTestNetworks: false, + // smartTransactionsOptInStatus: true, + // petnamesEnabled: true, + // featureNotificationsEnabled: false, + // privacyMode: false, + // showMultiRpcModal: false, + // tokenSortConfig: { + // key: 'tokenFiatAmount', + // order: 'dsc', + // sortCallback: 'stringNumeric', + // }, + // tokenNetworkFilter: {}, + // }, + // }, + // SignatureController: { + // unapprovedPersonalMsgs: {}, + // unapprovedTypedMessages: {}, + // }, + // TokensController: { + // allTokens: {}, + // }, + // TransactionController: { + // transactions: [], + // }, } as const;