@imtbl/sdk 1.77.4 → 1.77.5-alpha.2

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 (58) hide show
  1. package/dist/{blockchain_data-CSSYwdB-.js → blockchain_data-B74t5SqC.js} +2 -2
  2. package/dist/blockchain_data.js +3 -3
  3. package/dist/browser/checkout/{AddTokensWidget-CzAE1d3f.js → AddTokensWidget-ho7XUYky.js} +299 -266
  4. package/dist/browser/checkout/{BridgeWidget-6snvryex.js → BridgeWidget-CQwF01Ph.js} +9 -9
  5. package/dist/browser/checkout/{CommerceWidget-BQzxxBBp.js → CommerceWidget-CKBMeuAb.js} +17 -17
  6. package/dist/browser/checkout/{CryptoFiatProvider-DrL1vFka.js → CryptoFiatProvider-CrDHcmXp.js} +1 -1
  7. package/dist/browser/checkout/{FeesBreakdown-6N1PBhxc.js → FeesBreakdown-DgXe6Fa2.js} +1 -1
  8. package/dist/browser/checkout/{HandoverContent-DACeI3Ql.js → HandoverContent-CnLMKDDD.js} +1 -1
  9. package/dist/browser/checkout/{OnRampWidget-C27NOCDj.js → OnRampWidget-vzsjg7qL.js} +3 -3
  10. package/dist/browser/checkout/{SaleWidget-0wqfnQkL.js → SaleWidget-BfRakz0n.js} +14 -14
  11. package/dist/browser/checkout/{SpendingCapHero-se43V9Us.js → SpendingCapHero-CPj8E77p.js} +1 -1
  12. package/dist/browser/checkout/{SwapWidget-DL3WYUw9.js → SwapWidget-BzWepYEh.js} +9 -9
  13. package/dist/browser/checkout/{TokenImage-Im5drCmP.js → TokenImage-BIsOhmpw.js} +1 -1
  14. package/dist/browser/checkout/{TopUpView-h8yzvXWl.js → TopUpView-CmCvLBsf.js} +3 -3
  15. package/dist/browser/checkout/{WalletApproveHero-ByDRA_kK.js → WalletApproveHero-CxN_lwFf.js} +3 -3
  16. package/dist/browser/checkout/{WalletWidget-BRLER2vp.js → WalletWidget-uHMLosBc.js} +4 -4
  17. package/dist/browser/checkout/{auto-track-D_sVcc3q.js → auto-track-DhKG-Aj-.js} +1 -1
  18. package/dist/browser/checkout/{index-C6VrFT0d.js → index-B6MDZ65f.js} +1 -1
  19. package/dist/browser/checkout/{index-CpPB7WU9.js → index-BXHgeq5K.js} +1 -1
  20. package/dist/browser/checkout/{index-CLIIegap.js → index-BZBtvKSM.js} +1 -1
  21. package/dist/browser/checkout/{index-DIgPyYaY.js → index-CN4mb1eI.js} +1 -1
  22. package/dist/browser/checkout/{index-ZsTq7hP6.js → index-CThUeEZD.js} +2 -2
  23. package/dist/browser/checkout/{index-CU8j8oV7.js → index-CdH6Dx3k.js} +1 -1
  24. package/dist/browser/checkout/{index-D-6LYeBT.js → index-CmhfOYK-.js} +1 -1
  25. package/dist/browser/checkout/{index-D7zuN_2m.js → index-DD7N6gXr.js} +19 -19
  26. package/dist/browser/checkout/{index-Ciq_hY6N.js → index-DRsZuMPh.js} +1 -1
  27. package/dist/browser/checkout/{index-BrPk4SVq.js → index-DTvOW3g2.js} +1 -1
  28. package/dist/browser/checkout/{index.umd-BTRWYRB0.js → index.umd-BeA2p5DE.js} +1 -1
  29. package/dist/browser/checkout/sdk.js +4 -4
  30. package/dist/browser/checkout/{useInterval-DeDgB1gY.js → useInterval-CA09xlan.js} +1 -1
  31. package/dist/browser/checkout/widgets-esm.js +1 -1
  32. package/dist/browser/checkout/widgets.js +1143 -1055
  33. package/dist/{checkout-rc8rFe_T.js → checkout-7WFS_XJj.js} +5 -5
  34. package/dist/checkout.js +5 -5
  35. package/dist/{config-B14s5Yki.js → config-BxW6HRZg.js} +1 -1
  36. package/dist/config.js +1 -1
  37. package/dist/{index-BJw8kxPo.js → index-B9MfkDaq.js} +1 -1
  38. package/dist/{index-B6tCwHSk.js → index-BhuY1-GF.js} +3 -3
  39. package/dist/{index-DaUCuTCV.js → index-Bxz960C5.js} +1 -1
  40. package/dist/{index-BH4mFAq1.js → index-C1Pjpcef.js} +4 -4
  41. package/dist/{index-C-psCZRA.js → index-CktTkdn0.js} +1 -1
  42. package/dist/{index-DvANTswe.js → index-DF-RI8Zc.js} +1 -1
  43. package/dist/index.browser.js +4 -4
  44. package/dist/index.browser.js.map +1 -1
  45. package/dist/index.cjs +7 -7
  46. package/dist/index.js +14 -14
  47. package/dist/{minting_backend-CEy7Phcq.js → minting_backend-Ch5w3R8k.js} +3 -3
  48. package/dist/minting_backend.js +5 -5
  49. package/dist/{orderbook-BCx_6zlr.js → orderbook-D5HBZMmK.js} +1 -1
  50. package/dist/orderbook.js +2 -2
  51. package/dist/{passport-Cl4qWc0E.js → passport-BBQ8BLmA.js} +3 -3
  52. package/dist/passport.js +4 -4
  53. package/dist/version.json +1 -1
  54. package/dist/{webhook-DETmXUX7.js → webhook-UHB7iiVR.js} +1 -1
  55. package/dist/webhook.js +2 -2
  56. package/dist/{x-D9HTgYe2.js → x-DPqmRzAY.js} +3 -3
  57. package/dist/x.js +4 -4
  58. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
- import { r as reactExports, I as IMTBLWidgetEvents, A as AddTokensEventType, w as getDefaultExportFromCjs, x as commonjsGlobal, y as useProvidersContext, z as useAnalytics, U as UserJourney, D as isPassportProvider, F as BigNumber, o as jsx, p as jsxs, G as Box, u as useTranslation, H as Drawer, J as Divider, K as Heading, M as Button, N as WalletDrawer, Q as UnableToConnectDrawer, R as Fragment, T as WalletProviderRdns, X as removeSpace, Y as getProviderSlugFromRdns, Z as Web3Provider, _ as connectEIP6963Provider, $ as identifyUser, a0 as ConnectEIP6963ProviderError, a1 as ProvidersContextActions, a2 as MenuItem, j as ChainId, a3 as commonjsRequire, a4 as getRemoteImage, a5 as vFlex, a6 as OnboardingPagination, a7 as ViewContext, a8 as useHandover, a9 as HandoverTarget, aa as EventTargetContext, V as ViewActions, ab as getRemoteRive, ac as Trans, ad as Link, ae as Body, af as keyframes, ag as getDefaultTokenImage, ah as TokenFilterTypes, h as getL2ChainId, ai as isNativeToken, aj as getTokenImageByAddress, ak as SmartClone, al as FramedImage, am as FramedIcon, an as ButtCon, ao as TextInput, ap as VerticalMenu, aq as EllipsizedText, ar as Tooltip, as as Sticker, at as tokenValueFormat, au as DEFAULT_TOKEN_FORMATTING_DECIMALS, av as Stack, aw as hFlex, ax as centerFlexChildren, ay as Icon, az as Badge, aA as getRemoteVideo, aB as FramedVideo, aC as listVariants, aD as motion, aE as listItemVariants, aF as Banner, aG as fetchRiskAssessment, aH as isAddressSanctioned, aI as useInjectedProviders, aJ as trackFlow, aK as HeroFormControl, aL as SimpleLayout, m as SharedViews, aM as orchestrationEvents, aN as HeroTextInput, aO as requireSecp256k1$1, aP as requireLib_commonjs, aQ as require$$0$2, aR as bech32$2, aS as bnExports$1, aT as require$$0$3, aU as getAugmentedNamespace, aV as require$$0$4, aW as minimalisticAssert, aX as require$$2, aY as hash$6, aZ as trackError, a_ as MaxUint256, a$ as merge$2, b0 as SvgIcon, b1 as WalletWarningHero, b2 as Environment, b3 as t, b4 as PriceDisplay, L as LoadingView, b5 as useTheme, b6 as viewReducer, b7 as initialViewState, b8 as isValidAddress, b9 as amountInputValidation, ba as CloudImage, E as ErrorView, bb as ServiceUnavailableErrorView } from './index-D7zuN_2m.js';
2
- import { r as retry, T as TokenImage } from './TokenImage-Im5drCmP.js';
3
- import { f as formatUnits, p as parseUnits } from './index-CpPB7WU9.js';
4
- import { H as HandoverContent } from './HandoverContent-DACeI3Ql.js';
5
- import { C as Contract } from './index-C6VrFT0d.js';
6
- import { F as FeesBreakdown } from './FeesBreakdown-6N1PBhxc.js';
1
+ import { r as reactExports, I as IMTBLWidgetEvents, A as AddTokensEventType, w as getDefaultExportFromCjs, x as commonjsGlobal, y as BigNumber, z as useProvidersContext, D as isPassportProvider, o as jsx, p as jsxs, F as Box, u as useTranslation, G as Drawer, H as Divider, J as Heading, K as Button, M as useAnalytics, N as WalletDrawer, U as UnableToConnectDrawer, Q as Fragment, R as WalletProviderRdns, T as UserJourney, X as removeSpace, Y as getProviderSlugFromRdns, Z as Web3Provider, _ as connectEIP6963Provider, $ as identifyUser, a0 as ConnectEIP6963ProviderError, a1 as ProvidersContextActions, a2 as MenuItem, j as ChainId, a3 as commonjsRequire, a4 as getRemoteImage, a5 as vFlex, a6 as OnboardingPagination, a7 as ViewContext, a8 as useHandover, a9 as HandoverTarget, aa as EventTargetContext, V as ViewActions, ab as getRemoteRive, ac as Trans, ad as Link, ae as Body, af as keyframes, ag as getDefaultTokenImage, ah as TokenFilterTypes, h as getL2ChainId, ai as isNativeToken, aj as getTokenImageByAddress, ak as SmartClone, al as FramedImage, am as FramedIcon, an as ButtCon, ao as TextInput, ap as VerticalMenu, aq as EllipsizedText, ar as Tooltip, as as Sticker, at as tokenValueFormat, au as DEFAULT_TOKEN_FORMATTING_DECIMALS, av as Stack, aw as hFlex, ax as centerFlexChildren, ay as Icon, az as Badge, aA as getRemoteVideo, aB as FramedVideo, aC as listVariants, aD as motion, aE as listItemVariants, aF as Banner, aG as fetchRiskAssessment, aH as isAddressSanctioned, aI as useInjectedProviders, aJ as trackFlow, aK as HeroFormControl, aL as SimpleLayout, m as SharedViews, aM as orchestrationEvents, aN as HeroTextInput, aO as requireSecp256k1$1, aP as requireLib_commonjs, aQ as require$$0$2, aR as bech32$2, aS as bnExports$1, aT as require$$0$3, aU as getAugmentedNamespace, aV as require$$0$4, aW as minimalisticAssert, aX as require$$2, aY as hash$6, aZ as trackError, a_ as MaxUint256, a$ as merge$2, b0 as SvgIcon, b1 as WalletWarningHero, b2 as t, b3 as PriceDisplay, L as LoadingView, b4 as useTheme, b5 as viewReducer, b6 as initialViewState, b7 as Environment, b8 as isValidAddress, b9 as amountInputValidation, ba as CloudImage, E as ErrorView, bb as ServiceUnavailableErrorView } from './index-DD7N6gXr.js';
2
+ import { r as retry, T as TokenImage } from './TokenImage-BIsOhmpw.js';
3
+ import { p as parseUnits, f as formatUnits } from './index-BXHgeq5K.js';
4
+ import { H as HandoverContent } from './HandoverContent-CnLMKDDD.js';
5
+ import { C as Contract } from './index-B6MDZ65f.js';
6
+ import { F as FeesBreakdown } from './FeesBreakdown-DgXe6Fa2.js';
7
7
 
8
8
  /**
9
9
  * The function `useInterval` sets up an interval that repeatedly calls a given callback function with
@@ -1312,6 +1312,18 @@ const TOOLKIT_SQUID_URL = 'https://toolkit.immutable.com/squid-bridge/';
1312
1312
  const FIXED_HANDOVER_DURATION = 2000;
1313
1313
  const TOKEN_PRIORITY_ORDER = ['IMX', 'USDC', 'ETH'];
1314
1314
 
1315
+ const findToken = (tokens, address, chainId) => tokens.find((value) => value.address.toLowerCase() === address.toLowerCase()
1316
+ && value.chainId === chainId);
1317
+
1318
+ const isRouteToAmountGreaterThanToAmount = (routeResponse, toAmount) => {
1319
+ if (!routeResponse?.route?.estimate?.toAmount || !routeResponse?.route?.estimate?.toToken?.decimals) {
1320
+ throw new Error('Invalid route response or token decimals');
1321
+ }
1322
+ const toAmountInBaseUnits = parseUnits(toAmount, routeResponse?.route.estimate.toToken.decimals);
1323
+ const routeToAmountInBaseUnits = BigNumber.from(routeResponse.route.estimate.toAmount);
1324
+ return routeToAmountInBaseUnits.gt(toAmountInBaseUnits);
1325
+ };
1326
+
1315
1327
  const BASE_SLIPPAGE_HIGH_TIER = 0.005;
1316
1328
  const BASE_SLIPPAGE_MEDIUM_TIER = 0.01;
1317
1329
  const BASE_SLIPPAGE_LOW_TIER = 0.015;
@@ -1329,33 +1341,35 @@ const SLIPPAGE_TIERS = {
1329
1341
  value: BASE_SLIPPAGE_LOW_TIER,
1330
1342
  },
1331
1343
  };
1332
- const getSlippageTier = (usdAmount) => {
1333
- if (usdAmount >= SLIPPAGE_TIERS.high.threshold) {
1334
- return SLIPPAGE_TIERS.high.value;
1335
- }
1336
- if (usdAmount >= SLIPPAGE_TIERS.medium.threshold) {
1337
- return SLIPPAGE_TIERS.medium.value;
1338
- }
1339
- return SLIPPAGE_TIERS.low.value;
1340
- };
1341
- const useRoutes = () => {
1342
- const latestRequestIdRef = reactExports.useRef(0);
1343
- const { addTokensState: { id }, addTokensDispatch } = reactExports.useContext(AddTokensContext);
1344
- const { providersState: { toProvider, }, } = useProvidersContext();
1345
- const { track } = useAnalytics();
1346
- const setRoutes = (routes) => {
1347
- addTokensDispatch({
1348
- payload: {
1349
- type: AddTokensActions.SET_ROUTES,
1350
- routes,
1351
- },
1352
- });
1344
+ /**
1345
+ * Hook to calculate slippage based on thresholds
1346
+ */
1347
+ const useSlippage = () => {
1348
+ const getSlippageTier = (usdAmount) => {
1349
+ if (usdAmount >= SLIPPAGE_TIERS.high.threshold)
1350
+ return SLIPPAGE_TIERS.high.value;
1351
+ if (usdAmount >= SLIPPAGE_TIERS.medium.threshold)
1352
+ return SLIPPAGE_TIERS.medium.value;
1353
+ return SLIPPAGE_TIERS.low.value;
1353
1354
  };
1354
- const resetRoutes = () => {
1355
- setRoutes([]);
1355
+ const calculateAdjustedAmount = (baseAmount, usdAmount, additionalBuffer = 0) => {
1356
+ const slippage = getSlippageTier(usdAmount);
1357
+ return baseAmount * (1 + slippage + additionalBuffer);
1356
1358
  };
1357
- const findToken = (tokens, address, chainId) => tokens.find((value) => value.address.toLowerCase() === address.toLowerCase()
1358
- && value.chainId === chainId);
1359
+ return reactExports.useMemo(() => ({
1360
+ getSlippageTier,
1361
+ calculateAdjustedAmount,
1362
+ }), []);
1363
+ };
1364
+
1365
+ /**
1366
+ * Hook to handle route amount calculations.
1367
+ */
1368
+ const useRouteCalculation = () => {
1369
+ const { calculateAdjustedAmount } = useSlippage();
1370
+ /**
1371
+ * Calculate the fromAmount based on USD prices and slippage.
1372
+ */
1359
1373
  const calculateFromAmount = (fromToken, toToken, toAmount, additionalBuffer = 0) => {
1360
1374
  const toAmountNumber = parseFloat(toAmount);
1361
1375
  // Calculate the USD value of the toAmount
@@ -1363,16 +1377,49 @@ const useRoutes = () => {
1363
1377
  // Calculate the amount of fromToken needed to match this USD value
1364
1378
  const baseFromAmount = toAmountInUsd / fromToken.usdPrice;
1365
1379
  // Add a buffer for price fluctuations and fees
1366
- const fromAmountWithBuffer = baseFromAmount * (1 + getSlippageTier(toAmountInUsd) + additionalBuffer);
1380
+ const fromAmountWithBuffer = calculateAdjustedAmount(baseFromAmount, toAmountInUsd, additionalBuffer);
1367
1381
  return fromAmountWithBuffer.toString();
1368
1382
  };
1383
+ /**
1384
+ * Calculate the fromAmount using exchange rate returned from the route.
1385
+ */
1369
1386
  const calculateFromAmountFromRoute = (exchangeRate, toAmount, toAmountUSD) => {
1370
1387
  const toAmountUSDNumber = toAmountUSD ? parseFloat(toAmountUSD) : 0;
1371
1388
  const fromAmount = parseFloat(toAmount) / parseFloat(exchangeRate);
1372
- const fromAmountWithBuffer = fromAmount * (1 + getSlippageTier(toAmountUSDNumber));
1389
+ const fromAmountWithBuffer = calculateAdjustedAmount(fromAmount, toAmountUSDNumber);
1373
1390
  return fromAmountWithBuffer.toString();
1374
1391
  };
1375
- const getAmountData = (tokens, balance, toAmount, toChainId, toTokenAddress, additionalBuffer = 0) => {
1392
+ /**
1393
+ * Convert a string amount to a formatted amount with the specified number of decimals.
1394
+ */
1395
+ const convertToFormattedFromAmount = (amount, decimals) => {
1396
+ const parsedFromAmount = parseFloat(amount).toFixed(decimals);
1397
+ const formattedFromAmount = parseUnits(parsedFromAmount, decimals);
1398
+ return formattedFromAmount.toString();
1399
+ };
1400
+ return reactExports.useMemo(() => ({
1401
+ calculateFromAmount,
1402
+ calculateFromAmountFromRoute,
1403
+ convertToFormattedFromAmount,
1404
+ }), []);
1405
+ };
1406
+
1407
+ class RouteError extends Error {
1408
+ message;
1409
+ data;
1410
+ constructor(message, data) {
1411
+ super(message);
1412
+ this.message = message;
1413
+ this.data = data;
1414
+ Object.setPrototypeOf(this, RouteError.prototype);
1415
+ }
1416
+ }
1417
+
1418
+ const useRoutes = () => {
1419
+ const latestRequestIdRef = reactExports.useRef(0);
1420
+ const { providersState: { toProvider, }, } = useProvidersContext();
1421
+ const { calculateFromAmount, calculateFromAmountFromRoute, convertToFormattedFromAmount } = useRouteCalculation();
1422
+ const getFromAmountData = (tokens, balance, toAmount, toChainId, toTokenAddress, additionalBuffer = 0) => {
1376
1423
  const fromToken = findToken(tokens, balance.address, balance.chainId.toString());
1377
1424
  const toToken = findToken(tokens, toTokenAddress, toChainId);
1378
1425
  if (!fromToken || !toToken) {
@@ -1390,114 +1437,48 @@ const useRoutes = () => {
1390
1437
  const getSufficientFromAmounts = (tokens, balances, toChainId, toTokenAddress, toAmount) => {
1391
1438
  const filteredBalances = balances.filter((balance) => !(balance.address.toLowerCase() === toTokenAddress.toLowerCase()
1392
1439
  && balance.chainId === toChainId));
1393
- const amountDataArray = filteredBalances
1394
- .map((balance) => getAmountData(tokens, balance, toAmount, toChainId, toTokenAddress))
1440
+ const fromAmountDataArray = filteredBalances
1441
+ .map((balance) => getFromAmountData(tokens, balance, toAmount, toChainId, toTokenAddress))
1395
1442
  .filter((value) => value !== undefined);
1396
- return amountDataArray.filter((data) => {
1443
+ return fromAmountDataArray.filter((data) => {
1397
1444
  const formattedBalance = formatUnits(data.balance.balance, data.balance.decimals);
1398
1445
  return (parseFloat(formattedBalance.toString()) > parseFloat(data.fromAmount));
1399
1446
  });
1400
1447
  };
1401
- const convertToFormattedAmount = (amount, decimals) => {
1402
- const parsedFromAmount = parseFloat(amount).toFixed(decimals);
1403
- const formattedFromAmount = parseUnits(parsedFromAmount, decimals);
1404
- return formattedFromAmount.toString();
1405
- };
1406
- const getRouteWithRetry = async (squid, fromToken, toToken, toAddress, fromAmount, fromAddress, quoteOnly = true, postHook) => {
1407
- try {
1408
- return await retry(() => squid.getRoute({
1409
- fromChain: fromToken.chainId,
1410
- fromToken: fromToken.address,
1411
- fromAmount: convertToFormattedAmount(fromAmount, fromToken.decimals),
1412
- toChain: toToken.chainId,
1413
- toToken: toToken.address,
1414
- fromAddress,
1415
- toAddress,
1416
- quoteOnly,
1417
- enableBoost: true,
1418
- receiveGasOnDestination: !isPassportProvider(toProvider),
1419
- postHook,
1420
- }), {
1421
- retryIntervalMs: 1000,
1422
- retries: 5,
1423
- nonRetryable: (err) => err.response?.status !== 429,
1424
- });
1425
- }
1426
- catch (error) {
1427
- track({
1428
- userJourney: UserJourney.ADD_TOKENS,
1429
- screen: 'Routes',
1430
- action: 'Failed',
1431
- extras: {
1432
- contextId: id,
1433
- fromToken: fromToken.symbol,
1434
- toToken: toToken.symbol,
1435
- fromChain: fromToken.chainId,
1436
- toChain: toToken.chainId,
1437
- errorStatus: error.response?.status,
1438
- errorMessage: error.response?.data?.message,
1439
- errorStack: error.stack,
1440
- },
1441
- });
1442
- throw error;
1443
- }
1444
- };
1445
- const isRouteToAmountGreaterThanToAmount = (routeResponse, toAmount) => {
1446
- if (!routeResponse?.route?.estimate?.toAmount || !routeResponse?.route?.estimate?.toToken?.decimals) {
1447
- throw new Error('Invalid route response or token decimals');
1448
- }
1449
- const toAmountInBaseUnits = parseUnits(toAmount, routeResponse?.route.estimate.toToken.decimals);
1450
- const routeToAmountInBaseUnits = BigNumber.from(routeResponse.route.estimate.toAmount);
1451
- return routeToAmountInBaseUnits.gt(toAmountInBaseUnits);
1452
- };
1448
+ const getRouteWithRetry = async (squid, fromToken, toToken, toAddress, fromAmount, fromAddress, quoteOnly = true, postHook) => retry(() => squid.getRoute({
1449
+ fromChain: fromToken.chainId,
1450
+ fromToken: fromToken.address,
1451
+ fromAmount: convertToFormattedFromAmount(fromAmount, fromToken.decimals),
1452
+ toChain: toToken.chainId,
1453
+ toToken: toToken.address,
1454
+ fromAddress,
1455
+ toAddress,
1456
+ quoteOnly,
1457
+ enableBoost: true,
1458
+ receiveGasOnDestination: !isPassportProvider(toProvider),
1459
+ postHook,
1460
+ }), {
1461
+ retryIntervalMs: 1000,
1462
+ retries: 5,
1463
+ nonRetryable: (err) => err.response?.status !== 429,
1464
+ });
1453
1465
  const getRoute = async (squid, fromToken, toToken, toAddress, fromAmount, toAmount, fromAddress, quoteOnly = true, postHook) => {
1454
- try {
1455
- const routeResponse = await getRouteWithRetry(squid, fromToken, toToken, toAddress, fromAmount, fromAddress, quoteOnly, postHook);
1456
- if (!routeResponse?.route) {
1457
- return {};
1458
- }
1459
- if (isRouteToAmountGreaterThanToAmount(routeResponse, toAmount)) {
1460
- return { route: routeResponse };
1461
- }
1462
- const newFromAmount = calculateFromAmountFromRoute(routeResponse.route.estimate.exchangeRate, toAmount, routeResponse.route.estimate.toAmountUSD);
1463
- const newRoute = await getRouteWithRetry(squid, fromToken, toToken, toAddress, newFromAmount, fromAddress, quoteOnly, postHook);
1464
- if (!newRoute?.route) {
1465
- return {};
1466
- }
1467
- if (isRouteToAmountGreaterThanToAmount(newRoute, toAmount)) {
1468
- return { route: newRoute };
1469
- }
1470
- track({
1471
- userJourney: UserJourney.ADD_TOKENS,
1472
- screen: 'Routes',
1473
- action: 'Failed',
1474
- extras: {
1475
- contextId: id,
1476
- fromToken: fromToken.symbol,
1477
- toToken: toToken.symbol,
1478
- fromChain: fromToken.chainId,
1479
- toChain: toToken.chainId,
1480
- initialRoute: {
1481
- fromAmount,
1482
- toAmount,
1483
- exchangeRate: routeResponse.route.estimate.exchangeRate,
1484
- routeFromAmount: routeResponse.route.estimate.fromAmount,
1485
- routeToAmount: routeResponse.route.estimate.toAmount,
1486
- },
1487
- newRoute: {
1488
- fromAmount: newFromAmount,
1489
- toAmount,
1490
- exchangeRate: newRoute.route.estimate.exchangeRate,
1491
- routeFromAmount: newRoute.route.estimate.fromAmount,
1492
- routeToAmount: newRoute.route.estimate.toAmount,
1493
- },
1494
- },
1495
- });
1466
+ const routeResponse = await getRouteWithRetry(squid, fromToken, toToken, toAddress, fromAmount, fromAddress, quoteOnly, postHook);
1467
+ if (!routeResponse?.route) {
1496
1468
  return {};
1497
1469
  }
1498
- catch (error) {
1470
+ if (isRouteToAmountGreaterThanToAmount(routeResponse, toAmount)) {
1471
+ return { route: routeResponse };
1472
+ }
1473
+ const newFromAmount = calculateFromAmountFromRoute(routeResponse.route.estimate.exchangeRate, toAmount, routeResponse.route.estimate.toAmountUSD);
1474
+ const newRoute = await getRouteWithRetry(squid, fromToken, toToken, toAddress, newFromAmount, fromAddress, quoteOnly, postHook);
1475
+ if (!newRoute?.route) {
1499
1476
  return {};
1500
1477
  }
1478
+ if (isRouteToAmountGreaterThanToAmount(newRoute, toAmount)) {
1479
+ return { route: newRoute };
1480
+ }
1481
+ throw new Error('Unable to find a route with sufficient toAmount');
1501
1482
  };
1502
1483
  const getRoutesWithFeesValidation = async (squid, toTokenAddress, balances, fromAmountArray, postHook) => {
1503
1484
  const getGasCost = (route, chainId) => (route.route?.route.estimate.gasCosts || [])
@@ -1520,59 +1501,68 @@ const useRoutes = () => {
1520
1501
  return userBalance >= requiredAmount;
1521
1502
  };
1522
1503
  const routePromises = fromAmountArray.map(async (data) => {
1523
- try {
1524
- const routeResponse = await getRoute(squid, data.fromToken, data.toToken, toTokenAddress, data.fromAmount, data.toAmount, undefined, true, postHook);
1525
- if (!routeResponse?.route)
1526
- return null;
1527
- const gasCost = getGasCost(routeResponse, data.balance.chainId);
1528
- const feeCost = getTotalFees(routeResponse, data.balance.chainId);
1529
- const userGasBalance = findUserGasBalance(data.balance.chainId);
1530
- return {
1531
- amountData: data,
1532
- route: routeResponse.route,
1533
- isInsufficientGas: !hasSufficientNativeTokenBalance(userGasBalance, data.fromAmount, data.fromToken, gasCost, feeCost),
1534
- };
1535
- }
1536
- catch (error) {
1504
+ const routeResponse = await getRoute(squid, data.fromToken, data.toToken, toTokenAddress, data.fromAmount, data.toAmount, undefined, true, postHook);
1505
+ if (!routeResponse?.route)
1537
1506
  return null;
1538
- }
1507
+ const gasCost = getGasCost(routeResponse, data.balance.chainId);
1508
+ const feeCost = getTotalFees(routeResponse, data.balance.chainId);
1509
+ const userGasBalance = findUserGasBalance(data.balance.chainId);
1510
+ return {
1511
+ amountData: data,
1512
+ route: routeResponse.route,
1513
+ isInsufficientGas: !hasSufficientNativeTokenBalance(userGasBalance, data.fromAmount, data.fromToken, gasCost, feeCost),
1514
+ };
1539
1515
  });
1540
- const routesData = (await Promise.all(routePromises)).filter((route) => route !== null);
1516
+ const routesData = (await Promise.allSettled(routePromises))
1517
+ .filter((result) => result.status === 'fulfilled')
1518
+ .map((result) => result.value)
1519
+ .filter((route) => route !== null);
1541
1520
  return routesData;
1542
1521
  };
1543
- const fetchRoutesWithRateLimit = async (squid, tokens, balances, toChanId, toTokenAddress, toAmount, bulkNumber = 5, delayMs = 1000, isSwapAllowed = true) => {
1522
+ const fetchRoutes = async (squid, tokens, balances, toChainId, toTokenAddress, toAmount, bulkNumber = 5, delayMs = 1000, isSwapAllowed = true) => {
1544
1523
  const currentRequestId = ++latestRequestIdRef.current;
1545
- let fromAmountDataArray = getSufficientFromAmounts(tokens, balances, toChanId, toTokenAddress, toAmount);
1546
- if (!isSwapAllowed) {
1547
- fromAmountDataArray = fromAmountDataArray.filter((amountData) => amountData.balance.chainId !== toChanId);
1548
- }
1549
- let allRoutes = [];
1550
- await Promise.all(fromAmountDataArray
1551
- .reduce((acc, _, i) => {
1552
- if (i % bulkNumber === 0) {
1553
- acc.push(fromAmountDataArray.slice(i, i + bulkNumber));
1524
+ try {
1525
+ let fromAmountDataArray = getSufficientFromAmounts(tokens, balances, toChainId, toTokenAddress, toAmount);
1526
+ if (!isSwapAllowed) {
1527
+ fromAmountDataArray = fromAmountDataArray.filter((amountData) => amountData.balance.chainId !== toChainId);
1554
1528
  }
1555
- return acc;
1556
- }, [])
1557
- .map(async (slicedFromAmountDataArray) => {
1558
- allRoutes.push(...(await getRoutesWithFeesValidation(squid, toTokenAddress, balances, slicedFromAmountDataArray)));
1559
- await delay(delayMs);
1560
- }));
1561
- if (!isSwapAllowed) {
1562
- allRoutes = allRoutes.filter((routeData) => !routeData.route.route.estimate.actions.find((action) => action.type === dist$3.ActionType.SWAP));
1529
+ let allRoutes = [];
1530
+ await Promise.all(fromAmountDataArray
1531
+ .reduce((acc, _, i) => {
1532
+ if (i % bulkNumber === 0) {
1533
+ acc.push(fromAmountDataArray.slice(i, i + bulkNumber));
1534
+ }
1535
+ return acc;
1536
+ }, [])
1537
+ .map(async (slicedFromAmountDataArray) => {
1538
+ allRoutes.push(...(await getRoutesWithFeesValidation(squid, toTokenAddress, balances, slicedFromAmountDataArray)));
1539
+ await delay(delayMs);
1540
+ }));
1541
+ if (!isSwapAllowed) {
1542
+ allRoutes = allRoutes.filter((routeData) => !routeData.route.route.estimate.actions.find((action) => action.type === dist$3.ActionType.SWAP));
1543
+ }
1544
+ const sortedRoutes = sortRoutesByFastestTime(allRoutes);
1545
+ // Only return routes if the request is the latest one
1546
+ if (currentRequestId === latestRequestIdRef.current) {
1547
+ return sortedRoutes;
1548
+ }
1549
+ return [];
1563
1550
  }
1564
- const sortedRoutes = sortRoutesByFastestTime(allRoutes);
1565
- // Only update routes if the request is the latest one
1566
- if (currentRequestId === latestRequestIdRef.current) {
1567
- setRoutes(sortedRoutes);
1551
+ catch (error) {
1552
+ throw new RouteError('Failed to fetch routes', {
1553
+ fromToken: tokens.find((token) => token.address === toTokenAddress)?.symbol,
1554
+ toToken: tokens.find((token) => token.address === toTokenAddress)?.symbol,
1555
+ toChain: toChainId,
1556
+ errorStatus: error.response?.status,
1557
+ errorMessage: error.response?.data?.message,
1558
+ errorStack: error.stack,
1559
+ });
1568
1560
  }
1569
- return sortedRoutes;
1570
1561
  };
1571
1562
  return {
1572
- fetchRoutesWithRateLimit,
1573
- getAmountData,
1563
+ fetchRoutes,
1564
+ getFromAmountData,
1574
1565
  getRoute,
1575
- resetRoutes,
1576
1566
  };
1577
1567
  };
1578
1568
 
@@ -5295,7 +5285,7 @@ const checkSanctionedAddresses = async (addresses, config) => {
5295
5285
 
5296
5286
  function AddTokens({ checkout, toAmount, config, toTokenAddress, showOnrampOption = true, showSwapOption = true, showBridgeOption = true, onCloseButtonClick, showBackButton, onBackButtonClick, }) {
5297
5287
  const inputRef = reactExports.useRef(null);
5298
- const { fetchRoutesWithRateLimit, resetRoutes } = useRoutes();
5288
+ const { fetchRoutes } = useRoutes();
5299
5289
  const { showErrorHandover } = useError(config.environment);
5300
5290
  const { addTokensState, addTokensDispatch, } = reactExports.useContext(AddTokensContext);
5301
5291
  const { id, squid, chains, balances, tokens, selectedAmount, routes, selectedRouteData, selectedToken, isSwapAvailable, experiments, } = addTokensState;
@@ -5326,6 +5316,14 @@ function AddTokens({ checkout, toAmount, config, toTokenAddress, showOnrampOptio
5326
5316
  setIsAmountInputSynced(false);
5327
5317
  debouncedSetSelectedAmount.current(value);
5328
5318
  };
5319
+ const resetRoutes = () => {
5320
+ addTokensDispatch({
5321
+ payload: {
5322
+ type: AddTokensActions.SET_ROUTES,
5323
+ routes: [],
5324
+ },
5325
+ });
5326
+ };
5329
5327
  reactExports.useEffect(() => {
5330
5328
  if (selectedAmount === inputValue) {
5331
5329
  setIsAmountInputSynced(true);
@@ -5450,25 +5448,47 @@ function AddTokens({ checkout, toAmount, config, toTokenAddress, showOnrampOptio
5450
5448
  && selectedToken?.address
5451
5449
  && isValidAmount) {
5452
5450
  setFetchingRoutes(true);
5453
- const availableRoutes = await fetchRoutesWithRateLimit(squid, tokens, balances, ChainId.IMTBL_ZKEVM_MAINNET.toString(), selectedToken.address === 'native'
5454
- ? SQUID_NATIVE_TOKEN
5455
- : selectedToken.address, selectedAmount, 5, 1000, isSwapAvailable);
5456
- setFetchingRoutes(false);
5457
- track({
5458
- userJourney: UserJourney.ADD_TOKENS,
5459
- screen: 'InputScreen',
5460
- control: 'RoutesMenu',
5461
- controlType: 'MenuItem',
5462
- action: 'Request',
5463
- extras: {
5464
- contextId: id,
5465
- routesAvailable: availableRoutes.length,
5466
- geoBlocked: !isSwapAvailable,
5467
- },
5468
- });
5469
- if (availableRoutes.length === 0) {
5470
- setInsufficientBalance(true);
5451
+ try {
5452
+ const availableRoutes = await fetchRoutes(squid, tokens, balances, ChainId.IMTBL_ZKEVM_MAINNET.toString(), selectedToken.address === 'native'
5453
+ ? SQUID_NATIVE_TOKEN
5454
+ : selectedToken.address, selectedAmount, 5, 1000, isSwapAvailable);
5455
+ addTokensDispatch({
5456
+ payload: {
5457
+ type: AddTokensActions.SET_ROUTES,
5458
+ routes: availableRoutes,
5459
+ },
5460
+ });
5461
+ if (availableRoutes.length === 0) {
5462
+ setInsufficientBalance(true);
5463
+ }
5464
+ track({
5465
+ userJourney: UserJourney.ADD_TOKENS,
5466
+ screen: 'InputScreen',
5467
+ control: 'RoutesMenu',
5468
+ controlType: 'MenuItem',
5469
+ action: 'Request',
5470
+ extras: {
5471
+ contextId: id,
5472
+ routesAvailable: availableRoutes.length,
5473
+ geoBlocked: !isSwapAvailable,
5474
+ },
5475
+ });
5471
5476
  }
5477
+ catch (error) {
5478
+ if (error instanceof RouteError && error.data) {
5479
+ track({
5480
+ userJourney: UserJourney.ADD_TOKENS,
5481
+ screen: 'Routes',
5482
+ action: 'Failed',
5483
+ extras: {
5484
+ contextId: id,
5485
+ message: error.message,
5486
+ ...error.data,
5487
+ },
5488
+ });
5489
+ }
5490
+ }
5491
+ setFetchingRoutes(false);
5472
5492
  }
5473
5493
  })();
5474
5494
  }, [balances, squid, selectedToken, selectedAmount]);
@@ -172836,10 +172856,8 @@ function isRejectedError(err) {
172836
172856
  }
172837
172857
 
172838
172858
  const TRANSACTION_NOT_COMPLETED = 'transaction not completed';
172839
- const useExecute = (contextId, environment) => {
172840
- const { showErrorHandover } = useError(environment);
172859
+ const useExecute = (userJourney, onTransactionError) => {
172841
172860
  const { user } = useAnalytics();
172842
- const { eventTargetState: { eventTarget }, } = reactExports.useContext(EventTargetContext);
172843
172861
  const waitForReceipt = async (provider, txHash, maxAttempts = 120) => {
172844
172862
  const result = await retry(async () => {
172845
172863
  const receipt = await provider.getTransactionReceipt(txHash);
@@ -172860,62 +172878,6 @@ const useExecute = (contextId, environment) => {
172860
172878
  }
172861
172879
  return result;
172862
172880
  };
172863
- const handleTransactionError = (err) => {
172864
- const reason = `${err?.reason || err?.message || ''}`.toLowerCase();
172865
- let errorType = AddTokensErrorTypes.WALLET_FAILED;
172866
- if (reason.includes('failed') && reason.includes('open confirmation')) {
172867
- errorType = AddTokensErrorTypes.WALLET_POPUP_BLOCKED;
172868
- }
172869
- if (reason.includes('rejected') && reason.includes('user')) {
172870
- errorType = AddTokensErrorTypes.WALLET_REJECTED;
172871
- }
172872
- if (reason.includes('failed to submit')
172873
- && reason.includes('highest gas limit')) {
172874
- errorType = AddTokensErrorTypes.WALLET_REJECTED_NO_FUNDS;
172875
- }
172876
- if (reason.includes('status failed')
172877
- || reason.includes('transaction failed')) {
172878
- errorType = AddTokensErrorTypes.TRANSACTION_FAILED;
172879
- sendAddTokensFailedEvent(eventTarget, errorType);
172880
- }
172881
- if (reason.includes('unrecognized chain')
172882
- || reason.includes('unrecognized chain')) {
172883
- errorType = AddTokensErrorTypes.UNRECOGNISED_CHAIN;
172884
- }
172885
- const error = {
172886
- type: errorType,
172887
- data: { error: err },
172888
- };
172889
- showErrorHandover(errorType, { contextId, error });
172890
- };
172891
- // @TODO: Move to util function
172892
- const checkProviderChain = async (provider, chainId) => {
172893
- if (!provider.provider.request) {
172894
- throw new Error('provider does not have request method');
172895
- }
172896
- try {
172897
- const fromChainHex = `0x${parseInt(chainId, 10).toString(16)}`;
172898
- const providerChainId = await provider.provider.request({
172899
- method: 'eth_chainId',
172900
- });
172901
- if (fromChainHex !== providerChainId) {
172902
- await provider.provider.request({
172903
- method: 'wallet_switchEthereumChain',
172904
- params: [
172905
- {
172906
- chainId: fromChainHex,
172907
- },
172908
- ],
172909
- });
172910
- return true;
172911
- }
172912
- return true;
172913
- }
172914
- catch (error) {
172915
- handleTransactionError(error);
172916
- return false;
172917
- }
172918
- };
172919
172881
  const getAllowance = async (provider, routeResponse) => {
172920
172882
  try {
172921
172883
  if (!isSquidNativeToken(routeResponse?.route?.params.fromToken)) {
@@ -172935,7 +172897,7 @@ const useExecute = (contextId, environment) => {
172935
172897
  return MaxUint256; // no approval is needed for native tokens
172936
172898
  }
172937
172899
  catch (error) {
172938
- showErrorHandover(AddTokensErrorTypes.DEFAULT, { contextId, error });
172900
+ onTransactionError?.(error);
172939
172901
  return undefined;
172940
172902
  }
172941
172903
  };
@@ -172971,12 +172933,12 @@ const useExecute = (contextId, environment) => {
172971
172933
  const approve = async (fromProviderInfo, provider, routeResponse) => {
172972
172934
  try {
172973
172935
  if (!isSquidNativeToken(routeResponse?.route?.params.fromToken)) {
172974
- return await withMetricsAsync((flow) => callApprove(flow, fromProviderInfo, provider, routeResponse), `${UserJourney.ADD_TOKENS}_Approve`, await getAnonymousId(), (error) => (isRejectedError(error) ? 'rejected' : ''));
172936
+ return await withMetricsAsync((flow) => callApprove(flow, fromProviderInfo, provider, routeResponse), `${userJourney}_Approve`, await getAnonymousId(), (error) => (isRejectedError(error) ? 'rejected' : ''));
172975
172937
  }
172976
172938
  return undefined;
172977
172939
  }
172978
172940
  catch (error) {
172979
- handleTransactionError(error);
172941
+ onTransactionError?.(error);
172980
172942
  return undefined;
172981
172943
  }
172982
172944
  };
@@ -172994,10 +172956,10 @@ const useExecute = (contextId, environment) => {
172994
172956
  throw new Error('provider does not have request method');
172995
172957
  }
172996
172958
  try {
172997
- return await withMetricsAsync((flow) => callExecute(flow, squid, fromProviderInfo, provider, routeResponse), `${UserJourney.ADD_TOKENS}_Execute`, await getAnonymousId(), (error) => (isRejectedError(error) ? 'rejected' : ''));
172959
+ return await withMetricsAsync((flow) => callExecute(flow, squid, fromProviderInfo, provider, routeResponse), `${userJourney}_Execute`, await getAnonymousId(), (error) => (isRejectedError(error) ? 'rejected' : ''));
172998
172960
  }
172999
172961
  catch (error) {
173000
- handleTransactionError(error);
172962
+ onTransactionError?.(error);
173001
172963
  return undefined;
173002
172964
  }
173003
172965
  };
@@ -173029,12 +172991,11 @@ const useExecute = (contextId, environment) => {
173029
172991
  });
173030
172992
  }
173031
172993
  catch (error) {
173032
- handleTransactionError(error);
172994
+ onTransactionError?.(error);
173033
172995
  return undefined;
173034
172996
  }
173035
172997
  };
173036
172998
  return {
173037
- checkProviderChain,
173038
172999
  getAllowance,
173039
173000
  approve,
173040
173001
  execute,
@@ -173128,6 +173089,78 @@ function RouteFees({ visible, onClose, routeData, totalAmount, totalFiatAmount,
173128
173089
  return (jsx(FeesBreakdown, { visible: visible, loading: !routeData, fees: [...feeCosts, ...gasCosts], tokenSymbol: tokenSymbol, totalAmount: getFormattedNumber(totalAmount, feesToken?.decimals), totalFiatAmount: getFormattedAmounts(totalFiatAmount), onCloseDrawer: onClose }));
173129
173090
  }
173130
173091
 
173092
+ /**
173093
+ * Ensure the provider is connected to the correct chain.
173094
+ * If not, attempts to switch to the desired chain.
173095
+ */
173096
+ const verifyAndSwitchChain = async (provider, chainId) => {
173097
+ if (!provider.provider.request) {
173098
+ return {
173099
+ isChainCorrect: false,
173100
+ error: 'Provider does not support the request method.',
173101
+ };
173102
+ }
173103
+ try {
173104
+ const targetChainHex = `0x${parseInt(chainId, 10).toString(16)}`;
173105
+ const currentChainId = await provider.provider.request({
173106
+ method: 'eth_chainId',
173107
+ });
173108
+ if (targetChainHex !== currentChainId) {
173109
+ await provider.provider.request({
173110
+ method: 'wallet_switchEthereumChain',
173111
+ params: [
173112
+ {
173113
+ chainId: targetChainHex,
173114
+ },
173115
+ ],
173116
+ });
173117
+ }
173118
+ return { isChainCorrect: true };
173119
+ }
173120
+ catch (error) {
173121
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
173122
+ return {
173123
+ isChainCorrect: false,
173124
+ error: errorMessage,
173125
+ };
173126
+ }
173127
+ };
173128
+
173129
+ const useErrorHandler = () => {
173130
+ const { addTokensState: { id: contextId }, } = reactExports.useContext(AddTokensContext);
173131
+ const { providersState: { checkout, }, } = useProvidersContext();
173132
+ const { showErrorHandover } = useError(checkout.config.environment);
173133
+ const { eventTargetState: { eventTarget }, } = reactExports.useContext(EventTargetContext);
173134
+ const onTransactionError = (err) => {
173135
+ const reason = `${err?.reason || err?.message || ''}`.toLowerCase();
173136
+ let errorType = AddTokensErrorTypes.WALLET_FAILED;
173137
+ if (reason.includes('failed') && reason.includes('open confirmation')) {
173138
+ errorType = AddTokensErrorTypes.WALLET_POPUP_BLOCKED;
173139
+ }
173140
+ if (reason.includes('rejected') && reason.includes('user')) {
173141
+ errorType = AddTokensErrorTypes.WALLET_REJECTED;
173142
+ }
173143
+ if (reason.includes('failed to submit')
173144
+ && reason.includes('highest gas limit')) {
173145
+ errorType = AddTokensErrorTypes.WALLET_REJECTED_NO_FUNDS;
173146
+ }
173147
+ if (reason.includes('status failed')
173148
+ || reason.includes('transaction failed')) {
173149
+ errorType = AddTokensErrorTypes.TRANSACTION_FAILED;
173150
+ sendAddTokensFailedEvent(eventTarget, errorType);
173151
+ }
173152
+ if (reason.includes('unrecognized chain')) {
173153
+ errorType = AddTokensErrorTypes.UNRECOGNISED_CHAIN;
173154
+ }
173155
+ const error = {
173156
+ type: errorType,
173157
+ data: { error: err },
173158
+ };
173159
+ showErrorHandover(errorType, { contextId, error });
173160
+ };
173161
+ return { onTransactionError };
173162
+ };
173163
+
173131
173164
  const dividerSx = {
173132
173165
  content: "''",
173133
173166
  pos: 'absolute',
@@ -173140,6 +173173,7 @@ function Review({ data, showBackButton = false, onBackButtonClick, onCloseButton
173140
173173
  const { track, page } = useAnalytics();
173141
173174
  const { addTokensState: { id, squid, chains, tokens, }, } = reactExports.useContext(AddTokensContext);
173142
173175
  const { providersState: { checkout, fromProvider, fromAddress, toAddress, fromProviderInfo, }, } = useProvidersContext();
173176
+ const { showErrorHandover } = useError(checkout.config.environment);
173143
173177
  const { eventTargetState: { eventTarget }, } = reactExports.useContext(EventTargetContext);
173144
173178
  const [route, setRoute] = reactExports.useState();
173145
173179
  const [amountData, setAmountData] = reactExports.useState();
@@ -173147,12 +173181,12 @@ function Review({ data, showBackButton = false, onBackButtonClick, onCloseButton
173147
173181
  const [showFeeBreakdown, setShowFeeBreakdown] = reactExports.useState(false);
173148
173182
  const [showSecuringQuote, setShowSecuringQuote] = reactExports.useState(false);
173149
173183
  const [showAddressMissmatchDrawer, setShowAddressMissmatchDrawer] = reactExports.useState(false);
173150
- const { getAmountData, getRoute } = useRoutes();
173184
+ const { getFromAmountData, getRoute } = useRoutes();
173151
173185
  const { addHandover, closeHandover } = useHandover({
173152
173186
  id: HandoverTarget.GLOBAL,
173153
173187
  });
173154
- const { showErrorHandover } = useError(checkout.config.environment);
173155
- const { checkProviderChain, getAllowance, approve, execute, getStatus, } = useExecute(id, checkout?.config.environment || Environment.SANDBOX);
173188
+ const { onTransactionError } = useErrorHandler();
173189
+ const { getAllowance, approve, execute, getStatus, } = useExecute(UserJourney.ADD_TOKENS, onTransactionError);
173156
173190
  reactExports.useEffect(() => {
173157
173191
  page({
173158
173192
  userJourney: UserJourney.ADD_TOKENS,
@@ -173171,7 +173205,7 @@ function Review({ data, showBackButton = false, onBackButtonClick, onCloseButton
173171
173205
  if (!fromAddress || !toAddress)
173172
173206
  return;
173173
173207
  setShowSecuringQuote(true);
173174
- const updatedAmountData = getAmountData(tokens, data.balance, data.toAmount, data.toChainId, data.toTokenAddress === 'native'
173208
+ const updatedAmountData = getFromAmountData(tokens, data.balance, data.toAmount, data.toChainId, data.toTokenAddress === 'native'
173175
173209
  ? SQUID_NATIVE_TOKEN
173176
173210
  : data.toTokenAddress, data.additionalBuffer);
173177
173211
  if (!updatedAmountData)
@@ -173278,8 +173312,8 @@ function Review({ data, showBackButton = false, onBackButtonClick, onCloseButton
173278
173312
  headingText: t('views.ADD_TOKENS.handover.preparing.heading'),
173279
173313
  });
173280
173314
  const changeableProvider = await convertToNetworkChangeableProvider(fromProvider);
173281
- const isValidNetwork = await checkProviderChain(changeableProvider, route.route.params.fromChain);
173282
- if (!isValidNetwork) {
173315
+ const verifyChainResult = await verifyAndSwitchChain(changeableProvider, route.route.params.fromChain);
173316
+ if (!verifyChainResult.isChainCorrect) {
173283
173317
  return;
173284
173318
  }
173285
173319
  const allowance = await getAllowance(changeableProvider, route);
@@ -173434,7 +173468,6 @@ function Review({ data, showBackButton = false, onBackButtonClick, onCloseButton
173434
173468
  getRouteIntervalIdRef,
173435
173469
  approve,
173436
173470
  showHandover,
173437
- checkProviderChain,
173438
173471
  getAllowance,
173439
173472
  execute,
173440
173473
  closeHandover,