Skip to content

Conversation

Kriys94
Copy link
Contributor

@Kriys94 Kriys94 commented Oct 10, 2025

Explanation

Current State & Motivation

The core-backend package had several architectural issues that needed to be addressed:

  1. Inflexible Chain Management: AccountActivityService was proactively fetching supported chains from the Accounts API (/v2/supportedNetworks) with a hardcoded fallback list. This approach was:

    • Out of sync with backend capabilities (client-side caching vs. real-time backend state)
    • Unnecessarily complex with cache expiration logic
    • Made assumptions about supported chains rather than reacting to actual backend status
  2. Incomplete Connection Management: BackendWebSocketService only subscribed to AuthenticationController:stateChange events but didn't directly respond to wallet lock/unlock events from KeyringController. This created a dependency where connection management relied solely on authentication state changes.

  3. Reconnection Logic Based on Close Codes: The service used WebSocket close codes to determine reconnection behavior, which was fragile and didn't properly distinguish between manual disconnects (user action) and unexpected disconnects (network issues).

  4. Type Mismatches: The Transaction and Asset types didn't match the backend API contract, causing potential integration issues.

  5. No Performance Monitoring: There was no way to trace WebSocket operations for performance analysis in production environments.

  6. Inconsistent Address Casing: WebSocket-based token balance and detection updates had inconsistent address normalization, causing issues with state lookups and controller integration.

Solution

1. System Notification-Driven Chain Tracking (AccountActivityService)

Before: Client proactively fetches and caches supported chains

async getSupportedChains(): Promise<string[]> {
  // Fetch from API with cache + fallback to hardcoded list
}

After: Client reacts to backend system notifications

#chainsUp: Set<string> = new Set();

// Backend automatically sends system notifications with chain status
// Service tracks chains dynamically based on real-time backend state

Benefits:

  • Real-time chain status that matches backend capabilities
  • No stale cache issues
  • Simpler code (removed ~100 lines)
  • Backend has single source of truth

Flow:

  1. Client subscribes to account activity
  2. Backend automatically sends system notification: {chainIds: ['eip155:1', 'eip155:137'], status: 'up'}
  3. Service tracks these chains internally
  4. On disconnect, service flushes all tracked chains as 'down'
  5. On reconnect, backend sends fresh system notification with current status

2. Simplified Reconnection Logic (BackendWebSocketService)

Before: Reconnection based on close codes

#shouldReconnectOnClose(code: number): boolean {
  return code !== 1000; // Only don't reconnect on normal closure
}

After: Reconnection based on manual disconnect flag

#manualDisconnect = false;

connect() {
  this.#manualDisconnect = false; // Reset flag on explicit connect
}

disconnect() {
  this.#manualDisconnect = true; // Set flag to prevent auto-reconnect
}

onclose() {
  if (!this.#manualDisconnect) {
    this.#scheduleReconnect(); // Auto-reconnect unless manually disconnected
  }
}

Benefits:

  • Clear intent: manual disconnects stay disconnected, unexpected disconnects auto-reconnect
  • No ambiguity with close codes
  • Simpler logic

3. KeyringController Event Integration

Added direct subscriptions to wallet lock state:

#subscribeEvents() {
  // Sign in/out
  this.#messenger.subscribe('AuthenticationController:stateChange', ...);
  
  // Wallet lock/unlock (NEW)
  this.#messenger.subscribe('KeyringController:unlock', () => this.connect());
  this.#messenger.subscribe('KeyringController:lock', () => this.disconnect());
}

Connection Requirements (all must be true):

  1. ✅ Feature enabled (isEnabled() callback)
  2. ✅ User signed in (AuthenticationController.isSignedIn)
  3. ✅ Wallet unlocked (KeyringController state)

4. Type Alignment with Backend API

  • Transaction.hashTransaction.id (matches backend field name)
  • Asset now requires decimals: number (needed for proper token formatting)

5. Performance Tracing Integration

Added optional traceFn parameter to enable performance monitoring:

new BackendWebSocketService({
  messenger,
  url: BACKEND_WS_URL,
  traceFn: trace as TraceCallback, // Inject platform-specific trace function
  // ...other options
});

Benefits:

  • Platform-agnostic tracing support (enables Sentry integration in extension/mobile)
  • Traces WebSocket operations (connect, disconnect methods)
  • Enables performance monitoring in production
  • Core package remains platform-agnostic with no-op default

Integration:

  • Extension: Uses trace from shared/lib/trace.ts (Sentry-backed)
  • Mobile: Uses trace from app/util/trace.ts (Sentry-backed)
  • Core: Defaults to no-op if not provided, keeping the package platform-agnostic

Example usage:

// Extension/Mobile init files inject their platform-specific trace function
const service = new BackendWebSocketService({
  messenger,
  url: BACKEND_WS_URL,
  traceFn: trace as TraceCallback,
  // When operations occur, they're automatically traced:
  // - "BackendWebSocketService:connect"
  // - "BackendWebSocketService:disconnect"
});

6. Address Normalization for WebSocket Updates (assets-controllers)

Fixed inconsistent address casing in WebSocket-based token balance and detection updates to ensure proper state lookups and controller integration.

TokenBalancesController (#onAccountActivityBalanceUpdate):

  • Account addresses: Normalized to lowercase for tokenBalances state lookups
  • Token addresses: Normalized to checksum format for tokenBalances state storage
  • Native balance updates: Uses checksummed account addresses for AccountTrackerController:updateNativeBalances
  • New tokens: Uses checksummed token addresses for TokensController:addTokens

TokenDetectionController (addDetectedTokensViaWs):

  • Token addresses: Explicitly normalized to checksum format before calling TokensController:addTokens
  • Token cache lookups: Uses lowercase token addresses for tokensChainsCache lookups
  • Fresh cache: Fetches tokensChainsCache at the start of the method to prevent stale data

Benefits:

  • Consistent address format across different state stores
  • Prevents state lookup failures due to casing mismatches
  • Ensures compatibility between controllers with different address format expectations
  • Robust handling without assumptions about input format

Example:

// Before: Address casing was inconsistent
state.tokenBalances[address][tokenAddress] = balance; // Could fail if casing mismatched

// After: Explicit normalization
const normalizedAccount = address.toLowerCase();
const checksummedToken = toChecksumAddress(tokenAddress);
state.tokenBalances[normalizedAccount as Hex][checksummedToken] = balance;

Breaking Changes Impact

For AccountActivityService consumers:

  • Removed: getSupportedChains() method - consumers should subscribe to AccountActivityService:statusChanged events instead
  • Chain status is now event-driven rather than request-response

For type definitions:

  • Transaction objects must use id instead of hash
  • Asset objects must include decimals field

Testing Updates

  • Removed nock dependency (no longer fetching from external API)
  • Updated all tests to use system notification-driven flow
  • Added tests for KeyringController event integration
  • Added tests for manual disconnect flag behavior
  • Increased test coverage for edge cases in reconnection logic
  • Updated TokenDetectionController tests to expect checksummed addresses in addTokens calls

References

  • Part of ongoing core-backend stabilization effort
  • Aligns with backend system notification architecture

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, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

Note

Revamps core-backend WebSocket lifecycle (keyring lock/unlock, manual disconnect, tracing, new params/types, system notification–driven chains) and fixes assets controllers to normalize addresses for WebSocket token updates; docs/tests updated.

  • Core Backend (@metamask/core-backend):
    • WebSocket: New connection model (idempotent connect, auto-reconnect unless manual disconnect), subscribes to KeyringController:lock/unlock; exposes richer getConnectionInfo.
    • API Changes (BREAKING):
      • BackendWebSocketService.subscribe now requires channelType.
      • Types: Transaction.hashid; Asset adds required decimals; ServerNotificationMessage includes timestamp.
      • Messenger/events expanded; add peer dep on @metamask/keyring-controller.
    • Tracing: Optional traceFn to instrument connect/disconnect/notifications.
    • AccountActivityService: Drops getSupportedChains; chains tracked via system notifications; publishes statusChanged with optional timestamp.
    • Docs: README updated with new flow and “WebSocket Connection Management”.
  • Assets Controllers:
    • TokenBalancesController: Normalizes account (lowercase) and token (checksum) for WS updates; fixes tracking checks; updates native balance propagation; adds decimals handling in tests.
    • TokenDetectionController: Adds checksummed addresses and lowercase cache lookups in addDetectedTokensViaWs; metrics use checksummed addresses.
    • Changelog: Notes fix for address casing in WS balance updates.
  • Repo:
    • README: adds @metamask/core-backend to package list and dependency graph; minor graph edge additions.
    • Build/config: add keyring-controller refs; adjust dev/peer deps; test updates to reflect new behavior.

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

@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch 3 times, most recently from 61d7fa7 to 1a6bf0c Compare October 12, 2025 21:28
@Kriys94 Kriys94 marked this pull request as ready for review October 12, 2025 21:36
@Kriys94 Kriys94 requested review from a team as code owners October 12, 2025 21:36
cursor[bot]

This comment was marked as outdated.

@Kriys94 Kriys94 changed the title feat(core-backend): change behavior feat(core-backend): update websocket behavior Oct 13, 2025
bergarces
bergarces previously approved these changes Oct 13, 2025
Copy link
Contributor

@bergarces bergarces left a comment

Choose a reason for hiding this comment

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

Approving for the assets codeowner part.

cursor[bot]

This comment was marked as outdated.

@Kriys94
Copy link
Contributor Author

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

@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch from e7dac94 to 0189b42 Compare October 13, 2025 12:20
@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 13, 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.2-preview-0189b42",
  "@metamask-previews/accounts-controller": "33.1.1-preview-0189b42",
  "@metamask-previews/address-book-controller": "6.2.0-preview-0189b42",
  "@metamask-previews/announcement-controller": "7.1.0-preview-0189b42",
  "@metamask-previews/app-metadata-controller": "1.1.0-preview-0189b42",
  "@metamask-previews/approval-controller": "7.2.0-preview-0189b42",
  "@metamask-previews/assets-controllers": "80.0.0-preview-0189b42",
  "@metamask-previews/base-controller": "8.4.1-preview-0189b42",
  "@metamask-previews/bridge-controller": "50.0.0-preview-0189b42",
  "@metamask-previews/bridge-status-controller": "50.0.0-preview-0189b42",
  "@metamask-previews/build-utils": "3.0.4-preview-0189b42",
  "@metamask-previews/chain-agnostic-permission": "1.2.0-preview-0189b42",
  "@metamask-previews/composable-controller": "11.1.0-preview-0189b42",
  "@metamask-previews/controller-utils": "11.14.1-preview-0189b42",
  "@metamask-previews/core-backend": "1.0.1-preview-0189b42",
  "@metamask-previews/delegation-controller": "0.8.0-preview-0189b42",
  "@metamask-previews/earn-controller": "8.0.1-preview-0189b42",
  "@metamask-previews/eip-5792-middleware": "1.2.2-preview-0189b42",
  "@metamask-previews/eip1193-permission-middleware": "1.0.1-preview-0189b42",
  "@metamask-previews/ens-controller": "17.1.0-preview-0189b42",
  "@metamask-previews/error-reporting-service": "2.2.1-preview-0189b42",
  "@metamask-previews/eth-json-rpc-provider": "5.0.1-preview-0189b42",
  "@metamask-previews/foundryup": "1.0.1-preview-0189b42",
  "@metamask-previews/gas-fee-controller": "24.1.0-preview-0189b42",
  "@metamask-previews/gator-permissions-controller": "0.2.1-preview-0189b42",
  "@metamask-previews/json-rpc-engine": "10.1.1-preview-0189b42",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.8-preview-0189b42",
  "@metamask-previews/keyring-controller": "23.1.1-preview-0189b42",
  "@metamask-previews/logging-controller": "6.1.0-preview-0189b42",
  "@metamask-previews/message-manager": "13.0.1-preview-0189b42",
  "@metamask-previews/messenger": "0.3.0-preview-0189b42",
  "@metamask-previews/multichain-account-service": "1.6.1-preview-0189b42",
  "@metamask-previews/multichain-api-middleware": "1.2.1-preview-0189b42",
  "@metamask-previews/multichain-network-controller": "1.0.1-preview-0189b42",
  "@metamask-previews/multichain-transactions-controller": "5.1.0-preview-0189b42",
  "@metamask-previews/name-controller": "8.1.0-preview-0189b42",
  "@metamask-previews/network-controller": "24.2.1-preview-0189b42",
  "@metamask-previews/network-enablement-controller": "2.1.1-preview-0189b42",
  "@metamask-previews/notification-services-controller": "18.3.0-preview-0189b42",
  "@metamask-previews/permission-controller": "11.1.0-preview-0189b42",
  "@metamask-previews/permission-log-controller": "4.1.0-preview-0189b42",
  "@metamask-previews/phishing-controller": "14.1.2-preview-0189b42",
  "@metamask-previews/polling-controller": "14.0.1-preview-0189b42",
  "@metamask-previews/preferences-controller": "20.0.2-preview-0189b42",
  "@metamask-previews/profile-sync-controller": "25.1.1-preview-0189b42",
  "@metamask-previews/rate-limit-controller": "6.1.0-preview-0189b42",
  "@metamask-previews/remote-feature-flag-controller": "1.8.0-preview-0189b42",
  "@metamask-previews/sample-controllers": "2.0.1-preview-0189b42",
  "@metamask-previews/seedless-onboarding-controller": "4.1.0-preview-0189b42",
  "@metamask-previews/selected-network-controller": "24.0.1-preview-0189b42",
  "@metamask-previews/shield-controller": "0.3.2-preview-0189b42",
  "@metamask-previews/signature-controller": "34.0.1-preview-0189b42",
  "@metamask-previews/subscription-controller": "1.0.1-preview-0189b42",
  "@metamask-previews/token-search-discovery-controller": "3.4.0-preview-0189b42",
  "@metamask-previews/transaction-controller": "60.6.1-preview-0189b42",
  "@metamask-previews/user-operation-controller": "39.1.0-preview-0189b42"
}

bergarces
bergarces previously approved these changes Oct 13, 2025
@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 13, 2025

Version tested in Extension MetaMask/metamask-extension#36819

cryptodev-2s
cryptodev-2s previously approved these changes Oct 13, 2025
Copy link
Contributor

@cryptodev-2s cryptodev-2s left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Left some comments about the changelog and a couple of minor places in the code.

Also since you added a new peer dependency would you mind running yarn update-readme-content?

this.#isEnabled = options.isEnabled;
// Default to no-op trace function to keep core platform-agnostic
this.#trace =
options.traceFn ?? (((_request, fn) => fn?.()) as TraceCallback);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need a type assertion here? We should hardly ever need type assertions especially for defining default values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I put (((_request, fn) => fn?.()) as any) I got a linter issue

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, that's an indication that it ought to be written a different way, no?

But not a big deal, we can address this in a future PR.

});
this.#scheduleReconnect();
}
// For any unexpected disconnects, attempt reconnection
Copy link
Contributor

@mcmire mcmire Oct 13, 2025

Choose a reason for hiding this comment

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

Were we already reconnecting upon unexpected disconnect? Is the only connection-related change in this PR the fact that disconnect will now disable automatic reconnect, or is there something I'm missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Were we already reconnecting upon unexpected disconnect?
Yes we were but if the server disconnected with the event code 1000 then no. I realized it by having the WebSocket open for more than 1 hour. The server disconnected, but didn't reconnect. Which is undesirable because we want MetaMask to reconnect back. I have tested it and it works well now.

disconnect will now disable automatic reconnect
yes that is the only case where we dont try to not re-connect, i.e. only when we close the app.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice, thanks for clarifying.

@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 13, 2025

Feature tested in mobile with MetaMask/metamask-mobile#21111

Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Went through tests. Most are minor, but seems like some things could be cleaned up nonetheless.

cursor[bot]

This comment was marked as outdated.

@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch from ea0d770 to e6764b2 Compare October 13, 2025 23:36
bergarces
bergarces previously approved these changes Oct 14, 2025
Copy link
Contributor

@bergarces bergarces left a comment

Choose a reason for hiding this comment

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

Changes are ok with assets, they are non-breaking as they force lowercase, for TokenBalancesController state, which is what we already use.

This approval is only for the assets-controllers changes.

@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 14, 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.2-preview-25cab83",
  "@metamask-previews/accounts-controller": "33.1.1-preview-25cab83",
  "@metamask-previews/address-book-controller": "6.2.0-preview-25cab83",
  "@metamask-previews/announcement-controller": "7.1.0-preview-25cab83",
  "@metamask-previews/app-metadata-controller": "1.1.0-preview-25cab83",
  "@metamask-previews/approval-controller": "7.2.0-preview-25cab83",
  "@metamask-previews/assets-controllers": "80.0.0-preview-25cab83",
  "@metamask-previews/base-controller": "8.4.1-preview-25cab83",
  "@metamask-previews/bridge-controller": "51.0.0-preview-25cab83",
  "@metamask-previews/bridge-status-controller": "50.1.0-preview-25cab83",
  "@metamask-previews/build-utils": "3.0.4-preview-25cab83",
  "@metamask-previews/chain-agnostic-permission": "1.2.0-preview-25cab83",
  "@metamask-previews/composable-controller": "11.1.0-preview-25cab83",
  "@metamask-previews/controller-utils": "11.14.1-preview-25cab83",
  "@metamask-previews/core-backend": "1.0.1-preview-25cab83",
  "@metamask-previews/delegation-controller": "0.8.0-preview-25cab83",
  "@metamask-previews/earn-controller": "8.0.1-preview-25cab83",
  "@metamask-previews/eip-5792-middleware": "1.2.2-preview-25cab83",
  "@metamask-previews/eip1193-permission-middleware": "1.0.1-preview-25cab83",
  "@metamask-previews/ens-controller": "17.1.0-preview-25cab83",
  "@metamask-previews/error-reporting-service": "2.2.1-preview-25cab83",
  "@metamask-previews/eth-json-rpc-provider": "5.0.1-preview-25cab83",
  "@metamask-previews/foundryup": "1.0.1-preview-25cab83",
  "@metamask-previews/gas-fee-controller": "24.1.0-preview-25cab83",
  "@metamask-previews/gator-permissions-controller": "0.2.1-preview-25cab83",
  "@metamask-previews/json-rpc-engine": "10.1.1-preview-25cab83",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.8-preview-25cab83",
  "@metamask-previews/keyring-controller": "23.1.1-preview-25cab83",
  "@metamask-previews/logging-controller": "6.1.0-preview-25cab83",
  "@metamask-previews/message-manager": "13.0.1-preview-25cab83",
  "@metamask-previews/messenger": "0.3.0-preview-25cab83",
  "@metamask-previews/multichain-account-service": "1.6.1-preview-25cab83",
  "@metamask-previews/multichain-api-middleware": "1.2.1-preview-25cab83",
  "@metamask-previews/multichain-network-controller": "1.0.1-preview-25cab83",
  "@metamask-previews/multichain-transactions-controller": "5.1.0-preview-25cab83",
  "@metamask-previews/name-controller": "8.1.0-preview-25cab83",
  "@metamask-previews/network-controller": "24.2.1-preview-25cab83",
  "@metamask-previews/network-enablement-controller": "2.1.1-preview-25cab83",
  "@metamask-previews/notification-services-controller": "18.3.0-preview-25cab83",
  "@metamask-previews/permission-controller": "11.1.0-preview-25cab83",
  "@metamask-previews/permission-log-controller": "4.1.0-preview-25cab83",
  "@metamask-previews/phishing-controller": "14.1.2-preview-25cab83",
  "@metamask-previews/polling-controller": "14.0.1-preview-25cab83",
  "@metamask-previews/preferences-controller": "20.0.2-preview-25cab83",
  "@metamask-previews/profile-sync-controller": "25.1.1-preview-25cab83",
  "@metamask-previews/rate-limit-controller": "6.1.0-preview-25cab83",
  "@metamask-previews/remote-feature-flag-controller": "1.8.0-preview-25cab83",
  "@metamask-previews/sample-controllers": "2.0.1-preview-25cab83",
  "@metamask-previews/seedless-onboarding-controller": "4.1.0-preview-25cab83",
  "@metamask-previews/selected-network-controller": "24.0.1-preview-25cab83",
  "@metamask-previews/shield-controller": "0.3.2-preview-25cab83",
  "@metamask-previews/signature-controller": "34.0.1-preview-25cab83",
  "@metamask-previews/subscription-controller": "1.0.1-preview-25cab83",
  "@metamask-previews/token-search-discovery-controller": "3.4.0-preview-25cab83",
  "@metamask-previews/transaction-controller": "60.6.1-preview-25cab83",
  "@metamask-previews/user-operation-controller": "39.1.0-preview-25cab83"
}

@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch from 25cab83 to dc2b77e Compare October 14, 2025 11:55
@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch 2 times, most recently from 917096f to 99cc00a Compare October 14, 2025 13:21
@cryptodev-2s
Copy link
Contributor

@Kriys94 The overall changes look good to me, thanks for handling the reviews.
If you could just update the package dependency graph by running yarn update-readme-content, I’ll be good to approve.

@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch from 99cc00a to 00e978c Compare October 14, 2025 15:06
@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch from 00e978c to cf661ec Compare October 14, 2025 15:20
if (
this.#allIgnoredTokens?.[chainId]?.[account.toLowerCase()]?.some(
(addr) => addr.toLowerCase() === normalizedAddress,
(token) => token === tokenAddress,
Copy link

Choose a reason for hiding this comment

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

Bug: Token Tracking Case Sensitivity Issue

The #isTokenTracked method now uses case-sensitive address comparison, which can cause tokens to be incorrectly identified as untracked or not ignored. This happens because stored addresses in allTokens and allIgnoredTokens may not consistently match the casing of the input tokenAddress.

Fix in Cursor Fix in Web

const subscription = {
subscriptionId,
channels: [...channels],
channelType,
Copy link

Choose a reason for hiding this comment

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

Bug: Subscription Failures Not Properly Handled

The subscribe method no longer validates subscriptionResponse.failed, causing subscription failures to be silently ignored. This can lead to clients incorrectly assuming full subscription, resulting in missed notifications or unexpected application behavior.

Fix in Cursor Fix in Web

@Kriys94 Kriys94 force-pushed the feature/updateCoreBackend branch from cf661ec to 16e8b32 Compare October 14, 2025 15:23
Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

LGTM!

@Kriys94
Copy link
Contributor Author

Kriys94 commented Oct 14, 2025

@Kriys94 The overall changes look good to me, thanks for handling the reviews. If you could just update the package dependency graph by running yarn update-readme-content, I’ll be good to approve.

Done. Thanks for the review @cryptodev-2s @mcmire @bergarces

if (
this.#allIgnoredTokens?.[chainId]?.[account.toLowerCase()]?.some(
(addr) => addr.toLowerCase() === normalizedAddress,
(token) => token === tokenAddress,
Copy link

Choose a reason for hiding this comment

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

Bug: Token Address Matching Case Sensitivity Issue

The #isTokenTracked method changed from case-insensitive to case-sensitive address comparison. This causes it to incorrectly return false for tracked or ignored tokens when there's a casing mismatch between the input tokenAddress and addresses stored in allTokens or allIgnoredTokens.

Fix in Cursor Fix in Web

Copy link
Contributor

@bergarces bergarces left a comment

Choose a reason for hiding this comment

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

Approve from assets perspective, as forcing lowercase on state is not a breaking change, but a fix.

@Kriys94 Kriys94 merged commit 18d7b69 into main Oct 14, 2025
243 checks passed
@Kriys94 Kriys94 deleted the feature/updateCoreBackend branch October 14, 2025 15:30
@Kriys94 Kriys94 mentioned this pull request Oct 14, 2025
4 tasks
Kriys94 added a commit that referenced this pull request Oct 14, 2025
## Explanation

This release includes major version bumps for 4 packages, primarily
driven by breaking changes in `@metamask/core-backend` that introduce
automatic WebSocket connection management and several API improvements.

**Note:** While these are marked as breaking changes, they should not
affect MetaMask Extension or MetaMask Mobile at this time, as WebSocket
integration has not been implemented in these clients yet. The breaking
changes are primarily API improvements that will be relevant once
WebSocket functionality is adopted.

### 📦 Packages Included

- `@metamask/core-backend`: **1.0.1 → 2.0.0**
- `@metamask/assets-controllers`: **80.0.0 → 81.0.0**
- `@metamask/bridge-controller`: **51.0.0 → 52.0.0**
- `@metamask/bridge-status-controller`: **50.1.0 → 51.0.0**

### Current State and Why It Needs to Change

The `@metamask/core-backend` package required several breaking changes
to improve WebSocket connection management, type safety, and API
consistency. The package needed to automatically manage WebSocket
connections based on wallet lock state, and the type definitions needed
improvements for better developer experience.

### Solution

#### @metamask/core-backend (1.0.1 → 2.0.0)

**Breaking Changes:**
- Added required `channelType` argument to
`BackendWebSocketService.subscribe` method for better subscription
management
- Updated `Asset` type to require `decimals` field for proper token
amount formatting
- Implemented automatic WebSocket connection management based on wallet
lock state (requires `KeyringController:lock` and
`KeyringController:unlock` events)
- Renamed `Transaction.hash` to `Transaction.id` for consistency with
backend API
- Added new peer dependency on `@metamask/keyring-controller` (^23.0.0)
- Removed `getSupportedChains` method from `AccountActivityService`
(replaced with system notification-driven chain tracking)

**Non-Breaking Additions:**
- Added optional `traceFn` parameter for performance tracing integration
(e.g., Sentry)
- Added optional `timestamp` property to various notification types

#### @metamask/assets-controllers (80.0.0 → 81.0.0)

**Changes:**
- **BREAKING:** Bump dependency `@metamask/core-backend` from `^1.0.1`
to `^2.0.0`
- **BREAKING:** Bump peer dependency `@metamask/core-backend` from
`^1.0.1` to `^2.0.0`
- **Fixed:** Address casing in WebSocket-based token balance updates to
ensure consistency

#### @metamask/bridge-controller (51.0.0 → 52.0.0)

**Changes:**
- **BREAKING:** Bump dependency `@metamask/assets-controllers` from
`^80.0.0` to `^81.0.0`
- **BREAKING:** Bump peer dependency `@metamask/assets-controllers` from
`^80.0.0` to `^81.0.0`

#### @metamask/bridge-status-controller (50.1.0 → 51.0.0)

**Changes:**
- **BREAKING:** Bump dependency `@metamask/bridge-controller` from
`^51.0.0` to `^52.0.0`
- **BREAKING:** Bump peer dependency `@metamask/bridge-controller` from
`^51.0.0` to `^52.0.0`

### Why Cascade Updates Were Necessary

The breaking changes in `@metamask/core-backend` required a major
version bump. Since `@metamask/assets-controllers` has
`@metamask/core-backend` as both a dependency and peer dependency, it
needed to be updated to accept the new version. This cascaded to
`@metamask/bridge-controller` (which depends on
`@metamask/assets-controllers`) and `@metamask/bridge-status-controller`
(which depends on `@metamask/bridge-controller`).

### Migration Guide for Consumers

1. **Update `subscribe` calls** to include `channelType`:
   ```typescript
   // Before
   await messenger.call('BackendWebSocketService:subscribe', {
     account: '0x123...',
   });
   
   // After
   await messenger.call('BackendWebSocketService:subscribe', {
     account: '0x123...',
     channelType: 'balance', // or 'transaction'
   });
   ```

2. **Add KeyringController events** to your messenger:
   ```typescript
   AllowedEvents: [
     'KeyringController:lock',
     'KeyringController:unlock',
     // ... other events
   ]
   ```

3. **Update Asset type usage** to include `decimals`:
   ```typescript
   const asset: Asset = {
     address: '0x...',
     symbol: 'TOKEN',
     decimals: 18, // now required
   };
   ```

4. **Update Transaction references** from `hash` to `id`:
   ```typescript
   // Before: transaction.hash
   // After: transaction.id
   ```

5. **Add @metamask/keyring-controller** peer dependency:
   ```json
   {
     "peerDependencies": {
       "@metamask/keyring-controller": "^23.0.0"
     }
   }
   ```

6. **Remove `getSupportedChains` calls** - chain tracking is now
automatic via system notifications

## References

- Primary PR: #6819 - WebSocket connection management improvements
- Related: #6818, #6824
- Release PR: #6834

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs),
highlighting breaking changes as necessary
- [ ] I've prepared draft pull requests for clients and consumer
packages to resolve any breaking changes

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Releases core-backend v2 with breaking WebSocket and type changes, and
cascades required peer/dependency bumps across assets and bridge
packages.
> 
> - **Backend**
>   - `@metamask/core-backend@2.0.0` (major):
>     - Requires `channelType` in `BackendWebSocketService.subscribe`
> - Adds required `Asset.decimals`; renames transaction `hash` → `id`
> - Auto WebSocket connection management tied to lock/unlock; new peer
dep `@metamask/keyring-controller`
> - Optional `traceFn`; optional `timestamp` fields in
notifications/events
> - **Assets**
> - `@metamask/assets-controllers@81.0.0` (major): bump peer/dev dep
`@metamask/core-backend` to `^2.0.0`.
> - **Bridge**
> - `@metamask/bridge-controller@52.0.0` (major): bump peer/dev dep
`@metamask/assets-controllers` to `^81.0.0`.
> - `@metamask/bridge-status-controller@51.0.0` (major): bump peer/dev
dep `@metamask/bridge-controller` to `^52.0.0`.
> - **Repo**
>   - Monorepo version `618.0.0` → `619.0.0`; lockfile updated.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9e01bed. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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.

4 participants