@metamask-previews/eth-snap-keyring 22.2.0-e5bc458 → 22.3.0-30b0aa8

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 CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [22.3.0]
11
+
12
+ ### Added
13
+
14
+ - Add `static type` for v2 `SnapKeyring` ([#570](https://github.com/MetaMask/accounts/pull/570))
15
+
10
16
  ## [22.2.0]
11
17
 
12
18
  ### Added
@@ -739,7 +745,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
739
745
 
740
746
  - Initial release.
741
747
 
742
- [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@22.2.0...HEAD
748
+ [Unreleased]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@22.3.0...HEAD
749
+ [22.3.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@22.2.0...@metamask/eth-snap-keyring@22.3.0
743
750
  [22.2.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@22.1.0...@metamask/eth-snap-keyring@22.2.0
744
751
  [22.1.0]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@22.0.1...@metamask/eth-snap-keyring@22.1.0
745
752
  [22.0.1]: https://github.com/MetaMask/accounts/compare/@metamask/eth-snap-keyring@22.0.0...@metamask/eth-snap-keyring@22.0.1
@@ -403,4 +403,5 @@ async function _SnapKeyring_withLock(callback) {
403
403
  return (__classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").withLock ??
404
404
  (async (operation) => __classPrivateFieldGet(this, _SnapKeyring_lock, "f").runExclusive(operation)))(callback);
405
405
  };
406
+ SnapKeyring.type = `${v2_1.KeyringType.Snap}`;
406
407
  //# sourceMappingURL=SnapKeyring.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SnapKeyring.cjs","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":"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","sourcesContent":["import type { KeyringAccount } from '@metamask/keyring-api';\nimport { KeyringAccountStruct } from '@metamask/keyring-api';\nimport type {\n CreateAccountOptions,\n Keyring,\n KeyringCapabilities,\n} from '@metamask/keyring-api/v2';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport type { Infer } from '@metamask/superstruct';\nimport { assert, object, record, string, union } from '@metamask/superstruct';\nimport type { Json } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport {\n KeyringAccountV1Struct,\n normalizeAccount,\n transformAccount,\n} from '../account';\nimport { isAccountV1, migrateAccountV1 } from '../migrations';\nimport { SnapKeyringV1 } from '../SnapKeyringV1';\nimport type {\n AccountMethod,\n SnapKeyringV1Callbacks,\n SnapKeyringV1Options,\n} from '../SnapKeyringV1';\nimport { equalsIgnoreCase } from '../util';\n\n/**\n * Superstruct schema for {@link SnapKeyringState}.\n *\n * Accepts both v1 accounts (missing `scopes`) and v2 accounts so that\n * persisted state can be validated before migration.\n */\nexport const SnapKeyringStateStruct = object({\n snapId: string(),\n accounts: record(\n string(),\n union([KeyringAccountStruct, KeyringAccountV1Struct]),\n ),\n});\n\n/**\n * Serialized state of a single SnapKeyring instance.\n *\n * Note: this is an internal format only used between SnapKeyring and its\n * parent SnapKeyring. The external KeyringState format (flat `{ account,\n * snapId }` map) is preserved by SnapKeyring.serialize / deserialize.\n *\n * Inferred from {@link SnapKeyringStateStruct}: `snapId` is `string`\n * (not the branded `SnapId`) so the shape stays JSON-compatible without\n * unsafe casts.\n */\nexport type SnapKeyringState = Infer<typeof SnapKeyringStateStruct>;\n\n/**\n * Callbacks injected by the parent `SnapKeyring` for global coordination.\n */\nexport type SnapKeyringCallbacks = SnapKeyringV1Callbacks & {\n /**\n * Run a callback under a global lock to prevent TOCTOU races in\n * `createAccounts` when multiple snaps call `assertAccountCanBeUsed`\n * concurrently.\n *\n * Optional: if omitted, `SnapKeyringV2` falls back to its own per-instance\n * `Mutex`, which is sufficient when the keyring is used standalone.\n */\n withLock?: <Result>(callback: () => Promise<Result>) => Promise<Result>;\n};\n\ntype SnapKeyringOptions = Omit<SnapKeyringV1Options, 'callbacks'> & {\n callbacks: SnapKeyringCallbacks;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nexport function isSnapKeyring(keyring: Keyring): keyring is SnapKeyring {\n return keyring.type === KeyringType.Snap;\n}\n\n/**\n * Per-snap keyring wrapper that implements `Keyring`.\n *\n * Extends `SnapKeyringV1` — the v1 event-driven flow (account lifecycle,\n * request handling, asset events) is inherited. This class adds the\n * `KeyringV2` batch interface (`createAccounts`, `deleteAccount`, etc.) and\n * owns the `capabilities` property.\n *\n * The `KeyringAccountRegistry`, snap client, and messenger are all inherited\n * from `SnapKeyringV1` so there is no duplicated state.\n */\nexport class SnapKeyring extends SnapKeyringV1 implements Keyring {\n /**\n * V2-typed view of the callbacks. Stored separately from the V1 private\n * field so that V2-specific callbacks are accessible without casting.\n * Both fields hold the same object reference.\n */\n readonly #callbacks: SnapKeyringCallbacks;\n\n /**\n * Mutex that serializes `createAccounts` calls on this snap instance.\n * Owned here so that each `SnapKeyring` is fully self-contained.\n */\n readonly #lock: Mutex;\n\n // ──────────────────────────────────────────────\n // Keyring properties\n // ──────────────────────────────────────────────\n\n readonly type = `${KeyringType.Snap}` as const;\n\n /**\n * Capabilities are snap-specific. Initialized empty and can be updated\n * by the parent when snap metadata becomes available.\n */\n capabilities: KeyringCapabilities;\n\n constructor(options: SnapKeyringOptions) {\n super(options);\n this.#callbacks = options.callbacks;\n this.#lock = new Mutex();\n\n // Default capabilities — parent updates this when snap metadata is available.\n // We cast here because KeyringCapabilities requires a non-empty scopes array,\n // but we don't have the snap metadata at construction time (e.g. during deserialization).\n this.capabilities = { scopes: [] } as unknown as KeyringCapabilities;\n }\n\n /**\n * Destroy this keyring.\n *\n * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending\n * requests inherited from the v1 flow.\n */\n override async destroy(): Promise<void> {\n await super.destroy();\n }\n\n /**\n * Run a callback under the appropriate lock.\n *\n * Prefers the injected `withLock` callback (global lock provided by\n * `SnapKeyring`) so that `createAccounts` calls across different snaps\n * are serialized. Falls back to the per-instance `#lock` when no global\n * lock is provided.g. standalone use in tests).\n *\n * @param callback - Operation to run under the lock.\n * @returns The result of the callback.\n */\n async #withLock<Result>(callback: () => Promise<Result>): Promise<Result> {\n return (\n this.#callbacks.withLock ??\n (async (operation: () => Promise<Result>): Promise<Result> =>\n this.#lock.runExclusive(operation))\n )(callback);\n }\n\n // ──────────────────────────────────────────────\n // Keyring methods\n // ──────────────────────────────────────────────\n\n /**\n * Returns all accounts managed by this keyring.\n *\n * @returns A promise that resolves to an array of all accounts.\n */\n async getAccounts(): Promise<KeyringAccount[]> {\n return this.accounts();\n }\n\n /**\n * Returns the account with the specified ID.\n *\n * @param accountId - ID of the account to retrieve.\n * @returns A promise that resolves to the account.\n */\n async getAccount(accountId: AccountId): Promise<KeyringAccount> {\n const account = this.lookupAccount(accountId);\n if (!account) {\n throw new Error(\n `Account '${accountId}' not found in snap '${this.snapId}'`,\n );\n }\n return account;\n }\n\n /**\n * Creates one or more new accounts according to the provided options.\n *\n * Deterministic account creation MUST be idempotent, meaning that for\n * deterministic algorithms, like BIP-44, calling this method with the same\n * options should always return the same accounts, even if the accounts\n * already exist in the keyring.\n *\n * NOTE: If some accounts are not allowed (non-unique address, unsupported\n * generic account), this method will skip their creation and ask the Snap\n * to remove them from its state.\n *\n * @param options - Options describing how to create the account(s).\n * @returns A promise that resolves to an array of the created account objects.\n */\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<KeyringAccount[]> {\n return this.#withLock(async () => {\n // Keep track of address/account ID part of this batch, to avoid having duplicates.\n const batchAddresses = new Set<string>();\n const batchIds = new Set<string>();\n\n const accounts: KeyringAccount[] = [];\n const newAccounts: KeyringAccount[] = [];\n const snapAccounts = await this.client.createAccounts(options);\n\n try {\n for (const snapAccount of snapAccounts) {\n let account = normalizeAccount(transformAccount(snapAccount));\n const { address } = account;\n\n // Check for idempotency.\n const existingAccount = this.getExistingAccount(account);\n if (existingAccount) {\n // NOTE: We re-use the account from the internal state to avoid having the Snap\n // mutating the account object without updating the map.\n account = existingAccount;\n } else {\n await this.#callbacks.assertAccountCanBeUsed(account);\n\n // Also check for transient accounts that are not yet part of the keyring\n // state.\n if (batchAddresses.has(address) || batchIds.has(account.id)) {\n throw new Error(\n `Account '${account.id}' is already part of this batch (same address or account ID)`,\n );\n }\n batchAddresses.add(address);\n batchIds.add(account.id);\n\n // NOTE: This method does not rely on the `AccountCreated` event to add\n // accounts to the keyring, so we have to add them to the state manually.\n newAccounts.push(account);\n }\n\n // New AND existing accounts are returned to the caller no matter what.\n accounts.push(account);\n }\n\n // We update the keyring state only if needed.\n if (newAccounts.length > 0) {\n for (const account of newAccounts) {\n this.setAccount(account);\n }\n\n // NOTE: We assume this will never fail, thus, we don't need to rollback the\n // keyring state if anything goes wrong here.\n await this.#callbacks.saveState();\n }\n\n return accounts;\n } catch (error) {\n // Rollback Snap state.\n for (const snapAccount of snapAccounts) {\n // Make sure to only delete accounts that were not part of the keyring state.\n if (!this.getExistingAccount(snapAccount)) {\n try {\n await this.client.deleteAccount(snapAccount.id);\n } catch (rollbackError) {\n // Best-effort rollback; log snap-side failures for observability.\n console.error(\n `Account '${snapAccount.id}' may not have been removed from snap '${this.snapId}' during createAccounts rollback:`,\n rollbackError,\n );\n }\n }\n }\n\n throw error;\n }\n });\n }\n\n /**\n * Deletes the account with the specified ID.\n *\n * Removes the account from the local registry (firing `onUnregister` so the\n * parent can update its index), then asks the snap to delete it.\n *\n * @param accountId - ID of the account to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n // Always remove the account from the registry, even if the Snap is going to\n // fail to delete it. removeAccount fires onUnregister to clean #accountIndex.\n this.removeAccount(accountId);\n\n try {\n await this.client.deleteAccount(accountId);\n } catch (error) {\n // If the Snap failed to delete the account, log the error and continue\n // with the account deletion, otherwise the account will be stuck in the\n // keyring.\n console.error(\n `Account '${accountId}' may not have been removed from snap '${this.snapId}':`,\n error,\n );\n }\n }\n\n /**\n * Submits a request to the keyring.\n *\n * Validates that the account belongs to this wrapper, then delegates\n * to the inherited `submitSnapRequest` for the full request lifecycle\n * (sync / async / redirect).\n *\n * @param request - The keyring request to submit.\n * @param request.id - The request ID (unused — a fresh ID is generated internally).\n * @param request.origin - The sender origin.\n * @param request.scope - The CAIP-2 chain ID.\n * @param request.account - The account ID.\n * @param request.request - The inner JSON-RPC request.\n * @param request.request.method - The method to call.\n * @param request.request.params - The method parameters.\n * @returns A promise that resolves to the response.\n */\n async submitRequest(request: {\n id: string;\n origin: string;\n scope: string;\n account: AccountId;\n request: {\n method: string;\n params?: Json[] | Record<string, Json>;\n };\n }): Promise<Json> {\n const account = this.lookupAccount(request.account);\n if (!account) {\n throw new Error(\n `Account '${request.account}' not found in snap '${this.snapId}'`,\n );\n }\n return this.submitSnapRequest({\n origin: request.origin,\n account,\n method: request.request.method as AccountMethod,\n params: request.request.params,\n scope: request.scope,\n noPending: false,\n });\n }\n\n // ──────────────────────────────────────────────\n // Internal API (used by parent SnapKeyring for event handling, routing, etc.)\n // ──────────────────────────────────────────────\n\n /**\n * Upsert an account into the registry.\n *\n * Fires `onRegister` only when the account is new (not already present).\n * Safe to call for updates -- the parent index is already populated in that\n * case and the no-op path avoids a redundant write.\n *\n * @param account - The account to add or update.\n */\n setAccount(account: KeyringAccount): void {\n const isNew = !this.registry.has(account.id);\n this.registry.set(account);\n if (isNew) {\n this.#callbacks.onRegister?.(account.id);\n }\n }\n\n /**\n * Remove an account from the registry.\n *\n * Fires `onUnregister` so the parent can drop the account from its index.\n *\n * @param id - The account ID to remove.\n * @returns `true` if the account was removed, `false` if it was not found.\n */\n removeAccount(id: AccountId): boolean {\n if (!this.registry.has(id)) {\n return false;\n }\n this.registry.delete(id);\n this.#callbacks.onUnregister?.(id);\n return true;\n }\n\n /**\n * Check whether an account exists in this keyring.\n *\n * @param id - The account ID to check.\n * @returns `true` if the account exists.\n */\n hasAccount(id: AccountId): boolean {\n return this.registry.has(id);\n }\n\n /**\n * Get an account by its ID.\n *\n * @param id - The account ID to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupAccount(id: AccountId): KeyringAccount | undefined {\n return this.registry.get(id);\n }\n\n /**\n * Get an account by address (case-insensitive).\n *\n * Performs an O(1) exact lookup first; falls back to a linear scan to\n * handle addresses stored with different casing.\n *\n * @param address - The address to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupByAddress(address: string): KeyringAccount | undefined {\n const id = this.registry.getAccountId(address);\n if (id !== undefined) {\n return this.registry.get(id);\n }\n // The fallback only runs when the exact-match branch above misses,\n // which in practice only happens for EVM addresses with casing\n // differences (checksummed vs lowercase). Non-EVM addresses are\n // case-sensitive and always resolve on the exact branch.\n return this.registry\n .values()\n .find((account) => equalsIgnoreCase(account.address, address));\n }\n\n /**\n * Get all accounts in this keyring (synchronous).\n *\n * This exists alongside the async `getAccounts()` (from `Keyring`) because\n * `SnapKeyring` needs synchronous access for iteration in `serialize`,\n * `listAccounts`, `hasSnapId`, etc. without awaiting.\n *\n * @returns An array of all accounts.\n */\n accounts(): KeyringAccount[] {\n return this.registry.values();\n }\n\n /**\n * Serialize this keyring's state.\n *\n * The returned object uses the internal per-snap format; the parent\n * `SnapKeyring` reconstructs the flat external format in its own\n * `serialize()`.\n *\n * @returns The serialized state.\n */\n async serialize(): Promise<SnapKeyringState> {\n const accounts: SnapKeyringState['accounts'] = {};\n for (const account of this.registry.values()) {\n accounts[account.id] = account;\n }\n const state: SnapKeyringState = {\n snapId: this.snapId,\n accounts,\n };\n return state;\n }\n\n /**\n * Restore this keyring from a serialized state.\n *\n * Validates the payload (accepting both v1 and v2 accounts), migrates any\n * v1 accounts to v2, then replaces the registry. If validation fails, the\n * existing registry is left untouched.\n *\n * @param state - The state to deserialize.\n * @returns A promise that resolves when deserialization is complete.\n */\n async deserialize(state: Json): Promise<void> {\n // Validate the raw payload — accepts both v1 and v2 account shapes.\n assert(state, SnapKeyringStateStruct);\n\n // Bind the keyring to its snap ID (idempotent for the same ID, throws on\n // mismatch to prevent swapping a keyring's identity via deserialize).\n this.bindSnapId(state.snapId as SnapId);\n\n // Migrate v1 accounts to v2.\n const migratedAccounts: Record<string, KeyringAccount> = {};\n for (const [id, rawAccount] of Object.entries(state.accounts)) {\n if (isAccountV1(rawAccount)) {\n console.info(\n `SnapKeyring - Found a KeyringAccountV1, migrating to V2: ${rawAccount.id}`,\n );\n migratedAccounts[id] = migrateAccountV1(rawAccount);\n } else {\n migratedAccounts[id] = rawAccount as KeyringAccount;\n }\n }\n\n // Apply the migrated state to the registry.\n for (const id of [...this.registry.keys()]) {\n this.removeAccount(id);\n }\n\n for (const account of Object.values(migratedAccounts)) {\n this.setAccount(account);\n }\n }\n\n // ──────────────────────────────────────────────\n // Private helpers\n // ──────────────────────────────────────────────\n}\n"]}
1
+ {"version":3,"file":"SnapKeyring.cjs","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":"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","sourcesContent":["import type { KeyringAccount } from '@metamask/keyring-api';\nimport { KeyringAccountStruct } from '@metamask/keyring-api';\nimport type {\n CreateAccountOptions,\n Keyring,\n KeyringCapabilities,\n} from '@metamask/keyring-api/v2';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport type { Infer } from '@metamask/superstruct';\nimport { assert, object, record, string, union } from '@metamask/superstruct';\nimport type { Json } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport {\n KeyringAccountV1Struct,\n normalizeAccount,\n transformAccount,\n} from '../account';\nimport { isAccountV1, migrateAccountV1 } from '../migrations';\nimport { SnapKeyringV1 } from '../SnapKeyringV1';\nimport type {\n AccountMethod,\n SnapKeyringV1Callbacks,\n SnapKeyringV1Options,\n} from '../SnapKeyringV1';\nimport { equalsIgnoreCase } from '../util';\n\n/**\n * Superstruct schema for {@link SnapKeyringState}.\n *\n * Accepts both v1 accounts (missing `scopes`) and v2 accounts so that\n * persisted state can be validated before migration.\n */\nexport const SnapKeyringStateStruct = object({\n snapId: string(),\n accounts: record(\n string(),\n union([KeyringAccountStruct, KeyringAccountV1Struct]),\n ),\n});\n\n/**\n * Serialized state of a single SnapKeyring instance.\n *\n * Note: this is an internal format only used between SnapKeyring and its\n * parent SnapKeyring. The external KeyringState format (flat `{ account,\n * snapId }` map) is preserved by SnapKeyring.serialize / deserialize.\n *\n * Inferred from {@link SnapKeyringStateStruct}: `snapId` is `string`\n * (not the branded `SnapId`) so the shape stays JSON-compatible without\n * unsafe casts.\n */\nexport type SnapKeyringState = Infer<typeof SnapKeyringStateStruct>;\n\n/**\n * Callbacks injected by the parent `SnapKeyring` for global coordination.\n */\nexport type SnapKeyringCallbacks = SnapKeyringV1Callbacks & {\n /**\n * Run a callback under a global lock to prevent TOCTOU races in\n * `createAccounts` when multiple snaps call `assertAccountCanBeUsed`\n * concurrently.\n *\n * Optional: if omitted, `SnapKeyringV2` falls back to its own per-instance\n * `Mutex`, which is sufficient when the keyring is used standalone.\n */\n withLock?: <Result>(callback: () => Promise<Result>) => Promise<Result>;\n};\n\ntype SnapKeyringOptions = Omit<SnapKeyringV1Options, 'callbacks'> & {\n callbacks: SnapKeyringCallbacks;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nexport function isSnapKeyring(keyring: Keyring): keyring is SnapKeyring {\n return keyring.type === KeyringType.Snap;\n}\n\n/**\n * Per-snap keyring wrapper that implements `Keyring`.\n *\n * Extends `SnapKeyringV1` — the v1 event-driven flow (account lifecycle,\n * request handling, asset events) is inherited. This class adds the\n * `KeyringV2` batch interface (`createAccounts`, `deleteAccount`, etc.) and\n * owns the `capabilities` property.\n *\n * The `KeyringAccountRegistry`, snap client, and messenger are all inherited\n * from `SnapKeyringV1` so there is no duplicated state.\n */\nexport class SnapKeyring extends SnapKeyringV1 implements Keyring {\n /**\n * V2-typed view of the callbacks. Stored separately from the V1 private\n * field so that V2-specific callbacks are accessible without casting.\n * Both fields hold the same object reference.\n */\n readonly #callbacks: SnapKeyringCallbacks;\n\n /**\n * Mutex that serializes `createAccounts` calls on this snap instance.\n * Owned here so that each `SnapKeyring` is fully self-contained.\n */\n readonly #lock: Mutex;\n\n // ──────────────────────────────────────────────\n // Keyring properties\n // ──────────────────────────────────────────────\n\n readonly type = `${KeyringType.Snap}` as const;\n\n static readonly type = `${KeyringType.Snap}` as const;\n\n /**\n * Capabilities are snap-specific. Initialized empty and can be updated\n * by the parent when snap metadata becomes available.\n */\n capabilities: KeyringCapabilities;\n\n constructor(options: SnapKeyringOptions) {\n super(options);\n this.#callbacks = options.callbacks;\n this.#lock = new Mutex();\n\n // Default capabilities — parent updates this when snap metadata is available.\n // We cast here because KeyringCapabilities requires a non-empty scopes array,\n // but we don't have the snap metadata at construction time (e.g. during deserialization).\n this.capabilities = { scopes: [] } as unknown as KeyringCapabilities;\n }\n\n /**\n * Destroy this keyring.\n *\n * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending\n * requests inherited from the v1 flow.\n */\n override async destroy(): Promise<void> {\n await super.destroy();\n }\n\n /**\n * Run a callback under the appropriate lock.\n *\n * Prefers the injected `withLock` callback (global lock provided by\n * `SnapKeyring`) so that `createAccounts` calls across different snaps\n * are serialized. Falls back to the per-instance `#lock` when no global\n * lock is provided.g. standalone use in tests).\n *\n * @param callback - Operation to run under the lock.\n * @returns The result of the callback.\n */\n async #withLock<Result>(callback: () => Promise<Result>): Promise<Result> {\n return (\n this.#callbacks.withLock ??\n (async (operation: () => Promise<Result>): Promise<Result> =>\n this.#lock.runExclusive(operation))\n )(callback);\n }\n\n // ──────────────────────────────────────────────\n // Keyring methods\n // ──────────────────────────────────────────────\n\n /**\n * Returns all accounts managed by this keyring.\n *\n * @returns A promise that resolves to an array of all accounts.\n */\n async getAccounts(): Promise<KeyringAccount[]> {\n return this.accounts();\n }\n\n /**\n * Returns the account with the specified ID.\n *\n * @param accountId - ID of the account to retrieve.\n * @returns A promise that resolves to the account.\n */\n async getAccount(accountId: AccountId): Promise<KeyringAccount> {\n const account = this.lookupAccount(accountId);\n if (!account) {\n throw new Error(\n `Account '${accountId}' not found in snap '${this.snapId}'`,\n );\n }\n return account;\n }\n\n /**\n * Creates one or more new accounts according to the provided options.\n *\n * Deterministic account creation MUST be idempotent, meaning that for\n * deterministic algorithms, like BIP-44, calling this method with the same\n * options should always return the same accounts, even if the accounts\n * already exist in the keyring.\n *\n * NOTE: If some accounts are not allowed (non-unique address, unsupported\n * generic account), this method will skip their creation and ask the Snap\n * to remove them from its state.\n *\n * @param options - Options describing how to create the account(s).\n * @returns A promise that resolves to an array of the created account objects.\n */\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<KeyringAccount[]> {\n return this.#withLock(async () => {\n // Keep track of address/account ID part of this batch, to avoid having duplicates.\n const batchAddresses = new Set<string>();\n const batchIds = new Set<string>();\n\n const accounts: KeyringAccount[] = [];\n const newAccounts: KeyringAccount[] = [];\n const snapAccounts = await this.client.createAccounts(options);\n\n try {\n for (const snapAccount of snapAccounts) {\n let account = normalizeAccount(transformAccount(snapAccount));\n const { address } = account;\n\n // Check for idempotency.\n const existingAccount = this.getExistingAccount(account);\n if (existingAccount) {\n // NOTE: We re-use the account from the internal state to avoid having the Snap\n // mutating the account object without updating the map.\n account = existingAccount;\n } else {\n await this.#callbacks.assertAccountCanBeUsed(account);\n\n // Also check for transient accounts that are not yet part of the keyring\n // state.\n if (batchAddresses.has(address) || batchIds.has(account.id)) {\n throw new Error(\n `Account '${account.id}' is already part of this batch (same address or account ID)`,\n );\n }\n batchAddresses.add(address);\n batchIds.add(account.id);\n\n // NOTE: This method does not rely on the `AccountCreated` event to add\n // accounts to the keyring, so we have to add them to the state manually.\n newAccounts.push(account);\n }\n\n // New AND existing accounts are returned to the caller no matter what.\n accounts.push(account);\n }\n\n // We update the keyring state only if needed.\n if (newAccounts.length > 0) {\n for (const account of newAccounts) {\n this.setAccount(account);\n }\n\n // NOTE: We assume this will never fail, thus, we don't need to rollback the\n // keyring state if anything goes wrong here.\n await this.#callbacks.saveState();\n }\n\n return accounts;\n } catch (error) {\n // Rollback Snap state.\n for (const snapAccount of snapAccounts) {\n // Make sure to only delete accounts that were not part of the keyring state.\n if (!this.getExistingAccount(snapAccount)) {\n try {\n await this.client.deleteAccount(snapAccount.id);\n } catch (rollbackError) {\n // Best-effort rollback; log snap-side failures for observability.\n console.error(\n `Account '${snapAccount.id}' may not have been removed from snap '${this.snapId}' during createAccounts rollback:`,\n rollbackError,\n );\n }\n }\n }\n\n throw error;\n }\n });\n }\n\n /**\n * Deletes the account with the specified ID.\n *\n * Removes the account from the local registry (firing `onUnregister` so the\n * parent can update its index), then asks the snap to delete it.\n *\n * @param accountId - ID of the account to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n // Always remove the account from the registry, even if the Snap is going to\n // fail to delete it. removeAccount fires onUnregister to clean #accountIndex.\n this.removeAccount(accountId);\n\n try {\n await this.client.deleteAccount(accountId);\n } catch (error) {\n // If the Snap failed to delete the account, log the error and continue\n // with the account deletion, otherwise the account will be stuck in the\n // keyring.\n console.error(\n `Account '${accountId}' may not have been removed from snap '${this.snapId}':`,\n error,\n );\n }\n }\n\n /**\n * Submits a request to the keyring.\n *\n * Validates that the account belongs to this wrapper, then delegates\n * to the inherited `submitSnapRequest` for the full request lifecycle\n * (sync / async / redirect).\n *\n * @param request - The keyring request to submit.\n * @param request.id - The request ID (unused — a fresh ID is generated internally).\n * @param request.origin - The sender origin.\n * @param request.scope - The CAIP-2 chain ID.\n * @param request.account - The account ID.\n * @param request.request - The inner JSON-RPC request.\n * @param request.request.method - The method to call.\n * @param request.request.params - The method parameters.\n * @returns A promise that resolves to the response.\n */\n async submitRequest(request: {\n id: string;\n origin: string;\n scope: string;\n account: AccountId;\n request: {\n method: string;\n params?: Json[] | Record<string, Json>;\n };\n }): Promise<Json> {\n const account = this.lookupAccount(request.account);\n if (!account) {\n throw new Error(\n `Account '${request.account}' not found in snap '${this.snapId}'`,\n );\n }\n return this.submitSnapRequest({\n origin: request.origin,\n account,\n method: request.request.method as AccountMethod,\n params: request.request.params,\n scope: request.scope,\n noPending: false,\n });\n }\n\n // ──────────────────────────────────────────────\n // Internal API (used by parent SnapKeyring for event handling, routing, etc.)\n // ──────────────────────────────────────────────\n\n /**\n * Upsert an account into the registry.\n *\n * Fires `onRegister` only when the account is new (not already present).\n * Safe to call for updates -- the parent index is already populated in that\n * case and the no-op path avoids a redundant write.\n *\n * @param account - The account to add or update.\n */\n setAccount(account: KeyringAccount): void {\n const isNew = !this.registry.has(account.id);\n this.registry.set(account);\n if (isNew) {\n this.#callbacks.onRegister?.(account.id);\n }\n }\n\n /**\n * Remove an account from the registry.\n *\n * Fires `onUnregister` so the parent can drop the account from its index.\n *\n * @param id - The account ID to remove.\n * @returns `true` if the account was removed, `false` if it was not found.\n */\n removeAccount(id: AccountId): boolean {\n if (!this.registry.has(id)) {\n return false;\n }\n this.registry.delete(id);\n this.#callbacks.onUnregister?.(id);\n return true;\n }\n\n /**\n * Check whether an account exists in this keyring.\n *\n * @param id - The account ID to check.\n * @returns `true` if the account exists.\n */\n hasAccount(id: AccountId): boolean {\n return this.registry.has(id);\n }\n\n /**\n * Get an account by its ID.\n *\n * @param id - The account ID to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupAccount(id: AccountId): KeyringAccount | undefined {\n return this.registry.get(id);\n }\n\n /**\n * Get an account by address (case-insensitive).\n *\n * Performs an O(1) exact lookup first; falls back to a linear scan to\n * handle addresses stored with different casing.\n *\n * @param address - The address to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupByAddress(address: string): KeyringAccount | undefined {\n const id = this.registry.getAccountId(address);\n if (id !== undefined) {\n return this.registry.get(id);\n }\n // The fallback only runs when the exact-match branch above misses,\n // which in practice only happens for EVM addresses with casing\n // differences (checksummed vs lowercase). Non-EVM addresses are\n // case-sensitive and always resolve on the exact branch.\n return this.registry\n .values()\n .find((account) => equalsIgnoreCase(account.address, address));\n }\n\n /**\n * Get all accounts in this keyring (synchronous).\n *\n * This exists alongside the async `getAccounts()` (from `Keyring`) because\n * `SnapKeyring` needs synchronous access for iteration in `serialize`,\n * `listAccounts`, `hasSnapId`, etc. without awaiting.\n *\n * @returns An array of all accounts.\n */\n accounts(): KeyringAccount[] {\n return this.registry.values();\n }\n\n /**\n * Serialize this keyring's state.\n *\n * The returned object uses the internal per-snap format; the parent\n * `SnapKeyring` reconstructs the flat external format in its own\n * `serialize()`.\n *\n * @returns The serialized state.\n */\n async serialize(): Promise<SnapKeyringState> {\n const accounts: SnapKeyringState['accounts'] = {};\n for (const account of this.registry.values()) {\n accounts[account.id] = account;\n }\n const state: SnapKeyringState = {\n snapId: this.snapId,\n accounts,\n };\n return state;\n }\n\n /**\n * Restore this keyring from a serialized state.\n *\n * Validates the payload (accepting both v1 and v2 accounts), migrates any\n * v1 accounts to v2, then replaces the registry. If validation fails, the\n * existing registry is left untouched.\n *\n * @param state - The state to deserialize.\n * @returns A promise that resolves when deserialization is complete.\n */\n async deserialize(state: Json): Promise<void> {\n // Validate the raw payload — accepts both v1 and v2 account shapes.\n assert(state, SnapKeyringStateStruct);\n\n // Bind the keyring to its snap ID (idempotent for the same ID, throws on\n // mismatch to prevent swapping a keyring's identity via deserialize).\n this.bindSnapId(state.snapId as SnapId);\n\n // Migrate v1 accounts to v2.\n const migratedAccounts: Record<string, KeyringAccount> = {};\n for (const [id, rawAccount] of Object.entries(state.accounts)) {\n if (isAccountV1(rawAccount)) {\n console.info(\n `SnapKeyring - Found a KeyringAccountV1, migrating to V2: ${rawAccount.id}`,\n );\n migratedAccounts[id] = migrateAccountV1(rawAccount);\n } else {\n migratedAccounts[id] = rawAccount as KeyringAccount;\n }\n }\n\n // Apply the migrated state to the registry.\n for (const id of [...this.registry.keys()]) {\n this.removeAccount(id);\n }\n\n for (const account of Object.values(migratedAccounts)) {\n this.setAccount(account);\n }\n }\n\n // ──────────────────────────────────────────────\n // Private helpers\n // ──────────────────────────────────────────────\n}\n"]}
@@ -43,12 +43,7 @@ export declare const SnapKeyringStateStruct: import("@metamask/superstruct").Str
43
43
  derivationPath: string;
44
44
  groupIndex: number;
45
45
  } | {
46
- type: "private-key"; /**
47
- * Destroy this keyring.
48
- *
49
- * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending
50
- * requests inherited from the v1 flow.
51
- */
46
+ type: "private-key";
52
47
  } | {
53
48
  type: "custom";
54
49
  };
@@ -88,12 +83,7 @@ export declare const SnapKeyringStateStruct: import("@metamask/superstruct").Str
88
83
  derivationPath: string;
89
84
  groupIndex: number;
90
85
  } | {
91
- type: "private-key"; /**
92
- * Destroy this keyring.
93
- *
94
- * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending
95
- * requests inherited from the v1 flow.
96
- */
86
+ type: "private-key";
97
87
  } | {
98
88
  type: "custom";
99
89
  };
@@ -152,6 +142,7 @@ export declare function isSnapKeyring(keyring: Keyring): keyring is SnapKeyring;
152
142
  export declare class SnapKeyring extends SnapKeyringV1 implements Keyring {
153
143
  #private;
154
144
  readonly type: "snap";
145
+ static readonly type: "snap";
155
146
  /**
156
147
  * Capabilities are snap-specific. Initialized empty and can be updated
157
148
  * by the parent when snap metadata becomes available.
@@ -1 +1 @@
1
- {"version":3,"file":"SnapKeyring.d.cts","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SnapKeyring.d.cts","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":"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"}
@@ -43,12 +43,7 @@ export declare const SnapKeyringStateStruct: import("@metamask/superstruct").Str
43
43
  derivationPath: string;
44
44
  groupIndex: number;
45
45
  } | {
46
- type: "private-key"; /**
47
- * Destroy this keyring.
48
- *
49
- * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending
50
- * requests inherited from the v1 flow.
51
- */
46
+ type: "private-key";
52
47
  } | {
53
48
  type: "custom";
54
49
  };
@@ -88,12 +83,7 @@ export declare const SnapKeyringStateStruct: import("@metamask/superstruct").Str
88
83
  derivationPath: string;
89
84
  groupIndex: number;
90
85
  } | {
91
- type: "private-key"; /**
92
- * Destroy this keyring.
93
- *
94
- * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending
95
- * requests inherited from the v1 flow.
96
- */
86
+ type: "private-key";
97
87
  } | {
98
88
  type: "custom";
99
89
  };
@@ -152,6 +142,7 @@ export declare function isSnapKeyring(keyring: Keyring): keyring is SnapKeyring;
152
142
  export declare class SnapKeyring extends SnapKeyringV1 implements Keyring {
153
143
  #private;
154
144
  readonly type: "snap";
145
+ static readonly type: "snap";
155
146
  /**
156
147
  * Capabilities are snap-specific. Initialized empty and can be updated
157
148
  * by the parent when snap metadata becomes available.
@@ -1 +1 @@
1
- {"version":3,"file":"SnapKeyring.d.mts","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SnapKeyring.d.mts","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":"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"}
@@ -398,4 +398,5 @@ async function _SnapKeyring_withLock(callback) {
398
398
  return (__classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").withLock ??
399
399
  (async (operation) => __classPrivateFieldGet(this, _SnapKeyring_lock, "f").runExclusive(operation)))(callback);
400
400
  };
401
+ SnapKeyring.type = `${KeyringType.Snap}`;
401
402
  //# sourceMappingURL=SnapKeyring.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SnapKeyring.mjs","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":"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","sourcesContent":["import type { KeyringAccount } from '@metamask/keyring-api';\nimport { KeyringAccountStruct } from '@metamask/keyring-api';\nimport type {\n CreateAccountOptions,\n Keyring,\n KeyringCapabilities,\n} from '@metamask/keyring-api/v2';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport type { Infer } from '@metamask/superstruct';\nimport { assert, object, record, string, union } from '@metamask/superstruct';\nimport type { Json } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport {\n KeyringAccountV1Struct,\n normalizeAccount,\n transformAccount,\n} from '../account';\nimport { isAccountV1, migrateAccountV1 } from '../migrations';\nimport { SnapKeyringV1 } from '../SnapKeyringV1';\nimport type {\n AccountMethod,\n SnapKeyringV1Callbacks,\n SnapKeyringV1Options,\n} from '../SnapKeyringV1';\nimport { equalsIgnoreCase } from '../util';\n\n/**\n * Superstruct schema for {@link SnapKeyringState}.\n *\n * Accepts both v1 accounts (missing `scopes`) and v2 accounts so that\n * persisted state can be validated before migration.\n */\nexport const SnapKeyringStateStruct = object({\n snapId: string(),\n accounts: record(\n string(),\n union([KeyringAccountStruct, KeyringAccountV1Struct]),\n ),\n});\n\n/**\n * Serialized state of a single SnapKeyring instance.\n *\n * Note: this is an internal format only used between SnapKeyring and its\n * parent SnapKeyring. The external KeyringState format (flat `{ account,\n * snapId }` map) is preserved by SnapKeyring.serialize / deserialize.\n *\n * Inferred from {@link SnapKeyringStateStruct}: `snapId` is `string`\n * (not the branded `SnapId`) so the shape stays JSON-compatible without\n * unsafe casts.\n */\nexport type SnapKeyringState = Infer<typeof SnapKeyringStateStruct>;\n\n/**\n * Callbacks injected by the parent `SnapKeyring` for global coordination.\n */\nexport type SnapKeyringCallbacks = SnapKeyringV1Callbacks & {\n /**\n * Run a callback under a global lock to prevent TOCTOU races in\n * `createAccounts` when multiple snaps call `assertAccountCanBeUsed`\n * concurrently.\n *\n * Optional: if omitted, `SnapKeyringV2` falls back to its own per-instance\n * `Mutex`, which is sufficient when the keyring is used standalone.\n */\n withLock?: <Result>(callback: () => Promise<Result>) => Promise<Result>;\n};\n\ntype SnapKeyringOptions = Omit<SnapKeyringV1Options, 'callbacks'> & {\n callbacks: SnapKeyringCallbacks;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nexport function isSnapKeyring(keyring: Keyring): keyring is SnapKeyring {\n return keyring.type === KeyringType.Snap;\n}\n\n/**\n * Per-snap keyring wrapper that implements `Keyring`.\n *\n * Extends `SnapKeyringV1` — the v1 event-driven flow (account lifecycle,\n * request handling, asset events) is inherited. This class adds the\n * `KeyringV2` batch interface (`createAccounts`, `deleteAccount`, etc.) and\n * owns the `capabilities` property.\n *\n * The `KeyringAccountRegistry`, snap client, and messenger are all inherited\n * from `SnapKeyringV1` so there is no duplicated state.\n */\nexport class SnapKeyring extends SnapKeyringV1 implements Keyring {\n /**\n * V2-typed view of the callbacks. Stored separately from the V1 private\n * field so that V2-specific callbacks are accessible without casting.\n * Both fields hold the same object reference.\n */\n readonly #callbacks: SnapKeyringCallbacks;\n\n /**\n * Mutex that serializes `createAccounts` calls on this snap instance.\n * Owned here so that each `SnapKeyring` is fully self-contained.\n */\n readonly #lock: Mutex;\n\n // ──────────────────────────────────────────────\n // Keyring properties\n // ──────────────────────────────────────────────\n\n readonly type = `${KeyringType.Snap}` as const;\n\n /**\n * Capabilities are snap-specific. Initialized empty and can be updated\n * by the parent when snap metadata becomes available.\n */\n capabilities: KeyringCapabilities;\n\n constructor(options: SnapKeyringOptions) {\n super(options);\n this.#callbacks = options.callbacks;\n this.#lock = new Mutex();\n\n // Default capabilities — parent updates this when snap metadata is available.\n // We cast here because KeyringCapabilities requires a non-empty scopes array,\n // but we don't have the snap metadata at construction time (e.g. during deserialization).\n this.capabilities = { scopes: [] } as unknown as KeyringCapabilities;\n }\n\n /**\n * Destroy this keyring.\n *\n * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending\n * requests inherited from the v1 flow.\n */\n override async destroy(): Promise<void> {\n await super.destroy();\n }\n\n /**\n * Run a callback under the appropriate lock.\n *\n * Prefers the injected `withLock` callback (global lock provided by\n * `SnapKeyring`) so that `createAccounts` calls across different snaps\n * are serialized. Falls back to the per-instance `#lock` when no global\n * lock is provided.g. standalone use in tests).\n *\n * @param callback - Operation to run under the lock.\n * @returns The result of the callback.\n */\n async #withLock<Result>(callback: () => Promise<Result>): Promise<Result> {\n return (\n this.#callbacks.withLock ??\n (async (operation: () => Promise<Result>): Promise<Result> =>\n this.#lock.runExclusive(operation))\n )(callback);\n }\n\n // ──────────────────────────────────────────────\n // Keyring methods\n // ──────────────────────────────────────────────\n\n /**\n * Returns all accounts managed by this keyring.\n *\n * @returns A promise that resolves to an array of all accounts.\n */\n async getAccounts(): Promise<KeyringAccount[]> {\n return this.accounts();\n }\n\n /**\n * Returns the account with the specified ID.\n *\n * @param accountId - ID of the account to retrieve.\n * @returns A promise that resolves to the account.\n */\n async getAccount(accountId: AccountId): Promise<KeyringAccount> {\n const account = this.lookupAccount(accountId);\n if (!account) {\n throw new Error(\n `Account '${accountId}' not found in snap '${this.snapId}'`,\n );\n }\n return account;\n }\n\n /**\n * Creates one or more new accounts according to the provided options.\n *\n * Deterministic account creation MUST be idempotent, meaning that for\n * deterministic algorithms, like BIP-44, calling this method with the same\n * options should always return the same accounts, even if the accounts\n * already exist in the keyring.\n *\n * NOTE: If some accounts are not allowed (non-unique address, unsupported\n * generic account), this method will skip their creation and ask the Snap\n * to remove them from its state.\n *\n * @param options - Options describing how to create the account(s).\n * @returns A promise that resolves to an array of the created account objects.\n */\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<KeyringAccount[]> {\n return this.#withLock(async () => {\n // Keep track of address/account ID part of this batch, to avoid having duplicates.\n const batchAddresses = new Set<string>();\n const batchIds = new Set<string>();\n\n const accounts: KeyringAccount[] = [];\n const newAccounts: KeyringAccount[] = [];\n const snapAccounts = await this.client.createAccounts(options);\n\n try {\n for (const snapAccount of snapAccounts) {\n let account = normalizeAccount(transformAccount(snapAccount));\n const { address } = account;\n\n // Check for idempotency.\n const existingAccount = this.getExistingAccount(account);\n if (existingAccount) {\n // NOTE: We re-use the account from the internal state to avoid having the Snap\n // mutating the account object without updating the map.\n account = existingAccount;\n } else {\n await this.#callbacks.assertAccountCanBeUsed(account);\n\n // Also check for transient accounts that are not yet part of the keyring\n // state.\n if (batchAddresses.has(address) || batchIds.has(account.id)) {\n throw new Error(\n `Account '${account.id}' is already part of this batch (same address or account ID)`,\n );\n }\n batchAddresses.add(address);\n batchIds.add(account.id);\n\n // NOTE: This method does not rely on the `AccountCreated` event to add\n // accounts to the keyring, so we have to add them to the state manually.\n newAccounts.push(account);\n }\n\n // New AND existing accounts are returned to the caller no matter what.\n accounts.push(account);\n }\n\n // We update the keyring state only if needed.\n if (newAccounts.length > 0) {\n for (const account of newAccounts) {\n this.setAccount(account);\n }\n\n // NOTE: We assume this will never fail, thus, we don't need to rollback the\n // keyring state if anything goes wrong here.\n await this.#callbacks.saveState();\n }\n\n return accounts;\n } catch (error) {\n // Rollback Snap state.\n for (const snapAccount of snapAccounts) {\n // Make sure to only delete accounts that were not part of the keyring state.\n if (!this.getExistingAccount(snapAccount)) {\n try {\n await this.client.deleteAccount(snapAccount.id);\n } catch (rollbackError) {\n // Best-effort rollback; log snap-side failures for observability.\n console.error(\n `Account '${snapAccount.id}' may not have been removed from snap '${this.snapId}' during createAccounts rollback:`,\n rollbackError,\n );\n }\n }\n }\n\n throw error;\n }\n });\n }\n\n /**\n * Deletes the account with the specified ID.\n *\n * Removes the account from the local registry (firing `onUnregister` so the\n * parent can update its index), then asks the snap to delete it.\n *\n * @param accountId - ID of the account to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n // Always remove the account from the registry, even if the Snap is going to\n // fail to delete it. removeAccount fires onUnregister to clean #accountIndex.\n this.removeAccount(accountId);\n\n try {\n await this.client.deleteAccount(accountId);\n } catch (error) {\n // If the Snap failed to delete the account, log the error and continue\n // with the account deletion, otherwise the account will be stuck in the\n // keyring.\n console.error(\n `Account '${accountId}' may not have been removed from snap '${this.snapId}':`,\n error,\n );\n }\n }\n\n /**\n * Submits a request to the keyring.\n *\n * Validates that the account belongs to this wrapper, then delegates\n * to the inherited `submitSnapRequest` for the full request lifecycle\n * (sync / async / redirect).\n *\n * @param request - The keyring request to submit.\n * @param request.id - The request ID (unused — a fresh ID is generated internally).\n * @param request.origin - The sender origin.\n * @param request.scope - The CAIP-2 chain ID.\n * @param request.account - The account ID.\n * @param request.request - The inner JSON-RPC request.\n * @param request.request.method - The method to call.\n * @param request.request.params - The method parameters.\n * @returns A promise that resolves to the response.\n */\n async submitRequest(request: {\n id: string;\n origin: string;\n scope: string;\n account: AccountId;\n request: {\n method: string;\n params?: Json[] | Record<string, Json>;\n };\n }): Promise<Json> {\n const account = this.lookupAccount(request.account);\n if (!account) {\n throw new Error(\n `Account '${request.account}' not found in snap '${this.snapId}'`,\n );\n }\n return this.submitSnapRequest({\n origin: request.origin,\n account,\n method: request.request.method as AccountMethod,\n params: request.request.params,\n scope: request.scope,\n noPending: false,\n });\n }\n\n // ──────────────────────────────────────────────\n // Internal API (used by parent SnapKeyring for event handling, routing, etc.)\n // ──────────────────────────────────────────────\n\n /**\n * Upsert an account into the registry.\n *\n * Fires `onRegister` only when the account is new (not already present).\n * Safe to call for updates -- the parent index is already populated in that\n * case and the no-op path avoids a redundant write.\n *\n * @param account - The account to add or update.\n */\n setAccount(account: KeyringAccount): void {\n const isNew = !this.registry.has(account.id);\n this.registry.set(account);\n if (isNew) {\n this.#callbacks.onRegister?.(account.id);\n }\n }\n\n /**\n * Remove an account from the registry.\n *\n * Fires `onUnregister` so the parent can drop the account from its index.\n *\n * @param id - The account ID to remove.\n * @returns `true` if the account was removed, `false` if it was not found.\n */\n removeAccount(id: AccountId): boolean {\n if (!this.registry.has(id)) {\n return false;\n }\n this.registry.delete(id);\n this.#callbacks.onUnregister?.(id);\n return true;\n }\n\n /**\n * Check whether an account exists in this keyring.\n *\n * @param id - The account ID to check.\n * @returns `true` if the account exists.\n */\n hasAccount(id: AccountId): boolean {\n return this.registry.has(id);\n }\n\n /**\n * Get an account by its ID.\n *\n * @param id - The account ID to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupAccount(id: AccountId): KeyringAccount | undefined {\n return this.registry.get(id);\n }\n\n /**\n * Get an account by address (case-insensitive).\n *\n * Performs an O(1) exact lookup first; falls back to a linear scan to\n * handle addresses stored with different casing.\n *\n * @param address - The address to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupByAddress(address: string): KeyringAccount | undefined {\n const id = this.registry.getAccountId(address);\n if (id !== undefined) {\n return this.registry.get(id);\n }\n // The fallback only runs when the exact-match branch above misses,\n // which in practice only happens for EVM addresses with casing\n // differences (checksummed vs lowercase). Non-EVM addresses are\n // case-sensitive and always resolve on the exact branch.\n return this.registry\n .values()\n .find((account) => equalsIgnoreCase(account.address, address));\n }\n\n /**\n * Get all accounts in this keyring (synchronous).\n *\n * This exists alongside the async `getAccounts()` (from `Keyring`) because\n * `SnapKeyring` needs synchronous access for iteration in `serialize`,\n * `listAccounts`, `hasSnapId`, etc. without awaiting.\n *\n * @returns An array of all accounts.\n */\n accounts(): KeyringAccount[] {\n return this.registry.values();\n }\n\n /**\n * Serialize this keyring's state.\n *\n * The returned object uses the internal per-snap format; the parent\n * `SnapKeyring` reconstructs the flat external format in its own\n * `serialize()`.\n *\n * @returns The serialized state.\n */\n async serialize(): Promise<SnapKeyringState> {\n const accounts: SnapKeyringState['accounts'] = {};\n for (const account of this.registry.values()) {\n accounts[account.id] = account;\n }\n const state: SnapKeyringState = {\n snapId: this.snapId,\n accounts,\n };\n return state;\n }\n\n /**\n * Restore this keyring from a serialized state.\n *\n * Validates the payload (accepting both v1 and v2 accounts), migrates any\n * v1 accounts to v2, then replaces the registry. If validation fails, the\n * existing registry is left untouched.\n *\n * @param state - The state to deserialize.\n * @returns A promise that resolves when deserialization is complete.\n */\n async deserialize(state: Json): Promise<void> {\n // Validate the raw payload — accepts both v1 and v2 account shapes.\n assert(state, SnapKeyringStateStruct);\n\n // Bind the keyring to its snap ID (idempotent for the same ID, throws on\n // mismatch to prevent swapping a keyring's identity via deserialize).\n this.bindSnapId(state.snapId as SnapId);\n\n // Migrate v1 accounts to v2.\n const migratedAccounts: Record<string, KeyringAccount> = {};\n for (const [id, rawAccount] of Object.entries(state.accounts)) {\n if (isAccountV1(rawAccount)) {\n console.info(\n `SnapKeyring - Found a KeyringAccountV1, migrating to V2: ${rawAccount.id}`,\n );\n migratedAccounts[id] = migrateAccountV1(rawAccount);\n } else {\n migratedAccounts[id] = rawAccount as KeyringAccount;\n }\n }\n\n // Apply the migrated state to the registry.\n for (const id of [...this.registry.keys()]) {\n this.removeAccount(id);\n }\n\n for (const account of Object.values(migratedAccounts)) {\n this.setAccount(account);\n }\n }\n\n // ──────────────────────────────────────────────\n // Private helpers\n // ──────────────────────────────────────────────\n}\n"]}
1
+ {"version":3,"file":"SnapKeyring.mjs","sourceRoot":"","sources":["../../src/v2/SnapKeyring.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,OAAO,EAAE,oBAAoB,EAAE,8BAA8B;AAM7D,OAAO,EAAE,WAAW,EAAE,iCAAiC;AAIvD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,8BAA8B;AAE9E,OAAO,EAAE,KAAK,EAAE,oBAAoB;AAEpC,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EACjB,uBAAmB;AACpB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,gCAAsB;AAC9D,OAAO,EAAE,aAAa,EAAE,6BAAyB;AAMjD,OAAO,EAAE,gBAAgB,EAAE,oBAAgB;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;IAC3C,MAAM,EAAE,MAAM,EAAE;IAChB,QAAQ,EAAE,MAAM,CACd,MAAM,EAAE,EACR,KAAK,CAAC,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC,CACtD;CACF,CAAC,CAAC;AAkCH;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,WAAY,SAAQ,aAAa;IA4B5C,YAAY,OAA2B;QACrC,KAAK,CAAC,OAAO,CAAC,CAAC;;QA5BjB;;;;WAIG;QACM,yCAAiC;QAE1C;;;WAGG;QACM,oCAAa;QAEtB,iDAAiD;QACjD,qBAAqB;QACrB,iDAAiD;QAExC,SAAI,GAAG,GAAG,WAAW,CAAC,IAAI,EAAW,CAAC;QAY7C,uBAAA,IAAI,0BAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,qBAAS,IAAI,KAAK,EAAE,MAAA,CAAC;QAEzB,8EAA8E;QAC9E,8EAA8E;QAC9E,0FAA0F;QAC1F,IAAI,CAAC,YAAY,GAAG,EAAE,MAAM,EAAE,EAAE,EAAoC,CAAC;IACvE,CAAC;IAED;;;;;OAKG;IACM,KAAK,CAAC,OAAO;QACpB,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAqBD,iDAAiD;IACjD,kBAAkB;IAClB,iDAAiD;IAEjD;;;;OAIG;IACH,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IACzB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,UAAU,CAAC,SAAoB;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,YAAY,SAAS,wBAAwB,IAAI,CAAC,MAAM,GAAG,CAC5D,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,cAAc,CAClB,OAA6B;QAE7B,OAAO,uBAAA,IAAI,qDAAU,MAAd,IAAI,EAAW,KAAK,IAAI,EAAE;YAC/B,mFAAmF;YACnF,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;YAEnC,MAAM,QAAQ,GAAqB,EAAE,CAAC;YACtC,MAAM,WAAW,GAAqB,EAAE,CAAC;YACzC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAE/D,IAAI,CAAC;gBACH,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;oBACvC,IAAI,OAAO,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC;oBAC9D,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;oBAE5B,yBAAyB;oBACzB,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;oBACzD,IAAI,eAAe,EAAE,CAAC;wBACpB,+EAA+E;wBAC/E,wDAAwD;wBACxD,OAAO,GAAG,eAAe,CAAC;oBAC5B,CAAC;yBAAM,CAAC;wBACN,MAAM,uBAAA,IAAI,8BAAW,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;wBAEtD,yEAAyE;wBACzE,SAAS;wBACT,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;4BAC5D,MAAM,IAAI,KAAK,CACb,YAAY,OAAO,CAAC,EAAE,8DAA8D,CACrF,CAAC;wBACJ,CAAC;wBACD,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;wBAC5B,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;wBAEzB,uEAAuE;wBACvE,yEAAyE;wBACzE,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC5B,CAAC;oBAED,uEAAuE;oBACvE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACzB,CAAC;gBAED,8CAA8C;gBAC9C,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC3B,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;wBAClC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;oBAC3B,CAAC;oBAED,4EAA4E;oBAC5E,6CAA6C;oBAC7C,MAAM,uBAAA,IAAI,8BAAW,CAAC,SAAS,EAAE,CAAC;gBACpC,CAAC;gBAED,OAAO,QAAQ,CAAC;YAClB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,uBAAuB;gBACvB,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;oBACvC,6EAA6E;oBAC7E,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;wBAC1C,IAAI,CAAC;4BACH,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;wBAClD,CAAC;wBAAC,OAAO,aAAa,EAAE,CAAC;4BACvB,kEAAkE;4BAClE,OAAO,CAAC,KAAK,CACX,YAAY,WAAW,CAAC,EAAE,0CAA0C,IAAI,CAAC,MAAM,mCAAmC,EAClH,aAAa,CACd,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,aAAa,CAAC,SAAoB;QACtC,4EAA4E;QAC5E,8EAA8E;QAC9E,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAE9B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,uEAAuE;YACvE,wEAAwE;YACxE,WAAW;YACX,OAAO,CAAC,KAAK,CACX,YAAY,SAAS,0CAA0C,IAAI,CAAC,MAAM,IAAI,EAC9E,KAAK,CACN,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,aAAa,CAAC,OASnB;QACC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,YAAY,OAAO,CAAC,OAAO,wBAAwB,IAAI,CAAC,MAAM,GAAG,CAClE,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC;YAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO;YACP,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAuB;YAC/C,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC;IAED,iDAAiD;IACjD,8EAA8E;IAC9E,iDAAiD;IAEjD;;;;;;;;OAQG;IACH,UAAU,CAAC,OAAuB;QAChC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,KAAK,EAAE,CAAC;YACV,uBAAA,IAAI,8BAAW,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,aAAa,CAAC,EAAa;QACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,uBAAA,IAAI,8BAAW,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,EAAa;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,EAAa;QACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED;;;;;;;;OAQG;IACH,eAAe,CAAC,OAAe;QAC7B,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC;QACD,mEAAmE;QACnE,+DAA+D;QAC/D,gEAAgE;QAChE,yDAAyD;QACzD,OAAO,IAAI,CAAC,QAAQ;aACjB,MAAM,EAAE;aACR,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACnE,CAAC;IAED;;;;;;;;OAQG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IAChC,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,QAAQ,GAAiC,EAAE,CAAC;QAClD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;QACjC,CAAC;QACD,MAAM,KAAK,GAAqB;YAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ;SACT,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,WAAW,CAAC,KAAW;QAC3B,oEAAoE;QACpE,MAAM,CAAC,KAAK,EAAE,sBAAsB,CAAC,CAAC;QAEtC,yEAAyE;QACzE,sEAAsE;QACtE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAgB,CAAC,CAAC;QAExC,6BAA6B;QAC7B,MAAM,gBAAgB,GAAmC,EAAE,CAAC;QAC5D,KAAK,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9D,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,IAAI,CACV,4DAA4D,UAAU,CAAC,EAAE,EAAE,CAC5E,CAAC;gBACF,gBAAgB,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACN,gBAAgB,CAAC,EAAE,CAAC,GAAG,UAA4B,CAAC;YACtD,CAAC;QACH,CAAC;QAED,4CAA4C;QAC5C,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;;;AA7WD;;;;;;;;;;GAUG;AACH,KAAK,gCAAmB,QAA+B;IACrD,OAAO,CACL,uBAAA,IAAI,8BAAW,CAAC,QAAQ;QACxB,CAAC,KAAK,EAAE,SAAgC,EAAmB,EAAE,CAC3D,uBAAA,IAAI,yBAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CACtC,CAAC,QAAQ,CAAC,CAAC;AACd,CAAC;AA9Ce,gBAAI,GAAG,GAAG,WAAW,CAAC,IAAI,EAAW,AAAjC,CAAkC","sourcesContent":["import type { KeyringAccount } from '@metamask/keyring-api';\nimport { KeyringAccountStruct } from '@metamask/keyring-api';\nimport type {\n CreateAccountOptions,\n Keyring,\n KeyringCapabilities,\n} from '@metamask/keyring-api/v2';\nimport { KeyringType } from '@metamask/keyring-api/v2';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport type { Infer } from '@metamask/superstruct';\nimport { assert, object, record, string, union } from '@metamask/superstruct';\nimport type { Json } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport {\n KeyringAccountV1Struct,\n normalizeAccount,\n transformAccount,\n} from '../account';\nimport { isAccountV1, migrateAccountV1 } from '../migrations';\nimport { SnapKeyringV1 } from '../SnapKeyringV1';\nimport type {\n AccountMethod,\n SnapKeyringV1Callbacks,\n SnapKeyringV1Options,\n} from '../SnapKeyringV1';\nimport { equalsIgnoreCase } from '../util';\n\n/**\n * Superstruct schema for {@link SnapKeyringState}.\n *\n * Accepts both v1 accounts (missing `scopes`) and v2 accounts so that\n * persisted state can be validated before migration.\n */\nexport const SnapKeyringStateStruct = object({\n snapId: string(),\n accounts: record(\n string(),\n union([KeyringAccountStruct, KeyringAccountV1Struct]),\n ),\n});\n\n/**\n * Serialized state of a single SnapKeyring instance.\n *\n * Note: this is an internal format only used between SnapKeyring and its\n * parent SnapKeyring. The external KeyringState format (flat `{ account,\n * snapId }` map) is preserved by SnapKeyring.serialize / deserialize.\n *\n * Inferred from {@link SnapKeyringStateStruct}: `snapId` is `string`\n * (not the branded `SnapId`) so the shape stays JSON-compatible without\n * unsafe casts.\n */\nexport type SnapKeyringState = Infer<typeof SnapKeyringStateStruct>;\n\n/**\n * Callbacks injected by the parent `SnapKeyring` for global coordination.\n */\nexport type SnapKeyringCallbacks = SnapKeyringV1Callbacks & {\n /**\n * Run a callback under a global lock to prevent TOCTOU races in\n * `createAccounts` when multiple snaps call `assertAccountCanBeUsed`\n * concurrently.\n *\n * Optional: if omitted, `SnapKeyringV2` falls back to its own per-instance\n * `Mutex`, which is sufficient when the keyring is used standalone.\n */\n withLock?: <Result>(callback: () => Promise<Result>) => Promise<Result>;\n};\n\ntype SnapKeyringOptions = Omit<SnapKeyringV1Options, 'callbacks'> & {\n callbacks: SnapKeyringCallbacks;\n};\n\n/**\n * Checks if a given keyring is a Snap keyring (v2).\n *\n * @param keyring - The keyring to check.\n * @returns `true` if the keyring is a Snap keyring (v2), `false` otherwise.\n */\nexport function isSnapKeyring(keyring: Keyring): keyring is SnapKeyring {\n return keyring.type === KeyringType.Snap;\n}\n\n/**\n * Per-snap keyring wrapper that implements `Keyring`.\n *\n * Extends `SnapKeyringV1` — the v1 event-driven flow (account lifecycle,\n * request handling, asset events) is inherited. This class adds the\n * `KeyringV2` batch interface (`createAccounts`, `deleteAccount`, etc.) and\n * owns the `capabilities` property.\n *\n * The `KeyringAccountRegistry`, snap client, and messenger are all inherited\n * from `SnapKeyringV1` so there is no duplicated state.\n */\nexport class SnapKeyring extends SnapKeyringV1 implements Keyring {\n /**\n * V2-typed view of the callbacks. Stored separately from the V1 private\n * field so that V2-specific callbacks are accessible without casting.\n * Both fields hold the same object reference.\n */\n readonly #callbacks: SnapKeyringCallbacks;\n\n /**\n * Mutex that serializes `createAccounts` calls on this snap instance.\n * Owned here so that each `SnapKeyring` is fully self-contained.\n */\n readonly #lock: Mutex;\n\n // ──────────────────────────────────────────────\n // Keyring properties\n // ──────────────────────────────────────────────\n\n readonly type = `${KeyringType.Snap}` as const;\n\n static readonly type = `${KeyringType.Snap}` as const;\n\n /**\n * Capabilities are snap-specific. Initialized empty and can be updated\n * by the parent when snap metadata becomes available.\n */\n capabilities: KeyringCapabilities;\n\n constructor(options: SnapKeyringOptions) {\n super(options);\n this.#callbacks = options.callbacks;\n this.#lock = new Mutex();\n\n // Default capabilities — parent updates this when snap metadata is available.\n // We cast here because KeyringCapabilities requires a non-empty scopes array,\n // but we don't have the snap metadata at construction time (e.g. during deserialization).\n this.capabilities = { scopes: [] } as unknown as KeyringCapabilities;\n }\n\n /**\n * Destroy this keyring.\n *\n * Delegates to the parent `SnapKeyringV1.destroy()` to reject any pending\n * requests inherited from the v1 flow.\n */\n override async destroy(): Promise<void> {\n await super.destroy();\n }\n\n /**\n * Run a callback under the appropriate lock.\n *\n * Prefers the injected `withLock` callback (global lock provided by\n * `SnapKeyring`) so that `createAccounts` calls across different snaps\n * are serialized. Falls back to the per-instance `#lock` when no global\n * lock is provided.g. standalone use in tests).\n *\n * @param callback - Operation to run under the lock.\n * @returns The result of the callback.\n */\n async #withLock<Result>(callback: () => Promise<Result>): Promise<Result> {\n return (\n this.#callbacks.withLock ??\n (async (operation: () => Promise<Result>): Promise<Result> =>\n this.#lock.runExclusive(operation))\n )(callback);\n }\n\n // ──────────────────────────────────────────────\n // Keyring methods\n // ──────────────────────────────────────────────\n\n /**\n * Returns all accounts managed by this keyring.\n *\n * @returns A promise that resolves to an array of all accounts.\n */\n async getAccounts(): Promise<KeyringAccount[]> {\n return this.accounts();\n }\n\n /**\n * Returns the account with the specified ID.\n *\n * @param accountId - ID of the account to retrieve.\n * @returns A promise that resolves to the account.\n */\n async getAccount(accountId: AccountId): Promise<KeyringAccount> {\n const account = this.lookupAccount(accountId);\n if (!account) {\n throw new Error(\n `Account '${accountId}' not found in snap '${this.snapId}'`,\n );\n }\n return account;\n }\n\n /**\n * Creates one or more new accounts according to the provided options.\n *\n * Deterministic account creation MUST be idempotent, meaning that for\n * deterministic algorithms, like BIP-44, calling this method with the same\n * options should always return the same accounts, even if the accounts\n * already exist in the keyring.\n *\n * NOTE: If some accounts are not allowed (non-unique address, unsupported\n * generic account), this method will skip their creation and ask the Snap\n * to remove them from its state.\n *\n * @param options - Options describing how to create the account(s).\n * @returns A promise that resolves to an array of the created account objects.\n */\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<KeyringAccount[]> {\n return this.#withLock(async () => {\n // Keep track of address/account ID part of this batch, to avoid having duplicates.\n const batchAddresses = new Set<string>();\n const batchIds = new Set<string>();\n\n const accounts: KeyringAccount[] = [];\n const newAccounts: KeyringAccount[] = [];\n const snapAccounts = await this.client.createAccounts(options);\n\n try {\n for (const snapAccount of snapAccounts) {\n let account = normalizeAccount(transformAccount(snapAccount));\n const { address } = account;\n\n // Check for idempotency.\n const existingAccount = this.getExistingAccount(account);\n if (existingAccount) {\n // NOTE: We re-use the account from the internal state to avoid having the Snap\n // mutating the account object without updating the map.\n account = existingAccount;\n } else {\n await this.#callbacks.assertAccountCanBeUsed(account);\n\n // Also check for transient accounts that are not yet part of the keyring\n // state.\n if (batchAddresses.has(address) || batchIds.has(account.id)) {\n throw new Error(\n `Account '${account.id}' is already part of this batch (same address or account ID)`,\n );\n }\n batchAddresses.add(address);\n batchIds.add(account.id);\n\n // NOTE: This method does not rely on the `AccountCreated` event to add\n // accounts to the keyring, so we have to add them to the state manually.\n newAccounts.push(account);\n }\n\n // New AND existing accounts are returned to the caller no matter what.\n accounts.push(account);\n }\n\n // We update the keyring state only if needed.\n if (newAccounts.length > 0) {\n for (const account of newAccounts) {\n this.setAccount(account);\n }\n\n // NOTE: We assume this will never fail, thus, we don't need to rollback the\n // keyring state if anything goes wrong here.\n await this.#callbacks.saveState();\n }\n\n return accounts;\n } catch (error) {\n // Rollback Snap state.\n for (const snapAccount of snapAccounts) {\n // Make sure to only delete accounts that were not part of the keyring state.\n if (!this.getExistingAccount(snapAccount)) {\n try {\n await this.client.deleteAccount(snapAccount.id);\n } catch (rollbackError) {\n // Best-effort rollback; log snap-side failures for observability.\n console.error(\n `Account '${snapAccount.id}' may not have been removed from snap '${this.snapId}' during createAccounts rollback:`,\n rollbackError,\n );\n }\n }\n }\n\n throw error;\n }\n });\n }\n\n /**\n * Deletes the account with the specified ID.\n *\n * Removes the account from the local registry (firing `onUnregister` so the\n * parent can update its index), then asks the snap to delete it.\n *\n * @param accountId - ID of the account to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n // Always remove the account from the registry, even if the Snap is going to\n // fail to delete it. removeAccount fires onUnregister to clean #accountIndex.\n this.removeAccount(accountId);\n\n try {\n await this.client.deleteAccount(accountId);\n } catch (error) {\n // If the Snap failed to delete the account, log the error and continue\n // with the account deletion, otherwise the account will be stuck in the\n // keyring.\n console.error(\n `Account '${accountId}' may not have been removed from snap '${this.snapId}':`,\n error,\n );\n }\n }\n\n /**\n * Submits a request to the keyring.\n *\n * Validates that the account belongs to this wrapper, then delegates\n * to the inherited `submitSnapRequest` for the full request lifecycle\n * (sync / async / redirect).\n *\n * @param request - The keyring request to submit.\n * @param request.id - The request ID (unused — a fresh ID is generated internally).\n * @param request.origin - The sender origin.\n * @param request.scope - The CAIP-2 chain ID.\n * @param request.account - The account ID.\n * @param request.request - The inner JSON-RPC request.\n * @param request.request.method - The method to call.\n * @param request.request.params - The method parameters.\n * @returns A promise that resolves to the response.\n */\n async submitRequest(request: {\n id: string;\n origin: string;\n scope: string;\n account: AccountId;\n request: {\n method: string;\n params?: Json[] | Record<string, Json>;\n };\n }): Promise<Json> {\n const account = this.lookupAccount(request.account);\n if (!account) {\n throw new Error(\n `Account '${request.account}' not found in snap '${this.snapId}'`,\n );\n }\n return this.submitSnapRequest({\n origin: request.origin,\n account,\n method: request.request.method as AccountMethod,\n params: request.request.params,\n scope: request.scope,\n noPending: false,\n });\n }\n\n // ──────────────────────────────────────────────\n // Internal API (used by parent SnapKeyring for event handling, routing, etc.)\n // ──────────────────────────────────────────────\n\n /**\n * Upsert an account into the registry.\n *\n * Fires `onRegister` only when the account is new (not already present).\n * Safe to call for updates -- the parent index is already populated in that\n * case and the no-op path avoids a redundant write.\n *\n * @param account - The account to add or update.\n */\n setAccount(account: KeyringAccount): void {\n const isNew = !this.registry.has(account.id);\n this.registry.set(account);\n if (isNew) {\n this.#callbacks.onRegister?.(account.id);\n }\n }\n\n /**\n * Remove an account from the registry.\n *\n * Fires `onUnregister` so the parent can drop the account from its index.\n *\n * @param id - The account ID to remove.\n * @returns `true` if the account was removed, `false` if it was not found.\n */\n removeAccount(id: AccountId): boolean {\n if (!this.registry.has(id)) {\n return false;\n }\n this.registry.delete(id);\n this.#callbacks.onUnregister?.(id);\n return true;\n }\n\n /**\n * Check whether an account exists in this keyring.\n *\n * @param id - The account ID to check.\n * @returns `true` if the account exists.\n */\n hasAccount(id: AccountId): boolean {\n return this.registry.has(id);\n }\n\n /**\n * Get an account by its ID.\n *\n * @param id - The account ID to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupAccount(id: AccountId): KeyringAccount | undefined {\n return this.registry.get(id);\n }\n\n /**\n * Get an account by address (case-insensitive).\n *\n * Performs an O(1) exact lookup first; falls back to a linear scan to\n * handle addresses stored with different casing.\n *\n * @param address - The address to look up.\n * @returns The account, or `undefined` if not found.\n */\n lookupByAddress(address: string): KeyringAccount | undefined {\n const id = this.registry.getAccountId(address);\n if (id !== undefined) {\n return this.registry.get(id);\n }\n // The fallback only runs when the exact-match branch above misses,\n // which in practice only happens for EVM addresses with casing\n // differences (checksummed vs lowercase). Non-EVM addresses are\n // case-sensitive and always resolve on the exact branch.\n return this.registry\n .values()\n .find((account) => equalsIgnoreCase(account.address, address));\n }\n\n /**\n * Get all accounts in this keyring (synchronous).\n *\n * This exists alongside the async `getAccounts()` (from `Keyring`) because\n * `SnapKeyring` needs synchronous access for iteration in `serialize`,\n * `listAccounts`, `hasSnapId`, etc. without awaiting.\n *\n * @returns An array of all accounts.\n */\n accounts(): KeyringAccount[] {\n return this.registry.values();\n }\n\n /**\n * Serialize this keyring's state.\n *\n * The returned object uses the internal per-snap format; the parent\n * `SnapKeyring` reconstructs the flat external format in its own\n * `serialize()`.\n *\n * @returns The serialized state.\n */\n async serialize(): Promise<SnapKeyringState> {\n const accounts: SnapKeyringState['accounts'] = {};\n for (const account of this.registry.values()) {\n accounts[account.id] = account;\n }\n const state: SnapKeyringState = {\n snapId: this.snapId,\n accounts,\n };\n return state;\n }\n\n /**\n * Restore this keyring from a serialized state.\n *\n * Validates the payload (accepting both v1 and v2 accounts), migrates any\n * v1 accounts to v2, then replaces the registry. If validation fails, the\n * existing registry is left untouched.\n *\n * @param state - The state to deserialize.\n * @returns A promise that resolves when deserialization is complete.\n */\n async deserialize(state: Json): Promise<void> {\n // Validate the raw payload — accepts both v1 and v2 account shapes.\n assert(state, SnapKeyringStateStruct);\n\n // Bind the keyring to its snap ID (idempotent for the same ID, throws on\n // mismatch to prevent swapping a keyring's identity via deserialize).\n this.bindSnapId(state.snapId as SnapId);\n\n // Migrate v1 accounts to v2.\n const migratedAccounts: Record<string, KeyringAccount> = {};\n for (const [id, rawAccount] of Object.entries(state.accounts)) {\n if (isAccountV1(rawAccount)) {\n console.info(\n `SnapKeyring - Found a KeyringAccountV1, migrating to V2: ${rawAccount.id}`,\n );\n migratedAccounts[id] = migrateAccountV1(rawAccount);\n } else {\n migratedAccounts[id] = rawAccount as KeyringAccount;\n }\n }\n\n // Apply the migrated state to the registry.\n for (const id of [...this.registry.keys()]) {\n this.removeAccount(id);\n }\n\n for (const account of Object.values(migratedAccounts)) {\n this.setAccount(account);\n }\n }\n\n // ──────────────────────────────────────────────\n // Private helpers\n // ──────────────────────────────────────────────\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/eth-snap-keyring",
3
- "version": "22.2.0-e5bc458",
3
+ "version": "22.3.0-30b0aa8",
4
4
  "description": "Snaps keyring bridge",
5
5
  "keywords": [
6
6
  "keyring",
@@ -69,7 +69,7 @@
69
69
  "dependencies": {
70
70
  "@ethereumjs/tx": "^5.4.0",
71
71
  "@metamask/eth-sig-util": "^8.2.0",
72
- "@metamask/keyring-api": "23.2.0",
72
+ "@metamask/keyring-api": "23.3.0",
73
73
  "@metamask/keyring-internal-api": "11.0.1",
74
74
  "@metamask/keyring-internal-snap-client": "10.0.3",
75
75
  "@metamask/keyring-sdk": "2.2.0",
@@ -89,7 +89,7 @@
89
89
  "@lavamoat/allow-scripts": "^3.2.1",
90
90
  "@lavamoat/preinstall-always-fail": "^2.1.0",
91
91
  "@metamask/auto-changelog": "^6.1.0",
92
- "@metamask/keyring-api": "23.2.0",
92
+ "@metamask/keyring-api": "23.3.0",
93
93
  "@ts-bridge/cli": "^0.6.3",
94
94
  "@types/jest": "^29.5.12",
95
95
  "@types/node": "^20.12.12",