@metamask/ramps-controller 4.1.0 → 5.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 +20 -1
- package/dist/RampsController.cjs +205 -199
- package/dist/RampsController.cjs.map +1 -1
- package/dist/RampsController.d.cts +47 -49
- package/dist/RampsController.d.cts.map +1 -1
- package/dist/RampsController.d.mts +47 -49
- package/dist/RampsController.d.mts.map +1 -1
- package/dist/RampsController.mjs +205 -199
- package/dist/RampsController.mjs.map +1 -1
- package/dist/RampsService-method-action-types.cjs.map +1 -1
- package/dist/RampsService-method-action-types.d.cts +1 -1
- package/dist/RampsService-method-action-types.d.mts +1 -1
- package/dist/RampsService-method-action-types.mjs.map +1 -1
- package/dist/RampsService.cjs +32 -14
- package/dist/RampsService.cjs.map +1 -1
- package/dist/RampsService.d.cts +27 -8
- package/dist/RampsService.d.cts.map +1 -1
- package/dist/RampsService.d.mts +27 -8
- package/dist/RampsService.d.mts.map +1 -1
- package/dist/RampsService.mjs +32 -14
- package/dist/RampsService.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/RampsController.mjs
CHANGED
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _RampsController_instances, _RampsController_requestCacheTTL, _RampsController_requestCacheMaxSize, _RampsController_pendingRequests, _RampsController_removeRequestState, _RampsController_updateRequestState;
|
|
12
|
+
var _RampsController_instances, _RampsController_requestCacheTTL, _RampsController_requestCacheMaxSize, _RampsController_pendingRequests, _RampsController_removeRequestState, _RampsController_cleanupState, _RampsController_updateRequestState;
|
|
13
13
|
import { BaseController } from "@metamask/base-controller";
|
|
14
14
|
import { DEFAULT_REQUEST_CACHE_TTL, DEFAULT_REQUEST_CACHE_MAX_SIZE, createCacheKey, isCacheExpired, createLoadingState, createSuccessState, createErrorState, RequestStatus } from "./RequestCache.mjs";
|
|
15
15
|
// === GENERAL ===
|
|
@@ -29,7 +29,13 @@ const rampsControllerMetadata = {
|
|
|
29
29
|
includeInStateLogs: true,
|
|
30
30
|
usedInUi: true,
|
|
31
31
|
},
|
|
32
|
-
|
|
32
|
+
selectedProvider: {
|
|
33
|
+
persist: false,
|
|
34
|
+
includeInDebugSnapshot: true,
|
|
35
|
+
includeInStateLogs: true,
|
|
36
|
+
usedInUi: true,
|
|
37
|
+
},
|
|
38
|
+
countries: {
|
|
33
39
|
persist: true,
|
|
34
40
|
includeInDebugSnapshot: true,
|
|
35
41
|
includeInStateLogs: true,
|
|
@@ -47,6 +53,12 @@ const rampsControllerMetadata = {
|
|
|
47
53
|
includeInStateLogs: true,
|
|
48
54
|
usedInUi: true,
|
|
49
55
|
},
|
|
56
|
+
selectedToken: {
|
|
57
|
+
persist: false,
|
|
58
|
+
includeInDebugSnapshot: true,
|
|
59
|
+
includeInStateLogs: true,
|
|
60
|
+
usedInUi: true,
|
|
61
|
+
},
|
|
50
62
|
paymentMethods: {
|
|
51
63
|
persist: false,
|
|
52
64
|
includeInDebugSnapshot: true,
|
|
@@ -77,9 +89,11 @@ const rampsControllerMetadata = {
|
|
|
77
89
|
export function getDefaultRampsControllerState() {
|
|
78
90
|
return {
|
|
79
91
|
userRegion: null,
|
|
80
|
-
|
|
92
|
+
selectedProvider: null,
|
|
93
|
+
countries: [],
|
|
81
94
|
providers: [],
|
|
82
95
|
tokens: null,
|
|
96
|
+
selectedToken: null,
|
|
83
97
|
paymentMethods: [],
|
|
84
98
|
selectedPaymentMethod: null,
|
|
85
99
|
requests: {},
|
|
@@ -201,7 +215,6 @@ export class RampsController extends BaseController {
|
|
|
201
215
|
if (pending) {
|
|
202
216
|
return pending.promise;
|
|
203
217
|
}
|
|
204
|
-
// Check cache validity (unless force refresh)
|
|
205
218
|
if (!options?.forceRefresh) {
|
|
206
219
|
const cached = this.state.requests[cacheKey];
|
|
207
220
|
if (cached && !isCacheExpired(cached, ttl)) {
|
|
@@ -270,96 +283,6 @@ export class RampsController extends BaseController {
|
|
|
270
283
|
getRequestState(cacheKey) {
|
|
271
284
|
return this.state.requests[cacheKey];
|
|
272
285
|
}
|
|
273
|
-
/**
|
|
274
|
-
* Updates the user's region by fetching geolocation.
|
|
275
|
-
* This method calls the RampsService to get the geolocation.
|
|
276
|
-
*
|
|
277
|
-
* @param options - Options for cache behavior.
|
|
278
|
-
* @returns The user region object.
|
|
279
|
-
*/
|
|
280
|
-
async updateUserRegion(options) {
|
|
281
|
-
// If a userRegion already exists and forceRefresh is not requested,
|
|
282
|
-
// return it immediately without fetching geolocation.
|
|
283
|
-
// This ensures that once a region is set (either via geolocation or manual selection),
|
|
284
|
-
// it will not be overwritten by subsequent geolocation fetches.
|
|
285
|
-
if (this.state.userRegion && !options?.forceRefresh) {
|
|
286
|
-
return this.state.userRegion;
|
|
287
|
-
}
|
|
288
|
-
// When forceRefresh is true, clear the existing region and region-dependent state before fetching
|
|
289
|
-
if (options?.forceRefresh) {
|
|
290
|
-
this.update((state) => {
|
|
291
|
-
state.userRegion = null;
|
|
292
|
-
state.tokens = null;
|
|
293
|
-
state.providers = [];
|
|
294
|
-
state.paymentMethods = [];
|
|
295
|
-
state.selectedPaymentMethod = null;
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
const cacheKey = createCacheKey('updateUserRegion', []);
|
|
299
|
-
const regionCode = await this.executeRequest(cacheKey, async () => {
|
|
300
|
-
const result = await this.messenger.call('RampsService:getGeolocation');
|
|
301
|
-
return result;
|
|
302
|
-
}, options);
|
|
303
|
-
if (!regionCode) {
|
|
304
|
-
this.update((state) => {
|
|
305
|
-
state.userRegion = null;
|
|
306
|
-
state.tokens = null;
|
|
307
|
-
state.providers = [];
|
|
308
|
-
state.paymentMethods = [];
|
|
309
|
-
state.selectedPaymentMethod = null;
|
|
310
|
-
});
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
const normalizedRegion = regionCode.toLowerCase().trim();
|
|
314
|
-
try {
|
|
315
|
-
const countries = await this.getCountries('buy', options);
|
|
316
|
-
const userRegion = findRegionFromCode(normalizedRegion, countries);
|
|
317
|
-
if (userRegion) {
|
|
318
|
-
this.update((state) => {
|
|
319
|
-
const regionChanged = state.userRegion?.regionCode !== userRegion.regionCode;
|
|
320
|
-
state.userRegion = userRegion;
|
|
321
|
-
// Clear region-dependent state when region changes
|
|
322
|
-
if (regionChanged) {
|
|
323
|
-
state.tokens = null;
|
|
324
|
-
state.providers = [];
|
|
325
|
-
state.paymentMethods = [];
|
|
326
|
-
state.selectedPaymentMethod = null;
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
// Fetch providers for the new region
|
|
330
|
-
if (userRegion.regionCode) {
|
|
331
|
-
try {
|
|
332
|
-
await this.getProviders(userRegion.regionCode, options);
|
|
333
|
-
}
|
|
334
|
-
catch {
|
|
335
|
-
// Provider fetch failed - error state will be available via selectors
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return userRegion;
|
|
339
|
-
}
|
|
340
|
-
// Region not found in countries data
|
|
341
|
-
this.update((state) => {
|
|
342
|
-
state.userRegion = null;
|
|
343
|
-
state.tokens = null;
|
|
344
|
-
state.providers = [];
|
|
345
|
-
state.paymentMethods = [];
|
|
346
|
-
state.selectedPaymentMethod = null;
|
|
347
|
-
});
|
|
348
|
-
return null;
|
|
349
|
-
}
|
|
350
|
-
catch {
|
|
351
|
-
// If countries fetch fails, we can't create a valid UserRegion
|
|
352
|
-
// Return null to indicate we don't have valid country data
|
|
353
|
-
this.update((state) => {
|
|
354
|
-
state.userRegion = null;
|
|
355
|
-
state.tokens = null;
|
|
356
|
-
state.providers = [];
|
|
357
|
-
state.paymentMethods = [];
|
|
358
|
-
state.selectedPaymentMethod = null;
|
|
359
|
-
});
|
|
360
|
-
return null;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
286
|
/**
|
|
364
287
|
* Sets the user's region manually (without fetching geolocation).
|
|
365
288
|
* This allows users to override the detected region.
|
|
@@ -371,106 +294,129 @@ export class RampsController extends BaseController {
|
|
|
371
294
|
async setUserRegion(region, options) {
|
|
372
295
|
const normalizedRegion = region.toLowerCase().trim();
|
|
373
296
|
try {
|
|
374
|
-
const countries =
|
|
297
|
+
const { countries } = this.state;
|
|
298
|
+
if (!countries || countries.length === 0) {
|
|
299
|
+
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_cleanupState).call(this);
|
|
300
|
+
throw new Error('No countries found. Cannot set user region without valid country information.');
|
|
301
|
+
}
|
|
375
302
|
const userRegion = findRegionFromCode(normalizedRegion, countries);
|
|
376
|
-
if (userRegion) {
|
|
377
|
-
this.
|
|
378
|
-
|
|
303
|
+
if (!userRegion) {
|
|
304
|
+
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_cleanupState).call(this);
|
|
305
|
+
throw new Error(`Region "${normalizedRegion}" not found in countries data. Cannot set user region without valid country information.`);
|
|
306
|
+
}
|
|
307
|
+
// Only cleanup state if region is actually changing
|
|
308
|
+
const regionChanged = normalizedRegion !== this.state.userRegion?.regionCode;
|
|
309
|
+
// Set the new region atomically with cleanup to avoid intermediate null state
|
|
310
|
+
this.update((state) => {
|
|
311
|
+
if (regionChanged) {
|
|
312
|
+
state.selectedProvider = null;
|
|
313
|
+
state.selectedToken = null;
|
|
379
314
|
state.tokens = null;
|
|
380
315
|
state.providers = [];
|
|
381
316
|
state.paymentMethods = [];
|
|
382
317
|
state.selectedPaymentMethod = null;
|
|
383
|
-
});
|
|
384
|
-
// Fetch providers for the new region
|
|
385
|
-
try {
|
|
386
|
-
await this.getProviders(userRegion.regionCode, options);
|
|
387
318
|
}
|
|
388
|
-
|
|
389
|
-
// Provider fetch failed - error state will be available via selectors
|
|
390
|
-
}
|
|
391
|
-
return userRegion;
|
|
392
|
-
}
|
|
393
|
-
// Region not found in countries data
|
|
394
|
-
this.update((state) => {
|
|
395
|
-
state.userRegion = null;
|
|
396
|
-
state.tokens = null;
|
|
397
|
-
state.providers = [];
|
|
398
|
-
state.paymentMethods = [];
|
|
399
|
-
state.selectedPaymentMethod = null;
|
|
319
|
+
state.userRegion = userRegion;
|
|
400
320
|
});
|
|
401
|
-
|
|
321
|
+
// Only trigger fetches if region changed or if data is missing
|
|
322
|
+
if (regionChanged || !this.state.tokens) {
|
|
323
|
+
this.triggerGetTokens(userRegion.regionCode, 'buy', options);
|
|
324
|
+
}
|
|
325
|
+
if (regionChanged || this.state.providers.length === 0) {
|
|
326
|
+
this.triggerGetProviders(userRegion.regionCode, options);
|
|
327
|
+
}
|
|
328
|
+
return userRegion;
|
|
402
329
|
}
|
|
403
330
|
catch (error) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if (error instanceof Error && error.message.includes('not found')) {
|
|
407
|
-
throw error;
|
|
408
|
-
}
|
|
409
|
-
// Countries fetch failed
|
|
410
|
-
this.update((state) => {
|
|
411
|
-
state.userRegion = null;
|
|
412
|
-
state.tokens = null;
|
|
413
|
-
state.providers = [];
|
|
414
|
-
state.paymentMethods = [];
|
|
415
|
-
state.selectedPaymentMethod = null;
|
|
416
|
-
});
|
|
417
|
-
throw new Error('Failed to fetch countries data. Cannot set user region without valid country information.');
|
|
331
|
+
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_cleanupState).call(this);
|
|
332
|
+
throw error;
|
|
418
333
|
}
|
|
419
334
|
}
|
|
420
335
|
/**
|
|
421
|
-
* Sets the user's
|
|
422
|
-
*
|
|
336
|
+
* Sets the user's selected provider by ID, or clears the selection.
|
|
337
|
+
* Looks up the provider from the current providers in state and automatically
|
|
338
|
+
* fetches payment methods for that provider.
|
|
423
339
|
*
|
|
424
|
-
* @param
|
|
340
|
+
* @param providerId - The provider ID (e.g., "/providers/moonpay"), or null to clear.
|
|
341
|
+
* @throws If region is not set, providers are not loaded, or provider is not found.
|
|
425
342
|
*/
|
|
426
|
-
|
|
343
|
+
setSelectedProvider(providerId) {
|
|
344
|
+
if (providerId === null) {
|
|
345
|
+
this.update((state) => {
|
|
346
|
+
state.selectedProvider = null;
|
|
347
|
+
state.paymentMethods = [];
|
|
348
|
+
state.selectedPaymentMethod = null;
|
|
349
|
+
});
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const regionCode = this.state.userRegion?.regionCode;
|
|
353
|
+
if (!regionCode) {
|
|
354
|
+
throw new Error('Region is required. Cannot set selected provider without valid region information.');
|
|
355
|
+
}
|
|
356
|
+
const { providers } = this.state;
|
|
357
|
+
if (!providers || providers.length === 0) {
|
|
358
|
+
throw new Error('Providers not loaded. Cannot set selected provider before providers are fetched.');
|
|
359
|
+
}
|
|
360
|
+
const provider = providers.find((prov) => prov.id === providerId);
|
|
361
|
+
if (!provider) {
|
|
362
|
+
throw new Error(`Provider with ID "${providerId}" not found in available providers.`);
|
|
363
|
+
}
|
|
427
364
|
this.update((state) => {
|
|
428
|
-
state.
|
|
365
|
+
state.selectedProvider = provider;
|
|
366
|
+
state.paymentMethods = [];
|
|
367
|
+
state.selectedPaymentMethod = null;
|
|
368
|
+
});
|
|
369
|
+
// fetch payment methods for the new provider
|
|
370
|
+
// this is needed because you can change providers without changing the token
|
|
371
|
+
// (getPaymentMethods will use state as its default)
|
|
372
|
+
this.triggerGetPaymentMethods(regionCode, {
|
|
373
|
+
provider: provider.id,
|
|
429
374
|
});
|
|
430
375
|
}
|
|
431
376
|
/**
|
|
432
377
|
* Initializes the controller by fetching the user's region from geolocation.
|
|
433
378
|
* This should be called once at app startup to set up the initial region.
|
|
434
|
-
* After the region is set, tokens are fetched and saved to state.
|
|
435
379
|
*
|
|
436
380
|
* If a userRegion already exists (from persistence or manual selection),
|
|
437
|
-
* this method will skip geolocation fetch and
|
|
381
|
+
* this method will skip geolocation fetch and use the existing region.
|
|
438
382
|
*
|
|
439
383
|
* @param options - Options for cache behavior.
|
|
440
384
|
* @returns Promise that resolves when initialization is complete.
|
|
441
385
|
*/
|
|
442
386
|
async init(options) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
await this.getProviders(userRegion.regionCode, options);
|
|
456
|
-
}
|
|
457
|
-
catch {
|
|
458
|
-
// Provider fetch failed - error state will be available via selectors
|
|
459
|
-
}
|
|
387
|
+
await this.getCountries(options);
|
|
388
|
+
let regionCode = this.state.userRegion?.regionCode;
|
|
389
|
+
regionCode ?? (regionCode = await this.messenger.call('RampsService:getGeolocation'));
|
|
390
|
+
if (!regionCode) {
|
|
391
|
+
throw new Error('Failed to fetch geolocation. Cannot initialize controller without valid region information.');
|
|
392
|
+
}
|
|
393
|
+
await this.setUserRegion(regionCode, options);
|
|
394
|
+
}
|
|
395
|
+
hydrateState(options) {
|
|
396
|
+
const regionCode = this.state.userRegion?.regionCode;
|
|
397
|
+
if (!regionCode) {
|
|
398
|
+
throw new Error('Region code is required. Cannot hydrate state without valid region information.');
|
|
460
399
|
}
|
|
400
|
+
this.triggerGetTokens(regionCode, 'buy', options);
|
|
401
|
+
this.triggerGetProviders(regionCode, options);
|
|
461
402
|
}
|
|
462
403
|
/**
|
|
463
|
-
* Fetches the list of supported countries
|
|
404
|
+
* Fetches the list of supported countries.
|
|
405
|
+
* The API returns countries with support information for both buy and sell actions.
|
|
406
|
+
* The countries are saved in the controller state once fetched.
|
|
464
407
|
*
|
|
465
|
-
* @param action - The ramp action type ('buy' or 'sell').
|
|
466
408
|
* @param options - Options for cache behavior.
|
|
467
409
|
* @returns An array of countries.
|
|
468
410
|
*/
|
|
469
|
-
async getCountries(
|
|
470
|
-
const cacheKey = createCacheKey('getCountries', [
|
|
471
|
-
|
|
472
|
-
return this.messenger.call('RampsService:getCountries'
|
|
411
|
+
async getCountries(options) {
|
|
412
|
+
const cacheKey = createCacheKey('getCountries', []);
|
|
413
|
+
const countries = await this.executeRequest(cacheKey, async () => {
|
|
414
|
+
return this.messenger.call('RampsService:getCountries');
|
|
473
415
|
}, options);
|
|
416
|
+
this.update((state) => {
|
|
417
|
+
state.countries = countries;
|
|
418
|
+
});
|
|
419
|
+
return countries;
|
|
474
420
|
}
|
|
475
421
|
/**
|
|
476
422
|
* Fetches the list of available tokens for a given region and action.
|
|
@@ -506,6 +452,45 @@ export class RampsController extends BaseController {
|
|
|
506
452
|
});
|
|
507
453
|
return tokens;
|
|
508
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* Sets the user's selected token by asset ID.
|
|
457
|
+
* Looks up the token from the current tokens in state and automatically
|
|
458
|
+
* fetches payment methods for that token.
|
|
459
|
+
*
|
|
460
|
+
* @param assetId - The asset identifier in CAIP-19 format (e.g., "eip155:1/erc20:0x..."), or undefined to clear.
|
|
461
|
+
* @throws If region is not set, tokens are not loaded, or token is not found.
|
|
462
|
+
*/
|
|
463
|
+
setSelectedToken(assetId) {
|
|
464
|
+
if (!assetId) {
|
|
465
|
+
this.update((state) => {
|
|
466
|
+
state.selectedToken = null;
|
|
467
|
+
state.paymentMethods = [];
|
|
468
|
+
state.selectedPaymentMethod = null;
|
|
469
|
+
});
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const regionCode = this.state.userRegion?.regionCode;
|
|
473
|
+
if (!regionCode) {
|
|
474
|
+
throw new Error('Region is required. Cannot set selected token without valid region information.');
|
|
475
|
+
}
|
|
476
|
+
const { tokens } = this.state;
|
|
477
|
+
if (!tokens) {
|
|
478
|
+
throw new Error('Tokens not loaded. Cannot set selected token before tokens are fetched.');
|
|
479
|
+
}
|
|
480
|
+
const token = tokens.allTokens.find((tok) => tok.assetId === assetId) ??
|
|
481
|
+
tokens.topTokens.find((tok) => tok.assetId === assetId);
|
|
482
|
+
if (!token) {
|
|
483
|
+
throw new Error(`Token with asset ID "${assetId}" not found in available tokens.`);
|
|
484
|
+
}
|
|
485
|
+
this.update((state) => {
|
|
486
|
+
state.selectedToken = token;
|
|
487
|
+
state.paymentMethods = [];
|
|
488
|
+
state.selectedPaymentMethod = null;
|
|
489
|
+
});
|
|
490
|
+
this.triggerGetPaymentMethods(regionCode, {
|
|
491
|
+
assetId: token.assetId,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
509
494
|
/**
|
|
510
495
|
* Fetches the list of providers for a given region.
|
|
511
496
|
* The providers are saved in the controller state once fetched.
|
|
@@ -551,57 +536,81 @@ export class RampsController extends BaseController {
|
|
|
551
536
|
* Fetches the list of payment methods for a given context.
|
|
552
537
|
* The payment methods are saved in the controller state once fetched.
|
|
553
538
|
*
|
|
539
|
+
* @param region - User's region code (e.g. "fr", "us-ny").
|
|
554
540
|
* @param options - Query parameters for filtering payment methods.
|
|
555
|
-
* @param options.region - User's region code. If not provided, uses the user's region from controller state.
|
|
556
541
|
* @param options.fiat - Fiat currency code (e.g., "usd"). If not provided, uses the user's region currency.
|
|
557
542
|
* @param options.assetId - CAIP-19 cryptocurrency identifier.
|
|
558
543
|
* @param options.provider - Provider ID path.
|
|
559
|
-
* @param options.forceRefresh - Whether to bypass cache.
|
|
560
|
-
* @param options.ttl - Custom TTL for this request.
|
|
561
544
|
* @returns The payment methods response containing payments array.
|
|
562
545
|
*/
|
|
563
|
-
async getPaymentMethods(options) {
|
|
564
|
-
const
|
|
565
|
-
const fiatToUse = options
|
|
566
|
-
|
|
546
|
+
async getPaymentMethods(region, options) {
|
|
547
|
+
const regionCode = region ?? this.state.userRegion?.regionCode ?? null;
|
|
548
|
+
const fiatToUse = options?.fiat ?? this.state.userRegion?.country?.currency ?? null;
|
|
549
|
+
const assetIdToUse = options?.assetId ?? this.state.selectedToken?.assetId ?? '';
|
|
550
|
+
const providerToUse = options?.provider ?? this.state.selectedProvider?.id ?? '';
|
|
551
|
+
if (!regionCode) {
|
|
567
552
|
throw new Error('Region is required. Either provide a region parameter or ensure userRegion is set in controller state.');
|
|
568
553
|
}
|
|
569
554
|
if (!fiatToUse) {
|
|
570
555
|
throw new Error('Fiat currency is required. Either provide a fiat parameter or ensure userRegion is set in controller state.');
|
|
571
556
|
}
|
|
572
|
-
const normalizedRegion =
|
|
557
|
+
const normalizedRegion = regionCode.toLowerCase().trim();
|
|
573
558
|
const normalizedFiat = fiatToUse.toLowerCase().trim();
|
|
574
559
|
const cacheKey = createCacheKey('getPaymentMethods', [
|
|
575
560
|
normalizedRegion,
|
|
576
561
|
normalizedFiat,
|
|
577
|
-
|
|
578
|
-
|
|
562
|
+
assetIdToUse,
|
|
563
|
+
providerToUse,
|
|
579
564
|
]);
|
|
580
565
|
const response = await this.executeRequest(cacheKey, async () => {
|
|
581
566
|
return this.messenger.call('RampsService:getPaymentMethods', {
|
|
582
567
|
region: normalizedRegion,
|
|
583
568
|
fiat: normalizedFiat,
|
|
584
|
-
assetId:
|
|
585
|
-
provider:
|
|
569
|
+
assetId: assetIdToUse,
|
|
570
|
+
provider: providerToUse,
|
|
586
571
|
});
|
|
587
|
-
},
|
|
572
|
+
}, options);
|
|
588
573
|
this.update((state) => {
|
|
589
|
-
state.
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
574
|
+
const currentAssetId = state.selectedToken?.assetId ?? '';
|
|
575
|
+
const currentProviderId = state.selectedProvider?.id ?? '';
|
|
576
|
+
const tokenSelectionUnchanged = assetIdToUse === currentAssetId;
|
|
577
|
+
const providerSelectionUnchanged = providerToUse === currentProviderId;
|
|
578
|
+
// this is a race condition check to ensure that the selected token and provider in state are the same as the tokens we're requesting for
|
|
579
|
+
// ex: if the user rapidly changes the token or provider, the in-flight payment methods might not be valid
|
|
580
|
+
// so this check will ensure that the payment methods are still valid for the token and provider that were requested
|
|
581
|
+
if (tokenSelectionUnchanged && providerSelectionUnchanged) {
|
|
582
|
+
state.paymentMethods = response.payments;
|
|
583
|
+
// this will auto-select the first payment method if the selected payment method is not in the new payment methods
|
|
584
|
+
const currentSelectionStillValid = response.payments.some((pm) => pm.id === state.selectedPaymentMethod?.id);
|
|
585
|
+
if (!currentSelectionStillValid) {
|
|
586
|
+
state.selectedPaymentMethod = response.payments[0] ?? null;
|
|
587
|
+
}
|
|
595
588
|
}
|
|
596
589
|
});
|
|
597
590
|
return response;
|
|
598
591
|
}
|
|
599
592
|
/**
|
|
600
|
-
* Sets the user's selected payment method.
|
|
593
|
+
* Sets the user's selected payment method by ID.
|
|
594
|
+
* Looks up the payment method from the current payment methods in state.
|
|
601
595
|
*
|
|
602
|
-
* @param
|
|
596
|
+
* @param paymentMethodId - The payment method ID (e.g., "/payments/debit-credit-card"), or null to clear.
|
|
597
|
+
* @throws If payment methods are not loaded or payment method is not found.
|
|
603
598
|
*/
|
|
604
|
-
setSelectedPaymentMethod(
|
|
599
|
+
setSelectedPaymentMethod(paymentMethodId) {
|
|
600
|
+
if (!paymentMethodId) {
|
|
601
|
+
this.update((state) => {
|
|
602
|
+
state.selectedPaymentMethod = null;
|
|
603
|
+
});
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
const { paymentMethods } = this.state;
|
|
607
|
+
if (!paymentMethods || paymentMethods.length === 0) {
|
|
608
|
+
throw new Error('Payment methods not loaded. Cannot set selected payment method before payment methods are fetched.');
|
|
609
|
+
}
|
|
610
|
+
const paymentMethod = paymentMethods.find((pm) => pm.id === paymentMethodId);
|
|
611
|
+
if (!paymentMethod) {
|
|
612
|
+
throw new Error(`Payment method with ID "${paymentMethodId}" not found in available payment methods.`);
|
|
613
|
+
}
|
|
605
614
|
this.update((state) => {
|
|
606
615
|
state.selectedPaymentMethod = paymentMethod;
|
|
607
616
|
});
|
|
@@ -611,16 +620,6 @@ export class RampsController extends BaseController {
|
|
|
611
620
|
// These fire-and-forget methods are for use in React effects.
|
|
612
621
|
// Errors are stored in state and available via selectors.
|
|
613
622
|
// ============================================================
|
|
614
|
-
/**
|
|
615
|
-
* Triggers a user region update without throwing.
|
|
616
|
-
*
|
|
617
|
-
* @param options - Options for cache behavior.
|
|
618
|
-
*/
|
|
619
|
-
triggerUpdateUserRegion(options) {
|
|
620
|
-
this.updateUserRegion(options).catch(() => {
|
|
621
|
-
// Error stored in state
|
|
622
|
-
});
|
|
623
|
-
}
|
|
624
623
|
/**
|
|
625
624
|
* Triggers setting the user region without throwing.
|
|
626
625
|
*
|
|
@@ -635,11 +634,10 @@ export class RampsController extends BaseController {
|
|
|
635
634
|
/**
|
|
636
635
|
* Triggers fetching countries without throwing.
|
|
637
636
|
*
|
|
638
|
-
* @param action - The ramp action type ('buy' or 'sell').
|
|
639
637
|
* @param options - Options for cache behavior.
|
|
640
638
|
*/
|
|
641
|
-
triggerGetCountries(
|
|
642
|
-
this.getCountries(
|
|
639
|
+
triggerGetCountries(options) {
|
|
640
|
+
this.getCountries(options).catch(() => {
|
|
643
641
|
// Error stored in state
|
|
644
642
|
});
|
|
645
643
|
}
|
|
@@ -669,16 +667,14 @@ export class RampsController extends BaseController {
|
|
|
669
667
|
/**
|
|
670
668
|
* Triggers fetching payment methods without throwing.
|
|
671
669
|
*
|
|
670
|
+
* @param region - User's region code (e.g., "us", "fr", "us-ny").
|
|
672
671
|
* @param options - Query parameters for filtering payment methods.
|
|
673
|
-
* @param options.region - User's region code. If not provided, uses userRegion from state.
|
|
674
672
|
* @param options.fiat - Fiat currency code. If not provided, uses userRegion currency.
|
|
675
673
|
* @param options.assetId - CAIP-19 cryptocurrency identifier.
|
|
676
674
|
* @param options.provider - Provider ID path.
|
|
677
|
-
* @param options.forceRefresh - Whether to bypass cache.
|
|
678
|
-
* @param options.ttl - Custom TTL for this request.
|
|
679
675
|
*/
|
|
680
|
-
triggerGetPaymentMethods(options) {
|
|
681
|
-
this.getPaymentMethods(options).catch(() => {
|
|
676
|
+
triggerGetPaymentMethods(region, options) {
|
|
677
|
+
this.getPaymentMethods(region, options).catch(() => {
|
|
682
678
|
// Error stored in state
|
|
683
679
|
});
|
|
684
680
|
}
|
|
@@ -688,6 +684,16 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
|
|
|
688
684
|
const requests = state.requests;
|
|
689
685
|
delete requests[cacheKey];
|
|
690
686
|
});
|
|
687
|
+
}, _RampsController_cleanupState = function _RampsController_cleanupState() {
|
|
688
|
+
this.update((state) => {
|
|
689
|
+
state.userRegion = null;
|
|
690
|
+
state.selectedProvider = null;
|
|
691
|
+
state.selectedToken = null;
|
|
692
|
+
state.tokens = null;
|
|
693
|
+
state.providers = [];
|
|
694
|
+
state.paymentMethods = [];
|
|
695
|
+
state.selectedPaymentMethod = null;
|
|
696
|
+
});
|
|
691
697
|
}, _RampsController_updateRequestState = function _RampsController_updateRequestState(cacheKey, requestState) {
|
|
692
698
|
const maxSize = __classPrivateFieldGet(this, _RampsController_requestCacheMaxSize, "f");
|
|
693
699
|
const ttl = __classPrivateFieldGet(this, _RampsController_requestCacheTTL, "f");
|