Skip to content

perf: replace createDeepEqualSelector with createSelector in account selectors - #40859

Merged
hmalik88 merged 20 commits into
mainfrom
hm/mul-1419
Mar 18, 2026
Merged

perf: replace createDeepEqualSelector with createSelector in account selectors#40859
hmalik88 merged 20 commits into
mainfrom
hm/mul-1419

Conversation

@hmalik88

@hmalik88 hmalik88 commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Description

Account selectors across multi-srp.ts, selectors.js, and account-tree.ts were using createDeepEqualSelector, which uses lodash isEqual to recursively compare all input selector results on every call to decide whether to recompute. For account data, this is unnecessary overhead.

Account objects come from immer-backed controllers. Immer uses structural sharing — when data hasn't changed, the reference is identical (===). This means the deep traversal was doing O(accounts × fields) work per call just to confirm what a reference check would confirm in O(1).

This PR replaces createDeepEqualSelector with the most appropriate selector creator for each case:

  • createSelector — for selectors whose inputs come entirely from immer state, where reference equality is sufficient
  • createParameterizedSelector — for selectors that take a parameter (e.g. an account ID or address) and are called simultaneously for multiple values in list renders, requiring an LRU cache rather than a single cached result
  • createParameterizedShallowEqualSelector — for parameterized selectors whose inputs include arrays derived from upstream selectors. Shallow equality compares array elements by reference one level deep, which is correct since the elements are immer-backed objects. This handles edge cases where an upstream selector produces a new array containing the same element references, avoiding unnecessary recomputation without the cost of deep traversal

Two selectors were intentionally left as createDeepEqualSelector: getAccountGroupsByScopes and getAccountGroupsByAddress, because they take array arguments from callers rather than from immer state. Deep equality is legitimately useful there to avoid recomputation when the content is the same but the reference differs.

Changes

ui/selectors/multi-srp/multi-srp.ts

Selector: isPrimaryHdAndFirstPartySnapAccount

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Both inputs are immer-backed (account is passed directly, getMetaMaskHdKeyrings is now memoized) — === is sufficient
  • Visible benefit: Reduced overhead on every render that checks seed phrase reminder eligibility

Selector: getShouldShowSeedPhraseReminder

  • Change: createDeepEqualSelectorcreateSelector
  • Why: 6 inputs all from immer state or memoized selectors
  • Visible benefit: The seed phrase reminder banner check on the home screen no longer deep-traverses account + token data on every render

ui/selectors/selectors.js

Selector: getMetaMaskHdKeyrings

  • Change: function → createSelector
  • Why: Was calling .filter() directly — new array every call, which cascaded instability into isPrimaryHdAndFirstPartySnapAccount
  • Visible benefit: Stable keyring array reference; fixes the input stability chain upstream of the seed phrase reminder

Selector: getAllPermittedAccounts

  • Change: function → createParameterizedSelector(20)
  • Why: Was returning getCaipAccountIdsFromCaip25CaveatValue(...) or [] — new array every call regardless of state change
  • Visible benefit: Stable account list reference per origin; cascades stable refs into getOrderedConnectedAccountsForActiveTab and up to getWalletsWithAccounts

Selector: getOrderedConnectedAccountsForActiveTab

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Inputs now stable thanks to getAllPermittedAccounts fix
  • Visible benefit: Connected accounts list (popup header, permissions page) no longer deep-compares on every render

Selector: getUpdatedAndSortedAccountsWithCaipAccountId

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Single input (getUpdatedAndSortedAccounts) is immer-backed and already memoized
  • Visible benefit: Account list in the connect/review permissions flow reuses cached result instead of deep-comparing on each render

ui/selectors/multichain-accounts/account-tree.ts

Selector: getWalletsWithAccounts

  • Change: createDeepEqualSelectorcreateSelector
  • Why: 6 immer-backed inputs including getOrderedConnectedAccountsForActiveTab (now stable)
  • Visible benefit: The entire wallet+account tree avoids deep traversal on every render — biggest win, this feeds nearly everything in the multichain account UI

Selector: getNormalizedGroupsMetadata

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Immer-backed inputs
  • Visible benefit: Wallet metadata rendering (names, icons)

Selector: getAllAccountGroups

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Single immer input
  • Visible benefit: Base group list used throughout account tree

Selector: getMultichainAccountGroups / getSingleAccountGroups

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Derived from getAllAccountGroups (now stable)
  • Visible benefit: Multichain vs single-account group filters in the account list panel

Selector: getAccountGroupWithInternalAccounts

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Immer-backed inputs
  • Visible benefit: Groups joined with their account objects — feeds most of the account list UI

Selector: getMultichainAccountsToScopesMap

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Immer-backed inputs
  • Visible benefit: CAIP scope maps per account, used in network/scope selectors

Selector: getSelectedAccountGroup

  • Change: createDeepEqualSelectorcreateSelector
  • Why: Single immer input
  • Visible benefit: Selected account group in the header and active account views

Selector: getInternalAccountsFromGroupById

  • Change: createSelector (size 1) → createParameterizedSelector(20)
  • Why: Was evicting on every groupId call in list renders
  • Visible benefit: Root fix for the bot issue — stable array references for all 4 downstream selectors

Selector: getWalletIdAndNameByAccountAddress

  • Change: createDeepEqualSelectorcreateParameterizedSelector(20)
  • Why: Called once per address in lists — 50-entry LRU serves all visible accounts simultaneously
  • Visible benefit: Account name/wallet lookups in the address book, send flow, and account list

Selector: getMultichainAccountGroupById

  • Change: createDeepEqualSelectorcreateParameterizedSelector(5)
  • Why: Called per group in multi-account views
  • Visible benefit: Per-group data lookups in the multichain account list

Selector: getCaip25IdByAccountGroupAndScope

  • Change: createDeepEqualSelectorcreateParameterizedSelector(5) + input refactor
  • Why: The original bundled {accountGroup, scope} into one object (new ref every call) — split into two pass-through input selectors
  • Visible benefit: CAIP permission lookups per account per network scope

Selector: getInternalAccountByGroupAndCaip

  • Change: createDeepEqualSelectorcreateParameterizedSelector(10) + input refactor
  • Why: Same bundled-object problem, same fix
  • Visible benefit: Internal account lookups by group+chain, used in confirmation flows

Selector: getInternalAccountBySelectedAccountGroupAndCaip

  • Change: createDeepEqualSelectorcreateParameterizedSelector(10)
  • Why: Keyed by caipChainId, called across multiple chains
  • Visible benefit: Active account per chain in the currently selected group

Selector: getInternalAccountListSpreadByScopesByGroupId

  • Change: createDeepEqualSelectorcreateParameterizedShallowEqualSelector(20)
  • Why: Takes array input from getInternalAccountsFromGroupById — shallow equality handles the case where the array is new but elements are same immer references
  • Visible benefit: Per-group network address rows in the multichain account panel

Selector: getNetworkAddressCount

  • Change: createDeepEqualSelectorcreateParameterizedSelector(5)
  • Why: Depends on getInternalAccountListSpreadByScopesByGroupId which is now stable
  • Visible benefit: Address count badge per group

Selector: getIconSeedAddressByAccountGroupId

  • Change: createDeepEqualSelectorcreateParameterizedShallowEqualSelector(20)
  • Why: Same as getInternalAccountListSpreadByScopesByGroupId — array input, shallow equality is appropriate
  • Visible benefit: Account icon generation throughout the account list

Selector: getDefaultScopeAndAddressByAccountGroupId

  • Change: createDeepEqualSelectorcreateParameterizedSelector(20)
  • Why: Depends on stable getInternalAccountListSpreadByScopesByGroupId
  • Visible benefit: Default address display in the app header and account cell

Changelog

CHANGELOG entry: null

Related issues

Fixes: https://github.com/MetaMask/MetaMask-planning/issues/6591

Manual testing steps

  1. Build from this branch.
  2. Verify account list renders correctly
  3. Verify account switching works
  4. Verify connected sites tab shows correct accounts

Screenshots/Recordings

N/A

Pre-merge author checklist

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.

Note

Medium Risk
Touches core account/permission selectors used widely in rendering; changes are mostly memoization semantics, but incorrect parameterization or cache sizing could cause subtle stale data or UI update issues.

Overview
Reduces selector recomputation overhead in account- and multichain-related flows by replacing createDeepEqualSelector usages with createSelector where referential equality is sufficient.

Introduces/expands use of LRU-cached parameterized selectors (and shallow-equal variants) for selectors called with many different address/groupId/scope parameters in list renders, including refactors to avoid passing newly-created parameter objects that defeat memoization.

Updates getMetaMaskHdKeyrings and getAllPermittedAccounts to be memoized selectors (including per-origin caching), and adjusts an account menu test store setup to avoid mutating default state during merge.

Written by Cursor Bugbot for commit ed6a18b. This will update automatically on new commits. Configure here.

@hmalik88
hmalik88 requested a review from a team as a code owner March 12, 2026 20:09
@github-actions

Copy link
Copy Markdown
Contributor

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.

@metamaskbot metamaskbot added the team-accounts-framework Accounts team label Mar 12, 2026
@metamaskbotv2

metamaskbotv2 Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

✨ Files requiring CODEOWNER review ✨

🔑 @MetaMask/accounts-engineers (1 files, +68 -51)
  • 📁 ui/
    • 📁 selectors/
      • 📁 multichain-accounts/
        • 📄 account-tree.ts +68 -51

👨‍🔧 @MetaMask/core-extension-ux (1 files, +1 -1)
  • 📁 ui/
    • 📁 components/
      • 📁 multichain/
        • 📁 account-menu/
          • 📄 account-menu.test.tsx +1 -1

Comment thread ui/selectors/multichain-accounts/account-tree.ts
@hmalik88
hmalik88 marked this pull request as draft March 12, 2026 20:23
@metamaskbotv2

metamaskbotv2 Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor
Builds ready [9612fa3]
⚡ Performance Benchmarks
👆 Interaction Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Load New Accountload_new_account360256518113476518
total360256518113476518
Confirm Txconfirm_tx6033601960431060416043
total6033601960431060416043
Bridge User Actionsbridge_load_page2532492553255255
bridge_load_asset_picker1491441586149158
bridge_search_token6986977001700700
total1110109011411811171141
🔌 Startup Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Standard HomeuiStartup1443121717949814931630
load1198101214449412371371
domContentLoaded1191100414389112341366
domInteractive281699182578
firstPaint169711205156211285
backgroundConnect21819634317224242
firstReactRender20124872134
initialActions105113
loadScripts98881212249110241168
setupStore1374051522
numNetworkReqs403188164080
Power User HomeuiStartup5390220513637217964858317
load13001103175313113291644
domContentLoaded12821094174312513081593
domInteractive41202764135111
firstPaint21189526100279373
backgroundConnect18703028970174229025374
firstReactRender28185063039
initialActions106124
loadScripts1055898149711710721361
setupStore1665091934
numNetworkReqs1376128845147254
🧭 User Journey Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Onboarding Import WalletimportWalletToSocialScreen2192172211220221
srpButtonToSrpForm95939939599
confirmSrpToPwForm22222302223
pwFormToMetricsScreen16151601616
metricsToWalletReadyScreen16151711717
doneButtonToHomeScreen65159778879616788
openAccountMenuToAccountListLoaded290528992913629092913
total3937387240627139674062
Onboarding New WalletcreateWalletToSocialScreen2192182201218220
srpButtonToPwForm1121081153114115
createPwToRecoveryScreen999099
skipBackupToMetricsScreen39394004040
agreeButtonToOnboardingSuccess17161701717
doneButtonToAssetList51149552011520520
total92088895323922953
Asset DetailsassetClickToPriceChart49415964959
total49415964959
Solana Asset DetailsassetClickToPriceChart1356422459181224
total1356422459181224
Import Srp HomeloginToHomeScreen2287219723735923222373
openAccountMenuAfterLogin80411152693115
homeAfterImportWithNewWallet1654527242688223722426
total40212901480884347004808
Send TransactionsopenSendPageFromHome26252712627
selectTokenToSendFormLoaded31273423334
reviewTransactionToConfirmationPage782645920136916920
total95070013902529881390
SwapopenSwapPageFromHome1016015736129157
fetchAndDisplaySwapQuotes269026832701827012701
total2792274428413928302841
🌐 Dapp Page Load Benchmarks

Current Commit: 9612fa3 | Date: 3/12/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±42ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 733ms (±63ms) 🟢 | historical mean value: 737ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 84ms (±42ms) 🟢 | historical mean value: 83ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 42ms 1.01s 1.37s 1.06s 1.37s
domContentLoaded 733ms 63ms 707ms 1.31s 751ms 1.31s
firstPaint 84ms 42ms 64ms 500ms 96ms 500ms
firstContentfulPaint 84ms 42ms 64ms 500ms 96ms 500ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs
  • background: 58 Bytes (0%)
  • ui: -61 Bytes (0%)
  • common: 149 Bytes (0%)

@metamaskbotv2

metamaskbotv2 Bot commented Mar 17, 2026

Copy link
Copy Markdown
Contributor
Builds ready [b5d447b]
⚡ Performance Benchmarks
👆 Interaction Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Load New Accountload_new_account2872772979295297
total2872772979295297
Confirm Txconfirm_tx6028599360833460286083
total6028599360833460286083
Bridge User Actionsbridge_load_page25120827624268276
bridge_load_asset_picker26724829518270295
bridge_search_token74270076926757769
total12611097141510713281415
🔌 Startup Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Standard HomeuiStartup14711233194112115201689
load12191026164011012481414
domContentLoaded12121018161610812441400
domInteractive3017127212680
firstPaint169701239134219291
backgroundConnect21519726414217253
firstReactRender20134552130
initialActions301631624
loadScripts1013821139410710451203
setupStore1364961523
numNetworkReqs393187164078
Power User HomeuiStartup5604212815043218764808768
load13251166170912113731626
domContentLoaded13051144169911513471514
domInteractive38202082936102
firstPaint240921383179285381
backgroundConnect191630811812198227464643
firstReactRender25184962741
initialActions109113
loadScripts1072935144010611101291
setupStore1665971828
numNetworkReqs1479427237154231
🧭 User Journey Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Onboarding Import WalletimportWalletToSocialScreen2182162201219220
srpButtonToSrpForm93909529495
confirmSrpToPwForm22212312323
pwFormToMetricsScreen15151601516
metricsToWalletReadyScreen15151611616
doneButtonToHomeScreen708587860117833860
openAccountMenuToAccountListLoaded2909289329291329102929
total40213859414612541174146
Onboarding New WalletcreateWalletToSocialScreen2182172191219219
srpButtonToPwForm1081071091109109
createPwToRecoveryScreen989099
skipBackupToMetricsScreen37373803838
agreeButtonToOnboardingSuccess16161601616
doneButtonToAssetList56349271182591711
total9538821106849791106
Asset DetailsassetClickToPriceChart604880157680
total604880157680
Solana Asset DetailsassetClickToPriceChart1123618254160182
total1123618254160182
Import Srp HomeloginToHomeScreen221322072221622212221
openAccountMenuAfterLogin54475955959
homeAfterImportWithNewWallet1863577232474322852324
total42623377459551245394595
Send TransactionsopenSendPageFromHome29273323033
selectTokenToSendFormLoaded402462144862
reviewTransactionToConfirmationPage1157667148733314001487
total1234723161735314781617
SwapopenSwapPageFromHome1033216143125161
fetchAndDisplaySwapQuotes268926872691226902691
total2794272728524228122852
🌐 Dapp Page Load Benchmarks

Current Commit: b5d447b | Date: 3/17/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 982ms (±45ms) 🟢 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 690ms (±63ms) 🟢 | historical mean value: 742ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 82ms (±40ms) 🟢 | historical mean value: 92ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 982ms 45ms 953ms 1.30s 1.01s 1.30s
domContentLoaded 690ms 63ms 663ms 1.26s 717ms 1.26s
firstPaint 82ms 40ms 64ms 472ms 88ms 472ms
firstContentfulPaint 82ms 40ms 64ms 472ms 88ms 472ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs
  • background: 58 Bytes (0%)
  • ui: -20 Bytes (0%)
  • common: 149 Bytes (0%)

@metamaskbotv2

metamaskbotv2 Bot commented Mar 17, 2026

Copy link
Copy Markdown
Contributor
Builds ready [0050ae1]
⚡ Performance Benchmarks
👆 Interaction Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Load New Accountload_new_account28726033931279339
total28726033931279339
Confirm Txconfirm_tx601460146015060156015
total601460146015060156015
Bridge User Actionsbridge_load_page22118329442245294
bridge_load_asset_picker24518731353302313
bridge_search_token72670774613736746
total1193109412586112401258
🔌 Startup Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Standard HomeuiStartup14411204165810114841630
load1194100013818912331361
domContentLoaded118899513698812291352
domInteractive2816107182582
firstPaint1417139872187252
backgroundConnect21319525311218233
firstReactRender20136162127
initialActions208124
loadScripts99080511678710201151
setupStore1372851622
numNetworkReqs393182153879
Power User HomeuiStartup5510199013172213667798562
load13431156199014213931598
domContentLoaded13231146198213813701543
domInteractive42211993933166
firstPaint228821396149288366
backgroundConnect199631110755187532134961
firstReactRender26176572838
initialActions105114
loadScripts1086922169912511201314
setupStore1777691934
numNetworkReqs1396027946154249
🧭 User Journey Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Onboarding Import WalletimportWalletToSocialScreen2212182242223224
srpButtonToSrpForm93939409494
confirmSrpToPwForm22212202222
pwFormToMetricsScreen15151501515
metricsToWalletReadyScreen16151711617
doneButtonToHomeScreen62258866327625663
openAccountMenuToAccountListLoaded292029182923229232923
total3916390339401439143940
Onboarding New WalletcreateWalletToSocialScreen2212192242222224
srpButtonToPwForm1101061133110113
createPwToRecoveryScreen989099
skipBackupToMetricsScreen39394004040
agreeButtonToOnboardingSuccess17161811718
doneButtonToAssetList4944845038500503
total89587492518892925
Asset DetailsassetClickToPriceChart48465024950
total48465024950
Solana Asset DetailsassetClickToPriceChart804311025100110
total804311025100110
Import Srp HomeloginToHomeScreen2312223823856123752385
openAccountMenuAfterLogin61487396873
homeAfterImportWithNewWallet1712545276796223652767
total40842974509090946955090
Send TransactionsopenSendPageFromHome372457133857
selectTokenToSendFormLoaded34294143641
reviewTransactionToConfirmationPage1148904139819513321398
total1232973149619013891496
SwapopenSwapPageFromHome491981257581
fetchAndDisplaySwapQuotes268726782698826962698
total2736270727702627642770
🌐 Dapp Page Load Benchmarks

Current Commit: 0050ae1 | Date: 3/17/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.06s (±40ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 734ms (±61ms) 🟢 | historical mean value: 742ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 94ms (±127ms) 🟢 | historical mean value: 92ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.06s 40ms 1.03s 1.36s 1.10s 1.36s
domContentLoaded 734ms 61ms 704ms 1.29s 755ms 1.29s
firstPaint 94ms 127ms 64ms 1.36s 92ms 1.36s
firstContentfulPaint 94ms 127ms 64ms 1.36s 92ms 1.36s
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs
  • background: 58 Bytes (0%)
  • ui: -20 Bytes (0%)
  • common: 149 Bytes (0%)

},
};
const store = configureStore(merge(defaultState, state));
const store = configureStore(merge({}, defaultState, state));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

merge(defaultState, state) mutates defaultState in-place. Since defaultState.metamask.keyrings holds the same reference as mockState.metamask.keyrings, this mutation leaks across tests. With getMetaMaskHdKeyrings now a memoized createSelector, the selector compares the keyrings array by reference — same reference means cache hit, so it returns stale results from a previous test even though the array contents were mutated. Using merge({}, defaultState, state) deep-clones into a fresh target so each test gets independent state.

@hmalik88
hmalik88 marked this pull request as ready for review March 17, 2026 02:25

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment thread ui/selectors/selectors.js
Comment thread ui/selectors/multichain-accounts/account-tree.ts
@metamaskbotv2

metamaskbotv2 Bot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor
Builds ready [3b6a671]
⚡ Performance Benchmarks
👆 Interaction Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Load New Accountload_new_account30829234622301346
total30829234622301346
Confirm Txconfirm_tx602460156031660256031
total602460156031660256031
Bridge User Actionsbridge_load_page2352242509233250
bridge_load_asset_picker25724126911268269
bridge_search_token7637547706768770
total1272123913132512861313
🔌 Startup Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Standard HomeuiStartup14851231175810315151693
load1231100814459112641402
domContentLoaded1224100214348912611392
domInteractive3017115222693
firstPaint1597142976213277
backgroundConnect21919827114225248
firstReactRender20144862231
initialActions105123
loadScripts102081312388810541181
setupStore1374371626
numNetworkReqs393185164079
Power User HomeuiStartup5828219517037230665688589
load12901110199413713271539
domContentLoaded12691104198213112921497
domInteractive36201662832108
firstPaint2128952995277364
backgroundConnect222233814153224732735060
firstReactRender24163952735
initialActions105113
loadScripts1048905169512010761257
setupStore1575781830
numNetworkReqs1489340744156232
🧭 User Journey Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Onboarding Import WalletimportWalletToSocialScreen2192192200220220
srpButtonToSrpForm99941023101102
confirmSrpToPwForm24232512425
pwFormToMetricsScreen17161701717
metricsToWalletReadyScreen17161811818
doneButtonToHomeScreen63860768332671683
openAccountMenuToAccountListLoaded2931291529411129402941
total3953390839883439853988
Onboarding New WalletcreateWalletToSocialScreen2202172232221223
srpButtonToPwForm1061041102107110
createPwToRecoveryScreen889089
skipBackupToMetricsScreen38373803838
agreeButtonToOnboardingSuccess16161601616
doneButtonToAssetList603489753120743753
total994876115012411381150
Asset DetailsassetClickToPriceChart885411824113118
total885411824113118
Solana Asset DetailsassetClickToPriceChart1083918460166184
total1083918460166184
Import Srp HomeloginToHomeScreen225922522273822602273
openAccountMenuAfterLogin564071116471
homeAfterImportWithNewWallet2347229923863623862386
total4666462346883046884688
Send TransactionsopenSendPageFromHome442662156162
selectTokenToSendFormLoaded26222932929
reviewTransactionToConfirmationPage1207731151630314111516
total1280816160129714691601
SwapopenSwapPageFromHome103991073107107
fetchAndDisplaySwapQuotes268726792701826922701
total278127752787427822787
🌐 Dapp Page Load Benchmarks

Current Commit: 3b6a671 | Date: 3/18/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 998ms (±52ms) 🟢 | historical mean value: 1.03s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 703ms (±65ms) 🟢 | historical mean value: 724ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 93ms (±125ms) 🟢 | historical mean value: 88ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 998ms 52ms 956ms 1.37s 1.03s 1.37s
domContentLoaded 703ms 65ms 665ms 1.27s 736ms 1.27s
firstPaint 93ms 125ms 64ms 1.34s 96ms 1.34s
firstContentfulPaint 93ms 125ms 64ms 1.34s 96ms 1.34s
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs
  • background: 58 Bytes (0%)
  • ui: -23 Bytes (0%)
  • common: 95 Bytes (0%)

Comment thread ui/selectors/selectors.js Outdated
@metamaskbotv2

metamaskbotv2 Bot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor
Builds ready [ce60d1b]
⚡ Performance Benchmarks
👆 Interaction Benchmarks
🧭 User Journey Benchmarks

⚠️ Missing data: chrome/browserify/userJourneyAssets, chrome/browserify/userJourneyTransactions

🌐 Dapp Page Load Benchmarks

Current Commit: ce60d1b | Date: 3/18/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 969ms (±46ms) 🟢 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 682ms (±58ms) 🟢 | historical mean value: 731ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 87ms (±119ms) 🟢 | historical mean value: 84ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 969ms 46ms 941ms 1.35s 986ms 1.35s
domContentLoaded 682ms 58ms 658ms 1.21s 694ms 1.21s
firstPaint 87ms 119ms 60ms 1.27s 84ms 1.27s
firstContentfulPaint 87ms 119ms 60ms 1.27s 84ms 1.27s
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: -10.07 KiB (-0.12%)
  • common: 10.32 KiB (0.09%)

@sonarqubecloud

Copy link
Copy Markdown

@metamaskbotv2

metamaskbotv2 Bot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor
Builds ready [ed6a18b]
⚡ Performance Benchmarks
👆 Interaction Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Load New Accountload_new_account28625932526307325
total28625932526307325
Confirm Txconfirm_tx601160006024960176024
total601160006024960176024
Bridge User Actionsbridge_load_page23621526116249261
bridge_load_asset_picker1831741886188188
bridge_search_token6936926941693694
total1105109111341710971134
🔌 Startup Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Standard HomeuiStartup15831325214811616601754
load13131085180910913871464
domContentLoaded13061077180310913811453
domInteractive3320145232898
firstPaint1607837979222342
backgroundConnect23321129514239253
firstReactRender21135162230
initialActions106124
loadScripts1089855158110711581232
setupStore1684662026
numNetworkReqs393181154077
Power User HomeuiStartup60632089151972501692710334
load13801205298721714161656
domContentLoaded13601199297321513771596
domInteractive3520172243591
firstPaint241891402147312350
backgroundConnect195230712018237425516598
firstReactRender23174152531
initialActions105112
loadScripts1125974275021011441361
setupStore1573851625
numNetworkReqs1847733454200300
🧭 User Journey Benchmarks
BenchmarkMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P75 (ms)P95 (ms)
Onboarding Import WalletimportWalletToSocialScreen2232212251223225
srpButtonToSrpForm97959919799
confirmSrpToPwForm23232302323
pwFormToMetricsScreen16161601616
metricsToWalletReadyScreen17171701717
doneButtonToHomeScreen65060070440676704
openAccountMenuToAccountListLoaded30362907332516631223325
total40653881440620241844406
Onboarding New WalletcreateWalletToSocialScreen2192172211220221
srpButtonToPwForm1101091121111112
createPwToRecoveryScreen989099
skipBackupToMetricsScreen39383913939
agreeButtonToOnboardingSuccess18171911919
doneButtonToAssetList4894834945494494
total8848778905886890
Asset DetailsassetClickToPriceChart675084147984
total675084147984
Solana Asset DetailsassetClickToPriceChart1023814441140144
total1023814441140144
Import Srp HomeloginToHomeScreen2279220024449523282444
openAccountMenuAfterLogin72511032082103
homeAfterImportWithNewWallet2328228523623323582362
total4630455247165846304716
Send TransactionsopenSendPageFromHome512673217073
selectTokenToSendFormLoaded412668165168
reviewTransactionToConfirmationPage13911204160515914771605
total14861298170717316011707
SwapopenSwapPageFromHome733711330101113
fetchAndDisplaySwapQuotes269626892705526982705
total2770273428063128022806
🌐 Dapp Page Load Benchmarks

Current Commit: ed6a18b | Date: 3/18/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.07s (±52ms) 🟡 | historical mean value: 1.04s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 760ms (±70ms) 🟢 | historical mean value: 731ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 95ms (±136ms) 🟢 | historical mean value: 84ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.07s 52ms 1.03s 1.46s 1.12s 1.46s
domContentLoaded 760ms 70ms 724ms 1.38s 792ms 1.38s
firstPaint 95ms 136ms 64ms 1.45s 96ms 1.45s
firstContentfulPaint 95ms 136ms 64ms 1.45s 96ms 1.45s
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs
  • background: 58 Bytes (0%)
  • ui: -23 Bytes (0%)
  • common: 94 Bytes (0%)

@hmalik88
hmalik88 added this pull request to the merge queue Mar 18, 2026
Merged via the queue into main with commit ab2ea6f Mar 18, 2026
210 checks passed
@hmalik88
hmalik88 deleted the hm/mul-1419 branch March 18, 2026 17:57
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 18, 2026
@metamaskbot metamaskbot added the release-13.24.0 Issue or pull request that will be included in release 13.24.0 label Mar 18, 2026
@MajorLift

MajorLift commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

🧪 Validation Run

Verdict: ✅ nothing moved — Claim: replacing createDeepEqualSelector with createSelector in the account selectors does not cost extra recomputation. head ab2ea6ff92a · 2026-08-02 · selector-recompute check

Note

Trial run of the MetaMask evidence skills
feedback welcome, on the finding or on whether this format is useful to a reviewer.
Not a review verdict; nothing here blocks the PR.

Swapping a deep-equality memo for a reference-equality one can raise recomputations, because a structurally-identical-but-new input now counts as a change. getWalletsWithAccounts was measured in CI at the merge commit and at its parent, same fixture, same probe.

At the parent commit:

getWalletsWithAccounts recomputation count

Verdict: narrowed — unrelated writes cost nothing

Condition Calls Recomputations
Identical state reference 5 1
Fresh metamask slice, unrelated field 5 1
pinnedAccountList changed (a real input) 5 6

Correctness: the returned value is identical across all calls above, so the count
measures memoisation rather than a change in behaviour.

$ git checkout --detach 5befef4073be906ee07d6b15108616ac6bc61f2a && yarn jest ui/selectors/multichain-accounts/__recompute_probe__.test.ts
      RECOMPUTE_PROBE identical=1 unrelated=1 inputChanged=6 n=5 valueStable=true
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Time:        4.309 s, estimated 9 s

Produced by selector-recompute.sh via reselect's own counter; the probe is generated, run, and kept beside this artifact. head 5befef4073be906ee07d6b15108616ac6bc61f2a · 0 tracked changes · node v24.13.1. Run: https://github.com/MajorLift/metamask-skills/actions/runs/30765011348 — logs and artifacts attached there.

At the merge commit:

getWalletsWithAccounts recomputation count

Verdict: narrowed — unrelated writes cost nothing

Condition Calls Recomputations
Identical state reference 5 1
Fresh metamask slice, unrelated field 5 1
pinnedAccountList changed (a real input) 5 6

Correctness: the returned value is identical across all calls above, so the count
measures memoisation rather than a change in behaviour.

$ git checkout --detach ab2ea6ff92a25b044f97f7ab97e305e752c3cfe3 && yarn jest ui/selectors/multichain-accounts/__recompute_probe__.test.ts
      RECOMPUTE_PROBE identical=1 unrelated=1 inputChanged=6 n=5 valueStable=true
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Time:        8.835 s

Produced by selector-recompute.sh via reselect's own counter; the probe is generated, run, and kept beside this artifact. head ab2ea6ff92a25b044f97f7ab97e305e752c3cfe3 · 0 tracked changes · node v24.13.1. Run: https://github.com/MajorLift/metamask-skills/actions/runs/30765011348 — logs and artifacts attached there.

Follows from the arms above

  • Identical at both commits: one recomputation, and unrelated writes cost nothing. The swap did not move the count.
  • valueStable=true in both, so the counts measure memoisation rather than a change in what the selector returns.
  • This is the outcome the lane is least likely to produce and most needed for calibration: a check that only ever reports problems cannot be read as evidence when it reports none.

Open for review: one fixture, one perturbed key. getWalletsWithAccounts composes six input selectors, and this exercises the shapes the fixture reaches — a state this fixture does not construct could still distinguish the two memo strategies. The eight sibling selectors converted in the same change were not measured.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-13.24.0 Issue or pull request that will be included in release 13.24.0 size-M team-accounts-framework Accounts team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants