@metamask-previews/network-enablement-controller 0.1.1-preview-20c29407 → 0.1.1-preview-daea9b9c

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.
@@ -75,29 +75,37 @@ class NetworkEnablementController extends base_controller_1.BaseController {
75
75
  * Initializes the NetworkEnablementController by reading from NetworkController
76
76
  * state to populate enabled networks. Solana mainnet is always enabled by default.
77
77
  * This method should be called after NetworkController is initialized to avoid race conditions.
78
+ *
79
+ * This method preserves existing user preferences and only adds missing networks.
78
80
  */
79
81
  init() {
80
- // Create enabled map from controller states
81
- const enabledNetworkMap = {
82
- [utils_1.KnownCaipNamespace.Eip155]: {},
83
- [utils_1.KnownCaipNamespace.Solana]: {
84
- [types_1.SolScope.Mainnet]: true, // Always enable Solana mainnet
85
- },
86
- };
87
- // Get networks from NetworkController state
88
- try {
89
- const networkControllerState = this.messagingSystem.call('NetworkController:getState');
90
- Object.keys(networkControllerState.networkConfigurationsByChainId).forEach((chainId) => {
91
- enabledNetworkMap[utils_1.KnownCaipNamespace.Eip155][chainId] = true;
92
- });
93
- }
94
- catch {
95
- // Fallback: Keep Ethereum mainnet enabled if NetworkController is not available
96
- enabledNetworkMap[utils_1.KnownCaipNamespace.Eip155][controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.Mainnet]] = true;
97
- }
98
- // Update the state with networks from controller configurations
99
82
  this.update((state) => {
100
- state.enabledNetworkMap = enabledNetworkMap;
83
+ // Ensure required namespaces exist in the current state
84
+ __classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, state, utils_1.KnownCaipNamespace.Eip155);
85
+ __classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, state, utils_1.KnownCaipNamespace.Solana);
86
+ // Always ensure Solana mainnet is enabled
87
+ state.enabledNetworkMap[utils_1.KnownCaipNamespace.Solana][types_1.SolScope.Mainnet] =
88
+ true;
89
+ // Get networks from NetworkController state and add missing ones
90
+ try {
91
+ const networkControllerState = this.messagingSystem.call('NetworkController:getState');
92
+ Object.keys(networkControllerState.networkConfigurationsByChainId).forEach((chainId) => {
93
+ // Only add the network if it doesn't already exist in state
94
+ if (!(chainId in state.enabledNetworkMap[utils_1.KnownCaipNamespace.Eip155])) {
95
+ state.enabledNetworkMap[utils_1.KnownCaipNamespace.Eip155][chainId] =
96
+ true;
97
+ }
98
+ });
99
+ }
100
+ catch {
101
+ // Fallback: Ensure Ethereum mainnet is enabled if NetworkController is not available
102
+ // Only add if it doesn't already exist in state
103
+ const mainnetChainId = controller_utils_1.ChainId[controller_utils_1.BuiltInNetworkName.Mainnet];
104
+ if (!(mainnetChainId in state.enabledNetworkMap[utils_1.KnownCaipNamespace.Eip155])) {
105
+ state.enabledNetworkMap[utils_1.KnownCaipNamespace.Eip155][mainnetChainId] =
106
+ true;
107
+ }
108
+ }
101
109
  });
102
110
  }
103
111
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkEnablementController.cjs","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BuiltInNetworkName, ChainId } from '@metamask/controller-utils';\nimport type { MultichainNetworkControllerGetStateAction } from '@metamask/multichain-network-controller';\nimport type {\n NetworkControllerGetStateAction,\n NetworkControllerNetworkAddedEvent,\n NetworkControllerNetworkRemovedEvent,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport type { CaipChainId, CaipNamespace, Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport { SolScope } from './types';\nimport {\n deriveKeys,\n isOnlyNetworkEnabledInNamespace,\n isPopularNetwork,\n} from './utils';\n\nconst controllerName = 'NetworkEnablementController';\n\n/**\n * Information about an ordered network.\n */\nexport type NetworksInfo = {\n /**\n * The network's chain id\n */\n networkId: CaipChainId;\n};\n\n/**\n * A map of enabled networks by CAIP namespace and chain ID.\n * For EIP-155 networks, the keys are Hex chain IDs.\n * For other networks, the keys are CAIP chain IDs.\n */\ntype EnabledMap = Record<CaipNamespace, Record<CaipChainId | Hex, boolean>>;\n\n// State shape for NetworkEnablementController\nexport type NetworkEnablementControllerState = {\n enabledNetworkMap: EnabledMap;\n};\n\nexport type NetworkEnablementControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerSetEnabledNetworksAction = {\n type: `${typeof controllerName}:enableNetwork`;\n handler: NetworkEnablementController['enableNetwork'];\n};\n\nexport type NetworkEnablementControllerDisableNetworkAction = {\n type: `${typeof controllerName}:disableNetwork`;\n handler: NetworkEnablementController['disableNetwork'];\n};\n\n/**\n * All actions that {@link NetworkEnablementController} calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetStateAction\n | MultichainNetworkControllerGetStateAction;\n\nexport type NetworkEnablementControllerActions =\n | NetworkEnablementControllerGetStateAction\n | NetworkEnablementControllerSetEnabledNetworksAction\n | NetworkEnablementControllerDisableNetworkAction;\n\nexport type NetworkEnablementControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerEvents =\n NetworkEnablementControllerStateChangeEvent;\n\n/**\n * All events that {@link NetworkEnablementController} subscribes to internally.\n */\nexport type AllowedEvents =\n | NetworkControllerNetworkAddedEvent\n | NetworkControllerNetworkRemovedEvent\n | NetworkControllerStateChangeEvent;\n\nexport type NetworkEnablementControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n NetworkEnablementControllerActions | AllowedActions,\n NetworkEnablementControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Gets the initial default state for the NetworkEnablementController.\n * This provides a minimal state to avoid race conditions during initialization.\n *\n * @returns The initial default state with basic network enablement.\n */\nconst getDefaultNetworkEnablementControllerState =\n (): NetworkEnablementControllerState => ({\n enabledNetworkMap: {\n [KnownCaipNamespace.Eip155]: {\n [ChainId[BuiltInNetworkName.Mainnet]]: true,\n },\n [KnownCaipNamespace.Solana]: {\n [SolScope.Mainnet]: true,\n },\n },\n });\n\n// Metadata for the controller state\nconst metadata = {\n enabledNetworkMap: {\n persist: true,\n anonymous: true,\n },\n};\n\n/**\n * Controller responsible for managing network enablement state across different blockchain networks.\n *\n * This controller tracks which networks are enabled/disabled for the user and provides methods\n * to toggle network states. It supports both EVM (EIP-155) and non-EVM networks like Solana.\n *\n * The controller maintains a map of enabled networks organized by namespace (e.g., 'eip155', 'solana')\n * and provides methods to query and modify network enablement states.\n */\nexport class NetworkEnablementController extends BaseController<\n typeof controllerName,\n NetworkEnablementControllerState,\n NetworkEnablementControllerMessenger\n> {\n /**\n * Creates a NetworkEnablementController instance.\n *\n * @param args - The arguments to this function.\n * @param args.messenger - Messenger used to communicate with BaseV2 controller.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: NetworkEnablementControllerMessenger;\n state?: Partial<NetworkEnablementControllerState>;\n }) {\n super({\n messenger,\n metadata,\n name: controllerName,\n state: {\n ...getDefaultNetworkEnablementControllerState(),\n ...state,\n },\n });\n\n messenger.subscribe('NetworkController:networkAdded', ({ chainId }) => {\n this.#onAddNetwork(chainId);\n });\n\n messenger.subscribe('NetworkController:networkRemoved', ({ chainId }) => {\n this.#removeNetworkEntry(chainId);\n });\n }\n\n /**\n * Initializes the NetworkEnablementController by reading from NetworkController\n * state to populate enabled networks. Solana mainnet is always enabled by default.\n * This method should be called after NetworkController is initialized to avoid race conditions.\n */\n init(): void {\n // Create enabled map from controller states\n const enabledNetworkMap: EnabledMap = {\n [KnownCaipNamespace.Eip155]: {},\n [KnownCaipNamespace.Solana]: {\n [SolScope.Mainnet]: true, // Always enable Solana mainnet\n },\n };\n\n // Get networks from NetworkController state\n try {\n const networkControllerState = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n Object.keys(\n networkControllerState.networkConfigurationsByChainId,\n ).forEach((chainId) => {\n enabledNetworkMap[KnownCaipNamespace.Eip155][chainId as Hex] = true;\n });\n } catch {\n // Fallback: Keep Ethereum mainnet enabled if NetworkController is not available\n enabledNetworkMap[KnownCaipNamespace.Eip155][\n ChainId[BuiltInNetworkName.Mainnet]\n ] = true;\n }\n\n // Update the state with networks from controller configurations\n this.update((state) => {\n state.enabledNetworkMap = enabledNetworkMap;\n });\n }\n\n /**\n * Enables or disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally. This dual parameter support allows for backward\n * compatibility with existing EVM chain ID formats while supporting newer\n * multi-chain standards.\n *\n * When enabling a non-popular network, this method will disable all other networks\n * to ensure only one network is active at a time (exclusive mode).\n *\n * @param chainId - The chain ID of the network to enable or disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n enableNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n const isPopular = isPopularNetwork(reference);\n\n this.update((s) => {\n // if the namespace bucket does not exist, return\n // new nemespace are added only when a new network is added\n if (!s.enabledNetworkMap[namespace]) {\n return;\n }\n\n // If enabling a non-popular network, disable all networks in the same namespace\n if (!isPopular) {\n // disable all networks in the same namespace\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n } else {\n // disable all custom networks\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n const { reference: keyReference } = deriveKeys(key as CaipChainId);\n if (!isPopularNetwork(keyReference)) {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n }\n });\n }\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n\n /**\n * Disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally.\n *\n * Note: This method will prevent disabling the last remaining enabled network\n * to ensure at least one network is always available.\n *\n * @param chainId - The chain ID of the network to disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n disableNetwork(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n throw new Error('Cannot disable the last remaining enabled network');\n }\n\n this.update((s) => {\n s.enabledNetworkMap[namespace][storageKey] = false;\n });\n }\n\n /**\n * Checks if a network is enabled.\n *\n * @param chainId - The chain ID of the network to check. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n * @returns True if the network is enabled, false otherwise\n */\n isNetworkEnabled(chainId: Hex | CaipChainId): boolean {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n return this.state.enabledNetworkMap[namespace]?.[storageKey] ?? false;\n }\n\n /**\n * Ensures that a namespace bucket exists in the state.\n *\n * This method creates the namespace entry in the enabledNetworkMap if it doesn't\n * already exist. This is used to prepare the state structure before adding\n * network entries.\n *\n * @param state - The current controller state\n * @param ns - The CAIP namespace to ensure exists\n */\n #ensureNamespaceBucket(\n state: NetworkEnablementControllerState,\n ns: CaipNamespace,\n ) {\n if (!state.enabledNetworkMap[ns]) {\n state.enabledNetworkMap[ns] = {};\n }\n }\n\n /**\n * Removes a network entry from the state.\n *\n * This method is called when a network is removed from the system. It cleans up\n * the network entry and ensures that at least one network remains enabled.\n *\n * @param chainId - The chain ID to remove (Hex or CAIP-2 format)\n */\n #removeNetworkEntry(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n this.update((s) => {\n // fallback and enable ethereum mainnet\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n s.enabledNetworkMap[namespace][ChainId[BuiltInNetworkName.Mainnet]] =\n true;\n }\n\n if (namespace in s.enabledNetworkMap) {\n delete s.enabledNetworkMap[namespace][storageKey];\n }\n });\n }\n\n /**\n * Handles the addition of a new network to the controller.\n *\n * This method is called when a network is added to the system. It automatically\n * enables the new network and implements exclusive mode for non-popular networks.\n * If the network already exists, no changes are made.\n *\n * @param chainId - The chain ID of the network being added (Hex or CAIP-2 format)\n */\n #onAddNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n this.update((s) => {\n // Ensure the namespace bucket exists\n this.#ensureNamespaceBucket(s, namespace);\n\n // If adding a non-popular network, disable all other networks in the same namespace\n // This implements exclusive mode where only one non-popular network can be active\n if (!isPopularNetwork(reference)) {\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n }\n\n // Add the new network as enabled\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n}\n"]}
1
+ {"version":3,"file":"NetworkEnablementController.cjs","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BuiltInNetworkName, ChainId } from '@metamask/controller-utils';\nimport type { MultichainNetworkControllerGetStateAction } from '@metamask/multichain-network-controller';\nimport type {\n NetworkControllerGetStateAction,\n NetworkControllerNetworkAddedEvent,\n NetworkControllerNetworkRemovedEvent,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport type { CaipChainId, CaipNamespace, Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport { SolScope } from './types';\nimport {\n deriveKeys,\n isOnlyNetworkEnabledInNamespace,\n isPopularNetwork,\n} from './utils';\n\nconst controllerName = 'NetworkEnablementController';\n\n/**\n * Information about an ordered network.\n */\nexport type NetworksInfo = {\n /**\n * The network's chain id\n */\n networkId: CaipChainId;\n};\n\n/**\n * A map of enabled networks by CAIP namespace and chain ID.\n * For EIP-155 networks, the keys are Hex chain IDs.\n * For other networks, the keys are CAIP chain IDs.\n */\ntype EnabledMap = Record<CaipNamespace, Record<CaipChainId | Hex, boolean>>;\n\n// State shape for NetworkEnablementController\nexport type NetworkEnablementControllerState = {\n enabledNetworkMap: EnabledMap;\n};\n\nexport type NetworkEnablementControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerSetEnabledNetworksAction = {\n type: `${typeof controllerName}:enableNetwork`;\n handler: NetworkEnablementController['enableNetwork'];\n};\n\nexport type NetworkEnablementControllerDisableNetworkAction = {\n type: `${typeof controllerName}:disableNetwork`;\n handler: NetworkEnablementController['disableNetwork'];\n};\n\n/**\n * All actions that {@link NetworkEnablementController} calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetStateAction\n | MultichainNetworkControllerGetStateAction;\n\nexport type NetworkEnablementControllerActions =\n | NetworkEnablementControllerGetStateAction\n | NetworkEnablementControllerSetEnabledNetworksAction\n | NetworkEnablementControllerDisableNetworkAction;\n\nexport type NetworkEnablementControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerEvents =\n NetworkEnablementControllerStateChangeEvent;\n\n/**\n * All events that {@link NetworkEnablementController} subscribes to internally.\n */\nexport type AllowedEvents =\n | NetworkControllerNetworkAddedEvent\n | NetworkControllerNetworkRemovedEvent\n | NetworkControllerStateChangeEvent;\n\nexport type NetworkEnablementControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n NetworkEnablementControllerActions | AllowedActions,\n NetworkEnablementControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Gets the initial default state for the NetworkEnablementController.\n * This provides a minimal state to avoid race conditions during initialization.\n *\n * @returns The initial default state with basic network enablement.\n */\nconst getDefaultNetworkEnablementControllerState =\n (): NetworkEnablementControllerState => ({\n enabledNetworkMap: {\n [KnownCaipNamespace.Eip155]: {\n [ChainId[BuiltInNetworkName.Mainnet]]: true,\n },\n [KnownCaipNamespace.Solana]: {\n [SolScope.Mainnet]: true,\n },\n },\n });\n\n// Metadata for the controller state\nconst metadata = {\n enabledNetworkMap: {\n persist: true,\n anonymous: true,\n },\n};\n\n/**\n * Controller responsible for managing network enablement state across different blockchain networks.\n *\n * This controller tracks which networks are enabled/disabled for the user and provides methods\n * to toggle network states. It supports both EVM (EIP-155) and non-EVM networks like Solana.\n *\n * The controller maintains a map of enabled networks organized by namespace (e.g., 'eip155', 'solana')\n * and provides methods to query and modify network enablement states.\n */\nexport class NetworkEnablementController extends BaseController<\n typeof controllerName,\n NetworkEnablementControllerState,\n NetworkEnablementControllerMessenger\n> {\n /**\n * Creates a NetworkEnablementController instance.\n *\n * @param args - The arguments to this function.\n * @param args.messenger - Messenger used to communicate with BaseV2 controller.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: NetworkEnablementControllerMessenger;\n state?: Partial<NetworkEnablementControllerState>;\n }) {\n super({\n messenger,\n metadata,\n name: controllerName,\n state: {\n ...getDefaultNetworkEnablementControllerState(),\n ...state,\n },\n });\n\n messenger.subscribe('NetworkController:networkAdded', ({ chainId }) => {\n this.#onAddNetwork(chainId);\n });\n\n messenger.subscribe('NetworkController:networkRemoved', ({ chainId }) => {\n this.#removeNetworkEntry(chainId);\n });\n }\n\n /**\n * Initializes the NetworkEnablementController by reading from NetworkController\n * state to populate enabled networks. Solana mainnet is always enabled by default.\n * This method should be called after NetworkController is initialized to avoid race conditions.\n *\n * This method preserves existing user preferences and only adds missing networks.\n */\n init(): void {\n this.update((state) => {\n // Ensure required namespaces exist in the current state\n this.#ensureNamespaceBucket(state, KnownCaipNamespace.Eip155);\n this.#ensureNamespaceBucket(state, KnownCaipNamespace.Solana);\n\n // Always ensure Solana mainnet is enabled\n state.enabledNetworkMap[KnownCaipNamespace.Solana][SolScope.Mainnet] =\n true;\n\n // Get networks from NetworkController state and add missing ones\n try {\n const networkControllerState = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n Object.keys(\n networkControllerState.networkConfigurationsByChainId,\n ).forEach((chainId) => {\n // Only add the network if it doesn't already exist in state\n if (\n !(chainId in state.enabledNetworkMap[KnownCaipNamespace.Eip155])\n ) {\n state.enabledNetworkMap[KnownCaipNamespace.Eip155][chainId as Hex] =\n true;\n }\n });\n } catch {\n // Fallback: Ensure Ethereum mainnet is enabled if NetworkController is not available\n // Only add if it doesn't already exist in state\n const mainnetChainId = ChainId[BuiltInNetworkName.Mainnet];\n if (\n !(\n mainnetChainId in state.enabledNetworkMap[KnownCaipNamespace.Eip155]\n )\n ) {\n state.enabledNetworkMap[KnownCaipNamespace.Eip155][mainnetChainId] =\n true;\n }\n }\n });\n }\n\n /**\n * Enables or disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally. This dual parameter support allows for backward\n * compatibility with existing EVM chain ID formats while supporting newer\n * multi-chain standards.\n *\n * When enabling a non-popular network, this method will disable all other networks\n * to ensure only one network is active at a time (exclusive mode).\n *\n * @param chainId - The chain ID of the network to enable or disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n enableNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n const isPopular = isPopularNetwork(reference);\n\n this.update((s) => {\n // if the namespace bucket does not exist, return\n // new nemespace are added only when a new network is added\n if (!s.enabledNetworkMap[namespace]) {\n return;\n }\n\n // If enabling a non-popular network, disable all networks in the same namespace\n if (!isPopular) {\n // disable all networks in the same namespace\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n } else {\n // disable all custom networks\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n const { reference: keyReference } = deriveKeys(key as CaipChainId);\n if (!isPopularNetwork(keyReference)) {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n }\n });\n }\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n\n /**\n * Disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally.\n *\n * Note: This method will prevent disabling the last remaining enabled network\n * to ensure at least one network is always available.\n *\n * @param chainId - The chain ID of the network to disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n disableNetwork(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n throw new Error('Cannot disable the last remaining enabled network');\n }\n\n this.update((s) => {\n s.enabledNetworkMap[namespace][storageKey] = false;\n });\n }\n\n /**\n * Checks if a network is enabled.\n *\n * @param chainId - The chain ID of the network to check. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n * @returns True if the network is enabled, false otherwise\n */\n isNetworkEnabled(chainId: Hex | CaipChainId): boolean {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n return this.state.enabledNetworkMap[namespace]?.[storageKey] ?? false;\n }\n\n /**\n * Ensures that a namespace bucket exists in the state.\n *\n * This method creates the namespace entry in the enabledNetworkMap if it doesn't\n * already exist. This is used to prepare the state structure before adding\n * network entries.\n *\n * @param state - The current controller state\n * @param ns - The CAIP namespace to ensure exists\n */\n #ensureNamespaceBucket(\n state: NetworkEnablementControllerState,\n ns: CaipNamespace,\n ) {\n if (!state.enabledNetworkMap[ns]) {\n state.enabledNetworkMap[ns] = {};\n }\n }\n\n /**\n * Removes a network entry from the state.\n *\n * This method is called when a network is removed from the system. It cleans up\n * the network entry and ensures that at least one network remains enabled.\n *\n * @param chainId - The chain ID to remove (Hex or CAIP-2 format)\n */\n #removeNetworkEntry(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n this.update((s) => {\n // fallback and enable ethereum mainnet\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n s.enabledNetworkMap[namespace][ChainId[BuiltInNetworkName.Mainnet]] =\n true;\n }\n\n if (namespace in s.enabledNetworkMap) {\n delete s.enabledNetworkMap[namespace][storageKey];\n }\n });\n }\n\n /**\n * Handles the addition of a new network to the controller.\n *\n * This method is called when a network is added to the system. It automatically\n * enables the new network and implements exclusive mode for non-popular networks.\n * If the network already exists, no changes are made.\n *\n * @param chainId - The chain ID of the network being added (Hex or CAIP-2 format)\n */\n #onAddNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n this.update((s) => {\n // Ensure the namespace bucket exists\n this.#ensureNamespaceBucket(s, namespace);\n\n // If adding a non-popular network, disable all other networks in the same namespace\n // This implements exclusive mode where only one non-popular network can be active\n if (!isPopularNetwork(reference)) {\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n }\n\n // Add the new network as enabled\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n}\n"]}
@@ -69,6 +69,8 @@ export declare class NetworkEnablementController extends BaseController<typeof c
69
69
  * Initializes the NetworkEnablementController by reading from NetworkController
70
70
  * state to populate enabled networks. Solana mainnet is always enabled by default.
71
71
  * This method should be called after NetworkController is initialized to avoid race conditions.
72
+ *
73
+ * This method preserves existing user preferences and only adds missing networks.
72
74
  */
73
75
  init(): void;
74
76
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkEnablementController.d.cts","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AAEnC,OAAO,KAAK,EAAE,yCAAyC,EAAE,gDAAgD;AACzG,OAAO,KAAK,EACV,+BAA+B,EAC/B,kCAAkC,EAClC,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAUvE,QAAA,MAAM,cAAc,gCAAgC,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAG5E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,iBAAiB,EAAE,UAAU,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,mDAAmD,GAAG;IAChE,IAAI,EAAE,GAAG,OAAO,cAAc,gBAAgB,CAAC;IAC/C,OAAO,EAAE,2BAA2B,CAAC,eAAe,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,+CAA+C,GAAG;IAC5D,IAAI,EAAE,GAAG,OAAO,cAAc,iBAAiB,CAAC;IAChD,OAAO,EAAE,2BAA2B,CAAC,gBAAgB,CAAC,CAAC;CACxD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,+BAA+B,GAC/B,yCAAyC,CAAC;AAE9C,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,mDAAmD,GACnD,+CAA+C,CAAC;AAEpD,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,kCAAkC,GAClC,oCAAoC,GACpC,iCAAiC,CAAC;AAEtC,MAAM,MAAM,oCAAoC,GAAG,mBAAmB,CACpE,OAAO,cAAc,EACrB,kCAAkC,GAAG,cAAc,EACnD,iCAAiC,GAAG,aAAa,EACjD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AA4BF;;;;;;;;GAQG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IACC;;;;;;OAMG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;KACnD;IAoBD;;;;OAIG;IACH,IAAI,IAAI,IAAI;IAgCZ;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IA+B/C;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IAahD;;;;;;;OAOG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,OAAO;CA8EtD"}
1
+ {"version":3,"file":"NetworkEnablementController.d.cts","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AAEnC,OAAO,KAAK,EAAE,yCAAyC,EAAE,gDAAgD;AACzG,OAAO,KAAK,EACV,+BAA+B,EAC/B,kCAAkC,EAClC,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAUvE,QAAA,MAAM,cAAc,gCAAgC,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAG5E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,iBAAiB,EAAE,UAAU,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,mDAAmD,GAAG;IAChE,IAAI,EAAE,GAAG,OAAO,cAAc,gBAAgB,CAAC;IAC/C,OAAO,EAAE,2BAA2B,CAAC,eAAe,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,+CAA+C,GAAG;IAC5D,IAAI,EAAE,GAAG,OAAO,cAAc,iBAAiB,CAAC;IAChD,OAAO,EAAE,2BAA2B,CAAC,gBAAgB,CAAC,CAAC;CACxD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,+BAA+B,GAC/B,yCAAyC,CAAC;AAE9C,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,mDAAmD,GACnD,+CAA+C,CAAC;AAEpD,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,kCAAkC,GAClC,oCAAoC,GACpC,iCAAiC,CAAC;AAEtC,MAAM,MAAM,oCAAoC,GAAG,mBAAmB,CACpE,OAAO,cAAc,EACrB,kCAAkC,GAAG,cAAc,EACnD,iCAAiC,GAAG,aAAa,EACjD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AA4BF;;;;;;;;GAQG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IACC;;;;;;OAMG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;KACnD;IAoBD;;;;;;OAMG;IACH,IAAI,IAAI,IAAI;IA0CZ;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IA+B/C;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IAahD;;;;;;;OAOG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,OAAO;CA8EtD"}
@@ -69,6 +69,8 @@ export declare class NetworkEnablementController extends BaseController<typeof c
69
69
  * Initializes the NetworkEnablementController by reading from NetworkController
70
70
  * state to populate enabled networks. Solana mainnet is always enabled by default.
71
71
  * This method should be called after NetworkController is initialized to avoid race conditions.
72
+ *
73
+ * This method preserves existing user preferences and only adds missing networks.
72
74
  */
73
75
  init(): void;
74
76
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkEnablementController.d.mts","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AAEnC,OAAO,KAAK,EAAE,yCAAyC,EAAE,gDAAgD;AACzG,OAAO,KAAK,EACV,+BAA+B,EAC/B,kCAAkC,EAClC,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAUvE,QAAA,MAAM,cAAc,gCAAgC,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAG5E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,iBAAiB,EAAE,UAAU,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,mDAAmD,GAAG;IAChE,IAAI,EAAE,GAAG,OAAO,cAAc,gBAAgB,CAAC;IAC/C,OAAO,EAAE,2BAA2B,CAAC,eAAe,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,+CAA+C,GAAG;IAC5D,IAAI,EAAE,GAAG,OAAO,cAAc,iBAAiB,CAAC;IAChD,OAAO,EAAE,2BAA2B,CAAC,gBAAgB,CAAC,CAAC;CACxD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,+BAA+B,GAC/B,yCAAyC,CAAC;AAE9C,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,mDAAmD,GACnD,+CAA+C,CAAC;AAEpD,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,kCAAkC,GAClC,oCAAoC,GACpC,iCAAiC,CAAC;AAEtC,MAAM,MAAM,oCAAoC,GAAG,mBAAmB,CACpE,OAAO,cAAc,EACrB,kCAAkC,GAAG,cAAc,EACnD,iCAAiC,GAAG,aAAa,EACjD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AA4BF;;;;;;;;GAQG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IACC;;;;;;OAMG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;KACnD;IAoBD;;;;OAIG;IACH,IAAI,IAAI,IAAI;IAgCZ;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IA+B/C;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IAahD;;;;;;;OAOG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,OAAO;CA8EtD"}
1
+ {"version":3,"file":"NetworkEnablementController.d.mts","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AAEnC,OAAO,KAAK,EAAE,yCAAyC,EAAE,gDAAgD;AACzG,OAAO,KAAK,EACV,+BAA+B,EAC/B,kCAAkC,EAClC,oCAAoC,EACpC,iCAAiC,EAClC,qCAAqC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAUvE,QAAA,MAAM,cAAc,gCAAgC,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAG5E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,iBAAiB,EAAE,UAAU,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,mDAAmD,GAAG;IAChE,IAAI,EAAE,GAAG,OAAO,cAAc,gBAAgB,CAAC;IAC/C,OAAO,EAAE,2BAA2B,CAAC,eAAe,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,+CAA+C,GAAG;IAC5D,IAAI,EAAE,GAAG,OAAO,cAAc,iBAAiB,CAAC;IAChD,OAAO,EAAE,2BAA2B,CAAC,gBAAgB,CAAC,CAAC;CACxD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,+BAA+B,GAC/B,yCAAyC,CAAC;AAE9C,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,mDAAmD,GACnD,+CAA+C,CAAC;AAEpD,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,kCAAkC,GAClC,oCAAoC,GACpC,iCAAiC,CAAC;AAEtC,MAAM,MAAM,oCAAoC,GAAG,mBAAmB,CACpE,OAAO,cAAc,EACrB,kCAAkC,GAAG,cAAc,EACnD,iCAAiC,GAAG,aAAa,EACjD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AA4BF;;;;;;;;GAQG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IACC;;;;;;OAMG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;KACnD;IAoBD;;;;;;OAMG;IACH,IAAI,IAAI,IAAI;IA0CZ;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IA+B/C;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,IAAI;IAahD;;;;;;;OAOG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAG,OAAO;CA8EtD"}
@@ -72,29 +72,37 @@ export class NetworkEnablementController extends BaseController {
72
72
  * Initializes the NetworkEnablementController by reading from NetworkController
73
73
  * state to populate enabled networks. Solana mainnet is always enabled by default.
74
74
  * This method should be called after NetworkController is initialized to avoid race conditions.
75
+ *
76
+ * This method preserves existing user preferences and only adds missing networks.
75
77
  */
76
78
  init() {
77
- // Create enabled map from controller states
78
- const enabledNetworkMap = {
79
- [KnownCaipNamespace.Eip155]: {},
80
- [KnownCaipNamespace.Solana]: {
81
- [SolScope.Mainnet]: true, // Always enable Solana mainnet
82
- },
83
- };
84
- // Get networks from NetworkController state
85
- try {
86
- const networkControllerState = this.messagingSystem.call('NetworkController:getState');
87
- Object.keys(networkControllerState.networkConfigurationsByChainId).forEach((chainId) => {
88
- enabledNetworkMap[KnownCaipNamespace.Eip155][chainId] = true;
89
- });
90
- }
91
- catch {
92
- // Fallback: Keep Ethereum mainnet enabled if NetworkController is not available
93
- enabledNetworkMap[KnownCaipNamespace.Eip155][ChainId[BuiltInNetworkName.Mainnet]] = true;
94
- }
95
- // Update the state with networks from controller configurations
96
79
  this.update((state) => {
97
- state.enabledNetworkMap = enabledNetworkMap;
80
+ // Ensure required namespaces exist in the current state
81
+ __classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, state, KnownCaipNamespace.Eip155);
82
+ __classPrivateFieldGet(this, _NetworkEnablementController_instances, "m", _NetworkEnablementController_ensureNamespaceBucket).call(this, state, KnownCaipNamespace.Solana);
83
+ // Always ensure Solana mainnet is enabled
84
+ state.enabledNetworkMap[KnownCaipNamespace.Solana][SolScope.Mainnet] =
85
+ true;
86
+ // Get networks from NetworkController state and add missing ones
87
+ try {
88
+ const networkControllerState = this.messagingSystem.call('NetworkController:getState');
89
+ Object.keys(networkControllerState.networkConfigurationsByChainId).forEach((chainId) => {
90
+ // Only add the network if it doesn't already exist in state
91
+ if (!(chainId in state.enabledNetworkMap[KnownCaipNamespace.Eip155])) {
92
+ state.enabledNetworkMap[KnownCaipNamespace.Eip155][chainId] =
93
+ true;
94
+ }
95
+ });
96
+ }
97
+ catch {
98
+ // Fallback: Ensure Ethereum mainnet is enabled if NetworkController is not available
99
+ // Only add if it doesn't already exist in state
100
+ const mainnetChainId = ChainId[BuiltInNetworkName.Mainnet];
101
+ if (!(mainnetChainId in state.enabledNetworkMap[KnownCaipNamespace.Eip155])) {
102
+ state.enabledNetworkMap[KnownCaipNamespace.Eip155][mainnetChainId] =
103
+ true;
104
+ }
105
+ }
98
106
  });
99
107
  }
100
108
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkEnablementController.mjs","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BuiltInNetworkName, ChainId } from '@metamask/controller-utils';\nimport type { MultichainNetworkControllerGetStateAction } from '@metamask/multichain-network-controller';\nimport type {\n NetworkControllerGetStateAction,\n NetworkControllerNetworkAddedEvent,\n NetworkControllerNetworkRemovedEvent,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport type { CaipChainId, CaipNamespace, Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport { SolScope } from './types';\nimport {\n deriveKeys,\n isOnlyNetworkEnabledInNamespace,\n isPopularNetwork,\n} from './utils';\n\nconst controllerName = 'NetworkEnablementController';\n\n/**\n * Information about an ordered network.\n */\nexport type NetworksInfo = {\n /**\n * The network's chain id\n */\n networkId: CaipChainId;\n};\n\n/**\n * A map of enabled networks by CAIP namespace and chain ID.\n * For EIP-155 networks, the keys are Hex chain IDs.\n * For other networks, the keys are CAIP chain IDs.\n */\ntype EnabledMap = Record<CaipNamespace, Record<CaipChainId | Hex, boolean>>;\n\n// State shape for NetworkEnablementController\nexport type NetworkEnablementControllerState = {\n enabledNetworkMap: EnabledMap;\n};\n\nexport type NetworkEnablementControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerSetEnabledNetworksAction = {\n type: `${typeof controllerName}:enableNetwork`;\n handler: NetworkEnablementController['enableNetwork'];\n};\n\nexport type NetworkEnablementControllerDisableNetworkAction = {\n type: `${typeof controllerName}:disableNetwork`;\n handler: NetworkEnablementController['disableNetwork'];\n};\n\n/**\n * All actions that {@link NetworkEnablementController} calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetStateAction\n | MultichainNetworkControllerGetStateAction;\n\nexport type NetworkEnablementControllerActions =\n | NetworkEnablementControllerGetStateAction\n | NetworkEnablementControllerSetEnabledNetworksAction\n | NetworkEnablementControllerDisableNetworkAction;\n\nexport type NetworkEnablementControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerEvents =\n NetworkEnablementControllerStateChangeEvent;\n\n/**\n * All events that {@link NetworkEnablementController} subscribes to internally.\n */\nexport type AllowedEvents =\n | NetworkControllerNetworkAddedEvent\n | NetworkControllerNetworkRemovedEvent\n | NetworkControllerStateChangeEvent;\n\nexport type NetworkEnablementControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n NetworkEnablementControllerActions | AllowedActions,\n NetworkEnablementControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Gets the initial default state for the NetworkEnablementController.\n * This provides a minimal state to avoid race conditions during initialization.\n *\n * @returns The initial default state with basic network enablement.\n */\nconst getDefaultNetworkEnablementControllerState =\n (): NetworkEnablementControllerState => ({\n enabledNetworkMap: {\n [KnownCaipNamespace.Eip155]: {\n [ChainId[BuiltInNetworkName.Mainnet]]: true,\n },\n [KnownCaipNamespace.Solana]: {\n [SolScope.Mainnet]: true,\n },\n },\n });\n\n// Metadata for the controller state\nconst metadata = {\n enabledNetworkMap: {\n persist: true,\n anonymous: true,\n },\n};\n\n/**\n * Controller responsible for managing network enablement state across different blockchain networks.\n *\n * This controller tracks which networks are enabled/disabled for the user and provides methods\n * to toggle network states. It supports both EVM (EIP-155) and non-EVM networks like Solana.\n *\n * The controller maintains a map of enabled networks organized by namespace (e.g., 'eip155', 'solana')\n * and provides methods to query and modify network enablement states.\n */\nexport class NetworkEnablementController extends BaseController<\n typeof controllerName,\n NetworkEnablementControllerState,\n NetworkEnablementControllerMessenger\n> {\n /**\n * Creates a NetworkEnablementController instance.\n *\n * @param args - The arguments to this function.\n * @param args.messenger - Messenger used to communicate with BaseV2 controller.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: NetworkEnablementControllerMessenger;\n state?: Partial<NetworkEnablementControllerState>;\n }) {\n super({\n messenger,\n metadata,\n name: controllerName,\n state: {\n ...getDefaultNetworkEnablementControllerState(),\n ...state,\n },\n });\n\n messenger.subscribe('NetworkController:networkAdded', ({ chainId }) => {\n this.#onAddNetwork(chainId);\n });\n\n messenger.subscribe('NetworkController:networkRemoved', ({ chainId }) => {\n this.#removeNetworkEntry(chainId);\n });\n }\n\n /**\n * Initializes the NetworkEnablementController by reading from NetworkController\n * state to populate enabled networks. Solana mainnet is always enabled by default.\n * This method should be called after NetworkController is initialized to avoid race conditions.\n */\n init(): void {\n // Create enabled map from controller states\n const enabledNetworkMap: EnabledMap = {\n [KnownCaipNamespace.Eip155]: {},\n [KnownCaipNamespace.Solana]: {\n [SolScope.Mainnet]: true, // Always enable Solana mainnet\n },\n };\n\n // Get networks from NetworkController state\n try {\n const networkControllerState = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n Object.keys(\n networkControllerState.networkConfigurationsByChainId,\n ).forEach((chainId) => {\n enabledNetworkMap[KnownCaipNamespace.Eip155][chainId as Hex] = true;\n });\n } catch {\n // Fallback: Keep Ethereum mainnet enabled if NetworkController is not available\n enabledNetworkMap[KnownCaipNamespace.Eip155][\n ChainId[BuiltInNetworkName.Mainnet]\n ] = true;\n }\n\n // Update the state with networks from controller configurations\n this.update((state) => {\n state.enabledNetworkMap = enabledNetworkMap;\n });\n }\n\n /**\n * Enables or disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally. This dual parameter support allows for backward\n * compatibility with existing EVM chain ID formats while supporting newer\n * multi-chain standards.\n *\n * When enabling a non-popular network, this method will disable all other networks\n * to ensure only one network is active at a time (exclusive mode).\n *\n * @param chainId - The chain ID of the network to enable or disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n enableNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n const isPopular = isPopularNetwork(reference);\n\n this.update((s) => {\n // if the namespace bucket does not exist, return\n // new nemespace are added only when a new network is added\n if (!s.enabledNetworkMap[namespace]) {\n return;\n }\n\n // If enabling a non-popular network, disable all networks in the same namespace\n if (!isPopular) {\n // disable all networks in the same namespace\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n } else {\n // disable all custom networks\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n const { reference: keyReference } = deriveKeys(key as CaipChainId);\n if (!isPopularNetwork(keyReference)) {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n }\n });\n }\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n\n /**\n * Disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally.\n *\n * Note: This method will prevent disabling the last remaining enabled network\n * to ensure at least one network is always available.\n *\n * @param chainId - The chain ID of the network to disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n disableNetwork(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n throw new Error('Cannot disable the last remaining enabled network');\n }\n\n this.update((s) => {\n s.enabledNetworkMap[namespace][storageKey] = false;\n });\n }\n\n /**\n * Checks if a network is enabled.\n *\n * @param chainId - The chain ID of the network to check. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n * @returns True if the network is enabled, false otherwise\n */\n isNetworkEnabled(chainId: Hex | CaipChainId): boolean {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n return this.state.enabledNetworkMap[namespace]?.[storageKey] ?? false;\n }\n\n /**\n * Ensures that a namespace bucket exists in the state.\n *\n * This method creates the namespace entry in the enabledNetworkMap if it doesn't\n * already exist. This is used to prepare the state structure before adding\n * network entries.\n *\n * @param state - The current controller state\n * @param ns - The CAIP namespace to ensure exists\n */\n #ensureNamespaceBucket(\n state: NetworkEnablementControllerState,\n ns: CaipNamespace,\n ) {\n if (!state.enabledNetworkMap[ns]) {\n state.enabledNetworkMap[ns] = {};\n }\n }\n\n /**\n * Removes a network entry from the state.\n *\n * This method is called when a network is removed from the system. It cleans up\n * the network entry and ensures that at least one network remains enabled.\n *\n * @param chainId - The chain ID to remove (Hex or CAIP-2 format)\n */\n #removeNetworkEntry(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n this.update((s) => {\n // fallback and enable ethereum mainnet\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n s.enabledNetworkMap[namespace][ChainId[BuiltInNetworkName.Mainnet]] =\n true;\n }\n\n if (namespace in s.enabledNetworkMap) {\n delete s.enabledNetworkMap[namespace][storageKey];\n }\n });\n }\n\n /**\n * Handles the addition of a new network to the controller.\n *\n * This method is called when a network is added to the system. It automatically\n * enables the new network and implements exclusive mode for non-popular networks.\n * If the network already exists, no changes are made.\n *\n * @param chainId - The chain ID of the network being added (Hex or CAIP-2 format)\n */\n #onAddNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n this.update((s) => {\n // Ensure the namespace bucket exists\n this.#ensureNamespaceBucket(s, namespace);\n\n // If adding a non-popular network, disable all other networks in the same namespace\n // This implements exclusive mode where only one non-popular network can be active\n if (!isPopularNetwork(reference)) {\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n }\n\n // Add the new network as enabled\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n}\n"]}
1
+ {"version":3,"file":"NetworkEnablementController.mjs","sourceRoot":"","sources":["../src/NetworkEnablementController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BuiltInNetworkName, ChainId } from '@metamask/controller-utils';\nimport type { MultichainNetworkControllerGetStateAction } from '@metamask/multichain-network-controller';\nimport type {\n NetworkControllerGetStateAction,\n NetworkControllerNetworkAddedEvent,\n NetworkControllerNetworkRemovedEvent,\n NetworkControllerStateChangeEvent,\n} from '@metamask/network-controller';\nimport type { CaipChainId, CaipNamespace, Hex } from '@metamask/utils';\nimport { KnownCaipNamespace } from '@metamask/utils';\n\nimport { SolScope } from './types';\nimport {\n deriveKeys,\n isOnlyNetworkEnabledInNamespace,\n isPopularNetwork,\n} from './utils';\n\nconst controllerName = 'NetworkEnablementController';\n\n/**\n * Information about an ordered network.\n */\nexport type NetworksInfo = {\n /**\n * The network's chain id\n */\n networkId: CaipChainId;\n};\n\n/**\n * A map of enabled networks by CAIP namespace and chain ID.\n * For EIP-155 networks, the keys are Hex chain IDs.\n * For other networks, the keys are CAIP chain IDs.\n */\ntype EnabledMap = Record<CaipNamespace, Record<CaipChainId | Hex, boolean>>;\n\n// State shape for NetworkEnablementController\nexport type NetworkEnablementControllerState = {\n enabledNetworkMap: EnabledMap;\n};\n\nexport type NetworkEnablementControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerSetEnabledNetworksAction = {\n type: `${typeof controllerName}:enableNetwork`;\n handler: NetworkEnablementController['enableNetwork'];\n};\n\nexport type NetworkEnablementControllerDisableNetworkAction = {\n type: `${typeof controllerName}:disableNetwork`;\n handler: NetworkEnablementController['disableNetwork'];\n};\n\n/**\n * All actions that {@link NetworkEnablementController} calls internally.\n */\nexport type AllowedActions =\n | NetworkControllerGetStateAction\n | MultichainNetworkControllerGetStateAction;\n\nexport type NetworkEnablementControllerActions =\n | NetworkEnablementControllerGetStateAction\n | NetworkEnablementControllerSetEnabledNetworksAction\n | NetworkEnablementControllerDisableNetworkAction;\n\nexport type NetworkEnablementControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n NetworkEnablementControllerState\n >;\n\nexport type NetworkEnablementControllerEvents =\n NetworkEnablementControllerStateChangeEvent;\n\n/**\n * All events that {@link NetworkEnablementController} subscribes to internally.\n */\nexport type AllowedEvents =\n | NetworkControllerNetworkAddedEvent\n | NetworkControllerNetworkRemovedEvent\n | NetworkControllerStateChangeEvent;\n\nexport type NetworkEnablementControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n NetworkEnablementControllerActions | AllowedActions,\n NetworkEnablementControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Gets the initial default state for the NetworkEnablementController.\n * This provides a minimal state to avoid race conditions during initialization.\n *\n * @returns The initial default state with basic network enablement.\n */\nconst getDefaultNetworkEnablementControllerState =\n (): NetworkEnablementControllerState => ({\n enabledNetworkMap: {\n [KnownCaipNamespace.Eip155]: {\n [ChainId[BuiltInNetworkName.Mainnet]]: true,\n },\n [KnownCaipNamespace.Solana]: {\n [SolScope.Mainnet]: true,\n },\n },\n });\n\n// Metadata for the controller state\nconst metadata = {\n enabledNetworkMap: {\n persist: true,\n anonymous: true,\n },\n};\n\n/**\n * Controller responsible for managing network enablement state across different blockchain networks.\n *\n * This controller tracks which networks are enabled/disabled for the user and provides methods\n * to toggle network states. It supports both EVM (EIP-155) and non-EVM networks like Solana.\n *\n * The controller maintains a map of enabled networks organized by namespace (e.g., 'eip155', 'solana')\n * and provides methods to query and modify network enablement states.\n */\nexport class NetworkEnablementController extends BaseController<\n typeof controllerName,\n NetworkEnablementControllerState,\n NetworkEnablementControllerMessenger\n> {\n /**\n * Creates a NetworkEnablementController instance.\n *\n * @param args - The arguments to this function.\n * @param args.messenger - Messenger used to communicate with BaseV2 controller.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: NetworkEnablementControllerMessenger;\n state?: Partial<NetworkEnablementControllerState>;\n }) {\n super({\n messenger,\n metadata,\n name: controllerName,\n state: {\n ...getDefaultNetworkEnablementControllerState(),\n ...state,\n },\n });\n\n messenger.subscribe('NetworkController:networkAdded', ({ chainId }) => {\n this.#onAddNetwork(chainId);\n });\n\n messenger.subscribe('NetworkController:networkRemoved', ({ chainId }) => {\n this.#removeNetworkEntry(chainId);\n });\n }\n\n /**\n * Initializes the NetworkEnablementController by reading from NetworkController\n * state to populate enabled networks. Solana mainnet is always enabled by default.\n * This method should be called after NetworkController is initialized to avoid race conditions.\n *\n * This method preserves existing user preferences and only adds missing networks.\n */\n init(): void {\n this.update((state) => {\n // Ensure required namespaces exist in the current state\n this.#ensureNamespaceBucket(state, KnownCaipNamespace.Eip155);\n this.#ensureNamespaceBucket(state, KnownCaipNamespace.Solana);\n\n // Always ensure Solana mainnet is enabled\n state.enabledNetworkMap[KnownCaipNamespace.Solana][SolScope.Mainnet] =\n true;\n\n // Get networks from NetworkController state and add missing ones\n try {\n const networkControllerState = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n Object.keys(\n networkControllerState.networkConfigurationsByChainId,\n ).forEach((chainId) => {\n // Only add the network if it doesn't already exist in state\n if (\n !(chainId in state.enabledNetworkMap[KnownCaipNamespace.Eip155])\n ) {\n state.enabledNetworkMap[KnownCaipNamespace.Eip155][chainId as Hex] =\n true;\n }\n });\n } catch {\n // Fallback: Ensure Ethereum mainnet is enabled if NetworkController is not available\n // Only add if it doesn't already exist in state\n const mainnetChainId = ChainId[BuiltInNetworkName.Mainnet];\n if (\n !(\n mainnetChainId in state.enabledNetworkMap[KnownCaipNamespace.Eip155]\n )\n ) {\n state.enabledNetworkMap[KnownCaipNamespace.Eip155][mainnetChainId] =\n true;\n }\n }\n });\n }\n\n /**\n * Enables or disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally. This dual parameter support allows for backward\n * compatibility with existing EVM chain ID formats while supporting newer\n * multi-chain standards.\n *\n * When enabling a non-popular network, this method will disable all other networks\n * to ensure only one network is active at a time (exclusive mode).\n *\n * @param chainId - The chain ID of the network to enable or disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n enableNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n const isPopular = isPopularNetwork(reference);\n\n this.update((s) => {\n // if the namespace bucket does not exist, return\n // new nemespace are added only when a new network is added\n if (!s.enabledNetworkMap[namespace]) {\n return;\n }\n\n // If enabling a non-popular network, disable all networks in the same namespace\n if (!isPopular) {\n // disable all networks in the same namespace\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n } else {\n // disable all custom networks\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n const { reference: keyReference } = deriveKeys(key as CaipChainId);\n if (!isPopularNetwork(keyReference)) {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n }\n });\n }\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n\n /**\n * Disables a network for the user.\n *\n * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID\n * (for any blockchain network). The method will automatically convert Hex chain IDs\n * to CAIP-2 format internally.\n *\n * Note: This method will prevent disabling the last remaining enabled network\n * to ensure at least one network is always available.\n *\n * @param chainId - The chain ID of the network to disable. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n */\n disableNetwork(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n throw new Error('Cannot disable the last remaining enabled network');\n }\n\n this.update((s) => {\n s.enabledNetworkMap[namespace][storageKey] = false;\n });\n }\n\n /**\n * Checks if a network is enabled.\n *\n * @param chainId - The chain ID of the network to check. Can be either:\n * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks\n * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana)\n * @returns True if the network is enabled, false otherwise\n */\n isNetworkEnabled(chainId: Hex | CaipChainId): boolean {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n return this.state.enabledNetworkMap[namespace]?.[storageKey] ?? false;\n }\n\n /**\n * Ensures that a namespace bucket exists in the state.\n *\n * This method creates the namespace entry in the enabledNetworkMap if it doesn't\n * already exist. This is used to prepare the state structure before adding\n * network entries.\n *\n * @param state - The current controller state\n * @param ns - The CAIP namespace to ensure exists\n */\n #ensureNamespaceBucket(\n state: NetworkEnablementControllerState,\n ns: CaipNamespace,\n ) {\n if (!state.enabledNetworkMap[ns]) {\n state.enabledNetworkMap[ns] = {};\n }\n }\n\n /**\n * Removes a network entry from the state.\n *\n * This method is called when a network is removed from the system. It cleans up\n * the network entry and ensures that at least one network remains enabled.\n *\n * @param chainId - The chain ID to remove (Hex or CAIP-2 format)\n */\n #removeNetworkEntry(chainId: Hex | CaipChainId): void {\n const derivedKeys = deriveKeys(chainId);\n const { namespace, storageKey } = derivedKeys;\n\n this.update((s) => {\n // fallback and enable ethereum mainnet\n if (isOnlyNetworkEnabledInNamespace(this.state, derivedKeys)) {\n s.enabledNetworkMap[namespace][ChainId[BuiltInNetworkName.Mainnet]] =\n true;\n }\n\n if (namespace in s.enabledNetworkMap) {\n delete s.enabledNetworkMap[namespace][storageKey];\n }\n });\n }\n\n /**\n * Handles the addition of a new network to the controller.\n *\n * This method is called when a network is added to the system. It automatically\n * enables the new network and implements exclusive mode for non-popular networks.\n * If the network already exists, no changes are made.\n *\n * @param chainId - The chain ID of the network being added (Hex or CAIP-2 format)\n */\n #onAddNetwork(chainId: Hex | CaipChainId): void {\n const { namespace, storageKey, reference } = deriveKeys(chainId);\n\n this.update((s) => {\n // Ensure the namespace bucket exists\n this.#ensureNamespaceBucket(s, namespace);\n\n // If adding a non-popular network, disable all other networks in the same namespace\n // This implements exclusive mode where only one non-popular network can be active\n if (!isPopularNetwork(reference)) {\n Object.keys(s.enabledNetworkMap[namespace]).forEach((key) => {\n s.enabledNetworkMap[namespace][key as CaipChainId | Hex] = false;\n });\n }\n\n // Add the new network as enabled\n s.enabledNetworkMap[namespace][storageKey] = true;\n });\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/network-enablement-controller",
3
- "version": "0.1.1-preview-20c29407",
3
+ "version": "0.1.1-preview-daea9b9c",
4
4
  "description": "Provides an interface to the currently enabled network using a MetaMask-compatible provider object",
5
5
  "keywords": [
6
6
  "MetaMask",