From 2ed1445688c2d795d4f34532898a54c9b04f3edd Mon Sep 17 00:00:00 2001 From: salimtb Date: Sat, 18 Jul 2026 14:20:43 +0200 Subject: [PATCH 1/5] fix(assets-controller): fetch metadata for balances missing assetsInfo DetectionMiddleware only queues brand-new assets, so already-tracked balances without metadata never got enriched and stayed invisible in clients. --- packages/assets-controller/CHANGELOG.md | 4 +++ .../src/data-sources/TokenDataSource.test.ts | 28 +++++++++++++++++++ .../src/data-sources/TokenDataSource.ts | 21 +++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/assets-controller/CHANGELOG.md b/packages/assets-controller/CHANGELOG.md index d52bcc6eae..4681d17e2d 100644 --- a/packages/assets-controller/CHANGELOG.md +++ b/packages/assets-controller/CHANGELOG.md @@ -19,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bump `@metamask/network-enablement-controller` from `^5.5.0` to `^5.6.0` ([#9520](https://github.com/MetaMask/core/pull/9520)) - Bump `@metamask/phishing-controller` from `^17.2.1` to `^17.3.0` ([#9532](https://github.com/MetaMask/core/pull/9532)) +### Fixed + +- Fetch token metadata for assets in `assetsBalance` that are missing `assetsInfo` + ## [11.0.0] ### Fixed diff --git a/packages/assets-controller/src/data-sources/TokenDataSource.test.ts b/packages/assets-controller/src/data-sources/TokenDataSource.test.ts index 040c8f3c1a..a3efca6956 100644 --- a/packages/assets-controller/src/data-sources/TokenDataSource.test.ts +++ b/packages/assets-controller/src/data-sources/TokenDataSource.test.ts @@ -284,6 +284,34 @@ describe('TokenDataSource', () => { expect(next).toHaveBeenCalledWith(context); }); + it('middleware heals metadata for balances missing assetsInfo even when not detected', async () => { + const { controller, apiClient } = setupController({ + messenger: createTestMessenger(), + supportedNetworks: ['eip155:1'], + assetsResponse: [createMockAssetResponse(MOCK_TOKEN_ASSET)], + }); + + const next = jest.fn().mockResolvedValue(undefined); + const context = createMiddlewareContext({ + response: { + assetsBalance: { + 'mock-account-id': { + [MOCK_TOKEN_ASSET]: { amount: '1.5' }, + }, + }, + }, + }); + + await controller.assetsMiddleware(context, next); + + expect(apiClient.tokens.fetchV3Assets).toHaveBeenCalledWith( + [MOCK_TOKEN_ASSET], + expect.objectContaining({ includeIconUrl: true }), + ); + expect(context.response.assetsInfo?.[MOCK_TOKEN_ASSET]).toBeDefined(); + expect(next).toHaveBeenCalledWith(context); + }); + it('middleware skips assets with existing metadata containing image in response', async () => { const { controller, apiClient } = setupController({ messenger: createTestMessenger(), diff --git a/packages/assets-controller/src/data-sources/TokenDataSource.ts b/packages/assets-controller/src/data-sources/TokenDataSource.ts index 58eff1d80e..105d30e57e 100644 --- a/packages/assets-controller/src/data-sources/TokenDataSource.ts +++ b/packages/assets-controller/src/data-sources/TokenDataSource.ts @@ -154,6 +154,7 @@ function getOccurrenceFloorForAsset( * * This middleware-based data source: * - Checks detected assets for missing metadata/images + * - Also checks `assetsBalance` entries missing metadata/images * - Fetches metadata from Tokens API v3 for assets needing enrichment * - Filters EVM ERC-20 spam using per-chain floors from Token API * `/v1/suggestedOccurrenceFloors` (default floor 3) @@ -351,7 +352,7 @@ export class TokenDataSource { * * This middleware: * 1. Extracts the response from context - * 2. Fetches metadata for detected assets (assets without metadata) + * 2. Fetches metadata for detected assets and balances missing metadata * 3. Enriches the response with fetched metadata * 4. Calls next() at the end to continue the middleware chain * @@ -410,6 +411,24 @@ export class TokenDataSource { } } + // Also fetch metadata for balances that are missing it + if (response.assetsBalance) { + for (const accountBalances of Object.values(response.assetsBalance)) { + for (const assetId of Object.keys(accountBalances)) { + if (response.assetsInfo?.[assetId]?.image) { + continue; + } + if (stateMetadata[assetId]?.image) { + continue; + } + if (isStakingContractAssetId(assetId)) { + continue; + } + assetIdsNeedingMetadata.add(assetId); + } + } + } + if (assetIdsNeedingMetadata.size === 0) { return next(ctx); } From 4807fe5d2ebcab1600fa42d4f6bdf32457c6f698 Mon Sep 17 00:00:00 2001 From: salimtb Date: Sat, 18 Jul 2026 14:27:51 +0200 Subject: [PATCH 2/5] fix: clean up --- packages/assets-controllers/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/assets-controllers/CHANGELOG.md b/packages/assets-controllers/CHANGELOG.md index 864cfb9263..5e8fc5bec7 100644 --- a/packages/assets-controllers/CHANGELOG.md +++ b/packages/assets-controllers/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- `fetchTokenListByChainId` (`token-service`) now sets the token-list `occurrenceFloor` query param from Token API `GET /v1/suggestedOccurrenceFloors` (cached 1h), replacing hardcoded Linea/MegaETH/Tempo special cases. Missing chains or failed fetches fall back to 3. This affects `TokenDetectionController` and `TokenListController`, which both use this helper ([#9537](https://github.com/MetaMask/core/pull/9537)) +- `fetchTokenListByChainId` (`token-service`) now sets the token-list `occurrenceFloor` query param from Token API `GET /v1/suggestedOccurrenceFloors` (cached 1h), replacing hardcoded Linea/MegaETH/Tempo special cases. Missing chains or failed fetches fall back to 3. This affects `TokenDetectionController` and `TokenListController`, which both use this helper ([#9547](https://github.com/MetaMask/core/pull/9547)) - Bump `@metamask/network-enablement-controller` from `^5.5.0` to `^5.6.0` ([#9520](https://github.com/MetaMask/core/pull/9520)) - Bump `@metamask/phishing-controller` from `^17.2.1` to `^17.3.0` ([#9532](https://github.com/MetaMask/core/pull/9532)) - Modified native asset addresses for Stable (`988`), Rootstock (`30`) and Gnosis (`100`) in `codefi-v2.ts` ([#9386](https://github.com/MetaMask/core/pull/9386)) From e8da34b93727a9d58f548dc5c1db8badea8fca9f Mon Sep 17 00:00:00 2001 From: salimtb Date: Sat, 18 Jul 2026 14:32:35 +0200 Subject: [PATCH 3/5] fix: clean up --- packages/assets-controller/CHANGELOG.md | 2 +- packages/assets-controllers/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/assets-controller/CHANGELOG.md b/packages/assets-controller/CHANGELOG.md index 4681d17e2d..bd6b7a466a 100644 --- a/packages/assets-controller/CHANGELOG.md +++ b/packages/assets-controller/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fetch token metadata for assets in `assetsBalance` that are missing `assetsInfo` +- `TokenDataSource` now also fetches token metadata for assets present in `assetsBalance` that are missing `assetsInfo` (previously only detected assets without metadata were enriched) ([#9547](https://github.com/MetaMask/core/pull/9547)) ## [11.0.0] diff --git a/packages/assets-controllers/CHANGELOG.md b/packages/assets-controllers/CHANGELOG.md index 5e8fc5bec7..864cfb9263 100644 --- a/packages/assets-controllers/CHANGELOG.md +++ b/packages/assets-controllers/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- `fetchTokenListByChainId` (`token-service`) now sets the token-list `occurrenceFloor` query param from Token API `GET /v1/suggestedOccurrenceFloors` (cached 1h), replacing hardcoded Linea/MegaETH/Tempo special cases. Missing chains or failed fetches fall back to 3. This affects `TokenDetectionController` and `TokenListController`, which both use this helper ([#9547](https://github.com/MetaMask/core/pull/9547)) +- `fetchTokenListByChainId` (`token-service`) now sets the token-list `occurrenceFloor` query param from Token API `GET /v1/suggestedOccurrenceFloors` (cached 1h), replacing hardcoded Linea/MegaETH/Tempo special cases. Missing chains or failed fetches fall back to 3. This affects `TokenDetectionController` and `TokenListController`, which both use this helper ([#9537](https://github.com/MetaMask/core/pull/9537)) - Bump `@metamask/network-enablement-controller` from `^5.5.0` to `^5.6.0` ([#9520](https://github.com/MetaMask/core/pull/9520)) - Bump `@metamask/phishing-controller` from `^17.2.1` to `^17.3.0` ([#9532](https://github.com/MetaMask/core/pull/9532)) - Modified native asset addresses for Stable (`988`), Rootstock (`30`) and Gnosis (`100`) in `codefi-v2.ts` ([#9386](https://github.com/MetaMask/core/pull/9386)) From f19edaea74fc39f9a9382b17558d7a7f42d0926f Mon Sep 17 00:00:00 2001 From: salimtb Date: Sat, 18 Jul 2026 14:37:42 +0200 Subject: [PATCH 4/5] fix: add account api support for robinhood --- packages/assets-controllers/CHANGELOG.md | 1 + packages/assets-controllers/src/constants.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/assets-controllers/CHANGELOG.md b/packages/assets-controllers/CHANGELOG.md index 864cfb9263..22e9bc8433 100644 --- a/packages/assets-controllers/CHANGELOG.md +++ b/packages/assets-controllers/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Add Robinhood Chain (`4663`/`0x1237`) to `SUPPORTED_NETWORKS_ACCOUNTS_API_V4` so balances and token detection use the Accounts API instead of RPC-only ([#9547](https://github.com/MetaMask/core/pull/9547)) - Add Robinhood Chain (`4663`/`0x1237`) BalanceFetcher support for legacy single-call token detection ([#9473](https://github.com/MetaMask/core/pull/9473)) - Add `Robinhood` in `SupportedTokenDetectionNetworks` - Add Robinhood BalanceFetcher address in `SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID` diff --git a/packages/assets-controllers/src/constants.ts b/packages/assets-controllers/src/constants.ts index 3eae3a6db0..d1cbbbdb03 100644 --- a/packages/assets-controllers/src/constants.ts +++ b/packages/assets-controllers/src/constants.ts @@ -21,6 +21,7 @@ export const SUPPORTED_NETWORKS_ACCOUNTS_API_V4 = [ '0x8f', // 143 '0x3e7', // 999 HyperEVM '0x13b2', // 5042 Arc + '0x1237', // 4663 Robinhood ]; /** Lowercase ERC-20 address for MetaMask USD (mUSD), same contract on listed chains. */ From f7e9195203fdb82039c2bc935251ec950007a4dc Mon Sep 17 00:00:00 2001 From: salimtb Date: Sat, 18 Jul 2026 14:45:37 +0200 Subject: [PATCH 5/5] fix: clean up --- .../assets-controller/src/data-sources/TokenDataSource.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/assets-controller/src/data-sources/TokenDataSource.ts b/packages/assets-controller/src/data-sources/TokenDataSource.ts index 105d30e57e..ef50daa542 100644 --- a/packages/assets-controller/src/data-sources/TokenDataSource.ts +++ b/packages/assets-controller/src/data-sources/TokenDataSource.ts @@ -414,7 +414,9 @@ export class TokenDataSource { // Also fetch metadata for balances that are missing it if (response.assetsBalance) { for (const accountBalances of Object.values(response.assetsBalance)) { - for (const assetId of Object.keys(accountBalances)) { + for (const assetId of Object.keys( + accountBalances, + ) as Caip19AssetId[]) { if (response.assetsInfo?.[assetId]?.image) { continue; }