-
-
Notifications
You must be signed in to change notification settings - Fork 267
chore: integrate storageService with tokenListController #7413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
chore: integrate storageService with tokenListController #7413
Conversation
| tokensChainsCache: { | ||
| includeInStateLogs: false, | ||
| persist: true, | ||
| persist: false, // Persisted separately via StorageService |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making this false to block disk writes
…oading and saving
…tchTokenList calls
|
@metamaskbot publish-preview |
| // Only remove loaded chains, not chains from initial state that need first persist | ||
| for (const chainId of Object.keys(loadedCache) as Hex[]) { | ||
| this.#changedChainsToPersist.delete(chainId); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialization removes chains from persistence queue incorrectly
Medium Severity
The #loadCacheFromStorage method removes ALL chains in loadedCache from #changedChainsToPersist, but loadedCache contains all chains from storage, not just chains that were actually added to state. When a chain exists in both initial state and storage, the update() call preserves the initial state's data (correctly), but the chain is still removed from the persistence queue (incorrectly). This means initial state data that should be persisted to storage is silently dropped if the same chain also exists in storage with older data.
|
@metamaskbot publish-preview |
|
Preview builds have been published. See these instructions for more information about preview builds. Expand for full list of packages and versions. |
|
@metamaskbot publish-preview |
|
Preview builds have been published. See these instructions for more information about preview builds. Expand for full list of packages and versions. |
There was a problem hiding this comment.
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 1 potential issue.
| this.#persistDebounceTimer = undefined; | ||
| } | ||
| this.#changedChainsToPersist.clear(); | ||
| this.#chainsLoadedFromStorage.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pending state changes lost when controller is destroyed
Medium Severity
The destroy() method cancels the debounce timer and clears #changedChainsToPersist without flushing pending changes to storage. If the controller is destroyed within 500ms of a token fetch or state update, the updated token cache data will be discarded and never persisted. On next app launch, stale data would be loaded from storage instead of the fresher data that was fetched but not persisted.
|
@metamaskbot publish-preview |
|
Preview builds have been published. See these instructions for more information about preview builds. Expand for full list of packages and versions. |
There was a problem hiding this comment.
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 1 potential issue.
There was a problem hiding this comment.
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 1 potential issue.
There was a problem hiding this comment.
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.
Description
Optimizes TokenListController storage to reduce write amplification by persisting tokensChainsCache via StorageService using per-chain files instead of a single monolithic state property.
Mobile: MetaMask/metamask-mobile#24019
Extension: MetaMask/metamask-extension#39250
Related: https://github.com/MetaMask/metamask-mobile/pull/22943/files
Related: https://github.com/MetaMask/decisions/pull/110
Related: #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:
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:
References
Checklist
Note
BREAKING
TokenListControllernow persiststokensChainsCachevia StorageService using per‑chain keys (e.g.,tokensChainsCache:0x1) and requires clients to callawait initialize()after constructiontokensChainsCachepersist: false; state changes are auto‑persisted via debounced subscriptionBehavior/impl changes
clearingTokenListData()now async and removes all per‑chain files; deprecatedstart/restart/stopwrappers maintainedProject updates
@metamask/storage-servicedependency and TS references; extensive unit tests added/updated; changelog updated with breaking noteWritten by Cursor Bugbot for commit d6cac27. This will update automatically on new commits. Configure here.