@ensofinance/checkout-widget 0.0.17 → 0.0.19

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