Skip to content

feat(kyc-controller): Iron Money KYC path + status polling - #9852

Open
amitabh94 wants to merge 3 commits into
feat/kyc-controllerfrom
feat/iron-kyc-controller-m2
Open

feat(kyc-controller): Iron Money KYC path + status polling#9852
amitabh94 wants to merge 3 commits into
feat/kyc-controllerfrom
feat/iron-kyc-controller-m2

Conversation

@amitabh94

Copy link
Copy Markdown
Contributor

Summary

  • Adds vendor: 'iron' KYC flow for MetaMask Money: idle → terms → session → submit(SumSub) → done/error with no MoonPay Check/Auth frames.
  • Extends KycService with Milestone 1 contract clients (mocked in tests): POST /vendors/iron/customers, GET /vendors/iron/disclaimers, POST /vendors/iron/kyc-required, POST /consents, GET /kyc/status, plus createUkycSession({ vendorId: 'iron' }) without MoonPay metadata.
  • Adds createIronCustomer, refreshKycStatus, KycController:statusChanged, persisted userStatus* fields, and maps session_not_in_valid_statecompleted.

Stacking

  • Base: feat/kyc-controller (feat: KYC controller #9615)
  • Depends on Milestone 1 API endpoints landing on va-mmcx-kyc-api (not merged yet). Clients are implemented against the planned contract; tests mock fetch.

Deferred (follow-ups)

  • Full 3-state error UX wiring beyond status fields (need-more-information / terminal-failure / retryable SumSub session id)
  • Mobile Money navigator + toast rendering (Milestone 3)
  • Live integration once Milestone 1 is on shared-dev

Test plan

  • yarn workspace @metamask/kyc-controller run test (100% coverage)
  • yarn workspace @metamask/kyc-controller run messenger-action-types:check
  • Smoke against local/dev KYC API once Iron routes + /consents + /kyc/status exist

Made with Cursor

Introduce vendor:'iron' flow (no MoonPay Check/Auth frames) with KycService clients for Iron customers/disclaimers/consents and user-keyed GET /kyc/status, so Money can drive toast state against the planned Milestone 1 API contract.
@amitabh94
amitabh94 requested review from a team as code owners August 12, 2026 21:18

@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 3 potential issues.

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 a40fa2f. Configure here.

// eslint-disable-next-line @typescript-eslint/no-floating-promises
tick();
}, this.#userStatusPollIntervalMs);
this.#userStatusPollTimer.unref();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Timer unref crashes clients

High Severity

#ensureUserStatusPolling always calls .unref() on the setTimeout handle. In extension and React Native runtimes that handle is a number without unref, so the first pending refreshKycStatus poll throws and breaks Money status polling. Sibling session-status polling in this file avoids unref; other packages guard with an existence check.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a40fa2f. Configure here.

Comment thread packages/kyc-controller/src/KycController.ts
this.#ensureUserStatusPolling();
} else {
this.#stopUserStatusPolling();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reset restarts status polling

Medium Severity

When reset() lands during an in-flight refreshKycStatus, #fetchAndApplyUserStatus returns the cached status (often still pending, since reset preserves userStatus). refreshKycStatus then calls #ensureUserStatusPolling() and restarts the poll loop that reset just stopped.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a40fa2f. Configure here.

amitabh94 and others added 2 commits August 12, 2026 15:37
Add PR link and formatting for changelog, fix JSDoc/restricted-syntax/jest matcher lint errors, and apply Prettier to the package.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use oxfmt (not Prettier) so import order and markdown alignment match the monorepo misc formatter.

Co-authored-by: Cursor <cursoragent@cursor.com>
@amitabh94

Copy link
Copy Markdown
Contributor Author

Demo topology update (for reviewers): Iron feature commit a40fa2fc3f is already on neobank-demo (merged by @georgeweiler into the demo integration branch; umbrella #9853). Remaining CI lint/oxfmt fixes from this PR are synced via #9855neobank-demo.

This PR (#9852) should stay targeting feat/kyc-controller for the mainline stack (#9615). Do not retarget to main / neobank-demo.

amitabh94 added a commit that referenced this pull request Aug 12, 2026
## Summary
- `neobank-demo` already includes Sébastien’s `feat/kyc-controller`
stack and the Iron feature commit from #9852 (`a40fa2fc3f`, merged by
George).
- This PR cherry-picks the remaining #9852 CI fixes (`lint` / changelog
PR link / `oxfmt`) so the demo branch matches the Iron tip for package
publish/preview and mobile consumption.
- Keeps #9852 targeting `feat/kyc-controller` for the eventual mainline
path via #9615. Does **not** merge to `main`.

## Context (demo topology)
- Integration branch: `neobank-demo` (owner: @georgeweiler) — umbrella
PR #9853 → `main`
- Iron feature PR (mainline stack): #9852 → `feat/kyc-controller`
- KYC controller PR: #9615 → `main`

## Test plan
- [ ] Confirm diff is formatting/lint/changelog only (no Iron behavior
change)
- [ ] CI green on this PR
- [ ] After merge, `@metamaskbot publish-preview` on #9853 (or this PR)
if mobile needs a preview pin of `@metamask/kyc-controller`


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.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