diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4931485e00b..0950da58cae 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,8 +8,10 @@ app/component-library/ @MetaMask/design-system-engineers # Platform Team patches/ @MetaMask/mobile-platform -app/core/Engine.ts @MetaMask/mobile-platform -app/core/Engine.test.js @MetaMask/mobile-platform +app/core/Engine/Engine.ts @MetaMask/mobile-platform +app/core/Engine/Engine.test.ts @MetaMask/mobile-platform +app/core/Engine/index.ts @MetaMask/mobile-platform +app/core/Engine/types.ts @MetaMask/mobile-platform app/core/Analytics/ @MetaMask/mobile-platform app/util/metrics/ @MetaMask/mobile-platform app/components/hooks/useMetrics/ @MetaMask/mobile-platform @@ -41,7 +43,8 @@ app/reducers/sdk @MetaMask/sdk-devs @MetaMask/mobile-platform app/util/walletconnect.js @MetaMask/sdk-devs @MetaMask/mobile-platform # Accounts Team -app/core/Encryptor/ @MetaMask/accounts-engineers +app/core/Encryptor/ @MetaMask/accounts-engineers +app/core/Engine/controller/AccountsController @MetaMask/accounts-engineers # Swaps Team app/components/UI/Swaps @MetaMask/swaps-engineers @MetaMask/mobile-platform diff --git a/app/components/Nav/Main/index.test.tsx b/app/components/Nav/Main/index.test.tsx index 33d004c74fe..1d6ed7941c9 100644 --- a/app/components/Nav/Main/index.test.tsx +++ b/app/components/Nav/Main/index.test.tsx @@ -10,7 +10,7 @@ import { MetaMetricsEvents } from '../../hooks/useMetrics'; import { renderHookWithProvider } from '../../../util/test/renderWithProvider'; import Engine from '../../../core/Engine'; -jest.mock('../../../core/Engine.ts', () => ({ +jest.mock('../../../core/Engine', () => ({ controllerMessenger: { subscribeOnceIf: jest.fn(), }, diff --git a/app/components/UI/AccountOverview/index.test.tsx b/app/components/UI/AccountOverview/index.test.tsx index 49fb5077401..9df49d8d11b 100644 --- a/app/components/UI/AccountOverview/index.test.tsx +++ b/app/components/UI/AccountOverview/index.test.tsx @@ -11,7 +11,7 @@ import { const mockedEngine = Engine; -jest.mock('../../../core/Engine.ts', () => { +jest.mock('../../../core/Engine', () => { const { MOCK_ACCOUNTS_CONTROLLER_STATE: mockAccountsControllerState } = jest.requireActual('../../../util/test/accountsControllerTestUtils'); return { diff --git a/app/components/UI/AssetSearch/index.test.tsx b/app/components/UI/AssetSearch/index.test.tsx index 9838088af3b..6009fe1393a 100644 --- a/app/components/UI/AssetSearch/index.test.tsx +++ b/app/components/UI/AssetSearch/index.test.tsx @@ -5,7 +5,7 @@ import { backgroundState } from '../../../util/test/initial-root-state'; import Engine from '../../../core/Engine'; const mockedEngine = Engine; -jest.mock('../../../core/Engine.ts', () => ({ +jest.mock('../../../core/Engine', () => ({ init: () => mockedEngine.init({}), context: { KeyringController: { diff --git a/app/components/Views/AccountActions/AccountActions.test.tsx b/app/components/Views/AccountActions/AccountActions.test.tsx index 730761ea373..395735523c2 100644 --- a/app/components/Views/AccountActions/AccountActions.test.tsx +++ b/app/components/Views/AccountActions/AccountActions.test.tsx @@ -28,7 +28,6 @@ const initialState = { }; jest.mock('../../../core/Engine', () => ({ - ...jest.requireActual('../../../core/Engine'), context: { PreferencesController: { selectedAddress: `0xC4966c0D659D99699BFD7EB54D8fafEE40e4a756`, diff --git a/app/components/Views/Asset/index.test.js b/app/components/Views/Asset/index.test.js index bc1dc5ef4d6..968ed7f4b69 100644 --- a/app/components/Views/Asset/index.test.js +++ b/app/components/Views/Asset/index.test.js @@ -13,7 +13,7 @@ const mockInitialState = { }, }; -jest.mock('../../../core/Engine.ts', () => { +jest.mock('../../../core/Engine', () => { const { MOCK_ADDRESS_1, } = require('../../../util/test/accountsControllerTestUtils'); diff --git a/app/components/Views/confirmations/Approval/index.test.tsx b/app/components/Views/confirmations/Approval/index.test.tsx index 5346ec593a1..321dfd22f04 100644 --- a/app/components/Views/confirmations/Approval/index.test.tsx +++ b/app/components/Views/confirmations/Approval/index.test.tsx @@ -19,7 +19,7 @@ jest.mock('../../../../util/dappTransactions', () => ({ handleGetGasLimit: jest.fn(), })); -jest.mock('../../../../core/Engine.ts', () => ({ +jest.mock('../../../../core/Engine', () => ({ rejectPendingApproval: jest.fn(), context: { KeyringController: { diff --git a/app/components/Views/confirmations/ApproveView/Approve/index.test.tsx b/app/components/Views/confirmations/ApproveView/Approve/index.test.tsx index 8af433251e1..91b67a3beba 100644 --- a/app/components/Views/confirmations/ApproveView/Approve/index.test.tsx +++ b/app/components/Views/confirmations/ApproveView/Approve/index.test.tsx @@ -21,7 +21,7 @@ jest.mock('../../../../../core/GasPolling/GasPolling', () => ({ stopGasPolling: jest.fn().mockResolvedValue(null), })); -jest.mock('../../../../../core/Engine.ts', () => ({ +jest.mock('../../../../../core/Engine', () => ({ controllerMessenger: { tryUnsubscribe: jest.fn(), subscribe: jest.fn(), @@ -59,7 +59,8 @@ const routeMock = { }; const hideModalMock = jest.fn(); -const renderComponent = ({ store }: { store: Store }) => render( +const renderComponent = ({ store }: { store: Store }) => + render( diff --git a/app/core/Engine.test.ts b/app/core/Engine/Engine.test.ts similarity index 92% rename from app/core/Engine.test.ts rename to app/core/Engine/Engine.test.ts index 530723e73f6..b54e6d32fc5 100644 --- a/app/core/Engine.test.ts +++ b/app/core/Engine/Engine.test.ts @@ -1,27 +1,24 @@ -import Engine, { - Engine as EngineClass, - EngineState, - TransactionEventPayload, -} from './Engine'; -import { backgroundState } from '../util/test/initial-root-state'; +import Engine, { Engine as EngineClass } from './Engine'; +import { EngineState, TransactionEventPayload } from './types'; +import { backgroundState } from '../../util/test/initial-root-state'; import { zeroAddress } from 'ethereumjs-util'; -import { createMockAccountsControllerState } from '../util/test/accountsControllerTestUtils'; -import { mockNetworkState } from '../util/test/network'; -import MetaMetrics from './Analytics/MetaMetrics'; -import { store } from '../store'; -import { MetaMetricsEvents } from './Analytics'; +import { createMockAccountsControllerState } from '../../util/test/accountsControllerTestUtils'; +import { mockNetworkState } from '../../util/test/network'; +import MetaMetrics from '../Analytics/MetaMetrics'; +import { store } from '../../store'; +import { MetaMetricsEvents } from '../Analytics'; import { NetworkState } from '@metamask/network-controller'; import { Hex } from '@metamask/utils'; -import { MarketDataDetails } from '../components/UI/Tokens'; +import { MarketDataDetails } from '../../components/UI/Tokens'; import { TransactionMeta } from '@metamask/transaction-controller'; -import { RootState } from '../reducers'; -import { MetricsEventBuilder } from './Analytics/MetricsEventBuilder'; +import { RootState } from '../../reducers'; +import { MetricsEventBuilder } from '../Analytics/MetricsEventBuilder'; jest.unmock('./Engine'); -jest.mock('../store', () => ({ +jest.mock('../../store', () => ({ store: { getState: jest.fn(() => ({ engine: {} })) }, })); -jest.mock('../selectors/smartTransactionsController', () => ({ +jest.mock('../../selectors/smartTransactionsController', () => ({ selectShouldUseSmartTransaction: jest.fn().mockReturnValue(false), })); @@ -276,11 +273,17 @@ describe('Engine', () => { AccountTrackerController: { accountsByChainId: { [chainId]: { - [selectedAddress]: { balance: (ethBalance * 1e18).toString(), stakedBalance: (stakedEthBalance * 1e18).toString() }, + [selectedAddress]: { + balance: (ethBalance * 1e18).toString(), + stakedBalance: (stakedEthBalance * 1e18).toString(), + }, }, }, accounts: { - [selectedAddress]: { balance: (ethBalance * 1e18).toString(), stakedBalance: (stakedEthBalance * 1e18).toString() }, + [selectedAddress]: { + balance: (ethBalance * 1e18).toString(), + stakedBalance: (stakedEthBalance * 1e18).toString(), + }, }, }, TokensController: { diff --git a/app/core/Engine.ts b/app/core/Engine/Engine.ts similarity index 83% rename from app/core/Engine.ts rename to app/core/Engine/Engine.ts index 4e4f3e39345..20318a94bd5 100644 --- a/app/core/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -3,144 +3,67 @@ import Crypto from 'react-native-quick-crypto'; import { scrypt } from 'react-native-fast-crypto'; import { AccountTrackerController, - AccountTrackerControllerState, AssetsContractController, CurrencyRateController, - CurrencyRateState, - CurrencyRateStateChange, - GetCurrencyRateState, - GetTokenListState, NftController, NftDetectionController, - NftControllerState, TokenBalancesController, TokenDetectionController, TokenListController, - TokenListState, - TokenListStateChange, TokenRatesController, - TokenRatesControllerState, TokensController, - TokensControllerState, CodefiTokenPricesServiceV2, - TokensControllerActions, - TokensControllerEvents, - TokenListControllerActions, - TokenListControllerEvents, - TokenBalancesControllerState, - AssetsContractControllerGetERC20BalanceOfAction, - AssetsContractControllerGetERC721AssetNameAction, - AssetsContractControllerGetERC721AssetSymbolAction, - AssetsContractControllerGetERC721TokenURIAction, - AssetsContractControllerGetERC721OwnerOfAction, - AssetsContractControllerGetERC1155BalanceOfAction, - AssetsContractControllerGetERC1155TokenURIAction, } from '@metamask/assets-controllers'; ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) import { AppState } from 'react-native'; -import PREINSTALLED_SNAPS from '../lib/snaps/preinstalled-snaps'; +import PREINSTALLED_SNAPS from '../../lib/snaps/preinstalled-snaps'; ///: END:ONLY_INCLUDE_IF -import { - AddressBookController, - AddressBookControllerActions, - AddressBookControllerEvents, - AddressBookControllerState, -} from '@metamask/address-book-controller'; -import { BaseState } from '@metamask/base-controller'; +import { AddressBookController } from '@metamask/address-book-controller'; import { ComposableController } from '@metamask/composable-controller'; import { KeyringController, KeyringControllerState, - KeyringControllerActions, - KeyringControllerEvents, ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) KeyringTypes, ///: END:ONLY_INCLUDE_IF } from '@metamask/keyring-controller'; import { NetworkController, - NetworkControllerActions, - NetworkControllerEvents, NetworkControllerMessenger, NetworkState, NetworkStatus, } from '@metamask/network-controller'; -import { - PhishingController, - PhishingControllerActions, - PhishingControllerEvents, - PhishingControllerState, -} from '@metamask/phishing-controller'; -import { - PreferencesController, - PreferencesControllerActions, - PreferencesControllerEvents, - PreferencesState, -} from '@metamask/preferences-controller'; +import { PhishingController } from '@metamask/phishing-controller'; +import { PreferencesController } from '@metamask/preferences-controller'; import { TransactionController, - TransactionControllerEvents, - TransactionControllerState, TransactionMeta, TransactionControllerOptions, } from '@metamask/transaction-controller'; -import { - GasFeeController, - GasFeeState, - GasFeeStateChange, - GetGasFeeState, -} from '@metamask/gas-fee-controller'; +import { GasFeeController } from '@metamask/gas-fee-controller'; import { AcceptOptions, ApprovalController, - ApprovalControllerActions, - ApprovalControllerEvents, - ApprovalControllerState, } from '@metamask/approval-controller'; -import { - SelectedNetworkController, - SelectedNetworkControllerState, - SelectedNetworkControllerEvents, - SelectedNetworkControllerActions, -} from '@metamask/selected-network-controller'; +import { SelectedNetworkController } from '@metamask/selected-network-controller'; import { PermissionController, - PermissionControllerActions, - PermissionControllerEvents, - PermissionControllerState, ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) SubjectMetadataController, - SubjectMetadataControllerActions, - SubjectMetadataControllerEvents, - SubjectMetadataControllerState, ///: END:ONLY_INCLUDE_IF } from '@metamask/permission-controller'; -import SwapsController, { - swapsUtils, - SwapsControllerState, -} from '@metamask/swaps-controller'; -import { - PPOMController, - PPOMControllerActions, - PPOMControllerEvents, - PPOMState, -} from '@metamask/ppom-validator'; +import SwapsController, { swapsUtils } from '@metamask/swaps-controller'; +import { PPOMController } from '@metamask/ppom-validator'; ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) import { JsonSnapsRegistry, - AllowedActions as SnapsAllowedActions, - AllowedEvents as SnapsAllowedEvents, SnapController, - SnapsRegistryState, - SnapControllerEvents, - SnapControllerActions, - PersistedSnapControllerState, SnapsRegistryMessenger, } from '@metamask/snaps-controllers'; import { WebViewExecutionService } from '@metamask/snaps-controllers/react-native'; import { NotificationParameters } from '@metamask/snaps-rpc-methods/dist/restricted/notify.cjs'; -import { getSnapsWebViewPromise } from '../lib/snaps'; +import { getSnapsWebViewPromise } from '../../lib/snaps'; import { buildSnapEndowmentSpecifications, buildSnapRestrictedMethodSpecifications, @@ -150,27 +73,22 @@ import type { EnumToUnion, DialogType } from '@metamask/snaps-sdk'; import { Duplex } from 'stream'; ///: END:ONLY_INCLUDE_IF import { MetaMaskKeyring as QRHardwareKeyring } from '@keystonehq/metamask-airgapped-keyring'; -import { - LoggingController, - LoggingControllerState, - LoggingControllerActions, - LoggingControllerEvents, -} from '@metamask/logging-controller'; +import { LoggingController } from '@metamask/logging-controller'; import { LedgerKeyring, LedgerMobileBridge, LedgerTransportMiddleware, } from '@metamask/eth-ledger-bridge-keyring'; -import { Encryptor, LEGACY_DERIVATION_OPTIONS } from './Encryptor'; +import { Encryptor, LEGACY_DERIVATION_OPTIONS } from '../Encryptor'; import { isMainnetByChainId, fetchEstimatedMultiLayerL1Fee, isTestNet, deprecatedGetNetworkId, getDecimalChainId, -} from '../util/networks'; -import AppConstants from './AppConstants'; -import { store } from '../store'; +} from '../../util/networks'; +import AppConstants from '../AppConstants'; +import { store } from '../../store'; import { renderFromTokenMinimalUnit, balanceToFiatNumber, @@ -178,11 +96,11 @@ import { toHexadecimal, addHexPrefix, hexToBN, -} from '../util/number'; -import NotificationManager from './NotificationManager'; -import Logger from '../util/Logger'; -import { isZero } from '../util/lodash'; -import { MetaMetricsEvents, MetaMetrics } from './Analytics'; +} from '../../util/number'; +import NotificationManager from '../NotificationManager'; +import Logger from '../../util/Logger'; +import { isZero } from '../../util/lodash'; +import { MetaMetricsEvents, MetaMetrics } from '../Analytics'; ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) import { @@ -193,8 +111,8 @@ import { detectSnapLocation, fetchFunction, DetectSnapLocationOptions, -} from './Snaps'; -import { getRpcMethodMiddleware } from './RPCMethods/RPCMethodMiddleware'; +} from '../Snaps'; +import { getRpcMethodMiddleware } from '../RPCMethods/RPCMethodMiddleware'; import { AuthenticationController, @@ -209,47 +127,50 @@ import { getCaveatSpecifications, getPermissionSpecifications, unrestrictedMethods, -} from './Permissions/specifications.js'; -import { backupVault } from './BackupVault'; +} from '../Permissions/specifications.js'; +import { backupVault } from '../BackupVault'; import { SignatureController, - SignatureControllerActions, - SignatureControllerEvents, SignatureControllerOptions, } from '@metamask/signature-controller'; import { hasProperty, Hex, Json } from '@metamask/utils'; import { providerErrors } from '@metamask/rpc-errors'; -import { PPOM, ppomInit } from '../lib/ppom/PPOMView'; -import RNFSStorageBackend from '../lib/ppom/ppom-storage-backend'; +import { PPOM, ppomInit } from '../../lib/ppom/PPOMView'; +import RNFSStorageBackend from '../../lib/ppom/ppom-storage-backend'; import { - AccountsController, - AccountsControllerActions, - AccountsControllerEvents, - AccountsControllerMessenger, - AccountsControllerState, -} from '@metamask/accounts-controller'; + ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) + AccountsControllerSetSelectedAccountAction, + AccountsControllerGetAccountByAddressAction, + AccountsControllerSetAccountNameAction, + ///: END:ONLY_INCLUDE_IF + AccountsControllerGetAccountAction, + AccountsControllerGetSelectedAccountAction, + AccountsControllerListAccountsAction, + AccountsControllerUpdateAccountMetadataAction, + AccountsControllerSelectedEvmAccountChangeEvent, + AccountsControllerSelectedAccountChangeEvent, + AccountsControllerAccountAddedEvent, + AccountsControllerAccountRenamedEvent, +} from './controllers/AccountsController/constants'; +import { createAccountsController } from './controllers/AccountsController/utils'; import { captureException } from '@sentry/react-native'; import { lowerCase } from 'lodash'; import { networkIdUpdated, networkIdWillUpdate, -} from '../core/redux/slices/inpageProvider'; -import SmartTransactionsController, { - type SmartTransactionsControllerActions, - type SmartTransactionsControllerEvents, - type SmartTransactionsControllerState, -} from '@metamask/smart-transactions-controller'; -import { getAllowedSmartTransactionsChainIds } from '../../app/constants/smartTransactions'; -import { selectShouldUseSmartTransaction } from '../selectors/smartTransactionsController'; -import { selectSwapsChainFeatureFlags } from '../reducers/swaps'; +} from '../../core/redux/slices/inpageProvider'; +import SmartTransactionsController from '@metamask/smart-transactions-controller'; +import { getAllowedSmartTransactionsChainIds } from '../../../app/constants/smartTransactions'; +import { selectShouldUseSmartTransaction } from '../../selectors/smartTransactionsController'; +import { selectSwapsChainFeatureFlags } from '../../reducers/swaps'; import { SmartTransactionStatuses } from '@metamask/smart-transactions-controller/dist/types'; -import { submitSmartTransactionHook } from '../util/smart-transactions/smart-publish-hook'; +import { submitSmartTransactionHook } from '../../util/smart-transactions/smart-publish-hook'; import { zeroAddress } from 'ethereumjs-util'; import { ApprovalType, toChecksumHexAddress } from '@metamask/controller-utils'; -import { ExtendedControllerMessenger } from './ExtendedControllerMessenger'; +import { ExtendedControllerMessenger } from '../ExtendedControllerMessenger'; import EthQuery from '@metamask/eth-query'; -import DomainProxyMap from '../lib/DomainProxyMap/DomainProxyMap'; +import DomainProxyMap from '../../lib/DomainProxyMap/DomainProxyMap'; import { MetaMetricsEventCategory, MetaMetricsEventName, @@ -259,17 +180,24 @@ import { getSmartTransactionMetricsSensitiveProperties as getSmartTransactionMetricsSensitivePropertiesType, } from '@metamask/smart-transactions-controller/dist/utils'; ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) -import { snapKeyringBuilder } from './SnapKeyring'; -import { removeAccountsFromPermissions } from './Permissions'; -import { keyringSnapPermissionsBuilder } from './SnapKeyring/keyringSnapsPermissions'; -import { HandleSnapRequestArgs } from './Snaps/types'; -import { handleSnapRequest } from './Snaps/utils'; +import { snapKeyringBuilder } from '../SnapKeyring'; +import { removeAccountsFromPermissions } from '../Permissions'; +import { keyringSnapPermissionsBuilder } from '../SnapKeyring/keyringSnapsPermissions'; +import { HandleSnapRequestArgs } from '../Snaps/types'; +import { handleSnapRequest } from '../Snaps/utils'; ///: END:ONLY_INCLUDE_IF -import { getSmartTransactionMetricsProperties } from '../util/smart-transactions'; -import { trace } from '../util/trace'; -import { MetricsEventBuilder } from './Analytics/MetricsEventBuilder'; -import { JsonMap } from './Analytics/MetaMetrics.types'; -import { isPooledStakingFeatureEnabled } from '../components/UI/Stake/constants'; +import { getSmartTransactionMetricsProperties } from '../../util/smart-transactions'; +import { trace } from '../../util/trace'; +import { MetricsEventBuilder } from '../Analytics/MetricsEventBuilder'; +import { JsonMap } from '../Analytics/MetaMetrics.types'; +import { isPooledStakingFeatureEnabled } from '../../components/UI/Stake/constants'; +import { + ControllerMessenger, + Controllers, + EngineState, + EngineContext, + TransactionEventPayload, +} from './types'; const NON_EMPTY = 'NON_EMPTY'; @@ -280,195 +208,6 @@ const encryptor = new Encryptor({ // eslint-disable-next-line @typescript-eslint/no-explicit-any let currentChainId: any; -///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) -type AuthenticationControllerActions = AuthenticationController.AllowedActions; -type UserStorageControllerActions = UserStorageController.AllowedActions; -type NotificationsServicesControllerActions = - NotificationServicesController.AllowedActions; - -type SnapsGlobalActions = - | SnapControllerActions - | SubjectMetadataControllerActions - | PhishingControllerActions - | SnapsAllowedActions; - -type SnapsGlobalEvents = - | SnapControllerEvents - | SubjectMetadataControllerEvents - | PhishingControllerEvents - | SnapsAllowedEvents; -///: END:ONLY_INCLUDE_IF - -type GlobalActions = - | AddressBookControllerActions - | ApprovalControllerActions - | GetCurrencyRateState - | GetGasFeeState - | GetTokenListState - | KeyringControllerActions - | NetworkControllerActions - | PermissionControllerActions - | SignatureControllerActions - | LoggingControllerActions - ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) - | SnapsGlobalActions - | AuthenticationControllerActions - | UserStorageControllerActions - | NotificationsServicesControllerActions - ///: END:ONLY_INCLUDE_IF - | KeyringControllerActions - | AccountsControllerActions - | PreferencesControllerActions - | PPOMControllerActions - | TokensControllerActions - | TokenListControllerActions - | SelectedNetworkControllerActions - | SmartTransactionsControllerActions - | AssetsContractControllerGetERC20BalanceOfAction - | AssetsContractControllerGetERC721AssetNameAction - | AssetsContractControllerGetERC721AssetSymbolAction - | AssetsContractControllerGetERC721TokenURIAction - | AssetsContractControllerGetERC721OwnerOfAction - | AssetsContractControllerGetERC1155BalanceOfAction - | AssetsContractControllerGetERC1155TokenURIAction; - -type GlobalEvents = - | AddressBookControllerEvents - | ApprovalControllerEvents - | CurrencyRateStateChange - | GasFeeStateChange - | KeyringControllerEvents - | TokenListStateChange - | NetworkControllerEvents - | PermissionControllerEvents - ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) - | SnapsGlobalEvents - ///: END:ONLY_INCLUDE_IF - | SignatureControllerEvents - | LoggingControllerEvents - | KeyringControllerEvents - | PPOMControllerEvents - | AccountsControllerEvents - | PreferencesControllerEvents - | TokensControllerEvents - | TokenListControllerEvents - | TransactionControllerEvents - | SelectedNetworkControllerEvents - | SmartTransactionsControllerEvents; - -type PermissionsByRpcMethod = ReturnType; -type Permissions = PermissionsByRpcMethod[keyof PermissionsByRpcMethod]; - -export interface EngineState { - AccountTrackerController: AccountTrackerControllerState; - AddressBookController: AddressBookControllerState; - AssetsContractController: BaseState; - NftController: NftControllerState; - TokenListController: TokenListState; - CurrencyRateController: CurrencyRateState; - KeyringController: KeyringControllerState; - NetworkController: NetworkState; - PreferencesController: PreferencesState; - PhishingController: PhishingControllerState; - TokenBalancesController: TokenBalancesControllerState; - TokenRatesController: TokenRatesControllerState; - TransactionController: TransactionControllerState; - SmartTransactionsController: SmartTransactionsControllerState; - SwapsController: SwapsControllerState; - GasFeeController: GasFeeState; - TokensController: TokensControllerState; - TokenDetectionController: BaseState; - NftDetectionController: BaseState; - ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) - SnapController: PersistedSnapControllerState; - SnapsRegistry: SnapsRegistryState; - SubjectMetadataController: SubjectMetadataControllerState; - AuthenticationController: AuthenticationController.AuthenticationControllerState; - UserStorageController: UserStorageController.UserStorageControllerState; - NotificationServicesController: NotificationServicesController.NotificationServicesControllerState; - NotificationServicesPushController: NotificationServicesPushController.NotificationServicesPushControllerState; - ///: END:ONLY_INCLUDE_IF - PermissionController: PermissionControllerState; - ApprovalController: ApprovalControllerState; - LoggingController: LoggingControllerState; - PPOMController: PPOMState; - AccountsController: AccountsControllerState; - SelectedNetworkController: SelectedNetworkControllerState; -} - -/** - * All mobile controllers, keyed by name - */ -interface Controllers { - AccountsController: AccountsController; - AccountTrackerController: AccountTrackerController; - AddressBookController: AddressBookController; - ApprovalController: ApprovalController; - AssetsContractController: AssetsContractController; - CurrencyRateController: CurrencyRateController; - GasFeeController: GasFeeController; - KeyringController: KeyringController; - LoggingController: LoggingController; - NetworkController: NetworkController; - NftController: NftController; - NftDetectionController: NftDetectionController; - // TODO: Fix permission types - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - PermissionController: PermissionController; - SelectedNetworkController: SelectedNetworkController; - PhishingController: PhishingController; - PreferencesController: PreferencesController; - PPOMController: PPOMController; - TokenBalancesController: TokenBalancesController; - TokenListController: TokenListController; - TokenDetectionController: TokenDetectionController; - TokenRatesController: TokenRatesController; - TokensController: TokensController; - TransactionController: TransactionController; - SmartTransactionsController: SmartTransactionsController; - SignatureController: SignatureController; - ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) - SnapController: SnapController; - SubjectMetadataController: SubjectMetadataController; - AuthenticationController: AuthenticationController.Controller; - UserStorageController: UserStorageController.Controller; - NotificationServicesController: NotificationServicesController.Controller; - NotificationServicesPushController: NotificationServicesPushController.Controller; - ///: END:ONLY_INCLUDE_IF - SwapsController: SwapsController; -} - -/** - * Controllers that area always instantiated - */ -type RequiredControllers = Omit; - -/** - * Controllers that are sometimes not instantiated - */ -type OptionalControllers = Pick; - -/** - * Combines required and optional controllers for the Engine context type. - */ -export type EngineContext = RequiredControllers & Partial; - -/** - * Type definition for the controller messenger used in the Engine. - * It extends the base ControllerMessenger with global actions and events. - */ -export type ControllerMessenger = ExtendedControllerMessenger< - GlobalActions, - GlobalEvents ->; - -export interface TransactionEventPayload { - transactionMeta: TransactionMeta; - actionId?: string; - error?: string; -} - /** * Core controller responsible for composing other metamask controllers together * and exposing convenience methods for common wallet operations. @@ -598,31 +337,11 @@ export class Engine { networkController?.state.selectedNetworkClientId, ).configuration.chainId, }); - const accountsControllerMessenger: AccountsControllerMessenger = - this.controllerMessenger.getRestricted({ - name: 'AccountsController', - allowedEvents: [ - 'SnapController:stateChange', - 'KeyringController:accountRemoved', - 'KeyringController:stateChange', - ], - allowedActions: [ - 'KeyringController:getAccounts', - 'KeyringController:getKeyringsByType', - 'KeyringController:getKeyringForAccount', - ], - }); - - const defaultAccountsControllerState: AccountsControllerState = { - internalAccounts: { - accounts: {}, - selectedAccount: '', - }, - }; - const accountsController = new AccountsController({ - messenger: accountsControllerMessenger, - state: initialState.AccountsController ?? defaultAccountsControllerState, + // Create AccountsController + const accountsController = createAccountsController({ + messenger: this.controllerMessenger, + initialState: initialState.AccountsController, }); const nftController = new NftController({ @@ -635,8 +354,8 @@ export class Engine { allowedActions: [ `${approvalController.name}:addRequest`, `${networkController.name}:getNetworkClientById`, - 'AccountsController:getAccount', - 'AccountsController:getSelectedAccount', + AccountsControllerGetAccountAction, + AccountsControllerGetSelectedAccountAction, 'AssetsContractController:getERC721AssetName', 'AssetsContractController:getERC721AssetSymbol', 'AssetsContractController:getERC721TokenURI', @@ -647,7 +366,7 @@ export class Engine { allowedEvents: [ 'PreferencesController:stateChange', 'NetworkController:networkDidChange', - 'AccountsController:selectedEvmAccountChange', + AccountsControllerSelectedEvmAccountChangeEvent, ], }), }); @@ -676,14 +395,14 @@ export class Engine { allowedActions: [ `${approvalController.name}:addRequest`, 'NetworkController:getNetworkClientById', - 'AccountsController:getAccount', - 'AccountsController:getSelectedAccount', + AccountsControllerGetAccountAction, + AccountsControllerGetSelectedAccountAction, ], allowedEvents: [ 'PreferencesController:stateChange', 'NetworkController:networkDidChange', 'TokenListController:stateChange', - 'AccountsController:selectedEvmAccountChange', + AccountsControllerSelectedEvmAccountChangeEvent, ], }), }); @@ -785,9 +504,9 @@ export class Engine { 'PhishingController:testOrigin', 'PhishingController:maybeUpdateState', 'KeyringController:getAccounts', - 'AccountsController:setSelectedAccount', - 'AccountsController:getAccountByAddress', - 'AccountsController:setAccountName', + AccountsControllerSetSelectedAccountAction, + AccountsControllerGetAccountByAddressAction, + AccountsControllerSetAccountNameAction, ], allowedEvents: [], }); @@ -943,15 +662,15 @@ export class Engine { messenger: this.controllerMessenger.getRestricted({ name: 'AccountTrackerController', allowedActions: [ - 'AccountsController:getSelectedAccount', - 'AccountsController:listAccounts', + AccountsControllerGetSelectedAccountAction, + AccountsControllerListAccountsAction, 'PreferencesController:getState', 'NetworkController:getState', 'NetworkController:getNetworkClientById', ], allowedEvents: [ - 'AccountsController:selectedEvmAccountChange', - 'AccountsController:selectedAccountChange', + AccountsControllerSelectedEvmAccountChangeEvent, + AccountsControllerSelectedAccountChangeEvent, ], }), state: initialState.AccountTrackerController ?? { accounts: {} }, @@ -1269,14 +988,14 @@ export class Engine { 'AuthenticationController:performSignIn', 'NotificationServicesController:disableNotificationServices', 'NotificationServicesController:selectIsNotificationServicesEnabled', - 'AccountsController:listAccounts', - 'AccountsController:updateAccountMetadata', + AccountsControllerListAccountsAction, + AccountsControllerUpdateAccountMetadataAction, ], allowedEvents: [ 'KeyringController:unlock', 'KeyringController:lock', - 'AccountsController:accountAdded', - 'AccountsController:accountRenamed', + AccountsControllerAccountAddedEvent, + AccountsControllerAccountRenamedEvent, ], }), nativeScryptCrypto: scrypt, @@ -1411,7 +1130,7 @@ export class Engine { messenger: this.controllerMessenger.getRestricted({ name: 'TransactionController', allowedActions: [ - `${accountsController.name}:getSelectedAccount`, + AccountsControllerGetSelectedAccountAction, `${approvalController.name}:addRequest`, `${networkController.name}:getNetworkClientById`, `${networkController.name}:findNetworkClientIdByChainId`, @@ -1504,7 +1223,7 @@ export class Engine { messenger: this.controllerMessenger.getRestricted({ name: 'TokenDetectionController', allowedActions: [ - 'AccountsController:getSelectedAccount', + AccountsControllerGetSelectedAccountAction, 'NetworkController:getNetworkClientById', 'NetworkController:getNetworkConfigurationByNetworkClientId', 'NetworkController:getState', @@ -1513,7 +1232,7 @@ export class Engine { 'TokenListController:getState', 'TokensController:getState', 'TokensController:addDetectedTokens', - 'AccountsController:getAccount', + AccountsControllerGetAccountAction, ], allowedEvents: [ 'KeyringController:lock', @@ -1522,7 +1241,7 @@ export class Engine { 'NetworkController:networkDidChange', 'TokenListController:stateChange', 'TokensController:stateChange', - 'AccountsController:selectedEvmAccountChange', + AccountsControllerSelectedEvmAccountChangeEvent, ], }), trackMetaMetricsEvent: () => @@ -1558,7 +1277,7 @@ export class Engine { 'NetworkController:getState', 'NetworkController:getNetworkClientById', 'PreferencesController:getState', - 'AccountsController:getSelectedAccount', + AccountsControllerGetSelectedAccountAction, ], }), disabled: false, @@ -1573,7 +1292,7 @@ export class Engine { messenger: this.controllerMessenger.getRestricted({ name: 'TokenBalancesController', allowedActions: [ - 'AccountsController:getSelectedAccount', + AccountsControllerGetSelectedAccountAction, 'AssetsContractController:getERC20BalanceOf', ], allowedEvents: ['TokensController:stateChange'], @@ -1592,13 +1311,13 @@ export class Engine { 'TokensController:getState', 'NetworkController:getNetworkClientById', 'NetworkController:getState', - 'AccountsController:getAccount', - 'AccountsController:getSelectedAccount', + AccountsControllerGetAccountAction, + AccountsControllerGetSelectedAccountAction, ], allowedEvents: [ 'TokensController:stateChange', 'NetworkController:stateChange', - 'AccountsController:selectedEvmAccountChange', + AccountsControllerSelectedEvmAccountChangeEvent, ], }), tokenPricesService: codefiTokenApiV2, diff --git a/app/core/Engine/controllers/AccountsController/constants.ts b/app/core/Engine/controllers/AccountsController/constants.ts new file mode 100644 index 00000000000..5007533e2f0 --- /dev/null +++ b/app/core/Engine/controllers/AccountsController/constants.ts @@ -0,0 +1,39 @@ +import { + AccountsControllerGetAccountByAddressAction as AccountsControllerGetAccountByAddressActionType, + AccountsControllerSetAccountNameAction as AccountsControllerSetAccountNameActionType, + AccountsControllerSetSelectedAccountAction as AccountsControllerSetSelectedAccountActionType, + AccountsControllerGetAccountAction as AccountsControllerGetAccountActionType, + AccountsControllerGetSelectedAccountAction as AccountsControllerGetSelectedAccountActionType, + AccountsControllerListAccountsAction as AccountsControllerListAccountsActionType, + AccountsControllerUpdateAccountMetadataAction as AccountsControllerUpdateAccountMetadataActionType, + AccountsControllerSelectedEvmAccountChangeEvent as AccountsControllerSelectedEvmAccountChangeEventType, + AccountsControllerSelectedAccountChangeEvent as AccountsControllerSelectedAccountChangeEventType, + AccountsControllerAccountAddedEvent as AccountsControllerAccountAddedEventType, + AccountsControllerAccountRenamedEvent as AccountsControllerAccountRenamedEventType, +} from '@metamask/accounts-controller'; + +// Action types of AccountsController +export const AccountsControllerGetAccountByAddressAction: AccountsControllerGetAccountByAddressActionType['type'] = + 'AccountsController:getAccountByAddress'; +export const AccountsControllerSetAccountNameAction: AccountsControllerSetAccountNameActionType['type'] = + 'AccountsController:setAccountName'; +export const AccountsControllerGetAccountAction: AccountsControllerGetAccountActionType['type'] = + 'AccountsController:getAccount'; +export const AccountsControllerGetSelectedAccountAction: AccountsControllerGetSelectedAccountActionType['type'] = + 'AccountsController:getSelectedAccount'; +export const AccountsControllerSetSelectedAccountAction: AccountsControllerSetSelectedAccountActionType['type'] = + 'AccountsController:setSelectedAccount'; +export const AccountsControllerListAccountsAction: AccountsControllerListAccountsActionType['type'] = + 'AccountsController:listAccounts'; +export const AccountsControllerUpdateAccountMetadataAction: AccountsControllerUpdateAccountMetadataActionType['type'] = + 'AccountsController:updateAccountMetadata'; + +// Events of AccountsController +export const AccountsControllerSelectedEvmAccountChangeEvent: AccountsControllerSelectedEvmAccountChangeEventType['type'] = + 'AccountsController:selectedEvmAccountChange'; +export const AccountsControllerSelectedAccountChangeEvent: AccountsControllerSelectedAccountChangeEventType['type'] = + 'AccountsController:selectedAccountChange'; +export const AccountsControllerAccountAddedEvent: AccountsControllerAccountAddedEventType['type'] = + 'AccountsController:accountAdded'; +export const AccountsControllerAccountRenamedEvent: AccountsControllerAccountRenamedEventType['type'] = + 'AccountsController:accountRenamed'; diff --git a/app/core/Engine/controllers/AccountsController/utils.test.ts b/app/core/Engine/controllers/AccountsController/utils.test.ts new file mode 100644 index 00000000000..25f95dd2e14 --- /dev/null +++ b/app/core/Engine/controllers/AccountsController/utils.test.ts @@ -0,0 +1,73 @@ +import { AccountsControllerState } from '@metamask/accounts-controller'; +import { ExtendedControllerMessenger } from '../../../ExtendedControllerMessenger'; +import { + createAccountsController, + defaultAccountsControllerState, +} from './utils'; +import { ControllerMessenger } from '../../'; +import { withScope } from '@sentry/react-native'; +import { AGREED, METRICS_OPT_IN } from '../../../../constants/storage'; +import StorageWrapper from '../../../../store/storage-wrapper'; + +jest.mock('@sentry/react-native', () => ({ + withScope: jest.fn(), +})); +const mockedWithScope = jest.mocked(withScope); + +describe('accountControllersUtils', () => { + describe('createAccountsController', () => { + beforeEach(() => { + StorageWrapper.getItem = jest.fn((key: string) => { + switch (key) { + case METRICS_OPT_IN: + return Promise.resolve(AGREED); + default: + return Promise.resolve(''); + } + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('AccountsController state should be default state when no initial state is passed in', () => { + const controllerMessenger = new ExtendedControllerMessenger(); + const accountsController = createAccountsController({ + messenger: controllerMessenger, + }); + expect(accountsController.state).toEqual(defaultAccountsControllerState); + }); + it('AccountsController state should be initial state when initial state is passed in', () => { + const controllerMessenger = new ExtendedControllerMessenger(); + const initialAccountsControllerState: AccountsControllerState = { + internalAccounts: { + accounts: {}, + selectedAccount: '0x1', + }, + }; + const accountsController = createAccountsController({ + messenger: controllerMessenger, + initialState: initialAccountsControllerState, + }); + expect(accountsController.state).toEqual(initialAccountsControllerState); + }); + it('AccountsController name should be AccountsController', () => { + const controllerMessenger = new ExtendedControllerMessenger(); + const accountsControllerName = 'AccountsController'; + const accountsController = createAccountsController({ + messenger: controllerMessenger, + }); + expect(accountsController.name).toEqual(accountsControllerName); + }); + it('should catch error when controller fails to initialize', async () => { + const controllerMessenger = + 'controllerMessenger' as unknown as ControllerMessenger; + const accountsController = await createAccountsController({ + messenger: controllerMessenger, + }); + expect(mockedWithScope).toHaveBeenCalledTimes(1); + expect(accountsController).toEqual({}); + }); + }); +}); diff --git a/app/core/Engine/controllers/AccountsController/utils.ts b/app/core/Engine/controllers/AccountsController/utils.ts new file mode 100644 index 00000000000..44325a3bd65 --- /dev/null +++ b/app/core/Engine/controllers/AccountsController/utils.ts @@ -0,0 +1,60 @@ +import { + AccountsController, + AccountsControllerMessenger, + AccountsControllerState, +} from '@metamask/accounts-controller'; +import { ControllerMessenger } from '../../types'; +import Logger from '../../../../util/Logger'; + +// Default AccountsControllerState +export const defaultAccountsControllerState: AccountsControllerState = { + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, +}; + +/** + * Creates instance of AccountsController + * + * @param options.messenger - Controller messenger instance + * @param options.initialState - Initial state of AccountsController + * @returns - AccountsController instance + */ +export const createAccountsController = ({ + messenger, + initialState, +}: { + messenger: ControllerMessenger; + initialState?: AccountsControllerState; +}): AccountsController => { + let accountsController = {} as AccountsController; + + try { + const accountsControllerMessenger: AccountsControllerMessenger = + messenger.getRestricted({ + name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + ], + allowedActions: [ + 'KeyringController:getAccounts', + 'KeyringController:getKeyringsByType', + 'KeyringController:getKeyringForAccount', + ], + }); + + accountsController = new AccountsController({ + messenger: accountsControllerMessenger, + state: initialState ?? defaultAccountsControllerState, + }); + } catch (error) { + // Report error while initializing AccountsController + // TODO: Direct to vault recovery to reset controller states + Logger.error(error as Error, 'Failed to initialize AccountsController'); + } + + return accountsController; +}; diff --git a/app/core/Engine/index.ts b/app/core/Engine/index.ts new file mode 100644 index 00000000000..55587d2843a --- /dev/null +++ b/app/core/Engine/index.ts @@ -0,0 +1,2 @@ +export { default } from './Engine'; +export * from './types'; diff --git a/app/core/Engine/types.ts b/app/core/Engine/types.ts new file mode 100644 index 00000000000..456cfb8759f --- /dev/null +++ b/app/core/Engine/types.ts @@ -0,0 +1,348 @@ +import { ExtendedControllerMessenger } from '../ExtendedControllerMessenger'; +import { + AccountTrackerController, + AccountTrackerControllerState, + CurrencyRateController, + CurrencyRateStateChange, + GetCurrencyRateState, + CurrencyRateState, + NftController, + NftControllerState, + NftDetectionController, + TokenListController, + TokenListControllerActions, + TokenListControllerEvents, + GetTokenListState, + TokenListStateChange, + TokenListState, + TokensController, + TokensControllerActions, + TokensControllerEvents, + TokensControllerState, + TokenBalancesController, + TokenBalancesControllerState, + TokenDetectionController, + TokenRatesController, + TokenRatesControllerState, + AssetsContractController, + AssetsContractControllerGetERC20BalanceOfAction, + AssetsContractControllerGetERC721AssetNameAction, + AssetsContractControllerGetERC721AssetSymbolAction, + AssetsContractControllerGetERC721TokenURIAction, + AssetsContractControllerGetERC721OwnerOfAction, + AssetsContractControllerGetERC1155BalanceOfAction, + AssetsContractControllerGetERC1155TokenURIAction, +} from '@metamask/assets-controllers'; +import { + AddressBookController, + AddressBookControllerActions, + AddressBookControllerEvents, + AddressBookControllerState, +} from '@metamask/address-book-controller'; +import { + KeyringController, + KeyringControllerActions, + KeyringControllerEvents, + KeyringControllerState, +} from '@metamask/keyring-controller'; +import { + NetworkController, + NetworkControllerActions, + NetworkControllerEvents, + NetworkState, +} from '@metamask/network-controller'; +import { + PhishingController, + PhishingControllerActions, + PhishingControllerEvents, + PhishingControllerState, +} from '@metamask/phishing-controller'; +import { + PreferencesController, + PreferencesControllerActions, + PreferencesControllerEvents, + PreferencesState, +} from '@metamask/preferences-controller'; +import { + TransactionController, + TransactionControllerEvents, + TransactionControllerState, + TransactionMeta, +} from '@metamask/transaction-controller'; +import { + GasFeeController, + GasFeeStateChange, + GetGasFeeState, + GasFeeState, +} from '@metamask/gas-fee-controller'; +import { + ApprovalController, + ApprovalControllerActions, + ApprovalControllerEvents, + ApprovalControllerState, +} from '@metamask/approval-controller'; +import { + SelectedNetworkController, + SelectedNetworkControllerEvents, + SelectedNetworkControllerActions, + SelectedNetworkControllerState, +} from '@metamask/selected-network-controller'; +import { + PermissionController, + PermissionControllerActions, + PermissionControllerEvents, + PermissionControllerState, + ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) + SubjectMetadataController, + SubjectMetadataControllerActions, + SubjectMetadataControllerEvents, + SubjectMetadataControllerState, + ///: END:ONLY_INCLUDE_IF +} from '@metamask/permission-controller'; +import SwapsController, { + SwapsControllerState, +} from '@metamask/swaps-controller'; +import { + PPOMController, + PPOMControllerActions, + PPOMControllerEvents, + PPOMState, +} from '@metamask/ppom-validator'; +///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) +import { + SnapController, + AllowedActions as SnapsAllowedActions, + AllowedEvents as SnapsAllowedEvents, + SnapControllerEvents, + SnapControllerActions, + SnapsRegistryState, + PersistedSnapControllerState, +} from '@metamask/snaps-controllers'; +///: END:ONLY_INCLUDE_IF +import { + LoggingController, + LoggingControllerActions, + LoggingControllerEvents, + LoggingControllerState, +} from '@metamask/logging-controller'; +import { + SignatureController, + SignatureControllerActions, + SignatureControllerEvents, +} from '@metamask/signature-controller'; +import SmartTransactionsController, { + type SmartTransactionsControllerActions, + type SmartTransactionsControllerEvents, + SmartTransactionsControllerState, +} from '@metamask/smart-transactions-controller'; +///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) +import { + AuthenticationController, + UserStorageController, +} from '@metamask/profile-sync-controller'; +import { + NotificationServicesPushController, + NotificationServicesController, +} from '@metamask/notification-services-controller'; +///: END:ONLY_INCLUDE_IF +import { + AccountsController, + AccountsControllerActions, + AccountsControllerEvents, + AccountsControllerState, +} from '@metamask/accounts-controller'; +import { BaseState } from '@metamask/base-controller'; +import { getPermissionSpecifications } from '../Permissions/specifications.js'; + +/** + * Controllers that area always instantiated + */ +type RequiredControllers = Omit; + +/** + * Controllers that are sometimes not instantiated + */ +type OptionalControllers = Pick; + +type PermissionsByRpcMethod = ReturnType; +type Permissions = PermissionsByRpcMethod[keyof PermissionsByRpcMethod]; + +///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) +type AuthenticationControllerActions = AuthenticationController.AllowedActions; +type UserStorageControllerActions = UserStorageController.AllowedActions; +type NotificationsServicesControllerActions = + NotificationServicesController.AllowedActions; + +// TODO: Abstract this into controller utils for SnapsController +type SnapsGlobalActions = + | SnapControllerActions + | SubjectMetadataControllerActions + | PhishingControllerActions + | SnapsAllowedActions; +type SnapsGlobalEvents = + | SnapControllerEvents + | SubjectMetadataControllerEvents + | PhishingControllerEvents + | SnapsAllowedEvents; +///: END:ONLY_INCLUDE_IF + +type GlobalActions = + | AddressBookControllerActions + | ApprovalControllerActions + | GetCurrencyRateState + | GetGasFeeState + | GetTokenListState + | KeyringControllerActions + | NetworkControllerActions + | PermissionControllerActions + | SignatureControllerActions + | LoggingControllerActions + ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) + | SnapsGlobalActions + | AuthenticationControllerActions + | UserStorageControllerActions + | NotificationsServicesControllerActions + ///: END:ONLY_INCLUDE_IF + | KeyringControllerActions + | AccountsControllerActions + | PreferencesControllerActions + | PPOMControllerActions + | TokensControllerActions + | TokenListControllerActions + | SelectedNetworkControllerActions + | SmartTransactionsControllerActions + | AssetsContractControllerGetERC20BalanceOfAction + | AssetsContractControllerGetERC721AssetNameAction + | AssetsContractControllerGetERC721AssetSymbolAction + | AssetsContractControllerGetERC721TokenURIAction + | AssetsContractControllerGetERC721OwnerOfAction + | AssetsContractControllerGetERC1155BalanceOfAction + | AssetsContractControllerGetERC1155TokenURIAction; + +type GlobalEvents = + | AddressBookControllerEvents + | ApprovalControllerEvents + | CurrencyRateStateChange + | GasFeeStateChange + | KeyringControllerEvents + | TokenListStateChange + | NetworkControllerEvents + | PermissionControllerEvents + ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) + | SnapsGlobalEvents + ///: END:ONLY_INCLUDE_IF + | SignatureControllerEvents + | LoggingControllerEvents + | KeyringControllerEvents + | PPOMControllerEvents + | AccountsControllerEvents + | PreferencesControllerEvents + | TokensControllerEvents + | TokenListControllerEvents + | TransactionControllerEvents + | SelectedNetworkControllerEvents + | SmartTransactionsControllerEvents; + +// TODO: Abstract this into controller utils for TransactionController +export interface TransactionEventPayload { + transactionMeta: TransactionMeta; + actionId?: string; + error?: string; +} + +/** + * Type definition for the controller messenger used in the Engine. + * It extends the base ControllerMessenger with global actions and events. + */ +export type ControllerMessenger = ExtendedControllerMessenger< + GlobalActions, + GlobalEvents +>; + +/** + * All mobile controllers, keyed by name + */ +export interface Controllers { + AccountsController: AccountsController; + AccountTrackerController: AccountTrackerController; + AddressBookController: AddressBookController; + ApprovalController: ApprovalController; + AssetsContractController: AssetsContractController; + CurrencyRateController: CurrencyRateController; + GasFeeController: GasFeeController; + KeyringController: KeyringController; + LoggingController: LoggingController; + NetworkController: NetworkController; + NftController: NftController; + NftDetectionController: NftDetectionController; + // TODO: Fix permission types + // TODO: Replace "any" with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + PermissionController: PermissionController; + SelectedNetworkController: SelectedNetworkController; + PhishingController: PhishingController; + PreferencesController: PreferencesController; + PPOMController: PPOMController; + TokenBalancesController: TokenBalancesController; + TokenListController: TokenListController; + TokenDetectionController: TokenDetectionController; + TokenRatesController: TokenRatesController; + TokensController: TokensController; + TransactionController: TransactionController; + SmartTransactionsController: SmartTransactionsController; + SignatureController: SignatureController; + ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) + SnapController: SnapController; + SubjectMetadataController: SubjectMetadataController; + AuthenticationController: AuthenticationController.Controller; + UserStorageController: UserStorageController.Controller; + NotificationServicesController: NotificationServicesController.Controller; + NotificationServicesPushController: NotificationServicesPushController.Controller; + ///: END:ONLY_INCLUDE_IF + SwapsController: SwapsController; +} + +/** + * Combines required and optional controllers for the Engine context type. + */ +export type EngineContext = RequiredControllers & Partial; + +/** + * All engine state, keyed by controller name + */ +export interface EngineState { + AccountTrackerController: AccountTrackerControllerState; + AddressBookController: AddressBookControllerState; + AssetsContractController: BaseState; + NftController: NftControllerState; + TokenListController: TokenListState; + CurrencyRateController: CurrencyRateState; + KeyringController: KeyringControllerState; + NetworkController: NetworkState; + PreferencesController: PreferencesState; + PhishingController: PhishingControllerState; + TokenBalancesController: TokenBalancesControllerState; + TokenRatesController: TokenRatesControllerState; + TransactionController: TransactionControllerState; + SmartTransactionsController: SmartTransactionsControllerState; + SwapsController: SwapsControllerState; + GasFeeController: GasFeeState; + TokensController: TokensControllerState; + TokenDetectionController: BaseState; + NftDetectionController: BaseState; + ///: BEGIN:ONLY_INCLUDE_IF(preinstalled-snaps,external-snaps) + SnapController: PersistedSnapControllerState; + SnapsRegistry: SnapsRegistryState; + SubjectMetadataController: SubjectMetadataControllerState; + AuthenticationController: AuthenticationController.AuthenticationControllerState; + UserStorageController: UserStorageController.UserStorageControllerState; + NotificationServicesController: NotificationServicesController.NotificationServicesControllerState; + NotificationServicesPushController: NotificationServicesPushController.NotificationServicesPushControllerState; + ///: END:ONLY_INCLUDE_IF + PermissionController: PermissionControllerState; + ApprovalController: ApprovalControllerState; + LoggingController: LoggingControllerState; + PPOMController: PPOMState; + AccountsController: AccountsControllerState; + SelectedNetworkController: SelectedNetworkControllerState; +}