diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index b99c3976b8c9..b2754b85e4f2 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -405,6 +405,9 @@
"allow": {
"message": "Allow"
},
+ "allowMetaMaskToDetectTokens": {
+ "message": "Allow MetaMask to detect and display your tokens with autodetection. You’ll be able to:"
+ },
"allowMmiToConnectToCustodian": {
"message": "This will allow MMI to connect to $1 to import your accounts."
},
@@ -1529,6 +1532,9 @@
"displayNftMediaDescription": {
"message": "Displaying NFT media and data exposes your IP address to OpenSea or other third parties. This can allow attackers to associate your IP address with your Ethereum address. NFT autodetection relies on this setting, and won't be available when this is turned off."
},
+ "diveStraightIntoUsingYourTokens": {
+ "message": "Dive straight into using your tokens"
+ },
"doNotShare": {
"message": "Do not share this with anyone"
},
@@ -1657,6 +1663,9 @@
"editSpeedUpEditGasFeeModalTitle": {
"message": "Edit speed up gas fee"
},
+ "effortlesslyNavigateYourDigitalAssets": {
+ "message": "Effortlessly navigate your digital assets"
+ },
"enable": {
"message": "Enable"
},
@@ -1673,6 +1682,9 @@
"message": "enable $1",
"description": "$1 is a token symbol, e.g. ETH"
},
+ "enableTokenAutoDetection": {
+ "message": "Enable token autodetection"
+ },
"enabled": {
"message": "Enabled"
},
@@ -2161,6 +2173,9 @@
"imToken": {
"message": "imToken"
},
+ "immediateAccessToYourTokens": {
+ "message": "Immediate access to your tokens"
+ },
"import": {
"message": "Import",
"description": "Button to import an account from a selected file"
@@ -3094,6 +3109,9 @@
"notEnoughGas": {
"message": "Not enough gas"
},
+ "notRightNow": {
+ "message": "Not right now"
+ },
"note": {
"message": "Note"
},
diff --git a/app/images/wallet-alpha.png b/app/images/wallet-alpha.png
new file mode 100644
index 000000000000..bc88bcfb5f2d
Binary files /dev/null and b/app/images/wallet-alpha.png differ
diff --git a/app/scripts/controllers/app-metadata.ts b/app/scripts/controllers/app-metadata.ts
index 0d745730d0c0..79d346c8412d 100644
--- a/app/scripts/controllers/app-metadata.ts
+++ b/app/scripts/controllers/app-metadata.ts
@@ -9,6 +9,7 @@ export type AppMetadataControllerState = {
previousAppVersion: string;
previousMigrationVersion: number;
currentMigrationVersion: number;
+ showTokenAutodetectModalOnUpgrade: boolean | null;
};
/**
@@ -25,6 +26,7 @@ const defaultState: AppMetadataControllerState = {
previousAppVersion: '',
previousMigrationVersion: 0,
currentMigrationVersion: 0,
+ showTokenAutodetectModalOnUpgrade: false,
};
/**
@@ -76,6 +78,7 @@ export default class AppMetadataController extends EventEmitter {
this.store.updateState({
currentAppVersion: maybeNewAppVersion,
previousAppVersion: oldCurrentAppVersion,
+ showTokenAutodetectModalOnUpgrade: null,
});
}
}
@@ -96,4 +99,13 @@ export default class AppMetadataController extends EventEmitter {
});
}
}
+
+ /**
+ * Setter for the `showTokenAutodetectModalOnUpgrade` property
+ *
+ * @param val - Indicates the value of showTokenAutodetectModalOnUpgrade
+ */
+ setShowTokenAutodetectModalOnUpgrade(val: boolean): void {
+ this.store.updateState({ showTokenAutodetectModalOnUpgrade: val });
+ }
}
diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js
index 635eb5d4fc77..a8b6b7f1a755 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -97,6 +97,7 @@ export default class PreferencesController {
petnamesEnabled: true,
redesignedConfirmationsEnabled: true,
featureNotificationsEnabled: false,
+ showTokenAutodetectModal: null,
},
// ENS decentralized website resolution
ipfsGateway: IPFS_DEFAULT_GATEWAY_URL,
diff --git a/app/scripts/lib/backup.test.js b/app/scripts/lib/backup.test.js
index 81a7cd8c0093..b9f209a9a408 100644
--- a/app/scripts/lib/backup.test.js
+++ b/app/scripts/lib/backup.test.js
@@ -163,6 +163,7 @@ const jsonData = JSON.stringify({
showTestNetworks: true,
smartTransactionsOptInStatus: false,
useNativeCurrencyAsPrimaryCurrency: true,
+ showTokenAutodetectModal: false,
},
ipfsGateway: 'dweb.link',
ledgerTransportType: 'webhid',
diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js
index d0cdef3d6480..8cc5881d08d1 100644
--- a/app/scripts/lib/setupSentry.js
+++ b/app/scripts/lib/setupSentry.js
@@ -79,6 +79,7 @@ export const SENTRY_BACKGROUND_STATE = {
currentMigrationVersion: true,
previousAppVersion: true,
previousMigrationVersion: true,
+ showTokenAutodetectModalOnUpgrade: false,
},
ApprovalController: {
approvalFlows: false,
@@ -240,6 +241,7 @@ export const SENTRY_BACKGROUND_STATE = {
smartTransactionsOptInStatus: true,
useNativeCurrencyAsPrimaryCurrency: true,
petnamesEnabled: true,
+ showTokenAutodetectModal: false,
},
useExternalServices: false,
selectedAddress: false,
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 5d91f0f03ae1..52289a11182c 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -2961,6 +2961,7 @@ export default class MetamaskController extends EventEmitter {
networkController,
announcementController,
onboardingController,
+ appMetadataController,
permissionController,
preferencesController,
swapsController,
@@ -3394,6 +3395,12 @@ export default class MetamaskController extends EventEmitter {
this.encryptionPublicKeyController,
),
+ // AppMetadataController
+ setShowTokenAutodetectModalOnUpgrade:
+ appMetadataController.setShowTokenAutodetectModalOnUpgrade.bind(
+ appMetadataController,
+ ),
+
// onboarding controller
setSeedPhraseBackedUp:
onboardingController.setSeedPhraseBackedUp.bind(onboardingController),
diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts
index 9a9f8e7b9b13..e3f5dd805145 100644
--- a/shared/constants/metametrics.ts
+++ b/shared/constants/metametrics.ts
@@ -712,6 +712,8 @@ export enum MetaMetricsEventName {
SnapAccountTransactionFinalizeRedirectGoToSiteClicked = 'Snap Account Transaction Finalize Redirect "Go To Site" Clicked',
SnapAccountTransactionFinalizeRedirectSnapUrlClicked = 'Snap Account Transaction Finalize Redirect "Snap URL" Clicked',
SnapAccountTransactionFinalizeClosed = 'Snap Account Transaction Finalize Closed',
+ TokenAutoDetectionEnableModal = 'Token Autodetection Enabled from modal',
+ TokenAutoDetectionDisableModal = 'Token Autodetection Disabled from modal',
///: END:ONLY_INCLUDE_IF
TurnOffProfileSyncing = 'Turn Off Profile Syncing',
TurnOnProfileSyncing = 'Turn On Profile Syncing',
diff --git a/shared/modules/selectors/index.test.ts b/shared/modules/selectors/index.test.ts
index b2174eadcc8a..6f1298952d76 100644
--- a/shared/modules/selectors/index.test.ts
+++ b/shared/modules/selectors/index.test.ts
@@ -13,6 +13,7 @@ describe('Selectors', () => {
metamask: {
preferences: {
smartTransactionsOptInStatus: true,
+ showTokenAutodetectModal: true,
},
internalAccounts: {
selectedAccount: 'account1',
@@ -68,6 +69,14 @@ describe('Selectors', () => {
});
});
+ describe('getShowTokenAutodetectModal', () => {
+ it('should return show autodetection token modal status', () => {
+ const state = createMockState();
+ const result = getSmartTransactionsOptInStatus(state);
+ expect(result).toBe(true);
+ });
+ });
+
describe('getCurrentChainSupportsSmartTransactions', () => {
it('should return true if the chain ID is allowed for smart transactions', () => {
const state = createMockState();
diff --git a/shared/modules/selectors/index.ts b/shared/modules/selectors/index.ts
index 79362360877f..51c2d67f930c 100644
--- a/shared/modules/selectors/index.ts
+++ b/shared/modules/selectors/index.ts
@@ -1,2 +1,3 @@
export * from './smart-transactions';
export * from './feature-flags';
+export * from './token-auto-detect';
diff --git a/shared/modules/selectors/token-auto-detect.ts b/shared/modules/selectors/token-auto-detect.ts
new file mode 100644
index 000000000000..a6680a47af8d
--- /dev/null
+++ b/shared/modules/selectors/token-auto-detect.ts
@@ -0,0 +1,32 @@
+import { getUseTokenDetection } from '../../../ui/selectors/selectors';
+
+type TokenAutoDetectionMetaMaskState = {
+ metamask: {
+ preferences: {
+ showTokenAutodetectModal: boolean | null;
+ };
+ showTokenAutodetectModalOnUpgrade: boolean | null;
+ };
+};
+
+export const getShowTokenAutodetectModal = (
+ state: TokenAutoDetectionMetaMaskState,
+): boolean | null => {
+ return state.metamask.preferences?.showTokenAutodetectModal;
+};
+
+export const getIsShowTokenAutodetectModal = (
+ state: TokenAutoDetectionMetaMaskState,
+) => {
+ // Upgrade case
+ if (state.metamask.showTokenAutodetectModalOnUpgrade === null) {
+ return (
+ !getUseTokenDetection(state) &&
+ state.metamask.showTokenAutodetectModalOnUpgrade === null
+ );
+ }
+
+ return (
+ !getUseTokenDetection(state) && getShowTokenAutodetectModal(state) === null
+ );
+};
diff --git a/test/e2e/default-fixture.js b/test/e2e/default-fixture.js
index eb6c6ea7f4a4..74b526bb532c 100644
--- a/test/e2e/default-fixture.js
+++ b/test/e2e/default-fixture.js
@@ -190,6 +190,7 @@ function defaultFixture(inputChainId = CHAIN_IDS.LOCALHOST) {
smartTransactionsOptInStatus: false,
useNativeCurrencyAsPrimaryCurrency: true,
petnamesEnabled: true,
+ showTokenAutodetectModal: false,
},
selectedAddress: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1',
theme: 'light',
diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js
index e52fed2cfae4..04f5dd5e06b5 100644
--- a/test/e2e/fixture-builder.js
+++ b/test/e2e/fixture-builder.js
@@ -87,6 +87,7 @@ function onboardingFixture() {
smartTransactionsOptInStatus: false,
useNativeCurrencyAsPrimaryCurrency: true,
petnamesEnabled: true,
+ showTokenAutodetectModal: false,
},
useExternalServices: true,
theme: 'light',
diff --git a/test/e2e/restore/MetaMaskUserData.json b/test/e2e/restore/MetaMaskUserData.json
index 0f400e8a34e7..380efd5c5205 100644
--- a/test/e2e/restore/MetaMaskUserData.json
+++ b/test/e2e/restore/MetaMaskUserData.json
@@ -37,7 +37,8 @@
"showFiatInTestnets": false,
"showTestNetworks": false,
"smartTransactionsOptInStatus": false,
- "useNativeCurrencyAsPrimaryCurrency": true
+ "useNativeCurrencyAsPrimaryCurrency": true,
+ "showTokenAutodetectModal": "boolean"
},
"theme": "light",
"useBlockie": false,
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 f76c758dc98d..5570ea4b92ba 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
@@ -18,7 +18,8 @@
"currentAppVersion": "string",
"previousAppVersion": "",
"previousMigrationVersion": 0,
- "currentMigrationVersion": "number"
+ "currentMigrationVersion": "number",
+ "showTokenAutodetectModalOnUpgrade": "object"
},
"AppStateController": {
"connectedStatusPopoverHasBeenShown": true,
@@ -187,7 +188,8 @@
"showTestNetworks": false,
"smartTransactionsOptInStatus": false,
"useNativeCurrencyAsPrimaryCurrency": true,
- "petnamesEnabled": true
+ "petnamesEnabled": true,
+ "showTokenAutodetectModal": "boolean"
},
"ipfsGateway": "string",
"isIpfsGatewayEnabled": "boolean",
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 416bc7fc6fc8..ac852521854d 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
@@ -33,7 +33,8 @@
"showTestNetworks": false,
"smartTransactionsOptInStatus": false,
"useNativeCurrencyAsPrimaryCurrency": true,
- "petnamesEnabled": true
+ "petnamesEnabled": true,
+ "showTokenAutodetectModal": "boolean"
},
"firstTimeFlowType": "import",
"completedOnboarding": true,
@@ -91,6 +92,7 @@
"previousMigrationVersion": 0,
"currentMigrationVersion": "number",
"selectedNetworkClientId": "string",
+ "showTokenAutodetectModalOnUpgrade": "object",
"networksMetadata": {
"networkConfigurationId": {
"EIPS": { "1559": false },
diff --git a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json
index f8f209648ccd..707752ddef05 100644
--- a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json
+++ b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json
@@ -112,7 +112,8 @@
"showTestNetworks": false,
"smartTransactionsOptInStatus": false,
"useNativeCurrencyAsPrimaryCurrency": true,
- "petnamesEnabled": true
+ "petnamesEnabled": true,
+ "showTokenAutodetectModal": "boolean"
},
"selectedAddress": "string",
"theme": "light",
diff --git a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json
index 472e9ea517fb..cccbca085552 100644
--- a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json
+++ b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json
@@ -112,7 +112,8 @@
"showTestNetworks": false,
"smartTransactionsOptInStatus": false,
"useNativeCurrencyAsPrimaryCurrency": true,
- "petnamesEnabled": true
+ "petnamesEnabled": true,
+ "showTokenAutodetectModal": "boolean"
},
"selectedAddress": "string",
"theme": "light",
diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js
index 0719c6f1eea8..234a1316b94c 100644
--- a/test/jest/mock-store.js
+++ b/test/jest/mock-store.js
@@ -151,6 +151,7 @@ export const createSwapsMockStore = () => {
preferences: {
showFiatInTestnets: true,
smartTransactionsOptInStatus: true,
+ showTokenAutodetectModal: false,
},
transactions: [
{
diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss
index 4623b27cfd91..e516ff1fd8f6 100644
--- a/ui/components/app/app-components.scss
+++ b/ui/components/app/app-components.scss
@@ -45,6 +45,7 @@
@import 'recovery-phrase-reminder/index';
@import 'step-progress-bar/index.scss';
@import 'selected-account/index';
+@import 'auto-detect-token/index';
@import 'smart-transactions/index';
@import 'srp-input/srp-input';
@import 'snaps/snap-privacy-warning/index';
diff --git a/ui/components/app/auto-detect-token/auto-detect-token-modal.test.stories.js b/ui/components/app/auto-detect-token/auto-detect-token-modal.test.stories.js
new file mode 100644
index 000000000000..f9164697d402
--- /dev/null
+++ b/ui/components/app/auto-detect-token/auto-detect-token-modal.test.stories.js
@@ -0,0 +1,48 @@
+import React from 'react';
+import { Provider } from 'react-redux';
+import testData from '../../../../.storybook/test-data';
+import configureStore from '../../../store/store';
+import AutoDetectTokenModal from './auto-detect-token-modal';
+
+const customData = {
+ ...testData,
+ metamask: {
+ ...testData.metamask,
+ currentCurrency: 'USD',
+ intlLocale: 'en-US',
+ },
+};
+const customStore = configureStore(customData);
+
+export default {
+ title: 'Components/App/AutoDetectTokenModal',
+ component: AutoDetectTokenModal,
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ argTypes: {
+ isOpen: {
+ control: 'boolean',
+ },
+ onClose: { action: 'onClose' },
+ },
+ args: {
+ isOpen: true,
+ },
+};
+
+const Template = (args) => ;
+
+export const ModalOpen = Template.bind({});
+ModalOpen.args = {
+ isOpen: true,
+};
+
+export const ModalClosed = Template.bind({});
+ModalClosed.args = {
+ isOpen: false,
+};
diff --git a/ui/components/app/auto-detect-token/auto-detect-token-modal.test.tsx b/ui/components/app/auto-detect-token/auto-detect-token-modal.test.tsx
new file mode 100644
index 000000000000..95f2dc8127a5
--- /dev/null
+++ b/ui/components/app/auto-detect-token/auto-detect-token-modal.test.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import { screen, fireEvent } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { useDispatch } from 'react-redux';
+import configureMockStore from 'redux-mock-store';
+import mockState from '../../../../test/data/mock-state.json';
+import { renderWithProvider } from '../../../../test/lib/render-helpers';
+import AutoDetectTokenModal from './auto-detect-token-modal';
+
+// Mock store setup
+const mockStore = configureMockStore([])(mockState);
+
+jest.mock('react-redux', () => ({
+ ...jest.requireActual('react-redux'),
+ useDispatch: jest.fn(),
+}));
+
+describe('AutoDetectTokenModal', () => {
+ const useDispatchMock = jest.mocked(useDispatch);
+
+ beforeEach(() => {
+ jest.resetAllMocks();
+ useDispatchMock.mockReturnValue(jest.fn());
+ });
+
+ it('renders the modal when isOpen is true', () => {
+ renderWithProvider(
+ ({})}
+ setShowTokenAutodetectModalOnUpgrade={() => ({})}
+ />,
+ mockStore,
+ );
+
+ expect(screen.getByText('Enable token autodetection')).toBeInTheDocument();
+ expect(screen.getByText('Allow')).toBeInTheDocument();
+ expect(screen.getByText('Not right now')).toBeInTheDocument();
+ });
+
+ it('calls onClose with true when Allow button is clicked', () => {
+ useDispatchMock.mockReturnValue(jest.fn().mockResolvedValue({}));
+ const handleClose = jest.fn();
+ renderWithProvider(
+ ({})}
+ />,
+ mockStore,
+ );
+
+ fireEvent.click(screen.getByText('Allow'));
+ expect(handleClose).toHaveBeenCalledWith(true);
+ });
+
+ it('calls onClose with false when Not right now button is clicked', () => {
+ useDispatchMock.mockReturnValue(jest.fn().mockResolvedValue({}));
+ const handleClose = jest.fn();
+ const handleSetShowTokenAutodetectModalOnUpgrade = jest.fn();
+ renderWithProvider(
+ ,
+ mockStore,
+ );
+
+ fireEvent.click(screen.getByText('Not right now'));
+ expect(handleClose).toHaveBeenCalledWith(false);
+ });
+});
diff --git a/ui/components/app/auto-detect-token/auto-detect-token-modal.tsx b/ui/components/app/auto-detect-token/auto-detect-token-modal.tsx
new file mode 100644
index 000000000000..27ea2bfcaf70
--- /dev/null
+++ b/ui/components/app/auto-detect-token/auto-detect-token-modal.tsx
@@ -0,0 +1,138 @@
+import React, { useCallback, useContext } from 'react';
+
+import { useDispatch, useSelector } from 'react-redux';
+import {
+ Modal,
+ ModalContent,
+ ModalOverlay,
+ ModalHeader,
+ Box,
+ Text,
+ ModalBody,
+ ModalFooter,
+} from '../../component-library';
+import { useI18nContext } from '../../../hooks/useI18nContext';
+import {
+ AlignItems,
+ BorderRadius,
+ Display,
+ FlexDirection,
+ JustifyContent,
+ TextAlign,
+ TextVariant,
+} from '../../../helpers/constants/design-system';
+import { setUseTokenDetection } from '../../../store/actions';
+import { MetaMetricsContext } from '../../../contexts/metametrics';
+import {
+ MetaMetricsEventCategory,
+ MetaMetricsEventName,
+} from '../../../../shared/constants/metametrics';
+import { getProviderConfig } from '../../../ducks/metamask/metamask';
+import { getCurrentLocale } from '../../../ducks/locale/locale';
+import { ORIGIN_METAMASK } from '../../../../shared/constants/app';
+
+type AutoDetectTokenModalProps = {
+ isOpen: boolean;
+ onClose: (arg: boolean) => void;
+ setShowTokenAutodetectModalOnUpgrade: (arg: boolean) => void;
+};
+function AutoDetectTokenModal({
+ isOpen,
+ onClose,
+ setShowTokenAutodetectModalOnUpgrade,
+}: AutoDetectTokenModalProps) {
+ const t = useI18nContext();
+ const dispatch = useDispatch();
+ const trackEvent = useContext(MetaMetricsContext);
+ const { chainId } = useSelector(getProviderConfig);
+
+ const handleTokenAutoDetection = useCallback(
+ (val) => {
+ trackEvent({
+ event: val
+ ? MetaMetricsEventName.TokenAutoDetectionEnableModal
+ : MetaMetricsEventName.TokenAutoDetectionDisableModal,
+ category: MetaMetricsEventCategory.Navigation,
+ properties: {
+ chain_id: chainId,
+ locale: getCurrentLocale,
+ referrer: ORIGIN_METAMASK,
+ },
+ });
+ dispatch(setUseTokenDetection(val));
+ onClose(val);
+ setShowTokenAutodetectModalOnUpgrade(val);
+ },
+ [dispatch],
+ );
+
+ return (
+ onClose(true)}
+ isClosedOnOutsideClick={false}
+ isClosedOnEscapeKey={false}
+ className="mm-modal__custom-scrollbar auto-detect-in-modal"
+ autoFocus={false}
+ >
+
+
+
+ {t('enableTokenAutoDetection')}
+
+
+
+
+
+
+ {t('allowMetaMaskToDetectTokens')}
+
+
+ {t('immediateAccessToYourTokens')}
+
+
+ {t('effortlesslyNavigateYourDigitalAssets')}
+
+
+ {t('diveStraightIntoUsingYourTokens')}
+
+
+
+
+ handleTokenAutoDetection(true)}
+ submitButtonProps={{
+ children: t('allow'),
+ block: true,
+ }}
+ onCancel={() => handleTokenAutoDetection(false)}
+ cancelButtonProps={{
+ children: t('notRightNow'),
+ block: true,
+ }}
+ />
+
+
+ );
+}
+
+export default AutoDetectTokenModal;
diff --git a/ui/components/app/auto-detect-token/index.scss b/ui/components/app/auto-detect-token/index.scss
new file mode 100644
index 000000000000..5714d957f0f9
--- /dev/null
+++ b/ui/components/app/auto-detect-token/index.scss
@@ -0,0 +1,10 @@
+.auto-detect-in-modal {
+ &__benefit {
+ flex: 1;
+ }
+
+ &__dialog {
+ background-position: -80px 16px;
+ background-repeat: no-repeat;
+ }
+}
diff --git a/ui/components/multichain/asset-picker-amount/asset-picker/asset-picker.tsx b/ui/components/multichain/asset-picker-amount/asset-picker/asset-picker.tsx
index 1d39f37b2bd6..4c7be3c9db44 100644
--- a/ui/components/multichain/asset-picker-amount/asset-picker/asset-picker.tsx
+++ b/ui/components/multichain/asset-picker-amount/asset-picker/asset-picker.tsx
@@ -111,6 +111,7 @@ export function AssetPicker({
sendingAsset?.details?.symbol || nativeCurrencySymbol
}
/>
+
+
+
+
{showWhatsNew ? : null}
{!showWhatsNew && showRecoveryPhraseReminder ? (
{
///: END:ONLY_INCLUDE_IF
isSmartTransactionsOptInModalAvailable:
getIsSmartTransactionsOptInModalAvailable(state),
+ isShowTokenAutodetectModal: getIsShowTokenAutodetectModal(state),
};
};
@@ -248,6 +254,12 @@ const mapDispatchToProps = (dispatch) => {
setActiveNetwork: (networkConfigurationId) => {
dispatch(setActiveNetwork(networkConfigurationId));
},
+ setTokenAutodetectModal: (val) => {
+ dispatch(setShowTokenAutodetectModal(val));
+ },
+ setShowTokenAutodetectModalOnUpgrade: (val) => {
+ dispatch(setShowTokenAutodetectModalOnUpgrade(val));
+ },
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
setWaitForConfirmDeepLinkDialog: (wait) =>
dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(wait)),
diff --git a/ui/store/actionConstants.ts b/ui/store/actionConstants.ts
index 26cc4fbde04c..2029dbd7f94e 100644
--- a/ui/store/actionConstants.ts
+++ b/ui/store/actionConstants.ts
@@ -101,6 +101,9 @@ export const CLEAR_PENDING_TOKENS = 'CLEAR_PENDING_TOKENS';
export const SET_FIRST_TIME_FLOW_TYPE = 'SET_FIRST_TIME_FLOW_TYPE';
+export const SET_SHOW_TOKEN_AUTO_DETECT_MODAL_UPGRADE =
+ 'SET_SHOW_TOKEN_AUTO_DETECT_MODAL_UPGRADE';
+
export const SET_SELECTED_NETWORK_CONFIGURATION_ID =
'SET_SELECTED_NETWORK_CONFIGURATION_ID';
export const SET_NEW_NETWORK_ADDED = 'SET_NEW_NETWORK_ADDED';
diff --git a/ui/store/actions.ts b/ui/store/actions.ts
index 462483b68ec5..9dbac37da682 100644
--- a/ui/store/actions.ts
+++ b/ui/store/actions.ts
@@ -3115,6 +3115,10 @@ export function setSmartTransactionsOptInStatus(
};
}
+export function setShowTokenAutodetectModal(value: boolean) {
+ return setPreference('showTokenAutodetectModal', value);
+}
+
export function setAutoLockTimeLimit(value: boolean) {
return setPreference('autoLockTimeLimit', value);
}
@@ -4080,6 +4084,27 @@ export function setFirstTimeFlowType(
};
}
+export function setShowTokenAutodetectModalOnUpgrade(
+ val: boolean,
+): ThunkAction {
+ return (dispatch: MetaMaskReduxDispatch) => {
+ log.debug(`background.setShowTokenAutodetectModalOnUpgrade`);
+ callBackgroundMethod(
+ 'setShowTokenAutodetectModalOnUpgrade',
+ [val],
+ (err) => {
+ if (err) {
+ dispatch(displayWarning(err));
+ }
+ },
+ );
+ dispatch({
+ type: actionConstants.SET_SHOW_TOKEN_AUTO_DETECT_MODAL_UPGRADE,
+ value: val,
+ });
+ };
+}
+
export function setSelectedNetworkConfigurationId(
networkConfigurationId: string,
): PayloadAction {