Skip to content

fix(assets-controller): consume account activity - #9517

Open
Kriys94 wants to merge 8 commits into
mainfrom
fix/AssetsAccountActivity
Open

fix(assets-controller): consume account activity#9517
Kriys94 wants to merge 8 commits into
mainfrom
fix/AssetsAccountActivity

Conversation

@Kriys94

@Kriys94 Kriys94 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Explanation

Loom Video showing the whole flow and the real-time update: https://www.loom.com/share/1c7ea24a3d2d4653a9b94a5b8ab178a9

Preview build passing the e2e tests MetaMask/metamask-extension#44962

What is the current state of things and why does it need to change?

AssetsController currently gets real-time balances and per-chain status through two overlapping paths:

  • BackendWebsocketDataSource, which talks to BackendWebSocketService directly and manages its own channel subscriptions — but may never receive callbacks when AccountActivityService owns the server subscription.
  • A direct AccountActivityService:balanceUpdated subscription inside AssetsController itself, added as a workaround for exactly that gap.

This split ownership caused duplicated logic (two websocket balance-decoding paths), race-prone subscription handoffs, and chain-status information (up/down) that didn't participate in the controller's chain-claiming, so polling data sources could poll chains already covered by real-time websocket data.

What is the solution and how does it work?

Consolidate all real-time consumption behind AccountActivityService, which already owns the WebSocket connection and channel subscriptions, via a new thin data source:

  • Add AccountActivityDataSource — subscribes to the two high-level events published by AccountActivityService:
    • balanceUpdated — resolves the address against the wallet's selected accounts, converts the payload to a DataResponse (processAccountActivityBalanceUpdates, moved out of AssetsController utils into the data source), and pushes it to the controller through an injected onAssetsUpdate callback bound to AssetsController.handleAssetsUpdate.
    • statusChanged — chains reported "up" are claimed as active chains; chains reported "down" are released so polling sources take over. The service flushes all tracked chains as "down" on disconnect, so activeChains only ever reflects live status.
  • Chain-claiming priority: AccountActivityDataSource is now the highest-priority balance data source (AccountActivity → AccountsApi → Snap → RPC), so chains covered by real-time websocket data are reserved first and not redundantly polled by AccountsApiDataSource/RpcDataSource.
  • Remove BackendWebsocketDataSource and its factory/types, the BackendWebSocketService actions/events from the controller messenger, and the controller's direct balanceUpdated subscription/decoding path.
  • AccountActivityDataSource is event-driven and chain-agnostic: subscribe() is intentionally a no-op; it does not take part in the controller's subscribe/unsubscribe handoff. Debounce/jitter of chain-status bursts stays in AssetsController where re-subscription happens.
  • Custom-asset graduation now keys off AccountActivityDataSource (previously BackendWebsocketDataSource / the AccountActivityService source id).

Breaking changes

  • BREAKING: AssetsController messenger must now allow the AccountActivityService:statusChanged event.
  • BREAKING: BackendWebsocketDataSource and its factory/types are removed (BackendWebsocketDataSource, createBackendWebsocketDataSource, BackendWebsocketDataSourceOptions, BackendWebsocketDataSourceState). Consumers no longer need to delegate BackendWebSocketService actions/events to the AssetsController messenger.

References

  • Related to fix: remove ws balance freshness guard #9273 (direct AccountActivityService:balanceUpdated subscription this PR supersedes)
  • Consumer adoption: MetaMask/metamask-extension#<TODO — extension PR consuming preview 2dc3d26a4, updates messenger delegations>

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

High Risk
Breaking API removal and changes to balance/chain-claiming priority affect how real-time vs polled balances are merged across the wallet; incorrect messenger setup or status handling could cause stale balances or redundant polling.

Overview
BREAKING: Removes BackendWebsocketDataSource and all BackendWebSocketService messenger wiring; integrators must allow AccountActivityService:statusChanged on the AssetsController messenger.

Real-time balances and per-chain availability now flow through a new AccountActivityDataSource, which listens to AccountActivityService:balanceUpdated and statusChanged instead of managing WebSocket channels itself. Balance payloads are decoded inside the data source and forwarded via an injected onAssetsUpdate hook to handleAssetsUpdate; chain up/down status drives chain-claiming so polling sources (AccountsApi, RPC) only cover chains not held by live activity.

AssetsController drops its duplicate balanceUpdated handler and promotes AccountActivityDataSource to first place in the balance source priority list. #handleActiveChainsUpdate now no-ops unless the UI is open and the keyring is unlocked, and AccountsApiDataSource immediately fetches when subscription updates add newly handed-off chains.

Reviewed by Cursor Bugbot for commit 8655802. Bugbot is set up for automated code reviews on this repo. Configure here.

@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch 4 times, most recently from 3ddda90 to d937cef Compare July 20, 2026 08:07
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch from 90dafcd to 150e8b9 Compare July 22, 2026 14:15
@Kriys94
Kriys94 marked this pull request as ready for review July 22, 2026 14:15
@Kriys94
Kriys94 requested review from a team as code owners July 22, 2026 14:15
@Kriys94
Kriys94 temporarily deployed to default-branch July 22, 2026 14:16 — with GitHub Actions Inactive
Comment thread packages/assets-controller/src/AssetsController.ts
Comment thread packages/assets-controller/src/AssetsController.ts Outdated
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch 2 times, most recently from f9b8d3c to a44a1c0 Compare July 22, 2026 15:25
Comment thread packages/assets-controller/src/AssetsController.ts Outdated
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch from a44a1c0 to d1c1b1e Compare July 22, 2026 15:44
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch 3 times, most recently from c414460 to fe3dbde Compare July 24, 2026 19:03
@@ -1,78 +0,0 @@
import type { BalanceUpdate } from '@metamask/core-backend';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is moved in AccountActivityDataSource

Comment thread packages/assets-controller/src/AssetsController.ts Outdated
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch from fe3dbde to c0f4c0e Compare July 28, 2026 15:10
Comment thread packages/assets-controller/src/AssetsController.ts Outdated
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch from f7b1edb to defbccc Compare July 28, 2026 18:05
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch from defbccc to 2dc3d26 Compare July 28, 2026 19:12
@Kriys94

Kriys94 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.5-preview-2dc3d26a4
@metamask-previews/accounts-controller@39.0.5-preview-2dc3d26a4
@metamask-previews/address-book-controller@7.1.2-preview-2dc3d26a4
@metamask-previews/ai-controllers@0.8.0-preview-2dc3d26a4
@metamask-previews/analytics-controller@1.2.1-preview-2dc3d26a4
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-2dc3d26a4
@metamask-previews/announcement-controller@8.1.0-preview-2dc3d26a4
@metamask-previews/app-metadata-controller@2.0.1-preview-2dc3d26a4
@metamask-previews/approval-controller@9.0.2-preview-2dc3d26a4
@metamask-previews/assets-controller@11.2.1-preview-2dc3d26a4
@metamask-previews/assets-controllers@110.0.0-preview-2dc3d26a4
@metamask-previews/authenticated-user-storage@3.0.1-preview-2dc3d26a4
@metamask-previews/base-controller@9.1.0-preview-2dc3d26a4
@metamask-previews/base-data-service@0.1.3-preview-2dc3d26a4
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-2dc3d26a4
@metamask-previews/bridge-controller@78.0.0-preview-2dc3d26a4
@metamask-previews/bridge-status-controller@74.5.0-preview-2dc3d26a4
@metamask-previews/build-utils@3.0.4-preview-2dc3d26a4
@metamask-previews/chain-agnostic-permission@1.7.0-preview-2dc3d26a4
@metamask-previews/chomp-api-service@4.0.0-preview-2dc3d26a4
@metamask-previews/claims-controller@0.5.3-preview-2dc3d26a4
@metamask-previews/client-controller@1.0.1-preview-2dc3d26a4
@metamask-previews/client-utils@1.2.1-preview-2dc3d26a4
@metamask-previews/compliance-controller@2.1.0-preview-2dc3d26a4
@metamask-previews/composable-controller@12.0.1-preview-2dc3d26a4
@metamask-previews/config-registry-controller@0.4.1-preview-2dc3d26a4
@metamask-previews/connectivity-controller@0.3.0-preview-2dc3d26a4
@metamask-previews/controller-utils@12.3.0-preview-2dc3d26a4
@metamask-previews/core-backend@7.0.0-preview-2dc3d26a4
@metamask-previews/delegation-controller@3.0.2-preview-2dc3d26a4
@metamask-previews/earn-controller@12.2.2-preview-2dc3d26a4
@metamask-previews/eip-5792-middleware@3.0.5-preview-2dc3d26a4
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-2dc3d26a4
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-2dc3d26a4
@metamask-previews/ens-controller@19.1.5-preview-2dc3d26a4
@metamask-previews/eth-block-tracker@15.0.1-preview-2dc3d26a4
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-2dc3d26a4
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-2dc3d26a4
@metamask-previews/foundryup@1.0.1-preview-2dc3d26a4
@metamask-previews/gas-fee-controller@26.3.0-preview-2dc3d26a4
@metamask-previews/gator-permissions-controller@4.2.3-preview-2dc3d26a4
@metamask-previews/geolocation-controller@0.1.3-preview-2dc3d26a4
@metamask-previews/java-tron-up@1.0.0-preview-2dc3d26a4
@metamask-previews/json-rpc-engine@10.5.0-preview-2dc3d26a4
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-2dc3d26a4
@metamask-previews/keyring-controller@27.1.0-preview-2dc3d26a4
@metamask-previews/local-node-utils@1.0.0-preview-2dc3d26a4
@metamask-previews/logging-controller@8.0.2-preview-2dc3d26a4
@metamask-previews/message-manager@14.1.2-preview-2dc3d26a4
@metamask-previews/messenger@2.0.0-preview-2dc3d26a4
@metamask-previews/messenger-cli@0.2.0-preview-2dc3d26a4
@metamask-previews/money-account-api-data-service@0.4.0-preview-2dc3d26a4
@metamask-previews/money-account-balance-service@2.3.0-preview-2dc3d26a4
@metamask-previews/money-account-controller@0.3.3-preview-2dc3d26a4
@metamask-previews/money-account-upgrade-controller@3.0.0-preview-2dc3d26a4
@metamask-previews/multichain-account-service@13.0.0-preview-2dc3d26a4
@metamask-previews/multichain-api-middleware@4.0.1-preview-2dc3d26a4
@metamask-previews/multichain-network-controller@3.2.1-preview-2dc3d26a4
@metamask-previews/multichain-transactions-controller@7.1.1-preview-2dc3d26a4
@metamask-previews/name-controller@9.1.2-preview-2dc3d26a4
@metamask-previews/network-connection-banner-controller@0.1.0-preview-2dc3d26a4
@metamask-previews/network-controller@34.0.0-preview-2dc3d26a4
@metamask-previews/network-enablement-controller@5.6.0-preview-2dc3d26a4
@metamask-previews/notification-services-controller@26.0.0-preview-2dc3d26a4
@metamask-previews/passkey-controller@3.0.0-preview-2dc3d26a4
@metamask-previews/permission-controller@13.1.1-preview-2dc3d26a4
@metamask-previews/permission-log-controller@5.1.0-preview-2dc3d26a4
@metamask-previews/perps-controller@10.0.0-preview-2dc3d26a4
@metamask-previews/phishing-controller@17.3.0-preview-2dc3d26a4
@metamask-previews/platform-api-docs@0.0.0-preview-2dc3d26a4
@metamask-previews/polling-controller@16.0.8-preview-2dc3d26a4
@metamask-previews/preferences-controller@23.1.0-preview-2dc3d26a4
@metamask-previews/profile-metrics-controller@4.0.2-preview-2dc3d26a4
@metamask-previews/profile-sync-controller@28.3.0-preview-2dc3d26a4
@metamask-previews/ramps-controller@18.0.0-preview-2dc3d26a4
@metamask-previews/rate-limit-controller@7.0.1-preview-2dc3d26a4
@metamask-previews/react-data-query@0.2.2-preview-2dc3d26a4
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-2dc3d26a4
@metamask-previews/sample-controllers@5.0.3-preview-2dc3d26a4
@metamask-previews/seedless-onboarding-controller@10.1.0-preview-2dc3d26a4
@metamask-previews/selected-network-controller@26.1.5-preview-2dc3d26a4
@metamask-previews/sentinel-api-service@1.0.0-preview-2dc3d26a4
@metamask-previews/shield-controller@5.1.3-preview-2dc3d26a4
@metamask-previews/signature-controller@39.2.7-preview-2dc3d26a4
@metamask-previews/smart-transactions-controller@25.0.1-preview-2dc3d26a4
@metamask-previews/snap-account-service@2.0.0-preview-2dc3d26a4
@metamask-previews/social-controllers@2.7.0-preview-2dc3d26a4
@metamask-previews/solana-test-validator-up@1.0.0-preview-2dc3d26a4
@metamask-previews/stellar-quickstart-up@0.0.0-preview-2dc3d26a4
@metamask-previews/storage-service@1.0.2-preview-2dc3d26a4
@metamask-previews/subscription-controller@6.2.1-preview-2dc3d26a4
@metamask-previews/transaction-controller@69.2.1-preview-2dc3d26a4
@metamask-previews/transaction-pay-controller@26.0.1-preview-2dc3d26a4
@metamask-previews/user-operation-controller@41.2.7-preview-2dc3d26a4
@metamask-previews/wallet@8.1.0-preview-2dc3d26a4
@metamask-previews/wallet-cli@0.0.0-preview-2dc3d26a4

@Kriys94

Kriys94 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Preview build passing the e2e tests MetaMask/metamask-extension#44962

(event) => {
this.#onAccountActivityBalanceUpdated(event);
},
);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this in AccountActivityDataSource

@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch 2 times, most recently from ec12296 to 400d769 Compare July 29, 2026 20:41
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch from 400d769 to 19dfafb Compare July 30, 2026 09:46
@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch 2 times, most recently from a4cd551 to 87edd71 Compare July 30, 2026 10:16

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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 87edd71. Configure here.

@Kriys94
Kriys94 force-pushed the fix/AssetsAccountActivity branch from 87edd71 to 8655802 Compare July 30, 2026 10:31

@salimtb salimtb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM , i just tested some scenarios and all works as expected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants