{"version":3,"file":"SnapAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { assertIsBip44Account } from '@metamask/account-api';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback, TraceRequest } from '@metamask/controller-utils';\nimport type { SnapKeyring as SnapKeyringV2 } from '@metamask/eth-snap-keyring/v2';\nimport {\n  EMPTY_CAPABILITIES,\n  isSnapKeyring,\n} from '@metamask/eth-snap-keyring/v2';\nimport {\n  AccountCreationType,\n  assertCreateAccountOptionIsSupported,\n} from '@metamask/keyring-api';\nimport type {\n  CreateAccountBip44DeriveIndexOptions,\n  CreateAccountBip44DeriveIndexRangeOptions,\n  CreateAccountBip44DiscoverOptions,\n  CreateAccountOptions,\n  EntropySourceId,\n  KeyringAccount,\n} from '@metamask/keyring-api';\nimport type { KeyringCapabilities } from '@metamask/keyring-api/v2';\nimport type { KeyringMetadata } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { CaipChainId } from '@metamask/utils';\nimport { Semaphore } from 'async-mutex';\n\nimport {\n  toCreateAccountsV2DataTraces,\n  traceFallback,\n  TraceName,\n} from '../analytics';\nimport { reportError } from '../errors';\nimport { projectLogger as log, WARNING_PREFIX } from '../logger';\nimport type { MultichainAccountServiceMessenger } from '../types';\nimport { BaseBip44AccountProvider } from './BaseBip44AccountProvider';\nimport { createSnapKeyringClient } from './SnapKeyringClient';\nimport type { Sender, SnapKeyringClient } from './SnapKeyringClient';\nimport { withRetry, withTimeout } from './utils';\n\n/**\n * A proxy to the Snap's keyring operations that routes every call through the\n * `KeyringController` mutex (via {@link SnapAccountProvider.#withSnapKeyring}).\n * Callers receive this object from {@link SnapAccountProvider.withSnap} and\n * never interact with the raw keyring or the mutex directly.\n */\nexport type SnapKeyringProxy = {\n  createAccounts: SnapKeyringV2['createAccounts'];\n  deleteAccount: SnapKeyringV2['deleteAccount'];\n};\n\nexport type SnapAccountProviderConfig = {\n  maxConcurrency?: number;\n  discovery: {\n    enabled?: boolean;\n    maxAttempts: number;\n    timeoutMs: number;\n    backOffMs: number;\n  };\n  createAccounts: {\n    /**\n     * Timeout for account creation operations.\n     *\n     * NOTE: Batching (and thus whether a single call may create multiple\n     * accounts) is driven by the Snap's declared capabilities, not this config.\n     * The value might have to be adapted when the Snap supports batching.\n     */\n    timeoutMs: number;\n  };\n  resyncAccounts?: {\n    /**\n     * Whether to automatically remove extra Snap accounts when the Snap has\n     * more accounts than MetaMask. If `false`, a warning is logged instead.\n     * Defaults to `true`.\n     */\n    autoRemoveExtraSnapAccounts?: boolean;\n  };\n};\n\nexport abstract class SnapAccountProvider extends BaseBip44AccountProvider {\n  readonly snapId: SnapId;\n\n  protected readonly config: SnapAccountProviderConfig;\n\n  /**\n   * The Snap's keyring capabilities, sourced from `SnapAccountService` (which\n   * reads them from the Snap's manifest). Populated the first time the client\n   * is resolved; defaults to an empty capability set until then.\n   */\n  capabilities: KeyringCapabilities = EMPTY_CAPABILITIES;\n\n  /**\n   * Version-agnostic keyring client, resolved lazily once the Snap is ready and\n   * its capabilities are known — see {@link SnapAccountProvider.withSnap}.\n   */\n  #client?: SnapKeyringClient;\n\n  readonly #sender: Sender;\n\n  readonly #queue?: Semaphore;\n\n  readonly #trace: TraceCallback;\n\n  /**\n   * Scopes passed to the v1 `discoverAccounts` client method. Only used on the\n   * v1 discovery path.\n   *\n   * TODO: Remove once all Snaps are fully v2 — discovery is then driven by the\n   * Snap's own supported scopes via `createAccounts({ bip44:discover })`.\n   */\n  protected abstract readonly v1DiscoveryScopes: CaipChainId[];\n\n  constructor(\n    snapId: SnapId,\n    messenger: MultichainAccountServiceMessenger,\n    config: SnapAccountProviderConfig,\n    /* istanbul ignore next */\n    trace: TraceCallback = traceFallback,\n  ) {\n    super(messenger);\n\n    this.snapId = snapId;\n    this.#sender = this.#createSender(snapId);\n\n    const maxConcurrency = config.maxConcurrency ?? Infinity;\n    this.config = {\n      ...config,\n      discovery: {\n        ...config.discovery,\n        enabled: config.discovery.enabled ?? true,\n      },\n      maxConcurrency,\n    };\n\n    // Create semaphore only if concurrency is limited\n    if (isFinite(maxConcurrency)) {\n      this.#queue = new Semaphore(maxConcurrency);\n    }\n\n    this.#trace = trace;\n  }\n\n  /**\n   * Ensures that the Snap is ready to be used.\n   *\n   * Once this resolves, a Snap keyring for {@link snapId} is guaranteed to\n   * exist in the `KeyringController`, so subsequent {@link #withSnapKeyring}\n   * calls will not fail with \"No keyring matches the selector\".\n   *\n   * @returns A promise that resolves when the Snap is ready.\n   * @throws An error if the Snap could not become ready.\n   */\n  async ensureReady(): Promise<void> {\n    return this.messenger.call('SnapAccountService:ensureReady', this.snapId);\n  }\n\n  /**\n   * Wraps an async operation with concurrency limiting based on maxConcurrency config.\n   * If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.\n   * Otherwise, it's queued through the semaphore to respect the concurrency limit.\n   *\n   * @param operation - The async operation to execute.\n   * @returns The result of the operation.\n   */\n  protected async withMaxConcurrency<Result>(\n    operation: () => Promise<Result>,\n  ): Promise<Result> {\n    if (this.#queue) {\n      return this.#queue.runExclusive(operation);\n    }\n    return operation();\n  }\n\n  protected async trace<ReturnType>(\n    request: TraceRequest,\n    fn: () => Promise<ReturnType>,\n  ): Promise<ReturnType> {\n    return this.#trace(request, fn);\n  }\n\n  #createSender(snapId: string): Sender {\n    return {\n      send: async (request: JsonRpcRequest): Promise<Json> => {\n        const response = await this.messenger.call(\n          'SnapController:handleRequest',\n          {\n            snapId: snapId as SnapId,\n            origin: 'metamask',\n            handler: HandlerType.OnKeyringRequest,\n            request,\n          },\n        );\n        return response as Json;\n      },\n    };\n  }\n\n  /**\n   * Whether the Snap supports the v2 keyring protocol, inferred from its\n   * declared capabilities (a v2-capable Snap declares BIP-44 capabilities).\n   *\n   * @returns `true` if the Snap is v2-capable.\n   */\n  protected isV2(): boolean {\n    return Boolean(this.capabilities.bip44);\n  }\n\n  /**\n   * Resolves the version-agnostic keyring client, fetching the Snap's\n   * capabilities from `SnapAccountService` on first use and caching both the\n   * capabilities and the resulting client.\n   *\n   * Callers must ensure the Snap is ready (via\n   * {@link SnapAccountProvider.ensureReady}) beforehand so that the\n   * capabilities are reliably populated — {@link SnapAccountProvider.withSnap}\n   * guarantees this ordering.\n   *\n   * @returns The resolved {@link SnapKeyringClient}.\n   */\n  async #resolveClient(): Promise<SnapKeyringClient> {\n    if (!this.#client) {\n      this.capabilities = await this.messenger.call(\n        'SnapAccountService:getCapabilities',\n        this.snapId,\n      );\n      this.#client = createSnapKeyringClient(this.#sender, this.isV2());\n    }\n    return this.#client;\n  }\n\n  async resyncAccounts(\n    accounts: Bip44Account<InternalAccount>[],\n  ): Promise<void> {\n    await this.withSnap(async ({ client, keyring }) => {\n      const localSnapAccounts = accounts.filter(\n        (account) => account.metadata.snap?.id === this.snapId,\n      );\n      const snapAccounts = new Set(\n        (await client.getAccounts()).map((account) => account.id),\n      );\n\n      // NOTE: This should never happen, but if it does, we recover by deleting the\n      // extra accounts from the Snap to bring it back in sync with MetaMask.\n      if (localSnapAccounts.length < snapAccounts.size) {\n        const autoRemoveExtraSnapAccounts =\n          this.config.resyncAccounts?.autoRemoveExtraSnapAccounts ?? true;\n\n        if (autoRemoveExtraSnapAccounts) {\n          // Build a set of local account IDs for quick lookup\n          const localAccountIds = new Set(\n            localSnapAccounts.map((account) => account.id),\n          );\n\n          // Find and delete accounts that exist in Snap but not in MetaMask\n          await Promise.all(\n            [...snapAccounts].map(async (snapAccountId) => {\n              try {\n                if (!localAccountIds.has(snapAccountId)) {\n                  // This account exists in the Snap but not in MetaMask, delete it from\n                  // the Snap.\n                  await client.deleteAccount(snapAccountId);\n                  // Update the local Set so subsequent checks use the correct size\n                  snapAccounts.delete(snapAccountId);\n                }\n              } catch (error) {\n                reportError(\n                  this.messenger,\n                  `Unable to delete de-synced Snap account: ${this.snapId}`,\n                  error,\n                  {\n                    provider: this.getName(),\n                    snapAccountId,\n                  },\n                );\n              }\n            }),\n          );\n        } else {\n          const message = `Snap \"${this.snapId}\" has de-synced accounts, Snap has more accounts than MetaMask! (${localSnapAccounts.length} < ${snapAccounts.size})`;\n          log(`${WARNING_PREFIX} ${message}`);\n          console.warn(message);\n          return;\n        }\n      }\n\n      // We want this part to be fast, so we only check for sizes, but we might need\n      // to make a real \"diff\" between the 2 states to not miss any de-sync.\n      if (localSnapAccounts.length > snapAccounts.size) {\n        // We always use the MetaMask list as the main reference here.\n        await Promise.all(\n          localSnapAccounts.map(async (account) => {\n            const { id: entropySource, groupIndex } = account.options.entropy;\n\n            try {\n              if (!snapAccounts.has(account.id)) {\n                // We still need to remove the accounts from the Snap keyring since we're\n                // about to create the same account again, which will use a new ID, but will\n                // keep using the same address, and the Snap keyring does not allow this.\n                await keyring.deleteAccount(account.id);\n                // The Snap has no account in its state for this one, we re-create it.\n                await this.createAccounts({\n                  type: AccountCreationType.Bip44DeriveIndex,\n                  entropySource,\n                  groupIndex,\n                });\n              }\n            } catch (error) {\n              reportError(this.messenger, 'Unable to re-sync accounts', error, {\n                provider: this.getName(),\n                groupIndex,\n              });\n            }\n          }),\n        );\n      }\n    });\n  }\n\n  async #withSnapKeyring<CallbackResult = void>(\n    operation: ({\n      keyring,\n      metadata,\n    }: {\n      keyring: SnapKeyringV2;\n      metadata: KeyringMetadata;\n    }) => Promise<CallbackResult>,\n  ): Promise<CallbackResult> {\n    return this.withKeyringV2<SnapKeyringV2, CallbackResult>(\n      {\n        filter: (keyring) =>\n          isSnapKeyring(keyring) && keyring.snapId === this.snapId,\n      },\n      (args) => operation(args),\n    );\n  }\n\n  protected async withSnap<CallbackResult = void>(\n    operation: (snap: {\n      client: SnapKeyringClient;\n      keyring: SnapKeyringProxy;\n    }) => Promise<CallbackResult>,\n  ): Promise<CallbackResult> {\n    await this.ensureReady();\n    const client = await this.#resolveClient();\n    const keyring: SnapKeyringProxy = {\n      createAccounts: (options) =>\n        this.#withSnapKeyring(({ keyring: snapKeyring }) =>\n          snapKeyring.createAccounts(options),\n        ),\n      deleteAccount: (id) =>\n        this.#withSnapKeyring(({ keyring: snapKeyring }) =>\n          snapKeyring.deleteAccount(id),\n        ),\n    };\n    return await operation({ client, keyring });\n  }\n\n  abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;\n\n  protected toBip44Account(\n    account: KeyringAccount,\n    _options: { entropySource: EntropySourceId; groupIndex: number },\n  ): Bip44Account<KeyringAccount> {\n    assertIsBip44Account(account);\n    return account;\n  }\n\n  protected async createBip44Accounts(\n    keyring: SnapKeyringProxy,\n    options:\n      | CreateAccountBip44DeriveIndexOptions\n      | CreateAccountBip44DeriveIndexRangeOptions\n      | CreateAccountBip44DiscoverOptions,\n  ): Promise<Bip44Account<KeyringAccount>[]> {\n    return this.withMaxConcurrency(async () => {\n      const { entropySource } = options;\n\n      const snapAccounts = await withTimeout(\n        () =>\n          this.trace(\n            {\n              name: TraceName.ProviderCreateAccounts,\n              data: {\n                provider: this.getName(),\n                ...toCreateAccountsV2DataTraces(options),\n              },\n            },\n            () => keyring.createAccounts(options),\n          ),\n        this.config.createAccounts.timeoutMs,\n      );\n\n      const groupIndexOffset =\n        options.type === `${AccountCreationType.Bip44DeriveIndexRange}`\n          ? options.range.from\n          : options.groupIndex;\n\n      return snapAccounts.map((snapAccount, index) => {\n        const groupIndex = groupIndexOffset + index;\n        const account = this.toBip44Account(snapAccount, {\n          entropySource,\n          groupIndex,\n        });\n\n        this.accounts.add(snapAccount.id);\n        return account;\n      });\n    });\n  }\n\n  async createAccounts(\n    options: CreateAccountOptions,\n  ): Promise<Bip44Account<KeyringAccount>[]> {\n    assertCreateAccountOptionIsSupported(options, [\n      `${AccountCreationType.Bip44DeriveIndex}`,\n      `${AccountCreationType.Bip44DeriveIndexRange}`,\n    ]);\n\n    return this.withSnap(async ({ keyring }) =>\n      this.createBip44Accounts(keyring, options),\n    );\n  }\n\n  /**\n   * Delete a snap account by id.\n   *\n   * Resolves the account's address from the tracked account, then forwards to\n   * the legacy `SnapKeyring.removeAccount(address)`. The Snap keyring takes\n   * care of notifying the snap to clean up its own state through the normal\n   * account-removal flow (same path used by `resyncAccounts`).\n   *\n   * @param id - The id of the account to delete.\n   */\n  async deleteAccount(id: Bip44Account<KeyringAccount>['id']): Promise<void> {\n    const account = this.getAccount(id);\n\n    await this.#withSnapKeyring(async ({ keyring }) => {\n      await keyring.deleteAccount(account.id);\n    });\n\n    this.accounts.delete(id);\n  }\n\n  /**\n   * Discovers accounts for the given entropy source and group index.\n   *\n   * v2 Snaps drive discovery through `createAccounts({ bip44:discover })`: the\n   * Snap checks for on-chain activity (using its own supported scopes) and\n   * returns the created account(s), or nothing once discovery is exhausted.\n   *\n   * v1 Snaps use the client's `discoverAccounts` to detect activity on\n   * {@link v1DiscoveryScopes}, then create the account for the group index.\n   *\n   * @param options - The discovery options.\n   * @param options.entropySource - The entropy source to discover accounts for.\n   * @param options.groupIndex - The group index to discover accounts for.\n   * @returns The discovered (and created) accounts, or an empty array when\n   * there is nothing to discover at this group index.\n   */\n  async discoverAccounts({\n    entropySource,\n    groupIndex,\n  }: {\n    entropySource: EntropySourceId;\n    groupIndex: number;\n  }): Promise<Bip44Account<KeyringAccount>[]> {\n    return this.withSnap(async ({ client, keyring }) =>\n      this.trace(\n        {\n          name: TraceName.SnapDiscoverAccounts,\n          data: {\n            provider: this.getName(),\n          },\n        },\n        async () => {\n          if (!this.config.discovery.enabled) {\n            return [];\n          }\n\n          if (this.isV2()) {\n            // The v2 client has no `discoverAccounts`, so discovery is only\n            // possible when the Snap supports `bip44:discover`. Otherwise there\n            // is no way to discover and we report nothing.\n            if (!this.capabilities.bip44?.discover) {\n              return [];\n            }\n\n            // v2: the Snap detects on-chain activity and creates the account in\n            // a single `createAccounts({ bip44:discover })` call. An empty\n            // result means discovery is exhausted at this group index.\n            return this.createBip44Accounts(keyring, {\n              type: AccountCreationType.Bip44Discover,\n              entropySource,\n              groupIndex,\n            });\n          }\n\n          // v1: detect activity via the client, then create the account for\n          // this group index.\n          const discoveredAccounts = await withRetry(\n            () =>\n              withTimeout(\n                () =>\n                  client.discoverAccounts(\n                    this.v1DiscoveryScopes,\n                    entropySource,\n                    groupIndex,\n                  ),\n                this.config.discovery.timeoutMs,\n              ),\n            {\n              maxAttempts: this.config.discovery.maxAttempts,\n              backOffMs: this.config.discovery.backOffMs,\n            },\n          );\n\n          if (!discoveredAccounts.length) {\n            return [];\n          }\n\n          return this.createBip44Accounts(keyring, {\n            type: AccountCreationType.Bip44DeriveIndex,\n            entropySource,\n            groupIndex,\n          });\n        },\n      ),\n    );\n  }\n}\n\nexport const isSnapAccountProvider = (\n  provider: unknown,\n): provider is SnapAccountProvider => {\n  return provider instanceof SnapAccountProvider;\n};\n"]}