@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.
Files changed (195) hide show
  1. package/dist/checkout-widget.es.js +22025 -33937
  2. package/dist/checkout-widget.es.js.map +1 -1
  3. package/dist/checkout-widget.umd.js +61 -46
  4. package/dist/checkout-widget.umd.js.map +1 -1
  5. package/dist/index.d.ts +3 -1
  6. package/orval.config.ts +14 -9
  7. package/package.json +2 -2
  8. package/src/components/Checkout.tsx +3 -2
  9. package/src/components/steps/ExchangeFlow.tsx +526 -157
  10. package/src/enso-api/api.ts +19 -42
  11. package/src/enso-api/index.ts +1114 -1070
  12. package/src/enso-api/model/action.ts +1 -1
  13. package/src/enso-api/model/actionAction.ts +3 -1
  14. package/src/enso-api/model/actionInputs.ts +1 -1
  15. package/src/enso-api/model/actionToBundle.ts +1 -1
  16. package/src/enso-api/model/actionToBundleAction.ts +3 -1
  17. package/src/enso-api/model/actionToBundleArgs.ts +1 -1
  18. package/src/enso-api/model/approveActionDto.ts +1 -1
  19. package/src/enso-api/model/approveArgsDto.ts +1 -1
  20. package/src/enso-api/model/approveArgsDtoAmount.ts +1 -1
  21. package/src/enso-api/model/balanceActionDto.ts +1 -1
  22. package/src/enso-api/model/balanceArgsDto.ts +1 -1
  23. package/src/enso-api/model/borrowActionDto.ts +1 -1
  24. package/src/enso-api/model/borrowArgsDto.ts +1 -1
  25. package/src/enso-api/model/borrowArgsDtoAmountOut.ts +1 -1
  26. package/src/enso-api/model/bridgeActionDto.ts +1 -1
  27. package/src/enso-api/model/bridgeArgsDto.ts +1 -1
  28. package/src/enso-api/model/bridgeArgsDtoAmountIn.ts +1 -1
  29. package/src/enso-api/model/bridgeArgsDtoCallbackItem.ts +1 -1
  30. package/src/enso-api/model/bridgeLatencyEstimate.ts +33 -0
  31. package/src/enso-api/model/bridgeTransactionResponse.ts +37 -0
  32. package/src/enso-api/model/bridgeTransactionResponseStatus.ts +25 -0
  33. package/src/enso-api/model/bundleControllerBundleShortcutTransactionBodyItem.ts +1 -1
  34. package/src/enso-api/model/bundleControllerBundleShortcutTransactionParams.ts +1 -1
  35. package/src/enso-api/model/bundleControllerBundleShortcutTransactionRoutingStrategy.ts +2 -2
  36. package/src/enso-api/model/bundleShortcutTransaction.ts +13 -4
  37. package/src/enso-api/model/bundleShortcutTransactionAmountsOut.ts +1 -1
  38. package/src/enso-api/model/bundleShortcutTransactionFeeAmount.ts +1 -1
  39. package/src/enso-api/model/bundleShortcutTransactionMinAmountsOut.ts +15 -0
  40. package/src/enso-api/model/callActionDto.ts +1 -1
  41. package/src/enso-api/model/callArgsDto.ts +1 -1
  42. package/src/enso-api/model/callArgsDtoArgsItem.ts +1 -1
  43. package/src/enso-api/model/callArgsDtoArgsItemAnyOf.ts +1 -1
  44. package/src/enso-api/model/callArgsDtoValue.ts +1 -1
  45. package/src/enso-api/model/callOutput.ts +1 -1
  46. package/src/enso-api/model/connectedNetwork.ts +1 -1
  47. package/src/enso-api/model/depositActionDto.ts +1 -1
  48. package/src/enso-api/model/depositArgsDto.ts +1 -1
  49. package/src/enso-api/model/depositArgsDtoAmountIn.ts +1 -1
  50. package/src/enso-api/model/depositArgsDtoAmountInOneOfItem.ts +1 -1
  51. package/src/enso-api/model/depositArgsDtoTokenIn.ts +1 -1
  52. package/src/enso-api/model/depositArgsDtoTokenOut.ts +1 -1
  53. package/src/enso-api/model/depositCLMMActionDto.ts +1 -1
  54. package/src/enso-api/model/depositCLMMArgsDto.ts +1 -1
  55. package/src/enso-api/model/depositCLMMArgsDtoAmountInItem.ts +1 -1
  56. package/src/enso-api/model/depositCLMMArgsDtoAmountInItemAnyOf.ts +1 -1
  57. package/src/enso-api/model/ensoEvent.ts +30 -0
  58. package/src/enso-api/model/ensoFeeActionDto.ts +1 -1
  59. package/src/enso-api/model/ensoFeeArgsDto.ts +1 -1
  60. package/src/enso-api/model/ensoFeeArgsDtoAmount.ts +1 -1
  61. package/src/enso-api/model/ensoMetadata.ts +23 -0
  62. package/src/enso-api/model/feeActionDto.ts +1 -1
  63. package/src/enso-api/model/feeArgsDto.ts +1 -1
  64. package/src/enso-api/model/feeArgsDtoAmount.ts +1 -1
  65. package/src/enso-api/model/harvestActionDto.ts +1 -1
  66. package/src/enso-api/model/harvestArgsDto.ts +1 -1
  67. package/src/enso-api/model/hop.ts +1 -1
  68. package/src/enso-api/model/hopArgs.ts +1 -1
  69. package/src/enso-api/model/index.ts +63 -54
  70. package/src/enso-api/model/iporControllerIporShortcutTransactionParams.ts +1 -1
  71. package/src/enso-api/model/iporShortcutInput.ts +1 -1
  72. package/src/enso-api/model/iporShortcutTransaction.ts +1 -1
  73. package/src/enso-api/model/lZDestinationTokenData.ts +1 -1
  74. package/src/enso-api/model/lZPoolLookupResponse.ts +1 -1
  75. package/src/enso-api/model/layerZeroControllerCheckBridgeTransactionParams.ts +21 -0
  76. package/src/enso-api/model/layerZeroControllerGetPoolAddressParams.ts +1 -1
  77. package/src/enso-api/model/layerZeroMessageStatus.ts +39 -0
  78. package/src/enso-api/model/mergeActionDto.ts +1 -1
  79. package/src/enso-api/model/mergeArgsDto.ts +1 -1
  80. package/src/enso-api/model/mergeArgsDtoAmountInItem.ts +1 -1
  81. package/src/enso-api/model/minAmountOutActionDto.ts +1 -1
  82. package/src/enso-api/model/minAmountOutArgsDto.ts +1 -1
  83. package/src/enso-api/model/minAmountOutArgsDtoAmountOut.ts +1 -1
  84. package/src/enso-api/model/minAmountOutArgsDtoMinAmountOut.ts +1 -1
  85. package/src/enso-api/model/multiDepositActionDto.ts +1 -1
  86. package/src/enso-api/model/multiDepositArgsDto.ts +1 -1
  87. package/src/enso-api/model/multiDepositArgsDtoAmountInItem.ts +1 -1
  88. package/src/enso-api/model/multiDepositArgsDtoAmountInItemAnyOf.ts +1 -1
  89. package/src/enso-api/model/multiOutSingleDepositActionDto.ts +1 -1
  90. package/src/enso-api/model/multiOutSingleDepositArgsDto.ts +1 -1
  91. package/src/enso-api/model/multiOutSingleDepositArgsDtoAmountIn.ts +1 -1
  92. package/src/enso-api/model/multiRedeemActionDto.ts +1 -1
  93. package/src/enso-api/model/multiRedeemArgs2Dto.ts +1 -1
  94. package/src/enso-api/model/multiRedeemArgs2DtoAmountIn.ts +1 -1
  95. package/src/enso-api/model/network.ts +1 -1
  96. package/src/enso-api/model/networksControllerNetworksParams.ts +1 -1
  97. package/src/enso-api/model/nonTokenizedControllerTokens200.ts +1 -1
  98. package/src/enso-api/model/nonTokenizedControllerTokens200AllOf.ts +1 -1
  99. package/src/enso-api/model/nonTokenizedControllerTokensParams.ts +6 -2
  100. package/src/enso-api/model/nonTokenizedModel.ts +1 -1
  101. package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionParams.ts +2 -2
  102. package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionRoutingStrategy.ts +1 -1
  103. package/src/enso-api/model/nontokenizedRouteShortcutTransaction.ts +4 -1
  104. package/src/enso-api/model/paginatedResult.ts +1 -1
  105. package/src/enso-api/model/paginationMeta.ts +1 -1
  106. package/src/enso-api/model/paymasterFeeActionDto.ts +1 -1
  107. package/src/enso-api/model/paymasterFeeArgsDto.ts +1 -1
  108. package/src/enso-api/model/paymasterFeeArgsDtoAmount.ts +1 -1
  109. package/src/enso-api/model/permitTransferFromActionDto.ts +1 -1
  110. package/src/enso-api/model/permitTransferFromArgsDto.ts +1 -1
  111. package/src/enso-api/model/permitTransferFromArgsDtoAmount.ts +1 -1
  112. package/src/enso-api/model/permitTransferFromArgsDtoAmountOneOfItem.ts +1 -1
  113. package/src/enso-api/model/permitTransferFromArgsDtoToken.ts +1 -1
  114. package/src/enso-api/model/positionModel.ts +1 -1
  115. package/src/enso-api/model/price.ts +1 -1
  116. package/src/enso-api/model/pricesControllerGetPricesParams.ts +1 -1
  117. package/src/enso-api/model/project.ts +1 -1
  118. package/src/enso-api/model/protocol.ts +1 -1
  119. package/src/enso-api/model/protocolModel.ts +1 -1
  120. package/src/enso-api/model/protocolsControllerFindAllParams.ts +1 -1
  121. package/src/enso-api/model/redeemActionDto.ts +1 -1
  122. package/src/enso-api/model/redeemArgsDto.ts +1 -1
  123. package/src/enso-api/model/redeemArgsDtoAmountIn.ts +1 -1
  124. package/src/enso-api/model/redeemArgsDtoTokenOut.ts +1 -1
  125. package/src/enso-api/model/redeemCLMMActionDto.ts +1 -1
  126. package/src/enso-api/model/redeemCLMMArgsDto.ts +1 -1
  127. package/src/enso-api/model/redeemCLMMArgsDtoLiquidity.ts +1 -1
  128. package/src/enso-api/model/refundDetails.ts +21 -0
  129. package/src/enso-api/model/repayActionDto.ts +1 -1
  130. package/src/enso-api/model/repayArgsDto.ts +1 -1
  131. package/src/enso-api/model/repayArgsDtoAmountIn.ts +1 -1
  132. package/src/enso-api/model/routeActionDto.ts +1 -1
  133. package/src/enso-api/model/routeArgsDto.ts +1 -1
  134. package/src/enso-api/model/routeArgsDtoAmountIn.ts +1 -1
  135. package/src/enso-api/model/routeShortcutTransaction.ts +7 -4
  136. package/src/enso-api/model/routeShortcutVariableInputs.ts +2 -2
  137. package/src/enso-api/model/routeShortcutVariableInputsRoutingStrategy.ts +2 -2
  138. package/src/enso-api/model/routeShortcutVariableInputsVariableEstimates.ts +1 -1
  139. package/src/enso-api/model/routerControllerRouteShortcutTransactionParams.ts +1 -1
  140. package/src/enso-api/model/routerControllerRouteShortcutTransactionRoutingStrategy.ts +2 -2
  141. package/src/enso-api/model/singleDepositActionDto.ts +1 -1
  142. package/src/enso-api/model/singleDepositArgsDto.ts +1 -1
  143. package/src/enso-api/model/singleDepositArgsDtoAmountIn.ts +1 -1
  144. package/src/enso-api/model/singleRedeemActionDto.ts +1 -1
  145. package/src/enso-api/model/singleRedeemArgs2Dto.ts +1 -1
  146. package/src/enso-api/model/singleRedeemArgs2DtoAmountIn.ts +1 -1
  147. package/src/enso-api/model/slippageActionDto.ts +1 -1
  148. package/src/enso-api/model/slippageArgsDto.ts +1 -1
  149. package/src/enso-api/model/slippageArgsDtoAmountOut.ts +1 -1
  150. package/src/enso-api/model/splitActionDto.ts +1 -1
  151. package/src/enso-api/model/splitArgsDto.ts +1 -1
  152. package/src/enso-api/model/splitArgsDtoAmountIn.ts +1 -1
  153. package/src/enso-api/model/standard.ts +1 -1
  154. package/src/enso-api/model/standardAction.ts +1 -1
  155. package/src/enso-api/model/standardActionAction.ts +3 -1
  156. package/src/enso-api/model/swapActionDto.ts +1 -1
  157. package/src/enso-api/model/swapArgsDto.ts +1 -1
  158. package/src/enso-api/model/swapArgsDtoAmountIn.ts +1 -1
  159. package/src/enso-api/model/tokenModel.ts +1 -1
  160. package/src/enso-api/model/tokenizedMultiDepositActionDto.ts +1 -1
  161. package/src/enso-api/model/tokenizedMultiDepositArgsDto.ts +1 -1
  162. package/src/enso-api/model/tokenizedMultiDepositArgsDtoAmountInItem.ts +1 -1
  163. package/src/enso-api/model/tokenizedMultiDepositArgsDtoAmountInItemAnyOf.ts +1 -1
  164. package/src/enso-api/model/tokenizedMultiRedeemActionDto.ts +1 -1
  165. package/src/enso-api/model/tokenizedMultiRedeemArgsDto.ts +1 -1
  166. package/src/enso-api/model/tokenizedMultiRedeemArgsDtoAmountIn.ts +1 -1
  167. package/src/enso-api/model/tokenizedSingleDepositActionDto.ts +1 -1
  168. package/src/enso-api/model/tokenizedSingleDepositArgsDto.ts +1 -1
  169. package/src/enso-api/model/tokenizedSingleDepositArgsDtoAmountIn.ts +1 -1
  170. package/src/enso-api/model/tokenizedSingleRedeemActionDto.ts +1 -1
  171. package/src/enso-api/model/tokenizedSingleRedeemArgsDto.ts +1 -1
  172. package/src/enso-api/model/tokenizedSingleRedeemArgsDtoAmountIn.ts +1 -1
  173. package/src/enso-api/model/tokensControllerTokens200.ts +1 -1
  174. package/src/enso-api/model/tokensControllerTokens200AllOf.ts +1 -1
  175. package/src/enso-api/model/tokensControllerTokensLiquidityType.ts +1 -1
  176. package/src/enso-api/model/tokensControllerTokensParams.ts +1 -1
  177. package/src/enso-api/model/tokensControllerTokensType.ts +1 -1
  178. package/src/enso-api/model/transaction.ts +1 -1
  179. package/src/enso-api/model/transferActionDto.ts +1 -1
  180. package/src/enso-api/model/transferArgsDto.ts +1 -1
  181. package/src/enso-api/model/transferArgsDtoAmount.ts +1 -1
  182. package/src/enso-api/model/transferFromActionDto.ts +1 -1
  183. package/src/enso-api/model/transferFromArgsDto.ts +1 -1
  184. package/src/enso-api/model/transferFromArgsDtoAmount.ts +1 -1
  185. package/src/enso-api/model/userOperation.ts +7 -7
  186. package/src/enso-api/model/walletApproveTransaction.ts +1 -1
  187. package/src/enso-api/model/walletApproveTransactionTx.ts +1 -1
  188. package/src/enso-api/model/walletBalance.ts +21 -9
  189. package/src/enso-api/model/walletControllerCreateApproveTransactionParams.ts +1 -1
  190. package/src/enso-api/model/walletControllerCreateApproveTransactionRoutingStrategy.ts +2 -2
  191. package/src/enso-api/model/walletControllerWalletBalancesParams.ts +4 -4
  192. package/src/index.ts +3 -0
  193. package/src/types/index.ts +2 -0
  194. package/src/util/constants.tsx +19 -0
  195. 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
- accessToken:
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 } = useContext(CheckoutContext);
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 current chain support
261
+ // Filter integrations by effective chain support (intermediate chain if bridging)
245
262
  const filtered = data?.filter(
246
263
  (i) =>
247
- i.networks.some((n) => +n.chainId === chainIdOut) &&
248
- availableExchanges.includes(i.type),
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
- }, [chainIdOut]);
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, setChainIdIn } =
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
- const invalidChainId = chainIdOut && !MESH_NETWORKS.includes(chainIdOut);
334
- const handleMeshAccessPayload = useHandleMeshAccessPayload();
351
+ // Bridging is required if chainIdIn differs from chainIdOut
352
+ const needsBridging = chainIdIn !== chainIdOut;
335
353
 
336
- useEffect(() => {
337
- setChainIdIn(chainIdOut);
338
- }, [chainIdOut]);
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?.accessToken && parsed?.sessionId) {
357
- setMeshAccessToken(parsed.accessToken);
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: meshAccessToken,
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 current chain
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 && chainIdOut && selectedIntegration) {
620
+ if (meshAccessToken && sessionId && chainIdIn && selectedIntegration) {
602
621
  fetchData();
603
622
  }
604
- }, [address, chainIdOut, meshAccessToken, sessionId, selectedIntegration]);
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={chainIdOut || 1}
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 { setAmountIn } = useAppStore();
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
- ? (selectedToken.marketValue - EXCHANGE_MAX_LIMIT_GAP_USD).toFixed(2)
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
- // Apply limits to the target USD amount
808
- const limitedUsdAmount = Math.max(
809
- minValueForToken,
810
- Math.min(targetUsdAmount, +maxUsdAmount),
811
- );
828
+ let finalUsdAmount: number;
829
+ let finalTokenAmount: number;
812
830
 
813
- // Convert back to token amount
814
- const tokenPrice =
815
- selectedToken.marketValue / selectedToken.balance;
816
- const limitedTokenAmount = Math.min(
817
- limitedUsdAmount / tokenPrice,
818
- selectedToken.balance,
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
- setAmount(
822
- precisionizeNumber(limitedTokenAmount, roundingPrecision),
823
- );
824
- setUsdValue(limitedUsdAmount.toFixed(2));
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 = selectedToken
899
- ? EXCHANGE_MIN_LIMIT[
900
- selectedToken.symbol as keyof typeof EXCHANGE_MIN_LIMIT
901
- ]
902
- : 0;
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
- selectedToken && currentUsdValue > 0 && currentUsdValue > +maxUsdAmount;
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, chainIdOut } = useAppStore();
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(chainIdOut),
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("Tracking operation progress...");
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
- setMessage("Operation completed successfully!");
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 (data.operation?.status === "failed") {
1541
+ } else if (
1542
+ ["failed", "failed_permanent"].includes(
1543
+ data.operation?.status,
1544
+ )
1545
+ ) {
1403
1546
  setStatus("failed");
1404
- setMessage("Operation failed");
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); // Check every 3 seconds
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 (status) {
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 renderStatusIcon = () => {
1439
- switch (status) {
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
- <Box
1470
- display="flex"
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 renderProcessingText = () => {
1487
- if (status === "tracking" && isTimerFinished) {
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
- {message}
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
- <Table.Root
1543
- key={"status"}
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
- {(status === "completed" || status === "failed") && (
1951
+ {(phase === "completed" || phase === "failed") && (
1583
1952
  <Button
1584
1953
  onClick={() => setStep(WithdrawalStep.CheckSessionKey)}
1585
1954
  visual="solid"
1586
1955
  >
1587
- {status === "completed" ? "New Deposit" : "Retry Deposit"}
1956
+ {phase === "completed" ? "New Deposit" : "Retry Deposit"}
1588
1957
  </Button>
1589
1958
  )}
1590
1959
  </BodyWrapper>