@@ -218,8 +218,11 @@ export type NetworkConfiguration = {
218
218
* Custom RPC endpoints do not need a `networkClientId` property because it is
219
219
* assumed that they have not already been added and therefore network clients
220
220
* do not exist for them yet (and hence IDs need to be generated).
221
+ *
222
+ * However Custom RPC endpoints, that are synchronized between,
223
+ * can use the same `networkClientId` set on both devices.
221
224
*/
222
- export type AddNetworkCustomRpcEndpointFields = Omit <
225
+ export type AddNetworkCustomRpcEndpointFields = Partialize <
223
226
CustomRpcEndpoint ,
224
227
'networkClientId'
225
228
> ;
@@ -514,6 +517,11 @@ export type NetworkControllerRemoveNetworkAction = {
514
517
handler : NetworkController [ 'removeNetwork' ] ;
515
518
} ;
516
519
520
+ export type NetworkControllerDangerouslySetNetworkConfigurationAction = {
521
+ type : 'NetworkController:dangerouslySetNetworkConfiguration' ;
522
+ handler : NetworkController [ 'dangerouslySetNetworkConfiguration' ] ;
523
+ } ;
524
+
517
525
export type NetworkControllerActions =
518
526
| NetworkControllerGetStateAction
519
527
| NetworkControllerGetEthQueryAction
@@ -527,7 +535,8 @@ export type NetworkControllerActions =
527
535
| NetworkControllerGetNetworkConfigurationByNetworkClientId
528
536
| NetworkControllerAddNetworkAction
529
537
| NetworkControllerUpdateNetworkAction
530
- | NetworkControllerRemoveNetworkAction ;
538
+ | NetworkControllerRemoveNetworkAction
539
+ | NetworkControllerDangerouslySetNetworkConfigurationAction ;
531
540
532
541
export type NetworkControllerMessenger = RestrictedControllerMessenger <
533
542
typeof controllerName ,
@@ -1019,6 +1028,11 @@ export class NetworkController extends BaseController<
1019
1028
`${ this . name } :removeNetwork` ,
1020
1029
this . removeNetwork . bind ( this ) ,
1021
1030
) ;
1031
+
1032
+ this . messagingSystem . registerActionHandler (
1033
+ `${ this . name } :dangerouslySetNetworkConfiguration` ,
1034
+ this . dangerouslySetNetworkConfiguration . bind ( this ) ,
1035
+ ) ;
1022
1036
}
1023
1037
1024
1038
/**
@@ -1622,7 +1636,8 @@ export class NetworkController extends BaseController<
1622
1636
defaultOrCustomRpcEndpointFields . type === RpcEndpointType . Custom
1623
1637
? {
1624
1638
...defaultOrCustomRpcEndpointFields ,
1625
- networkClientId : uuidV4 ( ) ,
1639
+ networkClientId :
1640
+ defaultOrCustomRpcEndpointFields . networkClientId ?? uuidV4 ( ) ,
1626
1641
}
1627
1642
: defaultOrCustomRpcEndpointFields ;
1628
1643
return {
@@ -2016,6 +2031,105 @@ export class NetworkController extends BaseController<
2016
2031
) ;
2017
2032
}
2018
2033
2034
+ /**
2035
+ * This is used to override an existing network configuration.
2036
+ * This is only meant for internal use only and not to be exposed via the UI.
2037
+ * It is used as part of "Network Syncing", to sync networks, RPCs and block explorers cross devices.
2038
+ *
2039
+ * This will subsequently update the network client registry; state.networksMetadata, and state.selectedNetworkClientId
2040
+ * @param networkConfiguration - the network configuration to override
2041
+ */
2042
+ async dangerouslySetNetworkConfiguration (
2043
+ networkConfiguration : NetworkConfiguration ,
2044
+ ) {
2045
+ const prevNetworkConfig : NetworkConfiguration | undefined =
2046
+ networkConfiguration . chainId in this . state . networkConfigurationsByChainId
2047
+ ? this . state . networkConfigurationsByChainId [
2048
+ networkConfiguration . chainId
2049
+ ]
2050
+ : undefined ;
2051
+
2052
+ // Update Registry (remove old and add new)
2053
+ const autoManagedNetworkClientRegistry =
2054
+ this . #ensureAutoManagedNetworkClientRegistryPopulated( ) ;
2055
+ if ( prevNetworkConfig ) {
2056
+ const networkClientOperations = prevNetworkConfig . rpcEndpoints . map (
2057
+ ( rpcEndpoint ) => {
2058
+ return {
2059
+ type : 'remove' as const ,
2060
+ rpcEndpoint,
2061
+ } ;
2062
+ } ,
2063
+ ) ;
2064
+ this . #unregisterNetworkClientsAsNeeded( {
2065
+ networkClientOperations,
2066
+ autoManagedNetworkClientRegistry,
2067
+ } ) ;
2068
+ }
2069
+ const networkClientOperations = networkConfiguration . rpcEndpoints . map (
2070
+ ( rpcEndpoint ) => {
2071
+ return {
2072
+ type : 'add' as const ,
2073
+ rpcEndpoint,
2074
+ } ;
2075
+ } ,
2076
+ ) ;
2077
+ this . #registerNetworkClientsAsNeeded( {
2078
+ networkFields : networkConfiguration ,
2079
+ networkClientOperations,
2080
+ autoManagedNetworkClientRegistry,
2081
+ } ) ;
2082
+
2083
+ // update new `networkConfigurationsByChainId` (full replace)
2084
+ this . update ( ( state ) => {
2085
+ state . networkConfigurationsByChainId [ networkConfiguration . chainId ] =
2086
+ networkConfiguration ;
2087
+ } ) ;
2088
+ this . #networkConfigurationsByNetworkClientId =
2089
+ buildNetworkConfigurationsByNetworkClientId (
2090
+ this . state . networkConfigurationsByChainId ,
2091
+ ) ;
2092
+
2093
+ // update `networksMetadata` remove old
2094
+ if ( prevNetworkConfig ) {
2095
+ this . update ( ( state ) => {
2096
+ const newNetworksMetadata : NetworksMetadata = {
2097
+ ...state . networksMetadata ,
2098
+ } ;
2099
+ prevNetworkConfig . rpcEndpoints . forEach ( ( rpcEndpoint ) => {
2100
+ delete newNetworksMetadata [ rpcEndpoint . networkClientId ] ;
2101
+ } ) ;
2102
+ } ) ;
2103
+ }
2104
+
2105
+ // update `networksMetadata` update new
2106
+ for ( const rpcEndpoint of networkConfiguration . rpcEndpoints ) {
2107
+ await this . lookupNetwork ( rpcEndpoint . networkClientId ) ;
2108
+ }
2109
+
2110
+ // update selectedNetworkId
2111
+ const selectedClientId = this . state . selectedNetworkClientId ;
2112
+ const wasReplacedClientId = prevNetworkConfig ?. rpcEndpoints . some (
2113
+ ( r ) => r . networkClientId === selectedClientId ,
2114
+ ) ;
2115
+ const isValidClientIdInNewNetworks = networkConfiguration . rpcEndpoints . some (
2116
+ ( r ) => r . networkClientId === selectedClientId ,
2117
+ ) ;
2118
+ if ( wasReplacedClientId ) {
2119
+ if ( ! isValidClientIdInNewNetworks ) {
2120
+ // Update clientId to something that exists
2121
+ const newSelectedNetworkMetadata =
2122
+ networkConfiguration . rpcEndpoints . find (
2123
+ ( r ) => r . networkClientId in this . state . networksMetadata ,
2124
+ ) ?. networkClientId ;
2125
+ const anyClientId = Object . keys ( this . state . networksMetadata ) [ 0 ] ;
2126
+ const newlySelectedNetwork =
2127
+ newSelectedNetworkMetadata ?? anyClientId ?? selectedClientId ;
2128
+ await this . #refreshNetwork( newlySelectedNetwork ) ;
2129
+ }
2130
+ }
2131
+ }
2132
+
2019
2133
/**
2020
2134
* Assuming that the network has been previously switched, switches to this
2021
2135
* new network.
0 commit comments