@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.
- package/dist/browser/{AddTokensWidget-Dw62MGE7.js → AddTokensWidget-CF1YN2qr.js} +4 -4
- package/dist/browser/{BridgeWidget-pB9NQr0j.js → BridgeWidget-D1iYISBu.js} +6 -6
- package/dist/browser/{CommerceWidget-CmGjTT5f.js → CommerceWidget-0xlC0qeb.js} +13 -13
- package/dist/browser/{FeesBreakdown-D42F89mf.js → FeesBreakdown-9FvnOOCN.js} +1 -1
- package/dist/browser/{OnRampWidget-C11vbDpE.js → OnRampWidget-Db0Ma0JP.js} +3 -3
- package/dist/browser/{SaleWidget-C-kIuH_x.js → SaleWidget-BiU-JU_Y.js} +10 -10
- package/dist/browser/{SpendingCapHero-DxECFPhZ.js → SpendingCapHero-DoDWVXeM.js} +1 -1
- package/dist/browser/{SwapWidget-CaimjlZx.js → SwapWidget-0b44o7OG.js} +6 -6
- package/dist/browser/{TokenImage-CJcf0BVb.js → TokenImage-ON5CsElS.js} +1 -1
- package/dist/browser/{TopUpView-DIAfMQDk.js → TopUpView-BSsm_pag.js} +1 -1
- package/dist/browser/{WalletApproveHero-2qnl25R9.js → WalletApproveHero-BpQET2Ry.js} +2 -2
- package/dist/browser/{WalletWidget-EUpKwouL.js → WalletWidget-DPtHMDzk.js} +3 -3
- package/dist/browser/{auto-track-BLHegHT2.js → auto-track-YB97xHhP.js} +1 -1
- package/dist/browser/{index-BZQairfY.js → index-B6LlGDqn.js} +2 -2
- package/dist/browser/{index-B1kcsGhP.js → index-BGfRODL9.js} +1 -1
- package/dist/browser/{index-Co43S-f8.js → index-CYSUCb_r.js} +174 -192
- package/dist/browser/{index-C52OgfPn.js → index-CxVwwdjo.js} +1 -1
- package/dist/browser/{index-iCexzEAZ.js → index-DfqbSiW-.js} +1 -1
- package/dist/browser/{index-C7zLn4CO.js → index-DhJhrEPT.js} +1 -1
- package/dist/browser/{index-B6adB8ks.js → index-DkUaawBA.js} +1 -1
- package/dist/browser/{index-COIl8mga.js → index-_E9_8iXP.js} +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/{index.umd-ENtuIC6R.js → index.umd-C_C0lXQh.js} +1 -1
- package/dist/browser/{useInterval-BaXQ-Cl5.js → useInterval-BjJWflew.js} +1 -1
- package/dist/types/lib/squid/functions/execute.d.ts +8 -0
- package/dist/types/lib/squid/functions/routeCalculation.d.ts +22 -0
- package/dist/types/lib/squid/functions/slippage.d.ts +1 -0
- package/dist/types/lib/squid/hooks/useExecute.d.ts +1 -2
- package/dist/types/lib/squid/hooks/useRoutes.d.ts +1 -5
- package/package.json +7 -7
- package/src/lib/squid/functions/execute.ts +88 -0
- package/src/lib/squid/functions/routeCalculation.ts +162 -0
- package/src/lib/squid/functions/slippage.ts +36 -0
- package/src/lib/squid/hooks/useExecute.ts +3 -85
- package/src/lib/squid/hooks/useRoutes.ts +5 -115
- package/src/widgets/add-tokens/views/Review.tsx +2 -1
- package/src/widgets/purchase/views/Purchase.tsx +8 -2
- package/dist/types/lib/squid/hooks/useRouteCalculation.d.ts +0 -9
- package/dist/types/lib/squid/hooks/useSlippage.d.ts +0 -7
- package/src/lib/squid/hooks/useRouteCalculation.ts +0 -60
- package/src/lib/squid/hooks/useSlippage.ts +0 -45
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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 {
|
|
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;
|
package/dist/browser/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { er as WidgetsFactory } from './index-CYSUCb_r.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as reactExports,
|
|
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 {
|
|
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 {
|
|
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.
|
|
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.
|
|
22
|
-
"@imtbl/checkout-sdk": "2.4.
|
|
23
|
-
"@imtbl/config": "2.4.
|
|
24
|
-
"@imtbl/cryptofiat": "2.4.
|
|
25
|
-
"@imtbl/dex-sdk": "2.4.
|
|
26
|
-
"@imtbl/passport": "2.4.
|
|
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,
|
|
4
|
+
ethers, MaxUint256, TransactionReceipt,
|
|
5
5
|
} from 'ethers';
|
|
6
6
|
|
|
7
|
-
import { StatusResponse
|
|
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
|
};
|