Fix: assets controller custom asset metadata case#8727
Merged
Conversation
…cased asset IDs `TokenDataSource` stores `customAssets` checksummed (via `normalizeAssetId`) but the V3 Tokens API can echo the asset ID lower-cased. The case-sensitive `customAssetIds.has()` bypass missed in that case, dropping user-imported EVM tokens through the `MIN_TOKEN_OCCURRENCES` spam filter and wiping their metadata from `assetsInfo`. Compare lower-cased on both sides so customs reliably bypass the occurrence filter (and the non-EVM Blockaid bypass).
Contributor
Author
|
@metamaskbot publish-preview |
Contributor
Author
|
@metamaskbot publish-preview |
Contributor
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
`RpcDataSource` previously emitted a minimal stub for native asset
metadata (`{ type: 'native', symbol: chainStatus.nativeCurrency,
name: chainStatus.nativeCurrency, decimals: 18 }`) on every balance
fetch. Because the merge logic in `AssetsController#updateState` only
preserves existing metadata when the incoming payload has no `symbol`
and no `name`, this stub clobbered enrichment from the price/info API
(image, description, occurrences, aggregators, ...) and renamed
"Avalanche" to "AVAX" on every refresh.
Mirror the existing ERC-20 behavior for native assets: prefer the
existing metadata in state when present and only emit the stub when
nothing is in state yet (e.g. first sighting of the asset). The
fallback in the balance-fetch error path is gated the same way.
Contributor
Author
|
@metamaskbot publish-preview |
Contributor
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
…balance AccountsAPI can include zero-balance entries for tokens it indexes but the user no longer holds. Graduating those would remove them from `customAssets` and stop the supplemental RPC poll, leaving incoming transfers undetected until the next milestone fetch. Skip graduation unless the reported amount is strictly greater than zero.
When a network is permanently removed from NetworkController the user has no way to navigate back to it, so leftover entries in `assetsBalance`, `assetsInfo`, `assetsPrice`, `customAssets`, and `assetPreferences` just bloat persisted state forever. Subscribe to the existing `NetworkController:networkRemoved` event and drop every CAIP-19-keyed slice for the removed chain. Per-account containers that become empty after the purge are pruned. Subscription teardown is unchanged — it still cascades through NetworkEnablementController. Disabling a chain still preserves data (handled separately in `#handleEnabledNetworksChanged`).
Contributor
Author
|
@metamaskbot publish-preview |
Contributor
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ef7075b. Configure here.
Prithpal-Sooriya
approved these changes
May 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Explanation
References
Checklist
Note
Medium Risk
Medium risk due to switching the RPC detector’s token-list API endpoint/caching behavior and adding new required NetworkController events, which can affect asset detection/refresh across networks for consumers.
Overview
RPC token detection is reworked to use the same
token.api.cx.metamask.io/tokens/{chainId}endpoint and filtering rules asTokenListController, including chain-specificoccurrenceFloorhandling, Linea aggregator filtering, and forwardingiconUrl/aggregatorsinto detection results. A shared optional TanStack QueryqueryClientis introduced to cache/dedupe per-chain token-list fetches, andAssetsControllernow passes its existing API query client toRpcDataSourceby default.AssetsControllernow listens forNetworkController:networkAddedand newNetworkController:networkRemovedevents (breaking for restricted messengers) to force-refresh assets after network config changes, and refactors RPC custom-asset supplemental subscription selection into a pure helper. Fixes include making custom-asset spam-filter bypass case-insensitive inTokenDataSource, preventingRpcDataSourcefrom clobbering enriched native metadata with stubs on refresh/error paths, and only graduating custom assets when upstream sources report a strictly positive balance.Reviewed by Cursor Bugbot for commit 4249719. Bugbot is set up for automated code reviews on this repo. Configure here.