Skip to content

feat(ramp): bypass order-processing redirect in headless flows (Phase 6)#29340

Merged
saustrie-consensys merged 1 commit into
mainfrom
poc/headless-buy-phase-6
May 5, 2026
Merged

feat(ramp): bypass order-processing redirect in headless flows (Phase 6)#29340
saustrie-consensys merged 1 commit into
mainfrom
poc/headless-buy-phase-6

Conversation

@saustrie-consensys

@saustrie-consensys saustrie-consensys commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Description

This PR closes Phase 6 of the incremental Unified Buy (v2) headless buy plan (app/components/UI/Ramp/headless/PLAN.md): when a flow produces an orderId under a live headless session, the consumer's onOrderCreated callback fires and the ramp stack unwinds — no more redirect to RAMPS_ORDER_DETAILS, no showV2OrderToast the consumer didn't ask for.

Reason

  • Phase 5 (#29338) introduced the Headless Host and quote-first session API, but the flow still ended on RAMPS_ORDER_DETAILS with a toast — there was no way for external UIs to know an order was created. Phase 6 closes the loop so consumers can actually react to completion.

What changed

  • app/components/UI/Ramp/Views/Checkout/Checkout.tsx — adds headlessSessionId to CheckoutParams. When the widget callback URL resolves and getSession(headlessSessionId) returns a live session, the screen fires session.callbacks.onOrderCreated(orderId), calls closeSession(id, { reason: 'completed' }), and pops the parent stack. addOrder and protectWalletModalVisible still dispatch so Redux stays consistent; showV2OrderToast is suppressed. Non-headless behavior is unchanged.
  • app/components/UI/Ramp/hooks/useTransakRouting.ts — extracts headlessSessionId from config.baseRouteParams (already threaded by the Host via Phase 5's parameterization) and applies the same branching inside navigateToOrderProcessingCallback. handleNavigationStateChange's toast is suppressed when the session is live; addOrder + trackEvent keep firing so Redux + analytics parity are preserved.
  • app/components/UI/Ramp/hooks/useContinueWithQuote.ts — threads ctx.headlessSessionId into createCheckoutNavDetails so the v2 Checkout screen can see it on the aggregator/widget branch.
  • Error safety — consumer onOrderCreated errors are caught and logged via Logger.error; the session still closes and the stack still pops, so a consumer-side bug can never break the flow.
  • PLAN.md — Phase 6 ticked.

References

Tests

  • New headless session flow describe block in app/components/UI/Ramp/Views/Checkout/Checkout.test.tsx (5 cases): live-session success, addOrder + protectWalletModalVisible side-effect preservation, consumer onOrderCreated error swallow, missing-session fallback, absent-headlessSessionId unchanged path.
  • New headless session flow describe block in app/components/UI/Ramp/hooks/useTransakRouting.test.ts (4 cases): the same shape exercised through the Transak native callback path.
  • Regressed green locally: sessionRegistry.test.ts, useContinueWithQuote.test.ts, HeadlessHost.test.tsx. 101/101 pass across the five suites.

Changelog

CHANGELOG entry: null

Related issues

Fixes: No GitHub issue — incremental POC on branch poc/headless-buy-phase-6.

Continuity: #29338 (Phase 5 — Headless Host + quote-first start). #29213 (Phase 4 — useContinueWithQuote).

Manual testing steps

Feature: Headless Buy Phase 6 (onOrderCreated + stack unwind on order success)

  Scenario: Aggregator order success fires onOrderCreated and pops out of the ramp stack
    Given the app is an internal build and I am signed in
    And I open Settings → Fiat on-ramp → Headless Buy playground
    When I fetch quotes, tap "Start headless buy" on an aggregator (e.g. MoonPay) quote
    And I complete a sandbox order inside the Checkout WebView
    Then the playground event log should show `onOrderCreated(orderId)` followed by `onClose({ reason: 'completed' })`
    And the app should return to the playground (no RAMPS_ORDER_DETAILS flash, no toast)

  Scenario: Native Transak order success fires onOrderCreated and pops out of the ramp stack
    Given I am on the playground with a Transak native quote selected
    When I complete the native OTP + KYC + webview flow through to order creation
    Then the event log should show `onOrderCreated(orderId)` and `onClose({ reason: 'completed' })`
    And I should be returned to the playground

  Scenario: Non-headless Buy flow is unchanged
    Given I open Wallet → Buy through the regular flow
    When I complete an aggregator order
    Then the order-details screen should render with the usual toast
    And no headless callback should fire

  Scenario: Missing session falls back gracefully
    Given a headless order is produced after the session has been cancelled
    When the success callback resolves
    Then the flow falls back to the regular reset + toast (no dangling state)

Screenshots/Recordings

Before

N/A — Phase 6 wires the existing callback contract; no UI changes.

After

MoonPay succeeds (similar to Phase)

Can't provide a video for Transak since Transak KYC keeps asking me to submit a live selfie for my iOS simulator (even though my purchase amount is under $30)

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
  • I've tested with a power user scenario
  • I've instrumented key operations with Sentry traces for production performance metrics

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Changes success-path navigation and notification behavior in checkout/order routing, which could affect user flow completion if session detection or parent stack popping is wrong; covered by new unit tests but still touches core ramp navigation paths.

Overview
Headless buy flows now short-circuit the usual post-checkout UX: when Checkout or useTransakRouting detects a live headlessSessionId, it calls the session’s onOrderCreated(orderId), closes the session, and pops the ramp stack instead of resetting to RAMPS_ORDER_DETAILS and showing the V2 order toast.

useContinueWithQuote now forwards headlessSessionId into Checkout navigation so aggregator/widget checkouts can participate in this behavior, and the headless plan doc marks Phase 6 complete. Comprehensive unit tests were added to cover live-session success, callback error swallowing + logging, toast suppression, and fallback to the non-headless path when the session is missing/absent.

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

@saustrie-consensys saustrie-consensys requested a review from a team as a code owner April 24, 2026 16:40
@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@saustrie-consensys saustrie-consensys self-assigned this Apr 24, 2026
@saustrie-consensys saustrie-consensys added team-money-movement issues related to Money Movement features team-ramps labels Apr 24, 2026
Base automatically changed from poc/headless-buy-phase-5 to main April 28, 2026 21:08
@saustrie-consensys saustrie-consensys force-pushed the poc/headless-buy-phase-6 branch from d56ac89 to 740efe3 Compare April 29, 2026 18:32
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeRamps
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 90%
click to see 🤖 AI reasoning details

E2E Test Selection:
The changes are entirely within the Ramp (buy/sell crypto) feature area. Three files modify the headless buy session flow:

  1. Checkout.tsx: Added headlessSessionId param support. In headless mode, fires onOrderCreated callback, closes the session, and pops the ramp stack instead of navigating to RAMPS_ORDER_DETAILS. Suppresses the V2 order toast.

  2. useTransakRouting.ts: Added headless session support to navigateToOrderProcessingCallback and the Transak order processing flow. Same pattern - fires callback, closes session, pops stack, suppresses toast.

  3. useContinueWithQuote.ts: Passes headlessSessionId from context to checkout navigation params.

  4. PLAN.md: Documents Phase 6 as completed.

  5. Test files: Unit tests covering the new headless session flow paths.

The changes modify the order completion flow in the Ramp feature, which is a critical user journey. The existing non-headless code paths are preserved with proper fallback behavior. No shared components (TabBar, navigation, modals outside Ramp) are affected. The SmokeRamps tag covers buy/sell flows including the checkout and order processing paths that were modified. No other feature areas are impacted.

Performance Test Selection:
The changes are limited to the Ramp headless session flow - adding a new code path for headless mode order completion. These changes don't affect UI rendering performance, data loading, account/network list components, app startup, or any performance-sensitive areas. The modifications are logic-only (session registry lookups, navigation calls, callback invocations) with no impact on render times or data fetching performance.

View GitHub Actions results

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

E2E Fixture Validation — Schema is up to date
12 value mismatches detected (expected — fixture represents an existing user).
View details

@meltingice1337 meltingice1337 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@saustrie-consensys saustrie-consensys added this pull request to the merge queue May 5, 2026
Merged via the queue into main with commit 8a8f3bb May 5, 2026
100 checks passed
@saustrie-consensys saustrie-consensys deleted the poc/headless-buy-phase-6 branch May 5, 2026 13:54
@github-actions github-actions Bot locked and limited conversation to collaborators May 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

size-M team-money-movement issues related to Money Movement features team-ramps

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants