diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 32d27356ee7..6b6929e2d1d 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -169,10 +169,7 @@ }, "packages/assets-controllers/src/AssetsContractController.ts": { "@typescript-eslint/explicit-function-return-type": { - "count": 6 - }, - "id-length": { - "count": 1 + "count": 5 } }, "packages/assets-controllers/src/CurrencyRateController.test.ts": { @@ -213,7 +210,7 @@ }, "packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts": { "@typescript-eslint/explicit-function-return-type": { - "count": 7 + "count": 6 }, "@typescript-eslint/no-misused-promises": { "count": 3 @@ -362,7 +359,7 @@ }, "packages/assets-controllers/src/TokensController.ts": { "@typescript-eslint/explicit-function-return-type": { - "count": 14 + "count": 13 }, "@typescript-eslint/no-unused-vars": { "count": 1 diff --git a/packages/assets-controllers/CHANGELOG.md b/packages/assets-controllers/CHANGELOG.md index 0f69609a59a..9fe0114b609 100644 --- a/packages/assets-controllers/CHANGELOG.md +++ b/packages/assets-controllers/CHANGELOG.md @@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Expose missing public `AssetsContractController` methods through its messenger ([#8164](https://github.com/MetaMask/core/pull/8164)) + - The following action is now available: + - `AssetsContractController:getStakedBalanceForChain` + - Corresponding action type (`AssetsContractControllerGetStakedBalanceForChainAction`) is available as well. +- Expose missing public `MultichainAssetsRatesController` methods through its messenger ([#8164](https://github.com/MetaMask/core/pull/8164)) + - The following action is now available: + - `MultichainAssetsRatesController:fetchHistoricalPricesForAsset` + - Corresponding action type (`MultichainAssetsRatesControllerFetchHistoricalPricesForAssetAction`) is available as well. +- Expose missing public `TokenDetectionController` methods through its messenger ([#8164](https://github.com/MetaMask/core/pull/8164)) + - The following actions are now available: + - `TokenDetectionController:enable` + - `TokenDetectionController:disable` + - `TokenDetectionController:start` + - `TokenDetectionController:stop` + - Corresponding action type (`TokenDetectionControllerEnableAction`) is available as well. +- Expose missing public `TokensController` methods through its messenger ([#8164](https://github.com/MetaMask/core/pull/8164)) + - The following actions are now available: + - `TokensController:addToken` + - `TokensController:ignoreTokens` + - `TokensController:updateTokenType` + - `TokensController:watchAsset` + - `TokensController:clearIgnoredTokens` + - `TokensController:resetState` + - Corresponding action type (`TokensControllerAddTokenAction`) is available as well. + +### Changed + +- **BREAKING:** Standardize names of `AccountTrackerController` messenger action types ([#8164](https://github.com/MetaMask/core/pull/8164)) + - All existing types for messenger actions have been renamed so they include `Controller` (e.g. `AccountTrackerUpdateNativeBalancesAction` -> `AccountTrackerControllerUpdateNativeBalancesAction`). You will need to update imports appropriately. + - This change only affects the types. The action type strings themselves have not changed, so you do not need to update the list of actions you pass when initializing `AccountTrackerController` messengers. + ### Fixed - Add missing Tron staking lifecycle asset symbols to `TRON_RESOURCE` filter ([#8174](https://github.com/MetaMask/core/pull/8174)) diff --git a/packages/assets-controllers/package.json b/packages/assets-controllers/package.json index e2eed841856..6bf196976cb 100644 --- a/packages/assets-controllers/package.json +++ b/packages/assets-controllers/package.json @@ -40,6 +40,9 @@ "build:docs": "typedoc", "changelog:update": "../../scripts/update-changelog.sh @metamask/assets-controllers", "changelog:validate": "../../scripts/validate-changelog.sh @metamask/assets-controllers", + "generate-method-action-types": "tsx ../../scripts/generate-method-action-types.ts \"$@\" && yarn generate-method-action-types:multichain-assets-controller \"$@\" && yarn generate-method-action-types:multichain-assets-rates-controller \"$@\"", + "generate-method-action-types:multichain-assets-controller": "tsx ../../scripts/generate-method-action-types.ts src/MultichainAssetsController", + "generate-method-action-types:multichain-assets-rates-controller": "tsx ../../scripts/generate-method-action-types.ts src/MultichainAssetsRatesController", "since-latest-release": "../../scripts/since-latest-release.sh", "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache", @@ -110,6 +113,7 @@ "jest-environment-jsdom": "^29.7.0", "nock": "^13.3.1", "ts-jest": "^29.2.5", + "tsx": "^4.20.5", "typedoc": "^0.25.13", "typedoc-plugin-missing-exports": "^2.0.0", "typescript": "~5.3.3", diff --git a/packages/assets-controllers/src/AccountTrackerController-method-action-types.ts b/packages/assets-controllers/src/AccountTrackerController-method-action-types.ts new file mode 100644 index 00000000000..1b8eca12469 --- /dev/null +++ b/packages/assets-controllers/src/AccountTrackerController-method-action-types.ts @@ -0,0 +1,37 @@ +/** + * This file is auto generated by `scripts/generate-method-action-types.ts`. + * Do not edit manually. + */ + +import type { AccountTrackerController } from './AccountTrackerController'; + +/** + * Updates the balances of multiple native tokens in a single batch operation. + * This is more efficient than calling updateNativeToken multiple times as it + * triggers only one state update. + * + * @param balances - Array of balance updates, each containing address, chainId, and balance. + */ +export type AccountTrackerControllerUpdateNativeBalancesAction = { + type: `AccountTrackerController:updateNativeBalances`; + handler: AccountTrackerController['updateNativeBalances']; +}; + +/** + * Updates the staked balances of multiple accounts in a single batch operation. + * This is more efficient than updating staked balances individually as it + * triggers only one state update. + * + * @param stakedBalances - Array of staked balance updates, each containing address, chainId, and stakedBalance. + */ +export type AccountTrackerControllerUpdateStakedBalancesAction = { + type: `AccountTrackerController:updateStakedBalances`; + handler: AccountTrackerController['updateStakedBalances']; +}; + +/** + * Union of all AccountTrackerController action types. + */ +export type AccountTrackerControllerMethodActions = + | AccountTrackerControllerUpdateNativeBalancesAction + | AccountTrackerControllerUpdateStakedBalancesAction; diff --git a/packages/assets-controllers/src/AccountTrackerController.ts b/packages/assets-controllers/src/AccountTrackerController.ts index 089c9c9e24f..e7748a518d0 100644 --- a/packages/assets-controllers/src/AccountTrackerController.ts +++ b/packages/assets-controllers/src/AccountTrackerController.ts @@ -44,6 +44,7 @@ import type { Hex } from '@metamask/utils'; import { Mutex } from 'async-mutex'; import { cloneDeep, isEqual } from 'lodash'; +import type { AccountTrackerControllerMethodActions } from './AccountTrackerController-method-action-types'; import { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from './AssetsContractController'; import type { AssetsContractController, @@ -165,29 +166,12 @@ export type AccountTrackerControllerGetStateAction = ControllerGetStateAction< AccountTrackerControllerState >; -/** - * The action that can be performed to update multiple native token balances in batch. - */ -export type AccountTrackerUpdateNativeBalancesAction = { - type: `${typeof controllerName}:updateNativeBalances`; - handler: AccountTrackerController['updateNativeBalances']; -}; - -/** - * The action that can be performed to update multiple staked balances in batch. - */ -export type AccountTrackerUpdateStakedBalancesAction = { - type: `${typeof controllerName}:updateStakedBalances`; - handler: AccountTrackerController['updateStakedBalances']; -}; - /** * The actions that can be performed using the {@link AccountTrackerController}. */ export type AccountTrackerControllerActions = | AccountTrackerControllerGetStateAction - | AccountTrackerUpdateNativeBalancesAction - | AccountTrackerUpdateStakedBalancesAction; + | AccountTrackerControllerMethodActions; /** * The messenger of the {@link AccountTrackerController} for communication. @@ -246,6 +230,11 @@ type AccountTrackerPollingInput = { queryAllAccounts?: boolean; }; +const MESSENGER_EXPOSED_METHODS = [ + 'updateNativeBalances', + 'updateStakedBalances', +] as const; + /** * Controller that tracks the network balances for all user accounts. */ @@ -426,7 +415,7 @@ export class AccountTrackerController extends StaticIntervalPollingController = { - [ClassMethod in keyof Controller as Controller[ClassMethod] extends ActionConstraint['handler'] - ? ClassMethod - : never]: { - type: `${typeof name}:${ClassMethod & string}`; - handler: Controller[ClassMethod]; - }; -}; - -type AssetsContractControllerActionsMap = - ControllerActionsMap; - -/** - * The union of all public class method names of {@link AssetsContractController}. - */ -type AssetsContractControllerMethodName = - keyof AssetsContractControllerActionsMap; - /** * The union of all internal messenger actions available to the {@link AssetsContractControllerMessenger}. */ export type AssetsContractControllerActions = - AssetsContractControllerActionsMap[AssetsContractControllerMethodName]; - -export type AssetsContractControllerGetERC20StandardAction = - AssetsContractControllerActionsMap['getERC20Standard']; - -export type AssetsContractControllerGetERC721StandardAction = - AssetsContractControllerActionsMap['getERC721Standard']; - -export type AssetsContractControllerGetERC1155StandardAction = - AssetsContractControllerActionsMap['getERC1155Standard']; - -export type AssetsContractControllerGetERC20BalanceOfAction = - AssetsContractControllerActionsMap['getERC20BalanceOf']; - -export type AssetsContractControllerGetERC20TokenDecimalsAction = - AssetsContractControllerActionsMap['getERC20TokenDecimals']; - -export type AssetsContractControllerGetERC20TokenNameAction = - AssetsContractControllerActionsMap['getERC20TokenName']; - -export type AssetsContractControllerGetERC721NftTokenIdAction = - AssetsContractControllerActionsMap['getERC721NftTokenId']; - -export type AssetsContractControllerGetERC721TokenURIAction = - AssetsContractControllerActionsMap['getERC721TokenURI']; - -export type AssetsContractControllerGetERC721AssetNameAction = - AssetsContractControllerActionsMap['getERC721AssetName']; - -export type AssetsContractControllerGetERC721AssetSymbolAction = - AssetsContractControllerActionsMap['getERC721AssetSymbol']; - -export type AssetsContractControllerGetERC721OwnerOfAction = - AssetsContractControllerActionsMap['getERC721OwnerOf']; - -export type AssetsContractControllerGetERC1155TokenURIAction = - AssetsContractControllerActionsMap['getERC1155TokenURI']; - -export type AssetsContractControllerGetERC1155BalanceOfAction = - AssetsContractControllerActionsMap['getERC1155BalanceOf']; - -export type AssetsContractControllerTransferSingleERC1155Action = - AssetsContractControllerActionsMap['transferSingleERC1155']; - -export type AssetsContractControllerGetTokenStandardAndDetailsAction = - AssetsContractControllerActionsMap['getTokenStandardAndDetails']; - -export type AssetsContractControllerGetBalancesInSingleCallAction = - AssetsContractControllerActionsMap['getBalancesInSingleCall']; + AssetsContractControllerMethodActions; /** * The union of all internal messenger events available to the {@link AssetsContractControllerMessenger}. @@ -211,6 +138,26 @@ export type AssetsContractControllerMessenger = Messenger< export type StakedBalance = string | undefined; +const MESSENGER_EXPOSED_METHODS = [ + 'getERC20Standard', + 'getERC721Standard', + 'getERC1155Standard', + 'getERC20BalanceOf', + 'getERC20TokenDecimals', + 'getERC20TokenName', + 'getERC721NftTokenId', + 'getERC721TokenURI', + 'getERC721AssetName', + 'getERC721AssetSymbol', + 'getERC721OwnerOf', + 'getERC1155TokenURI', + 'getERC1155BalanceOf', + 'transferSingleERC1155', + 'getTokenStandardAndDetails', + 'getBalancesInSingleCall', + 'getStakedBalanceForChain', +] as const; + /** * Controller that interacts with contracts on mainnet through web3 */ @@ -244,39 +191,10 @@ export class AssetsContractController { this.#ipfsGateway = IPFS_DEFAULT_GATEWAY_URL; this.#chainId = initialChainId; - this.#registerActionHandlers(); + messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); this.#registerEventSubscriptions(); } - // TODO: Expand into base-controller utility function that batch registers action handlers. - #registerActionHandlers() { - const methodsExcludedFromMessenger = [ - 'constructor', - 'messenger', - 'setProvider', - 'provider', - 'ipfsGateway', - 'chainId', - ]; - - getKnownPropertyNames(Object.getPrototypeOf(this)).forEach( - (method) => { - if ( - ((key: keyof this): key is AssetsContractControllerMethodName => - !methodsExcludedFromMessenger.find((e) => e === key) && - typeof this[key] === 'function')(method) - ) { - this.messenger.registerActionHandler( - `${name}:${method}`, - // TODO: Write a generic for-loop implementation that iterates over an input union type in tandem with the input array. - // @ts-expect-error Both assigned argument and assignee parameter are using the entire union type for `method` instead of the type for the current element - this[method].bind(this), - ); - } - }, - ); - } - #registerEventSubscriptions() { this.messenger.subscribe( `PreferencesController:stateChange`, diff --git a/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController-method-action-types.ts b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController-method-action-types.ts new file mode 100644 index 00000000000..1d1163ea8ad --- /dev/null +++ b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController-method-action-types.ts @@ -0,0 +1,50 @@ +/** + * This file is auto generated by `scripts/generate-method-action-types.ts`. + * Do not edit manually. + */ + +import type { MultichainAssetsController } from './MultichainAssetsController'; + +/** + * Returns the metadata for the given asset + * + * @param asset - The asset to get metadata for + * @returns The metadata for the asset or undefined if not found. + */ +export type MultichainAssetsControllerGetAssetMetadataAction = { + type: `MultichainAssetsController:getAssetMetadata`; + handler: MultichainAssetsController['getAssetMetadata']; +}; + +/** + * Ignores a batch of assets for a specific account. + * + * @param assetsToIgnore - Array of asset IDs to ignore. + * @param accountId - The account ID to ignore assets for. + */ +export type MultichainAssetsControllerIgnoreAssetsAction = { + type: `MultichainAssetsController:ignoreAssets`; + handler: MultichainAssetsController['ignoreAssets']; +}; + +/** + * Adds multiple assets to the stored asset list for a specific account. + * All assets must belong to the same chain. + * + * @param assetIds - Array of CAIP asset IDs to add (must be from same chain). + * @param accountId - The account ID to add the assets to. + * @returns The updated asset list for the account. + * @throws Error if assets are from different chains. + */ +export type MultichainAssetsControllerAddAssetsAction = { + type: `MultichainAssetsController:addAssets`; + handler: MultichainAssetsController['addAssets']; +}; + +/** + * Union of all MultichainAssetsController action types. + */ +export type MultichainAssetsControllerMethodActions = + | MultichainAssetsControllerGetAssetMetadataAction + | MultichainAssetsControllerIgnoreAssetsAction + | MultichainAssetsControllerAddAssetsAction; diff --git a/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts index 1c46be237cb..76c08b6e5bb 100644 --- a/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts +++ b/packages/assets-controllers/src/MultichainAssetsController/MultichainAssetsController.ts @@ -41,6 +41,7 @@ import type { Json, JsonRpcRequest } from '@metamask/utils'; import type { MutexInterface } from 'async-mutex'; import { Mutex } from 'async-mutex'; +import type { MultichainAssetsControllerMethodActions } from './MultichainAssetsController-method-action-types'; import { getChainIdsCaveat } from './utils'; const controllerName = 'MultichainAssetsController'; @@ -77,21 +78,6 @@ export function getDefaultMultichainAssetsControllerState(): MultichainAssetsCon return { accountsAssets: {}, assetsMetadata: {}, allIgnoredAssets: {} }; } -export type MultichainAssetsControllerGetAssetMetadataAction = { - type: `${typeof controllerName}:getAssetMetadata`; - handler: MultichainAssetsController['getAssetMetadata']; -}; - -export type MultichainAssetsControllerIgnoreAssetsAction = { - type: `${typeof controllerName}:ignoreAssets`; - handler: MultichainAssetsController['ignoreAssets']; -}; - -export type MultichainAssetsControllerAddAssetsAction = { - type: `${typeof controllerName}:addAssets`; - handler: MultichainAssetsController['addAssets']; -}; - /** * Returns the state of the {@link MultichainAssetsController}. */ @@ -114,9 +100,7 @@ export type MultichainAssetsControllerStateChangeEvent = */ export type MultichainAssetsControllerActions = | MultichainAssetsControllerGetStateAction - | MultichainAssetsControllerGetAssetMetadataAction - | MultichainAssetsControllerIgnoreAssetsAction - | MultichainAssetsControllerAddAssetsAction; + | MultichainAssetsControllerMethodActions; /** * Events emitted by {@link MultichainAssetsController}. @@ -193,6 +177,12 @@ const assetsControllerMetadata: StateMetadata = }, }; +const MESSENGER_EXPOSED_METHODS = [ + 'getAssetMetadata', + 'ignoreAssets', + 'addAssets', +] as const; + // TODO: make this controller extends StaticIntervalPollingController and update all assetsMetadata once a day. export class MultichainAssetsController extends BaseController< @@ -237,7 +227,7 @@ export class MultichainAssetsController extends BaseController< async (event) => await this.#handleAccountAssetListUpdatedEvent(event), ); - this.#registerMessageHandlers(); + messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); } async #handleAccountAssetListUpdatedEvent( @@ -254,27 +244,6 @@ export class MultichainAssetsController extends BaseController< ); } - /** - * Constructor helper for registering the controller's messaging system - * actions. - */ - #registerMessageHandlers() { - this.messenger.registerActionHandler( - 'MultichainAssetsController:getAssetMetadata', - this.getAssetMetadata.bind(this), - ); - - this.messenger.registerActionHandler( - 'MultichainAssetsController:ignoreAssets', - this.ignoreAssets.bind(this), - ); - - this.messenger.registerActionHandler( - 'MultichainAssetsController:addAssets', - this.addAssets.bind(this), - ); - } - /** * Returns the metadata for the given asset * diff --git a/packages/assets-controllers/src/MultichainAssetsController/index.ts b/packages/assets-controllers/src/MultichainAssetsController/index.ts index bfe10978eb8..2ad53646897 100644 --- a/packages/assets-controllers/src/MultichainAssetsController/index.ts +++ b/packages/assets-controllers/src/MultichainAssetsController/index.ts @@ -12,3 +12,8 @@ export type { MultichainAssetsControllerAccountAssetListUpdatedEvent, MultichainAssetsControllerEvents, } from './MultichainAssetsController'; +export type { + MultichainAssetsControllerGetAssetMetadataAction, + MultichainAssetsControllerIgnoreAssetsAction, + MultichainAssetsControllerAddAssetsAction, +} from './MultichainAssetsController-method-action-types'; diff --git a/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController-method-action-types.ts b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController-method-action-types.ts new file mode 100644 index 00000000000..8e8c59b03ad --- /dev/null +++ b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController-method-action-types.ts @@ -0,0 +1,36 @@ +/** + * This file is auto generated by `scripts/generate-method-action-types.ts`. + * Do not edit manually. + */ + +import type { MultichainAssetsRatesController } from './MultichainAssetsRatesController'; + +/** + * Updates token conversion rates for each non-EVM account. + * + * @returns A promise that resolves when the rates are updated. + */ +export type MultichainAssetsRatesControllerUpdateAssetsRatesAction = { + type: `MultichainAssetsRatesController:updateAssetsRates`; + handler: MultichainAssetsRatesController['updateAssetsRates']; +}; + +/** + * Fetches historical prices for the current account + * + * @param asset - The asset to fetch historical prices for. + * @param account - optional account to fetch historical prices for + * @returns The historical prices. + */ +export type MultichainAssetsRatesControllerFetchHistoricalPricesForAssetAction = + { + type: `MultichainAssetsRatesController:fetchHistoricalPricesForAsset`; + handler: MultichainAssetsRatesController['fetchHistoricalPricesForAsset']; + }; + +/** + * Union of all MultichainAssetsRatesController action types. + */ +export type MultichainAssetsRatesControllerMethodActions = + | MultichainAssetsRatesControllerUpdateAssetsRatesAction + | MultichainAssetsRatesControllerFetchHistoricalPricesForAssetAction; diff --git a/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts index 08a231bee3f..bb448444913 100644 --- a/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts +++ b/packages/assets-controllers/src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts @@ -35,6 +35,7 @@ import { Mutex } from 'async-mutex'; import type { Draft } from 'immer'; import { MAP_CAIP_CURRENCIES } from './constant'; +import type { MultichainAssetsRatesControllerMethodActions } from './MultichainAssetsRatesController-method-action-types'; import type { CurrencyRateState, CurrencyRateStateChange, @@ -76,14 +77,6 @@ export type MultichainAssetsRatesControllerGetStateAction = MultichainAssetsRatesControllerState >; -/** - * Action to update the rates of all supported tokens. - */ -export type MultichainAssetsRatesControllerUpdateRatesAction = { - type: `${typeof controllerName}:updateAssetsRates`; - handler: MultichainAssetsRatesController['updateAssetsRates']; -}; - type UnifiedAssetConversion = AssetConversion & { marketData?: FungibleAssetMarketData; }; @@ -114,7 +107,7 @@ export type MultichainAssetsRatesControllerStateChange = */ export type MultichainAssetsRatesControllerActions = | MultichainAssetsRatesControllerGetStateAction - | MultichainAssetsRatesControllerUpdateRatesAction; + | MultichainAssetsRatesControllerMethodActions; /** * Events emitted by MultichainAssetsRatesController. @@ -188,6 +181,11 @@ type SnapRequestArgs = { params: T; }; +const MESSENGER_EXPOSED_METHODS = [ + 'updateAssetsRates', + 'fetchHistoricalPricesForAsset', +] as const; + /** * Controller that manages multichain token conversion rates. * @@ -233,6 +231,8 @@ export class MultichainAssetsRatesController extends StaticIntervalPollingContro this.setIntervalLength(interval); + messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); + // Subscribe to keyring lock/unlock events. this.messenger.subscribe('KeyringController:lock', () => { this.#isUnlocked = false; diff --git a/packages/assets-controllers/src/MultichainAssetsRatesController/index.ts b/packages/assets-controllers/src/MultichainAssetsRatesController/index.ts index b6c70944258..c285191f15f 100644 --- a/packages/assets-controllers/src/MultichainAssetsRatesController/index.ts +++ b/packages/assets-controllers/src/MultichainAssetsRatesController/index.ts @@ -6,6 +6,10 @@ export type { MultichainAssetsRatesControllerStateChange, MultichainAssetsRatesControllerMessenger, } from './MultichainAssetsRatesController'; +export type { + MultichainAssetsRatesControllerUpdateAssetsRatesAction, + MultichainAssetsRatesControllerFetchHistoricalPricesForAssetAction, +} from './MultichainAssetsRatesController-method-action-types'; export { MultichainAssetsRatesController, diff --git a/packages/assets-controllers/src/NftController.ts b/packages/assets-controllers/src/NftController.ts index 8d2bf8a5515..9e71b7ef5c4 100644 --- a/packages/assets-controllers/src/NftController.ts +++ b/packages/assets-controllers/src/NftController.ts @@ -49,7 +49,7 @@ import type { AssetsContractControllerGetERC721AssetSymbolAction, AssetsContractControllerGetERC721OwnerOfAction, AssetsContractControllerGetERC721TokenURIAction, -} from './AssetsContractController'; +} from './AssetsContractController-method-action-types'; import { compareNftMetadata, getFormattedIpfsUrl, diff --git a/packages/assets-controllers/src/TokenBalancesController-method-action-types.ts b/packages/assets-controllers/src/TokenBalancesController-method-action-types.ts new file mode 100644 index 00000000000..39ad0d2e8f5 --- /dev/null +++ b/packages/assets-controllers/src/TokenBalancesController-method-action-types.ts @@ -0,0 +1,23 @@ +/** + * This file is auto generated by `scripts/generate-method-action-types.ts`. + * Do not edit manually. + */ + +import type { TokenBalancesController } from './TokenBalancesController'; + +export type TokenBalancesControllerGetChainPollingConfigAction = { + type: `TokenBalancesController:getChainPollingConfig`; + handler: TokenBalancesController['getChainPollingConfig']; +}; + +export type TokenBalancesControllerUpdateChainPollingConfigsAction = { + type: `TokenBalancesController:updateChainPollingConfigs`; + handler: TokenBalancesController['updateChainPollingConfigs']; +}; + +/** + * Union of all TokenBalancesController action types. + */ +export type TokenBalancesControllerMethodActions = + | TokenBalancesControllerGetChainPollingConfigAction + | TokenBalancesControllerUpdateChainPollingConfigsAction; diff --git a/packages/assets-controllers/src/TokenBalancesController.ts b/packages/assets-controllers/src/TokenBalancesController.ts index 316c8e4f7ab..b5b1a67cb8e 100644 --- a/packages/assets-controllers/src/TokenBalancesController.ts +++ b/packages/assets-controllers/src/TokenBalancesController.ts @@ -56,11 +56,11 @@ import { import { produce } from 'immer'; import { isEqual } from 'lodash'; +import type { AccountTrackerControllerGetStateAction } from './AccountTrackerController'; import type { - AccountTrackerControllerGetStateAction, - AccountTrackerUpdateNativeBalancesAction, - AccountTrackerUpdateStakedBalancesAction, -} from './AccountTrackerController'; + AccountTrackerControllerUpdateNativeBalancesAction, + AccountTrackerControllerUpdateStakedBalancesAction, +} from './AccountTrackerController-method-action-types'; import { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from './AssetsContractController'; import { AccountsApiBalanceFetcher } from './multi-chain-accounts-service/api-balance-fetcher'; import type { @@ -69,11 +69,12 @@ import type { UnprocessedTokens, } from './multi-chain-accounts-service/api-balance-fetcher'; import { RpcBalanceFetcher } from './rpc-service/rpc-balance-fetcher'; +import type { TokenBalancesControllerMethodActions } from './TokenBalancesController-method-action-types'; import type { TokenDetectionControllerAddDetectedTokensViaPollingAction, TokenDetectionControllerAddDetectedTokensViaWsAction, TokenDetectionControllerDetectTokensAction, -} from './TokenDetectionController'; +} from './TokenDetectionController-method-action-types'; import type { TokensControllerGetStateAction, TokensControllerState, @@ -111,20 +112,9 @@ export type TokenBalancesControllerGetStateAction = ControllerGetStateAction< TokenBalancesControllerState >; -export type TokenBalancesControllerUpdateChainPollingConfigsAction = { - type: `TokenBalancesController:updateChainPollingConfigs`; - handler: TokenBalancesController['updateChainPollingConfigs']; -}; - -export type TokenBalancesControllerGetChainPollingConfigAction = { - type: `TokenBalancesController:getChainPollingConfig`; - handler: TokenBalancesController['getChainPollingConfig']; -}; - export type TokenBalancesControllerActions = | TokenBalancesControllerGetStateAction - | TokenBalancesControllerUpdateChainPollingConfigsAction - | TokenBalancesControllerGetChainPollingConfigAction; + | TokenBalancesControllerMethodActions; export type TokenBalancesControllerStateChangeEvent = ControllerStateChangeEvent; @@ -149,8 +139,8 @@ export type AllowedActions = | AccountsControllerGetSelectedAccountAction | AccountsControllerListAccountsAction | AccountTrackerControllerGetStateAction - | AccountTrackerUpdateNativeBalancesAction - | AccountTrackerUpdateStakedBalancesAction + | AccountTrackerControllerUpdateNativeBalancesAction + | AccountTrackerControllerUpdateStakedBalancesAction | KeyringControllerGetStateAction | AuthenticationController.AuthenticationControllerGetBearerTokenAction; @@ -262,6 +252,11 @@ type StakedBalanceUpdate = { chainId: Hex; stakedBalance: Hex; }; +const MESSENGER_EXPOSED_METHODS = [ + 'updateChainPollingConfigs', + 'getChainPollingConfig', +] as const; + export class TokenBalancesController extends StaticIntervalPollingController<{ chainIds: ChainIdHex[]; }>()< @@ -378,7 +373,7 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ this.#isUnlocked = isUnlocked; this.#subscribeToControllers(); - this.#registerActions(); + messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); } #subscribeToControllers(): void { @@ -451,18 +446,6 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ ); } - #registerActions(): void { - this.messenger.registerActionHandler( - `TokenBalancesController:updateChainPollingConfigs`, - this.updateChainPollingConfigs.bind(this), - ); - - this.messenger.registerActionHandler( - `TokenBalancesController:getChainPollingConfig`, - this.getChainPollingConfig.bind(this), - ); - } - /** * Whether the controller is active (keyring is unlocked and user is onboarded). * When locked or not onboarded, balance updates should be skipped. @@ -1512,13 +1495,6 @@ export class TokenBalancesController extends StaticIntervalPollingController<{ this.#statusChangeDebouncer.timer = null; } - this.messenger.unregisterActionHandler( - `TokenBalancesController:updateChainPollingConfigs`, - ); - this.messenger.unregisterActionHandler( - `TokenBalancesController:getChainPollingConfig`, - ); - super.destroy(); } } diff --git a/packages/assets-controllers/src/TokenDetectionController-method-action-types.ts b/packages/assets-controllers/src/TokenDetectionController-method-action-types.ts new file mode 100644 index 00000000000..76d99847bc8 --- /dev/null +++ b/packages/assets-controllers/src/TokenDetectionController-method-action-types.ts @@ -0,0 +1,104 @@ +/** + * This file is auto generated by `scripts/generate-method-action-types.ts`. + * Do not edit manually. + */ + +import type { TokenDetectionController } from './TokenDetectionController'; + +/** + * Allows controller to make active and passive polling requests + */ +export type TokenDetectionControllerEnableAction = { + type: `TokenDetectionController:enable`; + handler: TokenDetectionController['enable']; +}; + +/** + * Blocks controller from making network calls + */ +export type TokenDetectionControllerDisableAction = { + type: `TokenDetectionController:disable`; + handler: TokenDetectionController['disable']; +}; + +/** + * Start polling for detected tokens. + */ +export type TokenDetectionControllerStartAction = { + type: `TokenDetectionController:start`; + handler: TokenDetectionController['start']; +}; + +/** + * Stop polling for detected tokens. + */ +export type TokenDetectionControllerStopAction = { + type: `TokenDetectionController:stop`; + handler: TokenDetectionController['stop']; +}; + +/** + * For each token in the token list provided by the TokenListController, checks the token's balance for the selected account address on the active network. + * On mainnet, if token detection is disabled in preferences, ERC20 token auto detection will be triggered for each contract address in the legacy token list from the @metamask/contract-metadata repo. + * + * @param options - Options for token detection. + * @param options.chainIds - The chain IDs of the network client to use. + * @param options.selectedAddress - the selectedAddress against which to detect for token balances. + * @param options.forceRpc - Force RPC-based token detection for all specified chains, + * bypassing external services check and ensuring RPC is used even for chains + * that might otherwise be handled by the Accounts API. + */ +export type TokenDetectionControllerDetectTokensAction = { + type: `TokenDetectionController:detectTokens`; + handler: TokenDetectionController['detectTokens']; +}; + +/** + * Add tokens detected from websocket balance updates + * This method: + * - Checks if useTokenDetection preference is enabled (skips if disabled) + * - Checks if external services are enabled (skips if disabled) + * - Tokens are expected to be in the tokensChainsCache with full metadata + * - Balance fetching is skipped since balances are provided by the websocket + * - Ignored tokens have been filtered out by the caller + * + * @param options - The options object + * @param options.tokensSlice - Array of token addresses detected from websocket (already filtered to exclude ignored tokens) + * @param options.chainId - Hex chain ID + * @returns Promise that resolves when tokens are added + */ +export type TokenDetectionControllerAddDetectedTokensViaWsAction = { + type: `TokenDetectionController:addDetectedTokensViaWs`; + handler: TokenDetectionController['addDetectedTokensViaWs']; +}; + +/** + * Add tokens detected from polling balance updates + * This method: + * - Checks if useTokenDetection preference is enabled (skips if disabled) + * - Checks if external services are enabled (skips if disabled) + * - Filters out tokens already in allTokens or allIgnoredTokens + * - Tokens are expected to be in the tokensChainsCache with full metadata + * - Balance fetching is skipped since balances are provided by the caller + * + * @param options - The options object + * @param options.tokensSlice - Array of token addresses detected from polling + * @param options.chainId - Hex chain ID + * @returns Promise that resolves when tokens are added + */ +export type TokenDetectionControllerAddDetectedTokensViaPollingAction = { + type: `TokenDetectionController:addDetectedTokensViaPolling`; + handler: TokenDetectionController['addDetectedTokensViaPolling']; +}; + +/** + * Union of all TokenDetectionController action types. + */ +export type TokenDetectionControllerMethodActions = + | TokenDetectionControllerEnableAction + | TokenDetectionControllerDisableAction + | TokenDetectionControllerStartAction + | TokenDetectionControllerStopAction + | TokenDetectionControllerDetectTokensAction + | TokenDetectionControllerAddDetectedTokensViaWsAction + | TokenDetectionControllerAddDetectedTokensViaPollingAction; diff --git a/packages/assets-controllers/src/TokenDetectionController.ts b/packages/assets-controllers/src/TokenDetectionController.ts index de7ce68be4f..89a724c8a58 100644 --- a/packages/assets-controllers/src/TokenDetectionController.ts +++ b/packages/assets-controllers/src/TokenDetectionController.ts @@ -44,6 +44,7 @@ import { isEqual, mapValues, isObject, get } from 'lodash'; import type { AssetsContractController } from './AssetsContractController'; import { isTokenDetectionSupportedForNetwork } from './assetsUtil'; import { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from './constants'; +import type { TokenDetectionControllerMethodActions } from './TokenDetectionController-method-action-types'; import type { GetTokenListState, TokenListMap, @@ -51,11 +52,11 @@ import type { TokensChainsCache, } from './TokenListController'; import type { Token } from './TokenRatesController'; +import type { TokensControllerGetStateAction } from './TokensController'; import type { TokensControllerAddDetectedTokensAction, TokensControllerAddTokensAction, - TokensControllerGetStateAction, -} from './TokensController'; +} from './TokensController-method-action-types'; const DEFAULT_INTERVAL = 180000; @@ -118,26 +119,9 @@ export type TokenDetectionControllerGetStateAction = ControllerGetStateAction< TokenDetectionState >; -export type TokenDetectionControllerAddDetectedTokensViaWsAction = { - type: `TokenDetectionController:addDetectedTokensViaWs`; - handler: TokenDetectionController['addDetectedTokensViaWs']; -}; - -export type TokenDetectionControllerAddDetectedTokensViaPollingAction = { - type: `TokenDetectionController:addDetectedTokensViaPolling`; - handler: TokenDetectionController['addDetectedTokensViaPolling']; -}; - -export type TokenDetectionControllerDetectTokensAction = { - type: `TokenDetectionController:detectTokens`; - handler: TokenDetectionController['detectTokens']; -}; - export type TokenDetectionControllerActions = | TokenDetectionControllerGetStateAction - | TokenDetectionControllerAddDetectedTokensViaWsAction - | TokenDetectionControllerAddDetectedTokensViaPollingAction - | TokenDetectionControllerDetectTokensAction; + | TokenDetectionControllerMethodActions; export type AllowedActions = | AccountsControllerGetSelectedAccountAction @@ -181,6 +165,16 @@ type TokenDetectionPollingInput = { address: string; }; +const MESSENGER_EXPOSED_METHODS = [ + 'addDetectedTokensViaWs', + 'addDetectedTokensViaPolling', + 'detectTokens', + 'enable', + 'disable', + 'start', + 'stop', +] as const; + /** * Controller that passively polls on a set interval for Tokens auto detection * @@ -278,20 +272,7 @@ export class TokenDetectionController extends StaticIntervalPollingController = { const controllerName = 'TokensController'; -export type TokensControllerActions = - | TokensControllerGetStateAction - | TokensControllerAddDetectedTokensAction - | TokensControllerAddTokensAction; - export type TokensControllerGetStateAction = ControllerGetStateAction< typeof controllerName, TokensControllerState >; -export type TokensControllerAddDetectedTokensAction = { - type: `${typeof controllerName}:addDetectedTokens`; - handler: TokensController['addDetectedTokens']; -}; - -export type TokensControllerAddTokensAction = { - type: `${typeof controllerName}:addTokens`; - handler: TokensController['addTokens']; -}; +export type TokensControllerActions = + | TokensControllerGetStateAction + | TokensControllerMethodActions; /** * The external actions available to the {@link TokensController}. @@ -192,6 +182,17 @@ export const getDefaultTokensState = (): TokensControllerState => { }; }; +const MESSENGER_EXPOSED_METHODS = [ + 'addDetectedTokens', + 'addTokens', + 'addToken', + 'ignoreTokens', + 'updateTokenType', + 'watchAsset', + 'clearIgnoredTokens', + 'resetState', +] as const; + /** * Controller that stores assets and exposes convenience methods */ @@ -243,15 +244,7 @@ export class TokensController extends BaseController< this.#abortController = new AbortController(); - this.messenger.registerActionHandler( - `${controllerName}:addDetectedTokens` as const, - this.addDetectedTokens.bind(this), - ); - - this.messenger.registerActionHandler( - `${controllerName}:addTokens` as const, - this.addTokens.bind(this), - ); + messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); this.messenger.subscribe( 'AccountsController:selectedEvmAccountChange', @@ -768,7 +761,7 @@ export class TokensController extends BaseController< async updateTokenType( tokenAddress: string, networkClientId: NetworkClientId, - ) { + ): Promise { const chainIdToUse = this.messenger.call( 'NetworkController:getNetworkClientById', networkClientId, diff --git a/packages/assets-controllers/src/index.ts b/packages/assets-controllers/src/index.ts index 1692c36db60..7bfd3752fd3 100644 --- a/packages/assets-controllers/src/index.ts +++ b/packages/assets-controllers/src/index.ts @@ -6,13 +6,19 @@ export type { AccountTrackerControllerGetStateAction, AccountTrackerControllerStateChangeEvent, AccountTrackerControllerEvents, - AccountTrackerUpdateNativeBalancesAction, - AccountTrackerUpdateStakedBalancesAction, } from './AccountTrackerController'; export { AccountTrackerController } from './AccountTrackerController'; +export type { + AccountTrackerControllerUpdateNativeBalancesAction, + AccountTrackerControllerUpdateStakedBalancesAction, +} from './AccountTrackerController-method-action-types'; export type { AssetsContractControllerActions, AssetsContractControllerEvents, + AssetsContractControllerMessenger, + BalanceMap, +} from './AssetsContractController'; +export type { AssetsContractControllerGetERC20StandardAction, AssetsContractControllerGetERC721StandardAction, AssetsContractControllerGetERC1155StandardAction, @@ -29,9 +35,8 @@ export type { AssetsContractControllerTransferSingleERC1155Action, AssetsContractControllerGetTokenStandardAndDetailsAction, AssetsContractControllerGetBalancesInSingleCallAction, - AssetsContractControllerMessenger, - BalanceMap, -} from './AssetsContractController'; + AssetsContractControllerGetStakedBalanceForChainAction, +} from './AssetsContractController-method-action-types'; export { SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID, AssetsContractController, @@ -83,16 +88,26 @@ export type { TokenBalancesControllerState, } from './TokenBalancesController'; export { TokenBalancesController } from './TokenBalancesController'; +export type { + TokenBalancesControllerUpdateChainPollingConfigsAction, + TokenBalancesControllerGetChainPollingConfigAction, +} from './TokenBalancesController-method-action-types'; export type { TokenDetectionControllerMessenger, TokenDetectionControllerActions, TokenDetectionControllerGetStateAction, - TokenDetectionControllerDetectTokensAction, - TokenDetectionControllerAddDetectedTokensViaWsAction, - TokenDetectionControllerAddDetectedTokensViaPollingAction, TokenDetectionControllerEvents, TokenDetectionControllerStateChangeEvent, } from './TokenDetectionController'; +export type { + TokenDetectionControllerEnableAction, + TokenDetectionControllerDisableAction, + TokenDetectionControllerStartAction, + TokenDetectionControllerStopAction, + TokenDetectionControllerDetectTokensAction, + TokenDetectionControllerAddDetectedTokensViaWsAction, + TokenDetectionControllerAddDetectedTokensViaPollingAction, +} from './TokenDetectionController-method-action-types'; export { TokenDetectionController } from './TokenDetectionController'; export type { TokenListState, @@ -125,12 +140,20 @@ export type { TokensControllerState, TokensControllerActions, TokensControllerGetStateAction, - TokensControllerAddDetectedTokensAction, - TokensControllerAddTokensAction, TokensControllerEvents, TokensControllerStateChangeEvent, TokensControllerMessenger, } from './TokensController'; +export type { + TokensControllerAddTokenAction, + TokensControllerAddTokensAction, + TokensControllerIgnoreTokensAction, + TokensControllerAddDetectedTokensAction, + TokensControllerUpdateTokenTypeAction, + TokensControllerWatchAssetAction, + TokensControllerClearIgnoredTokensAction, + TokensControllerResetStateAction, +} from './TokensController-method-action-types'; export { TokensController } from './TokensController'; export { isTokenDetectionSupportedForNetwork, @@ -184,6 +207,11 @@ export type { MultichainAssetsControllerAccountAssetListUpdatedEvent, MultichainAssetsControllerMessenger, } from './MultichainAssetsController'; +export type { + MultichainAssetsControllerGetAssetMetadataAction, + MultichainAssetsControllerIgnoreAssetsAction, + MultichainAssetsControllerAddAssetsAction, +} from './MultichainAssetsController/MultichainAssetsController-method-action-types'; export { MultichainAssetsRatesController, @@ -199,6 +227,12 @@ export type { MultichainAssetsRatesControllerStateChange, MultichainAssetsRatesControllerMessenger, } from './MultichainAssetsRatesController'; + +export type { + MultichainAssetsRatesControllerUpdateAssetsRatesAction, + MultichainAssetsRatesControllerFetchHistoricalPricesForAssetAction, +} from './MultichainAssetsRatesController/MultichainAssetsRatesController-method-action-types'; + export { TokenSearchDiscoveryDataController } from './TokenSearchDiscoveryDataController'; export type { TokenDisplayData, diff --git a/packages/network-enablement-controller/CHANGELOG.md b/packages/network-enablement-controller/CHANGELOG.md index da653123f30..c6375e3b027 100644 --- a/packages/network-enablement-controller/CHANGELOG.md +++ b/packages/network-enablement-controller/CHANGELOG.md @@ -7,8 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Expose missing public `NetworkEnablementController` methods through its messenger ([#8164](https://github.com/MetaMask/core/pull/8164)) + - The following actions are now available: + - `NetworkEnablementController:init` + - `NetworkEnablementController:initNativeAssetIdentifiers` + - `NetworkEnablementController:enableNetworkInNamespace` + - `NetworkEnablementController:enableAllPopularNetworks` + - `NetworkEnablementController:isNetworkEnabled` + - Corresponding action type (`NetworkEnablementControllerIsNetworkEnabledAction`) is available as well. + ### Changed +- **BREAKING:** Standardize names of `NetworkEnablementController` messenger action types ([#8164](https://github.com/MetaMask/core/pull/8164)) + - The `NetworkEnablementController` action `NetworkEnablementControllerSetEnabledNetworksAction` has been renamed to `NetworkEnablementControllerEnableNetworkAction` so it matches the method name. + - These changes only affect the types. The action type strings themselves have not changed, so you do not need to update the list of actions you pass when initializing `NetworkEnablementController` messengers. - Bump `@metamask/multichain-network-controller` from `^3.0.4` to `^3.0.5` ([#8140](https://github.com/MetaMask/core/pull/8140)) - Bump `@metamask/transaction-controller` from `^62.20.0` to `^62.21.0` ([#8140](https://github.com/MetaMask/core/pull/8140)) diff --git a/packages/network-enablement-controller/package.json b/packages/network-enablement-controller/package.json index 28d0de10520..9ff93b3136b 100644 --- a/packages/network-enablement-controller/package.json +++ b/packages/network-enablement-controller/package.json @@ -40,6 +40,7 @@ "build:docs": "typedoc", "changelog:update": "../../scripts/update-changelog.sh @metamask/network-enablement-controller", "changelog:validate": "../../scripts/validate-changelog.sh @metamask/network-enablement-controller", + "generate-method-action-types": "tsx ../../scripts/generate-method-action-types.ts", "since-latest-release": "../../scripts/since-latest-release.sh", "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", "test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache", @@ -65,6 +66,7 @@ "deepmerge": "^4.2.2", "jest": "^29.7.0", "ts-jest": "^29.2.5", + "tsx": "^4.20.5", "typedoc": "^0.25.13", "typedoc-plugin-missing-exports": "^2.0.0", "typescript": "~5.3.3" diff --git a/packages/network-enablement-controller/src/NetworkEnablementController-method-action-types.ts b/packages/network-enablement-controller/src/NetworkEnablementController-method-action-types.ts new file mode 100644 index 00000000000..293f2623e5a --- /dev/null +++ b/packages/network-enablement-controller/src/NetworkEnablementController-method-action-types.ts @@ -0,0 +1,192 @@ +/** + * This file is auto generated by `scripts/generate-method-action-types.ts`. + * Do not edit manually. + */ + +import type { NetworkEnablementController } from './NetworkEnablementController'; + +/** + * Enables or disables a network for the user. + * + * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID + * (for any blockchain network). The method will automatically convert Hex chain IDs + * to CAIP-2 format internally. This dual parameter support allows for backward + * compatibility with existing EVM chain ID formats while supporting newer + * multi-chain standards. + * + * When enabling a non-popular network, this method will disable all other networks + * to ensure only one network is active at a time (exclusive mode). + * + * @param chainId - The chain ID of the network to enable or disable. Can be either: + * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks + * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana) + */ +export type NetworkEnablementControllerEnableNetworkAction = { + type: `NetworkEnablementController:enableNetwork`; + handler: NetworkEnablementController['enableNetwork']; +}; + +/** + * Enables a network for the user within a specific namespace. + * + * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID + * (for any blockchain network) and enables it within the specified namespace. + * The method validates that the chainId belongs to the specified namespace for safety. + * + * Before enabling the target network, this method disables all other networks + * in the same namespace to ensure exclusive behavior within the namespace. + * + * @param chainId - The chain ID of the network to enable. Can be either: + * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks + * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana) + * @param namespace - The CAIP namespace where the network should be enabled + * @throws Error if the chainId's derived namespace doesn't match the provided namespace + */ +export type NetworkEnablementControllerEnableNetworkInNamespaceAction = { + type: `NetworkEnablementController:enableNetworkInNamespace`; + handler: NetworkEnablementController['enableNetworkInNamespace']; +}; + +/** + * Enables all popular networks and Solana mainnet. + * + * This method first disables all networks across all namespaces, then enables + * all networks defined in POPULAR_NETWORKS (EVM networks), Solana mainnet, and + * Bitcoin mainnet. This provides exclusive behavior - only popular networks will + * be enabled after calling this method. + * + * Popular networks that don't exist in NetworkController or MultichainNetworkController configurations will be skipped silently. + */ +export type NetworkEnablementControllerEnableAllPopularNetworksAction = { + type: `NetworkEnablementController:enableAllPopularNetworks`; + handler: NetworkEnablementController['enableAllPopularNetworks']; +}; + +/** + * Initializes the network enablement state from network controller configurations. + * + * This method reads the current network configurations from both NetworkController + * and MultichainNetworkController and syncs the enabled network map and nativeAssetIdentifiers accordingly. + * It ensures proper namespace buckets exist for all configured networks and only + * adds missing networks with a default value of false, preserving existing user settings. + * + * This method should be called after the NetworkController and MultichainNetworkController + * have been initialized and their configurations are available. + */ +export type NetworkEnablementControllerInitAction = { + type: `NetworkEnablementController:init`; + handler: NetworkEnablementController['init']; +}; + +/** + * Initializes the native asset identifiers from network configurations. + * This method should be called from the client during controller initialization + * to populate the nativeAssetIdentifiers state based on actual network configurations. + * + * @param networks - Array of network configurations with chainId and nativeCurrency + * @example + * ```typescript + * const evmNetworks = Object.values(networkControllerState.networkConfigurationsByChainId) + * .map(config => ({ + * chainId: toEvmCaipChainId(config.chainId), + * nativeCurrency: config.nativeCurrency, + * })); + * + * const multichainNetworks = Object.values(multichainState.multichainNetworkConfigurationsByChainId) + * .map(config => ({ + * chainId: config.chainId, + * nativeCurrency: config.nativeCurrency, + * })); + * + * await controller.initNativeAssetIdentifiers([...evmNetworks, ...multichainNetworks]); + * ``` + */ +export type NetworkEnablementControllerInitNativeAssetIdentifiersAction = { + type: `NetworkEnablementController:initNativeAssetIdentifiers`; + handler: NetworkEnablementController['initNativeAssetIdentifiers']; +}; + +/** + * Disables a network for the user. + * + * This method accepts either a Hex chain ID (for EVM networks) or a CAIP-2 chain ID + * (for any blockchain network). The method will automatically convert Hex chain IDs + * to CAIP-2 format internally. + * + * Note: This method will prevent disabling the last remaining enabled network + * to ensure at least one network is always available. + * + * @param chainId - The chain ID of the network to disable. Can be either: + * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks + * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana) + */ +export type NetworkEnablementControllerDisableNetworkAction = { + type: `NetworkEnablementController:disableNetwork`; + handler: NetworkEnablementController['disableNetwork']; +}; + +/** + * Checks if a network is enabled. + * + * @param chainId - The chain ID of the network to check. Can be either: + * - A Hex string (e.g., '0x1' for Ethereum mainnet) for EVM networks + * - A CAIP-2 chain ID (e.g., 'eip155:1' for Ethereum mainnet, 'solana:mainnet' for Solana) + * @returns True if the network is enabled, false otherwise + */ +export type NetworkEnablementControllerIsNetworkEnabledAction = { + type: `NetworkEnablementController:isNetworkEnabled`; + handler: NetworkEnablementController['isNetworkEnabled']; +}; + +/** + * Returns popular EVM network chain IDs in hex form, restricted to networks + * that exist in NetworkController (networkConfigurationsByChainId). Source list + * is POPULAR_NETWORKS. + * + * @returns Hex chain IDs for popular EVM networks that are configured. + */ +export type NetworkEnablementControllerListPopularEvmNetworksAction = { + type: `NetworkEnablementController:listPopularEvmNetworks`; + handler: NetworkEnablementController['listPopularEvmNetworks']; +}; + +/** + * Returns popular multichain (Bitcoin, Solana, Tron) 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. + */ +export type NetworkEnablementControllerListPopularMultichainNetworksAction = { + type: `NetworkEnablementController:listPopularMultichainNetworks`; + handler: NetworkEnablementController['listPopularMultichainNetworks']; +}; + +/** + * Returns the list of popular network chain IDs in CAIP-2 form, restricted to + * networks that exist in NetworkController (networkConfigurationsByChainId) and + * MultichainNetworkController (multichainNetworkConfigurationsByChainId). EVM + * popular networks come from POPULAR_NETWORKS; multichain popular are Bitcoin, + * Solana, and Tron mainnets. + * + * @returns CAIP-2 chain IDs for popular EVM networks and multichain mainnets that are configured. + */ +export type NetworkEnablementControllerListPopularNetworksAction = { + type: `NetworkEnablementController:listPopularNetworks`; + handler: NetworkEnablementController['listPopularNetworks']; +}; + +/** + * Union of all NetworkEnablementController action types. + */ +export type NetworkEnablementControllerMethodActions = + | NetworkEnablementControllerEnableNetworkAction + | NetworkEnablementControllerEnableNetworkInNamespaceAction + | NetworkEnablementControllerEnableAllPopularNetworksAction + | NetworkEnablementControllerInitAction + | NetworkEnablementControllerInitNativeAssetIdentifiersAction + | NetworkEnablementControllerDisableNetworkAction + | NetworkEnablementControllerIsNetworkEnabledAction + | NetworkEnablementControllerListPopularEvmNetworksAction + | NetworkEnablementControllerListPopularMultichainNetworksAction + | NetworkEnablementControllerListPopularNetworksAction; diff --git a/packages/network-enablement-controller/src/NetworkEnablementController.test.ts b/packages/network-enablement-controller/src/NetworkEnablementController.test.ts index e941c868e61..7acf9fc43b7 100644 --- a/packages/network-enablement-controller/src/NetworkEnablementController.test.ts +++ b/packages/network-enablement-controller/src/NetworkEnablementController.test.ts @@ -2180,10 +2180,7 @@ describe('NetworkEnablementController', () => { it('returns same result as calling messenger action when registered', () => { const { controller, rootMessenger } = setupController(); - rootMessenger.registerActionHandler( - 'NetworkEnablementController:listPopularNetworks', - () => controller.listPopularNetworks(), - ); + const viaAction = rootMessenger.call( 'NetworkEnablementController:listPopularNetworks', ); @@ -2215,10 +2212,7 @@ describe('NetworkEnablementController', () => { it('returns same result as calling messenger action when registered', () => { const { controller, rootMessenger } = setupController(); - rootMessenger.registerActionHandler( - 'NetworkEnablementController:listPopularEvmNetworks', - () => controller.listPopularEvmNetworks(), - ); + const viaAction = rootMessenger.call( 'NetworkEnablementController:listPopularEvmNetworks', ); @@ -2253,10 +2247,7 @@ describe('NetworkEnablementController', () => { it('returns same result as calling messenger action when registered', () => { const { controller, rootMessenger } = setupController(); - rootMessenger.registerActionHandler( - 'NetworkEnablementController:listPopularMultichainNetworks', - () => controller.listPopularMultichainNetworks(), - ); + const viaAction = rootMessenger.call( 'NetworkEnablementController:listPopularMultichainNetworks', ); diff --git a/packages/network-enablement-controller/src/NetworkEnablementController.ts b/packages/network-enablement-controller/src/NetworkEnablementController.ts index 7b9a4646d92..8ea80bcc983 100644 --- a/packages/network-enablement-controller/src/NetworkEnablementController.ts +++ b/packages/network-enablement-controller/src/NetworkEnablementController.ts @@ -19,6 +19,7 @@ import type { CaipChainId, CaipNamespace, Hex } from '@metamask/utils'; import { KnownCaipNamespace } from '@metamask/utils'; import { POPULAR_NETWORKS } from './constants'; +import type { NetworkEnablementControllerMethodActions } from './NetworkEnablementController-method-action-types'; import { Slip44Service } from './services'; import { deriveKeys, @@ -28,6 +29,19 @@ import { const controllerName = 'NetworkEnablementController'; +const MESSENGER_EXPOSED_METHODS = [ + 'init', + 'initNativeAssetIdentifiers', + 'enableNetwork', + 'disableNetwork', + 'enableNetworkInNamespace', + 'enableAllPopularNetworks', + 'isNetworkEnabled', + 'listPopularNetworks', + 'listPopularEvmNetworks', + 'listPopularMultichainNetworks', +] as const; + /** * Information about an ordered network. */ @@ -78,32 +92,6 @@ export type NetworkEnablementControllerGetStateAction = typeof controllerName, NetworkEnablementControllerState >; - -export type NetworkEnablementControllerSetEnabledNetworksAction = { - type: `${typeof controllerName}:enableNetwork`; - handler: NetworkEnablementController['enableNetwork']; -}; - -export type NetworkEnablementControllerDisableNetworkAction = { - type: `${typeof controllerName}:disableNetwork`; - handler: NetworkEnablementController['disableNetwork']; -}; - -export type NetworkEnablementControllerListPopularNetworksAction = { - type: `${typeof controllerName}:listPopularNetworks`; - handler: NetworkEnablementController['listPopularNetworks']; -}; - -export type NetworkEnablementControllerListPopularEvmNetworksAction = { - type: `${typeof controllerName}:listPopularEvmNetworks`; - handler: NetworkEnablementController['listPopularEvmNetworks']; -}; - -export type NetworkEnablementControllerListPopularMultichainNetworksAction = { - type: `${typeof controllerName}:listPopularMultichainNetworks`; - handler: NetworkEnablementController['listPopularMultichainNetworks']; -}; - /** * All actions that {@link NetworkEnablementController} calls internally. */ @@ -113,11 +101,7 @@ export type AllowedActions = export type NetworkEnablementControllerActions = | NetworkEnablementControllerGetStateAction - | NetworkEnablementControllerSetEnabledNetworksAction - | NetworkEnablementControllerDisableNetworkAction - | NetworkEnablementControllerListPopularNetworksAction - | NetworkEnablementControllerListPopularEvmNetworksAction - | NetworkEnablementControllerListPopularMultichainNetworksAction; + | NetworkEnablementControllerMethodActions; export type NetworkEnablementControllerStateChangeEvent = ControllerStateChangeEvent< @@ -259,6 +243,8 @@ export class NetworkEnablementController extends BaseController< }, }); + messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); + messenger.subscribe('NetworkController:networkAdded', ({ chainId }) => { // eslint-disable-next-line no-void void this.#onAddNetwork(chainId); diff --git a/packages/network-enablement-controller/src/index.ts b/packages/network-enablement-controller/src/index.ts index c2e58216d9f..c70fddb022c 100644 --- a/packages/network-enablement-controller/src/index.ts +++ b/packages/network-enablement-controller/src/index.ts @@ -6,14 +6,24 @@ export type { NetworkEnablementControllerActions, NetworkEnablementControllerEvents, NetworkEnablementControllerMessenger, - NetworkEnablementControllerListPopularNetworksAction, - NetworkEnablementControllerListPopularEvmNetworksAction, - NetworkEnablementControllerListPopularMultichainNetworksAction, NativeAssetIdentifier, NativeAssetIdentifiersMap, NetworkConfig, } from './NetworkEnablementController'; +export type { + NetworkEnablementControllerEnableNetworkAction, + NetworkEnablementControllerEnableNetworkInNamespaceAction, + NetworkEnablementControllerEnableAllPopularNetworksAction, + NetworkEnablementControllerInitAction, + NetworkEnablementControllerInitNativeAssetIdentifiersAction, + NetworkEnablementControllerDisableNetworkAction, + NetworkEnablementControllerIsNetworkEnabledAction, + NetworkEnablementControllerListPopularEvmNetworksAction, + NetworkEnablementControllerListPopularMultichainNetworksAction, + NetworkEnablementControllerListPopularNetworksAction, +} from './NetworkEnablementController-method-action-types'; + export { selectEnabledNetworkMap, selectIsNetworkEnabled, diff --git a/yarn.lock b/yarn.lock index 63f7cc32b7a..340ed9f876b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2868,6 +2868,7 @@ __metadata: reselect: "npm:^5.1.1" single-call-balance-checker-abi: "npm:^1.0.0" ts-jest: "npm:^29.2.5" + tsx: "npm:^4.20.5" typedoc: "npm:^0.25.13" typedoc-plugin-missing-exports: "npm:^2.0.0" typescript: "npm:~5.3.3" @@ -4552,6 +4553,7 @@ __metadata: jest: "npm:^29.7.0" reselect: "npm:^5.1.1" ts-jest: "npm:^29.2.5" + tsx: "npm:^4.20.5" typedoc: "npm:^0.25.13" typedoc-plugin-missing-exports: "npm:^2.0.0" typescript: "npm:~5.3.3"