@metamask/snaps-controllers 9.10.0 → 9.11.1

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,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [9.11.1]
11
+
12
+ ### Fixed
13
+
14
+ - Pass full URLs to `PhishingController` ([#2835](https://github.com/MetaMask/snaps/pull/2835))
15
+ - Ignore Snap insight response if transaction or signature has already been signed ([#2825](https://github.com/MetaMask/snaps/pull/2825))
16
+
17
+ ## [9.11.0]
18
+
19
+ ### Changed
20
+
21
+ - Allow updating interface context ([#2809](https://github.com/MetaMask/snaps/pull/2809))
22
+ - `snap_updateInterface` now accepts a `context` parameter to update the
23
+ context of an interface.
24
+
25
+ ### Removed
26
+
27
+ - Remove `AccountSelector` component ([#2794](https://github.com/MetaMask/snaps/pull/2794))
28
+ - This is technically a breaking change, but the `AccountSelector` component was never actually implemented, so it
29
+ should not affect any existing code.
30
+
10
31
  ## [9.10.0]
11
32
 
12
33
  ### Changed
@@ -520,7 +541,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
520
541
  - The version of the package no longer needs to match the version of all other
521
542
  MetaMask Snaps packages.
522
543
 
523
- [Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@9.10.0...HEAD
544
+ [Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@9.11.1...HEAD
545
+ [9.11.1]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@9.11.0...@metamask/snaps-controllers@9.11.1
546
+ [9.11.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@9.10.0...@metamask/snaps-controllers@9.11.0
524
547
  [9.10.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@9.9.0...@metamask/snaps-controllers@9.10.0
525
548
  [9.9.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@9.8.0...@metamask/snaps-controllers@9.9.0
526
549
  [9.8.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@9.7.0...@metamask/snaps-controllers@9.8.0
@@ -172,6 +172,11 @@ async function _SnapInsightsController_handleSnapRequest({ snapId, handler, para
172
172
  },
173
173
  });
174
174
  }, _SnapInsightsController_handleSnapResponse = function _SnapInsightsController_handleSnapResponse({ id, snapId, response, error, }) {
175
+ // If the insight has been cleaned up already, we can skip setting the state.
176
+ // This may happen if a user accepts/rejects a transaction/signature faster than the Snap responds.
177
+ if (!__classPrivateFieldGet(this, _SnapInsightsController_instances, "m", _SnapInsightsController_hasInsight).call(this, id)) {
178
+ return;
179
+ }
175
180
  this.update((state) => {
176
181
  state.insights[id][snapId].loading = false;
177
182
  state.insights[id][snapId].interfaceId = response?.id;
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInsightsController.cjs","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n Caveat,\n GetPermissions,\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 } from '@metamask/utils';\n\nimport type { DeleteInterface } from '../interface';\nimport type { GetAllSnaps, HandleSnapRequest } from '../snaps';\nimport { getRunnableSnaps } from '../snaps';\nimport type {\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n SignatureStateChange,\n SignatureControllerState,\n StateSignature,\n TransactionControllerTransactionStatusUpdatedEvent,\n} from '../types';\n\nconst controllerName = 'SnapInsightsController';\n\nexport type SnapInsightsControllerAllowedActions =\n | HandleSnapRequest\n | GetAllSnaps\n | GetPermissions\n | DeleteInterface;\n\nexport type SnapInsightsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightsControllerActions =\n SnapInsightsControllerGetStateAction;\n\nexport type SnapInsightControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightControllerEvents = SnapInsightControllerStateChangeEvent;\n\nexport type SnapInsightsControllerAllowedEvents =\n | TransactionControllerUnapprovedTransactionAddedEvent\n | TransactionControllerTransactionStatusUpdatedEvent\n | SignatureStateChange;\n\nexport type SnapInsightsControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInsightsControllerActions | SnapInsightsControllerAllowedActions,\n SnapInsightControllerEvents | SnapInsightsControllerAllowedEvents,\n SnapInsightsControllerAllowedActions['type'],\n SnapInsightsControllerAllowedEvents['type']\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: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { insights: {}, ...state },\n });\n\n this.messagingSystem.subscribe(\n 'TransactionController:unapprovedTransactionAdded',\n this.#handleTransaction.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'TransactionController:transactionStatusUpdated',\n this.#handleTransactionStatusUpdate.bind(this),\n );\n\n this.messagingSystem.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 allSnaps = this.messagingSystem.call('SnapController:getAll');\n const filteredSnaps = getRunnableSnaps(allSnaps);\n\n return filteredSnaps.reduce<SnapWithPermission[]>((accumulator, snap) => {\n const permissions = this.messagingSystem.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:${parseInt(chainId, 16)}`;\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.messagingSystem.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.messagingSystem.call('SnapController:handleRequest', {\n snapId,\n origin: '',\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 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"]}
1
+ {"version":3,"file":"SnapInsightsController.cjs","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n Caveat,\n GetPermissions,\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 } from '@metamask/utils';\n\nimport type { DeleteInterface } from '../interface';\nimport type { GetAllSnaps, HandleSnapRequest } from '../snaps';\nimport { getRunnableSnaps } from '../snaps';\nimport type {\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n SignatureStateChange,\n SignatureControllerState,\n StateSignature,\n TransactionControllerTransactionStatusUpdatedEvent,\n} from '../types';\n\nconst controllerName = 'SnapInsightsController';\n\nexport type SnapInsightsControllerAllowedActions =\n | HandleSnapRequest\n | GetAllSnaps\n | GetPermissions\n | DeleteInterface;\n\nexport type SnapInsightsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightsControllerActions =\n SnapInsightsControllerGetStateAction;\n\nexport type SnapInsightControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightControllerEvents = SnapInsightControllerStateChangeEvent;\n\nexport type SnapInsightsControllerAllowedEvents =\n | TransactionControllerUnapprovedTransactionAddedEvent\n | TransactionControllerTransactionStatusUpdatedEvent\n | SignatureStateChange;\n\nexport type SnapInsightsControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInsightsControllerActions | SnapInsightsControllerAllowedActions,\n SnapInsightControllerEvents | SnapInsightsControllerAllowedEvents,\n SnapInsightsControllerAllowedActions['type'],\n SnapInsightsControllerAllowedEvents['type']\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: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { insights: {}, ...state },\n });\n\n this.messagingSystem.subscribe(\n 'TransactionController:unapprovedTransactionAdded',\n this.#handleTransaction.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'TransactionController:transactionStatusUpdated',\n this.#handleTransactionStatusUpdate.bind(this),\n );\n\n this.messagingSystem.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 allSnaps = this.messagingSystem.call('SnapController:getAll');\n const filteredSnaps = getRunnableSnaps(allSnaps);\n\n return filteredSnaps.reduce<SnapWithPermission[]>((accumulator, snap) => {\n const permissions = this.messagingSystem.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:${parseInt(chainId, 16)}`;\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.messagingSystem.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.messagingSystem.call('SnapController:handleRequest', {\n snapId,\n origin: '',\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInsightsController.d.cts","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAEV,cAAc,EAEf,wCAAwC;AAMzC,OAAO,KAAK,EAAQ,MAAM,EAAE,4BAA4B;AAIxD,OAAO,KAAK,EAAE,eAAe,EAAE,+BAAqB;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,2BAAiB;AAE/D,OAAO,KAAK,EACV,oDAAoD,EAEpD,oBAAoB,EAGpB,kDAAkD,EACnD,2BAAiB;AAElB,QAAA,MAAM,cAAc,2BAA2B,CAAC;AAEhD,MAAM,MAAM,oCAAoC,GAC5C,iBAAiB,GACjB,WAAW,GACX,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACvC,oCAAoC,CAAC;AAEvC,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF,MAAM,MAAM,mCAAmC,GAC3C,oDAAoD,GACpD,kDAAkD,GAClD,oBAAoB,CAAC;AAEzB,MAAM,MAAM,+BAA+B,GAAG,6BAA6B,CACzE,OAAO,cAAc,EACrB,6BAA6B,GAAG,oCAAoC,EACpE,2BAA2B,GAAG,mCAAmC,EACjE,oCAAoC,CAAC,MAAM,CAAC,EAC5C,mCAAmC,CAAC,MAAM,CAAC,CAC5C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,+BAA+B,CAAC;IAC3C,KAAK,CAAC,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAOF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,0BAA0B;CA6S7D"}
1
+ {"version":3,"file":"SnapInsightsController.d.cts","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAEV,cAAc,EAEf,wCAAwC;AAMzC,OAAO,KAAK,EAAQ,MAAM,EAAE,4BAA4B;AAIxD,OAAO,KAAK,EAAE,eAAe,EAAE,+BAAqB;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,2BAAiB;AAE/D,OAAO,KAAK,EACV,oDAAoD,EAEpD,oBAAoB,EAGpB,kDAAkD,EACnD,2BAAiB;AAElB,QAAA,MAAM,cAAc,2BAA2B,CAAC;AAEhD,MAAM,MAAM,oCAAoC,GAC5C,iBAAiB,GACjB,WAAW,GACX,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACvC,oCAAoC,CAAC;AAEvC,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF,MAAM,MAAM,mCAAmC,GAC3C,oDAAoD,GACpD,kDAAkD,GAClD,oBAAoB,CAAC;AAEzB,MAAM,MAAM,+BAA+B,GAAG,6BAA6B,CACzE,OAAO,cAAc,EACrB,6BAA6B,GAAG,oCAAoC,EACpE,2BAA2B,GAAG,mCAAmC,EACjE,oCAAoC,CAAC,MAAM,CAAC,EAC5C,mCAAmC,CAAC,MAAM,CAAC,CAC5C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,+BAA+B,CAAC;IAC3C,KAAK,CAAC,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAOF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,0BAA0B;CAmT7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInsightsController.d.mts","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAEV,cAAc,EAEf,wCAAwC;AAMzC,OAAO,KAAK,EAAQ,MAAM,EAAE,4BAA4B;AAIxD,OAAO,KAAK,EAAE,eAAe,EAAE,+BAAqB;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,2BAAiB;AAE/D,OAAO,KAAK,EACV,oDAAoD,EAEpD,oBAAoB,EAGpB,kDAAkD,EACnD,2BAAiB;AAElB,QAAA,MAAM,cAAc,2BAA2B,CAAC;AAEhD,MAAM,MAAM,oCAAoC,GAC5C,iBAAiB,GACjB,WAAW,GACX,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACvC,oCAAoC,CAAC;AAEvC,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF,MAAM,MAAM,mCAAmC,GAC3C,oDAAoD,GACpD,kDAAkD,GAClD,oBAAoB,CAAC;AAEzB,MAAM,MAAM,+BAA+B,GAAG,6BAA6B,CACzE,OAAO,cAAc,EACrB,6BAA6B,GAAG,oCAAoC,EACpE,2BAA2B,GAAG,mCAAmC,EACjE,oCAAoC,CAAC,MAAM,CAAC,EAC5C,mCAAmC,CAAC,MAAM,CAAC,CAC5C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,+BAA+B,CAAC;IAC3C,KAAK,CAAC,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAOF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,0BAA0B;CA6S7D"}
1
+ {"version":3,"file":"SnapInsightsController.d.mts","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAEV,cAAc,EAEf,wCAAwC;AAMzC,OAAO,KAAK,EAAQ,MAAM,EAAE,4BAA4B;AAIxD,OAAO,KAAK,EAAE,eAAe,EAAE,+BAAqB;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,2BAAiB;AAE/D,OAAO,KAAK,EACV,oDAAoD,EAEpD,oBAAoB,EAGpB,kDAAkD,EACnD,2BAAiB;AAElB,QAAA,MAAM,cAAc,2BAA2B,CAAC;AAEhD,MAAM,MAAM,oCAAoC,GAC5C,iBAAiB,GACjB,WAAW,GACX,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACvC,oCAAoC,CAAC;AAEvC,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF,MAAM,MAAM,mCAAmC,GAC3C,oDAAoD,GACpD,kDAAkD,GAClD,oBAAoB,CAAC;AAEzB,MAAM,MAAM,+BAA+B,GAAG,6BAA6B,CACzE,OAAO,cAAc,EACrB,6BAA6B,GAAG,oCAAoC,EACpE,2BAA2B,GAAG,mCAAmC,EACjE,oCAAoC,CAAC,MAAM,CAAC,EAC5C,mCAAmC,CAAC,MAAM,CAAC,CAC5C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,+BAA+B,CAAC;IAC3C,KAAK,CAAC,EAAE,2BAA2B,CAAC;CACrC,CAAC;AAOF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,0BAA0B;CAmT7D"}
@@ -168,6 +168,11 @@ async function _SnapInsightsController_handleSnapRequest({ snapId, handler, para
168
168
  },
169
169
  });
170
170
  }, _SnapInsightsController_handleSnapResponse = function _SnapInsightsController_handleSnapResponse({ id, snapId, response, error, }) {
171
+ // If the insight has been cleaned up already, we can skip setting the state.
172
+ // This may happen if a user accepts/rejects a transaction/signature faster than the Snap responds.
173
+ if (!__classPrivateFieldGet(this, _SnapInsightsController_instances, "m", _SnapInsightsController_hasInsight).call(this, id)) {
174
+ return;
175
+ }
171
176
  this.update((state) => {
172
177
  state.insights[id][snapId].loading = false;
173
178
  state.insights[id][snapId].interfaceId = response?.id;
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInsightsController.mjs","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n Caveat,\n GetPermissions,\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 } from '@metamask/utils';\n\nimport type { DeleteInterface } from '../interface';\nimport type { GetAllSnaps, HandleSnapRequest } from '../snaps';\nimport { getRunnableSnaps } from '../snaps';\nimport type {\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n SignatureStateChange,\n SignatureControllerState,\n StateSignature,\n TransactionControllerTransactionStatusUpdatedEvent,\n} from '../types';\n\nconst controllerName = 'SnapInsightsController';\n\nexport type SnapInsightsControllerAllowedActions =\n | HandleSnapRequest\n | GetAllSnaps\n | GetPermissions\n | DeleteInterface;\n\nexport type SnapInsightsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightsControllerActions =\n SnapInsightsControllerGetStateAction;\n\nexport type SnapInsightControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightControllerEvents = SnapInsightControllerStateChangeEvent;\n\nexport type SnapInsightsControllerAllowedEvents =\n | TransactionControllerUnapprovedTransactionAddedEvent\n | TransactionControllerTransactionStatusUpdatedEvent\n | SignatureStateChange;\n\nexport type SnapInsightsControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInsightsControllerActions | SnapInsightsControllerAllowedActions,\n SnapInsightControllerEvents | SnapInsightsControllerAllowedEvents,\n SnapInsightsControllerAllowedActions['type'],\n SnapInsightsControllerAllowedEvents['type']\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: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { insights: {}, ...state },\n });\n\n this.messagingSystem.subscribe(\n 'TransactionController:unapprovedTransactionAdded',\n this.#handleTransaction.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'TransactionController:transactionStatusUpdated',\n this.#handleTransactionStatusUpdate.bind(this),\n );\n\n this.messagingSystem.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 allSnaps = this.messagingSystem.call('SnapController:getAll');\n const filteredSnaps = getRunnableSnaps(allSnaps);\n\n return filteredSnaps.reduce<SnapWithPermission[]>((accumulator, snap) => {\n const permissions = this.messagingSystem.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:${parseInt(chainId, 16)}`;\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.messagingSystem.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.messagingSystem.call('SnapController:handleRequest', {\n snapId,\n origin: '',\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 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"]}
1
+ {"version":3,"file":"SnapInsightsController.mjs","sourceRoot":"","sources":["../../src/insights/SnapInsightsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n Caveat,\n GetPermissions,\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 } from '@metamask/utils';\n\nimport type { DeleteInterface } from '../interface';\nimport type { GetAllSnaps, HandleSnapRequest } from '../snaps';\nimport { getRunnableSnaps } from '../snaps';\nimport type {\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n SignatureStateChange,\n SignatureControllerState,\n StateSignature,\n TransactionControllerTransactionStatusUpdatedEvent,\n} from '../types';\n\nconst controllerName = 'SnapInsightsController';\n\nexport type SnapInsightsControllerAllowedActions =\n | HandleSnapRequest\n | GetAllSnaps\n | GetPermissions\n | DeleteInterface;\n\nexport type SnapInsightsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightsControllerActions =\n SnapInsightsControllerGetStateAction;\n\nexport type SnapInsightControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapInsightsControllerState\n>;\n\nexport type SnapInsightControllerEvents = SnapInsightControllerStateChangeEvent;\n\nexport type SnapInsightsControllerAllowedEvents =\n | TransactionControllerUnapprovedTransactionAddedEvent\n | TransactionControllerTransactionStatusUpdatedEvent\n | SignatureStateChange;\n\nexport type SnapInsightsControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInsightsControllerActions | SnapInsightsControllerAllowedActions,\n SnapInsightControllerEvents | SnapInsightsControllerAllowedEvents,\n SnapInsightsControllerAllowedActions['type'],\n SnapInsightsControllerAllowedEvents['type']\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: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { insights: {}, ...state },\n });\n\n this.messagingSystem.subscribe(\n 'TransactionController:unapprovedTransactionAdded',\n this.#handleTransaction.bind(this),\n );\n\n this.messagingSystem.subscribe(\n 'TransactionController:transactionStatusUpdated',\n this.#handleTransactionStatusUpdate.bind(this),\n );\n\n this.messagingSystem.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 allSnaps = this.messagingSystem.call('SnapController:getAll');\n const filteredSnaps = getRunnableSnaps(allSnaps);\n\n return filteredSnaps.reduce<SnapWithPermission[]>((accumulator, snap) => {\n const permissions = this.messagingSystem.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:${parseInt(chainId, 16)}`;\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.messagingSystem.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.messagingSystem.call('SnapController:handleRequest', {\n snapId,\n origin: '',\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"]}
@@ -74,16 +74,21 @@ class SnapInterfaceController extends base_controller_1.BaseController {
74
74
  * @param snapId - The snap id requesting the update.
75
75
  * @param id - The interface id.
76
76
  * @param content - The new content.
77
+ * @param context - An optional interface context object.
77
78
  */
78
- async updateInterface(snapId, id, content) {
79
+ async updateInterface(snapId, id, content, context) {
79
80
  __classPrivateFieldGet(this, _SnapInterfaceController_instances, "m", _SnapInterfaceController_validateArgs).call(this, snapId, id);
80
81
  const element = (0, utils_2.getJsxInterface)(content);
81
82
  await __classPrivateFieldGet(this, _SnapInterfaceController_instances, "m", _SnapInterfaceController_validateContent).call(this, element);
83
+ (0, utils_2.validateInterfaceContext)(context);
82
84
  const oldState = this.state.interfaces[id].state;
83
85
  const newState = (0, utils_2.constructState)(oldState, element);
84
86
  this.update((draftState) => {
85
87
  draftState.interfaces[id].state = newState;
86
88
  draftState.interfaces[id].content = (0, immer_1.castDraft)(element);
89
+ if (context) {
90
+ draftState.interfaces[id].context = context;
91
+ }
87
92
  });
88
93
  }
89
94
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInterfaceController.cjs","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AcceptRequest,\n HasApprovalRequest,\n} from '@metamask/approval-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n MaybeUpdateState,\n TestOrigin,\n} from '@metamask/phishing-controller';\nimport type {\n InterfaceState,\n SnapId,\n ComponentOrElement,\n InterfaceContext,\n} from '@metamask/snaps-sdk';\nimport type { JSXElement } from '@metamask/snaps-sdk/jsx';\nimport { getJsonSizeUnsafe, validateJsxLinks } from '@metamask/snaps-utils';\nimport type { Json } from '@metamask/utils';\nimport { assert } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { nanoid } from 'nanoid';\n\nimport type { GetSnap } from '../snaps';\nimport {\n constructState,\n getJsxInterface,\n validateInterfaceContext,\n} from './utils';\n\nconst MAX_UI_CONTENT_SIZE = 10_000_000; // 10 mb\n\nconst controllerName = 'SnapInterfaceController';\n\nexport type CreateInterface = {\n type: `${typeof controllerName}:createInterface`;\n handler: SnapInterfaceController['createInterface'];\n};\n\nexport type GetInterface = {\n type: `${typeof controllerName}:getInterface`;\n handler: SnapInterfaceController['getInterface'];\n};\n\nexport type UpdateInterface = {\n type: `${typeof controllerName}:updateInterface`;\n handler: SnapInterfaceController['updateInterface'];\n};\n\nexport type DeleteInterface = {\n type: `${typeof controllerName}:deleteInterface`;\n handler: SnapInterfaceController['deleteInterface'];\n};\n\nexport type UpdateInterfaceState = {\n type: `${typeof controllerName}:updateInterfaceState`;\n handler: SnapInterfaceController['updateInterfaceState'];\n};\n\nexport type ResolveInterface = {\n type: `${typeof controllerName}:resolveInterface`;\n handler: SnapInterfaceController['resolveInterface'];\n};\n\nexport type SnapInterfaceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInterfaceControllerState\n>;\n\nexport type SnapInterfaceControllerAllowedActions =\n | TestOrigin\n | MaybeUpdateState\n | HasApprovalRequest\n | AcceptRequest\n | GetSnap;\n\nexport type SnapInterfaceControllerActions =\n | CreateInterface\n | GetInterface\n | UpdateInterface\n | DeleteInterface\n | UpdateInterfaceState\n | ResolveInterface\n | SnapInterfaceControllerGetStateAction;\n\nexport type SnapInterfaceControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n SnapInterfaceControllerState\n >;\n\nexport type SnapInterfaceControllerEvents =\n SnapInterfaceControllerStateChangeEvent;\n\nexport type SnapInterfaceControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInterfaceControllerActions | SnapInterfaceControllerAllowedActions,\n SnapInterfaceControllerEvents,\n SnapInterfaceControllerAllowedActions['type'],\n SnapInterfaceControllerEvents['type']\n>;\n\nexport type StoredInterface = {\n snapId: SnapId;\n content: JSXElement;\n state: InterfaceState;\n context: InterfaceContext | null;\n};\n\nexport type SnapInterfaceControllerState = {\n interfaces: Record<string, StoredInterface>;\n};\n\nexport type SnapInterfaceControllerArgs = {\n messenger: SnapInterfaceControllerMessenger;\n state?: SnapInterfaceControllerState;\n};\n\n/**\n * Use this controller to manage snaps UI interfaces using RPC method hooks.\n */\nexport class SnapInterfaceController extends BaseController<\n typeof controllerName,\n SnapInterfaceControllerState,\n SnapInterfaceControllerMessenger\n> {\n constructor({ messenger, state }: SnapInterfaceControllerArgs) {\n super({\n messenger,\n metadata: {\n interfaces: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { interfaces: {}, ...state },\n });\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:createInterface`,\n this.createInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:getInterface`,\n this.getInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterface`,\n this.updateInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:deleteInterface`,\n this.deleteInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterfaceState`,\n this.updateInterfaceState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:resolveInterface`,\n this.resolveInterface.bind(this),\n );\n }\n\n /**\n * Create an interface in the controller state with the associated data.\n *\n * @param snapId - The snap id that created the interface.\n * @param content - The interface content.\n * @param context - An optional interface context object.\n * @returns The newly interface id.\n */\n async createInterface(\n snapId: SnapId,\n content: ComponentOrElement,\n context?: InterfaceContext,\n ) {\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n validateInterfaceContext(context);\n\n const id = nanoid();\n const componentState = constructState({}, element);\n\n this.update((draftState) => {\n // @ts-expect-error - TS2589: Type instantiation is excessively deep and\n // possibly infinite.\n draftState.interfaces[id] = {\n snapId,\n content: castDraft(element),\n state: componentState,\n context: context ?? null,\n };\n });\n\n return id;\n }\n\n /**\n * Get the data of a given interface id.\n *\n * @param snapId - The snap id requesting the interface data.\n * @param id - The interface id.\n * @returns The interface state.\n */\n getInterface(snapId: SnapId, id: string) {\n this.#validateArgs(snapId, id);\n\n return this.state.interfaces[id];\n }\n\n /**\n * Update the interface with the given content.\n *\n * @param snapId - The snap id requesting the update.\n * @param id - The interface id.\n * @param content - The new content.\n */\n async updateInterface(\n snapId: SnapId,\n id: string,\n content: ComponentOrElement,\n ) {\n this.#validateArgs(snapId, id);\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n\n const oldState = this.state.interfaces[id].state;\n const newState = constructState(oldState, element);\n\n this.update((draftState) => {\n draftState.interfaces[id].state = newState;\n draftState.interfaces[id].content = castDraft(element);\n });\n }\n\n /**\n * Delete an interface from state.\n *\n * @param id - The interface id.\n */\n deleteInterface(id: string) {\n this.update((draftState) => {\n delete draftState.interfaces[id];\n });\n }\n\n /**\n * Update the interface state.\n *\n * @param id - The interface id.\n * @param state - The new state.\n */\n updateInterfaceState(id: string, state: InterfaceState) {\n this.update((draftState) => {\n draftState.interfaces[id].state = state;\n });\n }\n\n /**\n * Resolve the promise of a given interface approval request.\n * The approval needs to have the same ID as the interface.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async resolveInterface(snapId: SnapId, id: string, value: Json) {\n this.#validateArgs(snapId, id);\n this.#validateApproval(id);\n\n await this.#acceptApprovalRequest(id, value);\n\n this.deleteInterface(id);\n }\n\n /**\n * Utility function to validate the args passed to the other methods.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n */\n #validateArgs(snapId: SnapId, id: string) {\n const existingInterface = this.state.interfaces[id];\n\n assert(\n existingInterface !== undefined,\n `Interface with id '${id}' not found.`,\n );\n assert(\n existingInterface.snapId === snapId,\n `Interface not created by ${snapId}.`,\n );\n }\n\n /**\n * Utility function to validate that the approval request exists.\n *\n * @param id - The interface id.\n */\n #validateApproval(id: string) {\n assert(\n this.#hasApprovalRequest(id),\n `Approval request with id '${id}' not found.`,\n );\n }\n\n /**\n * Trigger a Phishing list update if needed.\n */\n async #triggerPhishingListUpdate() {\n await this.messagingSystem.call('PhishingController:maybeUpdateState');\n }\n\n /**\n * Check an origin against the phishing list.\n *\n * @param origin - The origin to check.\n * @returns True if the origin is on the phishing list, otherwise false.\n */\n #checkPhishingList(origin: string) {\n return this.messagingSystem.call('PhishingController:testOrigin', origin)\n .result;\n }\n\n /**\n * Check if an approval request exists for a given interface by looking up\n * if the ApprovalController has a request with the given interface ID.\n *\n * @param id - The interface id.\n * @returns True if an approval request exists, otherwise false.\n */\n #hasApprovalRequest(id: string) {\n return this.messagingSystem.call('ApprovalController:hasRequest', {\n id,\n });\n }\n\n /**\n * Accept an approval request for a given interface.\n *\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async #acceptApprovalRequest(id: string, value: Json) {\n await this.messagingSystem.call(\n 'ApprovalController:acceptRequest',\n id,\n value,\n );\n }\n\n /**\n * Utility function to validate the components of an interface.\n * Throws if something is invalid.\n *\n * @param element - The JSX element to verify.\n */\n async #validateContent(element: JSXElement) {\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(element);\n assert(\n size <= MAX_UI_CONTENT_SIZE,\n `A Snap UI may not be larger than ${MAX_UI_CONTENT_SIZE / 1000000} MB.`,\n );\n\n await this.#triggerPhishingListUpdate();\n validateJsxLinks(\n element,\n this.#checkPhishingList.bind(this),\n (id: string) => this.messagingSystem.call('SnapController:get', id),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"SnapInterfaceController.cjs","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AcceptRequest,\n HasApprovalRequest,\n} from '@metamask/approval-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n MaybeUpdateState,\n TestOrigin,\n} from '@metamask/phishing-controller';\nimport type {\n InterfaceState,\n SnapId,\n ComponentOrElement,\n InterfaceContext,\n} from '@metamask/snaps-sdk';\nimport type { JSXElement } from '@metamask/snaps-sdk/jsx';\nimport { getJsonSizeUnsafe, validateJsxLinks } from '@metamask/snaps-utils';\nimport type { Json } from '@metamask/utils';\nimport { assert } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { nanoid } from 'nanoid';\n\nimport type { GetSnap } from '../snaps';\nimport {\n constructState,\n getJsxInterface,\n validateInterfaceContext,\n} from './utils';\n\nconst MAX_UI_CONTENT_SIZE = 10_000_000; // 10 mb\n\nconst controllerName = 'SnapInterfaceController';\n\nexport type CreateInterface = {\n type: `${typeof controllerName}:createInterface`;\n handler: SnapInterfaceController['createInterface'];\n};\n\nexport type GetInterface = {\n type: `${typeof controllerName}:getInterface`;\n handler: SnapInterfaceController['getInterface'];\n};\n\nexport type UpdateInterface = {\n type: `${typeof controllerName}:updateInterface`;\n handler: SnapInterfaceController['updateInterface'];\n};\n\nexport type DeleteInterface = {\n type: `${typeof controllerName}:deleteInterface`;\n handler: SnapInterfaceController['deleteInterface'];\n};\n\nexport type UpdateInterfaceState = {\n type: `${typeof controllerName}:updateInterfaceState`;\n handler: SnapInterfaceController['updateInterfaceState'];\n};\n\nexport type ResolveInterface = {\n type: `${typeof controllerName}:resolveInterface`;\n handler: SnapInterfaceController['resolveInterface'];\n};\n\nexport type SnapInterfaceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInterfaceControllerState\n>;\n\nexport type SnapInterfaceControllerAllowedActions =\n | TestOrigin\n | MaybeUpdateState\n | HasApprovalRequest\n | AcceptRequest\n | GetSnap;\n\nexport type SnapInterfaceControllerActions =\n | CreateInterface\n | GetInterface\n | UpdateInterface\n | DeleteInterface\n | UpdateInterfaceState\n | ResolveInterface\n | SnapInterfaceControllerGetStateAction;\n\nexport type SnapInterfaceControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n SnapInterfaceControllerState\n >;\n\nexport type SnapInterfaceControllerEvents =\n SnapInterfaceControllerStateChangeEvent;\n\nexport type SnapInterfaceControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInterfaceControllerActions | SnapInterfaceControllerAllowedActions,\n SnapInterfaceControllerEvents,\n SnapInterfaceControllerAllowedActions['type'],\n SnapInterfaceControllerEvents['type']\n>;\n\nexport type StoredInterface = {\n snapId: SnapId;\n content: JSXElement;\n state: InterfaceState;\n context: InterfaceContext | null;\n};\n\nexport type SnapInterfaceControllerState = {\n interfaces: Record<string, StoredInterface>;\n};\n\nexport type SnapInterfaceControllerArgs = {\n messenger: SnapInterfaceControllerMessenger;\n state?: SnapInterfaceControllerState;\n};\n\n/**\n * Use this controller to manage snaps UI interfaces using RPC method hooks.\n */\nexport class SnapInterfaceController extends BaseController<\n typeof controllerName,\n SnapInterfaceControllerState,\n SnapInterfaceControllerMessenger\n> {\n constructor({ messenger, state }: SnapInterfaceControllerArgs) {\n super({\n messenger,\n metadata: {\n interfaces: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { interfaces: {}, ...state },\n });\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:createInterface`,\n this.createInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:getInterface`,\n this.getInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterface`,\n this.updateInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:deleteInterface`,\n this.deleteInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterfaceState`,\n this.updateInterfaceState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:resolveInterface`,\n this.resolveInterface.bind(this),\n );\n }\n\n /**\n * Create an interface in the controller state with the associated data.\n *\n * @param snapId - The snap id that created the interface.\n * @param content - The interface content.\n * @param context - An optional interface context object.\n * @returns The newly interface id.\n */\n async createInterface(\n snapId: SnapId,\n content: ComponentOrElement,\n context?: InterfaceContext,\n ) {\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n validateInterfaceContext(context);\n\n const id = nanoid();\n const componentState = constructState({}, element);\n\n this.update((draftState) => {\n // @ts-expect-error - TS2589: Type instantiation is excessively deep and\n // possibly infinite.\n draftState.interfaces[id] = {\n snapId,\n content: castDraft(element),\n state: componentState,\n context: context ?? null,\n };\n });\n\n return id;\n }\n\n /**\n * Get the data of a given interface id.\n *\n * @param snapId - The snap id requesting the interface data.\n * @param id - The interface id.\n * @returns The interface state.\n */\n getInterface(snapId: SnapId, id: string) {\n this.#validateArgs(snapId, id);\n\n return this.state.interfaces[id];\n }\n\n /**\n * Update the interface with the given content.\n *\n * @param snapId - The snap id requesting the update.\n * @param id - The interface id.\n * @param content - The new content.\n * @param context - An optional interface context object.\n */\n async updateInterface(\n snapId: SnapId,\n id: string,\n content: ComponentOrElement,\n context?: InterfaceContext,\n ) {\n this.#validateArgs(snapId, id);\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n validateInterfaceContext(context);\n\n const oldState = this.state.interfaces[id].state;\n const newState = constructState(oldState, element);\n\n this.update((draftState) => {\n draftState.interfaces[id].state = newState;\n draftState.interfaces[id].content = castDraft(element);\n if (context) {\n draftState.interfaces[id].context = context;\n }\n });\n }\n\n /**\n * Delete an interface from state.\n *\n * @param id - The interface id.\n */\n deleteInterface(id: string) {\n this.update((draftState) => {\n delete draftState.interfaces[id];\n });\n }\n\n /**\n * Update the interface state.\n *\n * @param id - The interface id.\n * @param state - The new state.\n */\n updateInterfaceState(id: string, state: InterfaceState) {\n this.update((draftState) => {\n draftState.interfaces[id].state = state;\n });\n }\n\n /**\n * Resolve the promise of a given interface approval request.\n * The approval needs to have the same ID as the interface.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async resolveInterface(snapId: SnapId, id: string, value: Json) {\n this.#validateArgs(snapId, id);\n this.#validateApproval(id);\n\n await this.#acceptApprovalRequest(id, value);\n\n this.deleteInterface(id);\n }\n\n /**\n * Utility function to validate the args passed to the other methods.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n */\n #validateArgs(snapId: SnapId, id: string) {\n const existingInterface = this.state.interfaces[id];\n\n assert(\n existingInterface !== undefined,\n `Interface with id '${id}' not found.`,\n );\n assert(\n existingInterface.snapId === snapId,\n `Interface not created by ${snapId}.`,\n );\n }\n\n /**\n * Utility function to validate that the approval request exists.\n *\n * @param id - The interface id.\n */\n #validateApproval(id: string) {\n assert(\n this.#hasApprovalRequest(id),\n `Approval request with id '${id}' not found.`,\n );\n }\n\n /**\n * Trigger a Phishing list update if needed.\n */\n async #triggerPhishingListUpdate() {\n await this.messagingSystem.call('PhishingController:maybeUpdateState');\n }\n\n /**\n * Check an origin against the phishing list.\n *\n * @param origin - The origin to check.\n * @returns True if the origin is on the phishing list, otherwise false.\n */\n #checkPhishingList(origin: string) {\n return this.messagingSystem.call('PhishingController:testOrigin', origin)\n .result;\n }\n\n /**\n * Check if an approval request exists for a given interface by looking up\n * if the ApprovalController has a request with the given interface ID.\n *\n * @param id - The interface id.\n * @returns True if an approval request exists, otherwise false.\n */\n #hasApprovalRequest(id: string) {\n return this.messagingSystem.call('ApprovalController:hasRequest', {\n id,\n });\n }\n\n /**\n * Accept an approval request for a given interface.\n *\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async #acceptApprovalRequest(id: string, value: Json) {\n await this.messagingSystem.call(\n 'ApprovalController:acceptRequest',\n id,\n value,\n );\n }\n\n /**\n * Utility function to validate the components of an interface.\n * Throws if something is invalid.\n *\n * @param element - The JSX element to verify.\n */\n async #validateContent(element: JSXElement) {\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(element);\n assert(\n size <= MAX_UI_CONTENT_SIZE,\n `A Snap UI may not be larger than ${MAX_UI_CONTENT_SIZE / 1000000} MB.`,\n );\n\n await this.#triggerPhishingListUpdate();\n validateJsxLinks(\n element,\n this.#checkPhishingList.bind(this),\n (id: string) => this.messagingSystem.call('SnapController:get', id),\n );\n }\n}\n"]}
@@ -79,8 +79,9 @@ export declare class SnapInterfaceController extends BaseController<typeof contr
79
79
  * @param snapId - The snap id requesting the update.
80
80
  * @param id - The interface id.
81
81
  * @param content - The new content.
82
+ * @param context - An optional interface context object.
82
83
  */
83
- updateInterface(snapId: SnapId, id: string, content: ComponentOrElement): Promise<void>;
84
+ updateInterface(snapId: SnapId, id: string, content: ComponentOrElement, context?: InterfaceContext): Promise<void>;
84
85
  /**
85
86
  * Delete an interface from state.
86
87
  *
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInterfaceController.d.cts","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SnapInterfaceController.d.cts","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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"}
@@ -79,8 +79,9 @@ export declare class SnapInterfaceController extends BaseController<typeof contr
79
79
  * @param snapId - The snap id requesting the update.
80
80
  * @param id - The interface id.
81
81
  * @param content - The new content.
82
+ * @param context - An optional interface context object.
82
83
  */
83
- updateInterface(snapId: SnapId, id: string, content: ComponentOrElement): Promise<void>;
84
+ updateInterface(snapId: SnapId, id: string, content: ComponentOrElement, context?: InterfaceContext): Promise<void>;
84
85
  /**
85
86
  * Delete an interface from state.
86
87
  *
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInterfaceController.d.mts","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SnapInterfaceController.d.mts","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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"}
@@ -71,16 +71,21 @@ export class SnapInterfaceController extends BaseController {
71
71
  * @param snapId - The snap id requesting the update.
72
72
  * @param id - The interface id.
73
73
  * @param content - The new content.
74
+ * @param context - An optional interface context object.
74
75
  */
75
- async updateInterface(snapId, id, content) {
76
+ async updateInterface(snapId, id, content, context) {
76
77
  __classPrivateFieldGet(this, _SnapInterfaceController_instances, "m", _SnapInterfaceController_validateArgs).call(this, snapId, id);
77
78
  const element = getJsxInterface(content);
78
79
  await __classPrivateFieldGet(this, _SnapInterfaceController_instances, "m", _SnapInterfaceController_validateContent).call(this, element);
80
+ validateInterfaceContext(context);
79
81
  const oldState = this.state.interfaces[id].state;
80
82
  const newState = constructState(oldState, element);
81
83
  this.update((draftState) => {
82
84
  draftState.interfaces[id].state = newState;
83
85
  draftState.interfaces[id].content = castDraft(element);
86
+ if (context) {
87
+ draftState.interfaces[id].context = context;
88
+ }
84
89
  });
85
90
  }
86
91
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"SnapInterfaceController.mjs","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AcceptRequest,\n HasApprovalRequest,\n} from '@metamask/approval-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n MaybeUpdateState,\n TestOrigin,\n} from '@metamask/phishing-controller';\nimport type {\n InterfaceState,\n SnapId,\n ComponentOrElement,\n InterfaceContext,\n} from '@metamask/snaps-sdk';\nimport type { JSXElement } from '@metamask/snaps-sdk/jsx';\nimport { getJsonSizeUnsafe, validateJsxLinks } from '@metamask/snaps-utils';\nimport type { Json } from '@metamask/utils';\nimport { assert } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { nanoid } from 'nanoid';\n\nimport type { GetSnap } from '../snaps';\nimport {\n constructState,\n getJsxInterface,\n validateInterfaceContext,\n} from './utils';\n\nconst MAX_UI_CONTENT_SIZE = 10_000_000; // 10 mb\n\nconst controllerName = 'SnapInterfaceController';\n\nexport type CreateInterface = {\n type: `${typeof controllerName}:createInterface`;\n handler: SnapInterfaceController['createInterface'];\n};\n\nexport type GetInterface = {\n type: `${typeof controllerName}:getInterface`;\n handler: SnapInterfaceController['getInterface'];\n};\n\nexport type UpdateInterface = {\n type: `${typeof controllerName}:updateInterface`;\n handler: SnapInterfaceController['updateInterface'];\n};\n\nexport type DeleteInterface = {\n type: `${typeof controllerName}:deleteInterface`;\n handler: SnapInterfaceController['deleteInterface'];\n};\n\nexport type UpdateInterfaceState = {\n type: `${typeof controllerName}:updateInterfaceState`;\n handler: SnapInterfaceController['updateInterfaceState'];\n};\n\nexport type ResolveInterface = {\n type: `${typeof controllerName}:resolveInterface`;\n handler: SnapInterfaceController['resolveInterface'];\n};\n\nexport type SnapInterfaceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInterfaceControllerState\n>;\n\nexport type SnapInterfaceControllerAllowedActions =\n | TestOrigin\n | MaybeUpdateState\n | HasApprovalRequest\n | AcceptRequest\n | GetSnap;\n\nexport type SnapInterfaceControllerActions =\n | CreateInterface\n | GetInterface\n | UpdateInterface\n | DeleteInterface\n | UpdateInterfaceState\n | ResolveInterface\n | SnapInterfaceControllerGetStateAction;\n\nexport type SnapInterfaceControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n SnapInterfaceControllerState\n >;\n\nexport type SnapInterfaceControllerEvents =\n SnapInterfaceControllerStateChangeEvent;\n\nexport type SnapInterfaceControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInterfaceControllerActions | SnapInterfaceControllerAllowedActions,\n SnapInterfaceControllerEvents,\n SnapInterfaceControllerAllowedActions['type'],\n SnapInterfaceControllerEvents['type']\n>;\n\nexport type StoredInterface = {\n snapId: SnapId;\n content: JSXElement;\n state: InterfaceState;\n context: InterfaceContext | null;\n};\n\nexport type SnapInterfaceControllerState = {\n interfaces: Record<string, StoredInterface>;\n};\n\nexport type SnapInterfaceControllerArgs = {\n messenger: SnapInterfaceControllerMessenger;\n state?: SnapInterfaceControllerState;\n};\n\n/**\n * Use this controller to manage snaps UI interfaces using RPC method hooks.\n */\nexport class SnapInterfaceController extends BaseController<\n typeof controllerName,\n SnapInterfaceControllerState,\n SnapInterfaceControllerMessenger\n> {\n constructor({ messenger, state }: SnapInterfaceControllerArgs) {\n super({\n messenger,\n metadata: {\n interfaces: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { interfaces: {}, ...state },\n });\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:createInterface`,\n this.createInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:getInterface`,\n this.getInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterface`,\n this.updateInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:deleteInterface`,\n this.deleteInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterfaceState`,\n this.updateInterfaceState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:resolveInterface`,\n this.resolveInterface.bind(this),\n );\n }\n\n /**\n * Create an interface in the controller state with the associated data.\n *\n * @param snapId - The snap id that created the interface.\n * @param content - The interface content.\n * @param context - An optional interface context object.\n * @returns The newly interface id.\n */\n async createInterface(\n snapId: SnapId,\n content: ComponentOrElement,\n context?: InterfaceContext,\n ) {\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n validateInterfaceContext(context);\n\n const id = nanoid();\n const componentState = constructState({}, element);\n\n this.update((draftState) => {\n // @ts-expect-error - TS2589: Type instantiation is excessively deep and\n // possibly infinite.\n draftState.interfaces[id] = {\n snapId,\n content: castDraft(element),\n state: componentState,\n context: context ?? null,\n };\n });\n\n return id;\n }\n\n /**\n * Get the data of a given interface id.\n *\n * @param snapId - The snap id requesting the interface data.\n * @param id - The interface id.\n * @returns The interface state.\n */\n getInterface(snapId: SnapId, id: string) {\n this.#validateArgs(snapId, id);\n\n return this.state.interfaces[id];\n }\n\n /**\n * Update the interface with the given content.\n *\n * @param snapId - The snap id requesting the update.\n * @param id - The interface id.\n * @param content - The new content.\n */\n async updateInterface(\n snapId: SnapId,\n id: string,\n content: ComponentOrElement,\n ) {\n this.#validateArgs(snapId, id);\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n\n const oldState = this.state.interfaces[id].state;\n const newState = constructState(oldState, element);\n\n this.update((draftState) => {\n draftState.interfaces[id].state = newState;\n draftState.interfaces[id].content = castDraft(element);\n });\n }\n\n /**\n * Delete an interface from state.\n *\n * @param id - The interface id.\n */\n deleteInterface(id: string) {\n this.update((draftState) => {\n delete draftState.interfaces[id];\n });\n }\n\n /**\n * Update the interface state.\n *\n * @param id - The interface id.\n * @param state - The new state.\n */\n updateInterfaceState(id: string, state: InterfaceState) {\n this.update((draftState) => {\n draftState.interfaces[id].state = state;\n });\n }\n\n /**\n * Resolve the promise of a given interface approval request.\n * The approval needs to have the same ID as the interface.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async resolveInterface(snapId: SnapId, id: string, value: Json) {\n this.#validateArgs(snapId, id);\n this.#validateApproval(id);\n\n await this.#acceptApprovalRequest(id, value);\n\n this.deleteInterface(id);\n }\n\n /**\n * Utility function to validate the args passed to the other methods.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n */\n #validateArgs(snapId: SnapId, id: string) {\n const existingInterface = this.state.interfaces[id];\n\n assert(\n existingInterface !== undefined,\n `Interface with id '${id}' not found.`,\n );\n assert(\n existingInterface.snapId === snapId,\n `Interface not created by ${snapId}.`,\n );\n }\n\n /**\n * Utility function to validate that the approval request exists.\n *\n * @param id - The interface id.\n */\n #validateApproval(id: string) {\n assert(\n this.#hasApprovalRequest(id),\n `Approval request with id '${id}' not found.`,\n );\n }\n\n /**\n * Trigger a Phishing list update if needed.\n */\n async #triggerPhishingListUpdate() {\n await this.messagingSystem.call('PhishingController:maybeUpdateState');\n }\n\n /**\n * Check an origin against the phishing list.\n *\n * @param origin - The origin to check.\n * @returns True if the origin is on the phishing list, otherwise false.\n */\n #checkPhishingList(origin: string) {\n return this.messagingSystem.call('PhishingController:testOrigin', origin)\n .result;\n }\n\n /**\n * Check if an approval request exists for a given interface by looking up\n * if the ApprovalController has a request with the given interface ID.\n *\n * @param id - The interface id.\n * @returns True if an approval request exists, otherwise false.\n */\n #hasApprovalRequest(id: string) {\n return this.messagingSystem.call('ApprovalController:hasRequest', {\n id,\n });\n }\n\n /**\n * Accept an approval request for a given interface.\n *\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async #acceptApprovalRequest(id: string, value: Json) {\n await this.messagingSystem.call(\n 'ApprovalController:acceptRequest',\n id,\n value,\n );\n }\n\n /**\n * Utility function to validate the components of an interface.\n * Throws if something is invalid.\n *\n * @param element - The JSX element to verify.\n */\n async #validateContent(element: JSXElement) {\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(element);\n assert(\n size <= MAX_UI_CONTENT_SIZE,\n `A Snap UI may not be larger than ${MAX_UI_CONTENT_SIZE / 1000000} MB.`,\n );\n\n await this.#triggerPhishingListUpdate();\n validateJsxLinks(\n element,\n this.#checkPhishingList.bind(this),\n (id: string) => this.messagingSystem.call('SnapController:get', id),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"SnapInterfaceController.mjs","sourceRoot":"","sources":["../../src/interface/SnapInterfaceController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AcceptRequest,\n HasApprovalRequest,\n} from '@metamask/approval-controller';\nimport type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n MaybeUpdateState,\n TestOrigin,\n} from '@metamask/phishing-controller';\nimport type {\n InterfaceState,\n SnapId,\n ComponentOrElement,\n InterfaceContext,\n} from '@metamask/snaps-sdk';\nimport type { JSXElement } from '@metamask/snaps-sdk/jsx';\nimport { getJsonSizeUnsafe, validateJsxLinks } from '@metamask/snaps-utils';\nimport type { Json } from '@metamask/utils';\nimport { assert } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { nanoid } from 'nanoid';\n\nimport type { GetSnap } from '../snaps';\nimport {\n constructState,\n getJsxInterface,\n validateInterfaceContext,\n} from './utils';\n\nconst MAX_UI_CONTENT_SIZE = 10_000_000; // 10 mb\n\nconst controllerName = 'SnapInterfaceController';\n\nexport type CreateInterface = {\n type: `${typeof controllerName}:createInterface`;\n handler: SnapInterfaceController['createInterface'];\n};\n\nexport type GetInterface = {\n type: `${typeof controllerName}:getInterface`;\n handler: SnapInterfaceController['getInterface'];\n};\n\nexport type UpdateInterface = {\n type: `${typeof controllerName}:updateInterface`;\n handler: SnapInterfaceController['updateInterface'];\n};\n\nexport type DeleteInterface = {\n type: `${typeof controllerName}:deleteInterface`;\n handler: SnapInterfaceController['deleteInterface'];\n};\n\nexport type UpdateInterfaceState = {\n type: `${typeof controllerName}:updateInterfaceState`;\n handler: SnapInterfaceController['updateInterfaceState'];\n};\n\nexport type ResolveInterface = {\n type: `${typeof controllerName}:resolveInterface`;\n handler: SnapInterfaceController['resolveInterface'];\n};\n\nexport type SnapInterfaceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapInterfaceControllerState\n>;\n\nexport type SnapInterfaceControllerAllowedActions =\n | TestOrigin\n | MaybeUpdateState\n | HasApprovalRequest\n | AcceptRequest\n | GetSnap;\n\nexport type SnapInterfaceControllerActions =\n | CreateInterface\n | GetInterface\n | UpdateInterface\n | DeleteInterface\n | UpdateInterfaceState\n | ResolveInterface\n | SnapInterfaceControllerGetStateAction;\n\nexport type SnapInterfaceControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n SnapInterfaceControllerState\n >;\n\nexport type SnapInterfaceControllerEvents =\n SnapInterfaceControllerStateChangeEvent;\n\nexport type SnapInterfaceControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n SnapInterfaceControllerActions | SnapInterfaceControllerAllowedActions,\n SnapInterfaceControllerEvents,\n SnapInterfaceControllerAllowedActions['type'],\n SnapInterfaceControllerEvents['type']\n>;\n\nexport type StoredInterface = {\n snapId: SnapId;\n content: JSXElement;\n state: InterfaceState;\n context: InterfaceContext | null;\n};\n\nexport type SnapInterfaceControllerState = {\n interfaces: Record<string, StoredInterface>;\n};\n\nexport type SnapInterfaceControllerArgs = {\n messenger: SnapInterfaceControllerMessenger;\n state?: SnapInterfaceControllerState;\n};\n\n/**\n * Use this controller to manage snaps UI interfaces using RPC method hooks.\n */\nexport class SnapInterfaceController extends BaseController<\n typeof controllerName,\n SnapInterfaceControllerState,\n SnapInterfaceControllerMessenger\n> {\n constructor({ messenger, state }: SnapInterfaceControllerArgs) {\n super({\n messenger,\n metadata: {\n interfaces: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: { interfaces: {}, ...state },\n });\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:createInterface`,\n this.createInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:getInterface`,\n this.getInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterface`,\n this.updateInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:deleteInterface`,\n this.deleteInterface.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateInterfaceState`,\n this.updateInterfaceState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:resolveInterface`,\n this.resolveInterface.bind(this),\n );\n }\n\n /**\n * Create an interface in the controller state with the associated data.\n *\n * @param snapId - The snap id that created the interface.\n * @param content - The interface content.\n * @param context - An optional interface context object.\n * @returns The newly interface id.\n */\n async createInterface(\n snapId: SnapId,\n content: ComponentOrElement,\n context?: InterfaceContext,\n ) {\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n validateInterfaceContext(context);\n\n const id = nanoid();\n const componentState = constructState({}, element);\n\n this.update((draftState) => {\n // @ts-expect-error - TS2589: Type instantiation is excessively deep and\n // possibly infinite.\n draftState.interfaces[id] = {\n snapId,\n content: castDraft(element),\n state: componentState,\n context: context ?? null,\n };\n });\n\n return id;\n }\n\n /**\n * Get the data of a given interface id.\n *\n * @param snapId - The snap id requesting the interface data.\n * @param id - The interface id.\n * @returns The interface state.\n */\n getInterface(snapId: SnapId, id: string) {\n this.#validateArgs(snapId, id);\n\n return this.state.interfaces[id];\n }\n\n /**\n * Update the interface with the given content.\n *\n * @param snapId - The snap id requesting the update.\n * @param id - The interface id.\n * @param content - The new content.\n * @param context - An optional interface context object.\n */\n async updateInterface(\n snapId: SnapId,\n id: string,\n content: ComponentOrElement,\n context?: InterfaceContext,\n ) {\n this.#validateArgs(snapId, id);\n const element = getJsxInterface(content);\n await this.#validateContent(element);\n validateInterfaceContext(context);\n\n const oldState = this.state.interfaces[id].state;\n const newState = constructState(oldState, element);\n\n this.update((draftState) => {\n draftState.interfaces[id].state = newState;\n draftState.interfaces[id].content = castDraft(element);\n if (context) {\n draftState.interfaces[id].context = context;\n }\n });\n }\n\n /**\n * Delete an interface from state.\n *\n * @param id - The interface id.\n */\n deleteInterface(id: string) {\n this.update((draftState) => {\n delete draftState.interfaces[id];\n });\n }\n\n /**\n * Update the interface state.\n *\n * @param id - The interface id.\n * @param state - The new state.\n */\n updateInterfaceState(id: string, state: InterfaceState) {\n this.update((draftState) => {\n draftState.interfaces[id].state = state;\n });\n }\n\n /**\n * Resolve the promise of a given interface approval request.\n * The approval needs to have the same ID as the interface.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async resolveInterface(snapId: SnapId, id: string, value: Json) {\n this.#validateArgs(snapId, id);\n this.#validateApproval(id);\n\n await this.#acceptApprovalRequest(id, value);\n\n this.deleteInterface(id);\n }\n\n /**\n * Utility function to validate the args passed to the other methods.\n *\n * @param snapId - The snap id.\n * @param id - The interface id.\n */\n #validateArgs(snapId: SnapId, id: string) {\n const existingInterface = this.state.interfaces[id];\n\n assert(\n existingInterface !== undefined,\n `Interface with id '${id}' not found.`,\n );\n assert(\n existingInterface.snapId === snapId,\n `Interface not created by ${snapId}.`,\n );\n }\n\n /**\n * Utility function to validate that the approval request exists.\n *\n * @param id - The interface id.\n */\n #validateApproval(id: string) {\n assert(\n this.#hasApprovalRequest(id),\n `Approval request with id '${id}' not found.`,\n );\n }\n\n /**\n * Trigger a Phishing list update if needed.\n */\n async #triggerPhishingListUpdate() {\n await this.messagingSystem.call('PhishingController:maybeUpdateState');\n }\n\n /**\n * Check an origin against the phishing list.\n *\n * @param origin - The origin to check.\n * @returns True if the origin is on the phishing list, otherwise false.\n */\n #checkPhishingList(origin: string) {\n return this.messagingSystem.call('PhishingController:testOrigin', origin)\n .result;\n }\n\n /**\n * Check if an approval request exists for a given interface by looking up\n * if the ApprovalController has a request with the given interface ID.\n *\n * @param id - The interface id.\n * @returns True if an approval request exists, otherwise false.\n */\n #hasApprovalRequest(id: string) {\n return this.messagingSystem.call('ApprovalController:hasRequest', {\n id,\n });\n }\n\n /**\n * Accept an approval request for a given interface.\n *\n * @param id - The interface id.\n * @param value - The value to resolve the promise with.\n */\n async #acceptApprovalRequest(id: string, value: Json) {\n await this.messagingSystem.call(\n 'ApprovalController:acceptRequest',\n id,\n value,\n );\n }\n\n /**\n * Utility function to validate the components of an interface.\n * Throws if something is invalid.\n *\n * @param element - The JSX element to verify.\n */\n async #validateContent(element: JSXElement) {\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(element);\n assert(\n size <= MAX_UI_CONTENT_SIZE,\n `A Snap UI may not be larger than ${MAX_UI_CONTENT_SIZE / 1000000} MB.`,\n );\n\n await this.#triggerPhishingListUpdate();\n validateJsxLinks(\n element,\n this.#checkPhishingList.bind(this),\n (id: string) => this.messagingSystem.call('SnapController:get', id),\n );\n }\n}\n"]}
@@ -71,8 +71,6 @@ function getComponentStateValue(element) {
71
71
  switch (element.type) {
72
72
  case 'Checkbox':
73
73
  return element.props.checked;
74
- case 'AccountSelector':
75
- return element.props.selectedAddress;
76
74
  default:
77
75
  return element.props.value;
78
76
  }
@@ -127,8 +125,7 @@ function constructState(oldState, rootComponent) {
127
125
  component.type === 'RadioGroup' ||
128
126
  component.type === 'FileInput' ||
129
127
  component.type === 'Checkbox' ||
130
- component.type === 'Selector' ||
131
- component.type === 'AccountSelector')) {
128
+ component.type === 'Selector')) {
132
129
  const formState = newState[currentForm.name];
133
130
  assertNameIsUnique(formState, component.props.name);
134
131
  formState[component.props.name] = constructInputState(oldState, component, currentForm.name);
@@ -140,8 +137,7 @@ function constructState(oldState, rootComponent) {
140
137
  component.type === 'RadioGroup' ||
141
138
  component.type === 'FileInput' ||
142
139
  component.type === 'Checkbox' ||
143
- component.type === 'Selector' ||
144
- component.type === 'AccountSelector') {
140
+ component.type === 'Selector') {
145
141
  assertNameIsUnique(newState, component.props.name);
146
142
  newState[component.props.name] = constructInputState(oldState, component);
147
143
  }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert } from '@metamask/snaps-sdk';\nimport type {\n FormState,\n InterfaceState,\n ComponentOrElement,\n InterfaceContext,\n State,\n} from '@metamask/snaps-sdk';\nimport type {\n DropdownElement,\n InputElement,\n JSXElement,\n OptionElement,\n FileInputElement,\n CheckboxElement,\n RadioGroupElement,\n RadioElement,\n SelectorElement,\n SelectorOptionElement,\n AccountSelectorElement,\n} from '@metamask/snaps-sdk/jsx';\nimport { isJSXElementUnsafe } from '@metamask/snaps-sdk/jsx';\nimport {\n getJsonSizeUnsafe,\n getJsxChildren,\n getJsxElementFromComponent,\n walkJsx,\n} from '@metamask/snaps-utils';\n\n/**\n * Get a JSX element from a component or JSX element. If the component is a\n * JSX element, it is returned as is. Otherwise, the component is converted to\n * a JSX element.\n *\n * @param component - The component to convert.\n * @returns The JSX element.\n */\nexport function getJsxInterface(component: ComponentOrElement): JSXElement {\n if (isJSXElementUnsafe(component)) {\n return component;\n }\n\n return getJsxElementFromComponent(component);\n}\n\n/**\n * Assert that the component name is unique in state.\n *\n * @param state - The interface state to verify against.\n * @param name - The component name to verify.\n */\nexport function assertNameIsUnique(state: InterfaceState, name: string) {\n assert(\n state[name] === undefined,\n `Duplicate component names are not allowed, found multiple instances of: \"${name}\".`,\n );\n}\n\n/**\n * Construct default state for a component.\n *\n * This function is meant to be used inside constructInputState to account\n * for component specific defaults and will not override the component value or existing form state.\n *\n * @param element - The input element.\n * @returns The default state for the specific component, if any.\n */\nfunction constructComponentSpecificDefaultState(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement\n | AccountSelectorElement,\n) {\n switch (element.type) {\n case 'Dropdown': {\n const children = getJsxChildren(element) as OptionElement[];\n return children[0]?.props.value;\n }\n\n case 'RadioGroup': {\n const children = getJsxChildren(element) as RadioElement[];\n return children[0]?.props.value;\n }\n\n case 'Selector': {\n const children = getJsxChildren(element) as SelectorOptionElement[];\n return children[0]?.props.value;\n }\n\n case 'Checkbox':\n return false;\n\n default:\n return null;\n }\n}\n\n/**\n * Get the state value for a stateful component.\n *\n * Most components store the state value as a `value` prop.\n * This function exists to account for components where that isn't the case.\n *\n * @param element - The input element.\n * @returns The state value for a given component.\n */\nfunction getComponentStateValue(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement\n | AccountSelectorElement,\n) {\n switch (element.type) {\n case 'Checkbox':\n return element.props.checked;\n\n case 'AccountSelector':\n return element.props.selectedAddress;\n\n default:\n return element.props.value;\n }\n}\n\n/**\n * Construct the state for an input field.\n *\n * @param oldState - The previous state.\n * @param element - The input element.\n * @param form - An optional form that the input is enclosed in.\n * @returns The input state.\n */\nfunction constructInputState(\n oldState: InterfaceState,\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | FileInputElement\n | CheckboxElement\n | SelectorElement\n | AccountSelectorElement,\n form?: string,\n) {\n const oldStateUnwrapped = form ? (oldState[form] as FormState) : oldState;\n const oldInputState = oldStateUnwrapped?.[element.props.name] as State;\n\n if (element.type === 'FileInput') {\n return oldInputState ?? null;\n }\n\n return (\n getComponentStateValue(element) ??\n oldInputState ??\n constructComponentSpecificDefaultState(element) ??\n null\n );\n}\n\n/**\n * Construct the interface state for a given component tree.\n *\n * @param oldState - The previous state.\n * @param rootComponent - The UI component to construct state from.\n * @returns The interface state of the passed component.\n */\nexport function constructState(\n oldState: InterfaceState,\n rootComponent: JSXElement,\n): InterfaceState {\n const newState: InterfaceState = {};\n\n // Stack containing the forms we have visited and at which depth\n const formStack: { name: string; depth: number }[] = [];\n\n walkJsx(rootComponent, (component, depth) => {\n let currentForm = formStack[formStack.length - 1];\n\n // Pop the current form of the stack once we leave its depth.\n if (currentForm && depth <= currentForm.depth) {\n formStack.pop();\n currentForm = formStack[formStack.length - 1];\n }\n\n if (component.type === 'Form') {\n assertNameIsUnique(newState, component.props.name);\n formStack.push({ name: component.props.name, depth });\n newState[component.props.name] = {};\n return;\n }\n\n // Stateful components inside a form\n if (\n currentForm &&\n (component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector' ||\n component.type === 'AccountSelector')\n ) {\n const formState = newState[currentForm.name] as FormState;\n assertNameIsUnique(formState, component.props.name);\n formState[component.props.name] = constructInputState(\n oldState,\n component,\n currentForm.name,\n );\n return;\n }\n\n // Stateful components outside a form\n if (\n component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector' ||\n component.type === 'AccountSelector'\n ) {\n assertNameIsUnique(newState, component.props.name);\n newState[component.props.name] = constructInputState(oldState, component);\n }\n });\n\n return newState;\n}\n\nconst MAX_CONTEXT_SIZE = 1_000_000; // 1 mb\n\n/**\n * Validate a JSON blob to be used as the interface context.\n *\n * @param context - The JSON blob.\n * @throws If the JSON blob is too large.\n */\nexport function validateInterfaceContext(context?: InterfaceContext) {\n if (!context) {\n return;\n }\n\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(context);\n assert(\n size <= MAX_CONTEXT_SIZE,\n `A Snap interface context may not be larger than ${\n MAX_CONTEXT_SIZE / 1000000\n } MB.`,\n );\n}\n"]}
1
+ {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert } from '@metamask/snaps-sdk';\nimport type {\n FormState,\n InterfaceState,\n ComponentOrElement,\n InterfaceContext,\n State,\n} from '@metamask/snaps-sdk';\nimport type {\n DropdownElement,\n InputElement,\n JSXElement,\n OptionElement,\n FileInputElement,\n CheckboxElement,\n RadioGroupElement,\n RadioElement,\n SelectorElement,\n SelectorOptionElement,\n} from '@metamask/snaps-sdk/jsx';\nimport { isJSXElementUnsafe } from '@metamask/snaps-sdk/jsx';\nimport {\n getJsonSizeUnsafe,\n getJsxChildren,\n getJsxElementFromComponent,\n walkJsx,\n} from '@metamask/snaps-utils';\n\n/**\n * Get a JSX element from a component or JSX element. If the component is a\n * JSX element, it is returned as is. Otherwise, the component is converted to\n * a JSX element.\n *\n * @param component - The component to convert.\n * @returns The JSX element.\n */\nexport function getJsxInterface(component: ComponentOrElement): JSXElement {\n if (isJSXElementUnsafe(component)) {\n return component;\n }\n\n return getJsxElementFromComponent(component);\n}\n\n/**\n * Assert that the component name is unique in state.\n *\n * @param state - The interface state to verify against.\n * @param name - The component name to verify.\n */\nexport function assertNameIsUnique(state: InterfaceState, name: string) {\n assert(\n state[name] === undefined,\n `Duplicate component names are not allowed, found multiple instances of: \"${name}\".`,\n );\n}\n\n/**\n * Construct default state for a component.\n *\n * This function is meant to be used inside constructInputState to account\n * for component specific defaults and will not override the component value or existing form state.\n *\n * @param element - The input element.\n * @returns The default state for the specific component, if any.\n */\nfunction constructComponentSpecificDefaultState(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement,\n) {\n switch (element.type) {\n case 'Dropdown': {\n const children = getJsxChildren(element) as OptionElement[];\n return children[0]?.props.value;\n }\n\n case 'RadioGroup': {\n const children = getJsxChildren(element) as RadioElement[];\n return children[0]?.props.value;\n }\n\n case 'Selector': {\n const children = getJsxChildren(element) as SelectorOptionElement[];\n return children[0]?.props.value;\n }\n\n case 'Checkbox':\n return false;\n\n default:\n return null;\n }\n}\n\n/**\n * Get the state value for a stateful component.\n *\n * Most components store the state value as a `value` prop.\n * This function exists to account for components where that isn't the case.\n *\n * @param element - The input element.\n * @returns The state value for a given component.\n */\nfunction getComponentStateValue(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement,\n) {\n switch (element.type) {\n case 'Checkbox':\n return element.props.checked;\n\n default:\n return element.props.value;\n }\n}\n\n/**\n * Construct the state for an input field.\n *\n * @param oldState - The previous state.\n * @param element - The input element.\n * @param form - An optional form that the input is enclosed in.\n * @returns The input state.\n */\nfunction constructInputState(\n oldState: InterfaceState,\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | FileInputElement\n | CheckboxElement\n | SelectorElement,\n form?: string,\n) {\n const oldStateUnwrapped = form ? (oldState[form] as FormState) : oldState;\n const oldInputState = oldStateUnwrapped?.[element.props.name] as State;\n\n if (element.type === 'FileInput') {\n return oldInputState ?? null;\n }\n\n return (\n getComponentStateValue(element) ??\n oldInputState ??\n constructComponentSpecificDefaultState(element) ??\n null\n );\n}\n\n/**\n * Construct the interface state for a given component tree.\n *\n * @param oldState - The previous state.\n * @param rootComponent - The UI component to construct state from.\n * @returns The interface state of the passed component.\n */\nexport function constructState(\n oldState: InterfaceState,\n rootComponent: JSXElement,\n): InterfaceState {\n const newState: InterfaceState = {};\n\n // Stack containing the forms we have visited and at which depth\n const formStack: { name: string; depth: number }[] = [];\n\n walkJsx(rootComponent, (component, depth) => {\n let currentForm = formStack[formStack.length - 1];\n\n // Pop the current form of the stack once we leave its depth.\n if (currentForm && depth <= currentForm.depth) {\n formStack.pop();\n currentForm = formStack[formStack.length - 1];\n }\n\n if (component.type === 'Form') {\n assertNameIsUnique(newState, component.props.name);\n formStack.push({ name: component.props.name, depth });\n newState[component.props.name] = {};\n return;\n }\n\n // Stateful components inside a form\n if (\n currentForm &&\n (component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector')\n ) {\n const formState = newState[currentForm.name] as FormState;\n assertNameIsUnique(formState, component.props.name);\n formState[component.props.name] = constructInputState(\n oldState,\n component,\n currentForm.name,\n );\n return;\n }\n\n // Stateful components outside a form\n if (\n component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector'\n ) {\n assertNameIsUnique(newState, component.props.name);\n newState[component.props.name] = constructInputState(oldState, component);\n }\n });\n\n return newState;\n}\n\nconst MAX_CONTEXT_SIZE = 1_000_000; // 1 mb\n\n/**\n * Validate a JSON blob to be used as the interface context.\n *\n * @param context - The JSON blob.\n * @throws If the JSON blob is too large.\n */\nexport function validateInterfaceContext(context?: InterfaceContext) {\n if (!context) {\n return;\n }\n\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(context);\n assert(\n size <= MAX_CONTEXT_SIZE,\n `A Snap interface context may not be larger than ${\n MAX_CONTEXT_SIZE / 1000000\n } MB.`,\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAEjB,4BAA4B;AAC7B,OAAO,KAAK,EAGV,UAAU,EASX,gCAAgC;AASjC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,kBAAkB,GAAG,UAAU,CAMzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,QAKrE;AA6GD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,UAAU,GACxB,cAAc,CA2DhB;AAID;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,gBAAgB,QAclE"}
1
+ {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAEjB,4BAA4B;AAC7B,OAAO,KAAK,EAGV,UAAU,EAQX,gCAAgC;AASjC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,kBAAkB,GAAG,UAAU,CAMzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,QAKrE;AAuGD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,UAAU,GACxB,cAAc,CAyDhB;AAID;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,gBAAgB,QAclE"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAEjB,4BAA4B;AAC7B,OAAO,KAAK,EAGV,UAAU,EASX,gCAAgC;AASjC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,kBAAkB,GAAG,UAAU,CAMzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,QAKrE;AA6GD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,UAAU,GACxB,cAAc,CA2DhB;AAID;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,gBAAgB,QAclE"}
1
+ {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAEjB,4BAA4B;AAC7B,OAAO,KAAK,EAGV,UAAU,EAQX,gCAAgC;AASjC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,kBAAkB,GAAG,UAAU,CAMzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,QAKrE;AAuGD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,UAAU,GACxB,cAAc,CAyDhB;AAID;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,gBAAgB,QAclE"}
@@ -66,8 +66,6 @@ function getComponentStateValue(element) {
66
66
  switch (element.type) {
67
67
  case 'Checkbox':
68
68
  return element.props.checked;
69
- case 'AccountSelector':
70
- return element.props.selectedAddress;
71
69
  default:
72
70
  return element.props.value;
73
71
  }
@@ -122,8 +120,7 @@ export function constructState(oldState, rootComponent) {
122
120
  component.type === 'RadioGroup' ||
123
121
  component.type === 'FileInput' ||
124
122
  component.type === 'Checkbox' ||
125
- component.type === 'Selector' ||
126
- component.type === 'AccountSelector')) {
123
+ component.type === 'Selector')) {
127
124
  const formState = newState[currentForm.name];
128
125
  assertNameIsUnique(formState, component.props.name);
129
126
  formState[component.props.name] = constructInputState(oldState, component, currentForm.name);
@@ -135,8 +132,7 @@ export function constructState(oldState, rootComponent) {
135
132
  component.type === 'RadioGroup' ||
136
133
  component.type === 'FileInput' ||
137
134
  component.type === 'Checkbox' ||
138
- component.type === 'Selector' ||
139
- component.type === 'AccountSelector') {
135
+ component.type === 'Selector') {
140
136
  assertNameIsUnique(newState, component.props.name);
141
137
  newState[component.props.name] = constructInputState(oldState, component);
142
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert } from '@metamask/snaps-sdk';\nimport type {\n FormState,\n InterfaceState,\n ComponentOrElement,\n InterfaceContext,\n State,\n} from '@metamask/snaps-sdk';\nimport type {\n DropdownElement,\n InputElement,\n JSXElement,\n OptionElement,\n FileInputElement,\n CheckboxElement,\n RadioGroupElement,\n RadioElement,\n SelectorElement,\n SelectorOptionElement,\n AccountSelectorElement,\n} from '@metamask/snaps-sdk/jsx';\nimport { isJSXElementUnsafe } from '@metamask/snaps-sdk/jsx';\nimport {\n getJsonSizeUnsafe,\n getJsxChildren,\n getJsxElementFromComponent,\n walkJsx,\n} from '@metamask/snaps-utils';\n\n/**\n * Get a JSX element from a component or JSX element. If the component is a\n * JSX element, it is returned as is. Otherwise, the component is converted to\n * a JSX element.\n *\n * @param component - The component to convert.\n * @returns The JSX element.\n */\nexport function getJsxInterface(component: ComponentOrElement): JSXElement {\n if (isJSXElementUnsafe(component)) {\n return component;\n }\n\n return getJsxElementFromComponent(component);\n}\n\n/**\n * Assert that the component name is unique in state.\n *\n * @param state - The interface state to verify against.\n * @param name - The component name to verify.\n */\nexport function assertNameIsUnique(state: InterfaceState, name: string) {\n assert(\n state[name] === undefined,\n `Duplicate component names are not allowed, found multiple instances of: \"${name}\".`,\n );\n}\n\n/**\n * Construct default state for a component.\n *\n * This function is meant to be used inside constructInputState to account\n * for component specific defaults and will not override the component value or existing form state.\n *\n * @param element - The input element.\n * @returns The default state for the specific component, if any.\n */\nfunction constructComponentSpecificDefaultState(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement\n | AccountSelectorElement,\n) {\n switch (element.type) {\n case 'Dropdown': {\n const children = getJsxChildren(element) as OptionElement[];\n return children[0]?.props.value;\n }\n\n case 'RadioGroup': {\n const children = getJsxChildren(element) as RadioElement[];\n return children[0]?.props.value;\n }\n\n case 'Selector': {\n const children = getJsxChildren(element) as SelectorOptionElement[];\n return children[0]?.props.value;\n }\n\n case 'Checkbox':\n return false;\n\n default:\n return null;\n }\n}\n\n/**\n * Get the state value for a stateful component.\n *\n * Most components store the state value as a `value` prop.\n * This function exists to account for components where that isn't the case.\n *\n * @param element - The input element.\n * @returns The state value for a given component.\n */\nfunction getComponentStateValue(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement\n | AccountSelectorElement,\n) {\n switch (element.type) {\n case 'Checkbox':\n return element.props.checked;\n\n case 'AccountSelector':\n return element.props.selectedAddress;\n\n default:\n return element.props.value;\n }\n}\n\n/**\n * Construct the state for an input field.\n *\n * @param oldState - The previous state.\n * @param element - The input element.\n * @param form - An optional form that the input is enclosed in.\n * @returns The input state.\n */\nfunction constructInputState(\n oldState: InterfaceState,\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | FileInputElement\n | CheckboxElement\n | SelectorElement\n | AccountSelectorElement,\n form?: string,\n) {\n const oldStateUnwrapped = form ? (oldState[form] as FormState) : oldState;\n const oldInputState = oldStateUnwrapped?.[element.props.name] as State;\n\n if (element.type === 'FileInput') {\n return oldInputState ?? null;\n }\n\n return (\n getComponentStateValue(element) ??\n oldInputState ??\n constructComponentSpecificDefaultState(element) ??\n null\n );\n}\n\n/**\n * Construct the interface state for a given component tree.\n *\n * @param oldState - The previous state.\n * @param rootComponent - The UI component to construct state from.\n * @returns The interface state of the passed component.\n */\nexport function constructState(\n oldState: InterfaceState,\n rootComponent: JSXElement,\n): InterfaceState {\n const newState: InterfaceState = {};\n\n // Stack containing the forms we have visited and at which depth\n const formStack: { name: string; depth: number }[] = [];\n\n walkJsx(rootComponent, (component, depth) => {\n let currentForm = formStack[formStack.length - 1];\n\n // Pop the current form of the stack once we leave its depth.\n if (currentForm && depth <= currentForm.depth) {\n formStack.pop();\n currentForm = formStack[formStack.length - 1];\n }\n\n if (component.type === 'Form') {\n assertNameIsUnique(newState, component.props.name);\n formStack.push({ name: component.props.name, depth });\n newState[component.props.name] = {};\n return;\n }\n\n // Stateful components inside a form\n if (\n currentForm &&\n (component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector' ||\n component.type === 'AccountSelector')\n ) {\n const formState = newState[currentForm.name] as FormState;\n assertNameIsUnique(formState, component.props.name);\n formState[component.props.name] = constructInputState(\n oldState,\n component,\n currentForm.name,\n );\n return;\n }\n\n // Stateful components outside a form\n if (\n component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector' ||\n component.type === 'AccountSelector'\n ) {\n assertNameIsUnique(newState, component.props.name);\n newState[component.props.name] = constructInputState(oldState, component);\n }\n });\n\n return newState;\n}\n\nconst MAX_CONTEXT_SIZE = 1_000_000; // 1 mb\n\n/**\n * Validate a JSON blob to be used as the interface context.\n *\n * @param context - The JSON blob.\n * @throws If the JSON blob is too large.\n */\nexport function validateInterfaceContext(context?: InterfaceContext) {\n if (!context) {\n return;\n }\n\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(context);\n assert(\n size <= MAX_CONTEXT_SIZE,\n `A Snap interface context may not be larger than ${\n MAX_CONTEXT_SIZE / 1000000\n } MB.`,\n );\n}\n"]}
1
+ {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../src/interface/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,4BAA4B;AAoB7C,OAAO,EAAE,kBAAkB,EAAE,gCAAgC;AAC7D,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,0BAA0B,EAC1B,OAAO,EACR,8BAA8B;AAE/B;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,SAA6B;IAC3D,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,0BAA0B,CAAC,SAAS,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAqB,EAAE,IAAY;IACpE,MAAM,CACJ,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,EACzB,4EAA4E,IAAI,IAAI,CACrF,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,sCAAsC,CAC7C,OAKmB;IAEnB,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAoB,CAAC;YAC5D,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QAClC,CAAC;QAED,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAmB,CAAC;YAC3D,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QAClC,CAAC;QAED,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAA4B,CAAC;YACpE,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QAClC,CAAC;QAED,KAAK,UAAU;YACb,OAAO,KAAK,CAAC;QAEf;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,sBAAsB,CAC7B,OAKmB;IAEnB,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,UAAU;YACb,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;QAE/B;YACE,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAC1B,QAAwB,EACxB,OAMmB,EACnB,IAAa;IAEb,MAAM,iBAAiB,GAAG,IAAI,CAAC,CAAC,CAAE,QAAQ,CAAC,IAAI,CAAe,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1E,MAAM,aAAa,GAAG,iBAAiB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAU,CAAC;IAEvE,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACjC,OAAO,aAAa,IAAI,IAAI,CAAC;IAC/B,CAAC;IAED,OAAO,CACL,sBAAsB,CAAC,OAAO,CAAC;QAC/B,aAAa;QACb,sCAAsC,CAAC,OAAO,CAAC;QAC/C,IAAI,CACL,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAwB,EACxB,aAAyB;IAEzB,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,gEAAgE;IAChE,MAAM,SAAS,GAAsC,EAAE,CAAC;IAExD,OAAO,CAAC,aAAa,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;QAC1C,IAAI,WAAW,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAElD,6DAA6D;QAC7D,IAAI,WAAW,IAAI,KAAK,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;YAC9C,SAAS,CAAC,GAAG,EAAE,CAAC;YAChB,WAAW,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC9B,kBAAkB,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnD,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACpC,OAAO;QACT,CAAC;QAED,oCAAoC;QACpC,IACE,WAAW;YACX,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO;gBACzB,SAAS,CAAC,IAAI,KAAK,UAAU;gBAC7B,SAAS,CAAC,IAAI,KAAK,YAAY;gBAC/B,SAAS,CAAC,IAAI,KAAK,WAAW;gBAC9B,SAAS,CAAC,IAAI,KAAK,UAAU;gBAC7B,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC,EAChC,CAAC;YACD,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAc,CAAC;YAC1D,kBAAkB,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpD,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,mBAAmB,CACnD,QAAQ,EACR,SAAS,EACT,WAAW,CAAC,IAAI,CACjB,CAAC;YACF,OAAO;QACT,CAAC;QAED,qCAAqC;QACrC,IACE,SAAS,CAAC,IAAI,KAAK,OAAO;YAC1B,SAAS,CAAC,IAAI,KAAK,UAAU;YAC7B,SAAS,CAAC,IAAI,KAAK,YAAY;YAC/B,SAAS,CAAC,IAAI,KAAK,WAAW;YAC9B,SAAS,CAAC,IAAI,KAAK,UAAU;YAC7B,SAAS,CAAC,IAAI,KAAK,UAAU,EAC7B,CAAC;YACD,kBAAkB,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnD,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,gBAAgB,GAAG,OAAS,CAAC,CAAC,OAAO;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAA0B;IACjE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAED,qEAAqE;IACrE,0CAA0C;IAC1C,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,CACJ,IAAI,IAAI,gBAAgB,EACxB,mDACE,gBAAgB,GAAG,OACrB,MAAM,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { assert } from '@metamask/snaps-sdk';\nimport type {\n FormState,\n InterfaceState,\n ComponentOrElement,\n InterfaceContext,\n State,\n} from '@metamask/snaps-sdk';\nimport type {\n DropdownElement,\n InputElement,\n JSXElement,\n OptionElement,\n FileInputElement,\n CheckboxElement,\n RadioGroupElement,\n RadioElement,\n SelectorElement,\n SelectorOptionElement,\n} from '@metamask/snaps-sdk/jsx';\nimport { isJSXElementUnsafe } from '@metamask/snaps-sdk/jsx';\nimport {\n getJsonSizeUnsafe,\n getJsxChildren,\n getJsxElementFromComponent,\n walkJsx,\n} from '@metamask/snaps-utils';\n\n/**\n * Get a JSX element from a component or JSX element. If the component is a\n * JSX element, it is returned as is. Otherwise, the component is converted to\n * a JSX element.\n *\n * @param component - The component to convert.\n * @returns The JSX element.\n */\nexport function getJsxInterface(component: ComponentOrElement): JSXElement {\n if (isJSXElementUnsafe(component)) {\n return component;\n }\n\n return getJsxElementFromComponent(component);\n}\n\n/**\n * Assert that the component name is unique in state.\n *\n * @param state - The interface state to verify against.\n * @param name - The component name to verify.\n */\nexport function assertNameIsUnique(state: InterfaceState, name: string) {\n assert(\n state[name] === undefined,\n `Duplicate component names are not allowed, found multiple instances of: \"${name}\".`,\n );\n}\n\n/**\n * Construct default state for a component.\n *\n * This function is meant to be used inside constructInputState to account\n * for component specific defaults and will not override the component value or existing form state.\n *\n * @param element - The input element.\n * @returns The default state for the specific component, if any.\n */\nfunction constructComponentSpecificDefaultState(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement,\n) {\n switch (element.type) {\n case 'Dropdown': {\n const children = getJsxChildren(element) as OptionElement[];\n return children[0]?.props.value;\n }\n\n case 'RadioGroup': {\n const children = getJsxChildren(element) as RadioElement[];\n return children[0]?.props.value;\n }\n\n case 'Selector': {\n const children = getJsxChildren(element) as SelectorOptionElement[];\n return children[0]?.props.value;\n }\n\n case 'Checkbox':\n return false;\n\n default:\n return null;\n }\n}\n\n/**\n * Get the state value for a stateful component.\n *\n * Most components store the state value as a `value` prop.\n * This function exists to account for components where that isn't the case.\n *\n * @param element - The input element.\n * @returns The state value for a given component.\n */\nfunction getComponentStateValue(\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | CheckboxElement\n | SelectorElement,\n) {\n switch (element.type) {\n case 'Checkbox':\n return element.props.checked;\n\n default:\n return element.props.value;\n }\n}\n\n/**\n * Construct the state for an input field.\n *\n * @param oldState - The previous state.\n * @param element - The input element.\n * @param form - An optional form that the input is enclosed in.\n * @returns The input state.\n */\nfunction constructInputState(\n oldState: InterfaceState,\n element:\n | InputElement\n | DropdownElement\n | RadioGroupElement\n | FileInputElement\n | CheckboxElement\n | SelectorElement,\n form?: string,\n) {\n const oldStateUnwrapped = form ? (oldState[form] as FormState) : oldState;\n const oldInputState = oldStateUnwrapped?.[element.props.name] as State;\n\n if (element.type === 'FileInput') {\n return oldInputState ?? null;\n }\n\n return (\n getComponentStateValue(element) ??\n oldInputState ??\n constructComponentSpecificDefaultState(element) ??\n null\n );\n}\n\n/**\n * Construct the interface state for a given component tree.\n *\n * @param oldState - The previous state.\n * @param rootComponent - The UI component to construct state from.\n * @returns The interface state of the passed component.\n */\nexport function constructState(\n oldState: InterfaceState,\n rootComponent: JSXElement,\n): InterfaceState {\n const newState: InterfaceState = {};\n\n // Stack containing the forms we have visited and at which depth\n const formStack: { name: string; depth: number }[] = [];\n\n walkJsx(rootComponent, (component, depth) => {\n let currentForm = formStack[formStack.length - 1];\n\n // Pop the current form of the stack once we leave its depth.\n if (currentForm && depth <= currentForm.depth) {\n formStack.pop();\n currentForm = formStack[formStack.length - 1];\n }\n\n if (component.type === 'Form') {\n assertNameIsUnique(newState, component.props.name);\n formStack.push({ name: component.props.name, depth });\n newState[component.props.name] = {};\n return;\n }\n\n // Stateful components inside a form\n if (\n currentForm &&\n (component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector')\n ) {\n const formState = newState[currentForm.name] as FormState;\n assertNameIsUnique(formState, component.props.name);\n formState[component.props.name] = constructInputState(\n oldState,\n component,\n currentForm.name,\n );\n return;\n }\n\n // Stateful components outside a form\n if (\n component.type === 'Input' ||\n component.type === 'Dropdown' ||\n component.type === 'RadioGroup' ||\n component.type === 'FileInput' ||\n component.type === 'Checkbox' ||\n component.type === 'Selector'\n ) {\n assertNameIsUnique(newState, component.props.name);\n newState[component.props.name] = constructInputState(oldState, component);\n }\n });\n\n return newState;\n}\n\nconst MAX_CONTEXT_SIZE = 1_000_000; // 1 mb\n\n/**\n * Validate a JSON blob to be used as the interface context.\n *\n * @param context - The JSON blob.\n * @throws If the JSON blob is too large.\n */\nexport function validateInterfaceContext(context?: InterfaceContext) {\n if (!context) {\n return;\n }\n\n // We assume the validity of this JSON to be validated by the caller.\n // E.g., in the RPC method implementation.\n const size = getJsonSizeUnsafe(context);\n assert(\n size <= MAX_CONTEXT_SIZE,\n `A Snap interface context may not be larger than ${\n MAX_CONTEXT_SIZE / 1000000\n } MB.`,\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/snaps-controllers",
3
- "version": "9.10.0",
3
+ "version": "9.11.1",
4
4
  "description": "Controllers for MetaMask Snaps",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -89,9 +89,9 @@
89
89
  "@metamask/post-message-stream": "^8.1.1",
90
90
  "@metamask/rpc-errors": "^6.3.1",
91
91
  "@metamask/snaps-registry": "^3.2.1",
92
- "@metamask/snaps-rpc-methods": "^11.3.0",
93
- "@metamask/snaps-sdk": "^6.7.0",
94
- "@metamask/snaps-utils": "^8.3.0",
92
+ "@metamask/snaps-rpc-methods": "^11.5.0",
93
+ "@metamask/snaps-sdk": "^6.9.0",
94
+ "@metamask/snaps-utils": "^8.4.1",
95
95
  "@metamask/utils": "^9.2.1",
96
96
  "@xstate/fsm": "^2.0.0",
97
97
  "browserify-zlib": "^0.2.0",
@@ -165,7 +165,7 @@
165
165
  "webdriverio": "^8.19.0"
166
166
  },
167
167
  "peerDependencies": {
168
- "@metamask/snaps-execution-environments": "^6.9.0"
168
+ "@metamask/snaps-execution-environments": "^6.9.1"
169
169
  },
170
170
  "peerDependenciesMeta": {
171
171
  "@metamask/snaps-execution-environments": {