diff --git a/packages/network-enablement-controller/CHANGELOG.md b/packages/network-enablement-controller/CHANGELOG.md index e708938edd..7e69392179 100644 --- a/packages/network-enablement-controller/CHANGELOG.md +++ b/packages/network-enablement-controller/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add Stellar network enablement: default `enabledNetworkMap` entries for Stellar namespace (pubnet on, testnet off), enable Stellar pubnet during popular-network init when it exists in `MultichainNetworkController`, and include Stellar pubnet in `listPopularMultichainNetworks` ([#TODO](https://github.com/MetaMask/core/pull/TODO)) + ## [5.1.0] ### Changed diff --git a/packages/network-enablement-controller/package.json b/packages/network-enablement-controller/package.json index e6707a2827..db112e772d 100644 --- a/packages/network-enablement-controller/package.json +++ b/packages/network-enablement-controller/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/network-enablement-controller", - "version": "5.1.0", + "version": "5.1.0-dev.2", "description": "Provides an interface to the currently enabled network using a MetaMask-compatible provider object", "keywords": [ "Ethereum", @@ -61,7 +61,7 @@ "@metamask/network-controller": "^30.1.0", "@metamask/slip44": "^4.3.0", "@metamask/transaction-controller": "^65.0.0", - "@metamask/utils": "^11.9.0", + "@metamask/utils": "^11.11.0", "reselect": "^5.1.1" }, "devDependencies": { diff --git a/packages/network-enablement-controller/src/NetworkEnablementController.test.ts b/packages/network-enablement-controller/src/NetworkEnablementController.test.ts index 8712deadaa..8ca349966c 100644 --- a/packages/network-enablement-controller/src/NetworkEnablementController.test.ts +++ b/packages/network-enablement-controller/src/NetworkEnablementController.test.ts @@ -1,6 +1,6 @@ import { deriveStateFromMetadata } from '@metamask/base-controller'; import { BuiltInNetworkName, ChainId } from '@metamask/controller-utils'; -import { BtcScope, SolScope, TrxScope } from '@metamask/keyring-api'; +import { BtcScope, SolScope, TrxScope, XlmScope } from '@metamask/keyring-api'; import { Messenger, MOCK_ANY_NAMESPACE } from '@metamask/messenger'; import type { MessengerActions, @@ -83,6 +83,7 @@ const defaultMultichainGetState = (): MultichainGetStateReturn => ({ [BtcScope.Mainnet]: { chainId: BtcScope.Mainnet, name: 'Bitcoin' }, [SolScope.Mainnet]: { chainId: SolScope.Mainnet, name: 'Solana' }, [TrxScope.Mainnet]: { chainId: TrxScope.Mainnet, name: 'Tron' }, + [XlmScope.Pubnet]: { chainId: XlmScope.Pubnet, name: 'Stellar' }, }, selectedMultichainNetworkChainId: 'eip155:1', isEvmSelected: true, @@ -211,6 +212,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -267,6 +272,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: { ...getDefaultNativeAssetIdentifiers(), @@ -330,6 +339,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: expectedNativeAssetIdentifiers, }); @@ -471,6 +484,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: expectedNativeAssetIdentifiersForFallback, }); @@ -571,6 +588,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, // init() populates nativeAssetIdentifiers from NetworkController (EVM networks only) nativeAssetIdentifiers: { @@ -1172,6 +1193,10 @@ describe('NetworkEnablementController', () => { chainId: TrxScope.Mainnet, name: 'Tron Mainnet', }, + [XlmScope.Pubnet]: { + chainId: XlmScope.Pubnet, + name: 'Stellar Mainnet', + }, }, selectedMultichainNetworkChainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', @@ -1213,6 +1238,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1247,6 +1276,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1329,6 +1362,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1510,6 +1547,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1544,6 +1585,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1598,6 +1643,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: { ...getDefaultNativeAssetIdentifiers(), @@ -1636,6 +1685,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: { ...getDefaultNativeAssetIdentifiers(), @@ -1674,6 +1727,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: { ...getDefaultNativeAssetIdentifiers(), @@ -1723,6 +1780,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1764,6 +1825,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1818,6 +1883,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: false, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: { ...getDefaultNativeAssetIdentifiers(), @@ -1864,6 +1933,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -1912,6 +1985,10 @@ describe('NetworkEnablementController', () => { [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, nativeAssetIdentifiers: getDefaultNativeAssetIdentifiers(), }); @@ -2148,14 +2225,15 @@ describe('NetworkEnablementController', () => { const { controller } = setupController(); const result = controller.listPopularNetworks(); - // Default setup: 3 EVM (0x1, 0xe708, 0x2105) + 3 multichain (Btc, Sol, Trx) + // Default setup: 3 EVM (0x1, 0xe708, 0x2105) + 4 multichain (Btc, Sol, Trx, Stellar) expect(result).toContain('eip155:1'); expect(result).toContain('eip155:59144'); expect(result).toContain('eip155:8453'); expect(result).toContain(BtcScope.Mainnet); expect(result).toContain(SolScope.Mainnet); expect(result).toContain(TrxScope.Mainnet); - expect(result).toHaveLength(6); + expect(result).toContain(XlmScope.Pubnet); + expect(result).toHaveLength(7); }); it('excludes multichain mainnets when not in MultichainNetworkController state', () => { @@ -2175,6 +2253,7 @@ describe('NetworkEnablementController', () => { expect(result).not.toContain(BtcScope.Mainnet); expect(result).not.toContain(SolScope.Mainnet); expect(result).not.toContain(TrxScope.Mainnet); + expect(result).not.toContain(XlmScope.Pubnet); expect(result).toHaveLength(3); }); @@ -2222,14 +2301,15 @@ describe('NetworkEnablementController', () => { }); describe('listPopularMultichainNetworks', () => { - it('returns only Bitcoin, Solana, Tron mainnets that exist in MultichainNetworkController state', () => { + it('returns only Bitcoin, Solana, Tron, Stellar mainnets that exist in MultichainNetworkController state', () => { const { controller } = setupController(); const result = controller.listPopularMultichainNetworks(); expect(result).toContain(BtcScope.Mainnet); expect(result).toContain(SolScope.Mainnet); expect(result).toContain(TrxScope.Mainnet); - expect(result).toHaveLength(3); + expect(result).toContain(XlmScope.Pubnet); + expect(result).toHaveLength(4); }); it('returns empty when none of the multichain mainnets are configured', () => { diff --git a/packages/network-enablement-controller/src/NetworkEnablementController.ts b/packages/network-enablement-controller/src/NetworkEnablementController.ts index 8ea80bcc98..39e428e57b 100644 --- a/packages/network-enablement-controller/src/NetworkEnablementController.ts +++ b/packages/network-enablement-controller/src/NetworkEnablementController.ts @@ -4,7 +4,7 @@ import type { ControllerStateChangeEvent, } from '@metamask/base-controller'; import { BuiltInNetworkName, ChainId } from '@metamask/controller-utils'; -import { BtcScope, SolScope, TrxScope } from '@metamask/keyring-api'; +import { BtcScope, SolScope, TrxScope, XlmScope } from '@metamask/keyring-api'; import type { Messenger } from '@metamask/messenger'; import type { MultichainNetworkControllerGetStateAction } from '@metamask/multichain-network-controller'; import { toEvmCaipChainId } from '@metamask/multichain-network-controller'; @@ -183,6 +183,10 @@ const getDefaultNetworkEnablementControllerState = [TrxScope.Nile]: false, [TrxScope.Shasta]: false, }, + [KnownCaipNamespace.Stellar]: { + [XlmScope.Pubnet]: true, + [XlmScope.Testnet]: false, + }, }, // nativeAssetIdentifiers is initialized as empty and should be populated // by the client using initNativeAssetIdentifiers() during controller init @@ -418,6 +422,18 @@ export class NetworkEnablementController extends BaseController< // Enable Tron mainnet state.enabledNetworkMap[tronKeys.namespace][tronKeys.storageKey] = true; } + + // Enable Stellar mainnet if it exists in MultichainNetworkController configurations + const stellarKeys = deriveKeys(XlmScope.Pubnet as CaipChainId); + if ( + multichainState.multichainNetworkConfigurationsByChainId[ + XlmScope.Pubnet + ] + ) { + this.#ensureNamespaceBucket(state, stellarKeys.namespace); + state.enabledNetworkMap[stellarKeys.namespace][stellarKeys.storageKey] = + true; + } }); } @@ -768,11 +784,11 @@ export class NetworkEnablementController extends BaseController< } /** - * Returns popular multichain (Bitcoin, Solana, Tron) mainnet chain IDs in + * Returns popular multichain (Bitcoin, Solana, Tron, Stellar) mainnet chain IDs in * CAIP-2 form, restricted to networks that exist in MultichainNetworkController * (multichainNetworkConfigurationsByChainId). * - * @returns CAIP-2 chain IDs for Bitcoin, Solana, and Tron mainnets that are configured. + * @returns CAIP-2 chain IDs for Bitcoin, Solana, Tron, and Stellar mainnets that are configured. */ listPopularMultichainNetworks(): CaipChainId[] { const multichainState = this.messenger.call( @@ -782,6 +798,7 @@ export class NetworkEnablementController extends BaseController< BtcScope.Mainnet, SolScope.Mainnet, TrxScope.Mainnet, + XlmScope.Pubnet, ] as const; return multichainMainnets.filter( (chainId) => @@ -794,7 +811,7 @@ export class NetworkEnablementController extends BaseController< * networks that exist in NetworkController (networkConfigurationsByChainId) and * MultichainNetworkController (multichainNetworkConfigurationsByChainId). EVM * popular networks come from POPULAR_NETWORKS; multichain popular are Bitcoin, - * Solana, and Tron mainnets. + * Solana, Tron, and Stellar mainnets. * * @returns CAIP-2 chain IDs for popular EVM networks and multichain mainnets that are configured. */