@reown/appkit-core-react-native 1.1.0 → 1.2.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.
Files changed (110) hide show
  1. package/lib/commonjs/controllers/ApiController.js +1 -1
  2. package/lib/commonjs/controllers/BlockchainApiController.js +107 -21
  3. package/lib/commonjs/controllers/BlockchainApiController.js.map +1 -1
  4. package/lib/commonjs/controllers/ConnectionController.js +4 -2
  5. package/lib/commonjs/controllers/ConnectionController.js.map +1 -1
  6. package/lib/commonjs/controllers/NetworkController.js +6 -0
  7. package/lib/commonjs/controllers/NetworkController.js.map +1 -1
  8. package/lib/commonjs/controllers/RouterController.js.map +1 -1
  9. package/lib/commonjs/controllers/SnackController.js +5 -0
  10. package/lib/commonjs/controllers/SnackController.js.map +1 -1
  11. package/lib/commonjs/controllers/SwapController.js +578 -6
  12. package/lib/commonjs/controllers/SwapController.js.map +1 -1
  13. package/lib/commonjs/controllers/ThemeController.js +1 -1
  14. package/lib/commonjs/controllers/ThemeController.js.map +1 -1
  15. package/lib/commonjs/index.js +14 -0
  16. package/lib/commonjs/index.js.map +1 -1
  17. package/lib/commonjs/utils/ConnectionUtil.js +33 -0
  18. package/lib/commonjs/utils/ConnectionUtil.js.map +1 -0
  19. package/lib/commonjs/utils/ConstantsUtil.js +29 -0
  20. package/lib/commonjs/utils/ConstantsUtil.js.map +1 -1
  21. package/lib/commonjs/utils/CoreHelperUtil.js +12 -12
  22. package/lib/commonjs/utils/CoreHelperUtil.js.map +1 -1
  23. package/lib/commonjs/utils/NetworkUtil.js +46 -0
  24. package/lib/commonjs/utils/NetworkUtil.js.map +1 -0
  25. package/lib/commonjs/utils/RouterUtil.js +1 -1
  26. package/lib/commonjs/utils/RouterUtil.js.map +1 -1
  27. package/lib/commonjs/utils/SwapApiUtil.js +58 -0
  28. package/lib/commonjs/utils/SwapApiUtil.js.map +1 -1
  29. package/lib/commonjs/utils/SwapCalculationUtil.js +73 -0
  30. package/lib/commonjs/utils/SwapCalculationUtil.js.map +1 -1
  31. package/lib/module/controllers/ApiController.js +1 -1
  32. package/lib/module/controllers/BlockchainApiController.js +107 -21
  33. package/lib/module/controllers/BlockchainApiController.js.map +1 -1
  34. package/lib/module/controllers/ConnectionController.js +4 -2
  35. package/lib/module/controllers/ConnectionController.js.map +1 -1
  36. package/lib/module/controllers/NetworkController.js +6 -0
  37. package/lib/module/controllers/NetworkController.js.map +1 -1
  38. package/lib/module/controllers/RouterController.js.map +1 -1
  39. package/lib/module/controllers/SnackController.js +5 -0
  40. package/lib/module/controllers/SnackController.js.map +1 -1
  41. package/lib/module/controllers/SwapController.js +578 -6
  42. package/lib/module/controllers/SwapController.js.map +1 -1
  43. package/lib/module/controllers/ThemeController.js +1 -1
  44. package/lib/module/controllers/ThemeController.js.map +1 -1
  45. package/lib/module/index.js +2 -0
  46. package/lib/module/index.js.map +1 -1
  47. package/lib/module/utils/ConnectionUtil.js +27 -0
  48. package/lib/module/utils/ConnectionUtil.js.map +1 -0
  49. package/lib/module/utils/ConstantsUtil.js +29 -0
  50. package/lib/module/utils/ConstantsUtil.js.map +1 -1
  51. package/lib/module/utils/CoreHelperUtil.js +12 -12
  52. package/lib/module/utils/CoreHelperUtil.js.map +1 -1
  53. package/lib/module/utils/NetworkUtil.js +40 -0
  54. package/lib/module/utils/NetworkUtil.js.map +1 -0
  55. package/lib/module/utils/RouterUtil.js +1 -1
  56. package/lib/module/utils/RouterUtil.js.map +1 -1
  57. package/lib/module/utils/SwapApiUtil.js +58 -0
  58. package/lib/module/utils/SwapApiUtil.js.map +1 -1
  59. package/lib/module/utils/SwapCalculationUtil.js +73 -1
  60. package/lib/module/utils/SwapCalculationUtil.js.map +1 -1
  61. package/lib/typescript/controllers/ApiController.d.ts +1 -1
  62. package/lib/typescript/controllers/BlockchainApiController.d.ts +6 -1
  63. package/lib/typescript/controllers/BlockchainApiController.d.ts.map +1 -1
  64. package/lib/typescript/controllers/ConnectionController.d.ts +3 -1
  65. package/lib/typescript/controllers/ConnectionController.d.ts.map +1 -1
  66. package/lib/typescript/controllers/NetworkController.d.ts +1 -0
  67. package/lib/typescript/controllers/NetworkController.d.ts.map +1 -1
  68. package/lib/typescript/controllers/RouterController.d.ts +3 -2
  69. package/lib/typescript/controllers/RouterController.d.ts.map +1 -1
  70. package/lib/typescript/controllers/SnackController.d.ts +2 -1
  71. package/lib/typescript/controllers/SnackController.d.ts.map +1 -1
  72. package/lib/typescript/controllers/SwapController.d.ts +87 -0
  73. package/lib/typescript/controllers/SwapController.d.ts.map +1 -1
  74. package/lib/typescript/controllers/ThemeController.d.ts +2 -2
  75. package/lib/typescript/controllers/ThemeController.d.ts.map +1 -1
  76. package/lib/typescript/index.d.ts +2 -0
  77. package/lib/typescript/index.d.ts.map +1 -1
  78. package/lib/typescript/utils/ConnectionUtil.d.ts +4 -0
  79. package/lib/typescript/utils/ConnectionUtil.d.ts.map +1 -0
  80. package/lib/typescript/utils/ConstantsUtil.d.ts +4 -0
  81. package/lib/typescript/utils/ConstantsUtil.d.ts.map +1 -1
  82. package/lib/typescript/utils/CoreHelperUtil.d.ts +2 -2
  83. package/lib/typescript/utils/CoreHelperUtil.d.ts.map +1 -1
  84. package/lib/typescript/utils/NetworkUtil.d.ts +8 -0
  85. package/lib/typescript/utils/NetworkUtil.d.ts.map +1 -0
  86. package/lib/typescript/utils/RouterUtil.d.ts.map +1 -1
  87. package/lib/typescript/utils/SwapApiUtil.d.ts +8 -0
  88. package/lib/typescript/utils/SwapApiUtil.d.ts.map +1 -1
  89. package/lib/typescript/utils/SwapCalculationUtil.d.ts +19 -0
  90. package/lib/typescript/utils/SwapCalculationUtil.d.ts.map +1 -1
  91. package/lib/typescript/utils/TypeUtil.d.ts +146 -6
  92. package/lib/typescript/utils/TypeUtil.d.ts.map +1 -1
  93. package/package.json +2 -2
  94. package/src/controllers/ApiController.ts +1 -1
  95. package/src/controllers/BlockchainApiController.ts +114 -17
  96. package/src/controllers/ConnectionController.ts +6 -2
  97. package/src/controllers/NetworkController.ts +8 -0
  98. package/src/controllers/RouterController.ts +6 -1
  99. package/src/controllers/SnackController.ts +7 -1
  100. package/src/controllers/SwapController.ts +759 -6
  101. package/src/controllers/ThemeController.ts +3 -3
  102. package/src/index.ts +2 -0
  103. package/src/utils/ConnectionUtil.ts +27 -0
  104. package/src/utils/ConstantsUtil.ts +120 -0
  105. package/src/utils/CoreHelperUtil.ts +20 -15
  106. package/src/utils/NetworkUtil.ts +33 -0
  107. package/src/utils/RouterUtil.ts +4 -1
  108. package/src/utils/SwapApiUtil.ts +89 -0
  109. package/src/utils/SwapCalculationUtil.ts +125 -0
  110. package/src/utils/TypeUtil.ts +169 -10
@@ -1,11 +1,20 @@
1
1
  import { subscribeKey as subKey } from 'valtio/utils';
2
2
  import { proxy, subscribe as sub } from 'valtio';
3
+ import { NumberUtil } from '@reown/appkit-common-react-native';
3
4
  import { ConstantsUtil } from '../utils/ConstantsUtil';
4
5
  import { SwapApiUtil } from '../utils/SwapApiUtil';
5
6
  import { NetworkController } from './NetworkController';
6
7
  import { BlockchainApiController } from './BlockchainApiController';
7
8
  import { OptionsController } from './OptionsController';
8
9
  import { SwapCalculationUtil } from '../utils/SwapCalculationUtil';
10
+ import { SnackController } from './SnackController';
11
+ import { RouterController } from './RouterController';
12
+ import { ConnectorController } from './ConnectorController';
13
+ import { AccountController } from './AccountController';
14
+ import { CoreHelperUtil } from '../utils/CoreHelperUtil';
15
+ import { ConnectionController } from './ConnectionController';
16
+ import { TransactionsController } from './TransactionsController';
17
+ import { EventsController } from './EventsController';
9
18
 
10
19
  // -- Constants ---------------------------------------- //
11
20
  export const INITIAL_GAS_LIMIT = 150000;
@@ -13,16 +22,55 @@ export const TO_AMOUNT_DECIMALS = 6;
13
22
 
14
23
  // -- Types --------------------------------------------- //
15
24
 
25
+ class TransactionError extends Error {
26
+ constructor(message, shortMessage) {
27
+ super(message);
28
+ this.name = 'TransactionError';
29
+ this.shortMessage = shortMessage;
30
+ }
31
+ }
16
32
  // -- State --------------------------------------------- //
17
33
  const initialState = {
34
+ // Loading states
35
+ initializing: false,
36
+ initialized: false,
37
+ loadingPrices: false,
38
+ loadingQuote: false,
39
+ loadingApprovalTransaction: false,
40
+ loadingBuildTransaction: false,
41
+ loadingTransaction: false,
42
+ // Error states
43
+ fetchError: false,
44
+ // Approval & Swap transaction states
45
+ approvalTransaction: undefined,
46
+ swapTransaction: undefined,
47
+ transactionError: undefined,
18
48
  // Input values
49
+ sourceToken: undefined,
50
+ sourceTokenAmount: '',
51
+ sourceTokenPriceInUSD: 0,
52
+ toToken: undefined,
53
+ toTokenAmount: '',
54
+ toTokenPriceInUSD: 0,
19
55
  networkPrice: '0',
56
+ networkBalanceInUSD: '0',
20
57
  networkTokenSymbol: '',
58
+ inputError: undefined,
59
+ // Request values
60
+ slippage: ConstantsUtil.CONVERT_SLIPPAGE_TOLERANCE,
21
61
  // Tokens
62
+ tokens: undefined,
63
+ popularTokens: undefined,
64
+ suggestedTokens: undefined,
65
+ foundTokens: undefined,
66
+ myTokensWithBalance: undefined,
22
67
  tokensPriceMap: {},
23
68
  // Calculations
24
69
  gasFee: '0',
25
- gasPriceInUSD: 0
70
+ gasPriceInUSD: 0,
71
+ priceImpact: undefined,
72
+ maxSlippage: undefined,
73
+ providerFee: undefined
26
74
  };
27
75
  const state = proxy(initialState);
28
76
 
@@ -36,18 +84,164 @@ export const SwapController = {
36
84
  return subKey(state, key, callback);
37
85
  },
38
86
  getParams() {
39
- const caipNetwork = NetworkController.state.caipNetwork;
40
- const networkAddress = `${caipNetwork?.id}:${ConstantsUtil.NATIVE_TOKEN_ADDRESS}`;
87
+ const caipAddress = AccountController.state.caipAddress;
88
+ const address = CoreHelperUtil.getPlainAddress(caipAddress);
89
+ const networkAddress = NetworkController.getActiveNetworkTokenAddress();
90
+ const type = ConnectorController.state.connectedConnector;
91
+ if (!address) {
92
+ throw new Error('No address found to swap the tokens from.');
93
+ }
94
+ const invalidToToken = !state.toToken?.address || !state.toToken?.decimals;
95
+ const invalidSourceToken = !state.sourceToken?.address || !state.sourceToken?.decimals || state.sourceToken.address === state.toToken?.address || !NumberUtil.bigNumber(state.sourceTokenAmount).isGreaterThan(0);
96
+ const invalidSourceTokenAmount = !state.sourceTokenAmount;
41
97
  return {
42
- networkAddress
98
+ networkAddress,
99
+ fromAddress: address,
100
+ fromCaipAddress: caipAddress,
101
+ sourceTokenAddress: state.sourceToken?.address,
102
+ toTokenAddress: state.toToken?.address,
103
+ toTokenAmount: state.toTokenAmount,
104
+ toTokenDecimals: state.toToken?.decimals,
105
+ sourceTokenAmount: state.sourceTokenAmount,
106
+ sourceTokenDecimals: state.sourceToken?.decimals,
107
+ invalidToToken,
108
+ invalidSourceToken,
109
+ invalidSourceTokenAmount,
110
+ availableToSwap: caipAddress && !invalidToToken && !invalidSourceToken && !invalidSourceTokenAmount,
111
+ isAuthConnector: type === 'AUTH'
43
112
  };
44
113
  },
114
+ switchTokens() {
115
+ if (state.initializing || !state.initialized) {
116
+ return;
117
+ }
118
+ let newSourceToken = state.toToken ? {
119
+ ...state.toToken
120
+ } : undefined;
121
+ const sourceTokenWithBalance = state.myTokensWithBalance?.find(token => token.address === newSourceToken?.address);
122
+ if (sourceTokenWithBalance) {
123
+ newSourceToken = sourceTokenWithBalance;
124
+ }
125
+ const newToToken = state.sourceToken ? {
126
+ ...state.sourceToken
127
+ } : undefined;
128
+ const newSourceTokenAmount = newSourceToken && state.toTokenAmount === '' ? '1' : state.toTokenAmount;
129
+ this.setSourceToken(newSourceToken);
130
+ this.setToToken(newToToken);
131
+ this.setSourceTokenAmount(newSourceTokenAmount);
132
+ this.setToTokenAmount('');
133
+ this.swapTokens();
134
+ },
45
135
  resetState() {
136
+ state.myTokensWithBalance = initialState.myTokensWithBalance;
46
137
  state.tokensPriceMap = initialState.tokensPriceMap;
138
+ state.initialized = initialState.initialized;
139
+ state.sourceToken = initialState.sourceToken;
140
+ state.sourceTokenAmount = initialState.sourceTokenAmount;
141
+ state.sourceTokenPriceInUSD = initialState.sourceTokenPriceInUSD;
142
+ state.toToken = initialState.toToken;
143
+ state.toTokenAmount = initialState.toTokenAmount;
144
+ state.toTokenPriceInUSD = initialState.toTokenPriceInUSD;
47
145
  state.networkPrice = initialState.networkPrice;
48
146
  state.networkTokenSymbol = initialState.networkTokenSymbol;
147
+ state.networkBalanceInUSD = initialState.networkBalanceInUSD;
148
+ state.inputError = initialState.inputError;
149
+ },
150
+ async fetchTokens() {
151
+ const {
152
+ networkAddress
153
+ } = this.getParams();
154
+ await this.getTokenList();
155
+ await this.getNetworkTokenPrice();
156
+ await this.getMyTokensWithBalance();
157
+ const networkToken = state.tokens?.find(token => token.address === networkAddress);
158
+ if (networkToken) {
159
+ state.networkTokenSymbol = networkToken.symbol;
160
+ }
161
+ const sourceToken = state.myTokensWithBalance?.find(token => token.address.startsWith(networkAddress)) || state.myTokensWithBalance?.[0];
162
+ this.setSourceToken(sourceToken);
163
+ this.setSourceTokenAmount('1');
164
+ },
165
+ async getTokenList() {
166
+ const tokens = await SwapApiUtil.getTokenList();
167
+ state.tokens = tokens;
168
+ state.popularTokens = tokens.sort((aTokenInfo, bTokenInfo) => {
169
+ if (aTokenInfo.symbol < bTokenInfo.symbol) {
170
+ return -1;
171
+ }
172
+ if (aTokenInfo.symbol > bTokenInfo.symbol) {
173
+ return 1;
174
+ }
175
+ return 0;
176
+ });
177
+ state.suggestedTokens = tokens.filter(token => {
178
+ if (ConstantsUtil.SWAP_SUGGESTED_TOKENS.includes(token.symbol)) {
179
+ return true;
180
+ }
181
+ return false;
182
+ }, {});
183
+ },
184
+ async getMyTokensWithBalance(forceUpdate) {
185
+ const balances = await SwapApiUtil.getMyTokensWithBalance(forceUpdate);
186
+ if (!balances) {
187
+ return;
188
+ }
189
+ await this.getInitialGasPrice();
190
+ this.setBalances(balances);
191
+ },
192
+ getFilteredPopularTokens() {
193
+ return state.popularTokens?.filter(token => !state.myTokensWithBalance?.some(t => t.address === token.address));
194
+ },
195
+ setSourceToken(sourceToken) {
196
+ if (!sourceToken) {
197
+ state.sourceToken = sourceToken;
198
+ state.sourceTokenAmount = '';
199
+ state.sourceTokenPriceInUSD = 0;
200
+ return;
201
+ }
202
+ state.sourceToken = sourceToken;
203
+ this.setTokenPrice(sourceToken.address, 'sourceToken');
204
+ },
205
+ setSourceTokenAmount(amount) {
206
+ state.sourceTokenAmount = amount;
207
+ if (amount === '') {
208
+ state.toTokenAmount = '';
209
+ }
210
+ },
211
+ async initializeState() {
212
+ if (state.initializing) {
213
+ return;
214
+ }
215
+ state.initializing = true;
216
+ if (!state.initialized) {
217
+ try {
218
+ await this.fetchTokens();
219
+ state.initialized = true;
220
+ } catch (error) {
221
+ state.initialized = false;
222
+ SnackController.showError('Failed to initialize swap');
223
+ RouterController.goBack();
224
+ }
225
+ }
226
+ state.initializing = false;
227
+ },
228
+ async getAddressPrice(address) {
229
+ const existPrice = state.tokensPriceMap[address];
230
+ if (existPrice) {
231
+ return existPrice;
232
+ }
233
+ const response = await BlockchainApiController.fetchTokenPrice({
234
+ projectId: OptionsController.state.projectId,
235
+ addresses: [address]
236
+ });
237
+ const fungibles = response?.fungibles || [];
238
+ const allTokens = [...(state.tokens || []), ...(state.myTokensWithBalance || [])];
239
+ const symbol = allTokens?.find(token => token.address === address)?.symbol;
240
+ const price = fungibles.find(p => p.symbol.toLowerCase() === symbol?.toLowerCase())?.price || 0;
241
+ const priceAsFloat = parseFloat(price.toString());
242
+ state.tokensPriceMap[address] = priceAsFloat;
243
+ return priceAsFloat;
49
244
  },
50
- //this
51
245
  async getNetworkTokenPrice() {
52
246
  const {
53
247
  networkAddress
@@ -62,7 +256,6 @@ export const SwapController = {
62
256
  state.networkTokenSymbol = token?.symbol || '';
63
257
  state.networkPrice = price;
64
258
  },
65
- //this
66
259
  async getInitialGasPrice() {
67
260
  const res = await SwapApiUtil.fetchGasPrice();
68
261
  if (!res) {
@@ -81,6 +274,385 @@ export const SwapController = {
81
274
  gasPrice: gasFee,
82
275
  gasPriceInUSD: state.gasPriceInUSD
83
276
  };
277
+ },
278
+ getProviderFeePrice() {
279
+ return SwapCalculationUtil.getProviderFeePrice(state.sourceTokenAmount, state.sourceTokenPriceInUSD);
280
+ },
281
+ setBalances(balances) {
282
+ const {
283
+ networkAddress
284
+ } = this.getParams();
285
+ const caipNetwork = NetworkController.state.caipNetwork;
286
+ if (!caipNetwork) {
287
+ return;
288
+ }
289
+ const networkToken = balances.find(token => token.address === networkAddress);
290
+ balances.forEach(token => {
291
+ state.tokensPriceMap[token.address] = token.price || 0;
292
+ });
293
+ state.myTokensWithBalance = balances.filter(token => token.address?.startsWith(caipNetwork.id));
294
+ state.networkBalanceInUSD = networkToken ? NumberUtil.multiply(networkToken.quantity.numeric, networkToken.price).toString() : '0';
295
+ },
296
+ setToToken(toToken) {
297
+ if (!toToken) {
298
+ state.toToken = toToken;
299
+ state.toTokenAmount = '';
300
+ state.toTokenPriceInUSD = 0;
301
+ return;
302
+ }
303
+ state.toToken = toToken;
304
+ this.setTokenPrice(toToken.address, 'toToken');
305
+ },
306
+ setToTokenAmount(amount) {
307
+ state.toTokenAmount = amount ? NumberUtil.formatNumberToLocalString(amount, TO_AMOUNT_DECIMALS) : '';
308
+ },
309
+ async setTokenPrice(address, target) {
310
+ let price = state.tokensPriceMap[address] || 0;
311
+ if (!price) {
312
+ state.loadingPrices = true;
313
+ price = await this.getAddressPrice(address);
314
+ }
315
+ if (target === 'sourceToken') {
316
+ state.sourceTokenPriceInUSD = price;
317
+ } else if (target === 'toToken') {
318
+ state.toTokenPriceInUSD = price;
319
+ }
320
+ if (state.loadingPrices) {
321
+ state.loadingPrices = false;
322
+ }
323
+ if (this.getParams().availableToSwap) {
324
+ this.swapTokens();
325
+ }
326
+ },
327
+ // -- Swap ---------------------------------------------- //
328
+ async swapTokens() {
329
+ const address = AccountController.state.address;
330
+ const sourceToken = state.sourceToken;
331
+ const toToken = state.toToken;
332
+ const haveSourceTokenAmount = NumberUtil.bigNumber(state.sourceTokenAmount).isGreaterThan(0);
333
+ if (!toToken || !sourceToken || state.loadingPrices || !haveSourceTokenAmount) {
334
+ return;
335
+ }
336
+ state.loadingQuote = true;
337
+ const amountDecimal = NumberUtil.bigNumber(state.sourceTokenAmount).multipliedBy(10 ** sourceToken.decimals).integerValue();
338
+ const quoteResponse = await BlockchainApiController.fetchSwapQuote({
339
+ userAddress: address,
340
+ projectId: OptionsController.state.projectId,
341
+ from: sourceToken.address,
342
+ to: toToken.address,
343
+ gasPrice: state.gasFee,
344
+ amount: amountDecimal.toString()
345
+ });
346
+ state.loadingQuote = false;
347
+ const quoteToAmount = quoteResponse?.quotes?.[0]?.toAmount;
348
+ if (!quoteToAmount) {
349
+ return;
350
+ }
351
+ const toTokenAmount = NumberUtil.bigNumber(quoteToAmount).dividedBy(10 ** toToken.decimals).toString();
352
+ this.setToTokenAmount(toTokenAmount);
353
+ const isInsufficientToken = this.hasInsufficientToken(state.sourceTokenAmount, sourceToken.address);
354
+ if (isInsufficientToken) {
355
+ state.inputError = 'Insufficient balance';
356
+ } else {
357
+ state.inputError = undefined;
358
+ this.setTransactionDetails();
359
+ }
360
+ },
361
+ // -- Create Transactions -------------------------------------- //
362
+ async getTransaction() {
363
+ const {
364
+ fromCaipAddress,
365
+ availableToSwap
366
+ } = this.getParams();
367
+ const sourceToken = state.sourceToken;
368
+ const toToken = state.toToken;
369
+ if (!fromCaipAddress || !availableToSwap || !sourceToken || !toToken || state.loadingQuote) {
370
+ return undefined;
371
+ }
372
+ try {
373
+ state.loadingBuildTransaction = true;
374
+ const hasAllowance = await SwapApiUtil.fetchSwapAllowance({
375
+ userAddress: fromCaipAddress,
376
+ tokenAddress: sourceToken.address,
377
+ sourceTokenAmount: state.sourceTokenAmount,
378
+ sourceTokenDecimals: sourceToken.decimals
379
+ });
380
+ let transaction;
381
+ if (hasAllowance) {
382
+ transaction = await this.createSwapTransaction();
383
+ } else {
384
+ transaction = await this.createAllowanceTransaction();
385
+ }
386
+ state.loadingBuildTransaction = false;
387
+ state.fetchError = false;
388
+ return transaction;
389
+ } catch (error) {
390
+ RouterController.goBack();
391
+ SnackController.showError('Failed to check allowance');
392
+ state.loadingBuildTransaction = false;
393
+ state.approvalTransaction = undefined;
394
+ state.swapTransaction = undefined;
395
+ state.fetchError = true;
396
+ return undefined;
397
+ }
398
+ },
399
+ async createAllowanceTransaction() {
400
+ const {
401
+ fromCaipAddress,
402
+ fromAddress,
403
+ sourceTokenAddress,
404
+ toTokenAddress
405
+ } = this.getParams();
406
+ if (!fromCaipAddress || !toTokenAddress) {
407
+ return undefined;
408
+ }
409
+ if (!sourceTokenAddress) {
410
+ throw new Error('createAllowanceTransaction - No source token address found.');
411
+ }
412
+ try {
413
+ const response = await BlockchainApiController.generateApproveCalldata({
414
+ projectId: OptionsController.state.projectId,
415
+ from: sourceTokenAddress,
416
+ to: toTokenAddress,
417
+ userAddress: fromCaipAddress
418
+ });
419
+ if (!response) {
420
+ throw new Error('createAllowanceTransaction - No response from generateApproveCalldata');
421
+ }
422
+ const gasLimit = await ConnectionController.estimateGas({
423
+ address: fromAddress,
424
+ to: CoreHelperUtil.getPlainAddress(response.tx.to),
425
+ data: response.tx.data
426
+ });
427
+ const transaction = {
428
+ data: response.tx.data,
429
+ to: CoreHelperUtil.getPlainAddress(response.tx.from),
430
+ gas: gasLimit,
431
+ gasPrice: BigInt(response.tx.eip155.gasPrice),
432
+ value: BigInt(response.tx.value),
433
+ toAmount: state.toTokenAmount
434
+ };
435
+ state.swapTransaction = undefined;
436
+ state.approvalTransaction = {
437
+ data: transaction.data,
438
+ to: transaction.to,
439
+ gas: transaction.gas ?? BigInt(0),
440
+ gasPrice: transaction.gasPrice,
441
+ value: transaction.value,
442
+ toAmount: transaction.toAmount
443
+ };
444
+ return {
445
+ data: transaction.data,
446
+ to: transaction.to,
447
+ gas: transaction.gas ?? BigInt(0),
448
+ gasPrice: transaction.gasPrice,
449
+ value: transaction.value,
450
+ toAmount: transaction.toAmount
451
+ };
452
+ } catch (error) {
453
+ RouterController.goBack();
454
+ SnackController.showError('Failed to create approval transaction');
455
+ state.approvalTransaction = undefined;
456
+ state.swapTransaction = undefined;
457
+ state.fetchError = true;
458
+ return undefined;
459
+ }
460
+ },
461
+ async createSwapTransaction() {
462
+ const {
463
+ networkAddress,
464
+ fromCaipAddress,
465
+ sourceTokenAmount
466
+ } = this.getParams();
467
+ const sourceToken = state.sourceToken;
468
+ const toToken = state.toToken;
469
+ if (!fromCaipAddress || !sourceTokenAmount || !sourceToken || !toToken) {
470
+ return undefined;
471
+ }
472
+ const amount = ConnectionController.parseUnits(sourceTokenAmount, sourceToken.decimals)?.toString();
473
+ try {
474
+ const response = await BlockchainApiController.generateSwapCalldata({
475
+ projectId: OptionsController.state.projectId,
476
+ userAddress: fromCaipAddress,
477
+ from: sourceToken.address,
478
+ to: toToken.address,
479
+ amount: amount
480
+ });
481
+ if (!response) {
482
+ throw new Error('createSwapTransaction - No response from generateSwapCalldata');
483
+ }
484
+ const isSourceNetworkToken = sourceToken.address === networkAddress;
485
+ const gas = BigInt(response.tx.eip155.gas);
486
+ const gasPrice = BigInt(response.tx.eip155.gasPrice);
487
+ const transaction = {
488
+ data: response.tx.data,
489
+ to: CoreHelperUtil.getPlainAddress(response.tx.to),
490
+ gas,
491
+ gasPrice,
492
+ value: isSourceNetworkToken ? BigInt(amount ?? '0') : BigInt('0'),
493
+ toAmount: state.toTokenAmount
494
+ };
495
+ state.gasPriceInUSD = SwapCalculationUtil.getGasPriceInUSD(state.networkPrice, gas, gasPrice);
496
+ state.approvalTransaction = undefined;
497
+ state.swapTransaction = transaction;
498
+ return transaction;
499
+ } catch (error) {
500
+ RouterController.goBack();
501
+ SnackController.showError('Failed to create transaction');
502
+ state.approvalTransaction = undefined;
503
+ state.swapTransaction = undefined;
504
+ state.fetchError = true;
505
+ return undefined;
506
+ }
507
+ },
508
+ async sendTransactionForApproval(data) {
509
+ const {
510
+ fromAddress,
511
+ isAuthConnector
512
+ } = this.getParams();
513
+ state.loadingApprovalTransaction = true;
514
+ const approveLimitMessage = `Approve limit increase in your wallet`;
515
+ if (isAuthConnector) {
516
+ RouterController.pushTransactionStack({
517
+ view: null,
518
+ goBack: true,
519
+ onSuccess() {
520
+ SnackController.showLoading(approveLimitMessage);
521
+ }
522
+ });
523
+ } else {
524
+ SnackController.showLoading(approveLimitMessage);
525
+ }
526
+ try {
527
+ await ConnectionController.sendTransaction({
528
+ address: fromAddress,
529
+ to: data.to,
530
+ data: data.data,
531
+ value: BigInt(data.value),
532
+ gasPrice: BigInt(data.gasPrice),
533
+ chainNamespace: 'eip155'
534
+ });
535
+ await this.swapTokens();
536
+ await this.getTransaction();
537
+ state.approvalTransaction = undefined;
538
+ state.loadingApprovalTransaction = false;
539
+ } catch (err) {
540
+ const error = err;
541
+ state.transactionError = error?.shortMessage;
542
+ state.loadingApprovalTransaction = false;
543
+ SnackController.showError(error?.shortMessage ?? 'Transaction error');
544
+ }
545
+ },
546
+ async sendTransactionForSwap(data) {
547
+ if (!data) {
548
+ return undefined;
549
+ }
550
+ const {
551
+ fromAddress,
552
+ toTokenAmount,
553
+ isAuthConnector
554
+ } = this.getParams();
555
+ state.loadingTransaction = true;
556
+ const snackbarPendingMessage = `Swapping ${state.sourceToken?.symbol} to ${NumberUtil.formatNumberToLocalString(toTokenAmount, 3)} ${state.toToken?.symbol}`;
557
+ const snackbarSuccessMessage = `Swapped ${state.sourceToken?.symbol} to ${NumberUtil.formatNumberToLocalString(toTokenAmount, 3)} ${state.toToken?.symbol}`;
558
+ if (isAuthConnector) {
559
+ RouterController.pushTransactionStack({
560
+ view: 'Account',
561
+ goBack: false,
562
+ onSuccess() {
563
+ SnackController.showLoading(snackbarPendingMessage);
564
+ SwapController.resetState();
565
+ }
566
+ });
567
+ } else {
568
+ SnackController.showLoading('Confirm transaction in your wallet');
569
+ }
570
+ try {
571
+ const forceUpdateAddresses = [state.sourceToken?.address, state.toToken?.address].join(',');
572
+ const transactionHash = await ConnectionController.sendTransaction({
573
+ address: fromAddress,
574
+ to: data.to,
575
+ data: data.data,
576
+ gas: data.gas,
577
+ gasPrice: BigInt(data.gasPrice),
578
+ value: data.value,
579
+ chainNamespace: 'eip155'
580
+ });
581
+ state.loadingTransaction = false;
582
+ SnackController.showSuccess(snackbarSuccessMessage);
583
+ EventsController.sendEvent({
584
+ type: 'track',
585
+ event: 'SWAP_SUCCESS',
586
+ properties: {
587
+ network: NetworkController.state.caipNetwork?.id || '',
588
+ swapFromToken: this.state.sourceToken?.symbol || '',
589
+ swapToToken: this.state.toToken?.symbol || '',
590
+ swapFromAmount: this.state.sourceTokenAmount || '',
591
+ swapToAmount: this.state.toTokenAmount || '',
592
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
593
+ }
594
+ });
595
+ SwapController.resetState();
596
+ if (!isAuthConnector) {
597
+ RouterController.replace('AccountDefault');
598
+ }
599
+ SwapController.getMyTokensWithBalance(forceUpdateAddresses);
600
+ AccountController.fetchTokenBalance();
601
+ setTimeout(() => {
602
+ TransactionsController.fetchTransactions(AccountController.state.address, true);
603
+ }, 5000);
604
+ return transactionHash;
605
+ } catch (err) {
606
+ const error = err;
607
+ state.transactionError = error?.shortMessage;
608
+ state.loadingTransaction = false;
609
+ SnackController.showError(error?.shortMessage ?? 'Transaction error');
610
+ EventsController.sendEvent({
611
+ type: 'track',
612
+ event: 'SWAP_ERROR',
613
+ properties: {
614
+ message: error?.shortMessage ?? error?.message ?? 'Unknown',
615
+ network: NetworkController.state.caipNetwork?.id || '',
616
+ swapFromToken: this.state.sourceToken?.symbol || '',
617
+ swapToToken: this.state.toToken?.symbol || '',
618
+ swapFromAmount: this.state.sourceTokenAmount || '',
619
+ swapToAmount: this.state.toTokenAmount || '',
620
+ isSmartAccount: AccountController.state.preferredAccountType === 'smartAccount'
621
+ }
622
+ });
623
+ return undefined;
624
+ }
625
+ },
626
+ // -- Checks -------------------------------------------- //
627
+ hasInsufficientToken(sourceTokenAmount, sourceTokenAddress) {
628
+ const isInsufficientSourceTokenForSwap = SwapCalculationUtil.isInsufficientSourceTokenForSwap(sourceTokenAmount, sourceTokenAddress, state.myTokensWithBalance);
629
+ let insufficientNetworkTokenForGas = true;
630
+ if (AccountController.state.preferredAccountType === 'smartAccount') {
631
+ // Smart Accounts may pay gas in any ERC20 token
632
+ insufficientNetworkTokenForGas = false;
633
+ } else {
634
+ insufficientNetworkTokenForGas = SwapCalculationUtil.isInsufficientNetworkTokenForGas(state.networkBalanceInUSD, state.gasPriceInUSD);
635
+ }
636
+ return insufficientNetworkTokenForGas || isInsufficientSourceTokenForSwap;
637
+ },
638
+ // -- Calculations -------------------------------------- //
639
+ setTransactionDetails() {
640
+ const {
641
+ toTokenAddress,
642
+ toTokenDecimals
643
+ } = this.getParams();
644
+ if (!toTokenAddress || !toTokenDecimals) {
645
+ return;
646
+ }
647
+ state.gasPriceInUSD = SwapCalculationUtil.getGasPriceInUSD(state.networkPrice, BigInt(state.gasFee), BigInt(INITIAL_GAS_LIMIT));
648
+ state.priceImpact = SwapCalculationUtil.getPriceImpact({
649
+ sourceTokenAmount: state.sourceTokenAmount,
650
+ sourceTokenPriceInUSD: state.sourceTokenPriceInUSD,
651
+ toTokenPriceInUSD: state.toTokenPriceInUSD,
652
+ toTokenAmount: state.toTokenAmount
653
+ });
654
+ state.maxSlippage = SwapCalculationUtil.getMaxSlippage(state.slippage, state.toTokenAmount);
655
+ state.providerFee = SwapCalculationUtil.getProviderFee(state.sourceTokenAmount);
84
656
  }
85
657
  };
86
658
  //# sourceMappingURL=SwapController.js.map