@ensofinance/checkout-widget 0.0.17 → 0.0.19
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 +22053 -33949
- package/dist/checkout-widget.es.js.map +1 -1
- package/dist/checkout-widget.umd.js +61 -46
- package/dist/checkout-widget.umd.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/package.json +2 -2
- package/src/components/ChakraProvider.tsx +3 -0
- package/src/components/Checkout.tsx +6 -3
- package/src/components/steps/CardBuyFlow.tsx +778 -0
- package/src/components/steps/ExchangeFlow.tsx +526 -155
- package/src/enso-api/index.ts +276 -1
- package/src/enso-api/model/action.ts +1 -1
- package/src/enso-api/model/actionAction.ts +1 -1
- package/src/enso-api/model/actionInputs.ts +1 -1
- package/src/enso-api/model/actionToBundle.ts +1 -1
- package/src/enso-api/model/actionToBundleAction.ts +1 -1
- package/src/enso-api/model/actionToBundleArgs.ts +1 -1
- package/src/enso-api/model/approveActionDto.ts +1 -1
- package/src/enso-api/model/approveArgsDto.ts +1 -1
- package/src/enso-api/model/approveArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/balanceActionDto.ts +1 -1
- package/src/enso-api/model/balanceArgsDto.ts +1 -1
- package/src/enso-api/model/borrowActionDto.ts +1 -1
- package/src/enso-api/model/borrowArgsDto.ts +1 -1
- package/src/enso-api/model/borrowArgsDtoAmountOut.ts +1 -1
- package/src/enso-api/model/bridgeActionDto.ts +1 -1
- package/src/enso-api/model/bridgeArgsDto.ts +1 -1
- package/src/enso-api/model/bridgeArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/bridgeArgsDtoCallbackItem.ts +1 -1
- package/src/enso-api/model/bridgeLatencyEstimate.ts +1 -1
- package/src/enso-api/model/bridgeTransactionResponse.ts +37 -0
- package/src/enso-api/model/bridgeTransactionResponseStatus.ts +25 -0
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionBodyItem.ts +1 -1
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionParams.ts +1 -1
- package/src/enso-api/model/bundleControllerBundleShortcutTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransaction.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransactionAmountsOut.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransactionFeeAmount.ts +1 -1
- package/src/enso-api/model/bundleShortcutTransactionMinAmountsOut.ts +1 -1
- package/src/enso-api/model/callActionDto.ts +1 -1
- package/src/enso-api/model/callArgsDto.ts +1 -1
- package/src/enso-api/model/callArgsDtoArgsItem.ts +1 -1
- package/src/enso-api/model/callArgsDtoArgsItemAnyOf.ts +1 -1
- package/src/enso-api/model/callArgsDtoValue.ts +1 -1
- package/src/enso-api/model/callOutput.ts +1 -1
- package/src/enso-api/model/connectedNetwork.ts +1 -1
- package/src/enso-api/model/depositActionDto.ts +1 -1
- package/src/enso-api/model/depositArgsDto.ts +1 -1
- package/src/enso-api/model/depositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/depositArgsDtoAmountInOneOfItem.ts +1 -1
- package/src/enso-api/model/depositArgsDtoTokenIn.ts +1 -1
- package/src/enso-api/model/depositArgsDtoTokenOut.ts +1 -1
- package/src/enso-api/model/depositCLMMActionDto.ts +1 -1
- package/src/enso-api/model/depositCLMMArgsDto.ts +1 -1
- package/src/enso-api/model/depositCLMMArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/depositCLMMArgsDtoAmountInItemAnyOf.ts +1 -1
- package/src/enso-api/model/ensoEvent.ts +30 -0
- package/src/enso-api/model/ensoFeeActionDto.ts +1 -1
- package/src/enso-api/model/ensoFeeArgsDto.ts +1 -1
- package/src/enso-api/model/ensoFeeArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/ensoMetadata.ts +23 -0
- package/src/enso-api/model/feeActionDto.ts +1 -1
- package/src/enso-api/model/feeArgsDto.ts +1 -1
- package/src/enso-api/model/feeArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/harvestActionDto.ts +1 -1
- package/src/enso-api/model/harvestArgsDto.ts +1 -1
- package/src/enso-api/model/hop.ts +1 -1
- package/src/enso-api/model/hopArgs.ts +1 -1
- package/src/enso-api/model/index.ts +8 -1
- package/src/enso-api/model/iporControllerIporShortcutTransactionParams.ts +1 -1
- package/src/enso-api/model/iporShortcutInput.ts +1 -1
- package/src/enso-api/model/iporShortcutTransaction.ts +1 -1
- package/src/enso-api/model/lZDestinationTokenData.ts +1 -1
- package/src/enso-api/model/lZPoolLookupResponse.ts +1 -1
- package/src/enso-api/model/layerZeroControllerCheckBridgeTransactionParams.ts +21 -0
- package/src/enso-api/model/layerZeroControllerGetPoolAddressParams.ts +1 -1
- package/src/enso-api/model/layerZeroMessageStatus.ts +39 -0
- package/src/enso-api/model/mergeActionDto.ts +1 -1
- package/src/enso-api/model/mergeArgsDto.ts +1 -1
- package/src/enso-api/model/mergeArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/minAmountOutActionDto.ts +1 -1
- package/src/enso-api/model/minAmountOutArgsDto.ts +1 -1
- package/src/enso-api/model/minAmountOutArgsDtoAmountOut.ts +1 -1
- package/src/enso-api/model/minAmountOutArgsDtoMinAmountOut.ts +1 -1
- package/src/enso-api/model/multiDepositActionDto.ts +1 -1
- package/src/enso-api/model/multiDepositArgsDto.ts +1 -1
- package/src/enso-api/model/multiDepositArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/multiDepositArgsDtoAmountInItemAnyOf.ts +1 -1
- package/src/enso-api/model/multiOutSingleDepositActionDto.ts +1 -1
- package/src/enso-api/model/multiOutSingleDepositArgsDto.ts +1 -1
- package/src/enso-api/model/multiOutSingleDepositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/multiRedeemActionDto.ts +1 -1
- package/src/enso-api/model/multiRedeemArgs2Dto.ts +1 -1
- package/src/enso-api/model/multiRedeemArgs2DtoAmountIn.ts +1 -1
- package/src/enso-api/model/network.ts +1 -1
- package/src/enso-api/model/networksControllerNetworksParams.ts +1 -1
- package/src/enso-api/model/nonTokenizedControllerTokens200.ts +1 -1
- package/src/enso-api/model/nonTokenizedControllerTokens200AllOf.ts +1 -1
- package/src/enso-api/model/nonTokenizedControllerTokensParams.ts +1 -1
- package/src/enso-api/model/nonTokenizedModel.ts +1 -1
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionParams.ts +1 -1
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/nontokenizedRouteShortcutTransaction.ts +1 -1
- package/src/enso-api/model/paginatedResult.ts +1 -1
- package/src/enso-api/model/paginationMeta.ts +1 -1
- package/src/enso-api/model/paymasterFeeActionDto.ts +1 -1
- package/src/enso-api/model/paymasterFeeArgsDto.ts +1 -1
- package/src/enso-api/model/paymasterFeeArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/permitTransferFromActionDto.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDto.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDtoAmountOneOfItem.ts +1 -1
- package/src/enso-api/model/permitTransferFromArgsDtoToken.ts +1 -1
- package/src/enso-api/model/positionModel.ts +1 -1
- package/src/enso-api/model/price.ts +1 -1
- package/src/enso-api/model/pricesControllerGetPricesParams.ts +1 -1
- package/src/enso-api/model/project.ts +1 -1
- package/src/enso-api/model/protocol.ts +1 -1
- package/src/enso-api/model/protocolModel.ts +1 -1
- package/src/enso-api/model/protocolsControllerFindAllParams.ts +1 -1
- package/src/enso-api/model/redeemActionDto.ts +1 -1
- package/src/enso-api/model/redeemArgsDto.ts +1 -1
- package/src/enso-api/model/redeemArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/redeemArgsDtoTokenOut.ts +1 -1
- package/src/enso-api/model/redeemCLMMActionDto.ts +1 -1
- package/src/enso-api/model/redeemCLMMArgsDto.ts +1 -1
- package/src/enso-api/model/redeemCLMMArgsDtoLiquidity.ts +1 -1
- package/src/enso-api/model/refundDetails.ts +21 -0
- package/src/enso-api/model/repayActionDto.ts +1 -1
- package/src/enso-api/model/repayArgsDto.ts +1 -1
- package/src/enso-api/model/repayArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/routeActionDto.ts +1 -1
- package/src/enso-api/model/routeArgsDto.ts +1 -1
- package/src/enso-api/model/routeArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/routeShortcutTransaction.ts +1 -1
- package/src/enso-api/model/routeShortcutVariableInputs.ts +1 -1
- package/src/enso-api/model/routeShortcutVariableInputsRoutingStrategy.ts +1 -1
- package/src/enso-api/model/routeShortcutVariableInputsVariableEstimates.ts +1 -1
- package/src/enso-api/model/routerControllerRouteShortcutTransactionParams.ts +1 -1
- package/src/enso-api/model/routerControllerRouteShortcutTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/singleDepositActionDto.ts +1 -1
- package/src/enso-api/model/singleDepositArgsDto.ts +1 -1
- package/src/enso-api/model/singleDepositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/singleRedeemActionDto.ts +1 -1
- package/src/enso-api/model/singleRedeemArgs2Dto.ts +1 -1
- package/src/enso-api/model/singleRedeemArgs2DtoAmountIn.ts +1 -1
- package/src/enso-api/model/slippageActionDto.ts +1 -1
- package/src/enso-api/model/slippageArgsDto.ts +1 -1
- package/src/enso-api/model/slippageArgsDtoAmountOut.ts +1 -1
- package/src/enso-api/model/splitActionDto.ts +1 -1
- package/src/enso-api/model/splitArgsDto.ts +1 -1
- package/src/enso-api/model/splitArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/standard.ts +1 -1
- package/src/enso-api/model/standardAction.ts +1 -1
- package/src/enso-api/model/standardActionAction.ts +1 -1
- package/src/enso-api/model/swapActionDto.ts +1 -1
- package/src/enso-api/model/swapArgsDto.ts +1 -1
- package/src/enso-api/model/swapArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokenModel.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositArgsDtoAmountInItem.ts +1 -1
- package/src/enso-api/model/tokenizedMultiDepositArgsDtoAmountInItemAnyOf.ts +1 -1
- package/src/enso-api/model/tokenizedMultiRedeemActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiRedeemArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedMultiRedeemArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokenizedSingleDepositActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleDepositArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleDepositArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokenizedSingleRedeemActionDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleRedeemArgsDto.ts +1 -1
- package/src/enso-api/model/tokenizedSingleRedeemArgsDtoAmountIn.ts +1 -1
- package/src/enso-api/model/tokensControllerTokens200.ts +1 -1
- package/src/enso-api/model/tokensControllerTokens200AllOf.ts +1 -1
- package/src/enso-api/model/tokensControllerTokensLiquidityType.ts +1 -1
- package/src/enso-api/model/tokensControllerTokensParams.ts +1 -1
- package/src/enso-api/model/tokensControllerTokensType.ts +1 -1
- package/src/enso-api/model/transaction.ts +1 -1
- package/src/enso-api/model/transferActionDto.ts +1 -1
- package/src/enso-api/model/transferArgsDto.ts +1 -1
- package/src/enso-api/model/transferArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/transferFromActionDto.ts +1 -1
- package/src/enso-api/model/transferFromArgsDto.ts +1 -1
- package/src/enso-api/model/transferFromArgsDtoAmount.ts +1 -1
- package/src/enso-api/model/userOperation.ts +1 -1
- package/src/enso-api/model/walletApproveTransaction.ts +1 -1
- package/src/enso-api/model/walletApproveTransactionTx.ts +1 -1
- package/src/enso-api/model/walletBalance.ts +1 -1
- package/src/enso-api/model/walletControllerCreateApproveTransactionParams.ts +1 -1
- package/src/enso-api/model/walletControllerCreateApproveTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/walletControllerWalletBalancesParams.ts +1 -1
- package/src/index.ts +3 -0
- package/src/store.ts +8 -0
- package/src/types/index.ts +4 -0
- package/src/util/constants.tsx +12 -1
- package/src/util/enso-hooks.tsx +12 -5
- package/src/util/meld-hooks.tsx +319 -0
- package/src/util/tx-tracker.tsx +162 -1
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
} from "@chakra-ui/react";
|
|
12
12
|
import { ChevronLeft, X, ArrowDownUpIcon } from "lucide-react";
|
|
13
13
|
import { useContext, useEffect, useMemo, useState, useCallback } from "react";
|
|
14
|
-
import { IconButton, Button, Tab, Input } from "../ui";
|
|
15
14
|
import { useAccount, useSignMessage } from "wagmi";
|
|
16
15
|
import { getUserOperationHash } from "viem/account-abstraction";
|
|
17
16
|
import {
|
|
@@ -21,6 +20,7 @@ import {
|
|
|
21
20
|
HeaderWrapper,
|
|
22
21
|
ListWrapper,
|
|
23
22
|
} from "../ui/styled";
|
|
23
|
+
import { IconButton, Button, Tab, Input } from "../ui";
|
|
24
24
|
import { CheckoutContext } from "../Checkout";
|
|
25
25
|
import Modal from "../modal";
|
|
26
26
|
import {
|
|
@@ -40,6 +40,8 @@ import { useTokenFromListBySymbols, precisionizeNumber } from "@/util/common";
|
|
|
40
40
|
import {
|
|
41
41
|
EXCHANGE_MAX_LIMIT_GAP_USD,
|
|
42
42
|
EXCHANGE_MIN_LIMIT,
|
|
43
|
+
getCexIntermediateChain,
|
|
44
|
+
DEFAULT_CEX_BRIDGE_CHAIN_MAPPING,
|
|
43
45
|
} from "@/util/constants";
|
|
44
46
|
import {
|
|
45
47
|
useAppDetails,
|
|
@@ -54,6 +56,8 @@ import { ConfirmExchangeStep } from "../ExchangeConfirmSecurity";
|
|
|
54
56
|
import SuccessIcon from "@/assets/success.svg";
|
|
55
57
|
import FailIcon from "@/assets/fail.svg";
|
|
56
58
|
import { SupportedExchanges } from "@/types";
|
|
59
|
+
import { useLayerZeroStatus } from "@/util/tx-tracker";
|
|
60
|
+
import { STARGATE_CHAIN_NAMES, CHAINS_ETHERSCAN } from "@/util/constants";
|
|
57
61
|
|
|
58
62
|
const ENTRY_POINT_ADDRESS: `0x${string}` =
|
|
59
63
|
"0x0000000071727de22e5e9d8baf0edac6f37da032";
|
|
@@ -124,6 +128,9 @@ interface MatchedToken extends SupportedToken {
|
|
|
124
128
|
holding?: CryptocurrencyPosition;
|
|
125
129
|
}
|
|
126
130
|
|
|
131
|
+
const isDelayedBalanceUsed = (integrationType: string) =>
|
|
132
|
+
integrationType === "delayed";
|
|
133
|
+
|
|
127
134
|
// const MESH_API_URL = "http://localhost:8787";
|
|
128
135
|
const MESH_API_URL = "https://mesh-bff.enso-checkout.workers.dev";
|
|
129
136
|
|
|
@@ -194,8 +201,7 @@ const useHandleMeshAccessPayload = () => {
|
|
|
194
201
|
sessionStorage.setItem(
|
|
195
202
|
`${deviceKey}:${selectedIntegration?.type}`,
|
|
196
203
|
JSON.stringify({
|
|
197
|
-
|
|
198
|
-
accessTokenPayload.accountTokens[0].accessToken,
|
|
204
|
+
accessTokenPayload, // Store full object for proper restoration
|
|
199
205
|
sessionId,
|
|
200
206
|
timestamp: Date.now(),
|
|
201
207
|
}),
|
|
@@ -222,14 +228,26 @@ const ChooseExchangeStep = ({
|
|
|
222
228
|
}: {
|
|
223
229
|
setStep: (step: WithdrawalStep) => void;
|
|
224
230
|
}) => {
|
|
225
|
-
const { chainIdOut } = useAppStore();
|
|
231
|
+
const { chainIdOut, setChainIdIn } = useAppStore();
|
|
226
232
|
const [integrations, setIntegrations] = useState<MeshIntegration[]>([]);
|
|
227
233
|
const [loading, setLoading] = useState(true);
|
|
228
234
|
const [error, setError] = useState<string | null>(null);
|
|
229
235
|
const setSelectedIntegration = useAppStore(
|
|
230
236
|
(state) => state.setSelectedIntegration,
|
|
231
237
|
);
|
|
232
|
-
const { enableExchange } =
|
|
238
|
+
const { enableExchange, cexBridgeChainMapping } =
|
|
239
|
+
useContext(CheckoutContext);
|
|
240
|
+
const cexMapping =
|
|
241
|
+
cexBridgeChainMapping ?? DEFAULT_CEX_BRIDGE_CHAIN_MAPPING;
|
|
242
|
+
|
|
243
|
+
// Use intermediate chain for filtering if target chain needs bridging
|
|
244
|
+
const effectiveChainId =
|
|
245
|
+
getCexIntermediateChain(chainIdOut, cexMapping) ?? chainIdOut;
|
|
246
|
+
|
|
247
|
+
// Set chainIdIn to effective chain for cross-chain tracking
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
effectiveChainId ? setChainIdIn(effectiveChainId) : chainIdOut;
|
|
250
|
+
}, [effectiveChainId, setChainIdIn]);
|
|
233
251
|
|
|
234
252
|
useEffect(() => {
|
|
235
253
|
const fetchIntegrations = async () => {
|
|
@@ -240,11 +258,12 @@ const ChooseExchangeStep = ({
|
|
|
240
258
|
.map((e) => ExchangeToIntegrationType[e])
|
|
241
259
|
.filter(Boolean);
|
|
242
260
|
|
|
243
|
-
// Filter integrations by
|
|
261
|
+
// Filter integrations by effective chain support (intermediate chain if bridging)
|
|
244
262
|
const filtered = data?.filter(
|
|
245
263
|
(i) =>
|
|
246
|
-
i.networks.some(
|
|
247
|
-
|
|
264
|
+
i.networks.some(
|
|
265
|
+
(n) => +n.chainId === effectiveChainId,
|
|
266
|
+
) && availableExchanges.includes(i.type),
|
|
248
267
|
);
|
|
249
268
|
|
|
250
269
|
setIntegrations(filtered);
|
|
@@ -256,7 +275,7 @@ const ChooseExchangeStep = ({
|
|
|
256
275
|
}
|
|
257
276
|
};
|
|
258
277
|
fetchIntegrations();
|
|
259
|
-
}, [
|
|
278
|
+
}, [effectiveChainId]);
|
|
260
279
|
|
|
261
280
|
if (loading)
|
|
262
281
|
return (
|
|
@@ -322,19 +341,20 @@ const CheckSessionKeyStep = ({
|
|
|
322
341
|
}: {
|
|
323
342
|
setStep: (step: WithdrawalStep) => void;
|
|
324
343
|
}) => {
|
|
325
|
-
const { chainIdOut, setMeshAccessToken, setSessionId
|
|
344
|
+
const { chainIdIn, chainIdOut, setMeshAccessToken, setSessionId } =
|
|
326
345
|
useAppStore();
|
|
327
346
|
const { address } = useAccount();
|
|
328
347
|
const deviceKey = useDeviceId();
|
|
329
348
|
const [showConfirmation, setShowConfirmation] = useState(false);
|
|
330
349
|
const selectedIntegration = useAppStore((s) => s.selectedIntegration);
|
|
331
350
|
|
|
332
|
-
|
|
333
|
-
const
|
|
351
|
+
// Bridging is required if chainIdIn differs from chainIdOut
|
|
352
|
+
const needsBridging = chainIdIn !== chainIdOut;
|
|
334
353
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
354
|
+
// Invalid only if chain is not in MESH_NETWORKS AND cannot be bridged
|
|
355
|
+
const invalidChainId =
|
|
356
|
+
chainIdOut && !MESH_NETWORKS.includes(chainIdOut) && !needsBridging;
|
|
357
|
+
const handleMeshAccessPayload = useHandleMeshAccessPayload();
|
|
338
358
|
|
|
339
359
|
useEffect(() => {
|
|
340
360
|
if (!selectedIntegration) {
|
|
@@ -351,8 +371,8 @@ const CheckSessionKeyStep = ({
|
|
|
351
371
|
if (saved) {
|
|
352
372
|
try {
|
|
353
373
|
const parsed = JSON.parse(saved);
|
|
354
|
-
if (parsed?.
|
|
355
|
-
setMeshAccessToken(parsed.
|
|
374
|
+
if (parsed?.accessTokenPayload && parsed?.sessionId) {
|
|
375
|
+
setMeshAccessToken(parsed.accessTokenPayload);
|
|
356
376
|
setSessionId(parsed.sessionId);
|
|
357
377
|
setStep(WithdrawalStep.ChooseExchangeAsset);
|
|
358
378
|
return;
|
|
@@ -488,7 +508,6 @@ const ChooseAssetStep = ({
|
|
|
488
508
|
const [error, setError] = useState<string | null>(null);
|
|
489
509
|
const { address } = useAccount();
|
|
490
510
|
const {
|
|
491
|
-
chainIdOut,
|
|
492
511
|
meshAccessToken,
|
|
493
512
|
sessionId,
|
|
494
513
|
setMeshAccessToken,
|
|
@@ -513,7 +532,9 @@ const ChooseAssetStep = ({
|
|
|
513
532
|
"x-session-id": sessionId,
|
|
514
533
|
},
|
|
515
534
|
body: JSON.stringify({
|
|
516
|
-
authToken:
|
|
535
|
+
authToken:
|
|
536
|
+
meshAccessToken?.accountTokens?.[0]
|
|
537
|
+
?.accessToken,
|
|
517
538
|
brokerType: selectedIntegration?.type,
|
|
518
539
|
}),
|
|
519
540
|
},
|
|
@@ -541,7 +562,7 @@ const ChooseAssetStep = ({
|
|
|
541
562
|
);
|
|
542
563
|
}
|
|
543
564
|
|
|
544
|
-
// Fetch supported tokens for
|
|
565
|
+
// Fetch supported tokens for chainIdIn (intermediate chain if bridging)
|
|
545
566
|
const tokensResponse = await fetch(
|
|
546
567
|
`${MESH_API_URL}/tokens?chainId=${chainIdIn}&brokerType=${encodeURIComponent(selectedIntegration?.type || "")}`,
|
|
547
568
|
);
|
|
@@ -596,10 +617,10 @@ const ChooseAssetStep = ({
|
|
|
596
617
|
}
|
|
597
618
|
};
|
|
598
619
|
|
|
599
|
-
if (meshAccessToken && sessionId &&
|
|
620
|
+
if (meshAccessToken && sessionId && chainIdIn && selectedIntegration) {
|
|
600
621
|
fetchData();
|
|
601
622
|
}
|
|
602
|
-
}, [address,
|
|
623
|
+
}, [address, chainIdIn, meshAccessToken, sessionId, selectedIntegration]);
|
|
603
624
|
|
|
604
625
|
const geckoTokens = useTokenFromListBySymbols(
|
|
605
626
|
matchedTokens.map((token) => token.symbol),
|
|
@@ -632,7 +653,7 @@ const ChooseAssetStep = ({
|
|
|
632
653
|
{matchedTokens.map((token, index) => (
|
|
633
654
|
<AssetCard
|
|
634
655
|
key={`${token.symbol}-${index}`}
|
|
635
|
-
chainId={
|
|
656
|
+
chainId={chainIdIn}
|
|
636
657
|
icon={geckoTokens?.[index]?.logoURI?.replace(
|
|
637
658
|
"/thumb/",
|
|
638
659
|
"/large/",
|
|
@@ -780,48 +801,61 @@ const ChooseAmountStep = ({
|
|
|
780
801
|
const [amount, setAmount] = useState<string>("");
|
|
781
802
|
const [inputMode, setInputMode] = useState<"usd" | "token">("usd");
|
|
782
803
|
const [usdValue, setUsdValue] = useState<string>("");
|
|
783
|
-
const
|
|
784
|
-
const { tokenInData } = useAppDetails();
|
|
804
|
+
const setAmountIn = useAppStore((s) => s.setAmountIn);
|
|
805
|
+
const { tokenInData, selectedIntegration } = useAppDetails();
|
|
785
806
|
const isStable = selectedToken?.symbol.toLowerCase().includes("USD");
|
|
786
807
|
const roundingPrecision = isStable ? 2 : 6;
|
|
787
808
|
|
|
809
|
+
// Only apply CEX withdrawal limits if using a CEX holding (not smart account)
|
|
810
|
+
const isWithdrawal = !isDelayedBalanceUsed(selectedIntegration.type);
|
|
811
|
+
|
|
788
812
|
const maxUsdAmount = selectedToken
|
|
789
|
-
?
|
|
813
|
+
? isWithdrawal
|
|
814
|
+
? (selectedToken.marketValue - EXCHANGE_MAX_LIMIT_GAP_USD).toFixed(
|
|
815
|
+
2,
|
|
816
|
+
)
|
|
817
|
+
: selectedToken.marketValue.toFixed(2)
|
|
790
818
|
: 0;
|
|
791
819
|
|
|
792
|
-
// Handle percentage selection with limits
|
|
820
|
+
// Handle percentage selection with limits (only for CEX withdrawals)
|
|
793
821
|
const handlePercentageSelect = useCallback(
|
|
794
822
|
(percent: number) => {
|
|
795
823
|
if (!selectedToken) return;
|
|
796
824
|
|
|
797
|
-
const minValueForToken =
|
|
798
|
-
EXCHANGE_MIN_LIMIT[
|
|
799
|
-
selectedToken.symbol as keyof typeof EXCHANGE_MIN_LIMIT
|
|
800
|
-
] || 0;
|
|
801
|
-
|
|
802
825
|
// Calculate target USD amount based on percentage
|
|
803
826
|
const targetUsdAmount = (selectedToken.marketValue * percent) / 100;
|
|
804
827
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
minValueForToken,
|
|
808
|
-
Math.min(targetUsdAmount, +maxUsdAmount),
|
|
809
|
-
);
|
|
828
|
+
let finalUsdAmount: number;
|
|
829
|
+
let finalTokenAmount: number;
|
|
810
830
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
);
|
|
831
|
+
if (isWithdrawal) {
|
|
832
|
+
// Apply limits for CEX withdrawals
|
|
833
|
+
const minValueForToken =
|
|
834
|
+
EXCHANGE_MIN_LIMIT[
|
|
835
|
+
selectedToken.symbol as keyof typeof EXCHANGE_MIN_LIMIT
|
|
836
|
+
] || 0;
|
|
818
837
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
838
|
+
finalUsdAmount = Math.max(
|
|
839
|
+
minValueForToken,
|
|
840
|
+
Math.min(targetUsdAmount, +maxUsdAmount),
|
|
841
|
+
);
|
|
842
|
+
|
|
843
|
+
const tokenPrice =
|
|
844
|
+
selectedToken.marketValue / selectedToken.balance;
|
|
845
|
+
finalTokenAmount = Math.min(
|
|
846
|
+
finalUsdAmount / tokenPrice,
|
|
847
|
+
selectedToken.balance,
|
|
848
|
+
);
|
|
849
|
+
} else {
|
|
850
|
+
// No limits for smart account balances
|
|
851
|
+
finalUsdAmount = targetUsdAmount;
|
|
852
|
+
finalTokenAmount = (selectedToken.balance * percent) / 100;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
setAmount(precisionizeNumber(finalTokenAmount, roundingPrecision));
|
|
856
|
+
setUsdValue(finalUsdAmount.toFixed(2));
|
|
823
857
|
},
|
|
824
|
-
[selectedToken],
|
|
858
|
+
[selectedToken, isWithdrawal, maxUsdAmount, roundingPrecision],
|
|
825
859
|
);
|
|
826
860
|
|
|
827
861
|
// Set max value on load
|
|
@@ -891,21 +925,26 @@ const ChooseAmountStep = ({
|
|
|
891
925
|
? parseFloat(amount) > selectedToken.balance
|
|
892
926
|
: true;
|
|
893
927
|
|
|
894
|
-
// Limits validation logic
|
|
928
|
+
// Limits validation logic - only for CEX withdrawals
|
|
895
929
|
const currentUsdValue = parseFloat(usdValue);
|
|
896
|
-
const minValueForToken =
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
930
|
+
const minValueForToken =
|
|
931
|
+
isWithdrawal && selectedToken
|
|
932
|
+
? EXCHANGE_MIN_LIMIT[
|
|
933
|
+
selectedToken.symbol as keyof typeof EXCHANGE_MIN_LIMIT
|
|
934
|
+
]
|
|
935
|
+
: 0;
|
|
901
936
|
|
|
902
937
|
const isBelowMinAmount =
|
|
938
|
+
isWithdrawal &&
|
|
903
939
|
selectedToken &&
|
|
904
940
|
currentUsdValue > 0 &&
|
|
905
941
|
minValueForToken &&
|
|
906
942
|
+amount < minValueForToken;
|
|
907
943
|
const isAboveMaxAmount =
|
|
908
|
-
|
|
944
|
+
isWithdrawal &&
|
|
945
|
+
selectedToken &&
|
|
946
|
+
currentUsdValue > 0 &&
|
|
947
|
+
currentUsdValue > +maxUsdAmount;
|
|
909
948
|
|
|
910
949
|
const isAmountInvalid =
|
|
911
950
|
isBelowMinAmount || isAboveMaxAmount || notEnoughBalance;
|
|
@@ -1157,7 +1196,7 @@ const InitiateWithdrawalStep = ({
|
|
|
1157
1196
|
userOp: any;
|
|
1158
1197
|
setStep: (step: WithdrawalStep) => void;
|
|
1159
1198
|
}) => {
|
|
1160
|
-
const { meshAccessToken, amountIn,
|
|
1199
|
+
const { meshAccessToken, amountIn, chainIdIn } = useAppStore();
|
|
1161
1200
|
const { address } = useAccount();
|
|
1162
1201
|
const { tokenInData } = useAppDetails();
|
|
1163
1202
|
const sessionId = useAppStore((state) => state.sessionId);
|
|
@@ -1184,7 +1223,7 @@ const InitiateWithdrawalStep = ({
|
|
|
1184
1223
|
try {
|
|
1185
1224
|
const toAddresses = [
|
|
1186
1225
|
{
|
|
1187
|
-
networkId: getNetworkId(
|
|
1226
|
+
networkId: getNetworkId(chainIdIn),
|
|
1188
1227
|
symbol: selectedToken.symbol,
|
|
1189
1228
|
address: userOp.sender,
|
|
1190
1229
|
amount: transferAmount,
|
|
@@ -1290,6 +1329,53 @@ const InitiateWithdrawalStep = ({
|
|
|
1290
1329
|
);
|
|
1291
1330
|
};
|
|
1292
1331
|
|
|
1332
|
+
// Phase indicator component for cross-chain tracking
|
|
1333
|
+
const PhaseIndicator = ({
|
|
1334
|
+
currentPhase,
|
|
1335
|
+
phases,
|
|
1336
|
+
}: {
|
|
1337
|
+
currentPhase: number;
|
|
1338
|
+
phases: string[];
|
|
1339
|
+
}) => {
|
|
1340
|
+
return (
|
|
1341
|
+
<Box display="flex" gap={4} justifyContent="center" mb={4}>
|
|
1342
|
+
{phases.map((phase, index) => (
|
|
1343
|
+
<Box key={phase} display="flex" alignItems="center" gap={2}>
|
|
1344
|
+
<Box
|
|
1345
|
+
w={6}
|
|
1346
|
+
h={6}
|
|
1347
|
+
borderRadius="full"
|
|
1348
|
+
bg={
|
|
1349
|
+
index < currentPhase
|
|
1350
|
+
? "green.500"
|
|
1351
|
+
: index === currentPhase
|
|
1352
|
+
? "blue.500"
|
|
1353
|
+
: "gray.300"
|
|
1354
|
+
}
|
|
1355
|
+
display="flex"
|
|
1356
|
+
alignItems="center"
|
|
1357
|
+
justifyContent="center"
|
|
1358
|
+
color="white"
|
|
1359
|
+
fontSize="xs"
|
|
1360
|
+
fontWeight="bold"
|
|
1361
|
+
>
|
|
1362
|
+
{index < currentPhase ? "✓" : index + 1}
|
|
1363
|
+
</Box>
|
|
1364
|
+
<Text
|
|
1365
|
+
fontSize="sm"
|
|
1366
|
+
color={index === currentPhase ? "fg" : "fg.muted"}
|
|
1367
|
+
fontWeight={
|
|
1368
|
+
index === currentPhase ? "semibold" : "normal"
|
|
1369
|
+
}
|
|
1370
|
+
>
|
|
1371
|
+
{phase}
|
|
1372
|
+
</Text>
|
|
1373
|
+
</Box>
|
|
1374
|
+
))}
|
|
1375
|
+
</Box>
|
|
1376
|
+
);
|
|
1377
|
+
};
|
|
1378
|
+
|
|
1293
1379
|
const TrackUserOpStep = ({
|
|
1294
1380
|
selectedToken,
|
|
1295
1381
|
userOp,
|
|
@@ -1299,23 +1385,53 @@ const TrackUserOpStep = ({
|
|
|
1299
1385
|
userOp: any;
|
|
1300
1386
|
setStep: (step: WithdrawalStep) => void;
|
|
1301
1387
|
}) => {
|
|
1302
|
-
const { chainIdIn, tokenInData } = useAppDetails();
|
|
1388
|
+
const { chainIdIn, chainIdOut, tokenInData } = useAppDetails();
|
|
1303
1389
|
const { amountIn } = useAppStore();
|
|
1390
|
+
|
|
1391
|
+
// Determine if this is a cross-chain (bridge) flow
|
|
1392
|
+
const isCrosschain = chainIdIn !== chainIdOut;
|
|
1393
|
+
|
|
1394
|
+
// Phase management: for crosschain 'cex' -> 'bridge' -> 'completed', for single-chain just 'cex' -> 'completed'
|
|
1395
|
+
const [phase, setPhase] = useState<
|
|
1396
|
+
"cex" | "bridge" | "completed" | "failed"
|
|
1397
|
+
>("cex");
|
|
1304
1398
|
const [operationId, setOperationId] = useState<string | null>(null);
|
|
1305
1399
|
const [status, setStatus] = useState<
|
|
1306
1400
|
"sending" | "tracking" | "completed" | "failed"
|
|
1307
1401
|
>("sending");
|
|
1308
1402
|
const [message, setMessage] = useState("Sending operation to tracker...");
|
|
1403
|
+
const [txHash, setTxHash] = useState<`0x${string}` | null>(null);
|
|
1309
1404
|
const [isTimerFinished, setIsTimerFinished] = useState(false);
|
|
1310
1405
|
const [trackingInterval, setTrackingInterval] =
|
|
1311
1406
|
useState<NodeJS.Timeout | null>(null);
|
|
1407
|
+
const [destinationVerified, setDestinationVerified] = useState(false);
|
|
1408
|
+
const [destinationSuccess, setDestinationSuccess] = useState<
|
|
1409
|
+
boolean | null
|
|
1410
|
+
>(null);
|
|
1411
|
+
const [refundDetails, setRefundDetails] = useState<{
|
|
1412
|
+
token: string;
|
|
1413
|
+
amount: string;
|
|
1414
|
+
recipient: string;
|
|
1415
|
+
isNative: boolean;
|
|
1416
|
+
} | null>(null);
|
|
1417
|
+
const [destinationTxHash, setDestinationTxHash] = useState<string | null>(
|
|
1418
|
+
null,
|
|
1419
|
+
);
|
|
1312
1420
|
|
|
1421
|
+
// LayerZero tracking for bridge progress (real-time updates)
|
|
1422
|
+
const lzStatus = useLayerZeroStatus(
|
|
1423
|
+
txHash ?? undefined,
|
|
1424
|
+
isCrosschain && phase === "bridge",
|
|
1425
|
+
);
|
|
1426
|
+
|
|
1427
|
+
// Send UserOp to tracker
|
|
1313
1428
|
useEffect(() => {
|
|
1314
1429
|
const sendUserOpToTracker = async () => {
|
|
1315
1430
|
if (!selectedToken || !userOp || !tokenInData) {
|
|
1316
1431
|
console.error("Missing required data for tracking");
|
|
1317
1432
|
setStatus("failed");
|
|
1318
1433
|
setMessage("Missing required data");
|
|
1434
|
+
setPhase("failed");
|
|
1319
1435
|
return;
|
|
1320
1436
|
}
|
|
1321
1437
|
|
|
@@ -1362,7 +1478,11 @@ const TrackUserOpStep = ({
|
|
|
1362
1478
|
if (data.success && data.operationId) {
|
|
1363
1479
|
setOperationId(data.operationId);
|
|
1364
1480
|
setStatus("tracking");
|
|
1365
|
-
setMessage(
|
|
1481
|
+
setMessage(
|
|
1482
|
+
isCrosschain
|
|
1483
|
+
? "Funds forwarding in progress..."
|
|
1484
|
+
: "Tracking operation progress...",
|
|
1485
|
+
);
|
|
1366
1486
|
} else {
|
|
1367
1487
|
throw new Error(
|
|
1368
1488
|
data.message || "Failed to send operation to tracker",
|
|
@@ -1372,6 +1492,7 @@ const TrackUserOpStep = ({
|
|
|
1372
1492
|
console.error("Failed to send operation to tracker:", error);
|
|
1373
1493
|
setStatus("failed");
|
|
1374
1494
|
setMessage("Failed to send operation to tracker");
|
|
1495
|
+
setPhase("failed");
|
|
1375
1496
|
}
|
|
1376
1497
|
};
|
|
1377
1498
|
|
|
@@ -1392,14 +1513,43 @@ const TrackUserOpStep = ({
|
|
|
1392
1513
|
|
|
1393
1514
|
if (data.operation?.status === "completed") {
|
|
1394
1515
|
setStatus("completed");
|
|
1395
|
-
|
|
1516
|
+
|
|
1517
|
+
if (isCrosschain) {
|
|
1518
|
+
// For crosschain: move to bridge phase
|
|
1519
|
+
setMessage("Funds forwarding completed!");
|
|
1520
|
+
if (data.operation?.bundleTxHash) {
|
|
1521
|
+
setTxHash(
|
|
1522
|
+
data.operation.bundleTxHash as `0x${string}`,
|
|
1523
|
+
);
|
|
1524
|
+
setPhase("bridge");
|
|
1525
|
+
} else {
|
|
1526
|
+
console.warn(
|
|
1527
|
+
"No bundleTxHash returned from indexer, cannot track bridge",
|
|
1528
|
+
);
|
|
1529
|
+
setPhase("completed");
|
|
1530
|
+
}
|
|
1531
|
+
} else {
|
|
1532
|
+
// For single-chain: complete
|
|
1533
|
+
setMessage("Operation completed successfully!");
|
|
1534
|
+
setPhase("completed");
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1396
1537
|
if (trackingInterval) {
|
|
1397
1538
|
clearInterval(trackingInterval);
|
|
1398
1539
|
setTrackingInterval(null);
|
|
1399
1540
|
}
|
|
1400
|
-
} else if (
|
|
1541
|
+
} else if (
|
|
1542
|
+
["failed", "failed_permanent"].includes(
|
|
1543
|
+
data.operation?.status,
|
|
1544
|
+
)
|
|
1545
|
+
) {
|
|
1401
1546
|
setStatus("failed");
|
|
1402
|
-
setMessage(
|
|
1547
|
+
setMessage(
|
|
1548
|
+
isCrosschain
|
|
1549
|
+
? "Bridging failed. Please select Smart-account balance as a source to use withdrawn funds"
|
|
1550
|
+
: "Operation failed",
|
|
1551
|
+
);
|
|
1552
|
+
setPhase("failed");
|
|
1403
1553
|
if (trackingInterval) {
|
|
1404
1554
|
clearInterval(trackingInterval);
|
|
1405
1555
|
setTrackingInterval(null);
|
|
@@ -1410,20 +1560,94 @@ const TrackUserOpStep = ({
|
|
|
1410
1560
|
}
|
|
1411
1561
|
};
|
|
1412
1562
|
|
|
1413
|
-
const interval = setInterval(trackOperation, 3000);
|
|
1563
|
+
const interval = setInterval(trackOperation, 3000);
|
|
1414
1564
|
setTrackingInterval(interval);
|
|
1415
1565
|
|
|
1416
1566
|
return () => {
|
|
1417
1567
|
if (interval) clearInterval(interval);
|
|
1418
1568
|
};
|
|
1419
|
-
}, [operationId]);
|
|
1569
|
+
}, [operationId, status, isCrosschain]);
|
|
1570
|
+
|
|
1571
|
+
// Handle bridge completion - verify destination execution once LayerZero shows DELIVERED
|
|
1572
|
+
useEffect(() => {
|
|
1573
|
+
if (!isCrosschain || phase !== "bridge") return;
|
|
1574
|
+
|
|
1575
|
+
// If LayerZero failed, mark as failed immediately
|
|
1576
|
+
if (lzStatus.isFailed) {
|
|
1577
|
+
setPhase("failed");
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
// When LayerZero shows DELIVERED, verify destination execution with Enso API
|
|
1582
|
+
if (
|
|
1583
|
+
lzStatus.isComplete &&
|
|
1584
|
+
!destinationVerified &&
|
|
1585
|
+
txHash &&
|
|
1586
|
+
chainIdIn
|
|
1587
|
+
) {
|
|
1588
|
+
// TODO: use hook
|
|
1589
|
+
const verifyDestination = async () => {
|
|
1590
|
+
try {
|
|
1591
|
+
const res = await fetch(
|
|
1592
|
+
`https://api.enso.finance/api/v1/layerzero/bridge/check?chainId=${chainIdIn}&txHash=${txHash}`,
|
|
1593
|
+
);
|
|
1594
|
+
if (!res.ok) {
|
|
1595
|
+
// If API call fails, assume success (LayerZero delivered)
|
|
1596
|
+
setDestinationVerified(true);
|
|
1597
|
+
setDestinationSuccess(true);
|
|
1598
|
+
setPhase("completed");
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const data = await res.json();
|
|
1602
|
+
setDestinationVerified(true);
|
|
1603
|
+
setDestinationTxHash(data.destinationTxHash || null);
|
|
1604
|
+
|
|
1605
|
+
if (data.status === "success") {
|
|
1606
|
+
setDestinationSuccess(true);
|
|
1607
|
+
setPhase("completed");
|
|
1608
|
+
} else if (data.status === "failed") {
|
|
1609
|
+
setDestinationSuccess(false);
|
|
1610
|
+
setRefundDetails(
|
|
1611
|
+
data.ensoDestinationEvent?.refundDetails || null,
|
|
1612
|
+
);
|
|
1613
|
+
setPhase("failed");
|
|
1614
|
+
} else {
|
|
1615
|
+
// Still pending, assume success since LZ delivered
|
|
1616
|
+
setDestinationSuccess(true);
|
|
1617
|
+
setPhase("completed");
|
|
1618
|
+
}
|
|
1619
|
+
} catch (error) {
|
|
1620
|
+
console.error("Failed to verify destination:", error);
|
|
1621
|
+
// On error, assume success since LayerZero delivered
|
|
1622
|
+
setDestinationVerified(true);
|
|
1623
|
+
setDestinationSuccess(true);
|
|
1624
|
+
setPhase("completed");
|
|
1625
|
+
}
|
|
1626
|
+
};
|
|
1627
|
+
verifyDestination();
|
|
1628
|
+
}
|
|
1629
|
+
}, [
|
|
1630
|
+
phase,
|
|
1631
|
+
lzStatus.isComplete,
|
|
1632
|
+
lzStatus.isFailed,
|
|
1633
|
+
isCrosschain,
|
|
1634
|
+
destinationVerified,
|
|
1635
|
+
txHash,
|
|
1636
|
+
chainIdIn,
|
|
1637
|
+
]);
|
|
1420
1638
|
|
|
1421
1639
|
const handleTimerFinish = () => {
|
|
1422
1640
|
setIsTimerFinished(true);
|
|
1423
1641
|
};
|
|
1424
1642
|
|
|
1643
|
+
const getOverallStatus = () => {
|
|
1644
|
+
if (phase === "failed") return "failed";
|
|
1645
|
+
if (phase === "completed") return "completed";
|
|
1646
|
+
return "processing";
|
|
1647
|
+
};
|
|
1648
|
+
|
|
1425
1649
|
const getStatusColor = () => {
|
|
1426
|
-
switch (
|
|
1650
|
+
switch (getOverallStatus()) {
|
|
1427
1651
|
case "completed":
|
|
1428
1652
|
return "#14AE5C";
|
|
1429
1653
|
case "failed":
|
|
@@ -1433,57 +1657,108 @@ const TrackUserOpStep = ({
|
|
|
1433
1657
|
}
|
|
1434
1658
|
};
|
|
1435
1659
|
|
|
1436
|
-
const
|
|
1437
|
-
switch (
|
|
1438
|
-
case "sending":
|
|
1439
|
-
case "tracking":
|
|
1440
|
-
return (
|
|
1441
|
-
<CircleTimer
|
|
1442
|
-
start={status === "tracking"}
|
|
1443
|
-
onFinish={handleTimerFinish}
|
|
1444
|
-
duration={120}
|
|
1445
|
-
/>
|
|
1446
|
-
);
|
|
1447
|
-
|
|
1660
|
+
const getStatusText = () => {
|
|
1661
|
+
switch (getOverallStatus()) {
|
|
1448
1662
|
case "completed":
|
|
1449
|
-
return
|
|
1450
|
-
<Box
|
|
1451
|
-
display="flex"
|
|
1452
|
-
flexDirection="column"
|
|
1453
|
-
alignItems="center"
|
|
1454
|
-
>
|
|
1455
|
-
<Image
|
|
1456
|
-
src={SuccessIcon}
|
|
1457
|
-
boxShadow="0px 0px 20px #14AE5C"
|
|
1458
|
-
borderRadius="90%"
|
|
1459
|
-
width="58px"
|
|
1460
|
-
height="58px"
|
|
1461
|
-
/>
|
|
1462
|
-
</Box>
|
|
1463
|
-
);
|
|
1464
|
-
|
|
1663
|
+
return "Success";
|
|
1465
1664
|
case "failed":
|
|
1466
|
-
return
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
flexDirection="column"
|
|
1470
|
-
alignItems="center"
|
|
1471
|
-
>
|
|
1472
|
-
<Image
|
|
1473
|
-
src={FailIcon}
|
|
1474
|
-
boxShadow="0px 0px 20px #E84142"
|
|
1475
|
-
borderRadius="90%"
|
|
1476
|
-
width="58px"
|
|
1477
|
-
height="58px"
|
|
1478
|
-
/>
|
|
1479
|
-
</Box>
|
|
1480
|
-
);
|
|
1665
|
+
return "Failed";
|
|
1666
|
+
default:
|
|
1667
|
+
return "Processing";
|
|
1481
1668
|
}
|
|
1482
1669
|
};
|
|
1483
1670
|
|
|
1484
|
-
const
|
|
1485
|
-
if (
|
|
1671
|
+
const getCurrentMessage = () => {
|
|
1672
|
+
if (isCrosschain) {
|
|
1673
|
+
if (phase === "cex") {
|
|
1674
|
+
return `(1/2) ${message}`;
|
|
1675
|
+
} else if (phase === "bridge") {
|
|
1676
|
+
return `(2/2) ${lzStatus.message}`;
|
|
1677
|
+
} else if (phase === "completed") {
|
|
1678
|
+
return "Transfer completed successfully!";
|
|
1679
|
+
} else {
|
|
1680
|
+
return refundDetails
|
|
1681
|
+
? "Destination execution failed. Funds refunded to smart account."
|
|
1682
|
+
: "Transfer failed";
|
|
1683
|
+
}
|
|
1684
|
+
} else {
|
|
1685
|
+
if (phase === "completed") {
|
|
1686
|
+
return "Operation completed successfully!";
|
|
1687
|
+
} else if (phase === "failed") {
|
|
1688
|
+
return "Operation failed";
|
|
1689
|
+
}
|
|
1690
|
+
return message;
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
|
|
1694
|
+
const renderStatusIcon = () => {
|
|
1695
|
+
const isProcessing = phase === "cex" || phase === "bridge";
|
|
1696
|
+
|
|
1697
|
+
if (isProcessing) {
|
|
1698
|
+
return (
|
|
1699
|
+
<CircleTimer
|
|
1700
|
+
start={status === "tracking" || phase === "bridge"}
|
|
1701
|
+
onFinish={handleTimerFinish}
|
|
1702
|
+
duration={isCrosschain ? 180 : 120}
|
|
1703
|
+
/>
|
|
1704
|
+
);
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
if (phase === "completed") {
|
|
1486
1708
|
return (
|
|
1709
|
+
<Box display="flex" flexDirection="column" alignItems="center">
|
|
1710
|
+
<Image
|
|
1711
|
+
src={SuccessIcon}
|
|
1712
|
+
boxShadow="0px 0px 20px #14AE5C"
|
|
1713
|
+
borderRadius="90%"
|
|
1714
|
+
width="58px"
|
|
1715
|
+
height="58px"
|
|
1716
|
+
/>
|
|
1717
|
+
</Box>
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
return (
|
|
1722
|
+
<Box display="flex" flexDirection="column" alignItems="center">
|
|
1723
|
+
<Image
|
|
1724
|
+
src={FailIcon}
|
|
1725
|
+
boxShadow="0px 0px 20px #E84142"
|
|
1726
|
+
borderRadius="90%"
|
|
1727
|
+
width="58px"
|
|
1728
|
+
height="58px"
|
|
1729
|
+
/>
|
|
1730
|
+
</Box>
|
|
1731
|
+
);
|
|
1732
|
+
};
|
|
1733
|
+
|
|
1734
|
+
const intermediateChainName = chainIdIn
|
|
1735
|
+
? STARGATE_CHAIN_NAMES[chainIdIn as keyof typeof STARGATE_CHAIN_NAMES]
|
|
1736
|
+
: "Unknown";
|
|
1737
|
+
const targetChainName = chainIdOut
|
|
1738
|
+
? STARGATE_CHAIN_NAMES[chainIdOut as keyof typeof STARGATE_CHAIN_NAMES]
|
|
1739
|
+
: "Unknown";
|
|
1740
|
+
|
|
1741
|
+
return (
|
|
1742
|
+
<BodyWrapper>
|
|
1743
|
+
{/* Phase Indicator (crosschain only) */}
|
|
1744
|
+
{isCrosschain && (
|
|
1745
|
+
<PhaseIndicator
|
|
1746
|
+
currentPhase={
|
|
1747
|
+
phase === "cex" ? 0 : phase === "bridge" ? 1 : 2
|
|
1748
|
+
}
|
|
1749
|
+
phases={["Forward funds", "Bridge"]}
|
|
1750
|
+
/>
|
|
1751
|
+
)}
|
|
1752
|
+
|
|
1753
|
+
{/* Status Icon */}
|
|
1754
|
+
<Box
|
|
1755
|
+
display="flex"
|
|
1756
|
+
flexDirection="column"
|
|
1757
|
+
paddingBottom="16px"
|
|
1758
|
+
alignItems="center"
|
|
1759
|
+
width="100%"
|
|
1760
|
+
>
|
|
1761
|
+
{renderStatusIcon()}
|
|
1487
1762
|
<Box
|
|
1488
1763
|
display="flex"
|
|
1489
1764
|
flexDirection="column"
|
|
@@ -1497,52 +1772,24 @@ const TrackUserOpStep = ({
|
|
|
1497
1772
|
color="fg"
|
|
1498
1773
|
marginBottom="8px"
|
|
1499
1774
|
>
|
|
1500
|
-
{
|
|
1501
|
-
</Text>
|
|
1502
|
-
<Text fontSize="sm" color="fg.muted" maxWidth="280px">
|
|
1503
|
-
Your operation is being processed – no action is
|
|
1504
|
-
required from you.
|
|
1775
|
+
{getCurrentMessage()}
|
|
1505
1776
|
</Text>
|
|
1777
|
+
{(phase === "cex" || phase === "bridge") &&
|
|
1778
|
+
isTimerFinished && (
|
|
1779
|
+
<Text
|
|
1780
|
+
fontSize="sm"
|
|
1781
|
+
color="fg.muted"
|
|
1782
|
+
maxWidth="280px"
|
|
1783
|
+
>
|
|
1784
|
+
Your operation is being processed – no action is
|
|
1785
|
+
required from you.
|
|
1786
|
+
</Text>
|
|
1787
|
+
)}
|
|
1506
1788
|
</Box>
|
|
1507
|
-
);
|
|
1508
|
-
}
|
|
1509
|
-
return null;
|
|
1510
|
-
};
|
|
1511
|
-
|
|
1512
|
-
const getStatusText = () => {
|
|
1513
|
-
switch (status) {
|
|
1514
|
-
case "completed":
|
|
1515
|
-
return "Success";
|
|
1516
|
-
case "failed":
|
|
1517
|
-
return "Failed";
|
|
1518
|
-
case "tracking":
|
|
1519
|
-
return "Processing";
|
|
1520
|
-
case "sending":
|
|
1521
|
-
return "Sending";
|
|
1522
|
-
default:
|
|
1523
|
-
return "Unknown";
|
|
1524
|
-
}
|
|
1525
|
-
};
|
|
1526
|
-
|
|
1527
|
-
return (
|
|
1528
|
-
<BodyWrapper>
|
|
1529
|
-
<Box
|
|
1530
|
-
display={"flex"}
|
|
1531
|
-
flexDirection={"column"}
|
|
1532
|
-
paddingBottom={"16px"}
|
|
1533
|
-
alignItems={"center"}
|
|
1534
|
-
width={"100%"}
|
|
1535
|
-
>
|
|
1536
|
-
{renderStatusIcon()}
|
|
1537
|
-
{renderProcessingText()}
|
|
1538
1789
|
</Box>
|
|
1539
1790
|
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
size="sm"
|
|
1543
|
-
variant={"outline"}
|
|
1544
|
-
width={"100%"}
|
|
1545
|
-
>
|
|
1791
|
+
{/* Status Table */}
|
|
1792
|
+
<Table.Root key="status" size="sm" variant="outline" width="100%">
|
|
1546
1793
|
<Table.Body>
|
|
1547
1794
|
<Table.Row>
|
|
1548
1795
|
<Table.Cell>Status</Table.Cell>
|
|
@@ -1556,6 +1803,52 @@ const TrackUserOpStep = ({
|
|
|
1556
1803
|
</Text>
|
|
1557
1804
|
</Table.Cell>
|
|
1558
1805
|
</Table.Row>
|
|
1806
|
+
{isCrosschain && (
|
|
1807
|
+
<>
|
|
1808
|
+
<Table.Row>
|
|
1809
|
+
<Table.Cell>Current Phase</Table.Cell>
|
|
1810
|
+
<Table.Cell
|
|
1811
|
+
display="flex"
|
|
1812
|
+
textAlign="end"
|
|
1813
|
+
justifyContent="end"
|
|
1814
|
+
>
|
|
1815
|
+
<Text>
|
|
1816
|
+
{phase === "cex"
|
|
1817
|
+
? "Awaiting funds"
|
|
1818
|
+
: phase === "bridge"
|
|
1819
|
+
? "Bridging"
|
|
1820
|
+
: phase === "completed"
|
|
1821
|
+
? "Complete"
|
|
1822
|
+
: "Failed"}
|
|
1823
|
+
</Text>
|
|
1824
|
+
</Table.Cell>
|
|
1825
|
+
</Table.Row>
|
|
1826
|
+
<Table.Row>
|
|
1827
|
+
<Table.Cell>Intermediate Chain</Table.Cell>
|
|
1828
|
+
<Table.Cell
|
|
1829
|
+
display="flex"
|
|
1830
|
+
textAlign="end"
|
|
1831
|
+
justifyContent="end"
|
|
1832
|
+
>
|
|
1833
|
+
<Text textTransform="capitalize">
|
|
1834
|
+
{intermediateChainName}
|
|
1835
|
+
</Text>
|
|
1836
|
+
</Table.Cell>
|
|
1837
|
+
</Table.Row>
|
|
1838
|
+
<Table.Row>
|
|
1839
|
+
<Table.Cell>Final Destination</Table.Cell>
|
|
1840
|
+
<Table.Cell
|
|
1841
|
+
display="flex"
|
|
1842
|
+
textAlign="end"
|
|
1843
|
+
justifyContent="end"
|
|
1844
|
+
>
|
|
1845
|
+
<Text textTransform="capitalize">
|
|
1846
|
+
{targetChainName}
|
|
1847
|
+
</Text>
|
|
1848
|
+
</Table.Cell>
|
|
1849
|
+
</Table.Row>
|
|
1850
|
+
</>
|
|
1851
|
+
)}
|
|
1559
1852
|
{operationId && (
|
|
1560
1853
|
<Table.Row>
|
|
1561
1854
|
<Table.Cell>Operation ID</Table.Cell>
|
|
@@ -1570,6 +1863,84 @@ const TrackUserOpStep = ({
|
|
|
1570
1863
|
</Table.Cell>
|
|
1571
1864
|
</Table.Row>
|
|
1572
1865
|
)}
|
|
1866
|
+
{isCrosschain && txHash && (
|
|
1867
|
+
<Table.Row>
|
|
1868
|
+
<Table.Cell>Bridge TX</Table.Cell>
|
|
1869
|
+
<Table.Cell
|
|
1870
|
+
display="flex"
|
|
1871
|
+
textAlign="end"
|
|
1872
|
+
justifyContent="end"
|
|
1873
|
+
>
|
|
1874
|
+
<Text
|
|
1875
|
+
fontSize="sm"
|
|
1876
|
+
color="blue.500"
|
|
1877
|
+
cursor="pointer"
|
|
1878
|
+
onClick={() =>
|
|
1879
|
+
window.open(
|
|
1880
|
+
`https://layerzeroscan.com/tx/${txHash}`,
|
|
1881
|
+
"_blank",
|
|
1882
|
+
)
|
|
1883
|
+
}
|
|
1884
|
+
>
|
|
1885
|
+
View on LayerZero
|
|
1886
|
+
</Text>
|
|
1887
|
+
</Table.Cell>
|
|
1888
|
+
</Table.Row>
|
|
1889
|
+
)}
|
|
1890
|
+
{isCrosschain && destinationTxHash && (
|
|
1891
|
+
<Table.Row>
|
|
1892
|
+
<Table.Cell>Destination TX</Table.Cell>
|
|
1893
|
+
<Table.Cell
|
|
1894
|
+
display="flex"
|
|
1895
|
+
textAlign="end"
|
|
1896
|
+
justifyContent="end"
|
|
1897
|
+
>
|
|
1898
|
+
<Text
|
|
1899
|
+
fontSize="sm"
|
|
1900
|
+
color="blue.500"
|
|
1901
|
+
cursor="pointer"
|
|
1902
|
+
onClick={() => {
|
|
1903
|
+
const explorer =
|
|
1904
|
+
CHAINS_ETHERSCAN[
|
|
1905
|
+
chainIdOut as keyof typeof CHAINS_ETHERSCAN
|
|
1906
|
+
] || "https://etherscan.io";
|
|
1907
|
+
window.open(
|
|
1908
|
+
`${explorer}/tx/${destinationTxHash}`,
|
|
1909
|
+
"_blank",
|
|
1910
|
+
);
|
|
1911
|
+
}}
|
|
1912
|
+
>
|
|
1913
|
+
View on Explorer
|
|
1914
|
+
</Text>
|
|
1915
|
+
</Table.Cell>
|
|
1916
|
+
</Table.Row>
|
|
1917
|
+
)}
|
|
1918
|
+
{isCrosschain && phase === "bridge" && (
|
|
1919
|
+
<Table.Row>
|
|
1920
|
+
<Table.Cell>Bridge Progress</Table.Cell>
|
|
1921
|
+
<Table.Cell
|
|
1922
|
+
display="flex"
|
|
1923
|
+
textAlign="end"
|
|
1924
|
+
justifyContent="end"
|
|
1925
|
+
>
|
|
1926
|
+
<Text>({lzStatus.step}/4)</Text>
|
|
1927
|
+
</Table.Cell>
|
|
1928
|
+
</Table.Row>
|
|
1929
|
+
)}
|
|
1930
|
+
{isCrosschain && refundDetails && (
|
|
1931
|
+
<Table.Row>
|
|
1932
|
+
<Table.Cell>Refund</Table.Cell>
|
|
1933
|
+
<Table.Cell
|
|
1934
|
+
display="flex"
|
|
1935
|
+
textAlign="end"
|
|
1936
|
+
justifyContent="end"
|
|
1937
|
+
>
|
|
1938
|
+
<Text fontSize="sm" color="orange.500">
|
|
1939
|
+
Funds refunded to smart account
|
|
1940
|
+
</Text>
|
|
1941
|
+
</Table.Cell>
|
|
1942
|
+
</Table.Row>
|
|
1943
|
+
)}
|
|
1573
1944
|
</Table.Body>
|
|
1574
1945
|
</Table.Root>
|
|
1575
1946
|
|
|
@@ -1577,12 +1948,12 @@ const TrackUserOpStep = ({
|
|
|
1577
1948
|
|
|
1578
1949
|
<TransactionDetailRow />
|
|
1579
1950
|
|
|
1580
|
-
{(
|
|
1951
|
+
{(phase === "completed" || phase === "failed") && (
|
|
1581
1952
|
<Button
|
|
1582
1953
|
onClick={() => setStep(WithdrawalStep.CheckSessionKey)}
|
|
1583
1954
|
visual="solid"
|
|
1584
1955
|
>
|
|
1585
|
-
{
|
|
1956
|
+
{phase === "completed" ? "New Deposit" : "Retry Deposit"}
|
|
1586
1957
|
</Button>
|
|
1587
1958
|
)}
|
|
1588
1959
|
</BodyWrapper>
|