Skip to content

Fix virtual account and KYC flow routing for Wirex users - #2520

Merged
MusabShakeel576 merged 3 commits into
masterfrom
claude/kyc-issue-investigation-do57kq
Sep 14, 2026
Merged

MusabShakeel576 merged 3 commits into
masterfrom
claude/kyc-issue-investigation-do57kq

Conversation

@MusabShakeel576

Copy link
Copy Markdown
Contributor

Summary

This PR fixes critical routing issues in the virtual account and KYC flows that were causing Wirex users to be incorrectly sent through Rain's KYC verification process, resulting in 409 errors and broken user experiences. It also improves messaging and UX in the TransFi KYC pending screen.

Key Changes

Virtual Account Apply Action Logic

  • New file: virtualAccountApplyAction.ts - Extracted pure decision logic for determining what action the "Verify now" button should take
  • New test file: virtualAccountApplyAction.test.ts - Comprehensive test coverage documenting the routing rules and failure cases
  • Routes Wirex users to their own details screen instead of Rain KYC flow
  • Prevents starting new KYC checks when an application already exists (avoiding 409 KYC_ALREADY_EXISTS errors)
  • Properly handles missing rainApplicationStatus by checking kycApplicationEstablished flag

VirtualAccountApplyModal Updates

  • Integrated useVirtualAccountProvider hook to determine the account issuer
  • Disables "Verify now" button while provider is resolving (prevents guessing Rain for Wirex users)
  • Routes Wirex users to virtual account details screen with proper tracking
  • Uses new resolveVirtualAccountApplyAction function for consistent routing logic
  • Added provider information to tracking events

DepositTypeSelection Updates

  • Added provider check before showing Rain virtual account apply pitch
  • Wirex users now go directly to their details screen when selecting bank transfer
  • Added provider tracking to deposit method selection event

TransFi KYC Pending Screen Improvements

  • Slow verification detection: After 45 seconds without a verdict, updates messaging to indicate manual review is happening and allows users to close the modal
  • Hosted KYC flow fix: Keeps the screen open when user has a can_share status (not just rejected), preventing users from being stranded with the modal already open
  • Better rejection messaging: Distinguishes between retryable rejections and final compliance rejections with clearer user guidance
  • Direct verification option: When a profile exists and sharing keeps failing, offers "Verify with our partner" as the primary action
  • Added retry error display and improved button state management

Notable Implementation Details

  • The resolveVirtualAccountApplyAction function is kept pure and testable, following the same pattern as resolveRainKycAction
  • Provider resolution is checked before Rain status to prevent Wirex users from falling into Rain branches
  • The kycApplicationEstablished flag is used as a signal that a consumer exists, preventing unnecessary new KYC attempts
  • Tracking events now include provider information for better analytics on routing decisions

https://claude.ai/code/session_01PPtSeJ6KiwabgmJ1S5v4Uc

The virtual-account pitch gated on `rainApplicationStatus === APPROVED` and
sent everyone else to /kyc. A Wirex user has no Rain application and never
will, so they always took that branch — and the backend then refused a new
Didit session with 409 KYC_ALREADY_EXISTS, because their verification was
already on file. The KYC screen bounced them straight back out onto the card
review page. From the outside, "Verify now" spun and returned without ever
opening a verification.

The same 409 waits for any Rain user who already has a consumer: a missing
`rainApplicationStatus` is not evidence that no application exists. This is
the rule the card flow already encodes in resolveRainKycAction, and the
virtual-account flow never got it.

The decision moves into resolveVirtualAccountApplyAction, a pure function
beside the modal, so the routing is testable without mounting it:
  - Wirex issues the account  -> their own bank screen, which owns activation
  - Rain approved             -> the terms step
  - an application exists     -> the page showing its state, not a new check
  - nothing on file           -> identity verification

DepositTypeSelection — the main Add-funds screen, and the entry point Wirex
users actually came through — now routes on the provider too. The other two
entry points already did, which is why this only ever reproduced from here.

Alongside it, the buy-crypto verification screen stops dead-ending:
  - the exhausted state offers the partner's own hosted verification once a
    profile exists, instead of only "try again" on a share that has already
    been refused three times
  - a terminal rejection says the partner's decision is final and points to
    support, rather than "please try again later" — which read as a wait that
    would clear, so users kept coming back to the same screen
  - the pending spinner stops promising "under a minute" indefinitely

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPtSeJ6KiwabgmJ1S5v4Uc
@vercel

vercel Bot commented Sep 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated
solid-app Ignored Ignored Preview Sep 14, 2026 3:17pm UTC
solid-app-staging Ignored Ignored Preview Sep 14, 2026 3:17pm UTC

Request Review

@claude

claude Bot commented Sep 14, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.


🤖 Generated with Claude Code

Comment thread components/BuyCrypto/Transfi/TransfiKycPending.tsx
Both buttons on that screen fire their own request, and neither was guarded
against the other being in flight. "Try again" also calls setExhausted(false),
so a hosted-retry landing after it would set a verification URL on a screen
that had already moved on — two concurrent requests and a state that agrees
with neither.

Disable both while either is running. Reported by Seer on #2520; the race only
existed because this commit's parent gave the screen a second action.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPtSeJ6KiwabgmJ1S5v4Uc
@MusabShakeel576
MusabShakeel576 merged commit 762930f into master Sep 14, 2026
7 checks passed
@MusabShakeel576
MusabShakeel576 deleted the claude/kyc-issue-investigation-do57kq branch September 14, 2026 15:28
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.

2 participants