Skip to content

Commit 1a6bf0c

Browse files
committed
feat(core-backend): change behavior
1 parent b0fd6ae commit 1a6bf0c

File tree

10 files changed

+636
-801
lines changed

10 files changed

+636
-801
lines changed

packages/assets-controllers/src/TokenBalancesController.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,6 +4328,7 @@ describe('TokenBalancesController', () => {
43284328
type: `eip155:1/erc20:${tokenAddress}`,
43294329
unit: 'USDC',
43304330
fungible: true,
4331+
decimals: 6,
43314332
},
43324333
postBalance: {
43334334
amount: '0xf4240', // 1000000 in hex (1 USDC with 6 decimals)
@@ -4378,6 +4379,7 @@ describe('TokenBalancesController', () => {
43784379
type: 'eip155:1/slip44:60',
43794380
unit: 'ETH',
43804381
fungible: true,
4382+
decimals: 18,
43814383
},
43824384
postBalance: {
43834385
amount: '0xde0b6b3a7640000', // 1 ETH in wei
@@ -4431,6 +4433,7 @@ describe('TokenBalancesController', () => {
44314433
type: 'eip155:1/slip44:60',
44324434
unit: 'ETH',
44334435
fungible: true,
4436+
decimals: 18,
44344437
},
44354438
postBalance: {
44364439
amount: '0',
@@ -4468,6 +4471,7 @@ describe('TokenBalancesController', () => {
44684471
type: 'eip155:1/unknown:0x123',
44694472
unit: 'UNKNOWN',
44704473
fungible: true,
4474+
decimals: 18,
44714475
},
44724476
postBalance: {
44734477
amount: '1000',
@@ -4650,6 +4654,7 @@ describe('TokenBalancesController', () => {
46504654
type: `eip155:1/erc20:${token1}`,
46514655
unit: 'USDC',
46524656
fungible: true,
4657+
decimals: 6,
46534658
},
46544659
postBalance: {
46554660
amount: '0xf4240', // 1000000 in hex
@@ -4661,6 +4666,7 @@ describe('TokenBalancesController', () => {
46614666
type: `eip155:1/erc20:${token2}`,
46624667
unit: 'USDT',
46634668
fungible: true,
4669+
decimals: 6,
46644670
},
46654671
postBalance: {
46664672
amount: '0x1e8480', // 2000000 in hex
@@ -4706,6 +4712,7 @@ describe('TokenBalancesController', () => {
47064712
type: 'eip155:1/erc20:invalid-address', // Not a valid hex address
47074713
unit: 'INVALID',
47084714
fungible: true,
4715+
decimals: 18,
47094716
},
47104717
postBalance: { amount: '1000000' },
47114718
transfers: [],
@@ -4780,6 +4787,7 @@ describe('TokenBalancesController', () => {
47804787
type: `eip155:1/erc20:${newTokenAddress}`,
47814788
unit: 'USDC',
47824789
fungible: true,
4790+
decimals: 6,
47834791
},
47844792
postBalance: {
47854793
amount: '0xf4240', // 1000000 in hex
@@ -4853,6 +4861,7 @@ describe('TokenBalancesController', () => {
48534861
type: `eip155:1/erc20:${trackedTokenAddress}`,
48544862
unit: 'USDC',
48554863
fungible: true,
4864+
decimals: 6,
48564865
},
48574866
postBalance: {
48584867
amount: '0xf4240', // 1000000 in hex
@@ -4916,6 +4925,7 @@ describe('TokenBalancesController', () => {
49164925
type: `eip155:1/erc20:${ignoredTokenAddress}`,
49174926
unit: 'USDC',
49184927
fungible: true,
4928+
decimals: 6,
49194929
},
49204930
postBalance: {
49214931
amount: '0xf4240', // 1000000 in hex
@@ -4973,6 +4983,7 @@ describe('TokenBalancesController', () => {
49734983
type: 'eip155:1/slip44:60',
49744984
unit: 'ETH',
49754985
fungible: true,
4986+
decimals: 18,
49764987
},
49774988
postBalance: {
49784989
amount: '0xde0b6b3a7640000', // 1 ETH in wei
@@ -5039,6 +5050,7 @@ describe('TokenBalancesController', () => {
50395050
type: `eip155:1/erc20:${newTokenAddress}`,
50405051
unit: 'USDC',
50415052
fungible: true,
5053+
decimals: 6,
50425054
},
50435055
postBalance: {
50445056
amount: '0xf4240', // 1000000 in hex
@@ -5109,6 +5121,7 @@ describe('TokenBalancesController', () => {
51095121
type: `eip155:1/erc20:${trackedToken}`,
51105122
unit: 'USDC',
51115123
fungible: true,
5124+
decimals: 6,
51125125
},
51135126
postBalance: {
51145127
amount: '0xf4240', // 1000000 in hex
@@ -5120,6 +5133,7 @@ describe('TokenBalancesController', () => {
51205133
type: `eip155:1/erc20:${untrackedToken}`,
51215134
unit: 'USDT',
51225135
fungible: true,
5136+
decimals: 6,
51235137
},
51245138
postBalance: {
51255139
amount: '0x1e8480', // 2000000 in hex

packages/core-backend/CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- **BREAKING**: `BackendWebSocketService` - Simplified connection management and added KeyringController event integration ([#6819](https://github.com/MetaMask/core/pull/6819))
13+
- Added `KeyringController:lock` and `KeyringController:unlock` event subscriptions to automatically manage WebSocket connections based on wallet lock state
14+
- Renamed internal method `setupAuthentication()` to `subscribeEvents()` to reflect broader event handling responsibilities
15+
- Simplified reconnection logic: auto-reconnect on any unexpected disconnect, stay disconnected on manual disconnects (tracked via `#manualDisconnect` flag)
16+
- Removed `shouldReconnectOnClose()` method - reconnection decisions now based solely on manual disconnect flag rather than close codes
17+
- Updated `connect()` to reset manual disconnect flag, allowing reconnection after previous manual disconnects
18+
- Updated `disconnect()` to set manual disconnect flag, preventing automatic reconnection
19+
- Improved error handling in `connect()` to properly rethrow errors to callers
20+
- **BREAKING**: `AccountActivityService` - Replaced API-based chain support detection with system notification-driven chain tracking ([#6819](https://github.com/MetaMask/core/pull/6819))
21+
- Removed `getSupportedChains()` public method and all related API fetching logic
22+
- Removed hardcoded `DEFAULT_SUPPORTED_CHAINS` fallback list and cache expiration mechanism
23+
- Added internal `#chainsUp` Set to track chains reported as 'up' via system notifications
24+
- Updated system notification handler to dynamically track chain status (add to set when 'up', remove when 'down')
25+
- Updated WebSocket state change handler to flush all tracked chains as 'down' on disconnect/error (instead of using hardcoded list)
26+
- Chain status is now entirely driven by backend system notifications rather than proactive API calls
27+
- **BREAKING**: Updated `Transaction` type definition - renamed `hash` field to `id` for consistency with backend API ([#6819](https://github.com/MetaMask/core/pull/6819))
28+
- **BREAKING**: Updated `Asset` type definition - added required `decimals` field for proper token amount formatting ([#6819](https://github.com/MetaMask/core/pull/6819))
29+
- Updated documentation (README.md) to reflect new connection management model and chain tracking behavior ([#6819](https://github.com/MetaMask/core/pull/6819))
30+
- Added "WebSocket Connection Management" section explaining connection requirements and behavior
31+
- Updated sequence diagram to show system notification-driven chain status flow
32+
- Updated key flow characteristics to reflect internal chain tracking mechanism
33+
34+
### Removed
35+
36+
- Removed `nock` test dependency - no longer needed after removing API-based chain support fetching ([#6819](https://github.com/MetaMask/core/pull/6819))
37+
1038
## [1.0.1]
1139

1240
### Changed

packages/core-backend/README.md

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ Core backend services for MetaMask, serving as the data layer between Backend se
1616
- [Data Flow](#data-flow)
1717
- [Sequence Diagram: Real-time Account Activity Flow](#sequence-diagram-real-time-account-activity-flow)
1818
- [Key Flow Characteristics](#key-flow-characteristics)
19+
- [WebSocket Connection Management](#websocket-connection-management)
20+
- [Connection Requirements](#connection-requirements)
21+
- [Connection Behavior](#connection-behavior)
1922
- [API Reference](#api-reference)
2023
- [BackendWebSocketService](#backendwebsocketservice)
2124
- [Constructor Options](#constructor-options)
@@ -227,16 +230,17 @@ sequenceDiagram
227230
Backend->>WS: Connection established
228231
WS->>AA: WebSocket connection status notification<br/>(BackendWebSocketService:connectionStateChanged)<br/>{state: 'CONNECTED'}
229232
230-
par StatusChanged Event
231-
AA->>TBC: Chain availability notification<br/>(AccountActivityService:statusChanged)<br/>{chainIds: ['0x1', '0x89', ...], status: 'up'}
232-
TBC->>TBC: Increase polling interval from 20s to 10min<br/>(.updateChainPollingConfigs({0x89: 600000}))
233-
and Account Subscription
234-
AA->>AA: call('AccountsController:getSelectedAccount')
235-
AA->>WS: subscribe({channels, callback})
236-
WS->>Backend: {event: 'subscribe', channels: ['account-activity.v1.eip155:0:0x123...']}
237-
Backend->>WS: {event: 'subscribe-response', subscriptionId: 'sub-456'}
238-
WS->>AA: Subscription sucessful
239-
end
233+
AA->>AA: call('AccountsController:getSelectedAccount')
234+
AA->>WS: subscribe({channels, callback})
235+
WS->>Backend: {event: 'subscribe', channels: ['account-activity.v1.eip155:0:0x123...']}
236+
Backend->>WS: {event: 'subscribe-response', subscriptionId: 'sub-456'}
237+
238+
Note over WS,Backend: System notification sent automatically upon subscription
239+
Backend->>WS: {event: 'system-notification', data: {chainIds: ['eip155:1', 'eip155:137', ...], status: 'up'}}
240+
WS->>AA: System notification received
241+
AA->>AA: Track chains as 'up' internally
242+
AA->>TBC: Chain availability notification<br/>(AccountActivityService:statusChanged)<br/>{chainIds: ['0x1', '0x89', ...], status: 'up'}
243+
TBC->>TBC: Increase polling interval from 20s to 10min<br/>(.updateChainPollingConfigs({0x89: 600000}))
240244
241245
Note over TBC,Backend: User Account Change
242246
@@ -285,24 +289,60 @@ sequenceDiagram
285289
Note over TBC,Backend: Connection Health Management
286290
287291
Backend-->>WS: Connection lost
288-
WS->>TBC: WebSocket connection status notification<br/>(BackendWebSocketService:connectionStateChanged)<br/>{state: 'DISCONNECTED'}
289-
TBC->>TBC: Decrease polling interval from 10min to 20s(.updateChainPollingConfigs({0x89: 20000}))
292+
WS->>AA: WebSocket connection status notification<br/>(BackendWebSocketService:connectionStateChanged)<br/>{state: 'DISCONNECTED'}
293+
AA->>AA: Mark all tracked chains as 'down'<br/>(flush internal tracking set)
294+
AA->>TBC: Chain status notification for all tracked chains<br/>(AccountActivityService:statusChanged)<br/>{chainIds: ['0x1', '0x89', ...], status: 'down'}
295+
TBC->>TBC: Decrease polling interval from 10min to 20s<br/>(.updateChainPollingConfigs({0x89: 20000}))
290296
TBC->>HTTP: Fetch balances immediately
291297
WS->>WS: Automatic reconnection<br/>with exponential backoff
292-
WS->>Backend: Reconnection successful - Restart initial setup
298+
WS->>Backend: Reconnection successful
299+
300+
Note over AA,Backend: Restart initial setup - resubscribe and get fresh chain status
301+
AA->>WS: subscribe (same account, new subscription)
302+
WS->>Backend: {event: 'subscribe', channels: ['account-activity.v1.eip155:0:0x123...']}
303+
Backend->>WS: {event: 'subscribe-response', subscriptionId: 'sub-999'}
304+
Backend->>WS: {event: 'system-notification', data: {chainIds: [...], status: 'up'}}
305+
WS->>AA: System notification received
306+
AA->>AA: Track chains as 'up' again
307+
AA->>TBC: Chain availability notification<br/>(AccountActivityService:statusChanged)<br/>{chainIds: [...], status: 'up'}
308+
TBC->>TBC: Increase polling interval back to 10min
293309
```
294310

295311
#### Key Flow Characteristics
296312

297-
1. **Initial Setup**: BackendWebSocketService establishes connection, then AccountActivityService simultaneously notifies all chains are up AND subscribes to selected account, TokenBalancesController increases polling interval to 10 min, then makes initial HTTP request for current balance state
298-
2. **User Account Changes**: When users switch accounts, AccountActivityService unsubscribes from old account, TokenBalancesController makes HTTP calls to fill data gaps, then AccountActivityService subscribes to new account
299-
3. **Real-time Updates**: Backend pushes data through: Backend → BackendWebSocketService → AccountActivityService → TokenBalancesController (+ future TransactionController integration)
300-
4. **System Notifications**: Backend sends chain status updates (up/down) through WebSocket, AccountActivityService processes and forwards to TokenBalancesController which adjusts polling intervals and fetches balances immediately on chain down (chain down: 10min→20s + immediate fetch, chain up: 20s→10min)
301-
5. **Parallel Processing**: Transaction and balance updates processed simultaneously - AccountActivityService publishes both transactionUpdated (future) and balanceUpdated events in parallel
302-
6. **Dynamic Polling**: TokenBalancesController adjusts HTTP polling intervals based on WebSocket connection health (10 min when connected, 20s when disconnected)
303-
7. **Direct Balance Processing**: Real-time balance updates bypass HTTP polling and update TokenBalancesController state directly
304-
8. **Connection Resilience**: Automatic reconnection with resubscription to selected account
305-
9. **Ultra-Simple Error Handling**: Any error anywhere → force reconnection (no nested try-catch)
313+
1. **Initial Setup**: BackendWebSocketService establishes connection, then AccountActivityService subscribes to selected account. Backend automatically sends a system notification with all chains that are currently up. AccountActivityService tracks these chains internally and notifies TokenBalancesController, which increases polling interval to 5 min
314+
2. **Chain Status Tracking**: AccountActivityService maintains an internal set of chains that are 'up' based on system notifications. On disconnect/error, it marks all tracked chains as 'down' before clearing the set
315+
3. **System Notifications**: Backend automatically sends chain status updates (up/down) upon subscription and when status changes. AccountActivityService forwards these to TokenBalancesController, which adjusts polling intervals (up: 5min, down: 30s + immediate fetch)
316+
4. **User Account Changes**: When users switch accounts, AccountActivityService unsubscribes from old account and subscribes to new account. Backend sends fresh system notification with current chain status for the new account
317+
5. **Connection Resilience**: On reconnection, AccountActivityService resubscribes to selected account and receives fresh chain status via system notification. Automatic reconnection with exponential backoff
318+
6. **Real-time Updates**: Backend pushes data through: Backend → BackendWebSocketService → AccountActivityService → TokenBalancesController (+ future TransactionController integration)
319+
7. **Parallel Processing**: Transaction and balance updates processed simultaneously - AccountActivityService publishes both transactionUpdated (future) and balanceUpdated events in parallel
320+
8. **Direct Balance Processing**: Real-time balance updates bypass HTTP polling and update TokenBalancesController state directly
321+
322+
## WebSocket Connection Management
323+
324+
### Connection Requirements
325+
326+
The WebSocket connects when **ALL 3 conditions are true**:
327+
328+
1.**Feature enabled** - `isEnabled()` callback returns `true` (feature flag)
329+
2.**User signed in** - `AuthenticationController.isSignedIn = true`
330+
3.**Wallet unlocked** - `KeyringController.isUnlocked = true`
331+
332+
**Plus:** Platform code must call `connect()` when app opens/foregrounds and `disconnect()` when app closes/backgrounds.
333+
334+
### Connection Behavior
335+
336+
**Idempotent `connect()`:**
337+
338+
- Safe to call multiple times - validates conditions and returns early if already connected
339+
- Multiple rapid calls reuse the same connection promise (no duplicate connections)
340+
- No debouncing needed - handled automatically
341+
342+
**Auto-Reconnect:**
343+
344+
-**Unexpected disconnects** (network issues, server restart) → Auto-reconnect
345+
-**Manual disconnects** (app backgrounds, wallet locks, user signs out) → Stay disconnected
306346

307347
## API Reference
308348

packages/core-backend/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
"@types/jest": "^27.4.1",
6161
"deepmerge": "^4.2.2",
6262
"jest": "^27.5.1",
63-
"nock": "^13.3.1",
6463
"sinon": "^9.2.4",
6564
"ts-jest": "^27.1.4",
6665
"typedoc": "^0.24.8",

0 commit comments

Comments
 (0)