Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 18 additions & 20 deletions packages/kyc-controller/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,12 @@ classDiagram
+string statusMessage
+string error
+string email
+string termsAcceptedAt [persisted]
+string[] acceptedDisclaimerIds [persisted]
+KycVendor termsAcceptedVendor [persisted]
+KycDisclaimer[] disclaimers
+string disclaimersError
+KycVendorDisclaimersAccepted vendorDisclaimersAccepted [persisted]
+KycDisclaimer[] vendorDisclaimers
+string vendorError
+string geoCountry
+string sessionToken [secret]
+string accessToken [secret]
+string moonpaySessionToken [secret]
+string moonpayAccessToken [secret]
+string moonpayCustomerId
+KycProduct activeProduct
+Record kycRequiredByProduct [persisted]
Expand All @@ -200,14 +198,14 @@ classDiagram
KycControllerState --> SumSubState : sumsub
```

> Note: nullable fields (`error`, `email`, `sessionToken`, …) are typed as
> Note: nullable fields (`error`, `email`, `moonpaySessionToken`, …) are typed as
> `T | null` in the source; `Record` is `Partial<Record<KycProduct, boolean>>`.
> Types are simplified above for diagram readability.

State metadata highlights (`kycControllerMetadata`):

- **Persisted** (`persist: true`): `termsAcceptedAt`, `acceptedDisclaimerIds`,
`termsAcceptedVendor`, `sumsubTncAccepted`, `idosTncAccepted`,
- **Persisted** (`persist: true`): `vendorDisclaimersAccepted`,
`providerDisclaimersAccepted`, `idosDisclaimersAccepted`,
`kycRequiredByProduct`, `lastCheckedAt`. These survive restarts so the flow
can skip already-accepted terms and reuse cached results. Session-scoped
`sessionDisclaimers` and `credentialReusabilityConsentGiven` are in-memory
Expand All @@ -218,8 +216,8 @@ State metadata highlights (`kycControllerMetadata`):
vendor switch commits (`createVendorCustomer` succeeds, or the MoonPay
path proceeds); a failed or reset switch leaves the previous vendor's
acceptance in place.
- **Secrets, never persisted / never logged**: `sessionToken`, `accessToken`,
`moonpayCustomerId`, `email`, `disclaimers`, and the whole `sumsub` sub-tree.
- **Secrets, never persisted / never logged**: `moonpaySessionToken`, `moonpayAccessToken`,
`moonpayCustomerId`, `email`, `vendorDisclaimers`, and the whole `sumsub` sub-tree.
Switching away from MoonPay (`initialize` / `createVendorCustomer`) drops
these MoonPay Check/Auth artifacts immediately so `buildCheckFrameUrl` cannot
return a MoonPay URL while `activeVendor` is a consents-path vendor.
Expand All @@ -241,7 +239,7 @@ stateDiagram-v2
idle --> terms : initialize() (no saved terms)
idle --> session : initialize() (saved terms + email)

terms --> session : acceptTermsAndStartSession({ sumsubTncSigned, idosTncSigned })
terms --> session : acceptTermsAndStartSession({ providerDisclaimersAccepted, idosDisclaimersAccepted })
session --> check : createSession() ok
session --> terms : createSession() fails<br/>(clears saved terms, activeProduct + stale tokens)

Expand Down Expand Up @@ -279,7 +277,7 @@ stateDiagram-v2
> or SDK close without completion) rewinds to `terms` instead of forcing `done`.
> A terminal UKYC rejection after the SDK reported `Completed` still finishes as
> `done` so `refreshKycStatus` can surface the decision.
> `acceptTermsAndStartSession` requires `sumsubTncSigned` and `idosTncSigned`
> `acceptTermsAndStartSession` requires `providerDisclaimersAccepted` and `idosDisclaimersAccepted`
> (T&C2) for every vendor; omitted flags fail the flow instead of defaulting to
> `true`. Those flags are mapped onto the session catalog's `idOS` /
> `kycProvider` document records; `credentialReusabilityConsentGiven` is
Expand All @@ -290,8 +288,8 @@ stateDiagram-v2
> `form`, `submit`), a repeat `initialize` or `createVendorCustomer` is a
> **no-op** — it will not create a new session, switch `activeVendor`, clear
> tokens, or reset `activeProduct`. Call `reset()` first to start over.
> When a switch away from MoonPay is allowed, leftover `sessionToken`,
> `accessToken`, `moonpayCustomerId`, and `#authClientToken` are cleared so
> When a switch away from MoonPay is allowed, leftover `moonpaySessionToken`,
> `moonpayAccessToken`, `moonpayCustomerId`, and `#authClientToken` are cleared so
> Check/Auth URLs cannot outlive the MoonPay session. Check/Auth `complete`
> messages are also ignored unless `activeVendor` is `moonpay`, so a
> still-mounted MoonPay frame cannot recapture `moonpayCustomerId` under
Expand Down Expand Up @@ -345,12 +343,12 @@ sequenceDiagram
Note over Svc: map alpha-2 → alpha-3 locally
Ctrl->>Svc: fetchVendorDisclaimers({ country })
Svc->>API: GET /vendors/moonpay/disclaimers?country=
Ctrl-->>UI: phase = terms (+ disclaimers)
Ctrl-->>UI: phase = terms (+ vendorDisclaimers)

User->>Ctrl: acceptTermsAndStartSession({ email, sumsubTncSigned, idosTncSigned })
User->>Ctrl: acceptTermsAndStartSession({ email, providerDisclaimersAccepted, idosDisclaimersAccepted })
Ctrl->>Svc: createSession({ email, termsAcceptedAt, disclaimerIds })
Svc->>API: POST /sessions
Ctrl-->>UI: phase = check (+ sessionToken)
Ctrl-->>UI: phase = check (+ moonpaySessionToken)

UI->>Ctrl: buildCheckFrameUrl()
Ctrl-->>UI: URL (sessionToken + publicKey)
Expand All @@ -370,7 +368,7 @@ sequenceDiagram
UI->>Ctrl: handleFrameMessage(complete)
end

Ctrl-->>UI: phase = form (accessToken set)
Ctrl-->>UI: phase = form (moonpayAccessToken set)

Note over Ctrl: activeProduct set at initialize →<br/>continue automatically (no user action)
Ctrl->>Svc: checkKycRequired({ accessToken, country, capabilities })
Expand Down
6 changes: 6 additions & 0 deletions packages/kyc-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **BREAKING:** Rename `KycController` state field `accessToken` to `moonpayAccessToken` (MoonPay Auth-frame access token; `KycService.checkKycRequired` still accepts an `accessToken` parameter). ([#10062](https://github.com/MetaMask/core/pull/10062))
- **BREAKING:** Rename `KycController` state field `sessionToken` to `moonpaySessionToken` (MoonPay Check-frame session token; the Check-frame URL query parameter remains `sessionToken`). ([#10062](https://github.com/MetaMask/core/pull/10062))
- **BREAKING:** Replace persisted `termsAcceptedAt`, `acceptedDisclaimerIds`, and `termsAcceptedVendor` with `vendorDisclaimersAccepted`: a fixed map with `moonpay: { termsAcceptedAt } | null` and `iron: { disclaimerIds } | null` keys (default `{ moonpay: null, iron: null }`). ([#10062](https://github.com/MetaMask/core/pull/10062))
- **BREAKING:** Rename persisted `idosTncAccepted` to `idosDisclaimersAccepted` and change its type from `boolean | null` to `KycConsentRecord[] | null` (`{ key, version }[]`). `acceptTermsAndStartSession` now takes `idosDisclaimersAccepted: KycConsentRecord[]` instead of `idosTncSigned: boolean`. ([#10062](https://github.com/MetaMask/core/pull/10062))
- **BREAKING:** Rename persisted `sumsubTncAccepted` to `providerDisclaimersAccepted` (`{ sumsub: KycConsentRecord[] | null }`) and change `acceptTermsAndStartSession` to take `providerDisclaimersAccepted: KycConsentRecord[]` instead of `sumsubTncSigned: boolean`. ([#10062](https://github.com/MetaMask/core/pull/10062))
- **BREAKING:** Rename `KycController` state field `disclaimers` to `vendorDisclaimers` (vendor T&Cs fetched for the current country) and `disclaimersError` to `vendorError`. ([#10062](https://github.com/MetaMask/core/pull/10062))
- Add `KycService.fetchDisclaimersCatalog` / `KycService:fetchDisclaimersCatalog` (`GET /disclaimers?country=`, ISO 3166-1 alpha-3) for the pre-session idOS + KYC-provider catalog, plus the `KycDisclaimersCatalog` type (no `credentialReusabilityConsentGiven`). `fetchSessionDisclaimers` remains session-scoped (`GET /sessions/{sessionId}/disclaimers` → `KycSessionDisclaimers`). ([#10011](https://github.com/MetaMask/core/pull/10011))
- **BREAKING:** Rename `KycService.fetchDisclaimers` / `KycService:fetchDisclaimers` / `KycServiceFetchDisclaimersAction` to `fetchVendorDisclaimers` / `KycService:fetchVendorDisclaimers` / `KycServiceFetchVendorDisclaimersAction`. ([#10011](https://github.com/MetaMask/core/pull/10011))
- **BREAKING:** Rename `fractalEncryptionBaseUrl` to `idosEnclaveBaseUrl`, `KycService.fetchJwks` / `KycService:fetchJwks` / `KycServiceFetchJwksAction` to `fetchIdosEnclaveJwks` / `KycService:fetchIdosEnclaveJwks` / `KycServiceFetchIdosEnclaveJwksAction`, and related Fractal encryption naming to idOS enclave. ([#10008](https://github.com/MetaMask/core/pull/10008))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ export type KycControllerLoadDisclaimersAction = {
* @param params.product - The consuming feature the flow runs for. See
* {@link initialize} for how the product drives the automatic post
* authentication continuation.
* @param params.sumsubTncSigned - Whether Sumsub T&C were accepted (T&C2).
* Required for every vendor so callers explicitly declare acceptance.
* @param params.idosTncSigned - Whether idOS T&C were accepted (T&C2).
* Required for every vendor so callers explicitly declare acceptance.
* @param params.providerDisclaimersAccepted - Sumsub disclaimer documents the
* customer accepted (`{ key, version }` records). Required for every vendor
* so callers explicitly declare acceptance.
* @param params.idosDisclaimersAccepted - idOS disclaimer documents the
* customer accepted (`{ key, version }` records). Required for every vendor
* so callers explicitly declare acceptance.
* @param params.credentialReusabilityConsentGiven - Whether the customer
* consented to reuse existing idOS credentials. Used when recording
* session-scoped disclaimers on the consents path. Defaults to `false`.
Expand Down
Loading