diff --git a/packages/assets-controller/CHANGELOG.md b/packages/assets-controller/CHANGELOG.md index 3f2eff4d8e..80bc5d8767 100644 --- a/packages/assets-controller/CHANGELOG.md +++ b/packages/assets-controller/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `AccountsApiDataSource` now treats Accounts API `/v2/supportedNetworks` `partialSupport` as active chains in addition to `fullSupport`, still gated by the Snaps assets migration feature flags ([#10144](https://github.com/MetaMask/core/pull/10144)) - `AccountsApiDataSource` now reads Accounts API `/v2/supportedNetworks` as CAIP-2 `fullSupport` and `partialSupport` string arrays, matching the current API payload +### Fixed + +- Fix post-transaction balance refreshes for default-tracked native assets on AccountActivity-active chains ([#10198](https://github.com/MetaMask/core/pull/10198)) + ## [16.0.0] ### Changed diff --git a/packages/assets-controller/src/AssetsController.test.ts b/packages/assets-controller/src/AssetsController.test.ts index dc31450f49..a8b699308c 100644 --- a/packages/assets-controller/src/AssetsController.test.ts +++ b/packages/assets-controller/src/AssetsController.test.ts @@ -3007,6 +3007,39 @@ describe('AssetsController', () => { }); }); + it('force refreshes default-tracked native assets even when the chain is AccountActivity-active', async () => { + await withController(async ({ controller, messenger }) => { + const getAssetsSpy = jest + .spyOn(controller, 'getAssets') + .mockResolvedValue({}); + + messenger.publish('AccountActivityService:statusChanged', { + chainIds: ['eip155:5042'], + status: 'up', + }); + + await flushPromises(); + + messenger.publish('TransactionController:transactionConfirmed', { + chainId: '0x13b2', + txParams: { from: '0x1234567890123456789012345678901234567890' }, + }); + + await flushPromises(); + + expect(getAssetsSpy).toHaveBeenCalledWith( + [expect.objectContaining({ id: MOCK_ACCOUNT_ID })], + { + chainIds: ['eip155:5042'], + forceUpdate: true, + bypassServerCache: true, + }, + ); + + getAssetsSpy.mockRestore(); + }); + }); + it('publishes balanceChanged event when balance updates', async () => { await withController(async ({ controller, messenger }) => { const balanceChangedHandler = jest.fn(); diff --git a/packages/assets-controller/src/AssetsController.ts b/packages/assets-controller/src/AssetsController.ts index e3dffd5630..bdf55c7778 100644 --- a/packages/assets-controller/src/AssetsController.ts +++ b/packages/assets-controller/src/AssetsController.ts @@ -109,6 +109,7 @@ import { DEFAULT_TRACKED_ASSETS_BY_CHAIN, buildDefaultAssetsInfo, getDefaultAssetMetadata, + getDefaultTrackedAssetsForChain, } from './defaults.js'; import { AssetsDataSourceError } from './errors.js'; import { projectLogger, createModuleLogger } from './logger.js'; @@ -1258,12 +1259,19 @@ export class AssetsController extends BaseController< const caipChainId = `eip155:${parseInt(hexChainId, 16)}` as ChainId; + const hasDefaultTrackedNativeAsset = getDefaultTrackedAssetsForChain( + caipChainId, + ).some((assetId) => assetId.includes('/slip44:')); + // AccountActivity pushes live balance updates for its active chains; a // force getAssets would be redundant and can race the WebSocket path. + // Default-tracked native assets still need the full fetch pipeline because + // AccountActivity can miss their post-transaction balance updates. if ( this.#accountActivityDataSource .getActiveChainsSync() - .includes(caipChainId) + .includes(caipChainId) && + !hasDefaultTrackedNativeAsset ) { return; }