Skip to content

Commit 1d1b0e1

Browse files
feat: add main network sync controller integration (#4701)
## Explanation This adds the main network sync method to the `UserStorageController`. It also connects the `NetworkController` events and actions used for network syncing. ## References https://consensyssoftware.atlassian.net/browse/NOTIFY-1094 <!-- Are there any issues that this pull request is tied to? Are there other links that reviewers should consult to understand these changes better? For example: * Fixes #12345 * Related to #67890 --> ## Changelog <!-- If you're making any consumer-facing changes, list those changes here as if you were updating a changelog, using the template below as a guide. (CATEGORY is one of BREAKING, ADDED, CHANGED, DEPRECATED, REMOVED, or FIXED. For security-related issues, follow the Security Advisory process.) Please take care to name the exact pieces of the API you've added or changed (e.g. types, interfaces, functions, or methods). If there are any breaking changes, make sure to offer a solution for consumers to follow once they upgrade to the changes. Finally, if you're only making changes to development scripts or tests, you may replace the template below with "None". --> ### `@metamask/profile-sync-controller` - **ADDED**: network syncing controller config. Can pass in: `onNetworkAdded`, `onNetworkUpdated`, `onNetworkRemoved` callbacks. - **ADDED**: `NetworkController:networkRemoved`, `NetworkController:addNetwork`, `NetworkController:updateNetwork` action permissions - **ADDED**: `NetworkController:removeNetwork` event permissions - **ADDED**: add new method `syncNetworks` method used to initiate the main network sync - **ADDED**: add `performMainNetworkSync` method to call the NetworkController actions to get and update NetworkConfigurations. - **ADDED**: `getBoundedNetworksToAdd` logic to cap the amount of networks to add. - **ADDED**: `createUpdateNetworkProps` to correctly handle networks to update. - **ADDED**: add `getStorageOptions` private method to get storage options for syncing. - **CHANGED**: modified the batchNetworks call to use the user-storage batch API instead of multiple calls. ## 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 highlighted breaking changes using the "BREAKING" category above as appropriate
1 parent 60e3ce7 commit 1d1b0e1

20 files changed

+2106
-558
lines changed

packages/profile-sync-controller/src/controllers/user-storage/UserStorageController.test.ts

+136-203
Large diffs are not rendered by default.

packages/profile-sync-controller/src/controllers/user-storage/UserStorageController.ts

+105-46
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ import {
1919
type KeyringControllerAddNewAccountAction,
2020
KeyringTypes,
2121
} from '@metamask/keyring-controller';
22-
import type { NetworkConfiguration } from '@metamask/network-controller';
22+
import type {
23+
NetworkControllerAddNetworkAction,
24+
NetworkControllerGetStateAction,
25+
NetworkControllerNetworkRemovedEvent,
26+
NetworkControllerRemoveNetworkAction,
27+
NetworkControllerUpdateNetworkAction,
28+
} from '@metamask/network-controller';
2329
import type { HandleSnapRequest } from '@metamask/snaps-controllers';
2430

2531
import { createSHA256Hash } from '../../shared/encryption';
@@ -43,7 +49,10 @@ import {
4349
isNameDefaultAccountName,
4450
mapInternalAccountToUserStorageAccount,
4551
} from './accounts/user-storage';
46-
import { startNetworkSyncing } from './network-syncing/controller-integration';
52+
import {
53+
performMainNetworkSync,
54+
startNetworkSyncing,
55+
} from './network-syncing/controller-integration';
4756
import {
4857
batchDeleteUserStorage,
4958
batchUpsertUserStorage,
@@ -54,27 +63,6 @@ import {
5463
upsertUserStorage,
5564
} from './services';
5665

57-
// TODO: add external NetworkController event
58-
// Need to listen for when a network gets added
59-
type NetworkControllerNetworkAddedEvent = {
60-
type: 'NetworkController:networkAdded';
61-
payload: [networkConfiguration: NetworkConfiguration];
62-
};
63-
64-
// TODO: add external NetworkController event
65-
// Need to listen for when a network is updated, or the default rpc/block explorer changes
66-
type NetworkControllerNetworkChangedEvent = {
67-
type: 'NetworkController:networkChanged';
68-
payload: [networkConfiguration: NetworkConfiguration];
69-
};
70-
71-
// TODO: add external NetworkController event
72-
// Need to listen for when a network gets deleted
73-
type NetworkControllerNetworkDeletedEvent = {
74-
type: 'NetworkController:networkDeleted';
75-
payload: [networkConfiguration: NetworkConfiguration];
76-
};
77-
7866
// TODO: fix external dependencies
7967
export declare type NotificationServicesControllerDisableNotificationServices =
8068
{
@@ -108,6 +96,10 @@ export type UserStorageControllerState = {
10896
* Condition used by UI to determine if account syncing is ready to be dispatched.
10997
*/
11098
isAccountSyncingReadyToBeDispatched: boolean;
99+
/**
100+
* Condition used to ensure that we do not perform any network sync mutations until we have synced at least once
101+
*/
102+
hasNetworkSyncingSyncedAtLeastOnce?: boolean;
111103
};
112104

113105
export const defaultState: UserStorageControllerState = {
@@ -128,12 +120,16 @@ const metadata: StateMetadata<UserStorageControllerState> = {
128120
},
129121
hasAccountSyncingSyncedAtLeastOnce: {
130122
persist: true,
131-
anonymous: true,
123+
anonymous: false,
132124
},
133125
isAccountSyncingReadyToBeDispatched: {
134126
persist: false,
135127
anonymous: false,
136128
},
129+
hasNetworkSyncingSyncedAtLeastOnce: {
130+
persist: true,
131+
anonymous: false,
132+
},
137133
};
138134

139135
type ControllerConfig = {
@@ -160,6 +156,31 @@ type ControllerConfig = {
160156
situationMessage: string,
161157
) => void;
162158
};
159+
160+
networkSyncing?: {
161+
maxNumberOfNetworksToAdd?: number;
162+
/**
163+
* Callback that fires when network sync adds a network
164+
* This is used for analytics.
165+
* @param profileId - ID for a given User (shared cross devices once authenticated)
166+
* @param chainId - Chain ID for the network added (in hex)
167+
*/
168+
onNetworkAdded?: (profileId: string, chainId: string) => void;
169+
/**
170+
* Callback that fires when network sync updates a network
171+
* This is used for analytics.
172+
* @param profileId - ID for a given User (shared cross devices once authenticated)
173+
* @param chainId - Chain ID for the network added (in hex)
174+
*/
175+
onNetworkUpdated?: (profileId: string, chainId: string) => void;
176+
/**
177+
* Callback that fires when network sync deletes a network
178+
* This is used for analytics.
179+
* @param profileId - ID for a given User (shared cross devices once authenticated)
180+
* @param chainId - Chain ID for the network added (in hex)
181+
*/
182+
onNetworkRemoved?: (profileId: string, chainId: string) => void;
183+
};
163184
};
164185

165186
// Messenger Actions
@@ -216,10 +237,15 @@ export type AllowedActions =
216237
// Metamask Notifications
217238
| NotificationServicesControllerDisableNotificationServices
218239
| NotificationServicesControllerSelectIsNotificationServicesEnabled
219-
// Account syncing
240+
// Account Syncing
220241
| AccountsControllerListAccountsAction
221242
| AccountsControllerUpdateAccountMetadataAction
222-
| KeyringControllerAddNewAccountAction;
243+
| KeyringControllerAddNewAccountAction
244+
// Network Syncing
245+
| NetworkControllerGetStateAction
246+
| NetworkControllerAddNetworkAction
247+
| NetworkControllerRemoveNetworkAction
248+
| NetworkControllerUpdateNetworkAction;
223249

224250
// Messenger events
225251
export type UserStorageControllerStateChangeEvent = ControllerStateChangeEvent<
@@ -249,9 +275,7 @@ export type AllowedEvents =
249275
| AccountsControllerAccountAddedEvent
250276
| AccountsControllerAccountRenamedEvent
251277
// Network Syncing Events
252-
| NetworkControllerNetworkAddedEvent
253-
| NetworkControllerNetworkChangedEvent
254-
| NetworkControllerNetworkDeletedEvent;
278+
| NetworkControllerNetworkRemovedEvent;
255279

256280
// Messenger
257281
export type UserStorageControllerMessenger = RestrictedControllerMessenger<
@@ -275,6 +299,13 @@ export default class UserStorageController extends BaseController<
275299
UserStorageControllerState,
276300
UserStorageControllerMessenger
277301
> {
302+
// This is replaced with the actual value in the constructor
303+
// We will remove this once the feature will be released
304+
#env = {
305+
isAccountSyncingEnabled: false,
306+
isNetworkSyncingEnabled: false,
307+
};
308+
278309
#auth = {
279310
getBearerToken: async () => {
280311
return await this.messagingSystem.call(
@@ -303,8 +334,6 @@ export default class UserStorageController extends BaseController<
303334
};
304335

305336
#accounts = {
306-
// This is replaced with the actual value in the constructor
307-
isAccountSyncingEnabled: false,
308337
isAccountSyncingInProgress: false,
309338
maxNumberOfAccountsToAdd: 0,
310339
canSync: () => {
@@ -315,7 +344,7 @@ export default class UserStorageController extends BaseController<
315344
return false;
316345
}
317346

318-
if (!this.#accounts.isAccountSyncingEnabled) {
347+
if (!this.#env.isAccountSyncingEnabled) {
319348
return false;
320349
}
321350

@@ -482,12 +511,10 @@ export default class UserStorageController extends BaseController<
482511
state: { ...defaultState, ...state },
483512
});
484513

514+
this.#env.isAccountSyncingEnabled = Boolean(env?.isAccountSyncingEnabled);
515+
this.#env.isNetworkSyncingEnabled = Boolean(env?.isNetworkSyncingEnabled);
485516
this.#config = config;
486517

487-
this.#accounts.isAccountSyncingEnabled = Boolean(
488-
env?.isAccountSyncingEnabled,
489-
);
490-
491518
this.#accounts.maxNumberOfAccountsToAdd =
492519
config?.accountSyncing?.maxNumberOfAccountsToAdd ?? 100;
493520

@@ -498,18 +525,12 @@ export default class UserStorageController extends BaseController<
498525
this.#accounts.setupAccountSyncingSubscriptions();
499526

500527
// Network Syncing
501-
if (env?.isNetworkSyncingEnabled) {
528+
if (this.#env.isNetworkSyncingEnabled) {
502529
startNetworkSyncing({
503530
messenger,
504-
getStorageConfig: async () => {
505-
const { storageKey, bearerToken } =
506-
await this.#getStorageKeyAndBearerToken();
507-
return {
508-
storageKey,
509-
bearerToken,
510-
nativeScryptCrypto: this.#nativeScryptCrypto,
511-
};
512-
},
531+
getStorageConfig: () => this.#getStorageOptions(),
532+
isMutationSyncBlocked: () =>
533+
!this.state.hasNetworkSyncingSyncedAtLeastOnce,
513534
});
514535
}
515536
}
@@ -560,6 +581,20 @@ export default class UserStorageController extends BaseController<
560581
);
561582
}
562583

584+
async #getStorageOptions() {
585+
if (!this.state.isProfileSyncingEnabled) {
586+
return null;
587+
}
588+
589+
const { storageKey, bearerToken } =
590+
await this.#getStorageKeyAndBearerToken();
591+
return {
592+
storageKey,
593+
bearerToken,
594+
nativeScryptCrypto: this.#nativeScryptCrypto,
595+
};
596+
}
597+
563598
public async enableProfileSyncing(): Promise<void> {
564599
try {
565600
this.#setIsProfileSyncingUpdateLoading(true);
@@ -1128,4 +1163,28 @@ export default class UserStorageController extends BaseController<
11281163
);
11291164
}
11301165
}
1166+
1167+
async syncNetworks() {
1168+
if (!this.#env.isNetworkSyncingEnabled) {
1169+
return;
1170+
}
1171+
1172+
const profileId = await this.#auth.getProfileId();
1173+
1174+
await performMainNetworkSync({
1175+
messenger: this.messagingSystem,
1176+
getStorageConfig: () => this.#getStorageOptions(),
1177+
maxNetworksToAdd: this.#config?.networkSyncing?.maxNumberOfNetworksToAdd,
1178+
onNetworkAdded: (cId) =>
1179+
this.#config?.networkSyncing?.onNetworkAdded?.(profileId, cId),
1180+
onNetworkUpdated: (cId) =>
1181+
this.#config?.networkSyncing?.onNetworkUpdated?.(profileId, cId),
1182+
onNetworkRemoved: (cId) =>
1183+
this.#config?.networkSyncing?.onNetworkRemoved?.(profileId, cId),
1184+
});
1185+
1186+
this.update((s) => {
1187+
s.hasNetworkSyncingSyncedAtLeastOnce = true;
1188+
});
1189+
}
11311190
}

0 commit comments

Comments
 (0)