@metamask/ramps-controller 10.1.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [11.0.0]
11
+
12
+ ### Changed
13
+
14
+ - **BREAKING:** Replace `getWidgetUrl` with `getBuyWidgetData` (returns `BuyWidget | null`); add `addPrecreatedOrder` for custom-action ramp flows (e.g., PayPal) ([#8100](https://github.com/MetaMask/core/pull/8100))
15
+
16
+ ## [10.2.0]
17
+
18
+ ### Fixed
19
+
20
+ - `setSelectedProvider` no longer fetches payment methods when the selected token is explicitly not supported by the new provider, preventing empty payment method state with no user feedback ([#8103](https://github.com/MetaMask/core/pull/8103))
21
+
10
22
  ## [10.1.0]
11
23
 
12
24
  ### Added
@@ -192,7 +204,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
192
204
  - Add `OnRampService` for interacting with the OnRamp API
193
205
  - Add geolocation detection via IP address lookup
194
206
 
195
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@10.1.0...HEAD
207
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@11.0.0...HEAD
208
+ [11.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@10.2.0...@metamask/ramps-controller@11.0.0
209
+ [10.2.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@10.1.0...@metamask/ramps-controller@10.2.0
196
210
  [10.1.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@10.0.0...@metamask/ramps-controller@10.1.0
197
211
  [10.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@9.0.0...@metamask/ramps-controller@10.0.0
198
212
  [9.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@8.1.0...@metamask/ramps-controller@9.0.0
@@ -12,7 +12,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
12
12
  };
13
13
  var _RampsController_instances, _RampsController_requestCacheTTL, _RampsController_requestCacheMaxSize, _RampsController_pendingRequests, _RampsController_pendingResourceCount, _RampsController_orderPollingMeta, _RampsController_orderPollingTimer, _RampsController_isPolling, _RampsController_clearPendingResourceCountForDependentResources, _RampsController_abortDependentRequests, _RampsController_registerActionHandlers, _RampsController_mutateRequests, _RampsController_removeRequestState, _RampsController_cleanupState, _RampsController_fireAndForget, _RampsController_requireRegion, _RampsController_isRegionCurrent, _RampsController_isTokenCurrent, _RampsController_isProviderCurrent, _RampsController_updateResourceField, _RampsController_setResourceLoading, _RampsController_setResourceError, _RampsController_updateRequestState, _RampsController_refreshOrder, _RampsController_pollPendingOrders, _RampsController_syncTransakAuthOnError;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.RampsController = exports.getDefaultRampsControllerState = exports.RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS = exports.controllerName = void 0;
15
+ exports.RampsController = exports.normalizeProviderCode = exports.getDefaultRampsControllerState = exports.RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS = exports.controllerName = void 0;
16
16
  const base_controller_1 = require("@metamask/base-controller");
17
17
  const RampsService_1 = require("./RampsService.cjs");
18
18
  const RequestCache_1 = require("./RequestCache.cjs");
@@ -250,6 +250,10 @@ function findRegionFromCode(regionCode, countries) {
250
250
  regionCode: normalizedCode,
251
251
  };
252
252
  }
253
+ function normalizeProviderCode(providerCode) {
254
+ return providerCode.replace(/^\/providers\//u, '');
255
+ }
256
+ exports.normalizeProviderCode = normalizeProviderCode;
253
257
  // === ORDER POLLING CONSTANTS ===
254
258
  const TERMINAL_ORDER_STATUSES = new Set([
255
259
  RampsService_1.RampsOrderStatus.Completed,
@@ -545,11 +549,21 @@ class RampsController extends base_controller_1.BaseController {
545
549
  if (!provider) {
546
550
  throw new Error(`Provider with ID "${providerId}" not found in available providers.`);
547
551
  }
552
+ const selectedToken = this.state.tokens.selected;
553
+ const supportedCryptos = provider.supportedCryptoCurrencies;
554
+ // Only fetch payment methods if the selected token is supported by the new
555
+ // provider. If it isn't, the payment methods request would fail or return
556
+ // empty for the wrong reason; the UI will show the Token Not Available modal
557
+ // so the user can change token or pick a different provider.
558
+ const assetId = selectedToken?.assetId;
559
+ const tokenSupportedByProvider = !(assetId && supportedCryptos?.[assetId] === false);
548
560
  this.update((state) => {
549
561
  state.providers.selected = provider;
550
562
  resetResource(state, 'paymentMethods');
551
563
  });
552
- __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_fireAndForget).call(this, this.getPaymentMethods(regionCode, { provider: provider.id }));
564
+ if (tokenSupportedByProvider) {
565
+ __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_fireAndForget).call(this, this.getPaymentMethods(regionCode, { provider: provider.id }));
566
+ }
553
567
  }
554
568
  /**
555
569
  * Initializes the controller by fetching the user's region from geolocation.
@@ -935,25 +949,74 @@ class RampsController extends base_controller_1.BaseController {
935
949
  super.destroy();
936
950
  }
937
951
  /**
938
- * Fetches the widget URL from a quote for redirect providers.
952
+ * Fetches the widget data from a quote for redirect providers.
939
953
  * Makes a request to the buyURL endpoint via the RampsService to get the
940
- * actual provider widget URL.
954
+ * actual provider widget URL and optional order ID for polling.
941
955
  *
942
956
  * @param quote - The quote to fetch the widget URL from.
943
- * @returns Promise resolving to the widget URL string, or null if not available.
957
+ * @returns Promise resolving to the full BuyWidget (url, browser, orderId), or null if not available (missing buyURL or empty url in response).
958
+ * @throws Rethrows errors from the RampsService (e.g. HttpError, network failures) so clients can react to fetch failures.
944
959
  */
945
- async getWidgetUrl(quote) {
960
+ async getBuyWidgetData(quote) {
946
961
  const buyUrl = quote.quote?.buyURL;
947
962
  if (!buyUrl) {
948
963
  return null;
949
964
  }
950
- try {
951
- const buyWidget = await this.messenger.call('RampsService:getBuyWidgetUrl', buyUrl);
952
- return buyWidget.url ?? null;
953
- }
954
- catch {
965
+ const buyWidget = await this.messenger.call('RampsService:getBuyWidgetUrl', buyUrl);
966
+ if (!buyWidget?.url) {
955
967
  return null;
956
968
  }
969
+ return buyWidget;
970
+ }
971
+ /**
972
+ * Registers an order ID for polling until the order is created or resolved.
973
+ * Adds a minimal stub order to controller state; the existing order polling
974
+ * will fetch the full order when the provider has created it.
975
+ *
976
+ * @param params - Object containing order identifiers and wallet info.
977
+ * @param params.orderId - Full order ID (e.g. "/providers/paypal/orders/abc123") or order code.
978
+ * @param params.providerCode - Provider code (e.g. "paypal", "transak"), with or without /providers/ prefix.
979
+ * @param params.walletAddress - Wallet address for the order.
980
+ * @param params.chainId - Optional chain ID for the order.
981
+ */
982
+ addPrecreatedOrder(params) {
983
+ const { orderId, providerCode, walletAddress, chainId } = params;
984
+ const orderCode = orderId.includes('/orders/')
985
+ ? orderId.split('/orders/')[1]
986
+ : orderId;
987
+ if (!orderCode?.trim()) {
988
+ return;
989
+ }
990
+ const normalizedProviderCode = normalizeProviderCode(providerCode);
991
+ const stubOrder = {
992
+ providerOrderId: orderCode,
993
+ provider: {
994
+ id: `/providers/${normalizedProviderCode}`,
995
+ name: '',
996
+ environmentType: '',
997
+ description: '',
998
+ hqAddress: '',
999
+ links: [],
1000
+ logos: { light: '', dark: '', height: 0, width: 0 },
1001
+ },
1002
+ walletAddress,
1003
+ status: RampsService_1.RampsOrderStatus.Precreated,
1004
+ orderType: 'buy',
1005
+ createdAt: Date.now(),
1006
+ isOnlyLink: false,
1007
+ success: false,
1008
+ cryptoAmount: 0,
1009
+ fiatAmount: 0,
1010
+ providerOrderLink: '',
1011
+ totalFeesFiat: 0,
1012
+ txHash: '',
1013
+ network: chainId ? { chainId, name: '' } : { chainId: '', name: '' },
1014
+ canBeUpdated: true,
1015
+ idHasExpired: false,
1016
+ excludeFromPurchases: false,
1017
+ timeDescriptionPending: '',
1018
+ };
1019
+ this.addOrder(stubOrder);
957
1020
  }
958
1021
  /**
959
1022
  * Fetches an order from the unified V2 API endpoint.
@@ -968,10 +1031,17 @@ class RampsController extends base_controller_1.BaseController {
968
1031
  const order = await this.messenger.call('RampsService:getOrder', providerCode, orderCode, wallet);
969
1032
  this.update((state) => {
970
1033
  const idx = state.orders.findIndex((existing) => existing.providerOrderId === orderCode);
971
- if (idx !== -1) {
1034
+ if (idx === -1) {
1035
+ state.orders.push({
1036
+ ...order,
1037
+ providerOrderId: orderCode,
1038
+ });
1039
+ }
1040
+ else {
972
1041
  state.orders[idx] = {
973
1042
  ...state.orders[idx],
974
1043
  ...order,
1044
+ providerOrderId: orderCode,
975
1045
  };
976
1046
  }
977
1047
  });
@@ -1486,7 +1556,7 @@ async function _RampsController_refreshOrder(order) {
1486
1556
  if (!providerCode || !order.providerOrderId || !order.walletAddress) {
1487
1557
  return;
1488
1558
  }
1489
- const providerCodeSegment = providerCode.replace('/providers/', '');
1559
+ const providerCodeSegment = normalizeProviderCode(providerCode);
1490
1560
  const previousStatus = order.status;
1491
1561
  try {
1492
1562
  const updatedOrder = await this.getOrder(providerCodeSegment, order.providerOrderId, order.walletAddress);