feat(kyc-controller): add VBA onboarding KYC getters - #10279
georgeweiler wants to merge 6 commits into
Conversation
Expose KycVendor/KycProvider/KycStatus const objects and noop messenger methods so ramps can hydrate VBA onboarding without local KYC contracts. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Drop local KycVendor/KycProvider/KycStatus stubs and action types in favor of the package exports introduced in #10279. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Persist vendorCustomerIds from createVendorCustomer, and implement isCustomerCreated / hasCompletedVendorTerms / hasCompletedProviderTerms / getKycStatus(vendor) against real controller state so ramps hydration can advance past EmailOtpRequired. Co-authored-by: Cursor <cursoragent@cursor.com>
…ydrate Turn the VBA onboarding terms steps into account-backed operations and make hydration re-read status from the vendor account: - acceptVendorTerms / acceptProviderTerms now persist to the account (submitVendorDisclaimers; UKYC session + submitSessionDisclaimers) before recording locally, so acceptance is never claimed without a backend write - add KycService.fetchRequiredSignings (GET required-signings) and KycController.refreshVbaOnboardingStatus so hydrate reflects the account's vendor-terms and KYC status rather than only device-local state - gate getKycStatus on a persisted sumSubSubmitted flag so the session-created 'pending' routes to the SumSub screen until documents are actually submitted - persist activeVendor so a resumed flow keeps its Iron vendor context across reloads (avoids sending empty MoonPay session metadata) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| * that signal's last-known value rather than throwing, so hydration can still | ||
| * resolve a stage from whatever is current. | ||
| */ | ||
| async refreshVbaOnboardingStatus(): Promise<void> { |
There was a problem hiding this comment.
rename to something more generic and leave here? Or pull this logic into ramps controller?
- persist `ukycSessionId` so a reload reuses the consented UKYC session instead of `startSumSub` creating a fresh, unconsented one (Bugbot: provider session dropped after reload) - `acceptVendorTerms` captures the flow generation and writes via `#updateIfCurrent`, so a concurrent `reset()` no longer lands acceptance on an idle controller (Bugbot: vendor terms write ignores reset) - regenerate `KycController-method-action-types` for the updated method JSDoc - use `expect(await ...)` instead of the restricted `.resolves` matcher - apply oxfmt formatting Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 2e9e869. Configure here.
| this.#applyUpdate((state) => { | ||
| state.sumsub.sessionId = state.ukycSessionId; | ||
| }); | ||
| } |
There was a problem hiding this comment.
Reload skips vendor-processing short-circuit
Medium Severity
Restoring sumsub.sessionId from persisted ukycSessionId makes startSumSub skip session creation, the only place vendorProcessing is detected. After a reload, an applicant the relay already approved while the vendor is still finalizing is sent into the SumSub SDK instead of stopping with the vendor-processing status.
Reviewed by Cursor Bugbot for commit 2e9e869. Configure here.


Summary
Adds VBA / Pix onboarding support to
KycController: the exported enums and getters Mobile routes on, plus account-backed terms steps and a hydrate refresh so each onboarding stage reflects the customer's account rather than only device-local state.Enums + getters
KycVendor,KycProvider, andKycStatusconst objects (and matching types)isCustomerCreated(vendor)→ persistedvendorCustomerIdswritten on successfulcreateVendorCustomer(survivesreset(), cleared byclearState())hasCompletedVendorTerms(vendor)→ backendrequired-signingsafter refresh, falling back to localvendorDisclaimersAcceptedhasCompletedProviderTerms(sumsub)→ persistedproviderDisclaimersAccepted.sumsubgetKycStatus(vendor)overload → maps persisteduserStatus→KycStatusAccount-backed terms (server-side)
acceptVendorTerms()posts vendor signings to the account (submitVendorDisclaimers), then records local acceptance — never claims acceptance the account does not holdacceptProviderTerms()creates (or reuses) the UKYC session and posts idOS/SumSub session consents (submitSessionDisclaimers) without launching SumSub, recording locally only after the account write succeedsKycService.fetchRequiredSignings(GET /vendors/{vendor}/customers/{id}/required-signings) backs vendor-terms completionHydrate + routing
refreshVbaOnboardingStatus()pullsrequired-signingsandGET /kyc/status(each fetch soft-fails independently) so hydration reads the accountgetKycStatus(vendor)treats backendpendingasNOT_STARTEDuntil a persistedsumSubSubmittedflag is set when SumSub actually completes — so "session created, no documents yet" routes to the SumSub screen, not KYC-pendingactiveVendorso a resumed Iron flow keeps its vendor context across reloads (avoids sending empty MoonPay session metadata)This unblocks ramps VBA hydration so Mobile can call
hydrateVbaOnboardingand advance stages from the customer's real KYC progress.Follow-ups for KYC owners
getKycStatus(vendor)truly vendor-scoped if neededterminal-failure→REJECTEDvs a dedicated EDD stagefinalStatuscannot distinguish "awaiting documents" from "under review", hence the device-persistedsumSubSubmittedgate — revisit if a session-level signal becomes availableTesting
yarn workspace @metamask/kyc-controller run messenger-action-types:generateyarn workspace @metamask/kyc-controller run messenger-action-types:checkyarn workspace @metamask/kyc-controller exec jest --no-coverage src/KycController.test.ts src/KycService.test.ts(292 passing)yarn eslinton changed KYC filesyarn workspace @metamask/kyc-controller run buildyarn workspace @metamask/kyc-controller run changelog:validate🤖 Generated with Claude Code
Note
Medium Risk
Changes KYC onboarding persistence, terms acceptance order, and status routing for VBA flows; mistakes could mis-route users or claim terms the account does not hold, though the design fails closed on backend errors.
Overview
Adds VBA / Pix onboarding support to
KycController: exportedKycVendor,KycProvider, andKycStatusenums plus messenger getters Mobile can use to drive multi-step onboarding from persisted and refreshed account state.New flow APIs split terms from the monolithic session path:
acceptVendorTermsposts vendor signings to the account before recording locally;acceptProviderTermscreates or reuses a UKYC session, posts idOS/SumSub consents without launching SumSub, and letsstartSumSubreuse that session (including after reload via persistedukycSessionId).refreshVbaOnboardingStatushydrates vendor-terms completion fromfetchRequiredSigningsand KYC status fromGET /kyc/status, with independent soft-fail behavior.Persistence and routing changes include
vendorCustomerIdsandactiveVendorsurviving cold starts andreset(),isCustomerCreated, vendor overload ongetKycStatuswith asumSubSubmittedgate so backendpendingbefore document capture maps toNOT_STARTEDrather than KYC-pending, andhasCompletedVendorTerms/hasCompletedProviderTermsfor stage checks.Reviewed by Cursor Bugbot for commit 2e9e869. Bugbot is set up for automated code reviews on this repo. Configure here.