@reown/appkit-core-react-native 0.0.0-chore-update-valtio-20250611193623 → 0.0.0-chore-canary-20250722140131

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.
Files changed (132) hide show
  1. package/lib/commonjs/controllers/AccountController.js.map +1 -1
  2. package/lib/commonjs/controllers/ApiController.js.map +1 -1
  3. package/lib/commonjs/controllers/AssetController.js.map +1 -1
  4. package/lib/commonjs/controllers/BlockchainApiController.js +95 -0
  5. package/lib/commonjs/controllers/BlockchainApiController.js.map +1 -1
  6. package/lib/commonjs/controllers/ConnectionController.js.map +1 -1
  7. package/lib/commonjs/controllers/ConnectorController.js.map +1 -1
  8. package/lib/commonjs/controllers/EnsController.js +4 -4
  9. package/lib/commonjs/controllers/EnsController.js.map +1 -1
  10. package/lib/commonjs/controllers/EventsController.js +4 -4
  11. package/lib/commonjs/controllers/EventsController.js.map +1 -1
  12. package/lib/commonjs/controllers/ModalController.js.map +1 -1
  13. package/lib/commonjs/controllers/NetworkController.js.map +1 -1
  14. package/lib/commonjs/controllers/OnRampController.js +469 -0
  15. package/lib/commonjs/controllers/OnRampController.js.map +1 -0
  16. package/lib/commonjs/controllers/OptionsController.js +3 -0
  17. package/lib/commonjs/controllers/OptionsController.js.map +1 -1
  18. package/lib/commonjs/controllers/PublicStateController.js.map +1 -1
  19. package/lib/commonjs/controllers/RouterController.js +3 -2
  20. package/lib/commonjs/controllers/RouterController.js.map +1 -1
  21. package/lib/commonjs/controllers/SendController.js +5 -5
  22. package/lib/commonjs/controllers/SendController.js.map +1 -1
  23. package/lib/commonjs/controllers/SnackController.js.map +1 -1
  24. package/lib/commonjs/controllers/SwapController.js.map +1 -1
  25. package/lib/commonjs/controllers/ThemeController.js.map +1 -1
  26. package/lib/commonjs/controllers/TransactionsController.js +3 -3
  27. package/lib/commonjs/controllers/TransactionsController.js.map +1 -1
  28. package/lib/commonjs/controllers/WebviewController.js.map +1 -1
  29. package/lib/commonjs/index.js +7 -0
  30. package/lib/commonjs/index.js.map +1 -1
  31. package/lib/commonjs/utils/ApiUtil.js.map +1 -1
  32. package/lib/commonjs/utils/AssetUtil.js.map +1 -1
  33. package/lib/commonjs/utils/ConnectionUtil.js.map +1 -1
  34. package/lib/commonjs/utils/ConstantsUtil.js +69 -5
  35. package/lib/commonjs/utils/ConstantsUtil.js.map +1 -1
  36. package/lib/commonjs/utils/CoreHelperUtil.js +27 -0
  37. package/lib/commonjs/utils/CoreHelperUtil.js.map +1 -1
  38. package/lib/commonjs/utils/EventUtil.js.map +1 -1
  39. package/lib/commonjs/utils/FetchUtil.js +43 -13
  40. package/lib/commonjs/utils/FetchUtil.js.map +1 -1
  41. package/lib/commonjs/utils/NetworkUtil.js.map +1 -1
  42. package/lib/commonjs/utils/RouterUtil.js.map +1 -1
  43. package/lib/commonjs/utils/StorageUtil.js +185 -1
  44. package/lib/commonjs/utils/StorageUtil.js.map +1 -1
  45. package/lib/commonjs/utils/SwapApiUtil.js.map +1 -1
  46. package/lib/commonjs/utils/SwapCalculationUtil.js.map +1 -1
  47. package/lib/commonjs/utils/TypeUtil.js.map +1 -1
  48. package/lib/module/controllers/AccountController.js.map +1 -1
  49. package/lib/module/controllers/ApiController.js.map +1 -1
  50. package/lib/module/controllers/AssetController.js.map +1 -1
  51. package/lib/module/controllers/BlockchainApiController.js +95 -0
  52. package/lib/module/controllers/BlockchainApiController.js.map +1 -1
  53. package/lib/module/controllers/ConnectionController.js.map +1 -1
  54. package/lib/module/controllers/ConnectorController.js.map +1 -1
  55. package/lib/module/controllers/EnsController.js +2 -2
  56. package/lib/module/controllers/EnsController.js.map +1 -1
  57. package/lib/module/controllers/EventsController.js +1 -1
  58. package/lib/module/controllers/EventsController.js.map +1 -1
  59. package/lib/module/controllers/ModalController.js.map +1 -1
  60. package/lib/module/controllers/NetworkController.js.map +1 -1
  61. package/lib/module/controllers/OnRampController.js +464 -0
  62. package/lib/module/controllers/OnRampController.js.map +1 -0
  63. package/lib/module/controllers/OptionsController.js +3 -0
  64. package/lib/module/controllers/OptionsController.js.map +1 -1
  65. package/lib/module/controllers/PublicStateController.js.map +1 -1
  66. package/lib/module/controllers/RouterController.js +3 -2
  67. package/lib/module/controllers/RouterController.js.map +1 -1
  68. package/lib/module/controllers/SendController.js +2 -2
  69. package/lib/module/controllers/SendController.js.map +1 -1
  70. package/lib/module/controllers/SnackController.js.map +1 -1
  71. package/lib/module/controllers/SwapController.js.map +1 -1
  72. package/lib/module/controllers/ThemeController.js.map +1 -1
  73. package/lib/module/controllers/TransactionsController.js +1 -1
  74. package/lib/module/controllers/TransactionsController.js.map +1 -1
  75. package/lib/module/controllers/WebviewController.js.map +1 -1
  76. package/lib/module/index.js +1 -0
  77. package/lib/module/index.js.map +1 -1
  78. package/lib/module/utils/ApiUtil.js.map +1 -1
  79. package/lib/module/utils/AssetUtil.js.map +1 -1
  80. package/lib/module/utils/ConnectionUtil.js.map +1 -1
  81. package/lib/module/utils/ConstantsUtil.js +68 -4
  82. package/lib/module/utils/ConstantsUtil.js.map +1 -1
  83. package/lib/module/utils/CoreHelperUtil.js +26 -0
  84. package/lib/module/utils/CoreHelperUtil.js.map +1 -1
  85. package/lib/module/utils/EventUtil.js.map +1 -1
  86. package/lib/module/utils/FetchUtil.js +43 -13
  87. package/lib/module/utils/FetchUtil.js.map +1 -1
  88. package/lib/module/utils/NetworkUtil.js.map +1 -1
  89. package/lib/module/utils/RouterUtil.js.map +1 -1
  90. package/lib/module/utils/StorageUtil.js +186 -1
  91. package/lib/module/utils/StorageUtil.js.map +1 -1
  92. package/lib/module/utils/SwapApiUtil.js.map +1 -1
  93. package/lib/module/utils/SwapCalculationUtil.js.map +1 -1
  94. package/lib/module/utils/TypeUtil.js.map +1 -1
  95. package/lib/typescript/controllers/BlockchainApiController.d.ts +14 -1
  96. package/lib/typescript/controllers/BlockchainApiController.d.ts.map +1 -1
  97. package/lib/typescript/controllers/ModalController.d.ts +1 -1
  98. package/lib/typescript/controllers/ModalController.d.ts.map +1 -1
  99. package/lib/typescript/controllers/OnRampController.d.ts +56 -0
  100. package/lib/typescript/controllers/OnRampController.d.ts.map +1 -0
  101. package/lib/typescript/controllers/OptionsController.d.ts +2 -0
  102. package/lib/typescript/controllers/OptionsController.d.ts.map +1 -1
  103. package/lib/typescript/controllers/RouterController.d.ts +4 -3
  104. package/lib/typescript/controllers/RouterController.d.ts.map +1 -1
  105. package/lib/typescript/index.d.ts +1 -0
  106. package/lib/typescript/index.d.ts.map +1 -1
  107. package/lib/typescript/utils/ConstantsUtil.d.ts +55 -0
  108. package/lib/typescript/utils/ConstantsUtil.d.ts.map +1 -1
  109. package/lib/typescript/utils/CoreHelperUtil.d.ts +3 -0
  110. package/lib/typescript/utils/CoreHelperUtil.d.ts.map +1 -1
  111. package/lib/typescript/utils/FetchUtil.d.ts +4 -4
  112. package/lib/typescript/utils/FetchUtil.d.ts.map +1 -1
  113. package/lib/typescript/utils/StorageUtil.d.ts +16 -2
  114. package/lib/typescript/utils/StorageUtil.d.ts.map +1 -1
  115. package/lib/typescript/utils/TypeUtil.d.ts +167 -0
  116. package/lib/typescript/utils/TypeUtil.d.ts.map +1 -1
  117. package/package.json +4 -3
  118. package/src/controllers/BlockchainApiController.ts +116 -1
  119. package/src/controllers/EnsController.ts +2 -2
  120. package/src/controllers/EventsController.ts +1 -1
  121. package/src/controllers/ModalController.ts +1 -2
  122. package/src/controllers/OnRampController.ts +650 -0
  123. package/src/controllers/OptionsController.ts +5 -0
  124. package/src/controllers/RouterController.ts +16 -3
  125. package/src/controllers/SendController.ts +2 -2
  126. package/src/controllers/TransactionsController.ts +1 -1
  127. package/src/index.ts +1 -0
  128. package/src/utils/ConstantsUtil.ts +49 -4
  129. package/src/utils/CoreHelperUtil.ts +30 -0
  130. package/src/utils/FetchUtil.ts +45 -17
  131. package/src/utils/StorageUtil.ts +225 -3
  132. package/src/utils/TypeUtil.ts +188 -0
@@ -0,0 +1,650 @@
1
+ import { subscribeKey as subKey } from 'valtio/vanilla/utils';
2
+ import { proxy, subscribe as sub } from 'valtio/vanilla';
3
+ import type {
4
+ OnRampPaymentMethod,
5
+ OnRampCountry,
6
+ OnRampFiatCurrency,
7
+ OnRampQuote,
8
+ OnRampFiatLimit,
9
+ OnRampCryptoCurrency,
10
+ OnRampServiceProvider,
11
+ OnRampError,
12
+ OnRampErrorTypeValues,
13
+ OnRampCountryDefaults
14
+ } from '../utils/TypeUtil';
15
+
16
+ import { CoreHelperUtil } from '../utils/CoreHelperUtil';
17
+ import { NetworkController } from './NetworkController';
18
+ import { AccountController } from './AccountController';
19
+ import { OptionsController } from './OptionsController';
20
+ import { ConstantsUtil, OnRampErrorType } from '../utils/ConstantsUtil';
21
+ import { StorageUtil } from '../utils/StorageUtil';
22
+ import { SnackController } from './SnackController';
23
+ import { EventsController } from './EventsController';
24
+ import { BlockchainApiController } from './BlockchainApiController';
25
+
26
+ // -- Helpers ------------------------------------------- //
27
+
28
+ let quotesAbortController: AbortController | null = null;
29
+ const excludeProviders = ['BINANCECONNECT', 'COINBASEPAY'];
30
+
31
+ // -- Utils --------------------------------------------- //
32
+
33
+ const mapErrorMessage = (errorCode: string): OnRampError => {
34
+ const errorMap: Record<string, { type: OnRampErrorTypeValues; message: string }> = {
35
+ [OnRampErrorType.AMOUNT_TOO_LOW]: {
36
+ type: OnRampErrorType.AMOUNT_TOO_LOW,
37
+ message: 'The amount is too low'
38
+ },
39
+ [OnRampErrorType.AMOUNT_TOO_HIGH]: {
40
+ type: OnRampErrorType.AMOUNT_TOO_HIGH,
41
+ message: 'The amount is too high'
42
+ },
43
+ [OnRampErrorType.INVALID_AMOUNT]: {
44
+ type: OnRampErrorType.INVALID_AMOUNT,
45
+ message: 'Enter a valid amount'
46
+ },
47
+ [OnRampErrorType.INCOMPATIBLE_REQUEST]: {
48
+ type: OnRampErrorType.INCOMPATIBLE_REQUEST,
49
+ message: 'Enter a valid amount'
50
+ },
51
+ [OnRampErrorType.BAD_REQUEST]: {
52
+ type: OnRampErrorType.BAD_REQUEST,
53
+ message: 'Enter a valid amount'
54
+ },
55
+ [OnRampErrorType.NO_VALID_QUOTES]: {
56
+ type: OnRampErrorType.NO_VALID_QUOTES,
57
+ message: 'No quotes available'
58
+ }
59
+ };
60
+
61
+ return (
62
+ errorMap[errorCode] || {
63
+ type: OnRampErrorType.UNKNOWN,
64
+ message: 'Something went wrong. Please try again'
65
+ }
66
+ );
67
+ };
68
+
69
+ // -- Types --------------------------------------------- //
70
+ export interface OnRampControllerState {
71
+ countries: OnRampCountry[];
72
+ countriesDefaults?: OnRampCountryDefaults[];
73
+ selectedCountry?: OnRampCountry;
74
+ serviceProviders: OnRampServiceProvider[];
75
+ selectedServiceProvider?: OnRampServiceProvider;
76
+ paymentMethods: OnRampPaymentMethod[];
77
+ selectedPaymentMethod?: OnRampPaymentMethod;
78
+ purchaseCurrency?: OnRampCryptoCurrency;
79
+ purchaseCurrencies?: OnRampCryptoCurrency[];
80
+ paymentAmount?: number;
81
+ paymentCurrency?: OnRampFiatCurrency;
82
+ paymentCurrencies?: OnRampFiatCurrency[];
83
+ paymentCurrenciesLimits?: OnRampFiatLimit[];
84
+ quotes?: OnRampQuote[];
85
+ selectedQuote?: OnRampQuote;
86
+ widgetUrl?: string;
87
+ error?: OnRampError;
88
+ initialLoading?: boolean;
89
+ loading?: boolean;
90
+ quotesLoading: boolean;
91
+ }
92
+
93
+ type StateKey = keyof OnRampControllerState;
94
+
95
+ const defaultState = {
96
+ quotesLoading: false,
97
+ countries: [],
98
+ paymentMethods: [],
99
+ serviceProviders: [],
100
+ paymentAmount: undefined
101
+ };
102
+
103
+ // -- State --------------------------------------------- //
104
+ const state = proxy<OnRampControllerState>(defaultState);
105
+
106
+ // -- Controller ---------------------------------------- //
107
+ export const OnRampController = {
108
+ state,
109
+
110
+ subscribe(callback: (newState: OnRampControllerState) => void) {
111
+ return sub(state, () => callback(state));
112
+ },
113
+
114
+ subscribeKey<K extends StateKey>(key: K, callback: (value: OnRampControllerState[K]) => void) {
115
+ return subKey(state, key, callback);
116
+ },
117
+
118
+ async setSelectedCountry(country: OnRampCountry, updateCurrency = true) {
119
+ state.selectedCountry = country;
120
+ state.loading = true;
121
+
122
+ if (updateCurrency) {
123
+ const currencyCode =
124
+ state.countriesDefaults?.find(d => d.countryCode === country.countryCode)
125
+ ?.defaultCurrencyCode || 'USD';
126
+
127
+ const currency = state.paymentCurrencies?.find(c => c.currencyCode === currencyCode);
128
+
129
+ if (currency) {
130
+ this.setPaymentCurrency(currency);
131
+ }
132
+ }
133
+
134
+ await Promise.all([this.fetchPaymentMethods(), this.fetchCryptoCurrencies()]);
135
+ this.clearQuotes();
136
+
137
+ state.loading = false;
138
+
139
+ StorageUtil.setOnRampPreferredCountry(country);
140
+ },
141
+
142
+ setSelectedPaymentMethod(paymentMethod: OnRampPaymentMethod) {
143
+ state.selectedPaymentMethod = paymentMethod;
144
+ },
145
+
146
+ setPurchaseCurrency(currency: OnRampCryptoCurrency) {
147
+ state.purchaseCurrency = currency;
148
+
149
+ EventsController.sendEvent({
150
+ type: 'track',
151
+ event: 'SELECT_BUY_ASSET',
152
+ properties: {
153
+ asset: currency.currencyCode
154
+ }
155
+ });
156
+
157
+ this.clearQuotes();
158
+ },
159
+
160
+ setPaymentCurrency(currency: OnRampFiatCurrency, updateAmount = true) {
161
+ state.paymentCurrency = currency;
162
+
163
+ StorageUtil.setOnRampPreferredFiatCurrency(currency);
164
+
165
+ if (updateAmount) {
166
+ state.paymentAmount = undefined;
167
+ }
168
+
169
+ this.clearQuotes();
170
+ this.clearError();
171
+ },
172
+
173
+ setPaymentAmount(amount?: number | string) {
174
+ state.paymentAmount = amount ? Number(amount) : undefined;
175
+ },
176
+
177
+ setSelectedQuote(quote?: OnRampQuote) {
178
+ state.selectedQuote = quote;
179
+ },
180
+
181
+ updateSelectedPurchaseCurrency() {
182
+ let selectedCurrency;
183
+ if (NetworkController.state.caipNetwork?.id) {
184
+ const defaultCurrency =
185
+ ConstantsUtil.NETWORK_DEFAULT_CURRENCIES[
186
+ NetworkController.state.caipNetwork
187
+ ?.id as keyof typeof ConstantsUtil.NETWORK_DEFAULT_CURRENCIES
188
+ ];
189
+ selectedCurrency = state.purchaseCurrencies?.find(c => c.currencyCode === defaultCurrency);
190
+ }
191
+
192
+ state.purchaseCurrency = selectedCurrency ?? state.purchaseCurrencies?.[0] ?? undefined;
193
+ },
194
+
195
+ getServiceProviderImage(serviceProviderName?: string) {
196
+ if (!serviceProviderName) return undefined;
197
+
198
+ const provider = state.serviceProviders.find(p => p.serviceProvider === serviceProviderName);
199
+
200
+ return provider?.logos?.lightShort;
201
+ },
202
+
203
+ getCurrencyLimit(currency: OnRampFiatCurrency) {
204
+ return state.paymentCurrenciesLimits?.find(l => l.currencyCode === currency.currencyCode);
205
+ },
206
+
207
+ async fetchCountries() {
208
+ try {
209
+ let countries = await StorageUtil.getOnRampCountries();
210
+
211
+ if (!countries.length) {
212
+ countries = (await BlockchainApiController.fetchOnRampCountries()) ?? [];
213
+
214
+ if (countries.length) {
215
+ StorageUtil.setOnRampCountries(countries);
216
+ }
217
+ }
218
+
219
+ state.countries = countries;
220
+
221
+ const preferredCountry = await StorageUtil.getOnRampPreferredCountry();
222
+
223
+ if (preferredCountry) {
224
+ state.selectedCountry = preferredCountry;
225
+ } else {
226
+ const countryCode = CoreHelperUtil.getCountryFromTimezone();
227
+
228
+ state.selectedCountry =
229
+ countries.find(c => c.countryCode === countryCode) || countries[0] || undefined;
230
+ }
231
+ } catch (error) {
232
+ state.error = {
233
+ type: OnRampErrorType.FAILED_TO_LOAD_COUNTRIES,
234
+ message: 'Failed to load countries'
235
+ };
236
+ }
237
+ },
238
+
239
+ async fetchCountriesDefaults() {
240
+ try {
241
+ let countriesDefaults = await StorageUtil.getOnRampCountriesDefaults();
242
+
243
+ if (!countriesDefaults.length) {
244
+ countriesDefaults = (await BlockchainApiController.fetchOnRampCountriesDefaults()) ?? [];
245
+
246
+ if (countriesDefaults.length) {
247
+ StorageUtil.setOnRampCountriesDefaults(countriesDefaults);
248
+ }
249
+ }
250
+
251
+ state.countriesDefaults = countriesDefaults;
252
+ } catch (error) {
253
+ state.error = {
254
+ type: OnRampErrorType.FAILED_TO_LOAD_COUNTRIES,
255
+ message: 'Failed to load countries defaults'
256
+ };
257
+ }
258
+ },
259
+
260
+ async fetchServiceProviders() {
261
+ try {
262
+ let serviceProviders = await StorageUtil.getOnRampServiceProviders();
263
+
264
+ if (!serviceProviders.length) {
265
+ serviceProviders = (await BlockchainApiController.fetchOnRampServiceProviders()) ?? [];
266
+
267
+ if (serviceProviders.length) {
268
+ StorageUtil.setOnRampServiceProviders(serviceProviders);
269
+ }
270
+ }
271
+
272
+ state.serviceProviders = serviceProviders || [];
273
+ } catch (error) {
274
+ state.error = {
275
+ type: OnRampErrorType.FAILED_TO_LOAD_PROVIDERS,
276
+ message: 'Failed to load service providers'
277
+ };
278
+ }
279
+ },
280
+
281
+ async fetchPaymentMethods() {
282
+ try {
283
+ const paymentMethods = await BlockchainApiController.fetchOnRampPaymentMethods({
284
+ countries: state.selectedCountry?.countryCode
285
+ });
286
+
287
+ const defaultCountryPaymentMethods =
288
+ state.countriesDefaults?.find(d => d.countryCode === state.selectedCountry?.countryCode)
289
+ ?.defaultPaymentMethods || [];
290
+
291
+ state.paymentMethods =
292
+ paymentMethods?.sort((a, b) => {
293
+ const aIndex = defaultCountryPaymentMethods?.indexOf(a.paymentMethod);
294
+ const bIndex = defaultCountryPaymentMethods?.indexOf(b.paymentMethod);
295
+
296
+ if (aIndex === -1 && bIndex === -1) return 0;
297
+ if (aIndex === -1) return 1;
298
+ if (bIndex === -1) return -1;
299
+
300
+ return aIndex - bIndex;
301
+ }) || [];
302
+
303
+ state.selectedPaymentMethod = state.paymentMethods[0];
304
+ } catch (error) {
305
+ state.error = {
306
+ type: OnRampErrorType.FAILED_TO_LOAD_METHODS,
307
+ message: 'Failed to load payment methods'
308
+ };
309
+ state.paymentMethods = [];
310
+ state.selectedPaymentMethod = undefined;
311
+ }
312
+ },
313
+
314
+ async fetchCryptoCurrencies() {
315
+ try {
316
+ const cryptoCurrencies = await BlockchainApiController.fetchOnRampCryptoCurrencies({
317
+ countries: state.selectedCountry?.countryCode
318
+ });
319
+
320
+ state.purchaseCurrencies = cryptoCurrencies || [];
321
+
322
+ let selectedCurrency;
323
+ if (NetworkController.state.caipNetwork?.id) {
324
+ const defaultCurrency =
325
+ ConstantsUtil.NETWORK_DEFAULT_CURRENCIES[
326
+ NetworkController.state.caipNetwork
327
+ ?.id as keyof typeof ConstantsUtil.NETWORK_DEFAULT_CURRENCIES
328
+ ] || 'ETH';
329
+ selectedCurrency = state.purchaseCurrencies?.find(c => c.currencyCode === defaultCurrency);
330
+ }
331
+
332
+ state.purchaseCurrency = selectedCurrency || cryptoCurrencies?.[0] || undefined;
333
+ } catch (error) {
334
+ state.error = {
335
+ type: OnRampErrorType.FAILED_TO_LOAD_CURRENCIES,
336
+ message: 'Failed to load crypto currencies'
337
+ };
338
+ state.purchaseCurrencies = [];
339
+ state.purchaseCurrency = undefined;
340
+ }
341
+ },
342
+
343
+ async fetchFiatCurrencies() {
344
+ try {
345
+ let fiatCurrencies = await StorageUtil.getOnRampFiatCurrencies();
346
+ let currencyCode = 'USD';
347
+ const countryCode = state.selectedCountry?.countryCode;
348
+
349
+ if (!fiatCurrencies.length) {
350
+ fiatCurrencies = (await BlockchainApiController.fetchOnRampFiatCurrencies()) ?? [];
351
+
352
+ if (fiatCurrencies.length) {
353
+ StorageUtil.setOnRampFiatCurrencies(fiatCurrencies);
354
+ }
355
+ }
356
+
357
+ state.paymentCurrencies = fiatCurrencies || [];
358
+
359
+ if (countryCode) {
360
+ currencyCode =
361
+ state.countriesDefaults?.find(d => d.countryCode === countryCode)?.defaultCurrencyCode ||
362
+ 'USD';
363
+ }
364
+
365
+ const preferredCurrency = await StorageUtil.getOnRampPreferredFiatCurrency();
366
+
367
+ const defaultCurrency =
368
+ preferredCurrency ||
369
+ fiatCurrencies?.find(c => c.currencyCode === currencyCode) ||
370
+ fiatCurrencies?.[0] ||
371
+ undefined;
372
+
373
+ if (defaultCurrency) {
374
+ this.setPaymentCurrency(defaultCurrency);
375
+ }
376
+ } catch (error) {
377
+ state.error = {
378
+ type: OnRampErrorType.FAILED_TO_LOAD_CURRENCIES,
379
+ message: 'Failed to load fiat currencies'
380
+ };
381
+ state.paymentCurrencies = [];
382
+ state.paymentCurrency = undefined;
383
+ }
384
+ },
385
+
386
+ abortGetQuotes(clearState = true) {
387
+ if (quotesAbortController) {
388
+ quotesAbortController.abort();
389
+ quotesAbortController = null;
390
+ }
391
+
392
+ if (clearState) {
393
+ this.clearQuotes();
394
+ state.quotesLoading = false;
395
+ state.error = undefined;
396
+ }
397
+ },
398
+
399
+ getQuotesDebounced: CoreHelperUtil.debounce(function () {
400
+ OnRampController.getQuotes();
401
+ }, 500),
402
+
403
+ async getQuotes() {
404
+ if (!state.paymentAmount || state.paymentAmount <= 0) {
405
+ this.clearQuotes();
406
+
407
+ return;
408
+ }
409
+
410
+ state.quotesLoading = true;
411
+ state.selectedQuote = undefined;
412
+ state.selectedServiceProvider = undefined;
413
+ state.error = undefined;
414
+
415
+ this.abortGetQuotes(false);
416
+ quotesAbortController = new AbortController();
417
+ const currentSignal = quotesAbortController.signal;
418
+
419
+ try {
420
+ const body = {
421
+ countryCode: state.selectedCountry?.countryCode!,
422
+ destinationCurrencyCode: state.purchaseCurrency?.currencyCode!,
423
+ sourceAmount: state.paymentAmount,
424
+ sourceCurrencyCode: state.paymentCurrency?.currencyCode!,
425
+ walletAddress: AccountController.state.address!,
426
+ excludeProviders
427
+ };
428
+
429
+ const response = await BlockchainApiController.getOnRampQuotes(body, currentSignal);
430
+
431
+ if (!response || !response.length) {
432
+ throw { code: OnRampErrorType.NO_VALID_QUOTES };
433
+ }
434
+
435
+ const quotes = response.sort((a, b) => b.customerScore - a.customerScore);
436
+
437
+ state.quotes = quotes;
438
+
439
+ //Replace payment method if it's not in the quotes
440
+ const isValidPaymentMethod =
441
+ state.selectedPaymentMethod &&
442
+ quotes.some(
443
+ quote => quote.paymentMethodType === state.selectedPaymentMethod?.paymentMethod
444
+ );
445
+
446
+ if (!isValidPaymentMethod) {
447
+ const countryMethods =
448
+ state.countriesDefaults?.find(d => d.countryCode === state.selectedCountry?.countryCode)
449
+ ?.defaultPaymentMethods || [];
450
+
451
+ const availableQuoteMethods = new Set(quotes.map(q => q.paymentMethodType));
452
+
453
+ let newPaymentMethodType: string | undefined;
454
+ for (const dpm of countryMethods) {
455
+ if (availableQuoteMethods.has(dpm)) {
456
+ newPaymentMethodType = dpm;
457
+ break;
458
+ }
459
+ }
460
+
461
+ if (newPaymentMethodType) {
462
+ state.selectedPaymentMethod =
463
+ state.paymentMethods.find(m => m.paymentMethod === newPaymentMethodType) ||
464
+ state.paymentMethods.find(
465
+ method => method.paymentMethod === quotes[0]?.paymentMethodType
466
+ );
467
+ } else {
468
+ state.selectedPaymentMethod = state.paymentMethods.find(
469
+ method => method.paymentMethod === quotes[0]?.paymentMethodType
470
+ );
471
+ }
472
+ }
473
+
474
+ state.selectedQuote = quotes.find(
475
+ quote => quote.paymentMethodType === state.selectedPaymentMethod?.paymentMethod
476
+ );
477
+
478
+ state.selectedServiceProvider = state.serviceProviders.find(
479
+ sp => sp.serviceProvider === state.selectedQuote?.serviceProvider
480
+ );
481
+ } catch (error: any) {
482
+ if (error.name === 'AbortError') {
483
+ // Do nothing, another request was made
484
+ return;
485
+ }
486
+
487
+ EventsController.sendEvent({
488
+ type: 'track',
489
+ event: 'BUY_FAIL',
490
+ properties: {
491
+ message: error?.message ?? error?.code ?? 'Error getting quotes'
492
+ }
493
+ });
494
+
495
+ this.clearQuotes();
496
+ state.error = mapErrorMessage(error?.code || 'UNKNOWN_ERROR');
497
+ } finally {
498
+ if (!currentSignal.aborted) {
499
+ state.quotesLoading = false;
500
+ }
501
+ }
502
+ },
503
+
504
+ canGenerateQuote(): boolean {
505
+ return !!(
506
+ state.selectedCountry?.countryCode &&
507
+ state.selectedPaymentMethod?.paymentMethod &&
508
+ state.purchaseCurrency?.currencyCode &&
509
+ state.paymentAmount &&
510
+ state.paymentAmount > 0 &&
511
+ state.paymentCurrency?.currencyCode &&
512
+ state.selectedCountry &&
513
+ !state.loading &&
514
+ AccountController.state.address
515
+ );
516
+ },
517
+
518
+ async fetchFiatLimits() {
519
+ try {
520
+ let limits = await StorageUtil.getOnRampFiatLimits();
521
+
522
+ if (!limits.length) {
523
+ limits = (await BlockchainApiController.fetchOnRampFiatLimits()) ?? [];
524
+
525
+ if (limits.length) {
526
+ StorageUtil.setOnRampFiatLimits(limits);
527
+ }
528
+ }
529
+
530
+ state.paymentCurrenciesLimits = limits;
531
+ } catch (error) {
532
+ state.error = {
533
+ type: OnRampErrorType.FAILED_TO_LOAD_LIMITS,
534
+ message: 'Failed to load fiat limits'
535
+ };
536
+ state.paymentCurrenciesLimits = [];
537
+ }
538
+ },
539
+
540
+ async generateWidget({ quote }: { quote: OnRampQuote }) {
541
+ const metadata = OptionsController.state.metadata;
542
+ const eventProperties = {
543
+ asset: quote.destinationCurrencyCode,
544
+ network: state.purchaseCurrency?.chainName ?? '',
545
+ amount: quote.destinationAmount.toString(),
546
+ currency: quote.destinationCurrencyCode,
547
+ paymentMethod: quote.paymentMethodType,
548
+ provider: 'MELD',
549
+ serviceProvider: quote.serviceProvider
550
+ };
551
+
552
+ try {
553
+ if (!quote) {
554
+ throw new Error('Invalid quote');
555
+ }
556
+
557
+ const body = {
558
+ countryCode: quote.countryCode,
559
+ destinationCurrencyCode: quote.destinationCurrencyCode,
560
+ paymentMethodType: quote.paymentMethodType,
561
+ serviceProvider: quote.serviceProvider,
562
+ sourceAmount: quote.sourceAmount,
563
+ sourceCurrencyCode: quote.sourceCurrencyCode,
564
+ walletAddress: AccountController.state.address!,
565
+ redirectUrl: metadata?.redirect?.universal ?? metadata?.redirect?.native
566
+ };
567
+
568
+ const widget = await BlockchainApiController.getOnRampWidget(body);
569
+
570
+ if (!widget || !widget.widgetUrl) {
571
+ throw new Error('Invalid widget response');
572
+ }
573
+
574
+ EventsController.sendEvent({
575
+ type: 'track',
576
+ event: 'BUY_SUBMITTED',
577
+ properties: eventProperties
578
+ });
579
+
580
+ state.widgetUrl = widget.widgetUrl;
581
+
582
+ return widget;
583
+ } catch (e: any) {
584
+ EventsController.sendEvent({
585
+ type: 'track',
586
+ event: 'BUY_FAIL',
587
+ properties: {
588
+ ...eventProperties,
589
+ message: e?.message ?? e?.code ?? 'Error generating widget url'
590
+ }
591
+ });
592
+
593
+ state.error = mapErrorMessage(e?.code || 'UNKNOWN_ERROR');
594
+ SnackController.showInternalError({
595
+ shortMessage: 'Error creating purchase URL',
596
+ longMessage: e?.message ?? e?.code
597
+ });
598
+
599
+ return undefined;
600
+ }
601
+ },
602
+
603
+ clearError() {
604
+ state.error = undefined;
605
+ },
606
+
607
+ clearQuotes() {
608
+ state.quotes = [];
609
+ state.selectedQuote = undefined;
610
+ state.selectedServiceProvider = undefined;
611
+ },
612
+
613
+ async loadOnRampData() {
614
+ state.initialLoading = true;
615
+ state.error = undefined;
616
+
617
+ try {
618
+ await this.fetchCountries();
619
+ await this.fetchServiceProviders();
620
+
621
+ await Promise.all([
622
+ this.fetchCountriesDefaults(),
623
+ this.fetchPaymentMethods(),
624
+ this.fetchFiatLimits(),
625
+ this.fetchCryptoCurrencies(),
626
+ this.fetchFiatCurrencies()
627
+ ]);
628
+ } catch (error) {
629
+ if (!state.error) {
630
+ state.error = {
631
+ type: OnRampErrorType.FAILED_TO_LOAD,
632
+ message: 'Failed to load onramp data'
633
+ };
634
+ }
635
+ } finally {
636
+ state.initialLoading = false;
637
+ }
638
+ },
639
+
640
+ resetState() {
641
+ state.error = undefined;
642
+ state.quotesLoading = false;
643
+ state.quotes = [];
644
+ state.selectedQuote = undefined;
645
+ state.selectedServiceProvider = undefined;
646
+ state.widgetUrl = undefined;
647
+ state.paymentAmount = undefined;
648
+ this.updateSelectedPurchaseCurrency();
649
+ }
650
+ };
@@ -28,6 +28,7 @@ export interface OptionsControllerState {
28
28
  sdkVersion: SdkVersion;
29
29
  metadata?: Metadata;
30
30
  isSiweEnabled?: boolean;
31
+ isOnRampEnabled?: boolean;
31
32
  features?: Features;
32
33
  debug?: boolean;
33
34
  }
@@ -97,6 +98,10 @@ export const OptionsController = {
97
98
  state.debug = debug;
98
99
  },
99
100
 
101
+ setIsOnRampEnabled(isOnRampEnabled: OptionsControllerState['isOnRampEnabled']) {
102
+ state.isOnRampEnabled = isOnRampEnabled;
103
+ },
104
+
100
105
  isClipboardAvailable() {
101
106
  return !!state._clipboardClient;
102
107
  },
@@ -1,5 +1,11 @@
1
1
  import { proxy } from 'valtio';
2
- import type { WcWallet, CaipNetwork, Connector, SwapInputTarget } from '../utils/TypeUtil';
2
+ import type {
3
+ WcWallet,
4
+ CaipNetwork,
5
+ Connector,
6
+ SwapInputTarget,
7
+ OnRampTransactionResult
8
+ } from '../utils/TypeUtil';
3
9
 
4
10
  // -- Types --------------------------------------------- //
5
11
  type TransactionAction = {
@@ -28,6 +34,11 @@ export interface RouterControllerState {
28
34
  | 'EmailVerifyOtp'
29
35
  | 'GetWallet'
30
36
  | 'Networks'
37
+ | 'OnRamp'
38
+ | 'OnRampCheckout'
39
+ | 'OnRampLoading'
40
+ | 'OnRampSettings'
41
+ | 'OnRampTransaction'
31
42
  | 'SwitchNetwork'
32
43
  | 'Swap'
33
44
  | 'SwapSelectToken'
@@ -54,6 +65,7 @@ export interface RouterControllerState {
54
65
  email?: string;
55
66
  newEmail?: string;
56
67
  swapTarget?: SwapInputTarget;
68
+ onrampResult?: OnRampTransactionResult;
57
69
  };
58
70
  transactionStack: TransactionAction[];
59
71
  }
@@ -101,13 +113,14 @@ export const RouterController = {
101
113
  }
102
114
  },
103
115
 
104
- reset(view: RouterControllerState['view']) {
116
+ reset(view: RouterControllerState['view'], data?: RouterControllerState['data']) {
105
117
  state.view = view;
106
118
  state.history = [view];
119
+ state.data = data;
107
120
  },
108
121
 
109
122
  replace(view: RouterControllerState['view'], data?: RouterControllerState['data']) {
110
- if (state.history.length > 1 && state.history.at(-1) !== view) {
123
+ if (state.history.length >= 1 && state.history.at(-1) !== view) {
111
124
  state.view = view;
112
125
  state.history[state.history.length - 1] = view;
113
126
  state.data = data;