feat: init KYC controller and add logic from mobile repo#9615
Conversation
Signed-off-by: Sébastien Van Eyck <sebastien.vaneyck@consensys.net>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 505b840. Configure here.
| vendorUserId: 'mockedId', | ||
| jwtToken: params.jwtToken, | ||
| vendorMetadata: params.vendorMetadata, | ||
| }), |
There was a problem hiding this comment.
Hardcoded vendor user id
High Severity
createUkycSession always sends vendorUserId as the literal mockedId, while KycController already supplies the MoonPay customer id in vendorMetadata.moonPayUserId. UKYC session creation is tied to the wrong user even when identity frames succeeded.
Reviewed by Cursor Bugbot for commit 505b840. Configure here.
| this.update((state) => { | ||
| state.geoCountry = country; | ||
| }); | ||
| } |
There was a problem hiding this comment.
Override country not cached
Medium Severity
When loadDisclaimers is called with an explicit country, disclaimers load for that code but geoCountry stays unset because state is only updated when no cached country existed. Later checkKycRequired without a override fails with missing country.
Reviewed by Cursor Bugbot for commit 505b840. Configure here.
| } | ||
| if (!termsAcceptedAt || acceptedDisclaimerIds.length === 0) { | ||
| this.#fail('Missing terms acceptance for session creation.'); | ||
| return; |
There was a problem hiding this comment.
Terms timestamp before validation
Medium Severity
acceptTermsAndStartSession writes termsAcceptedAt and acceptedDisclaimerIds before #createSession validates them. If no disclaimers were loaded, it errors but leaves a persisted termsAcceptedAt with empty disclaimer ids.
Reviewed by Cursor Bugbot for commit 505b840. Configure here.


@metamask/kyc-controllerOverview
@metamask/kyc-controlleris a shared, platform-agnostic KYC / identity-verification package for MetaMask clients (mobile, extension, web). It centralizes all KYC orchestration logic in thecoremonorepo so every client consumes one implementation instead of maintaining its own.What's included
Core modules
KycController(src/KycController.ts) — ABaseControllerthat owns the entire identity flow:idle → terms → session → check → auth → form → submit → done / error.blocks.moonpay.com) over dedicated channels (ch_1,ch_2,ch_reset).KycSumSubLauncheradapter, keeping the controller SDK-free while each client injects its own launcher.KycService(src/KycService.ts) — A data service that performs the Universal KYC (UKYC) HTTP calls via an injectedfetch. It wraps requests withcreateServicePolicyfor resilience, validates responses withsuperstruct, and sources the auth bearer token (fromprofile-sync-controller) and geolocation (fromgeolocation-controller) through the messenger.Supporting modules
crypto.ts— X25519 key-pair generation and encrypted-credential decryption.countryCodes.ts— ISO 3166-1 alpha-2 → alpha-3 country-code mapping.selectors.ts— Memoized state selectors (selectKycPhase,selectKycSumSub,selectIsKycRequiredForProduct).types.ts— Shared vendor-neutral types (KycPhase,KycProduct,KycVendor,KycSumSubLauncher,KycDisclaimer, etc.).KycController-method-action-types.ts/KycService-method-action-types.ts— Messenger action type definitions for the controller and service.index.ts— Explicit (non-barrel) exports defining the package's public API.Tests
Comprehensive Jest test suites covering the controller, service, crypto, country codes, selectors, and the index/public API.
Package scaffolding & monorepo wiring
package.json,tsconfig.json,tsconfig.build.json,jest.config.js,typedoc.json,CHANGELOG.md,README.md, and theLICENSE,LICENSE.APACHE2, andLICENSE.MITfiles.tsconfig.json/tsconfig.build.jsonproject references, added to the rootREADME.mdpackage list, and reflected inyarn.lock.Public API
The package explicitly exports:
KycController,getDefaultKycControllerState,controllerName, plus its messenger, options, state, action, and event types.KycService,serviceName, plus its messenger, options, params, response, action, and event types.selectIsKycRequiredForProduct,selectKycPhase,selectKycSumSub.alpha2ToAlpha3,ALPHA2_TO_ALPHA3,decryptCredentials,generateKeyPair, and related crypto/domain types.Note
The SumSub sub-flow currently uses a placeholder
MOCK_JWT_TOKEN, which must be replaced with real UKYC-issued credentials before production use.Checklist
Note
High Risk
New identity-verification surface handling auth tokens, encrypted credentials, and profile-sync auth integration; some UKYC/SumSub paths still use explicit mock credentials before production hardening.
Overview
Introduces
@metamask/kyc-controller, a new monorepo package that centralizes identity/KYC orchestration for MetaMask clients (ported from mobile), wired into the root README, TypeScript project references, and dependency graph.KycControllerdrives the end-to-end flow: geolocation and disclaimers, persisted terms acceptance, UKYC session creation, MoonPay Check/Auth/Reset frame URLs andpostMessagehandling, X25519 + AES-GCM decryption of frame credentials, per-product KYC-required checks (ramps,card), and a SumSub sub-flow via an injectedKycSumSubLauncher. Messenger action types and reselect selectors are exported for consumers.KycServiceis the stateless HTTP layer against the Universal KYC API (prod/dev URLs, optionalbaseUrloverride), using wallet bearer tokens and geolocation from other controllers. Responses are validated with superstruct.The package ships with broad unit tests (100% coverage threshold), licenses, changelog, and build tooling (
chokidarwatch). Note:startSumSub/ UKYC session creation still use placeholder JWT andvendorUserIdvalues called out in source as pre-production.Reviewed by Cursor Bugbot for commit 505b840. Bugbot is set up for automated code reviews on this repo. Configure here.