@metamask/assets-controllers 53.1.0 → 54.0.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.
- package/CHANGELOG.md +21 -1
- package/dist/MultichainBalancesController/MultichainBalancesController.cjs +4 -0
- package/dist/MultichainBalancesController/MultichainBalancesController.cjs.map +1 -1
- package/dist/MultichainBalancesController/MultichainBalancesController.d.cts +2 -1
- package/dist/MultichainBalancesController/MultichainBalancesController.d.cts.map +1 -1
- package/dist/MultichainBalancesController/MultichainBalancesController.d.mts +2 -1
- package/dist/MultichainBalancesController/MultichainBalancesController.d.mts.map +1 -1
- package/dist/MultichainBalancesController/MultichainBalancesController.mjs +4 -0
- package/dist/MultichainBalancesController/MultichainBalancesController.mjs.map +1 -1
- package/dist/NftController.cjs +8 -3
- package/dist/NftController.cjs.map +1 -1
- package/dist/NftController.d.cts +5 -1
- package/dist/NftController.d.cts.map +1 -1
- package/dist/NftController.d.mts +5 -1
- package/dist/NftController.d.mts.map +1 -1
- package/dist/NftController.mjs +9 -4
- package/dist/NftController.mjs.map +1 -1
- package/dist/NftDetectionController.cjs +45 -26
- package/dist/NftDetectionController.cjs.map +1 -1
- package/dist/NftDetectionController.d.cts +5 -4
- package/dist/NftDetectionController.d.cts.map +1 -1
- package/dist/NftDetectionController.d.mts +5 -4
- package/dist/NftDetectionController.d.mts.map +1 -1
- package/dist/NftDetectionController.mjs +46 -27
- package/dist/NftDetectionController.mjs.map +1 -1
- package/dist/TokenRatesController.cjs +1 -1
- package/dist/TokenRatesController.cjs.map +1 -1
- package/dist/TokenRatesController.d.cts.map +1 -1
- package/dist/TokenRatesController.d.mts.map +1 -1
- package/dist/TokenRatesController.mjs +2 -2
- package/dist/TokenRatesController.mjs.map +1 -1
- package/dist/assetsUtil.cjs +1 -0
- package/dist/assetsUtil.cjs.map +1 -1
- package/dist/assetsUtil.d.cts.map +1 -1
- package/dist/assetsUtil.d.mts.map +1 -1
- package/dist/assetsUtil.mjs +1 -0
- package/dist/assetsUtil.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [54.0.0]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **BREAKING**: The `detectNfts` method in the `NftDetectionController` now accepts chain IDs directly instead of networkClientId, enabling NFT detection across multiple chains simultaneously ([#5448](https://github.com/MetaMask/core/pull/5448))
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Fixed token address conversion in the `TokenRatesController` to correctly preserve the checksum address format without unnecessary hex conversion ([#5490](https://github.com/MetaMask/core/pull/5490))
|
|
19
|
+
|
|
20
|
+
## [53.1.1]
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Check if `KeyringController` is unlocked before processing account events in `MultichainBalancesController` ([#5473](https://github.com/MetaMask/core/pull/5473))
|
|
25
|
+
- This is needed since some Snaps might decrypt their state which needs the `KeyringController` to be unlocked.
|
|
26
|
+
- Fix runtime error in NFT detection when metadata is `null` ([#5455](https://github.com/MetaMask/core/pull/5455))
|
|
27
|
+
|
|
10
28
|
## [53.1.0]
|
|
11
29
|
|
|
12
30
|
### Added
|
|
@@ -1460,7 +1478,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1460
1478
|
|
|
1461
1479
|
- Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/core/pull/845))
|
|
1462
1480
|
|
|
1463
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@
|
|
1481
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@54.0.0...HEAD
|
|
1482
|
+
[54.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@53.1.1...@metamask/assets-controllers@54.0.0
|
|
1483
|
+
[53.1.1]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@53.1.0...@metamask/assets-controllers@53.1.1
|
|
1464
1484
|
[53.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@53.0.0...@metamask/assets-controllers@53.1.0
|
|
1465
1485
|
[53.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@52.0.0...@metamask/assets-controllers@53.0.0
|
|
1466
1486
|
[52.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@51.0.2...@metamask/assets-controllers@52.0.0
|
|
@@ -90,6 +90,10 @@ _MultichainBalancesController_instances = new WeakSet(), _MultichainBalancesCont
|
|
|
90
90
|
* @param assets - The list of asset types for this account to upadte.
|
|
91
91
|
*/
|
|
92
92
|
async function _MultichainBalancesController_updateBalance(accountId, assets) {
|
|
93
|
+
const { isUnlocked } = this.messagingSystem.call('KeyringController:getState');
|
|
94
|
+
if (!isUnlocked) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
93
97
|
try {
|
|
94
98
|
const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, accountId);
|
|
95
99
|
if (account.metadata.snap) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainBalancesController.cjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountBalancesUpdatesEvent,\n} from '@metamask/accounts-controller';\nimport {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n Balance,\n CaipAssetType,\n AccountBalancesUpdatedEventPayload,\n} from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { Draft } from 'immer';\n\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerState,\n MultichainAssetsControllerStateChangeEvent,\n} from '../MultichainAssetsController';\n\nconst controllerName = 'MultichainBalancesController';\n\n/**\n * State used by the {@link MultichainBalancesController} to cache account balances.\n */\nexport type MultichainBalancesControllerState = {\n balances: {\n [account: string]: {\n [asset: string]: {\n amount: string;\n unit: string;\n };\n };\n };\n};\n\n/**\n * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\n\n/**\n * Returns the state of the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Event emitted when the state of the {@link MultichainBalancesController} changes.\n */\nexport type MultichainBalancesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerActions =\n MultichainBalancesControllerGetStateAction;\n\n/**\n * Events emitted by {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerEvents =\n MultichainBalancesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | MultichainAssetsControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | MultichainAssetsControllerStateChangeEvent;\n\n/**\n * Messenger type for the MultichainBalancesController.\n */\nexport type MultichainBalancesControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n MultichainBalancesControllerActions | AllowedActions,\n MultichainBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * {@link MultichainBalancesController}'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 */\nconst balancesControllerMetadata = {\n balances: {\n persist: true,\n anonymous: false,\n },\n};\n\n/**\n * The MultichainBalancesController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainBalancesController extends BaseController<\n typeof controllerName,\n MultichainBalancesControllerState,\n MultichainBalancesControllerMessenger\n> {\n constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\n ...state,\n },\n });\n\n // Fetch initial balances for all non-EVM accounts\n for (const account of this.#listAccounts()) {\n // Fetching the balance is asynchronous and we cannot use `await` here.\n // eslint-disable-next-line no-void\n void this.updateBalance(account.id);\n }\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (account: string) => this.#handleOnAccountRemoved(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (balanceUpdate: AccountBalancesUpdatedEventPayload) =>\n this.#handleOnAccountBalancesUpdated(balanceUpdate),\n );\n // TODO: Maybe add a MultichainAssetsController:accountAssetListUpdated event instead of using the entire state.\n // Since MultichainAssetsController already listens for the AccountsController:accountAdded, we can rely in it for that event\n // and not listen for it also here, in this controller, since it would be redundant\n this.messagingSystem.subscribe(\n 'MultichainAssetsController:stateChange',\n async (assetsState: MultichainAssetsControllerState) => {\n for (const accountId of Object.keys(assetsState.accountsAssets)) {\n await this.#updateBalance(\n accountId,\n assetsState.accountsAssets[accountId],\n );\n }\n },\n );\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n * @param assets - The list of asset types for this account to upadte.\n */\n async #updateBalance(\n accountId: string,\n assets: CaipAssetType[],\n ): Promise<void> {\n try {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assets,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\n } catch (error) {\n // FIXME: Maybe we shouldn't catch all errors here since this method is also being\n // used in the public methods. This means if something else uses `updateBalance` it\n // won't be able to catch and gets the error itself...\n console.error(\n `Failed to fetch balances for account ${accountId}:`,\n error,\n );\n }\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n */\n async updateBalance(accountId: string): Promise<void> {\n await this.#updateBalance(accountId, this.#listAccountAssets(accountId));\n }\n\n /**\n * Lists the multichain accounts coming from the `AccountsController`.\n *\n * @returns A list of multichain accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Lists the accounts that we should get balances for.\n *\n * @returns A list of accounts that we should get balances for.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Lists the accounts assets.\n *\n * @param accountId - The account ID.\n * @returns The list of assets for this account, returns an empty list if none.\n */\n #listAccountAssets(accountId: string): CaipAssetType[] {\n // TODO: Add an action `MultichainAssetsController:getAccountAssets` maybe?\n const assetsState = this.messagingSystem.call(\n 'MultichainAssetsController:getState',\n );\n\n return assetsState.accountsAssets[accountId] ?? [];\n }\n\n /**\n * Get a non-EVM account from its ID.\n *\n * @param accountId - The account ID.\n * @returns The non-EVM account.\n */\n #getAccount(accountId: string): InternalAccount {\n const account: InternalAccount | undefined = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles balance updates received from the AccountsController.\n *\n * @param balanceUpdate - The balance update event containing new balances.\n */\n #handleOnAccountBalancesUpdated(\n balanceUpdate: AccountBalancesUpdatedEventPayload,\n ): void {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n Object.entries(balanceUpdate.balances).forEach(\n ([accountId, assetBalances]) => {\n if (accountId in state.balances) {\n Object.assign(state.balances[accountId], assetBalances);\n }\n },\n );\n });\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The account ID being removed.\n */\n async #handleOnAccountRemoved(accountId: string): Promise<void> {\n if (accountId in this.state.balances) {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n delete state.balances[accountId];\n });\n }\n }\n\n /**\n * Get the balances for an account.\n *\n * @param accountId - ID of the account to get balances for.\n * @param snapId - ID of the Snap which manages the account.\n * @param assetTypes - Array of asset types to get balances for.\n * @returns A map of asset types to balances.\n */\n async #getBalances(\n accountId: string,\n snapId: string,\n assetTypes: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n return await this.#getClient(snapId).getAccountBalances(\n accountId,\n assetTypes,\n );\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messagingSystem.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MultichainBalancesController.cjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountBalancesUpdatesEvent,\n} from '@metamask/accounts-controller';\nimport {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n Balance,\n CaipAssetType,\n AccountBalancesUpdatedEventPayload,\n} from '@metamask/keyring-api';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { Draft } from 'immer';\n\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerState,\n MultichainAssetsControllerStateChangeEvent,\n} from '../MultichainAssetsController';\n\nconst controllerName = 'MultichainBalancesController';\n\n/**\n * State used by the {@link MultichainBalancesController} to cache account balances.\n */\nexport type MultichainBalancesControllerState = {\n balances: {\n [account: string]: {\n [asset: string]: {\n amount: string;\n unit: string;\n };\n };\n };\n};\n\n/**\n * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\n\n/**\n * Returns the state of the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Event emitted when the state of the {@link MultichainBalancesController} changes.\n */\nexport type MultichainBalancesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerActions =\n MultichainBalancesControllerGetStateAction;\n\n/**\n * Events emitted by {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerEvents =\n MultichainBalancesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | MultichainAssetsControllerGetStateAction\n | KeyringControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | MultichainAssetsControllerStateChangeEvent;\n\n/**\n * Messenger type for the MultichainBalancesController.\n */\nexport type MultichainBalancesControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n MultichainBalancesControllerActions | AllowedActions,\n MultichainBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * {@link MultichainBalancesController}'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 */\nconst balancesControllerMetadata = {\n balances: {\n persist: true,\n anonymous: false,\n },\n};\n\n/**\n * The MultichainBalancesController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainBalancesController extends BaseController<\n typeof controllerName,\n MultichainBalancesControllerState,\n MultichainBalancesControllerMessenger\n> {\n constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\n ...state,\n },\n });\n\n // Fetch initial balances for all non-EVM accounts\n for (const account of this.#listAccounts()) {\n // Fetching the balance is asynchronous and we cannot use `await` here.\n // eslint-disable-next-line no-void\n void this.updateBalance(account.id);\n }\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (account: string) => this.#handleOnAccountRemoved(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (balanceUpdate: AccountBalancesUpdatedEventPayload) =>\n this.#handleOnAccountBalancesUpdated(balanceUpdate),\n );\n // TODO: Maybe add a MultichainAssetsController:accountAssetListUpdated event instead of using the entire state.\n // Since MultichainAssetsController already listens for the AccountsController:accountAdded, we can rely in it for that event\n // and not listen for it also here, in this controller, since it would be redundant\n this.messagingSystem.subscribe(\n 'MultichainAssetsController:stateChange',\n async (assetsState: MultichainAssetsControllerState) => {\n for (const accountId of Object.keys(assetsState.accountsAssets)) {\n await this.#updateBalance(\n accountId,\n assetsState.accountsAssets[accountId],\n );\n }\n },\n );\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n * @param assets - The list of asset types for this account to upadte.\n */\n async #updateBalance(\n accountId: string,\n assets: CaipAssetType[],\n ): Promise<void> {\n const { isUnlocked } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n\n if (!isUnlocked) {\n return;\n }\n\n try {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assets,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\n } catch (error) {\n // FIXME: Maybe we shouldn't catch all errors here since this method is also being\n // used in the public methods. This means if something else uses `updateBalance` it\n // won't be able to catch and gets the error itself...\n console.error(\n `Failed to fetch balances for account ${accountId}:`,\n error,\n );\n }\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n */\n async updateBalance(accountId: string): Promise<void> {\n await this.#updateBalance(accountId, this.#listAccountAssets(accountId));\n }\n\n /**\n * Lists the multichain accounts coming from the `AccountsController`.\n *\n * @returns A list of multichain accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Lists the accounts that we should get balances for.\n *\n * @returns A list of accounts that we should get balances for.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Lists the accounts assets.\n *\n * @param accountId - The account ID.\n * @returns The list of assets for this account, returns an empty list if none.\n */\n #listAccountAssets(accountId: string): CaipAssetType[] {\n // TODO: Add an action `MultichainAssetsController:getAccountAssets` maybe?\n const assetsState = this.messagingSystem.call(\n 'MultichainAssetsController:getState',\n );\n\n return assetsState.accountsAssets[accountId] ?? [];\n }\n\n /**\n * Get a non-EVM account from its ID.\n *\n * @param accountId - The account ID.\n * @returns The non-EVM account.\n */\n #getAccount(accountId: string): InternalAccount {\n const account: InternalAccount | undefined = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles balance updates received from the AccountsController.\n *\n * @param balanceUpdate - The balance update event containing new balances.\n */\n #handleOnAccountBalancesUpdated(\n balanceUpdate: AccountBalancesUpdatedEventPayload,\n ): void {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n Object.entries(balanceUpdate.balances).forEach(\n ([accountId, assetBalances]) => {\n if (accountId in state.balances) {\n Object.assign(state.balances[accountId], assetBalances);\n }\n },\n );\n });\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The account ID being removed.\n */\n async #handleOnAccountRemoved(accountId: string): Promise<void> {\n if (accountId in this.state.balances) {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n delete state.balances[accountId];\n });\n }\n }\n\n /**\n * Get the balances for an account.\n *\n * @param accountId - ID of the account to get balances for.\n * @param snapId - ID of the Snap which manages the account.\n * @param assetTypes - Array of asset types to get balances for.\n * @returns A map of asset types to balances.\n */\n async #getBalances(\n accountId: string,\n snapId: string,\n assetTypes: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n return await this.#getClient(snapId).getAccountBalances(\n accountId,\n assetTypes,\n );\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messagingSystem.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction, AccountsControllerAccountBalancesUpdatesEvent } from "@metamask/accounts-controller";
|
|
2
2
|
import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger } from "@metamask/base-controller";
|
|
3
|
+
import type { KeyringControllerGetStateAction } from "@metamask/keyring-controller";
|
|
3
4
|
import type { HandleSnapRequest } from "@metamask/snaps-controllers";
|
|
4
5
|
import type { MultichainAssetsControllerGetStateAction, MultichainAssetsControllerStateChangeEvent } from "../MultichainAssetsController/index.cjs";
|
|
5
6
|
declare const controllerName = "MultichainBalancesController";
|
|
@@ -44,7 +45,7 @@ export type MultichainBalancesControllerEvents = MultichainBalancesControllerSta
|
|
|
44
45
|
/**
|
|
45
46
|
* Actions that this controller is allowed to call.
|
|
46
47
|
*/
|
|
47
|
-
type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | MultichainAssetsControllerGetStateAction;
|
|
48
|
+
type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | MultichainAssetsControllerGetStateAction | KeyringControllerGetStateAction;
|
|
48
49
|
/**
|
|
49
50
|
* Events that this controller is allowed to subscribe.
|
|
50
51
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainBalancesController.d.cts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC9C,6CAA6C,EAC9C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;
|
|
1
|
+
{"version":3,"file":"MultichainBalancesController.d.cts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC9C,6CAA6C,EAC9C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;AAOnC,OAAO,KAAK,EAAE,+BAA+B,EAAE,qCAAqC;AAGpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AAMrE,OAAO,KAAK,EACV,wCAAwC,EAExC,0CAA0C,EAC3C,gDAAsC;AAEvC,QAAA,MAAM,cAAc,iCAAiC,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE;QACR,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,CAAC,KAAK,EAAE,MAAM,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,2CAA2C,IAAI,iCAAiC,CAE/F;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,wBAAwB,CACtB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,uCAAuC,GACjD,0BAA0B,CACxB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC7C,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAC5C,uCAAuC,CAAC;AAE1C;;GAEG;AACH,KAAK,cAAc,GACf,iBAAiB,GACjB,8CAA8C,GAC9C,wCAAwC,GACxC,+BAA+B,CAAC;AAEpC;;GAEG;AACH,KAAK,aAAa,GACd,mCAAmC,GACnC,qCAAqC,GACrC,6CAA6C,GAC7C,0CAA0C,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,mBAAmB,CACrE,OAAO,cAAc,EACrB,mCAAmC,GAAG,cAAc,EACpD,kCAAkC,GAAG,aAAa,EAClD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAgBF;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,cAAc,CAC9D,OAAO,cAAc,EACrB,iCAAiC,EACjC,qCAAqC,CACtC;;gBACa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,qCAAqC,CAAC;QACjD,KAAK,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;KACpD;IAuFD;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA6ItD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction, AccountsControllerAccountBalancesUpdatesEvent } from "@metamask/accounts-controller";
|
|
2
2
|
import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger } from "@metamask/base-controller";
|
|
3
|
+
import type { KeyringControllerGetStateAction } from "@metamask/keyring-controller";
|
|
3
4
|
import type { HandleSnapRequest } from "@metamask/snaps-controllers";
|
|
4
5
|
import type { MultichainAssetsControllerGetStateAction, MultichainAssetsControllerStateChangeEvent } from "../MultichainAssetsController/index.mjs";
|
|
5
6
|
declare const controllerName = "MultichainBalancesController";
|
|
@@ -44,7 +45,7 @@ export type MultichainBalancesControllerEvents = MultichainBalancesControllerSta
|
|
|
44
45
|
/**
|
|
45
46
|
* Actions that this controller is allowed to call.
|
|
46
47
|
*/
|
|
47
|
-
type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | MultichainAssetsControllerGetStateAction;
|
|
48
|
+
type AllowedActions = HandleSnapRequest | AccountsControllerListMultichainAccountsAction | MultichainAssetsControllerGetStateAction | KeyringControllerGetStateAction;
|
|
48
49
|
/**
|
|
49
50
|
* Events that this controller is allowed to subscribe.
|
|
50
51
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainBalancesController.d.mts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC9C,6CAA6C,EAC9C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;
|
|
1
|
+
{"version":3,"file":"MultichainBalancesController.d.mts","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC9C,6CAA6C,EAC9C,sCAAsC;AACvC,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACzB,kCAAkC;AAOnC,OAAO,KAAK,EAAE,+BAA+B,EAAE,qCAAqC;AAGpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AAMrE,OAAO,KAAK,EACV,wCAAwC,EAExC,0CAA0C,EAC3C,gDAAsC;AAEvC,QAAA,MAAM,cAAc,iCAAiC,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE;QACR,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,CAAC,KAAK,EAAE,MAAM,GAAG;gBACf,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;aACd,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,2CAA2C,IAAI,iCAAiC,CAE/F;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,wBAAwB,CACtB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,uCAAuC,GACjD,0BAA0B,CACxB,OAAO,cAAc,EACrB,iCAAiC,CAClC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC7C,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAC5C,uCAAuC,CAAC;AAE1C;;GAEG;AACH,KAAK,cAAc,GACf,iBAAiB,GACjB,8CAA8C,GAC9C,wCAAwC,GACxC,+BAA+B,CAAC;AAEpC;;GAEG;AACH,KAAK,aAAa,GACd,mCAAmC,GACnC,qCAAqC,GACrC,6CAA6C,GAC7C,0CAA0C,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,mBAAmB,CACrE,OAAO,cAAc,EACrB,mCAAmC,GAAG,cAAc,EACpD,kCAAkC,GAAG,aAAa,EAClD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAgBF;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,cAAc,CAC9D,OAAO,cAAc,EACrB,iCAAiC,EACjC,qCAAqC,CACtC;;gBACa,EACV,SAAS,EACT,KAAU,GACX,EAAE;QACD,SAAS,EAAE,qCAAqC,CAAC;QACjD,KAAK,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;KACpD;IAuFD;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA6ItD"}
|
|
@@ -85,6 +85,10 @@ _MultichainBalancesController_instances = new WeakSet(), _MultichainBalancesCont
|
|
|
85
85
|
* @param assets - The list of asset types for this account to upadte.
|
|
86
86
|
*/
|
|
87
87
|
async function _MultichainBalancesController_updateBalance(accountId, assets) {
|
|
88
|
+
const { isUnlocked } = this.messagingSystem.call('KeyringController:getState');
|
|
89
|
+
if (!isUnlocked) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
88
92
|
try {
|
|
89
93
|
const account = __classPrivateFieldGet(this, _MultichainBalancesController_instances, "m", _MultichainBalancesController_getAccount).call(this, accountId);
|
|
90
94
|
if (account.metadata.snap) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainBalancesController.mjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountBalancesUpdatesEvent,\n} from '@metamask/accounts-controller';\nimport {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n Balance,\n CaipAssetType,\n AccountBalancesUpdatedEventPayload,\n} from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { Draft } from 'immer';\n\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerState,\n MultichainAssetsControllerStateChangeEvent,\n} from '../MultichainAssetsController';\n\nconst controllerName = 'MultichainBalancesController';\n\n/**\n * State used by the {@link MultichainBalancesController} to cache account balances.\n */\nexport type MultichainBalancesControllerState = {\n balances: {\n [account: string]: {\n [asset: string]: {\n amount: string;\n unit: string;\n };\n };\n };\n};\n\n/**\n * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\n\n/**\n * Returns the state of the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Event emitted when the state of the {@link MultichainBalancesController} changes.\n */\nexport type MultichainBalancesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerActions =\n MultichainBalancesControllerGetStateAction;\n\n/**\n * Events emitted by {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerEvents =\n MultichainBalancesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | MultichainAssetsControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | MultichainAssetsControllerStateChangeEvent;\n\n/**\n * Messenger type for the MultichainBalancesController.\n */\nexport type MultichainBalancesControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n MultichainBalancesControllerActions | AllowedActions,\n MultichainBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * {@link MultichainBalancesController}'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 */\nconst balancesControllerMetadata = {\n balances: {\n persist: true,\n anonymous: false,\n },\n};\n\n/**\n * The MultichainBalancesController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainBalancesController extends BaseController<\n typeof controllerName,\n MultichainBalancesControllerState,\n MultichainBalancesControllerMessenger\n> {\n constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\n ...state,\n },\n });\n\n // Fetch initial balances for all non-EVM accounts\n for (const account of this.#listAccounts()) {\n // Fetching the balance is asynchronous and we cannot use `await` here.\n // eslint-disable-next-line no-void\n void this.updateBalance(account.id);\n }\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (account: string) => this.#handleOnAccountRemoved(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (balanceUpdate: AccountBalancesUpdatedEventPayload) =>\n this.#handleOnAccountBalancesUpdated(balanceUpdate),\n );\n // TODO: Maybe add a MultichainAssetsController:accountAssetListUpdated event instead of using the entire state.\n // Since MultichainAssetsController already listens for the AccountsController:accountAdded, we can rely in it for that event\n // and not listen for it also here, in this controller, since it would be redundant\n this.messagingSystem.subscribe(\n 'MultichainAssetsController:stateChange',\n async (assetsState: MultichainAssetsControllerState) => {\n for (const accountId of Object.keys(assetsState.accountsAssets)) {\n await this.#updateBalance(\n accountId,\n assetsState.accountsAssets[accountId],\n );\n }\n },\n );\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n * @param assets - The list of asset types for this account to upadte.\n */\n async #updateBalance(\n accountId: string,\n assets: CaipAssetType[],\n ): Promise<void> {\n try {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assets,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\n } catch (error) {\n // FIXME: Maybe we shouldn't catch all errors here since this method is also being\n // used in the public methods. This means if something else uses `updateBalance` it\n // won't be able to catch and gets the error itself...\n console.error(\n `Failed to fetch balances for account ${accountId}:`,\n error,\n );\n }\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n */\n async updateBalance(accountId: string): Promise<void> {\n await this.#updateBalance(accountId, this.#listAccountAssets(accountId));\n }\n\n /**\n * Lists the multichain accounts coming from the `AccountsController`.\n *\n * @returns A list of multichain accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Lists the accounts that we should get balances for.\n *\n * @returns A list of accounts that we should get balances for.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Lists the accounts assets.\n *\n * @param accountId - The account ID.\n * @returns The list of assets for this account, returns an empty list if none.\n */\n #listAccountAssets(accountId: string): CaipAssetType[] {\n // TODO: Add an action `MultichainAssetsController:getAccountAssets` maybe?\n const assetsState = this.messagingSystem.call(\n 'MultichainAssetsController:getState',\n );\n\n return assetsState.accountsAssets[accountId] ?? [];\n }\n\n /**\n * Get a non-EVM account from its ID.\n *\n * @param accountId - The account ID.\n * @returns The non-EVM account.\n */\n #getAccount(accountId: string): InternalAccount {\n const account: InternalAccount | undefined = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles balance updates received from the AccountsController.\n *\n * @param balanceUpdate - The balance update event containing new balances.\n */\n #handleOnAccountBalancesUpdated(\n balanceUpdate: AccountBalancesUpdatedEventPayload,\n ): void {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n Object.entries(balanceUpdate.balances).forEach(\n ([accountId, assetBalances]) => {\n if (accountId in state.balances) {\n Object.assign(state.balances[accountId], assetBalances);\n }\n },\n );\n });\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The account ID being removed.\n */\n async #handleOnAccountRemoved(accountId: string): Promise<void> {\n if (accountId in this.state.balances) {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n delete state.balances[accountId];\n });\n }\n }\n\n /**\n * Get the balances for an account.\n *\n * @param accountId - ID of the account to get balances for.\n * @param snapId - ID of the Snap which manages the account.\n * @param assetTypes - Array of asset types to get balances for.\n * @returns A map of asset types to balances.\n */\n async #getBalances(\n accountId: string,\n snapId: string,\n assetTypes: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n return await this.#getClient(snapId).getAccountBalances(\n accountId,\n assetTypes,\n );\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messagingSystem.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MultichainBalancesController.mjs","sourceRoot":"","sources":["../../src/MultichainBalancesController/MultichainBalancesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountBalancesUpdatesEvent,\n} from '@metamask/accounts-controller';\nimport {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type {\n Balance,\n CaipAssetType,\n AccountBalancesUpdatedEventPayload,\n} from '@metamask/keyring-api';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\nimport type { Draft } from 'immer';\n\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerState,\n MultichainAssetsControllerStateChangeEvent,\n} from '../MultichainAssetsController';\n\nconst controllerName = 'MultichainBalancesController';\n\n/**\n * State used by the {@link MultichainBalancesController} to cache account balances.\n */\nexport type MultichainBalancesControllerState = {\n balances: {\n [account: string]: {\n [asset: string]: {\n amount: string;\n unit: string;\n };\n };\n };\n};\n\n/**\n * Constructs the default {@link MultichainBalancesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainBalancesController} state.\n */\nexport function getDefaultMultichainBalancesControllerState(): MultichainBalancesControllerState {\n return { balances: {} };\n}\n\n/**\n * Returns the state of the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Event emitted when the state of the {@link MultichainBalancesController} changes.\n */\nexport type MultichainBalancesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainBalancesControllerState\n >;\n\n/**\n * Actions exposed by the {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerActions =\n MultichainBalancesControllerGetStateAction;\n\n/**\n * Events emitted by {@link MultichainBalancesController}.\n */\nexport type MultichainBalancesControllerEvents =\n MultichainBalancesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\ntype AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | MultichainAssetsControllerGetStateAction\n | KeyringControllerGetStateAction;\n\n/**\n * Events that this controller is allowed to subscribe.\n */\ntype AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent\n | AccountsControllerAccountBalancesUpdatesEvent\n | MultichainAssetsControllerStateChangeEvent;\n\n/**\n * Messenger type for the MultichainBalancesController.\n */\nexport type MultichainBalancesControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n MultichainBalancesControllerActions | AllowedActions,\n MultichainBalancesControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * {@link MultichainBalancesController}'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 */\nconst balancesControllerMetadata = {\n balances: {\n persist: true,\n anonymous: false,\n },\n};\n\n/**\n * The MultichainBalancesController is responsible for fetching and caching account\n * balances.\n */\nexport class MultichainBalancesController extends BaseController<\n typeof controllerName,\n MultichainBalancesControllerState,\n MultichainBalancesControllerMessenger\n> {\n constructor({\n messenger,\n state = {},\n }: {\n messenger: MultichainBalancesControllerMessenger;\n state?: Partial<MultichainBalancesControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: balancesControllerMetadata,\n state: {\n ...getDefaultMultichainBalancesControllerState(),\n ...state,\n },\n });\n\n // Fetch initial balances for all non-EVM accounts\n for (const account of this.#listAccounts()) {\n // Fetching the balance is asynchronous and we cannot use `await` here.\n // eslint-disable-next-line no-void\n void this.updateBalance(account.id);\n }\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (account: string) => this.#handleOnAccountRemoved(account),\n );\n this.messagingSystem.subscribe(\n 'AccountsController:accountBalancesUpdated',\n (balanceUpdate: AccountBalancesUpdatedEventPayload) =>\n this.#handleOnAccountBalancesUpdated(balanceUpdate),\n );\n // TODO: Maybe add a MultichainAssetsController:accountAssetListUpdated event instead of using the entire state.\n // Since MultichainAssetsController already listens for the AccountsController:accountAdded, we can rely in it for that event\n // and not listen for it also here, in this controller, since it would be redundant\n this.messagingSystem.subscribe(\n 'MultichainAssetsController:stateChange',\n async (assetsState: MultichainAssetsControllerState) => {\n for (const accountId of Object.keys(assetsState.accountsAssets)) {\n await this.#updateBalance(\n accountId,\n assetsState.accountsAssets[accountId],\n );\n }\n },\n );\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n * @param assets - The list of asset types for this account to upadte.\n */\n async #updateBalance(\n accountId: string,\n assets: CaipAssetType[],\n ): Promise<void> {\n const { isUnlocked } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n\n if (!isUnlocked) {\n return;\n }\n\n try {\n const account = this.#getAccount(accountId);\n\n if (account.metadata.snap) {\n const accountBalance = await this.#getBalances(\n account.id,\n account.metadata.snap.id,\n assets,\n );\n\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n state.balances[accountId] = accountBalance;\n });\n }\n } catch (error) {\n // FIXME: Maybe we shouldn't catch all errors here since this method is also being\n // used in the public methods. This means if something else uses `updateBalance` it\n // won't be able to catch and gets the error itself...\n console.error(\n `Failed to fetch balances for account ${accountId}:`,\n error,\n );\n }\n }\n\n /**\n * Updates the balances of one account. This method doesn't return\n * anything, but it updates the state of the controller.\n *\n * @param accountId - The account ID.\n */\n async updateBalance(accountId: string): Promise<void> {\n await this.#updateBalance(accountId, this.#listAccountAssets(accountId));\n }\n\n /**\n * Lists the multichain accounts coming from the `AccountsController`.\n *\n * @returns A list of multichain accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n );\n }\n\n /**\n * Lists the accounts that we should get balances for.\n *\n * @returns A list of accounts that we should get balances for.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Lists the accounts assets.\n *\n * @param accountId - The account ID.\n * @returns The list of assets for this account, returns an empty list if none.\n */\n #listAccountAssets(accountId: string): CaipAssetType[] {\n // TODO: Add an action `MultichainAssetsController:getAccountAssets` maybe?\n const assetsState = this.messagingSystem.call(\n 'MultichainAssetsController:getState',\n );\n\n return assetsState.accountsAssets[accountId] ?? [];\n }\n\n /**\n * Get a non-EVM account from its ID.\n *\n * @param accountId - The account ID.\n * @returns The non-EVM account.\n */\n #getAccount(accountId: string): InternalAccount {\n const account: InternalAccount | undefined = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\n }\n\n /**\n * Checks for non-EVM accounts.\n *\n * @param account - The new account to be checked.\n * @returns True if the account is a non-EVM account, false otherwise.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) &&\n // Non-EVM accounts are backed by a Snap for now\n account.metadata.snap !== undefined\n );\n }\n\n /**\n * Handles balance updates received from the AccountsController.\n *\n * @param balanceUpdate - The balance update event containing new balances.\n */\n #handleOnAccountBalancesUpdated(\n balanceUpdate: AccountBalancesUpdatedEventPayload,\n ): void {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n Object.entries(balanceUpdate.balances).forEach(\n ([accountId, assetBalances]) => {\n if (accountId in state.balances) {\n Object.assign(state.balances[accountId], assetBalances);\n }\n },\n );\n });\n }\n\n /**\n * Handles changes when a new account has been removed.\n *\n * @param accountId - The account ID being removed.\n */\n async #handleOnAccountRemoved(accountId: string): Promise<void> {\n if (accountId in this.state.balances) {\n this.update((state: Draft<MultichainBalancesControllerState>) => {\n delete state.balances[accountId];\n });\n }\n }\n\n /**\n * Get the balances for an account.\n *\n * @param accountId - ID of the account to get balances for.\n * @param snapId - ID of the Snap which manages the account.\n * @param assetTypes - Array of asset types to get balances for.\n * @returns A map of asset types to balances.\n */\n async #getBalances(\n accountId: string,\n snapId: string,\n assetTypes: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n return await this.#getClient(snapId).getAccountBalances(\n accountId,\n assetTypes,\n );\n }\n\n /**\n * Gets a `KeyringClient` for a Snap.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getClient(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) =>\n (await this.messagingSystem.call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n })) as Promise<Json>,\n });\n }\n}\n"]}
|
package/dist/NftController.cjs
CHANGED
|
@@ -223,15 +223,16 @@ class NftController extends base_controller_1.BaseController {
|
|
|
223
223
|
* @param options.userAddress - The address of the current user.
|
|
224
224
|
* @param options.source - Whether the NFT was detected, added manually or suggested by a dapp.
|
|
225
225
|
* @param options.networkClientId - The networkClientId that can be used to identify the network client to use for this request.
|
|
226
|
+
* @param options.chainId - The chain ID to add the NFT to.
|
|
226
227
|
* @returns Promise resolving to the current NFT list.
|
|
227
228
|
*/
|
|
228
|
-
async addNft(tokenAddress, tokenId, { nftMetadata, userAddress, source = constants_1.Source.Custom, networkClientId, } = {}) {
|
|
229
|
+
async addNft(tokenAddress, tokenId, { nftMetadata, userAddress, source = constants_1.Source.Custom, networkClientId, chainId, } = {}) {
|
|
229
230
|
const addressToSearch = __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getAddressOrSelectedAddress).call(this, userAddress);
|
|
230
231
|
if (!addressToSearch) {
|
|
231
232
|
return;
|
|
232
233
|
}
|
|
233
234
|
const checksumHexAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress);
|
|
234
|
-
const
|
|
235
|
+
const chainIdToAddTo = chainId || __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getCorrectChainId).call(this, { networkClientId });
|
|
235
236
|
nftMetadata =
|
|
236
237
|
nftMetadata ||
|
|
237
238
|
(await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_getNftInformation).call(this, checksumHexAddress, tokenId, networkClientId));
|
|
@@ -244,9 +245,13 @@ class NftController extends base_controller_1.BaseController {
|
|
|
244
245
|
});
|
|
245
246
|
// If NFT contract was not added, do not add individual NFT
|
|
246
247
|
const nftContract = newNftContracts.find((contract) => contract.address.toLowerCase() === checksumHexAddress.toLowerCase());
|
|
248
|
+
// This is the case when the NFT is added manually and not detected automatically
|
|
249
|
+
if (!nftMetadata.chainId) {
|
|
250
|
+
nftMetadata.chainId = (0, controller_utils_1.convertHexToDecimal)(chainIdToAddTo);
|
|
251
|
+
}
|
|
247
252
|
// If NFT contract information, add individual NFT
|
|
248
253
|
if (nftContract) {
|
|
249
|
-
await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_addIndividualNft).call(this, checksumHexAddress, tokenId, nftMetadata, nftContract,
|
|
254
|
+
await __classPrivateFieldGet(this, _NftController_instances, "m", _NftController_addIndividualNft).call(this, checksumHexAddress, tokenId, nftMetadata, nftContract, chainIdToAddTo, addressToSearch, source);
|
|
250
255
|
}
|
|
251
256
|
}
|
|
252
257
|
/**
|