@ensofinance/checkout-widget 0.0.16 → 0.0.18
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 +22025 -33937
- 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/orval.config.ts +14 -9
- package/package.json +2 -2
- package/src/components/Checkout.tsx +3 -2
- package/src/components/steps/ExchangeFlow.tsx +526 -157
- package/src/enso-api/api.ts +19 -42
- package/src/enso-api/index.ts +1114 -1070
- package/src/enso-api/model/action.ts +1 -1
- package/src/enso-api/model/actionAction.ts +3 -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 +3 -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 +33 -0
- 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 +2 -2
- package/src/enso-api/model/bundleShortcutTransaction.ts +13 -4
- 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 +15 -0
- 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 +63 -54
- 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 +6 -2
- package/src/enso-api/model/nonTokenizedModel.ts +1 -1
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionParams.ts +2 -2
- package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionRoutingStrategy.ts +1 -1
- package/src/enso-api/model/nontokenizedRouteShortcutTransaction.ts +4 -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 +7 -4
- package/src/enso-api/model/routeShortcutVariableInputs.ts +2 -2
- package/src/enso-api/model/routeShortcutVariableInputsRoutingStrategy.ts +2 -2
- 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 +2 -2
- 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 +3 -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 +7 -7
- 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 +21 -9
- package/src/enso-api/model/walletControllerCreateApproveTransactionParams.ts +1 -1
- package/src/enso-api/model/walletControllerCreateApproveTransactionRoutingStrategy.ts +2 -2
- package/src/enso-api/model/walletControllerWalletBalancesParams.ts +4 -4
- package/src/index.ts +3 -0
- package/src/types/index.ts +2 -0
- package/src/util/constants.tsx +19 -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
|
|
|
@@ -191,12 +198,10 @@ const useHandleMeshAccessPayload = () => {
|
|
|
191
198
|
(accessTokenPayload: AccessTokenPayload, sessionId: string) => {
|
|
192
199
|
setMeshAccessToken(accessTokenPayload); // Persist access token and session id for future reloads
|
|
193
200
|
|
|
194
|
-
debugger;
|
|
195
201
|
sessionStorage.setItem(
|
|
196
202
|
`${deviceKey}:${selectedIntegration?.type}`,
|
|
197
203
|
JSON.stringify({
|
|
198
|
-
|
|
199
|
-
accessTokenPayload.accountTokens[0].accessToken,
|
|
204
|
+
accessTokenPayload, // Store full object for proper restoration
|
|
200
205
|
sessionId,
|
|
201
206
|
timestamp: Date.now(),
|
|
202
207
|
}),
|
|
@@ -223,14 +228,26 @@ const ChooseExchangeStep = ({
|
|
|
223
228
|
}: {
|
|
224
229
|
setStep: (step: WithdrawalStep) => void;
|
|
225
230
|
}) => {
|
|
226
|
-
const { chainIdOut } = useAppStore();
|
|
231
|
+
const { chainIdOut, setChainIdIn } = useAppStore();
|
|
227
232
|
const [integrations, setIntegrations] = useState<MeshIntegration[]>([]);
|
|
228
233
|
const [loading, setLoading] = useState(true);
|
|
229
234
|
const [error, setError] = useState<string | null>(null);
|
|
230
235
|
const setSelectedIntegration = useAppStore(
|
|
231
236
|
(state) => state.setSelectedIntegration,
|
|
232
237
|
);
|
|
233
|
-
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]);
|
|
234
251
|
|
|
235
252
|
useEffect(() => {
|
|
236
253
|
const fetchIntegrations = async () => {
|
|
@@ -241,11 +258,12 @@ const ChooseExchangeStep = ({
|
|
|
241
258
|
.map((e) => ExchangeToIntegrationType[e])
|
|
242
259
|
.filter(Boolean);
|
|
243
260
|
|
|
244
|
-
// Filter integrations by
|
|
261
|
+
// Filter integrations by effective chain support (intermediate chain if bridging)
|
|
245
262
|
const filtered = data?.filter(
|
|
246
263
|
(i) =>
|
|
247
|
-
i.networks.some(
|
|
248
|
-
|
|
264
|
+
i.networks.some(
|
|
265
|
+
(n) => +n.chainId === effectiveChainId,
|
|
266
|
+
) && availableExchanges.includes(i.type),
|
|
249
267
|
);
|
|
250
268
|
|
|
251
269
|
setIntegrations(filtered);
|
|
@@ -257,7 +275,7 @@ const ChooseExchangeStep = ({
|
|
|
257
275
|
}
|
|
258
276
|
};
|
|
259
277
|
fetchIntegrations();
|
|
260
|
-
}, [
|
|
278
|
+
}, [effectiveChainId]);
|
|
261
279
|
|
|
262
280
|
if (loading)
|
|
263
281
|
return (
|
|
@@ -323,19 +341,20 @@ const CheckSessionKeyStep = ({
|
|
|
323
341
|
}: {
|
|
324
342
|
setStep: (step: WithdrawalStep) => void;
|
|
325
343
|
}) => {
|
|
326
|
-
const { chainIdOut, setMeshAccessToken, setSessionId
|
|
344
|
+
const { chainIdIn, chainIdOut, setMeshAccessToken, setSessionId } =
|
|
327
345
|
useAppStore();
|
|
328
346
|
const { address } = useAccount();
|
|
329
347
|
const deviceKey = useDeviceId();
|
|
330
348
|
const [showConfirmation, setShowConfirmation] = useState(false);
|
|
331
349
|
const selectedIntegration = useAppStore((s) => s.selectedIntegration);
|
|
332
350
|
|
|
333
|
-
|
|
334
|
-
const
|
|
351
|
+
// Bridging is required if chainIdIn differs from chainIdOut
|
|
352
|
+
const needsBridging = chainIdIn !== chainIdOut;
|
|
335
353
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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();
|
|
339
358
|
|
|
340
359
|
useEffect(() => {
|
|
341
360
|
if (!selectedIntegration) {
|
|
@@ -349,12 +368,11 @@ const CheckSessionKeyStep = ({
|
|
|
349
368
|
`${deviceKey}:${selectedIntegration.type}`,
|
|
350
369
|
);
|
|
351
370
|
// On load: check for persisted connection and hydrate state
|
|
352
|
-
debugger;
|
|
353
371
|
if (saved) {
|
|
354
372
|
try {
|
|
355
373
|
const parsed = JSON.parse(saved);
|
|
356
|
-
if (parsed?.
|
|
357
|
-
setMeshAccessToken(parsed.
|
|
374
|
+
if (parsed?.accessTokenPayload && parsed?.sessionId) {
|
|
375
|
+
setMeshAccessToken(parsed.accessTokenPayload);
|
|
358
376
|
setSessionId(parsed.sessionId);
|
|
359
377
|
setStep(WithdrawalStep.ChooseExchangeAsset);
|
|
360
378
|
return;
|
|
@@ -490,7 +508,6 @@ const ChooseAssetStep = ({
|
|
|
490
508
|
const [error, setError] = useState<string | null>(null);
|
|
491
509
|
const { address } = useAccount();
|
|
492
510
|
const {
|
|
493
|
-
chainIdOut,
|
|
494
511
|
meshAccessToken,
|
|
495
512
|
sessionId,
|
|
496
513
|
setMeshAccessToken,
|
|
@@ -515,7 +532,9 @@ const ChooseAssetStep = ({
|
|
|
515
532
|
"x-session-id": sessionId,
|
|
516
533
|
},
|
|
517
534
|
body: JSON.stringify({
|
|
518
|
-
authToken:
|
|
535
|
+
authToken:
|
|
536
|
+
meshAccessToken?.accountTokens?.[0]
|
|
537
|
+
?.accessToken,
|
|
519
538
|
brokerType: selectedIntegration?.type,
|
|
520
539
|
}),
|
|
521
540
|
},
|
|
@@ -543,7 +562,7 @@ const ChooseAssetStep = ({
|
|
|
543
562
|
);
|
|
544
563
|
}
|
|
545
564
|
|
|
546
|
-
// Fetch supported tokens for
|
|
565
|
+
// Fetch supported tokens for chainIdIn (intermediate chain if bridging)
|
|
547
566
|
const tokensResponse = await fetch(
|
|
548
567
|
`${MESH_API_URL}/tokens?chainId=${chainIdIn}&brokerType=${encodeURIComponent(selectedIntegration?.type || "")}`,
|
|
549
568
|
);
|
|
@@ -598,10 +617,10 @@ const ChooseAssetStep = ({
|
|
|
598
617
|
}
|
|
599
618
|
};
|
|
600
619
|
|
|
601
|
-
if (meshAccessToken && sessionId &&
|
|
620
|
+
if (meshAccessToken && sessionId && chainIdIn && selectedIntegration) {
|
|
602
621
|
fetchData();
|
|
603
622
|
}
|
|
604
|
-
}, [address,
|
|
623
|
+
}, [address, chainIdIn, meshAccessToken, sessionId, selectedIntegration]);
|
|
605
624
|
|
|
606
625
|
const geckoTokens = useTokenFromListBySymbols(
|
|
607
626
|
matchedTokens.map((token) => token.symbol),
|
|
@@ -634,7 +653,7 @@ const ChooseAssetStep = ({
|
|
|
634
653
|
{matchedTokens.map((token, index) => (
|
|
635
654
|
<AssetCard
|
|
636
655
|
key={`${token.symbol}-${index}`}
|
|
637
|
-
chainId={
|
|
656
|
+
chainId={chainIdIn}
|
|
638
657
|
icon={geckoTokens?.[index]?.logoURI?.replace(
|
|
639
658
|
"/thumb/",
|
|
640
659
|
"/large/",
|
|
@@ -782,48 +801,61 @@ const ChooseAmountStep = ({
|
|
|
782
801
|
const [amount, setAmount] = useState<string>("");
|
|
783
802
|
const [inputMode, setInputMode] = useState<"usd" | "token">("usd");
|
|
784
803
|
const [usdValue, setUsdValue] = useState<string>("");
|
|
785
|
-
const
|
|
786
|
-
const { tokenInData } = useAppDetails();
|
|
804
|
+
const setAmountIn = useAppStore((s) => s.setAmountIn);
|
|
805
|
+
const { tokenInData, selectedIntegration } = useAppDetails();
|
|
787
806
|
const isStable = selectedToken?.symbol.toLowerCase().includes("USD");
|
|
788
807
|
const roundingPrecision = isStable ? 2 : 6;
|
|
789
808
|
|
|
809
|
+
// Only apply CEX withdrawal limits if using a CEX holding (not smart account)
|
|
810
|
+
const isWithdrawal = !isDelayedBalanceUsed(selectedIntegration.type);
|
|
811
|
+
|
|
790
812
|
const maxUsdAmount = selectedToken
|
|
791
|
-
?
|
|
813
|
+
? isWithdrawal
|
|
814
|
+
? (selectedToken.marketValue - EXCHANGE_MAX_LIMIT_GAP_USD).toFixed(
|
|
815
|
+
2,
|
|
816
|
+
)
|
|
817
|
+
: selectedToken.marketValue.toFixed(2)
|
|
792
818
|
: 0;
|
|
793
819
|
|
|
794
|
-
// Handle percentage selection with limits
|
|
820
|
+
// Handle percentage selection with limits (only for CEX withdrawals)
|
|
795
821
|
const handlePercentageSelect = useCallback(
|
|
796
822
|
(percent: number) => {
|
|
797
823
|
if (!selectedToken) return;
|
|
798
824
|
|
|
799
|
-
const minValueForToken =
|
|
800
|
-
EXCHANGE_MIN_LIMIT[
|
|
801
|
-
selectedToken.symbol as keyof typeof EXCHANGE_MIN_LIMIT
|
|
802
|
-
] || 0;
|
|
803
|
-
|
|
804
825
|
// Calculate target USD amount based on percentage
|
|
805
826
|
const targetUsdAmount = (selectedToken.marketValue * percent) / 100;
|
|
806
827
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
minValueForToken,
|
|
810
|
-
Math.min(targetUsdAmount, +maxUsdAmount),
|
|
811
|
-
);
|
|
828
|
+
let finalUsdAmount: number;
|
|
829
|
+
let finalTokenAmount: number;
|
|
812
830
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
);
|
|
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;
|
|
820
837
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
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));
|
|
825
857
|
},
|
|
826
|
-
[selectedToken],
|
|
858
|
+
[selectedToken, isWithdrawal, maxUsdAmount, roundingPrecision],
|
|
827
859
|
);
|
|
828
860
|
|
|
829
861
|
// Set max value on load
|
|
@@ -893,21 +925,26 @@ const ChooseAmountStep = ({
|
|
|
893
925
|
? parseFloat(amount) > selectedToken.balance
|
|
894
926
|
: true;
|
|
895
927
|
|
|
896
|
-
// Limits validation logic
|
|
928
|
+
// Limits validation logic - only for CEX withdrawals
|
|
897
929
|
const currentUsdValue = parseFloat(usdValue);
|
|
898
|
-
const minValueForToken =
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
930
|
+
const minValueForToken =
|
|
931
|
+
isWithdrawal && selectedToken
|
|
932
|
+
? EXCHANGE_MIN_LIMIT[
|
|
933
|
+
selectedToken.symbol as keyof typeof EXCHANGE_MIN_LIMIT
|
|
934
|
+
]
|
|
935
|
+
: 0;
|
|
903
936
|
|
|
904
937
|
const isBelowMinAmount =
|
|
938
|
+
isWithdrawal &&
|
|
905
939
|
selectedToken &&
|
|
906
940
|
currentUsdValue > 0 &&
|
|
907
941
|
minValueForToken &&
|
|
908
942
|
+amount < minValueForToken;
|
|
909
943
|
const isAboveMaxAmount =
|
|
910
|
-
|
|
944
|
+
isWithdrawal &&
|
|
945
|
+
selectedToken &&
|
|
946
|
+
currentUsdValue > 0 &&
|
|
947
|
+
currentUsdValue > +maxUsdAmount;
|
|
911
948
|
|
|
912
949
|
const isAmountInvalid =
|
|
913
950
|
isBelowMinAmount || isAboveMaxAmount || notEnoughBalance;
|
|
@@ -1159,7 +1196,7 @@ const InitiateWithdrawalStep = ({
|
|
|
1159
1196
|
userOp: any;
|
|
1160
1197
|
setStep: (step: WithdrawalStep) => void;
|
|
1161
1198
|
}) => {
|
|
1162
|
-
const { meshAccessToken, amountIn,
|
|
1199
|
+
const { meshAccessToken, amountIn, chainIdIn } = useAppStore();
|
|
1163
1200
|
const { address } = useAccount();
|
|
1164
1201
|
const { tokenInData } = useAppDetails();
|
|
1165
1202
|
const sessionId = useAppStore((state) => state.sessionId);
|
|
@@ -1186,7 +1223,7 @@ const InitiateWithdrawalStep = ({
|
|
|
1186
1223
|
try {
|
|
1187
1224
|
const toAddresses = [
|
|
1188
1225
|
{
|
|
1189
|
-
networkId: getNetworkId(
|
|
1226
|
+
networkId: getNetworkId(chainIdIn),
|
|
1190
1227
|
symbol: selectedToken.symbol,
|
|
1191
1228
|
address: userOp.sender,
|
|
1192
1229
|
amount: transferAmount,
|
|
@@ -1292,6 +1329,53 @@ const InitiateWithdrawalStep = ({
|
|
|
1292
1329
|
);
|
|
1293
1330
|
};
|
|
1294
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
|
+
|
|
1295
1379
|
const TrackUserOpStep = ({
|
|
1296
1380
|
selectedToken,
|
|
1297
1381
|
userOp,
|
|
@@ -1301,23 +1385,53 @@ const TrackUserOpStep = ({
|
|
|
1301
1385
|
userOp: any;
|
|
1302
1386
|
setStep: (step: WithdrawalStep) => void;
|
|
1303
1387
|
}) => {
|
|
1304
|
-
const { chainIdIn, tokenInData } = useAppDetails();
|
|
1388
|
+
const { chainIdIn, chainIdOut, tokenInData } = useAppDetails();
|
|
1305
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");
|
|
1306
1398
|
const [operationId, setOperationId] = useState<string | null>(null);
|
|
1307
1399
|
const [status, setStatus] = useState<
|
|
1308
1400
|
"sending" | "tracking" | "completed" | "failed"
|
|
1309
1401
|
>("sending");
|
|
1310
1402
|
const [message, setMessage] = useState("Sending operation to tracker...");
|
|
1403
|
+
const [txHash, setTxHash] = useState<`0x${string}` | null>(null);
|
|
1311
1404
|
const [isTimerFinished, setIsTimerFinished] = useState(false);
|
|
1312
1405
|
const [trackingInterval, setTrackingInterval] =
|
|
1313
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
|
+
);
|
|
1314
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
|
|
1315
1428
|
useEffect(() => {
|
|
1316
1429
|
const sendUserOpToTracker = async () => {
|
|
1317
1430
|
if (!selectedToken || !userOp || !tokenInData) {
|
|
1318
1431
|
console.error("Missing required data for tracking");
|
|
1319
1432
|
setStatus("failed");
|
|
1320
1433
|
setMessage("Missing required data");
|
|
1434
|
+
setPhase("failed");
|
|
1321
1435
|
return;
|
|
1322
1436
|
}
|
|
1323
1437
|
|
|
@@ -1364,7 +1478,11 @@ const TrackUserOpStep = ({
|
|
|
1364
1478
|
if (data.success && data.operationId) {
|
|
1365
1479
|
setOperationId(data.operationId);
|
|
1366
1480
|
setStatus("tracking");
|
|
1367
|
-
setMessage(
|
|
1481
|
+
setMessage(
|
|
1482
|
+
isCrosschain
|
|
1483
|
+
? "Funds forwarding in progress..."
|
|
1484
|
+
: "Tracking operation progress...",
|
|
1485
|
+
);
|
|
1368
1486
|
} else {
|
|
1369
1487
|
throw new Error(
|
|
1370
1488
|
data.message || "Failed to send operation to tracker",
|
|
@@ -1374,6 +1492,7 @@ const TrackUserOpStep = ({
|
|
|
1374
1492
|
console.error("Failed to send operation to tracker:", error);
|
|
1375
1493
|
setStatus("failed");
|
|
1376
1494
|
setMessage("Failed to send operation to tracker");
|
|
1495
|
+
setPhase("failed");
|
|
1377
1496
|
}
|
|
1378
1497
|
};
|
|
1379
1498
|
|
|
@@ -1394,14 +1513,43 @@ const TrackUserOpStep = ({
|
|
|
1394
1513
|
|
|
1395
1514
|
if (data.operation?.status === "completed") {
|
|
1396
1515
|
setStatus("completed");
|
|
1397
|
-
|
|
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
|
+
|
|
1398
1537
|
if (trackingInterval) {
|
|
1399
1538
|
clearInterval(trackingInterval);
|
|
1400
1539
|
setTrackingInterval(null);
|
|
1401
1540
|
}
|
|
1402
|
-
} else if (
|
|
1541
|
+
} else if (
|
|
1542
|
+
["failed", "failed_permanent"].includes(
|
|
1543
|
+
data.operation?.status,
|
|
1544
|
+
)
|
|
1545
|
+
) {
|
|
1403
1546
|
setStatus("failed");
|
|
1404
|
-
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");
|
|
1405
1553
|
if (trackingInterval) {
|
|
1406
1554
|
clearInterval(trackingInterval);
|
|
1407
1555
|
setTrackingInterval(null);
|
|
@@ -1412,20 +1560,94 @@ const TrackUserOpStep = ({
|
|
|
1412
1560
|
}
|
|
1413
1561
|
};
|
|
1414
1562
|
|
|
1415
|
-
const interval = setInterval(trackOperation, 3000);
|
|
1563
|
+
const interval = setInterval(trackOperation, 3000);
|
|
1416
1564
|
setTrackingInterval(interval);
|
|
1417
1565
|
|
|
1418
1566
|
return () => {
|
|
1419
1567
|
if (interval) clearInterval(interval);
|
|
1420
1568
|
};
|
|
1421
|
-
}, [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
|
+
]);
|
|
1422
1638
|
|
|
1423
1639
|
const handleTimerFinish = () => {
|
|
1424
1640
|
setIsTimerFinished(true);
|
|
1425
1641
|
};
|
|
1426
1642
|
|
|
1643
|
+
const getOverallStatus = () => {
|
|
1644
|
+
if (phase === "failed") return "failed";
|
|
1645
|
+
if (phase === "completed") return "completed";
|
|
1646
|
+
return "processing";
|
|
1647
|
+
};
|
|
1648
|
+
|
|
1427
1649
|
const getStatusColor = () => {
|
|
1428
|
-
switch (
|
|
1650
|
+
switch (getOverallStatus()) {
|
|
1429
1651
|
case "completed":
|
|
1430
1652
|
return "#14AE5C";
|
|
1431
1653
|
case "failed":
|
|
@@ -1435,57 +1657,108 @@ const TrackUserOpStep = ({
|
|
|
1435
1657
|
}
|
|
1436
1658
|
};
|
|
1437
1659
|
|
|
1438
|
-
const
|
|
1439
|
-
switch (
|
|
1440
|
-
case "sending":
|
|
1441
|
-
case "tracking":
|
|
1442
|
-
return (
|
|
1443
|
-
<CircleTimer
|
|
1444
|
-
start={status === "tracking"}
|
|
1445
|
-
onFinish={handleTimerFinish}
|
|
1446
|
-
duration={120}
|
|
1447
|
-
/>
|
|
1448
|
-
);
|
|
1449
|
-
|
|
1660
|
+
const getStatusText = () => {
|
|
1661
|
+
switch (getOverallStatus()) {
|
|
1450
1662
|
case "completed":
|
|
1451
|
-
return
|
|
1452
|
-
<Box
|
|
1453
|
-
display="flex"
|
|
1454
|
-
flexDirection="column"
|
|
1455
|
-
alignItems="center"
|
|
1456
|
-
>
|
|
1457
|
-
<Image
|
|
1458
|
-
src={SuccessIcon}
|
|
1459
|
-
boxShadow="0px 0px 20px #14AE5C"
|
|
1460
|
-
borderRadius="90%"
|
|
1461
|
-
width="58px"
|
|
1462
|
-
height="58px"
|
|
1463
|
-
/>
|
|
1464
|
-
</Box>
|
|
1465
|
-
);
|
|
1466
|
-
|
|
1663
|
+
return "Success";
|
|
1467
1664
|
case "failed":
|
|
1468
|
-
return
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
flexDirection="column"
|
|
1472
|
-
alignItems="center"
|
|
1473
|
-
>
|
|
1474
|
-
<Image
|
|
1475
|
-
src={FailIcon}
|
|
1476
|
-
boxShadow="0px 0px 20px #E84142"
|
|
1477
|
-
borderRadius="90%"
|
|
1478
|
-
width="58px"
|
|
1479
|
-
height="58px"
|
|
1480
|
-
/>
|
|
1481
|
-
</Box>
|
|
1482
|
-
);
|
|
1665
|
+
return "Failed";
|
|
1666
|
+
default:
|
|
1667
|
+
return "Processing";
|
|
1483
1668
|
}
|
|
1484
1669
|
};
|
|
1485
1670
|
|
|
1486
|
-
const
|
|
1487
|
-
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") {
|
|
1488
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()}
|
|
1489
1762
|
<Box
|
|
1490
1763
|
display="flex"
|
|
1491
1764
|
flexDirection="column"
|
|
@@ -1499,52 +1772,24 @@ const TrackUserOpStep = ({
|
|
|
1499
1772
|
color="fg"
|
|
1500
1773
|
marginBottom="8px"
|
|
1501
1774
|
>
|
|
1502
|
-
{
|
|
1503
|
-
</Text>
|
|
1504
|
-
<Text fontSize="sm" color="fg.muted" maxWidth="280px">
|
|
1505
|
-
Your operation is being processed – no action is
|
|
1506
|
-
required from you.
|
|
1775
|
+
{getCurrentMessage()}
|
|
1507
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
|
+
)}
|
|
1508
1788
|
</Box>
|
|
1509
|
-
);
|
|
1510
|
-
}
|
|
1511
|
-
return null;
|
|
1512
|
-
};
|
|
1513
|
-
|
|
1514
|
-
const getStatusText = () => {
|
|
1515
|
-
switch (status) {
|
|
1516
|
-
case "completed":
|
|
1517
|
-
return "Success";
|
|
1518
|
-
case "failed":
|
|
1519
|
-
return "Failed";
|
|
1520
|
-
case "tracking":
|
|
1521
|
-
return "Processing";
|
|
1522
|
-
case "sending":
|
|
1523
|
-
return "Sending";
|
|
1524
|
-
default:
|
|
1525
|
-
return "Unknown";
|
|
1526
|
-
}
|
|
1527
|
-
};
|
|
1528
|
-
|
|
1529
|
-
return (
|
|
1530
|
-
<BodyWrapper>
|
|
1531
|
-
<Box
|
|
1532
|
-
display={"flex"}
|
|
1533
|
-
flexDirection={"column"}
|
|
1534
|
-
paddingBottom={"16px"}
|
|
1535
|
-
alignItems={"center"}
|
|
1536
|
-
width={"100%"}
|
|
1537
|
-
>
|
|
1538
|
-
{renderStatusIcon()}
|
|
1539
|
-
{renderProcessingText()}
|
|
1540
1789
|
</Box>
|
|
1541
1790
|
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
size="sm"
|
|
1545
|
-
variant={"outline"}
|
|
1546
|
-
width={"100%"}
|
|
1547
|
-
>
|
|
1791
|
+
{/* Status Table */}
|
|
1792
|
+
<Table.Root key="status" size="sm" variant="outline" width="100%">
|
|
1548
1793
|
<Table.Body>
|
|
1549
1794
|
<Table.Row>
|
|
1550
1795
|
<Table.Cell>Status</Table.Cell>
|
|
@@ -1558,6 +1803,52 @@ const TrackUserOpStep = ({
|
|
|
1558
1803
|
</Text>
|
|
1559
1804
|
</Table.Cell>
|
|
1560
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
|
+
)}
|
|
1561
1852
|
{operationId && (
|
|
1562
1853
|
<Table.Row>
|
|
1563
1854
|
<Table.Cell>Operation ID</Table.Cell>
|
|
@@ -1572,6 +1863,84 @@ const TrackUserOpStep = ({
|
|
|
1572
1863
|
</Table.Cell>
|
|
1573
1864
|
</Table.Row>
|
|
1574
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
|
+
)}
|
|
1575
1944
|
</Table.Body>
|
|
1576
1945
|
</Table.Root>
|
|
1577
1946
|
|
|
@@ -1579,12 +1948,12 @@ const TrackUserOpStep = ({
|
|
|
1579
1948
|
|
|
1580
1949
|
<TransactionDetailRow />
|
|
1581
1950
|
|
|
1582
|
-
{(
|
|
1951
|
+
{(phase === "completed" || phase === "failed") && (
|
|
1583
1952
|
<Button
|
|
1584
1953
|
onClick={() => setStep(WithdrawalStep.CheckSessionKey)}
|
|
1585
1954
|
visual="solid"
|
|
1586
1955
|
>
|
|
1587
|
-
{
|
|
1956
|
+
{phase === "completed" ? "New Deposit" : "Retry Deposit"}
|
|
1588
1957
|
</Button>
|
|
1589
1958
|
)}
|
|
1590
1959
|
</BodyWrapper>
|