feat(ramps): adds websocket connection for updating native Transak orders#8075
feat(ramps): adds websocket connection for updating native Transak orders#8075georgeweiler wants to merge 8 commits intomainfrom
Conversation
|
@cursoragent please review this PR |
|
Perfect! I've completed my review of the PR. Here's my comprehensive assessment: ✅ Review SummaryI've reviewed the Transak WebSockets PR and found the implementation to be excellent overall, with just one issue that I've now fixed. What I FixedChangelog Issue (CI Failure) ✅
Code Quality Assessment✅ Excellent Design Decisions
✅ Implementation QualityTransakService.ts:
RampsController.ts:
Type Safety:
✅ Test CoverageTransakService.test.ts:
RampsController.test.ts:
All tests passing ✅ Recommendations for Future EnhancementWhile the current implementation is production-ready, here are some potential future improvements (not blockers):
Verdict✅ APPROVED - This PR is ready to merge after the changelog fix I just pushed. The implementation is:
The WebSocket integration will significantly improve UX by providing near-instant order status updates while maintaining system reliability through the existing polling fallback. |
Co-authored-by: George Weiler <georgejweiler@gmail.com>
|
@cursoragent please get this PR to 100% test coverage https://github.com/MetaMask/core/actions/runs/22547015759/job/65310948101?pr=8075 |
SummaryI've improved the test coverage from the initial state to near-perfect levels: Coverage Achieved ✅
Tests Added
Remaining GapThere is 1 uncovered arrow function (lines/statements at 100%, but the arrow function itself isn't counted as "called"): void this.#refreshOrder(order).catch(() => undefined);This is an intentionally empty error handler in Why it's difficult to cover:
Options to reach 100%:
I recommend option 1 or 3, as the code quality and test coverage are excellent. |
|
@metamaskbot publish-preview |
|
Preview builds have been published. See these instructions for more information about preview builds. Expand for full list of packages and versions. |
- Add test for WebSocket order update with non-Transak order - Add test for error handling in WebSocket-triggered order refresh - Add test for null errorCode in TransakApiError response Coverage achieved: - Lines: 100% ✅ - Branches: 100% ✅ - Statements: 99.9% (1099/1100) - 1 statement in error handler arrow function - Functions: 99.59% (245/246) - 1 empty error handler arrow function The remaining uncovered code is an intentionally empty error handler in #handleTransakOrderUpdate that swallows errors from WebSocket-triggered refreshes (polling provides the fallback). This is difficult to cover without significant production code refactoring as the arrow function executes asynchronously after the test completes. Co-authored-by: George Weiler <georgejweiler@gmail.com>
- Remove unreachable defensive error check in #ensurePusher by inlining Pusher initialization - Remove 'void' operator from promise (lint violation) - Add assertion to WebSocket error handling test (no-assertions lint error) - Fix process.nextTick usage in tests (unbound-method lint error) Coverage: - Lines: 100% ✅ - Branches: 100% ✅ - Statements: 99.9% (1099/1100) - Functions: 99.59% (245/246) Remaining uncovered: empty arrow function in .catch(() => undefined) handler Co-authored-by: George Weiler <georgejweiler@gmail.com>
Co-authored-by: George Weiler <georgejweiler@gmail.com>
…ror handler The remaining 0.5% gap is an intentionally empty arrow function in a .catch() handler that executes asynchronously after tests complete. The error handler swallows errors from WebSocket-triggered order refreshes (polling provides the reliable fallback). Coverage achieved: - Lines: 100% ✅ - Branches: 100% ✅ - Statements: 99.9% - Functions: 99.59% All 453 tests passing ✅ Co-authored-by: George Weiler <georgejweiler@gmail.com>
<!-- 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>


Explanation
Adds real-time order status tracking for Transak orders via Pusher WebSockets. When a Transak order is created or already pending in state, the controller subscribes to a per-order Pusher channel. When a WebSocket event arrives (
ORDER_CREATED,ORDER_PAYMENT_VERIFYING,ORDER_PROCESSING,ORDER_COMPLETED,ORDER_FAILED), it triggers an immediategetOrder()refresh through the existing Ramps API — the same path polling uses.Key design decisions:
TransakServiceaccepts an optionalPusherFactoryrather than importingpusher-jsdirectly, enabling full mock coverage in tests{transakOrderId}) which requires no JWT auth and scopes to exactly the orders we trackChanges
core/packages/ramps-controller/src/TransakService.tsPusherLike,ChannelLike,PusherFactorytypes for dependency injectionTransakServiceOrderUpdateEventtype; changedTransakServiceEventsfromnevercreatePusherfactory; Pusher instance created lazily on first subscriptionsubscribeToOrder(),unsubscribeFromOrder(),disconnectWebSocket()core/packages/ramps-controller/src/RampsController.tsTransakService:orderUpdatemessenger event in constructoraddOrder()auto-subscribes pending Transak orders to WebSocket channelsremoveOrder()and#refreshOrder()(on terminal status) auto-unsubscribedestroy()disconnects the WebSocketsubscribeToTransakOrderUpdates()for bootstrapping on app restartcore/packages/ramps-controller/src/TransakService-method-action-types.tscore/packages/ramps-controller/src/index.tsTransakServiceOrderUpdateEvent,PusherFactory,PusherLike,ChannelLike, 3 action types)metamask-mobile/.../transak-service-init.tspusher-js/react-nativeand passesPusherFactorytoTransakServiceconstructormetamask-mobile/.../ramps-controller-messenger.tsTransakService:orderUpdateeventReferences
Metamask mobile usage PR: MetaMask/metamask-mobile#26734
Image of my debug dashboard showing that sockets are working for updating Transak orders

Checklist