Skip to content

Conversation

Kriys94
Copy link
Contributor

@Kriys94 Kriys94 commented Oct 7, 2025

This PR integrates the TokenBalancesController with the new @metamask/core-backend package to enable real-time balance updates via WebSocket connections. This provides users with instant balance updates without relying solely on periodic polling.

Context & Dependencies

⚠️ This PR depends on #6722 being merged first, which introduces the @metamask/core-backend package with BackendWebSocketService and AccountActivityService.

Current State & Problem

Currently, the TokenBalancesController relies exclusively on periodic REST API polling to detect balance changes. This approach has several limitations:

  • High latency: Users must wait for the next polling interval (default 180s) to see balance updates
  • Increased API load: Constant polling from all users creates unnecessary server load
  • Poor UX for time-sensitive operations: Users don't get immediate feedback when balances change

Solution

This PR enhances TokenBalancesController to:

  • Subscribe to real-time balance updates via WebSocket when the AccountActivityService is available
  • Coordinate polling dynamically based on WebSocket connection state:
    • When WebSocket is connected: Reduce polling to 5-minute backup intervals
    • When WebSocket is disconnected: Resume default 20-second polling intervals
  • Maintain backward compatibility: Works identically when core-backend package is unavailable
  • Provide graceful degradation: Automatically falls back to polling if WebSocket fails

Key Implementation Details

Integration with AccountActivityService:

  • Subscribes to AccountActivityService:balanceUpdated events via messenger
  • Updates token balances immediately when WebSocket notifications arrive
  • Processes balance changes without waiting for polling cycles

Connection State Coordination:

  • Listens to BackendWebSocketService:connectionStateChanged events
  • Dynamically adjusts polling intervals to reduce API load when real-time updates are active
  • Ensures continuous data flow even during WebSocket reconnection attempts

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
    • Enhanced TokenBalancesController tests to 1,225 lines covering WebSocket integration scenarios
    • Added tests for connection state coordination and fallback behavior
    • Verified graceful degradation when core-backend is unavailable
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
    • Updated JSDoc for new methods and configuration options
    • Documented WebSocket integration behavior
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
    • Added CHANGELOG.md entries for @metamask/assets-controllers
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes
    • N/A - no breaking changes introduced, backward compatible integration

Note

Integrates TokenBalancesController with AccountActivityService for real-time balance updates, adds status-driven polling (with debounce/jitter) and WS-based token import, updates docs/tests, and introduces core-backend dependency with BREAKING messenger and interval changes.

  • Assets Controllers:
    • TokenBalancesController:
      • Subscribes to AccountActivityService:balanceUpdated and statusChanged for real-time updates and status-driven polling.
      • Adjusts polling dynamically (debounced 5s, jittered) and sets defaults: 30s (down) and 5m when WebSocket is up.
      • Processes ERC20/native updates, updates AccountTracker, imports untracked tokens via TokenDetectionController:addDetectedTokensViaWs.
      • Adds utilities (caipChainIdToHex, parseAssetType), handles allIgnoredTokens, and cleans up timers on destroy.
    • TokenDetectionController:
      • Adds public/action addDetectedTokensViaWs to add WS-detected tokens from cache; minor cleanups.
    • BREAKING:
      • Messenger must allow AccountActivityService:balanceUpdated, AccountActivityService:statusChanged, and TokenDetectionController:addDetectedTokensViaWs.
      • Default polling interval changed to 30s (was 180s).
    • Docs/Tests:
      • Adds docs/real-time-balance-updates-flow.md and updates README.
      • Extensive new tests for WS flows, utilities, and polling logic; tweaks Jest coverage threshold.
    • Deps/Config:
      • Adds @metamask/core-backend as dependency and peerDependency; updates tsconfig references and yarn.lock.

Written by Cursor Bugbot for commit 5dac77e. This will update automatically on new commits. Configure here.

@Kriys94 Kriys94 force-pushed the feature/token-balances-integration branch 7 times, most recently from 695f8e8 to b06186b Compare October 8, 2025 15:54
Copy link

socket-security bot commented Oct 8, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​metamask/​core-backend@​1.0.17710010090100

View full report

Copy link

socket-security bot commented Oct 8, 2025

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

Ignoring alerts on:

View full report

@Kriys94 Kriys94 force-pushed the feature/token-balances-integration branch from 9e3af3f to 54419f6 Compare October 8, 2025 21:26
@Kriys94 Kriys94 marked this pull request as ready for review October 9, 2025 12:44
@Kriys94 Kriys94 requested review from a team as code owners October 9, 2025 12:44
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@Kriys94 Kriys94 force-pushed the feature/token-balances-integration branch 4 times, most recently from a83a25c to bb5bd02 Compare October 10, 2025 10:19
This PR integrates the TokenBalancesController with the @metamask/core-backend
package to enable real-time balance updates via WebSocket connections.

Key Changes:
- Add real-time balance updates via WebSocket integration with AccountActivityService
- Add support for dynamic polling based on WebSocket connection status
- Add TokenDetectionController:addDetectedTokensViaWs action handler
- Add @metamask/core-backend as a dependency and peer dependency
- Extract parseAssetType into token-balances-utils for better code organization
- Update documentation and tests

Breaking Changes:
- TokenBalancesController messenger must now allow AccountActivityService events
- TokenBalancesController messenger must now allow TokenDetectionController:addDetectedTokensViaWs action
- Change TokenBalancesController default polling interval to 30 seconds (was 180 seconds)
@Kriys94 Kriys94 force-pushed the feature/token-balances-integration branch from bb5bd02 to d3a8b3b Compare October 10, 2025 10:27
@Prithpal-Sooriya
Copy link
Contributor

@SocketSecurity ignore npm/@metamask/[email protected]

This package is accepted to allow WS usage for these asset controllers.

  • If uses globalThis["fetch"] as part of the websocket connection.

);

// postBalance.amount is in hex format (raw units)
const balanceHex = postBalance.amount as Hex;
Copy link

Choose a reason for hiding this comment

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

Bug: Invalid Hex Assertion in Balance Update

The postBalance.amount value is type-asserted as Hex without validating its existence or format. If the AccountActivityService provides a balance update where postBalance.amount is missing or not a valid hex string, this could lead to unexpected behavior when the value is used downstream.

Fix in Cursor Fix in Web

@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 10, 2025

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "1.4.1-preview-5f3688c1",
  "@metamask-previews/accounts-controller": "33.1.1-preview-5f3688c1",
  "@metamask-previews/address-book-controller": "6.2.0-preview-5f3688c1",
  "@metamask-previews/announcement-controller": "7.1.0-preview-5f3688c1",
  "@metamask-previews/app-metadata-controller": "1.1.0-preview-5f3688c1",
  "@metamask-previews/approval-controller": "7.2.0-preview-5f3688c1",
  "@metamask-previews/assets-controllers": "79.0.1-preview-5f3688c1",
  "@metamask-previews/base-controller": "8.4.1-preview-5f3688c1",
  "@metamask-previews/bridge-controller": "49.0.1-preview-5f3688c1",
  "@metamask-previews/bridge-status-controller": "49.0.1-preview-5f3688c1",
  "@metamask-previews/build-utils": "3.0.4-preview-5f3688c1",
  "@metamask-previews/chain-agnostic-permission": "1.2.0-preview-5f3688c1",
  "@metamask-previews/composable-controller": "11.1.0-preview-5f3688c1",
  "@metamask-previews/controller-utils": "11.14.1-preview-5f3688c1",
  "@metamask-previews/core-backend": "1.0.1-preview-5f3688c1",
  "@metamask-previews/delegation-controller": "0.8.0-preview-5f3688c1",
  "@metamask-previews/earn-controller": "8.0.1-preview-5f3688c1",
  "@metamask-previews/eip-5792-middleware": "1.2.2-preview-5f3688c1",
  "@metamask-previews/eip1193-permission-middleware": "1.0.1-preview-5f3688c1",
  "@metamask-previews/ens-controller": "17.1.0-preview-5f3688c1",
  "@metamask-previews/error-reporting-service": "2.2.1-preview-5f3688c1",
  "@metamask-previews/eth-json-rpc-provider": "5.0.1-preview-5f3688c1",
  "@metamask-previews/foundryup": "1.0.1-preview-5f3688c1",
  "@metamask-previews/gas-fee-controller": "24.1.0-preview-5f3688c1",
  "@metamask-previews/gator-permissions-controller": "0.2.1-preview-5f3688c1",
  "@metamask-previews/json-rpc-engine": "10.1.1-preview-5f3688c1",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.8-preview-5f3688c1",
  "@metamask-previews/keyring-controller": "23.1.1-preview-5f3688c1",
  "@metamask-previews/logging-controller": "6.1.0-preview-5f3688c1",
  "@metamask-previews/message-manager": "13.0.1-preview-5f3688c1",
  "@metamask-previews/messenger": "0.3.0-preview-5f3688c1",
  "@metamask-previews/multichain-account-service": "1.6.1-preview-5f3688c1",
  "@metamask-previews/multichain-api-middleware": "1.2.1-preview-5f3688c1",
  "@metamask-previews/multichain-network-controller": "1.0.1-preview-5f3688c1",
  "@metamask-previews/multichain-transactions-controller": "5.1.0-preview-5f3688c1",
  "@metamask-previews/name-controller": "8.1.0-preview-5f3688c1",
  "@metamask-previews/network-controller": "24.2.1-preview-5f3688c1",
  "@metamask-previews/network-enablement-controller": "2.1.1-preview-5f3688c1",
  "@metamask-previews/notification-services-controller": "18.3.0-preview-5f3688c1",
  "@metamask-previews/permission-controller": "11.1.0-preview-5f3688c1",
  "@metamask-previews/permission-log-controller": "4.1.0-preview-5f3688c1",
  "@metamask-previews/phishing-controller": "14.1.1-preview-5f3688c1",
  "@metamask-previews/polling-controller": "14.0.1-preview-5f3688c1",
  "@metamask-previews/preferences-controller": "20.0.2-preview-5f3688c1",
  "@metamask-previews/profile-sync-controller": "25.1.1-preview-5f3688c1",
  "@metamask-previews/rate-limit-controller": "6.1.0-preview-5f3688c1",
  "@metamask-previews/remote-feature-flag-controller": "1.8.0-preview-5f3688c1",
  "@metamask-previews/sample-controllers": "2.0.1-preview-5f3688c1",
  "@metamask-previews/seedless-onboarding-controller": "4.1.0-preview-5f3688c1",
  "@metamask-previews/selected-network-controller": "24.0.1-preview-5f3688c1",
  "@metamask-previews/shield-controller": "0.3.1-preview-5f3688c1",
  "@metamask-previews/signature-controller": "34.0.1-preview-5f3688c1",
  "@metamask-previews/subscription-controller": "1.0.1-preview-5f3688c1",
  "@metamask-previews/token-search-discovery-controller": "3.4.0-preview-5f3688c1",
  "@metamask-previews/transaction-controller": "60.6.1-preview-5f3688c1",
  "@metamask-previews/user-operation-controller": "39.1.0-preview-5f3688c1"
}

@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 10, 2025

Tested the app and working successfully MetaMask/metamask-extension#36782

@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 10, 2025

App tested in mobile too MetaMask/metamask-mobile#21050

@Kriys94 Kriys94 merged commit 49d7b96 into main Oct 10, 2025
243 checks passed
@Kriys94 Kriys94 deleted the feature/token-balances-integration branch October 10, 2025 15:58
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.

3 participants