fix(assets-controller): consume account activity - #9517
Conversation
3ddda90 to
d937cef
Compare
90dafcd to
150e8b9
Compare
f9b8d3c to
a44a1c0
Compare
a44a1c0 to
d1c1b1e
Compare
c414460 to
fe3dbde
Compare
| @@ -1,78 +0,0 @@ | |||
| import type { BalanceUpdate } from '@metamask/core-backend'; | |||
There was a problem hiding this comment.
This code is moved in AccountActivityDataSource
fe3dbde to
c0f4c0e
Compare
f7b1edb to
defbccc
Compare
defbccc to
2dc3d26
Compare
|
@metamaskbot publish-preview |
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
|
Preview build passing the e2e tests MetaMask/metamask-extension#44962 |
| (event) => { | ||
| this.#onAccountActivityBalanceUpdated(event); | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Move this in AccountActivityDataSource
ec12296 to
400d769
Compare
400d769 to
19dfafb
Compare
a4cd551 to
87edd71
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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.
87edd71 to
8655802
Compare
salimtb
left a comment
There was a problem hiding this comment.
LGTM , i just tested some scenarios and all works as expected

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?
AssetsControllercurrently gets real-time balances and per-chain status through two overlapping paths:BackendWebsocketDataSource, which talks toBackendWebSocketServicedirectly and manages its own channel subscriptions — but may never receive callbacks whenAccountActivityServiceowns the server subscription.AccountActivityService:balanceUpdatedsubscription insideAssetsControlleritself, 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:AccountActivityDataSource— subscribes to the two high-level events published byAccountActivityService:balanceUpdated— resolves the address against the wallet's selected accounts, converts the payload to aDataResponse(processAccountActivityBalanceUpdates, moved out ofAssetsControllerutils into the data source), and pushes it to the controller through an injectedonAssetsUpdatecallback bound toAssetsController.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, soactiveChainsonly ever reflects live status.AccountActivityDataSourceis 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 byAccountsApiDataSource/RpcDataSource.BackendWebsocketDataSourceand its factory/types, theBackendWebSocketServiceactions/events from the controller messenger, and the controller's directbalanceUpdatedsubscription/decoding path.AccountActivityDataSourceis 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 inAssetsControllerwhere re-subscription happens.AccountActivityDataSource(previouslyBackendWebsocketDataSource/ theAccountActivityServicesource id).Breaking changes
AssetsControllermessenger must now allow theAccountActivityService:statusChangedevent.BackendWebsocketDataSourceand its factory/types are removed (BackendWebsocketDataSource,createBackendWebsocketDataSource,BackendWebsocketDataSourceOptions,BackendWebsocketDataSourceState). Consumers no longer need to delegateBackendWebSocketServiceactions/events to theAssetsControllermessenger.References
AccountActivityService:balanceUpdatedsubscription this PR supersedes)2dc3d26a4, updates messenger delegations>Checklist
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
BackendWebsocketDataSourceand allBackendWebSocketServicemessenger wiring; integrators must allowAccountActivityService:statusChangedon theAssetsControllermessenger.Real-time balances and per-chain availability now flow through a new
AccountActivityDataSource, which listens toAccountActivityService:balanceUpdatedandstatusChangedinstead of managing WebSocket channels itself. Balance payloads are decoded inside the data source and forwarded via an injectedonAssetsUpdatehook tohandleAssetsUpdate; chain up/down status drives chain-claiming so polling sources (AccountsApi, RPC) only cover chains not held by live activity.AssetsControllerdrops its duplicatebalanceUpdatedhandler and promotesAccountActivityDataSourceto first place in the balance source priority list.#handleActiveChainsUpdatenow no-ops unless the UI is open and the keyring is unlocked, andAccountsApiDataSourceimmediately 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.