fix: Add route protection when basic functionality toggle is off#39975
fix: Add route protection when basic functionality toggle is off#39975gauthierpetetin merged 53 commits intomainfrom
Conversation
#39866) - Add BASIC_FUNCTIONALITY_REQUIRED_ROUTE and dedicated feature-unavailable page - Add RequireBasicFunctionality HOC; wrap swap, rewards, notifications, DeFi, shield, perps, nonevm-balance-check routes - Add BasicFunctionalityRequired page with i18n (en, en_GB), static style constants - Register route in route-with-layout and routes.component; add unit tests Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
Builds ready [996b219]
UI Startup Metrics (1353 ± 98 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
…ed test Use I18N_KEYS constants for i18n key strings in mock to satisfy dot-notation rule without triggering naming-convention. Co-authored-by: Cursor <cursoragent@cursor.com>
Builds ready [a5730b2]
UI Startup Metrics (1374 ± 90 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Set useExternalServices: true in preloaded state so DeFi routes (protected by RequireBasicFunctionality) are accessible in the test. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace deprecated component-library imports (Box, Text, Button, ButtonLink) with @metamask/design-system-react to satisfy fitness function 'Don't import deprecated UI components in new files'. Co-authored-by: Cursor <cursoragent@cursor.com>
- Multiline design-system import and Text component props to satisfy prettier/prettier in CI. Co-authored-by: Cursor <cursoragent@cursor.com>
Builds ready [a4d1126]
UI Startup Metrics (1361 ± 98 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Use 'Go to the home page' (en, en_GB) to match deep link interstitial. Co-authored-by: Cursor <cursoragent@cursor.com>
Add useExternalServices: true to integration-init-state.json so routes protected by RequireBasicFunctionality are reachable by default. Remove redundant override from DeFi test. Co-authored-by: Cursor <cursoragent@cursor.com>
- Card minHeight 592px, logo 160x160px to match deep-link - Border radius 6px (BorderRadius.MD), description paddingBottom 12, button marginTop 48px Co-authored-by: Cursor <cursoragent@cursor.com>
ui/pages/basic-functionality-required/basic-functionality-required.test.tsx
Show resolved
Hide resolved
Builds ready [b504a5a]
⚡ Performance Benchmarks (1363 ± 101 ms)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
… contract Mock now calls onToggle(value) (current value) to match the real library, which passes the current value on click rather than the next value. Co-authored-by: Cursor <cursoragent@cursor.com>
Builds ready [32e4e6e]
⚡ Performance Benchmarks (1444 ± 115 ms)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
…grammar) Replace 'Open the $1 page' with one message key per destination (basicFunctionalityRequired_openSwapsPage, etc.) so each locale can translate the whole sentence with correct grammar (e.g. Russian 'Откройте страницу свопов'). Mirrors the deep link interstitial pattern (deepLink_theSwapsPage, etc.). Co-authored-by: Cursor <cursoragent@cursor.com>
Use discriminated union so CTA key is required when basicFunctionalityRequired is true and forbidden when false. Co-authored-by: Cursor <cursoragent@cursor.com>
Builds ready [7a69a54]
⚡ Performance Benchmarks (1381 ± 105 ms)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Builds ready [d744e66]
⚡ Performance Benchmarks (1434 ± 99 ms)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Builds ready [73f1e3a]
⚡ Performance Benchmarks
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
PERPS_ORDER_ENTRY_ROUTE (/perps/trade/:symbol) was missing basicFunctionalityOpenPageCtaKey. With basicFunctionalityRequired defaulting to true, createRouteWithLayout threw and broke route rendering. Use same CTA key as other perps routes. Made-with: Cursor
Replace hardcoded query strings with messages.xxx.message to satisfy locale-query-mismatch Rule 2 and keep tests in sync with translations. Made-with: Cursor
ui/pages/basic-functionality-required/basic-functionality-required.test.tsx
Outdated
Show resolved
Hide resolved
…-required test Use basicFunctionalityRequired_toggleLabel (same key as component) instead of basicConfigurationLabel. Rename mock variable to mockT to avoid shadowing imported messages. Made-with: Cursor
…onality-required test Made-with: Cursor
Builds ready [f37004c]
⚡ Performance Benchmarks
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
|



Description
When “Basic functionality” (use external services) is off, routes that depend on external services (e.g. swap, rewards, notifications, DeFi, perps) are now protected: the user is redirected to a dedicated “Basic functionality is off” page instead of the feature. That page offers an inline toggle to turn Basic functionality on and, when coming from a blocked route, a primary CTA to open the blocked feature (e.g. “Open the Swap page”) plus “Go to the home page.” This prevents users from landing on feature UIs that cannot work without external services and gives them a clear path to enable the setting or go home.
Changelog
CHANGELOG entry: When Basic functionality is off, protected routes now redirect to a “Basic functionality is off” page with an inline toggle and optional “Open the [feature] page” action instead of showing the feature.
Related issues
Fixes: #39866
Manual testing steps
yarn start.a. Direct route: chrome-extension://hebhblbkkdabgoldnojllkipeoacjioc/home.html#/cross-chain/swaps/prepare-bridge-page?swaps=true
b. Deep link: https://link.metamask.io/swap?from=eip155%3A1%2Ferc20%3A0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&to=eip155%3A1%2Ferc20%3A0xdAC17F958D2ee523a2206206994597C13D831ec7&value=0x38d7ea4c68000
Screenshots/Recordings
Or see Loom video
Additional information
Routes that require Basic Functionality
When Basic functionality is off, these routes redirect to
/feature-unavailable:/notifications/settings/notifications/:uuid/notifications/cross-chain/tx-details/:srcTxMetaId/cross-chain/*/defi/:chainId/:protocolId/nonevm-balance-check/shield-plan/rewards/perps/home/perps/market/:symbol/perps/activity/perps/market-list/snaps/snaps/view/*Routes that do not require Basic Functionality
These routes remain available when Basic functionality is off:
/(Home)/onboarding/*/lock/unlock/link(deep link)/feature-unavailable/restore-vault/smart-account-update/seed/:keyringId?/import-srp/settings/*/send/:page?/confirm-transaction/*(all confirmation routes)/confirm-add-suggested-token/confirm-add-suggested-nft/confirmation/:id?/new-account/*/connect/:id/*/asset/*(all asset routes)/permissions/gator-permissions/token-transfer/*/review-gator-permissions/*/review-permissions/:origin/account-list/multichain-account-address-list/:accountGroupId/multichain-account-private-key-list/:accountGroupId/add-wallet-page/multichain-account-details/:id/multichain-smart-account/:address/multichain-wallet-details-page/:idPre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Touches core routing/guard logic and adds a new redirect screen; misconfiguration could block access to key routes or create redirect loops, but changes are localized and well-tested.
Overview
When
useExternalServices("Basic functionality") is off, routes that depend on external services now redirect to a dedicatedBASIC_FUNCTIONALITY_OFF_ROUTEscreen instead of rendering the feature.Adds a
BasicFunctionalityRequiredroute guard (wired intocreateRouteWithLayoutby default) that passes the blocked URL + a per-feature i18n CTA key so the new page can show an inline toggle to re-enable basic functionality and optionally navigate back to the originally requested feature. Updates route config to opt out for allowed routes (e.g. home/settings/confirm flows) and to provide CTA keys for protected routes (swap/notifications/snaps/defi/rewards/perps/shield/etc.).Includes new i18n strings, unit + e2e coverage for the redirect/toggle/CTA flow, plus small fixes (boolean
disableUnderline, adduseExternalServicesto integration init state, minor settings container cleanup).Written by Cursor Bugbot for commit f37004c. This will update automatically on new commits. Configure here.