@metamask/ramps-controller 3.0.0 → 4.1.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 +42 -1
- package/dist/RampsController.cjs +420 -76
- package/dist/RampsController.cjs.map +1 -1
- package/dist/RampsController.d.cts +172 -29
- package/dist/RampsController.d.cts.map +1 -1
- package/dist/RampsController.d.mts +172 -29
- package/dist/RampsController.d.mts.map +1 -1
- package/dist/RampsController.mjs +421 -77
- 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 +34 -11
- package/dist/RampsService-method-action-types.d.cts.map +1 -1
- package/dist/RampsService-method-action-types.d.mts +34 -11
- package/dist/RampsService-method-action-types.d.mts.map +1 -1
- package/dist/RampsService-method-action-types.mjs.map +1 -1
- package/dist/RampsService.cjs +119 -14
- package/dist/RampsService.cjs.map +1 -1
- package/dist/RampsService.d.cts +127 -18
- package/dist/RampsService.d.cts.map +1 -1
- package/dist/RampsService.d.mts +127 -18
- package/dist/RampsService.d.mts.map +1 -1
- package/dist/RampsService.mjs +119 -14
- package/dist/RampsService.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.1.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Add sync trigger methods to RampsController ([#7662](https://github.com/MetaMask/core/pull/7662))
|
|
15
|
+
|
|
16
|
+
- Export `RampAction` type for `'buy' | 'sell'` ramp actions ([#7663](https://github.com/MetaMask/core/pull/7663))
|
|
17
|
+
- Add payment methods support with `getPaymentMethods()` method, `paymentMethods` and `selectedPaymentMethod` state ([#7665](https://github.com/MetaMask/core/pull/7665))
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Evict expired cache entries based on TTL in addition to size-based eviction ([#7674](https://github.com/MetaMask/core/pull/7674))
|
|
22
|
+
|
|
23
|
+
- Update `getTokens()` to use v2 API endpoint and support optional provider parameter ([#7664](https://github.com/MetaMask/core/pull/7664))
|
|
24
|
+
|
|
25
|
+
## [4.0.0]
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Add `preferredProvider` state and `setPreferredProvider()` method to RampsController ([#7617](https://github.com/MetaMask/core/pull/7617))
|
|
30
|
+
|
|
31
|
+
- Export `UserRegion` type ([#7646](https://github.com/MetaMask/core/pull/7646))
|
|
32
|
+
|
|
33
|
+
- Add `defaultAmount` and `quickAmounts` fields to the `Country` type ([#7645](https://github.com/MetaMask/core/pull/7645))
|
|
34
|
+
|
|
35
|
+
- Add `providers` state and `getProviders()` method to RampsController. Providers are automatically fetched on init and when the region changes ([#7652](https://github.com/MetaMask/core/pull/7652))
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **BREAKING:** Change `userRegion` from `string | null` to `UserRegion | null`. Access region code via `userRegion.regionCode`. ([#7646](https://github.com/MetaMask/core/pull/7646))
|
|
40
|
+
|
|
41
|
+
- Update `getCountries()` endpoint to use v2 API (`v2/regions/countries`) ([#7645](https://github.com/MetaMask/core/pull/7645))
|
|
42
|
+
|
|
43
|
+
- Add `getApiPath()` helper function for versioned API paths with v2 default ([#7645](https://github.com/MetaMask/core/pull/7645))
|
|
44
|
+
|
|
45
|
+
### Removed
|
|
46
|
+
|
|
47
|
+
- **BREAKING:** Remove eligibility concept from RampsController. The `eligibility` state, `updateEligibility()` method, and `getEligibility()` service method have been removed. The `Eligibility` type and `RampsServiceGetEligibilityAction` are no longer exported. ([#7651](https://github.com/MetaMask/core/pull/7645))
|
|
48
|
+
|
|
10
49
|
## [3.0.0]
|
|
11
50
|
|
|
12
51
|
### Added
|
|
@@ -55,7 +94,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
55
94
|
- Add `OnRampService` for interacting with the OnRamp API
|
|
56
95
|
- Add geolocation detection via IP address lookup
|
|
57
96
|
|
|
58
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@
|
|
97
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@4.1.0...HEAD
|
|
98
|
+
[4.1.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@4.0.0...@metamask/ramps-controller@4.1.0
|
|
99
|
+
[4.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@3.0.0...@metamask/ramps-controller@4.0.0
|
|
59
100
|
[3.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@2.1.0...@metamask/ramps-controller@3.0.0
|
|
60
101
|
[2.1.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@2.0.0...@metamask/ramps-controller@2.1.0
|
|
61
102
|
[2.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@1.0.0...@metamask/ramps-controller@2.0.0
|
package/dist/RampsController.cjs
CHANGED
|
@@ -32,7 +32,13 @@ const rampsControllerMetadata = {
|
|
|
32
32
|
includeInStateLogs: true,
|
|
33
33
|
usedInUi: true,
|
|
34
34
|
},
|
|
35
|
-
|
|
35
|
+
preferredProvider: {
|
|
36
|
+
persist: true,
|
|
37
|
+
includeInDebugSnapshot: true,
|
|
38
|
+
includeInStateLogs: true,
|
|
39
|
+
usedInUi: true,
|
|
40
|
+
},
|
|
41
|
+
providers: {
|
|
36
42
|
persist: true,
|
|
37
43
|
includeInDebugSnapshot: true,
|
|
38
44
|
includeInStateLogs: true,
|
|
@@ -44,6 +50,18 @@ const rampsControllerMetadata = {
|
|
|
44
50
|
includeInStateLogs: true,
|
|
45
51
|
usedInUi: true,
|
|
46
52
|
},
|
|
53
|
+
paymentMethods: {
|
|
54
|
+
persist: false,
|
|
55
|
+
includeInDebugSnapshot: true,
|
|
56
|
+
includeInStateLogs: true,
|
|
57
|
+
usedInUi: true,
|
|
58
|
+
},
|
|
59
|
+
selectedPaymentMethod: {
|
|
60
|
+
persist: false,
|
|
61
|
+
includeInDebugSnapshot: true,
|
|
62
|
+
includeInStateLogs: true,
|
|
63
|
+
usedInUi: true,
|
|
64
|
+
},
|
|
47
65
|
requests: {
|
|
48
66
|
persist: false,
|
|
49
67
|
includeInDebugSnapshot: true,
|
|
@@ -62,12 +80,68 @@ const rampsControllerMetadata = {
|
|
|
62
80
|
function getDefaultRampsControllerState() {
|
|
63
81
|
return {
|
|
64
82
|
userRegion: null,
|
|
65
|
-
|
|
83
|
+
preferredProvider: null,
|
|
84
|
+
providers: [],
|
|
66
85
|
tokens: null,
|
|
86
|
+
paymentMethods: [],
|
|
87
|
+
selectedPaymentMethod: null,
|
|
67
88
|
requests: {},
|
|
68
89
|
};
|
|
69
90
|
}
|
|
70
91
|
exports.getDefaultRampsControllerState = getDefaultRampsControllerState;
|
|
92
|
+
// === HELPER FUNCTIONS ===
|
|
93
|
+
/**
|
|
94
|
+
* Finds a country and state from a region code string.
|
|
95
|
+
*
|
|
96
|
+
* @param regionCode - The region code (e.g., "us-ca" or "us").
|
|
97
|
+
* @param countries - Array of countries to search.
|
|
98
|
+
* @returns UserRegion object with country and state, or null if not found.
|
|
99
|
+
*/
|
|
100
|
+
function findRegionFromCode(regionCode, countries) {
|
|
101
|
+
const normalizedCode = regionCode.toLowerCase().trim();
|
|
102
|
+
const parts = normalizedCode.split('-');
|
|
103
|
+
const countryCode = parts[0];
|
|
104
|
+
const stateCode = parts[1];
|
|
105
|
+
const country = countries.find((countryItem) => {
|
|
106
|
+
if (countryItem.isoCode?.toLowerCase() === countryCode) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (countryItem.id) {
|
|
110
|
+
const id = countryItem.id.toLowerCase();
|
|
111
|
+
if (id.startsWith('/regions/')) {
|
|
112
|
+
const extractedCode = id.replace('/regions/', '').split('/')[0];
|
|
113
|
+
return extractedCode === countryCode;
|
|
114
|
+
}
|
|
115
|
+
return id === countryCode || id.endsWith(`/${countryCode}`);
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
});
|
|
119
|
+
if (!country) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
let state = null;
|
|
123
|
+
if (stateCode && country.states) {
|
|
124
|
+
state =
|
|
125
|
+
country.states.find((stateItem) => {
|
|
126
|
+
if (stateItem.stateId?.toLowerCase() === stateCode) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
if (stateItem.id) {
|
|
130
|
+
const stateId = stateItem.id.toLowerCase();
|
|
131
|
+
if (stateId.includes(`-${stateCode}`) ||
|
|
132
|
+
stateId.endsWith(`/${stateCode}`)) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}) ?? null;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
country,
|
|
141
|
+
state,
|
|
142
|
+
regionCode: normalizedCode,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
71
145
|
// === CONTROLLER DEFINITION ===
|
|
72
146
|
/**
|
|
73
147
|
* Manages cryptocurrency on/off ramps functionality.
|
|
@@ -201,80 +275,170 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
201
275
|
return this.state.requests[cacheKey];
|
|
202
276
|
}
|
|
203
277
|
/**
|
|
204
|
-
* Updates the user's region by fetching geolocation
|
|
205
|
-
* This method calls the RampsService to get the geolocation
|
|
206
|
-
* then automatically fetches eligibility for that region.
|
|
278
|
+
* Updates the user's region by fetching geolocation.
|
|
279
|
+
* This method calls the RampsService to get the geolocation.
|
|
207
280
|
*
|
|
208
281
|
* @param options - Options for cache behavior.
|
|
209
|
-
* @returns The user region
|
|
282
|
+
* @returns The user region object.
|
|
210
283
|
*/
|
|
211
284
|
async updateUserRegion(options) {
|
|
285
|
+
// If a userRegion already exists and forceRefresh is not requested,
|
|
286
|
+
// return it immediately without fetching geolocation.
|
|
287
|
+
// This ensures that once a region is set (either via geolocation or manual selection),
|
|
288
|
+
// it will not be overwritten by subsequent geolocation fetches.
|
|
289
|
+
if (this.state.userRegion && !options?.forceRefresh) {
|
|
290
|
+
return this.state.userRegion;
|
|
291
|
+
}
|
|
292
|
+
// When forceRefresh is true, clear the existing region and region-dependent state before fetching
|
|
293
|
+
if (options?.forceRefresh) {
|
|
294
|
+
this.update((state) => {
|
|
295
|
+
state.userRegion = null;
|
|
296
|
+
state.tokens = null;
|
|
297
|
+
state.providers = [];
|
|
298
|
+
state.paymentMethods = [];
|
|
299
|
+
state.selectedPaymentMethod = null;
|
|
300
|
+
});
|
|
301
|
+
}
|
|
212
302
|
const cacheKey = (0, RequestCache_1.createCacheKey)('updateUserRegion', []);
|
|
213
|
-
const
|
|
303
|
+
const regionCode = await this.executeRequest(cacheKey, async () => {
|
|
214
304
|
const result = await this.messenger.call('RampsService:getGeolocation');
|
|
215
305
|
return result;
|
|
216
306
|
}, options);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
307
|
+
if (!regionCode) {
|
|
308
|
+
this.update((state) => {
|
|
309
|
+
state.userRegion = null;
|
|
310
|
+
state.tokens = null;
|
|
311
|
+
state.providers = [];
|
|
312
|
+
state.paymentMethods = [];
|
|
313
|
+
state.selectedPaymentMethod = null;
|
|
314
|
+
});
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
const normalizedRegion = regionCode.toLowerCase().trim();
|
|
318
|
+
try {
|
|
319
|
+
const countries = await this.getCountries('buy', options);
|
|
320
|
+
const userRegion = findRegionFromCode(normalizedRegion, countries);
|
|
321
|
+
if (userRegion) {
|
|
229
322
|
this.update((state) => {
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
323
|
+
const regionChanged = state.userRegion?.regionCode !== userRegion.regionCode;
|
|
324
|
+
state.userRegion = userRegion;
|
|
325
|
+
// Clear region-dependent state when region changes
|
|
326
|
+
if (regionChanged) {
|
|
233
327
|
state.tokens = null;
|
|
328
|
+
state.providers = [];
|
|
329
|
+
state.paymentMethods = [];
|
|
330
|
+
state.selectedPaymentMethod = null;
|
|
234
331
|
}
|
|
235
332
|
});
|
|
333
|
+
// Fetch providers for the new region
|
|
334
|
+
if (userRegion.regionCode) {
|
|
335
|
+
try {
|
|
336
|
+
await this.getProviders(userRegion.regionCode, options);
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
// Provider fetch failed - error state will be available via selectors
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return userRegion;
|
|
236
343
|
}
|
|
344
|
+
// Region not found in countries data
|
|
345
|
+
this.update((state) => {
|
|
346
|
+
state.userRegion = null;
|
|
347
|
+
state.tokens = null;
|
|
348
|
+
state.providers = [];
|
|
349
|
+
state.paymentMethods = [];
|
|
350
|
+
state.selectedPaymentMethod = null;
|
|
351
|
+
});
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
// If countries fetch fails, we can't create a valid UserRegion
|
|
356
|
+
// Return null to indicate we don't have valid country data
|
|
357
|
+
this.update((state) => {
|
|
358
|
+
state.userRegion = null;
|
|
359
|
+
state.tokens = null;
|
|
360
|
+
state.providers = [];
|
|
361
|
+
state.paymentMethods = [];
|
|
362
|
+
state.selectedPaymentMethod = null;
|
|
363
|
+
});
|
|
364
|
+
return null;
|
|
237
365
|
}
|
|
238
|
-
return normalizedRegion;
|
|
239
366
|
}
|
|
240
367
|
/**
|
|
241
368
|
* Sets the user's region manually (without fetching geolocation).
|
|
242
369
|
* This allows users to override the detected region.
|
|
243
370
|
*
|
|
244
371
|
* @param region - The region code to set (e.g., "US-CA").
|
|
245
|
-
* @param options - Options for cache behavior
|
|
246
|
-
* @returns The
|
|
372
|
+
* @param options - Options for cache behavior.
|
|
373
|
+
* @returns The user region object.
|
|
247
374
|
*/
|
|
248
375
|
async setUserRegion(region, options) {
|
|
249
376
|
const normalizedRegion = region.toLowerCase().trim();
|
|
250
|
-
this.update((state) => {
|
|
251
|
-
state.userRegion = normalizedRegion;
|
|
252
|
-
state.tokens = null;
|
|
253
|
-
});
|
|
254
377
|
try {
|
|
255
|
-
|
|
378
|
+
const countries = await this.getCountries('buy', options);
|
|
379
|
+
const userRegion = findRegionFromCode(normalizedRegion, countries);
|
|
380
|
+
if (userRegion) {
|
|
381
|
+
this.update((state) => {
|
|
382
|
+
state.userRegion = userRegion;
|
|
383
|
+
state.tokens = null;
|
|
384
|
+
state.providers = [];
|
|
385
|
+
state.paymentMethods = [];
|
|
386
|
+
state.selectedPaymentMethod = null;
|
|
387
|
+
});
|
|
388
|
+
// Fetch providers for the new region
|
|
389
|
+
try {
|
|
390
|
+
await this.getProviders(userRegion.regionCode, options);
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
// Provider fetch failed - error state will be available via selectors
|
|
394
|
+
}
|
|
395
|
+
return userRegion;
|
|
396
|
+
}
|
|
397
|
+
// Region not found in countries data
|
|
398
|
+
this.update((state) => {
|
|
399
|
+
state.userRegion = null;
|
|
400
|
+
state.tokens = null;
|
|
401
|
+
state.providers = [];
|
|
402
|
+
state.paymentMethods = [];
|
|
403
|
+
state.selectedPaymentMethod = null;
|
|
404
|
+
});
|
|
405
|
+
throw new Error(`Region "${normalizedRegion}" not found in countries data. Cannot set user region without valid country information.`);
|
|
256
406
|
}
|
|
257
407
|
catch (error) {
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
408
|
+
// If the error is "not found", re-throw it
|
|
409
|
+
// Otherwise, it's from countries fetch failure
|
|
410
|
+
if (error instanceof Error && error.message.includes('not found')) {
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
// Countries fetch failed
|
|
263
414
|
this.update((state) => {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
415
|
+
state.userRegion = null;
|
|
416
|
+
state.tokens = null;
|
|
417
|
+
state.providers = [];
|
|
418
|
+
state.paymentMethods = [];
|
|
419
|
+
state.selectedPaymentMethod = null;
|
|
269
420
|
});
|
|
270
|
-
throw
|
|
421
|
+
throw new Error('Failed to fetch countries data. Cannot set user region without valid country information.');
|
|
271
422
|
}
|
|
272
423
|
}
|
|
424
|
+
/**
|
|
425
|
+
* Sets the user's preferred provider.
|
|
426
|
+
* This allows users to set their preferred ramp provider.
|
|
427
|
+
*
|
|
428
|
+
* @param provider - The provider object to set.
|
|
429
|
+
*/
|
|
430
|
+
setPreferredProvider(provider) {
|
|
431
|
+
this.update((state) => {
|
|
432
|
+
state.preferredProvider = provider;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
273
435
|
/**
|
|
274
436
|
* Initializes the controller by fetching the user's region from geolocation.
|
|
275
437
|
* This should be called once at app startup to set up the initial region.
|
|
276
|
-
* After the region is set
|
|
277
|
-
*
|
|
438
|
+
* After the region is set, tokens are fetched and saved to state.
|
|
439
|
+
*
|
|
440
|
+
* If a userRegion already exists (from persistence or manual selection),
|
|
441
|
+
* this method will skip geolocation fetch and only fetch tokens if needed.
|
|
278
442
|
*
|
|
279
443
|
* @param options - Options for cache behavior.
|
|
280
444
|
* @returns Promise that resolves when initialization is complete.
|
|
@@ -286,40 +450,25 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
286
450
|
});
|
|
287
451
|
if (userRegion) {
|
|
288
452
|
try {
|
|
289
|
-
await this.getTokens(userRegion, 'buy', options);
|
|
453
|
+
await this.getTokens(userRegion.regionCode, 'buy', options);
|
|
290
454
|
}
|
|
291
455
|
catch {
|
|
292
456
|
// Token fetch failed - error state will be available via selectors
|
|
293
457
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Updates the eligibility information for a given region.
|
|
298
|
-
*
|
|
299
|
-
* @param isoCode - The ISO code for the region (e.g., "us", "fr", "us-ny").
|
|
300
|
-
* @param options - Options for cache behavior.
|
|
301
|
-
* @returns The eligibility information.
|
|
302
|
-
*/
|
|
303
|
-
async updateEligibility(isoCode, options) {
|
|
304
|
-
const normalizedIsoCode = isoCode.toLowerCase().trim();
|
|
305
|
-
const cacheKey = (0, RequestCache_1.createCacheKey)('updateEligibility', [normalizedIsoCode]);
|
|
306
|
-
const eligibility = await this.executeRequest(cacheKey, async () => {
|
|
307
|
-
return this.messenger.call('RampsService:getEligibility', normalizedIsoCode);
|
|
308
|
-
}, options);
|
|
309
|
-
this.update((state) => {
|
|
310
|
-
const userRegion = state.userRegion?.toLowerCase().trim();
|
|
311
|
-
if (userRegion === undefined || userRegion === normalizedIsoCode) {
|
|
312
|
-
state.eligibility = eligibility;
|
|
458
|
+
try {
|
|
459
|
+
await this.getProviders(userRegion.regionCode, options);
|
|
313
460
|
}
|
|
314
|
-
|
|
315
|
-
|
|
461
|
+
catch {
|
|
462
|
+
// Provider fetch failed - error state will be available via selectors
|
|
463
|
+
}
|
|
464
|
+
}
|
|
316
465
|
}
|
|
317
466
|
/**
|
|
318
467
|
* Fetches the list of supported countries for a given ramp action.
|
|
319
468
|
*
|
|
320
469
|
* @param action - The ramp action type ('buy' or 'sell').
|
|
321
470
|
* @param options - Options for cache behavior.
|
|
322
|
-
* @returns An array of countries
|
|
471
|
+
* @returns An array of countries.
|
|
323
472
|
*/
|
|
324
473
|
async getCountries(action = 'buy', options) {
|
|
325
474
|
const cacheKey = (0, RequestCache_1.createCacheKey)('getCountries', [action]);
|
|
@@ -333,27 +482,210 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
333
482
|
*
|
|
334
483
|
* @param region - The region code (e.g., "us", "fr", "us-ny"). If not provided, uses the user's region from controller state.
|
|
335
484
|
* @param action - The ramp action type ('buy' or 'sell').
|
|
336
|
-
* @param options - Options for cache behavior.
|
|
485
|
+
* @param options - Options for cache behavior and query filters.
|
|
486
|
+
* @param options.provider - Provider ID(s) to filter by.
|
|
337
487
|
* @returns The tokens response containing topTokens and allTokens.
|
|
338
488
|
*/
|
|
339
489
|
async getTokens(region, action = 'buy', options) {
|
|
340
|
-
const regionToUse = region ?? this.state.userRegion;
|
|
490
|
+
const regionToUse = region ?? this.state.userRegion?.regionCode;
|
|
341
491
|
if (!regionToUse) {
|
|
342
492
|
throw new Error('Region is required. Either provide a region parameter or ensure userRegion is set in controller state.');
|
|
343
493
|
}
|
|
344
494
|
const normalizedRegion = regionToUse.toLowerCase().trim();
|
|
345
|
-
const cacheKey = (0, RequestCache_1.createCacheKey)('getTokens', [
|
|
495
|
+
const cacheKey = (0, RequestCache_1.createCacheKey)('getTokens', [
|
|
496
|
+
normalizedRegion,
|
|
497
|
+
action,
|
|
498
|
+
options?.provider,
|
|
499
|
+
]);
|
|
346
500
|
const tokens = await this.executeRequest(cacheKey, async () => {
|
|
347
|
-
return this.messenger.call('RampsService:getTokens', normalizedRegion, action
|
|
501
|
+
return this.messenger.call('RampsService:getTokens', normalizedRegion, action, {
|
|
502
|
+
provider: options?.provider,
|
|
503
|
+
});
|
|
348
504
|
}, options);
|
|
349
505
|
this.update((state) => {
|
|
350
|
-
const
|
|
351
|
-
if (
|
|
506
|
+
const userRegionCode = state.userRegion?.regionCode;
|
|
507
|
+
if (userRegionCode === undefined || userRegionCode === normalizedRegion) {
|
|
352
508
|
state.tokens = tokens;
|
|
353
509
|
}
|
|
354
510
|
});
|
|
355
511
|
return tokens;
|
|
356
512
|
}
|
|
513
|
+
/**
|
|
514
|
+
* Fetches the list of providers for a given region.
|
|
515
|
+
* The providers are saved in the controller state once fetched.
|
|
516
|
+
*
|
|
517
|
+
* @param region - The region code (e.g., "us", "fr", "us-ny"). If not provided, uses the user's region from controller state.
|
|
518
|
+
* @param options - Options for cache behavior and query filters.
|
|
519
|
+
* @param options.provider - Provider ID(s) to filter by.
|
|
520
|
+
* @param options.crypto - Crypto currency ID(s) to filter by.
|
|
521
|
+
* @param options.fiat - Fiat currency ID(s) to filter by.
|
|
522
|
+
* @param options.payments - Payment method ID(s) to filter by.
|
|
523
|
+
* @returns The providers response containing providers array.
|
|
524
|
+
*/
|
|
525
|
+
async getProviders(region, options) {
|
|
526
|
+
const regionToUse = region ?? this.state.userRegion?.regionCode;
|
|
527
|
+
if (!regionToUse) {
|
|
528
|
+
throw new Error('Region is required. Either provide a region parameter or ensure userRegion is set in controller state.');
|
|
529
|
+
}
|
|
530
|
+
const normalizedRegion = regionToUse.toLowerCase().trim();
|
|
531
|
+
const cacheKey = (0, RequestCache_1.createCacheKey)('getProviders', [
|
|
532
|
+
normalizedRegion,
|
|
533
|
+
options?.provider,
|
|
534
|
+
options?.crypto,
|
|
535
|
+
options?.fiat,
|
|
536
|
+
options?.payments,
|
|
537
|
+
]);
|
|
538
|
+
const { providers } = await this.executeRequest(cacheKey, async () => {
|
|
539
|
+
return this.messenger.call('RampsService:getProviders', normalizedRegion, {
|
|
540
|
+
provider: options?.provider,
|
|
541
|
+
crypto: options?.crypto,
|
|
542
|
+
fiat: options?.fiat,
|
|
543
|
+
payments: options?.payments,
|
|
544
|
+
});
|
|
545
|
+
}, options);
|
|
546
|
+
this.update((state) => {
|
|
547
|
+
const userRegionCode = state.userRegion?.regionCode;
|
|
548
|
+
if (userRegionCode === undefined || userRegionCode === normalizedRegion) {
|
|
549
|
+
state.providers = providers;
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
return { providers };
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Fetches the list of payment methods for a given context.
|
|
556
|
+
* The payment methods are saved in the controller state once fetched.
|
|
557
|
+
*
|
|
558
|
+
* @param options - Query parameters for filtering payment methods.
|
|
559
|
+
* @param options.region - User's region code. If not provided, uses the user's region from controller state.
|
|
560
|
+
* @param options.fiat - Fiat currency code (e.g., "usd"). If not provided, uses the user's region currency.
|
|
561
|
+
* @param options.assetId - CAIP-19 cryptocurrency identifier.
|
|
562
|
+
* @param options.provider - Provider ID path.
|
|
563
|
+
* @param options.forceRefresh - Whether to bypass cache.
|
|
564
|
+
* @param options.ttl - Custom TTL for this request.
|
|
565
|
+
* @returns The payment methods response containing payments array.
|
|
566
|
+
*/
|
|
567
|
+
async getPaymentMethods(options) {
|
|
568
|
+
const regionToUse = options.region ?? this.state.userRegion?.regionCode;
|
|
569
|
+
const fiatToUse = options.fiat ?? this.state.userRegion?.country?.currency;
|
|
570
|
+
if (!regionToUse) {
|
|
571
|
+
throw new Error('Region is required. Either provide a region parameter or ensure userRegion is set in controller state.');
|
|
572
|
+
}
|
|
573
|
+
if (!fiatToUse) {
|
|
574
|
+
throw new Error('Fiat currency is required. Either provide a fiat parameter or ensure userRegion is set in controller state.');
|
|
575
|
+
}
|
|
576
|
+
const normalizedRegion = regionToUse.toLowerCase().trim();
|
|
577
|
+
const normalizedFiat = fiatToUse.toLowerCase().trim();
|
|
578
|
+
const cacheKey = (0, RequestCache_1.createCacheKey)('getPaymentMethods', [
|
|
579
|
+
normalizedRegion,
|
|
580
|
+
normalizedFiat,
|
|
581
|
+
options.assetId,
|
|
582
|
+
options.provider,
|
|
583
|
+
]);
|
|
584
|
+
const response = await this.executeRequest(cacheKey, async () => {
|
|
585
|
+
return this.messenger.call('RampsService:getPaymentMethods', {
|
|
586
|
+
region: normalizedRegion,
|
|
587
|
+
fiat: normalizedFiat,
|
|
588
|
+
assetId: options.assetId,
|
|
589
|
+
provider: options.provider,
|
|
590
|
+
});
|
|
591
|
+
}, { forceRefresh: options.forceRefresh, ttl: options.ttl });
|
|
592
|
+
this.update((state) => {
|
|
593
|
+
state.paymentMethods = response.payments;
|
|
594
|
+
// Only clear selected payment method if it's no longer in the new list
|
|
595
|
+
// This preserves the selection when cached data is returned (same context)
|
|
596
|
+
if (state.selectedPaymentMethod &&
|
|
597
|
+
!response.payments.some((pm) => pm.id === state.selectedPaymentMethod?.id)) {
|
|
598
|
+
state.selectedPaymentMethod = null;
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
return response;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Sets the user's selected payment method.
|
|
605
|
+
*
|
|
606
|
+
* @param paymentMethod - The payment method to select, or null to clear.
|
|
607
|
+
*/
|
|
608
|
+
setSelectedPaymentMethod(paymentMethod) {
|
|
609
|
+
this.update((state) => {
|
|
610
|
+
state.selectedPaymentMethod = paymentMethod;
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
// ============================================================
|
|
614
|
+
// Sync Trigger Methods
|
|
615
|
+
// These fire-and-forget methods are for use in React effects.
|
|
616
|
+
// Errors are stored in state and available via selectors.
|
|
617
|
+
// ============================================================
|
|
618
|
+
/**
|
|
619
|
+
* Triggers a user region update without throwing.
|
|
620
|
+
*
|
|
621
|
+
* @param options - Options for cache behavior.
|
|
622
|
+
*/
|
|
623
|
+
triggerUpdateUserRegion(options) {
|
|
624
|
+
this.updateUserRegion(options).catch(() => {
|
|
625
|
+
// Error stored in state
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Triggers setting the user region without throwing.
|
|
630
|
+
*
|
|
631
|
+
* @param region - The region code to set (e.g., "US-CA").
|
|
632
|
+
* @param options - Options for cache behavior.
|
|
633
|
+
*/
|
|
634
|
+
triggerSetUserRegion(region, options) {
|
|
635
|
+
this.setUserRegion(region, options).catch(() => {
|
|
636
|
+
// Error stored in state
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Triggers fetching countries without throwing.
|
|
641
|
+
*
|
|
642
|
+
* @param action - The ramp action type ('buy' or 'sell').
|
|
643
|
+
* @param options - Options for cache behavior.
|
|
644
|
+
*/
|
|
645
|
+
triggerGetCountries(action = 'buy', options) {
|
|
646
|
+
this.getCountries(action, options).catch(() => {
|
|
647
|
+
// Error stored in state
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Triggers fetching tokens without throwing.
|
|
652
|
+
*
|
|
653
|
+
* @param region - The region code. If not provided, uses userRegion from state.
|
|
654
|
+
* @param action - The ramp action type ('buy' or 'sell').
|
|
655
|
+
* @param options - Options for cache behavior.
|
|
656
|
+
*/
|
|
657
|
+
triggerGetTokens(region, action = 'buy', options) {
|
|
658
|
+
this.getTokens(region, action, options).catch(() => {
|
|
659
|
+
// Error stored in state
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Triggers fetching providers without throwing.
|
|
664
|
+
*
|
|
665
|
+
* @param region - The region code. If not provided, uses userRegion from state.
|
|
666
|
+
* @param options - Options for cache behavior and query filters.
|
|
667
|
+
*/
|
|
668
|
+
triggerGetProviders(region, options) {
|
|
669
|
+
this.getProviders(region, options).catch(() => {
|
|
670
|
+
// Error stored in state
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Triggers fetching payment methods without throwing.
|
|
675
|
+
*
|
|
676
|
+
* @param options - Query parameters for filtering payment methods.
|
|
677
|
+
* @param options.region - User's region code. If not provided, uses userRegion from state.
|
|
678
|
+
* @param options.fiat - Fiat currency code. If not provided, uses userRegion currency.
|
|
679
|
+
* @param options.assetId - CAIP-19 cryptocurrency identifier.
|
|
680
|
+
* @param options.provider - Provider ID path.
|
|
681
|
+
* @param options.forceRefresh - Whether to bypass cache.
|
|
682
|
+
* @param options.ttl - Custom TTL for this request.
|
|
683
|
+
*/
|
|
684
|
+
triggerGetPaymentMethods(options) {
|
|
685
|
+
this.getPaymentMethods(options).catch(() => {
|
|
686
|
+
// Error stored in state
|
|
687
|
+
});
|
|
688
|
+
}
|
|
357
689
|
}
|
|
358
690
|
exports.RampsController = RampsController;
|
|
359
691
|
_RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheMaxSize = new WeakMap(), _RampsController_pendingRequests = new WeakMap(), _RampsController_instances = new WeakSet(), _RampsController_removeRequestState = function _RampsController_removeRequestState(cacheKey) {
|
|
@@ -363,20 +695,32 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
|
|
|
363
695
|
});
|
|
364
696
|
}, _RampsController_updateRequestState = function _RampsController_updateRequestState(cacheKey, requestState) {
|
|
365
697
|
const maxSize = __classPrivateFieldGet(this, _RampsController_requestCacheMaxSize, "f");
|
|
698
|
+
const ttl = __classPrivateFieldGet(this, _RampsController_requestCacheTTL, "f");
|
|
366
699
|
this.update((state) => {
|
|
367
700
|
const requests = state.requests;
|
|
368
701
|
requests[cacheKey] = requestState;
|
|
369
|
-
// Evict
|
|
702
|
+
// Evict expired entries based on TTL
|
|
703
|
+
// Only evict SUCCESS states that have exceeded their TTL
|
|
370
704
|
const keys = Object.keys(requests);
|
|
371
|
-
|
|
705
|
+
for (const key of keys) {
|
|
706
|
+
const entry = requests[key];
|
|
707
|
+
if (entry &&
|
|
708
|
+
entry.status === RequestCache_1.RequestStatus.SUCCESS &&
|
|
709
|
+
(0, RequestCache_1.isCacheExpired)(entry, ttl)) {
|
|
710
|
+
delete requests[key];
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
// Evict oldest entries if cache still exceeds max size
|
|
714
|
+
const remainingKeys = Object.keys(requests);
|
|
715
|
+
if (remainingKeys.length > maxSize) {
|
|
372
716
|
// Sort by timestamp (oldest first)
|
|
373
|
-
const sortedKeys =
|
|
717
|
+
const sortedKeys = remainingKeys.sort((a, b) => {
|
|
374
718
|
const aTime = requests[a]?.timestamp ?? 0;
|
|
375
719
|
const bTime = requests[b]?.timestamp ?? 0;
|
|
376
720
|
return aTime - bTime;
|
|
377
721
|
});
|
|
378
722
|
// Remove oldest entries until we're under the limit
|
|
379
|
-
const entriesToRemove =
|
|
723
|
+
const entriesToRemove = remainingKeys.length - maxSize;
|
|
380
724
|
for (let i = 0; i < entriesToRemove; i++) {
|
|
381
725
|
const keyToRemove = sortedKeys[i];
|
|
382
726
|
if (keyToRemove) {
|