Repository navigation
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 - add a persisted seven-stage `vbaOnboardingStage` contract for Mobile routing - `hydrateVbaOnboarding` refreshes KYC state from the customer's account via `KycController:refreshVbaOnboardingStatus` **before** reading the stage gates, then maps Iron/SumSub getters (`KycVendor` / `KycProvider` / `KycStatus` from MetaMask#10279) to a routable stage - the refresh action is delegated via a **local structural messenger-action type**, so this package compiles without a `kyc-controller` release that already exports it (KYC PR merges first) - load authoritative autoramp accounts through the new `NeoBankService:getAutoramps` action before deciding whether account creation is needed - automatically register the Money Account wallet and create an autoramp after KYC acceptance - coalesce overlapping hydration polls to avoid duplicate signatures and account creation This is a simplified replacement for MetaMask#10116. KYC flow interpretation stays in `KycController`; this PR imports the shared enums/action types from `@metamask/kyc-controller` rather than declaring them locally. **Depends on:** MetaMask#10279 (KYC getters + VBA status refresh). Until that lands, this branch is expected not to typecheck against main's `kyc-controller` package — that is intentional. The proxy is expected to support authenticated `GET /neobank/autoramps` requests. ## Testing - `yarn jest src/NeoBankService.test.ts src/RampsController.test.ts --runInBand --no-coverage` - `yarn workspace @metamask/ramps-controller run test` - `yarn build` (may fail until MetaMask#10279 merges) - `yarn workspace @metamask/ramps-controller run messenger-action-types:check` - targeted ESLint for changed files - `yarn changelog:validate` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches KYC-gated money-account activation (wallet signing and autoramp creation) and expands the required messenger surface, so host wiring mistakes or race bugs could affect onboarding. > > **Overview** > Adds **Mobile VBA onboarding routing** via a persisted `vbaOnboardingStage` and `RampsController:hydrateVbaOnboarding`, which derives the next screen from Iron/SumSub KYC session state (email OTP, vendor/provider terms, SumSub, pending/rejected, or completed). > > After KYC is **approved**, hydration registers the Money Account wallet, loads the customer’s autoramps through new **`NeoBankService:getAutoramps`** (`GET /neobank/autoramps`), syncs local autoramp state, and **creates an autoramp only when none is usable** for the wallet; transient neobank failures keep the user on **KycPending** instead of completing. Overlapping hydration calls are **coalesced** to avoid duplicate signatures or autoramp creation during polling. > > **Breaking:** integrators must wire four new **`KycController`** messenger actions (`getSessionStatusForVendor`, `refreshSessionStatus`, and the two disclaimer checks). Action types are declared structurally in ramps-controller so it does not add a `@metamask/kyc-controller` dependency. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6e0eb4b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>


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.