@metamask/multichain-network-controller 0.1.0

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +20 -0
  3. package/README.md +15 -0
  4. package/dist/MultichainNetworkController.cjs +130 -0
  5. package/dist/MultichainNetworkController.cjs.map +1 -0
  6. package/dist/MultichainNetworkController.d.cts +22 -0
  7. package/dist/MultichainNetworkController.d.cts.map +1 -0
  8. package/dist/MultichainNetworkController.d.mts +22 -0
  9. package/dist/MultichainNetworkController.d.mts.map +1 -0
  10. package/dist/MultichainNetworkController.mjs +126 -0
  11. package/dist/MultichainNetworkController.mjs.map +1 -0
  12. package/dist/constants.cjs +61 -0
  13. package/dist/constants.cjs.map +1 -0
  14. package/dist/constants.d.cts +39 -0
  15. package/dist/constants.d.cts.map +1 -0
  16. package/dist/constants.d.mts +39 -0
  17. package/dist/constants.d.mts.map +1 -0
  18. package/dist/constants.mjs +57 -0
  19. package/dist/constants.mjs.map +1 -0
  20. package/dist/index.cjs +13 -0
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.cts +5 -0
  23. package/dist/index.d.cts.map +1 -0
  24. package/dist/index.d.mts +5 -0
  25. package/dist/index.d.mts.map +1 -0
  26. package/dist/index.mjs +4 -0
  27. package/dist/index.mjs.map +1 -0
  28. package/dist/types.cjs +5 -0
  29. package/dist/types.cjs.map +1 -0
  30. package/dist/types.d.cts +117 -0
  31. package/dist/types.d.cts.map +1 -0
  32. package/dist/types.d.mts +117 -0
  33. package/dist/types.d.mts.map +1 -0
  34. package/dist/types.mjs +2 -0
  35. package/dist/types.mjs.map +1 -0
  36. package/dist/utils.cjs +71 -0
  37. package/dist/utils.cjs.map +1 -0
  38. package/dist/utils.d.cts +41 -0
  39. package/dist/utils.d.cts.map +1 -0
  40. package/dist/utils.d.mts +41 -0
  41. package/dist/utils.d.mts.map +1 -0
  42. package/dist/utils.mjs +63 -0
  43. package/dist/utils.mjs.map +1 -0
  44. package/package.json +81 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0]
11
+
12
+ ### Added
13
+
14
+ - Initial release ([#5215](https://github.com/MetaMask/core/pull/5215))
15
+ - Handle both EVM and non-EVM network and account switching for the associated network.
16
+ - Act as a proxy for the `NetworkController` (for EVM network changes).
17
+
18
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/multichain-network-controller@0.1.0...HEAD
19
+ [0.1.0]: https://github.com/MetaMask/core/releases/tag/@metamask/multichain-network-controller@0.1.0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 MetaMask
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # `@metamask/multichain-network-controller`
2
+
3
+ ...
4
+
5
+ ## Installation
6
+
7
+ `yarn add @metamask/multichain-network-controller`
8
+
9
+ or
10
+
11
+ `npm install @metamask/multichain-network-controller`
12
+
13
+ ## Contributing
14
+
15
+ This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var _MultichainNetworkController_instances, _MultichainNetworkController_setActiveEvmNetwork, _MultichainNetworkController_setActiveNonEvmNetwork, _MultichainNetworkController_handleOnSelectedAccountChange, _MultichainNetworkController_subscribeToMessageEvents, _MultichainNetworkController_registerMessageHandlers;
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MultichainNetworkController = void 0;
10
+ const base_controller_1 = require("@metamask/base-controller");
11
+ const keyring_api_1 = require("@metamask/keyring-api");
12
+ const utils_1 = require("@metamask/utils");
13
+ const constants_1 = require("./constants.cjs");
14
+ const types_1 = require("./types.cjs");
15
+ const utils_2 = require("./utils.cjs");
16
+ /**
17
+ * The MultichainNetworkController is responsible for fetching and caching account
18
+ * balances.
19
+ */
20
+ class MultichainNetworkController extends base_controller_1.BaseController {
21
+ constructor({ messenger, state, }) {
22
+ super({
23
+ messenger,
24
+ name: types_1.MULTICHAIN_NETWORK_CONTROLLER_NAME,
25
+ metadata: constants_1.MULTICHAIN_NETWORK_CONTROLLER_METADATA,
26
+ state: {
27
+ ...(0, constants_1.getDefaultMultichainNetworkControllerState)(),
28
+ ...state,
29
+ },
30
+ });
31
+ _MultichainNetworkController_instances.add(this);
32
+ __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_subscribeToMessageEvents).call(this);
33
+ __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_registerMessageHandlers).call(this);
34
+ }
35
+ /**
36
+ * Sets the active network.
37
+ *
38
+ * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.
39
+ * @returns - A promise that resolves when the network is set active.
40
+ */
41
+ async setActiveNetwork(id) {
42
+ if ((0, utils_1.isCaipChainId)(id)) {
43
+ const isSupportedCaipChainId = (0, utils_2.checkIfSupportedCaipChainId)(id);
44
+ if (!isSupportedCaipChainId) {
45
+ throw new Error(`Unsupported Caip chain ID: ${String(id)}`);
46
+ }
47
+ return __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_setActiveNonEvmNetwork).call(this, id);
48
+ }
49
+ return await __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_setActiveEvmNetwork).call(this, id);
50
+ }
51
+ }
52
+ exports.MultichainNetworkController = MultichainNetworkController;
53
+ _MultichainNetworkController_instances = new WeakSet(), _MultichainNetworkController_setActiveEvmNetwork =
54
+ /**
55
+ * Sets the active EVM network.
56
+ *
57
+ * @param id - The client ID of the EVM network to set active.
58
+ */
59
+ async function _MultichainNetworkController_setActiveEvmNetwork(id) {
60
+ const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
61
+ const shouldSetEvmActive = !this.state.isEvmSelected;
62
+ const shouldNotifyNetworkChange = id !== selectedNetworkClientId;
63
+ // No changes needed if EVM is active and network is already selected
64
+ if (!shouldSetEvmActive && !shouldNotifyNetworkChange) {
65
+ return;
66
+ }
67
+ // Update EVM selection state if needed
68
+ if (shouldSetEvmActive) {
69
+ this.update((state) => {
70
+ state.isEvmSelected = true;
71
+ });
72
+ }
73
+ // Only notify the network controller if the selected evm network is different
74
+ if (shouldNotifyNetworkChange) {
75
+ await this.messagingSystem.call('NetworkController:setActiveNetwork', id);
76
+ }
77
+ // Only publish the networkDidChange event if either the EVM network is different or we're switching between EVM and non-EVM networks
78
+ if (shouldSetEvmActive || shouldNotifyNetworkChange) {
79
+ this.messagingSystem.publish('MultichainNetworkController:networkDidChange', id);
80
+ }
81
+ }, _MultichainNetworkController_setActiveNonEvmNetwork = function _MultichainNetworkController_setActiveNonEvmNetwork(id) {
82
+ if (id === this.state.selectedMultichainNetworkChainId &&
83
+ !this.state.isEvmSelected) {
84
+ // Same non-EVM network is already selected, no need to update
85
+ return;
86
+ }
87
+ this.update((state) => {
88
+ state.selectedMultichainNetworkChainId = id;
89
+ state.isEvmSelected = false;
90
+ });
91
+ // Notify listeners that the network changed
92
+ this.messagingSystem.publish('MultichainNetworkController:networkDidChange', id);
93
+ }, _MultichainNetworkController_handleOnSelectedAccountChange = function _MultichainNetworkController_handleOnSelectedAccountChange(account) {
94
+ const { type: accountType, address: accountAddress } = account;
95
+ const isEvmAccount = (0, keyring_api_1.isEvmAccountType)(accountType);
96
+ // Handle switching to EVM network
97
+ if (isEvmAccount) {
98
+ if (this.state.isEvmSelected) {
99
+ // No need to update if already on evm network
100
+ return;
101
+ }
102
+ // Make EVM network active
103
+ this.update((state) => {
104
+ state.isEvmSelected = true;
105
+ });
106
+ return;
107
+ }
108
+ // Handle switching to non-EVM network
109
+ const nonEvmChainId = (0, utils_2.getChainIdForNonEvmAddress)(accountAddress);
110
+ const isSameNonEvmNetwork = nonEvmChainId === this.state.selectedMultichainNetworkChainId;
111
+ if (isSameNonEvmNetwork) {
112
+ // No need to update if already on the same non-EVM network
113
+ this.update((state) => {
114
+ state.isEvmSelected = false;
115
+ });
116
+ return;
117
+ }
118
+ this.update((state) => {
119
+ state.selectedMultichainNetworkChainId = nonEvmChainId;
120
+ state.isEvmSelected = false;
121
+ });
122
+ // No need to publish NetworkController:setActiveNetwork because EVM accounts falls back to use the last selected EVM network
123
+ // DO NOT publish MultichainNetworkController:networkDidChange to prevent circular listener loops
124
+ }, _MultichainNetworkController_subscribeToMessageEvents = function _MultichainNetworkController_subscribeToMessageEvents() {
125
+ // Handle network switch when account is changed
126
+ this.messagingSystem.subscribe('AccountsController:selectedAccountChange', (account) => __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_handleOnSelectedAccountChange).call(this, account));
127
+ }, _MultichainNetworkController_registerMessageHandlers = function _MultichainNetworkController_registerMessageHandlers() {
128
+ this.messagingSystem.registerActionHandler('MultichainNetworkController:setActiveNetwork', this.setActiveNetwork.bind(this));
129
+ };
130
+ //# sourceMappingURL=MultichainNetworkController.cjs.map
@@ -0,0 +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 { isCaipChainId } from '@metamask/utils';\n\nimport {\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} 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 },\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 * 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"]}
@@ -0,0 +1,22 @@
1
+ import { BaseController } from "@metamask/base-controller";
2
+ import type { NetworkClientId } from "@metamask/network-controller";
3
+ import { MULTICHAIN_NETWORK_CONTROLLER_NAME, type MultichainNetworkControllerState, type MultichainNetworkControllerMessenger, type SupportedCaipChainId } from "./types.cjs";
4
+ /**
5
+ * The MultichainNetworkController is responsible for fetching and caching account
6
+ * balances.
7
+ */
8
+ export declare class MultichainNetworkController extends BaseController<typeof MULTICHAIN_NETWORK_CONTROLLER_NAME, MultichainNetworkControllerState, MultichainNetworkControllerMessenger> {
9
+ #private;
10
+ constructor({ messenger, state, }: {
11
+ messenger: MultichainNetworkControllerMessenger;
12
+ state?: Omit<Partial<MultichainNetworkControllerState>, 'multichainNetworkConfigurationsByChainId'>;
13
+ });
14
+ /**
15
+ * Sets the active network.
16
+ *
17
+ * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.
18
+ * @returns - A promise that resolves when the network is set active.
19
+ */
20
+ setActiveNetwork(id: SupportedCaipChainId | NetworkClientId): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=MultichainNetworkController.d.cts.map
@@ -0,0 +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;AAOpE,OAAO,EACL,kCAAkC,EAClC,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,oBAAoB,EAC1B,oBAAgB;AAMjB;;;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;IAgFD;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,oBAAoB,GAAG,eAAe,GACzC,OAAO,CAAC,IAAI,CAAC;CA8EjB"}
@@ -0,0 +1,22 @@
1
+ import { BaseController } from "@metamask/base-controller";
2
+ import type { NetworkClientId } from "@metamask/network-controller";
3
+ import { MULTICHAIN_NETWORK_CONTROLLER_NAME, type MultichainNetworkControllerState, type MultichainNetworkControllerMessenger, type SupportedCaipChainId } from "./types.mjs";
4
+ /**
5
+ * The MultichainNetworkController is responsible for fetching and caching account
6
+ * balances.
7
+ */
8
+ export declare class MultichainNetworkController extends BaseController<typeof MULTICHAIN_NETWORK_CONTROLLER_NAME, MultichainNetworkControllerState, MultichainNetworkControllerMessenger> {
9
+ #private;
10
+ constructor({ messenger, state, }: {
11
+ messenger: MultichainNetworkControllerMessenger;
12
+ state?: Omit<Partial<MultichainNetworkControllerState>, 'multichainNetworkConfigurationsByChainId'>;
13
+ });
14
+ /**
15
+ * Sets the active network.
16
+ *
17
+ * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.
18
+ * @returns - A promise that resolves when the network is set active.
19
+ */
20
+ setActiveNetwork(id: SupportedCaipChainId | NetworkClientId): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=MultichainNetworkController.d.mts.map
@@ -0,0 +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;AAOpE,OAAO,EACL,kCAAkC,EAClC,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,oBAAoB,EAC1B,oBAAgB;AAMjB;;;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;IAgFD;;;;;OAKG;IACG,gBAAgB,CACpB,EAAE,EAAE,oBAAoB,GAAG,eAAe,GACzC,OAAO,CAAC,IAAI,CAAC;CA8EjB"}
@@ -0,0 +1,126 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _MultichainNetworkController_instances, _MultichainNetworkController_setActiveEvmNetwork, _MultichainNetworkController_setActiveNonEvmNetwork, _MultichainNetworkController_handleOnSelectedAccountChange, _MultichainNetworkController_subscribeToMessageEvents, _MultichainNetworkController_registerMessageHandlers;
7
+ import { BaseController } from "@metamask/base-controller";
8
+ import { isEvmAccountType } from "@metamask/keyring-api";
9
+ import { isCaipChainId } from "@metamask/utils";
10
+ import { MULTICHAIN_NETWORK_CONTROLLER_METADATA, getDefaultMultichainNetworkControllerState } from "./constants.mjs";
11
+ import { MULTICHAIN_NETWORK_CONTROLLER_NAME } from "./types.mjs";
12
+ import { checkIfSupportedCaipChainId, getChainIdForNonEvmAddress } from "./utils.mjs";
13
+ /**
14
+ * The MultichainNetworkController is responsible for fetching and caching account
15
+ * balances.
16
+ */
17
+ export class MultichainNetworkController extends BaseController {
18
+ constructor({ messenger, state, }) {
19
+ super({
20
+ messenger,
21
+ name: MULTICHAIN_NETWORK_CONTROLLER_NAME,
22
+ metadata: MULTICHAIN_NETWORK_CONTROLLER_METADATA,
23
+ state: {
24
+ ...getDefaultMultichainNetworkControllerState(),
25
+ ...state,
26
+ },
27
+ });
28
+ _MultichainNetworkController_instances.add(this);
29
+ __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_subscribeToMessageEvents).call(this);
30
+ __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_registerMessageHandlers).call(this);
31
+ }
32
+ /**
33
+ * Sets the active network.
34
+ *
35
+ * @param id - The non-EVM Caip chain ID or EVM client ID of the network to set active.
36
+ * @returns - A promise that resolves when the network is set active.
37
+ */
38
+ async setActiveNetwork(id) {
39
+ if (isCaipChainId(id)) {
40
+ const isSupportedCaipChainId = checkIfSupportedCaipChainId(id);
41
+ if (!isSupportedCaipChainId) {
42
+ throw new Error(`Unsupported Caip chain ID: ${String(id)}`);
43
+ }
44
+ return __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_setActiveNonEvmNetwork).call(this, id);
45
+ }
46
+ return await __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_setActiveEvmNetwork).call(this, id);
47
+ }
48
+ }
49
+ _MultichainNetworkController_instances = new WeakSet(), _MultichainNetworkController_setActiveEvmNetwork =
50
+ /**
51
+ * Sets the active EVM network.
52
+ *
53
+ * @param id - The client ID of the EVM network to set active.
54
+ */
55
+ async function _MultichainNetworkController_setActiveEvmNetwork(id) {
56
+ const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
57
+ const shouldSetEvmActive = !this.state.isEvmSelected;
58
+ const shouldNotifyNetworkChange = id !== selectedNetworkClientId;
59
+ // No changes needed if EVM is active and network is already selected
60
+ if (!shouldSetEvmActive && !shouldNotifyNetworkChange) {
61
+ return;
62
+ }
63
+ // Update EVM selection state if needed
64
+ if (shouldSetEvmActive) {
65
+ this.update((state) => {
66
+ state.isEvmSelected = true;
67
+ });
68
+ }
69
+ // Only notify the network controller if the selected evm network is different
70
+ if (shouldNotifyNetworkChange) {
71
+ await this.messagingSystem.call('NetworkController:setActiveNetwork', id);
72
+ }
73
+ // Only publish the networkDidChange event if either the EVM network is different or we're switching between EVM and non-EVM networks
74
+ if (shouldSetEvmActive || shouldNotifyNetworkChange) {
75
+ this.messagingSystem.publish('MultichainNetworkController:networkDidChange', id);
76
+ }
77
+ }, _MultichainNetworkController_setActiveNonEvmNetwork = function _MultichainNetworkController_setActiveNonEvmNetwork(id) {
78
+ if (id === this.state.selectedMultichainNetworkChainId &&
79
+ !this.state.isEvmSelected) {
80
+ // Same non-EVM network is already selected, no need to update
81
+ return;
82
+ }
83
+ this.update((state) => {
84
+ state.selectedMultichainNetworkChainId = id;
85
+ state.isEvmSelected = false;
86
+ });
87
+ // Notify listeners that the network changed
88
+ this.messagingSystem.publish('MultichainNetworkController:networkDidChange', id);
89
+ }, _MultichainNetworkController_handleOnSelectedAccountChange = function _MultichainNetworkController_handleOnSelectedAccountChange(account) {
90
+ const { type: accountType, address: accountAddress } = account;
91
+ const isEvmAccount = isEvmAccountType(accountType);
92
+ // Handle switching to EVM network
93
+ if (isEvmAccount) {
94
+ if (this.state.isEvmSelected) {
95
+ // No need to update if already on evm network
96
+ return;
97
+ }
98
+ // Make EVM network active
99
+ this.update((state) => {
100
+ state.isEvmSelected = true;
101
+ });
102
+ return;
103
+ }
104
+ // Handle switching to non-EVM network
105
+ const nonEvmChainId = getChainIdForNonEvmAddress(accountAddress);
106
+ const isSameNonEvmNetwork = nonEvmChainId === this.state.selectedMultichainNetworkChainId;
107
+ if (isSameNonEvmNetwork) {
108
+ // No need to update if already on the same non-EVM network
109
+ this.update((state) => {
110
+ state.isEvmSelected = false;
111
+ });
112
+ return;
113
+ }
114
+ this.update((state) => {
115
+ state.selectedMultichainNetworkChainId = nonEvmChainId;
116
+ state.isEvmSelected = false;
117
+ });
118
+ // No need to publish NetworkController:setActiveNetwork because EVM accounts falls back to use the last selected EVM network
119
+ // DO NOT publish MultichainNetworkController:networkDidChange to prevent circular listener loops
120
+ }, _MultichainNetworkController_subscribeToMessageEvents = function _MultichainNetworkController_subscribeToMessageEvents() {
121
+ // Handle network switch when account is changed
122
+ this.messagingSystem.subscribe('AccountsController:selectedAccountChange', (account) => __classPrivateFieldGet(this, _MultichainNetworkController_instances, "m", _MultichainNetworkController_handleOnSelectedAccountChange).call(this, account));
123
+ }, _MultichainNetworkController_registerMessageHandlers = function _MultichainNetworkController_registerMessageHandlers() {
124
+ this.messagingSystem.registerActionHandler('MultichainNetworkController:setActiveNetwork', this.setActiveNetwork.bind(this));
125
+ };
126
+ //# sourceMappingURL=MultichainNetworkController.mjs.map
@@ -0,0 +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 { isCaipChainId } from '@metamask/utils';\n\nimport {\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} 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 },\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 * 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"]}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MULTICHAIN_NETWORK_CONTROLLER_METADATA = exports.getDefaultMultichainNetworkControllerState = exports.NETWORKS_METADATA = exports.AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS = exports.SOL_NATIVE_ASSET = exports.BTC_NATIVE_ASSET = void 0;
4
+ const keyring_api_1 = require("@metamask/keyring-api");
5
+ const network_controller_1 = require("@metamask/network-controller");
6
+ exports.BTC_NATIVE_ASSET = `${keyring_api_1.BtcScope.Mainnet}/slip44:0`;
7
+ exports.SOL_NATIVE_ASSET = `${keyring_api_1.SolScope.Mainnet}/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`;
8
+ /**
9
+ * Supported networks by the MultichainNetworkController
10
+ */
11
+ exports.AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS = {
12
+ [keyring_api_1.BtcScope.Mainnet]: {
13
+ chainId: keyring_api_1.BtcScope.Mainnet,
14
+ name: 'Bitcoin Mainnet',
15
+ nativeCurrency: exports.BTC_NATIVE_ASSET,
16
+ isEvm: false,
17
+ },
18
+ [keyring_api_1.SolScope.Mainnet]: {
19
+ chainId: keyring_api_1.SolScope.Mainnet,
20
+ name: 'Solana Mainnet',
21
+ nativeCurrency: exports.SOL_NATIVE_ASSET,
22
+ isEvm: false,
23
+ },
24
+ };
25
+ /**
26
+ * Metadata for the supported networks.
27
+ */
28
+ exports.NETWORKS_METADATA = {
29
+ [keyring_api_1.BtcScope.Mainnet]: {
30
+ features: [],
31
+ status: network_controller_1.NetworkStatus.Available,
32
+ },
33
+ [keyring_api_1.SolScope.Mainnet]: {
34
+ features: [],
35
+ status: network_controller_1.NetworkStatus.Available,
36
+ },
37
+ };
38
+ /**
39
+ * Default state of the {@link MultichainNetworkController}.
40
+ *
41
+ * @returns The default state of the {@link MultichainNetworkController}.
42
+ */
43
+ const getDefaultMultichainNetworkControllerState = () => ({
44
+ multichainNetworkConfigurationsByChainId: exports.AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,
45
+ selectedMultichainNetworkChainId: keyring_api_1.SolScope.Mainnet,
46
+ isEvmSelected: true,
47
+ });
48
+ exports.getDefaultMultichainNetworkControllerState = getDefaultMultichainNetworkControllerState;
49
+ /**
50
+ * {@link MultichainNetworkController}'s metadata.
51
+ *
52
+ * This allows us to choose if fields of the state should be persisted or not
53
+ * using the `persist` flag; and if they can be sent to Sentry or not, using
54
+ * the `anonymous` flag.
55
+ */
56
+ exports.MULTICHAIN_NETWORK_CONTROLLER_METADATA = {
57
+ multichainNetworkConfigurationsByChainId: { persist: true, anonymous: true },
58
+ selectedMultichainNetworkChainId: { persist: true, anonymous: true },
59
+ isEvmSelected: { persist: true, anonymous: true },
60
+ };
61
+ //# sourceMappingURL=constants.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AACA,uDAA2D;AAC3D,qEAA6D;AAShD,QAAA,gBAAgB,GAAG,GAAG,sBAAQ,CAAC,OAAO,WAAW,CAAC;AAClD,QAAA,gBAAgB,GAAG,GAAG,sBAAQ,CAAC,OAAO,qDAAqD,CAAC;AAEzG;;GAEG;AACU,QAAA,2CAA2C,GAGpD;IACF,CAAC,sBAAQ,CAAC,OAAO,CAAC,EAAE;QAClB,OAAO,EAAE,sBAAQ,CAAC,OAAO;QACzB,IAAI,EAAE,iBAAiB;QACvB,cAAc,EAAE,wBAAgB;QAChC,KAAK,EAAE,KAAK;KACb;IACD,CAAC,sBAAQ,CAAC,OAAO,CAAC,EAAE;QAClB,OAAO,EAAE,sBAAQ,CAAC,OAAO;QACzB,IAAI,EAAE,gBAAgB;QACtB,cAAc,EAAE,wBAAgB;QAChC,KAAK,EAAE,KAAK;KACb;CACF,CAAC;AAEF;;GAEG;AACU,QAAA,iBAAiB,GAA8C;IAC1E,CAAC,sBAAQ,CAAC,OAAO,CAAC,EAAE;QAClB,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,kCAAa,CAAC,SAAS;KAChC;IACD,CAAC,sBAAQ,CAAC,OAAO,CAAC,EAAE;QAClB,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,kCAAa,CAAC,SAAS;KAChC;CACF,CAAC;AAEF;;;;GAIG;AACI,MAAM,0CAA0C,GACrD,GAAqC,EAAE,CAAC,CAAC;IACvC,wCAAwC,EACtC,mDAA2C;IAC7C,gCAAgC,EAAE,sBAAQ,CAAC,OAAO;IAClD,aAAa,EAAE,IAAI;CACpB,CAAC,CAAC;AANQ,QAAA,0CAA0C,8CAMlD;AAEL;;;;;;GAMG;AACU,QAAA,sCAAsC,GAAG;IACpD,wCAAwC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;IAC5E,gCAAgC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;IACpE,aAAa,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;CACQ,CAAC","sourcesContent":["import { type StateMetadata } from '@metamask/base-controller';\nimport { BtcScope, SolScope } from '@metamask/keyring-api';\nimport { NetworkStatus } from '@metamask/network-controller';\n\nimport type {\n MultichainNetworkConfiguration,\n MultichainNetworkControllerState,\n MultichainNetworkMetadata,\n SupportedCaipChainId,\n} from './types';\n\nexport const BTC_NATIVE_ASSET = `${BtcScope.Mainnet}/slip44:0`;\nexport const SOL_NATIVE_ASSET = `${SolScope.Mainnet}/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`;\n\n/**\n * Supported networks by the MultichainNetworkController\n */\nexport const AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS: Record<\n SupportedCaipChainId,\n MultichainNetworkConfiguration\n> = {\n [BtcScope.Mainnet]: {\n chainId: BtcScope.Mainnet,\n name: 'Bitcoin Mainnet',\n nativeCurrency: BTC_NATIVE_ASSET,\n isEvm: false,\n },\n [SolScope.Mainnet]: {\n chainId: SolScope.Mainnet,\n name: 'Solana Mainnet',\n nativeCurrency: SOL_NATIVE_ASSET,\n isEvm: false,\n },\n};\n\n/**\n * Metadata for the supported networks.\n */\nexport const NETWORKS_METADATA: Record<string, MultichainNetworkMetadata> = {\n [BtcScope.Mainnet]: {\n features: [],\n status: NetworkStatus.Available,\n },\n [SolScope.Mainnet]: {\n features: [],\n status: NetworkStatus.Available,\n },\n};\n\n/**\n * Default state of the {@link MultichainNetworkController}.\n *\n * @returns The default state of the {@link MultichainNetworkController}.\n */\nexport const getDefaultMultichainNetworkControllerState =\n (): MultichainNetworkControllerState => ({\n multichainNetworkConfigurationsByChainId:\n AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,\n selectedMultichainNetworkChainId: SolScope.Mainnet,\n isEvmSelected: true,\n });\n\n/**\n * {@link MultichainNetworkController}'s metadata.\n *\n * This allows us to choose if fields of the state should be persisted or not\n * using the `persist` flag; and if they can be sent to Sentry or not, using\n * the `anonymous` flag.\n */\nexport const MULTICHAIN_NETWORK_CONTROLLER_METADATA = {\n multichainNetworkConfigurationsByChainId: { persist: true, anonymous: true },\n selectedMultichainNetworkChainId: { persist: true, anonymous: true },\n isEvmSelected: { persist: true, anonymous: true },\n} satisfies StateMetadata<MultichainNetworkControllerState>;\n"]}
@@ -0,0 +1,39 @@
1
+ import type { MultichainNetworkConfiguration, MultichainNetworkControllerState, MultichainNetworkMetadata, SupportedCaipChainId } from "./types.cjs";
2
+ export declare const BTC_NATIVE_ASSET = "bip122:000000000019d6689c085ae165831e93/slip44:0";
3
+ export declare const SOL_NATIVE_ASSET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
4
+ /**
5
+ * Supported networks by the MultichainNetworkController
6
+ */
7
+ export declare const AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS: Record<SupportedCaipChainId, MultichainNetworkConfiguration>;
8
+ /**
9
+ * Metadata for the supported networks.
10
+ */
11
+ export declare const NETWORKS_METADATA: Record<string, MultichainNetworkMetadata>;
12
+ /**
13
+ * Default state of the {@link MultichainNetworkController}.
14
+ *
15
+ * @returns The default state of the {@link MultichainNetworkController}.
16
+ */
17
+ export declare const getDefaultMultichainNetworkControllerState: () => MultichainNetworkControllerState;
18
+ /**
19
+ * {@link MultichainNetworkController}'s metadata.
20
+ *
21
+ * This allows us to choose if fields of the state should be persisted or not
22
+ * using the `persist` flag; and if they can be sent to Sentry or not, using
23
+ * the `anonymous` flag.
24
+ */
25
+ export declare const MULTICHAIN_NETWORK_CONTROLLER_METADATA: {
26
+ multichainNetworkConfigurationsByChainId: {
27
+ persist: true;
28
+ anonymous: true;
29
+ };
30
+ selectedMultichainNetworkChainId: {
31
+ persist: true;
32
+ anonymous: true;
33
+ };
34
+ isEvmSelected: {
35
+ persist: true;
36
+ anonymous: true;
37
+ };
38
+ };
39
+ //# sourceMappingURL=constants.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,8BAA8B,EAC9B,gCAAgC,EAChC,yBAAyB,EACzB,oBAAoB,EACrB,oBAAgB;AAEjB,eAAO,MAAM,gBAAgB,qDAAiC,CAAC;AAC/D,eAAO,MAAM,gBAAgB,+FAA2E,CAAC;AAEzG;;GAEG;AACH,eAAO,MAAM,2CAA2C,EAAE,MAAM,CAC9D,oBAAoB,EACpB,8BAA8B,CAc/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CASvE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0CAA0C,QACjD,gCAKF,CAAC;AAEL;;;;;;GAMG;AACH,eAAO,MAAM,sCAAsC;;;;;;;;;;;;;CAIQ,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { MultichainNetworkConfiguration, MultichainNetworkControllerState, MultichainNetworkMetadata, SupportedCaipChainId } from "./types.mjs";
2
+ export declare const BTC_NATIVE_ASSET = "bip122:000000000019d6689c085ae165831e93/slip44:0";
3
+ export declare const SOL_NATIVE_ASSET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
4
+ /**
5
+ * Supported networks by the MultichainNetworkController
6
+ */
7
+ export declare const AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS: Record<SupportedCaipChainId, MultichainNetworkConfiguration>;
8
+ /**
9
+ * Metadata for the supported networks.
10
+ */
11
+ export declare const NETWORKS_METADATA: Record<string, MultichainNetworkMetadata>;
12
+ /**
13
+ * Default state of the {@link MultichainNetworkController}.
14
+ *
15
+ * @returns The default state of the {@link MultichainNetworkController}.
16
+ */
17
+ export declare const getDefaultMultichainNetworkControllerState: () => MultichainNetworkControllerState;
18
+ /**
19
+ * {@link MultichainNetworkController}'s metadata.
20
+ *
21
+ * This allows us to choose if fields of the state should be persisted or not
22
+ * using the `persist` flag; and if they can be sent to Sentry or not, using
23
+ * the `anonymous` flag.
24
+ */
25
+ export declare const MULTICHAIN_NETWORK_CONTROLLER_METADATA: {
26
+ multichainNetworkConfigurationsByChainId: {
27
+ persist: true;
28
+ anonymous: true;
29
+ };
30
+ selectedMultichainNetworkChainId: {
31
+ persist: true;
32
+ anonymous: true;
33
+ };
34
+ isEvmSelected: {
35
+ persist: true;
36
+ anonymous: true;
37
+ };
38
+ };
39
+ //# sourceMappingURL=constants.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,8BAA8B,EAC9B,gCAAgC,EAChC,yBAAyB,EACzB,oBAAoB,EACrB,oBAAgB;AAEjB,eAAO,MAAM,gBAAgB,qDAAiC,CAAC;AAC/D,eAAO,MAAM,gBAAgB,+FAA2E,CAAC;AAEzG;;GAEG;AACH,eAAO,MAAM,2CAA2C,EAAE,MAAM,CAC9D,oBAAoB,EACpB,8BAA8B,CAc/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CASvE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0CAA0C,QACjD,gCAKF,CAAC;AAEL;;;;;;GAMG;AACH,eAAO,MAAM,sCAAsC;;;;;;;;;;;;;CAIQ,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { BtcScope, SolScope } from "@metamask/keyring-api";
2
+ import { NetworkStatus } from "@metamask/network-controller";
3
+ export const BTC_NATIVE_ASSET = `${BtcScope.Mainnet}/slip44:0`;
4
+ export const SOL_NATIVE_ASSET = `${SolScope.Mainnet}/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`;
5
+ /**
6
+ * Supported networks by the MultichainNetworkController
7
+ */
8
+ export const AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS = {
9
+ [BtcScope.Mainnet]: {
10
+ chainId: BtcScope.Mainnet,
11
+ name: 'Bitcoin Mainnet',
12
+ nativeCurrency: BTC_NATIVE_ASSET,
13
+ isEvm: false,
14
+ },
15
+ [SolScope.Mainnet]: {
16
+ chainId: SolScope.Mainnet,
17
+ name: 'Solana Mainnet',
18
+ nativeCurrency: SOL_NATIVE_ASSET,
19
+ isEvm: false,
20
+ },
21
+ };
22
+ /**
23
+ * Metadata for the supported networks.
24
+ */
25
+ export const NETWORKS_METADATA = {
26
+ [BtcScope.Mainnet]: {
27
+ features: [],
28
+ status: NetworkStatus.Available,
29
+ },
30
+ [SolScope.Mainnet]: {
31
+ features: [],
32
+ status: NetworkStatus.Available,
33
+ },
34
+ };
35
+ /**
36
+ * Default state of the {@link MultichainNetworkController}.
37
+ *
38
+ * @returns The default state of the {@link MultichainNetworkController}.
39
+ */
40
+ export const getDefaultMultichainNetworkControllerState = () => ({
41
+ multichainNetworkConfigurationsByChainId: AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS,
42
+ selectedMultichainNetworkChainId: SolScope.Mainnet,
43
+ isEvmSelected: true,
44
+ });
45
+ /**
46
+ * {@link MultichainNetworkController}'s metadata.
47
+ *
48
+ * This allows us to choose if fields of the state should be persisted or not
49
+ * using the `persist` flag; and if they can be sent to Sentry or not, using
50
+ * the `anonymous` flag.
51
+ */
52
+ export const MULTICHAIN_NETWORK_CONTROLLER_METADATA = {
53
+ multichainNetworkConfigurationsByChainId: { persist: true, anonymous: true },
54
+ selectedMultichainNetworkChainId: { persist: true, anonymous: true },
55
+ isEvmSelected: { persist: true, anonymous: true },
56
+ };
57
+ //# sourceMappingURL=constants.mjs.map