feat: creates headless ramps hook#26728
Closed
georgeweiler wants to merge 30 commits into
Closed
Conversation
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. |
7 tasks
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Mar 2, 2026
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Moves V2 ramp order state management from Redux (`FiatOrder`) into the `RampsController`, eliminating the conversion layer where clean `RampsOrder` API data was mangled into a legacy shape and immediately cast back. This PR will allow for future PRs such as a headless ramps experience where callers can subscribe to order updates: #26728 or implementing websocket connections for real-time order status updates: MetaMask/core#8075 Please reference loom videos below for a demo of this PR. **What changed:** - **Order creation** (Checkout + Transak native): `addOrder(rampsOrder)` stores directly in controller state. No more `createInitialFiatOrder()`, `rampsOrderToFiatOrder()`, or `dispatch(addFiatOrder())`. Transak deposit orders merge `paymentDetails` from the `TransakDepositOrder` onto the `RampsOrder` before storing, preserving inline bank transfer details. - **Order detail screen**: `OrderDetails` + `OrderContent` read `RampsOrder` from controller state via `useRampsOrders` hook. No Redux, no `processFiatOrder`, no `useInterval` polling. Pull-to-refresh calls `refreshOrder()`. Controller polling keeps data fresh automatically. - **Bank details screen**: `V2BankDetails` reads order lifecycle from controller state and fetches deposit-specific data (payment details) from `TransakService`. Cancel and confirm use `providerOrderId` directly. - **Orders list**: `OrdersList` merges legacy `FiatOrder[]` from Redux with V2 `RampsOrder[]` from controller state via `DisplayOrder` projection. Legacy orders route to the aggregator detail screen; V2 orders route to the new controller-native detail screen. - **Side effects**: `ramps-controller-init.ts` subscribes to `RampsController:orderStatusChanged` for notification and analytics handlers, and starts controller order polling on init. Follows the same pattern as `TransactionController:transactionConfirmed` handlers. - **Messenger**: `RampsControllerInitMessenger` delegates the `orderStatusChanged` event so init-level subscriptions work. **What stays untouched:** Legacy `AGGREGATOR`, `DEPOSIT`, and older orders remain in Redux. Their processors, detail screens, types, and polling are unchanged. <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Core PR that added orders MetaMask/core#8045 Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After**  Loom video of the controller state being polled, created and updated for Aggregator order (Moonpay) https://www.loom.com/share/70658e66e55c444cadc02aad407c3da2 Loom video of the controller state being polled, created and updated for Native order (Transak) https://www.loom.com/share/2c6d5941cbfa48c4be7cc36000e40e89 <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Updates unified ramp checkout/order list navigation and switches V2 order creation/storage to controller state, which could impact order visibility and detail routing for buy/deposit flows. Risk is mitigated by updated unit tests, but regressions could affect transaction history UX. > > **Overview** > **V2 ramp orders are now stored and read from `RampsController` instead of being converted into legacy `FiatOrder` Redux state.** `Checkout` uses `useRampsOrders` (`getOrderFromCallback`, `addOrder`) and always `reset`s into `Routes.RAMP.RAMPS_ORDER_DETAILS` with `showCloseButton`, even when order IDs are `null`. > > **Orders list UI and navigation were reworked to merge legacy Redux orders with controller V2 orders.** `OrdersList` now projects both into a unified `DisplayOrder` list (`mergeDisplayOrders`), renders new list rows, and routes presses by source/provider (legacy aggregator -> `OrderDetails`, V2 -> `RampsOrderDetails`, deposit -> new `DepositOrderDetails`, created deposit -> deposit flow). > > Adds `Routes.DEPOSIT.ORDER_DETAILS` to the main navigator and updates provider selection to consider completed controller orders when computing previously-used providers. Tests/snapshots were updated accordingly, and V2 toast wiring now passes `status` (typed as `RampsOrderStatus`) instead of legacy `state`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f7c7f73. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Contributor
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - draft PR All E2E tests pre-selected. |
Contributor
|
✅ E2E Fixture Validation — Schema is up to date |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Description
Introduces a headless ramps API so external teams can embed buy flows without the default token/quote selection UI.
What changed:
useRampsQuickBuyhook — Hook for external teams to initiate a headless ramps buy flow:assetIdopenBuyModal({ assetId, paymentMethodId, amount })to launch checkoutRampsController:orderStatusChangedand exposes the latest order status update viaordergoToBuyOrder(orderId)to navigate to the order details screenHeadlessBuyview — Screen that runs the actual buy flow. ReceivesassetId,paymentMethodId, andamountas params; fetches a quote; routes to native (Transak) or aggregator checkout; and closes when the order reaches a terminal status (Completed, Failed, Cancelled, IdExpired).createHeadlessBuyNavDetails— Navigation helper that routes into the ramps stack with the right params forHeadlessBuy.Routes.RAMP.HEADLESS_BUY— Route added and wired into the ramps stack.HeadlessBuyDemo— QA demo component that usesuseRampsQuickBuyto exercise token selection, payment method selection, amount input, and the buy flow. Not registered in main app routes.What stays untouched: Existing ramps flows (token selection, build quote, checkout) remain unchanged. Headless ramps is additive.
Dependencies: Builds on the order state refactor in #26596, which moved V2 orders into
RampsControllerand enables subscription toorderStatusChanged.Changelog
CHANGELOG entry: Allow any page to open the buy experience
Related issues
Fixes: #26733
Manual testing steps
Screenshots/Recordings
Before
After
Pre-merge author checklist
Pre-merge reviewer checklist