@metamask-previews/compliance-controller 2.0.1-preview-681bd3562 → 2.0.1-preview-d3514bcb5
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 +9 -0
- package/README.md +2 -5
- package/dist/ComplianceController.cjs +4 -3
- package/dist/ComplianceController.cjs.map +1 -1
- package/dist/ComplianceController.d.cts.map +1 -1
- package/dist/ComplianceController.d.mts.map +1 -1
- package/dist/ComplianceController.mjs +4 -3
- package/dist/ComplianceController.mjs.map +1 -1
- package/dist/ComplianceService.cjs +27 -7
- package/dist/ComplianceService.cjs.map +1 -1
- package/dist/ComplianceService.d.cts +20 -9
- package/dist/ComplianceService.d.cts.map +1 -1
- package/dist/ComplianceService.d.mts +20 -9
- package/dist/ComplianceService.d.mts.map +1 -1
- package/dist/ComplianceService.mjs +27 -7
- package/dist/ComplianceService.mjs.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/selectors.cjs +13 -2
- package/dist/selectors.cjs.map +1 -1
- package/dist/selectors.d.cts +9 -0
- package/dist/selectors.d.cts.map +1 -1
- package/dist/selectors.d.mts +9 -0
- package/dist/selectors.d.mts.map +1 -1
- package/dist/selectors.mjs +11 -1
- package/dist/selectors.mjs.map +1 -1
- package/dist/utils.cjs +15 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +3 -0
- package/dist/utils.d.cts.map +1 -0
- package/dist/utils.d.mts +3 -0
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +11 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,10 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add `ComplianceService` support for an explicit Compliance API URL ([#8820](https://github.com/MetaMask/core/pull/8820)).
|
|
13
|
+
- Add `selectAreAnyWalletsBlocked` ([#8820](https://github.com/MetaMask/core/pull/8820)).
|
|
14
|
+
|
|
10
15
|
### Changed
|
|
11
16
|
|
|
12
17
|
- Bump `@metamask/controller-utils` from `^12.0.0` to `^12.1.0` ([#8774](https://github.com/MetaMask/core/pull/8774))
|
|
13
18
|
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Match EVM address casing consistently when reading cached wallet compliance statuses ([#8820](https://github.com/MetaMask/core/pull/8820)).
|
|
22
|
+
|
|
14
23
|
## [2.0.1]
|
|
15
24
|
|
|
16
25
|
### Changed
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Manages OFAC compliance checks for wallet addresses by interfacing with the Comp
|
|
|
7
7
|
This package provides:
|
|
8
8
|
|
|
9
9
|
- **`ComplianceService`** — A data service that communicates with the Compliance API to check whether wallet addresses are sanctioned under OFAC regulations.
|
|
10
|
-
- **`ComplianceController`** — A controller that manages compliance state, caching wallet compliance results
|
|
10
|
+
- **`ComplianceController`** — A controller that manages compliance state, caching wallet compliance results.
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -47,7 +47,7 @@ const serviceMessenger = new Messenger({
|
|
|
47
47
|
new ComplianceService({
|
|
48
48
|
messenger: serviceMessenger,
|
|
49
49
|
fetch,
|
|
50
|
-
|
|
50
|
+
apiUrl: 'https://compliance.api.cx.metamask.io',
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
// Create controller messenger and controller
|
|
@@ -70,9 +70,6 @@ await rootMessenger.call('ComplianceController:checkWalletsCompliance', [
|
|
|
70
70
|
'0x1234...',
|
|
71
71
|
'0x5678...',
|
|
72
72
|
]);
|
|
73
|
-
|
|
74
|
-
// Fetch the full blocked wallets list
|
|
75
|
-
await rootMessenger.call('ComplianceController:updateBlockedWallets');
|
|
76
73
|
```
|
|
77
74
|
|
|
78
75
|
## Contributing
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ComplianceController = exports.getDefaultComplianceControllerState = exports.controllerName = void 0;
|
|
4
4
|
const base_controller_1 = require("@metamask/base-controller");
|
|
5
|
+
const utils_1 = require("./utils.cjs");
|
|
5
6
|
// === GENERAL ===
|
|
6
7
|
/**
|
|
7
8
|
* The name of the {@link ComplianceController}, used to namespace the
|
|
@@ -100,7 +101,7 @@ class ComplianceController extends base_controller_1.BaseController {
|
|
|
100
101
|
return status;
|
|
101
102
|
}
|
|
102
103
|
catch (error) {
|
|
103
|
-
const cached = this.state.walletComplianceStatusMap
|
|
104
|
+
const cached = (0, utils_1.getWalletComplianceStatus)(this.state.walletComplianceStatusMap, address);
|
|
104
105
|
if (cached) {
|
|
105
106
|
return cached;
|
|
106
107
|
}
|
|
@@ -136,8 +137,8 @@ class ComplianceController extends base_controller_1.BaseController {
|
|
|
136
137
|
return statuses;
|
|
137
138
|
}
|
|
138
139
|
catch (error) {
|
|
139
|
-
const cachedStatuses = addresses.map((address) => this.state.walletComplianceStatusMap
|
|
140
|
-
if (cachedStatuses.every(Boolean)) {
|
|
140
|
+
const cachedStatuses = addresses.map((address) => (0, utils_1.getWalletComplianceStatus)(this.state.walletComplianceStatusMap, address));
|
|
141
|
+
if (cachedStatuses.every((status) => Boolean(status))) {
|
|
141
142
|
return cachedStatuses;
|
|
142
143
|
}
|
|
143
144
|
throw error;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceController.cjs","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { ComplianceControllerMethodActions } from './ComplianceController-method-action-types';\nimport type {\n ComplianceServiceCheckWalletComplianceAction,\n ComplianceServiceCheckWalletsComplianceAction,\n} from './ComplianceService-method-action-types';\nimport type { WalletComplianceStatus } from './types';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'ComplianceController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link ComplianceController}.\n */\nexport type ComplianceControllerState = {\n /**\n * A map of wallet addresses to their compliance check results, used as a\n * fallback cache when the API is unavailable.\n */\n walletComplianceStatusMap: Record<string, WalletComplianceStatus>;\n\n /**\n * The date/time (in ISO-8601 format) when the last compliance check was\n * performed, or `null` if no checks have been performed yet.\n */\n lastCheckedAt: string | null;\n};\n\n/**\n * The metadata for each property in {@link ComplianceControllerState}.\n */\nconst complianceControllerMetadata = {\n walletComplianceStatusMap: {\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n persist: true,\n usedInUi: true,\n },\n lastCheckedAt: {\n includeInDebugSnapshot: false,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<ComplianceControllerState>;\n\n/**\n * Constructs the default {@link ComplianceController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link ComplianceController} state.\n */\nexport function getDefaultComplianceControllerState(): ComplianceControllerState {\n return {\n walletComplianceStatusMap: {},\n lastCheckedAt: null,\n };\n}\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n 'clearComplianceState',\n] as const;\n\n/**\n * Retrieves the state of the {@link ComplianceController}.\n */\nexport type ComplianceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Actions that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerActions =\n | ComplianceControllerGetStateAction\n | ComplianceControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceController} calls.\n */\ntype AllowedActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction;\n\n/**\n * Published when the state of {@link ComplianceController} changes.\n */\nexport type ComplianceControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Events that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerEvents = ComplianceControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link ComplianceController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceController}.\n */\nexport type ComplianceControllerMessenger = Messenger<\n typeof controllerName,\n ComplianceControllerActions | AllowedActions,\n ComplianceControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * `ComplianceController` manages OFAC compliance state for wallet addresses.\n * It performs on-demand compliance checks via the API and caches results\n * per address in state. Cached results serve as a fallback if the API is\n * unavailable for a subsequent check on the same address.\n */\nexport class ComplianceController extends BaseController<\n typeof controllerName,\n ComplianceControllerState,\n ComplianceControllerMessenger\n> {\n /**\n * Constructs a new {@link ComplianceController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to init this\n * controller. Missing properties will be filled in with defaults.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: ComplianceControllerMessenger;\n state?: Partial<ComplianceControllerState>;\n }) {\n super({\n messenger,\n metadata: complianceControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultComplianceControllerState(),\n ...state,\n },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Checks compliance status for a single wallet address via the API and\n * persists the result to state. If the API call fails and a previously\n * cached result exists for the address, the cached result is returned as a\n * fallback. If no cached result exists, the error is re-thrown.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(\n address: string,\n ): Promise<WalletComplianceStatus> {\n try {\n const result = await this.messenger.call(\n 'ComplianceService:checkWalletCompliance',\n address,\n );\n\n const now = new Date().toISOString();\n const status: WalletComplianceStatus = {\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n };\n\n this.update((draftState) => {\n draftState.walletComplianceStatusMap[address] = status;\n draftState.lastCheckedAt = now;\n });\n\n return status;\n } catch (error) {\n const cached = this.state.walletComplianceStatusMap[address];\n if (cached) {\n return cached;\n }\n throw error;\n }\n }\n\n /**\n * Checks compliance status for multiple wallet addresses via the API and\n * persists the results to state. If the API call fails and every requested\n * address has a previously cached result, those cached results are returned\n * as a fallback. If any address lacks a cached result, the error is\n * re-thrown.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<WalletComplianceStatus[]> {\n try {\n const results = await this.messenger.call(\n 'ComplianceService:checkWalletsCompliance',\n addresses,\n );\n\n const now = new Date().toISOString();\n const statuses: WalletComplianceStatus[] = results.map((result) => ({\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n }));\n\n this.update((draftState) => {\n for (let idx = 0; idx < statuses.length; idx++) {\n const callerAddress = addresses[idx];\n draftState.walletComplianceStatusMap[callerAddress] = statuses[idx];\n }\n draftState.lastCheckedAt = now;\n });\n\n return statuses;\n } catch (error) {\n const cachedStatuses = addresses.map(\n (address) => this.state.walletComplianceStatusMap[address],\n );\n if (cachedStatuses.every(Boolean)) {\n return cachedStatuses;\n }\n throw error;\n }\n }\n\n /**\n * Clears all compliance data from state.\n */\n clearComplianceState(): void {\n this.update((draftState) => {\n draftState.walletComplianceStatusMap = {};\n draftState.lastCheckedAt = null;\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ComplianceController.cjs","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { ComplianceControllerMethodActions } from './ComplianceController-method-action-types';\nimport type {\n ComplianceServiceCheckWalletComplianceAction,\n ComplianceServiceCheckWalletsComplianceAction,\n} from './ComplianceService-method-action-types';\nimport type { WalletComplianceStatus } from './types';\nimport { getWalletComplianceStatus } from './utils';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'ComplianceController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link ComplianceController}.\n */\nexport type ComplianceControllerState = {\n /**\n * A map of wallet addresses to their compliance check results, used as a\n * fallback cache when the API is unavailable.\n */\n walletComplianceStatusMap: Record<string, WalletComplianceStatus>;\n\n /**\n * The date/time (in ISO-8601 format) when the last compliance check was\n * performed, or `null` if no checks have been performed yet.\n */\n lastCheckedAt: string | null;\n};\n\n/**\n * The metadata for each property in {@link ComplianceControllerState}.\n */\nconst complianceControllerMetadata = {\n walletComplianceStatusMap: {\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n persist: true,\n usedInUi: true,\n },\n lastCheckedAt: {\n includeInDebugSnapshot: false,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<ComplianceControllerState>;\n\n/**\n * Constructs the default {@link ComplianceController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link ComplianceController} state.\n */\nexport function getDefaultComplianceControllerState(): ComplianceControllerState {\n return {\n walletComplianceStatusMap: {},\n lastCheckedAt: null,\n };\n}\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n 'clearComplianceState',\n] as const;\n\n/**\n * Retrieves the state of the {@link ComplianceController}.\n */\nexport type ComplianceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Actions that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerActions =\n | ComplianceControllerGetStateAction\n | ComplianceControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceController} calls.\n */\ntype AllowedActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction;\n\n/**\n * Published when the state of {@link ComplianceController} changes.\n */\nexport type ComplianceControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Events that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerEvents = ComplianceControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link ComplianceController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceController}.\n */\nexport type ComplianceControllerMessenger = Messenger<\n typeof controllerName,\n ComplianceControllerActions | AllowedActions,\n ComplianceControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * `ComplianceController` manages OFAC compliance state for wallet addresses.\n * It performs on-demand compliance checks via the API and caches results\n * per address in state. Cached results serve as a fallback if the API is\n * unavailable for a subsequent check on the same address.\n */\nexport class ComplianceController extends BaseController<\n typeof controllerName,\n ComplianceControllerState,\n ComplianceControllerMessenger\n> {\n /**\n * Constructs a new {@link ComplianceController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to init this\n * controller. Missing properties will be filled in with defaults.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: ComplianceControllerMessenger;\n state?: Partial<ComplianceControllerState>;\n }) {\n super({\n messenger,\n metadata: complianceControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultComplianceControllerState(),\n ...state,\n },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Checks compliance status for a single wallet address via the API and\n * persists the result to state. If the API call fails and a previously\n * cached result exists for the address, the cached result is returned as a\n * fallback. If no cached result exists, the error is re-thrown.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(\n address: string,\n ): Promise<WalletComplianceStatus> {\n try {\n const result = await this.messenger.call(\n 'ComplianceService:checkWalletCompliance',\n address,\n );\n\n const now = new Date().toISOString();\n const status: WalletComplianceStatus = {\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n };\n\n this.update((draftState) => {\n draftState.walletComplianceStatusMap[address] = status;\n draftState.lastCheckedAt = now;\n });\n\n return status;\n } catch (error) {\n const cached = getWalletComplianceStatus(\n this.state.walletComplianceStatusMap,\n address,\n );\n if (cached) {\n return cached;\n }\n throw error;\n }\n }\n\n /**\n * Checks compliance status for multiple wallet addresses via the API and\n * persists the results to state. If the API call fails and every requested\n * address has a previously cached result, those cached results are returned\n * as a fallback. If any address lacks a cached result, the error is\n * re-thrown.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<WalletComplianceStatus[]> {\n try {\n const results = await this.messenger.call(\n 'ComplianceService:checkWalletsCompliance',\n addresses,\n );\n\n const now = new Date().toISOString();\n const statuses: WalletComplianceStatus[] = results.map((result) => ({\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n }));\n\n this.update((draftState) => {\n for (let idx = 0; idx < statuses.length; idx++) {\n const callerAddress = addresses[idx];\n draftState.walletComplianceStatusMap[callerAddress] = statuses[idx];\n }\n draftState.lastCheckedAt = now;\n });\n\n return statuses;\n } catch (error) {\n const cachedStatuses = addresses.map((address) =>\n getWalletComplianceStatus(\n this.state.walletComplianceStatusMap,\n address,\n ),\n );\n if (\n cachedStatuses.every((status): status is WalletComplianceStatus =>\n Boolean(status),\n )\n ) {\n return cachedStatuses;\n }\n throw error;\n }\n }\n\n /**\n * Clears all compliance data from state.\n */\n clearComplianceState(): void {\n this.update((draftState) => {\n draftState.walletComplianceStatusMap = {};\n draftState.lastCheckedAt = null;\n });\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceController.d.cts","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,iCAAiC,EAAE,uDAAmD;AACpG,OAAO,KAAK,EACV,4CAA4C,EAC5C,6CAA6C,EAC9C,oDAAgD;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAgB;
|
|
1
|
+
{"version":3,"file":"ComplianceController.d.cts","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,iCAAiC,EAAE,uDAAmD;AACpG,OAAO,KAAK,EACV,4CAA4C,EAC5C,6CAA6C,EAC9C,oDAAgD;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAgB;AAKtD;;;;GAIG;AACH,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAIrD;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAElE;;;OAGG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAoBF;;;;;;;GAOG;AACH,wBAAgB,mCAAmC,IAAI,yBAAyB,CAK/E;AAUD;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAAG,wBAAwB,CACvE,OAAO,cAAc,EACrB,yBAAyB,CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,kCAAkC,GAClC,iCAAiC,CAAC;AAEtC;;GAEG;AACH,KAAK,cAAc,GACf,4CAA4C,GAC5C,6CAA6C,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG,0BAA0B,CAC3E,OAAO,cAAc,EACrB,yBAAyB,CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG,oCAAoC,CAAC;AAE9E;;GAEG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG,SAAS,CACnD,OAAO,cAAc,EACrB,2BAA2B,GAAG,cAAc,EAC5C,0BAA0B,GAAG,aAAa,CAC3C,CAAC;AAIF;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,cAAc,CACtD,OAAO,cAAc,EACrB,yBAAyB,EACzB,6BAA6B,CAC9B;IACC;;;;;;;OAOG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,6BAA6B,CAAC;QACzC,KAAK,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;KAC5C;IAiBD;;;;;;;;OAQG;IACG,qBAAqB,CACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,sBAAsB,CAAC;IAgClC;;;;;;;;;OASG;IACG,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAyCpC;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAM7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceController.d.mts","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,iCAAiC,EAAE,uDAAmD;AACpG,OAAO,KAAK,EACV,4CAA4C,EAC5C,6CAA6C,EAC9C,oDAAgD;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAgB;
|
|
1
|
+
{"version":3,"file":"ComplianceController.d.mts","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,iCAAiC,EAAE,uDAAmD;AACpG,OAAO,KAAK,EACV,4CAA4C,EAC5C,6CAA6C,EAC9C,oDAAgD;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAgB;AAKtD;;;;GAIG;AACH,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAIrD;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAElE;;;OAGG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAoBF;;;;;;;GAOG;AACH,wBAAgB,mCAAmC,IAAI,yBAAyB,CAK/E;AAUD;;GAEG;AACH,MAAM,MAAM,kCAAkC,GAAG,wBAAwB,CACvE,OAAO,cAAc,EACrB,yBAAyB,CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,kCAAkC,GAClC,iCAAiC,CAAC;AAEtC;;GAEG;AACH,KAAK,cAAc,GACf,4CAA4C,GAC5C,6CAA6C,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG,0BAA0B,CAC3E,OAAO,cAAc,EACrB,yBAAyB,CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG,oCAAoC,CAAC;AAE9E;;GAEG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG,SAAS,CACnD,OAAO,cAAc,EACrB,2BAA2B,GAAG,cAAc,EAC5C,0BAA0B,GAAG,aAAa,CAC3C,CAAC;AAIF;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,cAAc,CACtD,OAAO,cAAc,EACrB,yBAAyB,EACzB,6BAA6B,CAC9B;IACC;;;;;;;OAOG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,6BAA6B,CAAC;QACzC,KAAK,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;KAC5C;IAiBD;;;;;;;;OAQG;IACG,qBAAqB,CACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,sBAAsB,CAAC;IAgClC;;;;;;;;;OASG;IACG,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAyCpC;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAM7B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseController } from "@metamask/base-controller";
|
|
2
|
+
import { getWalletComplianceStatus } from "./utils.mjs";
|
|
2
3
|
// === GENERAL ===
|
|
3
4
|
/**
|
|
4
5
|
* The name of the {@link ComplianceController}, used to namespace the
|
|
@@ -96,7 +97,7 @@ export class ComplianceController extends BaseController {
|
|
|
96
97
|
return status;
|
|
97
98
|
}
|
|
98
99
|
catch (error) {
|
|
99
|
-
const cached = this.state.walletComplianceStatusMap
|
|
100
|
+
const cached = getWalletComplianceStatus(this.state.walletComplianceStatusMap, address);
|
|
100
101
|
if (cached) {
|
|
101
102
|
return cached;
|
|
102
103
|
}
|
|
@@ -132,8 +133,8 @@ export class ComplianceController extends BaseController {
|
|
|
132
133
|
return statuses;
|
|
133
134
|
}
|
|
134
135
|
catch (error) {
|
|
135
|
-
const cachedStatuses = addresses.map((address) => this.state.walletComplianceStatusMap
|
|
136
|
-
if (cachedStatuses.every(Boolean)) {
|
|
136
|
+
const cachedStatuses = addresses.map((address) => getWalletComplianceStatus(this.state.walletComplianceStatusMap, address));
|
|
137
|
+
if (cachedStatuses.every((status) => Boolean(status))) {
|
|
137
138
|
return cachedStatuses;
|
|
138
139
|
}
|
|
139
140
|
throw error;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceController.mjs","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAU3D,kBAAkB;AAElB;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAqBrD;;GAEG;AACH,MAAM,4BAA4B,GAAG;IACnC,yBAAyB,EAAE;QACzB,sBAAsB,EAAE,KAAK;QAC7B,kBAAkB,EAAE,KAAK;QACzB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf;IACD,aAAa,EAAE;QACb,sBAAsB,EAAE,KAAK;QAC7B,kBAAkB,EAAE,IAAI;QACxB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,KAAK;KAChB;CACiD,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,UAAU,mCAAmC;IACjD,OAAO;QACL,yBAAyB,EAAE,EAAE;QAC7B,aAAa,EAAE,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,oBAAoB;AAEpB,MAAM,yBAAyB,GAAG;IAChC,uBAAuB;IACvB,wBAAwB;IACxB,sBAAsB;CACd,CAAC;AAoDX,gCAAgC;AAEhC;;;;;GAKG;AACH,MAAM,OAAO,oBAAqB,SAAQ,cAIzC;IACC;;;;;;;OAOG;IACH,YAAY,EACV,SAAS,EACT,KAAK,GAIN;QACC,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ,EAAE,4BAA4B;YACtC,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE;gBACL,GAAG,mCAAmC,EAAE;gBACxC,GAAG,KAAK;aACT;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,CAAC,4BAA4B,CACzC,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,qBAAqB,CACzB,OAAe;QAEf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACtC,yCAAyC,EACzC,OAAO,CACR,CAAC;YAEF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,MAAM,GAA2B;gBACrC,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,SAAS,EAAE,GAAG;aACf,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;gBACzB,UAAU,CAAC,yBAAyB,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;gBACvD,UAAU,CAAC,aAAa,GAAG,GAAG,CAAC;YACjC,CAAC,CAAC,CAAC;YAEH,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC;YAC7D,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,sBAAsB,CAC1B,SAAmB;QAEnB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACvC,0CAA0C,EAC1C,SAAS,CACV,CAAC;YAEF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,QAAQ,GAA6B,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAClE,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,SAAS,EAAE,GAAG;aACf,CAAC,CAAC,CAAC;YAEJ,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;gBACzB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;oBAC/C,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;oBACrC,UAAU,CAAC,yBAAyB,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACtE,CAAC;gBACD,UAAU,CAAC,aAAa,GAAG,GAAG,CAAC;YACjC,CAAC,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,GAAG,SAAS,CAAC,GAAG,CAClC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAC3D,CAAC;YACF,IAAI,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,OAAO,cAAc,CAAC;YACxB,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,oBAAoB;QAClB,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;YACzB,UAAU,CAAC,yBAAyB,GAAG,EAAE,CAAC;YAC1C,UAAU,CAAC,aAAa,GAAG,IAAI,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { ComplianceControllerMethodActions } from './ComplianceController-method-action-types';\nimport type {\n ComplianceServiceCheckWalletComplianceAction,\n ComplianceServiceCheckWalletsComplianceAction,\n} from './ComplianceService-method-action-types';\nimport type { WalletComplianceStatus } from './types';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'ComplianceController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link ComplianceController}.\n */\nexport type ComplianceControllerState = {\n /**\n * A map of wallet addresses to their compliance check results, used as a\n * fallback cache when the API is unavailable.\n */\n walletComplianceStatusMap: Record<string, WalletComplianceStatus>;\n\n /**\n * The date/time (in ISO-8601 format) when the last compliance check was\n * performed, or `null` if no checks have been performed yet.\n */\n lastCheckedAt: string | null;\n};\n\n/**\n * The metadata for each property in {@link ComplianceControllerState}.\n */\nconst complianceControllerMetadata = {\n walletComplianceStatusMap: {\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n persist: true,\n usedInUi: true,\n },\n lastCheckedAt: {\n includeInDebugSnapshot: false,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<ComplianceControllerState>;\n\n/**\n * Constructs the default {@link ComplianceController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link ComplianceController} state.\n */\nexport function getDefaultComplianceControllerState(): ComplianceControllerState {\n return {\n walletComplianceStatusMap: {},\n lastCheckedAt: null,\n };\n}\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n 'clearComplianceState',\n] as const;\n\n/**\n * Retrieves the state of the {@link ComplianceController}.\n */\nexport type ComplianceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Actions that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerActions =\n | ComplianceControllerGetStateAction\n | ComplianceControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceController} calls.\n */\ntype AllowedActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction;\n\n/**\n * Published when the state of {@link ComplianceController} changes.\n */\nexport type ComplianceControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Events that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerEvents = ComplianceControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link ComplianceController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceController}.\n */\nexport type ComplianceControllerMessenger = Messenger<\n typeof controllerName,\n ComplianceControllerActions | AllowedActions,\n ComplianceControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * `ComplianceController` manages OFAC compliance state for wallet addresses.\n * It performs on-demand compliance checks via the API and caches results\n * per address in state. Cached results serve as a fallback if the API is\n * unavailable for a subsequent check on the same address.\n */\nexport class ComplianceController extends BaseController<\n typeof controllerName,\n ComplianceControllerState,\n ComplianceControllerMessenger\n> {\n /**\n * Constructs a new {@link ComplianceController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to init this\n * controller. Missing properties will be filled in with defaults.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: ComplianceControllerMessenger;\n state?: Partial<ComplianceControllerState>;\n }) {\n super({\n messenger,\n metadata: complianceControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultComplianceControllerState(),\n ...state,\n },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Checks compliance status for a single wallet address via the API and\n * persists the result to state. If the API call fails and a previously\n * cached result exists for the address, the cached result is returned as a\n * fallback. If no cached result exists, the error is re-thrown.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(\n address: string,\n ): Promise<WalletComplianceStatus> {\n try {\n const result = await this.messenger.call(\n 'ComplianceService:checkWalletCompliance',\n address,\n );\n\n const now = new Date().toISOString();\n const status: WalletComplianceStatus = {\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n };\n\n this.update((draftState) => {\n draftState.walletComplianceStatusMap[address] = status;\n draftState.lastCheckedAt = now;\n });\n\n return status;\n } catch (error) {\n const cached = this.state.walletComplianceStatusMap[address];\n if (cached) {\n return cached;\n }\n throw error;\n }\n }\n\n /**\n * Checks compliance status for multiple wallet addresses via the API and\n * persists the results to state. If the API call fails and every requested\n * address has a previously cached result, those cached results are returned\n * as a fallback. If any address lacks a cached result, the error is\n * re-thrown.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<WalletComplianceStatus[]> {\n try {\n const results = await this.messenger.call(\n 'ComplianceService:checkWalletsCompliance',\n addresses,\n );\n\n const now = new Date().toISOString();\n const statuses: WalletComplianceStatus[] = results.map((result) => ({\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n }));\n\n this.update((draftState) => {\n for (let idx = 0; idx < statuses.length; idx++) {\n const callerAddress = addresses[idx];\n draftState.walletComplianceStatusMap[callerAddress] = statuses[idx];\n }\n draftState.lastCheckedAt = now;\n });\n\n return statuses;\n } catch (error) {\n const cachedStatuses = addresses.map(\n (address) => this.state.walletComplianceStatusMap[address],\n );\n if (cachedStatuses.every(Boolean)) {\n return cachedStatuses;\n }\n throw error;\n }\n }\n\n /**\n * Clears all compliance data from state.\n */\n clearComplianceState(): void {\n this.update((draftState) => {\n draftState.walletComplianceStatusMap = {};\n draftState.lastCheckedAt = null;\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ComplianceController.mjs","sourceRoot":"","sources":["../src/ComplianceController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { ComplianceControllerMethodActions } from './ComplianceController-method-action-types';\nimport type {\n ComplianceServiceCheckWalletComplianceAction,\n ComplianceServiceCheckWalletsComplianceAction,\n} from './ComplianceService-method-action-types';\nimport type { WalletComplianceStatus } from './types';\nimport { getWalletComplianceStatus } from './utils';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'ComplianceController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link ComplianceController}.\n */\nexport type ComplianceControllerState = {\n /**\n * A map of wallet addresses to their compliance check results, used as a\n * fallback cache when the API is unavailable.\n */\n walletComplianceStatusMap: Record<string, WalletComplianceStatus>;\n\n /**\n * The date/time (in ISO-8601 format) when the last compliance check was\n * performed, or `null` if no checks have been performed yet.\n */\n lastCheckedAt: string | null;\n};\n\n/**\n * The metadata for each property in {@link ComplianceControllerState}.\n */\nconst complianceControllerMetadata = {\n walletComplianceStatusMap: {\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n persist: true,\n usedInUi: true,\n },\n lastCheckedAt: {\n includeInDebugSnapshot: false,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<ComplianceControllerState>;\n\n/**\n * Constructs the default {@link ComplianceController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link ComplianceController} state.\n */\nexport function getDefaultComplianceControllerState(): ComplianceControllerState {\n return {\n walletComplianceStatusMap: {},\n lastCheckedAt: null,\n };\n}\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n 'clearComplianceState',\n] as const;\n\n/**\n * Retrieves the state of the {@link ComplianceController}.\n */\nexport type ComplianceControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Actions that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerActions =\n | ComplianceControllerGetStateAction\n | ComplianceControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceController} calls.\n */\ntype AllowedActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction;\n\n/**\n * Published when the state of {@link ComplianceController} changes.\n */\nexport type ComplianceControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n ComplianceControllerState\n>;\n\n/**\n * Events that {@link ComplianceController} exposes to other consumers.\n */\nexport type ComplianceControllerEvents = ComplianceControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link ComplianceController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceController}.\n */\nexport type ComplianceControllerMessenger = Messenger<\n typeof controllerName,\n ComplianceControllerActions | AllowedActions,\n ComplianceControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * `ComplianceController` manages OFAC compliance state for wallet addresses.\n * It performs on-demand compliance checks via the API and caches results\n * per address in state. Cached results serve as a fallback if the API is\n * unavailable for a subsequent check on the same address.\n */\nexport class ComplianceController extends BaseController<\n typeof controllerName,\n ComplianceControllerState,\n ComplianceControllerMessenger\n> {\n /**\n * Constructs a new {@link ComplianceController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to init this\n * controller. Missing properties will be filled in with defaults.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: ComplianceControllerMessenger;\n state?: Partial<ComplianceControllerState>;\n }) {\n super({\n messenger,\n metadata: complianceControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultComplianceControllerState(),\n ...state,\n },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Checks compliance status for a single wallet address via the API and\n * persists the result to state. If the API call fails and a previously\n * cached result exists for the address, the cached result is returned as a\n * fallback. If no cached result exists, the error is re-thrown.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(\n address: string,\n ): Promise<WalletComplianceStatus> {\n try {\n const result = await this.messenger.call(\n 'ComplianceService:checkWalletCompliance',\n address,\n );\n\n const now = new Date().toISOString();\n const status: WalletComplianceStatus = {\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n };\n\n this.update((draftState) => {\n draftState.walletComplianceStatusMap[address] = status;\n draftState.lastCheckedAt = now;\n });\n\n return status;\n } catch (error) {\n const cached = getWalletComplianceStatus(\n this.state.walletComplianceStatusMap,\n address,\n );\n if (cached) {\n return cached;\n }\n throw error;\n }\n }\n\n /**\n * Checks compliance status for multiple wallet addresses via the API and\n * persists the results to state. If the API call fails and every requested\n * address has a previously cached result, those cached results are returned\n * as a fallback. If any address lacks a cached result, the error is\n * re-thrown.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<WalletComplianceStatus[]> {\n try {\n const results = await this.messenger.call(\n 'ComplianceService:checkWalletsCompliance',\n addresses,\n );\n\n const now = new Date().toISOString();\n const statuses: WalletComplianceStatus[] = results.map((result) => ({\n address: result.address,\n blocked: result.blocked,\n checkedAt: now,\n }));\n\n this.update((draftState) => {\n for (let idx = 0; idx < statuses.length; idx++) {\n const callerAddress = addresses[idx];\n draftState.walletComplianceStatusMap[callerAddress] = statuses[idx];\n }\n draftState.lastCheckedAt = now;\n });\n\n return statuses;\n } catch (error) {\n const cachedStatuses = addresses.map((address) =>\n getWalletComplianceStatus(\n this.state.walletComplianceStatusMap,\n address,\n ),\n );\n if (\n cachedStatuses.every((status): status is WalletComplianceStatus =>\n Boolean(status),\n )\n ) {\n return cachedStatuses;\n }\n throw error;\n }\n }\n\n /**\n * Clears all compliance data from state.\n */\n clearComplianceState(): void {\n this.update((draftState) => {\n draftState.walletComplianceStatusMap = {};\n draftState.lastCheckedAt = null;\n });\n }\n}\n"]}
|
|
@@ -75,7 +75,7 @@ const BatchWalletCheckResponseItemStruct = WalletCheckResponseStruct;
|
|
|
75
75
|
* new ComplianceService({
|
|
76
76
|
* messenger: serviceMessenger,
|
|
77
77
|
* fetch,
|
|
78
|
-
*
|
|
78
|
+
* apiUrl: 'https://compliance.api.cx.metamask.io',
|
|
79
79
|
* });
|
|
80
80
|
*
|
|
81
81
|
* // Check a single wallet
|
|
@@ -93,12 +93,13 @@ class ComplianceService {
|
|
|
93
93
|
* @param args - The constructor arguments.
|
|
94
94
|
* @param args.messenger - The messenger suited for this service.
|
|
95
95
|
* @param args.fetch - A function that can be used to make an HTTP request.
|
|
96
|
-
* @param args.
|
|
97
|
-
* the
|
|
96
|
+
* @param args.apiUrl - The explicit Compliance API URL.
|
|
97
|
+
* @param args.env - The fallback environment to use for the Compliance API
|
|
98
|
+
* when `apiUrl` is not provided.
|
|
98
99
|
* @param args.policyOptions - Options to pass to `createServicePolicy`, which
|
|
99
100
|
* is used to wrap each request. See {@link CreateServicePolicyOptions}.
|
|
100
101
|
*/
|
|
101
|
-
constructor({ messenger, fetch: fetchFunction, env, policyOptions = {}, }) {
|
|
102
|
+
constructor({ messenger, fetch: fetchFunction, apiUrl, env = 'production', policyOptions = {}, }) {
|
|
102
103
|
/**
|
|
103
104
|
* The messenger suited for this service.
|
|
104
105
|
*/
|
|
@@ -120,7 +121,7 @@ class ComplianceService {
|
|
|
120
121
|
this.name = exports.serviceName;
|
|
121
122
|
__classPrivateFieldSet(this, _ComplianceService_messenger, messenger, "f");
|
|
122
123
|
__classPrivateFieldSet(this, _ComplianceService_fetch, fetchFunction, "f");
|
|
123
|
-
__classPrivateFieldSet(this, _ComplianceService_complianceApiUrl,
|
|
124
|
+
__classPrivateFieldSet(this, _ComplianceService_complianceApiUrl, getComplianceApiUrl({ apiUrl, env }), "f");
|
|
124
125
|
__classPrivateFieldSet(this, _ComplianceService_policy, (0, controller_utils_1.createServicePolicy)(policyOptions), "f");
|
|
125
126
|
__classPrivateFieldGet(this, _ComplianceService_messenger, "f").registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
126
127
|
}
|
|
@@ -165,7 +166,7 @@ class ComplianceService {
|
|
|
165
166
|
*/
|
|
166
167
|
async checkWalletCompliance(address) {
|
|
167
168
|
const response = await __classPrivateFieldGet(this, _ComplianceService_policy, "f").execute(async () => {
|
|
168
|
-
const url = new URL(
|
|
169
|
+
const url = new URL(`v1/wallet/${encodeURIComponent(address)}`, __classPrivateFieldGet(this, _ComplianceService_complianceApiUrl, "f"));
|
|
169
170
|
const localResponse = await __classPrivateFieldGet(this, _ComplianceService_fetch, "f").call(this, url);
|
|
170
171
|
if (!localResponse.ok) {
|
|
171
172
|
throw new controller_utils_1.HttpError(localResponse.status, `Fetching '${url.toString()}' failed with status '${localResponse.status}'`);
|
|
@@ -183,7 +184,7 @@ class ComplianceService {
|
|
|
183
184
|
*/
|
|
184
185
|
async checkWalletsCompliance(addresses) {
|
|
185
186
|
const response = await __classPrivateFieldGet(this, _ComplianceService_policy, "f").execute(async () => {
|
|
186
|
-
const url = new URL('
|
|
187
|
+
const url = new URL('v1/wallet/batch', __classPrivateFieldGet(this, _ComplianceService_complianceApiUrl, "f"));
|
|
187
188
|
const localResponse = await __classPrivateFieldGet(this, _ComplianceService_fetch, "f").call(this, url, {
|
|
188
189
|
method: 'POST',
|
|
189
190
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -200,6 +201,25 @@ class ComplianceService {
|
|
|
200
201
|
}
|
|
201
202
|
exports.ComplianceService = ComplianceService;
|
|
202
203
|
_a = ComplianceService, _ComplianceService_messenger = new WeakMap(), _ComplianceService_fetch = new WeakMap(), _ComplianceService_complianceApiUrl = new WeakMap(), _ComplianceService_policy = new WeakMap();
|
|
204
|
+
function getComplianceApiUrl({ apiUrl, env, }) {
|
|
205
|
+
if (apiUrl === undefined) {
|
|
206
|
+
return COMPLIANCE_API_URLS[env];
|
|
207
|
+
}
|
|
208
|
+
let url;
|
|
209
|
+
try {
|
|
210
|
+
url = new URL(apiUrl);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
throw new Error(`Invalid Compliance API URL: ${apiUrl}`);
|
|
214
|
+
}
|
|
215
|
+
if (url.search || url.hash) {
|
|
216
|
+
throw new Error(`Invalid Compliance API URL: ${apiUrl}. Query strings and fragments are not supported.`);
|
|
217
|
+
}
|
|
218
|
+
if (!url.pathname.endsWith('/')) {
|
|
219
|
+
url.pathname = `${url.pathname}/`;
|
|
220
|
+
}
|
|
221
|
+
return url.href;
|
|
222
|
+
}
|
|
203
223
|
/**
|
|
204
224
|
* Validates an API response against a superstruct schema.
|
|
205
225
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceService.cjs","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Infer } from '@metamask/superstruct';\nimport { array, boolean, object, string } from '@metamask/superstruct';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { ComplianceServiceMethodActions } from './ComplianceService-method-action-types';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'ComplianceService';\n\n/**\n * The supported environments for the Compliance API.\n */\nexport type ComplianceServiceEnvironment = 'production' | 'development';\n\nconst COMPLIANCE_API_URLS: Record<ComplianceServiceEnvironment, string> = {\n production: 'https://compliance.api.cx.metamask.io',\n development: 'https://compliance.dev-api.cx.metamask.io',\n};\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n] as const;\n\n/**\n * Actions that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceActions = ComplianceServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceService} calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceEvents = never;\n\n/**\n * Events from other messengers that {@link ComplianceService} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceService}.\n */\nexport type ComplianceServiceMessenger = Messenger<\n typeof serviceName,\n ComplianceServiceActions | AllowedActions,\n ComplianceServiceEvents | AllowedEvents\n>;\n\n// === API RESPONSE SCHEMAS ===\n\n/**\n * Schema for the response from `GET /v1/wallet/:address`.\n */\nconst WalletCheckResponseStruct = object({\n address: string(),\n blocked: boolean(),\n});\n\n/**\n * The validated shape of a single wallet compliance check response.\n */\ntype WalletCheckResponse = Infer<typeof WalletCheckResponseStruct>;\n\n/**\n * Schema for each item in the response from `POST /v1/wallet/batch`.\n * Reuses the same shape as a single wallet check.\n */\nconst BatchWalletCheckResponseItemStruct = WalletCheckResponseStruct;\n\n/**\n * The validated shape of a single item in a batch compliance check response.\n */\ntype BatchWalletCheckResponseItem = Infer<\n typeof BatchWalletCheckResponseItemStruct\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * `ComplianceService` communicates with the Compliance API to check whether\n * wallet addresses are sanctioned under OFAC regulations.\n *\n * @example\n *\n * ``` ts\n * import { Messenger } from '@metamask/messenger';\n * import type {\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * } from '@metamask/compliance-controller';\n * import { ComplianceService } from '@metamask/compliance-controller';\n *\n * const rootMessenger = new Messenger<\n * 'Root',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * >({ namespace: 'Root' });\n * const serviceMessenger = new Messenger<\n * 'ComplianceService',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * typeof rootMessenger,\n * >({\n * namespace: 'ComplianceService',\n * parent: rootMessenger,\n * });\n * new ComplianceService({\n * messenger: serviceMessenger,\n * fetch,\n * env: 'production',\n * });\n *\n * // Check a single wallet\n * const result = await rootMessenger.call(\n * 'ComplianceService:checkWalletCompliance',\n * '0x1234...',\n * );\n * // => { address: '0x1234...', blocked: false }\n * ```\n */\nexport class ComplianceService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n /**\n * The messenger suited for this service.\n */\n readonly #messenger: ConstructorParameters<\n typeof ComplianceService\n >[0]['messenger'];\n\n /**\n * A function that can be used to make an HTTP request.\n */\n readonly #fetch: ConstructorParameters<typeof ComplianceService>[0]['fetch'];\n\n /**\n * The resolved base URL for the Compliance API.\n */\n readonly #complianceApiUrl: string;\n\n /**\n * The policy that wraps each request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n /**\n * Constructs a new ComplianceService object.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * @param args.env - The environment to use for the Compliance API. Determines\n * the base URL.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n fetch: fetchFunction,\n env,\n policyOptions = {},\n }: {\n messenger: ComplianceServiceMessenger;\n fetch: typeof fetch;\n env: ComplianceServiceEnvironment;\n policyOptions?: CreateServicePolicyOptions;\n }) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#fetch = fetchFunction;\n this.#complianceApiUrl = COMPLIANCE_API_URLS[env];\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a non-500\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when the service is degraded due\n * to slow responses or repeated failures.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Checks compliance status for a single wallet address.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(address: string): Promise<WalletCheckResponse> {\n const response = await this.#policy.execute(async () => {\n const url = new URL(\n `/v1/wallet/${encodeURIComponent(address)}`,\n this.#complianceApiUrl,\n );\n const localResponse = await this.#fetch(url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n WalletCheckResponseStruct,\n 'compliance wallet check API',\n );\n }\n\n /**\n * Checks compliance status for multiple wallet addresses in a single request.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<BatchWalletCheckResponseItem[]> {\n const response = await this.#policy.execute(async () => {\n const url = new URL('/v1/wallet/batch', this.#complianceApiUrl);\n const localResponse = await this.#fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(addresses),\n });\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n array(BatchWalletCheckResponseItemStruct),\n 'compliance batch check API',\n );\n }\n}\n\n/**\n * Validates an API response against a superstruct schema.\n *\n * @param data - The raw response data to validate.\n * @param struct - The superstruct schema to validate against.\n * @param struct.is - The type guard function from the schema.\n * @param apiName - A human-readable name for the API, used in error messages.\n * @returns The validated data.\n * @throws If the data does not match the schema.\n */\nfunction validateResponse<Response>(\n data: unknown,\n struct: { is: (value: unknown) => value is Response },\n apiName: string,\n): Response {\n if (struct.is(data)) {\n return data;\n }\n throw new Error(`Malformed response received from ${apiName}`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ComplianceService.cjs","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Infer } from '@metamask/superstruct';\nimport { array, boolean, object, string } from '@metamask/superstruct';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { ComplianceServiceMethodActions } from './ComplianceService-method-action-types';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'ComplianceService';\n\n/**\n * The supported environments for the Compliance API.\n */\nexport type ComplianceServiceEnvironment = 'production' | 'development';\n\nconst COMPLIANCE_API_URLS: Record<ComplianceServiceEnvironment, string> = {\n production: 'https://compliance.api.cx.metamask.io',\n development: 'https://compliance.dev-api.cx.metamask.io',\n};\n\nexport type ComplianceServiceOptions = {\n messenger: ComplianceServiceMessenger;\n fetch: typeof fetch;\n /**\n * Explicit Compliance API URL. Prefer this for application builds so API\n * endpoints can be managed by build configuration. Path components are\n * preserved as a base path for Compliance API routes.\n */\n apiUrl?: string;\n /**\n * Fallback environment used when `apiUrl` is not provided.\n */\n env?: ComplianceServiceEnvironment;\n policyOptions?: CreateServicePolicyOptions;\n};\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n] as const;\n\n/**\n * Actions that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceActions = ComplianceServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceService} calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceEvents = never;\n\n/**\n * Events from other messengers that {@link ComplianceService} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceService}.\n */\nexport type ComplianceServiceMessenger = Messenger<\n typeof serviceName,\n ComplianceServiceActions | AllowedActions,\n ComplianceServiceEvents | AllowedEvents\n>;\n\n// === API RESPONSE SCHEMAS ===\n\n/**\n * Schema for the response from `GET /v1/wallet/:address`.\n */\nconst WalletCheckResponseStruct = object({\n address: string(),\n blocked: boolean(),\n});\n\n/**\n * The validated shape of a single wallet compliance check response.\n */\ntype WalletCheckResponse = Infer<typeof WalletCheckResponseStruct>;\n\n/**\n * Schema for each item in the response from `POST /v1/wallet/batch`.\n * Reuses the same shape as a single wallet check.\n */\nconst BatchWalletCheckResponseItemStruct = WalletCheckResponseStruct;\n\n/**\n * The validated shape of a single item in a batch compliance check response.\n */\ntype BatchWalletCheckResponseItem = Infer<\n typeof BatchWalletCheckResponseItemStruct\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * `ComplianceService` communicates with the Compliance API to check whether\n * wallet addresses are sanctioned under OFAC regulations.\n *\n * @example\n *\n * ``` ts\n * import { Messenger } from '@metamask/messenger';\n * import type {\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * } from '@metamask/compliance-controller';\n * import { ComplianceService } from '@metamask/compliance-controller';\n *\n * const rootMessenger = new Messenger<\n * 'Root',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * >({ namespace: 'Root' });\n * const serviceMessenger = new Messenger<\n * 'ComplianceService',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * typeof rootMessenger,\n * >({\n * namespace: 'ComplianceService',\n * parent: rootMessenger,\n * });\n * new ComplianceService({\n * messenger: serviceMessenger,\n * fetch,\n * apiUrl: 'https://compliance.api.cx.metamask.io',\n * });\n *\n * // Check a single wallet\n * const result = await rootMessenger.call(\n * 'ComplianceService:checkWalletCompliance',\n * '0x1234...',\n * );\n * // => { address: '0x1234...', blocked: false }\n * ```\n */\nexport class ComplianceService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n /**\n * The messenger suited for this service.\n */\n readonly #messenger: ConstructorParameters<\n typeof ComplianceService\n >[0]['messenger'];\n\n /**\n * A function that can be used to make an HTTP request.\n */\n readonly #fetch: ConstructorParameters<typeof ComplianceService>[0]['fetch'];\n\n /**\n * The resolved base URL for the Compliance API.\n */\n readonly #complianceApiUrl: string;\n\n /**\n * The policy that wraps each request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n /**\n * Constructs a new ComplianceService object.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * @param args.apiUrl - The explicit Compliance API URL.\n * @param args.env - The fallback environment to use for the Compliance API\n * when `apiUrl` is not provided.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n fetch: fetchFunction,\n apiUrl,\n env = 'production',\n policyOptions = {},\n }: ComplianceServiceOptions) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#fetch = fetchFunction;\n this.#complianceApiUrl = getComplianceApiUrl({ apiUrl, env });\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a non-500\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when the service is degraded due\n * to slow responses or repeated failures.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Checks compliance status for a single wallet address.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(address: string): Promise<WalletCheckResponse> {\n const response = await this.#policy.execute(async () => {\n const url = new URL(\n `v1/wallet/${encodeURIComponent(address)}`,\n this.#complianceApiUrl,\n );\n const localResponse = await this.#fetch(url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n WalletCheckResponseStruct,\n 'compliance wallet check API',\n );\n }\n\n /**\n * Checks compliance status for multiple wallet addresses in a single request.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<BatchWalletCheckResponseItem[]> {\n const response = await this.#policy.execute(async () => {\n const url = new URL('v1/wallet/batch', this.#complianceApiUrl);\n const localResponse = await this.#fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(addresses),\n });\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n array(BatchWalletCheckResponseItemStruct),\n 'compliance batch check API',\n );\n }\n}\n\nfunction getComplianceApiUrl({\n apiUrl,\n env,\n}: {\n apiUrl?: string;\n env: ComplianceServiceEnvironment;\n}): string {\n if (apiUrl === undefined) {\n return COMPLIANCE_API_URLS[env];\n }\n\n let url: URL;\n try {\n url = new URL(apiUrl);\n } catch {\n throw new Error(`Invalid Compliance API URL: ${apiUrl}`);\n }\n\n if (url.search || url.hash) {\n throw new Error(\n `Invalid Compliance API URL: ${apiUrl}. Query strings and fragments are not supported.`,\n );\n }\n if (!url.pathname.endsWith('/')) {\n url.pathname = `${url.pathname}/`;\n }\n return url.href;\n}\n\n/**\n * Validates an API response against a superstruct schema.\n *\n * @param data - The raw response data to validate.\n * @param struct - The superstruct schema to validate against.\n * @param struct.is - The type guard function from the schema.\n * @param apiName - A human-readable name for the API, used in error messages.\n * @returns The validated data.\n * @throws If the data does not match the schema.\n */\nfunction validateResponse<Response>(\n data: unknown,\n struct: { is: (value: unknown) => value is Response },\n apiName: string,\n): Response {\n if (struct.is(data)) {\n return data;\n }\n throw new Error(`Malformed response received from ${apiName}`);\n}\n"]}
|
|
@@ -12,6 +12,21 @@ export declare const serviceName = "ComplianceService";
|
|
|
12
12
|
* The supported environments for the Compliance API.
|
|
13
13
|
*/
|
|
14
14
|
export type ComplianceServiceEnvironment = 'production' | 'development';
|
|
15
|
+
export type ComplianceServiceOptions = {
|
|
16
|
+
messenger: ComplianceServiceMessenger;
|
|
17
|
+
fetch: typeof fetch;
|
|
18
|
+
/**
|
|
19
|
+
* Explicit Compliance API URL. Prefer this for application builds so API
|
|
20
|
+
* endpoints can be managed by build configuration. Path components are
|
|
21
|
+
* preserved as a base path for Compliance API routes.
|
|
22
|
+
*/
|
|
23
|
+
apiUrl?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Fallback environment used when `apiUrl` is not provided.
|
|
26
|
+
*/
|
|
27
|
+
env?: ComplianceServiceEnvironment;
|
|
28
|
+
policyOptions?: CreateServicePolicyOptions;
|
|
29
|
+
};
|
|
15
30
|
/**
|
|
16
31
|
* Actions that {@link ComplianceService} exposes to other consumers.
|
|
17
32
|
*/
|
|
@@ -93,7 +108,7 @@ type BatchWalletCheckResponseItem = Infer<typeof BatchWalletCheckResponseItemStr
|
|
|
93
108
|
* new ComplianceService({
|
|
94
109
|
* messenger: serviceMessenger,
|
|
95
110
|
* fetch,
|
|
96
|
-
*
|
|
111
|
+
* apiUrl: 'https://compliance.api.cx.metamask.io',
|
|
97
112
|
* });
|
|
98
113
|
*
|
|
99
114
|
* // Check a single wallet
|
|
@@ -116,17 +131,13 @@ export declare class ComplianceService {
|
|
|
116
131
|
* @param args - The constructor arguments.
|
|
117
132
|
* @param args.messenger - The messenger suited for this service.
|
|
118
133
|
* @param args.fetch - A function that can be used to make an HTTP request.
|
|
119
|
-
* @param args.
|
|
120
|
-
* the
|
|
134
|
+
* @param args.apiUrl - The explicit Compliance API URL.
|
|
135
|
+
* @param args.env - The fallback environment to use for the Compliance API
|
|
136
|
+
* when `apiUrl` is not provided.
|
|
121
137
|
* @param args.policyOptions - Options to pass to `createServicePolicy`, which
|
|
122
138
|
* is used to wrap each request. See {@link CreateServicePolicyOptions}.
|
|
123
139
|
*/
|
|
124
|
-
constructor({ messenger, fetch: fetchFunction, env, policyOptions, }:
|
|
125
|
-
messenger: ComplianceServiceMessenger;
|
|
126
|
-
fetch: typeof fetch;
|
|
127
|
-
env: ComplianceServiceEnvironment;
|
|
128
|
-
policyOptions?: CreateServicePolicyOptions;
|
|
129
|
-
});
|
|
140
|
+
constructor({ messenger, fetch: fetchFunction, apiUrl, env, policyOptions, }: ComplianceServiceOptions);
|
|
130
141
|
/**
|
|
131
142
|
* Registers a handler that will be called after a request returns a non-500
|
|
132
143
|
* response, causing a retry.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceService.d.cts","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,8BAA8B;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,8BAA8B,EAAE,oDAAgD;AAI9F;;;GAGG;AACH,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,YAAY,GAAG,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ComplianceService.d.cts","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,8BAA8B;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,8BAA8B,EAAE,oDAAgD;AAI9F;;;GAGG;AACH,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,YAAY,GAAG,aAAa,CAAC;AAOxE,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,0BAA0B,CAAC;IACtC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,GAAG,CAAC,EAAE,4BAA4B,CAAC;IACnC,aAAa,CAAC,EAAE,0BAA0B,CAAC;CAC5C,CAAC;AASF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEtE;;GAEG;AACH,KAAK,cAAc,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAE5C;;GAEG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG,SAAS,CAChD,OAAO,WAAW,EAClB,wBAAwB,GAAG,cAAc,EACzC,uBAAuB,GAAG,aAAa,CACxC,CAAC;AAIF;;GAEG;AACH,QAAA,MAAM,yBAAyB;;;;;;EAG7B,CAAC;AAEH;;GAEG;AACH,KAAK,mBAAmB,GAAG,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAEnE;;;GAGG;AACH,QAAA,MAAM,kCAAkC;;;;;;EAA4B,CAAC;AAErE;;GAEG;AACH,KAAK,4BAA4B,GAAG,KAAK,CACvC,OAAO,kCAAkC,CAC1C,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBAAa,iBAAiB;;IAC5B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC;IA0BlC;;;;;;;;;;;OAWG;gBACS,EACV,SAAS,EACT,KAAK,EAAE,aAAa,EACpB,MAAM,EACN,GAAkB,EAClB,aAAkB,GACnB,EAAE,wBAAwB;IAa3B;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACnD,WAAW;IAId;;;;;OAKG;IACG,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwB1E;;;;;OAKG;IACG,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,4BAA4B,EAAE,CAAC;CAwB3C"}
|
|
@@ -12,6 +12,21 @@ export declare const serviceName = "ComplianceService";
|
|
|
12
12
|
* The supported environments for the Compliance API.
|
|
13
13
|
*/
|
|
14
14
|
export type ComplianceServiceEnvironment = 'production' | 'development';
|
|
15
|
+
export type ComplianceServiceOptions = {
|
|
16
|
+
messenger: ComplianceServiceMessenger;
|
|
17
|
+
fetch: typeof fetch;
|
|
18
|
+
/**
|
|
19
|
+
* Explicit Compliance API URL. Prefer this for application builds so API
|
|
20
|
+
* endpoints can be managed by build configuration. Path components are
|
|
21
|
+
* preserved as a base path for Compliance API routes.
|
|
22
|
+
*/
|
|
23
|
+
apiUrl?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Fallback environment used when `apiUrl` is not provided.
|
|
26
|
+
*/
|
|
27
|
+
env?: ComplianceServiceEnvironment;
|
|
28
|
+
policyOptions?: CreateServicePolicyOptions;
|
|
29
|
+
};
|
|
15
30
|
/**
|
|
16
31
|
* Actions that {@link ComplianceService} exposes to other consumers.
|
|
17
32
|
*/
|
|
@@ -93,7 +108,7 @@ type BatchWalletCheckResponseItem = Infer<typeof BatchWalletCheckResponseItemStr
|
|
|
93
108
|
* new ComplianceService({
|
|
94
109
|
* messenger: serviceMessenger,
|
|
95
110
|
* fetch,
|
|
96
|
-
*
|
|
111
|
+
* apiUrl: 'https://compliance.api.cx.metamask.io',
|
|
97
112
|
* });
|
|
98
113
|
*
|
|
99
114
|
* // Check a single wallet
|
|
@@ -116,17 +131,13 @@ export declare class ComplianceService {
|
|
|
116
131
|
* @param args - The constructor arguments.
|
|
117
132
|
* @param args.messenger - The messenger suited for this service.
|
|
118
133
|
* @param args.fetch - A function that can be used to make an HTTP request.
|
|
119
|
-
* @param args.
|
|
120
|
-
* the
|
|
134
|
+
* @param args.apiUrl - The explicit Compliance API URL.
|
|
135
|
+
* @param args.env - The fallback environment to use for the Compliance API
|
|
136
|
+
* when `apiUrl` is not provided.
|
|
121
137
|
* @param args.policyOptions - Options to pass to `createServicePolicy`, which
|
|
122
138
|
* is used to wrap each request. See {@link CreateServicePolicyOptions}.
|
|
123
139
|
*/
|
|
124
|
-
constructor({ messenger, fetch: fetchFunction, env, policyOptions, }:
|
|
125
|
-
messenger: ComplianceServiceMessenger;
|
|
126
|
-
fetch: typeof fetch;
|
|
127
|
-
env: ComplianceServiceEnvironment;
|
|
128
|
-
policyOptions?: CreateServicePolicyOptions;
|
|
129
|
-
});
|
|
140
|
+
constructor({ messenger, fetch: fetchFunction, apiUrl, env, policyOptions, }: ComplianceServiceOptions);
|
|
130
141
|
/**
|
|
131
142
|
* Registers a handler that will be called after a request returns a non-500
|
|
132
143
|
* response, causing a retry.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceService.d.mts","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,8BAA8B;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,8BAA8B,EAAE,oDAAgD;AAI9F;;;GAGG;AACH,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,YAAY,GAAG,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ComplianceService.d.mts","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,8BAA8B;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,8BAA8B,EAAE,oDAAgD;AAI9F;;;GAGG;AACH,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,YAAY,GAAG,aAAa,CAAC;AAOxE,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,0BAA0B,CAAC;IACtC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,GAAG,CAAC,EAAE,4BAA4B,CAAC;IACnC,aAAa,CAAC,EAAE,0BAA0B,CAAC;CAC5C,CAAC;AASF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,8BAA8B,CAAC;AAEtE;;GAEG;AACH,KAAK,cAAc,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAE5C;;GAEG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG,SAAS,CAChD,OAAO,WAAW,EAClB,wBAAwB,GAAG,cAAc,EACzC,uBAAuB,GAAG,aAAa,CACxC,CAAC;AAIF;;GAEG;AACH,QAAA,MAAM,yBAAyB;;;;;;EAG7B,CAAC;AAEH;;GAEG;AACH,KAAK,mBAAmB,GAAG,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAEnE;;;GAGG;AACH,QAAA,MAAM,kCAAkC;;;;;;EAA4B,CAAC;AAErE;;GAEG;AACH,KAAK,4BAA4B,GAAG,KAAK,CACvC,OAAO,kCAAkC,CAC1C,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBAAa,iBAAiB;;IAC5B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC;IA0BlC;;;;;;;;;;;OAWG;gBACS,EACV,SAAS,EACT,KAAK,EAAE,aAAa,EACpB,MAAM,EACN,GAAkB,EAClB,aAAkB,GACnB,EAAE,wBAAwB;IAa3B;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACnD,WAAW;IAId;;;;;OAKG;IACG,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwB1E;;;;;OAKG;IACG,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,4BAA4B,EAAE,CAAC;CAwB3C"}
|
|
@@ -72,7 +72,7 @@ const BatchWalletCheckResponseItemStruct = WalletCheckResponseStruct;
|
|
|
72
72
|
* new ComplianceService({
|
|
73
73
|
* messenger: serviceMessenger,
|
|
74
74
|
* fetch,
|
|
75
|
-
*
|
|
75
|
+
* apiUrl: 'https://compliance.api.cx.metamask.io',
|
|
76
76
|
* });
|
|
77
77
|
*
|
|
78
78
|
* // Check a single wallet
|
|
@@ -90,12 +90,13 @@ export class ComplianceService {
|
|
|
90
90
|
* @param args - The constructor arguments.
|
|
91
91
|
* @param args.messenger - The messenger suited for this service.
|
|
92
92
|
* @param args.fetch - A function that can be used to make an HTTP request.
|
|
93
|
-
* @param args.
|
|
94
|
-
* the
|
|
93
|
+
* @param args.apiUrl - The explicit Compliance API URL.
|
|
94
|
+
* @param args.env - The fallback environment to use for the Compliance API
|
|
95
|
+
* when `apiUrl` is not provided.
|
|
95
96
|
* @param args.policyOptions - Options to pass to `createServicePolicy`, which
|
|
96
97
|
* is used to wrap each request. See {@link CreateServicePolicyOptions}.
|
|
97
98
|
*/
|
|
98
|
-
constructor({ messenger, fetch: fetchFunction, env, policyOptions = {}, }) {
|
|
99
|
+
constructor({ messenger, fetch: fetchFunction, apiUrl, env = 'production', policyOptions = {}, }) {
|
|
99
100
|
/**
|
|
100
101
|
* The messenger suited for this service.
|
|
101
102
|
*/
|
|
@@ -117,7 +118,7 @@ export class ComplianceService {
|
|
|
117
118
|
this.name = serviceName;
|
|
118
119
|
__classPrivateFieldSet(this, _ComplianceService_messenger, messenger, "f");
|
|
119
120
|
__classPrivateFieldSet(this, _ComplianceService_fetch, fetchFunction, "f");
|
|
120
|
-
__classPrivateFieldSet(this, _ComplianceService_complianceApiUrl,
|
|
121
|
+
__classPrivateFieldSet(this, _ComplianceService_complianceApiUrl, getComplianceApiUrl({ apiUrl, env }), "f");
|
|
121
122
|
__classPrivateFieldSet(this, _ComplianceService_policy, createServicePolicy(policyOptions), "f");
|
|
122
123
|
__classPrivateFieldGet(this, _ComplianceService_messenger, "f").registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
123
124
|
}
|
|
@@ -162,7 +163,7 @@ export class ComplianceService {
|
|
|
162
163
|
*/
|
|
163
164
|
async checkWalletCompliance(address) {
|
|
164
165
|
const response = await __classPrivateFieldGet(this, _ComplianceService_policy, "f").execute(async () => {
|
|
165
|
-
const url = new URL(
|
|
166
|
+
const url = new URL(`v1/wallet/${encodeURIComponent(address)}`, __classPrivateFieldGet(this, _ComplianceService_complianceApiUrl, "f"));
|
|
166
167
|
const localResponse = await __classPrivateFieldGet(this, _ComplianceService_fetch, "f").call(this, url);
|
|
167
168
|
if (!localResponse.ok) {
|
|
168
169
|
throw new HttpError(localResponse.status, `Fetching '${url.toString()}' failed with status '${localResponse.status}'`);
|
|
@@ -180,7 +181,7 @@ export class ComplianceService {
|
|
|
180
181
|
*/
|
|
181
182
|
async checkWalletsCompliance(addresses) {
|
|
182
183
|
const response = await __classPrivateFieldGet(this, _ComplianceService_policy, "f").execute(async () => {
|
|
183
|
-
const url = new URL('
|
|
184
|
+
const url = new URL('v1/wallet/batch', __classPrivateFieldGet(this, _ComplianceService_complianceApiUrl, "f"));
|
|
184
185
|
const localResponse = await __classPrivateFieldGet(this, _ComplianceService_fetch, "f").call(this, url, {
|
|
185
186
|
method: 'POST',
|
|
186
187
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -196,6 +197,25 @@ export class ComplianceService {
|
|
|
196
197
|
}
|
|
197
198
|
}
|
|
198
199
|
_a = ComplianceService, _ComplianceService_messenger = new WeakMap(), _ComplianceService_fetch = new WeakMap(), _ComplianceService_complianceApiUrl = new WeakMap(), _ComplianceService_policy = new WeakMap();
|
|
200
|
+
function getComplianceApiUrl({ apiUrl, env, }) {
|
|
201
|
+
if (apiUrl === undefined) {
|
|
202
|
+
return COMPLIANCE_API_URLS[env];
|
|
203
|
+
}
|
|
204
|
+
let url;
|
|
205
|
+
try {
|
|
206
|
+
url = new URL(apiUrl);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
throw new Error(`Invalid Compliance API URL: ${apiUrl}`);
|
|
210
|
+
}
|
|
211
|
+
if (url.search || url.hash) {
|
|
212
|
+
throw new Error(`Invalid Compliance API URL: ${apiUrl}. Query strings and fragments are not supported.`);
|
|
213
|
+
}
|
|
214
|
+
if (!url.pathname.endsWith('/')) {
|
|
215
|
+
url.pathname = `${url.pathname}/`;
|
|
216
|
+
}
|
|
217
|
+
return url.href;
|
|
218
|
+
}
|
|
199
219
|
/**
|
|
200
220
|
* Validates an API response against a superstruct schema.
|
|
201
221
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplianceService.mjs","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Infer } from '@metamask/superstruct';\nimport { array, boolean, object, string } from '@metamask/superstruct';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { ComplianceServiceMethodActions } from './ComplianceService-method-action-types';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'ComplianceService';\n\n/**\n * The supported environments for the Compliance API.\n */\nexport type ComplianceServiceEnvironment = 'production' | 'development';\n\nconst COMPLIANCE_API_URLS: Record<ComplianceServiceEnvironment, string> = {\n production: 'https://compliance.api.cx.metamask.io',\n development: 'https://compliance.dev-api.cx.metamask.io',\n};\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n] as const;\n\n/**\n * Actions that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceActions = ComplianceServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceService} calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceEvents = never;\n\n/**\n * Events from other messengers that {@link ComplianceService} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceService}.\n */\nexport type ComplianceServiceMessenger = Messenger<\n typeof serviceName,\n ComplianceServiceActions | AllowedActions,\n ComplianceServiceEvents | AllowedEvents\n>;\n\n// === API RESPONSE SCHEMAS ===\n\n/**\n * Schema for the response from `GET /v1/wallet/:address`.\n */\nconst WalletCheckResponseStruct = object({\n address: string(),\n blocked: boolean(),\n});\n\n/**\n * The validated shape of a single wallet compliance check response.\n */\ntype WalletCheckResponse = Infer<typeof WalletCheckResponseStruct>;\n\n/**\n * Schema for each item in the response from `POST /v1/wallet/batch`.\n * Reuses the same shape as a single wallet check.\n */\nconst BatchWalletCheckResponseItemStruct = WalletCheckResponseStruct;\n\n/**\n * The validated shape of a single item in a batch compliance check response.\n */\ntype BatchWalletCheckResponseItem = Infer<\n typeof BatchWalletCheckResponseItemStruct\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * `ComplianceService` communicates with the Compliance API to check whether\n * wallet addresses are sanctioned under OFAC regulations.\n *\n * @example\n *\n * ``` ts\n * import { Messenger } from '@metamask/messenger';\n * import type {\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * } from '@metamask/compliance-controller';\n * import { ComplianceService } from '@metamask/compliance-controller';\n *\n * const rootMessenger = new Messenger<\n * 'Root',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * >({ namespace: 'Root' });\n * const serviceMessenger = new Messenger<\n * 'ComplianceService',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * typeof rootMessenger,\n * >({\n * namespace: 'ComplianceService',\n * parent: rootMessenger,\n * });\n * new ComplianceService({\n * messenger: serviceMessenger,\n * fetch,\n * env: 'production',\n * });\n *\n * // Check a single wallet\n * const result = await rootMessenger.call(\n * 'ComplianceService:checkWalletCompliance',\n * '0x1234...',\n * );\n * // => { address: '0x1234...', blocked: false }\n * ```\n */\nexport class ComplianceService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n /**\n * The messenger suited for this service.\n */\n readonly #messenger: ConstructorParameters<\n typeof ComplianceService\n >[0]['messenger'];\n\n /**\n * A function that can be used to make an HTTP request.\n */\n readonly #fetch: ConstructorParameters<typeof ComplianceService>[0]['fetch'];\n\n /**\n * The resolved base URL for the Compliance API.\n */\n readonly #complianceApiUrl: string;\n\n /**\n * The policy that wraps each request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n /**\n * Constructs a new ComplianceService object.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * @param args.env - The environment to use for the Compliance API. Determines\n * the base URL.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n fetch: fetchFunction,\n env,\n policyOptions = {},\n }: {\n messenger: ComplianceServiceMessenger;\n fetch: typeof fetch;\n env: ComplianceServiceEnvironment;\n policyOptions?: CreateServicePolicyOptions;\n }) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#fetch = fetchFunction;\n this.#complianceApiUrl = COMPLIANCE_API_URLS[env];\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a non-500\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when the service is degraded due\n * to slow responses or repeated failures.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Checks compliance status for a single wallet address.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(address: string): Promise<WalletCheckResponse> {\n const response = await this.#policy.execute(async () => {\n const url = new URL(\n `/v1/wallet/${encodeURIComponent(address)}`,\n this.#complianceApiUrl,\n );\n const localResponse = await this.#fetch(url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n WalletCheckResponseStruct,\n 'compliance wallet check API',\n );\n }\n\n /**\n * Checks compliance status for multiple wallet addresses in a single request.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<BatchWalletCheckResponseItem[]> {\n const response = await this.#policy.execute(async () => {\n const url = new URL('/v1/wallet/batch', this.#complianceApiUrl);\n const localResponse = await this.#fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(addresses),\n });\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n array(BatchWalletCheckResponseItemStruct),\n 'compliance batch check API',\n );\n }\n}\n\n/**\n * Validates an API response against a superstruct schema.\n *\n * @param data - The raw response data to validate.\n * @param struct - The superstruct schema to validate against.\n * @param struct.is - The type guard function from the schema.\n * @param apiName - A human-readable name for the API, used in error messages.\n * @returns The validated data.\n * @throws If the data does not match the schema.\n */\nfunction validateResponse<Response>(\n data: unknown,\n struct: { is: (value: unknown) => value is Response },\n apiName: string,\n): Response {\n if (struct.is(data)) {\n return data;\n }\n throw new Error(`Malformed response received from ${apiName}`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ComplianceService.mjs","sourceRoot":"","sources":["../src/ComplianceService.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Infer } from '@metamask/superstruct';\nimport { array, boolean, object, string } from '@metamask/superstruct';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { ComplianceServiceMethodActions } from './ComplianceService-method-action-types';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link ComplianceService}, used to namespace the service's\n * actions and events.\n */\nexport const serviceName = 'ComplianceService';\n\n/**\n * The supported environments for the Compliance API.\n */\nexport type ComplianceServiceEnvironment = 'production' | 'development';\n\nconst COMPLIANCE_API_URLS: Record<ComplianceServiceEnvironment, string> = {\n production: 'https://compliance.api.cx.metamask.io',\n development: 'https://compliance.dev-api.cx.metamask.io',\n};\n\nexport type ComplianceServiceOptions = {\n messenger: ComplianceServiceMessenger;\n fetch: typeof fetch;\n /**\n * Explicit Compliance API URL. Prefer this for application builds so API\n * endpoints can be managed by build configuration. Path components are\n * preserved as a base path for Compliance API routes.\n */\n apiUrl?: string;\n /**\n * Fallback environment used when `apiUrl` is not provided.\n */\n env?: ComplianceServiceEnvironment;\n policyOptions?: CreateServicePolicyOptions;\n};\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n] as const;\n\n/**\n * Actions that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceActions = ComplianceServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link ComplianceService} calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link ComplianceService} exposes to other consumers.\n */\nexport type ComplianceServiceEvents = never;\n\n/**\n * Events from other messengers that {@link ComplianceService} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link ComplianceService}.\n */\nexport type ComplianceServiceMessenger = Messenger<\n typeof serviceName,\n ComplianceServiceActions | AllowedActions,\n ComplianceServiceEvents | AllowedEvents\n>;\n\n// === API RESPONSE SCHEMAS ===\n\n/**\n * Schema for the response from `GET /v1/wallet/:address`.\n */\nconst WalletCheckResponseStruct = object({\n address: string(),\n blocked: boolean(),\n});\n\n/**\n * The validated shape of a single wallet compliance check response.\n */\ntype WalletCheckResponse = Infer<typeof WalletCheckResponseStruct>;\n\n/**\n * Schema for each item in the response from `POST /v1/wallet/batch`.\n * Reuses the same shape as a single wallet check.\n */\nconst BatchWalletCheckResponseItemStruct = WalletCheckResponseStruct;\n\n/**\n * The validated shape of a single item in a batch compliance check response.\n */\ntype BatchWalletCheckResponseItem = Infer<\n typeof BatchWalletCheckResponseItemStruct\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * `ComplianceService` communicates with the Compliance API to check whether\n * wallet addresses are sanctioned under OFAC regulations.\n *\n * @example\n *\n * ``` ts\n * import { Messenger } from '@metamask/messenger';\n * import type {\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * } from '@metamask/compliance-controller';\n * import { ComplianceService } from '@metamask/compliance-controller';\n *\n * const rootMessenger = new Messenger<\n * 'Root',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * >({ namespace: 'Root' });\n * const serviceMessenger = new Messenger<\n * 'ComplianceService',\n * ComplianceServiceActions,\n * ComplianceServiceEvents,\n * typeof rootMessenger,\n * >({\n * namespace: 'ComplianceService',\n * parent: rootMessenger,\n * });\n * new ComplianceService({\n * messenger: serviceMessenger,\n * fetch,\n * apiUrl: 'https://compliance.api.cx.metamask.io',\n * });\n *\n * // Check a single wallet\n * const result = await rootMessenger.call(\n * 'ComplianceService:checkWalletCompliance',\n * '0x1234...',\n * );\n * // => { address: '0x1234...', blocked: false }\n * ```\n */\nexport class ComplianceService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n /**\n * The messenger suited for this service.\n */\n readonly #messenger: ConstructorParameters<\n typeof ComplianceService\n >[0]['messenger'];\n\n /**\n * A function that can be used to make an HTTP request.\n */\n readonly #fetch: ConstructorParameters<typeof ComplianceService>[0]['fetch'];\n\n /**\n * The resolved base URL for the Compliance API.\n */\n readonly #complianceApiUrl: string;\n\n /**\n * The policy that wraps each request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n /**\n * Constructs a new ComplianceService object.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * @param args.apiUrl - The explicit Compliance API URL.\n * @param args.env - The fallback environment to use for the Compliance API\n * when `apiUrl` is not provided.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n fetch: fetchFunction,\n apiUrl,\n env = 'production',\n policyOptions = {},\n }: ComplianceServiceOptions) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#fetch = fetchFunction;\n this.#complianceApiUrl = getComplianceApiUrl({ apiUrl, env });\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a non-500\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when the service is degraded due\n * to slow responses or repeated failures.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Checks compliance status for a single wallet address.\n *\n * @param address - The wallet address to check.\n * @returns The compliance status of the wallet.\n */\n async checkWalletCompliance(address: string): Promise<WalletCheckResponse> {\n const response = await this.#policy.execute(async () => {\n const url = new URL(\n `v1/wallet/${encodeURIComponent(address)}`,\n this.#complianceApiUrl,\n );\n const localResponse = await this.#fetch(url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n WalletCheckResponseStruct,\n 'compliance wallet check API',\n );\n }\n\n /**\n * Checks compliance status for multiple wallet addresses in a single request.\n *\n * @param addresses - The wallet addresses to check.\n * @returns The compliance statuses of the wallets.\n */\n async checkWalletsCompliance(\n addresses: string[],\n ): Promise<BatchWalletCheckResponseItem[]> {\n const response = await this.#policy.execute(async () => {\n const url = new URL('v1/wallet/batch', this.#complianceApiUrl);\n const localResponse = await this.#fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(addresses),\n });\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Fetching '${url.toString()}' failed with status '${localResponse.status}'`,\n );\n }\n return localResponse;\n });\n const jsonResponse: unknown = await response.json();\n\n return validateResponse(\n jsonResponse,\n array(BatchWalletCheckResponseItemStruct),\n 'compliance batch check API',\n );\n }\n}\n\nfunction getComplianceApiUrl({\n apiUrl,\n env,\n}: {\n apiUrl?: string;\n env: ComplianceServiceEnvironment;\n}): string {\n if (apiUrl === undefined) {\n return COMPLIANCE_API_URLS[env];\n }\n\n let url: URL;\n try {\n url = new URL(apiUrl);\n } catch {\n throw new Error(`Invalid Compliance API URL: ${apiUrl}`);\n }\n\n if (url.search || url.hash) {\n throw new Error(\n `Invalid Compliance API URL: ${apiUrl}. Query strings and fragments are not supported.`,\n );\n }\n if (!url.pathname.endsWith('/')) {\n url.pathname = `${url.pathname}/`;\n }\n return url.href;\n}\n\n/**\n * Validates an API response against a superstruct schema.\n *\n * @param data - The raw response data to validate.\n * @param struct - The superstruct schema to validate against.\n * @param struct.is - The type guard function from the schema.\n * @param apiName - A human-readable name for the API, used in error messages.\n * @returns The validated data.\n * @throws If the data does not match the schema.\n */\nfunction validateResponse<Response>(\n data: unknown,\n struct: { is: (value: unknown) => value is Response },\n apiName: string,\n): Response {\n if (struct.is(data)) {\n return data;\n }\n throw new Error(`Malformed response received from ${apiName}`);\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.selectIsWalletBlocked = exports.getDefaultComplianceControllerState = exports.ComplianceController = exports.ComplianceService = void 0;
|
|
3
|
+
exports.selectIsWalletBlocked = exports.selectAreAnyWalletsBlocked = exports.getDefaultComplianceControllerState = exports.ComplianceController = exports.ComplianceService = void 0;
|
|
4
4
|
var ComplianceService_1 = require("./ComplianceService.cjs");
|
|
5
5
|
Object.defineProperty(exports, "ComplianceService", { enumerable: true, get: function () { return ComplianceService_1.ComplianceService; } });
|
|
6
6
|
var ComplianceController_1 = require("./ComplianceController.cjs");
|
|
7
7
|
Object.defineProperty(exports, "ComplianceController", { enumerable: true, get: function () { return ComplianceController_1.ComplianceController; } });
|
|
8
8
|
Object.defineProperty(exports, "getDefaultComplianceControllerState", { enumerable: true, get: function () { return ComplianceController_1.getDefaultComplianceControllerState; } });
|
|
9
9
|
var selectors_1 = require("./selectors.cjs");
|
|
10
|
+
Object.defineProperty(exports, "selectAreAnyWalletsBlocked", { enumerable: true, get: function () { return selectors_1.selectAreAnyWalletsBlocked; } });
|
|
10
11
|
Object.defineProperty(exports, "selectIsWalletBlocked", { enumerable: true, get: function () { return selectors_1.selectIsWalletBlocked; } });
|
|
11
12
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAWA,6DAAwD;AAA/C,sHAAA,iBAAiB,OAAA;AAc1B,mEAGgC;AAF9B,4HAAA,oBAAoB,OAAA;AACpB,2IAAA,mCAAmC,OAAA;AAErC,6CAAgF;AAAvE,uHAAA,0BAA0B,OAAA;AAAE,kHAAA,qBAAqB,OAAA","sourcesContent":["export type {\n ComplianceServiceActions,\n ComplianceServiceEnvironment,\n ComplianceServiceEvents,\n ComplianceServiceMessenger,\n ComplianceServiceOptions,\n} from './ComplianceService';\nexport type {\n ComplianceServiceCheckWalletComplianceAction,\n ComplianceServiceCheckWalletsComplianceAction,\n} from './ComplianceService-method-action-types';\nexport { ComplianceService } from './ComplianceService';\nexport type {\n ComplianceControllerActions,\n ComplianceControllerEvents,\n ComplianceControllerGetStateAction,\n ComplianceControllerMessenger,\n ComplianceControllerState,\n ComplianceControllerStateChangeEvent,\n} from './ComplianceController';\nexport type {\n ComplianceControllerCheckWalletComplianceAction,\n ComplianceControllerCheckWalletsComplianceAction,\n ComplianceControllerClearComplianceStateAction,\n} from './ComplianceController-method-action-types';\nexport {\n ComplianceController,\n getDefaultComplianceControllerState,\n} from './ComplianceController';\nexport { selectAreAnyWalletsBlocked, selectIsWalletBlocked } from './selectors';\nexport type { WalletComplianceStatus } from './types';\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type { ComplianceServiceActions, ComplianceServiceEnvironment, ComplianceServiceEvents, ComplianceServiceMessenger, } from "./ComplianceService.cjs";
|
|
1
|
+
export type { ComplianceServiceActions, ComplianceServiceEnvironment, ComplianceServiceEvents, ComplianceServiceMessenger, ComplianceServiceOptions, } from "./ComplianceService.cjs";
|
|
2
2
|
export type { ComplianceServiceCheckWalletComplianceAction, ComplianceServiceCheckWalletsComplianceAction, } from "./ComplianceService-method-action-types.cjs";
|
|
3
3
|
export { ComplianceService } from "./ComplianceService.cjs";
|
|
4
4
|
export type { ComplianceControllerActions, ComplianceControllerEvents, ComplianceControllerGetStateAction, ComplianceControllerMessenger, ComplianceControllerState, ComplianceControllerStateChangeEvent, } from "./ComplianceController.cjs";
|
|
5
5
|
export type { ComplianceControllerCheckWalletComplianceAction, ComplianceControllerCheckWalletsComplianceAction, ComplianceControllerClearComplianceStateAction, } from "./ComplianceController-method-action-types.cjs";
|
|
6
6
|
export { ComplianceController, getDefaultComplianceControllerState, } from "./ComplianceController.cjs";
|
|
7
|
-
export { selectIsWalletBlocked } from "./selectors.cjs";
|
|
7
|
+
export { selectAreAnyWalletsBlocked, selectIsWalletBlocked } from "./selectors.cjs";
|
|
8
8
|
export type { WalletComplianceStatus } from "./types.cjs";
|
|
9
9
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,GACzB,gCAA4B;AAC7B,YAAY,EACV,4CAA4C,EAC5C,6CAA6C,GAC9C,oDAAgD;AACjD,OAAO,EAAE,iBAAiB,EAAE,gCAA4B;AACxD,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,kCAAkC,EAClC,6BAA6B,EAC7B,yBAAyB,EACzB,oCAAoC,GACrC,mCAA+B;AAChC,YAAY,EACV,+CAA+C,EAC/C,gDAAgD,EAChD,8CAA8C,GAC/C,uDAAmD;AACpD,OAAO,EACL,oBAAoB,EACpB,mCAAmC,GACpC,mCAA+B;AAChC,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,wBAAoB;AAChF,YAAY,EAAE,sBAAsB,EAAE,oBAAgB"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type { ComplianceServiceActions, ComplianceServiceEnvironment, ComplianceServiceEvents, ComplianceServiceMessenger, } from "./ComplianceService.mjs";
|
|
1
|
+
export type { ComplianceServiceActions, ComplianceServiceEnvironment, ComplianceServiceEvents, ComplianceServiceMessenger, ComplianceServiceOptions, } from "./ComplianceService.mjs";
|
|
2
2
|
export type { ComplianceServiceCheckWalletComplianceAction, ComplianceServiceCheckWalletsComplianceAction, } from "./ComplianceService-method-action-types.mjs";
|
|
3
3
|
export { ComplianceService } from "./ComplianceService.mjs";
|
|
4
4
|
export type { ComplianceControllerActions, ComplianceControllerEvents, ComplianceControllerGetStateAction, ComplianceControllerMessenger, ComplianceControllerState, ComplianceControllerStateChangeEvent, } from "./ComplianceController.mjs";
|
|
5
5
|
export type { ComplianceControllerCheckWalletComplianceAction, ComplianceControllerCheckWalletsComplianceAction, ComplianceControllerClearComplianceStateAction, } from "./ComplianceController-method-action-types.mjs";
|
|
6
6
|
export { ComplianceController, getDefaultComplianceControllerState, } from "./ComplianceController.mjs";
|
|
7
|
-
export { selectIsWalletBlocked } from "./selectors.mjs";
|
|
7
|
+
export { selectAreAnyWalletsBlocked, selectIsWalletBlocked } from "./selectors.mjs";
|
|
8
8
|
export type { WalletComplianceStatus } from "./types.mjs";
|
|
9
9
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,GACzB,gCAA4B;AAC7B,YAAY,EACV,4CAA4C,EAC5C,6CAA6C,GAC9C,oDAAgD;AACjD,OAAO,EAAE,iBAAiB,EAAE,gCAA4B;AACxD,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,kCAAkC,EAClC,6BAA6B,EAC7B,yBAAyB,EACzB,oCAAoC,GACrC,mCAA+B;AAChC,YAAY,EACV,+CAA+C,EAC/C,gDAAgD,EAChD,8CAA8C,GAC/C,uDAAmD;AACpD,OAAO,EACL,oBAAoB,EACpB,mCAAmC,GACpC,mCAA+B;AAChC,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,wBAAoB;AAChF,YAAY,EAAE,sBAAsB,EAAE,oBAAgB"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ComplianceService } from "./ComplianceService.mjs";
|
|
2
2
|
export { ComplianceController, getDefaultComplianceControllerState } from "./ComplianceController.mjs";
|
|
3
|
-
export { selectIsWalletBlocked } from "./selectors.mjs";
|
|
3
|
+
export { selectAreAnyWalletsBlocked, selectIsWalletBlocked } from "./selectors.mjs";
|
|
4
4
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,iBAAiB,EAAE,gCAA4B;AAcxD,OAAO,EACL,oBAAoB,EACpB,mCAAmC,EACpC,mCAA+B;AAChC,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,wBAAoB","sourcesContent":["export type {\n ComplianceServiceActions,\n ComplianceServiceEnvironment,\n ComplianceServiceEvents,\n ComplianceServiceMessenger,\n ComplianceServiceOptions,\n} from './ComplianceService';\nexport type {\n ComplianceServiceCheckWalletComplianceAction,\n ComplianceServiceCheckWalletsComplianceAction,\n} from './ComplianceService-method-action-types';\nexport { ComplianceService } from './ComplianceService';\nexport type {\n ComplianceControllerActions,\n ComplianceControllerEvents,\n ComplianceControllerGetStateAction,\n ComplianceControllerMessenger,\n ComplianceControllerState,\n ComplianceControllerStateChangeEvent,\n} from './ComplianceController';\nexport type {\n ComplianceControllerCheckWalletComplianceAction,\n ComplianceControllerCheckWalletsComplianceAction,\n ComplianceControllerClearComplianceStateAction,\n} from './ComplianceController-method-action-types';\nexport {\n ComplianceController,\n getDefaultComplianceControllerState,\n} from './ComplianceController';\nexport { selectAreAnyWalletsBlocked, selectIsWalletBlocked } from './selectors';\nexport type { WalletComplianceStatus } from './types';\n"]}
|
package/dist/selectors.cjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.selectIsWalletBlocked = void 0;
|
|
3
|
+
exports.selectAreAnyWalletsBlocked = exports.selectIsWalletBlocked = void 0;
|
|
4
4
|
const reselect_1 = require("reselect");
|
|
5
|
+
const utils_1 = require("./utils.cjs");
|
|
5
6
|
const selectWalletComplianceStatusMap = (state) => state.walletComplianceStatusMap;
|
|
6
7
|
/**
|
|
7
8
|
* Creates a selector that returns whether a wallet address is blocked, based
|
|
@@ -11,6 +12,16 @@ const selectWalletComplianceStatusMap = (state) => state.walletComplianceStatusM
|
|
|
11
12
|
* @returns A selector that takes `ComplianceControllerState` and returns
|
|
12
13
|
* `true` if the wallet is blocked, `false` otherwise.
|
|
13
14
|
*/
|
|
14
|
-
const selectIsWalletBlocked = (address) => (0, reselect_1.createSelector)([selectWalletComplianceStatusMap], (statusMap) => statusMap
|
|
15
|
+
const selectIsWalletBlocked = (address) => (0, reselect_1.createSelector)([selectWalletComplianceStatusMap], (statusMap) => (0, utils_1.getWalletComplianceStatus)(statusMap, address)?.blocked ?? false);
|
|
15
16
|
exports.selectIsWalletBlocked = selectIsWalletBlocked;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a selector that returns whether any wallet address is blocked, based
|
|
19
|
+
* on the per-address compliance status cache.
|
|
20
|
+
*
|
|
21
|
+
* @param addresses - The wallet addresses to check.
|
|
22
|
+
* @returns A selector that takes `ComplianceControllerState` and returns
|
|
23
|
+
* `true` if any wallet is blocked, `false` otherwise.
|
|
24
|
+
*/
|
|
25
|
+
const selectAreAnyWalletsBlocked = (addresses) => (0, reselect_1.createSelector)([selectWalletComplianceStatusMap], (statusMap) => addresses.some((address) => (0, utils_1.getWalletComplianceStatus)(statusMap, address)?.blocked));
|
|
26
|
+
exports.selectAreAnyWalletsBlocked = selectAreAnyWalletsBlocked;
|
|
16
27
|
//# sourceMappingURL=selectors.cjs.map
|
package/dist/selectors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.cjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":";;;AAAA,uCAA0C;
|
|
1
|
+
{"version":3,"file":"selectors.cjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":";;;AAAA,uCAA0C;AAG1C,uCAAoD;AAEpD,MAAM,+BAA+B,GAAG,CACtC,KAAgC,EACwB,EAAE,CAC1D,KAAK,CAAC,yBAAyB,CAAC;AAElC;;;;;;;GAOG;AACI,MAAM,qBAAqB,GAAG,CACnC,OAAe,EACkC,EAAE,CACnD,IAAA,yBAAc,EACZ,CAAC,+BAA+B,CAAC,EACjC,CAAC,SAAS,EAAW,EAAE,CACrB,IAAA,iCAAyB,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,IAAI,KAAK,CAClE,CAAC;AAPS,QAAA,qBAAqB,yBAO9B;AAEJ;;;;;;;GAOG;AACI,MAAM,0BAA0B,GAAG,CACxC,SAAmB,EAC8B,EAAE,CACnD,IAAA,yBAAc,EAAC,CAAC,+BAA+B,CAAC,EAAE,CAAC,SAAS,EAAW,EAAE,CACvE,SAAS,CAAC,IAAI,CACZ,CAAC,OAAO,EAAE,EAAE,CAAC,IAAA,iCAAyB,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CACpE,CACF,CAAC;AAPS,QAAA,0BAA0B,8BAOnC","sourcesContent":["import { createSelector } from 'reselect';\n\nimport type { ComplianceControllerState } from './ComplianceController';\nimport { getWalletComplianceStatus } from './utils';\n\nconst selectWalletComplianceStatusMap = (\n state: ComplianceControllerState,\n): ComplianceControllerState['walletComplianceStatusMap'] =>\n state.walletComplianceStatusMap;\n\n/**\n * Creates a selector that returns whether a wallet address is blocked, based\n * on the per-address compliance status cache.\n *\n * @param address - The wallet address to check.\n * @returns A selector that takes `ComplianceControllerState` and returns\n * `true` if the wallet is blocked, `false` otherwise.\n */\nexport const selectIsWalletBlocked = (\n address: string,\n): ((state: ComplianceControllerState) => boolean) =>\n createSelector(\n [selectWalletComplianceStatusMap],\n (statusMap): boolean =>\n getWalletComplianceStatus(statusMap, address)?.blocked ?? false,\n );\n\n/**\n * Creates a selector that returns whether any wallet address is blocked, based\n * on the per-address compliance status cache.\n *\n * @param addresses - The wallet addresses to check.\n * @returns A selector that takes `ComplianceControllerState` and returns\n * `true` if any wallet is blocked, `false` otherwise.\n */\nexport const selectAreAnyWalletsBlocked = (\n addresses: string[],\n): ((state: ComplianceControllerState) => boolean) =>\n createSelector([selectWalletComplianceStatusMap], (statusMap): boolean =>\n addresses.some(\n (address) => getWalletComplianceStatus(statusMap, address)?.blocked,\n ),\n );\n"]}
|
package/dist/selectors.d.cts
CHANGED
|
@@ -8,4 +8,13 @@ import type { ComplianceControllerState } from "./ComplianceController.cjs";
|
|
|
8
8
|
* `true` if the wallet is blocked, `false` otherwise.
|
|
9
9
|
*/
|
|
10
10
|
export declare const selectIsWalletBlocked: (address: string) => (state: ComplianceControllerState) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a selector that returns whether any wallet address is blocked, based
|
|
13
|
+
* on the per-address compliance status cache.
|
|
14
|
+
*
|
|
15
|
+
* @param addresses - The wallet addresses to check.
|
|
16
|
+
* @returns A selector that takes `ComplianceControllerState` and returns
|
|
17
|
+
* `true` if any wallet is blocked, `false` otherwise.
|
|
18
|
+
*/
|
|
19
|
+
export declare const selectAreAnyWalletsBlocked: (addresses: string[]) => (state: ComplianceControllerState) => boolean;
|
|
11
20
|
//# sourceMappingURL=selectors.d.cts.map
|
package/dist/selectors.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.d.cts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,mCAA+B;
|
|
1
|
+
{"version":3,"file":"selectors.d.cts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,mCAA+B;AAQxE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,YACvB,MAAM,aACL,yBAAyB,KAAK,OAKvC,CAAC;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,cAC1B,MAAM,EAAE,aACT,yBAAyB,KAAK,OAKvC,CAAC"}
|
package/dist/selectors.d.mts
CHANGED
|
@@ -8,4 +8,13 @@ import type { ComplianceControllerState } from "./ComplianceController.mjs";
|
|
|
8
8
|
* `true` if the wallet is blocked, `false` otherwise.
|
|
9
9
|
*/
|
|
10
10
|
export declare const selectIsWalletBlocked: (address: string) => (state: ComplianceControllerState) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a selector that returns whether any wallet address is blocked, based
|
|
13
|
+
* on the per-address compliance status cache.
|
|
14
|
+
*
|
|
15
|
+
* @param addresses - The wallet addresses to check.
|
|
16
|
+
* @returns A selector that takes `ComplianceControllerState` and returns
|
|
17
|
+
* `true` if any wallet is blocked, `false` otherwise.
|
|
18
|
+
*/
|
|
19
|
+
export declare const selectAreAnyWalletsBlocked: (addresses: string[]) => (state: ComplianceControllerState) => boolean;
|
|
11
20
|
//# sourceMappingURL=selectors.d.mts.map
|
package/dist/selectors.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.d.mts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,mCAA+B;
|
|
1
|
+
{"version":3,"file":"selectors.d.mts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,mCAA+B;AAQxE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,YACvB,MAAM,aACL,yBAAyB,KAAK,OAKvC,CAAC;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,cAC1B,MAAM,EAAE,aACT,yBAAyB,KAAK,OAKvC,CAAC"}
|
package/dist/selectors.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createSelector } from "reselect";
|
|
2
|
+
import { getWalletComplianceStatus } from "./utils.mjs";
|
|
2
3
|
const selectWalletComplianceStatusMap = (state) => state.walletComplianceStatusMap;
|
|
3
4
|
/**
|
|
4
5
|
* Creates a selector that returns whether a wallet address is blocked, based
|
|
@@ -8,5 +9,14 @@ const selectWalletComplianceStatusMap = (state) => state.walletComplianceStatusM
|
|
|
8
9
|
* @returns A selector that takes `ComplianceControllerState` and returns
|
|
9
10
|
* `true` if the wallet is blocked, `false` otherwise.
|
|
10
11
|
*/
|
|
11
|
-
export const selectIsWalletBlocked = (address) => createSelector([selectWalletComplianceStatusMap], (statusMap) => statusMap
|
|
12
|
+
export const selectIsWalletBlocked = (address) => createSelector([selectWalletComplianceStatusMap], (statusMap) => getWalletComplianceStatus(statusMap, address)?.blocked ?? false);
|
|
13
|
+
/**
|
|
14
|
+
* Creates a selector that returns whether any wallet address is blocked, based
|
|
15
|
+
* on the per-address compliance status cache.
|
|
16
|
+
*
|
|
17
|
+
* @param addresses - The wallet addresses to check.
|
|
18
|
+
* @returns A selector that takes `ComplianceControllerState` and returns
|
|
19
|
+
* `true` if any wallet is blocked, `false` otherwise.
|
|
20
|
+
*/
|
|
21
|
+
export const selectAreAnyWalletsBlocked = (addresses) => createSelector([selectWalletComplianceStatusMap], (statusMap) => addresses.some((address) => getWalletComplianceStatus(statusMap, address)?.blocked));
|
|
12
22
|
//# sourceMappingURL=selectors.mjs.map
|
package/dist/selectors.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectors.mjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB;
|
|
1
|
+
{"version":3,"file":"selectors.mjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB;AAG1C,OAAO,EAAE,yBAAyB,EAAE,oBAAgB;AAEpD,MAAM,+BAA+B,GAAG,CACtC,KAAgC,EACwB,EAAE,CAC1D,KAAK,CAAC,yBAAyB,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAe,EACkC,EAAE,CACnD,cAAc,CACZ,CAAC,+BAA+B,CAAC,EACjC,CAAC,SAAS,EAAW,EAAE,CACrB,yBAAyB,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,IAAI,KAAK,CAClE,CAAC;AAEJ;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,SAAmB,EAC8B,EAAE,CACnD,cAAc,CAAC,CAAC,+BAA+B,CAAC,EAAE,CAAC,SAAS,EAAW,EAAE,CACvE,SAAS,CAAC,IAAI,CACZ,CAAC,OAAO,EAAE,EAAE,CAAC,yBAAyB,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CACpE,CACF,CAAC","sourcesContent":["import { createSelector } from 'reselect';\n\nimport type { ComplianceControllerState } from './ComplianceController';\nimport { getWalletComplianceStatus } from './utils';\n\nconst selectWalletComplianceStatusMap = (\n state: ComplianceControllerState,\n): ComplianceControllerState['walletComplianceStatusMap'] =>\n state.walletComplianceStatusMap;\n\n/**\n * Creates a selector that returns whether a wallet address is blocked, based\n * on the per-address compliance status cache.\n *\n * @param address - The wallet address to check.\n * @returns A selector that takes `ComplianceControllerState` and returns\n * `true` if the wallet is blocked, `false` otherwise.\n */\nexport const selectIsWalletBlocked = (\n address: string,\n): ((state: ComplianceControllerState) => boolean) =>\n createSelector(\n [selectWalletComplianceStatusMap],\n (statusMap): boolean =>\n getWalletComplianceStatus(statusMap, address)?.blocked ?? false,\n );\n\n/**\n * Creates a selector that returns whether any wallet address is blocked, based\n * on the per-address compliance status cache.\n *\n * @param addresses - The wallet addresses to check.\n * @returns A selector that takes `ComplianceControllerState` and returns\n * `true` if any wallet is blocked, `false` otherwise.\n */\nexport const selectAreAnyWalletsBlocked = (\n addresses: string[],\n): ((state: ComplianceControllerState) => boolean) =>\n createSelector([selectWalletComplianceStatusMap], (statusMap): boolean =>\n addresses.some(\n (address) => getWalletComplianceStatus(statusMap, address)?.blocked,\n ),\n );\n"]}
|
package/dist/utils.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getWalletComplianceStatus = void 0;
|
|
4
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
5
|
+
const getWalletComplianceStatus = (statusMap, address) => {
|
|
6
|
+
const exactMatch = statusMap[address];
|
|
7
|
+
if (exactMatch || !(0, controller_utils_1.isValidHexAddress)(address, { allowNonPrefixed: false })) {
|
|
8
|
+
return exactMatch;
|
|
9
|
+
}
|
|
10
|
+
const matchingAddress = Object.keys(statusMap).find((cachedAddress) => (0, controller_utils_1.isValidHexAddress)(cachedAddress, { allowNonPrefixed: false }) &&
|
|
11
|
+
(0, controller_utils_1.isEqualCaseInsensitive)(cachedAddress, address));
|
|
12
|
+
return matchingAddress ? statusMap[matchingAddress] : undefined;
|
|
13
|
+
};
|
|
14
|
+
exports.getWalletComplianceStatus = getWalletComplianceStatus;
|
|
15
|
+
//# sourceMappingURL=utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;AAAA,iEAGoC;AAI7B,MAAM,yBAAyB,GAAG,CACvC,SAAiD,EACjD,OAAe,EACqB,EAAE;IACtC,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAEtC,IAAI,UAAU,IAAI,CAAC,IAAA,oCAAiB,EAAC,OAAO,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC3E,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CACjD,CAAC,aAAa,EAAE,EAAE,CAChB,IAAA,oCAAiB,EAAC,aAAa,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC;QAC7D,IAAA,yCAAsB,EAAC,aAAa,EAAE,OAAO,CAAC,CACjD,CAAC;IAEF,OAAO,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC,CAAC;AAjBW,QAAA,yBAAyB,6BAiBpC","sourcesContent":["import {\n isEqualCaseInsensitive,\n isValidHexAddress,\n} from '@metamask/controller-utils';\n\nimport type { WalletComplianceStatus } from './types';\n\nexport const getWalletComplianceStatus = (\n statusMap: Record<string, WalletComplianceStatus>,\n address: string,\n): WalletComplianceStatus | undefined => {\n const exactMatch = statusMap[address];\n\n if (exactMatch || !isValidHexAddress(address, { allowNonPrefixed: false })) {\n return exactMatch;\n }\n\n const matchingAddress = Object.keys(statusMap).find(\n (cachedAddress) =>\n isValidHexAddress(cachedAddress, { allowNonPrefixed: false }) &&\n isEqualCaseInsensitive(cachedAddress, address),\n );\n\n return matchingAddress ? statusMap[matchingAddress] : undefined;\n};\n"]}
|
package/dist/utils.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAgB;AAEtD,eAAO,MAAM,yBAAyB,cACzB,OAAO,MAAM,EAAE,sBAAsB,CAAC,WACxC,MAAM,KACd,sBAAsB,GAAG,SAc3B,CAAC"}
|
package/dist/utils.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAgB;AAEtD,eAAO,MAAM,yBAAyB,cACzB,OAAO,MAAM,EAAE,sBAAsB,CAAC,WACxC,MAAM,KACd,sBAAsB,GAAG,SAc3B,CAAC"}
|
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isEqualCaseInsensitive, isValidHexAddress } from "@metamask/controller-utils";
|
|
2
|
+
export const getWalletComplianceStatus = (statusMap, address) => {
|
|
3
|
+
const exactMatch = statusMap[address];
|
|
4
|
+
if (exactMatch || !isValidHexAddress(address, { allowNonPrefixed: false })) {
|
|
5
|
+
return exactMatch;
|
|
6
|
+
}
|
|
7
|
+
const matchingAddress = Object.keys(statusMap).find((cachedAddress) => isValidHexAddress(cachedAddress, { allowNonPrefixed: false }) &&
|
|
8
|
+
isEqualCaseInsensitive(cachedAddress, address));
|
|
9
|
+
return matchingAddress ? statusMap[matchingAddress] : undefined;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EAClB,mCAAmC;AAIpC,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,SAAiD,EACjD,OAAe,EACqB,EAAE;IACtC,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAEtC,IAAI,UAAU,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC3E,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CACjD,CAAC,aAAa,EAAE,EAAE,CAChB,iBAAiB,CAAC,aAAa,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC;QAC7D,sBAAsB,CAAC,aAAa,EAAE,OAAO,CAAC,CACjD,CAAC;IAEF,OAAO,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC,CAAC","sourcesContent":["import {\n isEqualCaseInsensitive,\n isValidHexAddress,\n} from '@metamask/controller-utils';\n\nimport type { WalletComplianceStatus } from './types';\n\nexport const getWalletComplianceStatus = (\n statusMap: Record<string, WalletComplianceStatus>,\n address: string,\n): WalletComplianceStatus | undefined => {\n const exactMatch = statusMap[address];\n\n if (exactMatch || !isValidHexAddress(address, { allowNonPrefixed: false })) {\n return exactMatch;\n }\n\n const matchingAddress = Object.keys(statusMap).find(\n (cachedAddress) =>\n isValidHexAddress(cachedAddress, { allowNonPrefixed: false }) &&\n isEqualCaseInsensitive(cachedAddress, address),\n );\n\n return matchingAddress ? statusMap[matchingAddress] : undefined;\n};\n"]}
|