chore: integrate storageService with tokenListController
Description
Optimizes TokenListController storage to reduce write amplification by persisting tokensChainsCache via StorageService using per-chain files instead of a single monolithic state property.
Related: https://github.com/MetaMask/metamask-mobile/pull/22943/files
Related: https://github.com/MetaMask/decisions/pull/110
Related: https://github.com/MetaMask/core/pull/7192
Explanation
The tokensChainsCache (~5MB total, containing token lists for all chains) was persisted as part of the controller state. Every time a single chain's token list was updated (~100-500KB), the entire ~5MB cache was rewritten to disk, causing:
- Startup performance issues (loading large state on app initialization)
- Runtime performance degradation (frequent large writes during token fetches)
- Impacts both extension
Solution
Per-Chain File Storage: Each chain's cache is now stored in a separate file (e.g., tokensChainsCache:0x1, tokensChainsCache:0x89) Only the updated chain (~100-500KB) is written on each token fetch, reducing write operations by ~90-95% All chains are loaded in parallel at startup to maintain compatibility with TokenDetectionController Key Changes:
- Set tokensChainsCache metadata to persist: false to prevent framework-managed persistence
- Added #loadCacheFromStorage() to load all per-chain files in parallel on initialization
- Added #saveChainCacheToStorage(chainId) to persist only the specific chain that changed
- Added #migrateStateToStorage() to automatically migrate existing cache data on first launch after upgrade
- Updated clearingTokenListData() to remove all per-chain files
References
Checklist
- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
- [ ] I've communicated my changes to consumers by updating changelogs for packages I've changed
- [ ] I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them
[!NOTE] TokenListController now persists
tokensChainsCacheto StorageService per-chain with migration, parallel loading, improved error handling, and updated tests; adds StorageService dependency and disables framework persistence for that state.
- TokenListController
- Persist
tokensChainsCacheviaStorageServiceusing per-chain keys (e.g.,tokensChainsCache:0x1); load all chains in parallel at init.- Add migration from state to per-chain storage; set state metadata
persist: falsefortokensChainsCacheto avoid duplication.- Save only the updated chain on fetch; make
clearingTokenListData()async to clear both state and stored per‑chain files; add robust error logging around load/save/clear and network changes.- Integrate
StorageServiceactions in messenger; switch to private#fields; exportDataCache.- Tests
- Add StorageService mock handlers; extensive tests for migration, save/load, error paths; update to
awaitclearingTokenListData(); minor typings fix forgetTokensPath.- Build/Deps/Changelog
- Add
@metamask/storage-servicedependency and TS project references; updateCHANGELOG.mdto document new persistence model.Written by Cursor Bugbot for commit eec88692cbf3407d657badc6020eb435c8dc16ab. This will update automatically on new commits. Configure here.