@metamask-previews/kyc-controller 0.0.0-preview-11d78534e
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 +21 -0
- package/LICENSE +6 -0
- package/LICENSE.APACHE2 +201 -0
- package/LICENSE.MIT +21 -0
- package/README.md +648 -0
- package/dist/KycController-method-action-types.cjs +7 -0
- package/dist/KycController-method-action-types.cjs.map +1 -0
- package/dist/KycController-method-action-types.d.cts +143 -0
- package/dist/KycController-method-action-types.d.cts.map +1 -0
- package/dist/KycController-method-action-types.d.mts +143 -0
- package/dist/KycController-method-action-types.d.mts.map +1 -0
- package/dist/KycController-method-action-types.mjs +6 -0
- package/dist/KycController-method-action-types.mjs.map +1 -0
- package/dist/KycController.cjs +800 -0
- package/dist/KycController.cjs.map +1 -0
- package/dist/KycController.d.cts +219 -0
- package/dist/KycController.d.cts.map +1 -0
- package/dist/KycController.d.mts +219 -0
- package/dist/KycController.d.mts.map +1 -0
- package/dist/KycController.mjs +795 -0
- package/dist/KycController.mjs.map +1 -0
- package/dist/KycService-method-action-types.cjs +7 -0
- package/dist/KycService-method-action-types.cjs.map +1 -0
- package/dist/KycService-method-action-types.d.cts +74 -0
- package/dist/KycService-method-action-types.d.cts.map +1 -0
- package/dist/KycService-method-action-types.d.mts +74 -0
- package/dist/KycService-method-action-types.d.mts.map +1 -0
- package/dist/KycService-method-action-types.mjs +6 -0
- package/dist/KycService-method-action-types.mjs.map +1 -0
- package/dist/KycService.cjs +238 -0
- package/dist/KycService.cjs.map +1 -0
- package/dist/KycService.d.cts +169 -0
- package/dist/KycService.d.cts.map +1 -0
- package/dist/KycService.d.mts +169 -0
- package/dist/KycService.d.mts.map +1 -0
- package/dist/KycService.mjs +234 -0
- package/dist/KycService.mjs.map +1 -0
- package/dist/countryCodes.cjs +274 -0
- package/dist/countryCodes.cjs.map +1 -0
- package/dist/countryCodes.d.cts +18 -0
- package/dist/countryCodes.d.cts.map +1 -0
- package/dist/countryCodes.d.mts +18 -0
- package/dist/countryCodes.d.mts.map +1 -0
- package/dist/countryCodes.mjs +270 -0
- package/dist/countryCodes.mjs.map +1 -0
- package/dist/crypto.cjs +165 -0
- package/dist/crypto.cjs.map +1 -0
- package/dist/crypto.d.cts +83 -0
- package/dist/crypto.d.cts.map +1 -0
- package/dist/crypto.d.mts +83 -0
- package/dist/crypto.d.mts.map +1 -0
- package/dist/crypto.mjs +160 -0
- package/dist/crypto.mjs.map +1 -0
- package/dist/index.cjs +21 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -0
- package/dist/selectors.cjs +30 -0
- package/dist/selectors.cjs.map +1 -0
- package/dist/selectors.d.cts +24 -0
- package/dist/selectors.d.cts.map +1 -0
- package/dist/selectors.d.mts +24 -0
- package/dist/selectors.d.mts.map +1 -0
- package/dist/selectors.mjs +24 -0
- package/dist/selectors.mjs.map +1 -0
- package/dist/types.cjs +10 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +93 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +93 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +9 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +89 -0
package/README.md
ADDED
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
# KYC Controller `@metamask/kyc-controller`
|
|
2
|
+
|
|
3
|
+
Shared KYC / identity verification controller used across MetaMask clients
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
`yarn add @metamask/kyc-controller`
|
|
8
|
+
|
|
9
|
+
or
|
|
10
|
+
|
|
11
|
+
`npm install @metamask/kyc-controller`
|
|
12
|
+
|
|
13
|
+
## Development
|
|
14
|
+
|
|
15
|
+
To rebuild the package automatically whenever you change a source file, run the `build:watch` script:
|
|
16
|
+
|
|
17
|
+
`yarn workspace @metamask/kyc-controller run build:watch`
|
|
18
|
+
|
|
19
|
+
This watches `src/**/*.ts` and re-runs the build on each change (it also performs an initial build on start), which is useful when developing against a client that consumes this package locally.
|
|
20
|
+
|
|
21
|
+
## Contributing
|
|
22
|
+
|
|
23
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## Architecture
|
|
27
|
+
|
|
28
|
+
`@metamask/kyc-controller` is a shared, **platform-agnostic** package that owns
|
|
29
|
+
the end-to-end KYC / identity-verification flow used across MetaMask clients
|
|
30
|
+
(mobile, extension, web). It hides the vendor implementation (currently
|
|
31
|
+
**MoonPay** for identity + **SumSub** for document verification) behind a
|
|
32
|
+
vendor-neutral, per-product surface consumed by features such as **ramps** and
|
|
33
|
+
**card**.
|
|
34
|
+
|
|
35
|
+
This document explains:
|
|
36
|
+
|
|
37
|
+
- The package's internal building blocks and responsibilities.
|
|
38
|
+
- How the pieces communicate (messenger actions, injected adapters).
|
|
39
|
+
- The identity flow as a state machine and an end-to-end sequence.
|
|
40
|
+
- The encrypted frame message protocol and crypto.
|
|
41
|
+
- How the **metamask-mobile** client wires everything together on the client
|
|
42
|
+
side.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### 1. Design principles
|
|
47
|
+
|
|
48
|
+
The package is built around a few deliberate constraints:
|
|
49
|
+
|
|
50
|
+
| Principle | How it shows up in the code |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| **Vendor-neutral surface** | Consumers deal with `KycProduct` (`'ramps' \| 'card'`) and a phase machine, never with MoonPay/SumSub specifics. `KycVendor` is internal. |
|
|
53
|
+
| **Platform-agnostic core** | No React, no `Buffer`/`atob`, no native SDK imports. Crypto uses `@noble/*` + `@scure/base`. WebView/iframe presentation and the SumSub SDK are **injected** by each client. |
|
|
54
|
+
| **Controller owns orchestration; clients own presentation** | `KycController` owns all state, HTTP orchestration, crypto and the frame protocol. Clients only render frames, forward raw messages, and present the SumSub SDK. |
|
|
55
|
+
| **Stateless service** | `KycService` performs HTTP only; it holds no state and derives auth/geolocation from other controllers via the messenger. |
|
|
56
|
+
| **Everything through the messenger** | Both classes register their public methods as messenger actions, and reach external capabilities (auth token, geolocation) via delegated actions. |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### 2. Component overview
|
|
61
|
+
|
|
62
|
+
The package splits cleanly into a **stateful orchestrator** (`KycController`), a
|
|
63
|
+
**stateless HTTP client** (`KycService`), and supporting modules (crypto,
|
|
64
|
+
selectors, types).
|
|
65
|
+
|
|
66
|
+
```mermaid
|
|
67
|
+
graph TB
|
|
68
|
+
subgraph pkg["@metamask/kyc-controller"]
|
|
69
|
+
direction TB
|
|
70
|
+
Controller["KycController<br/><i>(BaseController)</i><br/>state + orchestration + frame protocol"]
|
|
71
|
+
Service["KycService<br/><i>(stateless)</i><br/>HTTP + response validation"]
|
|
72
|
+
Crypto["crypto.ts<br/>X25519 ECDH + AES-256-GCM"]
|
|
73
|
+
Selectors["selectors.ts<br/>memoized reselect selectors"]
|
|
74
|
+
Types["types.ts<br/>KycPhase, KycProduct,<br/>KycSumSubLauncher, ..."]
|
|
75
|
+
Country["countryCodes.ts<br/>alpha-2 → alpha-3"]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
subgraph deps["External MetaMask dependencies"]
|
|
79
|
+
Base["@metamask/base-controller"]
|
|
80
|
+
Msgr["@metamask/messenger"]
|
|
81
|
+
CU["@metamask/controller-utils<br/>createServicePolicy, HttpError"]
|
|
82
|
+
Geo["GeolocationController"]
|
|
83
|
+
Auth["AuthenticationController<br/>(profile-sync)"]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
subgraph vendor["Vendor backends (HTTP / frames)"]
|
|
87
|
+
UKYC["Universal KYC API<br/>kyc-api.cx.metamask.io"]
|
|
88
|
+
Frames["MoonPay frames<br/>blocks.moonpay.com"]
|
|
89
|
+
SumSubSDK["SumSub SDK<br/>(native / web)"]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
Controller -->|"decryptCredentials()"| Crypto
|
|
93
|
+
Controller -->|"messenger.call(KycService:*)"| Service
|
|
94
|
+
Controller -.->|"injected launcher"| SumSubSDK
|
|
95
|
+
Controller -->|"builds frame URLs<br/>handles frame messages"| Frames
|
|
96
|
+
|
|
97
|
+
Service -->|"createServicePolicy / HttpError"| CU
|
|
98
|
+
Service -->|"messenger.call(GeolocationController:getGeolocation)"| Geo
|
|
99
|
+
Service -->|"messenger.call(AuthenticationController:getBearerToken)"| Auth
|
|
100
|
+
Service -->|"fetch()"| UKYC
|
|
101
|
+
|
|
102
|
+
Controller --- Base
|
|
103
|
+
Controller --- Msgr
|
|
104
|
+
Service --- Msgr
|
|
105
|
+
Selectors -.->|"read"| Controller
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### 2.1 `KycController`
|
|
109
|
+
|
|
110
|
+
- Extends `BaseController<'KycController', KycControllerState, KycControllerMessenger>`.
|
|
111
|
+
- Holds **all flow state** (see [§3](#3-state-shape)).
|
|
112
|
+
- Owns an ephemeral **X25519 keypair** (`#keypair`) generated at construction —
|
|
113
|
+
never persisted, used only for the frame key exchange.
|
|
114
|
+
- Registers its public methods as messenger actions via
|
|
115
|
+
`registerMethodActionHandlers`.
|
|
116
|
+
- Calls `KycService` exclusively **through the messenger** (`KycService:*`
|
|
117
|
+
actions), never a direct reference.
|
|
118
|
+
- Delegates SumSub SDK presentation to an injected `sumsubLauncher`
|
|
119
|
+
(`KycSumSubLauncher`).
|
|
120
|
+
- When the flow is scoped to a product (passed to `initialize` /
|
|
121
|
+
`acceptTermsAndStartSession` and stored as `activeProduct`), automatically
|
|
122
|
+
runs the KYC-required check once authenticated and chains into document
|
|
123
|
+
verification when KYC is required — no extra consumer calls needed.
|
|
124
|
+
|
|
125
|
+
Exposed messenger actions (`MESSENGER_EXPOSED_METHODS`):
|
|
126
|
+
|
|
127
|
+
`initialize`, `loadDisclaimers`, `acceptTermsAndStartSession`,
|
|
128
|
+
`clearSavedTerms`, `handleFrameMessage`, `buildCheckFrameUrl`,
|
|
129
|
+
`buildAuthFrameUrl`, `buildResetFrameUrl`, `checkKycRequired`, `getKycStatus`,
|
|
130
|
+
`startSumSub`, `reset`.
|
|
131
|
+
|
|
132
|
+
#### 2.2 `KycService`
|
|
133
|
+
|
|
134
|
+
- **Stateless**, platform-agnostic HTTP client for the Universal KYC (UKYC)
|
|
135
|
+
backend.
|
|
136
|
+
- Base URL derived from `env` (`production` / `development`) or an explicit
|
|
137
|
+
`baseUrl` override.
|
|
138
|
+
- Every request is wrapped in a **service policy** (`createServicePolicy`) for
|
|
139
|
+
retries/circuit-breaking, and carries a **bearer token** obtained from
|
|
140
|
+
`AuthenticationController:getBearerToken`.
|
|
141
|
+
- Every response is validated with **superstruct** before being returned;
|
|
142
|
+
malformed responses throw a descriptive error.
|
|
143
|
+
- Resolves the customer's country from `GeolocationController:getGeolocation`
|
|
144
|
+
and maps alpha-2 → alpha-3.
|
|
145
|
+
|
|
146
|
+
Exposed messenger actions (`MESSENGER_EXPOSED_METHODS`):
|
|
147
|
+
|
|
148
|
+
`getGeoCountry`, `fetchDisclaimers`, `createSession`, `checkKycRequired`,
|
|
149
|
+
`createUkycSession`, `submitWrappedKey`.
|
|
150
|
+
|
|
151
|
+
Endpoints:
|
|
152
|
+
|
|
153
|
+
| Method | HTTP | Endpoint | Purpose |
|
|
154
|
+
| --- | --- | --- | --- |
|
|
155
|
+
| `getGeoCountry` | — | (geolocation action) | Resolve alpha-3 country |
|
|
156
|
+
| `fetchDisclaimers` | `GET` | `/vendors/moonpay/disclaimers?country=` | Terms to accept |
|
|
157
|
+
| `createSession` | `POST` | `/vendors/moonpay/sessions` | Create vendor session |
|
|
158
|
+
| `checkKycRequired` | `POST` | `/vendors/moonpay/kyc-required` | Is KYC required? (normalizes `required` → `kycRequired`) |
|
|
159
|
+
| `createUkycSession` | `POST` | `/sessions` | Start SumSub sub-flow |
|
|
160
|
+
| `submitWrappedKey` | `POST` | `/sessions/{id}/wrapped-key` | Exchange wrapped key → applicant token |
|
|
161
|
+
|
|
162
|
+
### 2.3 `crypto.ts`
|
|
163
|
+
|
|
164
|
+
Implements the Check/Auth frame credential decryption:
|
|
165
|
+
|
|
166
|
+
1. Client generates an X25519 keypair; the public key (hex) is added to the
|
|
167
|
+
frame URL.
|
|
168
|
+
2. The frame returns `{ ephemeralPublicKey, iv|nonce, ciphertext }`.
|
|
169
|
+
3. Client derives `shared = X25519(ourPriv, theirEphemeralPub)`, then
|
|
170
|
+
`key = HKDF-SHA256(shared, 32 bytes)`, then AES-256-GCM decrypts the
|
|
171
|
+
ciphertext (which includes the 16-byte tag). IV must be 12 bytes.
|
|
172
|
+
|
|
173
|
+
It tolerates envelopes delivered as an object, a JSON string, or base64(JSON),
|
|
174
|
+
and hex-or-base64 binary fields.
|
|
175
|
+
|
|
176
|
+
#### 2.4 `selectors.ts`
|
|
177
|
+
|
|
178
|
+
Memoized `reselect` selectors over `KycControllerState`:
|
|
179
|
+
`selectKycPhase`, `selectKycSumSub`, and the parametric
|
|
180
|
+
`selectIsKycRequiredForProduct(product)`.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### 3. State shape
|
|
185
|
+
|
|
186
|
+
```mermaid
|
|
187
|
+
classDiagram
|
|
188
|
+
class KycControllerState {
|
|
189
|
+
+KycPhase phase
|
|
190
|
+
+string statusMessage
|
|
191
|
+
+string error
|
|
192
|
+
+string email
|
|
193
|
+
+string termsAcceptedAt [persisted]
|
|
194
|
+
+string[] acceptedDisclaimerIds [persisted]
|
|
195
|
+
+KycDisclaimer[] disclaimers
|
|
196
|
+
+string disclaimersError
|
|
197
|
+
+string geoCountry
|
|
198
|
+
+string sessionToken [secret]
|
|
199
|
+
+string accessToken [secret]
|
|
200
|
+
+string moonpayCustomerId
|
|
201
|
+
+KycProduct activeProduct
|
|
202
|
+
+Record kycRequiredByProduct [persisted]
|
|
203
|
+
+string lastCheckedAt [persisted]
|
|
204
|
+
+SumSubState sumsub
|
|
205
|
+
}
|
|
206
|
+
class SumSubState {
|
|
207
|
+
+KycSumSubStatus status
|
|
208
|
+
+Json result
|
|
209
|
+
+string sessionId
|
|
210
|
+
+string applicantAccessToken
|
|
211
|
+
}
|
|
212
|
+
KycControllerState --> SumSubState : sumsub
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
> Note: nullable fields (`error`, `email`, `sessionToken`, …) are typed as
|
|
216
|
+
> `T | null` in the source; `Record` is `Partial<Record<KycProduct, boolean>>`.
|
|
217
|
+
> Types are simplified above for diagram readability.
|
|
218
|
+
|
|
219
|
+
State metadata highlights (`kycControllerMetadata`):
|
|
220
|
+
|
|
221
|
+
- **Persisted** (`persist: true`): `termsAcceptedAt`, `acceptedDisclaimerIds`,
|
|
222
|
+
`kycRequiredByProduct`, `lastCheckedAt`. These survive restarts so the flow
|
|
223
|
+
can skip already-accepted terms and reuse cached results.
|
|
224
|
+
- **Secrets, never persisted / never logged**: `sessionToken`, `accessToken`,
|
|
225
|
+
`moonpayCustomerId`, `email`, `disclaimers`, and the whole `sumsub` sub-tree.
|
|
226
|
+
- Additional non-state secrets kept **off** the state object entirely: the
|
|
227
|
+
X25519 private key (`#keypair`) and the Auth-frame client token
|
|
228
|
+
(`#authClientToken`).
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### 4. The identity flow (phase state machine)
|
|
233
|
+
|
|
234
|
+
`KycPhase` models the linear identity flow. Each transition is driven by a
|
|
235
|
+
controller method or an incoming frame message.
|
|
236
|
+
|
|
237
|
+
```mermaid
|
|
238
|
+
stateDiagram-v2
|
|
239
|
+
[*] --> idle
|
|
240
|
+
idle --> terms : initialize() (no saved terms)
|
|
241
|
+
idle --> session : initialize() (saved terms + email)
|
|
242
|
+
|
|
243
|
+
terms --> session : acceptTermsAndStartSession()
|
|
244
|
+
session --> check : createSession() ok
|
|
245
|
+
session --> terms : createSession() fails (clears saved terms)
|
|
246
|
+
|
|
247
|
+
check --> form : Check frame → active (already authenticated)
|
|
248
|
+
check --> auth : Check frame → connectionRequired (needs OTP)
|
|
249
|
+
check --> terms : Check frame → termsAcceptanceRequired
|
|
250
|
+
|
|
251
|
+
auth --> form : Auth frame → active (OTP verified)
|
|
252
|
+
auth --> terms : Auth frame → termsAcceptanceRequired
|
|
253
|
+
|
|
254
|
+
form --> submit : checkKycRequired()<br/>(auto when a product is set)
|
|
255
|
+
submit --> done : kyc-required response ok
|
|
256
|
+
submit --> error : request failed
|
|
257
|
+
|
|
258
|
+
check --> error : unexpected status / decrypt failure
|
|
259
|
+
auth --> error : unexpected status
|
|
260
|
+
done --> [*]
|
|
261
|
+
error --> idle : reset()
|
|
262
|
+
done --> idle : reset()
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
> When the flow is scoped to a product (a `product` is passed to `initialize`
|
|
266
|
+
> or `acceptTermsAndStartSession`), reaching `form` **automatically** runs the
|
|
267
|
+
> KYC-required check (`form → submit → done`) with no user interaction, and — if
|
|
268
|
+
> KYC is required — automatically launches the SumSub document-verification
|
|
269
|
+
> sub-flow (see [§7](#7-sumsub-sub-flow)). When no product is set the flow stops
|
|
270
|
+
> at `form` and the consumer drives `checkKycRequired` / `startSumSub` manually.
|
|
271
|
+
|
|
272
|
+
Phase meanings (from `types.ts`):
|
|
273
|
+
|
|
274
|
+
| Phase | Meaning |
|
|
275
|
+
| --- | --- |
|
|
276
|
+
| `idle` | Nothing started. |
|
|
277
|
+
| `terms` | Waiting for the customer to accept vendor terms. |
|
|
278
|
+
| `session` | Creating the vendor session. |
|
|
279
|
+
| `check` | Running the **invisible** connection-check frame. |
|
|
280
|
+
| `auth` | Running the **visible** authentication (email OTP) frame. |
|
|
281
|
+
| `form` | Authenticated. Auto-runs the KYC-required check when a product is set; otherwise waits for the consumer. |
|
|
282
|
+
| `submit` | Submitting the KYC-required check. |
|
|
283
|
+
| `done` | Complete — see `kycRequiredByProduct` / `sumsub`. Document verification auto-launches when KYC is required. |
|
|
284
|
+
| `error` | Halted — see `error`. |
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
### 5. End-to-end sequence
|
|
289
|
+
|
|
290
|
+
This sequence shows the full happy path including the two frames and the SumSub
|
|
291
|
+
hand-off. The **client transport** (WebView on mobile, iframe on web) is
|
|
292
|
+
generic — it only forwards raw frame messages to `handleFrameMessage` and posts
|
|
293
|
+
back any returned `reply`.
|
|
294
|
+
|
|
295
|
+
```mermaid
|
|
296
|
+
sequenceDiagram
|
|
297
|
+
autonumber
|
|
298
|
+
actor User
|
|
299
|
+
participant UI as Client UI + transport<br/>(WebView/iframe)
|
|
300
|
+
participant Ctrl as KycController
|
|
301
|
+
participant Svc as KycService
|
|
302
|
+
participant Geo as GeolocationController
|
|
303
|
+
participant API as UKYC API
|
|
304
|
+
participant Frame as MoonPay Check/Auth frame
|
|
305
|
+
participant Launcher as SumSub launcher (injected)
|
|
306
|
+
|
|
307
|
+
User->>Ctrl: initialize({ email, product })
|
|
308
|
+
Ctrl->>Svc: getGeoCountry()
|
|
309
|
+
Svc->>Geo: getGeolocation()
|
|
310
|
+
Note over Svc: map alpha-2 → alpha-3 locally
|
|
311
|
+
Ctrl->>Svc: fetchDisclaimers({ country })
|
|
312
|
+
Svc->>API: GET /disclaimers
|
|
313
|
+
Ctrl-->>UI: phase = terms (+ disclaimers)
|
|
314
|
+
|
|
315
|
+
User->>Ctrl: acceptTermsAndStartSession({ email })
|
|
316
|
+
Ctrl->>Svc: createSession({ email, termsAcceptedAt, disclaimerIds })
|
|
317
|
+
Svc->>API: POST /sessions
|
|
318
|
+
Ctrl-->>UI: phase = check (+ sessionToken)
|
|
319
|
+
|
|
320
|
+
UI->>Ctrl: buildCheckFrameUrl()
|
|
321
|
+
Ctrl-->>UI: URL (sessionToken + publicKey)
|
|
322
|
+
UI->>Frame: load Check frame (invisible)
|
|
323
|
+
Frame-->>UI: handshake
|
|
324
|
+
UI->>Ctrl: handleFrameMessage(handshake)
|
|
325
|
+
Ctrl-->>UI: reply = ack
|
|
326
|
+
UI->>Frame: post ack
|
|
327
|
+
Frame-->>UI: complete (status + encrypted credentials)
|
|
328
|
+
UI->>Ctrl: handleFrameMessage(complete)
|
|
329
|
+
Note over Ctrl: decryptCredentials() → accessToken / clientToken
|
|
330
|
+
|
|
331
|
+
alt Check → connectionRequired
|
|
332
|
+
Ctrl-->>UI: phase = auth
|
|
333
|
+
UI->>Frame: load Auth frame (visible, OTP)
|
|
334
|
+
Frame-->>UI: complete (active + credentials)
|
|
335
|
+
UI->>Ctrl: handleFrameMessage(complete)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
Ctrl-->>UI: phase = form (accessToken set)
|
|
339
|
+
|
|
340
|
+
Note over Ctrl: activeProduct set at initialize →<br/>continue automatically (no user action)
|
|
341
|
+
Ctrl->>Svc: checkKycRequired({ accessToken, country, capabilities })
|
|
342
|
+
Svc->>API: POST /kyc-required
|
|
343
|
+
Ctrl-->>UI: phase = done (kycRequiredByProduct[product])
|
|
344
|
+
|
|
345
|
+
opt kycRequired === true → auto-launch document verification
|
|
346
|
+
Ctrl->>Svc: createUkycSession({ jwtToken, vendorMetadata })
|
|
347
|
+
Svc->>API: POST /sessions
|
|
348
|
+
Ctrl->>Svc: submitWrappedKey({ sessionId, wrappedUserKey, ... })
|
|
349
|
+
Svc->>API: POST /sessions/{id}/wrapped-key
|
|
350
|
+
Ctrl->>Launcher: launch({ applicantAccessToken, onTokenExpiration, onStatusChange })
|
|
351
|
+
Launcher-->>Ctrl: SDK result
|
|
352
|
+
Ctrl-->>UI: sumsub.status = complete (+ result)
|
|
353
|
+
end
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
> The KYC-required check and the document-verification launch after `form` are
|
|
357
|
+
> driven by the controller itself, not the user — the flow captures the
|
|
358
|
+
> `product` at `initialize` and continues automatically. If `initialize` is
|
|
359
|
+
> called without a `product`, the flow stops at `form` and the consumer triggers
|
|
360
|
+
> `checkKycRequired` (and later `startSumSub`) explicitly.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
### 6. Frame message protocol & crypto
|
|
365
|
+
|
|
366
|
+
The Check, Auth and Reset frames all speak a small `postMessage` protocol.
|
|
367
|
+
`KycController.handleFrameMessage` implements the identity portion; the client
|
|
368
|
+
transport is responsible only for delivering messages and injecting replies.
|
|
369
|
+
|
|
370
|
+
```mermaid
|
|
371
|
+
sequenceDiagram
|
|
372
|
+
autonumber
|
|
373
|
+
participant Frame as MoonPay frame
|
|
374
|
+
participant UI as Client transport
|
|
375
|
+
participant Ctrl as KycController
|
|
376
|
+
|
|
377
|
+
Frame->>UI: { kind: "handshake", meta:{channelId} }
|
|
378
|
+
UI->>Ctrl: handleFrameMessage({ message })
|
|
379
|
+
Ctrl-->>UI: { reply: { version:2, meta:{channelId}, kind:"ack" } }
|
|
380
|
+
UI->>Frame: postMessage(ack)
|
|
381
|
+
|
|
382
|
+
Frame->>UI: { kind:"complete", meta:{channelId},<br/>payload:{ status, credentials, customer } }
|
|
383
|
+
UI->>Ctrl: handleFrameMessage({ message })
|
|
384
|
+
Note over Ctrl: 1. store customer.id (moonpayCustomerId)<br/>2. decryptCredentials(envelope, privKey)<br/>3. route by channelId (ch_1 Check / ch_2 Auth)
|
|
385
|
+
Ctrl->>Ctrl: apply outcome → next phase
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Channels: `ch_1` = Check, `ch_2` = Auth, `ch_reset` = Reset.
|
|
389
|
+
|
|
390
|
+
Credential decryption (`crypto.ts`):
|
|
391
|
+
|
|
392
|
+
```mermaid
|
|
393
|
+
graph LR
|
|
394
|
+
A["envelope<br/>{ ephemeralPublicKey, iv|nonce, ciphertext }"] --> B["X25519 ECDH<br/>shared = f(ourPriv, theirPub)"]
|
|
395
|
+
B --> C["HKDF-SHA256<br/>key (32 bytes)"]
|
|
396
|
+
C --> D["AES-256-GCM decrypt<br/>(iv = 12 bytes)"]
|
|
397
|
+
D --> E["JSON credentials<br/>{ accessToken?, clientToken? }"]
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Check-frame outcomes (`#handleCheckOutcome`):
|
|
401
|
+
|
|
402
|
+
- `active` + `accessToken` → phase `form` (already authenticated).
|
|
403
|
+
- `connectionRequired` + `clientToken` → store `#authClientToken`, phase `auth`.
|
|
404
|
+
- `termsAcceptanceRequired` → clear saved terms, phase `terms`.
|
|
405
|
+
- anything else → `error`.
|
|
406
|
+
|
|
407
|
+
Auth-frame outcomes (`#handleAuthOutcome`):
|
|
408
|
+
|
|
409
|
+
- `active` + `accessToken` → phase `form`.
|
|
410
|
+
- `termsAcceptanceRequired` → clear saved terms, phase `terms`.
|
|
411
|
+
- anything else → `error`.
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
### 7. SumSub sub-flow
|
|
416
|
+
|
|
417
|
+
The document-verification sub-flow tracks its own status independently of the
|
|
418
|
+
identity `phase`, and delegates the actual SDK presentation to the injected
|
|
419
|
+
launcher.
|
|
420
|
+
|
|
421
|
+
```mermaid
|
|
422
|
+
stateDiagram-v2
|
|
423
|
+
[*] --> idle
|
|
424
|
+
idle --> creatingSession : startSumSub()
|
|
425
|
+
creatingSession --> fetchingToken : createUkycSession() ok
|
|
426
|
+
fetchingToken --> launching : submitWrappedKey() ok
|
|
427
|
+
launching --> inProgress : launcher.onStatusChange
|
|
428
|
+
inProgress --> complete : status = Completed
|
|
429
|
+
launching --> complete : SDK resolves
|
|
430
|
+
creatingSession --> failed : error
|
|
431
|
+
fetchingToken --> failed : error
|
|
432
|
+
launching --> failed : launcher unavailable / error
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
The `KycSumSubLauncher` interface (injected per client):
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
type KycSumSubLauncher = {
|
|
439
|
+
isAvailable(): boolean;
|
|
440
|
+
launch(params: KycSumSubLaunchParams): Promise<Record<string, unknown>>;
|
|
441
|
+
};
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
`launch` receives `applicantAccessToken`, an `onTokenExpiration` callback (the
|
|
445
|
+
controller re-runs `submitWrappedKey` to refresh), and an `onStatusChange`
|
|
446
|
+
callback that the controller maps into `sumsub.status`.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
### 8. Messenger wiring
|
|
451
|
+
|
|
452
|
+
Both classes are messenger-driven. The controller depends on the service's
|
|
453
|
+
actions; the service depends on auth + geolocation actions from other
|
|
454
|
+
controllers.
|
|
455
|
+
|
|
456
|
+
```mermaid
|
|
457
|
+
graph LR
|
|
458
|
+
subgraph CtrlMsgr["KycControllerMessenger"]
|
|
459
|
+
C_own["Own actions:<br/>KycController:getState + 12 methods"]
|
|
460
|
+
C_ext["Allowed (delegated):<br/>KycService:*"]
|
|
461
|
+
end
|
|
462
|
+
subgraph SvcMsgr["KycServiceMessenger"]
|
|
463
|
+
S_own["Own actions:<br/>KycService: 6 methods"]
|
|
464
|
+
S_ext["Allowed (delegated):<br/>AuthenticationController:getBearerToken<br/>GeolocationController:getGeolocation"]
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
C_ext -.delegates.-> S_own
|
|
468
|
+
S_ext -.delegates.-> Auth["AuthenticationController"]
|
|
469
|
+
S_ext -.delegates.-> Geo["GeolocationController"]
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
- `KycController` emits `KycController:stateChange` and exposes
|
|
473
|
+
`KycController:getState` plus its method actions.
|
|
474
|
+
- `KycController`'s `AllowedActions` = `KycServiceMethodActions` — it can call
|
|
475
|
+
the service.
|
|
476
|
+
- `KycService`'s `AllowedActions` = the auth bearer-token and geolocation
|
|
477
|
+
actions.
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
### 9. Client-side usage (metamask-mobile)
|
|
482
|
+
|
|
483
|
+
The mobile app is a reference consumer. It wires the controller/service into the
|
|
484
|
+
Engine, injects a React Native SumSub launcher, bridges WebView frame messages,
|
|
485
|
+
and reads state through Redux selectors. The **package stays free of any of
|
|
486
|
+
this** — all React/native/WebView code lives in the app.
|
|
487
|
+
|
|
488
|
+
```mermaid
|
|
489
|
+
graph TB
|
|
490
|
+
subgraph app["metamask-mobile"]
|
|
491
|
+
direction TB
|
|
492
|
+
subgraph engine["Engine wiring"]
|
|
493
|
+
CInit["kyc-controller-init.ts<br/>new KycController({ messenger, state, sumsubLauncher })"]
|
|
494
|
+
SInit["kyc-service-init.ts<br/>new KycService({ fetch, env, messenger, baseUrl })"]
|
|
495
|
+
CMsgr["kyc-controller-messenger.ts<br/>delegates KycService:*"]
|
|
496
|
+
SMsgr["kyc-service-messenger.ts<br/>delegates Auth + Geolocation"]
|
|
497
|
+
Launcher["reactNativeSumSubLauncher.ts<br/>lazy-loads @sumsub/react-native-mobilesdk-module"]
|
|
498
|
+
end
|
|
499
|
+
subgraph ui["UI layer"]
|
|
500
|
+
Hook["useKycFlow.ts<br/>binds controller ↔ React"]
|
|
501
|
+
Frame["MoonpayFrame + useMoonpayFrame<br/>WebView postMessage bridge"]
|
|
502
|
+
Reset["useMoonpayReset.ts<br/>Reset frame"]
|
|
503
|
+
Demo["MoonpayDemo / SumSubDemo / KYCDemo<br/>screens"]
|
|
504
|
+
end
|
|
505
|
+
subgraph redux["Redux"]
|
|
506
|
+
Sel["selectors/kycController.ts<br/>wraps core selectors"]
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
subgraph core["@metamask/kyc-controller"]
|
|
511
|
+
KC["KycController"]
|
|
512
|
+
KS["KycService"]
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
CInit --> KC
|
|
516
|
+
SInit --> KS
|
|
517
|
+
CInit --> Launcher
|
|
518
|
+
Launcher -. injected .-> KC
|
|
519
|
+
CMsgr --> KC
|
|
520
|
+
SMsgr --> KS
|
|
521
|
+
|
|
522
|
+
Hook -->|"Engine.context.KycController.*"| KC
|
|
523
|
+
Hook -->|"useSelector"| Sel
|
|
524
|
+
Sel -->|"state.engine.backgroundState.KycController"| KC
|
|
525
|
+
Frame -->|"raw frame message"| Hook
|
|
526
|
+
Hook -->|"handleFrameMessage()"| KC
|
|
527
|
+
Demo --> Hook
|
|
528
|
+
Demo --> Frame
|
|
529
|
+
Demo --> Reset
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
#### 9.1 Engine wiring
|
|
533
|
+
|
|
534
|
+
- **`kyc-controller-init.ts`** constructs `KycController` with the persisted
|
|
535
|
+
state slice and injects `reactNativeSumSubLauncher`.
|
|
536
|
+
- **`kyc-service-init.ts`** constructs `KycService` with the global `fetch`, an
|
|
537
|
+
`env` derived from `isProduction()`, and (currently) a dev `baseUrl` override.
|
|
538
|
+
- **`kyc-controller-messenger.ts`** delegates the six `KycService:*` actions to
|
|
539
|
+
the controller's messenger.
|
|
540
|
+
- **`kyc-service-messenger.ts`** delegates
|
|
541
|
+
`AuthenticationController:getBearerToken` and
|
|
542
|
+
`GeolocationController:getGeolocation` to the service's messenger.
|
|
543
|
+
|
|
544
|
+
#### 9.2 SumSub launcher adapter
|
|
545
|
+
|
|
546
|
+
`reactNativeSumSubLauncher` implements `KycSumSubLauncher`:
|
|
547
|
+
|
|
548
|
+
- `isAvailable()` checks for the native module (`NativeModules.SNSMobileSDKModule`).
|
|
549
|
+
- `launch()` **lazily imports** `@sumsub/react-native-mobilesdk-module` (so
|
|
550
|
+
merely wiring the controller never loads the native module — important for
|
|
551
|
+
Jest / Expo Go), initializes the SDK with the applicant token, and forwards
|
|
552
|
+
`onStatusChanged` / token-expiration callbacks back to the controller.
|
|
553
|
+
|
|
554
|
+
#### 9.3 React binding — `useKycFlow`
|
|
555
|
+
|
|
556
|
+
A thin hook that:
|
|
557
|
+
|
|
558
|
+
- Reads controller state from Redux via the `selectors/kycController.ts`
|
|
559
|
+
selectors.
|
|
560
|
+
- Forwards user intents to controller actions through
|
|
561
|
+
`Engine.context.KycController.*` (`initialize`, `acceptTermsAndStartSession`,
|
|
562
|
+
`checkKycRequired`, `startSumSub`, `clearSavedTerms`, `reset`).
|
|
563
|
+
- Builds frame URLs on demand (`buildCheckFrameUrl` / `buildAuthFrameUrl`) as
|
|
564
|
+
the phase changes.
|
|
565
|
+
- Bridges WebView frame messages into `handleFrameMessage` and posts back the
|
|
566
|
+
returned `reply`.
|
|
567
|
+
- Keeps view-only concerns (email input, debug log, frame visibility) in local
|
|
568
|
+
React state.
|
|
569
|
+
|
|
570
|
+
#### 9.4 WebView transport — `useMoonpayFrame` / `MoonpayFrame`
|
|
571
|
+
|
|
572
|
+
- Injects a `postMessage` bridge into the frame that forwards the frame's
|
|
573
|
+
outbound messages to React Native via `window.ReactNativeWebView.postMessage`.
|
|
574
|
+
- **Validates the origin** (`https://blocks.moonpay.com`) before handing a
|
|
575
|
+
message to the controller.
|
|
576
|
+
- Implements `reply()` by dispatching a `MessageEvent` back into the WebView on
|
|
577
|
+
both `document` and `window` (platform quirk between iOS WKWebView and Android
|
|
578
|
+
System WebView).
|
|
579
|
+
- The Check frame is rendered **invisible** (1×1, opacity 0) unless the user
|
|
580
|
+
toggles it in the debug panel; the Auth frame is rendered visibly for OTP.
|
|
581
|
+
|
|
582
|
+
#### 9.5 Redux selectors
|
|
583
|
+
|
|
584
|
+
`selectors/kycController.ts` wraps the package's core selectors and reads the
|
|
585
|
+
slice at `state.engine.backgroundState.KycController`, exposing app-friendly
|
|
586
|
+
selectors (`selectKycPhase`, `selectKycSumSub`,
|
|
587
|
+
`selectIsKycRequiredForProduct(product)`, plus per-field selectors).
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
### 10. Boundaries & responsibilities summary
|
|
592
|
+
|
|
593
|
+
```mermaid
|
|
594
|
+
graph LR
|
|
595
|
+
subgraph shared["Shared package (platform-agnostic)"]
|
|
596
|
+
A1["Flow orchestration + state"]
|
|
597
|
+
A2["HTTP + response validation"]
|
|
598
|
+
A3["Crypto (X25519 / AES-GCM)"]
|
|
599
|
+
A4["Frame message protocol"]
|
|
600
|
+
A5["Selectors + vendor-neutral types"]
|
|
601
|
+
end
|
|
602
|
+
subgraph client["Client (per platform)"]
|
|
603
|
+
B1["Engine/DI wiring"]
|
|
604
|
+
B2["WebView / iframe transport"]
|
|
605
|
+
B3["SumSub SDK launcher"]
|
|
606
|
+
B4["Auth token + geolocation providers"]
|
|
607
|
+
B5["UI + Redux binding"]
|
|
608
|
+
end
|
|
609
|
+
shared -. injected adapters .- client
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
| Concern | Owner |
|
|
613
|
+
| --- | --- |
|
|
614
|
+
| Flow phase machine & state | `KycController` (shared) |
|
|
615
|
+
| UKYC HTTP + validation + retries | `KycService` (shared) |
|
|
616
|
+
| Credential decryption / key exchange | `crypto.ts` (shared) |
|
|
617
|
+
| Frame message semantics | `KycController.handleFrameMessage` (shared) |
|
|
618
|
+
| Frame **transport** (WebView/iframe) | Client |
|
|
619
|
+
| SumSub SDK presentation | Client (via `KycSumSubLauncher`) |
|
|
620
|
+
| Auth bearer token / geolocation | Other controllers (via messenger) |
|
|
621
|
+
| Persistence of state | Client (base-controller persistence) |
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
625
|
+
### Appendix — key source files
|
|
626
|
+
|
|
627
|
+
| File | Responsibility |
|
|
628
|
+
| --- | --- |
|
|
629
|
+
| `src/KycController.ts` | Stateful orchestrator, phase machine, frame protocol. |
|
|
630
|
+
| `src/KycService.ts` | Stateless UKYC HTTP client + superstruct validation. |
|
|
631
|
+
| `src/crypto.ts` | X25519 ECDH + AES-256-GCM credential decryption. |
|
|
632
|
+
| `src/selectors.ts` | Memoized selectors over controller state. |
|
|
633
|
+
| `src/types.ts` | `KycPhase`, `KycProduct`, `KycSumSubLauncher`, etc. |
|
|
634
|
+
| `src/countryCodes.ts` | ISO alpha-2 → alpha-3 mapping. |
|
|
635
|
+
| `src/index.ts` | Public exports (no barrel wildcards). |
|
|
636
|
+
|
|
637
|
+
Reference client (metamask-mobile):
|
|
638
|
+
|
|
639
|
+
| File | Responsibility |
|
|
640
|
+
| --- | --- |
|
|
641
|
+
| `app/core/Engine/controllers/kyc/kyc-controller-init.ts` | Construct controller + inject launcher. |
|
|
642
|
+
| `app/core/Engine/controllers/kyc/kyc-service-init.ts` | Construct service. |
|
|
643
|
+
| `app/core/Engine/controllers/kyc/reactNativeSumSubLauncher.ts` | Native SumSub adapter. |
|
|
644
|
+
| `app/core/Engine/messengers/kyc/*.ts` | Messenger delegation. |
|
|
645
|
+
| `app/components/Views/MoonpayDemo/useKycFlow.ts` | React ↔ controller binding. |
|
|
646
|
+
| `app/components/Views/MoonpayDemo/useMoonpayFrame.ts` | WebView postMessage bridge. |
|
|
647
|
+
| `app/selectors/kycController.ts` | Redux selectors. |
|
|
648
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KycController-method-action-types.cjs","sourceRoot":"","sources":["../src/KycController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { KycController } from './KycController';\n\n/**\n * Resolves persisted terms + geolocation, and auto-creates a session when\n * terms are already accepted and an email is available.\n *\n * @param params - Optional parameters.\n * @param params.email - The account email to associate with the session.\n * @param params.product - The consuming feature the flow runs for. When\n * provided, the controller automatically runs the KYC-required check once\n * authentication completes (and chains into document verification when KYC\n * is required). When omitted, the flow stops at `form` and the consumer must\n * call `checkKycRequired` manually.\n */\nexport type KycControllerInitializeAction = {\n type: `KycController:initialize`;\n handler: KycController['initialize'];\n};\n\n/**\n * Loads the disclaimers for the resolved (or provided) country.\n *\n * @param params - Optional parameters.\n * @param params.country - ISO 3166-1 alpha-3 country code override.\n */\nexport type KycControllerLoadDisclaimersAction = {\n type: `KycController:loadDisclaimers`;\n handler: KycController['loadDisclaimers'];\n};\n\n/**\n * Captures terms acceptance for the currently loaded disclaimers and creates\n * a session.\n *\n * @param params - Optional parameters.\n * @param params.email - The account email to associate with the session.\n * @param params.product - The consuming feature the flow runs for. See\n * {@link initialize} for how the product drives the automatic post\n * authentication continuation.\n */\nexport type KycControllerAcceptTermsAndStartSessionAction = {\n type: `KycController:acceptTermsAndStartSession`;\n handler: KycController['acceptTermsAndStartSession'];\n};\n\n/**\n * Clears the persisted terms acceptance.\n */\nexport type KycControllerClearSavedTermsAction = {\n type: `KycController:clearSavedTerms`;\n handler: KycController['clearSavedTerms'];\n};\n\n/**\n * Handles a message posted by a Check/Auth frame and advances the flow.\n *\n * The transport-agnostic caller (WebView on mobile, iframe on web) forwards\n * the raw message and injects the returned `reply` back into the frame.\n *\n * @param params - The parameters.\n * @param params.message - The raw message posted by the frame.\n * @returns An object whose optional `reply` should be posted back.\n */\nexport type KycControllerHandleFrameMessageAction = {\n type: `KycController:handleFrameMessage`;\n handler: KycController['handleFrameMessage'];\n};\n\n/**\n * Builds the Check-frame URL, or `null` when no session exists yet.\n *\n * @returns The Check-frame URL or `null`.\n */\nexport type KycControllerBuildCheckFrameUrlAction = {\n type: `KycController:buildCheckFrameUrl`;\n handler: KycController['buildCheckFrameUrl'];\n};\n\n/**\n * Builds the Auth-frame URL, or `null` when no client token is available.\n *\n * @returns The Auth-frame URL or `null`.\n */\nexport type KycControllerBuildAuthFrameUrlAction = {\n type: `KycController:buildAuthFrameUrl`;\n handler: KycController['buildAuthFrameUrl'];\n};\n\n/**\n * Builds the Reset-frame URL.\n *\n * @returns The Reset-frame URL.\n */\nexport type KycControllerBuildResetFrameUrlAction = {\n type: `KycController:buildResetFrameUrl`;\n handler: KycController['buildResetFrameUrl'];\n};\n\n/**\n * Checks whether KYC is required for a product and caches the result.\n *\n * @param params - The parameters.\n * @param params.product - The consuming feature.\n * @param params.country - Optional alpha-3 country override.\n * @returns Whether KYC is required.\n */\nexport type KycControllerCheckKycRequiredAction = {\n type: `KycController:checkKycRequired`;\n handler: KycController['checkKycRequired'];\n};\n\n/**\n * Reads the cached \"is KYC required\" result for a product.\n *\n * @param params - The parameters.\n * @param params.product - The consuming feature.\n * @returns The cached value, or `undefined` if not yet checked.\n */\nexport type KycControllerGetKycStatusAction = {\n type: `KycController:getKycStatus`;\n handler: KycController['getKycStatus'];\n};\n\n/**\n * Runs the SumSub document-verification sub-flow: creates a UKYC session,\n * exchanges the wrapped key for an applicant access token, and presents the\n * SDK via the injected launcher.\n *\n * @param params - Optional parameters.\n * @param params.locale - BCP-47 locale for the SDK UI.\n * @param params.debug - Enables SDK debug logging.\n * @returns The SDK result.\n */\nexport type KycControllerStartSumSubAction = {\n type: `KycController:startSumSub`;\n handler: KycController['startSumSub'];\n};\n\n/**\n * Resets the flow to idle, clearing session tokens and sub-flow state while\n * preserving persisted terms acceptance and the per-product cache.\n */\nexport type KycControllerResetAction = {\n type: `KycController:reset`;\n handler: KycController['reset'];\n};\n\n/**\n * Union of all KycController action types.\n */\nexport type KycControllerMethodActions =\n | KycControllerInitializeAction\n | KycControllerLoadDisclaimersAction\n | KycControllerAcceptTermsAndStartSessionAction\n | KycControllerClearSavedTermsAction\n | KycControllerHandleFrameMessageAction\n | KycControllerBuildCheckFrameUrlAction\n | KycControllerBuildAuthFrameUrlAction\n | KycControllerBuildResetFrameUrlAction\n | KycControllerCheckKycRequiredAction\n | KycControllerGetKycStatusAction\n | KycControllerStartSumSubAction\n | KycControllerResetAction;\n"]}
|