diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index 740c50e7b45..af0db0aaa5d 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -277,6 +277,7 @@ export class Engine { constructor( initialState: Partial = {}, initialKeyringState?: KeyringControllerState | null, + metaMetricsId?: string, ) { logEngineCreation(initialState, initialKeyringState); @@ -514,6 +515,7 @@ export class Engine { allowedEvents: [], }), disabled: !isBasicFunctionalityToggleEnabled(), + getMetaMetricsId: () => metaMetricsId ?? '', }); const phishingController = new PhishingController({ @@ -2169,8 +2171,9 @@ export default { init( state: Partial | undefined, keyringState: KeyringControllerState | null = null, + metaMetricsId?: string, ) { - instance = Engine.instance || new Engine(state, keyringState); + instance = Engine.instance || new Engine(state, keyringState, metaMetricsId); Object.freeze(instance); return instance; }, diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts index 4e024983f3e..d7f68a42f21 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts @@ -4,4 +4,6 @@ export interface RemoteFeatureFlagInitParamTypes { state?: RemoteFeatureFlagControllerState; messenger: RemoteFeatureFlagControllerMessenger; disabled: boolean; + getMetaMetricsId: () => string; } + diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts index 39ab4c1013a..add22ad2184 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts @@ -4,6 +4,7 @@ import { RemoteFeatureFlagControllerMessenger, } from '@metamask/remote-feature-flag-controller'; import { createRemoteFeatureFlagController } from './utils'; +import { v4 as uuidv4 } from 'uuid'; describe('RemoteFeatureFlagController utils', () => { let messenger: RemoteFeatureFlagControllerMessenger; @@ -20,6 +21,7 @@ describe('RemoteFeatureFlagController utils', () => { state: undefined, messenger, disabled: false, + getMetaMetricsId: () => uuidv4(), }); expect(controller).toBeDefined(); @@ -43,6 +45,7 @@ describe('RemoteFeatureFlagController utils', () => { state: initialState, messenger, disabled: false, + getMetaMetricsId: () => uuidv4(), }); expect(controller.state).toStrictEqual(initialState); @@ -58,6 +61,7 @@ describe('RemoteFeatureFlagController utils', () => { state: undefined, messenger, disabled: false, + getMetaMetricsId: () => uuidv4(), }); expect(spy).toHaveBeenCalled(); @@ -73,6 +77,7 @@ describe('RemoteFeatureFlagController utils', () => { state: undefined, messenger, disabled: true, + getMetaMetricsId: () => uuidv4(), }); expect(spy).not.toHaveBeenCalled(); @@ -88,6 +93,7 @@ describe('RemoteFeatureFlagController utils', () => { state: initialState, messenger, disabled: false, + getMetaMetricsId: () => uuidv4(), }); expect(controller.state).toStrictEqual({ diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts index 55477c7a099..0e4dac6c947 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts @@ -33,11 +33,13 @@ export const createRemoteFeatureFlagController = ({ state, messenger, disabled, + getMetaMetricsId, }: RemoteFeatureFlagInitParamTypes) => { const remoteFeatureFlagController = new RemoteFeatureFlagController({ messenger, state, disabled, + getMetaMetricsId, clientConfigApiService: new ClientConfigApiService({ fetch, config: { diff --git a/app/core/EngineService/EngineService.test.ts b/app/core/EngineService/EngineService.test.ts index b35cbe45aba..09c09f23050 100644 --- a/app/core/EngineService/EngineService.test.ts +++ b/app/core/EngineService/EngineService.test.ts @@ -1,3 +1,4 @@ +import { waitFor } from '@testing-library/react-native'; import { EngineService } from './EngineService'; import ReduxService, { type ReduxStore } from '../redux'; import Engine from '../Engine'; @@ -119,37 +120,44 @@ describe('EngineService', () => { engineService = new EngineService(); }); - it('should have Engine initialized', () => { + it('should have Engine initialized', async () => { engineService.start(); - expect(Engine.context).toBeDefined(); + await waitFor(() => { + expect(Engine.context).toBeDefined(); + }); }); - it('should log Engine initialization with state info', () => { + it('should log Engine initialization with state info', async () => { engineService.start(); - expect(Logger.log).toHaveBeenCalledWith( - 'EngineService: Initializing Engine:', - { - hasState: true, - }, - ); + await waitFor(() => { + expect(Logger.log).toHaveBeenCalledWith( + 'EngineService: Initializing Engine:', + { + hasState: true, + }, + ); + }); + }); - it('should log Engine initialization with empty state', () => { + it('should log Engine initialization with empty state', async () => { jest.spyOn(ReduxService, 'store', 'get').mockReturnValue({ getState: () => ({ engine: { backgroundState: {} } }), } as unknown as ReduxStore); engineService.start(); - expect(Logger.log).toHaveBeenCalledWith( - 'EngineService: Initializing Engine:', - { - hasState: false, - }, - ); + await waitFor(() => { + expect(Logger.log).toHaveBeenCalledWith( + 'EngineService: Initializing Engine:', + { + hasState: false, + }, + ); + }); }); it('should have recovered vault on redux store and log initialization', async () => { - engineService.start(); + await engineService.start(); const { success } = await engineService.initializeVaultFromBackup(); expect(success).toBeTruthy(); expect(Engine.context.KeyringController.state.vault).toBeDefined(); @@ -161,19 +169,21 @@ describe('EngineService', () => { ); }); - it('should navigate to vault recovery if Engine fails to initialize', () => { + it('should navigate to vault recovery if Engine fails to initialize', async () => { jest.spyOn(Engine, 'init').mockImplementation(() => { throw new Error('Failed to initialize Engine'); }); engineService.start(); - // Logs error to Sentry - expect(Logger.error).toHaveBeenCalledWith( - new Error('Failed to initialize Engine'), - 'Failed to initialize Engine! Falling back to vault recovery.', - ); - // Navigates to vault recovery - expect(NavigationService.navigation?.reset).toHaveBeenCalledWith({ - routes: [{ name: Routes.VAULT_RECOVERY.RESTORE_WALLET }], + await waitFor(() => { + // Logs error to Sentry + expect(Logger.error).toHaveBeenCalledWith( + new Error('Failed to initialize Engine'), + 'Failed to initialize Engine! Falling back to vault recovery.', + ); + // Navigates to vault recovery + expect(NavigationService.navigation?.reset).toHaveBeenCalledWith({ + routes: [{ name: Routes.VAULT_RECOVERY.RESTORE_WALLET }], + }); }); }); }); diff --git a/app/core/EngineService/EngineService.ts b/app/core/EngineService/EngineService.ts index dd49c701361..6285908493f 100644 --- a/app/core/EngineService/EngineService.ts +++ b/app/core/EngineService/EngineService.ts @@ -13,6 +13,7 @@ import ReduxService from '../redux'; import NavigationService from '../NavigationService'; import Routes from '../../constants/navigation/Routes'; import { KeyringControllerState } from '@metamask/keyring-controller'; +import { MetaMetrics } from '../Analytics'; const LOG_TAG = 'EngineService'; @@ -43,7 +44,7 @@ export class EngineService { * - TypeError: undefined is not an object (evaluating 'TokenListController.tokenList') * - V8: SES_UNHANDLED_REJECTION */ - start = () => { + start = async () => { const reduxState = ReduxService.store.getState(); trace({ name: TraceName.EngineInitialization, @@ -57,7 +58,8 @@ export class EngineService { hasState: Object.keys(state).length > 0, }); - Engine.init(state); + const metaMetricsId = await MetaMetrics.getInstance().getMetaMetricsId(); + Engine.init(state, null, metaMetricsId); this.updateControllers(Engine); } catch (error) { Logger.error( @@ -257,7 +259,8 @@ export class EngineService { hasState: Object.keys(state).length > 0, }); - const instance = Engine.init(state, newKeyringState); + const metaMetricsId = await MetaMetrics.getInstance().getMetaMetricsId(); + const instance = Engine.init(state, newKeyringState, metaMetricsId); if (instance) { this.updateControllers(instance); // this is a hack to give the engine time to reinitialize diff --git a/package.json b/package.json index 5230866d3d8..67dccf3961c 100644 --- a/package.json +++ b/package.json @@ -192,7 +192,7 @@ "@metamask/react-native-payments": "^2.0.0", "@metamask/react-native-search-api": "1.0.1", "@metamask/react-native-webview": "^14.0.4", - "@metamask/remote-feature-flag-controller": "^1.0.0", + "@metamask/remote-feature-flag-controller": "^1.3.0", "@metamask/rpc-errors": "^7.0.2", "@metamask/scure-bip39": "^2.1.0", "@metamask/sdk-communication-layer": "0.29.0-wallet", diff --git a/yarn.lock b/yarn.lock index 61868ccf2e6..9cc2c8ed2ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4455,7 +4455,7 @@ single-call-balance-checker-abi "^1.0.0" uuid "^8.3.2" -"@metamask/base-controller@^7.0.1", "@metamask/base-controller@^7.0.2", "@metamask/base-controller@^7.1.1": +"@metamask/base-controller@^7.0.1", "@metamask/base-controller@^7.0.2", "@metamask/base-controller@^7.1.0", "@metamask/base-controller@^7.1.1": version "7.1.1" resolved "https://registry.yarnpkg.com/@metamask/base-controller/-/base-controller-7.1.1.tgz#837216ee099563b2106202fa0ed376dc909dfbb9" integrity sha512-4nbA6RL9y0SdHdn4MmMTREX6ISJL7OGHn0GXXszv0tp1fdjsn+SBs28uu1a9ceg1J7R/lO6JH7jAAz8zRtt8Nw== @@ -5261,14 +5261,15 @@ escape-string-regexp "^4.0.0" invariant "2.2.4" -"@metamask/remote-feature-flag-controller@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@metamask/remote-feature-flag-controller/-/remote-feature-flag-controller-1.0.0.tgz#048162eaa6fa34401cfbabfa0eb33f0255bb2945" - integrity sha512-jrjEQhW/RdHQ/GQbgXH97N6YqDUW7nGA40lEr0TUSIhJVVaHDX0gCiNmJZcQ89yLY4DZ0bisEwjrCu8LycYiQQ== +"@metamask/remote-feature-flag-controller@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@metamask/remote-feature-flag-controller/-/remote-feature-flag-controller-1.3.0.tgz#b83fc08c413b229b24046c84e2599d4dab2bafd8" + integrity sha512-h5DnnqbFxLsm8N98rrlVwUpQvvH03epb+1YhRMghIKa5WtjyoERV2wp0MuSH8l2Or4+ccx8eLv/X2bsnmtujGw== dependencies: - "@metamask/base-controller" "^7.0.2" - "@metamask/utils" "^10.0.0" + "@metamask/base-controller" "^7.1.0" + "@metamask/utils" "^11.0.1" cockatiel "^3.1.2" + uuid "^8.3.2" "@metamask/rpc-errors@7.0.2", "@metamask/rpc-errors@^6.2.1", "@metamask/rpc-errors@^7.0.0", "@metamask/rpc-errors@^7.0.1", "@metamask/rpc-errors@^7.0.2": version "7.0.2"