Skip to content

Conversation

@cryptotavares
Copy link
Contributor

@cryptotavares cryptotavares commented Jan 6, 2026

Description

The getNumberOfAllUnapprovedTransactionsAndMessages selector was unmemoized and created new objects via spread operators on every state change, causing unnecessary recomputations in a critical hot path (app header badge count).

This PR implements several optimizations:

  1. Memoization: Converts to a memoized selector using reselect's createSelector
  2. Reference equality: Uses standard createSelector since Redux/Immer provides stable input references
  3. Direct count summation: Sums Object.keys().length directly instead of spreading objects into a merged object, which:
    • Reduces memory allocation from O(N) to O(1)
    • Eliminates potential ID collision bugs (if tx/message IDs overlapped, spread would overwrite and undercount)
    • Only allocates arrays when inputs actually change (memoization prevents recomputation on stable refs)

Open in GitHub Codespaces

Changelog

CHANGELOG entry: null

Related issues

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

Manual testing steps

  1. Open MetaMask extension
  2. Navigate to a dapp and initiate a transaction
  3. Verify the badge count in the header updates correctly
  4. Verify no regression in badge count functionality

Screenshots/Recordings

Not applicable - internal performance optimization with no UI changes.

Before

N/A

After

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

Optimizes a hot-path selector used for the header badge count.

  • Converts getNumberOfAllUnapprovedTransactionsAndMessages to a memoized createSelector
  • Avoids object spreads by summing Object.keys(...).length across sources with nullish guards
  • Reduces unnecessary recomputation and memory allocation; removes risk of ID collisions from object merging

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

@github-actions
Copy link
Contributor

github-actions bot commented Jan 6, 2026

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.

@cryptotavares cryptotavares force-pushed the fix/memoize-getNumberOfAllUnapprovedTransactionsAndMessages branch from bb6e19c to 54597f0 Compare January 6, 2026 22:58
@github-actions github-actions bot added the size-S label Jan 6, 2026
Shallow equality O(n) is sufficient since inputs come from Immer-managed
state with stable references, avoiding expensive deep equality O(n×d).
@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Jan 6, 2026

Builds ready [9c84545]
UI Startup Metrics (1309 ± 101 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13091090164510113821465
load108888013979911531230
domContentLoaded108287713909911491224
domInteractive2716105192486
firstPaint1436630161189282
backgroundConnect22020225611227244
firstReactRender1594051624
getState3517115143770
initialActions104112
loadScripts8696731149999381017
setupStore1266071217
numNetworkReqs171177161167
BrowserifyPower User HomeuiStartup------
load------
domContentLoaded------
domInteractive------
firstPaint------
backgroundConnect------
firstReactRender------
getState------
initialActions------
loadScripts------
setupStore------
numNetworkReqs------
WebpackStandard HomeuiStartup83565611721038871052
load66758194479719831
domContentLoaded66257593979711825
domInteractive2616113192284
firstPaint1085833057133227
backgroundConnect2851173034107
firstReactRender17114761932
getState361573154764
initialActions103111
loadScripts65957393677708817
setupStore1357491432
numNetworkReqs171185171166
WebpackPower User HomeuiStartup------
load------
domContentLoaded------
domInteractive------
firstPaint------
backgroundConnect------
firstReactRender------
getState------
initialActions------
loadScripts------
setupStore------
numNetworkReqs------
FirefoxBrowserifyStandard HomeuiStartup14031099198218115251690
load1127942173113912031393
domContentLoaded1127942173013912021393
domInteractive69322344289156
firstPaint------
backgroundConnect62202745496184
firstReactRender1292521317
getState146139171140
initialActions102112
loadScripts1086927170212211381315
setupStore174260291248
numNetworkReqs19989201477
BrowserifyPower User HomeuiStartup24021440387550127472999
load1684988235646620852307
domContentLoaded1684988235646620852306
domInteractive84358719886252
firstPaint------
backgroundConnect337221086338353995
firstReactRender19115282336
getState10857854111103202
initialActions209123
loadScripts1446969219440518712143
setupStore4259169544139
numNetworkReqs67191833478155
WebpackStandard HomeuiStartup16291330250420817382070
load13391112182712014031513
domContentLoaded13391111182712014011512
domInteractive77293324395132
firstPaint------
backgroundConnect63232694771155
firstReactRender16115681727
getState2161413014118
initialActions113122
loadScripts13011097173910313511481
setupStore2432513816123
numNetworkReqs19982181472
WebpackPower User HomeuiStartup27211653472462431363603
load20041200297651424672616
domContentLoaded20041199297651424672616
domInteractive1032988615689413
firstPaint------
backgroundConnect3503013573674101118
firstReactRender2313143162554
getState1025825837105182
initialActions204123
loadScripts17481146278945521782518
setupStore535107114244191
numNetworkReqs67211813578158
📊 Page Load Benchmark Results

Current Commit: 9c84545 | Date: 1/6/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.02s (±37ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 710ms (±35ms) 🟢 | historical mean value: 729ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 74ms (±11ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.02s 37ms 994ms 1.30s 1.04s 1.30s
domContentLoaded 710ms 35ms 690ms 976ms 723ms 976ms
firstPaint 74ms 11ms 60ms 164ms 84ms 164ms
firstContentfulPaint 74ms 11ms 60ms 164ms 84ms 164ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 237 Bytes (0%)

- Switch to createSelector (reference equality) since Redux/Immer
  provides stable input references
- Sum Object.keys lengths directly instead of spreading objects
- Avoids O(N) memory allocation and potential ID collision issues
@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Jan 7, 2026

Builds ready [4a406e7]
UI Startup Metrics (1289 ± 110 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup12891051152511013621480
load1074861132010111231247
domContentLoaded1066857131010011151238
domInteractive261497192385
firstPaint2256511992462011085
backgroundConnect21619924311225238
firstReactRender1493451624
getState351873103959
initialActions105112
loadScripts8596581096999091020
setupStore1173241217
numNetworkReqs171171161167
BrowserifyPower User HomeuiStartup17861453214114218662046
load1094913142511911721329
domContentLoaded1081908141011811581316
domInteractive34182573428114
firstPaint190731343179214383
backgroundConnect26921158486271528
firstReactRender16113131720
getState16713028829178223
initialActions102112
loadScripts85569311921189291092
setupStore1575481439
numNetworkReqs66541311763116
WebpackStandard HomeuiStartup781647113084823956
load63757289270653795
domContentLoaded63256888670649789
domInteractive2515123212177
firstPaint1105932960151228
backgroundConnect235110253396
firstReactRender15103041724
getState321457124352
initialActions105112
loadScripts62956687868646779
setupStore1253971426
numNetworkReqs181179181173
WebpackPower User HomeuiStartup1248948173818313441640
load7706121207110866946
domContentLoaded7636041195109860938
domInteractive34182013228116
firstPaint1386832371197269
backgroundConnect76861215159543
firstReactRender18143531924
getState14812226020156171
initialActions102012
loadScripts7596011182107853933
setupStore1686791435
numNetworkReqs68532242763127
FirefoxBrowserifyStandard HomeuiStartup14721085236222915811957
load1182931199319812431691
domContentLoaded1182926199219812431691
domInteractive893295412491181
firstPaint------
backgroundConnect64182265573196
firstReactRender1392731319
getState1265681227
initialActions103122
loadScripts1143917196818611741566
setupStore144137151341
numNetworkReqs19985191475
BrowserifyPower User HomeuiStartup23411464377449727072880
load16561000247247820602287
domContentLoaded16561000247247820602287
domInteractive84353997483258
firstPaint------
backgroundConnect3092710413453341007
firstReactRender19125272427
getState935323532109139
initialActions217123
loadScripts1416984227642418842204
setupStore255251352297
numNetworkReqs755214527101127
WebpackStandard HomeuiStartup15861317235219916692019
load13281130176413013941628
domContentLoaded13281129176413013941628
domInteractive772923244100143
firstPaint------
backgroundConnect58212234462162
firstReactRender1710108111625
getState186168271581
initialActions103122
loadScripts12941109167611413471528
setupStore185128231587
numNetworkReqs19986191473
WebpackPower User HomeuiStartup27251728420255230953565
load20631222301151824902706
domContentLoaded20621221301151824902706
domInteractive893063310586325
firstPaint------
backgroundConnect3762812153914611148
firstReactRender21126292630
getState965720128101149
initialActions207123
loadScripts17541147284347322372525
setupStore2441943717118
numNetworkReqs74451673082144
📊 Page Load Benchmark Results

Current Commit: 4a406e7 | Date: 1/7/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±37ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 722ms (±35ms) 🟢 | historical mean value: 726ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±9ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 37ms 1.02s 1.31s 1.07s 1.31s
domContentLoaded 722ms 35ms 700ms 986ms 751ms 986ms
firstPaint 76ms 9ms 60ms 152ms 88ms 152ms
firstContentfulPaint 76ms 9ms 60ms 152ms 88ms 152ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 430 Bytes (0.01%)
  • ui: 2.52 KiB (0.03%)
  • common: 3.11 KiB (0.03%)

@cryptotavares cryptotavares marked this pull request as ready for review January 7, 2026 17:33
@cryptotavares cryptotavares added the team-confirmations Push issues to confirmations team label Jan 7, 2026
@cryptotavares cryptotavares added this pull request to the merge queue Jan 8, 2026
Merged via the queue into main with commit 3fe3d5f Jan 8, 2026
185 of 186 checks passed
@cryptotavares cryptotavares deleted the fix/memoize-getNumberOfAllUnapprovedTransactionsAndMessages branch January 8, 2026 11:46
@github-actions github-actions bot locked and limited conversation to collaborators Jan 8, 2026
@metamaskbot metamaskbot added the release-13.14.0 Issue or pull request that will be included in release 13.14.0 label Jan 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-13.14.0 Issue or pull request that will be included in release 13.14.0 size-S team-confirmations Push issues to confirmations team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants