core icon indicating copy to clipboard operation
core copied to clipboard

chore: integrate storageService with tokenListController

Open sahar-fehri opened this issue 2 months ago • 0 comments

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 tokensChainsCache to 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 tokensChainsCache via StorageService using 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: false for tokensChainsCache to 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 StorageService actions in messenger; switch to private # fields; export DataCache.
  • Tests
    • Add StorageService mock handlers; extensive tests for migration, save/load, error paths; update to await clearingTokenListData(); minor typings fix for getTokensPath.
  • Build/Deps/Changelog
    • Add @metamask/storage-service dependency and TS project references; update CHANGELOG.md to document new persistence model.

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

sahar-fehri avatar Dec 09 '25 11:12 sahar-fehri