Skip to content

feat: add setting to dismiss prompt to enable smart contract #31609

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 9, 2025
6 changes: 6 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion app/_locales/en_GB/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions app/scripts/controllers/preferences-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ describe('preferences controller', () => {
hideZeroBalanceTokens: false,
petnamesEnabled: true,
shouldShowAggregatedBalancePopover: true,
dismissSmartAccountSuggestionEnabled: false,
featureNotificationsEnabled: false,
showConfirmationAdvancedDetails: false,
showMultiRpcModal: false,
Expand Down Expand Up @@ -736,6 +737,7 @@ describe('preferences controller', () => {
petnamesEnabled: true,
privacyMode: false,
shouldShowAggregatedBalancePopover: true,
dismissSmartAccountSuggestionEnabled: false,
featureNotificationsEnabled: false,
showConfirmationAdvancedDetails: true,
showMultiRpcModal: false,
Expand Down
2 changes: 2 additions & 0 deletions app/scripts/controllers/preferences-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export type Preferences = {
};
tokenNetworkFilter: Record<string, boolean>;
shouldShowAggregatedBalancePopover: boolean;
dismissSmartAccountSuggestionEnabled: boolean;
};

// Omitting properties that already exist in the PreferencesState, as part of the preferences property.
Expand Down Expand Up @@ -200,6 +201,7 @@ export const getDefaultPreferencesControllerState =
showMultiRpcModal: false,
privacyMode: false,
shouldShowAggregatedBalancePopover: true, // by default user should see popover;
dismissSmartAccountSuggestionEnabled: false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have the accountUpgradeDisabledChains also, should this be combined into that?

Do we also want to display those in the settings UI?

Copy link
Contributor Author

@jpuri jpuri Apr 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep I was also thinking about re-using this - and I think this will be more a user level thing and not account level, additionally it will reflect across the app

tokenSortConfig: {
key: 'tokenFiatAmount',
order: 'dsc',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AuthorizationList } from '@metamask/transaction-controller';
import React from 'react';
import { act } from '@testing-library/react';
import * as ReduxFunctions from 'react-redux';

import configureStore from '../../../../../../store/store';
import { getMockConfirmStateForTransaction } from '../../../../../../../test/data/confirmations/helper';
import { genUnapprovedContractInteractionConfirmation } from '../../../../../../../test/data/confirmations/contract-interaction';
Expand Down Expand Up @@ -66,4 +68,10 @@ describe('Acknowledge', () => {
const { container } = render({});
expect(container).toBeEmptyDOMElement();
});

it('does not render if preference dismissSmartAccountSuggestionEnabled is enabled', () => {
jest.spyOn(ReduxFunctions, 'useSelector').mockReturnValue(true);
const { container } = render({});
expect(container).toBeEmptyDOMElement();
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { useIsUpgradeTransaction } from '../../info/hooks/useIsUpgradeTransaction';
import { getDismissSmartAccountSuggestionEnabled } from '../../../../../../selectors';
import { useI18nContext } from '../../../../../../hooks/useI18nContext';
import { Checkbox } from '../../../../../../components/component-library';
import { AlignItems } from '../../../../../../helpers/constants/design-system';
Expand All @@ -13,8 +16,11 @@ export function Acknowledge(props: AcknowledgeProps) {
const t = useI18nContext();
const isUpgradeTransaction = useIsUpgradeTransaction();
const { isAcknowledged, onAcknowledgeToggle } = props;
const dismissSmartAccountSuggestionEnabled = useSelector(
getDismissSmartAccountSuggestionEnabled,
);

if (!isUpgradeTransaction) {
if (!isUpgradeTransaction || dismissSmartAccountSuggestionEnabled) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately we can't just hide the acknowledge checkbox as the transaction would still perform the upgrade once approved.

If we instead check this here:

https://github.com/MetaMask/metamask-extension/blob/main/app/scripts/lib/transaction/eip5792.ts#L187

Then the middleware would reject the request outright since the user has said they never want to upgrade.

Plus technically we should also check if the user is already upgraded and skip this check, but that can be done in a separate ticket as I have pending changes in the transaction controller to get that information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh my bad, I fixed this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me create task for

Plus technically we should also check if the user is already upgraded and skip this check, but that can be done in a separate ticket as I have pending changes in the transaction controller to get that information.

return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,74 @@ exports[`AdvancedTab Component should match snapshot 1`] = `
</div>
</div>
</div>
<div
class="mm-box settings-page__content-row mm-box--display-flex mm-box--gap-4 mm-box--flex-direction-row mm-box--justify-content-space-between"
data-testid="advanced-setting-dismiss-smart-account-suggestion-enabled"
>
<div
class="settings-page__content-item"
>
<span>

Dismiss "Switch to Smart Account" suggestion
</span>
<div
class="settings-page__content-description"
>
Turn this on to no longer see the "Switch to Smart Account" suggestion on any account. Smart accounts unlocks faster transactions, lower network fees and more flexibility on payment for those.
</div>
</div>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--off"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(133, 139, 154);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 0; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 1;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: var(--shadow-size-xs) var(--color-shadow-default); border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(255, 255, 255); left: 3px;"
/>
</div>
<input
data-testid="settings-page-dismiss-smart-account-suggestion-enabled-toggle"
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="false"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
<div
class="mm-box settings-page__content-row mm-box--display-flex mm-box--gap-4 mm-box--flex-direction-row mm-box--justify-content-space-between"
data-testid="advanced-setting-enable-smart-transactions"
Expand Down
43 changes: 43 additions & 0 deletions ui/pages/settings/advanced-tab/advanced-tab.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export default class AdvancedTab extends PureComponent {
backupUserData: PropTypes.func.isRequired,
showExtensionInFullSizeView: PropTypes.bool,
setShowExtensionInFullSizeView: PropTypes.func.isRequired,
dismissSmartAccountSuggestionEnabled: PropTypes.bool.isRequired,
setDismissSmartAccountSuggestionEnabled: PropTypes.func.isRequired,
};

state = {
Expand Down Expand Up @@ -203,6 +205,46 @@ export default class AdvancedTab extends PureComponent {
);
}

renderToggleDismissSmartAccountSuggestion() {
const { t } = this.context;
const {
dismissSmartAccountSuggestionEnabled,
setDismissSmartAccountSuggestionEnabled,
} = this.props;

return (
<Box
ref={this.settingsRefs[2]}
className="settings-page__content-row"
data-testid="advanced-setting-dismiss-smart-account-suggestion-enabled"
display={Display.Flex}
flexDirection={FlexDirection.Row}
justifyContent={JustifyContent.spaceBetween}
gap={4}
>
<div className="settings-page__content-item">
<span> {t('dismissSmartAccountSuggestionEnabledTitle')}</span>
<div className="settings-page__content-description">
{t('dismissSmartAccountSuggestionEnabledDescription')}
</div>
</div>

<div className="settings-page__content-item-col">
<ToggleButton
value={dismissSmartAccountSuggestionEnabled}
onToggle={(oldValue) => {
const newValue = !oldValue;
setDismissSmartAccountSuggestionEnabled(newValue);
}}
offLabel={t('off')}
onLabel={t('on')}
dataTestId="settings-page-dismiss-smart-account-suggestion-enabled-toggle"
/>
</div>
</Box>
);
}

renderToggleStxOptIn() {
const { t } = this.context;
const { smartTransactionsEnabled, setSmartTransactionsEnabled } =
Expand Down Expand Up @@ -557,6 +599,7 @@ export default class AdvancedTab extends PureComponent {
) : null}
{this.renderStateLogs()}
{this.renderResetAccount()}
{this.renderToggleDismissSmartAccountSuggestion()}
{this.renderToggleStxOptIn()}
{this.renderHexDataOptIn()}
{this.renderShowConversionInTestnets()}
Expand Down
26 changes: 24 additions & 2 deletions ui/pages/settings/advanced-tab/advanced-tab.component.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const mockSetAutoLockTimeLimit = jest.fn().mockReturnValue({ type: 'TYPE' });
const mockSetShowTestNetworks = jest.fn();
const mockSetShowFiatConversionOnTestnetsPreference = jest.fn();
const mockSetStxPrefEnabled = jest.fn();
const mockSetDismissSmartAccountSuggestionEnabled = jest.fn();
const mockDisplayErrorInSettings = jest.fn();

jest.mock('../../../store/actions.ts', () => {
Expand All @@ -20,6 +21,8 @@ jest.mock('../../../store/actions.ts', () => {
setShowFiatConversionOnTestnetsPreference: () =>
mockSetShowFiatConversionOnTestnetsPreference,
setSmartTransactionsPreferenceEnabled: () => mockSetStxPrefEnabled,
setDismissSmartAccountSuggestionEnabled: () =>
mockSetDismissSmartAccountSuggestionEnabled,
};
});

Expand Down Expand Up @@ -102,7 +105,7 @@ describe('AdvancedTab Component', () => {
it('should toggle show fiat on test networks', () => {
const { queryAllByRole } = renderWithProvider(<AdvancedTab />, mockStore);

const testShowFiatOnTestnets = queryAllByRole('checkbox')[2];
const testShowFiatOnTestnets = queryAllByRole('checkbox')[3];

fireEvent.click(testShowFiatOnTestnets);

Expand All @@ -112,7 +115,7 @@ describe('AdvancedTab Component', () => {
it('should toggle show test networks', () => {
const { queryAllByRole } = renderWithProvider(<AdvancedTab />, mockStore);

const testNetworkToggle = queryAllByRole('checkbox')[3];
const testNetworkToggle = queryAllByRole('checkbox')[4];

fireEvent.click(testNetworkToggle);

Expand All @@ -134,6 +137,25 @@ describe('AdvancedTab Component', () => {
});
});

describe('renderToggleDismissSmartAccountSuggestion', () => {
it('should render the toggle button for Dismiss Smart Account Suggestion', () => {
const { queryByTestId } = renderWithProvider(<AdvancedTab />, mockStore);
const toggleButton = queryByTestId(
'advanced-setting-dismiss-smart-account-suggestion-enabled',
);
expect(toggleButton).toBeInTheDocument();
});

it('should call setSmartTransactionsOptInStatus when the toggle button is clicked', () => {
const { queryByTestId } = renderWithProvider(<AdvancedTab />, mockStore);
const toggleButton = queryByTestId(
'settings-page-dismiss-smart-account-suggestion-enabled-toggle',
);
fireEvent.click(toggleButton);
expect(mockSetDismissSmartAccountSuggestionEnabled).toHaveBeenCalled();
});
});

describe('renderStateLogs', () => {
it('should render the toggle button for state log download', () => {
const { queryByTestId } = renderWithProvider(<AdvancedTab />, mockStore);
Expand Down
6 changes: 6 additions & 0 deletions ui/pages/settings/advanced-tab/advanced-tab.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
backupUserData,
setAutoLockTimeLimit,
setDismissSeedBackUpReminder,
setDismissSmartAccountSuggestionEnabled,
setFeatureFlag,
setShowExtensionInFullSizeView,
setShowFiatConversionOnTestnetsPreference,
Expand All @@ -33,6 +34,7 @@ export const mapStateToProps = (state) => {
showTestNetworks,
showExtensionInFullSizeView,
autoLockTimeLimit = DEFAULT_AUTO_LOCK_TIME_LIMIT,
dismissSmartAccountSuggestionEnabled,
} = getPreferences(state);

return {
Expand All @@ -44,6 +46,7 @@ export const mapStateToProps = (state) => {
smartTransactionsEnabled: getSmartTransactionsPreferenceEnabled(state),
autoLockTimeLimit,
dismissSeedBackUpReminder,
dismissSmartAccountSuggestionEnabled,
};
};

Expand Down Expand Up @@ -75,6 +78,9 @@ export const mapDispatchToProps = (dispatch) => {
setDismissSeedBackUpReminder: (value) => {
return dispatch(setDismissSeedBackUpReminder(value));
},
setDismissSmartAccountSuggestionEnabled: (value) => {
return dispatch(setDismissSmartAccountSuggestionEnabled(value));
},
};
};

Expand Down
5 changes: 5 additions & 0 deletions ui/selectors/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,11 @@ export function getShouldShowAggregatedBalancePopover(state) {
return shouldShowAggregatedBalancePopover;
}

export function getDismissSmartAccountSuggestionEnabled(state) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use ui/pages/confirmations/selectors/preferences.ts instead of adding to this huge file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

const { dismissSmartAccountSuggestionEnabled } = getPreferences(state);
return dismissSmartAccountSuggestionEnabled;
}

export const getConnectedSnapsList = createDeepEqualSelector(
getSnapsList,
(snapsData) => {
Expand Down
4 changes: 4 additions & 0 deletions ui/store/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3262,6 +3262,10 @@ export function setShowExtensionInFullSizeView(value: boolean) {
return setPreference('showExtensionInFullSizeView', value);
}

export function setDismissSmartAccountSuggestionEnabled(value: boolean) {
return setPreference('setDismissSmartAccountSuggestionEnabled', value);
}

export function setTokenSortConfig(value: SortCriteria) {
return setPreference('tokenSortConfig', value, false);
}
Expand Down
Loading