diff --git a/packages/assets-controller/CHANGELOG.md b/packages/assets-controller/CHANGELOG.md index d52bcc6eae..bd6b7a466a 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 + +- `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] ### 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..ef50daa542 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,26 @@ 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, + ) as Caip19AssetId[]) { + 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); } 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. */