@imtbl/checkout-widgets 2.4.13 → 2.4.14-alpha.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 (41) hide show
  1. package/dist/browser/{AddTokensWidget-Dw62MGE7.js → AddTokensWidget-CF1YN2qr.js} +4 -4
  2. package/dist/browser/{BridgeWidget-pB9NQr0j.js → BridgeWidget-D1iYISBu.js} +6 -6
  3. package/dist/browser/{CommerceWidget-CmGjTT5f.js → CommerceWidget-0xlC0qeb.js} +13 -13
  4. package/dist/browser/{FeesBreakdown-D42F89mf.js → FeesBreakdown-9FvnOOCN.js} +1 -1
  5. package/dist/browser/{OnRampWidget-C11vbDpE.js → OnRampWidget-Db0Ma0JP.js} +3 -3
  6. package/dist/browser/{SaleWidget-C-kIuH_x.js → SaleWidget-BiU-JU_Y.js} +10 -10
  7. package/dist/browser/{SpendingCapHero-DxECFPhZ.js → SpendingCapHero-DoDWVXeM.js} +1 -1
  8. package/dist/browser/{SwapWidget-CaimjlZx.js → SwapWidget-0b44o7OG.js} +6 -6
  9. package/dist/browser/{TokenImage-CJcf0BVb.js → TokenImage-ON5CsElS.js} +1 -1
  10. package/dist/browser/{TopUpView-DIAfMQDk.js → TopUpView-BSsm_pag.js} +1 -1
  11. package/dist/browser/{WalletApproveHero-2qnl25R9.js → WalletApproveHero-BpQET2Ry.js} +2 -2
  12. package/dist/browser/{WalletWidget-EUpKwouL.js → WalletWidget-DPtHMDzk.js} +3 -3
  13. package/dist/browser/{auto-track-BLHegHT2.js → auto-track-YB97xHhP.js} +1 -1
  14. package/dist/browser/{index-BZQairfY.js → index-B6LlGDqn.js} +2 -2
  15. package/dist/browser/{index-B1kcsGhP.js → index-BGfRODL9.js} +1 -1
  16. package/dist/browser/{index-Co43S-f8.js → index-CYSUCb_r.js} +174 -192
  17. package/dist/browser/{index-C52OgfPn.js → index-CxVwwdjo.js} +1 -1
  18. package/dist/browser/{index-iCexzEAZ.js → index-DfqbSiW-.js} +1 -1
  19. package/dist/browser/{index-C7zLn4CO.js → index-DhJhrEPT.js} +1 -1
  20. package/dist/browser/{index-B6adB8ks.js → index-DkUaawBA.js} +1 -1
  21. package/dist/browser/{index-COIl8mga.js → index-_E9_8iXP.js} +1 -1
  22. package/dist/browser/index.js +1 -1
  23. package/dist/browser/{index.umd-ENtuIC6R.js → index.umd-C_C0lXQh.js} +1 -1
  24. package/dist/browser/{useInterval-BaXQ-Cl5.js → useInterval-BjJWflew.js} +1 -1
  25. package/dist/types/lib/squid/functions/execute.d.ts +8 -0
  26. package/dist/types/lib/squid/functions/routeCalculation.d.ts +22 -0
  27. package/dist/types/lib/squid/functions/slippage.d.ts +1 -0
  28. package/dist/types/lib/squid/hooks/useExecute.d.ts +1 -2
  29. package/dist/types/lib/squid/hooks/useRoutes.d.ts +1 -5
  30. package/package.json +7 -7
  31. package/src/lib/squid/functions/execute.ts +88 -0
  32. package/src/lib/squid/functions/routeCalculation.ts +162 -0
  33. package/src/lib/squid/functions/slippage.ts +36 -0
  34. package/src/lib/squid/hooks/useExecute.ts +3 -85
  35. package/src/lib/squid/hooks/useRoutes.ts +5 -115
  36. package/src/widgets/add-tokens/views/Review.tsx +2 -1
  37. package/src/widgets/purchase/views/Purchase.tsx +8 -2
  38. package/dist/types/lib/squid/hooks/useRouteCalculation.d.ts +0 -9
  39. package/dist/types/lib/squid/hooks/useSlippage.d.ts +0 -7
  40. package/src/lib/squid/hooks/useRouteCalculation.ts +0 -60
  41. package/src/lib/squid/hooks/useSlippage.ts +0 -45
@@ -1,4 +1,4 @@
1
- import { e4 as __awaiter, e5 as __generator, e6 as loadScript, e7 as getNextIntegrationsURL, e8 as unloadScript, e9 as __spreadArray, ea as isOffline, eb as __assign, ec as ContextCancelation, ed as applyDestinationMiddleware, ee as dist, ef as isServer, eg as mergedOptions, eh as isPlainObject, ei as pWhile, ej as PriorityQueue, ek as PersistedPriorityQueue, el as attempt, em as isOnline, en as Context } from './index-Co43S-f8.js';
1
+ import { e5 as __awaiter, e6 as __generator, e7 as loadScript, e8 as getNextIntegrationsURL, e9 as unloadScript, ea as __spreadArray, eb as isOffline, ec as __assign, ed as ContextCancelation, ee as applyDestinationMiddleware, ef as dist, eg as isServer, eh as mergedOptions, ei as isPlainObject, ej as pWhile, ek as PriorityQueue, el as PersistedPriorityQueue, em as attempt, en as isOnline, eo as Context } from './index-CYSUCb_r.js';
2
2
  import { i as isPlanEventEnabled } from './is-plan-event-enabled-mXX0dwl-.js';
3
3
 
4
4
  function normalizeName(name) {
@@ -1,4 +1,4 @@
1
- import { dW as se$1, dX as T$2, dY as oe$1, dZ as R$1, d_ as a$2, d$ as te$1, e0 as p$1, e1 as ne$1, e2 as y$1 } from './index-Co43S-f8.js';
1
+ import { dX as se$1, dY as T$2, dZ as oe$1, d_ as R$1, d$ as a$2, e0 as te$1, e1 as p$1, e2 as ne$1, e3 as y$1 } from './index-CYSUCb_r.js';
2
2
 
3
3
  /**
4
4
  * @license
@@ -1,4 +1,4 @@
1
- import { ep as gracefulDecodeURIComponent, eh as isPlainObject } from './index-Co43S-f8.js';
1
+ import { eq as gracefulDecodeURIComponent, ei as isPlainObject } from './index-CYSUCb_r.js';
2
2
 
3
3
  /**
4
4
  * Returns an object containing only the properties prefixed by the input
@@ -1,4 +1,4 @@
1
- import { e4 as __awaiter, e5 as __generator, ef as isServer, e7 as getNextIntegrationsURL, e6 as loadScript } from './index-Co43S-f8.js';
1
+ import { e5 as __awaiter, e6 as __generator, eg as isServer, e8 as getNextIntegrationsURL, e7 as loadScript } from './index-CYSUCb_r.js';
2
2
 
3
3
  function remoteMiddlewares(ctx, settings, obfuscate) {
4
4
  var _a;
@@ -1,4 +1,4 @@
1
- import { eb as __assign } from './index-Co43S-f8.js';
1
+ import { ec as __assign } from './index-CYSUCb_r.js';
2
2
  import { i as isPlanEventEnabled } from './is-plan-event-enabled-mXX0dwl-.js';
3
3
 
4
4
  function disabledActionDestinations(plan, settings) {
@@ -1 +1 @@
1
- export { eq as WidgetsFactory } from './index-Co43S-f8.js';
1
+ export { er as WidgetsFactory } from './index-CYSUCb_r.js';
@@ -1,4 +1,4 @@
1
- import { ay as getDefaultExportFromCjs } from './index-Co43S-f8.js';
1
+ import { ay as getDefaultExportFromCjs } from './index-CYSUCb_r.js';
2
2
 
3
3
  function _mergeNamespaces(n, m) {
4
4
  m.forEach(function (e) {
@@ -1,4 +1,4 @@
1
- import { r as reactExports, dV as useBrowserLayoutEffect } from './index-Co43S-f8.js';
1
+ import { r as reactExports, dW as useBrowserLayoutEffect } from './index-CYSUCb_r.js';
2
2
 
3
3
  // Inspired by https://usehooks-ts.com/react-hook/use-interval
4
4
  function useInterval(callback, delay) {
@@ -0,0 +1,8 @@
1
+ import { EIP6963ProviderInfo, WrappedBrowserProvider } from '@imtbl/checkout-sdk';
2
+ import { Flow } from '@imtbl/metrics';
3
+ import { ethers, TransactionReceipt } from 'ethers';
4
+ import { RouteResponse } from '@0xsquid/squid-types';
5
+ import { Squid } from '@0xsquid/sdk';
6
+ export declare const waitForReceipt: (provider: WrappedBrowserProvider, txHash: string, maxAttempts?: number) => Promise<ethers.TransactionReceipt>;
7
+ export declare const callApprove: (flow: Flow, fromProviderInfo: EIP6963ProviderInfo, provider: WrappedBrowserProvider, routeResponse: RouteResponse) => Promise<TransactionReceipt>;
8
+ export declare const callExecute: (flow: Flow, squid: Squid, fromProviderInfo: EIP6963ProviderInfo, provider: WrappedBrowserProvider, routeResponse: RouteResponse) => Promise<TransactionReceipt>;
@@ -0,0 +1,22 @@
1
+ import { TokenBalance } from '@0xsquid/sdk/dist/types';
2
+ import { WrappedBrowserProvider } from '@imtbl/checkout-sdk';
3
+ import { FromAmountData, Token } from '../types';
4
+ /**
5
+ * Functions to handle route amount calculations.
6
+ */
7
+ /**
8
+ * Calculate the fromAmount based on USD prices and slippage.
9
+ */
10
+ export declare const calculateFromAmount: (fromToken: Token, toToken: Token, toAmount: string, additionalBuffer?: number) => string;
11
+ /**
12
+ * Calculate the fromAmount using exchange rate returned from the route.
13
+ */
14
+ export declare const calculateFromAmountFromRoute: (exchangeRate: string, toAmount: string, toAmountUSD?: string) => string;
15
+ /**
16
+ * Convert a string amount to a formatted amount with the specified number of decimals.
17
+ */
18
+ export declare const convertToFormattedFromAmount: (amount: string, decimals: number) => string;
19
+ export declare const getFromAmountData: (tokens: Token[], balance: TokenBalance, toAmount: string, toChainId: string, toTokenAddress: string, additionalBuffer?: number) => FromAmountData | undefined;
20
+ export declare const getSufficientFromAmounts: (tokens: Token[], balances: TokenBalance[], toChainId: string, toTokenAddress: string, toAmount: string) => FromAmountData[];
21
+ export declare const hasSufficientBalance: (balances: TokenBalance[], toTokenAddress: string, toChainId: string, toAmount: string) => boolean;
22
+ export declare const hasSufficientGas: (balances: TokenBalance[], selectedChainId: string | number, provider: WrappedBrowserProvider | undefined) => boolean;
@@ -0,0 +1 @@
1
+ export declare const calculateAdjustedAmount: (baseAmount: number, usdAmount: number, additionalBuffer?: number) => number;
@@ -1,6 +1,6 @@
1
1
  import { RouteResponse } from '@0xsquid/squid-types';
2
2
  import { Squid } from '@0xsquid/sdk';
3
- import { ethers, TransactionReceipt } from 'ethers';
3
+ import { TransactionReceipt } from 'ethers';
4
4
  import { StatusResponse } from '@0xsquid/sdk/dist/types';
5
5
  import { EIP6963ProviderInfo, WrappedBrowserProvider } from '@imtbl/checkout-sdk';
6
6
  import { UserJourney } from '../../../context/analytics-provider/SegmentAnalyticsProvider';
@@ -9,5 +9,4 @@ export declare const useExecute: (userJourney: UserJourney, onTransactionError?:
9
9
  approve: (fromProviderInfo: EIP6963ProviderInfo, provider: WrappedBrowserProvider, routeResponse: RouteResponse) => Promise<TransactionReceipt | undefined>;
10
10
  execute: (squid: Squid, fromProviderInfo: EIP6963ProviderInfo, provider: WrappedBrowserProvider, routeResponse: RouteResponse) => Promise<TransactionReceipt | undefined>;
11
11
  getStatus: (squid: Squid, transactionHash: string) => Promise<StatusResponse | undefined>;
12
- waitForReceipt: (provider: WrappedBrowserProvider, txHash: string, maxAttempts?: number) => Promise<ethers.TransactionReceipt>;
13
12
  };
@@ -1,12 +1,8 @@
1
1
  import { TokenBalance } from '@0xsquid/sdk/dist/types';
2
2
  import { Squid } from '@0xsquid/sdk';
3
- import { WrappedBrowserProvider } from '@imtbl/checkout-sdk';
4
- import { FromAmountData, RouteData, RouteResponseData, Token } from '../types';
3
+ import { RouteData, RouteResponseData, Token } from '../types';
5
4
  import { SquidPostHook } from '../../primary-sales';
6
5
  export declare const useRoutes: () => {
7
- hasSufficientBalance: (balances: TokenBalance[], toTokenAddress: string, toChainId: string, toAmount: string) => boolean;
8
- hasSufficientGas: (balances: TokenBalance[], selectedChainId: string | number, provider: WrappedBrowserProvider | undefined) => boolean;
9
6
  fetchRoutes: (squid: Squid, tokens: Token[], balances: TokenBalance[], toChainId: string, toTokenAddress: string, toAmount: string, bulkNumber?: number, delayMs?: number, isSwapAllowed?: boolean) => Promise<RouteData[]>;
10
- getFromAmountData: (tokens: Token[], balance: TokenBalance, toAmount: string, toChainId: string, toTokenAddress: string, additionalBuffer?: number) => FromAmountData | undefined;
11
7
  getRoute: (squid: Squid, fromToken: Token, toToken: Token, toAddress: string, fromAmount: string, toAmount: string, fromAddress?: string, quoteOnly?: boolean, postHook?: SquidPostHook) => Promise<RouteResponseData>;
12
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imtbl/checkout-widgets",
3
- "version": "2.4.13",
3
+ "version": "2.4.14-alpha.0",
4
4
  "browserslist": {
5
5
  "production": [
6
6
  ">0.2%",
@@ -18,12 +18,12 @@
18
18
  "@biom3/design-tokens": "^0.4.5",
19
19
  "@biom3/react": "^0.29.4",
20
20
  "@emotion/react": "^11.11.3",
21
- "@imtbl/bridge-sdk": "2.4.13",
22
- "@imtbl/checkout-sdk": "2.4.13",
23
- "@imtbl/config": "2.4.13",
24
- "@imtbl/cryptofiat": "2.4.13",
25
- "@imtbl/dex-sdk": "2.4.13",
26
- "@imtbl/passport": "2.4.13",
21
+ "@imtbl/bridge-sdk": "2.4.14-alpha.0",
22
+ "@imtbl/checkout-sdk": "2.4.14-alpha.0",
23
+ "@imtbl/config": "2.4.14-alpha.0",
24
+ "@imtbl/cryptofiat": "2.4.14-alpha.0",
25
+ "@imtbl/dex-sdk": "2.4.14-alpha.0",
26
+ "@imtbl/passport": "2.4.14-alpha.0",
27
27
  "@imtbl/react-analytics": "0.3.2-alpha",
28
28
  "@rive-app/react-canvas-lite": "^4.9.0",
29
29
  "@walletconnect/ethereum-provider": "^2.11.1",
@@ -0,0 +1,88 @@
1
+ import { EIP6963ProviderInfo, WrappedBrowserProvider } from '@imtbl/checkout-sdk';
2
+ import { Flow } from '@imtbl/metrics';
3
+ import { ethers, TransactionReceipt, TransactionResponse } from 'ethers';
4
+ import { RouteResponse } from '@0xsquid/squid-types';
5
+ import { Squid } from '@0xsquid/sdk';
6
+ import { EvmWallet } from '@0xsquid/sdk/dist/types';
7
+ import { retry } from '../../retry';
8
+
9
+ export const waitForReceipt = async (
10
+ provider: WrappedBrowserProvider,
11
+ txHash: string,
12
+ maxAttempts = 120,
13
+ ) => {
14
+ const result = await retry(
15
+ async () => {
16
+ const receipt = await provider.getTransactionReceipt(txHash);
17
+ if (!receipt) {
18
+ throw new Error('receipt not found');
19
+ }
20
+ if (receipt.status === 0) {
21
+ throw new Error('status failed');
22
+ }
23
+ return receipt;
24
+ },
25
+ {
26
+ retries: maxAttempts,
27
+ retryIntervalMs: 1000,
28
+ nonRetryable: (error) => error.message === 'status failed',
29
+ },
30
+ );
31
+
32
+ if (!result) {
33
+ throw new Error(
34
+ `Transaction receipt not found after ${maxAttempts} attempts`,
35
+ );
36
+ }
37
+
38
+ return result;
39
+ };
40
+
41
+ export const callApprove = async (
42
+ flow: Flow,
43
+ fromProviderInfo: EIP6963ProviderInfo,
44
+ provider: WrappedBrowserProvider,
45
+ routeResponse: RouteResponse,
46
+ ): Promise<TransactionReceipt> => {
47
+ flow.addEvent(`provider_${fromProviderInfo.name}`);
48
+ const erc20Abi = [
49
+ 'function approve(address spender, uint256 amount) public returns (bool)',
50
+ ];
51
+ const fromToken = routeResponse?.route.params.fromToken;
52
+ const signer = await provider.getSigner();
53
+ const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer);
54
+
55
+ const fromAmount = routeResponse?.route.params.fromAmount;
56
+ if (!fromAmount) {
57
+ throw new Error('fromAmount is undefined');
58
+ }
59
+
60
+ const transactionRequestTarget = routeResponse?.route?.transactionRequest?.target;
61
+ if (!transactionRequestTarget) {
62
+ throw new Error('transactionRequest target is undefined');
63
+ }
64
+
65
+ const tx = await tokenContract.approve(
66
+ transactionRequestTarget,
67
+ fromAmount,
68
+ );
69
+ flow.addEvent('transactionSent');
70
+
71
+ return await waitForReceipt(provider, tx.hash);
72
+ };
73
+
74
+ export const callExecute = async (
75
+ flow: Flow,
76
+ squid: Squid,
77
+ fromProviderInfo: EIP6963ProviderInfo,
78
+ provider: WrappedBrowserProvider,
79
+ routeResponse: RouteResponse,
80
+ ): Promise<TransactionReceipt> => {
81
+ flow.addEvent(`provider_${fromProviderInfo.name}`);
82
+ const tx = (await squid.executeRoute({
83
+ signer: await provider.getSigner() as unknown as EvmWallet,
84
+ route: routeResponse.route,
85
+ })) as unknown as TransactionResponse;
86
+ flow.addEvent('transactionSent');
87
+ return await waitForReceipt(provider, tx.hash);
88
+ };
@@ -0,0 +1,162 @@
1
+ import { formatUnits, parseUnits } from 'ethers';
2
+ import { TokenBalance } from '@0xsquid/sdk/dist/types';
3
+ import { WrappedBrowserProvider } from '@imtbl/checkout-sdk';
4
+ import { calculateAdjustedAmount } from './slippage';
5
+ import { FromAmountData, Token } from '../types';
6
+ import { findToken } from './findToken';
7
+ import { isPassportProvider } from '../../provider/utils';
8
+ import { SQUID_NATIVE_TOKEN } from '../config';
9
+
10
+ const INSUFFICIENT_GAS_THRESHOLD = 0.1;
11
+
12
+ /**
13
+ * Functions to handle route amount calculations.
14
+ */
15
+
16
+ /**
17
+ * Calculate the fromAmount based on USD prices and slippage.
18
+ */
19
+ export const calculateFromAmount = (
20
+ fromToken: Token,
21
+ toToken: Token,
22
+ toAmount: string,
23
+ additionalBuffer: number = 0,
24
+ ) => {
25
+ const toAmountNumber = parseFloat(toAmount);
26
+ // Calculate the USD value of the toAmount
27
+ const toAmountInUsd = toAmountNumber * toToken.usdPrice;
28
+ // Calculate the amount of fromToken needed to match this USD value
29
+ const baseFromAmount = toAmountInUsd / fromToken.usdPrice;
30
+ // Add a buffer for price fluctuations and fees
31
+ const fromAmountWithBuffer = calculateAdjustedAmount(baseFromAmount, toAmountInUsd, additionalBuffer);
32
+
33
+ return fromAmountWithBuffer.toString();
34
+ };
35
+
36
+ /**
37
+ * Calculate the fromAmount using exchange rate returned from the route.
38
+ */
39
+ export const calculateFromAmountFromRoute = (
40
+ exchangeRate: string,
41
+ toAmount: string,
42
+ toAmountUSD?: string,
43
+ ) => {
44
+ const toAmountUSDNumber = toAmountUSD ? parseFloat(toAmountUSD) : 0;
45
+ const fromAmount = parseFloat(toAmount) / parseFloat(exchangeRate);
46
+ const fromAmountWithBuffer = calculateAdjustedAmount(fromAmount, toAmountUSDNumber);
47
+ return fromAmountWithBuffer.toString();
48
+ };
49
+
50
+ /**
51
+ * Convert a string amount to a formatted amount with the specified number of decimals.
52
+ */
53
+ export const convertToFormattedFromAmount = (amount: string, decimals: number) => {
54
+ const parsedFromAmount = parseFloat(amount).toFixed(decimals);
55
+ const formattedFromAmount = parseUnits(parsedFromAmount, decimals);
56
+ return formattedFromAmount.toString();
57
+ };
58
+
59
+ export const getFromAmountData = (
60
+ tokens: Token[],
61
+ balance: TokenBalance,
62
+ toAmount: string,
63
+ toChainId: string,
64
+ toTokenAddress: string,
65
+ additionalBuffer: number = 0,
66
+ ): FromAmountData | undefined => {
67
+ const fromToken = findToken(
68
+ tokens,
69
+ balance.address,
70
+ balance.chainId.toString(),
71
+ );
72
+ const toToken = findToken(tokens, toTokenAddress, toChainId);
73
+
74
+ if (!fromToken || !toToken) {
75
+ return undefined;
76
+ }
77
+
78
+ return {
79
+ fromToken,
80
+ fromAmount: calculateFromAmount(
81
+ fromToken,
82
+ toToken,
83
+ toAmount,
84
+ additionalBuffer,
85
+ ),
86
+ toToken,
87
+ toAmount,
88
+ balance,
89
+ additionalBuffer,
90
+ };
91
+ };
92
+
93
+ export const getSufficientFromAmounts = (
94
+ tokens: Token[],
95
+ balances: TokenBalance[],
96
+ toChainId: string,
97
+ toTokenAddress: string,
98
+ toAmount: string,
99
+ ): FromAmountData[] => {
100
+ const filteredBalances = balances.filter(
101
+ (balance) => !(
102
+ balance.address.toLowerCase() === toTokenAddress.toLowerCase()
103
+ && balance.chainId === toChainId
104
+ ),
105
+ );
106
+
107
+ const fromAmountDataArray: FromAmountData[] = filteredBalances
108
+ .map((balance) => getFromAmountData(tokens, balance, toAmount, toChainId, toTokenAddress))
109
+ .filter((value) => value !== undefined);
110
+
111
+ return fromAmountDataArray.filter((data: FromAmountData) => {
112
+ const formattedBalance = formatUnits(
113
+ data.balance.balance,
114
+ data.balance.decimals,
115
+ );
116
+ return (
117
+ parseFloat(formattedBalance.toString()) > parseFloat(data.fromAmount)
118
+ );
119
+ });
120
+ };
121
+
122
+ export const hasSufficientBalance = (
123
+ balances: TokenBalance[],
124
+ toTokenAddress: string,
125
+ toChainId: string,
126
+ toAmount: string,
127
+ ): boolean => {
128
+ const matchingTokens = balances.filter(
129
+ (balance) => balance.address.toLowerCase() === toTokenAddress.toLowerCase()
130
+ && balance.chainId.toString() === toChainId.toString(),
131
+ );
132
+
133
+ if (matchingTokens.length > 0) {
134
+ return matchingTokens.some((balance) => {
135
+ const tokenAmount = parseFloat(formatUnits(balance.balance, balance.decimals));
136
+ return tokenAmount >= parseFloat(toAmount);
137
+ });
138
+ }
139
+
140
+ return false;
141
+ };
142
+
143
+ export const hasSufficientGas = (
144
+ balances: TokenBalance[],
145
+ selectedChainId: string | number,
146
+ provider: WrappedBrowserProvider | undefined,
147
+ ): boolean => {
148
+ if (!provider) return false;
149
+ if (isPassportProvider(provider)) return true;
150
+
151
+ const nativeCurrencyBalance = balances.find(
152
+ (balance) => balance.address.toLowerCase() === SQUID_NATIVE_TOKEN.toLowerCase()
153
+ && balance.chainId.toString() === selectedChainId.toString(),
154
+ );
155
+ if (!nativeCurrencyBalance) return false;
156
+
157
+ const nativeCurrencyBalanceAmount = parseFloat(
158
+ formatUnits(nativeCurrencyBalance.balance, nativeCurrencyBalance.decimals),
159
+ );
160
+ if (nativeCurrencyBalanceAmount < INSUFFICIENT_GAS_THRESHOLD) return false;
161
+ return true;
162
+ };
@@ -0,0 +1,36 @@
1
+ const BASE_SLIPPAGE_HIGH_TIER = 0.005;
2
+ const BASE_SLIPPAGE_MEDIUM_TIER = 0.01;
3
+ const BASE_SLIPPAGE_LOW_TIER = 0.015;
4
+
5
+ const SLIPPAGE_TIERS = {
6
+ high: {
7
+ threshold: 999,
8
+ value: BASE_SLIPPAGE_HIGH_TIER,
9
+ },
10
+ medium: {
11
+ threshold: 99,
12
+ value: BASE_SLIPPAGE_MEDIUM_TIER,
13
+ },
14
+ low: {
15
+ threshold: 0,
16
+ value: BASE_SLIPPAGE_LOW_TIER,
17
+ },
18
+ } as const;
19
+
20
+ /**
21
+ * Functions to calculate slippage based on thresholds
22
+ */
23
+ const getSlippageTier = (usdAmount: number): number => {
24
+ if (usdAmount >= SLIPPAGE_TIERS.high.threshold) return SLIPPAGE_TIERS.high.value;
25
+ if (usdAmount >= SLIPPAGE_TIERS.medium.threshold) return SLIPPAGE_TIERS.medium.value;
26
+ return SLIPPAGE_TIERS.low.value;
27
+ };
28
+
29
+ export const calculateAdjustedAmount = (
30
+ baseAmount: number,
31
+ usdAmount: number,
32
+ additionalBuffer: number = 0,
33
+ ): number => {
34
+ const slippage = getSlippageTier(usdAmount);
35
+ return baseAmount * (1 + slippage + additionalBuffer);
36
+ };
@@ -1,17 +1,17 @@
1
1
  import { RouteResponse } from '@0xsquid/squid-types';
2
2
  import { Squid } from '@0xsquid/sdk';
3
3
  import {
4
- ethers, MaxUint256, TransactionReceipt, TransactionResponse,
4
+ ethers, MaxUint256, TransactionReceipt,
5
5
  } from 'ethers';
6
6
 
7
- import { StatusResponse, EvmWallet } from '@0xsquid/sdk/dist/types';
8
- import { Flow } from '@imtbl/metrics';
7
+ import { StatusResponse } from '@0xsquid/sdk/dist/types';
9
8
  import { EIP6963ProviderInfo, WrappedBrowserProvider } from '@imtbl/checkout-sdk';
10
9
  import { isSquidNativeToken } from '../functions/isSquidNativeToken';
11
10
  import { retry } from '../../retry';
12
11
  import { withMetricsAsync } from '../../metrics';
13
12
  import { useAnalytics, UserJourney } from '../../../context/analytics-provider/SegmentAnalyticsProvider';
14
13
  import { isRejectedError } from '../../../functions/errorType';
14
+ import { callApprove, callExecute } from '../functions/execute';
15
15
 
16
16
  const TRANSACTION_NOT_COMPLETED = 'transaction not completed';
17
17
 
@@ -21,38 +21,6 @@ export const useExecute = (
21
21
  ) => {
22
22
  const { user } = useAnalytics();
23
23
 
24
- const waitForReceipt = async (
25
- provider: WrappedBrowserProvider,
26
- txHash: string,
27
- maxAttempts = 120,
28
- ) => {
29
- const result = await retry(
30
- async () => {
31
- const receipt = await provider.getTransactionReceipt(txHash);
32
- if (!receipt) {
33
- throw new Error('receipt not found');
34
- }
35
- if (receipt.status === 0) {
36
- throw new Error('status failed');
37
- }
38
- return receipt;
39
- },
40
- {
41
- retries: maxAttempts,
42
- retryIntervalMs: 1000,
43
- nonRetryable: (error) => error.message === 'status failed',
44
- },
45
- );
46
-
47
- if (!result) {
48
- throw new Error(
49
- `Transaction receipt not found after ${maxAttempts} attempts`,
50
- );
51
- }
52
-
53
- return result;
54
- };
55
-
56
24
  const getAllowance = async (
57
25
  provider: WrappedBrowserProvider,
58
26
  routeResponse: RouteResponse,
@@ -86,39 +54,6 @@ export const useExecute = (
86
54
  }
87
55
  };
88
56
 
89
- const callApprove = async (
90
- flow:Flow,
91
- fromProviderInfo: EIP6963ProviderInfo,
92
- provider: WrappedBrowserProvider,
93
- routeResponse: RouteResponse,
94
- ): Promise<TransactionReceipt> => {
95
- flow.addEvent(`provider_${fromProviderInfo.name}`);
96
- const erc20Abi = [
97
- 'function approve(address spender, uint256 amount) public returns (bool)',
98
- ];
99
- const fromToken = routeResponse?.route.params.fromToken;
100
- const signer = await provider.getSigner();
101
- const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer);
102
-
103
- const fromAmount = routeResponse?.route.params.fromAmount;
104
- if (!fromAmount) {
105
- throw new Error('fromAmount is undefined');
106
- }
107
-
108
- const transactionRequestTarget = routeResponse?.route?.transactionRequest?.target;
109
- if (!transactionRequestTarget) {
110
- throw new Error('transactionRequest target is undefined');
111
- }
112
-
113
- const tx = await tokenContract.approve(
114
- transactionRequestTarget,
115
- fromAmount,
116
- );
117
- flow.addEvent('transactionSent');
118
-
119
- return await waitForReceipt(provider, tx.hash);
120
- };
121
-
122
57
  const getAnonymousId = async () => {
123
58
  try {
124
59
  const userData = await user();
@@ -149,22 +84,6 @@ export const useExecute = (
149
84
  }
150
85
  };
151
86
 
152
- const callExecute = async (
153
- flow: Flow,
154
- squid: Squid,
155
- fromProviderInfo: EIP6963ProviderInfo,
156
- provider: WrappedBrowserProvider,
157
- routeResponse: RouteResponse,
158
- ): Promise<TransactionReceipt> => {
159
- flow.addEvent(`provider_${fromProviderInfo.name}`);
160
- const tx = (await squid.executeRoute({
161
- signer: await provider.getSigner() as unknown as EvmWallet,
162
- route: routeResponse.route,
163
- })) as unknown as TransactionResponse;
164
- flow.addEvent('transactionSent');
165
- return await waitForReceipt(provider, tx.hash);
166
- };
167
-
168
87
  const execute = async (
169
88
  squid: Squid,
170
89
  fromProviderInfo: EIP6963ProviderInfo,
@@ -234,6 +153,5 @@ export const useExecute = (
234
153
  approve,
235
154
  execute,
236
155
  getStatus,
237
- waitForReceipt,
238
156
  };
239
157
  };