Skip to content

Commit ccd3cbc

Browse files
authored
feat: add setting to dismiss prompt to enable smart contract (#31609)
## **Description** We should add a toggle within Settings > Advanced to not be asked to update an account to a Smart Account again. ## **Related issues** Fixes: MetaMask/MetaMask-planning#4559 ## **Manual testing steps** 1. Go to settings > advance 2. Toggle on option Dismiss `"Switch to Smart Account" suggestion` 3. Ensure that propmt does not appear again ## **Screenshots/Recordings** <img width="1077" alt="Screenshot 2025-04-04 at 9 29 08 PM" src="https://github.com/user-attachments/assets/25a55645-67cc-4aa6-9bbd-c72783dfa15d" /> ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I’ve included tests if applicable - [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
1 parent d990dfb commit ccd3cbc

File tree

12 files changed

+224
-7
lines changed

12 files changed

+224
-7
lines changed

app/_locales/en/messages.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/_locales/en_GB/messages.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/scripts/controllers/preferences-controller.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ describe('preferences controller', () => {
708708
hideZeroBalanceTokens: false,
709709
petnamesEnabled: true,
710710
shouldShowAggregatedBalancePopover: true,
711+
dismissSmartAccountSuggestionEnabled: false,
711712
featureNotificationsEnabled: false,
712713
showConfirmationAdvancedDetails: false,
713714
showMultiRpcModal: false,
@@ -736,6 +737,7 @@ describe('preferences controller', () => {
736737
petnamesEnabled: true,
737738
privacyMode: false,
738739
shouldShowAggregatedBalancePopover: true,
740+
dismissSmartAccountSuggestionEnabled: false,
739741
featureNotificationsEnabled: false,
740742
showConfirmationAdvancedDetails: true,
741743
showMultiRpcModal: false,

app/scripts/controllers/preferences-controller.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export type Preferences = {
106106
};
107107
tokenNetworkFilter: Record<string, boolean>;
108108
shouldShowAggregatedBalancePopover: boolean;
109+
dismissSmartAccountSuggestionEnabled: boolean;
109110
};
110111

111112
// Omitting properties that already exist in the PreferencesState, as part of the preferences property.
@@ -201,6 +202,7 @@ export const getDefaultPreferencesControllerState =
201202
showMultiRpcModal: false,
202203
privacyMode: false,
203204
shouldShowAggregatedBalancePopover: true, // by default user should see popover;
205+
dismissSmartAccountSuggestionEnabled: false,
204206
tokenSortConfig: {
205207
key: 'tokenFiatAmount',
206208
order: 'dsc',

app/scripts/lib/transaction/eip5792.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ describe('EIP-5792', () => {
9090
Parameters<typeof processSendCalls>[0]['validateSecurity']
9191
>;
9292

93+
let getDismissSmartAccountSuggestionEnabledMock: jest.MockedFn<() => boolean>;
94+
9395
let messenger: EIP5792Messenger;
9496

9597
beforeEach(() => {
@@ -100,6 +102,7 @@ describe('EIP-5792', () => {
100102
getNetworkClientByIdMock = jest.fn();
101103
getDisabledAccountUpgradeChainsMock = jest.fn();
102104
validateSecurityMock = jest.fn();
105+
getDismissSmartAccountSuggestionEnabledMock = jest.fn();
103106

104107
messenger = new Messenger();
105108

@@ -133,6 +136,8 @@ describe('EIP-5792', () => {
133136
addTransactionBatch: addTransactionBatchMock,
134137
getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock,
135138
validateSecurity: validateSecurityMock,
139+
getDismissSmartAccountSuggestionEnabled:
140+
getDismissSmartAccountSuggestionEnabledMock,
136141
},
137142
messenger,
138143
SEND_CALLS_MOCK,
@@ -157,6 +162,8 @@ describe('EIP-5792', () => {
157162
getDisabledAccountUpgradeChains:
158163
getDisabledAccountUpgradeChainsMock,
159164
validateSecurity: validateSecurityMock,
165+
getDismissSmartAccountSuggestionEnabled:
166+
getDismissSmartAccountSuggestionEnabledMock,
160167
},
161168
messenger,
162169
SEND_CALLS_MOCK,
@@ -173,6 +180,8 @@ describe('EIP-5792', () => {
173180
getDisabledAccountUpgradeChains:
174181
getDisabledAccountUpgradeChainsMock,
175182
validateSecurity: validateSecurityMock,
183+
getDismissSmartAccountSuggestionEnabled:
184+
getDismissSmartAccountSuggestionEnabledMock,
176185
},
177186
messenger,
178187
{ ...SEND_CALLS_MOCK, version: '2.0' },
@@ -189,6 +198,8 @@ describe('EIP-5792', () => {
189198
getDisabledAccountUpgradeChains:
190199
getDisabledAccountUpgradeChainsMock,
191200
validateSecurity: validateSecurityMock,
201+
getDismissSmartAccountSuggestionEnabled:
202+
getDismissSmartAccountSuggestionEnabledMock,
192203
},
193204
messenger,
194205
{ ...SEND_CALLS_MOCK, chainId: CHAIN_ID_2_MOCK },
@@ -209,6 +220,30 @@ describe('EIP-5792', () => {
209220
getDisabledAccountUpgradeChains:
210221
getDisabledAccountUpgradeChainsMock,
211222
validateSecurity: validateSecurityMock,
223+
getDismissSmartAccountSuggestionEnabled:
224+
getDismissSmartAccountSuggestionEnabledMock,
225+
},
226+
messenger,
227+
SEND_CALLS_MOCK,
228+
REQUEST_MOCK,
229+
),
230+
).rejects.toThrow(
231+
`EIP-5792 is not supported for this chain and account - Chain ID: ${CHAIN_ID_MOCK}, Account: ${SEND_CALLS_MOCK.from}`,
232+
);
233+
});
234+
235+
it('throws if user enabled preference to dismiss option to upgrade account', async () => {
236+
getDismissSmartAccountSuggestionEnabledMock.mockReturnValue(true);
237+
238+
await expect(
239+
processSendCalls(
240+
{
241+
addTransactionBatch: addTransactionBatchMock,
242+
getDisabledAccountUpgradeChains:
243+
getDisabledAccountUpgradeChainsMock,
244+
validateSecurity: validateSecurityMock,
245+
getDismissSmartAccountSuggestionEnabled:
246+
getDismissSmartAccountSuggestionEnabledMock,
212247
},
213248
messenger,
214249
SEND_CALLS_MOCK,
@@ -227,6 +262,8 @@ describe('EIP-5792', () => {
227262
getDisabledAccountUpgradeChains:
228263
getDisabledAccountUpgradeChainsMock,
229264
validateSecurity: validateSecurityMock,
265+
getDismissSmartAccountSuggestionEnabled:
266+
getDismissSmartAccountSuggestionEnabledMock,
230267
},
231268
messenger,
232269
{
@@ -250,6 +287,8 @@ describe('EIP-5792', () => {
250287
getDisabledAccountUpgradeChains:
251288
getDisabledAccountUpgradeChainsMock,
252289
validateSecurity: validateSecurityMock,
290+
getDismissSmartAccountSuggestionEnabled:
291+
getDismissSmartAccountSuggestionEnabledMock,
253292
},
254293
messenger,
255294
{

app/scripts/lib/transaction/eip5792.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export async function processSendCalls(
3737
request: ValidateSecurityRequest,
3838
chainId: Hex,
3939
) => Promise<void>;
40+
getDismissSmartAccountSuggestionEnabled: () => boolean;
4041
},
4142
messenger: EIP5792Messenger,
4243
params: SendCalls,
@@ -46,6 +47,7 @@ export async function processSendCalls(
4647
addTransactionBatch,
4748
getDisabledAccountUpgradeChains,
4849
validateSecurity: validateSecurityHook,
50+
getDismissSmartAccountSuggestionEnabled,
4951
} = hooks;
5052

5153
const { calls, from } = params;
@@ -58,8 +60,15 @@ export async function processSendCalls(
5860
).configuration.chainId;
5961

6062
const disabledChains = getDisabledAccountUpgradeChains();
61-
62-
validateSendCalls(params, dappChainId, disabledChains);
63+
const dismissSmartAccountSuggestionEnabled =
64+
getDismissSmartAccountSuggestionEnabled();
65+
66+
validateSendCalls(
67+
params,
68+
dappChainId,
69+
disabledChains,
70+
dismissSmartAccountSuggestionEnabled,
71+
);
6372

6473
const securityAlertId = generateSecurityAlertId();
6574
const validateSecurity = validateSecurityHook.bind(null, securityAlertId);
@@ -127,11 +136,17 @@ function validateSendCalls(
127136
sendCalls: SendCalls,
128137
dappChainId: Hex,
129138
disabledChains: Hex[],
139+
dismissSmartAccountSuggestionEnabled: boolean,
130140
) {
131141
validateSendCallsVersion(sendCalls);
132142
validateSendCallsChainId(sendCalls, dappChainId);
133143
validateCapabilities(sendCalls);
134-
validateUserDisabled(sendCalls, disabledChains, dappChainId);
144+
validateUserDisabled(
145+
sendCalls,
146+
disabledChains,
147+
dappChainId,
148+
dismissSmartAccountSuggestionEnabled,
149+
);
135150
}
136151

137152
function validateSendCallsVersion(sendCalls: SendCalls) {
@@ -188,11 +203,12 @@ function validateUserDisabled(
188203
sendCalls: SendCalls,
189204
disabledChains: Hex[],
190205
dappChainId: Hex,
206+
dismissSmartAccountSuggestionEnabled: boolean,
191207
) {
192208
const { from } = sendCalls;
193209
const isDisabled = disabledChains.includes(dappChainId);
194210

195-
if (isDisabled) {
211+
if (isDisabled || dismissSmartAccountSuggestionEnabled) {
196212
throw rpcErrors.methodNotSupported(
197213
`EIP-5792 is not supported for this chain and account - Chain ID: ${dappChainId}, Account: ${from}`,
198214
);

app/scripts/metamask-controller.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,9 @@ export default class MetamaskController extends EventEmitter {
20082008
updateSecurityAlertResponse:
20092009
this.updateSecurityAlertResponse.bind(this),
20102010
}),
2011+
getDismissSmartAccountSuggestionEnabled: () =>
2012+
this.preferencesController.state.preferences
2013+
.dismissSmartAccountSuggestionEnabled,
20112014
},
20122015
this.controllerMessenger,
20132016
),

ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,74 @@ exports[`AdvancedTab Component should match snapshot 1`] = `
6666
</div>
6767
</div>
6868
</div>
69+
<div
70+
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"
71+
data-testid="advanced-setting-dismiss-smart-account-suggestion-enabled"
72+
>
73+
<div
74+
class="settings-page__content-item"
75+
>
76+
<span>
77+
78+
Dismiss "Switch to Smart Account" suggestion
79+
</span>
80+
<div
81+
class="settings-page__content-description"
82+
>
83+
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.
84+
</div>
85+
</div>
86+
<div
87+
class="settings-page__content-item-col"
88+
>
89+
<label
90+
class="toggle-button toggle-button--off"
91+
tabindex="0"
92+
>
93+
<div
94+
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;"
95+
>
96+
<div
97+
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(133, 139, 154);"
98+
>
99+
<div
100+
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;"
101+
/>
102+
<div
103+
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;"
104+
/>
105+
</div>
106+
<div
107+
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
108+
>
109+
<div
110+
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;"
111+
/>
112+
</div>
113+
<input
114+
data-testid="settings-page-dismiss-smart-account-suggestion-enabled-toggle"
115+
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
116+
type="checkbox"
117+
value="false"
118+
/>
119+
</div>
120+
<div
121+
class="toggle-button__status"
122+
>
123+
<span
124+
class="toggle-button__label-off"
125+
>
126+
Off
127+
</span>
128+
<span
129+
class="toggle-button__label-on"
130+
>
131+
On
132+
</span>
133+
</div>
134+
</label>
135+
</div>
136+
</div>
69137
<div
70138
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"
71139
data-testid="advanced-setting-enable-smart-transactions"

ui/pages/settings/advanced-tab/advanced-tab.component.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export default class AdvancedTab extends PureComponent {
5858
setShowExtensionInFullSizeView: PropTypes.func.isRequired,
5959
manageInstitutionalWallets: PropTypes.bool,
6060
setManageInstitutionalWallets: PropTypes.func.isRequired,
61+
dismissSmartAccountSuggestionEnabled: PropTypes.bool.isRequired,
62+
setDismissSmartAccountSuggestionEnabled: PropTypes.func.isRequired,
6163
};
6264

6365
state = {
@@ -205,6 +207,46 @@ export default class AdvancedTab extends PureComponent {
205207
);
206208
}
207209

210+
renderToggleDismissSmartAccountSuggestion() {
211+
const { t } = this.context;
212+
const {
213+
dismissSmartAccountSuggestionEnabled,
214+
setDismissSmartAccountSuggestionEnabled,
215+
} = this.props;
216+
217+
return (
218+
<Box
219+
ref={this.settingsRefs[2]}
220+
className="settings-page__content-row"
221+
data-testid="advanced-setting-dismiss-smart-account-suggestion-enabled"
222+
display={Display.Flex}
223+
flexDirection={FlexDirection.Row}
224+
justifyContent={JustifyContent.spaceBetween}
225+
gap={4}
226+
>
227+
<div className="settings-page__content-item">
228+
<span> {t('dismissSmartAccountSuggestionEnabledTitle')}</span>
229+
<div className="settings-page__content-description">
230+
{t('dismissSmartAccountSuggestionEnabledDescription')}
231+
</div>
232+
</div>
233+
234+
<div className="settings-page__content-item-col">
235+
<ToggleButton
236+
value={dismissSmartAccountSuggestionEnabled}
237+
onToggle={(oldValue) => {
238+
const newValue = !oldValue;
239+
setDismissSmartAccountSuggestionEnabled(newValue);
240+
}}
241+
offLabel={t('off')}
242+
onLabel={t('on')}
243+
dataTestId="settings-page-dismiss-smart-account-suggestion-enabled-toggle"
244+
/>
245+
</div>
246+
</Box>
247+
);
248+
}
249+
208250
renderToggleStxOptIn() {
209251
const { t } = this.context;
210252
const { smartTransactionsEnabled, setSmartTransactionsEnabled } =
@@ -593,6 +635,7 @@ export default class AdvancedTab extends PureComponent {
593635
) : null}
594636
{this.renderStateLogs()}
595637
{this.renderResetAccount()}
638+
{this.renderToggleDismissSmartAccountSuggestion()}
596639
{this.renderToggleStxOptIn()}
597640
{this.renderHexDataOptIn()}
598641
{this.renderShowConversionInTestnets()}

0 commit comments

Comments
 (0)