Skip to content

feat(kyc-controller): add VBA onboarding KYC getters - #10279

Closed
georgeweiler wants to merge 6 commits into
mainfrom
kyc-vba-api-stubs
Closed

georgeweiler wants to merge 6 commits into
mainfrom
kyc-vba-api-stubs

Conversation

@georgeweiler

@georgeweiler georgeweiler commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

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

  • export KycVendor, KycProvider, and KycStatus const objects (and matching types)
  • isCustomerCreated(vendor) → persisted vendorCustomerIds written on successful createVendorCustomer (survives reset(), cleared by clearState())
  • hasCompletedVendorTerms(vendor) → backend required-signings after refresh, falling back to local vendorDisclaimersAccepted
  • hasCompletedProviderTerms(sumsub) → persisted providerDisclaimersAccepted.sumsub
  • getKycStatus(vendor) overload → maps persisted userStatus → KycStatus

Account-backed terms (server-side)

  • acceptVendorTerms() posts vendor signings to the account (submitVendorDisclaimers), then records local acceptance — never claims acceptance the account does not hold
  • acceptProviderTerms() creates (or reuses) the UKYC session and posts idOS/SumSub session consents (submitSessionDisclaimers) without launching SumSub, recording locally only after the account write succeeds
  • new KycService.fetchRequiredSignings (GET /vendors/{vendor}/customers/{id}/required-signings) backs vendor-terms completion

Hydrate + routing

  • refreshVbaOnboardingStatus() pulls required-signings and GET /kyc/status (each fetch soft-fails independently) so hydration reads the account
  • getKycStatus(vendor) treats backend pending as NOT_STARTED until a persisted sumSubSubmitted flag is set when SumSub actually completes — so "session created, no documents yet" routes to the SumSub screen, not KYC-pending
  • persist activeVendor so 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 hydrateVbaOnboarding and advance stages from the customer's real KYC progress.

Follow-ups for KYC owners

  • make getKycStatus(vendor) truly vendor-scoped if needed
  • confirm terminal-failure → REJECTED vs a dedicated EDD stage
  • optional network-backed customer lookup for cross-device cold starts without a persisted id
  • backend finalStatus cannot distinguish "awaiting documents" from "under review", hence the device-persisted sumSubSubmitted gate — revisit if a session-level signal becomes available

Testing

  • yarn workspace @metamask/kyc-controller run messenger-action-types:generate
  • yarn workspace @metamask/kyc-controller run messenger-action-types:check
  • yarn workspace @metamask/kyc-controller exec jest --no-coverage src/KycController.test.ts src/KycService.test.ts (292 passing)
  • yarn eslint on changed KYC files
  • yarn workspace @metamask/kyc-controller run build
  • yarn 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: exported KycVendor, KycProvider, and KycStatus enums 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: acceptVendorTerms posts vendor signings to the account before recording locally; acceptProviderTerms creates or reuses a UKYC session, posts idOS/SumSub consents without launching SumSub, and lets startSumSub reuse that session (including after reload via persisted ukycSessionId). refreshVbaOnboardingStatus hydrates vendor-terms completion from fetchRequiredSignings and KYC status from GET /kyc/status, with independent soft-fail behavior.

Persistence and routing changes include vendorCustomerIds and activeVendor surviving cold starts and reset(), isCustomerCreated, vendor overload on getKycStatus with a sumSubSubmitted gate so backend pending before document capture maps to NOT_STARTED rather than KYC-pending, and hasCompletedVendorTerms / hasCompletedProviderTerms for stage checks.

Reviewed by Cursor Bugbot for commit 2e9e869. Bugbot is set up for automated code reviews on this repo. Configure here.

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>
georgeweiler added a commit that referenced this pull request Sep 17, 2026
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>
georgeweiler and others added 2 commits September 16, 2026 20:25
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>
@georgeweiler georgeweiler changed the title feat(kyc-controller): add VBA onboarding stub getters feat(kyc-controller): add VBA onboarding KYC getters Sep 17, 2026
…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>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

* that signal's last-known value rather than throwing, so hydration can still
* resolve a stage from whatever is current.
*/
async refreshVbaOnboardingStatus(): Promise<void> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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;
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2e9e869. Configure here.

pull Bot pushed a commit to Reality2byte/core that referenced this pull request Sep 21, 2026
## 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant