@ensofinance/checkout-widget 0.0.1
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/checkout-widget.es.js +52889 -0
- package/dist/checkout-widget.es.js.map +1 -0
- package/dist/checkout-widget.umd.js +203 -0
- package/dist/checkout-widget.umd.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/enso-api.yaml +1982 -0
- package/orval.config.ts +25 -0
- package/package.json +79 -0
- package/src/assets/BinanceBadge.svg +4 -0
- package/src/assets/CoinbaseIcon.svg +4 -0
- package/src/assets/USD Coin (USDC).svg +5 -0
- package/src/assets/avecIcon.svg +5 -0
- package/src/assets/base.webp +0 -0
- package/src/assets/depositIcon.svg +6 -0
- package/src/assets/eth.webp +0 -0
- package/src/assets/ethMainnetIcon.svg +10 -0
- package/src/assets/fail.svg +5 -0
- package/src/assets/kraken.png +0 -0
- package/src/assets/logo.svg +10 -0
- package/src/assets/mastercard.png +0 -0
- package/src/assets/metamask.png +0 -0
- package/src/assets/rabby.png +0 -0
- package/src/assets/success.svg +4 -0
- package/src/assets/usdc.webp +0 -0
- package/src/assets/usdt.webp +0 -0
- package/src/assets/visa.png +0 -0
- package/src/assets/visa.webp +0 -0
- package/src/components/BridgeFee.tsx +58 -0
- package/src/components/ChakraProvider.tsx +372 -0
- package/src/components/Checkout.tsx +127 -0
- package/src/components/CheckoutModal.tsx +22 -0
- package/src/components/CircleTimer.tsx +66 -0
- package/src/components/CurrencySwapDisplay.tsx +153 -0
- package/src/components/DepositProcessing.tsx +116 -0
- package/src/components/ExchangeConfirmSecurity.tsx +110 -0
- package/src/components/QuoteParameters.tsx +341 -0
- package/src/components/TransactionDetailRow.tsx +124 -0
- package/src/components/cards/AssetCard.tsx +167 -0
- package/src/components/cards/ExchangeCard.tsx +53 -0
- package/src/components/cards/OptionCard.tsx +59 -0
- package/src/components/cards/WalletCard.tsx +99 -0
- package/src/components/cards/index.ts +6 -0
- package/src/components/modal.tsx +83 -0
- package/src/components/steps/ExchangeFlow.tsx +1402 -0
- package/src/components/steps/InitialStep.tsx +169 -0
- package/src/components/steps/QuoteStep.tsx +121 -0
- package/src/components/steps/WalletAmountStep.tsx +258 -0
- package/src/components/steps/WalletConfirmStep.tsx +404 -0
- package/src/components/steps/WalletTokenStep.tsx +128 -0
- package/src/components/ui/index.tsx +394 -0
- package/src/components/ui/styled.tsx +85 -0
- package/src/components/ui/toaster.tsx +43 -0
- package/src/components/ui/tooltip.tsx +46 -0
- package/src/enso-api/api.ts +173 -0
- package/src/enso-api/custom-instance.ts +35 -0
- package/src/enso-api/index.ts +5119 -0
- package/src/enso-api/model/action.ts +17 -0
- package/src/enso-api/model/actionAction.ts +52 -0
- package/src/enso-api/model/actionInputs.ts +12 -0
- package/src/enso-api/model/actionToBundle.ts +19 -0
- package/src/enso-api/model/actionToBundleAction.ts +53 -0
- package/src/enso-api/model/actionToBundleArgs.ts +12 -0
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionParams.ts +53 -0
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionRoutingStrategy.ts +23 -0
- package/src/enso-api/model/bundleShortcutTransaction.ts +35 -0
- package/src/enso-api/model/bundleShortcutTransactionAmountsOut.ts +15 -0
- package/src/enso-api/model/bundleShortcutTransactionFeeAmount.ts +12 -0
- package/src/enso-api/model/connectedNetwork.ts +16 -0
- package/src/enso-api/model/hop.ts +24 -0
- package/src/enso-api/model/hopArgs.ts +12 -0
- package/src/enso-api/model/index.ts +70 -0
- package/src/enso-api/model/iporControllerIporShortcutTransactionParams.ts +21 -0
- package/src/enso-api/model/iporShortcutInput.ts +33 -0
- package/src/enso-api/model/iporShortcutTransaction.ts +22 -0
- package/src/enso-api/model/lZDestinationTokenData.ts +19 -0
- package/src/enso-api/model/lZPoolLookupResponse.ts +26 -0
- package/src/enso-api/model/layerZeroControllerGetPoolAddressParams.ts +29 -0
- package/src/enso-api/model/network.ts +15 -0
- package/src/enso-api/model/networksControllerNetworksParams.ts +21 -0
- package/src/enso-api/model/nonTokenizedControllerTokens200.ts +15 -0
- package/src/enso-api/model/nonTokenizedControllerTokens200AllOf.ts +16 -0
- package/src/enso-api/model/nonTokenizedControllerTokensParams.ts +41 -0
- package/src/enso-api/model/nonTokenizedModel.ts +27 -0
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionParams.ts +64 -0
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionRoutingStrategy.ts +22 -0
- package/src/enso-api/model/paginatedResult.ts +16 -0
- package/src/enso-api/model/paginationMeta.ts +27 -0
- package/src/enso-api/model/positionModel.ts +77 -0
- package/src/enso-api/model/price.ts +20 -0
- package/src/enso-api/model/pricesControllerGetPricesParams.ts +17 -0
- package/src/enso-api/model/project.ts +15 -0
- package/src/enso-api/model/protocol.ts +15 -0
- package/src/enso-api/model/protocolModel.ts +26 -0
- package/src/enso-api/model/protocolsControllerFindAllParams.ts +21 -0
- package/src/enso-api/model/routeShortcutTransaction.ts +33 -0
- package/src/enso-api/model/routeShortcutVariableInputs.ts +68 -0
- package/src/enso-api/model/routeShortcutVariableInputsRoutingStrategy.ts +27 -0
- package/src/enso-api/model/routeShortcutVariableInputsVariableEstimates.ts +14 -0
- package/src/enso-api/model/routerControllerRouteShortcutTransactionParams.ts +91 -0
- package/src/enso-api/model/routerControllerRouteShortcutTransactionRoutingStrategy.ts +23 -0
- package/src/enso-api/model/standard.ts +18 -0
- package/src/enso-api/model/standardAction.ts +20 -0
- package/src/enso-api/model/standardActionAction.ts +53 -0
- package/src/enso-api/model/tokenModel.ts +36 -0
- package/src/enso-api/model/tokensControllerTokens200.ts +15 -0
- package/src/enso-api/model/tokensControllerTokens200AllOf.ts +16 -0
- package/src/enso-api/model/tokensControllerTokensParams.ts +91 -0
- package/src/enso-api/model/tokensControllerTokensType.ts +19 -0
- package/src/enso-api/model/transaction.ts +17 -0
- package/src/enso-api/model/userOperation.ts +28 -0
- package/src/enso-api/model/walletApproveTransaction.ts +24 -0
- package/src/enso-api/model/walletApproveTransactionTx.ts +15 -0
- package/src/enso-api/model/walletBalance.ts +29 -0
- package/src/enso-api/model/walletControllerCreateApproveTransactionParams.ts +35 -0
- package/src/enso-api/model/walletControllerCreateApproveTransactionRoutingStrategy.ts +23 -0
- package/src/enso-api/model/walletControllerWalletBalancesParams.ts +25 -0
- package/src/index.ts +17 -0
- package/src/store.ts +68 -0
- package/src/types/assets.d.ts +29 -0
- package/src/types/index.ts +21 -0
- package/src/util/common.tsx +324 -0
- package/src/util/constants.tsx +213 -0
- package/src/util/enso-hooks.tsx +203 -0
- package/src/util/index.tsx +68 -0
- package/src/util/tx-tracker.tsx +301 -0
- package/src/util/wallet.tsx +258 -0
- package/tsconfig.json +13 -0
- package/vite.config.ts +51 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useAccount,
|
|
3
|
+
useCapabilities,
|
|
4
|
+
useSendCalls,
|
|
5
|
+
useWalletClient,
|
|
6
|
+
} from "wagmi";
|
|
7
|
+
import { Address } from "viem";
|
|
8
|
+
import { useCallback, useMemo } from "react";
|
|
9
|
+
import { useEnsoToken, useEnsoPrice, useEnsoData } from "@/enso-api/api";
|
|
10
|
+
import { getWalletDisplayName, getWalletIcon } from "@/util/wallet";
|
|
11
|
+
import { formatUSD, normalizeValue } from "@/util";
|
|
12
|
+
import { useAppStore } from "@/store";
|
|
13
|
+
import { VITALIK_ADDRESS } from "./constants";
|
|
14
|
+
|
|
15
|
+
export const useAppDetails = () => {
|
|
16
|
+
const { address = VITALIK_ADDRESS } = useAccount();
|
|
17
|
+
const amountIn = useAppStore((state) => state.amountIn);
|
|
18
|
+
const tokenIn = useAppStore((state) => state.tokenIn);
|
|
19
|
+
const tokenOut = useAppStore((state) => state.tokenOut);
|
|
20
|
+
const slippage = useAppStore((state) => state.slippage);
|
|
21
|
+
const chainIdIn = useAppStore((state) => state.chainIdIn);
|
|
22
|
+
const chainIdOut = useAppStore((state) => state.chainIdOut);
|
|
23
|
+
const isCheckout = useAppStore((state) => state.isCheckout);
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
data: [tokenInData],
|
|
27
|
+
} = useEnsoToken(tokenIn, chainIdIn);
|
|
28
|
+
const {
|
|
29
|
+
data: [tokenOutData],
|
|
30
|
+
} = useEnsoToken(tokenOut, chainIdOut);
|
|
31
|
+
const { data: tokenInPrice } = useEnsoPrice(chainIdIn, tokenIn);
|
|
32
|
+
const { data: tokenOutPrice } = useEnsoPrice(chainIdOut, tokenOut);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
chainIdIn,
|
|
36
|
+
chainIdOut,
|
|
37
|
+
tokenInData,
|
|
38
|
+
tokenOutData,
|
|
39
|
+
amountIn,
|
|
40
|
+
slippage,
|
|
41
|
+
address,
|
|
42
|
+
tokenInPrice,
|
|
43
|
+
tokenOutPrice,
|
|
44
|
+
tokenIn,
|
|
45
|
+
tokenOut,
|
|
46
|
+
isCheckout,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const useSendTxns = ({
|
|
51
|
+
address,
|
|
52
|
+
chainId,
|
|
53
|
+
calls,
|
|
54
|
+
}: {
|
|
55
|
+
address: string;
|
|
56
|
+
chainId: number;
|
|
57
|
+
calls: any[];
|
|
58
|
+
}) => {
|
|
59
|
+
const { sendCalls } = useSendCalls();
|
|
60
|
+
const { data: caps } = useCapabilities();
|
|
61
|
+
// const atomicOkay = caps?.[chainId]?.atomic?.status === "ready";
|
|
62
|
+
const atomicOkay = false;
|
|
63
|
+
// const useFallback = !atomicOkay; // one-line policy; tweak to taste
|
|
64
|
+
const wallet = useWalletClient();
|
|
65
|
+
|
|
66
|
+
console.log(caps, atomicOkay);
|
|
67
|
+
|
|
68
|
+
const sendTxns = useCallback(
|
|
69
|
+
async (
|
|
70
|
+
onTxSend: (hash: string) => void,
|
|
71
|
+
onFail: (error: any) => void,
|
|
72
|
+
) => {
|
|
73
|
+
if (!atomicOkay) {
|
|
74
|
+
// Send transactions sequentially when atomic is not supported
|
|
75
|
+
console.log(
|
|
76
|
+
"Atomic not supported, sending transactions sequentially",
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
for (const call of calls) {
|
|
81
|
+
console.log("Sending individual transaction:", call);
|
|
82
|
+
|
|
83
|
+
const result = await wallet.data?.sendTransaction({
|
|
84
|
+
...call,
|
|
85
|
+
account: address as Address,
|
|
86
|
+
chainId,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log("Sequential transaction result:", result);
|
|
90
|
+
|
|
91
|
+
// Check if transaction failed and stop execution
|
|
92
|
+
if (!result) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Transaction failed for call: ${JSON.stringify(call)}`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (call === calls[calls.length - 1]) {
|
|
99
|
+
onTxSend(result);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log("All sequential transactions completed");
|
|
104
|
+
} catch (err) {
|
|
105
|
+
console.error("Error in sequential transaction:", err);
|
|
106
|
+
onFail(err);
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Use atomic transactions when supported
|
|
113
|
+
wallet.data
|
|
114
|
+
?.sendCalls(
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
{
|
|
117
|
+
calls,
|
|
118
|
+
account: address as Address,
|
|
119
|
+
forceAtomic: true, // request atomic only when possible
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
.then((result) => {
|
|
123
|
+
debugger;
|
|
124
|
+
console.log(result);
|
|
125
|
+
})
|
|
126
|
+
.catch((err) => {
|
|
127
|
+
debugger;
|
|
128
|
+
console.error(err);
|
|
129
|
+
onFail(err);
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
[sendCalls, calls, atomicOkay, chainId, wallet.data],
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const ready = calls.length > 0 && wallet.data;
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
ready,
|
|
139
|
+
sendTxns,
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const useRouteData = () => {
|
|
144
|
+
const {
|
|
145
|
+
tokenInData,
|
|
146
|
+
amountIn,
|
|
147
|
+
slippage,
|
|
148
|
+
address,
|
|
149
|
+
chainIdIn,
|
|
150
|
+
chainIdOut,
|
|
151
|
+
tokenInPrice,
|
|
152
|
+
tokenIn,
|
|
153
|
+
tokenOut,
|
|
154
|
+
isCheckout,
|
|
155
|
+
} = useAppDetails();
|
|
156
|
+
|
|
157
|
+
const {
|
|
158
|
+
data: routeData,
|
|
159
|
+
isLoading,
|
|
160
|
+
error,
|
|
161
|
+
isFetched,
|
|
162
|
+
} = useEnsoData({
|
|
163
|
+
routingStrategy: isCheckout ? "checkout" : "router",
|
|
164
|
+
fromAddress: address,
|
|
165
|
+
receiver: address,
|
|
166
|
+
spender: address,
|
|
167
|
+
amountIn,
|
|
168
|
+
tokenIn,
|
|
169
|
+
tokenOut,
|
|
170
|
+
slippage,
|
|
171
|
+
chainId: chainIdIn,
|
|
172
|
+
outChainId: chainIdOut,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const usdAmountIn = useMemo(
|
|
176
|
+
() =>
|
|
177
|
+
formatUSD(
|
|
178
|
+
normalizeValue(
|
|
179
|
+
(+amountIn * tokenInPrice).toFixed(),
|
|
180
|
+
tokenInData?.decimals,
|
|
181
|
+
),
|
|
182
|
+
),
|
|
183
|
+
[amountIn, tokenInPrice, tokenInData?.decimals],
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
chainIdOut,
|
|
188
|
+
routeData,
|
|
189
|
+
routeFetched: isFetched,
|
|
190
|
+
routeLoading: isLoading,
|
|
191
|
+
usdAmountIn,
|
|
192
|
+
routerError: error,
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export const useWalletIcon = () => {
|
|
197
|
+
const { connector } = useAccount();
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
walletIcon: getWalletIcon(connector?.name),
|
|
201
|
+
walletDisplayName: getWalletDisplayName(connector?.name),
|
|
202
|
+
};
|
|
203
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Address, formatUnits, parseUnits } from "viem";
|
|
2
|
+
import { STARGATE_CHAIN_NAMES } from "./constants";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
|
|
5
|
+
export const denormalizeValue = (value: string, decimals = 0) =>
|
|
6
|
+
parseUnits(value, decimals).toString();
|
|
7
|
+
|
|
8
|
+
export const normalizeValue = (value: bigint | string = "0", decimals = 0) => {
|
|
9
|
+
try {
|
|
10
|
+
return formatUnits(BigInt(value), decimals);
|
|
11
|
+
} catch (e) {
|
|
12
|
+
console.error(e);
|
|
13
|
+
return "0";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const compareCaseInsensitive = (a: string, b: string) => {
|
|
18
|
+
return !!(a && b && a?.toLowerCase() === b?.toLowerCase());
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const shortenAddress = (address: Address, short = false) =>
|
|
22
|
+
`${short ? "" : address.slice(0, 4)}...${address.slice(-4)}`;
|
|
23
|
+
|
|
24
|
+
const formatter = Intl.NumberFormat("en", {
|
|
25
|
+
maximumFractionDigits: 4,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const preciseFormatter = Intl.NumberFormat("en", {
|
|
29
|
+
maximumFractionDigits: 6,
|
|
30
|
+
});
|
|
31
|
+
const usdFormatter = Intl.NumberFormat("en", {
|
|
32
|
+
style: "currency",
|
|
33
|
+
currency: "USD",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const formatNumber = (value: number | string, precise?: boolean) => {
|
|
37
|
+
const formatterToUse = precise ? preciseFormatter : formatter;
|
|
38
|
+
|
|
39
|
+
return isNaN(+value) ? "0.0" : formatterToUse.format(+value);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const formatUSD = (value: number | string) => {
|
|
43
|
+
return usdFormatter.format(+value);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const formatCompactUsd = (value: number | string) => {
|
|
47
|
+
const num = typeof value === "string" ? parseFloat(value) : value;
|
|
48
|
+
|
|
49
|
+
if (isNaN(num)) return "0";
|
|
50
|
+
|
|
51
|
+
const formatter = Intl.NumberFormat("en", {
|
|
52
|
+
notation: "compact",
|
|
53
|
+
maximumFractionDigits: 2,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return formatter.format(num);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const getChainIcon = (chainId: number) =>
|
|
60
|
+
`https://icons-ckg.pages.dev/stargate-light/networks/${STARGATE_CHAIN_NAMES[chainId]}.svg`;
|
|
61
|
+
|
|
62
|
+
export const usePrevious = <T extends any>(value: T): T | undefined => {
|
|
63
|
+
const ref = useRef<T>();
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
ref.current = value;
|
|
66
|
+
});
|
|
67
|
+
return ref.current;
|
|
68
|
+
};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { ReactNode, useCallback, useEffect, useState } from "react";
|
|
2
|
+
import { useWaitForTransactionReceipt } from "wagmi";
|
|
3
|
+
import { create } from "zustand";
|
|
4
|
+
import { useQuery } from "@tanstack/react-query";
|
|
5
|
+
import { getChainEtherscanUrl } from "./common";
|
|
6
|
+
import { SupportedChainId } from "@/util/constants";
|
|
7
|
+
|
|
8
|
+
type TrackParams = {
|
|
9
|
+
hash: `0x${string}` | undefined;
|
|
10
|
+
chainId: SupportedChainId;
|
|
11
|
+
crosschain: boolean;
|
|
12
|
+
message: string;
|
|
13
|
+
onConfirmed: (
|
|
14
|
+
receipt: ReturnType<typeof useWaitForTransactionReceipt>["data"],
|
|
15
|
+
) => void;
|
|
16
|
+
status?: string | ReactNode;
|
|
17
|
+
isActive?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const useTrackingStore = create<{
|
|
21
|
+
txs: TrackParams[];
|
|
22
|
+
addTx: (tx: TrackParams) => void;
|
|
23
|
+
removeTx: (hash: `0x${string}`) => void;
|
|
24
|
+
updateTx: (hash: `0x${string}`, tx: Partial<TrackParams>) => void;
|
|
25
|
+
}>((set) => ({
|
|
26
|
+
txs: [],
|
|
27
|
+
addTx: (tx: TrackParams) => set((state) => ({ txs: [...state.txs, tx] })),
|
|
28
|
+
removeTx: (hash: `0x${string}`) =>
|
|
29
|
+
set((state) => ({ txs: state.txs.filter((tx) => tx.hash !== hash) })),
|
|
30
|
+
updateTx: (hash: `0x${string}`, tx: Partial<TrackParams>) =>
|
|
31
|
+
set((state) => ({
|
|
32
|
+
txs: state.txs.map((txn) =>
|
|
33
|
+
txn.hash === hash ? { ...txn, ...tx } : txn,
|
|
34
|
+
),
|
|
35
|
+
})),
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
export const useTxByHash = (hash: string) => {
|
|
39
|
+
const { txs } = useTrackingStore();
|
|
40
|
+
|
|
41
|
+
return txs.find((tx) => tx.hash === hash);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const useTrackTx = () => {
|
|
45
|
+
const { addTx } = useTrackingStore();
|
|
46
|
+
|
|
47
|
+
const track = useCallback((args: TrackParams) => {
|
|
48
|
+
if (!args.hash) return;
|
|
49
|
+
addTx(args);
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
return { track };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
enum LayerZeroStatus {
|
|
56
|
+
Pending = "PENDING",
|
|
57
|
+
Success = "SUCCEEDED",
|
|
58
|
+
Failed = "FAILED",
|
|
59
|
+
Inflight = "INFLIGHT",
|
|
60
|
+
Confirming = "CONFIRMING",
|
|
61
|
+
Delivered = "DELIVERED",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const useLayerZeroUrl = (hash?: `0x${string}`, reset?: () => void) => {
|
|
65
|
+
// const [loadingToastId, setLoadingToastId] = useState<string>();
|
|
66
|
+
const updateTx = useTrackingStore((state) => state.updateTx);
|
|
67
|
+
const { data } = useQuery({
|
|
68
|
+
queryKey: ["layerZeroUrl", hash || "none", !!reset],
|
|
69
|
+
queryFn: async () => {
|
|
70
|
+
if (!hash) return null;
|
|
71
|
+
return fetch(
|
|
72
|
+
`https://scan.layerzero-api.com/v1/messages/tx/${hash}`,
|
|
73
|
+
)
|
|
74
|
+
.then((res) => res.json())
|
|
75
|
+
.then((res) => res.data[0]);
|
|
76
|
+
},
|
|
77
|
+
refetchInterval: 2000,
|
|
78
|
+
enabled: !!(reset && hash),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// useEffect(() => {
|
|
82
|
+
// if (data?.source?.status === LayerZeroStatus.Success) {
|
|
83
|
+
// updateTx(hash, {
|
|
84
|
+
// status: "(0/4) Waiting for source transaction completion",
|
|
85
|
+
// });
|
|
86
|
+
// }
|
|
87
|
+
// }, [data?.source?.status]);
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (!hash) return;
|
|
91
|
+
|
|
92
|
+
// const action = {
|
|
93
|
+
// label: "View on Explorer",
|
|
94
|
+
// onClick: () =>
|
|
95
|
+
// window.open(`https://layerzeroscan.com/tx/${hash}`, "_blank"),
|
|
96
|
+
// };
|
|
97
|
+
|
|
98
|
+
// if (!loadingToastId) {
|
|
99
|
+
|
|
100
|
+
// toaster.create({
|
|
101
|
+
// id: hash,
|
|
102
|
+
// title: "Pending (0/4)",
|
|
103
|
+
// description: "Waiting for source transaction completion",
|
|
104
|
+
// type: "loading",
|
|
105
|
+
// action,
|
|
106
|
+
// });
|
|
107
|
+
// } else
|
|
108
|
+
if (
|
|
109
|
+
data?.source?.status &&
|
|
110
|
+
data.source.status !== LayerZeroStatus.Success
|
|
111
|
+
) {
|
|
112
|
+
updateTx(hash, {
|
|
113
|
+
status: "(1/4) Waiting for funds to be sent on destination",
|
|
114
|
+
});
|
|
115
|
+
// toaster.update(loadingToastId, {
|
|
116
|
+
// title: "Pending (1/4)",
|
|
117
|
+
// description: "Waiting for funds to be sent on destination",
|
|
118
|
+
// });
|
|
119
|
+
} else if (data?.status?.name === LayerZeroStatus.Delivered) {
|
|
120
|
+
reset?.();
|
|
121
|
+
updateTx(hash, {
|
|
122
|
+
status: "(4/4) Bridging is complete",
|
|
123
|
+
isActive: false,
|
|
124
|
+
});
|
|
125
|
+
// toaster.update(loadingToastId, {
|
|
126
|
+
// title: "Success (4/4) ",
|
|
127
|
+
// description: "Bridging is complete",
|
|
128
|
+
// type: "success",
|
|
129
|
+
// action,
|
|
130
|
+
// });
|
|
131
|
+
// setLoadingToastId(undefined);
|
|
132
|
+
} else if (data?.status?.name === LayerZeroStatus.Confirming) {
|
|
133
|
+
updateTx(hash, {
|
|
134
|
+
status: "(3/4) Waiting for destination execution",
|
|
135
|
+
});
|
|
136
|
+
// toaster.update(loadingToastId, {
|
|
137
|
+
// title: "Pending (3/4)",
|
|
138
|
+
// description: "Waiting for destination execution",
|
|
139
|
+
// });
|
|
140
|
+
} else if (data?.status?.name === LayerZeroStatus.Inflight) {
|
|
141
|
+
updateTx(hash, {
|
|
142
|
+
status: "(2/4) Waiting for funds to be delivered on destination",
|
|
143
|
+
});
|
|
144
|
+
// toaster.update(loadingToastId, {
|
|
145
|
+
// title: "Pending (2/4)",
|
|
146
|
+
// description: "Waiting for funds to be delivered on destination",
|
|
147
|
+
// });
|
|
148
|
+
}
|
|
149
|
+
}, [data, hash]);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const useSingleChainTransactionTracking = (
|
|
153
|
+
hash: `0x${string}` | undefined,
|
|
154
|
+
chainId: SupportedChainId,
|
|
155
|
+
description: string,
|
|
156
|
+
waitForTransaction: ReturnType<typeof useWaitForTransactionReceipt>,
|
|
157
|
+
reset?: () => void,
|
|
158
|
+
) => {
|
|
159
|
+
// const [loadingToastId, setLoadingToastId] = useState<string | undefined>();
|
|
160
|
+
const link = getChainEtherscanUrl({ hash, chainId });
|
|
161
|
+
const updateTx = useTrackingStore((state) => state.updateTx);
|
|
162
|
+
|
|
163
|
+
// toast error if tx failed to be mined and success if it is having confirmation
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (!reset) return;
|
|
166
|
+
|
|
167
|
+
if (waitForTransaction.error) {
|
|
168
|
+
updateTx(hash, {
|
|
169
|
+
status: "Transaction Failed",
|
|
170
|
+
isActive: false,
|
|
171
|
+
});
|
|
172
|
+
// toaster.update(hash, {
|
|
173
|
+
// title: "Error",
|
|
174
|
+
// description: waitForTransaction.error.message,
|
|
175
|
+
// type: "error",
|
|
176
|
+
// action: link
|
|
177
|
+
// ? {
|
|
178
|
+
// label: "View on Explorer",
|
|
179
|
+
// onClick: () => window.open(link, "_blank"),
|
|
180
|
+
// }
|
|
181
|
+
// : undefined,
|
|
182
|
+
// });
|
|
183
|
+
} else if (waitForTransaction.data) {
|
|
184
|
+
// Close loading toast if it exists
|
|
185
|
+
// setLoadingToastId(undefined);
|
|
186
|
+
// reset tx hash to eliminate recurring notifications
|
|
187
|
+
reset?.();
|
|
188
|
+
updateTx(hash, {
|
|
189
|
+
status: "Transaction Confirmed",
|
|
190
|
+
isActive: false,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// toaster.update(loadingToastId, {
|
|
194
|
+
// title: "Success",
|
|
195
|
+
// description: description,
|
|
196
|
+
// type: "success",
|
|
197
|
+
// action: link
|
|
198
|
+
// ? {
|
|
199
|
+
// label: "View on Explorer",
|
|
200
|
+
// onClick: () => window.open(link, "_blank"),
|
|
201
|
+
// }
|
|
202
|
+
// : undefined,
|
|
203
|
+
// });
|
|
204
|
+
}
|
|
205
|
+
// else if (waitForTransaction.isLoading) {
|
|
206
|
+
|
|
207
|
+
// // if (!loadingToastId) {
|
|
208
|
+
// toaster.create({
|
|
209
|
+
// id: hash,
|
|
210
|
+
// title: "Transaction Pending",
|
|
211
|
+
// description: description,
|
|
212
|
+
// type: "loading",
|
|
213
|
+
// action: link
|
|
214
|
+
// ? {
|
|
215
|
+
// label: "View on Explorer",
|
|
216
|
+
// onClick: () => window.open(link, "_blank"),
|
|
217
|
+
// }
|
|
218
|
+
// : undefined,
|
|
219
|
+
// });
|
|
220
|
+
// setLoadingToastId(hash);
|
|
221
|
+
// }
|
|
222
|
+
// }
|
|
223
|
+
}, [
|
|
224
|
+
waitForTransaction.data,
|
|
225
|
+
waitForTransaction.error,
|
|
226
|
+
waitForTransaction.isLoading,
|
|
227
|
+
description,
|
|
228
|
+
link,
|
|
229
|
+
reset,
|
|
230
|
+
]);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const SingleChainTracker = ({
|
|
234
|
+
hash,
|
|
235
|
+
chainId,
|
|
236
|
+
message = "Transaction confirmed",
|
|
237
|
+
onConfirmed,
|
|
238
|
+
}: Omit<TrackParams, "crosschain">) => {
|
|
239
|
+
const { removeTx } = useTrackingStore();
|
|
240
|
+
const receipt = useWaitForTransactionReceipt({
|
|
241
|
+
hash,
|
|
242
|
+
chainId,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
useEffect(() => {
|
|
246
|
+
if (receipt.data) {
|
|
247
|
+
onConfirmed?.(receipt.data);
|
|
248
|
+
}
|
|
249
|
+
}, [receipt.data, onConfirmed]);
|
|
250
|
+
|
|
251
|
+
useSingleChainTransactionTracking(hash, chainId, message, receipt, () =>
|
|
252
|
+
removeTx(hash),
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
return null;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const CrosschainTracker = ({
|
|
259
|
+
hash,
|
|
260
|
+
chainId,
|
|
261
|
+
onConfirmed,
|
|
262
|
+
}: Omit<TrackParams, "crosschain" | "message">) => {
|
|
263
|
+
// const { removeTx } = useTrackingStore();
|
|
264
|
+
const receipt = useWaitForTransactionReceipt({
|
|
265
|
+
hash,
|
|
266
|
+
chainId,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// useEffect(() => {
|
|
270
|
+
// if (receipt.data) {
|
|
271
|
+
// onConfirmed?.(receipt.data);
|
|
272
|
+
// }
|
|
273
|
+
// }, [receipt.data, onConfirmed]);
|
|
274
|
+
|
|
275
|
+
useLayerZeroUrl(receipt.data ? hash : undefined, () =>
|
|
276
|
+
onConfirmed?.(receipt.data),
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
return null;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const Tracker = (props: TrackParams) => {
|
|
283
|
+
if (props.crosschain) {
|
|
284
|
+
return <CrosschainTracker {...props} />;
|
|
285
|
+
}
|
|
286
|
+
return <SingleChainTracker {...props} />;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export const TxTracker = () => {
|
|
290
|
+
const { txs } = useTrackingStore();
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<>
|
|
294
|
+
{txs
|
|
295
|
+
.filter((tx) => tx.isActive)
|
|
296
|
+
.map((tx) => (
|
|
297
|
+
<Tracker key={tx.hash} {...tx} />
|
|
298
|
+
))}
|
|
299
|
+
</>
|
|
300
|
+
);
|
|
301
|
+
};
|