Skip to content

feat(ramps): publish and enforce per-asset buy limits (TRAM-3994) - #10254

Draft
wenfix wants to merge 4 commits into
mainfrom
ramps-controller
Draft

wenfix wants to merge 4 commits into
mainfrom
ramps-controller

Conversation

@wenfix

@wenfix wenfix commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Explanation

The v2 ramps API published limits keyed by fiat currency + payment method only, so the extension displayed a single token-agnostic minimum for providers whose minimum varies per token. For Coinbase this showed "Minimum purchase is 2 EUR" regardless of token, even though 2 EUR only holds for ETH and most other tokens require 5 EUR — users only discovered the real minimum on Coinbase's website after redirect, when Confirm & Purchase was greyed out (TRAM-3994).

The backend side (onramp-api) now publishes per-asset limits on the v2 providers response as limits.assets[assetId]. This PR teaches @metamask/ramps-controller to carry and resolve them:

  • ProviderLimits gains an optional assets map (ProviderAssetLimitsMap) keyed by CAIP-19 asset id, mirroring the API wire shape, with ProviderAssetLimits and ProviderAssetPaymentLimit for the optional per-payment-method breakdown.
  • New getProviderBuyLimit helper resolves a provider's effective buy limit for a fiat currency, payment method, and deposit asset, intersecting the token-agnostic fiat limits with the per-asset limits (tightest bounds win, fiat fees win, maxAmount: 0 treated as unbounded) the same way the ramps API enforces buy limits server-side. Payment method ids match in both bare and /payments/-prefixed form; EVM asset ids match case-insensitively.
  • The widened all-providers getQuotes quote pick now applies this helper for buy quotes, so a provider whose limits for the requested asset do not fit the amount is skipped instead of being judged by the token-agnostic fiat minimum. Sell quotes keep the prior fiat-map check, since per-asset limits are a buy dimension.

Note: the client intersects for every provider that publishes asset limits, which can be stricter than API quotes for providers the backend does not enforce per-crypto limits for (its ENFORCE_CRYPTO_PAYMENT_LIMITS_PROVIDERS gate is deployment config invisible to clients). Stricter is the safe direction — it matches what the provider's own checkout enforces.

References

  • TRAM-3994 ([Bug]: Ramps - Minimum purchase Coinbase incorrect)
  • Root-cause analysis: TRAM-3994 (backend item 1 and extension item 3 are handled separately)
  • Backend wire format: onramp-api commit 60623e4a ("fix: publish per-asset limits on v2 providers response")

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

The v2 regions providers endpoint now publishes token-specific limits
(ProviderLimits.assets) so clients can show per-token minimum/maximum
purchase amounts instead of the token-agnostic fiat limits, which are
wrong for providers whose minimum varies per token (e.g. Coinbase: 2 EUR
for ETH, 5 EUR for most other tokens).

- Add ProviderAssetLimits / ProviderAssetPaymentLimit /
  ProviderAssetLimitsMap types mirroring the API wire shape
- Add getProviderBuyLimit helper, which resolves the effective buy limit
  for a fiat currency, payment method, and deposit asset by intersecting
  the fiat and per-asset limit dimensions the same way the ramps API
  enforces buy limits server-side
Apply review feedback:

- Use getProviderBuyLimit for the widened quote pick's limit-fit check on
  buy quotes, so a provider whose limits for the requested asset do not
  fit the amount is skipped instead of being judged by the token-agnostic
  fiat limits. Sell quotes keep the fiat-map check, since per-asset
  limits are a buy dimension.
- Return per-asset limits in the uniform ProviderLimit shape (no leaked
  payment field) when the limit comes from the per-payment breakdown.
- Document that the client intersects for every provider publishing
  asset limits, which can be stricter than API quotes for providers the
  backend does not enforce per-crypto limits for.
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.

1 participant