@metamask-previews/assets-controller 14.0.2-preview-878689a26 → 14.0.3-preview-64bce4b11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,11 +9,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
+ - Bump `@metamask/transaction-controller` from `^69.6.1` to `^69.7.0` ([#10046](https://github.com/MetaMask/core/pull/10046))
13
+
14
+ ### Fixed
15
+
16
+ - Fix stale ARC USDC/EURC balances after confirmed swaps by running an authoritative RPC balance refresh for post-transaction asset updates ([#10058](https://github.com/MetaMask/core/pull/10058))
17
+
18
+ ## [14.0.3]
19
+
20
+ ### Changed
21
+
12
22
  - Bump `@metamask/remote-feature-flag-controller` from `^6.0.0` to `^6.1.0` ([#9980](https://github.com/MetaMask/core/pull/9980))
13
23
 
14
24
  ### Fixed
15
25
 
16
26
  - Clean up spam assets on keyring unlock, gated behind the `assetsUnifyState` remote feature flag's `useUnlockCleanup` property (disabled unless the flag explicitly enables it) ([#9973](https://github.com/MetaMask/core/pull/9973))
27
+ - Skip transaction-driven force `getAssets` refreshes on chains where AccountActivity already provides live WebSocket balance updates, avoiding a race with the Accounts API that could overwrite correct balances ([#10030](https://github.com/MetaMask/core/pull/10030))
17
28
 
18
29
  ## [14.0.2]
19
30
 
@@ -960,7 +971,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
960
971
  - Refactor `RpcDataSource` to delegate polling to `BalanceFetcher` and `TokenDetector` services ([#7709](https://github.com/MetaMask/core/pull/7709))
961
972
  - Refactor `BalanceFetcher` and `TokenDetector` to extend `StaticIntervalPollingControllerOnly` for independent polling management ([#7709](https://github.com/MetaMask/core/pull/7709))
962
973
 
963
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@14.0.2...HEAD
974
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@14.0.3...HEAD
975
+ [14.0.3]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@14.0.2...@metamask/assets-controller@14.0.3
964
976
  [14.0.2]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@14.0.1...@metamask/assets-controller@14.0.2
965
977
  [14.0.1]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@14.0.0...@metamask/assets-controller@14.0.1
966
978
  [14.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@13.1.4...@metamask/assets-controller@14.0.0
@@ -13,7 +13,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trace, _AssetsController_captureException, _AssetsController_firstInitFetchReported, _AssetsController_stateSizeReported, _AssetsController_emitStateSizeTrace, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_accountTreeInitialized, _AssetsController_controllerMutex, _AssetsController_accountRefreshMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_lastKnownAccountIds, _AssetsController_getSelectedAccounts, _AssetsController_accountActivityDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_customAssetGraduationMiddleware, _AssetsController_rpcFallbackMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_queryApiClient, _AssetsController_onActiveChainsUpdated, _AssetsController_initializeNativeAssetsMap, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_onUnapprovedTransactionAdded, _AssetsController_onTransactionConfirmed, _AssetsController_runSpamCleanup, _AssetsController_updateActive, _AssetsController_handleAccountTreeStateChange, _AssetsController_runAccountTreeRefresh, _AssetsController_runStartupRefresh, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _AssetsController_executeMiddlewares, _AssetsController_assertNonEmptyAccountId, _AssetsController_normalizeAssetIdOrThrow, _AssetsController_fetchMissingPricesWithoutCache, _AssetsController_getNativeAssetMap, _AssetsController_isNativeAsset, _AssetsController_getAssetType, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_getSlowPipelineChainIds, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_ensureDefaultTrackedAssetsSeeded, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_getAssetFromState, _AssetsController_shouldHideNativeToken, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeRpcCustomAssetsSupplement, _AssetsController_unsubscribeBySubscriptionKey, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged, _AssetsController_handleNetworkAdded, _AssetsController_refreshActiveChainsOnNetworkSwitch, _AssetsController_getSelectedEvmChainIdFromNetworkState, _AssetsController_handleNetworkDidChange, _AssetsController_refreshAssetsAfterNetworkChange, _AssetsController_refreshAssetsAfterNetworkAdded;
16
+ var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trace, _AssetsController_captureException, _AssetsController_firstInitFetchReported, _AssetsController_stateSizeReported, _AssetsController_emitStateSizeTrace, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_accountTreeInitialized, _AssetsController_controllerMutex, _AssetsController_accountRefreshMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_lastKnownAccountIds, _AssetsController_getSelectedAccounts, _AssetsController_accountActivityDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_customAssetGraduationMiddleware, _AssetsController_rpcFallbackMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_queryApiClient, _AssetsController_onActiveChainsUpdated, _AssetsController_initializeNativeAssetsMap, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_refreshAssetsForTransaction, _AssetsController_runSpamCleanup, _AssetsController_updateActive, _AssetsController_handleAccountTreeStateChange, _AssetsController_runAccountTreeRefresh, _AssetsController_runStartupRefresh, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _AssetsController_executeMiddlewares, _AssetsController_assertNonEmptyAccountId, _AssetsController_normalizeAssetIdOrThrow, _AssetsController_fetchMissingPricesWithoutCache, _AssetsController_getNativeAssetMap, _AssetsController_isNativeAsset, _AssetsController_getAssetType, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_getSlowPipelineChainIds, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_ensureDefaultTrackedAssetsSeeded, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_getAssetFromState, _AssetsController_shouldHideNativeToken, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeRpcCustomAssetsSupplement, _AssetsController_unsubscribeBySubscriptionKey, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged, _AssetsController_handleNetworkAdded, _AssetsController_refreshActiveChainsOnNetworkSwitch, _AssetsController_getSelectedEvmChainIdFromNetworkState, _AssetsController_handleNetworkDidChange, _AssetsController_refreshAssetsAfterNetworkChange, _AssetsController_refreshAssetsAfterNetworkAdded;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.AssetsController = exports.getDefaultAssetsControllerState = void 0;
19
19
  const base_controller_1 = require("@metamask/base-controller");
@@ -473,9 +473,27 @@ class AssetsController extends base_controller_1.BaseController {
473
473
  }
474
474
  // Collect custom assets for all requested accounts
475
475
  const customAssets = [];
476
+ const chainIdSet = new Set(chainIds);
476
477
  for (const account of accounts) {
477
478
  const accountCustomAssets = this.getCustomAssets(account.id);
478
479
  customAssets.push(...accountCustomAssets);
480
+ // When refreshing after a confirmed transaction, also include graduated
481
+ // tokens — ERC-20s currently in assetsBalance but removed from
482
+ // customAssets by CustomAssetGraduationMiddleware. The Accounts API
483
+ // indexes incoming transfers (received tokens) slower than outgoing
484
+ // ones, so without a direct RPC query the "to" token in a swap keeps
485
+ // the stale API-cached balance until the next polling cycle.
486
+ if (options?.postTransaction) {
487
+ const stateBalances = this.state.assetsBalance[account.id] ?? {};
488
+ for (const assetId of Object.keys(stateBalances)) {
489
+ const assetChainId = assetId.split('/')[0];
490
+ if (chainIdSet.has(assetChainId) &&
491
+ !(0, index_js_1.isStakingContractAssetId)(assetId) &&
492
+ !customAssets.includes(assetId)) {
493
+ customAssets.push(assetId);
494
+ }
495
+ }
496
+ }
479
497
  }
480
498
  if (options?.forceUpdate) {
481
499
  // Pipeline spans only on unlock/first-init fetch; later forceUpdates pass
@@ -574,11 +592,15 @@ class AssetsController extends base_controller_1.BaseController {
574
592
  __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
575
593
  // Background (slow) lane — flattened sibling of the fast lane (not nested
576
594
  // inside its withTrace callback). Still fire-and-forget so UI is not blocked.
577
- const slowPipelineChainIds = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSlowPipelineChainIds).call(this, chainIds, response);
595
+ const slowPipelineChainIds = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSlowPipelineChainIds).call(this, chainIds, response, { forceAll: options?.postTransaction === true });
578
596
  if (slowPipelineChainIds.length > 0) {
579
- const slowSources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
580
- ? [__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"), __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")]
581
- : [__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")];
597
+ let slowSources;
598
+ if (options?.postTransaction || !__classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)) {
599
+ slowSources = [__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")];
600
+ }
601
+ else {
602
+ slowSources = [__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"), __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")];
603
+ }
582
604
  const slowRequest = { ...request, chainIds: slowPipelineChainIds };
583
605
  (0, trace_js_1.withTrace)({
584
606
  name: TRACE_BACKGROUND_FETCH,
@@ -1349,16 +1371,20 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1349
1371
  __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, false, "f");
1350
1372
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1351
1373
  });
1352
- // Subscribe to unapproved transactions - TXs that need confirmation
1353
- // Ensures that balances for the account making transaction are updated (e.g. for gas estimations)
1374
+ // Subscribe to unapproved transactions - TXs that need confirmation.
1375
+ // Ensures balances for the account making the transaction are updated
1376
+ // (e.g. for gas estimations), except on AccountActivity-active chains.
1354
1377
  this.messenger.subscribe('TransactionController:unapprovedTransactionAdded', (transactionMeta) => {
1355
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_onUnapprovedTransactionAdded).call(this, transactionMeta);
1378
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_refreshAssetsForTransaction).call(this, transactionMeta);
1356
1379
  });
1357
1380
  // Post-tx refresh via the full fetch pipeline (Accounts API + RPC fallback).
1381
+ // Skipped for chains covered by AccountActivity (real-time WS updates).
1358
1382
  // RpcDataSource also listens for transactionConfirmed, but only refreshes
1359
1383
  // chains it owns via an active subscription.
1360
1384
  this.messenger.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
1361
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_onTransactionConfirmed).call(this, transactionMeta);
1385
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_refreshAssetsForTransaction).call(this, transactionMeta, {
1386
+ postTransaction: true,
1387
+ });
1362
1388
  });
1363
1389
  // Start tracking only after the account tree is fully built. Unlock can
1364
1390
  // happen before `AccountTreeController.init()`, and `:stateChange` fires
@@ -1371,34 +1397,22 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1371
1397
  __classPrivateFieldSet(this, _AssetsController_accountTreeInitialized, false, "f");
1372
1398
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1373
1399
  });
1374
- }, _AssetsController_onUnapprovedTransactionAdded = function _AssetsController_onUnapprovedTransactionAdded(transactionMeta) {
1400
+ }, _AssetsController_refreshAssetsForTransaction = function _AssetsController_refreshAssetsForTransaction(transactionMeta, options) {
1375
1401
  const hexChainId = transactionMeta.chainId;
1376
1402
  if (!hexChainId) {
1377
1403
  return;
1378
1404
  }
1379
1405
  const caipChainId = `eip155:${parseInt(hexChainId, 16)}`;
1380
- const fromAddress = transactionMeta.txParams.from?.toLowerCase();
1381
- if (!fromAddress) {
1382
- return;
1383
- }
1384
- const matchedAccount = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this).find((account) => account.address.toLowerCase() === fromAddress);
1385
- if (!matchedAccount) {
1406
+ // AccountActivity pushes live balance updates for its active chains; a
1407
+ // pre-confirmation force getAssets would be redundant and can race the
1408
+ // WebSocket path. After confirmation, still run the post-transaction RPC
1409
+ // pass because AccountActivity may update only part of a swap pair.
1410
+ if (!options?.postTransaction &&
1411
+ __classPrivateFieldGet(this, _AssetsController_accountActivityDataSource, "f")
1412
+ .getActiveChainsSync()
1413
+ .includes(caipChainId)) {
1386
1414
  return;
1387
1415
  }
1388
- this.getAssets([matchedAccount], {
1389
- chainIds: [caipChainId],
1390
- forceUpdate: true,
1391
- }).catch((error) => {
1392
- log('Failed to refresh assets after unapproved transaction added', {
1393
- error,
1394
- });
1395
- });
1396
- }, _AssetsController_onTransactionConfirmed = function _AssetsController_onTransactionConfirmed(transactionMeta) {
1397
- const hexChainId = transactionMeta.chainId;
1398
- if (!hexChainId) {
1399
- return;
1400
- }
1401
- const caipChainId = `eip155:${parseInt(hexChainId, 16)}`;
1402
1416
  const fromAddress = transactionMeta.txParams.from?.toLowerCase();
1403
1417
  if (!fromAddress) {
1404
1418
  return;
@@ -1410,8 +1424,9 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1410
1424
  this.getAssets([matchedAccount], {
1411
1425
  chainIds: [caipChainId],
1412
1426
  forceUpdate: true,
1427
+ postTransaction: options?.postTransaction,
1413
1428
  }).catch((error) => {
1414
- log('Failed to refresh assets after transaction confirmed', { error });
1429
+ log('Failed to refresh assets after transaction event', { error });
1415
1430
  });
1416
1431
  }, _AssetsController_runSpamCleanup = async function _AssetsController_runSpamCleanup() {
1417
1432
  try {
@@ -1760,7 +1775,11 @@ async function _AssetsController_executeMiddlewares(params) {
1760
1775
  return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
1761
1776
  }, _AssetsController_getNativeAssetIdsForAccount = function _AssetsController_getNativeAssetIdsForAccount(account) {
1762
1777
  return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account));
1763
- }, _AssetsController_getSlowPipelineChainIds = function _AssetsController_getSlowPipelineChainIds(chainIds, fastResponse) {
1778
+ }, _AssetsController_getSlowPipelineChainIds = function _AssetsController_getSlowPipelineChainIds(chainIds, fastResponse, options) {
1779
+ // Post-transaction: always run RPC to override potentially stale Accounts API data.
1780
+ if (options?.forceAll) {
1781
+ return chainIds;
1782
+ }
1764
1783
  const accountsApiChains = new Set(__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f").getActiveChainsSync());
1765
1784
  return chainIds.filter((chainId) => {
1766
1785
  if (fastResponse.errors?.[chainId]) {