@metamask-previews/snap-account-service 2.0.0-preview-a1d0bbfa8 → 2.0.0-preview-d77c814bb
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 +0 -6
- package/dist/SnapAccountService.cjs +10 -11
- package/dist/SnapAccountService.cjs.map +1 -1
- package/dist/SnapAccountService.d.cts.map +1 -1
- package/dist/SnapAccountService.d.mts.map +1 -1
- package/dist/SnapAccountService.mjs +10 -11
- package/dist/SnapAccountService.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/errors.cjs +0 -137
- package/dist/errors.cjs.map +0 -1
- package/dist/errors.d.cts +0 -86
- package/dist/errors.d.cts.map +0 -1
- package/dist/errors.d.mts +0 -86
- package/dist/errors.d.mts.map +0 -1
- package/dist/errors.mjs +0 -129
- package/dist/errors.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,12 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
### Added
|
|
11
|
-
|
|
12
|
-
- Report migration error in case of failure ([#9696](https://github.com/MetaMask/core/pull/9696))
|
|
13
|
-
- The migration is a mandatory and it is not supposed to fail.
|
|
14
|
-
- Reporting should help identifying which step could have failed and help addressing the actual issue.
|
|
15
|
-
|
|
16
10
|
### Changed
|
|
17
11
|
|
|
18
12
|
- Bump `@metamask/account-tree-controller` from `^7.5.4` to `^7.5.5` ([#9470](https://github.com/MetaMask/core/pull/9470))
|
|
@@ -21,7 +21,6 @@ const keyring_controller_1 = require("@metamask/keyring-controller");
|
|
|
21
21
|
const v2_3 = require("@metamask/keyring-internal-snap-client/v2");
|
|
22
22
|
const keyring_snap_sdk_1 = require("@metamask/keyring-snap-sdk");
|
|
23
23
|
const utils_1 = require("@metamask/utils");
|
|
24
|
-
const errors_js_1 = require("./errors.cjs");
|
|
25
24
|
const logger_js_1 = require("./logger.cjs");
|
|
26
25
|
const SnapPlatformWatcher_js_1 = require("./SnapPlatformWatcher.cjs");
|
|
27
26
|
const SnapTracker_js_1 = require("./SnapTracker.cjs");
|
|
@@ -321,14 +320,14 @@ _SnapAccountService_messenger = new WeakMap(), _SnapAccountService_watcher = new
|
|
|
321
320
|
void __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_forwardSelectedAccounts).call(this, groupId, __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getAccountGroup).call(this, groupId)?.accounts);
|
|
322
321
|
}, _SnapAccountService_handleUnlock = function _SnapAccountService_handleUnlock() {
|
|
323
322
|
// eslint-disable-next-line no-void
|
|
324
|
-
void
|
|
323
|
+
void this.ensureMigrated()
|
|
324
|
+
.then(async () => {
|
|
325
325
|
// If the migration is successful, we re-forward the current groups to each new keyrings!
|
|
326
326
|
const groupId = __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getSelectedAccountGroupId).call(this);
|
|
327
|
-
// NOTE: This cannot throw, all errors are swallowed under the hood, so we don't need to
|
|
328
|
-
// catch anything here.
|
|
329
327
|
return await __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_forwardSelectedAccounts).call(this, groupId, __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getAccountGroup).call(this, groupId)?.accounts);
|
|
330
|
-
}
|
|
331
|
-
|
|
328
|
+
})
|
|
329
|
+
.catch((error) => {
|
|
330
|
+
console.error('Migration failed after unlock:', error);
|
|
332
331
|
});
|
|
333
332
|
}, _SnapAccountService_handleAccountGroupCreatedOrUpdated = function _SnapAccountService_handleAccountGroupCreatedOrUpdated(group) {
|
|
334
333
|
if (group.id === __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getSelectedAccountGroupId).call(this)) {
|
|
@@ -379,15 +378,15 @@ async function _SnapAccountService_migrate() {
|
|
|
379
378
|
// accounts over.
|
|
380
379
|
for (const state of states.values()) {
|
|
381
380
|
(0, logger_js_1.projectLogger)(`Migrating accounts for Snap "${state.snapId}"...`);
|
|
382
|
-
await
|
|
381
|
+
await controller.addNewKeyring(
|
|
383
382
|
// IMPORTANT: The Snap keyring (v2) can also be used as a v1
|
|
384
|
-
// keyring. So the builder associated with the v2 keyring type
|
|
385
|
-
//
|
|
386
|
-
v2_2.KeyringType.Snap, state)
|
|
383
|
+
// keyring. So the builder associated with the v2 keyring type is
|
|
384
|
+
// able to build both v1 and v2 keyrings.
|
|
385
|
+
v2_2.KeyringType.Snap, state);
|
|
387
386
|
}
|
|
388
387
|
// Remove the legacy Snap keyring after migration.
|
|
389
388
|
(0, logger_js_1.projectLogger)('Removing legacy Snap keyring...');
|
|
390
|
-
await
|
|
389
|
+
await controller.removeKeyring(legacySnapKeyringEntry.metadata.id);
|
|
391
390
|
(0, logger_js_1.projectLogger)('Migration completed!');
|
|
392
391
|
});
|
|
393
392
|
}, _SnapAccountService_ensureKeyringIsReady =
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountService.cjs","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountGroupId } from '@metamask/account-api';\nimport {\n SnapKeyring as LegacySnapKeyring,\n SnapMessage,\n} from '@metamask/eth-snap-keyring';\nimport {\n SnapKeyring,\n SnapKeyringState,\n isSnapKeyring,\n} from '@metamask/eth-snap-keyring/v2';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n AccountTransactionsUpdatedEventPayload,\n Balance,\n CaipAssetType,\n CaipAssetTypeOrId,\n CaipChainId,\n Pagination,\n ResolvedAccountAddress,\n TransactionsPage,\n} from '@metamask/keyring-api';\nimport {\n AccountAssetListUpdatedEventStruct,\n AccountBalancesUpdatedEventStruct,\n AccountTransactionsUpdatedEventStruct,\n KeyringEvent,\n} from '@metamask/keyring-api';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { KeyringCapabilities } from '@metamask/keyring-api/v2';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerStateChangeEvent,\n KeyringControllerUnlockEvent,\n KeyringControllerWithControllerAction,\n KeyringControllerWithKeyringV2Action,\n KeyringControllerWithKeyringV2UnsafeAction,\n} from '@metamask/keyring-controller';\nimport {\n isKeyringNotFoundError,\n KeyringTypes,\n} from '@metamask/keyring-controller';\nimport { KeyringInternalSnapClient } from '@metamask/keyring-internal-snap-client/v2';\nimport { SnapManageAccountsMethod } from '@metamask/keyring-snap-sdk';\nimport type {\n AccountId,\n BaseKeyring,\n JsonRpcRequest,\n} from '@metamask/keyring-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerGetSnapAction,\n SnapControllerGetStateAction,\n SnapControllerHandleRequestAction,\n SnapControllerSnapBlockedEvent,\n SnapControllerSnapDisabledEvent,\n SnapControllerSnapEnabledEvent,\n SnapControllerSnapInstalledEvent,\n SnapControllerSnapUnblockedEvent,\n SnapControllerSnapUninstalledEvent,\n SnapControllerStateChangeEvent,\n} from '@metamask/snaps-controllers';\nimport { SnapId } from '@metamask/snaps-sdk';\nimport type { Json } from '@metamask/utils';\nimport { assertStruct } from '@metamask/utils';\n\nimport { reportError, withSafeError } from './errors.js';\nimport { projectLogger as log } from './logger.js';\nimport type {\n SnapAccountServiceEnsureReadyAction,\n SnapAccountServiceEnsureMigratedAction,\n SnapAccountServiceGetCapabilitiesAction,\n SnapAccountServiceGetAccountAssetsAction,\n SnapAccountServiceGetAccountBalancesAction,\n SnapAccountServiceGetAccountTransactionsAction,\n SnapAccountServiceGetSnapsAction,\n SnapAccountServiceHandleKeyringSnapMessageAction,\n SnapAccountServiceResolveAccountAddressAction,\n SnapAccountServiceSetSelectedAccountsAction,\n} from './SnapAccountService-method-action-types.js';\nimport { SnapPlatformWatcher } from './SnapPlatformWatcher.js';\nimport type { SnapPlatformWatcherConfig } from './SnapPlatformWatcher.js';\nimport { SnapTracker } from './SnapTracker.js';\nimport type {\n AccountTreeControllerGetAccountGroupObjectAction,\n AccountTreeControllerGetSelectedAccountGroupAction,\n AccountTreeControllerSelectedAccountGroupChangeEvent,\n AccountTreeControllerAccountGroupCreatedEvent,\n AccountTreeControllerAccountGroupUpdatedEvent,\n AccountTreeControllerAccountGroupRemovedEvent,\n AccountGroupObject,\n} from './types.js';\n\n/**\n * The name of the {@link SnapAccountService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'SnapAccountService';\n\n/**\n * All of the methods within {@link SnapAccountService} that are exposed via\n * the messenger.\n */\nconst MESSENGER_EXPOSED_METHODS = [\n 'ensureMigrated',\n 'ensureReady',\n 'getCapabilities',\n 'getAccountAssets',\n 'getAccountBalances',\n 'getAccountTransactions',\n 'getSnaps',\n 'handleKeyringSnapMessage',\n 'resolveAccountAddress',\n 'setSelectedAccounts',\n] as const;\n\n/**\n * Actions that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceActions =\n | SnapAccountServiceEnsureMigratedAction\n | SnapAccountServiceEnsureReadyAction\n | SnapAccountServiceGetCapabilitiesAction\n | SnapAccountServiceGetAccountAssetsAction\n | SnapAccountServiceGetAccountBalancesAction\n | SnapAccountServiceGetAccountTransactionsAction\n | SnapAccountServiceGetSnapsAction\n | SnapAccountServiceHandleKeyringSnapMessageAction\n | SnapAccountServiceResolveAccountAddressAction\n | SnapAccountServiceSetSelectedAccountsAction;\n\n/**\n * Actions from other messengers that {@link SnapAccountService} calls.\n */\ntype AllowedActions =\n | SnapControllerGetStateAction\n | SnapControllerGetSnapAction\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | KeyringControllerGetStateAction\n | KeyringControllerWithControllerAction\n | KeyringControllerWithKeyringV2Action\n | KeyringControllerWithKeyringV2UnsafeAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetSelectedAccountGroupAction;\n\n/**\n * Events that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceAccountBalancesUpdatedEvent = {\n type: `${typeof serviceName}:accountBalancesUpdated`;\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountAssetListUpdatedEvent = {\n type: `${typeof serviceName}:accountAssetListUpdated`;\n payload: [AccountAssetListUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountTransactionsUpdatedEvent = {\n type: `${typeof serviceName}:accountTransactionsUpdated`;\n payload: [AccountTransactionsUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceEvents =\n | SnapAccountServiceAccountAssetListUpdatedEvent\n | SnapAccountServiceAccountBalancesUpdatedEvent\n | SnapAccountServiceAccountTransactionsUpdatedEvent;\n\n/**\n * Events from other messengers that {@link SnapAccountService} subscribes to.\n */\ntype AllowedEvents =\n | SnapControllerStateChangeEvent\n | SnapControllerSnapInstalledEvent\n | SnapControllerSnapEnabledEvent\n | SnapControllerSnapDisabledEvent\n | SnapControllerSnapBlockedEvent\n | SnapControllerSnapUnblockedEvent\n | SnapControllerSnapUninstalledEvent\n | KeyringControllerStateChangeEvent\n | KeyringControllerUnlockEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent\n | AccountTreeControllerAccountGroupCreatedEvent\n | AccountTreeControllerAccountGroupUpdatedEvent\n | AccountTreeControllerAccountGroupRemovedEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * {@link SnapAccountService}.\n */\nexport type SnapAccountServiceMessenger = Messenger<\n typeof serviceName,\n SnapAccountServiceActions | AllowedActions,\n SnapAccountServiceEvents | AllowedEvents\n>;\n\n/**\n * Configuration for the {@link SnapAccountService}.\n */\nexport type SnapAccountServiceConfig = {\n snapPlatformWatcher?: SnapPlatformWatcherConfig;\n};\n\n/**\n * The options that {@link SnapAccountService} takes.\n */\nexport type SnapAccountServiceOptions = {\n messenger: SnapAccountServiceMessenger;\n config?: SnapAccountServiceConfig;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @param keyring.type - The type of the keyring.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nfunction isLegacySnapKeyring(keyring: {\n type: BaseKeyring['type'];\n}): keyring is LegacySnapKeyring {\n return keyring.type === KeyringTypes.snap;\n}\n\n/**\n * Account data update events that can be forwarded from Snaps.\n *\n * These events are then re-emitted by the service for other consumers.\n */\ntype AccountDataUpdatedKeyringEvent =\n | KeyringEvent.AccountAssetListUpdated\n | KeyringEvent.AccountBalancesUpdated\n | KeyringEvent.AccountTransactionsUpdated;\n\n/**\n * Checks if a Snap message method is an account data update event.\n *\n * @param event - The Snap message event.\n * @returns `true` if the method can be forwarded without the legacy Snap keyring.\n */\nfunction isAccountDataUpdatedKeyringEvent(\n event: string,\n): event is AccountDataUpdatedKeyringEvent {\n return (\n event === KeyringEvent.AccountAssetListUpdated ||\n event === KeyringEvent.AccountBalancesUpdated ||\n event === KeyringEvent.AccountTransactionsUpdated\n );\n}\n\n/**\n * Service responsible for managing account management snaps.\n */\nexport class SnapAccountService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: SnapAccountServiceMessenger;\n\n readonly #watcher: SnapPlatformWatcher;\n\n readonly #tracker: SnapTracker;\n\n readonly #client: KeyringInternalSnapClient;\n\n #migrated = false;\n\n #migratePromise: Promise<void> | null = null;\n\n /**\n * Constructs a new {@link SnapAccountService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.config - Optional service configuration.\n */\n constructor({ messenger, config }: SnapAccountServiceOptions) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#watcher = new SnapPlatformWatcher(\n messenger,\n config?.snapPlatformWatcher,\n );\n this.#tracker = new SnapTracker(messenger);\n this.#client = new KeyringInternalSnapClient({\n messenger: messenger.buildChild({\n namespace: 'KeyringInternalSnapClient',\n actions: ['SnapController:handleRequest'],\n }),\n });\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:selectedAccountGroupChange',\n (groupId) => this.#handleSelectedAccountGroupChange(groupId),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupCreated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupUpdated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupRemoved',\n (groupId) => this.#handleAccountGroupRemoved(groupId),\n );\n\n this.#messenger.subscribe('KeyringController:unlock', () =>\n this.#handleUnlock(),\n );\n }\n\n /**\n * Handles changes to the selected account group by forwarding the new\n * group's accounts to the Snap keyring.\n *\n * @param groupId - The ID of the newly selected account group.\n */\n #handleSelectedAccountGroupChange(groupId: AccountGroupId | ''): void {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n }\n\n /**\n * Handles the keyring controller unlock event by triggering the migration\n * and forwarding the currently selected account group's accounts to the Snap\n * keyring.\n */\n #handleUnlock(): void {\n // eslint-disable-next-line no-void\n void withSafeError('Snap keyring v2 migration', () =>\n this.ensureMigrated(),\n ).then(\n async () => {\n // If the migration is successful, we re-forward the current groups to each new keyrings!\n const groupId = this.#getSelectedAccountGroupId();\n // NOTE: This cannot throw, all errors are swallowed under the hood, so we don't need to\n // catch anything here.\n return await this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n },\n (error) => {\n reportError(this.#messenger, 'Migration failed after unlock', error);\n },\n );\n }\n\n /**\n * Handles created or updated account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the created/updated group is currently selected.\n *\n * @param group - The account group being created or updated.\n */\n #handleAccountGroupCreatedOrUpdated(group: AccountGroupObject): void {\n if (group.id === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(group.id, group.accounts);\n }\n }\n\n /**\n * Handles removed account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the removed group is currently selected.\n *\n * @param groupId - The ID of the account group being removed.\n */\n #handleAccountGroupRemoved(groupId: AccountGroupId): void {\n if (groupId === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n [], // Clearing accounts since the group is removed\n );\n }\n }\n\n /**\n * Returns the IDs of all currently tracked account-management Snaps —\n * Snaps that are installed, enabled, not blocked, and have the\n * `endowment:keyring` permission.\n *\n * @returns The IDs of tracked account-management Snaps.\n */\n getSnaps(): SnapId[] {\n return this.#tracker.getSnaps();\n }\n\n /**\n * Ensures everything is ready to use Snap accounts for the given Snap.\n * 1. Validates that `snapId` is a tracked account-management Snap.\n * 2. Asserts that the legacy -> v2 migration has been triggered (expected to\n * happen at `KeyringController:unlock` time).\n * 3. Atomically creates the v2 keyring for this Snap if it doesn't exist\n * yet.\n * 4. Waits for the Snap platform to be fully started.\n *\n * Safe to call concurrently — each step is idempotent or mutex-protected.\n *\n * @param snapId - ID of the Snap to ensure readiness for.\n * @throws If `snapId` is not a tracked account-management Snap.\n * @throws If the migration has not been triggered yet (wallet not unlocked).\n */\n async ensureReady(snapId: SnapId): Promise<void> {\n if (!this.#tracker.canUse(snapId)) {\n throw new Error(`Unknown snap: \"${snapId}\"`);\n }\n\n // The migration is required to ensure the v2 keyring exists.\n await this.ensureMigrated();\n\n // We still try to create the keyring for the Snap here, since we might\n // want to use a new Snap that never had accounts before.\n await this.#ensureKeyringIsReady(snapId);\n\n // Before doing anything with our Snap, we need to make sure the platform\n // is ready to process requests.\n await this.#watcher.ensureCanUseSnapPlatform();\n }\n\n /**\n * Migrate the legacy Snap keyring to the new (per-snap) Snap keyring v2.\n * Expected to be triggered at `KeyringController:unlock` time.\n * Safe to call concurrently — the migration runs only once; all callers\n * await the same promise.\n *\n * @returns A promise that resolves when the migration is complete.\n */\n async ensureMigrated(): Promise<void> {\n if (this.#migrated) {\n return;\n }\n\n if (!this.#migratePromise) {\n this.#migratePromise = this.#migrate()\n .then(() => {\n this.#migrated = true;\n return undefined;\n })\n .catch((error) => {\n // Clear the promise so the next call can retry.\n this.#migratePromise = null;\n throw error;\n });\n }\n\n await this.#migratePromise;\n }\n\n /**\n * Performs the actual migration logic. Should only be called once, and is not\n * safe to call concurrently.\n */\n async #migrate(): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const { keyrings } = controller;\n\n const legacySnapKeyringEntry = keyrings.find(({ keyring }) =>\n isLegacySnapKeyring(keyring),\n );\n if (!legacySnapKeyringEntry) {\n log('No legacy Snap keyring found. Migration not required.');\n return;\n }\n\n log('Migration started...');\n\n // The legacy Snap keyring has never been a true `EthKeyring` so we\n // need to cast it to `unknown` first.\n const legacySnapKeyring =\n legacySnapKeyringEntry.keyring as unknown as LegacySnapKeyring;\n\n // Compute the account list for each Snap, grouped by snap ID.\n const states = new Map<SnapId, SnapKeyringState>();\n for (const internalAccount of legacySnapKeyring.listAccounts()) {\n // Convert `InternalAccount` to `KeyringAccount` since the Snap\n // keyring (v2) expects accounts in that format and will verify it\n // with `superstruct` when adding the keyring.\n const { metadata, ...account } = internalAccount;\n\n const snap = metadata?.snap;\n if (snap) {\n const snapId = snap.id as SnapId;\n\n let state = states.get(snapId);\n if (!state) {\n state = { snapId, accounts: {} };\n states.set(snapId, state);\n }\n state.accounts[account.id] = account;\n }\n }\n\n // Create the new Snap keyring (v2) for each Snap and migrate the\n // accounts over.\n for (const state of states.values()) {\n log(`Migrating accounts for Snap \"${state.snapId}\"...`);\n await withSafeError(\n `Adding v2 Snap keyring for \"${state.snapId}\"`,\n async () =>\n controller.addNewKeyring(\n // IMPORTANT: The Snap keyring (v2) can also be used as a v1\n // keyring. So the builder associated with the v2 keyring type\n // is able to build both v1 and v2 keyrings.\n KeyringType.Snap,\n state,\n ),\n );\n }\n\n // Remove the legacy Snap keyring after migration.\n log('Removing legacy Snap keyring...');\n await withSafeError('Removing legacy Snap keyring', async () =>\n controller.removeKeyring(legacySnapKeyringEntry.metadata.id),\n );\n\n log('Migration completed!');\n },\n );\n }\n\n /**\n * Ensures a Snap keyring is ready for the given Snap. If it doesn't exist yet, it will be created.\n * Safe to call concurrently.\n *\n * @param snapId - The Snap ID to ensure the keyring is ready for.\n */\n async #ensureKeyringIsReady(snapId: SnapId): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const hasKeyring = controller.keyrings.some(\n ({ keyringV2 }) =>\n keyringV2 &&\n isSnapKeyring(keyringV2) &&\n keyringV2.snapId === snapId,\n );\n\n if (!hasKeyring) {\n log(`Creating v2 keyring for Snap \"${snapId}\"...`);\n await controller.addNewKeyring(KeyringType.Snap, {\n snapId,\n accounts: {},\n });\n }\n },\n );\n }\n\n /**\n * Shared body for {@link SnapAccountService.#withKeyringV2} and\n * {@link SnapAccountService.#withKeyringV2Unsafe}. Hides the per-Snap\n * filter and the cast back to {@link SnapKeyring} (the messenger action's\n * callback receives a generic `Keyring`; the selector's type predicate\n * doesn't flow through the messenger's generics).\n *\n * @param action - The messenger action to invoke.\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Call<Result>(\n action:\n | 'KeyringController:withKeyringV2'\n | 'KeyringController:withKeyringV2Unsafe',\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#messenger.call(\n action,\n {\n filter: (keyring): keyring is SnapKeyring =>\n isSnapKeyring(keyring) && keyring.snapId === snapId,\n },\n async ({ keyring }) => operation(keyring as SnapKeyring),\n ) as Result;\n }\n\n /**\n * Lock-free variant of {@link SnapAccountService.#withKeyringV2}. Only use\n * for operations that do not mutate keyring or controller state — see\n * `KeyringController.withKeyringV2Unsafe` for the contract.\n *\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Unsafe<Result>(\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#withKeyringV2Call(\n 'KeyringController:withKeyringV2Unsafe',\n snapId,\n operation,\n );\n }\n\n /**\n * Returns the keyring capabilities declared by the given Snap. These are\n * populated by the bridge keyring from the Snap's manifest, and describe\n * which keyring features the Snap supports (scopes, BIP-44 options, etc.).\n *\n * Consumers use this to decide whether to drive the Snap through the v1 or\n * v2 keyring path. Reading capabilities does not mutate state, so the\n * lock-free keyring access is used.\n *\n * @param snapId - ID of the Snap.\n * @returns The Snap's keyring capabilities.\n */\n async getCapabilities(snapId: SnapId): Promise<KeyringCapabilities> {\n return this.#withKeyringV2Unsafe(\n snapId,\n async (keyring) => keyring.capabilities,\n );\n }\n\n /**\n * Returns the CAIP-19 asset type/ID list supported by an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @returns A promise resolving to the list of supported CAIP-19 asset type/IDs.\n */\n async getAccountAssets(\n snapId: SnapId,\n id: AccountId,\n ): Promise<CaipAssetTypeOrId[]> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountAssets(id);\n }\n\n /**\n * Returns the balances for an account for the requested asset types.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param assets - List of CAIP-19 fungible asset types to fetch balances for.\n * @returns A promise resolving to a map of asset type to balance.\n */\n async getAccountBalances(\n snapId: SnapId,\n id: AccountId,\n assets: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountBalances(id, assets);\n }\n\n /**\n * Returns a page of transactions for an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param pagination - Pagination options.\n * @returns A promise resolving to a page of transactions.\n */\n async getAccountTransactions(\n snapId: SnapId,\n id: AccountId,\n pagination: Pagination,\n ): Promise<TransactionsPage> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .getAccountTransactions(id, pagination);\n }\n\n /**\n * Resolves the account address to use for routing a signing request.\n *\n * @param snapId - ID of the Snap.\n * @param scope - CAIP-2 chain ID of the signing request.\n * @param request - The signing JSON-RPC request.\n * @returns A promise resolving to the resolved address, or `null` if the\n * Snap cannot determine an address for this request.\n */\n async resolveAccountAddress(\n snapId: SnapId,\n scope: CaipChainId,\n request: JsonRpcRequest,\n ): Promise<ResolvedAccountAddress | null> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .resolveAccountAddress(scope, request);\n }\n\n /**\n * Notifies a Snap of the currently selected accounts.\n *\n * For v1 Snaps the call goes through the keyring (signing interface); for\n * v2 Snaps it is routed via the RPC client because the keyring only covers\n * keyring-only operations (signing, account lifecycle).\n *\n * @param snapId - ID of the Snap.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async setSelectedAccounts(\n snapId: SnapId,\n accounts: AccountId[],\n ): Promise<void> {\n await this.ensureReady(snapId);\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n await this.#setSelectedAccountsForKeyring(snapId, keyring, accounts);\n });\n }\n\n /**\n * Dispatches a `setSelectedAccounts` call to the correct layer based on\n * whether the keyring has a v1 interface or not.\n *\n * The keyring is a pure interface for keyring-only operations (signing,\n * account lifecycle). Extra Snap-level methods like `setSelectedAccounts`\n * are invoked via the client for v2 Snaps, which communicates with the Snap\n * over RPC.\n *\n * @param snapId - ID of the Snap.\n * @param keyring - The Snap keyring (v2) instance.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async #setSelectedAccountsForKeyring(\n snapId: SnapId,\n keyring: SnapKeyring,\n accounts: AccountId[],\n ): Promise<void> {\n if (keyring.v1) {\n // We used to keep track of selected accounts in the v1 keyring, so we need to forward the call there for v1 Snaps.\n await keyring.v1.setSelectedAccounts(accounts);\n } else {\n await this.#client.withSnapId(snapId).setSelectedAccounts(accounts);\n }\n }\n\n /**\n * Handle a message from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param message - Message sent by the Snap.\n * @returns The execution result.\n */\n async handleKeyringSnapMessage(\n snapId: SnapId,\n message: SnapMessage,\n ): Promise<Json> {\n const { method: event } = message;\n if (isAccountDataUpdatedKeyringEvent(event)) {\n return this.#publishAccountDataUpdatedEvent(snapId, event, message);\n }\n\n // Handle specific methods.\n if (message.method === SnapManageAccountsMethod.GetSelectedAccounts) {\n const groupId = this.#getSelectedAccountGroupId();\n const accounts = this.#getAccountGroup(groupId)?.accounts ?? [];\n\n try {\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) =>\n accounts.filter((id) => keyring.hasAccount(id)),\n );\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n // Some Snaps might be using `getSelectedAccounts` early in their lifecycle, before the keyring is created. So we\n // do not throw in that case to avoid disrupting their initialization process.\n return [];\n }\n\n throw error;\n }\n }\n\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" to its keyring...`,\n );\n\n // We can create a new keyring if the message is an AccountCreated event.\n const isAccountCreatedMessage = event === KeyringEvent.AccountCreated;\n\n // Create the Snap keyring if it doesn't exist yet (in an atomic way). We cannot assume\n // the keyring exists (e.g for the MMI Snap).\n // NOTE: We only auto-create it for v1 account creation flows.\n if (isAccountCreatedMessage) {\n await this.ensureReady(snapId);\n }\n\n // This part of the flow relies on v1 flows, but v2 keyrings are compatible with those messages\n // too.\n try {\n // NOTE: We use \"unsafe\" here since none of the messages should trigger mutations to the keyring state.\n // The exception might be `:accountCreated`, but even in that case, the mutation is handled differently\n // in the client by call `:persistAllKeyrings` explicitly.\n // Using `:withKeyringV2` would cause a deadlock when we're initiating operations like `removeAccount` from\n // the keyring itself:\n // 1: withKeyring(..., ({ keyring }) => { keyring.removeAccount(...) })\n // 2. removeAccount(...) -> handleKeyringSnapMessage(..., { method: 'accountRemoved', ... })\n // 3. handleKeyringSnapMessage tries to acquire the same lock again via withKeyringV2 -> deadlock.\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n if (!keyring.v1) {\n log(\n `Received message \"${event}\" for Snap \"${snapId}\", but that's a v2 keyring... Rejecting.`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring for Snap \"${snapId}\" is v2, not v1.`,\n );\n }\n\n return await keyring.v1.handleKeyringSnapMessage(message);\n });\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n log(\n `No Snap keyring found for Snap \"${snapId}\". Cannot handle message with method \"${event}\".`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring does not exist yet for Snap \"${snapId}\".`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Publishes an account data update event from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param event - Account data update event.\n * @param message - Message sent by the Snap.\n * @returns `null`.\n */\n #publishAccountDataUpdatedEvent(\n snapId: SnapId,\n event: AccountDataUpdatedKeyringEvent,\n message: SnapMessage,\n ): null {\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" as a SnapAccountService event...`,\n );\n\n if (event === KeyringEvent.AccountAssetListUpdated) {\n assertStruct(message, AccountAssetListUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountAssetListUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountBalancesUpdated) {\n assertStruct(message, AccountBalancesUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountBalancesUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountTransactionsUpdated) {\n assertStruct(message, AccountTransactionsUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountTransactionsUpdated',\n message.params,\n );\n }\n\n // We need to return a valid JSON value, so we cannot use `undefined` here.\n return null;\n }\n\n // eslint-disable-next-line jsdoc/require-returns\n /**\n * Forwards the accounts of the given account group to the Snap keyring.\n *\n * @param groupId - The ID of the account group whose accounts should be\n * forwarded. If empty, this is a no-op.\n * @param accounts - The accounts to forward. If not defined, this is a no-op.\n */\n async #forwardSelectedAccounts(\n groupId: AccountGroupId | '',\n accounts: AccountId[] | undefined,\n ): Promise<void> {\n const skipping = (reason: string): void =>\n log(`${reason}, skipping forwarding selected accounts to Snap keyring`);\n\n if (!this.#migrated) {\n return skipping('Not migrated yet');\n }\n\n if (!groupId) {\n return skipping('No selected account group');\n }\n\n if (!accounts) {\n return skipping(`Account group (\"${groupId}\") has no accounts`);\n }\n\n const forwardSelectedAccounts = async (): Promise<void> => {\n if (accounts.length) {\n log(\n `Forwarding selected accounts (from \"${groupId}\"): ${accounts.join(', ')}`,\n );\n } else {\n log(`Clearing selected accounts (from \"${groupId}\")`);\n }\n\n await Promise.all(\n this.#tracker.getSnaps().map(async (snapId) => {\n try {\n // We can safely invoke this method without taking the controller lock\n // because it should not mutate the keyring state. So we can use\n // `withKeyringV2Unsafe` in this case.\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n // The group's accounts may belong to several Snaps; only\n // forward the subset this Snap actually owns. An empty\n // subset still gets forwarded to explicitly clear the\n // Snap selected accounts.\n const snapAccounts = accounts.filter((id) =>\n keyring.hasAccount(id),\n );\n await this.#setSelectedAccountsForKeyring(\n snapId,\n keyring,\n snapAccounts,\n );\n });\n } catch (error) {\n // Tracked Snaps without a v2 keyring yet are expected —\n // forwarding will resume on the next event once `ensureReady`\n // has run.\n if (!isKeyringNotFoundError(error)) {\n console.error(\n `Error forwarding selected accounts to Snap \"${snapId}\":`,\n error,\n );\n }\n }\n }),\n );\n };\n\n // There is nothing we can do if forwarding fails. This will auto-recover on the next relevant event.\n return await forwardSelectedAccounts().catch((error) => {\n console.error('Error forwarding selected accounts:', error);\n });\n }\n\n /**\n * Gets the account group object for the given group ID.\n *\n * @param groupId - The ID of the account group.\n * @returns The account group object, or undefined if the group ID is empty or the group does not exist.\n */\n #getAccountGroup(\n groupId: AccountGroupId | '',\n ): AccountGroupObject | undefined {\n if (!groupId) {\n return undefined;\n }\n\n return this.#messenger.call(\n 'AccountTreeController:getAccountGroupObject',\n groupId,\n );\n }\n\n /**\n * Gets the currently selected account group ID.\n *\n * @returns The currently selected account group ID, or an empty string if\n * there is no selected account group.\n */\n #getSelectedAccountGroupId(): AccountGroupId | '' {\n return this.#messenger.call(\n 'AccountTreeController:getSelectedAccountGroup',\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SnapAccountService.cjs","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountGroupId } from '@metamask/account-api';\nimport {\n SnapKeyring as LegacySnapKeyring,\n SnapMessage,\n} from '@metamask/eth-snap-keyring';\nimport {\n SnapKeyring,\n SnapKeyringState,\n isSnapKeyring,\n} from '@metamask/eth-snap-keyring/v2';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n AccountTransactionsUpdatedEventPayload,\n Balance,\n CaipAssetType,\n CaipAssetTypeOrId,\n CaipChainId,\n Pagination,\n ResolvedAccountAddress,\n TransactionsPage,\n} from '@metamask/keyring-api';\nimport {\n AccountAssetListUpdatedEventStruct,\n AccountBalancesUpdatedEventStruct,\n AccountTransactionsUpdatedEventStruct,\n KeyringEvent,\n} from '@metamask/keyring-api';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { KeyringCapabilities } from '@metamask/keyring-api/v2';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerStateChangeEvent,\n KeyringControllerUnlockEvent,\n KeyringControllerWithControllerAction,\n KeyringControllerWithKeyringV2Action,\n KeyringControllerWithKeyringV2UnsafeAction,\n} from '@metamask/keyring-controller';\nimport {\n isKeyringNotFoundError,\n KeyringTypes,\n} from '@metamask/keyring-controller';\nimport { KeyringInternalSnapClient } from '@metamask/keyring-internal-snap-client/v2';\nimport { SnapManageAccountsMethod } from '@metamask/keyring-snap-sdk';\nimport type {\n AccountId,\n BaseKeyring,\n JsonRpcRequest,\n} from '@metamask/keyring-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerGetSnapAction,\n SnapControllerGetStateAction,\n SnapControllerHandleRequestAction,\n SnapControllerSnapBlockedEvent,\n SnapControllerSnapDisabledEvent,\n SnapControllerSnapEnabledEvent,\n SnapControllerSnapInstalledEvent,\n SnapControllerSnapUnblockedEvent,\n SnapControllerSnapUninstalledEvent,\n SnapControllerStateChangeEvent,\n} from '@metamask/snaps-controllers';\nimport { SnapId } from '@metamask/snaps-sdk';\nimport type { Json } from '@metamask/utils';\nimport { assertStruct } from '@metamask/utils';\n\nimport { projectLogger as log } from './logger.js';\nimport type {\n SnapAccountServiceEnsureReadyAction,\n SnapAccountServiceEnsureMigratedAction,\n SnapAccountServiceGetCapabilitiesAction,\n SnapAccountServiceGetAccountAssetsAction,\n SnapAccountServiceGetAccountBalancesAction,\n SnapAccountServiceGetAccountTransactionsAction,\n SnapAccountServiceGetSnapsAction,\n SnapAccountServiceHandleKeyringSnapMessageAction,\n SnapAccountServiceResolveAccountAddressAction,\n SnapAccountServiceSetSelectedAccountsAction,\n} from './SnapAccountService-method-action-types.js';\nimport { SnapPlatformWatcher } from './SnapPlatformWatcher.js';\nimport type { SnapPlatformWatcherConfig } from './SnapPlatformWatcher.js';\nimport { SnapTracker } from './SnapTracker.js';\nimport type {\n AccountTreeControllerGetAccountGroupObjectAction,\n AccountTreeControllerGetSelectedAccountGroupAction,\n AccountTreeControllerSelectedAccountGroupChangeEvent,\n AccountTreeControllerAccountGroupCreatedEvent,\n AccountTreeControllerAccountGroupUpdatedEvent,\n AccountTreeControllerAccountGroupRemovedEvent,\n AccountGroupObject,\n} from './types.js';\n\n/**\n * The name of the {@link SnapAccountService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'SnapAccountService';\n\n/**\n * All of the methods within {@link SnapAccountService} that are exposed via\n * the messenger.\n */\nconst MESSENGER_EXPOSED_METHODS = [\n 'ensureMigrated',\n 'ensureReady',\n 'getCapabilities',\n 'getAccountAssets',\n 'getAccountBalances',\n 'getAccountTransactions',\n 'getSnaps',\n 'handleKeyringSnapMessage',\n 'resolveAccountAddress',\n 'setSelectedAccounts',\n] as const;\n\n/**\n * Actions that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceActions =\n | SnapAccountServiceEnsureMigratedAction\n | SnapAccountServiceEnsureReadyAction\n | SnapAccountServiceGetCapabilitiesAction\n | SnapAccountServiceGetAccountAssetsAction\n | SnapAccountServiceGetAccountBalancesAction\n | SnapAccountServiceGetAccountTransactionsAction\n | SnapAccountServiceGetSnapsAction\n | SnapAccountServiceHandleKeyringSnapMessageAction\n | SnapAccountServiceResolveAccountAddressAction\n | SnapAccountServiceSetSelectedAccountsAction;\n\n/**\n * Actions from other messengers that {@link SnapAccountService} calls.\n */\ntype AllowedActions =\n | SnapControllerGetStateAction\n | SnapControllerGetSnapAction\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | KeyringControllerGetStateAction\n | KeyringControllerWithControllerAction\n | KeyringControllerWithKeyringV2Action\n | KeyringControllerWithKeyringV2UnsafeAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetSelectedAccountGroupAction;\n\n/**\n * Events that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceAccountBalancesUpdatedEvent = {\n type: `${typeof serviceName}:accountBalancesUpdated`;\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountAssetListUpdatedEvent = {\n type: `${typeof serviceName}:accountAssetListUpdated`;\n payload: [AccountAssetListUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountTransactionsUpdatedEvent = {\n type: `${typeof serviceName}:accountTransactionsUpdated`;\n payload: [AccountTransactionsUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceEvents =\n | SnapAccountServiceAccountAssetListUpdatedEvent\n | SnapAccountServiceAccountBalancesUpdatedEvent\n | SnapAccountServiceAccountTransactionsUpdatedEvent;\n\n/**\n * Events from other messengers that {@link SnapAccountService} subscribes to.\n */\ntype AllowedEvents =\n | SnapControllerStateChangeEvent\n | SnapControllerSnapInstalledEvent\n | SnapControllerSnapEnabledEvent\n | SnapControllerSnapDisabledEvent\n | SnapControllerSnapBlockedEvent\n | SnapControllerSnapUnblockedEvent\n | SnapControllerSnapUninstalledEvent\n | KeyringControllerStateChangeEvent\n | KeyringControllerUnlockEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent\n | AccountTreeControllerAccountGroupCreatedEvent\n | AccountTreeControllerAccountGroupUpdatedEvent\n | AccountTreeControllerAccountGroupRemovedEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * {@link SnapAccountService}.\n */\nexport type SnapAccountServiceMessenger = Messenger<\n typeof serviceName,\n SnapAccountServiceActions | AllowedActions,\n SnapAccountServiceEvents | AllowedEvents\n>;\n\n/**\n * Configuration for the {@link SnapAccountService}.\n */\nexport type SnapAccountServiceConfig = {\n snapPlatformWatcher?: SnapPlatformWatcherConfig;\n};\n\n/**\n * The options that {@link SnapAccountService} takes.\n */\nexport type SnapAccountServiceOptions = {\n messenger: SnapAccountServiceMessenger;\n config?: SnapAccountServiceConfig;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @param keyring.type - The type of the keyring.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nfunction isLegacySnapKeyring(keyring: {\n type: BaseKeyring['type'];\n}): keyring is LegacySnapKeyring {\n return keyring.type === KeyringTypes.snap;\n}\n\n/**\n * Account data update events that can be forwarded from Snaps.\n *\n * These events are then re-emitted by the service for other consumers.\n */\ntype AccountDataUpdatedKeyringEvent =\n | KeyringEvent.AccountAssetListUpdated\n | KeyringEvent.AccountBalancesUpdated\n | KeyringEvent.AccountTransactionsUpdated;\n\n/**\n * Checks if a Snap message method is an account data update event.\n *\n * @param event - The Snap message event.\n * @returns `true` if the method can be forwarded without the legacy Snap keyring.\n */\nfunction isAccountDataUpdatedKeyringEvent(\n event: string,\n): event is AccountDataUpdatedKeyringEvent {\n return (\n event === KeyringEvent.AccountAssetListUpdated ||\n event === KeyringEvent.AccountBalancesUpdated ||\n event === KeyringEvent.AccountTransactionsUpdated\n );\n}\n\n/**\n * Service responsible for managing account management snaps.\n */\nexport class SnapAccountService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: SnapAccountServiceMessenger;\n\n readonly #watcher: SnapPlatformWatcher;\n\n readonly #tracker: SnapTracker;\n\n readonly #client: KeyringInternalSnapClient;\n\n #migrated = false;\n\n #migratePromise: Promise<void> | null = null;\n\n /**\n * Constructs a new {@link SnapAccountService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.config - Optional service configuration.\n */\n constructor({ messenger, config }: SnapAccountServiceOptions) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#watcher = new SnapPlatformWatcher(\n messenger,\n config?.snapPlatformWatcher,\n );\n this.#tracker = new SnapTracker(messenger);\n this.#client = new KeyringInternalSnapClient({\n messenger: messenger.buildChild({\n namespace: 'KeyringInternalSnapClient',\n actions: ['SnapController:handleRequest'],\n }),\n });\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:selectedAccountGroupChange',\n (groupId) => this.#handleSelectedAccountGroupChange(groupId),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupCreated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupUpdated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupRemoved',\n (groupId) => this.#handleAccountGroupRemoved(groupId),\n );\n\n this.#messenger.subscribe('KeyringController:unlock', () =>\n this.#handleUnlock(),\n );\n }\n\n /**\n * Handles changes to the selected account group by forwarding the new\n * group's accounts to the Snap keyring.\n *\n * @param groupId - The ID of the newly selected account group.\n */\n #handleSelectedAccountGroupChange(groupId: AccountGroupId | ''): void {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n }\n\n /**\n * Handles the keyring controller unlock event by triggering the migration\n * and forwarding the currently selected account group's accounts to the Snap\n * keyring.\n */\n #handleUnlock(): void {\n // eslint-disable-next-line no-void\n void this.ensureMigrated()\n .then(async () => {\n // If the migration is successful, we re-forward the current groups to each new keyrings!\n const groupId = this.#getSelectedAccountGroupId();\n return await this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n })\n .catch((error) => {\n console.error('Migration failed after unlock:', error);\n });\n }\n\n /**\n * Handles created or updated account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the created/updated group is currently selected.\n *\n * @param group - The account group being created or updated.\n */\n #handleAccountGroupCreatedOrUpdated(group: AccountGroupObject): void {\n if (group.id === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(group.id, group.accounts);\n }\n }\n\n /**\n * Handles removed account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the removed group is currently selected.\n *\n * @param groupId - The ID of the account group being removed.\n */\n #handleAccountGroupRemoved(groupId: AccountGroupId): void {\n if (groupId === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n [], // Clearing accounts since the group is removed\n );\n }\n }\n\n /**\n * Returns the IDs of all currently tracked account-management Snaps —\n * Snaps that are installed, enabled, not blocked, and have the\n * `endowment:keyring` permission.\n *\n * @returns The IDs of tracked account-management Snaps.\n */\n getSnaps(): SnapId[] {\n return this.#tracker.getSnaps();\n }\n\n /**\n * Ensures everything is ready to use Snap accounts for the given Snap.\n * 1. Validates that `snapId` is a tracked account-management Snap.\n * 2. Asserts that the legacy -> v2 migration has been triggered (expected to\n * happen at `KeyringController:unlock` time).\n * 3. Atomically creates the v2 keyring for this Snap if it doesn't exist\n * yet.\n * 4. Waits for the Snap platform to be fully started.\n *\n * Safe to call concurrently — each step is idempotent or mutex-protected.\n *\n * @param snapId - ID of the Snap to ensure readiness for.\n * @throws If `snapId` is not a tracked account-management Snap.\n * @throws If the migration has not been triggered yet (wallet not unlocked).\n */\n async ensureReady(snapId: SnapId): Promise<void> {\n if (!this.#tracker.canUse(snapId)) {\n throw new Error(`Unknown snap: \"${snapId}\"`);\n }\n\n // The migration is required to ensure the v2 keyring exists.\n await this.ensureMigrated();\n\n // We still try to create the keyring for the Snap here, since we might\n // want to use a new Snap that never had accounts before.\n await this.#ensureKeyringIsReady(snapId);\n\n // Before doing anything with our Snap, we need to make sure the platform\n // is ready to process requests.\n await this.#watcher.ensureCanUseSnapPlatform();\n }\n\n /**\n * Migrate the legacy Snap keyring to the new (per-snap) Snap keyring v2.\n * Expected to be triggered at `KeyringController:unlock` time.\n * Safe to call concurrently — the migration runs only once; all callers\n * await the same promise.\n *\n * @returns A promise that resolves when the migration is complete.\n */\n async ensureMigrated(): Promise<void> {\n if (this.#migrated) {\n return;\n }\n\n if (!this.#migratePromise) {\n this.#migratePromise = this.#migrate()\n .then(() => {\n this.#migrated = true;\n return undefined;\n })\n .catch((error) => {\n // Clear the promise so the next call can retry.\n this.#migratePromise = null;\n throw error;\n });\n }\n\n await this.#migratePromise;\n }\n\n /**\n * Performs the actual migration logic. Should only be called once, and is not\n * safe to call concurrently.\n */\n async #migrate(): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const { keyrings } = controller;\n\n const legacySnapKeyringEntry = keyrings.find(({ keyring }) =>\n isLegacySnapKeyring(keyring),\n );\n if (!legacySnapKeyringEntry) {\n log('No legacy Snap keyring found. Migration not required.');\n return;\n }\n\n log('Migration started...');\n\n // The legacy Snap keyring has never been a true `EthKeyring` so we\n // need to cast it to `unknown` first.\n const legacySnapKeyring =\n legacySnapKeyringEntry.keyring as unknown as LegacySnapKeyring;\n\n // Compute the account list for each Snap, grouped by snap ID.\n const states = new Map<SnapId, SnapKeyringState>();\n for (const internalAccount of legacySnapKeyring.listAccounts()) {\n // Convert `InternalAccount` to `KeyringAccount` since the Snap\n // keyring (v2) expects accounts in that format and will verify it\n // with `superstruct` when adding the keyring.\n const { metadata, ...account } = internalAccount;\n\n const snap = metadata?.snap;\n if (snap) {\n const snapId = snap.id as SnapId;\n\n let state = states.get(snapId);\n if (!state) {\n state = { snapId, accounts: {} };\n states.set(snapId, state);\n }\n state.accounts[account.id] = account;\n }\n }\n\n // Create the new Snap keyring (v2) for each Snap and migrate the\n // accounts over.\n for (const state of states.values()) {\n log(`Migrating accounts for Snap \"${state.snapId}\"...`);\n await controller.addNewKeyring(\n // IMPORTANT: The Snap keyring (v2) can also be used as a v1\n // keyring. So the builder associated with the v2 keyring type is\n // able to build both v1 and v2 keyrings.\n KeyringType.Snap,\n state,\n );\n }\n\n // Remove the legacy Snap keyring after migration.\n log('Removing legacy Snap keyring...');\n await controller.removeKeyring(legacySnapKeyringEntry.metadata.id);\n\n log('Migration completed!');\n },\n );\n }\n\n /**\n * Ensures a Snap keyring is ready for the given Snap. If it doesn't exist yet, it will be created.\n * Safe to call concurrently.\n *\n * @param snapId - The Snap ID to ensure the keyring is ready for.\n */\n async #ensureKeyringIsReady(snapId: SnapId): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const hasKeyring = controller.keyrings.some(\n ({ keyringV2 }) =>\n keyringV2 &&\n isSnapKeyring(keyringV2) &&\n keyringV2.snapId === snapId,\n );\n\n if (!hasKeyring) {\n log(`Creating v2 keyring for Snap \"${snapId}\"...`);\n await controller.addNewKeyring(KeyringType.Snap, {\n snapId,\n accounts: {},\n });\n }\n },\n );\n }\n\n /**\n * Shared body for {@link SnapAccountService.#withKeyringV2} and\n * {@link SnapAccountService.#withKeyringV2Unsafe}. Hides the per-Snap\n * filter and the cast back to {@link SnapKeyring} (the messenger action's\n * callback receives a generic `Keyring`; the selector's type predicate\n * doesn't flow through the messenger's generics).\n *\n * @param action - The messenger action to invoke.\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Call<Result>(\n action:\n | 'KeyringController:withKeyringV2'\n | 'KeyringController:withKeyringV2Unsafe',\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#messenger.call(\n action,\n {\n filter: (keyring): keyring is SnapKeyring =>\n isSnapKeyring(keyring) && keyring.snapId === snapId,\n },\n async ({ keyring }) => operation(keyring as SnapKeyring),\n ) as Result;\n }\n\n /**\n * Lock-free variant of {@link SnapAccountService.#withKeyringV2}. Only use\n * for operations that do not mutate keyring or controller state — see\n * `KeyringController.withKeyringV2Unsafe` for the contract.\n *\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Unsafe<Result>(\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#withKeyringV2Call(\n 'KeyringController:withKeyringV2Unsafe',\n snapId,\n operation,\n );\n }\n\n /**\n * Returns the keyring capabilities declared by the given Snap. These are\n * populated by the bridge keyring from the Snap's manifest, and describe\n * which keyring features the Snap supports (scopes, BIP-44 options, etc.).\n *\n * Consumers use this to decide whether to drive the Snap through the v1 or\n * v2 keyring path. Reading capabilities does not mutate state, so the\n * lock-free keyring access is used.\n *\n * @param snapId - ID of the Snap.\n * @returns The Snap's keyring capabilities.\n */\n async getCapabilities(snapId: SnapId): Promise<KeyringCapabilities> {\n return this.#withKeyringV2Unsafe(\n snapId,\n async (keyring) => keyring.capabilities,\n );\n }\n\n /**\n * Returns the CAIP-19 asset type/ID list supported by an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @returns A promise resolving to the list of supported CAIP-19 asset type/IDs.\n */\n async getAccountAssets(\n snapId: SnapId,\n id: AccountId,\n ): Promise<CaipAssetTypeOrId[]> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountAssets(id);\n }\n\n /**\n * Returns the balances for an account for the requested asset types.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param assets - List of CAIP-19 fungible asset types to fetch balances for.\n * @returns A promise resolving to a map of asset type to balance.\n */\n async getAccountBalances(\n snapId: SnapId,\n id: AccountId,\n assets: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountBalances(id, assets);\n }\n\n /**\n * Returns a page of transactions for an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param pagination - Pagination options.\n * @returns A promise resolving to a page of transactions.\n */\n async getAccountTransactions(\n snapId: SnapId,\n id: AccountId,\n pagination: Pagination,\n ): Promise<TransactionsPage> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .getAccountTransactions(id, pagination);\n }\n\n /**\n * Resolves the account address to use for routing a signing request.\n *\n * @param snapId - ID of the Snap.\n * @param scope - CAIP-2 chain ID of the signing request.\n * @param request - The signing JSON-RPC request.\n * @returns A promise resolving to the resolved address, or `null` if the\n * Snap cannot determine an address for this request.\n */\n async resolveAccountAddress(\n snapId: SnapId,\n scope: CaipChainId,\n request: JsonRpcRequest,\n ): Promise<ResolvedAccountAddress | null> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .resolveAccountAddress(scope, request);\n }\n\n /**\n * Notifies a Snap of the currently selected accounts.\n *\n * For v1 Snaps the call goes through the keyring (signing interface); for\n * v2 Snaps it is routed via the RPC client because the keyring only covers\n * keyring-only operations (signing, account lifecycle).\n *\n * @param snapId - ID of the Snap.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async setSelectedAccounts(\n snapId: SnapId,\n accounts: AccountId[],\n ): Promise<void> {\n await this.ensureReady(snapId);\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n await this.#setSelectedAccountsForKeyring(snapId, keyring, accounts);\n });\n }\n\n /**\n * Dispatches a `setSelectedAccounts` call to the correct layer based on\n * whether the keyring has a v1 interface or not.\n *\n * The keyring is a pure interface for keyring-only operations (signing,\n * account lifecycle). Extra Snap-level methods like `setSelectedAccounts`\n * are invoked via the client for v2 Snaps, which communicates with the Snap\n * over RPC.\n *\n * @param snapId - ID of the Snap.\n * @param keyring - The Snap keyring (v2) instance.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async #setSelectedAccountsForKeyring(\n snapId: SnapId,\n keyring: SnapKeyring,\n accounts: AccountId[],\n ): Promise<void> {\n if (keyring.v1) {\n // We used to keep track of selected accounts in the v1 keyring, so we need to forward the call there for v1 Snaps.\n await keyring.v1.setSelectedAccounts(accounts);\n } else {\n await this.#client.withSnapId(snapId).setSelectedAccounts(accounts);\n }\n }\n\n /**\n * Handle a message from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param message - Message sent by the Snap.\n * @returns The execution result.\n */\n async handleKeyringSnapMessage(\n snapId: SnapId,\n message: SnapMessage,\n ): Promise<Json> {\n const { method: event } = message;\n if (isAccountDataUpdatedKeyringEvent(event)) {\n return this.#publishAccountDataUpdatedEvent(snapId, event, message);\n }\n\n // Handle specific methods.\n if (message.method === SnapManageAccountsMethod.GetSelectedAccounts) {\n const groupId = this.#getSelectedAccountGroupId();\n const accounts = this.#getAccountGroup(groupId)?.accounts ?? [];\n\n try {\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) =>\n accounts.filter((id) => keyring.hasAccount(id)),\n );\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n // Some Snaps might be using `getSelectedAccounts` early in their lifecycle, before the keyring is created. So we\n // do not throw in that case to avoid disrupting their initialization process.\n return [];\n }\n\n throw error;\n }\n }\n\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" to its keyring...`,\n );\n\n // We can create a new keyring if the message is an AccountCreated event.\n const isAccountCreatedMessage = event === KeyringEvent.AccountCreated;\n\n // Create the Snap keyring if it doesn't exist yet (in an atomic way). We cannot assume\n // the keyring exists (e.g for the MMI Snap).\n // NOTE: We only auto-create it for v1 account creation flows.\n if (isAccountCreatedMessage) {\n await this.ensureReady(snapId);\n }\n\n // This part of the flow relies on v1 flows, but v2 keyrings are compatible with those messages\n // too.\n try {\n // NOTE: We use \"unsafe\" here since none of the messages should trigger mutations to the keyring state.\n // The exception might be `:accountCreated`, but even in that case, the mutation is handled differently\n // in the client by call `:persistAllKeyrings` explicitly.\n // Using `:withKeyringV2` would cause a deadlock when we're initiating operations like `removeAccount` from\n // the keyring itself:\n // 1: withKeyring(..., ({ keyring }) => { keyring.removeAccount(...) })\n // 2. removeAccount(...) -> handleKeyringSnapMessage(..., { method: 'accountRemoved', ... })\n // 3. handleKeyringSnapMessage tries to acquire the same lock again via withKeyringV2 -> deadlock.\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n if (!keyring.v1) {\n log(\n `Received message \"${event}\" for Snap \"${snapId}\", but that's a v2 keyring... Rejecting.`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring for Snap \"${snapId}\" is v2, not v1.`,\n );\n }\n\n return await keyring.v1.handleKeyringSnapMessage(message);\n });\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n log(\n `No Snap keyring found for Snap \"${snapId}\". Cannot handle message with method \"${event}\".`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring does not exist yet for Snap \"${snapId}\".`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Publishes an account data update event from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param event - Account data update event.\n * @param message - Message sent by the Snap.\n * @returns `null`.\n */\n #publishAccountDataUpdatedEvent(\n snapId: SnapId,\n event: AccountDataUpdatedKeyringEvent,\n message: SnapMessage,\n ): null {\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" as a SnapAccountService event...`,\n );\n\n if (event === KeyringEvent.AccountAssetListUpdated) {\n assertStruct(message, AccountAssetListUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountAssetListUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountBalancesUpdated) {\n assertStruct(message, AccountBalancesUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountBalancesUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountTransactionsUpdated) {\n assertStruct(message, AccountTransactionsUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountTransactionsUpdated',\n message.params,\n );\n }\n\n // We need to return a valid JSON value, so we cannot use `undefined` here.\n return null;\n }\n\n // eslint-disable-next-line jsdoc/require-returns\n /**\n * Forwards the accounts of the given account group to the Snap keyring.\n *\n * @param groupId - The ID of the account group whose accounts should be\n * forwarded. If empty, this is a no-op.\n * @param accounts - The accounts to forward. If not defined, this is a no-op.\n */\n async #forwardSelectedAccounts(\n groupId: AccountGroupId | '',\n accounts: AccountId[] | undefined,\n ): Promise<void> {\n const skipping = (reason: string): void =>\n log(`${reason}, skipping forwarding selected accounts to Snap keyring`);\n\n if (!this.#migrated) {\n return skipping('Not migrated yet');\n }\n\n if (!groupId) {\n return skipping('No selected account group');\n }\n\n if (!accounts) {\n return skipping(`Account group (\"${groupId}\") has no accounts`);\n }\n\n const forwardSelectedAccounts = async (): Promise<void> => {\n if (accounts.length) {\n log(\n `Forwarding selected accounts (from \"${groupId}\"): ${accounts.join(', ')}`,\n );\n } else {\n log(`Clearing selected accounts (from \"${groupId}\")`);\n }\n\n await Promise.all(\n this.#tracker.getSnaps().map(async (snapId) => {\n try {\n // We can safely invoke this method without taking the controller lock\n // because it should not mutate the keyring state. So we can use\n // `withKeyringV2Unsafe` in this case.\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n // The group's accounts may belong to several Snaps; only\n // forward the subset this Snap actually owns. An empty\n // subset still gets forwarded to explicitly clear the\n // Snap selected accounts.\n const snapAccounts = accounts.filter((id) =>\n keyring.hasAccount(id),\n );\n await this.#setSelectedAccountsForKeyring(\n snapId,\n keyring,\n snapAccounts,\n );\n });\n } catch (error) {\n // Tracked Snaps without a v2 keyring yet are expected —\n // forwarding will resume on the next event once `ensureReady`\n // has run.\n if (!isKeyringNotFoundError(error)) {\n console.error(\n `Error forwarding selected accounts to Snap \"${snapId}\":`,\n error,\n );\n }\n }\n }),\n );\n };\n\n // There is nothing we can do if forwarding fails. This will auto-recover on the next relevant event.\n return await forwardSelectedAccounts().catch((error) => {\n console.error('Error forwarding selected accounts:', error);\n });\n }\n\n /**\n * Gets the account group object for the given group ID.\n *\n * @param groupId - The ID of the account group.\n * @returns The account group object, or undefined if the group ID is empty or the group does not exist.\n */\n #getAccountGroup(\n groupId: AccountGroupId | '',\n ): AccountGroupObject | undefined {\n if (!groupId) {\n return undefined;\n }\n\n return this.#messenger.call(\n 'AccountTreeController:getAccountGroupObject',\n groupId,\n );\n }\n\n /**\n * Gets the currently selected account group ID.\n *\n * @returns The currently selected account group ID, or an empty string if\n * there is no selected account group.\n */\n #getSelectedAccountGroupId(): AccountGroupId | '' {\n return this.#messenger.call(\n 'AccountTreeController:getSelectedAccountGroup',\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountService.d.cts","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACZ,mCAAmC;AAMpC,OAAO,KAAK,EACV,mCAAmC,EACnC,kCAAkC,EAClC,sCAAsC,EACtC,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,gBAAgB,EACjB,8BAA8B;AAQ/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,iCAAiC;AACpE,OAAO,KAAK,EACV,+BAA+B,EAC/B,iCAAiC,EACjC,4BAA4B,EAC5B,qCAAqC,EACrC,oCAAoC,EACpC,0CAA0C,EAC3C,qCAAqC;AAOtC,OAAO,KAAK,EACV,SAAS,EAET,cAAc,EACf,gCAAgC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,oCAAoC,EACpC,2BAA2B,EAC3B,4BAA4B,EAC5B,iCAAiC,EACjC,8BAA8B,EAC9B,+BAA+B,EAC/B,8BAA8B,EAC9B,gCAAgC,EAChC,gCAAgC,EAChC,kCAAkC,EAClC,8BAA8B,EAC/B,oCAAoC;AACrC,OAAO,EAAE,MAAM,EAAE,4BAA4B;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;
|
|
1
|
+
{"version":3,"file":"SnapAccountService.d.cts","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountService.d.mts","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACZ,mCAAmC;AAMpC,OAAO,KAAK,EACV,mCAAmC,EACnC,kCAAkC,EAClC,sCAAsC,EACtC,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,gBAAgB,EACjB,8BAA8B;AAQ/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,iCAAiC;AACpE,OAAO,KAAK,EACV,+BAA+B,EAC/B,iCAAiC,EACjC,4BAA4B,EAC5B,qCAAqC,EACrC,oCAAoC,EACpC,0CAA0C,EAC3C,qCAAqC;AAOtC,OAAO,KAAK,EACV,SAAS,EAET,cAAc,EACf,gCAAgC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,oCAAoC,EACpC,2BAA2B,EAC3B,4BAA4B,EAC5B,iCAAiC,EACjC,8BAA8B,EAC9B,+BAA+B,EAC/B,8BAA8B,EAC9B,gCAAgC,EAChC,gCAAgC,EAChC,kCAAkC,EAClC,8BAA8B,EAC/B,oCAAoC;AACrC,OAAO,EAAE,MAAM,EAAE,4BAA4B;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;
|
|
1
|
+
{"version":3,"file":"SnapAccountService.d.mts","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,6 @@ import { isKeyringNotFoundError, KeyringTypes } from "@metamask/keyring-controll
|
|
|
18
18
|
import { KeyringInternalSnapClient } from "@metamask/keyring-internal-snap-client/v2";
|
|
19
19
|
import { SnapManageAccountsMethod } from "@metamask/keyring-snap-sdk";
|
|
20
20
|
import { assertStruct } from "@metamask/utils";
|
|
21
|
-
import { reportError, withSafeError } from "./errors.mjs";
|
|
22
21
|
import { projectLogger as log } from "./logger.mjs";
|
|
23
22
|
import { SnapPlatformWatcher } from "./SnapPlatformWatcher.mjs";
|
|
24
23
|
import { SnapTracker } from "./SnapTracker.mjs";
|
|
@@ -317,14 +316,14 @@ _SnapAccountService_messenger = new WeakMap(), _SnapAccountService_watcher = new
|
|
|
317
316
|
void __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_forwardSelectedAccounts).call(this, groupId, __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getAccountGroup).call(this, groupId)?.accounts);
|
|
318
317
|
}, _SnapAccountService_handleUnlock = function _SnapAccountService_handleUnlock() {
|
|
319
318
|
// eslint-disable-next-line no-void
|
|
320
|
-
void
|
|
319
|
+
void this.ensureMigrated()
|
|
320
|
+
.then(async () => {
|
|
321
321
|
// If the migration is successful, we re-forward the current groups to each new keyrings!
|
|
322
322
|
const groupId = __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getSelectedAccountGroupId).call(this);
|
|
323
|
-
// NOTE: This cannot throw, all errors are swallowed under the hood, so we don't need to
|
|
324
|
-
// catch anything here.
|
|
325
323
|
return await __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_forwardSelectedAccounts).call(this, groupId, __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getAccountGroup).call(this, groupId)?.accounts);
|
|
326
|
-
}
|
|
327
|
-
|
|
324
|
+
})
|
|
325
|
+
.catch((error) => {
|
|
326
|
+
console.error('Migration failed after unlock:', error);
|
|
328
327
|
});
|
|
329
328
|
}, _SnapAccountService_handleAccountGroupCreatedOrUpdated = function _SnapAccountService_handleAccountGroupCreatedOrUpdated(group) {
|
|
330
329
|
if (group.id === __classPrivateFieldGet(this, _SnapAccountService_instances, "m", _SnapAccountService_getSelectedAccountGroupId).call(this)) {
|
|
@@ -375,15 +374,15 @@ async function _SnapAccountService_migrate() {
|
|
|
375
374
|
// accounts over.
|
|
376
375
|
for (const state of states.values()) {
|
|
377
376
|
log(`Migrating accounts for Snap "${state.snapId}"...`);
|
|
378
|
-
await
|
|
377
|
+
await controller.addNewKeyring(
|
|
379
378
|
// IMPORTANT: The Snap keyring (v2) can also be used as a v1
|
|
380
|
-
// keyring. So the builder associated with the v2 keyring type
|
|
381
|
-
//
|
|
382
|
-
KeyringType.Snap, state)
|
|
379
|
+
// keyring. So the builder associated with the v2 keyring type is
|
|
380
|
+
// able to build both v1 and v2 keyrings.
|
|
381
|
+
KeyringType.Snap, state);
|
|
383
382
|
}
|
|
384
383
|
// Remove the legacy Snap keyring after migration.
|
|
385
384
|
log('Removing legacy Snap keyring...');
|
|
386
|
-
await
|
|
385
|
+
await controller.removeKeyring(legacySnapKeyringEntry.metadata.id);
|
|
387
386
|
log('Migration completed!');
|
|
388
387
|
});
|
|
389
388
|
}, _SnapAccountService_ensureKeyringIsReady =
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountService.mjs","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountGroupId } from '@metamask/account-api';\nimport {\n SnapKeyring as LegacySnapKeyring,\n SnapMessage,\n} from '@metamask/eth-snap-keyring';\nimport {\n SnapKeyring,\n SnapKeyringState,\n isSnapKeyring,\n} from '@metamask/eth-snap-keyring/v2';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n AccountTransactionsUpdatedEventPayload,\n Balance,\n CaipAssetType,\n CaipAssetTypeOrId,\n CaipChainId,\n Pagination,\n ResolvedAccountAddress,\n TransactionsPage,\n} from '@metamask/keyring-api';\nimport {\n AccountAssetListUpdatedEventStruct,\n AccountBalancesUpdatedEventStruct,\n AccountTransactionsUpdatedEventStruct,\n KeyringEvent,\n} from '@metamask/keyring-api';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { KeyringCapabilities } from '@metamask/keyring-api/v2';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerStateChangeEvent,\n KeyringControllerUnlockEvent,\n KeyringControllerWithControllerAction,\n KeyringControllerWithKeyringV2Action,\n KeyringControllerWithKeyringV2UnsafeAction,\n} from '@metamask/keyring-controller';\nimport {\n isKeyringNotFoundError,\n KeyringTypes,\n} from '@metamask/keyring-controller';\nimport { KeyringInternalSnapClient } from '@metamask/keyring-internal-snap-client/v2';\nimport { SnapManageAccountsMethod } from '@metamask/keyring-snap-sdk';\nimport type {\n AccountId,\n BaseKeyring,\n JsonRpcRequest,\n} from '@metamask/keyring-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerGetSnapAction,\n SnapControllerGetStateAction,\n SnapControllerHandleRequestAction,\n SnapControllerSnapBlockedEvent,\n SnapControllerSnapDisabledEvent,\n SnapControllerSnapEnabledEvent,\n SnapControllerSnapInstalledEvent,\n SnapControllerSnapUnblockedEvent,\n SnapControllerSnapUninstalledEvent,\n SnapControllerStateChangeEvent,\n} from '@metamask/snaps-controllers';\nimport { SnapId } from '@metamask/snaps-sdk';\nimport type { Json } from '@metamask/utils';\nimport { assertStruct } from '@metamask/utils';\n\nimport { reportError, withSafeError } from './errors.js';\nimport { projectLogger as log } from './logger.js';\nimport type {\n SnapAccountServiceEnsureReadyAction,\n SnapAccountServiceEnsureMigratedAction,\n SnapAccountServiceGetCapabilitiesAction,\n SnapAccountServiceGetAccountAssetsAction,\n SnapAccountServiceGetAccountBalancesAction,\n SnapAccountServiceGetAccountTransactionsAction,\n SnapAccountServiceGetSnapsAction,\n SnapAccountServiceHandleKeyringSnapMessageAction,\n SnapAccountServiceResolveAccountAddressAction,\n SnapAccountServiceSetSelectedAccountsAction,\n} from './SnapAccountService-method-action-types.js';\nimport { SnapPlatformWatcher } from './SnapPlatformWatcher.js';\nimport type { SnapPlatformWatcherConfig } from './SnapPlatformWatcher.js';\nimport { SnapTracker } from './SnapTracker.js';\nimport type {\n AccountTreeControllerGetAccountGroupObjectAction,\n AccountTreeControllerGetSelectedAccountGroupAction,\n AccountTreeControllerSelectedAccountGroupChangeEvent,\n AccountTreeControllerAccountGroupCreatedEvent,\n AccountTreeControllerAccountGroupUpdatedEvent,\n AccountTreeControllerAccountGroupRemovedEvent,\n AccountGroupObject,\n} from './types.js';\n\n/**\n * The name of the {@link SnapAccountService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'SnapAccountService';\n\n/**\n * All of the methods within {@link SnapAccountService} that are exposed via\n * the messenger.\n */\nconst MESSENGER_EXPOSED_METHODS = [\n 'ensureMigrated',\n 'ensureReady',\n 'getCapabilities',\n 'getAccountAssets',\n 'getAccountBalances',\n 'getAccountTransactions',\n 'getSnaps',\n 'handleKeyringSnapMessage',\n 'resolveAccountAddress',\n 'setSelectedAccounts',\n] as const;\n\n/**\n * Actions that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceActions =\n | SnapAccountServiceEnsureMigratedAction\n | SnapAccountServiceEnsureReadyAction\n | SnapAccountServiceGetCapabilitiesAction\n | SnapAccountServiceGetAccountAssetsAction\n | SnapAccountServiceGetAccountBalancesAction\n | SnapAccountServiceGetAccountTransactionsAction\n | SnapAccountServiceGetSnapsAction\n | SnapAccountServiceHandleKeyringSnapMessageAction\n | SnapAccountServiceResolveAccountAddressAction\n | SnapAccountServiceSetSelectedAccountsAction;\n\n/**\n * Actions from other messengers that {@link SnapAccountService} calls.\n */\ntype AllowedActions =\n | SnapControllerGetStateAction\n | SnapControllerGetSnapAction\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | KeyringControllerGetStateAction\n | KeyringControllerWithControllerAction\n | KeyringControllerWithKeyringV2Action\n | KeyringControllerWithKeyringV2UnsafeAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetSelectedAccountGroupAction;\n\n/**\n * Events that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceAccountBalancesUpdatedEvent = {\n type: `${typeof serviceName}:accountBalancesUpdated`;\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountAssetListUpdatedEvent = {\n type: `${typeof serviceName}:accountAssetListUpdated`;\n payload: [AccountAssetListUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountTransactionsUpdatedEvent = {\n type: `${typeof serviceName}:accountTransactionsUpdated`;\n payload: [AccountTransactionsUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceEvents =\n | SnapAccountServiceAccountAssetListUpdatedEvent\n | SnapAccountServiceAccountBalancesUpdatedEvent\n | SnapAccountServiceAccountTransactionsUpdatedEvent;\n\n/**\n * Events from other messengers that {@link SnapAccountService} subscribes to.\n */\ntype AllowedEvents =\n | SnapControllerStateChangeEvent\n | SnapControllerSnapInstalledEvent\n | SnapControllerSnapEnabledEvent\n | SnapControllerSnapDisabledEvent\n | SnapControllerSnapBlockedEvent\n | SnapControllerSnapUnblockedEvent\n | SnapControllerSnapUninstalledEvent\n | KeyringControllerStateChangeEvent\n | KeyringControllerUnlockEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent\n | AccountTreeControllerAccountGroupCreatedEvent\n | AccountTreeControllerAccountGroupUpdatedEvent\n | AccountTreeControllerAccountGroupRemovedEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * {@link SnapAccountService}.\n */\nexport type SnapAccountServiceMessenger = Messenger<\n typeof serviceName,\n SnapAccountServiceActions | AllowedActions,\n SnapAccountServiceEvents | AllowedEvents\n>;\n\n/**\n * Configuration for the {@link SnapAccountService}.\n */\nexport type SnapAccountServiceConfig = {\n snapPlatformWatcher?: SnapPlatformWatcherConfig;\n};\n\n/**\n * The options that {@link SnapAccountService} takes.\n */\nexport type SnapAccountServiceOptions = {\n messenger: SnapAccountServiceMessenger;\n config?: SnapAccountServiceConfig;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @param keyring.type - The type of the keyring.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nfunction isLegacySnapKeyring(keyring: {\n type: BaseKeyring['type'];\n}): keyring is LegacySnapKeyring {\n return keyring.type === KeyringTypes.snap;\n}\n\n/**\n * Account data update events that can be forwarded from Snaps.\n *\n * These events are then re-emitted by the service for other consumers.\n */\ntype AccountDataUpdatedKeyringEvent =\n | KeyringEvent.AccountAssetListUpdated\n | KeyringEvent.AccountBalancesUpdated\n | KeyringEvent.AccountTransactionsUpdated;\n\n/**\n * Checks if a Snap message method is an account data update event.\n *\n * @param event - The Snap message event.\n * @returns `true` if the method can be forwarded without the legacy Snap keyring.\n */\nfunction isAccountDataUpdatedKeyringEvent(\n event: string,\n): event is AccountDataUpdatedKeyringEvent {\n return (\n event === KeyringEvent.AccountAssetListUpdated ||\n event === KeyringEvent.AccountBalancesUpdated ||\n event === KeyringEvent.AccountTransactionsUpdated\n );\n}\n\n/**\n * Service responsible for managing account management snaps.\n */\nexport class SnapAccountService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: SnapAccountServiceMessenger;\n\n readonly #watcher: SnapPlatformWatcher;\n\n readonly #tracker: SnapTracker;\n\n readonly #client: KeyringInternalSnapClient;\n\n #migrated = false;\n\n #migratePromise: Promise<void> | null = null;\n\n /**\n * Constructs a new {@link SnapAccountService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.config - Optional service configuration.\n */\n constructor({ messenger, config }: SnapAccountServiceOptions) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#watcher = new SnapPlatformWatcher(\n messenger,\n config?.snapPlatformWatcher,\n );\n this.#tracker = new SnapTracker(messenger);\n this.#client = new KeyringInternalSnapClient({\n messenger: messenger.buildChild({\n namespace: 'KeyringInternalSnapClient',\n actions: ['SnapController:handleRequest'],\n }),\n });\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:selectedAccountGroupChange',\n (groupId) => this.#handleSelectedAccountGroupChange(groupId),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupCreated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupUpdated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupRemoved',\n (groupId) => this.#handleAccountGroupRemoved(groupId),\n );\n\n this.#messenger.subscribe('KeyringController:unlock', () =>\n this.#handleUnlock(),\n );\n }\n\n /**\n * Handles changes to the selected account group by forwarding the new\n * group's accounts to the Snap keyring.\n *\n * @param groupId - The ID of the newly selected account group.\n */\n #handleSelectedAccountGroupChange(groupId: AccountGroupId | ''): void {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n }\n\n /**\n * Handles the keyring controller unlock event by triggering the migration\n * and forwarding the currently selected account group's accounts to the Snap\n * keyring.\n */\n #handleUnlock(): void {\n // eslint-disable-next-line no-void\n void withSafeError('Snap keyring v2 migration', () =>\n this.ensureMigrated(),\n ).then(\n async () => {\n // If the migration is successful, we re-forward the current groups to each new keyrings!\n const groupId = this.#getSelectedAccountGroupId();\n // NOTE: This cannot throw, all errors are swallowed under the hood, so we don't need to\n // catch anything here.\n return await this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n },\n (error) => {\n reportError(this.#messenger, 'Migration failed after unlock', error);\n },\n );\n }\n\n /**\n * Handles created or updated account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the created/updated group is currently selected.\n *\n * @param group - The account group being created or updated.\n */\n #handleAccountGroupCreatedOrUpdated(group: AccountGroupObject): void {\n if (group.id === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(group.id, group.accounts);\n }\n }\n\n /**\n * Handles removed account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the removed group is currently selected.\n *\n * @param groupId - The ID of the account group being removed.\n */\n #handleAccountGroupRemoved(groupId: AccountGroupId): void {\n if (groupId === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n [], // Clearing accounts since the group is removed\n );\n }\n }\n\n /**\n * Returns the IDs of all currently tracked account-management Snaps —\n * Snaps that are installed, enabled, not blocked, and have the\n * `endowment:keyring` permission.\n *\n * @returns The IDs of tracked account-management Snaps.\n */\n getSnaps(): SnapId[] {\n return this.#tracker.getSnaps();\n }\n\n /**\n * Ensures everything is ready to use Snap accounts for the given Snap.\n * 1. Validates that `snapId` is a tracked account-management Snap.\n * 2. Asserts that the legacy -> v2 migration has been triggered (expected to\n * happen at `KeyringController:unlock` time).\n * 3. Atomically creates the v2 keyring for this Snap if it doesn't exist\n * yet.\n * 4. Waits for the Snap platform to be fully started.\n *\n * Safe to call concurrently — each step is idempotent or mutex-protected.\n *\n * @param snapId - ID of the Snap to ensure readiness for.\n * @throws If `snapId` is not a tracked account-management Snap.\n * @throws If the migration has not been triggered yet (wallet not unlocked).\n */\n async ensureReady(snapId: SnapId): Promise<void> {\n if (!this.#tracker.canUse(snapId)) {\n throw new Error(`Unknown snap: \"${snapId}\"`);\n }\n\n // The migration is required to ensure the v2 keyring exists.\n await this.ensureMigrated();\n\n // We still try to create the keyring for the Snap here, since we might\n // want to use a new Snap that never had accounts before.\n await this.#ensureKeyringIsReady(snapId);\n\n // Before doing anything with our Snap, we need to make sure the platform\n // is ready to process requests.\n await this.#watcher.ensureCanUseSnapPlatform();\n }\n\n /**\n * Migrate the legacy Snap keyring to the new (per-snap) Snap keyring v2.\n * Expected to be triggered at `KeyringController:unlock` time.\n * Safe to call concurrently — the migration runs only once; all callers\n * await the same promise.\n *\n * @returns A promise that resolves when the migration is complete.\n */\n async ensureMigrated(): Promise<void> {\n if (this.#migrated) {\n return;\n }\n\n if (!this.#migratePromise) {\n this.#migratePromise = this.#migrate()\n .then(() => {\n this.#migrated = true;\n return undefined;\n })\n .catch((error) => {\n // Clear the promise so the next call can retry.\n this.#migratePromise = null;\n throw error;\n });\n }\n\n await this.#migratePromise;\n }\n\n /**\n * Performs the actual migration logic. Should only be called once, and is not\n * safe to call concurrently.\n */\n async #migrate(): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const { keyrings } = controller;\n\n const legacySnapKeyringEntry = keyrings.find(({ keyring }) =>\n isLegacySnapKeyring(keyring),\n );\n if (!legacySnapKeyringEntry) {\n log('No legacy Snap keyring found. Migration not required.');\n return;\n }\n\n log('Migration started...');\n\n // The legacy Snap keyring has never been a true `EthKeyring` so we\n // need to cast it to `unknown` first.\n const legacySnapKeyring =\n legacySnapKeyringEntry.keyring as unknown as LegacySnapKeyring;\n\n // Compute the account list for each Snap, grouped by snap ID.\n const states = new Map<SnapId, SnapKeyringState>();\n for (const internalAccount of legacySnapKeyring.listAccounts()) {\n // Convert `InternalAccount` to `KeyringAccount` since the Snap\n // keyring (v2) expects accounts in that format and will verify it\n // with `superstruct` when adding the keyring.\n const { metadata, ...account } = internalAccount;\n\n const snap = metadata?.snap;\n if (snap) {\n const snapId = snap.id as SnapId;\n\n let state = states.get(snapId);\n if (!state) {\n state = { snapId, accounts: {} };\n states.set(snapId, state);\n }\n state.accounts[account.id] = account;\n }\n }\n\n // Create the new Snap keyring (v2) for each Snap and migrate the\n // accounts over.\n for (const state of states.values()) {\n log(`Migrating accounts for Snap \"${state.snapId}\"...`);\n await withSafeError(\n `Adding v2 Snap keyring for \"${state.snapId}\"`,\n async () =>\n controller.addNewKeyring(\n // IMPORTANT: The Snap keyring (v2) can also be used as a v1\n // keyring. So the builder associated with the v2 keyring type\n // is able to build both v1 and v2 keyrings.\n KeyringType.Snap,\n state,\n ),\n );\n }\n\n // Remove the legacy Snap keyring after migration.\n log('Removing legacy Snap keyring...');\n await withSafeError('Removing legacy Snap keyring', async () =>\n controller.removeKeyring(legacySnapKeyringEntry.metadata.id),\n );\n\n log('Migration completed!');\n },\n );\n }\n\n /**\n * Ensures a Snap keyring is ready for the given Snap. If it doesn't exist yet, it will be created.\n * Safe to call concurrently.\n *\n * @param snapId - The Snap ID to ensure the keyring is ready for.\n */\n async #ensureKeyringIsReady(snapId: SnapId): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const hasKeyring = controller.keyrings.some(\n ({ keyringV2 }) =>\n keyringV2 &&\n isSnapKeyring(keyringV2) &&\n keyringV2.snapId === snapId,\n );\n\n if (!hasKeyring) {\n log(`Creating v2 keyring for Snap \"${snapId}\"...`);\n await controller.addNewKeyring(KeyringType.Snap, {\n snapId,\n accounts: {},\n });\n }\n },\n );\n }\n\n /**\n * Shared body for {@link SnapAccountService.#withKeyringV2} and\n * {@link SnapAccountService.#withKeyringV2Unsafe}. Hides the per-Snap\n * filter and the cast back to {@link SnapKeyring} (the messenger action's\n * callback receives a generic `Keyring`; the selector's type predicate\n * doesn't flow through the messenger's generics).\n *\n * @param action - The messenger action to invoke.\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Call<Result>(\n action:\n | 'KeyringController:withKeyringV2'\n | 'KeyringController:withKeyringV2Unsafe',\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#messenger.call(\n action,\n {\n filter: (keyring): keyring is SnapKeyring =>\n isSnapKeyring(keyring) && keyring.snapId === snapId,\n },\n async ({ keyring }) => operation(keyring as SnapKeyring),\n ) as Result;\n }\n\n /**\n * Lock-free variant of {@link SnapAccountService.#withKeyringV2}. Only use\n * for operations that do not mutate keyring or controller state — see\n * `KeyringController.withKeyringV2Unsafe` for the contract.\n *\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Unsafe<Result>(\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#withKeyringV2Call(\n 'KeyringController:withKeyringV2Unsafe',\n snapId,\n operation,\n );\n }\n\n /**\n * Returns the keyring capabilities declared by the given Snap. These are\n * populated by the bridge keyring from the Snap's manifest, and describe\n * which keyring features the Snap supports (scopes, BIP-44 options, etc.).\n *\n * Consumers use this to decide whether to drive the Snap through the v1 or\n * v2 keyring path. Reading capabilities does not mutate state, so the\n * lock-free keyring access is used.\n *\n * @param snapId - ID of the Snap.\n * @returns The Snap's keyring capabilities.\n */\n async getCapabilities(snapId: SnapId): Promise<KeyringCapabilities> {\n return this.#withKeyringV2Unsafe(\n snapId,\n async (keyring) => keyring.capabilities,\n );\n }\n\n /**\n * Returns the CAIP-19 asset type/ID list supported by an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @returns A promise resolving to the list of supported CAIP-19 asset type/IDs.\n */\n async getAccountAssets(\n snapId: SnapId,\n id: AccountId,\n ): Promise<CaipAssetTypeOrId[]> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountAssets(id);\n }\n\n /**\n * Returns the balances for an account for the requested asset types.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param assets - List of CAIP-19 fungible asset types to fetch balances for.\n * @returns A promise resolving to a map of asset type to balance.\n */\n async getAccountBalances(\n snapId: SnapId,\n id: AccountId,\n assets: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountBalances(id, assets);\n }\n\n /**\n * Returns a page of transactions for an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param pagination - Pagination options.\n * @returns A promise resolving to a page of transactions.\n */\n async getAccountTransactions(\n snapId: SnapId,\n id: AccountId,\n pagination: Pagination,\n ): Promise<TransactionsPage> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .getAccountTransactions(id, pagination);\n }\n\n /**\n * Resolves the account address to use for routing a signing request.\n *\n * @param snapId - ID of the Snap.\n * @param scope - CAIP-2 chain ID of the signing request.\n * @param request - The signing JSON-RPC request.\n * @returns A promise resolving to the resolved address, or `null` if the\n * Snap cannot determine an address for this request.\n */\n async resolveAccountAddress(\n snapId: SnapId,\n scope: CaipChainId,\n request: JsonRpcRequest,\n ): Promise<ResolvedAccountAddress | null> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .resolveAccountAddress(scope, request);\n }\n\n /**\n * Notifies a Snap of the currently selected accounts.\n *\n * For v1 Snaps the call goes through the keyring (signing interface); for\n * v2 Snaps it is routed via the RPC client because the keyring only covers\n * keyring-only operations (signing, account lifecycle).\n *\n * @param snapId - ID of the Snap.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async setSelectedAccounts(\n snapId: SnapId,\n accounts: AccountId[],\n ): Promise<void> {\n await this.ensureReady(snapId);\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n await this.#setSelectedAccountsForKeyring(snapId, keyring, accounts);\n });\n }\n\n /**\n * Dispatches a `setSelectedAccounts` call to the correct layer based on\n * whether the keyring has a v1 interface or not.\n *\n * The keyring is a pure interface for keyring-only operations (signing,\n * account lifecycle). Extra Snap-level methods like `setSelectedAccounts`\n * are invoked via the client for v2 Snaps, which communicates with the Snap\n * over RPC.\n *\n * @param snapId - ID of the Snap.\n * @param keyring - The Snap keyring (v2) instance.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async #setSelectedAccountsForKeyring(\n snapId: SnapId,\n keyring: SnapKeyring,\n accounts: AccountId[],\n ): Promise<void> {\n if (keyring.v1) {\n // We used to keep track of selected accounts in the v1 keyring, so we need to forward the call there for v1 Snaps.\n await keyring.v1.setSelectedAccounts(accounts);\n } else {\n await this.#client.withSnapId(snapId).setSelectedAccounts(accounts);\n }\n }\n\n /**\n * Handle a message from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param message - Message sent by the Snap.\n * @returns The execution result.\n */\n async handleKeyringSnapMessage(\n snapId: SnapId,\n message: SnapMessage,\n ): Promise<Json> {\n const { method: event } = message;\n if (isAccountDataUpdatedKeyringEvent(event)) {\n return this.#publishAccountDataUpdatedEvent(snapId, event, message);\n }\n\n // Handle specific methods.\n if (message.method === SnapManageAccountsMethod.GetSelectedAccounts) {\n const groupId = this.#getSelectedAccountGroupId();\n const accounts = this.#getAccountGroup(groupId)?.accounts ?? [];\n\n try {\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) =>\n accounts.filter((id) => keyring.hasAccount(id)),\n );\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n // Some Snaps might be using `getSelectedAccounts` early in their lifecycle, before the keyring is created. So we\n // do not throw in that case to avoid disrupting their initialization process.\n return [];\n }\n\n throw error;\n }\n }\n\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" to its keyring...`,\n );\n\n // We can create a new keyring if the message is an AccountCreated event.\n const isAccountCreatedMessage = event === KeyringEvent.AccountCreated;\n\n // Create the Snap keyring if it doesn't exist yet (in an atomic way). We cannot assume\n // the keyring exists (e.g for the MMI Snap).\n // NOTE: We only auto-create it for v1 account creation flows.\n if (isAccountCreatedMessage) {\n await this.ensureReady(snapId);\n }\n\n // This part of the flow relies on v1 flows, but v2 keyrings are compatible with those messages\n // too.\n try {\n // NOTE: We use \"unsafe\" here since none of the messages should trigger mutations to the keyring state.\n // The exception might be `:accountCreated`, but even in that case, the mutation is handled differently\n // in the client by call `:persistAllKeyrings` explicitly.\n // Using `:withKeyringV2` would cause a deadlock when we're initiating operations like `removeAccount` from\n // the keyring itself:\n // 1: withKeyring(..., ({ keyring }) => { keyring.removeAccount(...) })\n // 2. removeAccount(...) -> handleKeyringSnapMessage(..., { method: 'accountRemoved', ... })\n // 3. handleKeyringSnapMessage tries to acquire the same lock again via withKeyringV2 -> deadlock.\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n if (!keyring.v1) {\n log(\n `Received message \"${event}\" for Snap \"${snapId}\", but that's a v2 keyring... Rejecting.`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring for Snap \"${snapId}\" is v2, not v1.`,\n );\n }\n\n return await keyring.v1.handleKeyringSnapMessage(message);\n });\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n log(\n `No Snap keyring found for Snap \"${snapId}\". Cannot handle message with method \"${event}\".`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring does not exist yet for Snap \"${snapId}\".`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Publishes an account data update event from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param event - Account data update event.\n * @param message - Message sent by the Snap.\n * @returns `null`.\n */\n #publishAccountDataUpdatedEvent(\n snapId: SnapId,\n event: AccountDataUpdatedKeyringEvent,\n message: SnapMessage,\n ): null {\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" as a SnapAccountService event...`,\n );\n\n if (event === KeyringEvent.AccountAssetListUpdated) {\n assertStruct(message, AccountAssetListUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountAssetListUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountBalancesUpdated) {\n assertStruct(message, AccountBalancesUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountBalancesUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountTransactionsUpdated) {\n assertStruct(message, AccountTransactionsUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountTransactionsUpdated',\n message.params,\n );\n }\n\n // We need to return a valid JSON value, so we cannot use `undefined` here.\n return null;\n }\n\n // eslint-disable-next-line jsdoc/require-returns\n /**\n * Forwards the accounts of the given account group to the Snap keyring.\n *\n * @param groupId - The ID of the account group whose accounts should be\n * forwarded. If empty, this is a no-op.\n * @param accounts - The accounts to forward. If not defined, this is a no-op.\n */\n async #forwardSelectedAccounts(\n groupId: AccountGroupId | '',\n accounts: AccountId[] | undefined,\n ): Promise<void> {\n const skipping = (reason: string): void =>\n log(`${reason}, skipping forwarding selected accounts to Snap keyring`);\n\n if (!this.#migrated) {\n return skipping('Not migrated yet');\n }\n\n if (!groupId) {\n return skipping('No selected account group');\n }\n\n if (!accounts) {\n return skipping(`Account group (\"${groupId}\") has no accounts`);\n }\n\n const forwardSelectedAccounts = async (): Promise<void> => {\n if (accounts.length) {\n log(\n `Forwarding selected accounts (from \"${groupId}\"): ${accounts.join(', ')}`,\n );\n } else {\n log(`Clearing selected accounts (from \"${groupId}\")`);\n }\n\n await Promise.all(\n this.#tracker.getSnaps().map(async (snapId) => {\n try {\n // We can safely invoke this method without taking the controller lock\n // because it should not mutate the keyring state. So we can use\n // `withKeyringV2Unsafe` in this case.\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n // The group's accounts may belong to several Snaps; only\n // forward the subset this Snap actually owns. An empty\n // subset still gets forwarded to explicitly clear the\n // Snap selected accounts.\n const snapAccounts = accounts.filter((id) =>\n keyring.hasAccount(id),\n );\n await this.#setSelectedAccountsForKeyring(\n snapId,\n keyring,\n snapAccounts,\n );\n });\n } catch (error) {\n // Tracked Snaps without a v2 keyring yet are expected —\n // forwarding will resume on the next event once `ensureReady`\n // has run.\n if (!isKeyringNotFoundError(error)) {\n console.error(\n `Error forwarding selected accounts to Snap \"${snapId}\":`,\n error,\n );\n }\n }\n }),\n );\n };\n\n // There is nothing we can do if forwarding fails. This will auto-recover on the next relevant event.\n return await forwardSelectedAccounts().catch((error) => {\n console.error('Error forwarding selected accounts:', error);\n });\n }\n\n /**\n * Gets the account group object for the given group ID.\n *\n * @param groupId - The ID of the account group.\n * @returns The account group object, or undefined if the group ID is empty or the group does not exist.\n */\n #getAccountGroup(\n groupId: AccountGroupId | '',\n ): AccountGroupObject | undefined {\n if (!groupId) {\n return undefined;\n }\n\n return this.#messenger.call(\n 'AccountTreeController:getAccountGroupObject',\n groupId,\n );\n }\n\n /**\n * Gets the currently selected account group ID.\n *\n * @returns The currently selected account group ID, or an empty string if\n * there is no selected account group.\n */\n #getSelectedAccountGroupId(): AccountGroupId | '' {\n return this.#messenger.call(\n 'AccountTreeController:getSelectedAccountGroup',\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SnapAccountService.mjs","sourceRoot":"","sources":["../src/SnapAccountService.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountGroupId } from '@metamask/account-api';\nimport {\n SnapKeyring as LegacySnapKeyring,\n SnapMessage,\n} from '@metamask/eth-snap-keyring';\nimport {\n SnapKeyring,\n SnapKeyringState,\n isSnapKeyring,\n} from '@metamask/eth-snap-keyring/v2';\nimport type {\n AccountAssetListUpdatedEventPayload,\n AccountBalancesUpdatedEventPayload,\n AccountTransactionsUpdatedEventPayload,\n Balance,\n CaipAssetType,\n CaipAssetTypeOrId,\n CaipChainId,\n Pagination,\n ResolvedAccountAddress,\n TransactionsPage,\n} from '@metamask/keyring-api';\nimport {\n AccountAssetListUpdatedEventStruct,\n AccountBalancesUpdatedEventStruct,\n AccountTransactionsUpdatedEventStruct,\n KeyringEvent,\n} from '@metamask/keyring-api';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { KeyringCapabilities } from '@metamask/keyring-api/v2';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerStateChangeEvent,\n KeyringControllerUnlockEvent,\n KeyringControllerWithControllerAction,\n KeyringControllerWithKeyringV2Action,\n KeyringControllerWithKeyringV2UnsafeAction,\n} from '@metamask/keyring-controller';\nimport {\n isKeyringNotFoundError,\n KeyringTypes,\n} from '@metamask/keyring-controller';\nimport { KeyringInternalSnapClient } from '@metamask/keyring-internal-snap-client/v2';\nimport { SnapManageAccountsMethod } from '@metamask/keyring-snap-sdk';\nimport type {\n AccountId,\n BaseKeyring,\n JsonRpcRequest,\n} from '@metamask/keyring-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerGetSnapAction,\n SnapControllerGetStateAction,\n SnapControllerHandleRequestAction,\n SnapControllerSnapBlockedEvent,\n SnapControllerSnapDisabledEvent,\n SnapControllerSnapEnabledEvent,\n SnapControllerSnapInstalledEvent,\n SnapControllerSnapUnblockedEvent,\n SnapControllerSnapUninstalledEvent,\n SnapControllerStateChangeEvent,\n} from '@metamask/snaps-controllers';\nimport { SnapId } from '@metamask/snaps-sdk';\nimport type { Json } from '@metamask/utils';\nimport { assertStruct } from '@metamask/utils';\n\nimport { projectLogger as log } from './logger.js';\nimport type {\n SnapAccountServiceEnsureReadyAction,\n SnapAccountServiceEnsureMigratedAction,\n SnapAccountServiceGetCapabilitiesAction,\n SnapAccountServiceGetAccountAssetsAction,\n SnapAccountServiceGetAccountBalancesAction,\n SnapAccountServiceGetAccountTransactionsAction,\n SnapAccountServiceGetSnapsAction,\n SnapAccountServiceHandleKeyringSnapMessageAction,\n SnapAccountServiceResolveAccountAddressAction,\n SnapAccountServiceSetSelectedAccountsAction,\n} from './SnapAccountService-method-action-types.js';\nimport { SnapPlatformWatcher } from './SnapPlatformWatcher.js';\nimport type { SnapPlatformWatcherConfig } from './SnapPlatformWatcher.js';\nimport { SnapTracker } from './SnapTracker.js';\nimport type {\n AccountTreeControllerGetAccountGroupObjectAction,\n AccountTreeControllerGetSelectedAccountGroupAction,\n AccountTreeControllerSelectedAccountGroupChangeEvent,\n AccountTreeControllerAccountGroupCreatedEvent,\n AccountTreeControllerAccountGroupUpdatedEvent,\n AccountTreeControllerAccountGroupRemovedEvent,\n AccountGroupObject,\n} from './types.js';\n\n/**\n * The name of the {@link SnapAccountService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'SnapAccountService';\n\n/**\n * All of the methods within {@link SnapAccountService} that are exposed via\n * the messenger.\n */\nconst MESSENGER_EXPOSED_METHODS = [\n 'ensureMigrated',\n 'ensureReady',\n 'getCapabilities',\n 'getAccountAssets',\n 'getAccountBalances',\n 'getAccountTransactions',\n 'getSnaps',\n 'handleKeyringSnapMessage',\n 'resolveAccountAddress',\n 'setSelectedAccounts',\n] as const;\n\n/**\n * Actions that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceActions =\n | SnapAccountServiceEnsureMigratedAction\n | SnapAccountServiceEnsureReadyAction\n | SnapAccountServiceGetCapabilitiesAction\n | SnapAccountServiceGetAccountAssetsAction\n | SnapAccountServiceGetAccountBalancesAction\n | SnapAccountServiceGetAccountTransactionsAction\n | SnapAccountServiceGetSnapsAction\n | SnapAccountServiceHandleKeyringSnapMessageAction\n | SnapAccountServiceResolveAccountAddressAction\n | SnapAccountServiceSetSelectedAccountsAction;\n\n/**\n * Actions from other messengers that {@link SnapAccountService} calls.\n */\ntype AllowedActions =\n | SnapControllerGetStateAction\n | SnapControllerGetSnapAction\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | KeyringControllerGetStateAction\n | KeyringControllerWithControllerAction\n | KeyringControllerWithKeyringV2Action\n | KeyringControllerWithKeyringV2UnsafeAction\n | AccountTreeControllerGetAccountGroupObjectAction\n | AccountTreeControllerGetSelectedAccountGroupAction;\n\n/**\n * Events that {@link SnapAccountService} exposes to other consumers.\n */\nexport type SnapAccountServiceAccountBalancesUpdatedEvent = {\n type: `${typeof serviceName}:accountBalancesUpdated`;\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountAssetListUpdatedEvent = {\n type: `${typeof serviceName}:accountAssetListUpdated`;\n payload: [AccountAssetListUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceAccountTransactionsUpdatedEvent = {\n type: `${typeof serviceName}:accountTransactionsUpdated`;\n payload: [AccountTransactionsUpdatedEventPayload];\n};\n\nexport type SnapAccountServiceEvents =\n | SnapAccountServiceAccountAssetListUpdatedEvent\n | SnapAccountServiceAccountBalancesUpdatedEvent\n | SnapAccountServiceAccountTransactionsUpdatedEvent;\n\n/**\n * Events from other messengers that {@link SnapAccountService} subscribes to.\n */\ntype AllowedEvents =\n | SnapControllerStateChangeEvent\n | SnapControllerSnapInstalledEvent\n | SnapControllerSnapEnabledEvent\n | SnapControllerSnapDisabledEvent\n | SnapControllerSnapBlockedEvent\n | SnapControllerSnapUnblockedEvent\n | SnapControllerSnapUninstalledEvent\n | KeyringControllerStateChangeEvent\n | KeyringControllerUnlockEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent\n | AccountTreeControllerAccountGroupCreatedEvent\n | AccountTreeControllerAccountGroupUpdatedEvent\n | AccountTreeControllerAccountGroupRemovedEvent;\n\n/**\n * The messenger which is restricted to actions and events accessed by\n * {@link SnapAccountService}.\n */\nexport type SnapAccountServiceMessenger = Messenger<\n typeof serviceName,\n SnapAccountServiceActions | AllowedActions,\n SnapAccountServiceEvents | AllowedEvents\n>;\n\n/**\n * Configuration for the {@link SnapAccountService}.\n */\nexport type SnapAccountServiceConfig = {\n snapPlatformWatcher?: SnapPlatformWatcherConfig;\n};\n\n/**\n * The options that {@link SnapAccountService} takes.\n */\nexport type SnapAccountServiceOptions = {\n messenger: SnapAccountServiceMessenger;\n config?: SnapAccountServiceConfig;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @param keyring.type - The type of the keyring.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nfunction isLegacySnapKeyring(keyring: {\n type: BaseKeyring['type'];\n}): keyring is LegacySnapKeyring {\n return keyring.type === KeyringTypes.snap;\n}\n\n/**\n * Account data update events that can be forwarded from Snaps.\n *\n * These events are then re-emitted by the service for other consumers.\n */\ntype AccountDataUpdatedKeyringEvent =\n | KeyringEvent.AccountAssetListUpdated\n | KeyringEvent.AccountBalancesUpdated\n | KeyringEvent.AccountTransactionsUpdated;\n\n/**\n * Checks if a Snap message method is an account data update event.\n *\n * @param event - The Snap message event.\n * @returns `true` if the method can be forwarded without the legacy Snap keyring.\n */\nfunction isAccountDataUpdatedKeyringEvent(\n event: string,\n): event is AccountDataUpdatedKeyringEvent {\n return (\n event === KeyringEvent.AccountAssetListUpdated ||\n event === KeyringEvent.AccountBalancesUpdated ||\n event === KeyringEvent.AccountTransactionsUpdated\n );\n}\n\n/**\n * Service responsible for managing account management snaps.\n */\nexport class SnapAccountService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: SnapAccountServiceMessenger;\n\n readonly #watcher: SnapPlatformWatcher;\n\n readonly #tracker: SnapTracker;\n\n readonly #client: KeyringInternalSnapClient;\n\n #migrated = false;\n\n #migratePromise: Promise<void> | null = null;\n\n /**\n * Constructs a new {@link SnapAccountService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.config - Optional service configuration.\n */\n constructor({ messenger, config }: SnapAccountServiceOptions) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#watcher = new SnapPlatformWatcher(\n messenger,\n config?.snapPlatformWatcher,\n );\n this.#tracker = new SnapTracker(messenger);\n this.#client = new KeyringInternalSnapClient({\n messenger: messenger.buildChild({\n namespace: 'KeyringInternalSnapClient',\n actions: ['SnapController:handleRequest'],\n }),\n });\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:selectedAccountGroupChange',\n (groupId) => this.#handleSelectedAccountGroupChange(groupId),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupCreated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupUpdated',\n (group) => this.#handleAccountGroupCreatedOrUpdated(group),\n );\n\n this.#messenger.subscribe(\n 'AccountTreeController:accountGroupRemoved',\n (groupId) => this.#handleAccountGroupRemoved(groupId),\n );\n\n this.#messenger.subscribe('KeyringController:unlock', () =>\n this.#handleUnlock(),\n );\n }\n\n /**\n * Handles changes to the selected account group by forwarding the new\n * group's accounts to the Snap keyring.\n *\n * @param groupId - The ID of the newly selected account group.\n */\n #handleSelectedAccountGroupChange(groupId: AccountGroupId | ''): void {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n }\n\n /**\n * Handles the keyring controller unlock event by triggering the migration\n * and forwarding the currently selected account group's accounts to the Snap\n * keyring.\n */\n #handleUnlock(): void {\n // eslint-disable-next-line no-void\n void this.ensureMigrated()\n .then(async () => {\n // If the migration is successful, we re-forward the current groups to each new keyrings!\n const groupId = this.#getSelectedAccountGroupId();\n return await this.#forwardSelectedAccounts(\n groupId,\n this.#getAccountGroup(groupId)?.accounts,\n );\n })\n .catch((error) => {\n console.error('Migration failed after unlock:', error);\n });\n }\n\n /**\n * Handles created or updated account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the created/updated group is currently selected.\n *\n * @param group - The account group being created or updated.\n */\n #handleAccountGroupCreatedOrUpdated(group: AccountGroupObject): void {\n if (group.id === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(group.id, group.accounts);\n }\n }\n\n /**\n * Handles removed account groups by forwarding the accounts of the currently\n * selected account group to the Snap keyring, if the removed group is currently selected.\n *\n * @param groupId - The ID of the account group being removed.\n */\n #handleAccountGroupRemoved(groupId: AccountGroupId): void {\n if (groupId === this.#getSelectedAccountGroupId()) {\n // eslint-disable-next-line no-void\n void this.#forwardSelectedAccounts(\n groupId,\n [], // Clearing accounts since the group is removed\n );\n }\n }\n\n /**\n * Returns the IDs of all currently tracked account-management Snaps —\n * Snaps that are installed, enabled, not blocked, and have the\n * `endowment:keyring` permission.\n *\n * @returns The IDs of tracked account-management Snaps.\n */\n getSnaps(): SnapId[] {\n return this.#tracker.getSnaps();\n }\n\n /**\n * Ensures everything is ready to use Snap accounts for the given Snap.\n * 1. Validates that `snapId` is a tracked account-management Snap.\n * 2. Asserts that the legacy -> v2 migration has been triggered (expected to\n * happen at `KeyringController:unlock` time).\n * 3. Atomically creates the v2 keyring for this Snap if it doesn't exist\n * yet.\n * 4. Waits for the Snap platform to be fully started.\n *\n * Safe to call concurrently — each step is idempotent or mutex-protected.\n *\n * @param snapId - ID of the Snap to ensure readiness for.\n * @throws If `snapId` is not a tracked account-management Snap.\n * @throws If the migration has not been triggered yet (wallet not unlocked).\n */\n async ensureReady(snapId: SnapId): Promise<void> {\n if (!this.#tracker.canUse(snapId)) {\n throw new Error(`Unknown snap: \"${snapId}\"`);\n }\n\n // The migration is required to ensure the v2 keyring exists.\n await this.ensureMigrated();\n\n // We still try to create the keyring for the Snap here, since we might\n // want to use a new Snap that never had accounts before.\n await this.#ensureKeyringIsReady(snapId);\n\n // Before doing anything with our Snap, we need to make sure the platform\n // is ready to process requests.\n await this.#watcher.ensureCanUseSnapPlatform();\n }\n\n /**\n * Migrate the legacy Snap keyring to the new (per-snap) Snap keyring v2.\n * Expected to be triggered at `KeyringController:unlock` time.\n * Safe to call concurrently — the migration runs only once; all callers\n * await the same promise.\n *\n * @returns A promise that resolves when the migration is complete.\n */\n async ensureMigrated(): Promise<void> {\n if (this.#migrated) {\n return;\n }\n\n if (!this.#migratePromise) {\n this.#migratePromise = this.#migrate()\n .then(() => {\n this.#migrated = true;\n return undefined;\n })\n .catch((error) => {\n // Clear the promise so the next call can retry.\n this.#migratePromise = null;\n throw error;\n });\n }\n\n await this.#migratePromise;\n }\n\n /**\n * Performs the actual migration logic. Should only be called once, and is not\n * safe to call concurrently.\n */\n async #migrate(): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const { keyrings } = controller;\n\n const legacySnapKeyringEntry = keyrings.find(({ keyring }) =>\n isLegacySnapKeyring(keyring),\n );\n if (!legacySnapKeyringEntry) {\n log('No legacy Snap keyring found. Migration not required.');\n return;\n }\n\n log('Migration started...');\n\n // The legacy Snap keyring has never been a true `EthKeyring` so we\n // need to cast it to `unknown` first.\n const legacySnapKeyring =\n legacySnapKeyringEntry.keyring as unknown as LegacySnapKeyring;\n\n // Compute the account list for each Snap, grouped by snap ID.\n const states = new Map<SnapId, SnapKeyringState>();\n for (const internalAccount of legacySnapKeyring.listAccounts()) {\n // Convert `InternalAccount` to `KeyringAccount` since the Snap\n // keyring (v2) expects accounts in that format and will verify it\n // with `superstruct` when adding the keyring.\n const { metadata, ...account } = internalAccount;\n\n const snap = metadata?.snap;\n if (snap) {\n const snapId = snap.id as SnapId;\n\n let state = states.get(snapId);\n if (!state) {\n state = { snapId, accounts: {} };\n states.set(snapId, state);\n }\n state.accounts[account.id] = account;\n }\n }\n\n // Create the new Snap keyring (v2) for each Snap and migrate the\n // accounts over.\n for (const state of states.values()) {\n log(`Migrating accounts for Snap \"${state.snapId}\"...`);\n await controller.addNewKeyring(\n // IMPORTANT: The Snap keyring (v2) can also be used as a v1\n // keyring. So the builder associated with the v2 keyring type is\n // able to build both v1 and v2 keyrings.\n KeyringType.Snap,\n state,\n );\n }\n\n // Remove the legacy Snap keyring after migration.\n log('Removing legacy Snap keyring...');\n await controller.removeKeyring(legacySnapKeyringEntry.metadata.id);\n\n log('Migration completed!');\n },\n );\n }\n\n /**\n * Ensures a Snap keyring is ready for the given Snap. If it doesn't exist yet, it will be created.\n * Safe to call concurrently.\n *\n * @param snapId - The Snap ID to ensure the keyring is ready for.\n */\n async #ensureKeyringIsReady(snapId: SnapId): Promise<void> {\n await this.#messenger.call(\n 'KeyringController:withController',\n async (controller) => {\n const hasKeyring = controller.keyrings.some(\n ({ keyringV2 }) =>\n keyringV2 &&\n isSnapKeyring(keyringV2) &&\n keyringV2.snapId === snapId,\n );\n\n if (!hasKeyring) {\n log(`Creating v2 keyring for Snap \"${snapId}\"...`);\n await controller.addNewKeyring(KeyringType.Snap, {\n snapId,\n accounts: {},\n });\n }\n },\n );\n }\n\n /**\n * Shared body for {@link SnapAccountService.#withKeyringV2} and\n * {@link SnapAccountService.#withKeyringV2Unsafe}. Hides the per-Snap\n * filter and the cast back to {@link SnapKeyring} (the messenger action's\n * callback receives a generic `Keyring`; the selector's type predicate\n * doesn't flow through the messenger's generics).\n *\n * @param action - The messenger action to invoke.\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Call<Result>(\n action:\n | 'KeyringController:withKeyringV2'\n | 'KeyringController:withKeyringV2Unsafe',\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#messenger.call(\n action,\n {\n filter: (keyring): keyring is SnapKeyring =>\n isSnapKeyring(keyring) && keyring.snapId === snapId,\n },\n async ({ keyring }) => operation(keyring as SnapKeyring),\n ) as Result;\n }\n\n /**\n * Lock-free variant of {@link SnapAccountService.#withKeyringV2}. Only use\n * for operations that do not mutate keyring or controller state — see\n * `KeyringController.withKeyringV2Unsafe` for the contract.\n *\n * @param snapId - The Snap ID to look up the keyring for.\n * @param operation - The operation to run with the matching keyring.\n * @returns The result of the operation.\n */\n async #withKeyringV2Unsafe<Result>(\n snapId: SnapId,\n operation: (keyring: SnapKeyring) => Promise<Result>,\n ): Promise<Result> {\n return this.#withKeyringV2Call(\n 'KeyringController:withKeyringV2Unsafe',\n snapId,\n operation,\n );\n }\n\n /**\n * Returns the keyring capabilities declared by the given Snap. These are\n * populated by the bridge keyring from the Snap's manifest, and describe\n * which keyring features the Snap supports (scopes, BIP-44 options, etc.).\n *\n * Consumers use this to decide whether to drive the Snap through the v1 or\n * v2 keyring path. Reading capabilities does not mutate state, so the\n * lock-free keyring access is used.\n *\n * @param snapId - ID of the Snap.\n * @returns The Snap's keyring capabilities.\n */\n async getCapabilities(snapId: SnapId): Promise<KeyringCapabilities> {\n return this.#withKeyringV2Unsafe(\n snapId,\n async (keyring) => keyring.capabilities,\n );\n }\n\n /**\n * Returns the CAIP-19 asset type/ID list supported by an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @returns A promise resolving to the list of supported CAIP-19 asset type/IDs.\n */\n async getAccountAssets(\n snapId: SnapId,\n id: AccountId,\n ): Promise<CaipAssetTypeOrId[]> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountAssets(id);\n }\n\n /**\n * Returns the balances for an account for the requested asset types.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param assets - List of CAIP-19 fungible asset types to fetch balances for.\n * @returns A promise resolving to a map of asset type to balance.\n */\n async getAccountBalances(\n snapId: SnapId,\n id: AccountId,\n assets: CaipAssetType[],\n ): Promise<Record<CaipAssetType, Balance>> {\n await this.ensureReady(snapId);\n return this.#client.withSnapId(snapId).getAccountBalances(id, assets);\n }\n\n /**\n * Returns a page of transactions for an account.\n *\n * @param snapId - ID of the Snap.\n * @param id - ID of the account.\n * @param pagination - Pagination options.\n * @returns A promise resolving to a page of transactions.\n */\n async getAccountTransactions(\n snapId: SnapId,\n id: AccountId,\n pagination: Pagination,\n ): Promise<TransactionsPage> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .getAccountTransactions(id, pagination);\n }\n\n /**\n * Resolves the account address to use for routing a signing request.\n *\n * @param snapId - ID of the Snap.\n * @param scope - CAIP-2 chain ID of the signing request.\n * @param request - The signing JSON-RPC request.\n * @returns A promise resolving to the resolved address, or `null` if the\n * Snap cannot determine an address for this request.\n */\n async resolveAccountAddress(\n snapId: SnapId,\n scope: CaipChainId,\n request: JsonRpcRequest,\n ): Promise<ResolvedAccountAddress | null> {\n await this.ensureReady(snapId);\n return this.#client\n .withSnapId(snapId)\n .resolveAccountAddress(scope, request);\n }\n\n /**\n * Notifies a Snap of the currently selected accounts.\n *\n * For v1 Snaps the call goes through the keyring (signing interface); for\n * v2 Snaps it is routed via the RPC client because the keyring only covers\n * keyring-only operations (signing, account lifecycle).\n *\n * @param snapId - ID of the Snap.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async setSelectedAccounts(\n snapId: SnapId,\n accounts: AccountId[],\n ): Promise<void> {\n await this.ensureReady(snapId);\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n await this.#setSelectedAccountsForKeyring(snapId, keyring, accounts);\n });\n }\n\n /**\n * Dispatches a `setSelectedAccounts` call to the correct layer based on\n * whether the keyring has a v1 interface or not.\n *\n * The keyring is a pure interface for keyring-only operations (signing,\n * account lifecycle). Extra Snap-level methods like `setSelectedAccounts`\n * are invoked via the client for v2 Snaps, which communicates with the Snap\n * over RPC.\n *\n * @param snapId - ID of the Snap.\n * @param keyring - The Snap keyring (v2) instance.\n * @param accounts - IDs of the accounts to mark as selected.\n */\n async #setSelectedAccountsForKeyring(\n snapId: SnapId,\n keyring: SnapKeyring,\n accounts: AccountId[],\n ): Promise<void> {\n if (keyring.v1) {\n // We used to keep track of selected accounts in the v1 keyring, so we need to forward the call there for v1 Snaps.\n await keyring.v1.setSelectedAccounts(accounts);\n } else {\n await this.#client.withSnapId(snapId).setSelectedAccounts(accounts);\n }\n }\n\n /**\n * Handle a message from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param message - Message sent by the Snap.\n * @returns The execution result.\n */\n async handleKeyringSnapMessage(\n snapId: SnapId,\n message: SnapMessage,\n ): Promise<Json> {\n const { method: event } = message;\n if (isAccountDataUpdatedKeyringEvent(event)) {\n return this.#publishAccountDataUpdatedEvent(snapId, event, message);\n }\n\n // Handle specific methods.\n if (message.method === SnapManageAccountsMethod.GetSelectedAccounts) {\n const groupId = this.#getSelectedAccountGroupId();\n const accounts = this.#getAccountGroup(groupId)?.accounts ?? [];\n\n try {\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) =>\n accounts.filter((id) => keyring.hasAccount(id)),\n );\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n // Some Snaps might be using `getSelectedAccounts` early in their lifecycle, before the keyring is created. So we\n // do not throw in that case to avoid disrupting their initialization process.\n return [];\n }\n\n throw error;\n }\n }\n\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" to its keyring...`,\n );\n\n // We can create a new keyring if the message is an AccountCreated event.\n const isAccountCreatedMessage = event === KeyringEvent.AccountCreated;\n\n // Create the Snap keyring if it doesn't exist yet (in an atomic way). We cannot assume\n // the keyring exists (e.g for the MMI Snap).\n // NOTE: We only auto-create it for v1 account creation flows.\n if (isAccountCreatedMessage) {\n await this.ensureReady(snapId);\n }\n\n // This part of the flow relies on v1 flows, but v2 keyrings are compatible with those messages\n // too.\n try {\n // NOTE: We use \"unsafe\" here since none of the messages should trigger mutations to the keyring state.\n // The exception might be `:accountCreated`, but even in that case, the mutation is handled differently\n // in the client by call `:persistAllKeyrings` explicitly.\n // Using `:withKeyringV2` would cause a deadlock when we're initiating operations like `removeAccount` from\n // the keyring itself:\n // 1: withKeyring(..., ({ keyring }) => { keyring.removeAccount(...) })\n // 2. removeAccount(...) -> handleKeyringSnapMessage(..., { method: 'accountRemoved', ... })\n // 3. handleKeyringSnapMessage tries to acquire the same lock again via withKeyringV2 -> deadlock.\n return await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n if (!keyring.v1) {\n log(\n `Received message \"${event}\" for Snap \"${snapId}\", but that's a v2 keyring... Rejecting.`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring for Snap \"${snapId}\" is v2, not v1.`,\n );\n }\n\n return await keyring.v1.handleKeyringSnapMessage(message);\n });\n } catch (error) {\n if (isKeyringNotFoundError(error)) {\n log(\n `No Snap keyring found for Snap \"${snapId}\". Cannot handle message with method \"${event}\".`,\n );\n\n throw new Error(\n `Cannot delegate keyring Snap message, keyring does not exist yet for Snap \"${snapId}\".`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Publishes an account data update event from a Snap.\n *\n * @param snapId - ID of the Snap.\n * @param event - Account data update event.\n * @param message - Message sent by the Snap.\n * @returns `null`.\n */\n #publishAccountDataUpdatedEvent(\n snapId: SnapId,\n event: AccountDataUpdatedKeyringEvent,\n message: SnapMessage,\n ): null {\n log(\n `Forwarding message \"${event}\" from Snap \"${snapId}\" as a SnapAccountService event...`,\n );\n\n if (event === KeyringEvent.AccountAssetListUpdated) {\n assertStruct(message, AccountAssetListUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountAssetListUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountBalancesUpdated) {\n assertStruct(message, AccountBalancesUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountBalancesUpdated',\n message.params,\n );\n } else if (event === KeyringEvent.AccountTransactionsUpdated) {\n assertStruct(message, AccountTransactionsUpdatedEventStruct);\n this.#messenger.publish(\n 'SnapAccountService:accountTransactionsUpdated',\n message.params,\n );\n }\n\n // We need to return a valid JSON value, so we cannot use `undefined` here.\n return null;\n }\n\n // eslint-disable-next-line jsdoc/require-returns\n /**\n * Forwards the accounts of the given account group to the Snap keyring.\n *\n * @param groupId - The ID of the account group whose accounts should be\n * forwarded. If empty, this is a no-op.\n * @param accounts - The accounts to forward. If not defined, this is a no-op.\n */\n async #forwardSelectedAccounts(\n groupId: AccountGroupId | '',\n accounts: AccountId[] | undefined,\n ): Promise<void> {\n const skipping = (reason: string): void =>\n log(`${reason}, skipping forwarding selected accounts to Snap keyring`);\n\n if (!this.#migrated) {\n return skipping('Not migrated yet');\n }\n\n if (!groupId) {\n return skipping('No selected account group');\n }\n\n if (!accounts) {\n return skipping(`Account group (\"${groupId}\") has no accounts`);\n }\n\n const forwardSelectedAccounts = async (): Promise<void> => {\n if (accounts.length) {\n log(\n `Forwarding selected accounts (from \"${groupId}\"): ${accounts.join(', ')}`,\n );\n } else {\n log(`Clearing selected accounts (from \"${groupId}\")`);\n }\n\n await Promise.all(\n this.#tracker.getSnaps().map(async (snapId) => {\n try {\n // We can safely invoke this method without taking the controller lock\n // because it should not mutate the keyring state. So we can use\n // `withKeyringV2Unsafe` in this case.\n await this.#withKeyringV2Unsafe(snapId, async (keyring) => {\n // The group's accounts may belong to several Snaps; only\n // forward the subset this Snap actually owns. An empty\n // subset still gets forwarded to explicitly clear the\n // Snap selected accounts.\n const snapAccounts = accounts.filter((id) =>\n keyring.hasAccount(id),\n );\n await this.#setSelectedAccountsForKeyring(\n snapId,\n keyring,\n snapAccounts,\n );\n });\n } catch (error) {\n // Tracked Snaps without a v2 keyring yet are expected —\n // forwarding will resume on the next event once `ensureReady`\n // has run.\n if (!isKeyringNotFoundError(error)) {\n console.error(\n `Error forwarding selected accounts to Snap \"${snapId}\":`,\n error,\n );\n }\n }\n }),\n );\n };\n\n // There is nothing we can do if forwarding fails. This will auto-recover on the next relevant event.\n return await forwardSelectedAccounts().catch((error) => {\n console.error('Error forwarding selected accounts:', error);\n });\n }\n\n /**\n * Gets the account group object for the given group ID.\n *\n * @param groupId - The ID of the account group.\n * @returns The account group object, or undefined if the group ID is empty or the group does not exist.\n */\n #getAccountGroup(\n groupId: AccountGroupId | '',\n ): AccountGroupObject | undefined {\n if (!groupId) {\n return undefined;\n }\n\n return this.#messenger.call(\n 'AccountTreeController:getAccountGroupObject',\n groupId,\n );\n }\n\n /**\n * Gets the currently selected account group ID.\n *\n * @returns The currently selected account group ID, or an empty string if\n * there is no selected account group.\n */\n #getSelectedAccountGroupId(): AccountGroupId | '' {\n return this.#messenger.call(\n 'AccountTreeController:getSelectedAccountGroup',\n );\n }\n}\n"]}
|
package/package.json
CHANGED
package/dist/errors.cjs
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.reportError = exports.createSentryError = exports.withSafeError = exports.isSafeError = exports.SafeError = void 0;
|
|
4
|
-
const keyring_controller_1 = require("@metamask/keyring-controller");
|
|
5
|
-
/**
|
|
6
|
-
* Thrown by {@link withSafeError} when the wrapped callback fails with an error
|
|
7
|
-
* whose message is not safe to forward to Sentry (e.g., a superstruct
|
|
8
|
-
* `StructError` that may embed account addresses, or an unknown third-party
|
|
9
|
-
* error). The message on a `SafeError` is always authored by us and contains
|
|
10
|
-
* no user data.
|
|
11
|
-
*
|
|
12
|
-
* `SafeError` instances pass through nested {@link withSafeError} calls unchanged;
|
|
13
|
-
* the innermost step description is preserved rather than re-wrapped.
|
|
14
|
-
*/
|
|
15
|
-
class SafeError extends Error {
|
|
16
|
-
constructor(message) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.name = 'SafeError';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
exports.SafeError = SafeError;
|
|
22
|
-
/**
|
|
23
|
-
* Returns `true` if the error is a `SafeError`.
|
|
24
|
-
*
|
|
25
|
-
* Uses duck-typing on `error.name` rather than `instanceof` so that the check
|
|
26
|
-
* remains correct when multiple versions of this package coexist in the
|
|
27
|
-
* dependency tree (different versions produce different classes, so
|
|
28
|
-
* `instanceof` would return `false` for errors from another version).
|
|
29
|
-
*
|
|
30
|
-
* @param error - The value to check.
|
|
31
|
-
* @returns Whether the error is a `SafeError`.
|
|
32
|
-
*/
|
|
33
|
-
function isSafeError(error) {
|
|
34
|
-
return (typeof error === 'object' &&
|
|
35
|
-
error !== null &&
|
|
36
|
-
error.name === 'SafeError');
|
|
37
|
-
}
|
|
38
|
-
exports.isSafeError = isSafeError;
|
|
39
|
-
/**
|
|
40
|
-
* Returns `true` if the error is a `StructError`-like object.
|
|
41
|
-
*
|
|
42
|
-
* @param error - The value to check.
|
|
43
|
-
* @returns Whether the error is a `StructError`-like object.
|
|
44
|
-
*/
|
|
45
|
-
function isStructError(error) {
|
|
46
|
-
const isError = error instanceof Error && error.name === 'StructError';
|
|
47
|
-
if (!isError) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
const structError = error;
|
|
51
|
-
return (Array.isArray(structError.path) && typeof structError.type === 'string');
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Produces a safe, human-readable summary of a superstruct validation failure.
|
|
55
|
-
* Reports only the field path and expected type, never the actual failing
|
|
56
|
-
* value, which may contain account addresses or other user data.
|
|
57
|
-
*
|
|
58
|
-
* @param error - The StructError-like object.
|
|
59
|
-
* @returns A safe description string.
|
|
60
|
-
*/
|
|
61
|
-
function describeStructFailure(error) {
|
|
62
|
-
const path = error.path.length > 0 ? `"${error.path.map(String).join('.')}"` : '<root>';
|
|
63
|
-
return `Validation failed at ${path} (expected: ${error.refinement ?? error.type})`;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Executes `fn` and, if it throws, sanitizes the error before re-throwing to
|
|
67
|
-
* guarantee the caller always gets an error whose message is safe to forward
|
|
68
|
-
* to Sentry.
|
|
69
|
-
*
|
|
70
|
-
* Sanitization rules applied to whatever `fn` throws:
|
|
71
|
-
* - {@link SafeError}: re-thrown as-is (innermost step description preserved,
|
|
72
|
-
* no re-wrapping on nested {@link withSafeError} calls).
|
|
73
|
-
* - {@link KeyringControllerError}: re-thrown as-is (uses static, enum-based
|
|
74
|
-
* messages; no user data).
|
|
75
|
-
* - `StructError` (from `@metamask/superstruct`): wrapped in a
|
|
76
|
-
* {@link SafeError} containing only the failing field path and expected type,
|
|
77
|
-
* never the actual value.
|
|
78
|
-
* - Anything else: wrapped in a {@link SafeError} with a generic fallback
|
|
79
|
-
* message; the original error is discarded to prevent accidental leakage.
|
|
80
|
-
*
|
|
81
|
-
* @param step - Human-readable label for this execution step, prepended to the
|
|
82
|
-
* `SafeError` message when the error is not already safe.
|
|
83
|
-
* @param fn - The async callback to execute.
|
|
84
|
-
* @returns The result of `fn`.
|
|
85
|
-
*/
|
|
86
|
-
async function withSafeError(step, fn) {
|
|
87
|
-
try {
|
|
88
|
-
return await fn();
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
if (isSafeError(error) || (0, keyring_controller_1.isKeyringControllerError)(error)) {
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
if (isStructError(error)) {
|
|
95
|
-
throw new SafeError(`${step}: ${describeStructFailure(error)}`);
|
|
96
|
-
}
|
|
97
|
-
throw new SafeError(`${step}: An unexpected error occurred`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
exports.withSafeError = withSafeError;
|
|
101
|
-
/**
|
|
102
|
-
* Creates a Sentry error from an error message, an inner error and a context.
|
|
103
|
-
*
|
|
104
|
-
* NOTE: Sentry defaults to a depth of 3 when extracting non-native attributes.
|
|
105
|
-
* As such, the context depth shouldn't be too deep.
|
|
106
|
-
*
|
|
107
|
-
* @param message - The error message to create a Sentry error from.
|
|
108
|
-
* @param innerError - The inner error to create a Sentry error from.
|
|
109
|
-
* @param context - The context to add to the Sentry error.
|
|
110
|
-
* @returns A Sentry error.
|
|
111
|
-
*/
|
|
112
|
-
const createSentryError = (message, innerError, context) => {
|
|
113
|
-
const error = new Error(message);
|
|
114
|
-
error.cause = innerError;
|
|
115
|
-
if (context) {
|
|
116
|
-
error.context = context;
|
|
117
|
-
}
|
|
118
|
-
return error;
|
|
119
|
-
};
|
|
120
|
-
exports.createSentryError = createSentryError;
|
|
121
|
-
/**
|
|
122
|
-
* Reports an error by logging it to the console and optionally capturing it
|
|
123
|
-
* in Sentry via the messenger's `captureException` method.
|
|
124
|
-
*
|
|
125
|
-
* @param messenger - Object with an optional `captureException` method.
|
|
126
|
-
* @param messenger.captureException - Optional method to capture exceptions in Sentry.
|
|
127
|
-
* @param message - The static message describing what failed.
|
|
128
|
-
* @param error - The caught error.
|
|
129
|
-
* @param context - Optional context to attach to the Sentry error.
|
|
130
|
-
*/
|
|
131
|
-
function reportError(messenger, message, error, context) {
|
|
132
|
-
console.error(message, error);
|
|
133
|
-
const sentryError = (0, exports.createSentryError)(message, error, context);
|
|
134
|
-
messenger.captureException?.(sentryError);
|
|
135
|
-
}
|
|
136
|
-
exports.reportError = reportError;
|
|
137
|
-
//# sourceMappingURL=errors.cjs.map
|
package/dist/errors.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.cjs","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,qEAAwE;AAExE;;;;;;;;;GASG;AACH,MAAa,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AALD,8BAKC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAA4B,CAAC,IAAI,KAAK,WAAW,CACnD,CAAC;AACJ,CAAC;AAND,kCAMC;AAiBD;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAc;IACnC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC;IACvE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,KAGnB,CAAC;IACF,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,QAAQ,CACxE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,KAAsB;IACnD,MAAM,IAAI,GACR,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC7E,OAAO,wBAAwB,IAAI,eAAe,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;AACtF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACI,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,EAA6B;IAE7B,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,IAAA,6CAAwB,EAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,KAAK,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,gCAAgC,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAfD,sCAeC;AAkBD;;;;;;;;;;GAUG;AACI,MAAM,iBAAiB,GAAG,CAG/B,OAAe,EACf,UAAiB,EACjB,OAAkB,EACK,EAAE;IACzB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAA0B,CAAC;IAC1D,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC;IACzB,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAbW,QAAA,iBAAiB,qBAa5B;AAEF;;;;;;;;;GASG;AACH,SAAgB,WAAW,CACzB,SAAwD,EACxD,OAAe,EACf,KAAc,EACd,OAAiC;IAEjC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAE9B,MAAM,WAAW,GAAG,IAAA,yBAAiB,EAAC,OAAO,EAAE,KAAc,EAAE,OAAO,CAAC,CAAC;IACxE,SAAS,CAAC,gBAAgB,EAAE,CAAC,WAAW,CAAC,CAAC;AAC5C,CAAC;AAVD,kCAUC","sourcesContent":["import { isKeyringControllerError } from '@metamask/keyring-controller';\n\n/**\n * Thrown by {@link withSafeError} when the wrapped callback fails with an error\n * whose message is not safe to forward to Sentry (e.g., a superstruct\n * `StructError` that may embed account addresses, or an unknown third-party\n * error). The message on a `SafeError` is always authored by us and contains\n * no user data.\n *\n * `SafeError` instances pass through nested {@link withSafeError} calls unchanged;\n * the innermost step description is preserved rather than re-wrapped.\n */\nexport class SafeError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SafeError';\n }\n}\n\n/**\n * Returns `true` if the error is a `SafeError`.\n *\n * Uses duck-typing on `error.name` rather than `instanceof` so that the check\n * remains correct when multiple versions of this package coexist in the\n * dependency tree (different versions produce different classes, so\n * `instanceof` would return `false` for errors from another version).\n *\n * @param error - The value to check.\n * @returns Whether the error is a `SafeError`.\n */\nexport function isSafeError(error: unknown): error is SafeError {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as { name?: unknown }).name === 'SafeError'\n );\n}\n\n/**\n * Duck-typed shape of `@metamask/superstruct`'s `StructError`.\n *\n * We avoid a direct `instanceof` check because `@metamask/superstruct` is not\n * a declared dependency of this package; it reaches us transitively. Checking\n * `name` plus the presence of `path` and `type` is sufficient to identify it\n * without coupling to the transitive dep.\n */\ntype StructErrorLike = Error & {\n name: 'StructError';\n path: unknown[];\n type: string;\n refinement?: string;\n};\n\n/**\n * Returns `true` if the error is a `StructError`-like object.\n *\n * @param error - The value to check.\n * @returns Whether the error is a `StructError`-like object.\n */\nfunction isStructError(error: unknown): error is StructErrorLike {\n const isError = error instanceof Error && error.name === 'StructError';\n if (!isError) {\n return false;\n }\n\n const structError = error as {\n path?: string[];\n type?: string;\n };\n return (\n Array.isArray(structError.path) && typeof structError.type === 'string'\n );\n}\n\n/**\n * Produces a safe, human-readable summary of a superstruct validation failure.\n * Reports only the field path and expected type, never the actual failing\n * value, which may contain account addresses or other user data.\n *\n * @param error - The StructError-like object.\n * @returns A safe description string.\n */\nfunction describeStructFailure(error: StructErrorLike): string {\n const path =\n error.path.length > 0 ? `\"${error.path.map(String).join('.')}\"` : '<root>';\n return `Validation failed at ${path} (expected: ${error.refinement ?? error.type})`;\n}\n\n/**\n * Executes `fn` and, if it throws, sanitizes the error before re-throwing to\n * guarantee the caller always gets an error whose message is safe to forward\n * to Sentry.\n *\n * Sanitization rules applied to whatever `fn` throws:\n * - {@link SafeError}: re-thrown as-is (innermost step description preserved,\n * no re-wrapping on nested {@link withSafeError} calls).\n * - {@link KeyringControllerError}: re-thrown as-is (uses static, enum-based\n * messages; no user data).\n * - `StructError` (from `@metamask/superstruct`): wrapped in a\n * {@link SafeError} containing only the failing field path and expected type,\n * never the actual value.\n * - Anything else: wrapped in a {@link SafeError} with a generic fallback\n * message; the original error is discarded to prevent accidental leakage.\n *\n * @param step - Human-readable label for this execution step, prepended to the\n * `SafeError` message when the error is not already safe.\n * @param fn - The async callback to execute.\n * @returns The result of `fn`.\n */\nexport async function withSafeError<ReturnType>(\n step: string,\n fn: () => Promise<ReturnType>,\n): Promise<ReturnType> {\n try {\n return await fn();\n } catch (error) {\n if (isSafeError(error) || isKeyringControllerError(error)) {\n throw error;\n }\n if (isStructError(error)) {\n throw new SafeError(`${step}: ${describeStructFailure(error)}`);\n }\n throw new SafeError(`${step}: An unexpected error occurred`);\n }\n}\n\n/**\n * Augmented `Error` shape produced by {@link createSentryError}. The runtime\n * value carries a `cause` and (optionally) a structured `context` payload\n * that downstream Sentry tooling can read.\n *\n * The `TContext` type parameter narrows the shape of `context` for callers\n * that know what they put in — most useful in tests when asserting on a\n * captured error.\n */\nexport type SentryError<\n TContext extends Record<string, unknown> = Record<string, unknown>,\n> = Error & {\n cause: Error;\n context?: TContext;\n};\n\n/**\n * Creates a Sentry error from an error message, an inner error and a context.\n *\n * NOTE: Sentry defaults to a depth of 3 when extracting non-native attributes.\n * As such, the context depth shouldn't be too deep.\n *\n * @param message - The error message to create a Sentry error from.\n * @param innerError - The inner error to create a Sentry error from.\n * @param context - The context to add to the Sentry error.\n * @returns A Sentry error.\n */\nexport const createSentryError = <\n TContext extends Record<string, unknown> = Record<string, unknown>,\n>(\n message: string,\n innerError: Error,\n context?: TContext,\n): SentryError<TContext> => {\n const error = new Error(message) as SentryError<TContext>;\n error.cause = innerError;\n if (context) {\n error.context = context;\n }\n return error;\n};\n\n/**\n * Reports an error by logging it to the console and optionally capturing it\n * in Sentry via the messenger's `captureException` method.\n *\n * @param messenger - Object with an optional `captureException` method.\n * @param messenger.captureException - Optional method to capture exceptions in Sentry.\n * @param message - The static message describing what failed.\n * @param error - The caught error.\n * @param context - Optional context to attach to the Sentry error.\n */\nexport function reportError(\n messenger: { captureException?: (error: Error) => void },\n message: string,\n error: unknown,\n context?: Record<string, unknown>,\n): void {\n console.error(message, error);\n\n const sentryError = createSentryError(message, error as Error, context);\n messenger.captureException?.(sentryError);\n}\n"]}
|
package/dist/errors.d.cts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thrown by {@link withSafeError} when the wrapped callback fails with an error
|
|
3
|
-
* whose message is not safe to forward to Sentry (e.g., a superstruct
|
|
4
|
-
* `StructError` that may embed account addresses, or an unknown third-party
|
|
5
|
-
* error). The message on a `SafeError` is always authored by us and contains
|
|
6
|
-
* no user data.
|
|
7
|
-
*
|
|
8
|
-
* `SafeError` instances pass through nested {@link withSafeError} calls unchanged;
|
|
9
|
-
* the innermost step description is preserved rather than re-wrapped.
|
|
10
|
-
*/
|
|
11
|
-
export declare class SafeError extends Error {
|
|
12
|
-
constructor(message: string);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Returns `true` if the error is a `SafeError`.
|
|
16
|
-
*
|
|
17
|
-
* Uses duck-typing on `error.name` rather than `instanceof` so that the check
|
|
18
|
-
* remains correct when multiple versions of this package coexist in the
|
|
19
|
-
* dependency tree (different versions produce different classes, so
|
|
20
|
-
* `instanceof` would return `false` for errors from another version).
|
|
21
|
-
*
|
|
22
|
-
* @param error - The value to check.
|
|
23
|
-
* @returns Whether the error is a `SafeError`.
|
|
24
|
-
*/
|
|
25
|
-
export declare function isSafeError(error: unknown): error is SafeError;
|
|
26
|
-
/**
|
|
27
|
-
* Executes `fn` and, if it throws, sanitizes the error before re-throwing to
|
|
28
|
-
* guarantee the caller always gets an error whose message is safe to forward
|
|
29
|
-
* to Sentry.
|
|
30
|
-
*
|
|
31
|
-
* Sanitization rules applied to whatever `fn` throws:
|
|
32
|
-
* - {@link SafeError}: re-thrown as-is (innermost step description preserved,
|
|
33
|
-
* no re-wrapping on nested {@link withSafeError} calls).
|
|
34
|
-
* - {@link KeyringControllerError}: re-thrown as-is (uses static, enum-based
|
|
35
|
-
* messages; no user data).
|
|
36
|
-
* - `StructError` (from `@metamask/superstruct`): wrapped in a
|
|
37
|
-
* {@link SafeError} containing only the failing field path and expected type,
|
|
38
|
-
* never the actual value.
|
|
39
|
-
* - Anything else: wrapped in a {@link SafeError} with a generic fallback
|
|
40
|
-
* message; the original error is discarded to prevent accidental leakage.
|
|
41
|
-
*
|
|
42
|
-
* @param step - Human-readable label for this execution step, prepended to the
|
|
43
|
-
* `SafeError` message when the error is not already safe.
|
|
44
|
-
* @param fn - The async callback to execute.
|
|
45
|
-
* @returns The result of `fn`.
|
|
46
|
-
*/
|
|
47
|
-
export declare function withSafeError<ReturnType>(step: string, fn: () => Promise<ReturnType>): Promise<ReturnType>;
|
|
48
|
-
/**
|
|
49
|
-
* Augmented `Error` shape produced by {@link createSentryError}. The runtime
|
|
50
|
-
* value carries a `cause` and (optionally) a structured `context` payload
|
|
51
|
-
* that downstream Sentry tooling can read.
|
|
52
|
-
*
|
|
53
|
-
* The `TContext` type parameter narrows the shape of `context` for callers
|
|
54
|
-
* that know what they put in — most useful in tests when asserting on a
|
|
55
|
-
* captured error.
|
|
56
|
-
*/
|
|
57
|
-
export type SentryError<TContext extends Record<string, unknown> = Record<string, unknown>> = Error & {
|
|
58
|
-
cause: Error;
|
|
59
|
-
context?: TContext;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Creates a Sentry error from an error message, an inner error and a context.
|
|
63
|
-
*
|
|
64
|
-
* NOTE: Sentry defaults to a depth of 3 when extracting non-native attributes.
|
|
65
|
-
* As such, the context depth shouldn't be too deep.
|
|
66
|
-
*
|
|
67
|
-
* @param message - The error message to create a Sentry error from.
|
|
68
|
-
* @param innerError - The inner error to create a Sentry error from.
|
|
69
|
-
* @param context - The context to add to the Sentry error.
|
|
70
|
-
* @returns A Sentry error.
|
|
71
|
-
*/
|
|
72
|
-
export declare const createSentryError: <TContext extends Record<string, unknown> = Record<string, unknown>>(message: string, innerError: Error, context?: TContext | undefined) => SentryError<TContext>;
|
|
73
|
-
/**
|
|
74
|
-
* Reports an error by logging it to the console and optionally capturing it
|
|
75
|
-
* in Sentry via the messenger's `captureException` method.
|
|
76
|
-
*
|
|
77
|
-
* @param messenger - Object with an optional `captureException` method.
|
|
78
|
-
* @param messenger.captureException - Optional method to capture exceptions in Sentry.
|
|
79
|
-
* @param message - The static message describing what failed.
|
|
80
|
-
* @param error - The caught error.
|
|
81
|
-
* @param context - Optional context to attach to the Sentry error.
|
|
82
|
-
*/
|
|
83
|
-
export declare function reportError(messenger: {
|
|
84
|
-
captureException?: (error: Error) => void;
|
|
85
|
-
}, message: string, error: unknown, context?: Record<string, unknown>): void;
|
|
86
|
-
//# sourceMappingURL=errors.d.cts.map
|
package/dist/errors.d.cts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.cts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAM9D;AAoDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAC5C,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,CAYrB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,CACrB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE,KAAK,GAAG;IACV,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,gFAGnB,MAAM,cACH,KAAK,0DASlB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE;IAAE,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAAE,EACxD,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAKN"}
|
package/dist/errors.d.mts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thrown by {@link withSafeError} when the wrapped callback fails with an error
|
|
3
|
-
* whose message is not safe to forward to Sentry (e.g., a superstruct
|
|
4
|
-
* `StructError` that may embed account addresses, or an unknown third-party
|
|
5
|
-
* error). The message on a `SafeError` is always authored by us and contains
|
|
6
|
-
* no user data.
|
|
7
|
-
*
|
|
8
|
-
* `SafeError` instances pass through nested {@link withSafeError} calls unchanged;
|
|
9
|
-
* the innermost step description is preserved rather than re-wrapped.
|
|
10
|
-
*/
|
|
11
|
-
export declare class SafeError extends Error {
|
|
12
|
-
constructor(message: string);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Returns `true` if the error is a `SafeError`.
|
|
16
|
-
*
|
|
17
|
-
* Uses duck-typing on `error.name` rather than `instanceof` so that the check
|
|
18
|
-
* remains correct when multiple versions of this package coexist in the
|
|
19
|
-
* dependency tree (different versions produce different classes, so
|
|
20
|
-
* `instanceof` would return `false` for errors from another version).
|
|
21
|
-
*
|
|
22
|
-
* @param error - The value to check.
|
|
23
|
-
* @returns Whether the error is a `SafeError`.
|
|
24
|
-
*/
|
|
25
|
-
export declare function isSafeError(error: unknown): error is SafeError;
|
|
26
|
-
/**
|
|
27
|
-
* Executes `fn` and, if it throws, sanitizes the error before re-throwing to
|
|
28
|
-
* guarantee the caller always gets an error whose message is safe to forward
|
|
29
|
-
* to Sentry.
|
|
30
|
-
*
|
|
31
|
-
* Sanitization rules applied to whatever `fn` throws:
|
|
32
|
-
* - {@link SafeError}: re-thrown as-is (innermost step description preserved,
|
|
33
|
-
* no re-wrapping on nested {@link withSafeError} calls).
|
|
34
|
-
* - {@link KeyringControllerError}: re-thrown as-is (uses static, enum-based
|
|
35
|
-
* messages; no user data).
|
|
36
|
-
* - `StructError` (from `@metamask/superstruct`): wrapped in a
|
|
37
|
-
* {@link SafeError} containing only the failing field path and expected type,
|
|
38
|
-
* never the actual value.
|
|
39
|
-
* - Anything else: wrapped in a {@link SafeError} with a generic fallback
|
|
40
|
-
* message; the original error is discarded to prevent accidental leakage.
|
|
41
|
-
*
|
|
42
|
-
* @param step - Human-readable label for this execution step, prepended to the
|
|
43
|
-
* `SafeError` message when the error is not already safe.
|
|
44
|
-
* @param fn - The async callback to execute.
|
|
45
|
-
* @returns The result of `fn`.
|
|
46
|
-
*/
|
|
47
|
-
export declare function withSafeError<ReturnType>(step: string, fn: () => Promise<ReturnType>): Promise<ReturnType>;
|
|
48
|
-
/**
|
|
49
|
-
* Augmented `Error` shape produced by {@link createSentryError}. The runtime
|
|
50
|
-
* value carries a `cause` and (optionally) a structured `context` payload
|
|
51
|
-
* that downstream Sentry tooling can read.
|
|
52
|
-
*
|
|
53
|
-
* The `TContext` type parameter narrows the shape of `context` for callers
|
|
54
|
-
* that know what they put in — most useful in tests when asserting on a
|
|
55
|
-
* captured error.
|
|
56
|
-
*/
|
|
57
|
-
export type SentryError<TContext extends Record<string, unknown> = Record<string, unknown>> = Error & {
|
|
58
|
-
cause: Error;
|
|
59
|
-
context?: TContext;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Creates a Sentry error from an error message, an inner error and a context.
|
|
63
|
-
*
|
|
64
|
-
* NOTE: Sentry defaults to a depth of 3 when extracting non-native attributes.
|
|
65
|
-
* As such, the context depth shouldn't be too deep.
|
|
66
|
-
*
|
|
67
|
-
* @param message - The error message to create a Sentry error from.
|
|
68
|
-
* @param innerError - The inner error to create a Sentry error from.
|
|
69
|
-
* @param context - The context to add to the Sentry error.
|
|
70
|
-
* @returns A Sentry error.
|
|
71
|
-
*/
|
|
72
|
-
export declare const createSentryError: <TContext extends Record<string, unknown> = Record<string, unknown>>(message: string, innerError: Error, context?: TContext | undefined) => SentryError<TContext>;
|
|
73
|
-
/**
|
|
74
|
-
* Reports an error by logging it to the console and optionally capturing it
|
|
75
|
-
* in Sentry via the messenger's `captureException` method.
|
|
76
|
-
*
|
|
77
|
-
* @param messenger - Object with an optional `captureException` method.
|
|
78
|
-
* @param messenger.captureException - Optional method to capture exceptions in Sentry.
|
|
79
|
-
* @param message - The static message describing what failed.
|
|
80
|
-
* @param error - The caught error.
|
|
81
|
-
* @param context - Optional context to attach to the Sentry error.
|
|
82
|
-
*/
|
|
83
|
-
export declare function reportError(messenger: {
|
|
84
|
-
captureException?: (error: Error) => void;
|
|
85
|
-
}, message: string, error: unknown, context?: Record<string, unknown>): void;
|
|
86
|
-
//# sourceMappingURL=errors.d.mts.map
|
package/dist/errors.d.mts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.mts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAM9D;AAoDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAC5C,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,CAYrB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,CACrB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE,KAAK,GAAG;IACV,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,gFAGnB,MAAM,cACH,KAAK,0DASlB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE;IAAE,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAAE,EACxD,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAKN"}
|
package/dist/errors.mjs
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { isKeyringControllerError } from "@metamask/keyring-controller";
|
|
2
|
-
/**
|
|
3
|
-
* Thrown by {@link withSafeError} when the wrapped callback fails with an error
|
|
4
|
-
* whose message is not safe to forward to Sentry (e.g., a superstruct
|
|
5
|
-
* `StructError` that may embed account addresses, or an unknown third-party
|
|
6
|
-
* error). The message on a `SafeError` is always authored by us and contains
|
|
7
|
-
* no user data.
|
|
8
|
-
*
|
|
9
|
-
* `SafeError` instances pass through nested {@link withSafeError} calls unchanged;
|
|
10
|
-
* the innermost step description is preserved rather than re-wrapped.
|
|
11
|
-
*/
|
|
12
|
-
export class SafeError extends Error {
|
|
13
|
-
constructor(message) {
|
|
14
|
-
super(message);
|
|
15
|
-
this.name = 'SafeError';
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Returns `true` if the error is a `SafeError`.
|
|
20
|
-
*
|
|
21
|
-
* Uses duck-typing on `error.name` rather than `instanceof` so that the check
|
|
22
|
-
* remains correct when multiple versions of this package coexist in the
|
|
23
|
-
* dependency tree (different versions produce different classes, so
|
|
24
|
-
* `instanceof` would return `false` for errors from another version).
|
|
25
|
-
*
|
|
26
|
-
* @param error - The value to check.
|
|
27
|
-
* @returns Whether the error is a `SafeError`.
|
|
28
|
-
*/
|
|
29
|
-
export function isSafeError(error) {
|
|
30
|
-
return (typeof error === 'object' &&
|
|
31
|
-
error !== null &&
|
|
32
|
-
error.name === 'SafeError');
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Returns `true` if the error is a `StructError`-like object.
|
|
36
|
-
*
|
|
37
|
-
* @param error - The value to check.
|
|
38
|
-
* @returns Whether the error is a `StructError`-like object.
|
|
39
|
-
*/
|
|
40
|
-
function isStructError(error) {
|
|
41
|
-
const isError = error instanceof Error && error.name === 'StructError';
|
|
42
|
-
if (!isError) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
const structError = error;
|
|
46
|
-
return (Array.isArray(structError.path) && typeof structError.type === 'string');
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Produces a safe, human-readable summary of a superstruct validation failure.
|
|
50
|
-
* Reports only the field path and expected type, never the actual failing
|
|
51
|
-
* value, which may contain account addresses or other user data.
|
|
52
|
-
*
|
|
53
|
-
* @param error - The StructError-like object.
|
|
54
|
-
* @returns A safe description string.
|
|
55
|
-
*/
|
|
56
|
-
function describeStructFailure(error) {
|
|
57
|
-
const path = error.path.length > 0 ? `"${error.path.map(String).join('.')}"` : '<root>';
|
|
58
|
-
return `Validation failed at ${path} (expected: ${error.refinement ?? error.type})`;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Executes `fn` and, if it throws, sanitizes the error before re-throwing to
|
|
62
|
-
* guarantee the caller always gets an error whose message is safe to forward
|
|
63
|
-
* to Sentry.
|
|
64
|
-
*
|
|
65
|
-
* Sanitization rules applied to whatever `fn` throws:
|
|
66
|
-
* - {@link SafeError}: re-thrown as-is (innermost step description preserved,
|
|
67
|
-
* no re-wrapping on nested {@link withSafeError} calls).
|
|
68
|
-
* - {@link KeyringControllerError}: re-thrown as-is (uses static, enum-based
|
|
69
|
-
* messages; no user data).
|
|
70
|
-
* - `StructError` (from `@metamask/superstruct`): wrapped in a
|
|
71
|
-
* {@link SafeError} containing only the failing field path and expected type,
|
|
72
|
-
* never the actual value.
|
|
73
|
-
* - Anything else: wrapped in a {@link SafeError} with a generic fallback
|
|
74
|
-
* message; the original error is discarded to prevent accidental leakage.
|
|
75
|
-
*
|
|
76
|
-
* @param step - Human-readable label for this execution step, prepended to the
|
|
77
|
-
* `SafeError` message when the error is not already safe.
|
|
78
|
-
* @param fn - The async callback to execute.
|
|
79
|
-
* @returns The result of `fn`.
|
|
80
|
-
*/
|
|
81
|
-
export async function withSafeError(step, fn) {
|
|
82
|
-
try {
|
|
83
|
-
return await fn();
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
if (isSafeError(error) || isKeyringControllerError(error)) {
|
|
87
|
-
throw error;
|
|
88
|
-
}
|
|
89
|
-
if (isStructError(error)) {
|
|
90
|
-
throw new SafeError(`${step}: ${describeStructFailure(error)}`);
|
|
91
|
-
}
|
|
92
|
-
throw new SafeError(`${step}: An unexpected error occurred`);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Creates a Sentry error from an error message, an inner error and a context.
|
|
97
|
-
*
|
|
98
|
-
* NOTE: Sentry defaults to a depth of 3 when extracting non-native attributes.
|
|
99
|
-
* As such, the context depth shouldn't be too deep.
|
|
100
|
-
*
|
|
101
|
-
* @param message - The error message to create a Sentry error from.
|
|
102
|
-
* @param innerError - The inner error to create a Sentry error from.
|
|
103
|
-
* @param context - The context to add to the Sentry error.
|
|
104
|
-
* @returns A Sentry error.
|
|
105
|
-
*/
|
|
106
|
-
export const createSentryError = (message, innerError, context) => {
|
|
107
|
-
const error = new Error(message);
|
|
108
|
-
error.cause = innerError;
|
|
109
|
-
if (context) {
|
|
110
|
-
error.context = context;
|
|
111
|
-
}
|
|
112
|
-
return error;
|
|
113
|
-
};
|
|
114
|
-
/**
|
|
115
|
-
* Reports an error by logging it to the console and optionally capturing it
|
|
116
|
-
* in Sentry via the messenger's `captureException` method.
|
|
117
|
-
*
|
|
118
|
-
* @param messenger - Object with an optional `captureException` method.
|
|
119
|
-
* @param messenger.captureException - Optional method to capture exceptions in Sentry.
|
|
120
|
-
* @param message - The static message describing what failed.
|
|
121
|
-
* @param error - The caught error.
|
|
122
|
-
* @param context - Optional context to attach to the Sentry error.
|
|
123
|
-
*/
|
|
124
|
-
export function reportError(messenger, message, error, context) {
|
|
125
|
-
console.error(message, error);
|
|
126
|
-
const sentryError = createSentryError(message, error, context);
|
|
127
|
-
messenger.captureException?.(sentryError);
|
|
128
|
-
}
|
|
129
|
-
//# sourceMappingURL=errors.mjs.map
|
package/dist/errors.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.mjs","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,qCAAqC;AAExE;;;;;;;;;GASG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAA4B,CAAC,IAAI,KAAK,WAAW,CACnD,CAAC;AACJ,CAAC;AAiBD;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAc;IACnC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC;IACvE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,KAGnB,CAAC;IACF,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,QAAQ,CACxE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,KAAsB;IACnD,MAAM,IAAI,GACR,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC7E,OAAO,wBAAwB,IAAI,eAAe,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;AACtF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,EAA6B;IAE7B,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,wBAAwB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,KAAK,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,gCAAgC,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAkBD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAG/B,OAAe,EACf,UAAiB,EACjB,OAAkB,EACK,EAAE;IACzB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAA0B,CAAC;IAC1D,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC;IACzB,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,SAAwD,EACxD,OAAe,EACf,KAAc,EACd,OAAiC;IAEjC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAE9B,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAc,EAAE,OAAO,CAAC,CAAC;IACxE,SAAS,CAAC,gBAAgB,EAAE,CAAC,WAAW,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { isKeyringControllerError } from '@metamask/keyring-controller';\n\n/**\n * Thrown by {@link withSafeError} when the wrapped callback fails with an error\n * whose message is not safe to forward to Sentry (e.g., a superstruct\n * `StructError` that may embed account addresses, or an unknown third-party\n * error). The message on a `SafeError` is always authored by us and contains\n * no user data.\n *\n * `SafeError` instances pass through nested {@link withSafeError} calls unchanged;\n * the innermost step description is preserved rather than re-wrapped.\n */\nexport class SafeError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SafeError';\n }\n}\n\n/**\n * Returns `true` if the error is a `SafeError`.\n *\n * Uses duck-typing on `error.name` rather than `instanceof` so that the check\n * remains correct when multiple versions of this package coexist in the\n * dependency tree (different versions produce different classes, so\n * `instanceof` would return `false` for errors from another version).\n *\n * @param error - The value to check.\n * @returns Whether the error is a `SafeError`.\n */\nexport function isSafeError(error: unknown): error is SafeError {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as { name?: unknown }).name === 'SafeError'\n );\n}\n\n/**\n * Duck-typed shape of `@metamask/superstruct`'s `StructError`.\n *\n * We avoid a direct `instanceof` check because `@metamask/superstruct` is not\n * a declared dependency of this package; it reaches us transitively. Checking\n * `name` plus the presence of `path` and `type` is sufficient to identify it\n * without coupling to the transitive dep.\n */\ntype StructErrorLike = Error & {\n name: 'StructError';\n path: unknown[];\n type: string;\n refinement?: string;\n};\n\n/**\n * Returns `true` if the error is a `StructError`-like object.\n *\n * @param error - The value to check.\n * @returns Whether the error is a `StructError`-like object.\n */\nfunction isStructError(error: unknown): error is StructErrorLike {\n const isError = error instanceof Error && error.name === 'StructError';\n if (!isError) {\n return false;\n }\n\n const structError = error as {\n path?: string[];\n type?: string;\n };\n return (\n Array.isArray(structError.path) && typeof structError.type === 'string'\n );\n}\n\n/**\n * Produces a safe, human-readable summary of a superstruct validation failure.\n * Reports only the field path and expected type, never the actual failing\n * value, which may contain account addresses or other user data.\n *\n * @param error - The StructError-like object.\n * @returns A safe description string.\n */\nfunction describeStructFailure(error: StructErrorLike): string {\n const path =\n error.path.length > 0 ? `\"${error.path.map(String).join('.')}\"` : '<root>';\n return `Validation failed at ${path} (expected: ${error.refinement ?? error.type})`;\n}\n\n/**\n * Executes `fn` and, if it throws, sanitizes the error before re-throwing to\n * guarantee the caller always gets an error whose message is safe to forward\n * to Sentry.\n *\n * Sanitization rules applied to whatever `fn` throws:\n * - {@link SafeError}: re-thrown as-is (innermost step description preserved,\n * no re-wrapping on nested {@link withSafeError} calls).\n * - {@link KeyringControllerError}: re-thrown as-is (uses static, enum-based\n * messages; no user data).\n * - `StructError` (from `@metamask/superstruct`): wrapped in a\n * {@link SafeError} containing only the failing field path and expected type,\n * never the actual value.\n * - Anything else: wrapped in a {@link SafeError} with a generic fallback\n * message; the original error is discarded to prevent accidental leakage.\n *\n * @param step - Human-readable label for this execution step, prepended to the\n * `SafeError` message when the error is not already safe.\n * @param fn - The async callback to execute.\n * @returns The result of `fn`.\n */\nexport async function withSafeError<ReturnType>(\n step: string,\n fn: () => Promise<ReturnType>,\n): Promise<ReturnType> {\n try {\n return await fn();\n } catch (error) {\n if (isSafeError(error) || isKeyringControllerError(error)) {\n throw error;\n }\n if (isStructError(error)) {\n throw new SafeError(`${step}: ${describeStructFailure(error)}`);\n }\n throw new SafeError(`${step}: An unexpected error occurred`);\n }\n}\n\n/**\n * Augmented `Error` shape produced by {@link createSentryError}. The runtime\n * value carries a `cause` and (optionally) a structured `context` payload\n * that downstream Sentry tooling can read.\n *\n * The `TContext` type parameter narrows the shape of `context` for callers\n * that know what they put in — most useful in tests when asserting on a\n * captured error.\n */\nexport type SentryError<\n TContext extends Record<string, unknown> = Record<string, unknown>,\n> = Error & {\n cause: Error;\n context?: TContext;\n};\n\n/**\n * Creates a Sentry error from an error message, an inner error and a context.\n *\n * NOTE: Sentry defaults to a depth of 3 when extracting non-native attributes.\n * As such, the context depth shouldn't be too deep.\n *\n * @param message - The error message to create a Sentry error from.\n * @param innerError - The inner error to create a Sentry error from.\n * @param context - The context to add to the Sentry error.\n * @returns A Sentry error.\n */\nexport const createSentryError = <\n TContext extends Record<string, unknown> = Record<string, unknown>,\n>(\n message: string,\n innerError: Error,\n context?: TContext,\n): SentryError<TContext> => {\n const error = new Error(message) as SentryError<TContext>;\n error.cause = innerError;\n if (context) {\n error.context = context;\n }\n return error;\n};\n\n/**\n * Reports an error by logging it to the console and optionally capturing it\n * in Sentry via the messenger's `captureException` method.\n *\n * @param messenger - Object with an optional `captureException` method.\n * @param messenger.captureException - Optional method to capture exceptions in Sentry.\n * @param message - The static message describing what failed.\n * @param error - The caught error.\n * @param context - Optional context to attach to the Sentry error.\n */\nexport function reportError(\n messenger: { captureException?: (error: Error) => void },\n message: string,\n error: unknown,\n context?: Record<string, unknown>,\n): void {\n console.error(message, error);\n\n const sentryError = createSentryError(message, error as Error, context);\n messenger.captureException?.(sentryError);\n}\n"]}
|