Skip to content

feat: implement non prefix ids backwards compatiblity on ramps#32819

Merged
meltingice1337 merged 8 commits into
mainfrom
fix/TRAM-3560-non-prefix-providers
Jul 13, 2026
Merged

feat: implement non prefix ids backwards compatiblity on ramps#32819
meltingice1337 merged 8 commits into
mainfrom
fix/TRAM-3560-non-prefix-providers

Conversation

@meltingice1337

@meltingice1337 meltingice1337 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Description

Backend ramps entity ids (providers, payment methods, currencies, regions) are migrating from the legacy path form (e.g. /providers/transak) to the canonical, non-prefixed form (e.g. transak). The client had accumulated defensive normalization to strip the legacy prefix, and one comparison that keyed directly off the legacy prefix. Now that provider ids arrive canonical, the normalization is redundant and the prefix-based comparison no longer matches. This PR aligns the ramps client with canonical (non-prefixed) provider ids.

Two mechanical changes:

  • Pass provider ids/codes through unchanged. normalizeProviderCode(id) from @metamask/ramps-controller is just id.replace(/^\/providers\//, ''). With canonical ids it is a no-op, so the wrapping calls are removed and the raw id/code is used directly. Affected call sites: BuildQuote.tsx (matching the selected provider against a quote's provider), Checkout.tsx (addPrecreatedOrder provider code), BankDetails.tsx / OrderDetails.tsx / useTransakRouting.ts (the refreshOrder provider code, including the transak-native deposit fallback), useContinueWithQuote.ts (widget provider code), and unifiedOrderProcessor.ts (order provider code).
  • Fix the Transak logout detection in the Settings modal (SettingsModal.tsx). isTransakNativeProvider matched on the legacy path prefix '/providers/transak-native', which never matches a canonical transak-native id, so the "Log out of Transak" option would silently disappear once ids went non-prefixed. It now matches the canonical code 'transak-native', still covering the transak-native-staging variant via startsWith.

Tests are updated accordingly: cases that asserted the prefix-stripping behavior are removed, and the Settings modal test now exercises the canonical transak-native code.

Changelog

CHANGELOG entry: Fixed the ramps Settings "Log out of Transak" option and provider-code handling so they keep working after backend provider ids move to the non-prefixed format.

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3560

Manual testing steps

Feature: Ramps client works with non-prefixed (canonical) provider ids

  Scenario: Transak logout option shows for a canonical provider id
    Given I am authenticated with Transak
    And the selected provider id is the canonical form ("transak-native" or "transak-native-staging")
    When I open the ramps Settings modal
    Then the "Log out of Transak" option is visible

  Scenario: Non-Transak provider does not show the logout option
    Given the selected provider id is a non-Transak canonical id (e.g. "moonpay")
    When I open the ramps Settings modal
    Then the "Log out of Transak" option is not shown

  Scenario: Buy flow selects the matching quote across canonical ids
    Given the provider catalog and quotes return canonical provider ids ("transak")
    When I select a provider on the Build Quote screen
    Then the quote whose provider matches the selected provider is used

  Scenario: Order refresh and creation flow through canonical codes
    Given an order references a canonical provider id
    When I open Order Details / Bank Details and refresh, or create a precreated order at Checkout
    Then the provider code is passed through unchanged and the order refreshes/creates successfully

Screenshots/Recordings

N/A — no new UI. The only user-visible effect is that the existing "Log out of Transak" option keeps rendering when the provider id arrives in the non-prefixed form; the remaining changes are internal provider-code plumbing. Behavior is covered by unit tests.

Before

After

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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
Touches buy/checkout/order-refresh paths across ramps; a mismatch between API ids and client assumptions could break quote selection or order polling, though scope is mostly mechanical id plumbing plus one user-visible Settings fix.

Overview
Aligns the ramps UI with canonical, non-prefixed provider ids (e.g. transak instead of /providers/transak) after the backend migration, by bumping @metamask/ramps-controller to ^16.0.0 and stopping client-side prefix stripping.

Provider codes are passed through unchanged everywhere normalizeProviderCode was used: quote matching in Build Quote, Checkout precreated orders, order refresh in Order Details / Bank Details / Transak routing / unified order processor, and continue-with-quote widget flows. Comparisons now use strict equality on the raw id.

Settings modal Transak logout detection no longer keys off the legacy path prefix '/providers/transak-native' (which would never match canonical ids). It now matches the canonical code transak-native, still covering transak-native-staging via startsWith.

Tests drop prefix-normalization scenarios and use canonical mock provider ids.

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

@github-actions

github-actions Bot commented Jul 6, 2026

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.

@github-actions github-actions Bot added the pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. label Jul 6, 2026
@metamask-ci metamask-ci Bot added the team-money-movement issues related to Money Movement features label Jul 6, 2026
@github-actions github-actions Bot added the size-M label Jul 6, 2026
@meltingice1337 meltingice1337 removed the pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. label Jul 6, 2026
@meltingice1337 meltingice1337 marked this pull request as ready for review July 6, 2026 14:28
@meltingice1337 meltingice1337 requested a review from a team as a code owner July 6, 2026 14:28
@github-actions github-actions Bot added the risk:medium AI analysis: medium risk label Jul 6, 2026
roz0n
roz0n previously approved these changes Jul 6, 2026
@github-actions github-actions Bot added risk:low AI analysis: low risk and removed risk:medium AI analysis: medium risk labels Jul 8, 2026
@github-actions github-actions Bot added risk:medium AI analysis: medium risk and removed risk:low AI analysis: low risk labels Jul 9, 2026
pull Bot pushed a commit to Reality2byte/core that referenced this pull request Jul 10, 2026
…ty (MetaMask#9448)

## Explanation

`@metamask/ramps-controller` normalized provider IDs by stripping a
`/providers/` prefix through a `normalizeProviderCode` helper. This
normalization was applied in two places: across the `getQuotes`
scope-aware selection logic (matching the providers list, each quote's
`provider`, custom-action provider IDs, and the sort-order IDs) and when
building a precreated stub order, where the provider code was re-wrapped
as `/providers/<code>`. The Ramps backend now returns canonical,
non-prefixed provider IDs, so this normalization is unnecessary and
inconsistent with the new contract.

This PR removes provider-ID normalization entirely so IDs are compared
and stored as-is (canonical). Concretely: the `normalizeProviderCode`
function and its public export are removed; the six
`normalizeProviderCode(...)` call sites in the `getQuotes` selection
logic are dropped so the map keys and lookups use the raw provider IDs;
and a precreated stub order's `provider.id` is now the canonical
provider code passed to the create-order call rather than a
`/providers/`-prefixed value. The dedicated `normalizeProviderCode` unit
test is removed and the stub-order test now expects the canonical
`paypal` ID.

One detail worth calling out for reviewers: the six removed call sites
were added recently in MetaMask#9353 (scope-aware in-app provider widening).
Because normalization is removed uniformly from both sides of every map
key and lookup, matching behavior is preserved for
consistently-formatted IDs, and the existing `getQuotes` tests continue
to pass unchanged (308 tests green).

This is a breaking change: `normalizeProviderCode` is no longer
exported, and the precreated stub order's `provider.id` changes shape
from `/providers/<code>` to `<code>`. Consumers must supply non-prefixed
(canonical) provider IDs. The mobile consumer PR removes all
`normalizeProviderCode` usages and the app-side normalization to adopt
this.

## References

* Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3560
* Consumer PR (mobile):
MetaMask/metamask-mobile#32819
* Related to MetaMask#9353 (introduced the `getQuotes` normalization removed
here)

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [x] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Breaking API and state shape changes for buy/quote flows; wrong IDs
from consumers that still pass `/providers/`-prefixed values could break
quote selection or order polling until clients migrate.
> 
> **Overview**
> **Breaking change:** `@metamask/ramps-controller` drops `/providers/`
prefix normalization so provider IDs are compared and stored as
canonical codes (e.g. `paypal`, `transak`).
> 
> The **`normalizeProviderCode` helper and its public export are
removed**. In **`getQuotes`** scope-aware selection, maps and lookups
now use raw `provider.id`, quote `provider`, custom-action `providerId`,
and sort-order IDs with no stripping. **`addPrecreatedOrder`** sets stub
`provider.id` to the passed `providerCode` instead of
`/providers/<code>`.
> 
> JSDoc and the changelog document the contract. Tests drop the
normalizer suite, expect canonical `paypal` on stubs, and add coverage
for plain-ID matching in scoped quote selection.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e352e4f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Darius Costolas <10818970+meltingice1337@users.noreply.github.com>
@meltingice1337 meltingice1337 requested a review from a team as a code owner July 13, 2026 13:04
@socket-security

socket-security Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​metamask/​ramps-controller@​16.0.0981007999100

View full report

@github-actions github-actions Bot added risk:high AI analysis: high risk and removed risk:medium AI analysis: medium risk labels Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Flaky unit test detection

Run history flaky detection

View recent run history

Historical failure rate is a hint, not proof — review each suggestion in context. See the flaky-test-detection skill for the full pattern reference and manual audit workflow.

Failures / runs sampled per window:

File 7d 15d 30d
app/components/UI/Ramp/hooks/useTransakRouting.test.ts 0/50 0/178 0/375

AI-detected flaky patterns

app/components/UI/Ramp/hooks/useTransakRouting.test.ts

  • J9 — Module-level mutable let bindings not reset in beforeEach (high)
    • Module-level let variables (mockUserRegion, mockSelectedPaymentMethod) are mutated in individual tests (e.g. mockSelectedPaymentMethod = { id: '/payments/bank-transfer', isManualBankTransfer: true }) but only partially reset in beforeEach. This creates test-order dependency that can lead to intermittent failures when tests run in randomized order or under load.
    • Suggested fix in app/components/UI/Ramp/hooks/useTransakRouting.test.ts:
      -let mockUserRegion: unknown = {
      -  country: { currency: 'USD', isoCode: 'US' },
      -  regionCode: 'us-ca',
      -};
      -let mockSelectedPaymentMethod: unknown;
      -let capturedHandleNavigationStateChange: ((state: any) => void) | null = null;
      -
      -// later in describe
      -beforeEach(() => {
      -  jest.clearAllMocks();
      -  capturedHandleNavigationStateChange = null;
      -  (
      -    jest.requireMock('../headless/sessionRegistry').getSession as jest.Mock
      -  ).mockReturnValue(undefined);
      -});
      +let mockUserRegion: unknown = {
      +  country: { currency: 'USD', isoCode: 'US' },
      +  regionCode: 'us-ca',
      +};
      +let mockSelectedPaymentMethod: unknown;
      +let capturedHandleNavigationStateChange: ((state: any) => void) | null = null;
      +
      +beforeEach(() => {
      +  mockUserRegion = {
      +    country: { currency: 'USD', isoCode: 'US' },
      +    regionCode: 'us-ca',
      +  };
      +  mockSelectedPaymentMethod = undefined;
      +  capturedHandleNavigationStateChange = null;
      +  jest.clearAllMocks();
      +  (
      +    jest.requireMock('../headless/sessionRegistry').getSession as jest.Mock
      +  ).mockReturnValue(undefined);
      +});
  • J10 — jest.spyOn() without restoreAllMocks()/mockRestore() afterward (medium)
    • Multiple tests use jest.spyOn (e.g. on global.URL in the URL parsing error test, and potentially others via requireMock). The beforeEach only uses clearAllMocks (which does not restore original implementations). Without restoreAllMocks in afterEach, spies leak between tests causing non-deterministic behavior.
    • Suggested fix in app/components/UI/Ramp/hooks/useTransakRouting.test.ts:
      -describe('useTransakRouting', () => {
      -  beforeEach(() => {
      -    jest.clearAllMocks();
      -    capturedHandleNavigationStateChange = null;
      -    (
      -      jest.requireMock('../headless/sessionRegistry').getSession as jest.Mock
      -    ).mockReturnValue(undefined);
      -  });
      -  it('returns expected functions', () => {
      +describe('useTransakRouting', () => {
      +  beforeEach(() => {
      +    jest.clearAllMocks();
      +    capturedHandleNavigationStateChange = null;
      +    (
      +      jest.requireMock('../headless/sessionRegistry').getSession as jest.Mock
      +    ).mockReturnValue(undefined);
      +  });
      +
      +  afterEach(() => {
      +    jest.restoreAllMocks();
      +  });
      +
      +  it('returns expected functions', () => {

This check is informational only and does not block merging.

@meltingice1337 meltingice1337 enabled auto-merge July 13, 2026 14:57
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeSwap, SmokeStake, SmokeWalletPlatform, SmokeMoney, SmokePerps, SmokeMultiChainAPI, SmokePredictions, SmokeSeedlessOnboarding, SmokeBrowser, SmokeSnaps
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: high
  • AI Confidence: 100%
click to see 🤖 AI reasoning details

E2E Test Selection:
Hard rule (controller-version-update): @MetaMask controller package version updated in package.json: @metamask/ramps-controller. Running all tests.

Performance Test Selection:
The changes are focused on provider code normalization logic in the Ramp feature - removing the normalizeProviderCode function and using raw provider IDs directly. These are functional/correctness changes, not performance-sensitive changes. No performance test scenarios (account list, onboarding, login, swaps, launch, asset loading, predict, perps) are impacted by these changes.

View GitHub Actions results

@sonarqubecloud

Copy link
Copy Markdown

@meltingice1337 meltingice1337 added this pull request to the merge queue Jul 13, 2026
Merged via the queue into main with commit 921b70e Jul 13, 2026
177 of 179 checks passed
@meltingice1337 meltingice1337 deleted the fix/TRAM-3560-non-prefix-providers branch July 13, 2026 15:52
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 13, 2026
@metamask-ci metamask-ci Bot added the release-8.4.0 Issue or pull request that will be included in release 8.4.0 label Jul 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-8.4.0 Issue or pull request that will be included in release 8.4.0 risk:high AI analysis: high risk size-M team-money-movement issues related to Money Movement features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants