MetaMask / MetaMask/metamask-mobile

Audit parameterized selectors with single-entry caches across `app/selectors` (51 hits, 14 files)

Open
#31,494 1 comment 0 reactions 0 assignees View on GitHub
area-performance INVALID-ISSUE-TEMPLATE Sev3 ta-needs-engineer-escalation ta-triaged team-mobile-platform
Dominant language
TypeScript
Stars
3k
Forks
1.7k
Avg merge
1d 14h
Merged PRs (30d)
669

Description

> **Performance audit finding** · Severity: **Medium (batch)** · Effort: Large · Fix risk: Simple per instance · Test safety net: Partial
> Owner: per-file CODEOWNERS
> Scope: `app/selectors/` (51 hits, 14 files)

### What is this about?

Parameterized selectors (`(_state, arg) => arg` input pattern) built with `createSelector` have a **single-entry cache**: calls with alternating arguments from different components bust the cache on every call, so the selector recomputes per call site per render despite being "memoized". Sweep results on `main` (`b3e7eb88`), hits per file:

- [ ] `app/selectors/earnController/earn/index.ts` (6)
- [ ] `app/selectors/tokensController.ts` (5) — worst instance filed separately: #31490
- [ ] `app/selectors/tokenRatesController.ts` (4)
- [ ] `app/selectors/networkController.ts` (4)
- [ ] `app/selectors/currencyRateController.ts` (4)
- [ ] `app/selectors/smartTransactionsController.ts` (3)
- [ ] `app/selectors/multisrp/index.ts` (3)
- [ ] `app/selectors/transactionController.ts` (2)
- [ ] `app/selectors/tokenSearchDiscoveryDataController.ts` (2)
- [ ] `app/selectors/multichainAccounts/accounts.ts` (2)
- [ ] `app/selectors/assets/assets-list.ts` (2)
- [ ] `app/selectors/accountsController.ts` (2) — compound instance filed separately: #31491
- [ ] `app/selectors/transactionPayController.ts` (1)
- [ ] `app/selectors/snaps/permissionController.ts` (1)

Detection recipe: `grep -rn "(_state\|(_," app/selectors --include="*.ts"`

### Technical Details

Per instance, triage in this order: (1) **lookup-map selector** — memoize one keyed index, consumers key into it (preferred; removes per-arg caching entirely); (2) **factory selector** instantiated per call site with `useMemo`; (3) `lruMemoize` with `maxSize` (last resort). Instances called from a single call site with a stable argument are fine — close them as no-op with a note.

### Acceptance Criteria

- Each file's hits triaged: fixed (with reference-stability test) or explicitly waived (single stable call site).
- No parameterized selector consumed per-row in a list retains a single-entry cache.

### References

- Source: `mms-performance` sweep recipes added in MetaMask/skills#49 (`mm-state-normalization`); pattern catalogued in the extension audit as MetaMask-planning#6484
- Status: **UNVALIDATED** per instance (static sweep; needs per-instance review)

Contributor guide

Open the contributing guide

Research direction

Start with the provided grep recipe, then inspect the 14 listed files and each selector's call sites. Triage each hit as a lookup-map selector, factory selector, lruMemoize case, or stable single-call-site no-op; add reference-stability tests for fixes and document waived instances. Done means all 51 hits are fixed or explicitly waived, with no per-row single-entry cache remaining.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
mobile, performance
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.