From a76dd4c09c8099b37885cb58fed26434489c19e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:22:21 +0000 Subject: [PATCH 01/21] metro bundler: use local module --- metro.config.js | 18 ++++++++++++++++++ package.json | 2 +- yarn.lock | 11 +++-------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/metro.config.js b/metro.config.js index 0e1eca9e0db..78d2c9760ad 100644 --- a/metro.config.js +++ b/metro.config.js @@ -9,6 +9,18 @@ const { getDefaultConfig } = require('expo/metro-config'); const { mergeConfig } = require('@react-native/metro-config'); +const path = require("path"); + +const featureFlagModuleDir = path.resolve(__dirname, "../../core/feature-flags/packages/remote-feature-flag-controller"); + +const extraNodeModules = { + "@metamask/remote-feature-flag-controller": featureFlagModuleDir, +}; + +const watchFolders = [ + featureFlagModuleDir, +]; + module.exports = function (baseConfig) { const defaultConfig = mergeConfig(baseConfig, getDefaultConfig(__dirname)); const { @@ -16,10 +28,16 @@ module.exports = function (baseConfig) { } = defaultConfig; return mergeConfig(defaultConfig, { + watchFolders, resolver: { assetExts: assetExts.filter((ext) => ext !== 'svg'), sourceExts: [...sourceExts, 'svg', 'cjs', 'mjs'], resolverMainFields: ['sbmodern', 'react-native', 'browser', 'main'], + extraNodeModules: new Proxy (extraNodeModules, { + get: (target, name) => + name in target ? target[name] : path.join(process.cwd(), `node_modules/${name}`), + }), + unstable_enableSymlinks: true, }, transformer: { babelTransformerPath: require.resolve('./metro.transform.js'), diff --git a/package.json b/package.json index b11e4906799..cfbb8564e1f 100644 --- a/package.json +++ b/package.json @@ -188,7 +188,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": "link:../../core/feature-flags/packages/remote-feature-flag-controller", "@metamask/rpc-errors": "^7.0.1", "@metamask/scure-bip39": "^2.1.0", "@metamask/sdk-communication-layer": "0.29.0-wallet", diff --git a/yarn.lock b/yarn.lock index e295783628c..2043f90da4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5191,14 +5191,9 @@ 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== - dependencies: - "@metamask/base-controller" "^7.0.2" - "@metamask/utils" "^10.0.0" - cockatiel "^3.1.2" +"@metamask/remote-feature-flag-controller@link:../../core/feature-flags/packages/remote-feature-flag-controller": + version "0.0.0" + uid "" "@metamask/rpc-errors@7.0.1", "@metamask/rpc-errors@^6.2.1", "@metamask/rpc-errors@^6.3.1", "@metamask/rpc-errors@^7.0.0", "@metamask/rpc-errors@^7.0.1": version "7.0.1" From d25ef6e2436974fe9a6ef75b02b00cc05e1af759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 11 Dec 2024 17:11:01 +0000 Subject: [PATCH 02/21] dev env: ignore ts errors --- metro.transform.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/metro.transform.js b/metro.transform.js index 3354bcd0e0f..5db70919a61 100644 --- a/metro.transform.js +++ b/metro.transform.js @@ -70,9 +70,6 @@ module.exports.transform = async ({ src, filename, options }) => { active: getBuildTypeFeatures(), }); - if (didModify) { - await lintTransformedFile(getESLintInstance(), filename, processedSource); - } return defaultTransformer.transform({ src: processedSource, filename, From 877699c0dee0b97488fbdc2701eaceb281647608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 11 Dec 2024 17:14:07 +0000 Subject: [PATCH 03/21] engine: fetch metametrics id before engine init --- app/core/Engine/Engine.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index 45ecd83150b..bf4e2371cd1 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -274,6 +274,7 @@ export class Engine { // eslint-disable-next-line @typescript-eslint/default-param-last constructor( initialState: Partial = {}, + metaMetricsId: string | undefined, initialKeyringState?: KeyringControllerState | null, ) { this.controllerMessenger = new ExtendedControllerMessenger(); @@ -510,8 +511,10 @@ export class Engine { allowedEvents: [], }), disabled: !isBasicFunctionalityToggleEnabled(), + metaMetricsId, }); + console.log('controller', remoteFeatureFlagController); const phishingController = new PhishingController({ messenger: this.controllerMessenger.getRestricted({ name: 'PhishingController', @@ -2156,8 +2159,8 @@ export default { instance = null; }, - init(state: Partial | undefined, keyringState = null) { - instance = Engine.instance || new Engine(state, keyringState); + init(state: Partial | undefined, keyringState = null, metaMetricsId: string | undefined) { + instance = Engine.instance || new Engine(state, metaMetricsId, keyringState); Object.freeze(instance); return instance; }, From 7ffa2660957299c68ad48bbdd4c6170b457d2f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 11 Dec 2024 17:24:09 +0000 Subject: [PATCH 04/21] feature flag controller: use metaMetricsId --- .../Engine/controllers/RemoteFeatureFlagController/types.ts | 5 +++-- .../Engine/controllers/RemoteFeatureFlagController/utils.ts | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts index b42163fa235..8a0eebd0da1 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts @@ -2,7 +2,8 @@ import { RemoteFeatureFlagControllerMessenger, RemoteFeatureFlagControllerState export interface RemoteFeatureFlagInitParamTypes { state?: RemoteFeatureFlagControllerState; - messenger: RemoteFeatureFlagControllerMessenger, - disabled: boolean + messenger: RemoteFeatureFlagControllerMessenger; + disabled: boolean; + metaMetricsId: string | undefined; } diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts index c45fbe167bf..4581a4805b4 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts @@ -33,12 +33,14 @@ export const createRemoteFeatureFlagController = ({ state, messenger, disabled, + metaMetricsId, }: RemoteFeatureFlagInitParamTypes) => { const remoteFeatureFlagController = new RemoteFeatureFlagController({ messenger, state, disabled, + metaMetricsId, clientConfigApiService: new ClientConfigApiService({ fetch, config: { From 8769485b89f4b5b9b2228eb6ae2fc92e938a52c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:23:25 +0000 Subject: [PATCH 05/21] use promise to get metametrics id --- app/core/Engine/Engine.ts | 7 +++---- .../controllers/RemoteFeatureFlagController/types.ts | 2 +- .../controllers/RemoteFeatureFlagController/utils.ts | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index bf4e2371cd1..0f36a8a2297 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -274,7 +274,6 @@ export class Engine { // eslint-disable-next-line @typescript-eslint/default-param-last constructor( initialState: Partial = {}, - metaMetricsId: string | undefined, initialKeyringState?: KeyringControllerState | null, ) { this.controllerMessenger = new ExtendedControllerMessenger(); @@ -511,7 +510,7 @@ export class Engine { allowedEvents: [], }), disabled: !isBasicFunctionalityToggleEnabled(), - metaMetricsId, + getMetaMetricsId: MetaMetrics.getInstance().getMetaMetricsId(), }); console.log('controller', remoteFeatureFlagController); @@ -2159,8 +2158,8 @@ export default { instance = null; }, - init(state: Partial | undefined, keyringState = null, metaMetricsId: string | undefined) { - instance = Engine.instance || new Engine(state, metaMetricsId, keyringState); + init(state: Partial | undefined, keyringState = null) { + instance = Engine.instance || new Engine(state, keyringState); Object.freeze(instance); return instance; }, diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts index 8a0eebd0da1..b36e7cf05b7 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts @@ -4,6 +4,6 @@ export interface RemoteFeatureFlagInitParamTypes { state?: RemoteFeatureFlagControllerState; messenger: RemoteFeatureFlagControllerMessenger; disabled: boolean; - metaMetricsId: string | undefined; + getMetaMetricsId: Promise; } diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts index 4581a4805b4..1d7bcdfb2d8 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts @@ -9,6 +9,7 @@ import { import Logger from '../../../../util/Logger'; import { RemoteFeatureFlagInitParamTypes } from './types'; +import { uuidv4 } from '@walletconnect/utils'; const getFeatureFlagAppEnvironment = () => { const env = process.env.METAMASK_ENVIRONMENT; @@ -33,14 +34,14 @@ export const createRemoteFeatureFlagController = ({ state, messenger, disabled, - metaMetricsId, + getMetaMetricsId, }: RemoteFeatureFlagInitParamTypes) => { const remoteFeatureFlagController = new RemoteFeatureFlagController({ messenger, state, disabled, - metaMetricsId, + getMetaMetricsId, clientConfigApiService: new ClientConfigApiService({ fetch, config: { From d0e7eb93ae195a280a7ae8f15713dae16c1fe11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:34:52 +0000 Subject: [PATCH 06/21] remove dev code --- app/core/Engine/Engine.ts | 1 - app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index 0f36a8a2297..b1849e7122c 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -513,7 +513,6 @@ export class Engine { getMetaMetricsId: MetaMetrics.getInstance().getMetaMetricsId(), }); - console.log('controller', remoteFeatureFlagController); const phishingController = new PhishingController({ messenger: this.controllerMessenger.getRestricted({ name: 'PhishingController', diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts index 1d7bcdfb2d8..87012c403ad 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.ts @@ -9,7 +9,6 @@ import { import Logger from '../../../../util/Logger'; import { RemoteFeatureFlagInitParamTypes } from './types'; -import { uuidv4 } from '@walletconnect/utils'; const getFeatureFlagAppEnvironment = () => { const env = process.env.METAMASK_ENVIRONMENT; From 6406624c9b27798b8ddab757c2eb9777fafd74f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:50:06 +0000 Subject: [PATCH 07/21] getMetaMetricsId as a sync function --- app/core/Engine/Engine.ts | 24 ++++++++++++------- .../RemoteFeatureFlagController/types.ts | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index b1849e7122c..48dc1777185 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -502,6 +502,12 @@ export class Engine { 'https://gas.api.cx.metamask.io/networks//suggestedGasFees', }); + const getMetaMetricsId = () => { + // MetaMetrics.getInstance().getMetaMetricsId() + return 'uid'; + + }; + const remoteFeatureFlagController = createRemoteFeatureFlagController({ state: initialState.RemoteFeatureFlagController, messenger: this.controllerMessenger.getRestricted({ @@ -510,7 +516,7 @@ export class Engine { allowedEvents: [], }), disabled: !isBasicFunctionalityToggleEnabled(), - getMetaMetricsId: MetaMetrics.getInstance().getMetaMetricsId(), + getMetaMetricsId, }); const phishingController = new PhishingController({ @@ -1174,7 +1180,7 @@ export class Engine { return Boolean( hasProperty(showIncomingTransactions, currentChainId) && - showIncomingTransactions?.[currentHexChainId], + showIncomingTransactions?.[currentHexChainId], ); }, updateTransactions: true, @@ -1518,8 +1524,8 @@ export class Engine { (state: NetworkState) => { if ( state.networksMetadata[state.selectedNetworkClientId].status === - NetworkStatus.Available && - getGlobalChainId(networkController) !== currentChainId + NetworkStatus.Available && + getGlobalChainId(networkController) !== currentChainId ) { // We should add a state or event emitter saying the provider changed setTimeout(() => { @@ -1740,7 +1746,7 @@ export class Engine { const decimalsToShow = (currentCurrency === 'usd' && 2) || undefined; if ( accountsByChainId?.[toHexadecimal(chainId)]?.[ - selectSelectedInternalAccountFormattedAddress + selectSelectedInternalAccountFormattedAddress ] ) { // TODO - Non EVM accounts like BTC do not use hex formatted balances. We will need to modify this to use CAIP-2 identifiers in the future. @@ -1779,7 +1785,7 @@ export class Engine { const tokenBalances = allTokenBalances?.[selectedInternalAccount.address as Hex]?.[ - chainId + chainId ] ?? {}; tokens.forEach( (item: { address: string; balance?: string; decimals: number }) => { @@ -1790,9 +1796,9 @@ export class Engine { item.balance || (item.address in tokenBalances ? renderFromTokenMinimalUnit( - tokenBalances[item.address as Hex], - item.decimals, - ) + tokenBalances[item.address as Hex], + item.decimals, + ) : undefined); const tokenBalanceFiat = balanceToFiatNumber( // TODO: Fix this by handling or eliminating the undefined case diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts index b36e7cf05b7..d7f68a42f21 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/types.ts @@ -4,6 +4,6 @@ export interface RemoteFeatureFlagInitParamTypes { state?: RemoteFeatureFlagControllerState; messenger: RemoteFeatureFlagControllerMessenger; disabled: boolean; - getMetaMetricsId: Promise; + getMetaMetricsId: () => string; } From e93b20146351cc4e43b854a1ad737dfa5854e452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:35:13 +0000 Subject: [PATCH 08/21] add metametricsid to redux --- app/actions/user/index.ts | 13 +++++++++++++ app/actions/user/types.ts | 9 ++++++++- app/components/Nav/App/index.js | 6 +++++- app/core/Engine/Engine.ts | 8 +------- app/reducers/user/index.ts | 6 ++++++ app/reducers/user/types.ts | 1 + app/store/sagas/index.ts | 3 +++ metro.config.js | 18 ------------------ 8 files changed, 37 insertions(+), 27 deletions(-) diff --git a/app/actions/user/index.ts b/app/actions/user/index.ts index 9071fcffd50..03533b9e509 100644 --- a/app/actions/user/index.ts +++ b/app/actions/user/index.ts @@ -21,6 +21,7 @@ import { type CheckedAuthAction, type PersistedDataLoadedAction, UserActionType, + SetMetaMetricsIdAction, } from './types'; export * from './types'; @@ -151,6 +152,18 @@ export function checkedAuth(initialScreen: string): CheckedAuthAction { }; } +/** + * Temporary action to initialize metametricsId before Engine Init + * + * @param metaMetricsId - MetaMetrics ID + */ +export function setMetaMetricsId(metaMetricsId: string): SetMetaMetricsIdAction { + return { + type: UserActionType.SET_METAMETRICS_ID, + payload: { metaMetricsId }, + } +} + /** * Action to signal that persisted data has been loaded */ diff --git a/app/actions/user/types.ts b/app/actions/user/types.ts index 704aee6092d..5db9d6da977 100644 --- a/app/actions/user/types.ts +++ b/app/actions/user/types.ts @@ -1,3 +1,4 @@ +import { setMetaMetricsId } from '.'; import { type AppThemeKey } from '../../util/theme/models'; import { type Action } from 'redux'; @@ -23,6 +24,7 @@ export enum UserActionType { SET_GAS_EDUCATION_CAROUSEL_SEEN = 'SET_GAS_EDUCATION_CAROUSEL_SEEN', SET_APP_THEME = 'SET_APP_THEME', CHECKED_AUTH = 'CHECKED_AUTH', + SET_METAMETRICS_ID = 'SET_METAMETRICS_ID', } // User actions @@ -85,6 +87,10 @@ export type CheckedAuthAction = Action & { payload: { initialScreen: string }; }; +export type SetMetaMetricsIdAction = Action & { + payload: { metaMetricsId: string }; +}; + /** * User actions union type */ @@ -108,4 +114,5 @@ export type UserAction = | LoadingUnsetAction | SetGasEducationCarouselSeenAction | SetAppThemeAction - | CheckedAuthAction; + | CheckedAuthAction + | SetMetaMetricsIdAction; diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 32ec533e3ae..000c95523b6 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -46,6 +46,7 @@ import { setCurrentRoute, onNavigationReady, } from '../../../actions/navigation'; +import { setMetaMetricsId } from '../../../actions/user'; import { findRouteNameFromNavigatorState } from '../../../util/general'; import { Authentication } from '../../../core/'; import { useTheme } from '../../../util/theme'; @@ -748,9 +749,12 @@ const App = (props) => { ...generateUserSettingsAnalyticsMetaData(), }; await metrics.addTraitsToUser(consolidatedTraits); + return await metrics.getMetaMetricsId(); }; - initMetrics().catch((err) => { + initMetrics().then((metaMetricsId) => { + dispatch(setMetaMetricsId(metaMetricsId)); + }).catch((err) => { Logger.error(err, 'Error initializing MetaMetrics'); }); }, []); diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index 3e73db4b29e..281cd47f32c 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -502,12 +502,6 @@ export class Engine { 'https://gas.api.cx.metamask.io/networks//suggestedGasFees', }); - const getMetaMetricsId = () => { - // MetaMetrics.getInstance().getMetaMetricsId() - return 'uid'; - - }; - const remoteFeatureFlagController = createRemoteFeatureFlagController({ state: initialState.RemoteFeatureFlagController, messenger: this.controllerMessenger.getRestricted({ @@ -516,7 +510,7 @@ export class Engine { allowedEvents: [], }), disabled: !isBasicFunctionalityToggleEnabled(), - getMetaMetricsId, + getMetaMetricsId: () => store.getState().user.metaMetricsId, }); const phishingController = new PhishingController({ diff --git a/app/reducers/user/index.ts b/app/reducers/user/index.ts index 5941561d6ea..cba02446b6e 100644 --- a/app/reducers/user/index.ts +++ b/app/reducers/user/index.ts @@ -22,6 +22,7 @@ export const userInitialState: UserState = { initialScreen: '', appTheme: AppThemeKey.os, ambiguousAddressEntries: {}, + metaMetricsId: '', }; /** @@ -109,6 +110,11 @@ const userReducer = ( ...state, appTheme: action.payload.theme, }; + case UserActionType.SET_METAMETRICS_ID: + return { + ...state, + metaMetricsId: action.payload.metaMetricsId, + } default: return state; } diff --git a/app/reducers/user/types.ts b/app/reducers/user/types.ts index 4080aebc5ee..44c66b57e55 100644 --- a/app/reducers/user/types.ts +++ b/app/reducers/user/types.ts @@ -16,4 +16,5 @@ export interface UserState { initialScreen: string; appTheme: AppThemeKey; ambiguousAddressEntries: Record; + metaMetricsId: string; } diff --git a/app/store/sagas/index.ts b/app/store/sagas/index.ts index b7b0724a993..624a89e2a52 100644 --- a/app/store/sagas/index.ts +++ b/app/store/sagas/index.ts @@ -133,8 +133,11 @@ export function* startAppServices() { yield all([ take(UserActionType.ON_PERSISTED_DATA_LOADED), take(NavigationActionType.ON_NAVIGATION_READY), + //temp set metametrics id before engine init + take(UserActionType.SET_METAMETRICS_ID), ]); // Start services + // init metametrics EngineService.start(); AppStateEventProcessor.start(); // TODO: Track a property in redux to gate keep the app until services are initialized diff --git a/metro.config.js b/metro.config.js index 78d2c9760ad..0e1eca9e0db 100644 --- a/metro.config.js +++ b/metro.config.js @@ -9,18 +9,6 @@ const { getDefaultConfig } = require('expo/metro-config'); const { mergeConfig } = require('@react-native/metro-config'); -const path = require("path"); - -const featureFlagModuleDir = path.resolve(__dirname, "../../core/feature-flags/packages/remote-feature-flag-controller"); - -const extraNodeModules = { - "@metamask/remote-feature-flag-controller": featureFlagModuleDir, -}; - -const watchFolders = [ - featureFlagModuleDir, -]; - module.exports = function (baseConfig) { const defaultConfig = mergeConfig(baseConfig, getDefaultConfig(__dirname)); const { @@ -28,16 +16,10 @@ module.exports = function (baseConfig) { } = defaultConfig; return mergeConfig(defaultConfig, { - watchFolders, resolver: { assetExts: assetExts.filter((ext) => ext !== 'svg'), sourceExts: [...sourceExts, 'svg', 'cjs', 'mjs'], resolverMainFields: ['sbmodern', 'react-native', 'browser', 'main'], - extraNodeModules: new Proxy (extraNodeModules, { - get: (target, name) => - name in target ? target[name] : path.join(process.cwd(), `node_modules/${name}`), - }), - unstable_enableSymlinks: true, }, transformer: { babelTransformerPath: require.resolve('./metro.transform.js'), From 9aa427d8608068761caf7fa8e984a57b2f9bfda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:09:02 +0000 Subject: [PATCH 09/21] bump @metamask/remote-feature-flag-controller --- package.json | 2 +- yarn.lock | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 51c37aa5462..397db788c1d 100644 --- a/package.json +++ b/package.json @@ -191,7 +191,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": "link:../../core/feature-flags/packages/remote-feature-flag-controller", + "@metamask/remote-feature-flag-controller": "^1.3.0", "@metamask/rpc-errors": "^7.0.1", "@metamask/scure-bip39": "^2.1.0", "@metamask/sdk-communication-layer": "0.29.0-wallet", diff --git a/yarn.lock b/yarn.lock index 8a0a63c5a38..3a0784cedfd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4452,6 +4452,14 @@ "@metamask/utils" "^10.0.0" immer "^9.0.6" +"@metamask/base-controller@^7.1.0": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@metamask/base-controller/-/base-controller-7.1.1.tgz#837216ee099563b2106202fa0ed376dc909dfbb9" + integrity sha512-4nbA6RL9y0SdHdn4MmMTREX6ISJL7OGHn0GXXszv0tp1fdjsn+SBs28uu1a9ceg1J7R/lO6JH7jAAz8zRtt8Nw== + dependencies: + "@metamask/utils" "^11.0.1" + immer "^9.0.6" + "@metamask/bitcoin-wallet-snap@^0.8.2": version "0.8.2" resolved "https://registry.yarnpkg.com/@metamask/bitcoin-wallet-snap/-/bitcoin-wallet-snap-0.8.2.tgz#dd37c48366997e6e9927837e28cc65a6008d1524" @@ -5137,9 +5145,15 @@ escape-string-regexp "^4.0.0" invariant "2.2.4" -"@metamask/remote-feature-flag-controller@link:../../core/feature-flags/packages/remote-feature-flag-controller": - version "0.0.0" - uid "" +"@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.1.0" + "@metamask/utils" "^11.0.1" + cockatiel "^3.1.2" + uuid "^8.3.2" "@metamask/rpc-errors@7.0.1", "@metamask/rpc-errors@^6.2.1", "@metamask/rpc-errors@^7.0.0", "@metamask/rpc-errors@^7.0.1": version "7.0.1" @@ -5410,7 +5424,7 @@ lodash "^4.17.21" uuid "^8.3.2" -"@metamask/utils@^10.0.0", "@metamask/utils@^10.0.1", "@metamask/utils@^8.2.0", "@metamask/utils@^8.3.0", "@metamask/utils@^9.0.0", "@metamask/utils@^9.1.0", "@metamask/utils@^9.2.1": +"@metamask/utils@^10.0.0", "@metamask/utils@^10.0.1", "@metamask/utils@^11.0.1", "@metamask/utils@^8.2.0", "@metamask/utils@^8.3.0", "@metamask/utils@^9.0.0", "@metamask/utils@^9.1.0", "@metamask/utils@^9.2.1": version "10.0.1" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-10.0.1.tgz#a765f96c20e35fc51c068fb9f88a3332b40b215e" integrity sha512-zHgAitJtRwviVVFnRUA2PLRMaAwatr3jiHgiH7mPicJaeSK4ma01aGR4fHy0iy5tlVo1ZiioTmJ1Hbp8FZ6pSg== From d44068e6fa535b0f59ea80a82bc63758524ed203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:27:37 +0000 Subject: [PATCH 10/21] revert indents --- app/core/Engine/Engine.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index fb078970ae3..ea36eb7325b 100644 --- a/app/core/Engine/Engine.ts +++ b/app/core/Engine/Engine.ts @@ -1178,7 +1178,7 @@ export class Engine { return Boolean( hasProperty(showIncomingTransactions, currentChainId) && - showIncomingTransactions?.[currentHexChainId], + showIncomingTransactions?.[currentHexChainId], ); }, updateTransactions: true, @@ -1523,7 +1523,7 @@ export class Engine { (state: NetworkState) => { if ( state.networksMetadata[state.selectedNetworkClientId].status === - NetworkStatus.Available && + NetworkStatus.Available && getGlobalChainId(networkController) !== currentChainId ) { // We should add a state or event emitter saying the provider changed @@ -1744,7 +1744,7 @@ export class Engine { const decimalsToShow = (currentCurrency === 'usd' && 2) || undefined; if ( accountsByChainId?.[toHexadecimal(chainId)]?.[ - selectSelectedInternalAccountFormattedAddress + selectSelectedInternalAccountFormattedAddress ] ) { // TODO - Non EVM accounts like BTC do not use hex formatted balances. We will need to modify this to use CAIP-2 identifiers in the future. @@ -1783,7 +1783,7 @@ export class Engine { const tokenBalances = allTokenBalances?.[selectedInternalAccount.address as Hex]?.[ - chainId + chainId ] ?? {}; tokens.forEach( (item: { address: string; balance?: string; decimals: number }) => { @@ -1794,9 +1794,9 @@ export class Engine { item.balance || (item.address in tokenBalances ? renderFromTokenMinimalUnit( - tokenBalances[item.address as Hex], - item.decimals, - ) + tokenBalances[item.address as Hex], + item.decimals, + ) : undefined); const tokenBalanceFiat = balanceToFiatNumber( // TODO: Fix this by handling or eliminating the undefined case From dee7b470bd0dd96bc3bdf677cd7edfc758da8e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:54:31 +0000 Subject: [PATCH 11/21] dedupe --- yarn.lock | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5e3a0387d75..e328d438207 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4444,15 +4444,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": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@metamask/base-controller/-/base-controller-7.0.2.tgz#bf908858215cd4f7d072b3b0f7f0946cf886ee49" - integrity sha512-zeZ5QPKedGT/r2M1NsT4lE7z4u9ciSNcOXG2vUdmfA+QT9YLwIm5+t56UGku3ZTjKGxDn9Ukca3BEkRc57Gt0A== - dependencies: - "@metamask/utils" "^10.0.0" - immer "^9.0.6" - -"@metamask/base-controller@^7.1.0": +"@metamask/base-controller@^7.0.1", "@metamask/base-controller@^7.0.2", "@metamask/base-controller@^7.1.0": version "7.1.1" resolved "https://registry.yarnpkg.com/@metamask/base-controller/-/base-controller-7.1.1.tgz#837216ee099563b2106202fa0ed376dc909dfbb9" integrity sha512-4nbA6RL9y0SdHdn4MmMTREX6ISJL7OGHn0GXXszv0tp1fdjsn+SBs28uu1a9ceg1J7R/lO6JH7jAAz8zRtt8Nw== From a77adcf50b89af5c5e3b1badbd625c9d841f7acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:40:43 +0000 Subject: [PATCH 12/21] fix feature flag controller unit tests --- .../controllers/RemoteFeatureFlagController/utils.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts index 39ab4c1013a..c22901d21dd 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(); From a81f019bb39a0fe4becbf8817953c954daad85b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:03:58 +0000 Subject: [PATCH 13/21] fix linter & sagas tests --- app/actions/user/types.ts | 1 - app/components/Nav/App/index.js | 1 + app/store/sagas/sagas.test.ts | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/actions/user/types.ts b/app/actions/user/types.ts index 5db9d6da977..25c08866fe6 100644 --- a/app/actions/user/types.ts +++ b/app/actions/user/types.ts @@ -1,4 +1,3 @@ -import { setMetaMetricsId } from '.'; import { type AppThemeKey } from '../../util/theme/models'; import { type Action } from 'redux'; diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 000c95523b6..c91014edbdb 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -753,6 +753,7 @@ const App = (props) => { }; initMetrics().then((metaMetricsId) => { + // eslint-disable-next-line react-hooks/exhaustive-deps dispatch(setMetaMetricsId(metaMetricsId)); }).catch((err) => { Logger.error(err, 'Error initializing MetaMetrics'); diff --git a/app/store/sagas/sagas.test.ts b/app/store/sagas/sagas.test.ts index 70ffa35e276..df187dabd36 100644 --- a/app/store/sagas/sagas.test.ts +++ b/app/store/sagas/sagas.test.ts @@ -156,6 +156,7 @@ describe('startAppServices', () => { // Dispatch both required actions .dispatch({ type: UserActionType.ON_PERSISTED_DATA_LOADED }) .dispatch({ type: NavigationActionType.ON_NAVIGATION_READY }) + .dispatch({ tyep: UserActionType.SET_METAMETRICS_ID }) .run(); // Verify services are started From e6324fd7d9389ade0e0b44ed18642b22539b0d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:04:26 +0000 Subject: [PATCH 14/21] fix typo --- app/store/sagas/sagas.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/store/sagas/sagas.test.ts b/app/store/sagas/sagas.test.ts index df187dabd36..fe1a64e6f05 100644 --- a/app/store/sagas/sagas.test.ts +++ b/app/store/sagas/sagas.test.ts @@ -156,7 +156,7 @@ describe('startAppServices', () => { // Dispatch both required actions .dispatch({ type: UserActionType.ON_PERSISTED_DATA_LOADED }) .dispatch({ type: NavigationActionType.ON_NAVIGATION_READY }) - .dispatch({ tyep: UserActionType.SET_METAMETRICS_ID }) + .dispatch({ type: UserActionType.SET_METAMETRICS_ID }) .run(); // Verify services are started From 00af1259ba37ac4f9411f281cec5bfe5ed90f285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:14:55 +0000 Subject: [PATCH 15/21] snapshot --- app/components/Nav/App/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index c91014edbdb..635a6f0ee23 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -753,11 +753,12 @@ const App = (props) => { }; initMetrics().then((metaMetricsId) => { - // eslint-disable-next-line react-hooks/exhaustive-deps dispatch(setMetaMetricsId(metaMetricsId)); }).catch((err) => { Logger.error(err, 'Error initializing MetaMetrics'); }); + // no need to include dispatch as a dependency + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { From b75a525fed2681a35ac65da17aaf52c15ff6b059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Thu, 16 Jan 2025 12:02:59 +0000 Subject: [PATCH 16/21] handle metametrics init failure --- app/components/Nav/App/index.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 635a6f0ee23..41a4706fc51 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -147,6 +147,7 @@ import { TraceOperation, } from '../../../util/trace'; import getUIStartupSpan from '../../../core/Performance/UIStartup'; +import { v4 as uuidv4 } from 'uuid'; const clearStackNavigatorOptions = { headerShown: false, @@ -595,6 +596,7 @@ const App = (props) => { const dispatch = useDispatch(); const sdkInit = useRef(); const [onboarded, setOnboarded] = useState(false); + const [isMetaMetricsConfigured, setIsMetaMetricsConfigured] = useState(false); trace({ name: TraceName.NavInit, @@ -739,9 +741,11 @@ const App = (props) => { }, [dispatch, handleDeeplink, navigator, queueOfHandleDeeplinkFunctions]); useEffect(() => { + if (isMetaMetricsConfigured) return; + const initMetrics = async () => { const metrics = MetaMetrics.getInstance(); - await metrics.configure(); + const metaMetricsConfigState = await metrics.configure(); // identify user with the latest traits // run only after the MetaMetrics is configured const consolidatedTraits = { @@ -749,6 +753,7 @@ const App = (props) => { ...generateUserSettingsAnalyticsMetaData(), }; await metrics.addTraitsToUser(consolidatedTraits); + setIsMetaMetricsConfigured(metaMetricsConfigState); return await metrics.getMetaMetricsId(); }; @@ -756,10 +761,11 @@ const App = (props) => { dispatch(setMetaMetricsId(metaMetricsId)); }).catch((err) => { Logger.error(err, 'Error initializing MetaMetrics'); + // Throw error instead of blocking Engine init + // metaMetricsId is a requirement for engine initialization + throw new Error('Error initializing. Please try again'); }); - // no need to include dispatch as a dependency - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [dispatch]); useEffect(() => { // Init SDKConnect only if the navigator is ready, user is onboarded, and SDK is not initialized. From b7f31b2fc98fd11ec43043795e5100f3ac91a7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Thu, 16 Jan 2025 12:08:42 +0000 Subject: [PATCH 17/21] revert metro transform changes --- metro.transform.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/metro.transform.js b/metro.transform.js index 5db70919a61..3354bcd0e0f 100644 --- a/metro.transform.js +++ b/metro.transform.js @@ -70,6 +70,9 @@ module.exports.transform = async ({ src, filename, options }) => { active: getBuildTypeFeatures(), }); + if (didModify) { + await lintTransformedFile(getESLintInstance(), filename, processedSource); + } return defaultTransformer.transform({ src: processedSource, filename, From 2b9f80779d475e71556dc59a986a56f5750fb488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:29:12 +0000 Subject: [PATCH 18/21] revert nav app changes --- app/components/Nav/App/index.js | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 41a4706fc51..32ec533e3ae 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -46,7 +46,6 @@ import { setCurrentRoute, onNavigationReady, } from '../../../actions/navigation'; -import { setMetaMetricsId } from '../../../actions/user'; import { findRouteNameFromNavigatorState } from '../../../util/general'; import { Authentication } from '../../../core/'; import { useTheme } from '../../../util/theme'; @@ -147,7 +146,6 @@ import { TraceOperation, } from '../../../util/trace'; import getUIStartupSpan from '../../../core/Performance/UIStartup'; -import { v4 as uuidv4 } from 'uuid'; const clearStackNavigatorOptions = { headerShown: false, @@ -596,7 +594,6 @@ const App = (props) => { const dispatch = useDispatch(); const sdkInit = useRef(); const [onboarded, setOnboarded] = useState(false); - const [isMetaMetricsConfigured, setIsMetaMetricsConfigured] = useState(false); trace({ name: TraceName.NavInit, @@ -741,11 +738,9 @@ const App = (props) => { }, [dispatch, handleDeeplink, navigator, queueOfHandleDeeplinkFunctions]); useEffect(() => { - if (isMetaMetricsConfigured) return; - const initMetrics = async () => { const metrics = MetaMetrics.getInstance(); - const metaMetricsConfigState = await metrics.configure(); + await metrics.configure(); // identify user with the latest traits // run only after the MetaMetrics is configured const consolidatedTraits = { @@ -753,19 +748,12 @@ const App = (props) => { ...generateUserSettingsAnalyticsMetaData(), }; await metrics.addTraitsToUser(consolidatedTraits); - setIsMetaMetricsConfigured(metaMetricsConfigState); - return await metrics.getMetaMetricsId(); }; - initMetrics().then((metaMetricsId) => { - dispatch(setMetaMetricsId(metaMetricsId)); - }).catch((err) => { + initMetrics().catch((err) => { Logger.error(err, 'Error initializing MetaMetrics'); - // Throw error instead of blocking Engine init - // metaMetricsId is a requirement for engine initialization - throw new Error('Error initializing. Please try again'); }); - }, [dispatch]); + }, []); useEffect(() => { // Init SDKConnect only if the navigator is ready, user is onboarded, and SDK is not initialized. From dc631d1fae471c560e5eea73e015d25663fd6d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:21:59 +0000 Subject: [PATCH 19/21] fix unit tests --- app/components/Nav/App/index.js | 5 ++++- .../RemoteFeatureFlagController/utils.test.ts | 9 +++++---- app/store/sagas/index.ts | 5 ++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 32ec533e3ae..92915b20743 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -46,6 +46,7 @@ import { setCurrentRoute, onNavigationReady, } from '../../../actions/navigation'; +import { setMetaMetricsId } from '../../../actions/user'; import { findRouteNameFromNavigatorState } from '../../../util/general'; import { Authentication } from '../../../core/'; import { useTheme } from '../../../util/theme'; @@ -748,12 +749,14 @@ const App = (props) => { ...generateUserSettingsAnalyticsMetaData(), }; await metrics.addTraitsToUser(consolidatedTraits); + const id = await metrics.getMetaMetricsId(); + dispatch(setMetaMetricsId(id)); }; initMetrics().catch((err) => { Logger.error(err, 'Error initializing MetaMetrics'); }); - }, []); + }, [dispatch]); useEffect(() => { // Init SDKConnect only if the navigator is ready, user is onboarded, and SDK is not initialized. diff --git a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts index c22901d21dd..add22ad2184 100644 --- a/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts +++ b/app/core/Engine/controllers/RemoteFeatureFlagController/utils.test.ts @@ -21,7 +21,7 @@ describe('RemoteFeatureFlagController utils', () => { state: undefined, messenger, disabled: false, - getMetaMetricsId: () => uuidv4() + getMetaMetricsId: () => uuidv4(), }); expect(controller).toBeDefined(); @@ -45,7 +45,7 @@ describe('RemoteFeatureFlagController utils', () => { state: initialState, messenger, disabled: false, - getMetaMetricsId: () => uuidv4() + getMetaMetricsId: () => uuidv4(), }); expect(controller.state).toStrictEqual(initialState); @@ -61,7 +61,7 @@ describe('RemoteFeatureFlagController utils', () => { state: undefined, messenger, disabled: false, - getMetaMetricsId: () => uuidv4() + getMetaMetricsId: () => uuidv4(), }); expect(spy).toHaveBeenCalled(); @@ -77,7 +77,7 @@ describe('RemoteFeatureFlagController utils', () => { state: undefined, messenger, disabled: true, - getMetaMetricsId: () => uuidv4() + getMetaMetricsId: () => uuidv4(), }); expect(spy).not.toHaveBeenCalled(); @@ -93,6 +93,7 @@ describe('RemoteFeatureFlagController utils', () => { state: initialState, messenger, disabled: false, + getMetaMetricsId: () => uuidv4(), }); expect(controller.state).toStrictEqual({ diff --git a/app/store/sagas/index.ts b/app/store/sagas/index.ts index 624a89e2a52..f4beba7f716 100644 --- a/app/store/sagas/index.ts +++ b/app/store/sagas/index.ts @@ -129,15 +129,14 @@ export function* basicFunctionalityToggle() { * Handles initializing app services on start up */ export function* startAppServices() { - // Wait for persisted data to be loaded and navigation to be ready + // Wait for persisted data to be loaded, navigation to be ready and metametrics initialized. + // Remote feature flag controller requires metaMetricsId to be initialized yield all([ take(UserActionType.ON_PERSISTED_DATA_LOADED), take(NavigationActionType.ON_NAVIGATION_READY), - //temp set metametrics id before engine init take(UserActionType.SET_METAMETRICS_ID), ]); // Start services - // init metametrics EngineService.start(); AppStateEventProcessor.start(); // TODO: Track a property in redux to gate keep the app until services are initialized From 3d4cdbd781571ae7539ac6e27ff09816b998e97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:14:10 +0000 Subject: [PATCH 20/21] revert redux metametricsId setup --- app/actions/user/index.ts | 13 ------------- app/actions/user/types.ts | 8 +------- app/components/Nav/App/index.js | 5 +---- app/reducers/user/index.ts | 6 ------ app/reducers/user/types.ts | 1 - app/store/sagas/index.ts | 4 +--- app/store/sagas/sagas.test.ts | 1 - 7 files changed, 3 insertions(+), 35 deletions(-) diff --git a/app/actions/user/index.ts b/app/actions/user/index.ts index 03533b9e509..9071fcffd50 100644 --- a/app/actions/user/index.ts +++ b/app/actions/user/index.ts @@ -21,7 +21,6 @@ import { type CheckedAuthAction, type PersistedDataLoadedAction, UserActionType, - SetMetaMetricsIdAction, } from './types'; export * from './types'; @@ -152,18 +151,6 @@ export function checkedAuth(initialScreen: string): CheckedAuthAction { }; } -/** - * Temporary action to initialize metametricsId before Engine Init - * - * @param metaMetricsId - MetaMetrics ID - */ -export function setMetaMetricsId(metaMetricsId: string): SetMetaMetricsIdAction { - return { - type: UserActionType.SET_METAMETRICS_ID, - payload: { metaMetricsId }, - } -} - /** * Action to signal that persisted data has been loaded */ diff --git a/app/actions/user/types.ts b/app/actions/user/types.ts index 25c08866fe6..704aee6092d 100644 --- a/app/actions/user/types.ts +++ b/app/actions/user/types.ts @@ -23,7 +23,6 @@ export enum UserActionType { SET_GAS_EDUCATION_CAROUSEL_SEEN = 'SET_GAS_EDUCATION_CAROUSEL_SEEN', SET_APP_THEME = 'SET_APP_THEME', CHECKED_AUTH = 'CHECKED_AUTH', - SET_METAMETRICS_ID = 'SET_METAMETRICS_ID', } // User actions @@ -86,10 +85,6 @@ export type CheckedAuthAction = Action & { payload: { initialScreen: string }; }; -export type SetMetaMetricsIdAction = Action & { - payload: { metaMetricsId: string }; -}; - /** * User actions union type */ @@ -113,5 +108,4 @@ export type UserAction = | LoadingUnsetAction | SetGasEducationCarouselSeenAction | SetAppThemeAction - | CheckedAuthAction - | SetMetaMetricsIdAction; + | CheckedAuthAction; diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 92915b20743..32ec533e3ae 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -46,7 +46,6 @@ import { setCurrentRoute, onNavigationReady, } from '../../../actions/navigation'; -import { setMetaMetricsId } from '../../../actions/user'; import { findRouteNameFromNavigatorState } from '../../../util/general'; import { Authentication } from '../../../core/'; import { useTheme } from '../../../util/theme'; @@ -749,14 +748,12 @@ const App = (props) => { ...generateUserSettingsAnalyticsMetaData(), }; await metrics.addTraitsToUser(consolidatedTraits); - const id = await metrics.getMetaMetricsId(); - dispatch(setMetaMetricsId(id)); }; initMetrics().catch((err) => { Logger.error(err, 'Error initializing MetaMetrics'); }); - }, [dispatch]); + }, []); useEffect(() => { // Init SDKConnect only if the navigator is ready, user is onboarded, and SDK is not initialized. diff --git a/app/reducers/user/index.ts b/app/reducers/user/index.ts index cba02446b6e..5941561d6ea 100644 --- a/app/reducers/user/index.ts +++ b/app/reducers/user/index.ts @@ -22,7 +22,6 @@ export const userInitialState: UserState = { initialScreen: '', appTheme: AppThemeKey.os, ambiguousAddressEntries: {}, - metaMetricsId: '', }; /** @@ -110,11 +109,6 @@ const userReducer = ( ...state, appTheme: action.payload.theme, }; - case UserActionType.SET_METAMETRICS_ID: - return { - ...state, - metaMetricsId: action.payload.metaMetricsId, - } default: return state; } diff --git a/app/reducers/user/types.ts b/app/reducers/user/types.ts index 44c66b57e55..4080aebc5ee 100644 --- a/app/reducers/user/types.ts +++ b/app/reducers/user/types.ts @@ -16,5 +16,4 @@ export interface UserState { initialScreen: string; appTheme: AppThemeKey; ambiguousAddressEntries: Record; - metaMetricsId: string; } diff --git a/app/store/sagas/index.ts b/app/store/sagas/index.ts index f4beba7f716..b7b0724a993 100644 --- a/app/store/sagas/index.ts +++ b/app/store/sagas/index.ts @@ -129,12 +129,10 @@ export function* basicFunctionalityToggle() { * Handles initializing app services on start up */ export function* startAppServices() { - // Wait for persisted data to be loaded, navigation to be ready and metametrics initialized. - // Remote feature flag controller requires metaMetricsId to be initialized + // Wait for persisted data to be loaded and navigation to be ready yield all([ take(UserActionType.ON_PERSISTED_DATA_LOADED), take(NavigationActionType.ON_NAVIGATION_READY), - take(UserActionType.SET_METAMETRICS_ID), ]); // Start services EngineService.start(); diff --git a/app/store/sagas/sagas.test.ts b/app/store/sagas/sagas.test.ts index fe1a64e6f05..70ffa35e276 100644 --- a/app/store/sagas/sagas.test.ts +++ b/app/store/sagas/sagas.test.ts @@ -156,7 +156,6 @@ describe('startAppServices', () => { // Dispatch both required actions .dispatch({ type: UserActionType.ON_PERSISTED_DATA_LOADED }) .dispatch({ type: NavigationActionType.ON_NAVIGATION_READY }) - .dispatch({ type: UserActionType.SET_METAMETRICS_ID }) .run(); // Verify services are started From 4d7c9b7b19a55e3148232c606bdbc64d66710210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <175489935+joaoloureirop@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:15:36 +0000 Subject: [PATCH 21/21] pass metaMetricsId into Engine contructor --- app/core/Engine/Engine.ts | 6 +- app/core/EngineService/EngineService.test.ts | 62 ++++++++++++-------- app/core/EngineService/EngineService.ts | 9 ++- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/app/core/Engine/Engine.ts b/app/core/Engine/Engine.ts index ea36eb7325b..deb931c10fc 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,7 +515,7 @@ export class Engine { allowedEvents: [], }), disabled: !isBasicFunctionalityToggleEnabled(), - getMetaMetricsId: () => store.getState().user.metaMetricsId, + getMetaMetricsId: () => metaMetricsId ?? '', }); const phishingController = new PhishingController({ @@ -2166,8 +2167,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/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