@metamask-previews/multichain-network-controller 0.3.0-preview-c555b24d → 0.3.0-preview-1634185

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
16
 
17
17
  - The `AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS` now includes non-EVM testnets ([#5589](https://github.com/MetaMask/core/pull/5589))
18
18
 
19
+ ### Fixed
20
+
21
+ - Fix the condition to update the active network based on the `AccountsController:selectedAccountChange` event ([#5642](https://github.com/MetaMask/core/pull/5642))
22
+
19
23
  ## [0.3.0]
20
24
 
21
25
  ### Changed
@@ -26,11 +26,9 @@ class MultichainNetworkController extends base_controller_1.BaseController {
26
26
  state: {
27
27
  ...(0, constants_1.getDefaultMultichainNetworkControllerState)(),
28
28
  ...state,
29
- multichainNetworkConfigurationsByChainId: {
30
- // We can keep the current network as a hardcoded value
31
- // since it is not expected to add/remove networks yet.
32
- ...constants_1.AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,
33
- },
29
+ // We can keep the current network as a hardcoded value
30
+ // since it is not expected to add/remove networks yet.
31
+ multichainNetworkConfigurationsByChainId: constants_1.AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,
34
32
  },
35
33
  });
36
34
  _MultichainNetworkController_instances.add(this);
@@ -134,7 +132,7 @@ async function _MultichainNetworkController_removeEvmNetwork(chainId) {
134
132
  }, _MultichainNetworkController_removeNonEvmNetwork = function _MultichainNetworkController_removeNonEvmNetwork(_chainId) {
135
133
  throw new Error('Removal of non-EVM networks is not supported');
136
134
  }, _MultichainNetworkController_handleOnSelectedAccountChange = function _MultichainNetworkController_handleOnSelectedAccountChange(account) {
137
- const { type: accountType, address: accountAddress } = account;
135
+ const { type: accountType, address: accountAddress, scopes } = account;
138
136
  const isEvmAccount = (0, keyring_api_1.isEvmAccountType)(accountType);
139
137
  // Handle switching to EVM network
140
138
  if (isEvmAccount) {
@@ -149,15 +147,14 @@ async function _MultichainNetworkController_removeEvmNetwork(chainId) {
149
147
  return;
150
148
  }
151
149
  // Handle switching to non-EVM network
152
- const nonEvmChainId = (0, utils_2.getChainIdForNonEvmAddress)(accountAddress);
153
- const isSameNonEvmNetwork = nonEvmChainId === this.state.selectedMultichainNetworkChainId;
154
- if (isSameNonEvmNetwork) {
155
- // No need to update if already on the same non-EVM network
150
+ if (scopes.includes(this.state.selectedMultichainNetworkChainId)) {
151
+ // No need to update if the account's scope includes the active network
156
152
  this.update((state) => {
157
153
  state.isEvmSelected = false;
158
154
  });
159
155
  return;
160
156
  }
157
+ const nonEvmChainId = (0, utils_2.getChainIdForNonEvmAddress)(accountAddress);
161
158
  this.update((state) => {
162
159
  state.selectedMultichainNetworkChainId = nonEvmChainId;
163
160
  state.isEvmSelected = false;
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainNetworkController.cjs","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { type CaipChainId, isCaipChainId } from '@metamask/utils';\n\nimport {\n AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n getDefaultMultichainNetworkControllerState,\n} from './constants';\nimport {\n MULTICHAIN_NETWORK_CONTROLLER_NAME,\n type MultichainNetworkControllerState,\n type MultichainNetworkControllerMessenger,\n type SupportedCaipChainId,\n} from './types';\nimport {\n checkIfSupportedCaipChainId,\n getChainIdForNonEvmAddress,\n convertEvmCaipToHexChainId,\n isEvmCaipChainId,\n} from './utils';\n\n/**\n * The MultichainNetworkController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainNetworkController extends BaseController<\n typeof MULTICHAIN_NETWORK_CONTROLLER_NAME,\n MultichainNetworkControllerState,\n MultichainNetworkControllerMessenger\n> {\n constructor({\n messenger,\n state,\n }: {\n messenger: MultichainNetworkControllerMessenger;\n state?: Omit<\n Partial<MultichainNetworkControllerState>,\n 'multichainNetworkConfigurationsByChainId'\n >;\n }) {\n super({\n messenger,\n name: MULTICHAIN_NETWORK_CONTROLLER_NAME,\n metadata: MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n state: {\n ...getDefaultMultichainNetworkControllerState(),\n ...state,\n multichainNetworkConfigurationsByChainId: {\n // We can keep the current network as a hardcoded value\n // since it is not expected to add/remove networks yet.\n ...AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n },\n },\n });\n\n this.#subscribeToMessageEvents();\n this.#registerMessageHandlers();\n }\n\n /**\n * Sets the active EVM network.\n *\n * @param id - The client ID of the EVM network to set active.\n */\n async #setActiveEvmNetwork(id: NetworkClientId): Promise<void> {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n const shouldSetEvmActive = !this.state.isEvmSelected;\n const shouldNotifyNetworkChange = id !== selectedNetworkClientId;\n\n // No changes needed if EVM is active and network is already selected\n if (!shouldSetEvmActive && !shouldNotifyNetworkChange) {\n return;\n }\n\n // Update EVM selection state if needed\n if (shouldSetEvmActive) {\n this.update((state) => {\n state.isEvmSelected = true;\n });\n }\n\n // Only notify the network controller if the selected evm network is different\n if (shouldNotifyNetworkChange) {\n await this.messagingSystem.call('NetworkController:setActiveNetwork', id);\n }\n\n // Only publish the networkDidChange event if either the EVM network is different or we're switching between EVM and non-EVM networks\n if (shouldSetEvmActive || shouldNotifyNetworkChange) {\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n }\n\n /**\n * Sets the active non-EVM network.\n *\n * @param id - The chain ID of the non-EVM network to set active.\n */\n #setActiveNonEvmNetwork(id: SupportedCaipChainId): void {\n if (\n id === this.state.selectedMultichainNetworkChainId &&\n !this.state.isEvmSelected\n ) {\n // Same non-EVM network is already selected, no need to update\n return;\n }\n\n this.update((state) => {\n state.selectedMultichainNetworkChainId = id;\n state.isEvmSelected = false;\n });\n\n // Notify listeners that the network changed\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n\n /**\n * Sets the active network.\n *\n * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.\n * @returns - A promise that resolves when the network is set active.\n */\n async setActiveNetwork(\n id: SupportedCaipChainId | NetworkClientId,\n ): Promise<void> {\n if (isCaipChainId(id)) {\n const isSupportedCaipChainId = checkIfSupportedCaipChainId(id);\n if (!isSupportedCaipChainId) {\n throw new Error(`Unsupported Caip chain ID: ${String(id)}`);\n }\n return this.#setActiveNonEvmNetwork(id);\n }\n\n return await this.#setActiveEvmNetwork(id);\n }\n\n /**\n * Removes an EVM network from the list of networks.\n * This method re-directs the request to the network-controller.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async #removeEvmNetwork(chainId: CaipChainId): Promise<void> {\n const hexChainId = convertEvmCaipToHexChainId(chainId);\n const selectedChainId = this.messagingSystem.call(\n 'NetworkController:getSelectedChainId',\n );\n\n if (selectedChainId === hexChainId) {\n // We prevent removing the currently selected network.\n if (this.state.isEvmSelected) {\n throw new Error('Cannot remove the currently selected network');\n }\n\n // If a non-EVM network is selected, we can delete the currently EVM selected network, but\n // we automatically switch to EVM mainnet.\n const ethereumMainnetHexChainId = '0x1'; // TODO: Should probably be a constant.\n const clientId = this.messagingSystem.call(\n 'NetworkController:findNetworkClientIdByChainId',\n ethereumMainnetHexChainId,\n );\n\n await this.messagingSystem.call(\n 'NetworkController:setActiveNetwork',\n clientId,\n );\n }\n\n this.messagingSystem.call('NetworkController:removeNetwork', hexChainId);\n }\n\n /**\n * Removes a non-EVM network from the list of networks.\n * This method is not supported and throws an error.\n *\n * @param _chainId - The chain ID of the network to remove.\n * @throws - An error indicating that removal of non-EVM networks is not supported.\n */\n #removeNonEvmNetwork(_chainId: CaipChainId): void {\n throw new Error('Removal of non-EVM networks is not supported');\n }\n\n /**\n * Removes a network from the list of networks.\n * It only supports EVM networks.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async removeNetwork(chainId: CaipChainId): Promise<void> {\n if (isEvmCaipChainId(chainId)) {\n return await this.#removeEvmNetwork(chainId);\n }\n\n return this.#removeNonEvmNetwork(chainId);\n }\n\n /**\n * Handles switching between EVM and non-EVM networks when an account is changed\n *\n * @param account - The account that was changed\n */\n #handleOnSelectedAccountChange(account: InternalAccount) {\n const { type: accountType, address: accountAddress } = account;\n const isEvmAccount = isEvmAccountType(accountType);\n\n // Handle switching to EVM network\n if (isEvmAccount) {\n if (this.state.isEvmSelected) {\n // No need to update if already on evm network\n return;\n }\n\n // Make EVM network active\n this.update((state) => {\n state.isEvmSelected = true;\n });\n\n return;\n }\n\n // Handle switching to non-EVM network\n const nonEvmChainId = getChainIdForNonEvmAddress(accountAddress);\n const isSameNonEvmNetwork =\n nonEvmChainId === this.state.selectedMultichainNetworkChainId;\n\n if (isSameNonEvmNetwork) {\n // No need to update if already on the same non-EVM network\n this.update((state) => {\n state.isEvmSelected = false;\n });\n return;\n }\n\n this.update((state) => {\n state.selectedMultichainNetworkChainId = nonEvmChainId;\n state.isEvmSelected = false;\n });\n\n // No need to publish NetworkController:setActiveNetwork because EVM accounts falls back to use the last selected EVM network\n // DO NOT publish MultichainNetworkController:networkDidChange to prevent circular listener loops\n }\n\n /**\n * Subscribes to message events.\n */\n #subscribeToMessageEvents() {\n // Handle network switch when account is changed\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => this.#handleOnSelectedAccountChange(account),\n );\n }\n\n /**\n * Registers message handlers.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n 'MultichainNetworkController:setActiveNetwork',\n this.setActiveNetwork.bind(this),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainNetworkController.cjs","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { type CaipChainId, isCaipChainId } from '@metamask/utils';\n\nimport {\n AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n getDefaultMultichainNetworkControllerState,\n} from './constants';\nimport {\n MULTICHAIN_NETWORK_CONTROLLER_NAME,\n type MultichainNetworkControllerState,\n type MultichainNetworkControllerMessenger,\n type SupportedCaipChainId,\n} from './types';\nimport {\n checkIfSupportedCaipChainId,\n getChainIdForNonEvmAddress,\n convertEvmCaipToHexChainId,\n isEvmCaipChainId,\n} from './utils';\n\n/**\n * The MultichainNetworkController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainNetworkController extends BaseController<\n typeof MULTICHAIN_NETWORK_CONTROLLER_NAME,\n MultichainNetworkControllerState,\n MultichainNetworkControllerMessenger\n> {\n constructor({\n messenger,\n state,\n }: {\n messenger: MultichainNetworkControllerMessenger;\n state?: Omit<\n Partial<MultichainNetworkControllerState>,\n 'multichainNetworkConfigurationsByChainId'\n >;\n }) {\n super({\n messenger,\n name: MULTICHAIN_NETWORK_CONTROLLER_NAME,\n metadata: MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n state: {\n ...getDefaultMultichainNetworkControllerState(),\n ...state,\n // We can keep the current network as a hardcoded value\n // since it is not expected to add/remove networks yet.\n multichainNetworkConfigurationsByChainId:\n AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n },\n });\n\n this.#subscribeToMessageEvents();\n this.#registerMessageHandlers();\n }\n\n /**\n * Sets the active EVM network.\n *\n * @param id - The client ID of the EVM network to set active.\n */\n async #setActiveEvmNetwork(id: NetworkClientId): Promise<void> {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n const shouldSetEvmActive = !this.state.isEvmSelected;\n const shouldNotifyNetworkChange = id !== selectedNetworkClientId;\n\n // No changes needed if EVM is active and network is already selected\n if (!shouldSetEvmActive && !shouldNotifyNetworkChange) {\n return;\n }\n\n // Update EVM selection state if needed\n if (shouldSetEvmActive) {\n this.update((state) => {\n state.isEvmSelected = true;\n });\n }\n\n // Only notify the network controller if the selected evm network is different\n if (shouldNotifyNetworkChange) {\n await this.messagingSystem.call('NetworkController:setActiveNetwork', id);\n }\n\n // Only publish the networkDidChange event if either the EVM network is different or we're switching between EVM and non-EVM networks\n if (shouldSetEvmActive || shouldNotifyNetworkChange) {\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n }\n\n /**\n * Sets the active non-EVM network.\n *\n * @param id - The chain ID of the non-EVM network to set active.\n */\n #setActiveNonEvmNetwork(id: SupportedCaipChainId): void {\n if (\n id === this.state.selectedMultichainNetworkChainId &&\n !this.state.isEvmSelected\n ) {\n // Same non-EVM network is already selected, no need to update\n return;\n }\n\n this.update((state) => {\n state.selectedMultichainNetworkChainId = id;\n state.isEvmSelected = false;\n });\n\n // Notify listeners that the network changed\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n\n /**\n * Sets the active network.\n *\n * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.\n * @returns - A promise that resolves when the network is set active.\n */\n async setActiveNetwork(\n id: SupportedCaipChainId | NetworkClientId,\n ): Promise<void> {\n if (isCaipChainId(id)) {\n const isSupportedCaipChainId = checkIfSupportedCaipChainId(id);\n if (!isSupportedCaipChainId) {\n throw new Error(`Unsupported Caip chain ID: ${String(id)}`);\n }\n return this.#setActiveNonEvmNetwork(id);\n }\n\n return await this.#setActiveEvmNetwork(id);\n }\n\n /**\n * Removes an EVM network from the list of networks.\n * This method re-directs the request to the network-controller.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async #removeEvmNetwork(chainId: CaipChainId): Promise<void> {\n const hexChainId = convertEvmCaipToHexChainId(chainId);\n const selectedChainId = this.messagingSystem.call(\n 'NetworkController:getSelectedChainId',\n );\n\n if (selectedChainId === hexChainId) {\n // We prevent removing the currently selected network.\n if (this.state.isEvmSelected) {\n throw new Error('Cannot remove the currently selected network');\n }\n\n // If a non-EVM network is selected, we can delete the currently EVM selected network, but\n // we automatically switch to EVM mainnet.\n const ethereumMainnetHexChainId = '0x1'; // TODO: Should probably be a constant.\n const clientId = this.messagingSystem.call(\n 'NetworkController:findNetworkClientIdByChainId',\n ethereumMainnetHexChainId,\n );\n\n await this.messagingSystem.call(\n 'NetworkController:setActiveNetwork',\n clientId,\n );\n }\n\n this.messagingSystem.call('NetworkController:removeNetwork', hexChainId);\n }\n\n /**\n * Removes a non-EVM network from the list of networks.\n * This method is not supported and throws an error.\n *\n * @param _chainId - The chain ID of the network to remove.\n * @throws - An error indicating that removal of non-EVM networks is not supported.\n */\n #removeNonEvmNetwork(_chainId: CaipChainId): void {\n throw new Error('Removal of non-EVM networks is not supported');\n }\n\n /**\n * Removes a network from the list of networks.\n * It only supports EVM networks.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async removeNetwork(chainId: CaipChainId): Promise<void> {\n if (isEvmCaipChainId(chainId)) {\n return await this.#removeEvmNetwork(chainId);\n }\n\n return this.#removeNonEvmNetwork(chainId);\n }\n\n /**\n * Handles switching between EVM and non-EVM networks when an account is changed\n *\n * @param account - The account that was changed\n */\n #handleOnSelectedAccountChange(account: InternalAccount) {\n const { type: accountType, address: accountAddress, scopes } = account;\n const isEvmAccount = isEvmAccountType(accountType);\n\n // Handle switching to EVM network\n if (isEvmAccount) {\n if (this.state.isEvmSelected) {\n // No need to update if already on evm network\n return;\n }\n\n // Make EVM network active\n this.update((state) => {\n state.isEvmSelected = true;\n });\n\n return;\n }\n\n // Handle switching to non-EVM network\n if (scopes.includes(this.state.selectedMultichainNetworkChainId)) {\n // No need to update if the account's scope includes the active network\n this.update((state) => {\n state.isEvmSelected = false;\n });\n return;\n }\n\n const nonEvmChainId = getChainIdForNonEvmAddress(accountAddress);\n this.update((state) => {\n state.selectedMultichainNetworkChainId = nonEvmChainId;\n state.isEvmSelected = false;\n });\n\n // No need to publish NetworkController:setActiveNetwork because EVM accounts falls back to use the last selected EVM network\n // DO NOT publish MultichainNetworkController:networkDidChange to prevent circular listener loops\n }\n\n /**\n * Subscribes to message events.\n */\n #subscribeToMessageEvents() {\n // Handle network switch when account is changed\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => this.#handleOnSelectedAccountChange(account),\n );\n }\n\n /**\n * Registers message handlers.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n 'MultichainNetworkController:setActiveNetwork',\n this.setActiveNetwork.bind(this),\n );\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainNetworkController.d.cts","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AACpE,OAAO,EAAE,KAAK,WAAW,EAAiB,wBAAwB;AAOlE,OAAO,EACL,kCAAkC,EAClC,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,oBAAoB,EAC1B,oBAAgB;AAQjB;;;GAGG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,kCAAkC,EACzC,gCAAgC,EAChC,oCAAoC,CACrC;;gBACa,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,IAAI,CACV,OAAO,CAAC,gCAAgC,CAAC,EACzC,0CAA0C,CAC3C,CAAC;KACH;IAqFD;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,oBAAoB,GAAG,eAAe,GACzC,OAAO,CAAC,IAAI,CAAC;IA2DhB;;;;;;OAMG;IACG,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CA0EzD"}
1
+ {"version":3,"file":"MultichainNetworkController.d.cts","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AACpE,OAAO,EAAE,KAAK,WAAW,EAAiB,wBAAwB;AAOlE,OAAO,EACL,kCAAkC,EAClC,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,oBAAoB,EAC1B,oBAAgB;AAQjB;;;GAGG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,kCAAkC,EACzC,gCAAgC,EAChC,oCAAoC,CACrC;;gBACa,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,IAAI,CACV,OAAO,CAAC,gCAAgC,CAAC,EACzC,0CAA0C,CAC3C,CAAC;KACH;IAoFD;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,oBAAoB,GAAG,eAAe,GACzC,OAAO,CAAC,IAAI,CAAC;IA2DhB;;;;;;OAMG;IACG,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAuEzD"}
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainNetworkController.d.mts","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AACpE,OAAO,EAAE,KAAK,WAAW,EAAiB,wBAAwB;AAOlE,OAAO,EACL,kCAAkC,EAClC,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,oBAAoB,EAC1B,oBAAgB;AAQjB;;;GAGG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,kCAAkC,EACzC,gCAAgC,EAChC,oCAAoC,CACrC;;gBACa,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,IAAI,CACV,OAAO,CAAC,gCAAgC,CAAC,EACzC,0CAA0C,CAC3C,CAAC;KACH;IAqFD;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,oBAAoB,GAAG,eAAe,GACzC,OAAO,CAAC,IAAI,CAAC;IA2DhB;;;;;;OAMG;IACG,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CA0EzD"}
1
+ {"version":3,"file":"MultichainNetworkController.d.mts","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AACpE,OAAO,EAAE,KAAK,WAAW,EAAiB,wBAAwB;AAOlE,OAAO,EACL,kCAAkC,EAClC,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,oBAAoB,EAC1B,oBAAgB;AAQjB;;;GAGG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,kCAAkC,EACzC,gCAAgC,EAChC,oCAAoC,CACrC;;gBACa,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,IAAI,CACV,OAAO,CAAC,gCAAgC,CAAC,EACzC,0CAA0C,CAC3C,CAAC;KACH;IAoFD;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,oBAAoB,GAAG,eAAe,GACzC,OAAO,CAAC,IAAI,CAAC;IA2DhB;;;;;;OAMG;IACG,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAuEzD"}
@@ -23,11 +23,9 @@ export class MultichainNetworkController extends BaseController {
23
23
  state: {
24
24
  ...getDefaultMultichainNetworkControllerState(),
25
25
  ...state,
26
- multichainNetworkConfigurationsByChainId: {
27
- // We can keep the current network as a hardcoded value
28
- // since it is not expected to add/remove networks yet.
29
- ...AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,
30
- },
26
+ // We can keep the current network as a hardcoded value
27
+ // since it is not expected to add/remove networks yet.
28
+ multichainNetworkConfigurationsByChainId: AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,
31
29
  },
32
30
  });
33
31
  _MultichainNetworkController_instances.add(this);
@@ -130,7 +128,7 @@ async function _MultichainNetworkController_removeEvmNetwork(chainId) {
130
128
  }, _MultichainNetworkController_removeNonEvmNetwork = function _MultichainNetworkController_removeNonEvmNetwork(_chainId) {
131
129
  throw new Error('Removal of non-EVM networks is not supported');
132
130
  }, _MultichainNetworkController_handleOnSelectedAccountChange = function _MultichainNetworkController_handleOnSelectedAccountChange(account) {
133
- const { type: accountType, address: accountAddress } = account;
131
+ const { type: accountType, address: accountAddress, scopes } = account;
134
132
  const isEvmAccount = isEvmAccountType(accountType);
135
133
  // Handle switching to EVM network
136
134
  if (isEvmAccount) {
@@ -145,15 +143,14 @@ async function _MultichainNetworkController_removeEvmNetwork(chainId) {
145
143
  return;
146
144
  }
147
145
  // Handle switching to non-EVM network
148
- const nonEvmChainId = getChainIdForNonEvmAddress(accountAddress);
149
- const isSameNonEvmNetwork = nonEvmChainId === this.state.selectedMultichainNetworkChainId;
150
- if (isSameNonEvmNetwork) {
151
- // No need to update if already on the same non-EVM network
146
+ if (scopes.includes(this.state.selectedMultichainNetworkChainId)) {
147
+ // No need to update if the account's scope includes the active network
152
148
  this.update((state) => {
153
149
  state.isEvmSelected = false;
154
150
  });
155
151
  return;
156
152
  }
153
+ const nonEvmChainId = getChainIdForNonEvmAddress(accountAddress);
157
154
  this.update((state) => {
158
155
  state.selectedMultichainNetworkChainId = nonEvmChainId;
159
156
  state.isEvmSelected = false;
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainNetworkController.mjs","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { type CaipChainId, isCaipChainId } from '@metamask/utils';\n\nimport {\n AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n getDefaultMultichainNetworkControllerState,\n} from './constants';\nimport {\n MULTICHAIN_NETWORK_CONTROLLER_NAME,\n type MultichainNetworkControllerState,\n type MultichainNetworkControllerMessenger,\n type SupportedCaipChainId,\n} from './types';\nimport {\n checkIfSupportedCaipChainId,\n getChainIdForNonEvmAddress,\n convertEvmCaipToHexChainId,\n isEvmCaipChainId,\n} from './utils';\n\n/**\n * The MultichainNetworkController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainNetworkController extends BaseController<\n typeof MULTICHAIN_NETWORK_CONTROLLER_NAME,\n MultichainNetworkControllerState,\n MultichainNetworkControllerMessenger\n> {\n constructor({\n messenger,\n state,\n }: {\n messenger: MultichainNetworkControllerMessenger;\n state?: Omit<\n Partial<MultichainNetworkControllerState>,\n 'multichainNetworkConfigurationsByChainId'\n >;\n }) {\n super({\n messenger,\n name: MULTICHAIN_NETWORK_CONTROLLER_NAME,\n metadata: MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n state: {\n ...getDefaultMultichainNetworkControllerState(),\n ...state,\n multichainNetworkConfigurationsByChainId: {\n // We can keep the current network as a hardcoded value\n // since it is not expected to add/remove networks yet.\n ...AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n },\n },\n });\n\n this.#subscribeToMessageEvents();\n this.#registerMessageHandlers();\n }\n\n /**\n * Sets the active EVM network.\n *\n * @param id - The client ID of the EVM network to set active.\n */\n async #setActiveEvmNetwork(id: NetworkClientId): Promise<void> {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n const shouldSetEvmActive = !this.state.isEvmSelected;\n const shouldNotifyNetworkChange = id !== selectedNetworkClientId;\n\n // No changes needed if EVM is active and network is already selected\n if (!shouldSetEvmActive && !shouldNotifyNetworkChange) {\n return;\n }\n\n // Update EVM selection state if needed\n if (shouldSetEvmActive) {\n this.update((state) => {\n state.isEvmSelected = true;\n });\n }\n\n // Only notify the network controller if the selected evm network is different\n if (shouldNotifyNetworkChange) {\n await this.messagingSystem.call('NetworkController:setActiveNetwork', id);\n }\n\n // Only publish the networkDidChange event if either the EVM network is different or we're switching between EVM and non-EVM networks\n if (shouldSetEvmActive || shouldNotifyNetworkChange) {\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n }\n\n /**\n * Sets the active non-EVM network.\n *\n * @param id - The chain ID of the non-EVM network to set active.\n */\n #setActiveNonEvmNetwork(id: SupportedCaipChainId): void {\n if (\n id === this.state.selectedMultichainNetworkChainId &&\n !this.state.isEvmSelected\n ) {\n // Same non-EVM network is already selected, no need to update\n return;\n }\n\n this.update((state) => {\n state.selectedMultichainNetworkChainId = id;\n state.isEvmSelected = false;\n });\n\n // Notify listeners that the network changed\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n\n /**\n * Sets the active network.\n *\n * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.\n * @returns - A promise that resolves when the network is set active.\n */\n async setActiveNetwork(\n id: SupportedCaipChainId | NetworkClientId,\n ): Promise<void> {\n if (isCaipChainId(id)) {\n const isSupportedCaipChainId = checkIfSupportedCaipChainId(id);\n if (!isSupportedCaipChainId) {\n throw new Error(`Unsupported Caip chain ID: ${String(id)}`);\n }\n return this.#setActiveNonEvmNetwork(id);\n }\n\n return await this.#setActiveEvmNetwork(id);\n }\n\n /**\n * Removes an EVM network from the list of networks.\n * This method re-directs the request to the network-controller.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async #removeEvmNetwork(chainId: CaipChainId): Promise<void> {\n const hexChainId = convertEvmCaipToHexChainId(chainId);\n const selectedChainId = this.messagingSystem.call(\n 'NetworkController:getSelectedChainId',\n );\n\n if (selectedChainId === hexChainId) {\n // We prevent removing the currently selected network.\n if (this.state.isEvmSelected) {\n throw new Error('Cannot remove the currently selected network');\n }\n\n // If a non-EVM network is selected, we can delete the currently EVM selected network, but\n // we automatically switch to EVM mainnet.\n const ethereumMainnetHexChainId = '0x1'; // TODO: Should probably be a constant.\n const clientId = this.messagingSystem.call(\n 'NetworkController:findNetworkClientIdByChainId',\n ethereumMainnetHexChainId,\n );\n\n await this.messagingSystem.call(\n 'NetworkController:setActiveNetwork',\n clientId,\n );\n }\n\n this.messagingSystem.call('NetworkController:removeNetwork', hexChainId);\n }\n\n /**\n * Removes a non-EVM network from the list of networks.\n * This method is not supported and throws an error.\n *\n * @param _chainId - The chain ID of the network to remove.\n * @throws - An error indicating that removal of non-EVM networks is not supported.\n */\n #removeNonEvmNetwork(_chainId: CaipChainId): void {\n throw new Error('Removal of non-EVM networks is not supported');\n }\n\n /**\n * Removes a network from the list of networks.\n * It only supports EVM networks.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async removeNetwork(chainId: CaipChainId): Promise<void> {\n if (isEvmCaipChainId(chainId)) {\n return await this.#removeEvmNetwork(chainId);\n }\n\n return this.#removeNonEvmNetwork(chainId);\n }\n\n /**\n * Handles switching between EVM and non-EVM networks when an account is changed\n *\n * @param account - The account that was changed\n */\n #handleOnSelectedAccountChange(account: InternalAccount) {\n const { type: accountType, address: accountAddress } = account;\n const isEvmAccount = isEvmAccountType(accountType);\n\n // Handle switching to EVM network\n if (isEvmAccount) {\n if (this.state.isEvmSelected) {\n // No need to update if already on evm network\n return;\n }\n\n // Make EVM network active\n this.update((state) => {\n state.isEvmSelected = true;\n });\n\n return;\n }\n\n // Handle switching to non-EVM network\n const nonEvmChainId = getChainIdForNonEvmAddress(accountAddress);\n const isSameNonEvmNetwork =\n nonEvmChainId === this.state.selectedMultichainNetworkChainId;\n\n if (isSameNonEvmNetwork) {\n // No need to update if already on the same non-EVM network\n this.update((state) => {\n state.isEvmSelected = false;\n });\n return;\n }\n\n this.update((state) => {\n state.selectedMultichainNetworkChainId = nonEvmChainId;\n state.isEvmSelected = false;\n });\n\n // No need to publish NetworkController:setActiveNetwork because EVM accounts falls back to use the last selected EVM network\n // DO NOT publish MultichainNetworkController:networkDidChange to prevent circular listener loops\n }\n\n /**\n * Subscribes to message events.\n */\n #subscribeToMessageEvents() {\n // Handle network switch when account is changed\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => this.#handleOnSelectedAccountChange(account),\n );\n }\n\n /**\n * Registers message handlers.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n 'MultichainNetworkController:setActiveNetwork',\n this.setActiveNetwork.bind(this),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainNetworkController.mjs","sourceRoot":"","sources":["../src/MultichainNetworkController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { type CaipChainId, isCaipChainId } from '@metamask/utils';\n\nimport {\n AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n getDefaultMultichainNetworkControllerState,\n} from './constants';\nimport {\n MULTICHAIN_NETWORK_CONTROLLER_NAME,\n type MultichainNetworkControllerState,\n type MultichainNetworkControllerMessenger,\n type SupportedCaipChainId,\n} from './types';\nimport {\n checkIfSupportedCaipChainId,\n getChainIdForNonEvmAddress,\n convertEvmCaipToHexChainId,\n isEvmCaipChainId,\n} from './utils';\n\n/**\n * The MultichainNetworkController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainNetworkController extends BaseController<\n typeof MULTICHAIN_NETWORK_CONTROLLER_NAME,\n MultichainNetworkControllerState,\n MultichainNetworkControllerMessenger\n> {\n constructor({\n messenger,\n state,\n }: {\n messenger: MultichainNetworkControllerMessenger;\n state?: Omit<\n Partial<MultichainNetworkControllerState>,\n 'multichainNetworkConfigurationsByChainId'\n >;\n }) {\n super({\n messenger,\n name: MULTICHAIN_NETWORK_CONTROLLER_NAME,\n metadata: MULTICHAIN_NETWORK_CONTROLLER_METADATA,\n state: {\n ...getDefaultMultichainNetworkControllerState(),\n ...state,\n // We can keep the current network as a hardcoded value\n // since it is not expected to add/remove networks yet.\n multichainNetworkConfigurationsByChainId:\n AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n },\n });\n\n this.#subscribeToMessageEvents();\n this.#registerMessageHandlers();\n }\n\n /**\n * Sets the active EVM network.\n *\n * @param id - The client ID of the EVM network to set active.\n */\n async #setActiveEvmNetwork(id: NetworkClientId): Promise<void> {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n\n const shouldSetEvmActive = !this.state.isEvmSelected;\n const shouldNotifyNetworkChange = id !== selectedNetworkClientId;\n\n // No changes needed if EVM is active and network is already selected\n if (!shouldSetEvmActive && !shouldNotifyNetworkChange) {\n return;\n }\n\n // Update EVM selection state if needed\n if (shouldSetEvmActive) {\n this.update((state) => {\n state.isEvmSelected = true;\n });\n }\n\n // Only notify the network controller if the selected evm network is different\n if (shouldNotifyNetworkChange) {\n await this.messagingSystem.call('NetworkController:setActiveNetwork', id);\n }\n\n // Only publish the networkDidChange event if either the EVM network is different or we're switching between EVM and non-EVM networks\n if (shouldSetEvmActive || shouldNotifyNetworkChange) {\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n }\n\n /**\n * Sets the active non-EVM network.\n *\n * @param id - The chain ID of the non-EVM network to set active.\n */\n #setActiveNonEvmNetwork(id: SupportedCaipChainId): void {\n if (\n id === this.state.selectedMultichainNetworkChainId &&\n !this.state.isEvmSelected\n ) {\n // Same non-EVM network is already selected, no need to update\n return;\n }\n\n this.update((state) => {\n state.selectedMultichainNetworkChainId = id;\n state.isEvmSelected = false;\n });\n\n // Notify listeners that the network changed\n this.messagingSystem.publish(\n 'MultichainNetworkController:networkDidChange',\n id,\n );\n }\n\n /**\n * Sets the active network.\n *\n * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.\n * @returns - A promise that resolves when the network is set active.\n */\n async setActiveNetwork(\n id: SupportedCaipChainId | NetworkClientId,\n ): Promise<void> {\n if (isCaipChainId(id)) {\n const isSupportedCaipChainId = checkIfSupportedCaipChainId(id);\n if (!isSupportedCaipChainId) {\n throw new Error(`Unsupported Caip chain ID: ${String(id)}`);\n }\n return this.#setActiveNonEvmNetwork(id);\n }\n\n return await this.#setActiveEvmNetwork(id);\n }\n\n /**\n * Removes an EVM network from the list of networks.\n * This method re-directs the request to the network-controller.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async #removeEvmNetwork(chainId: CaipChainId): Promise<void> {\n const hexChainId = convertEvmCaipToHexChainId(chainId);\n const selectedChainId = this.messagingSystem.call(\n 'NetworkController:getSelectedChainId',\n );\n\n if (selectedChainId === hexChainId) {\n // We prevent removing the currently selected network.\n if (this.state.isEvmSelected) {\n throw new Error('Cannot remove the currently selected network');\n }\n\n // If a non-EVM network is selected, we can delete the currently EVM selected network, but\n // we automatically switch to EVM mainnet.\n const ethereumMainnetHexChainId = '0x1'; // TODO: Should probably be a constant.\n const clientId = this.messagingSystem.call(\n 'NetworkController:findNetworkClientIdByChainId',\n ethereumMainnetHexChainId,\n );\n\n await this.messagingSystem.call(\n 'NetworkController:setActiveNetwork',\n clientId,\n );\n }\n\n this.messagingSystem.call('NetworkController:removeNetwork', hexChainId);\n }\n\n /**\n * Removes a non-EVM network from the list of networks.\n * This method is not supported and throws an error.\n *\n * @param _chainId - The chain ID of the network to remove.\n * @throws - An error indicating that removal of non-EVM networks is not supported.\n */\n #removeNonEvmNetwork(_chainId: CaipChainId): void {\n throw new Error('Removal of non-EVM networks is not supported');\n }\n\n /**\n * Removes a network from the list of networks.\n * It only supports EVM networks.\n *\n * @param chainId - The chain ID of the network to remove.\n * @returns - A promise that resolves when the network is removed.\n */\n async removeNetwork(chainId: CaipChainId): Promise<void> {\n if (isEvmCaipChainId(chainId)) {\n return await this.#removeEvmNetwork(chainId);\n }\n\n return this.#removeNonEvmNetwork(chainId);\n }\n\n /**\n * Handles switching between EVM and non-EVM networks when an account is changed\n *\n * @param account - The account that was changed\n */\n #handleOnSelectedAccountChange(account: InternalAccount) {\n const { type: accountType, address: accountAddress, scopes } = account;\n const isEvmAccount = isEvmAccountType(accountType);\n\n // Handle switching to EVM network\n if (isEvmAccount) {\n if (this.state.isEvmSelected) {\n // No need to update if already on evm network\n return;\n }\n\n // Make EVM network active\n this.update((state) => {\n state.isEvmSelected = true;\n });\n\n return;\n }\n\n // Handle switching to non-EVM network\n if (scopes.includes(this.state.selectedMultichainNetworkChainId)) {\n // No need to update if the account's scope includes the active network\n this.update((state) => {\n state.isEvmSelected = false;\n });\n return;\n }\n\n const nonEvmChainId = getChainIdForNonEvmAddress(accountAddress);\n this.update((state) => {\n state.selectedMultichainNetworkChainId = nonEvmChainId;\n state.isEvmSelected = false;\n });\n\n // No need to publish NetworkController:setActiveNetwork because EVM accounts falls back to use the last selected EVM network\n // DO NOT publish MultichainNetworkController:networkDidChange to prevent circular listener loops\n }\n\n /**\n * Subscribes to message events.\n */\n #subscribeToMessageEvents() {\n // Handle network switch when account is changed\n this.messagingSystem.subscribe(\n 'AccountsController:selectedAccountChange',\n (account) => this.#handleOnSelectedAccountChange(account),\n );\n }\n\n /**\n * Registers message handlers.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n 'MultichainNetworkController:setActiveNetwork',\n this.setActiveNetwork.bind(this),\n );\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/multichain-network-controller",
3
- "version": "0.3.0-preview-c555b24d",
3
+ "version": "0.3.0-preview-1634185",
4
4
  "description": "Multichain network controller",
5
5
  "keywords": [
6
6
  "MetaMask",