{"version":3,"file":"SnapInsightsController.cjs","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n  ControllerGetStateAction,\n  ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n  Caveat,\n  PermissionControllerGetPermissionsAction,\n  ValidPermission,\n} from '@metamask/permission-controller';\nimport {\n  getSignatureOriginCaveat,\n  getTransactionOriginCaveat,\n  SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { Json, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { hasProperty, hexToBigInt } from '@metamask/utils';\n\nimport type { SnapInterfaceControllerDeleteInterfaceAction } from '../interface';\nimport type {\n  SnapControllerGetRunnableSnapsAction,\n  SnapControllerHandleRequestAction,\n} from '../snaps';\nimport type {\n  TransactionControllerUnapprovedTransactionAddedEvent,\n  TransactionMeta,\n  SignatureControllerStateChangeEvent,\n  SignatureControllerState,\n  StateSignature,\n  TransactionControllerTransactionStatusUpdatedEvent,\n} from '../types';\n\nconst controllerName = 'SnapInsightsController';\n\ntype AllowedActions =\n  | PermissionControllerGetPermissionsAction\n  | SnapControllerGetRunnableSnapsAction\n  | SnapControllerHandleRequestAction\n  | SnapInterfaceControllerDeleteInterfaceAction;\n\nexport type SnapInsightsControllerGetStateAction = ControllerGetStateAction<\n  typeof controllerName,\n  SnapInsightsControllerState\n>;\n\nexport type SnapInsightsControllerActions =\n  SnapInsightsControllerGetStateAction;\n\nexport type SnapInsightsControllerStateChangeEvent = ControllerStateChangeEvent<\n  typeof controllerName,\n  SnapInsightsControllerState\n>;\n\nexport type SnapInsightsControllerEvents =\n  SnapInsightsControllerStateChangeEvent;\n\ntype AllowedEvents =\n  | TransactionControllerUnapprovedTransactionAddedEvent\n  | TransactionControllerTransactionStatusUpdatedEvent\n  | SignatureControllerStateChangeEvent;\n\nexport type SnapInsightsControllerMessenger = Messenger<\n  typeof controllerName,\n  SnapInsightsControllerActions | AllowedActions,\n  SnapInsightsControllerEvents | AllowedEvents\n>;\n\nexport type SnapInsight = {\n  snapId: SnapId;\n  interfaceId?: string | null;\n  error?: string;\n  loading: boolean;\n  severity?: string;\n};\n\nexport type SnapInsightsControllerState = {\n  insights: Record<string, Record<SnapId, SnapInsight>>;\n};\n\nexport type SnapInsightsControllerArgs = {\n  messenger: SnapInsightsControllerMessenger;\n  state?: SnapInsightsControllerState;\n};\n\ntype SnapWithPermission = {\n  snapId: SnapId;\n  permission: ValidPermission<string, Caveat<string, Json>>;\n};\n\n/**\n * Controller for monitoring for new transactions and signatures to provide insight for.\n */\nexport class SnapInsightsController extends BaseController<\n  typeof controllerName,\n  SnapInsightsControllerState,\n  SnapInsightsControllerMessenger\n> {\n  constructor({ messenger, state }: SnapInsightsControllerArgs) {\n    super({\n      messenger,\n      metadata: {\n        insights: {\n          includeInStateLogs: true,\n          persist: false,\n          includeInDebugSnapshot: false,\n          usedInUi: true,\n        },\n      },\n      name: controllerName,\n      state: { insights: {}, ...state },\n    });\n\n    this.messenger.subscribe(\n      'TransactionController:unapprovedTransactionAdded',\n      this.#handleTransaction.bind(this),\n    );\n\n    this.messenger.subscribe(\n      'TransactionController:transactionStatusUpdated',\n      this.#handleTransactionStatusUpdate.bind(this),\n    );\n\n    this.messenger.subscribe(\n      'SignatureController:stateChange',\n      this.#handleSignatureStateChange.bind(this),\n    );\n  }\n\n  /**\n   * Check if an insight already exists for a given ID.\n   *\n   * @param id - The ID.\n   * @returns True if the insight already exists, otherwise false.\n   */\n  #hasInsight(id: string) {\n    return hasProperty(this.state.insights, id);\n  }\n\n  /**\n   * Get a list of runnable Snaps that have a given permission.\n   * Also includes the permission object itself.\n   *\n   * @param permissionName - The permission name.\n   * @returns A list of objects containing Snap IDs and the permission object.\n   */\n  #getSnapsWithPermission(permissionName: string) {\n    const filteredSnaps = this.messenger.call(\n      'SnapController:getRunnableSnaps',\n    );\n\n    return filteredSnaps.reduce<SnapWithPermission[]>((accumulator, snap) => {\n      const permissions = this.messenger.call(\n        'PermissionController:getPermissions',\n        snap.id,\n      );\n      if (permissions && hasProperty(permissions, permissionName)) {\n        accumulator.push({\n          snapId: snap.id,\n          permission: permissions[permissionName],\n        });\n      }\n\n      return accumulator;\n    }, []);\n  }\n\n  /**\n   * Handle a newly added unapproved transaction.\n   * This function fetches insights from all available Snaps\n   * and populates the insights state blob with the responses.\n   *\n   * @param transaction - The transaction object.\n   */\n  #handleTransaction(transaction: TransactionMeta) {\n    const { id, txParams, chainId, origin } = transaction;\n\n    // This assumes that the transactions are EVM-compatible for now.\n    const caipChainId = `eip155:${hexToBigInt(chainId).toString(10)}`;\n\n    const snaps = this.#getSnapsWithPermission(\n      SnapEndowments.TransactionInsight,\n    );\n\n    snaps.forEach(({ snapId, permission }) => {\n      const hasTransactionOriginCaveat = getTransactionOriginCaveat(permission);\n      const transactionOrigin =\n        hasTransactionOriginCaveat && origin ? origin : null;\n\n      this.update((state) => {\n        state.insights[id] ??= {};\n        state.insights[id][snapId] = { snapId, loading: true };\n      });\n\n      this.#handleSnapRequest({\n        snapId,\n        handler: HandlerType.OnTransaction,\n        params: {\n          transaction: txParams,\n          chainId: caipChainId,\n          transactionOrigin,\n        },\n      })\n        .then((response) =>\n          this.#handleSnapResponse({\n            id,\n            snapId,\n            response: response as Record<string, Json>,\n          }),\n        )\n        .catch((error) => this.#handleSnapResponse({ id, snapId, error }));\n    });\n  }\n\n  /**\n   * Handle the stateChange event emitted by the SignatureController.\n   * This function will remove existing insights from the state when applicable, as well as\n   * trigger insight fetching for newly added signatures.\n   *\n   * @param state - The SignatureController state blob.\n   */\n  #handleSignatureStateChange(state: SignatureControllerState) {\n    // If any IDs have disappeared since the last state update, the insight may be cleaned up.\n    for (const id of Object.keys(this.state.insights)) {\n      if (\n        !hasProperty(state.unapprovedTypedMessages, id) &&\n        !hasProperty(state.unapprovedPersonalMsgs, id)\n      ) {\n        this.#handleInsightCleanup(id);\n      }\n    }\n\n    if (\n      state.unapprovedPersonalMsgCount > 0 ||\n      state.unapprovedTypedMessagesCount > 0\n    ) {\n      const snaps = this.#getSnapsWithPermission(\n        SnapEndowments.SignatureInsight,\n      );\n\n      // This isn't very efficient, but SignatureController doesn't expose a better event for us to use yet.\n      for (const personalSignature of Object.values(\n        state.unapprovedPersonalMsgs,\n      )) {\n        this.#handleSignature(snaps, personalSignature);\n      }\n\n      for (const typedMessage of Object.values(state.unapprovedTypedMessages)) {\n        this.#handleSignature(snaps, typedMessage);\n      }\n    }\n  }\n\n  /**\n   * Handle a newly added unapproved signature.\n   * This function fetches insights from all available Snaps\n   * and populates the insights state blob with the responses.\n   *\n   * @param snaps - A list of Snaps to invoke.\n   * @param signature - The signature object.\n   */\n  #handleSignature(snaps: SnapWithPermission[], signature: StateSignature) {\n    const { id, msgParams } = signature;\n\n    if (this.#hasInsight(id)) {\n      return;\n    }\n\n    const { from, data, signatureMethod, origin } = msgParams;\n\n    /**\n     * Both eth_signTypedData_v3 and eth_signTypedData_v4 methods\n     * need to be parsed because their data is stringified. All other\n     * signature methods do not, so they are ignored.\n     */\n    const shouldParse =\n      signatureMethod === 'eth_signTypedData_v3' ||\n      signatureMethod === 'eth_signTypedData_v4';\n\n    const payload = {\n      from,\n      data: shouldParse ? JSON.parse(data as string) : data,\n      signatureMethod,\n    };\n\n    snaps.forEach(({ snapId, permission }) => {\n      const hasSignatureOriginCaveat = getSignatureOriginCaveat(permission);\n      const signatureOrigin =\n        origin && hasSignatureOriginCaveat ? origin : null;\n\n      this.update((state) => {\n        state.insights[id] ??= {};\n        state.insights[id][snapId] = { snapId, loading: true };\n      });\n\n      this.#handleSnapRequest({\n        snapId,\n        handler: HandlerType.OnSignature,\n        params: { signature: payload, signatureOrigin },\n      })\n        .then((response) =>\n          this.#handleSnapResponse({\n            id,\n            snapId,\n            response: response as Record<string, Json>,\n          }),\n        )\n        .catch((error) => this.#handleSnapResponse({ id, snapId, error }));\n    });\n  }\n\n  /**\n   * Handle the transactionStatusUpdated event emitted by the TransactionController.\n   * This function will remove insights for the transaction in question\n   * once the transaction status has changed from unapproved.\n   *\n   * @param args - An options bag.\n   * @param args.transactionMeta - The transaction.\n   */\n  #handleTransactionStatusUpdate({\n    transactionMeta,\n  }: {\n    transactionMeta: TransactionMeta;\n  }) {\n    if (transactionMeta.status !== 'unapproved') {\n      this.#handleInsightCleanup(transactionMeta.id);\n    }\n  }\n\n  #handleInsightCleanup(id: string) {\n    if (!this.#hasInsight(id)) {\n      return;\n    }\n\n    // Delete interfaces from interface controller.\n    Object.values(this.state.insights[id])\n      .filter((insight) => insight.interfaceId)\n      .forEach((insight) => {\n        this.messenger.call(\n          'SnapInterfaceController:deleteInterface',\n          insight.interfaceId as string,\n        );\n      });\n\n    this.update((state) => {\n      delete state.insights[id];\n    });\n  }\n\n  /**\n   * Handle sending a request to a given Snap with a given payload.\n   *\n   * @param args - An options bag.\n   * @param args.snapId - The Snap ID.\n   * @param args.handler - The handler to invoke.\n   * @param args.params - The JSON-RPC params to send.\n   * @returns The response from the Snap.\n   */\n  async #handleSnapRequest({\n    snapId,\n    handler,\n    params,\n  }: {\n    snapId: SnapId;\n    handler: HandlerType.OnTransaction | HandlerType.OnSignature;\n    params: Record<string, Json>;\n  }) {\n    return this.messenger.call('SnapController:handleRequest', {\n      snapId,\n      origin: 'metamask',\n      handler,\n      request: {\n        method: '',\n        params,\n      },\n    });\n  }\n\n  /**\n   * Handle response from a given Snap by persisting the response or error in state.\n   *\n   * @param args - An options bag.\n   * @param args.id - The transaction or signature ID.\n   * @param args.snapId - The Snap ID.\n   * @param args.response - An optional response object returned by the Snap.\n   * @param args.error - An optional error returned by the Snap.\n   */\n  #handleSnapResponse({\n    id,\n    snapId,\n    response,\n    error,\n  }: {\n    id: string;\n    snapId: SnapId;\n    response?: Record<string, Json>;\n    error?: Error;\n  }) {\n    // If the insight has been cleaned up already, we can skip setting the state.\n    // This may happen if a user accepts/rejects a transaction/signature faster than the Snap responds.\n    if (!this.#hasInsight(id)) {\n      return;\n    }\n\n    this.update((state) => {\n      state.insights[id][snapId].loading = false;\n      state.insights[id][snapId].interfaceId = response?.id as string;\n      state.insights[id][snapId].severity = response?.severity as string;\n      state.insights[id][snapId].error = error?.message;\n    });\n  }\n}\n"]}