Skip to content

Commit 06000ea

Browse files
committed
feat: add Websocket Service into Transaction confirmation and Token Balance Controllers
1 parent fe4b71b commit 06000ea

File tree

13 files changed

+1150
-676
lines changed

13 files changed

+1150
-676
lines changed

packages/assets-controllers/src/MultichainBalancesController/MultichainBalancesController.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import type {
2929
MultichainAssetsControllerGetStateAction,
3030
MultichainAssetsControllerAccountAssetListUpdatedEvent,
3131
} from '../MultichainAssetsController';
32+
import type {
33+
AccountActivityServiceBalanceUpdatedEvent,
34+
} from '@metamask/backend-platform';
3235

3336
const controllerName = 'MultichainBalancesController';
3437

@@ -104,7 +107,8 @@ type AllowedEvents =
104107
| AccountsControllerAccountAddedEvent
105108
| AccountsControllerAccountRemovedEvent
106109
| AccountsControllerAccountBalancesUpdatesEvent
107-
| MultichainAssetsControllerAccountAssetListUpdatedEvent;
110+
| MultichainAssetsControllerAccountAssetListUpdatedEvent
111+
| AccountActivityServiceBalanceUpdatedEvent;
108112
/**
109113
* Messenger type for the MultichainBalancesController.
110114
*/
@@ -185,6 +189,19 @@ export class MultichainBalancesController extends BaseController<
185189
await this.#handleOnAccountAssetListUpdated(newAccountAssets);
186190
},
187191
);
192+
193+
// Subscribe to AccountActivityService balance updates
194+
try {
195+
this.messagingSystem.subscribe(
196+
'AccountActivityService:balanceUpdated',
197+
(balances: AccountBalancesUpdatedEventPayload) => {
198+
this.#handleOnAccountBalancesUpdated(balances);
199+
},
200+
);
201+
} catch (error) {
202+
// AccountActivityService might not be available in all environments
203+
console.log('AccountActivityService not available for balance updates:', error);
204+
}
188205
}
189206

190207
/**

packages/assets-controllers/src/TokenBalancesController.ts

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ import type {
4141
TokensControllerState,
4242
TokensControllerStateChangeEvent,
4343
} from './TokensController';
44+
import type {
45+
AccountActivityServiceBalanceUpdatedEvent,
46+
} from '@metamask/backend-platform';
47+
import type { AccountBalancesUpdatedEventPayload } from '@metamask/keyring-api';
4448

4549
const DEFAULT_INTERVAL = 180000;
4650

@@ -104,7 +108,8 @@ export type AllowedEvents =
104108
| TokensControllerStateChangeEvent
105109
| PreferencesControllerStateChangeEvent
106110
| NetworkControllerStateChangeEvent
107-
| KeyringControllerAccountRemovedEvent;
111+
| KeyringControllerAccountRemovedEvent
112+
| AccountActivityServiceBalanceUpdatedEvent;
108113

109114
export type TokenBalancesControllerMessenger = RestrictedMessenger<
110115
typeof controllerName,
@@ -202,6 +207,18 @@ export class TokenBalancesController extends StaticIntervalPollingController<Tok
202207
'KeyringController:accountRemoved',
203208
(accountAddress: string) => this.#handleOnAccountRemoved(accountAddress),
204209
);
210+
211+
// Subscribe to AccountActivityService balance updates for EVM networks
212+
try {
213+
this.messagingSystem.subscribe(
214+
'AccountActivityService:balanceUpdated',
215+
(balances: AccountBalancesUpdatedEventPayload) =>
216+
this.#handleAccountActivityBalanceUpdated(balances),
217+
);
218+
} catch (error) {
219+
// AccountActivityService might not be available in all environments
220+
console.log('AccountActivityService not available for EVM token balance updates:', error);
221+
}
205222
}
206223

207224
/**
@@ -305,6 +322,71 @@ export class TokenBalancesController extends StaticIntervalPollingController<Tok
305322
});
306323
}
307324

325+
/**
326+
* Handles balance updates received from the AccountActivityService for EVM networks.
327+
* Converts account IDs to addresses and updates token balances accordingly.
328+
*
329+
* @param balanceUpdate - The balance update from AccountActivityService containing new balances.
330+
*/
331+
#handleAccountActivityBalanceUpdated(
332+
balanceUpdate: AccountBalancesUpdatedEventPayload,
333+
): void {
334+
// Convert account IDs to addresses first
335+
const addressBalances: Record<string, Record<string, { unit: string; amount: string }>> = {};
336+
337+
for (const [accountId, assetBalances] of Object.entries(balanceUpdate.balances)) {
338+
let accountAddress: string;
339+
340+
if (accountId.startsWith('0x')) {
341+
// Already an address
342+
accountAddress = accountId;
343+
} else {
344+
// Convert account ID to address
345+
try {
346+
const accounts = this.messagingSystem.call('AccountsController:listAccounts');
347+
const account = accounts.find(acc => acc.id === accountId);
348+
if (!account) {
349+
continue;
350+
}
351+
accountAddress = account.address;
352+
} catch (error) {
353+
continue;
354+
}
355+
}
356+
357+
// Only process valid EVM addresses
358+
if (isStrictHexString(accountAddress.toLowerCase()) && isValidHexAddress(accountAddress)) {
359+
addressBalances[accountAddress] = assetBalances;
360+
}
361+
}
362+
363+
// Update state with address-based balances
364+
this.update((state) => {
365+
for (const [accountAddress, assetBalances] of Object.entries(addressBalances)) {
366+
const address = accountAddress as Hex;
367+
368+
// Initialize account if needed
369+
if (!state.tokenBalances[address]) {
370+
state.tokenBalances[address] = {};
371+
}
372+
373+
// Process each EVM asset
374+
for (const [assetType, balance] of Object.entries(assetBalances)) {
375+
const evmERC20AssetMatch = assetType.match(/^eip155:(\d+)\/erc20:(0x[a-fA-F0-9]{40})$/i);
376+
377+
if (evmERC20AssetMatch) {
378+
const chainId = `0x${parseInt(evmERC20AssetMatch[1], 10).toString(16)}` as Hex;
379+
const tokenAddress = evmERC20AssetMatch[2] as Hex;
380+
381+
// Initialize chain and token if needed
382+
((state.tokenBalances[address] ??= {})[chainId] ??= {})[tokenAddress] =
383+
`0x${parseInt(balance.amount, 10).toString(16)}` as Hex;
384+
}
385+
}
386+
}
387+
});
388+
}
389+
308390
/**
309391
* Returns an array of chain ids that have tokens.
310392
* @param allTokens - The state for imported tokens across all chains.

0 commit comments

Comments
 (0)