@metamask-previews/compliance-controller 1.0.2-preview-7bc465a23 → 2.0.0-preview-1d148d2

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/ComplianceController-method-action-types.cjs.map +1 -1
  3. package/dist/ComplianceController-method-action-types.d.cts +8 -22
  4. package/dist/ComplianceController-method-action-types.d.cts.map +1 -1
  5. package/dist/ComplianceController-method-action-types.d.mts +8 -22
  6. package/dist/ComplianceController-method-action-types.d.mts.map +1 -1
  7. package/dist/ComplianceController-method-action-types.mjs.map +1 -1
  8. package/dist/ComplianceController.cjs +55 -112
  9. package/dist/ComplianceController.cjs.map +1 -1
  10. package/dist/ComplianceController.d.cts +16 -37
  11. package/dist/ComplianceController.d.cts.map +1 -1
  12. package/dist/ComplianceController.d.mts +16 -37
  13. package/dist/ComplianceController.d.mts.map +1 -1
  14. package/dist/ComplianceController.mjs +55 -112
  15. package/dist/ComplianceController.mjs.map +1 -1
  16. package/dist/ComplianceService-method-action-types.cjs.map +1 -1
  17. package/dist/ComplianceService-method-action-types.d.cts +1 -10
  18. package/dist/ComplianceService-method-action-types.d.cts.map +1 -1
  19. package/dist/ComplianceService-method-action-types.d.mts +1 -10
  20. package/dist/ComplianceService-method-action-types.d.mts.map +1 -1
  21. package/dist/ComplianceService-method-action-types.mjs.map +1 -1
  22. package/dist/ComplianceService.cjs +0 -29
  23. package/dist/ComplianceService.cjs.map +1 -1
  24. package/dist/ComplianceService.d.cts +0 -31
  25. package/dist/ComplianceService.d.cts.map +1 -1
  26. package/dist/ComplianceService.d.mts +0 -31
  27. package/dist/ComplianceService.d.mts.map +1 -1
  28. package/dist/ComplianceService.mjs +1 -30
  29. package/dist/ComplianceService.mjs.map +1 -1
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +3 -3
  32. package/dist/index.d.cts.map +1 -1
  33. package/dist/index.d.mts +3 -3
  34. package/dist/index.d.mts.map +1 -1
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/selectors.cjs +2 -9
  37. package/dist/selectors.cjs.map +1 -1
  38. package/dist/selectors.d.cts +1 -2
  39. package/dist/selectors.d.cts.map +1 -1
  40. package/dist/selectors.d.mts +1 -2
  41. package/dist/selectors.d.mts.map +1 -1
  42. package/dist/selectors.mjs +2 -9
  43. package/dist/selectors.mjs.map +1 -1
  44. package/dist/types.cjs.map +1 -1
  45. package/dist/types.d.cts +0 -25
  46. package/dist/types.d.cts.map +1 -1
  47. package/dist/types.d.mts +0 -25
  48. package/dist/types.d.mts.map +1 -1
  49. package/dist/types.mjs.map +1 -1
  50. package/package.json +3 -3
@@ -2,8 +2,8 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@meta
2
2
  import { BaseController } from "@metamask/base-controller";
3
3
  import type { Messenger } from "@metamask/messenger";
4
4
  import type { ComplianceControllerMethodActions } from "./ComplianceController-method-action-types.mjs";
5
- import type { ComplianceServiceMethodActions } from "./ComplianceService-method-action-types.mjs";
6
- import type { BlockedWalletsInfo, WalletComplianceStatus } from "./types.mjs";
5
+ import type { ComplianceServiceCheckWalletComplianceAction, ComplianceServiceCheckWalletsComplianceAction } from "./ComplianceService-method-action-types.mjs";
6
+ import type { WalletComplianceStatus } from "./types.mjs";
7
7
  /**
8
8
  * The name of the {@link ComplianceController}, used to namespace the
9
9
  * controller's actions and events and to namespace the controller's state data
@@ -15,18 +15,10 @@ export declare const controllerName = "ComplianceController";
15
15
  */
16
16
  export type ComplianceControllerState = {
17
17
  /**
18
- * A map of wallet addresses to their on-demand compliance check results.
18
+ * A map of wallet addresses to their compliance check results, used as a
19
+ * fallback cache when the API is unavailable.
19
20
  */
20
21
  walletComplianceStatusMap: Record<string, WalletComplianceStatus>;
21
- /**
22
- * Information about all blocked wallets, or `null` if not yet fetched.
23
- */
24
- blockedWallets: BlockedWalletsInfo | null;
25
- /**
26
- * Timestamp (in milliseconds) of the last blocked wallets fetch, or 0 if
27
- * never fetched.
28
- */
29
- blockedWalletsLastFetched: number;
30
22
  /**
31
23
  * The date/time (in ISO-8601 format) when the last compliance check was
32
24
  * performed, or `null` if no checks have been performed yet.
@@ -53,7 +45,7 @@ export type ComplianceControllerActions = ComplianceControllerGetStateAction | C
53
45
  /**
54
46
  * Actions from other messengers that {@link ComplianceController} calls.
55
47
  */
56
- type AllowedActions = ComplianceServiceMethodActions;
48
+ type AllowedActions = ComplianceServiceCheckWalletComplianceAction | ComplianceServiceCheckWalletsComplianceAction;
57
49
  /**
58
50
  * Published when the state of {@link ComplianceController} changes.
59
51
  */
@@ -73,12 +65,11 @@ type AllowedEvents = never;
73
65
  export type ComplianceControllerMessenger = Messenger<typeof controllerName, ComplianceControllerActions | AllowedActions, ComplianceControllerEvents | AllowedEvents>;
74
66
  /**
75
67
  * `ComplianceController` manages OFAC compliance state for wallet addresses.
76
- * It proactively fetches and caches the blocked wallets list from the
77
- * Compliance API so that consumers can perform synchronous lookups via the
78
- * `selectIsWalletBlocked` selector without making API calls.
68
+ * It performs on-demand compliance checks via the API and caches results
69
+ * per address in state. Cached results serve as a fallback if the API is
70
+ * unavailable for a subsequent check on the same address.
79
71
  */
80
72
  export declare class ComplianceController extends BaseController<typeof controllerName, ComplianceControllerState, ComplianceControllerMessenger> {
81
- #private;
82
73
  /**
83
74
  * Constructs a new {@link ComplianceController}.
84
75
  *
@@ -86,24 +77,16 @@ export declare class ComplianceController extends BaseController<typeof controll
86
77
  * @param args.messenger - The messenger suited for this controller.
87
78
  * @param args.state - The desired state with which to init this
88
79
  * controller. Missing properties will be filled in with defaults.
89
- * @param args.blockedWalletsRefreshInterval - The interval in milliseconds
90
- * after which the blocked wallets list is considered stale. Defaults to 1
91
- * hour.
92
80
  */
93
- constructor({ messenger, state, blockedWalletsRefreshInterval, }: {
81
+ constructor({ messenger, state, }: {
94
82
  messenger: ComplianceControllerMessenger;
95
83
  state?: Partial<ComplianceControllerState>;
96
- blockedWalletsRefreshInterval?: number;
97
84
  });
98
- /**
99
- * Initializes the controller by fetching the blocked wallets list if it
100
- * is missing or stale. Call once after construction to ensure the blocklist
101
- * is ready for `selectIsWalletBlocked` lookups.
102
- */
103
- init(): Promise<void>;
104
85
  /**
105
86
  * Checks compliance status for a single wallet address via the API and
106
- * persists the result to state.
87
+ * persists the result to state. If the API call fails and a previously
88
+ * cached result exists for the address, the cached result is returned as a
89
+ * fallback. If no cached result exists, the error is re-thrown.
107
90
  *
108
91
  * @param address - The wallet address to check.
109
92
  * @returns The compliance status of the wallet.
@@ -111,19 +94,15 @@ export declare class ComplianceController extends BaseController<typeof controll
111
94
  checkWalletCompliance(address: string): Promise<WalletComplianceStatus>;
112
95
  /**
113
96
  * Checks compliance status for multiple wallet addresses via the API and
114
- * persists the results to state.
97
+ * persists the results to state. If the API call fails and every requested
98
+ * address has a previously cached result, those cached results are returned
99
+ * as a fallback. If any address lacks a cached result, the error is
100
+ * re-thrown.
115
101
  *
116
102
  * @param addresses - The wallet addresses to check.
117
103
  * @returns The compliance statuses of the wallets.
118
104
  */
119
105
  checkWalletsCompliance(addresses: string[]): Promise<WalletComplianceStatus[]>;
120
- /**
121
- * Fetches the full list of blocked wallets from the API and persists the
122
- * data to state. This also updates the `blockedWalletsLastFetched` timestamp.
123
- *
124
- * @returns The blocked wallets information.
125
- */
126
- updateBlockedWallets(): Promise<BlockedWalletsInfo>;
127
106
  /**
128
107
  * Clears all compliance data from state.
129
108
  */
@@ -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,EAAE,8BAA8B,EAAE,oDAAgD;AAC9F,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,oBAAgB;AAI1E;;;;GAIG;AACH,eAAO,MAAM,cAAc,yBAAyB,CAAC;AASrD;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC;;OAEG;IACH,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAElE;;OAEG;IACH,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAE1C;;;OAGG;IACH,yBAAyB,EAAE,MAAM,CAAC;IAElC;;;OAGG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,mCAAmC,IAAI,yBAAyB,CAO/E;AAYD;;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,GAAG,8BAA8B,CAAC;AAErD;;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;;IAOC;;;;;;;;;;OAUG;gBACS,EACV,SAAS,EACT,KAAK,EACL,6BAAwE,GACzE,EAAE;QACD,SAAS,EAAE,6BAA6B,CAAC;QACzC,KAAK,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAC3C,6BAA6B,CAAC,EAAE,MAAM,CAAC;KACxC;IAmBD;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B;;;;;;OAMG;IACG,qBAAqB,CACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,sBAAsB,CAAC;IAqBlC;;;;;;OAMG;IACG,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAwBpC;;;;;OAKG;IACG,oBAAoB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAsBzD;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAsB7B"}
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;AAItD;;;;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;IA6BlC;;;;;;;;;OASG;IACG,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAkCpC;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAM7B"}
@@ -1,15 +1,3 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _ComplianceController_instances, _ComplianceController_blockedWalletsRefreshInterval, _ComplianceController_isBlockedWalletsStale;
13
1
  import { BaseController } from "@metamask/base-controller";
14
2
  // === GENERAL ===
15
3
  /**
@@ -18,10 +6,6 @@ import { BaseController } from "@metamask/base-controller";
18
6
  * when composed with other controllers.
19
7
  */
20
8
  export const controllerName = 'ComplianceController';
21
- /**
22
- * The default refresh interval for the blocked wallets list (1 hour).
23
- */
24
- const DEFAULT_BLOCKED_WALLETS_REFRESH_INTERVAL = 60 * 60 * 1000;
25
9
  /**
26
10
  * The metadata for each property in {@link ComplianceControllerState}.
27
11
  */
@@ -32,18 +16,6 @@ const complianceControllerMetadata = {
32
16
  persist: true,
33
17
  usedInUi: true,
34
18
  },
35
- blockedWallets: {
36
- includeInDebugSnapshot: false,
37
- includeInStateLogs: false,
38
- persist: true,
39
- usedInUi: false,
40
- },
41
- blockedWalletsLastFetched: {
42
- includeInDebugSnapshot: false,
43
- includeInStateLogs: true,
44
- persist: true,
45
- usedInUi: false,
46
- },
47
19
  lastCheckedAt: {
48
20
  includeInDebugSnapshot: false,
49
21
  includeInStateLogs: true,
@@ -62,25 +34,21 @@ const complianceControllerMetadata = {
62
34
  export function getDefaultComplianceControllerState() {
63
35
  return {
64
36
  walletComplianceStatusMap: {},
65
- blockedWallets: null,
66
- blockedWalletsLastFetched: 0,
67
37
  lastCheckedAt: null,
68
38
  };
69
39
  }
70
40
  // === MESSENGER ===
71
41
  const MESSENGER_EXPOSED_METHODS = [
72
- 'init',
73
42
  'checkWalletCompliance',
74
43
  'checkWalletsCompliance',
75
- 'updateBlockedWallets',
76
44
  'clearComplianceState',
77
45
  ];
78
46
  // === CONTROLLER DEFINITION ===
79
47
  /**
80
48
  * `ComplianceController` manages OFAC compliance state for wallet addresses.
81
- * It proactively fetches and caches the blocked wallets list from the
82
- * Compliance API so that consumers can perform synchronous lookups via the
83
- * `selectIsWalletBlocked` selector without making API calls.
49
+ * It performs on-demand compliance checks via the API and caches results
50
+ * per address in state. Cached results serve as a fallback if the API is
51
+ * unavailable for a subsequent check on the same address.
84
52
  */
85
53
  export class ComplianceController extends BaseController {
86
54
  /**
@@ -90,11 +58,8 @@ export class ComplianceController extends BaseController {
90
58
  * @param args.messenger - The messenger suited for this controller.
91
59
  * @param args.state - The desired state with which to init this
92
60
  * controller. Missing properties will be filled in with defaults.
93
- * @param args.blockedWalletsRefreshInterval - The interval in milliseconds
94
- * after which the blocked wallets list is considered stale. Defaults to 1
95
- * hour.
96
61
  */
97
- constructor({ messenger, state, blockedWalletsRefreshInterval = DEFAULT_BLOCKED_WALLETS_REFRESH_INTERVAL, }) {
62
+ constructor({ messenger, state, }) {
98
63
  super({
99
64
  messenger,
100
65
  metadata: complianceControllerMetadata,
@@ -104,91 +69,75 @@ export class ComplianceController extends BaseController {
104
69
  ...state,
105
70
  },
106
71
  });
107
- _ComplianceController_instances.add(this);
108
- /**
109
- * The interval (in milliseconds) after which the blocked wallets list
110
- * is considered stale.
111
- */
112
- _ComplianceController_blockedWalletsRefreshInterval.set(this, void 0);
113
- __classPrivateFieldSet(this, _ComplianceController_blockedWalletsRefreshInterval, blockedWalletsRefreshInterval, "f");
114
72
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
115
73
  }
116
- /**
117
- * Initializes the controller by fetching the blocked wallets list if it
118
- * is missing or stale. Call once after construction to ensure the blocklist
119
- * is ready for `selectIsWalletBlocked` lookups.
120
- */
121
- async init() {
122
- if (__classPrivateFieldGet(this, _ComplianceController_instances, "m", _ComplianceController_isBlockedWalletsStale).call(this)) {
123
- await this.updateBlockedWallets();
124
- }
125
- }
126
74
  /**
127
75
  * Checks compliance status for a single wallet address via the API and
128
- * persists the result to state.
76
+ * persists the result to state. If the API call fails and a previously
77
+ * cached result exists for the address, the cached result is returned as a
78
+ * fallback. If no cached result exists, the error is re-thrown.
129
79
  *
130
80
  * @param address - The wallet address to check.
131
81
  * @returns The compliance status of the wallet.
132
82
  */
133
83
  async checkWalletCompliance(address) {
134
- const result = await this.messenger.call('ComplianceService:checkWalletCompliance', address);
135
- const now = new Date().toISOString();
136
- const status = {
137
- address: result.address,
138
- blocked: result.blocked,
139
- checkedAt: now,
140
- };
141
- this.update((draftState) => {
142
- draftState.walletComplianceStatusMap[address] = status;
143
- draftState.lastCheckedAt = now;
144
- });
145
- return status;
84
+ try {
85
+ const result = await this.messenger.call('ComplianceService:checkWalletCompliance', address);
86
+ const now = new Date().toISOString();
87
+ const status = {
88
+ address: result.address,
89
+ blocked: result.blocked,
90
+ checkedAt: now,
91
+ };
92
+ this.update((draftState) => {
93
+ draftState.walletComplianceStatusMap[address] = status;
94
+ draftState.lastCheckedAt = now;
95
+ });
96
+ return status;
97
+ }
98
+ catch (error) {
99
+ const cached = this.state.walletComplianceStatusMap[address];
100
+ if (cached) {
101
+ return cached;
102
+ }
103
+ throw error;
104
+ }
146
105
  }
147
106
  /**
148
107
  * Checks compliance status for multiple wallet addresses via the API and
149
- * persists the results to state.
108
+ * persists the results to state. If the API call fails and every requested
109
+ * address has a previously cached result, those cached results are returned
110
+ * as a fallback. If any address lacks a cached result, the error is
111
+ * re-thrown.
150
112
  *
151
113
  * @param addresses - The wallet addresses to check.
152
114
  * @returns The compliance statuses of the wallets.
153
115
  */
154
116
  async checkWalletsCompliance(addresses) {
155
- const results = await this.messenger.call('ComplianceService:checkWalletsCompliance', addresses);
156
- const now = new Date().toISOString();
157
- const statuses = results.map((result) => ({
158
- address: result.address,
159
- blocked: result.blocked,
160
- checkedAt: now,
161
- }));
162
- this.update((draftState) => {
163
- for (let idx = 0; idx < statuses.length; idx++) {
164
- const callerAddress = addresses[idx];
165
- draftState.walletComplianceStatusMap[callerAddress] = statuses[idx];
117
+ try {
118
+ const results = await this.messenger.call('ComplianceService:checkWalletsCompliance', addresses);
119
+ const now = new Date().toISOString();
120
+ const statuses = results.map((result) => ({
121
+ address: result.address,
122
+ blocked: result.blocked,
123
+ checkedAt: now,
124
+ }));
125
+ this.update((draftState) => {
126
+ for (let idx = 0; idx < statuses.length; idx++) {
127
+ const callerAddress = addresses[idx];
128
+ draftState.walletComplianceStatusMap[callerAddress] = statuses[idx];
129
+ }
130
+ draftState.lastCheckedAt = now;
131
+ });
132
+ return statuses;
133
+ }
134
+ catch (error) {
135
+ const cachedStatuses = addresses.map((address) => this.state.walletComplianceStatusMap[address]);
136
+ if (cachedStatuses.every(Boolean)) {
137
+ return cachedStatuses;
166
138
  }
167
- draftState.lastCheckedAt = now;
168
- });
169
- return statuses;
170
- }
171
- /**
172
- * Fetches the full list of blocked wallets from the API and persists the
173
- * data to state. This also updates the `blockedWalletsLastFetched` timestamp.
174
- *
175
- * @returns The blocked wallets information.
176
- */
177
- async updateBlockedWallets() {
178
- const result = await this.messenger.call('ComplianceService:updateBlockedWallets');
179
- const now = new Date().toISOString();
180
- const blockedWallets = {
181
- addresses: result.addresses,
182
- sources: result.sources,
183
- lastUpdated: result.lastUpdated,
184
- fetchedAt: now,
185
- };
186
- this.update((draftState) => {
187
- draftState.blockedWallets = blockedWallets;
188
- draftState.blockedWalletsLastFetched = Date.now();
189
- draftState.lastCheckedAt = now;
190
- });
191
- return blockedWallets;
139
+ throw error;
140
+ }
192
141
  }
193
142
  /**
194
143
  * Clears all compliance data from state.
@@ -196,14 +145,8 @@ export class ComplianceController extends BaseController {
196
145
  clearComplianceState() {
197
146
  this.update((draftState) => {
198
147
  draftState.walletComplianceStatusMap = {};
199
- draftState.blockedWallets = null;
200
- draftState.blockedWalletsLastFetched = 0;
201
148
  draftState.lastCheckedAt = null;
202
149
  });
203
150
  }
204
151
  }
205
- _ComplianceController_blockedWalletsRefreshInterval = new WeakMap(), _ComplianceController_instances = new WeakSet(), _ComplianceController_isBlockedWalletsStale = function _ComplianceController_isBlockedWalletsStale() {
206
- return (Date.now() - this.state.blockedWalletsLastFetched >=
207
- __classPrivateFieldGet(this, _ComplianceController_blockedWalletsRefreshInterval, "f"));
208
- };
209
152
  //# sourceMappingURL=ComplianceController.mjs.map
@@ -1 +1 @@
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 { ComplianceServiceMethodActions } from './ComplianceService-method-action-types';\nimport type { BlockedWalletsInfo, 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/**\n * The default refresh interval for the blocked wallets list (1 hour).\n */\nconst DEFAULT_BLOCKED_WALLETS_REFRESH_INTERVAL = 60 * 60 * 1000;\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 on-demand compliance check results.\n */\n walletComplianceStatusMap: Record<string, WalletComplianceStatus>;\n\n /**\n * Information about all blocked wallets, or `null` if not yet fetched.\n */\n blockedWallets: BlockedWalletsInfo | null;\n\n /**\n * Timestamp (in milliseconds) of the last blocked wallets fetch, or 0 if\n * never fetched.\n */\n blockedWalletsLastFetched: number;\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 blockedWallets: {\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n persist: true,\n usedInUi: false,\n },\n blockedWalletsLastFetched: {\n includeInDebugSnapshot: false,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\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 blockedWallets: null,\n blockedWalletsLastFetched: 0,\n lastCheckedAt: null,\n };\n}\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'init',\n 'checkWalletCompliance',\n 'checkWalletsCompliance',\n 'updateBlockedWallets',\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 = ComplianceServiceMethodActions;\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 proactively fetches and caches the blocked wallets list from the\n * Compliance API so that consumers can perform synchronous lookups via the\n * `selectIsWalletBlocked` selector without making API calls.\n */\nexport class ComplianceController extends BaseController<\n typeof controllerName,\n ComplianceControllerState,\n ComplianceControllerMessenger\n> {\n /**\n * The interval (in milliseconds) after which the blocked wallets list\n * is considered stale.\n */\n readonly #blockedWalletsRefreshInterval: number;\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 * @param args.blockedWalletsRefreshInterval - The interval in milliseconds\n * after which the blocked wallets list is considered stale. Defaults to 1\n * hour.\n */\n constructor({\n messenger,\n state,\n blockedWalletsRefreshInterval = DEFAULT_BLOCKED_WALLETS_REFRESH_INTERVAL,\n }: {\n messenger: ComplianceControllerMessenger;\n state?: Partial<ComplianceControllerState>;\n blockedWalletsRefreshInterval?: number;\n }) {\n super({\n messenger,\n metadata: complianceControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultComplianceControllerState(),\n ...state,\n },\n });\n\n this.#blockedWalletsRefreshInterval = blockedWalletsRefreshInterval;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Initializes the controller by fetching the blocked wallets list if it\n * is missing or stale. Call once after construction to ensure the blocklist\n * is ready for `selectIsWalletBlocked` lookups.\n */\n async init(): Promise<void> {\n if (this.#isBlockedWalletsStale()) {\n await this.updateBlockedWallets();\n }\n }\n\n /**\n * Checks compliance status for a single wallet address via the API and\n * persists the result to state.\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 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 }\n\n /**\n * Checks compliance status for multiple wallet addresses via the API and\n * persists the results to state.\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 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 }\n\n /**\n * Fetches the full list of blocked wallets from the API and persists the\n * data to state. This also updates the `blockedWalletsLastFetched` timestamp.\n *\n * @returns The blocked wallets information.\n */\n async updateBlockedWallets(): Promise<BlockedWalletsInfo> {\n const result = await this.messenger.call(\n 'ComplianceService:updateBlockedWallets',\n );\n\n const now = new Date().toISOString();\n const blockedWallets: BlockedWalletsInfo = {\n addresses: result.addresses,\n sources: result.sources,\n lastUpdated: result.lastUpdated,\n fetchedAt: now,\n };\n\n this.update((draftState) => {\n draftState.blockedWallets = blockedWallets;\n draftState.blockedWalletsLastFetched = Date.now();\n draftState.lastCheckedAt = now;\n });\n\n return blockedWallets;\n }\n\n /**\n * Clears all compliance data from state.\n */\n clearComplianceState(): void {\n this.update((draftState) => {\n draftState.walletComplianceStatusMap = {};\n draftState.blockedWallets = null;\n draftState.blockedWalletsLastFetched = 0;\n draftState.lastCheckedAt = null;\n });\n }\n\n /**\n * Determines whether the blocked wallets list is stale and needs to be\n * refreshed.\n *\n * @returns `true` if the list has never been fetched or the refresh\n * interval has elapsed.\n */\n #isBlockedWalletsStale(): boolean {\n return (\n Date.now() - this.state.blockedWalletsLastFetched >=\n this.#blockedWalletsRefreshInterval\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';\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 +1 @@
1
- {"version":3,"file":"ComplianceService-method-action-types.cjs","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { ComplianceService } from './ComplianceService';\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 */\nexport type ComplianceServiceCheckWalletComplianceAction = {\n type: `ComplianceService:checkWalletCompliance`;\n handler: ComplianceService['checkWalletCompliance'];\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 */\nexport type ComplianceServiceCheckWalletsComplianceAction = {\n type: `ComplianceService:checkWalletsCompliance`;\n handler: ComplianceService['checkWalletsCompliance'];\n};\n\n/**\n * Fetches the full list of blocked wallets and source metadata.\n *\n * @returns The blocked wallets data.\n */\nexport type ComplianceServiceUpdateBlockedWalletsAction = {\n type: `ComplianceService:updateBlockedWallets`;\n handler: ComplianceService['updateBlockedWallets'];\n};\n\n/**\n * Union of all ComplianceService action types.\n */\nexport type ComplianceServiceMethodActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction\n | ComplianceServiceUpdateBlockedWalletsAction;\n"]}
1
+ {"version":3,"file":"ComplianceService-method-action-types.cjs","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { ComplianceService } from './ComplianceService';\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 */\nexport type ComplianceServiceCheckWalletComplianceAction = {\n type: `ComplianceService:checkWalletCompliance`;\n handler: ComplianceService['checkWalletCompliance'];\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 */\nexport type ComplianceServiceCheckWalletsComplianceAction = {\n type: `ComplianceService:checkWalletsCompliance`;\n handler: ComplianceService['checkWalletsCompliance'];\n};\n\n/**\n * Union of all ComplianceService action types.\n */\nexport type ComplianceServiceMethodActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction;\n"]}
@@ -23,17 +23,8 @@ export type ComplianceServiceCheckWalletsComplianceAction = {
23
23
  type: `ComplianceService:checkWalletsCompliance`;
24
24
  handler: ComplianceService['checkWalletsCompliance'];
25
25
  };
26
- /**
27
- * Fetches the full list of blocked wallets and source metadata.
28
- *
29
- * @returns The blocked wallets data.
30
- */
31
- export type ComplianceServiceUpdateBlockedWalletsAction = {
32
- type: `ComplianceService:updateBlockedWallets`;
33
- handler: ComplianceService['updateBlockedWallets'];
34
- };
35
26
  /**
36
27
  * Union of all ComplianceService action types.
37
28
  */
38
- export type ComplianceServiceMethodActions = ComplianceServiceCheckWalletComplianceAction | ComplianceServiceCheckWalletsComplianceAction | ComplianceServiceUpdateBlockedWalletsAction;
29
+ export type ComplianceServiceMethodActions = ComplianceServiceCheckWalletComplianceAction | ComplianceServiceCheckWalletsComplianceAction;
39
30
  //# sourceMappingURL=ComplianceService-method-action-types.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ComplianceService-method-action-types.d.cts","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gCAA4B;AAE7D;;;;;GAKG;AACH,MAAM,MAAM,4CAA4C,GAAG;IACzD,IAAI,EAAE,yCAAyC,CAAC;IAChD,OAAO,EAAE,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;CACtD,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,2CAA2C,GAAG;IACxD,IAAI,EAAE,wCAAwC,CAAC;IAC/C,OAAO,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;CACpD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,8BAA8B,GACtC,4CAA4C,GAC5C,6CAA6C,GAC7C,2CAA2C,CAAC"}
1
+ {"version":3,"file":"ComplianceService-method-action-types.d.cts","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gCAA4B;AAE7D;;;;;GAKG;AACH,MAAM,MAAM,4CAA4C,GAAG;IACzD,IAAI,EAAE,yCAAyC,CAAC;IAChD,OAAO,EAAE,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,8BAA8B,GACtC,4CAA4C,GAC5C,6CAA6C,CAAC"}
@@ -23,17 +23,8 @@ export type ComplianceServiceCheckWalletsComplianceAction = {
23
23
  type: `ComplianceService:checkWalletsCompliance`;
24
24
  handler: ComplianceService['checkWalletsCompliance'];
25
25
  };
26
- /**
27
- * Fetches the full list of blocked wallets and source metadata.
28
- *
29
- * @returns The blocked wallets data.
30
- */
31
- export type ComplianceServiceUpdateBlockedWalletsAction = {
32
- type: `ComplianceService:updateBlockedWallets`;
33
- handler: ComplianceService['updateBlockedWallets'];
34
- };
35
26
  /**
36
27
  * Union of all ComplianceService action types.
37
28
  */
38
- export type ComplianceServiceMethodActions = ComplianceServiceCheckWalletComplianceAction | ComplianceServiceCheckWalletsComplianceAction | ComplianceServiceUpdateBlockedWalletsAction;
29
+ export type ComplianceServiceMethodActions = ComplianceServiceCheckWalletComplianceAction | ComplianceServiceCheckWalletsComplianceAction;
39
30
  //# sourceMappingURL=ComplianceService-method-action-types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ComplianceService-method-action-types.d.mts","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gCAA4B;AAE7D;;;;;GAKG;AACH,MAAM,MAAM,4CAA4C,GAAG;IACzD,IAAI,EAAE,yCAAyC,CAAC;IAChD,OAAO,EAAE,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;CACtD,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,2CAA2C,GAAG;IACxD,IAAI,EAAE,wCAAwC,CAAC;IAC/C,OAAO,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;CACpD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,8BAA8B,GACtC,4CAA4C,GAC5C,6CAA6C,GAC7C,2CAA2C,CAAC"}
1
+ {"version":3,"file":"ComplianceService-method-action-types.d.mts","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gCAA4B;AAE7D;;;;;GAKG;AACH,MAAM,MAAM,4CAA4C,GAAG;IACzD,IAAI,EAAE,yCAAyC,CAAC;IAChD,OAAO,EAAE,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,8BAA8B,GACtC,4CAA4C,GAC5C,6CAA6C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ComplianceService-method-action-types.mjs","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { ComplianceService } from './ComplianceService';\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 */\nexport type ComplianceServiceCheckWalletComplianceAction = {\n type: `ComplianceService:checkWalletCompliance`;\n handler: ComplianceService['checkWalletCompliance'];\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 */\nexport type ComplianceServiceCheckWalletsComplianceAction = {\n type: `ComplianceService:checkWalletsCompliance`;\n handler: ComplianceService['checkWalletsCompliance'];\n};\n\n/**\n * Fetches the full list of blocked wallets and source metadata.\n *\n * @returns The blocked wallets data.\n */\nexport type ComplianceServiceUpdateBlockedWalletsAction = {\n type: `ComplianceService:updateBlockedWallets`;\n handler: ComplianceService['updateBlockedWallets'];\n};\n\n/**\n * Union of all ComplianceService action types.\n */\nexport type ComplianceServiceMethodActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction\n | ComplianceServiceUpdateBlockedWalletsAction;\n"]}
1
+ {"version":3,"file":"ComplianceService-method-action-types.mjs","sourceRoot":"","sources":["../src/ComplianceService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { ComplianceService } from './ComplianceService';\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 */\nexport type ComplianceServiceCheckWalletComplianceAction = {\n type: `ComplianceService:checkWalletCompliance`;\n handler: ComplianceService['checkWalletCompliance'];\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 */\nexport type ComplianceServiceCheckWalletsComplianceAction = {\n type: `ComplianceService:checkWalletsCompliance`;\n handler: ComplianceService['checkWalletsCompliance'];\n};\n\n/**\n * Union of all ComplianceService action types.\n */\nexport type ComplianceServiceMethodActions =\n | ComplianceServiceCheckWalletComplianceAction\n | ComplianceServiceCheckWalletsComplianceAction;\n"]}
@@ -29,7 +29,6 @@ const COMPLIANCE_API_URLS = {
29
29
  const MESSENGER_EXPOSED_METHODS = [
30
30
  'checkWalletCompliance',
31
31
  'checkWalletsCompliance',
32
- 'updateBlockedWallets',
33
32
  ];
34
33
  // === API RESPONSE SCHEMAS ===
35
34
  /**
@@ -44,17 +43,6 @@ const WalletCheckResponseStruct = (0, superstruct_1.object)({
44
43
  * Reuses the same shape as a single wallet check.
45
44
  */
46
45
  const BatchWalletCheckResponseItemStruct = WalletCheckResponseStruct;
47
- /**
48
- * Schema for the response from `GET /v1/blocked-wallets`.
49
- */
50
- const BlockedWalletsResponseStruct = (0, superstruct_1.object)({
51
- addresses: (0, superstruct_1.array)((0, superstruct_1.string)()),
52
- sources: (0, superstruct_1.object)({
53
- ofac: (0, superstruct_1.number)(),
54
- remote: (0, superstruct_1.number)(),
55
- }),
56
- lastUpdated: (0, superstruct_1.string)(),
57
- });
58
46
  // === SERVICE DEFINITION ===
59
47
  /**
60
48
  * `ComplianceService` communicates with the Compliance API to check whether
@@ -209,23 +197,6 @@ class ComplianceService {
209
197
  const jsonResponse = await response.json();
210
198
  return validateResponse(jsonResponse, (0, superstruct_1.array)(BatchWalletCheckResponseItemStruct), 'compliance batch check API');
211
199
  }
212
- /**
213
- * Fetches the full list of blocked wallets and source metadata.
214
- *
215
- * @returns The blocked wallets data.
216
- */
217
- async updateBlockedWallets() {
218
- const response = await __classPrivateFieldGet(this, _ComplianceService_policy, "f").execute(async () => {
219
- const url = new URL('/v1/blocked-wallets', __classPrivateFieldGet(this, _ComplianceService_complianceApiUrl, "f"));
220
- const localResponse = await __classPrivateFieldGet(this, _ComplianceService_fetch, "f").call(this, url);
221
- if (!localResponse.ok) {
222
- throw new controller_utils_1.HttpError(localResponse.status, `Fetching '${url.toString()}' failed with status '${localResponse.status}'`);
223
- }
224
- return localResponse;
225
- });
226
- const jsonResponse = await response.json();
227
- return validateResponse(jsonResponse, BlockedWalletsResponseStruct, 'compliance blocked wallets API');
228
- }
229
200
  }
230
201
  exports.ComplianceService = ComplianceService;
231
202
  _a = ComplianceService, _ComplianceService_messenger = new WeakMap(), _ComplianceService_fetch = new WeakMap(), _ComplianceService_complianceApiUrl = new WeakMap(), _ComplianceService_policy = new WeakMap();
@@ -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, number, 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 'updateBlockedWallets',\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/**\n * Schema for the response from `GET /v1/blocked-wallets`.\n */\nconst BlockedWalletsResponseStruct = object({\n addresses: array(string()),\n sources: object({\n ofac: number(),\n remote: number(),\n }),\n lastUpdated: string(),\n});\n\n/**\n * The validated shape of the blocked wallets response.\n */\ntype BlockedWalletsResponse = Infer<typeof BlockedWalletsResponseStruct>;\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 * Fetches the full list of blocked wallets and source metadata.\n *\n * @returns The blocked wallets data.\n */\n async updateBlockedWallets(): Promise<BlockedWalletsResponse> {\n const response = await this.#policy.execute(async () => {\n const url = new URL('/v1/blocked-wallets', this.#complianceApiUrl);\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 BlockedWalletsResponseStruct,\n 'compliance blocked wallets 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\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"]}