From 6d3a56aebc52c27005bc0b923ed5a7fdb28a251b Mon Sep 17 00:00:00 2001 From: Brian Bergeron Date: Fri, 13 Sep 2024 08:04:51 -0700 Subject: [PATCH] feat(migration): enable token auto-detection when basic functionality is on (#27110) Cherry picks https://github.com/MetaMask/metamask-extension/pull/26406 to 12.3.0 Co-authored-by: sahar-fehri --- app/scripts/migrations/125.1.test.ts | 107 ++++++++++++++++++ app/scripts/migrations/125.1.ts | 50 ++++++++ app/scripts/migrations/index.js | 1 + ...rs-after-init-opt-in-background-state.json | 2 +- .../errors-after-init-opt-in-ui-state.json | 2 +- .../multichain/asset-picker-send.spec.ts | 13 ++- 6 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 app/scripts/migrations/125.1.test.ts create mode 100644 app/scripts/migrations/125.1.ts diff --git a/app/scripts/migrations/125.1.test.ts b/app/scripts/migrations/125.1.test.ts new file mode 100644 index 000000000000..eb00db9d1e07 --- /dev/null +++ b/app/scripts/migrations/125.1.test.ts @@ -0,0 +1,107 @@ +import { migrate, version } from './125.1'; + +const oldVersion = 125; + +describe(`migration #${version}`, () => { + afterEach(() => jest.resetAllMocks()); + + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('Gracefully handles empty/undefined PreferencesController', async () => { + for (const PreferencesController of [{}, undefined, null, 1, '', []]) { + const oldStorage = { + meta: { version: oldVersion }, + data: { PreferencesController }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data.TxController).toStrictEqual(undefined); + } + }); + + it('Enables token autodetection when basic functionality is on', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PreferencesController: { + useExternalServices: true, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toEqual({ + PreferencesController: { + useExternalServices: true, + useTokenDetection: true, + }, + }); + }); + + it('Does not enable token autodetection when basic functionality is off', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PreferencesController: { + useExternalServices: false, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toEqual({ + PreferencesController: { + useExternalServices: false, + }, + }); + }); + + it('Removes showTokenAutodetectModalOnUpgrade from the app metadata controller', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + AppMetadataController: { + previousMigrationVersion: oldVersion, + currentMigrationVersion: version, + showTokenAutodetectModalOnUpgrade: null, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toEqual({ + AppMetadataController: { + previousMigrationVersion: oldVersion, + currentMigrationVersion: version, + }, + }); + }); + + it('Does nothing if showTokenAutodetectModalOnUpgrade is not in the app metadata controller', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + AppMetadataController: { + previousMigrationVersion: oldVersion, + currentMigrationVersion: version, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toEqual({ + AppMetadataController: { + previousMigrationVersion: oldVersion, + currentMigrationVersion: version, + }, + }); + }); +}); diff --git a/app/scripts/migrations/125.1.ts b/app/scripts/migrations/125.1.ts new file mode 100644 index 000000000000..d3c975a78a11 --- /dev/null +++ b/app/scripts/migrations/125.1.ts @@ -0,0 +1,50 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { cloneDeep } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 125.1; + +/** + * This migration enables token auto-detection if the basic functionality toggle is on. + * + * It also removes an unused property `showTokenAutodetectModalOnUpgrade` from the app metadata controller. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly + * what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by + * controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState(state: Record) { + if ( + hasProperty(state, 'PreferencesController') && + isObject(state.PreferencesController) && + state.PreferencesController.useExternalServices === true + ) { + state.PreferencesController.useTokenDetection = true; + } + + if ( + hasProperty(state, 'AppMetadataController') && + isObject(state.AppMetadataController) + ) { + delete state.AppMetadataController.showTokenAutodetectModalOnUpgrade; + } + + return state; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 0146779d408f..bb64ec957f75 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -144,6 +144,7 @@ const migrations = [ require('./123'), require('./124'), require('./125'), + require('./125.1'), ]; export default migrations; diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json index 7a4d6335dab5..2d2c362b30f8 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json @@ -175,7 +175,7 @@ "dismissSeedBackUpReminder": true, "useMultiAccountBalanceChecker": true, "useSafeChainsListValidation": "boolean", - "useTokenDetection": false, + "useTokenDetection": true, "useNftDetection": false, "use4ByteResolution": true, "useCurrencyRateCheck": true, diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json index c74b7f35c85d..d5ff2eecc5eb 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -109,7 +109,7 @@ "dismissSeedBackUpReminder": true, "useMultiAccountBalanceChecker": true, "useSafeChainsListValidation": true, - "useTokenDetection": false, + "useTokenDetection": true, "useNftDetection": false, "useCurrencyRateCheck": true, "useRequestQueue": true, diff --git a/test/e2e/tests/multichain/asset-picker-send.spec.ts b/test/e2e/tests/multichain/asset-picker-send.spec.ts index 8358e8242f69..5accb14c6074 100644 --- a/test/e2e/tests/multichain/asset-picker-send.spec.ts +++ b/test/e2e/tests/multichain/asset-picker-send.spec.ts @@ -34,6 +34,15 @@ describe('AssetPickerSendFlow @no-mmi', function () { async ({ driver }: { driver: Driver }) => { await unlockWallet(driver); + // Disable token auto detection + await driver.openNewURL( + `${driver.extensionUrl}/home.html#settings/security`, + ); + await driver.clickElement( + '[data-testid="autoDetectTokens"] .toggle-button', + ); + await driver.navigate(); + // Open the send flow openActionMenuAndStartSendFlow(driver); @@ -72,13 +81,13 @@ describe('AssetPickerSendFlow @no-mmi', function () { assert.equal(tokenListSecondaryValue, '$250,000.00'); - // Search for BNB + // Search for CHZ const searchInputField = await driver.waitForSelector( '[data-testid="asset-picker-modal-search-input"]', ); await searchInputField.sendKeys('CHZ'); - // check that BNB is disabled + // check that CHZ is disabled const [, tkn] = await driver.findElements( '[data-testid="multichain-token-list-button"]', );