@unifold/ui-react 0.1.41 → 0.1.43

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/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Button: () => Button,
34
34
  BuyWithCard: () => BuyWithCard,
35
+ CheckoutModal: () => CheckoutModal,
35
36
  ConfirmingView: () => ConfirmingView,
36
37
  CurrencyListItem: () => CurrencyListItem,
37
38
  CurrencyListSection: () => CurrencyListSection,
@@ -55,6 +56,7 @@ __export(index_exports, {
55
56
  DialogPortal: () => DialogPortal,
56
57
  DialogTitle: () => DialogTitle,
57
58
  DialogTrigger: () => DialogTrigger,
59
+ HYPERCORE_CHAIN_ID: () => HYPERCORE_CHAIN_ID,
58
60
  Select: () => Select,
59
61
  SelectContent: () => SelectContent,
60
62
  SelectGroup: () => SelectGroup,
@@ -74,17 +76,35 @@ __export(index_exports, {
74
76
  TransferCryptoButton: () => TransferCryptoButton,
75
77
  TransferCryptoDoubleInput: () => TransferCryptoDoubleInput,
76
78
  TransferCryptoSingleInput: () => TransferCryptoSingleInput,
79
+ WithdrawConfirmingView: () => WithdrawConfirmingView,
80
+ WithdrawDoubleInput: () => WithdrawDoubleInput,
81
+ WithdrawExecutionItem: () => WithdrawExecutionItem,
82
+ WithdrawForm: () => WithdrawForm,
83
+ WithdrawModal: () => WithdrawModal,
84
+ WithdrawTokenSelector: () => WithdrawTokenSelector,
77
85
  buttonVariants: () => buttonVariants,
78
86
  cn: () => cn,
79
87
  colors: () => colors,
80
88
  defaultColors: () => defaultColors,
89
+ detectBrowserWallet: () => detectBrowserWallet,
81
90
  getColors: () => getColors,
91
+ isHypercoreChain: () => isHypercoreChain,
82
92
  mergeColors: () => mergeColors,
83
93
  resolveComponentTokens: () => resolveComponentTokens,
94
+ sendEvmWithdraw: () => sendEvmWithdraw,
95
+ sendHypercoreWithdraw: () => sendHypercoreWithdraw,
96
+ sendSolanaWithdraw: () => sendSolanaWithdraw,
84
97
  truncateAddress: () => truncateAddress,
98
+ useAddressBalance: () => useAddressBalance,
85
99
  useAllowedCountry: () => useAllowedCountry,
86
100
  useDepositPolling: () => useDepositPolling,
87
- useTheme: () => useTheme
101
+ useDepositQuote: () => useDepositQuote,
102
+ usePaymentIntent: () => usePaymentIntent,
103
+ useSourceTokenValidation: () => useSourceTokenValidation,
104
+ useSupportedDestinationTokens: () => useSupportedDestinationTokens,
105
+ useTheme: () => useTheme,
106
+ useVerifyRecipientAddress: () => useVerifyRecipientAddress,
107
+ useWithdrawPolling: () => useWithdrawPolling
88
108
  });
89
109
  module.exports = __toCommonJS(index_exports);
90
110
 
@@ -693,6 +713,7 @@ function useDepositAddress(params) {
693
713
  destinationChainType,
694
714
  destinationChainId,
695
715
  destinationTokenAddress,
716
+ actionType,
696
717
  enabled = true
697
718
  } = params;
698
719
  return (0, import_react_query.useQuery)({
@@ -704,6 +725,7 @@ function useDepositAddress(params) {
704
725
  destinationChainType ?? null,
705
726
  destinationChainId ?? null,
706
727
  destinationTokenAddress ?? null,
728
+ actionType ?? null,
707
729
  publishableKey
708
730
  ],
709
731
  queryFn: () => (0, import_core.createDepositAddress)(
@@ -712,7 +734,8 @@ function useDepositAddress(params) {
712
734
  recipient_address: recipientAddress,
713
735
  destination_chain_type: destinationChainType,
714
736
  destination_chain_id: destinationChainId,
715
- destination_token_address: destinationTokenAddress
737
+ destination_token_address: destinationTokenAddress,
738
+ action_type: actionType
716
739
  },
717
740
  publishableKey
718
741
  ),
@@ -1426,6 +1449,30 @@ var en_default = {
1426
1449
  youReceive: "You receive",
1427
1450
  intentAddressNote: "The wallet address displayed in the payment provider is a temporary deposit address. Your funds will be automatically converted and deposited into your account."
1428
1451
  }
1452
+ },
1453
+ withdrawModal: {
1454
+ title: "Withdraw",
1455
+ withdrawCrypto: {
1456
+ title: "Withdraw with Crypto",
1457
+ subtitle: "Send to any wallet address"
1458
+ },
1459
+ selectToken: "Select withdrawal token",
1460
+ receiveToken: "Receive token",
1461
+ receiveChain: "Receive chain",
1462
+ recipientAddress: "Recipient address",
1463
+ recipientAddressPlaceholder: "Enter wallet address",
1464
+ amount: "Amount",
1465
+ amountPlaceholder: "0.00",
1466
+ balance: "Balance",
1467
+ minimum: "min",
1468
+ withdraw: "Withdraw",
1469
+ invalidAddress: "Please enter a valid address",
1470
+ invalidAmount: "Please enter a valid amount",
1471
+ verifyingAddress: "Verifying address...",
1472
+ loading: "Loading...",
1473
+ noTokensAvailable: "No tokens available",
1474
+ review: "Review Withdrawal",
1475
+ back: "Back"
1429
1476
  }
1430
1477
  };
1431
1478
 
@@ -1449,6 +1496,7 @@ var CUTOFF_BUFFER_MS = 6e4;
1449
1496
  function useDepositPolling({
1450
1497
  userId,
1451
1498
  publishableKey,
1499
+ clientSecret,
1452
1500
  depositConfirmationMode = "auto_ui",
1453
1501
  depositWalletId,
1454
1502
  enabled = true,
@@ -1506,11 +1554,12 @@ function useDepositPolling({
1506
1554
  depositWalletId
1507
1555
  ]);
1508
1556
  (0, import_react3.useEffect)(() => {
1509
- if (!userId || !enabled) return;
1557
+ if (!enabled) return;
1558
+ if (!clientSecret && !userId) return;
1510
1559
  const modalOpenedAt = modalOpenedAtRef.current;
1511
1560
  const poll = async () => {
1512
1561
  try {
1513
- const response = await (0, import_core6.queryExecutions)(userId, publishableKey);
1562
+ const response = clientSecret ? await (0, import_core6.listPaymentIntentExecutions)(clientSecret, publishableKey) : await (0, import_core6.queryExecutions)(userId, publishableKey, import_core6.ActionType.Deposit);
1514
1563
  const cutoff = new Date(modalOpenedAt.getTime() - CUTOFF_BUFFER_MS);
1515
1564
  const sortedExecutions = [...response.data].sort((a, b) => {
1516
1565
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
@@ -1594,7 +1643,7 @@ function useDepositPolling({
1594
1643
  clearInterval(pollInterval);
1595
1644
  setIsPolling(false);
1596
1645
  };
1597
- }, [userId, publishableKey, enabled]);
1646
+ }, [userId, publishableKey, clientSecret, enabled]);
1598
1647
  (0, import_react3.useEffect)(() => {
1599
1648
  if (!pollingEnabled || !depositWalletId) return;
1600
1649
  const triggerPoll = async () => {
@@ -1646,7 +1695,8 @@ function formatCurrency(currency) {
1646
1695
  }
1647
1696
  function DepositDetailContent({
1648
1697
  execution,
1649
- className
1698
+ className,
1699
+ variant = "deposit"
1650
1700
  }) {
1651
1701
  const { colors: colors2, fonts, components } = useTheme();
1652
1702
  const [chains, setChains] = (0, import_react4.useState)([]);
@@ -2052,7 +2102,7 @@ function DepositDetailContent({
2052
2102
  color: components.card.rowLeftLabel,
2053
2103
  fontFamily: fonts.regular
2054
2104
  },
2055
- children: "Deposit Tx"
2105
+ children: variant === "withdraw" ? "Withdrawal Tx" : "Deposit Tx"
2056
2106
  }
2057
2107
  ),
2058
2108
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -7338,7 +7388,7 @@ function DepositsModal({
7338
7388
  if (!open || !userId) return;
7339
7389
  const fetchExecutions = async () => {
7340
7390
  try {
7341
- const response = await (0, import_core19.queryExecutions)(userId, publishableKey);
7391
+ const response = await (0, import_core19.queryExecutions)(userId, publishableKey, import_core19.ActionType.Deposit);
7342
7392
  const sorted = [...response.data].sort((a, b) => {
7343
7393
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
7344
7394
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -7460,7 +7510,7 @@ function saveRecentToken(token) {
7460
7510
  try {
7461
7511
  const recent = getRecentTokens();
7462
7512
  const filtered = recent.filter(
7463
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7513
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7464
7514
  );
7465
7515
  filtered.unshift(token);
7466
7516
  const trimmed = filtered.slice(0, MAX_RECENT_TOKENS);
@@ -7473,7 +7523,7 @@ function removeRecentToken(token) {
7473
7523
  try {
7474
7524
  const recent = getRecentTokens();
7475
7525
  const filtered = recent.filter(
7476
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7526
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7477
7527
  );
7478
7528
  localStorage.setItem(STORAGE_KEY, JSON.stringify(filtered));
7479
7529
  return filtered;
@@ -7512,7 +7562,7 @@ function TokenSelectorSheet({
7512
7562
  const addOption = (symbol, chainType, chainId, isRecent) => {
7513
7563
  const key = `${symbol}-${chainType}:${chainId}`;
7514
7564
  if (seen.has(key)) return;
7515
- const tokenData = tokens.find((t7) => t7.symbol === symbol);
7565
+ const tokenData = tokens.find((t11) => t11.symbol === symbol);
7516
7566
  if (!tokenData) return;
7517
7567
  const chainData = tokenData.chains.find(
7518
7568
  (c) => c.chain_type === chainType && c.chain_id === chainId
@@ -7983,35 +8033,35 @@ function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSour
7983
8033
  let selectedChainData;
7984
8034
  const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
7985
8035
  if (defaultSourceTokenAddress && hasChainDefaults) {
7986
- for (const t7 of supportedTokens) {
7987
- const matchingChain = t7.chains.find(
8036
+ for (const t11 of supportedTokens) {
8037
+ const matchingChain = t11.chains.find(
7988
8038
  (c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
7989
8039
  );
7990
8040
  if (matchingChain) {
7991
- selectedTokenData = t7;
8041
+ selectedTokenData = t11;
7992
8042
  selectedChainData = matchingChain;
7993
8043
  break;
7994
8044
  }
7995
8045
  }
7996
8046
  }
7997
8047
  if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
7998
- for (const t7 of supportedTokens) {
7999
- if (t7.symbol !== defaultSourceSymbol) continue;
8000
- const matchedChain = t7.chains.find(
8048
+ for (const t11 of supportedTokens) {
8049
+ if (t11.symbol !== defaultSourceSymbol) continue;
8050
+ const matchedChain = t11.chains.find(
8001
8051
  (c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
8002
8052
  );
8003
8053
  if (matchedChain) {
8004
- selectedTokenData = t7;
8054
+ selectedTokenData = t11;
8005
8055
  selectedChainData = matchedChain;
8006
8056
  break;
8007
8057
  }
8008
8058
  }
8009
8059
  }
8010
8060
  if (!selectedTokenData) {
8011
- for (const t7 of supportedTokens) {
8012
- if (t7.chains.length > 0) {
8013
- selectedTokenData = t7;
8014
- selectedChainData = t7.chains[0];
8061
+ for (const t11 of supportedTokens) {
8062
+ if (t11.chains.length > 0) {
8063
+ selectedTokenData = t11;
8064
+ selectedChainData = t11.chains[0];
8015
8065
  break;
8016
8066
  }
8017
8067
  }
@@ -8060,7 +8110,7 @@ function useDefaultSourceToken({
8060
8110
  ]);
8061
8111
  (0, import_react13.useEffect)(() => {
8062
8112
  if (!supportedTokens.length || !token) return;
8063
- const currentToken = supportedTokens.find((t7) => t7.symbol === token);
8113
+ const currentToken = supportedTokens.find((t11) => t11.symbol === token);
8064
8114
  if (!currentToken || currentToken.chains.length === 0) return;
8065
8115
  const isChainAvailable = chain && currentToken.chains.some((c) => {
8066
8116
  return getChainKey(c.chain_id, c.chain_type) === chain;
@@ -8330,6 +8380,7 @@ var parseChainKey = (chainKey) => {
8330
8380
  function TransferCryptoSingleInput({
8331
8381
  userId,
8332
8382
  publishableKey,
8383
+ clientSecret,
8333
8384
  recipientAddress,
8334
8385
  destinationChainType,
8335
8386
  destinationChainId,
@@ -8342,7 +8393,9 @@ function TransferCryptoSingleInput({
8342
8393
  onExecutionsChange,
8343
8394
  onDepositSuccess,
8344
8395
  onDepositError,
8345
- wallets: externalWallets
8396
+ wallets: externalWallets,
8397
+ onSourceTokenChange,
8398
+ checkoutQuote
8346
8399
  }) {
8347
8400
  const { themeClass, colors: colors2, fonts, components } = useTheme();
8348
8401
  const isDarkMode = themeClass.includes("uf-dark");
@@ -8384,8 +8437,8 @@ function TransferCryptoSingleInput({
8384
8437
  const error = walletsError?.message ?? null;
8385
8438
  const allAvailableChains = (0, import_react15.useMemo)(() => {
8386
8439
  const chainsMap = /* @__PURE__ */ new Map();
8387
- supportedTokens.forEach((t7) => {
8388
- t7.chains.forEach((c) => {
8440
+ supportedTokens.forEach((t11) => {
8441
+ t11.chains.forEach((c) => {
8389
8442
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8390
8443
  if (!chainsMap.has(comboKey)) {
8391
8444
  chainsMap.set(comboKey, c);
@@ -8409,18 +8462,34 @@ function TransferCryptoSingleInput({
8409
8462
  } = useDepositPolling({
8410
8463
  userId,
8411
8464
  publishableKey,
8465
+ clientSecret,
8412
8466
  depositConfirmationMode,
8413
8467
  depositWalletId: currentWallet?.id,
8414
8468
  enabled: true,
8415
8469
  onDepositSuccess,
8416
8470
  onDepositError
8417
8471
  });
8472
+ (0, import_react15.useEffect)(() => {
8473
+ if (!onSourceTokenChange || !token || !chain || !initialSelectionDone) return;
8474
+ const { chainType, chainId } = parseChainKey(chain);
8475
+ const matchedToken = supportedTokens.find((t11) => t11.symbol === token);
8476
+ const matchedChain = matchedToken?.chains.find(
8477
+ (c) => c.chain_type === chainType && c.chain_id === chainId
8478
+ );
8479
+ onSourceTokenChange({
8480
+ symbol: token,
8481
+ chainType,
8482
+ chainId,
8483
+ tokenAddress: matchedChain?.token_address ?? "",
8484
+ minimumDepositAmountUsd: matchedChain?.minimum_deposit_amount_usd ?? 0
8485
+ });
8486
+ }, [token, chain, initialSelectionDone, onSourceTokenChange, supportedTokens]);
8418
8487
  (0, import_react15.useEffect)(() => {
8419
8488
  if (onExecutionsChange) {
8420
8489
  onExecutionsChange(depositExecutions);
8421
8490
  }
8422
8491
  }, [depositExecutions, onExecutionsChange]);
8423
- const selectedToken = token ? supportedTokens.find((t7) => t7.symbol === token) : void 0;
8492
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8424
8493
  const availableChainsForToken = selectedToken?.chains || [];
8425
8494
  const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
8426
8495
  const key = getChainKey2(c.chain_id, c.chain_type);
@@ -8434,7 +8503,7 @@ function TransferCryptoSingleInput({
8434
8503
  setCopied(true);
8435
8504
  setTimeout(() => setCopied(false), 2e3);
8436
8505
  };
8437
- const formatProcessingTime2 = (seconds) => {
8506
+ const formatProcessingTime3 = (seconds) => {
8438
8507
  if (seconds === null) {
8439
8508
  return t4.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
8440
8509
  }
@@ -8561,6 +8630,53 @@ function TransferCryptoSingleInput({
8561
8630
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Retrying automatically every 5 seconds..." })
8562
8631
  ] })
8563
8632
  ] }),
8633
+ checkoutQuote && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8634
+ "div",
8635
+ {
8636
+ className: "uf-rounded-xl uf-px-3 uf-py-2 uf-flex uf-items-center uf-justify-between",
8637
+ style: {
8638
+ backgroundColor: components.card.backgroundColor,
8639
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`,
8640
+ borderRadius: components.card.borderRadius
8641
+ },
8642
+ children: [
8643
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8644
+ "span",
8645
+ {
8646
+ className: "uf-text-xs",
8647
+ style: { color: components.card.subtitleColor, fontFamily: fonts.regular },
8648
+ children: "You send"
8649
+ }
8650
+ ),
8651
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8652
+ "span",
8653
+ {
8654
+ className: "uf-text-sm uf-font-semibold",
8655
+ style: { color: components.card.titleColor, fontFamily: fonts.semibold },
8656
+ children: [
8657
+ (Number(checkoutQuote.sourceAmount) / 10 ** checkoutQuote.sourceTokenDecimals).toFixed(
8658
+ Math.min(checkoutQuote.sourceTokenDecimals, 6)
8659
+ ),
8660
+ " ",
8661
+ checkoutQuote.sourceTokenSymbol,
8662
+ checkoutQuote.sourceAmountUsd && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8663
+ "span",
8664
+ {
8665
+ className: "uf-text-xs uf-font-normal uf-ml-1.5",
8666
+ style: { color: components.card.subtitleColor },
8667
+ children: [
8668
+ "($",
8669
+ checkoutQuote.sourceAmountUsd,
8670
+ ")"
8671
+ ]
8672
+ }
8673
+ )
8674
+ ]
8675
+ }
8676
+ )
8677
+ ]
8678
+ }
8679
+ ),
8564
8680
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-pt-2", children: [
8565
8681
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1", style: { color: components.card.labelColor }, children: "Intent address" }),
8566
8682
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-shadow-lg", style: { borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: loading || tokensLoading || !initialSelectionDone ? (
@@ -8643,7 +8759,7 @@ function TransferCryptoSingleInput({
8643
8759
  t4.processingTime.label,
8644
8760
  ":",
8645
8761
  " ",
8646
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
8762
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
8647
8763
  ] })
8648
8764
  ] }),
8649
8765
  detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react16.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react16.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
@@ -8957,8 +9073,8 @@ function TransferCryptoDoubleInput({
8957
9073
  const error = walletsError?.message ?? null;
8958
9074
  const allAvailableChains = (0, import_react16.useMemo)(() => {
8959
9075
  const chainsMap = /* @__PURE__ */ new Map();
8960
- supportedTokens.forEach((t7) => {
8961
- t7.chains.forEach((c) => {
9076
+ supportedTokens.forEach((t11) => {
9077
+ t11.chains.forEach((c) => {
8962
9078
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8963
9079
  if (!chainsMap.has(comboKey)) {
8964
9080
  chainsMap.set(comboKey, c);
@@ -8993,7 +9109,7 @@ function TransferCryptoDoubleInput({
8993
9109
  onExecutionsChange(depositExecutions);
8994
9110
  }
8995
9111
  }, [depositExecutions, onExecutionsChange]);
8996
- const selectedToken = token ? supportedTokens.find((t7) => t7.symbol === token) : void 0;
9112
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8997
9113
  const availableChainsForToken = selectedToken?.chains || [];
8998
9114
  const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
8999
9115
  const key = getChainKey3(c.chain_id, c.chain_type);
@@ -9007,7 +9123,7 @@ function TransferCryptoDoubleInput({
9007
9123
  setCopied(true);
9008
9124
  setTimeout(() => setCopied(false), 2e3);
9009
9125
  };
9010
- const formatProcessingTime2 = (seconds) => {
9126
+ const formatProcessingTime3 = (seconds) => {
9011
9127
  if (seconds === null) {
9012
9128
  return t5.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
9013
9129
  }
@@ -9234,7 +9350,7 @@ function TransferCryptoDoubleInput({
9234
9350
  t5.processingTime.label,
9235
9351
  ":",
9236
9352
  " ",
9237
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
9353
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
9238
9354
  ] })
9239
9355
  ] }),
9240
9356
  detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react18.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react18.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
@@ -9412,9 +9528,16 @@ function SelectTokenView({
9412
9528
  onBack,
9413
9529
  onClose,
9414
9530
  onDisconnectWallet,
9415
- isDisconnectingWallet = false
9531
+ isDisconnectingWallet = false,
9532
+ checkoutAmountUsd,
9533
+ checkoutReceivedUsd
9416
9534
  }) {
9417
9535
  const { colors: colors2, fonts, components } = useTheme();
9536
+ const isCheckout = !!checkoutAmountUsd;
9537
+ const headerSubtitle = isCheckout ? parseFloat(checkoutReceivedUsd || "0") > 0 ? `$${checkoutReceivedUsd} / $${checkoutAmountUsd} received` : `Amount due: $${checkoutAmountUsd}` : formatBalanceDisplay(
9538
+ `$${totalBalanceUsd || "0.00"}`,
9539
+ projectName
9540
+ );
9418
9541
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
9419
9542
  "div",
9420
9543
  {
@@ -9423,11 +9546,8 @@ function SelectTokenView({
9423
9546
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
9424
9547
  DepositHeader,
9425
9548
  {
9426
- title: "Select Token",
9427
- subtitle: formatBalanceDisplay(
9428
- `$${totalBalanceUsd || "0.00"}`,
9429
- projectName
9430
- ),
9549
+ title: isCheckout ? "Select Token" : "Select Token",
9550
+ subtitle: headerSubtitle,
9431
9551
  showBack: true,
9432
9552
  onBack,
9433
9553
  onClose
@@ -9658,10 +9778,19 @@ function EnterAmountView({
9658
9778
  onReview,
9659
9779
  onBack,
9660
9780
  onClose,
9661
- quickSelectMode
9781
+ quickSelectMode,
9782
+ checkoutAmountUsd,
9783
+ checkoutReceivedUsd
9662
9784
  }) {
9663
9785
  const { colors: colors2, fonts, components } = useTheme();
9786
+ const isCheckout = !!checkoutAmountUsd;
9664
9787
  const balanceSubtitle = selectedBalance?.amount_usd ? `Balance: $${parseFloat(selectedBalance.amount_usd).toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (${formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol)} ${selectedToken.symbol})` : `Balance: ${formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol)} ${selectedToken.symbol}`;
9788
+ const checkoutRemainingUsd = isCheckout ? Math.max(
9789
+ parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0"),
9790
+ 0
9791
+ ).toFixed(2) : null;
9792
+ const headerTitle = isCheckout ? `Pay $${checkoutRemainingUsd}` : "Enter Amount";
9793
+ const headerSubtitle = isCheckout ? parseFloat(checkoutReceivedUsd || "0") > 0 ? `$${checkoutReceivedUsd} / $${checkoutAmountUsd} received` : null : balanceSubtitle;
9665
9794
  const usePercentageChips = quickSelectMode === "percentage" && maxUsdAmount > 0;
9666
9795
  const chipButtonClass = "uf-flex-1 uf-min-w-0 uf-basis-0 uf-py-2 uf-px-1 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-colors hover:uf-opacity-80 uf-whitespace-nowrap";
9667
9796
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
@@ -9675,14 +9804,27 @@ function EnterAmountView({
9675
9804
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
9676
9805
  DepositHeader,
9677
9806
  {
9678
- title: "Enter Amount",
9679
- subtitle: balanceSubtitle,
9807
+ title: headerTitle,
9808
+ subtitle: headerSubtitle ?? void 0,
9680
9809
  showBack: true,
9681
9810
  onBack,
9682
9811
  onClose
9683
9812
  }
9684
9813
  ),
9685
- walletInfoProp ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-flex uf-w-full uf-justify-center uf-mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(WalletWithNetworkBadge, { walletInfo: walletInfoProp }) }) : null,
9814
+ walletInfoProp ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-flex uf-w-full uf-justify-center uf-mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-1", children: [
9815
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(WalletWithNetworkBadge, { walletInfo: walletInfoProp }),
9816
+ isCheckout && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
9817
+ "span",
9818
+ {
9819
+ className: "uf-text-xs",
9820
+ style: {
9821
+ color: colors2.foregroundMuted,
9822
+ fontFamily: fonts.regular
9823
+ },
9824
+ children: balanceSubtitle
9825
+ }
9826
+ )
9827
+ ] }) }) : null,
9686
9828
  /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: [
9687
9829
  /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-min-h-0 uf-flex-1", children: [
9688
9830
  /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-text-center uf-py-8", children: [
@@ -9705,7 +9847,9 @@ function EnterAmountView({
9705
9847
  inputMode: "decimal",
9706
9848
  placeholder: "0",
9707
9849
  value: amountUsd,
9850
+ readOnly: isCheckout,
9708
9851
  onChange: (e) => {
9852
+ if (isCheckout) return;
9709
9853
  const value = e.target.value;
9710
9854
  if (value === "" || /^\d*\.?\d*$/.test(value)) {
9711
9855
  const decimalIndex = value.indexOf(".");
@@ -9716,7 +9860,7 @@ function EnterAmountView({
9716
9860
  onAmountChange(value);
9717
9861
  }
9718
9862
  },
9719
- className: "uf-bg-transparent uf-outline-none uf-text-center uf-font-normal uf-w-auto uf-min-w-[60px]",
9863
+ className: `uf-bg-transparent uf-outline-none uf-text-center uf-font-normal uf-w-auto uf-min-w-[60px] ${isCheckout ? "uf-cursor-default" : ""}`,
9720
9864
  style: {
9721
9865
  fontSize: `${Math.max(3.75 - (amountUsd || "0").length * 0.15, 2)}rem`,
9722
9866
  color: components.input.textColor,
@@ -9738,7 +9882,7 @@ function EnterAmountView({
9738
9882
  }
9739
9883
  )
9740
9884
  ] }),
9741
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-mb-4 uf-flex uf-w-full uf-min-w-0 uf-flex-nowrap uf-gap-1.5 uf-overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: usePercentageChips ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9885
+ !isCheckout && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-mb-4 uf-flex uf-w-full uf-min-w-0 uf-flex-nowrap uf-gap-1.5 uf-overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: usePercentageChips ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
9742
9886
  PERCENT_QUICK_AMOUNTS.map((pct) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9743
9887
  "button",
9744
9888
  {
@@ -9807,7 +9951,46 @@ function EnterAmountView({
9807
9951
  }
9808
9952
  )
9809
9953
  ] }) }),
9810
- tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9954
+ tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && inputUsdNum > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9955
+ "div",
9956
+ {
9957
+ className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
9958
+ style: {
9959
+ backgroundColor: colors2.warning + "15",
9960
+ border: `1px solid ${colors2.warning}30`,
9961
+ borderRadius: components.card.borderRadius,
9962
+ animation: "uf-fadeSlideIn 0.4s ease-out"
9963
+ },
9964
+ children: [
9965
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9966
+ "div",
9967
+ {
9968
+ className: "uf-text-xs uf-font-medium",
9969
+ style: { color: colors2.warning, fontFamily: fonts.medium },
9970
+ children: [
9971
+ "Minimum for ",
9972
+ selectedToken.symbol,
9973
+ " on ",
9974
+ selectedToken.chain_name,
9975
+ " is $",
9976
+ tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
9977
+ ]
9978
+ }
9979
+ ),
9980
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9981
+ "div",
9982
+ {
9983
+ className: "uf-text-xs uf-mt-0.5",
9984
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
9985
+ children: [
9986
+ "Amount adjusted from remaining $",
9987
+ (parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0")).toFixed(2)
9988
+ ]
9989
+ }
9990
+ )
9991
+ ]
9992
+ }
9993
+ ) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
9811
9994
  "div",
9812
9995
  {
9813
9996
  className: "uf-text-center uf-text-xs uf-mb-3",
@@ -9817,7 +10000,7 @@ function EnterAmountView({
9817
10000
  tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
9818
10001
  ]
9819
10002
  }
9820
- ),
10003
+ )),
9821
10004
  inputUsdNum > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_jsx_runtime46.Fragment, { children: inputUsdNum > maxUsdAmount ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
9822
10005
  "div",
9823
10006
  {
@@ -9832,7 +10015,44 @@ function EnterAmountView({
9832
10015
  style: { color: colors2.error },
9833
10016
  children: error
9834
10017
  }
9835
- ) })
10018
+ ) }),
10019
+ isCheckout && selectedToken.icon_url && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2 uf-py-2", children: [
10020
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-relative", children: [
10021
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
10022
+ "img",
10023
+ {
10024
+ src: selectedToken.icon_url,
10025
+ alt: selectedToken.symbol,
10026
+ width: 20,
10027
+ height: 20,
10028
+ className: "uf-w-5 uf-h-5 uf-rounded-full"
10029
+ }
10030
+ ),
10031
+ selectedToken.chain_icon_url && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
10032
+ "img",
10033
+ {
10034
+ src: selectedToken.chain_icon_url,
10035
+ alt: selectedToken.chain_name,
10036
+ width: 10,
10037
+ height: 10,
10038
+ className: "uf-w-2.5 uf-h-2.5 uf-rounded-full uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-border",
10039
+ style: { borderColor: colors2.background }
10040
+ }
10041
+ )
10042
+ ] }),
10043
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
10044
+ "span",
10045
+ {
10046
+ className: "uf-text-xs",
10047
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
10048
+ children: [
10049
+ selectedToken.symbol,
10050
+ " on ",
10051
+ selectedToken.chain_name
10052
+ ]
10053
+ }
10054
+ )
10055
+ ] })
9836
10056
  ] }),
9837
10057
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-shrink-0 uf-pt-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
9838
10058
  "button",
@@ -9860,6 +10080,18 @@ function EnterAmountView({
9860
10080
  // src/components/deposits/browser-wallets/ReviewView.tsx
9861
10081
  var import_lucide_react20 = require("lucide-react");
9862
10082
  var import_jsx_runtime47 = require("react/jsx-runtime");
10083
+ var WALLET_ICONS2 = {
10084
+ metamask: MetamaskIcon,
10085
+ phantom: PhantomIcon,
10086
+ coinbase: CoinbaseIcon,
10087
+ trust: TrustIcon,
10088
+ rainbow: RainbowIcon,
10089
+ rabby: RabbyIcon,
10090
+ okx: OkxIcon,
10091
+ solflare: SolflareIcon,
10092
+ backpack: BackpackIcon,
10093
+ glow: GlowIcon
10094
+ };
9863
10095
  function ReviewView({
9864
10096
  walletInfo,
9865
10097
  recipientAddress,
@@ -9894,30 +10126,17 @@ function ReviewView({
9894
10126
  ),
9895
10127
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: [
9896
10128
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-min-h-0 uf-flex-1 uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: [
9897
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-text-center", children: [
9898
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
9899
- "div",
9900
- {
9901
- className: "uf-text-4xl uf-font-medium",
9902
- style: { color: colors2.foreground, fontFamily: fonts.medium },
9903
- children: [
9904
- "$",
9905
- amountUsd || "0"
9906
- ]
9907
- }
9908
- ),
9909
- formattedTokenAmount && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
9910
- "div",
9911
- {
9912
- className: "uf-text-sm uf-mt-2",
9913
- style: { color: colors2.foregroundMuted },
9914
- children: [
9915
- "\u2248 ",
9916
- formattedTokenAmount
9917
- ]
9918
- }
9919
- )
9920
- ] }),
10129
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "uf-text-center", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
10130
+ "div",
10131
+ {
10132
+ className: "uf-text-4xl uf-font-medium",
10133
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
10134
+ children: [
10135
+ "$",
10136
+ amountUsd || "0"
10137
+ ]
10138
+ }
10139
+ ) }),
9921
10140
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
9922
10141
  "div",
9923
10142
  {
@@ -9934,7 +10153,31 @@ function ReviewView({
9934
10153
  {
9935
10154
  className: "uf-text-sm",
9936
10155
  style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
9937
- children: "Source"
10156
+ children: "From"
10157
+ }
10158
+ ),
10159
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
10160
+ WALLET_ICONS2[walletInfo.icon] && (() => {
10161
+ const Icon2 = WALLET_ICONS2[walletInfo.icon];
10162
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "uf-w-5 uf-h-5 uf-rounded-full uf-overflow-hidden uf-flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Icon2, { size: 20, variant: "color" }) });
10163
+ })(),
10164
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
10165
+ "span",
10166
+ {
10167
+ className: "uf-text-sm uf-font-medium",
10168
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
10169
+ children: walletInfo.name
10170
+ }
10171
+ )
10172
+ ] })
10173
+ ] }),
10174
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-justify-between uf-items-center", children: [
10175
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
10176
+ "span",
10177
+ {
10178
+ className: "uf-text-sm",
10179
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
10180
+ children: "You send"
9938
10181
  }
9939
10182
  ),
9940
10183
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
@@ -9946,17 +10189,12 @@ function ReviewView({
9946
10189
  className: "uf-w-5 uf-h-5 uf-rounded-full"
9947
10190
  }
9948
10191
  ),
9949
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
10192
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
9950
10193
  "span",
9951
10194
  {
9952
10195
  className: "uf-text-sm uf-font-medium",
9953
10196
  style: { color: colors2.foreground, fontFamily: fonts.medium },
9954
- children: [
9955
- walletInfo.name,
9956
- " (",
9957
- truncateAddress2(walletInfo.address),
9958
- ")"
9959
- ]
10197
+ children: formattedTokenAmount || `$${amountUsd}`
9960
10198
  }
9961
10199
  )
9962
10200
  ] })
@@ -10119,7 +10357,10 @@ function ReviewView({
10119
10357
  borderRadius: components.button.borderRadius,
10120
10358
  border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
10121
10359
  },
10122
- children: isConfirming ? "Confirming..." : "Confirm Order"
10360
+ children: isConfirming ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
10361
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react20.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
10362
+ "Confirming..."
10363
+ ] }) : "Confirm Order"
10123
10364
  }
10124
10365
  ) })
10125
10366
  ] })
@@ -10133,17 +10374,35 @@ function ReviewView({
10133
10374
  var import_react17 = require("react");
10134
10375
  var import_lucide_react21 = require("lucide-react");
10135
10376
  var import_jsx_runtime48 = require("react/jsx-runtime");
10377
+ var SETTLE_FALLBACK_MS = 15e3;
10136
10378
  function ConfirmingView({
10137
10379
  isConfirming,
10138
10380
  onClose,
10139
10381
  executions = [],
10140
- isPolling = false
10382
+ isPolling = false,
10383
+ onNewDeposit,
10384
+ onDone,
10385
+ paymentIntentStatus,
10386
+ amountReceivedUsd,
10387
+ amountReceivedUsdAtSubmission
10141
10388
  }) {
10142
- const { colors: colors2, fonts } = useTheme();
10389
+ const { colors: colors2, fonts, components } = useTheme();
10143
10390
  const [containerEl, setContainerEl] = (0, import_react17.useState)(null);
10144
10391
  const containerCallbackRef = (0, import_react17.useCallback)((el) => {
10145
10392
  setContainerEl(el);
10146
10393
  }, []);
10394
+ const [fallbackSettled, setFallbackSettled] = (0, import_react17.useState)(false);
10395
+ const hasExecution = executions.length > 0;
10396
+ const isCheckoutMode = paymentIntentStatus != null;
10397
+ const isPaymentComplete = paymentIntentStatus === "succeeded";
10398
+ const amountChanged = amountReceivedUsdAtSubmission != null && amountReceivedUsd != null && amountReceivedUsd !== amountReceivedUsdAtSubmission;
10399
+ const piSettled = !isCheckoutMode || isPaymentComplete || amountChanged || fallbackSettled;
10400
+ (0, import_react17.useEffect)(() => {
10401
+ if (!hasExecution || piSettled) return;
10402
+ const timeout = setTimeout(() => setFallbackSettled(true), SETTLE_FALLBACK_MS);
10403
+ return () => clearTimeout(timeout);
10404
+ }, [hasExecution, piSettled]);
10405
+ const showButtons = hasExecution && piSettled;
10147
10406
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PortalContainerProvider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
10148
10407
  "div",
10149
10408
  {
@@ -10156,8 +10415,8 @@ function ConfirmingView({
10156
10415
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
10157
10416
  DepositHeader,
10158
10417
  {
10159
- title: isConfirming ? "Confirming..." : "Processing",
10160
- onClose
10418
+ title: isConfirming ? "Confirming..." : hasExecution && isPaymentComplete ? "Payment Complete" : hasExecution ? "Deposit Received" : "Processing",
10419
+ onClose: isPaymentComplete && onDone ? onDone : onClose
10161
10420
  }
10162
10421
  ),
10163
10422
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "uf-flex uf-flex-1 uf-flex-col uf-items-center uf-justify-center uf-py-8", children: isConfirming ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
@@ -10184,11 +10443,70 @@ function ConfirmingView({
10184
10443
  children: "Please confirm the transaction in your wallet"
10185
10444
  }
10186
10445
  )
10187
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
10446
+ ] }) : hasExecution ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
10188
10447
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
10189
10448
  import_lucide_react21.CheckCircle2,
10190
10449
  {
10191
10450
  className: "uf-w-12 uf-h-12 uf-mb-4",
10451
+ style: { color: "rgb(34, 197, 94)" }
10452
+ }
10453
+ ),
10454
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
10455
+ "div",
10456
+ {
10457
+ className: "uf-text-lg uf-font-medium",
10458
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
10459
+ children: isPaymentComplete ? "Payment Complete" : "Deposit Received"
10460
+ }
10461
+ ),
10462
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
10463
+ "div",
10464
+ {
10465
+ className: "uf-text-sm uf-mt-2 uf-text-center uf-px-6",
10466
+ style: { color: colors2.foregroundMuted },
10467
+ children: isPaymentComplete ? "Your payment has been fulfilled." : showButtons ? "Your deposit is being processed." : "Checking payment status..."
10468
+ }
10469
+ ),
10470
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "uf-mt-6 uf-flex uf-flex-col uf-items-center uf-gap-3", children: !showButtons ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
10471
+ import_lucide_react21.Loader2,
10472
+ {
10473
+ className: "uf-w-5 uf-h-5 uf-animate-spin",
10474
+ style: { color: colors2.foregroundMuted }
10475
+ }
10476
+ ) : isPaymentComplete && onDone ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
10477
+ "button",
10478
+ {
10479
+ onClick: onDone,
10480
+ className: "uf-w-full uf-py-3 uf-px-8 uf-text-sm uf-font-medium uf-transition-opacity hover:uf-opacity-80",
10481
+ style: {
10482
+ backgroundColor: colors2.primary,
10483
+ color: colors2.primaryForeground,
10484
+ fontFamily: fonts.medium,
10485
+ borderRadius: components.button.borderRadius
10486
+ },
10487
+ children: "Done"
10488
+ }
10489
+ ) : onNewDeposit ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
10490
+ "button",
10491
+ {
10492
+ onClick: onNewDeposit,
10493
+ className: "uf-flex uf-items-center uf-gap-2 uf-px-5 uf-py-2.5 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-opacity hover:uf-opacity-80",
10494
+ style: {
10495
+ backgroundColor: colors2.primary,
10496
+ color: colors2.primaryForeground,
10497
+ fontFamily: fonts.medium
10498
+ },
10499
+ children: [
10500
+ "Make another deposit",
10501
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react21.ArrowRight, { className: "uf-w-4 uf-h-4" })
10502
+ ]
10503
+ }
10504
+ ) : null })
10505
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
10506
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
10507
+ import_lucide_react21.Loader2,
10508
+ {
10509
+ className: "uf-w-12 uf-h-12 uf-animate-spin uf-mb-4",
10192
10510
  style: { color: colors2.primary }
10193
10511
  }
10194
10512
  ),
@@ -10205,7 +10523,7 @@ function ConfirmingView({
10205
10523
  {
10206
10524
  className: "uf-text-sm uf-mt-2 uf-text-center uf-px-6",
10207
10525
  style: { color: colors2.foregroundMuted },
10208
- children: "You can close this window or wait for confirmation."
10526
+ children: "Waiting for your deposit to be detected..."
10209
10527
  }
10210
10528
  )
10211
10529
  ] }) }),
@@ -10232,6 +10550,7 @@ function BrowserWalletModal({
10232
10550
  depositWallet,
10233
10551
  userId,
10234
10552
  publishableKey,
10553
+ clientSecret,
10235
10554
  assetCdnUrl,
10236
10555
  projectName,
10237
10556
  theme = "dark",
@@ -10240,7 +10559,13 @@ function BrowserWalletModal({
10240
10559
  onDepositSuccess,
10241
10560
  onDepositError,
10242
10561
  amountQuickSelect = "percentage",
10243
- onWalletDisconnect
10562
+ onWalletDisconnect,
10563
+ prefillAmountUsd,
10564
+ checkoutAmountUsd,
10565
+ checkoutReceivedUsd,
10566
+ onNewDeposit,
10567
+ onDone,
10568
+ paymentIntentStatus
10244
10569
  }) {
10245
10570
  const { colors: colors2, fonts, components } = useTheme();
10246
10571
  const [step, setStep] = React26.useState("select-token");
@@ -10258,6 +10583,7 @@ function BrowserWalletModal({
10258
10583
  const [tokenChainDetails, setTokenChainDetails] = React26.useState(null);
10259
10584
  const [loadingTokenDetails, setLoadingTokenDetails] = React26.useState(false);
10260
10585
  const [showTransactionDetails, setShowTransactionDetails] = React26.useState(false);
10586
+ const [receivedUsdAtSubmission, setReceivedUsdAtSubmission] = React26.useState(null);
10261
10587
  const themeClass = theme === "dark" ? "uf-dark" : "";
10262
10588
  const chainType = depositWallet.chain_type;
10263
10589
  const recipientAddress = depositWallet.address;
@@ -10265,15 +10591,19 @@ function BrowserWalletModal({
10265
10591
  const { executions: depositExecutions, isPolling } = useDepositPolling({
10266
10592
  userId,
10267
10593
  publishableKey,
10594
+ clientSecret,
10268
10595
  enabled: open && hasSignedTransaction,
10269
10596
  onDepositSuccess,
10270
10597
  onDepositError
10271
10598
  });
10599
+ const prevOpenRef = React26.useRef(false);
10272
10600
  React26.useEffect(() => {
10273
- if (open) {
10601
+ const wasOpen = prevOpenRef.current;
10602
+ prevOpenRef.current = open;
10603
+ if (open && !wasOpen) {
10274
10604
  setStep("select-token");
10275
10605
  setSelectedBalance(null);
10276
- setAmountUsd("");
10606
+ setAmountUsd(prefillAmountUsd ?? "");
10277
10607
  setError(null);
10278
10608
  setIsConfirming(false);
10279
10609
  setTokenChainDetails(null);
@@ -10281,7 +10611,15 @@ function BrowserWalletModal({
10281
10611
  setHasSignedTransaction(false);
10282
10612
  setIsDisconnectingWallet(false);
10283
10613
  }
10284
- }, [open]);
10614
+ }, [open, prefillAmountUsd]);
10615
+ React26.useEffect(() => {
10616
+ if (!prefillAmountUsd || !tokenChainDetails || step !== "input-amount") return;
10617
+ const minDeposit = tokenChainDetails.minimum_deposit_amount_usd || 0;
10618
+ const currentAmount = parseFloat(amountUsd) || 0;
10619
+ if (currentAmount > 0 && currentAmount < minDeposit) {
10620
+ setAmountUsd(minDeposit.toFixed(2));
10621
+ }
10622
+ }, [tokenChainDetails, step, prefillAmountUsd]);
10285
10623
  React26.useEffect(() => {
10286
10624
  if (step === "review") {
10287
10625
  setShowTransactionDetails(false);
@@ -10308,7 +10646,7 @@ function BrowserWalletModal({
10308
10646
  );
10309
10647
  if (cancelled) return;
10310
10648
  const supportedToken = response.data.find(
10311
- (t7) => t7.symbol.toLowerCase() === token.symbol.toLowerCase()
10649
+ (t11) => t11.symbol.toLowerCase() === token.symbol.toLowerCase()
10312
10650
  );
10313
10651
  if (supportedToken) {
10314
10652
  const chainDetail = supportedToken.chains.find(
@@ -10399,7 +10737,7 @@ function BrowserWalletModal({
10399
10737
  setError(null);
10400
10738
  if (step === "input-amount") {
10401
10739
  setStep("select-token");
10402
- setAmountUsd("");
10740
+ setAmountUsd(prefillAmountUsd ?? "");
10403
10741
  setTokenChainDetails(null);
10404
10742
  } else if (step === "review") {
10405
10743
  setStep("input-amount");
@@ -10485,7 +10823,6 @@ function BrowserWalletModal({
10485
10823
  }
10486
10824
  }
10487
10825
  setIsConfirming(true);
10488
- setStep("confirming");
10489
10826
  setError(null);
10490
10827
  try {
10491
10828
  let txHash;
@@ -10503,16 +10840,17 @@ function BrowserWalletModal({
10503
10840
  } else {
10504
10841
  txHash = await sendEthereumTransaction(token, tokenAmount.toString());
10505
10842
  }
10843
+ setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
10506
10844
  setHasSignedTransaction(true);
10507
- onSuccess?.(txHash);
10508
10845
  setIsConfirming(false);
10846
+ setStep("confirming");
10847
+ onSuccess?.(txHash);
10509
10848
  } catch (err) {
10510
10849
  console.error("[BrowserWalletModal] Transaction error:", err);
10511
10850
  const errorMessage = err instanceof Error ? err.message : "Transaction failed";
10512
10851
  setError(errorMessage);
10513
10852
  onError?.(err instanceof Error ? err : new Error(errorMessage));
10514
10853
  setIsConfirming(false);
10515
- setStep("review");
10516
10854
  }
10517
10855
  };
10518
10856
  const sendEthereumTransaction = async (token, amountStr) => {
@@ -10761,7 +11099,9 @@ function BrowserWalletModal({
10761
11099
  onBack: handleClose,
10762
11100
  onClose: handleFullClose,
10763
11101
  onDisconnectWallet: onWalletDisconnect ? () => void handleDisconnectFromSelectToken() : void 0,
10764
- isDisconnectingWallet
11102
+ isDisconnectingWallet,
11103
+ checkoutAmountUsd,
11104
+ checkoutReceivedUsd
10765
11105
  }
10766
11106
  ),
10767
11107
  step === "input-amount" && selectedToken && selectedBalance && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
@@ -10782,7 +11122,9 @@ function BrowserWalletModal({
10782
11122
  onReview: handleReview,
10783
11123
  onBack: handleBack,
10784
11124
  onClose: handleFullClose,
10785
- quickSelectMode: amountQuickSelect
11125
+ quickSelectMode: amountQuickSelect,
11126
+ checkoutAmountUsd,
11127
+ checkoutReceivedUsd
10786
11128
  }
10787
11129
  ),
10788
11130
  step === "review" && selectedToken && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
@@ -10811,7 +11153,12 @@ function BrowserWalletModal({
10811
11153
  isConfirming,
10812
11154
  onClose: handleFullClose,
10813
11155
  executions: depositExecutions,
10814
- isPolling
11156
+ isPolling,
11157
+ onNewDeposit,
11158
+ onDone,
11159
+ paymentIntentStatus,
11160
+ amountReceivedUsd: checkoutReceivedUsd,
11161
+ amountReceivedUsdAtSubmission: receivedUsdAtSubmission
10815
11162
  }
10816
11163
  )
10817
11164
  ] })
@@ -10825,7 +11172,7 @@ function BrowserWalletModal({
10825
11172
  var React27 = __toESM(require("react"));
10826
11173
  var import_lucide_react22 = require("lucide-react");
10827
11174
  var import_jsx_runtime50 = require("react/jsx-runtime");
10828
- var WALLET_ICONS2 = {
11175
+ var WALLET_ICONS3 = {
10829
11176
  metamask: MetamaskIcon,
10830
11177
  phantom: PhantomIcon,
10831
11178
  coinbase: CoinbaseIcon,
@@ -11264,10 +11611,10 @@ function WalletSelectionModal({
11264
11611
  },
11265
11612
  children: [
11266
11613
  /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
11267
- WALLET_ICONS2[wallet.id] ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
11614
+ WALLET_ICONS3[wallet.id] ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
11268
11615
  WalletIconWithNetwork,
11269
11616
  {
11270
- WalletIcon: WALLET_ICONS2[wallet.id],
11617
+ WalletIcon: WALLET_ICONS3[wallet.id],
11271
11618
  networks: wallet.networks,
11272
11619
  size: 40,
11273
11620
  className: "uf-rounded-lg"
@@ -11338,10 +11685,10 @@ function WalletSelectionModal({
11338
11685
  style: { minHeight: WALLET_STEP_BODY_MIN_HEIGHT },
11339
11686
  children: [
11340
11687
  /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-pb-4 uf-shrink-0", children: [
11341
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uf-mb-2", children: WALLET_ICONS2[selectedWallet.id] ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
11688
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uf-mb-2", children: WALLET_ICONS3[selectedWallet.id] ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
11342
11689
  WalletIconWithNetwork,
11343
11690
  {
11344
- WalletIcon: WALLET_ICONS2[selectedWallet.id],
11691
+ WalletIcon: WALLET_ICONS3[selectedWallet.id],
11345
11692
  networks: selectedWallet.networks,
11346
11693
  size: 48,
11347
11694
  className: "uf-rounded-lg"
@@ -11624,7 +11971,7 @@ function DepositModal({
11624
11971
  if (view !== "tracker" || !userId) return;
11625
11972
  const fetchExecutions = async () => {
11626
11973
  try {
11627
- const response = await (0, import_core23.queryExecutions)(userId, publishableKey);
11974
+ const response = await (0, import_core23.queryExecutions)(userId, publishableKey, import_core23.ActionType.Deposit);
11628
11975
  const sorted = [...response.data].sort((a, b) => {
11629
11976
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
11630
11977
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -12143,10 +12490,2711 @@ function DepositModal({
12143
12490
  }
12144
12491
  ) });
12145
12492
  }
12493
+
12494
+ // src/components/checkout/CheckoutModal.tsx
12495
+ var import_react19 = require("react");
12496
+ var import_lucide_react24 = require("lucide-react");
12497
+
12498
+ // src/hooks/use-payment-intent.ts
12499
+ var import_react_query9 = require("@tanstack/react-query");
12500
+ var import_core24 = require("@unifold/core");
12501
+ function usePaymentIntent(params) {
12502
+ const {
12503
+ clientSecret,
12504
+ publishableKey,
12505
+ enabled = true,
12506
+ pollingInterval = 5e3
12507
+ } = params;
12508
+ return (0, import_react_query9.useQuery)({
12509
+ queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
12510
+ queryFn: () => (0, import_core24.retrievePaymentIntent)(clientSecret, publishableKey),
12511
+ enabled: enabled && !!clientSecret && !!publishableKey,
12512
+ staleTime: 0,
12513
+ refetchInterval: pollingInterval || false,
12514
+ refetchOnWindowFocus: true,
12515
+ retry: 3,
12516
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
12517
+ });
12518
+ }
12519
+
12520
+ // src/hooks/use-deposit-quote.ts
12521
+ var import_react_query10 = require("@tanstack/react-query");
12522
+ var import_core25 = require("@unifold/core");
12523
+ function useDepositQuote(params) {
12524
+ const {
12525
+ publishableKey,
12526
+ sourceChainType,
12527
+ sourceChainId,
12528
+ sourceTokenAddress,
12529
+ destinationAmount,
12530
+ destinationChainType,
12531
+ destinationChainId,
12532
+ destinationTokenAddress,
12533
+ enabled = true
12534
+ } = params;
12535
+ const request = {
12536
+ source_chain_type: sourceChainType,
12537
+ source_chain_id: sourceChainId,
12538
+ source_token_address: sourceTokenAddress,
12539
+ destination_amount: destinationAmount,
12540
+ destination_chain_type: destinationChainType,
12541
+ destination_chain_id: destinationChainId,
12542
+ destination_token_address: destinationTokenAddress
12543
+ };
12544
+ return (0, import_react_query10.useQuery)({
12545
+ queryKey: [
12546
+ "unifold",
12547
+ "depositQuote",
12548
+ sourceChainType,
12549
+ sourceChainId,
12550
+ sourceTokenAddress,
12551
+ destinationAmount,
12552
+ destinationChainType,
12553
+ destinationChainId,
12554
+ destinationTokenAddress,
12555
+ publishableKey
12556
+ ],
12557
+ queryFn: () => (0, import_core25.getDepositQuote)(request, publishableKey),
12558
+ enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
12559
+ staleTime: 6e4,
12560
+ gcTime: 5 * 6e4,
12561
+ refetchOnWindowFocus: false,
12562
+ retry: 2,
12563
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
12564
+ });
12565
+ }
12566
+
12567
+ // src/components/checkout/CheckoutModal.tsx
12568
+ var import_jsx_runtime52 = require("react/jsx-runtime");
12569
+ function mapDepositAddressesToWallets(depositAddresses, pi) {
12570
+ return depositAddresses.map((da, idx) => ({
12571
+ id: da.id,
12572
+ chain_type: da.chain_type,
12573
+ address_type: da.address_type,
12574
+ address: da.address,
12575
+ destination_chain_type: pi.destination_chain_type,
12576
+ destination_chain_id: pi.destination_chain_id,
12577
+ destination_token_address: pi.destination_token_address,
12578
+ recipient_address: pi.recipient_address,
12579
+ is_primary: idx === 0
12580
+ }));
12581
+ }
12582
+ function SkeletonButton2() {
12583
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-justify-between uf-animate-pulse", children: [
12584
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
12585
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-bg-muted uf-rounded-lg uf-w-9 uf-h-9" }),
12586
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-space-y-1.5", children: [
12587
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-h-3.5 uf-w-24 uf-bg-muted uf-rounded" }),
12588
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-h-3 uf-w-32 uf-bg-muted uf-rounded" })
12589
+ ] })
12590
+ ] }),
12591
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react24.ChevronRight, { className: "uf-w-4 uf-h-4 uf-text-muted" }) })
12592
+ ] });
12593
+ }
12594
+ function CheckoutModal({
12595
+ open,
12596
+ onOpenChange,
12597
+ clientSecret,
12598
+ publishableKey,
12599
+ modalTitle,
12600
+ enableConnectWallet = false,
12601
+ theme = "dark",
12602
+ onCheckoutSuccess,
12603
+ onCheckoutError
12604
+ }) {
12605
+ const { colors: colors2, fonts, components } = useTheme();
12606
+ const [view, setView] = (0, import_react19.useState)("main");
12607
+ const resetViewTimeoutRef = (0, import_react19.useRef)(
12608
+ null
12609
+ );
12610
+ const [browserWalletModalOpen, setBrowserWalletModalOpen] = (0, import_react19.useState)(false);
12611
+ const [browserWalletInfo, setBrowserWalletInfo] = (0, import_react19.useState)(null);
12612
+ const [walletSelectionModalOpen, setWalletSelectionModalOpen] = (0, import_react19.useState)(false);
12613
+ const [browserWalletChainType, setBrowserWalletChainType] = (0, import_react19.useState)(() => getStoredWalletChainType());
12614
+ const isMobileView = useIsMobileViewport();
12615
+ const [resolvedTheme, setResolvedTheme] = (0, import_react19.useState)(
12616
+ theme === "auto" ? "dark" : theme
12617
+ );
12618
+ (0, import_react19.useEffect)(() => {
12619
+ if (theme === "auto") {
12620
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
12621
+ setResolvedTheme(mediaQuery.matches ? "dark" : "light");
12622
+ const handler = (e) => {
12623
+ setResolvedTheme(e.matches ? "dark" : "light");
12624
+ };
12625
+ mediaQuery.addEventListener("change", handler);
12626
+ return () => mediaQuery.removeEventListener("change", handler);
12627
+ } else {
12628
+ setResolvedTheme(theme);
12629
+ }
12630
+ }, [theme]);
12631
+ const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
12632
+ const {
12633
+ data: paymentIntent,
12634
+ isLoading: piLoading,
12635
+ error: piError
12636
+ } = usePaymentIntent({
12637
+ clientSecret,
12638
+ publishableKey,
12639
+ enabled: open && !!clientSecret,
12640
+ pollingInterval: 5e3
12641
+ });
12642
+ const { projectConfig } = useProjectConfig({
12643
+ publishableKey,
12644
+ enabled: open
12645
+ });
12646
+ const prevStatusRef = (0, import_react19.useRef)(null);
12647
+ (0, import_react19.useEffect)(() => {
12648
+ if (!paymentIntent) return;
12649
+ const prev = prevStatusRef.current;
12650
+ prevStatusRef.current = paymentIntent.status;
12651
+ if (prev && prev !== paymentIntent.status && paymentIntent.status === "succeeded") {
12652
+ if (!browserWalletModalOpen) {
12653
+ setView("main");
12654
+ }
12655
+ onCheckoutSuccess?.({
12656
+ paymentIntentId: paymentIntent.id,
12657
+ status: paymentIntent.status
12658
+ });
12659
+ }
12660
+ }, [paymentIntent, onCheckoutSuccess, browserWalletModalOpen]);
12661
+ const wallets = (0, import_react19.useMemo)(() => {
12662
+ if (!paymentIntent) return [];
12663
+ return mapDepositAddressesToWallets(
12664
+ paymentIntent.deposit_addresses,
12665
+ paymentIntent
12666
+ );
12667
+ }, [paymentIntent]);
12668
+ const formatCryptoAmount = (0, import_react19.useMemo)(() => {
12669
+ if (!paymentIntent) return (_) => "";
12670
+ const decimals = paymentIntent.destination_token_decimals ?? 6;
12671
+ const symbol = paymentIntent.currency.toUpperCase();
12672
+ return (baseUnits) => {
12673
+ const num = Number(baseUnits) / 10 ** decimals;
12674
+ const formatted = num % 1 === 0 ? num.toFixed(0) : num.toFixed(2);
12675
+ return `${formatted} ${symbol}`;
12676
+ };
12677
+ }, [paymentIntent]);
12678
+ const remainingAmountUsd = (0, import_react19.useMemo)(() => {
12679
+ if (!paymentIntent) return void 0;
12680
+ const total = parseFloat(paymentIntent.amount_usd);
12681
+ const received = parseFloat(paymentIntent.amount_received_usd);
12682
+ if (isNaN(total) || isNaN(received)) return paymentIntent.amount_usd;
12683
+ const remaining = total - received;
12684
+ return remaining > 0 ? remaining.toFixed(2) : "0.00";
12685
+ }, [paymentIntent]);
12686
+ const remainingCrypto = (0, import_react19.useMemo)(() => {
12687
+ if (!paymentIntent) return void 0;
12688
+ const total = BigInt(paymentIntent.amount);
12689
+ const received = BigInt(paymentIntent.amount_received);
12690
+ const remaining = total - received;
12691
+ return remaining > 0n ? remaining.toString() : "0";
12692
+ }, [paymentIntent]);
12693
+ const [selectedSource, setSelectedSource] = (0, import_react19.useState)(null);
12694
+ const quoteDestinationAmount = (0, import_react19.useMemo)(() => {
12695
+ if (!paymentIntent || !selectedSource) return "0";
12696
+ const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
12697
+ const totalBaseUnits = Number(paymentIntent.amount);
12698
+ const totalUsd = parseFloat(paymentIntent.amount_usd);
12699
+ const baseUnitsPerUsd = totalUsd > 0 ? totalBaseUnits / totalUsd : 0;
12700
+ const minUsd = Math.max(selectedSource.minimumDepositAmountUsd, 3);
12701
+ const minDepositBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
12702
+ const effective = remaining > minDepositBaseUnits ? remaining : minDepositBaseUnits;
12703
+ return effective > 0n ? effective.toString() : "0";
12704
+ }, [paymentIntent, selectedSource]);
12705
+ const { data: sourceQuote } = useDepositQuote({
12706
+ publishableKey,
12707
+ sourceChainType: selectedSource?.chainType ?? "",
12708
+ sourceChainId: selectedSource?.chainId ?? "",
12709
+ sourceTokenAddress: selectedSource?.tokenAddress ?? "",
12710
+ destinationAmount: quoteDestinationAmount,
12711
+ destinationChainType: paymentIntent?.destination_chain_type ?? "",
12712
+ destinationChainId: paymentIntent?.destination_chain_id ?? "",
12713
+ destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
12714
+ enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
12715
+ });
12716
+ const handleBrowserWalletClick = (0, import_react19.useCallback)(
12717
+ (walletInfo) => {
12718
+ const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
12719
+ setStoredWalletChainType(walletChainType);
12720
+ setBrowserWalletChainType(walletChainType);
12721
+ const matchingDepositWallet = wallets.find(
12722
+ (w) => w.chain_type === walletChainType
12723
+ );
12724
+ if (!matchingDepositWallet) {
12725
+ onCheckoutError?.({
12726
+ message: `Unable to pay from ${walletChainType}. Please try a different wallet.`,
12727
+ code: "NO_DEPOSIT_ADDRESS"
12728
+ });
12729
+ return;
12730
+ }
12731
+ setBrowserWalletInfo({
12732
+ ...walletInfo,
12733
+ depositWallet: matchingDepositWallet
12734
+ });
12735
+ setBrowserWalletModalOpen(true);
12736
+ },
12737
+ [wallets, onCheckoutError]
12738
+ );
12739
+ const handleWalletConnectClick = (0, import_react19.useCallback)(() => {
12740
+ setWalletSelectionModalOpen(true);
12741
+ }, []);
12742
+ const handleWalletConnected = (0, import_react19.useCallback)(
12743
+ (walletInfo) => {
12744
+ const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
12745
+ setStoredWalletChainType(walletChainType);
12746
+ setBrowserWalletChainType(walletChainType);
12747
+ const matchingDepositWallet = wallets.find(
12748
+ (w) => w.chain_type === walletChainType
12749
+ );
12750
+ if (!matchingDepositWallet) {
12751
+ onCheckoutError?.({
12752
+ message: `Unable to pay from ${walletChainType}. Please try a different wallet.`,
12753
+ code: "NO_DEPOSIT_ADDRESS"
12754
+ });
12755
+ setWalletSelectionModalOpen(false);
12756
+ return;
12757
+ }
12758
+ setBrowserWalletInfo({
12759
+ ...walletInfo,
12760
+ depositWallet: matchingDepositWallet
12761
+ });
12762
+ setWalletSelectionModalOpen(false);
12763
+ setBrowserWalletModalOpen(true);
12764
+ },
12765
+ [wallets, onCheckoutError]
12766
+ );
12767
+ const handleWalletDisconnect = (0, import_react19.useCallback)(() => {
12768
+ setUserDisconnectedWallet(true);
12769
+ clearStoredWalletChainType();
12770
+ setBrowserWalletChainType(void 0);
12771
+ setBrowserWalletInfo(null);
12772
+ setBrowserWalletModalOpen(false);
12773
+ }, []);
12774
+ const handleClose = (0, import_react19.useCallback)(() => {
12775
+ onOpenChange(false);
12776
+ if (resetViewTimeoutRef.current) {
12777
+ clearTimeout(resetViewTimeoutRef.current);
12778
+ }
12779
+ resetViewTimeoutRef.current = setTimeout(() => {
12780
+ setView("main");
12781
+ setBrowserWalletInfo(null);
12782
+ resetViewTimeoutRef.current = null;
12783
+ }, 200);
12784
+ }, [onOpenChange]);
12785
+ (0, import_react19.useLayoutEffect)(() => {
12786
+ if (!open) return;
12787
+ if (resetViewTimeoutRef.current) {
12788
+ clearTimeout(resetViewTimeoutRef.current);
12789
+ resetViewTimeoutRef.current = null;
12790
+ }
12791
+ setView("main");
12792
+ setBrowserWalletInfo(null);
12793
+ }, [open]);
12794
+ (0, import_react19.useEffect)(
12795
+ () => () => {
12796
+ if (resetViewTimeoutRef.current) {
12797
+ clearTimeout(resetViewTimeoutRef.current);
12798
+ }
12799
+ },
12800
+ []
12801
+ );
12802
+ const handleBack = (0, import_react19.useCallback)(() => {
12803
+ setView("main");
12804
+ }, []);
12805
+ const poweredByFooter = /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12806
+ PoweredByUnifold,
12807
+ {
12808
+ color: colors2.foregroundMuted,
12809
+ className: "uf-flex uf-justify-center uf-shrink-0"
12810
+ }
12811
+ ) });
12812
+ const progressSection = paymentIntent ? (() => {
12813
+ const received = parseFloat(paymentIntent.amount_received_usd);
12814
+ const total = parseFloat(paymentIntent.amount_usd);
12815
+ const remaining = Math.max(total - received, 0);
12816
+ const pct = total > 0 ? Math.min(received / total * 100, 100) : 0;
12817
+ const hasPartial = received > 0;
12818
+ const amountStr = paymentIntent.amount_usd;
12819
+ const dynamicFontSize = `${Math.max(3.75 - amountStr.length * 0.15, 2)}rem`;
12820
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-text-center uf-py-2 uf-space-y-1", children: [
12821
+ paymentIntent.description && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12822
+ "div",
12823
+ {
12824
+ className: "uf-text-xs",
12825
+ style: {
12826
+ color: colors2.foregroundMuted,
12827
+ fontFamily: fonts.regular
12828
+ },
12829
+ children: paymentIntent.description
12830
+ }
12831
+ ),
12832
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-center", children: [
12833
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12834
+ "span",
12835
+ {
12836
+ className: "uf-mr-1",
12837
+ style: {
12838
+ fontSize: `calc(${dynamicFontSize} * 0.6)`,
12839
+ color: colors2.foregroundMuted,
12840
+ fontFamily: fonts.regular
12841
+ },
12842
+ children: "$"
12843
+ }
12844
+ ),
12845
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12846
+ "span",
12847
+ {
12848
+ style: {
12849
+ fontSize: dynamicFontSize,
12850
+ color: colors2.foreground,
12851
+ fontFamily: fonts.regular,
12852
+ lineHeight: 1.1
12853
+ },
12854
+ children: amountStr
12855
+ }
12856
+ )
12857
+ ] }),
12858
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12859
+ "div",
12860
+ {
12861
+ className: "uf-text-xs",
12862
+ style: {
12863
+ color: colors2.foregroundMuted,
12864
+ fontFamily: fonts.regular
12865
+ },
12866
+ children: paymentIntent.currency.toUpperCase()
12867
+ }
12868
+ ),
12869
+ hasPartial && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-pt-2 uf-space-y-1.5", children: [
12870
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12871
+ "div",
12872
+ {
12873
+ className: "uf-w-full uf-h-1.5 uf-rounded-full uf-overflow-hidden",
12874
+ style: { backgroundColor: colors2.border },
12875
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12876
+ "div",
12877
+ {
12878
+ className: "uf-h-full uf-rounded-full uf-transition-all uf-duration-500",
12879
+ style: {
12880
+ width: `${pct}%`,
12881
+ backgroundColor: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : colors2.primary
12882
+ }
12883
+ }
12884
+ )
12885
+ }
12886
+ ),
12887
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
12888
+ "div",
12889
+ {
12890
+ className: "uf-text-xs",
12891
+ style: {
12892
+ color: colors2.foregroundMuted,
12893
+ fontFamily: fonts.regular
12894
+ },
12895
+ children: [
12896
+ "$",
12897
+ paymentIntent.amount_received_usd,
12898
+ " / $",
12899
+ amountStr,
12900
+ " received",
12901
+ remaining > 0 && paymentIntent.status !== "succeeded" && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("span", { style: { color: colors2.foreground, fontFamily: fonts.medium }, children: [
12902
+ " ",
12903
+ "\xB7 $",
12904
+ remaining.toFixed(2),
12905
+ " remaining"
12906
+ ] })
12907
+ ]
12908
+ }
12909
+ )
12910
+ ] }),
12911
+ paymentIntent.status !== "requires_payment" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12912
+ "span",
12913
+ {
12914
+ className: "uf-text-xs uf-font-medium uf-px-2.5 uf-py-1 uf-rounded-full uf-inline-block",
12915
+ style: {
12916
+ backgroundColor: paymentIntent.status === "succeeded" ? "rgba(34, 197, 94, 0.15)" : paymentIntent.status === "processing" ? "rgba(59, 130, 246, 0.15)" : "rgba(239, 68, 68, 0.15)",
12917
+ color: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : paymentIntent.status === "processing" ? "rgb(59, 130, 246)" : "rgb(239, 68, 68)",
12918
+ fontFamily: fonts.medium
12919
+ },
12920
+ children: paymentIntent.status === "succeeded" ? "Payment Complete" : paymentIntent.status === "processing" ? "Partial Payment Received" : paymentIntent.status === "canceled" ? "Canceled" : paymentIntent.status === "expired" ? "Expired" : paymentIntent.status
12921
+ }
12922
+ ) })
12923
+ ] });
12924
+ })() : null;
12925
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(PortalContainerProvider, { value: null, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(Dialog, { open, onOpenChange: handleClose, modal: true, children: [
12926
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12927
+ DialogContent,
12928
+ {
12929
+ className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden uf-p-0 uf-overflow-visible ${view === "main" ? "!uf-top-auto !uf-h-auto !uf-max-h-[60vh] sm:!uf-max-h-none sm:!uf-top-[50%]" : "!uf-top-0 !uf-h-full sm:!uf-h-auto sm:!uf-top-[50%]"} ${themeClass}`,
12930
+ style: { backgroundColor: colors2.background },
12931
+ onPointerDownOutside: (e) => e.preventDefault(),
12932
+ onInteractOutside: (e) => e.preventDefault(),
12933
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ThemeStyleInjector, { children: view === "main" ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
12934
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12935
+ DepositHeader,
12936
+ {
12937
+ title: modalTitle || "Checkout",
12938
+ showClose: true,
12939
+ onClose: handleClose
12940
+ }
12941
+ ),
12942
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
12943
+ piLoading ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-space-y-3", children: [
12944
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12945
+ "div",
12946
+ {
12947
+ className: "uf-rounded-xl uf-p-4 uf-animate-pulse",
12948
+ style: {
12949
+ backgroundColor: components.card.backgroundColor,
12950
+ borderRadius: components.card.borderRadius,
12951
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
12952
+ },
12953
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-2", children: [
12954
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12955
+ "div",
12956
+ {
12957
+ className: "uf-h-8 uf-w-24 uf-rounded",
12958
+ style: {
12959
+ backgroundColor: components.card.borderColor
12960
+ }
12961
+ }
12962
+ ),
12963
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12964
+ "div",
12965
+ {
12966
+ className: "uf-h-4 uf-w-16 uf-rounded",
12967
+ style: {
12968
+ backgroundColor: components.card.borderColor
12969
+ }
12970
+ }
12971
+ )
12972
+ ] })
12973
+ }
12974
+ ),
12975
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SkeletonButton2, {}),
12976
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SkeletonButton2, {})
12977
+ ] }) : piError ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
12978
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react24.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
12979
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12980
+ "h3",
12981
+ {
12982
+ className: "uf-text-lg uf-font-semibold uf-mb-2",
12983
+ style: {
12984
+ color: colors2.foreground,
12985
+ fontFamily: fonts.semibold
12986
+ },
12987
+ children: "Unable to Load Checkout"
12988
+ }
12989
+ ),
12990
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12991
+ "p",
12992
+ {
12993
+ className: "uf-text-sm uf-max-w-[280px]",
12994
+ style: {
12995
+ color: colors2.foregroundMuted,
12996
+ fontFamily: fonts.regular
12997
+ },
12998
+ children: piError instanceof Error ? piError.message : "Something went wrong. Please try again."
12999
+ }
13000
+ )
13001
+ ] }) : paymentIntent ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-space-y-3", children: [
13002
+ progressSection,
13003
+ (paymentIntent.status === "requires_payment" || paymentIntent.status === "processing") && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
13004
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
13005
+ TransferCryptoButton,
13006
+ {
13007
+ onClick: () => setView("transfer"),
13008
+ title: "Transfer Crypto",
13009
+ subtitle: "Send from any wallet or exchange",
13010
+ featuredTokens: projectConfig?.transfer_crypto.networks
13011
+ }
13012
+ ),
13013
+ enableConnectWallet && !isMobileView && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
13014
+ BrowserWalletButton,
13015
+ {
13016
+ onClick: handleBrowserWalletClick,
13017
+ onConnectClick: handleWalletConnectClick,
13018
+ onDisconnect: handleWalletDisconnect,
13019
+ chainType: browserWalletChainType,
13020
+ publishableKey
13021
+ }
13022
+ )
13023
+ ] })
13024
+ ] }) : null,
13025
+ poweredByFooter
13026
+ ] })
13027
+ ] }) : view === "transfer" ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
13028
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
13029
+ DepositHeader,
13030
+ {
13031
+ title: `Pay $${remainingAmountUsd ?? paymentIntent?.amount_usd ?? ""}`,
13032
+ showBack: true,
13033
+ onBack: handleBack,
13034
+ onClose: handleClose
13035
+ }
13036
+ ),
13037
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
13038
+ paymentIntent ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
13039
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
13040
+ "div",
13041
+ {
13042
+ className: "uf-rounded-lg uf-px-3 uf-py-2 uf-flex uf-items-center uf-justify-between",
13043
+ style: {
13044
+ backgroundColor: components.card.backgroundColor,
13045
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`,
13046
+ borderRadius: components.card.borderRadius
13047
+ },
13048
+ children: [
13049
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
13050
+ "span",
13051
+ {
13052
+ className: "uf-text-xs",
13053
+ style: {
13054
+ color: colors2.foregroundMuted,
13055
+ fontFamily: fonts.regular
13056
+ },
13057
+ children: parseFloat(paymentIntent.amount_received_usd) > 0 ? `$${paymentIntent.amount_received_usd} / $${paymentIntent.amount_usd} received` : "Amount due"
13058
+ }
13059
+ ),
13060
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
13061
+ "span",
13062
+ {
13063
+ className: "uf-text-sm uf-font-semibold",
13064
+ style: {
13065
+ color: colors2.foreground,
13066
+ fontFamily: fonts.semibold
13067
+ },
13068
+ children: [
13069
+ formatCryptoAmount(remainingCrypto ?? paymentIntent.amount),
13070
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
13071
+ "span",
13072
+ {
13073
+ className: "uf-text-xs uf-font-normal uf-ml-1",
13074
+ style: { color: colors2.foregroundMuted },
13075
+ children: [
13076
+ "($",
13077
+ remainingAmountUsd ?? paymentIntent.amount_usd,
13078
+ ")"
13079
+ ]
13080
+ }
13081
+ )
13082
+ ]
13083
+ }
13084
+ )
13085
+ ]
13086
+ }
13087
+ ),
13088
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
13089
+ TransferCryptoSingleInput,
13090
+ {
13091
+ userId: paymentIntent.user_id || "",
13092
+ publishableKey,
13093
+ clientSecret,
13094
+ recipientAddress: paymentIntent.recipient_address,
13095
+ destinationChainType: paymentIntent.destination_chain_type,
13096
+ destinationChainId: paymentIntent.destination_chain_id,
13097
+ destinationTokenAddress: paymentIntent.destination_token_address,
13098
+ depositConfirmationMode: "auto_ui",
13099
+ wallets,
13100
+ onSourceTokenChange: setSelectedSource,
13101
+ checkoutQuote: sourceQuote ? {
13102
+ sourceAmount: sourceQuote.source_amount,
13103
+ sourceTokenDecimals: sourceQuote.source_token_decimals,
13104
+ sourceTokenSymbol: sourceQuote.source_token_symbol,
13105
+ sourceAmountUsd: sourceQuote.source_amount_usd
13106
+ } : null
13107
+ }
13108
+ )
13109
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SkeletonButton2, {}),
13110
+ poweredByFooter
13111
+ ] })
13112
+ ] }) : null })
13113
+ }
13114
+ ),
13115
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
13116
+ WalletSelectionModal,
13117
+ {
13118
+ open: walletSelectionModalOpen,
13119
+ onOpenChange: setWalletSelectionModalOpen,
13120
+ onWalletConnected: handleWalletConnected,
13121
+ onClose: () => setWalletSelectionModalOpen(false),
13122
+ theme: resolvedTheme
13123
+ }
13124
+ ),
13125
+ browserWalletInfo && browserWalletInfo.depositWallet && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
13126
+ BrowserWalletModal,
13127
+ {
13128
+ open: browserWalletModalOpen,
13129
+ onOpenChange: setBrowserWalletModalOpen,
13130
+ onFullClose: handleClose,
13131
+ walletInfo: browserWalletInfo,
13132
+ depositWallet: browserWalletInfo.depositWallet,
13133
+ userId: paymentIntent?.user_id || "",
13134
+ publishableKey,
13135
+ clientSecret,
13136
+ theme: resolvedTheme,
13137
+ prefillAmountUsd: remainingAmountUsd,
13138
+ checkoutAmountUsd: paymentIntent?.amount_usd,
13139
+ checkoutReceivedUsd: paymentIntent?.amount_received_usd,
13140
+ onSuccess: (txHash) => {
13141
+ onCheckoutSuccess?.({
13142
+ paymentIntentId: paymentIntent?.id || "",
13143
+ status: "processing"
13144
+ });
13145
+ },
13146
+ onError: (error) => {
13147
+ onCheckoutError?.({
13148
+ message: error.message,
13149
+ error
13150
+ });
13151
+ },
13152
+ onWalletDisconnect: handleWalletDisconnect,
13153
+ onNewDeposit: () => {
13154
+ setBrowserWalletModalOpen(false);
13155
+ setView("main");
13156
+ },
13157
+ onDone: () => {
13158
+ setBrowserWalletModalOpen(false);
13159
+ setView("main");
13160
+ },
13161
+ paymentIntentStatus: paymentIntent?.status
13162
+ }
13163
+ )
13164
+ ] }) });
13165
+ }
13166
+
13167
+ // src/components/withdrawals/WithdrawModal.tsx
13168
+ var import_react23 = require("react");
13169
+ var import_lucide_react27 = require("lucide-react");
13170
+
13171
+ // src/hooks/use-supported-destination-tokens.ts
13172
+ var import_react_query11 = require("@tanstack/react-query");
13173
+ var import_core26 = require("@unifold/core");
13174
+ function useSupportedDestinationTokens(publishableKey, enabled = true) {
13175
+ return (0, import_react_query11.useQuery)({
13176
+ queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
13177
+ queryFn: () => (0, import_core26.getSupportedDestinationTokens)(publishableKey),
13178
+ staleTime: 1e3 * 60 * 5,
13179
+ gcTime: 1e3 * 60 * 30,
13180
+ refetchOnMount: false,
13181
+ refetchOnWindowFocus: false,
13182
+ enabled
13183
+ });
13184
+ }
13185
+
13186
+ // src/hooks/use-source-token-validation.ts
13187
+ var import_react_query12 = require("@tanstack/react-query");
13188
+ var import_core27 = require("@unifold/core");
13189
+ function useSourceTokenValidation(params) {
13190
+ const {
13191
+ sourceChainType,
13192
+ sourceChainId,
13193
+ sourceTokenAddress,
13194
+ sourceTokenSymbol,
13195
+ publishableKey,
13196
+ enabled = true
13197
+ } = params;
13198
+ const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
13199
+ return (0, import_react_query12.useQuery)({
13200
+ queryKey: [
13201
+ "unifold",
13202
+ "sourceTokenValidation",
13203
+ sourceChainType ?? null,
13204
+ sourceChainId ?? null,
13205
+ sourceTokenAddress ?? null,
13206
+ publishableKey
13207
+ ],
13208
+ queryFn: async () => {
13209
+ const res = await (0, import_core27.getSupportedDepositTokens)(publishableKey);
13210
+ let matchedMinUsd = null;
13211
+ let matchedProcessingTime = null;
13212
+ let matchedSlippage = null;
13213
+ let matchedPriceImpact = null;
13214
+ const found = res.data.some(
13215
+ (token) => token.chains.some((chain) => {
13216
+ const match = chain.chain_type === sourceChainType && chain.chain_id === sourceChainId && chain.token_address.toLowerCase() === sourceTokenAddress.toLowerCase();
13217
+ if (match) {
13218
+ matchedMinUsd = chain.minimum_deposit_amount_usd;
13219
+ matchedProcessingTime = chain.estimated_processing_time;
13220
+ matchedSlippage = chain.max_slippage_percent;
13221
+ matchedPriceImpact = chain.estimated_price_impact_percent;
13222
+ }
13223
+ return match;
13224
+ })
13225
+ );
13226
+ return {
13227
+ isSupported: found,
13228
+ minimumAmountUsd: matchedMinUsd,
13229
+ estimatedProcessingTime: matchedProcessingTime,
13230
+ maxSlippagePercent: matchedSlippage,
13231
+ priceImpactPercent: matchedPriceImpact,
13232
+ errorMessage: found ? null : `${sourceTokenSymbol || "Source token"} is not a supported withdrawal token. Supported tokens include USDC, USDT, and other stablecoins.`
13233
+ };
13234
+ },
13235
+ enabled: enabled && hasParams,
13236
+ staleTime: 1e3 * 60 * 5,
13237
+ gcTime: 1e3 * 60 * 30,
13238
+ refetchOnMount: false,
13239
+ refetchOnWindowFocus: false
13240
+ });
13241
+ }
13242
+
13243
+ // src/hooks/use-address-balance.ts
13244
+ var import_react_query13 = require("@tanstack/react-query");
13245
+ var import_core28 = require("@unifold/core");
13246
+ function useAddressBalance(params) {
13247
+ const {
13248
+ address,
13249
+ chainType,
13250
+ chainId,
13251
+ tokenAddress,
13252
+ publishableKey,
13253
+ enabled = true
13254
+ } = params;
13255
+ const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
13256
+ return (0, import_react_query13.useQuery)({
13257
+ queryKey: [
13258
+ "unifold",
13259
+ "addressBalance",
13260
+ address ?? null,
13261
+ chainType ?? null,
13262
+ chainId ?? null,
13263
+ tokenAddress ?? null,
13264
+ publishableKey
13265
+ ],
13266
+ queryFn: async () => {
13267
+ const res = await (0, import_core28.getAddressBalance)(
13268
+ address,
13269
+ chainType,
13270
+ chainId,
13271
+ tokenAddress,
13272
+ publishableKey
13273
+ );
13274
+ if (res.balance) {
13275
+ const decimals = res.balance.token?.decimals ?? 6;
13276
+ const symbol = res.balance.token?.symbol ?? "";
13277
+ const baseUnit = res.balance.amount;
13278
+ const raw = BigInt(baseUnit);
13279
+ const divisor = BigInt(10 ** decimals);
13280
+ const whole = raw / divisor;
13281
+ const frac = raw % divisor;
13282
+ const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
13283
+ const balanceHuman = fracStr ? `${whole}.${fracStr}` : whole.toString();
13284
+ return {
13285
+ balanceBaseUnit: baseUnit,
13286
+ balanceHuman,
13287
+ balanceUsd: res.balance.amount_usd,
13288
+ exchangeRate: res.balance.exchange_rate,
13289
+ decimals,
13290
+ symbol
13291
+ };
13292
+ }
13293
+ return { balanceBaseUnit: "0", balanceHuman: "0", balanceUsd: "0", exchangeRate: null, decimals: 6, symbol: "" };
13294
+ },
13295
+ enabled: enabled && hasParams,
13296
+ staleTime: 1e3 * 30,
13297
+ gcTime: 1e3 * 60 * 5,
13298
+ refetchInterval: 1e3 * 30,
13299
+ refetchOnMount: "always",
13300
+ refetchOnWindowFocus: false
13301
+ });
13302
+ }
13303
+
13304
+ // src/hooks/use-executions.ts
13305
+ var import_react_query14 = require("@tanstack/react-query");
13306
+ var import_core29 = require("@unifold/core");
13307
+ function useExecutions(userId, publishableKey, options) {
13308
+ const actionType = options?.actionType ?? import_core29.ActionType.Deposit;
13309
+ return (0, import_react_query14.useQuery)({
13310
+ queryKey: ["unifold", "executions", actionType, userId, publishableKey],
13311
+ queryFn: () => (0, import_core29.queryExecutions)(userId, publishableKey, actionType),
13312
+ enabled: (options?.enabled ?? true) && !!userId,
13313
+ refetchInterval: options?.refetchInterval ?? 3e3,
13314
+ staleTime: 0,
13315
+ gcTime: 1e3 * 60 * 5,
13316
+ refetchOnWindowFocus: false
13317
+ });
13318
+ }
13319
+
13320
+ // src/hooks/use-withdraw-polling.ts
13321
+ var import_react20 = require("react");
13322
+ var import_core30 = require("@unifold/core");
13323
+ var POLL_INTERVAL_MS2 = 2500;
13324
+ var POLL_ENDPOINT_INTERVAL_MS2 = 3e3;
13325
+ var CUTOFF_BUFFER_MS2 = 6e4;
13326
+ function useWithdrawPolling({
13327
+ userId,
13328
+ publishableKey,
13329
+ depositWalletId,
13330
+ enabled = false,
13331
+ onWithdrawSuccess,
13332
+ onWithdrawError
13333
+ }) {
13334
+ const [executions, setExecutions] = (0, import_react20.useState)([]);
13335
+ const [isPolling, setIsPolling] = (0, import_react20.useState)(false);
13336
+ const enabledAtRef = (0, import_react20.useRef)(/* @__PURE__ */ new Date());
13337
+ const trackedRef = (0, import_react20.useRef)(/* @__PURE__ */ new Map());
13338
+ const prevEnabledRef = (0, import_react20.useRef)(false);
13339
+ const onSuccessRef = (0, import_react20.useRef)(onWithdrawSuccess);
13340
+ const onErrorRef = (0, import_react20.useRef)(onWithdrawError);
13341
+ (0, import_react20.useEffect)(() => {
13342
+ onSuccessRef.current = onWithdrawSuccess;
13343
+ }, [onWithdrawSuccess]);
13344
+ (0, import_react20.useEffect)(() => {
13345
+ onErrorRef.current = onWithdrawError;
13346
+ }, [onWithdrawError]);
13347
+ (0, import_react20.useEffect)(() => {
13348
+ if (enabled && !prevEnabledRef.current) {
13349
+ enabledAtRef.current = /* @__PURE__ */ new Date();
13350
+ trackedRef.current.clear();
13351
+ }
13352
+ if (!enabled) {
13353
+ trackedRef.current.clear();
13354
+ }
13355
+ prevEnabledRef.current = enabled;
13356
+ }, [enabled]);
13357
+ (0, import_react20.useEffect)(() => {
13358
+ if (!userId || !enabled) return;
13359
+ const enabledAt = enabledAtRef.current;
13360
+ const poll = async () => {
13361
+ try {
13362
+ const response = await (0, import_core30.queryExecutions)(userId, publishableKey, import_core30.ActionType.Withdraw);
13363
+ const cutoff = new Date(enabledAt.getTime() - CUTOFF_BUFFER_MS2);
13364
+ const sorted = [...response.data].sort((a, b) => {
13365
+ const tA = a.created_at ? new Date(a.created_at).getTime() : 0;
13366
+ const tB = b.created_at ? new Date(b.created_at).getTime() : 0;
13367
+ return tB - tA;
13368
+ });
13369
+ const inProgress = [import_core30.ExecutionStatus.PENDING, import_core30.ExecutionStatus.WAITING, import_core30.ExecutionStatus.DELAYED];
13370
+ const terminal = [import_core30.ExecutionStatus.SUCCEEDED, import_core30.ExecutionStatus.FAILED];
13371
+ let target = null;
13372
+ for (const ex of sorted) {
13373
+ const t11 = ex.created_at ? new Date(ex.created_at) : null;
13374
+ if (!t11 || t11 < cutoff) continue;
13375
+ const prev = trackedRef.current.get(ex.id);
13376
+ if (!prev) {
13377
+ target = ex;
13378
+ break;
13379
+ }
13380
+ if (inProgress.includes(prev) && terminal.includes(ex.status)) {
13381
+ target = ex;
13382
+ break;
13383
+ }
13384
+ }
13385
+ if (target) {
13386
+ const ex = target;
13387
+ const exTime = ex.created_at ? new Date(ex.created_at) : null;
13388
+ if (!exTime || exTime < enabledAtRef.current) return;
13389
+ const prev = trackedRef.current.get(ex.id);
13390
+ trackedRef.current.set(ex.id, ex.status);
13391
+ setExecutions((list) => {
13392
+ const idx = list.findIndex((e) => e.id === ex.id);
13393
+ if (idx >= 0) {
13394
+ const u = [...list];
13395
+ u[idx] = ex;
13396
+ return u;
13397
+ }
13398
+ return [...list, ex];
13399
+ });
13400
+ if (ex.status === import_core30.ExecutionStatus.SUCCEEDED && (!prev || inProgress.includes(prev))) {
13401
+ onSuccessRef.current?.({ message: "Withdrawal completed successfully", executionId: ex.id, transaction: ex });
13402
+ } else if (ex.status === import_core30.ExecutionStatus.FAILED && prev !== import_core30.ExecutionStatus.FAILED) {
13403
+ onErrorRef.current?.({ message: "Withdrawal failed", code: "WITHDRAW_FAILED", error: ex });
13404
+ }
13405
+ }
13406
+ } catch (error) {
13407
+ console.error("Failed to fetch withdraw executions:", error);
13408
+ onErrorRef.current?.({ message: "Failed to fetch withdrawal status", code: "POLLING_ERROR", error });
13409
+ }
13410
+ };
13411
+ void poll();
13412
+ const interval = setInterval(poll, POLL_INTERVAL_MS2);
13413
+ setIsPolling(true);
13414
+ return () => {
13415
+ clearInterval(interval);
13416
+ setIsPolling(false);
13417
+ };
13418
+ }, [userId, publishableKey, enabled]);
13419
+ (0, import_react20.useEffect)(() => {
13420
+ if (!enabled || !depositWalletId) return;
13421
+ const trigger = async () => {
13422
+ try {
13423
+ await (0, import_core30.pollDirectExecutions)({ deposit_wallet_id: depositWalletId }, publishableKey);
13424
+ } catch {
13425
+ }
13426
+ };
13427
+ trigger();
13428
+ const interval = setInterval(trigger, POLL_ENDPOINT_INTERVAL_MS2);
13429
+ return () => clearInterval(interval);
13430
+ }, [enabled, depositWalletId, publishableKey]);
13431
+ return { executions, isPolling };
13432
+ }
13433
+
13434
+ // src/components/withdrawals/WithdrawDoubleInput.tsx
13435
+ var import_jsx_runtime53 = require("react/jsx-runtime");
13436
+ var t7 = i18n.withdrawModal;
13437
+ var getChainKey4 = (chainId, chainType) => `${chainType}:${chainId}`;
13438
+ function WithdrawDoubleInput({
13439
+ tokens,
13440
+ selectedTokenSymbol,
13441
+ selectedChainKey,
13442
+ onTokenChange,
13443
+ onChainChange,
13444
+ isLoading = false
13445
+ }) {
13446
+ const { fonts, components } = useTheme();
13447
+ const isDarkMode = useTheme().themeClass.includes("uf-dark");
13448
+ const selectedToken = selectedTokenSymbol ? tokens.find((t11) => t11.symbol === selectedTokenSymbol) : void 0;
13449
+ const availableChainsForToken = selectedToken?.chains || [];
13450
+ const renderTokenItem = (tokenData) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13451
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13452
+ "img",
13453
+ {
13454
+ src: tokenData.icon_url,
13455
+ alt: tokenData.symbol,
13456
+ width: 20,
13457
+ height: 20,
13458
+ loading: "lazy",
13459
+ className: "uf-rounded-full uf-flex-shrink-0"
13460
+ }
13461
+ ),
13462
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: tokenData.symbol })
13463
+ ] });
13464
+ const renderChainItem = (chainData) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13465
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13466
+ "img",
13467
+ {
13468
+ src: chainData.icon_url,
13469
+ alt: chainData.chain_name,
13470
+ width: 20,
13471
+ height: 20,
13472
+ loading: "lazy",
13473
+ className: "uf-rounded-full uf-flex-shrink-0"
13474
+ }
13475
+ ),
13476
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: chainData.chain_name })
13477
+ ] });
13478
+ const currentChainData = selectedChainKey ? availableChainsForToken.find(
13479
+ (c) => getChainKey4(c.chain_id, c.chain_type) === selectedChainKey
13480
+ ) : void 0;
13481
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-grid uf-grid-cols-2 uf-gap-2.5", children: [
13482
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
13483
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13484
+ "div",
13485
+ {
13486
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
13487
+ style: { color: components.card.labelColor },
13488
+ children: t7.receiveToken
13489
+ }
13490
+ ),
13491
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
13492
+ Select,
13493
+ {
13494
+ value: selectedTokenSymbol ?? "",
13495
+ onValueChange: onTokenChange,
13496
+ disabled: isLoading || tokens.length === 0,
13497
+ children: [
13498
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13499
+ SelectTrigger,
13500
+ {
13501
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
13502
+ style: {
13503
+ backgroundColor: components.card.backgroundColor,
13504
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
13505
+ },
13506
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(SelectValue, { children: isLoading || !selectedTokenSymbol ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: selectedTokenSymbol }) })
13507
+ }
13508
+ ),
13509
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13510
+ SelectContent,
13511
+ {
13512
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]",
13513
+ style: {
13514
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
13515
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
13516
+ },
13517
+ children: tokens.map((tokenData) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13518
+ SelectItem,
13519
+ {
13520
+ value: tokenData.symbol,
13521
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
13522
+ children: renderTokenItem(tokenData)
13523
+ },
13524
+ tokenData.symbol
13525
+ ))
13526
+ }
13527
+ )
13528
+ ]
13529
+ }
13530
+ )
13531
+ ] }),
13532
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
13533
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13534
+ "div",
13535
+ {
13536
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
13537
+ style: { color: components.card.labelColor },
13538
+ children: t7.receiveChain
13539
+ }
13540
+ ),
13541
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
13542
+ Select,
13543
+ {
13544
+ value: selectedChainKey ?? "",
13545
+ onValueChange: onChainChange,
13546
+ disabled: isLoading || availableChainsForToken.length === 0,
13547
+ children: [
13548
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13549
+ SelectTrigger,
13550
+ {
13551
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
13552
+ style: {
13553
+ backgroundColor: components.card.backgroundColor,
13554
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
13555
+ },
13556
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(SelectValue, { children: isLoading || !selectedChainKey ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: selectedChainKey }) })
13557
+ }
13558
+ ),
13559
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13560
+ SelectContent,
13561
+ {
13562
+ align: "end",
13563
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
13564
+ style: {
13565
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
13566
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
13567
+ },
13568
+ children: availableChainsForToken.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uf-px-2 uf-py-3 uf-text-xs uf-text-muted-foreground uf-text-center", children: "No chains available" }) : availableChainsForToken.map((chainData) => {
13569
+ const chainKey = getChainKey4(chainData.chain_id, chainData.chain_type);
13570
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13571
+ SelectItem,
13572
+ {
13573
+ value: chainKey,
13574
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
13575
+ children: renderChainItem(chainData)
13576
+ },
13577
+ chainKey
13578
+ );
13579
+ })
13580
+ }
13581
+ )
13582
+ ]
13583
+ }
13584
+ )
13585
+ ] })
13586
+ ] });
13587
+ }
13588
+
13589
+ // src/components/withdrawals/WithdrawForm.tsx
13590
+ var import_react21 = require("react");
13591
+ var import_lucide_react25 = require("lucide-react");
13592
+
13593
+ // src/hooks/use-verify-recipient-address.ts
13594
+ var import_react_query15 = require("@tanstack/react-query");
13595
+ var import_core31 = require("@unifold/core");
13596
+ function useVerifyRecipientAddress(params) {
13597
+ const {
13598
+ chainType,
13599
+ chainId,
13600
+ tokenAddress,
13601
+ recipientAddress,
13602
+ publishableKey,
13603
+ enabled = true
13604
+ } = params;
13605
+ const trimmedAddress = recipientAddress?.trim() || "";
13606
+ const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
13607
+ return (0, import_react_query15.useQuery)({
13608
+ queryKey: [
13609
+ "unifold",
13610
+ "verifyRecipientAddress",
13611
+ chainType ?? null,
13612
+ chainId ?? null,
13613
+ tokenAddress ?? null,
13614
+ trimmedAddress,
13615
+ publishableKey
13616
+ ],
13617
+ queryFn: () => (0, import_core31.verifyRecipientAddress)(
13618
+ {
13619
+ chain_type: chainType,
13620
+ chain_id: chainId,
13621
+ token_address: tokenAddress,
13622
+ recipient_address: trimmedAddress
13623
+ },
13624
+ publishableKey
13625
+ ),
13626
+ enabled: enabled && hasAllParams,
13627
+ staleTime: 1e3 * 60 * 5,
13628
+ gcTime: 1e3 * 60 * 30,
13629
+ retry: 1,
13630
+ refetchOnMount: false,
13631
+ refetchOnWindowFocus: false
13632
+ });
13633
+ }
13634
+
13635
+ // src/components/withdrawals/send-withdraw.ts
13636
+ var import_core32 = require("@unifold/core");
13637
+ async function sendEvmWithdraw(params) {
13638
+ const {
13639
+ provider,
13640
+ fromAddress,
13641
+ depositWalletAddress,
13642
+ sourceTokenAddress,
13643
+ sourceChainId,
13644
+ amountBaseUnit
13645
+ } = params;
13646
+ const currentChainIdHex = await provider.request({
13647
+ method: "eth_chainId",
13648
+ params: []
13649
+ });
13650
+ const currentChainId = parseInt(currentChainIdHex, 16).toString();
13651
+ if (currentChainId !== sourceChainId) {
13652
+ const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
13653
+ try {
13654
+ await provider.request({
13655
+ method: "wallet_switchEthereumChain",
13656
+ params: [{ chainId: requiredHex }]
13657
+ });
13658
+ const newHex = await provider.request({ method: "eth_chainId", params: [] });
13659
+ if (parseInt(newHex, 16).toString() !== sourceChainId) {
13660
+ throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
13661
+ }
13662
+ } catch (err) {
13663
+ if (err && typeof err === "object" && "code" in err) {
13664
+ const e = err;
13665
+ if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
13666
+ if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
13667
+ }
13668
+ throw err;
13669
+ }
13670
+ }
13671
+ const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
13672
+ const amountBig = BigInt(amountBaseUnit);
13673
+ const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
13674
+ from: fromAddress,
13675
+ to: sourceTokenAddress,
13676
+ data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
13677
+ };
13678
+ let gasEstimate;
13679
+ try {
13680
+ const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
13681
+ gasEstimate = BigInt(hex);
13682
+ } catch {
13683
+ gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
13684
+ }
13685
+ const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
13686
+ const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
13687
+ const gasCost = gasWithBuffer * gasPrice;
13688
+ const ethBalance = BigInt(
13689
+ await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
13690
+ );
13691
+ const totalRequired = isNative ? gasCost + amountBig : gasCost;
13692
+ if (ethBalance < totalRequired) {
13693
+ const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
13694
+ if (isNative) {
13695
+ throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
13696
+ }
13697
+ throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
13698
+ }
13699
+ const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
13700
+ return txHash;
13701
+ }
13702
+ async function sendSolanaWithdraw(params) {
13703
+ const {
13704
+ provider,
13705
+ fromAddress,
13706
+ depositWalletAddress,
13707
+ sourceTokenAddress,
13708
+ amountBaseUnit,
13709
+ publishableKey
13710
+ } = params;
13711
+ if (!provider.publicKey) {
13712
+ await provider.connect();
13713
+ }
13714
+ const buildResponse = await (0, import_core32.buildSolanaTransaction)(
13715
+ {
13716
+ chain_id: "mainnet",
13717
+ token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
13718
+ source_address: fromAddress,
13719
+ destination_address: depositWalletAddress,
13720
+ amount: amountBaseUnit
13721
+ },
13722
+ publishableKey
13723
+ );
13724
+ const { VersionedTransaction } = await import(
13725
+ /* @vite-ignore */
13726
+ "@solana/web3.js"
13727
+ );
13728
+ const binaryString = atob(buildResponse.transaction);
13729
+ const bytes = new Uint8Array(binaryString.length);
13730
+ for (let i = 0; i < binaryString.length; i++) {
13731
+ bytes[i] = binaryString.charCodeAt(i);
13732
+ }
13733
+ const transaction = VersionedTransaction.deserialize(bytes);
13734
+ const signedTransaction = await provider.signTransaction(transaction);
13735
+ const serialized = signedTransaction.serialize();
13736
+ let binaryStr = "";
13737
+ for (let i = 0; i < serialized.length; i++) {
13738
+ binaryStr += String.fromCharCode(serialized[i]);
13739
+ }
13740
+ const sendResponse = await (0, import_core32.sendSolanaTransaction)(
13741
+ { chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
13742
+ publishableKey
13743
+ );
13744
+ return sendResponse.signature;
13745
+ }
13746
+ var HYPERCORE_CHAIN_ID = "1337";
13747
+ var HYPERCORE_SPOT_USDC_ADDRESS = "0x6d1e7cde53ba9467b783cb7c530ce054";
13748
+ function isHypercoreChain(chainId) {
13749
+ return chainId === HYPERCORE_CHAIN_ID;
13750
+ }
13751
+ async function sendHypercoreWithdraw(params) {
13752
+ const {
13753
+ provider,
13754
+ fromAddress,
13755
+ depositWalletAddress,
13756
+ sourceTokenAddress,
13757
+ amount,
13758
+ tokenSymbol,
13759
+ publishableKey
13760
+ } = params;
13761
+ const isSpot = sourceTokenAddress.toLowerCase() === HYPERCORE_SPOT_USDC_ADDRESS;
13762
+ const currentChainHex = await provider.request({
13763
+ method: "eth_chainId",
13764
+ params: []
13765
+ });
13766
+ const activeChainId = String(parseInt(currentChainHex, 16));
13767
+ const buildResult = await (0, import_core32.buildHypercoreTransaction)(
13768
+ {
13769
+ action_type: isSpot ? "spot_send" : "usd_send",
13770
+ signature_chain_type: "ethereum",
13771
+ signature_chain_id: activeChainId,
13772
+ recipient_address: depositWalletAddress,
13773
+ token_address: sourceTokenAddress,
13774
+ token_symbol: tokenSymbol || void 0,
13775
+ amount
13776
+ },
13777
+ publishableKey
13778
+ );
13779
+ const signature = await provider.request({
13780
+ method: "eth_signTypedData_v4",
13781
+ params: [fromAddress, JSON.stringify(buildResult.typed_data)]
13782
+ });
13783
+ await (0, import_core32.sendHypercoreTransaction)(
13784
+ {
13785
+ action_payload: buildResult.action_payload,
13786
+ signature,
13787
+ nonce: buildResult.nonce
13788
+ },
13789
+ publishableKey
13790
+ );
13791
+ }
13792
+ async function detectBrowserWallet(chainType, senderAddress) {
13793
+ const win = typeof window !== "undefined" ? window : null;
13794
+ if (!win || !senderAddress) return null;
13795
+ const anyWin = win;
13796
+ if (chainType === "solana") {
13797
+ const solProviders = [];
13798
+ if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
13799
+ if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
13800
+ if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
13801
+ if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
13802
+ for (const { provider, name } of solProviders) {
13803
+ if (!provider) continue;
13804
+ try {
13805
+ let addr;
13806
+ if (provider.isConnected && provider.publicKey) {
13807
+ addr = provider.publicKey.toString();
13808
+ } else {
13809
+ const resp = await provider.connect({ onlyIfTrusted: true });
13810
+ if (resp?.publicKey) addr = resp.publicKey.toString();
13811
+ }
13812
+ if (addr && addr === senderAddress) {
13813
+ return { chainFamily: "solana", provider, name, address: addr };
13814
+ }
13815
+ } catch {
13816
+ }
13817
+ }
13818
+ }
13819
+ if (chainType === "ethereum") {
13820
+ const evmProviders = [];
13821
+ const seen = /* @__PURE__ */ new Set();
13822
+ const add = (p, name) => {
13823
+ if (p && typeof p.request === "function" && !seen.has(p)) {
13824
+ seen.add(p);
13825
+ evmProviders.push({ provider: p, name });
13826
+ }
13827
+ };
13828
+ add(anyWin.phantom?.ethereum, "Phantom");
13829
+ add(anyWin.coinbaseWalletExtension, "Coinbase");
13830
+ add(anyWin.trustwallet?.ethereum, "Trust Wallet");
13831
+ add(anyWin.okxwallet, "OKX Wallet");
13832
+ if (anyWin.__eip6963Providers) {
13833
+ for (const detail of anyWin.__eip6963Providers) {
13834
+ const rdns = detail.info?.rdns || "";
13835
+ let name = detail.info?.name || "Wallet";
13836
+ if (rdns.includes("metamask")) name = "MetaMask";
13837
+ else if (rdns.includes("rabby")) name = "Rabby";
13838
+ else if (rdns.includes("rainbow")) name = "Rainbow";
13839
+ add(detail.provider, name);
13840
+ }
13841
+ }
13842
+ if (win.ethereum) {
13843
+ const eth = win.ethereum;
13844
+ let name = "Wallet";
13845
+ if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
13846
+ else if (eth.isRabby) name = "Rabby";
13847
+ else if (eth.isRainbow) name = "Rainbow";
13848
+ else if (eth.isCoinbaseWallet) name = "Coinbase";
13849
+ add(eth, name);
13850
+ }
13851
+ for (const { provider, name } of evmProviders) {
13852
+ try {
13853
+ const accounts = await provider.request({ method: "eth_accounts" });
13854
+ if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
13855
+ return { chainFamily: "evm", provider, name, address: accounts[0] };
13856
+ }
13857
+ } catch {
13858
+ }
13859
+ }
13860
+ }
13861
+ return null;
13862
+ }
13863
+
13864
+ // src/components/withdrawals/WithdrawForm.tsx
13865
+ var import_jsx_runtime54 = require("react/jsx-runtime");
13866
+ var t8 = i18n.withdrawModal;
13867
+ var tCrypto = i18n.transferCrypto;
13868
+ function formatProcessingTime2(seconds) {
13869
+ if (seconds === null) {
13870
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
13871
+ }
13872
+ const minutes = Math.ceil(seconds / 60);
13873
+ if (minutes < 60) {
13874
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", String(minutes));
13875
+ }
13876
+ const hours = Math.ceil(minutes / 60);
13877
+ return tCrypto.processingTime.lessThanHours.replace("{{hours}}", String(hours));
13878
+ }
13879
+ function computeBaseUnit(balanceBaseUnit, inputAmount, balanceAmount) {
13880
+ if (balanceAmount <= 0 || inputAmount <= 0) return "0";
13881
+ if (inputAmount >= balanceAmount) return balanceBaseUnit;
13882
+ const PRECISION = 10n ** 18n;
13883
+ const ratioScaled = BigInt(Math.round(inputAmount / balanceAmount * Number(PRECISION)));
13884
+ const result = BigInt(balanceBaseUnit) * ratioScaled / PRECISION;
13885
+ return result.toString();
13886
+ }
13887
+ function toSafeDecimalString(n, maxDecimals) {
13888
+ if (n === 0) return "0";
13889
+ return n.toFixed(maxDecimals).replace(/\.?0+$/, "");
13890
+ }
13891
+ function WithdrawForm({
13892
+ publishableKey,
13893
+ externalUserId,
13894
+ sourceChainType,
13895
+ selectedToken,
13896
+ selectedChain,
13897
+ sourceTokenSymbol,
13898
+ recipientAddressProp,
13899
+ balanceData,
13900
+ isLoadingBalance,
13901
+ minimumWithdrawAmountUsd,
13902
+ estimatedProcessingTime,
13903
+ maxSlippagePercent,
13904
+ priceImpactPercent,
13905
+ detectedWallet,
13906
+ sourceChainId,
13907
+ sourceTokenAddress,
13908
+ isWalletMatch,
13909
+ connectedWalletName,
13910
+ canWithdraw,
13911
+ onWithdraw,
13912
+ onWithdrawError,
13913
+ onDepositWalletCreation,
13914
+ onWithdrawSubmitted,
13915
+ footerLeft
13916
+ }) {
13917
+ const { colors: colors2, fonts, components } = useTheme();
13918
+ const [recipientAddress, setRecipientAddress] = (0, import_react21.useState)(recipientAddressProp || "");
13919
+ const [amount, setAmount] = (0, import_react21.useState)("");
13920
+ const [inputUnit, setInputUnit] = (0, import_react21.useState)("crypto");
13921
+ const [isSubmitting, setIsSubmitting] = (0, import_react21.useState)(false);
13922
+ const [submitError, setSubmitError] = (0, import_react21.useState)(null);
13923
+ const [detailsExpanded, setDetailsExpanded] = (0, import_react21.useState)(false);
13924
+ const [glossaryOpen, setGlossaryOpen] = (0, import_react21.useState)(false);
13925
+ (0, import_react21.useEffect)(() => {
13926
+ setRecipientAddress(recipientAddressProp || "");
13927
+ setAmount("");
13928
+ setInputUnit("crypto");
13929
+ setSubmitError(null);
13930
+ }, [recipientAddressProp]);
13931
+ const trimmedAddress = recipientAddress.trim();
13932
+ const [debouncedAddress, setDebouncedAddress] = (0, import_react21.useState)(trimmedAddress);
13933
+ (0, import_react21.useEffect)(() => {
13934
+ const id = setTimeout(() => setDebouncedAddress(trimmedAddress), 500);
13935
+ return () => clearTimeout(id);
13936
+ }, [trimmedAddress]);
13937
+ const {
13938
+ data: addressVerification,
13939
+ isLoading: isVerifyingAddress,
13940
+ error: verifyError
13941
+ } = useVerifyRecipientAddress({
13942
+ chainType: selectedChain?.chain_type,
13943
+ chainId: selectedChain?.chain_id,
13944
+ tokenAddress: selectedChain?.token_address,
13945
+ recipientAddress: debouncedAddress,
13946
+ publishableKey,
13947
+ enabled: debouncedAddress.length > 5 && !!selectedChain
13948
+ });
13949
+ const isDebouncing = trimmedAddress !== debouncedAddress;
13950
+ const addressError = (0, import_react21.useMemo)(() => {
13951
+ if (!trimmedAddress || trimmedAddress.length <= 5) return null;
13952
+ if (isDebouncing || isVerifyingAddress) return null;
13953
+ if (verifyError) return t8.invalidAddress;
13954
+ if (addressVerification && !addressVerification.valid) {
13955
+ if (addressVerification.failure_code === "account_not_found")
13956
+ return `Account not found on ${selectedChain?.chain_name}`;
13957
+ if (addressVerification.failure_code === "not_opted_in")
13958
+ return `Recipient has not opted in to ${selectedToken?.symbol} on ${selectedChain?.chain_name}`;
13959
+ return t8.invalidAddress;
13960
+ }
13961
+ return null;
13962
+ }, [trimmedAddress, isDebouncing, isVerifyingAddress, verifyError, addressVerification, selectedChain, selectedToken]);
13963
+ const isAddressValid = !isDebouncing && !!addressVerification?.valid && !addressError;
13964
+ const exchangeRate = (0, import_react21.useMemo)(() => {
13965
+ if (!balanceData?.exchangeRate) return 0;
13966
+ return parseFloat(balanceData.exchangeRate);
13967
+ }, [balanceData]);
13968
+ const balanceCrypto = (0, import_react21.useMemo)(() => {
13969
+ if (!balanceData?.balanceHuman) return 0;
13970
+ return parseFloat(balanceData.balanceHuman);
13971
+ }, [balanceData]);
13972
+ const balanceUsdNum = (0, import_react21.useMemo)(() => {
13973
+ if (!balanceData?.balanceUsd) return 0;
13974
+ return parseFloat(balanceData.balanceUsd);
13975
+ }, [balanceData]);
13976
+ const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
13977
+ const sourceDecimals = balanceData?.decimals ?? 6;
13978
+ const cryptoAmountFromInput = (0, import_react21.useMemo)(() => {
13979
+ const val = parseFloat(amount);
13980
+ if (!val || val <= 0) return 0;
13981
+ if (inputUnit === "crypto") return val;
13982
+ return exchangeRate > 0 ? val / exchangeRate : 0;
13983
+ }, [amount, inputUnit, exchangeRate]);
13984
+ const fiatAmountFromInput = (0, import_react21.useMemo)(() => {
13985
+ const val = parseFloat(amount);
13986
+ if (!val || val <= 0) return 0;
13987
+ if (inputUnit === "fiat") return val;
13988
+ return val * exchangeRate;
13989
+ }, [amount, inputUnit, exchangeRate]);
13990
+ const convertedDisplay = (0, import_react21.useMemo)(() => {
13991
+ if (!amount || parseFloat(amount) <= 0) return null;
13992
+ if (inputUnit === "crypto") {
13993
+ return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
13994
+ }
13995
+ return `${cryptoAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 6 })} ${tokenSymbol}`;
13996
+ }, [amount, inputUnit, fiatAmountFromInput, cryptoAmountFromInput, tokenSymbol]);
13997
+ const balanceDisplay = (0, import_react21.useMemo)(() => {
13998
+ if (isLoadingBalance || !balanceData) return null;
13999
+ if (inputUnit === "crypto") {
14000
+ return `${balanceCrypto.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${tokenSymbol}`;
14001
+ }
14002
+ return `$${balanceUsdNum.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
14003
+ }, [isLoadingBalance, balanceData, inputUnit, balanceCrypto, balanceUsdNum, tokenSymbol]);
14004
+ const handleSwitchUnit = (0, import_react21.useCallback)(() => {
14005
+ const val = parseFloat(amount);
14006
+ if (!val || val <= 0 || exchangeRate <= 0) {
14007
+ setInputUnit((u) => u === "crypto" ? "fiat" : "crypto");
14008
+ setAmount("");
14009
+ return;
14010
+ }
14011
+ if (inputUnit === "crypto") {
14012
+ const fiat = val * exchangeRate;
14013
+ setAmount(fiat.toFixed(2));
14014
+ setInputUnit("fiat");
14015
+ } else {
14016
+ const crypto = val / exchangeRate;
14017
+ setAmount(crypto.toFixed(sourceDecimals > 6 ? 6 : sourceDecimals));
14018
+ setInputUnit("crypto");
14019
+ }
14020
+ }, [amount, inputUnit, exchangeRate, sourceDecimals]);
14021
+ const handleMaxClick = (0, import_react21.useCallback)(() => {
14022
+ if (inputUnit === "crypto") {
14023
+ if (balanceCrypto <= 0) return;
14024
+ setAmount(balanceData?.balanceHuman ?? "0");
14025
+ } else {
14026
+ if (balanceUsdNum <= 0) return;
14027
+ setAmount((Math.floor(balanceUsdNum * 100) / 100).toFixed(2));
14028
+ }
14029
+ }, [inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
14030
+ const isBelowMinimum = minimumWithdrawAmountUsd !== null && fiatAmountFromInput > 0 && fiatAmountFromInput < minimumWithdrawAmountUsd;
14031
+ const isOverBalance = inputUnit === "crypto" ? cryptoAmountFromInput > 0 && balanceCrypto > 0 && cryptoAmountFromInput > balanceCrypto : fiatAmountFromInput > 0 && balanceUsdNum > 0 && fiatAmountFromInput > balanceUsdNum;
14032
+ const isFormValid = trimmedAddress.length > 0 && amount.trim().length > 0 && cryptoAmountFromInput > 0 && isAddressValid && !isBelowMinimum && !isOverBalance && !!balanceData;
14033
+ const handleWithdraw = (0, import_react21.useCallback)(async () => {
14034
+ if (!selectedToken || !selectedChain) return;
14035
+ if (!isFormValid) return;
14036
+ setIsSubmitting(true);
14037
+ setSubmitError(null);
14038
+ try {
14039
+ const depositWallet = await onDepositWalletCreation({
14040
+ destinationChainType: selectedChain.chain_type,
14041
+ destinationChainId: selectedChain.chain_id,
14042
+ destinationTokenAddress: selectedChain.token_address,
14043
+ recipientAddress: trimmedAddress
14044
+ });
14045
+ const amountBaseUnit = computeBaseUnit(
14046
+ balanceData.balanceBaseUnit,
14047
+ parseFloat(amount),
14048
+ inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
14049
+ );
14050
+ const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
14051
+ const txInfo = {
14052
+ sourceChainType,
14053
+ sourceChainId,
14054
+ sourceTokenAddress,
14055
+ sourceTokenSymbol: tokenSymbol,
14056
+ destinationChainType: selectedChain.chain_type,
14057
+ destinationChainId: selectedChain.chain_id,
14058
+ destinationTokenAddress: selectedChain.token_address,
14059
+ destinationTokenSymbol: selectedToken.symbol,
14060
+ amount: humanAmount,
14061
+ amountBaseUnit,
14062
+ withdrawIntentAddress: depositWallet.address,
14063
+ recipientAddress: trimmedAddress
14064
+ };
14065
+ if (detectedWallet) {
14066
+ if (detectedWallet.chainFamily === "evm" && isHypercoreChain(sourceChainId)) {
14067
+ await sendHypercoreWithdraw({
14068
+ provider: detectedWallet.provider,
14069
+ fromAddress: detectedWallet.address,
14070
+ depositWalletAddress: depositWallet.address,
14071
+ sourceTokenAddress,
14072
+ amount: humanAmount,
14073
+ tokenSymbol,
14074
+ publishableKey
14075
+ });
14076
+ } else if (detectedWallet.chainFamily === "evm") {
14077
+ await sendEvmWithdraw({
14078
+ provider: detectedWallet.provider,
14079
+ fromAddress: detectedWallet.address,
14080
+ depositWalletAddress: depositWallet.address,
14081
+ sourceTokenAddress,
14082
+ sourceChainId,
14083
+ amountBaseUnit
14084
+ });
14085
+ } else if (detectedWallet.chainFamily === "solana") {
14086
+ await sendSolanaWithdraw({
14087
+ provider: detectedWallet.provider,
14088
+ fromAddress: detectedWallet.address,
14089
+ depositWalletAddress: depositWallet.address,
14090
+ sourceTokenAddress,
14091
+ amountBaseUnit,
14092
+ publishableKey
14093
+ });
14094
+ }
14095
+ } else if (onWithdraw) {
14096
+ await onWithdraw(txInfo);
14097
+ } else {
14098
+ throw new Error("No withdrawal method available. Please connect a wallet.");
14099
+ }
14100
+ onWithdrawSubmitted?.(txInfo);
14101
+ } catch (err) {
14102
+ const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
14103
+ setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
14104
+ onWithdrawError?.({
14105
+ message: raw,
14106
+ error: err,
14107
+ code: "WITHDRAW_FAILED"
14108
+ });
14109
+ } finally {
14110
+ setIsSubmitting(false);
14111
+ }
14112
+ }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
14113
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
14114
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { children: [
14115
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14116
+ "div",
14117
+ {
14118
+ className: "uf-text-xs uf-mb-1.5",
14119
+ style: { color: components.card.labelColor, fontFamily: fonts.medium },
14120
+ children: t8.recipientAddress
14121
+ }
14122
+ ),
14123
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14124
+ "style",
14125
+ {
14126
+ dangerouslySetInnerHTML: {
14127
+ __html: `.uf-withdraw-addr::placeholder { color: ${components.search.placeholderColor}; }`
14128
+ }
14129
+ }
14130
+ ),
14131
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
14132
+ "div",
14133
+ {
14134
+ className: "uf-flex uf-items-center uf-gap-1 uf-pr-2",
14135
+ style: {
14136
+ backgroundColor: components.search.backgroundColor,
14137
+ borderRadius: components.input.borderRadius,
14138
+ border: `${components.input.borderWidth}px solid ${addressError ? colors2.error : components.input.borderColor}`
14139
+ },
14140
+ children: [
14141
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14142
+ "input",
14143
+ {
14144
+ type: "text",
14145
+ placeholder: t8.recipientAddressPlaceholder,
14146
+ value: recipientAddress,
14147
+ onChange: (e) => {
14148
+ setRecipientAddress(e.target.value);
14149
+ setSubmitError(null);
14150
+ },
14151
+ className: "uf-withdraw-addr uf-flex-1 uf-min-w-0 uf-px-3 uf-py-2.5 uf-text-sm uf-bg-transparent uf-outline-none",
14152
+ style: {
14153
+ color: components.search.inputColor,
14154
+ fontFamily: fonts.regular
14155
+ }
14156
+ }
14157
+ ),
14158
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14159
+ "button",
14160
+ {
14161
+ type: "button",
14162
+ onClick: async () => {
14163
+ try {
14164
+ const text = await navigator.clipboard.readText();
14165
+ if (text) {
14166
+ setRecipientAddress(text.trim());
14167
+ setSubmitError(null);
14168
+ }
14169
+ } catch {
14170
+ }
14171
+ },
14172
+ className: "uf-flex-shrink-0 uf-p-1 uf-rounded uf-transition-colors hover:uf-opacity-70",
14173
+ style: { color: colors2.foregroundMuted },
14174
+ title: "Paste from clipboard",
14175
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ClipboardPaste, { className: "uf-w-4 uf-h-4" })
14176
+ }
14177
+ )
14178
+ ]
14179
+ }
14180
+ ),
14181
+ (isDebouncing || isVerifyingAddress) && trimmedAddress.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
14182
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Loader2, { className: "uf-w-3 uf-h-3 uf-animate-spin", style: { color: colors2.foregroundMuted } }),
14183
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: t8.verifyingAddress })
14184
+ ] }),
14185
+ addressError && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
14186
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.AlertTriangle, { className: "uf-w-3 uf-h-3", style: { color: colors2.error } }),
14187
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-xs", style: { color: colors2.error, fontFamily: fonts.regular }, children: addressError })
14188
+ ] })
14189
+ ] }),
14190
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { children: [
14191
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-text-xs uf-mb-1.5", style: { color: components.card.labelColor, fontFamily: fonts.medium }, children: [
14192
+ t8.amount,
14193
+ minimumWithdrawAmountUsd != null && minimumWithdrawAmountUsd > 0 && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { style: { color: colors2.warning, fontFamily: fonts.regular }, children: ` ($${minimumWithdrawAmountUsd.toFixed(2)} min)` })
14194
+ ] }),
14195
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14196
+ "style",
14197
+ {
14198
+ dangerouslySetInnerHTML: {
14199
+ __html: `.uf-withdraw-amt::placeholder { color: ${components.search.placeholderColor}; }`
14200
+ }
14201
+ }
14202
+ ),
14203
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
14204
+ "div",
14205
+ {
14206
+ className: "uf-flex uf-items-center uf-gap-2 uf-px-3 uf-py-2.5",
14207
+ style: {
14208
+ backgroundColor: components.search.backgroundColor,
14209
+ borderRadius: components.input.borderRadius,
14210
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
14211
+ },
14212
+ children: [
14213
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14214
+ "input",
14215
+ {
14216
+ type: "text",
14217
+ inputMode: "decimal",
14218
+ placeholder: "0.00",
14219
+ value: amount,
14220
+ onChange: (e) => {
14221
+ const val = e.target.value;
14222
+ if (val === "" || /^\d*\.?\d*$/.test(val)) {
14223
+ setAmount(val);
14224
+ setSubmitError(null);
14225
+ }
14226
+ },
14227
+ className: "uf-withdraw-amt uf-flex-1 uf-min-w-0 uf-bg-transparent uf-text-sm uf-outline-none",
14228
+ style: {
14229
+ color: components.search.inputColor,
14230
+ fontFamily: fonts.regular
14231
+ }
14232
+ }
14233
+ ),
14234
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-sm uf-shrink-0", style: { color: colors2.foregroundMuted, fontFamily: fonts.medium }, children: inputUnit === "crypto" ? tokenSymbol : "USD" }),
14235
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14236
+ "button",
14237
+ {
14238
+ type: "button",
14239
+ onClick: handleMaxClick,
14240
+ className: "uf-shrink-0 uf-px-2 uf-py-0.5 uf-rounded-md uf-text-xs uf-font-medium uf-transition-colors hover:uf-opacity-80",
14241
+ style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium },
14242
+ children: "Max"
14243
+ }
14244
+ )
14245
+ ]
14246
+ }
14247
+ ),
14248
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-mt-1.5 uf-px-3", children: [
14249
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
14250
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: convertedDisplay || (inputUnit === "crypto" ? "$0.00" : `0.00 ${tokenSymbol}`) }),
14251
+ exchangeRate > 0 && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14252
+ "button",
14253
+ {
14254
+ type: "button",
14255
+ onClick: handleSwitchUnit,
14256
+ className: "uf-p-0.5 uf-rounded uf-transition-colors hover:uf-opacity-70",
14257
+ style: { color: colors2.foregroundMuted },
14258
+ title: "Switch unit",
14259
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ArrowUpDown, { className: "uf-w-3 uf-h-3" })
14260
+ }
14261
+ )
14262
+ ] }),
14263
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { children: [
14264
+ balanceDisplay && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: [
14265
+ t8.balance,
14266
+ ": ",
14267
+ balanceDisplay
14268
+ ] }),
14269
+ isLoadingBalance && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-h-3 uf-w-16 uf-bg-muted uf-rounded uf-animate-pulse" })
14270
+ ] })
14271
+ ] })
14272
+ ] }),
14273
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-px-2.5", style: { backgroundColor: components.card.backgroundColor, borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: [
14274
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
14275
+ "button",
14276
+ {
14277
+ type: "button",
14278
+ onClick: () => setDetailsExpanded(!detailsExpanded),
14279
+ className: "uf-w-full uf-flex uf-items-center uf-justify-between uf-py-2.5",
14280
+ children: [
14281
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
14282
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Clock, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
14283
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
14284
+ tCrypto.processingTime.label,
14285
+ ":",
14286
+ " ",
14287
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(estimatedProcessingTime) })
14288
+ ] })
14289
+ ] }),
14290
+ detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
14291
+ ]
14292
+ }
14293
+ ),
14294
+ detailsExpanded && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-pb-3 uf-space-y-2.5", children: [
14295
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
14296
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ShieldCheck, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
14297
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
14298
+ tCrypto.slippage.label,
14299
+ ":",
14300
+ " ",
14301
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
14302
+ tCrypto.slippage.auto,
14303
+ " \u2022 ",
14304
+ (maxSlippagePercent ?? 0.25).toFixed(2),
14305
+ "%"
14306
+ ] })
14307
+ ] })
14308
+ ] }),
14309
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
14310
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.DollarSign, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
14311
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
14312
+ tCrypto.priceImpact.label,
14313
+ ":",
14314
+ " ",
14315
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
14316
+ (priceImpactPercent ?? 0).toFixed(2),
14317
+ "%"
14318
+ ] })
14319
+ ] })
14320
+ ] })
14321
+ ] })
14322
+ ] }),
14323
+ !canWithdraw && !submitError && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
14324
+ "div",
14325
+ {
14326
+ className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
14327
+ style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
14328
+ children: [
14329
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Wallet, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
14330
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No connected wallet detected. Please connect a wallet that matches your account to withdraw." })
14331
+ ]
14332
+ }
14333
+ ),
14334
+ isWalletMatch && connectedWalletName ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14335
+ "button",
14336
+ {
14337
+ type: "button",
14338
+ onClick: handleWithdraw,
14339
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
14340
+ className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed uf-flex uf-items-center uf-justify-center uf-gap-2",
14341
+ style: {
14342
+ backgroundColor: colors2.primary,
14343
+ color: colors2.primaryForeground,
14344
+ fontFamily: fonts.medium,
14345
+ borderRadius: components.button.borderRadius,
14346
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
14347
+ },
14348
+ children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
14349
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
14350
+ "Processing..."
14351
+ ] }) : isOverBalance ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_jsx_runtime54.Fragment, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_jsx_runtime54.Fragment, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_jsx_runtime54.Fragment, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
14352
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Wallet, { className: "uf-w-4 uf-h-4" }),
14353
+ "Withdraw from ",
14354
+ connectedWalletName
14355
+ ] })
14356
+ }
14357
+ ) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14358
+ "button",
14359
+ {
14360
+ type: "button",
14361
+ onClick: handleWithdraw,
14362
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
14363
+ className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
14364
+ style: {
14365
+ backgroundColor: colors2.primary,
14366
+ color: colors2.primaryForeground,
14367
+ fontFamily: fonts.medium,
14368
+ borderRadius: components.button.borderRadius,
14369
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
14370
+ },
14371
+ children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
14372
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
14373
+ "Processing..."
14374
+ ] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
14375
+ }
14376
+ ),
14377
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
14378
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { children: footerLeft }),
14379
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) })
14380
+ ] }),
14381
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
14382
+ GlossaryModal,
14383
+ {
14384
+ open: glossaryOpen,
14385
+ onOpenChange: setGlossaryOpen
14386
+ }
14387
+ )
14388
+ ] });
14389
+ }
14390
+
14391
+ // src/components/withdrawals/WithdrawExecutionItem.tsx
14392
+ var import_lucide_react26 = require("lucide-react");
14393
+ var import_core33 = require("@unifold/core");
14394
+ var import_jsx_runtime55 = require("react/jsx-runtime");
14395
+ function WithdrawExecutionItem({
14396
+ execution,
14397
+ onClick
14398
+ }) {
14399
+ const { colors: colors2, fonts, components } = useTheme();
14400
+ const isPending = execution.status === import_core33.ExecutionStatus.PENDING || execution.status === import_core33.ExecutionStatus.WAITING || execution.status === import_core33.ExecutionStatus.DELAYED;
14401
+ const formatDateTime = (timestamp) => {
14402
+ try {
14403
+ const date = new Date(timestamp);
14404
+ const monthDay = date.toLocaleDateString("en-US", {
14405
+ month: "short",
14406
+ day: "numeric",
14407
+ year: "numeric"
14408
+ });
14409
+ const time = date.toLocaleTimeString("en-US", {
14410
+ hour: "numeric",
14411
+ minute: "2-digit",
14412
+ hour12: true
14413
+ }).toLowerCase();
14414
+ return `${monthDay} at ${time}`;
14415
+ } catch {
14416
+ return timestamp;
14417
+ }
14418
+ };
14419
+ const formatUsdAmount2 = (sourceAmountUsd) => {
14420
+ try {
14421
+ const amount = Number(sourceAmountUsd);
14422
+ return new Intl.NumberFormat("en-US", {
14423
+ style: "currency",
14424
+ currency: "USD",
14425
+ minimumFractionDigits: 2,
14426
+ maximumFractionDigits: 2
14427
+ }).format(amount);
14428
+ } catch {
14429
+ return "$0.00";
14430
+ }
14431
+ };
14432
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
14433
+ "button",
14434
+ {
14435
+ onClick,
14436
+ className: "uf-w-full uf-p-3 uf-flex uf-items-center uf-gap-3 hover:uf-bg-secondary/80 uf-transition-colors uf-text-left",
14437
+ style: {
14438
+ backgroundColor: components.card.backgroundColor,
14439
+ borderRadius: components.list.rowBorderRadius,
14440
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
14441
+ },
14442
+ children: [
14443
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uf-relative uf-flex-shrink-0 uf-w-9 uf-h-9", children: [
14444
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14445
+ "img",
14446
+ {
14447
+ src: execution.destination_token_metadata?.icon_url || (0, import_core33.getIconUrl)("/icons/tokens/svg/usdc.svg"),
14448
+ alt: "Token",
14449
+ width: 36,
14450
+ height: 36,
14451
+ loading: "lazy",
14452
+ className: "uf-rounded-full uf-w-9 uf-h-9"
14453
+ }
14454
+ ),
14455
+ isPending ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14456
+ "div",
14457
+ {
14458
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
14459
+ style: { backgroundColor: colors2.warning },
14460
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14461
+ "svg",
14462
+ {
14463
+ width: "10",
14464
+ height: "10",
14465
+ viewBox: "0 0 12 12",
14466
+ fill: "none",
14467
+ className: "uf-animate-spin uf-block",
14468
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14469
+ "path",
14470
+ {
14471
+ d: "M6 1V3M6 9V11M1 6H3M9 6H11M2.5 2.5L4 4M8 8L9.5 9.5M2.5 9.5L4 8M8 4L9.5 2.5",
14472
+ stroke: "white",
14473
+ strokeWidth: "2",
14474
+ strokeLinecap: "round"
14475
+ }
14476
+ )
14477
+ }
14478
+ )
14479
+ }
14480
+ ) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14481
+ "div",
14482
+ {
14483
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
14484
+ style: { backgroundColor: colors2.success },
14485
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14486
+ "svg",
14487
+ {
14488
+ width: "10",
14489
+ height: "10",
14490
+ viewBox: "0 0 12 12",
14491
+ fill: "none",
14492
+ className: "uf-block",
14493
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14494
+ "path",
14495
+ {
14496
+ d: "M10 3L4.5 8.5L2 6",
14497
+ stroke: "white",
14498
+ strokeWidth: "2",
14499
+ strokeLinecap: "round",
14500
+ strokeLinejoin: "round"
14501
+ }
14502
+ )
14503
+ }
14504
+ )
14505
+ }
14506
+ )
14507
+ ] }),
14508
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uf-flex-1 uf-min-w-0", children: [
14509
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14510
+ "h3",
14511
+ {
14512
+ className: "uf-font-medium uf-text-sm uf-leading-tight",
14513
+ style: {
14514
+ color: components.card.titleColor,
14515
+ fontFamily: fonts.medium
14516
+ },
14517
+ children: isPending ? "Withdrawal processing" : "Withdrawal completed"
14518
+ }
14519
+ ),
14520
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14521
+ "p",
14522
+ {
14523
+ className: "uf-text-xs uf-leading-tight",
14524
+ style: {
14525
+ color: components.card.subtitleColor,
14526
+ fontFamily: fonts.regular
14527
+ },
14528
+ children: formatDateTime(execution.created_at || (/* @__PURE__ */ new Date()).toISOString())
14529
+ }
14530
+ )
14531
+ ] }),
14532
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14533
+ "span",
14534
+ {
14535
+ className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
14536
+ style: {
14537
+ color: components.card.textRightColor,
14538
+ fontFamily: fonts.medium
14539
+ },
14540
+ children: formatUsdAmount2(execution.source_amount_usd || "0")
14541
+ }
14542
+ ),
14543
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
14544
+ import_lucide_react26.ChevronRight,
14545
+ {
14546
+ className: "uf-w-4 uf-h-4 uf-flex-shrink-0",
14547
+ style: { color: components.card.actionColor }
14548
+ }
14549
+ )
14550
+ ]
14551
+ }
14552
+ );
14553
+ }
14554
+
14555
+ // src/components/withdrawals/WithdrawConfirmingView.tsx
14556
+ var import_react22 = require("react");
14557
+ var import_jsx_runtime56 = require("react/jsx-runtime");
14558
+ function truncateAddress4(addr) {
14559
+ if (addr.length <= 12) return addr;
14560
+ return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
14561
+ }
14562
+ var SHOW_BUTTON_DELAY_MS = 5e3;
14563
+ function WithdrawConfirmingView({
14564
+ txInfo,
14565
+ executions,
14566
+ onClose,
14567
+ onViewTracker
14568
+ }) {
14569
+ const { colors: colors2, fonts, components } = useTheme();
14570
+ const [showButton, setShowButton] = (0, import_react22.useState)(false);
14571
+ const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
14572
+ (0, import_react22.useEffect)(() => {
14573
+ if (latestExecution) return;
14574
+ const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
14575
+ return () => clearTimeout(timer);
14576
+ }, [latestExecution]);
14577
+ const btnRadius = components.button.borderRadius;
14578
+ const btnBorder = `${components.button.borderWidth}px solid ${components.button.borderColor}`;
14579
+ if (latestExecution) {
14580
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
14581
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositHeader, { title: "Withdrawal Details", showClose: true, onClose }),
14582
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositDetailContent, { execution: latestExecution, variant: "withdraw" }),
14583
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "uf-flex uf-gap-2 uf-px-2 uf-pt-2", children: [
14584
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14585
+ "button",
14586
+ {
14587
+ type: "button",
14588
+ onClick: onViewTracker,
14589
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
14590
+ style: {
14591
+ backgroundColor: components.button.secondaryBackground,
14592
+ color: components.button.secondaryText,
14593
+ fontFamily: fonts.medium,
14594
+ borderRadius: btnRadius,
14595
+ border: btnBorder
14596
+ },
14597
+ children: "Withdrawal History"
14598
+ }
14599
+ ),
14600
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14601
+ "button",
14602
+ {
14603
+ type: "button",
14604
+ onClick: onClose,
14605
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
14606
+ style: {
14607
+ backgroundColor: components.button.primaryBackground,
14608
+ color: components.button.primaryText,
14609
+ fontFamily: fonts.medium,
14610
+ borderRadius: btnRadius,
14611
+ border: btnBorder
14612
+ },
14613
+ children: "Close"
14614
+ }
14615
+ )
14616
+ ] }),
14617
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14618
+ PoweredByUnifold,
14619
+ {
14620
+ color: colors2.foregroundMuted,
14621
+ className: "uf-flex uf-justify-center uf-shrink-0"
14622
+ }
14623
+ ) })
14624
+ ] });
14625
+ }
14626
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
14627
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositHeader, { title: "Withdrawal Status", showClose: true, onClose }),
14628
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4", children: [
14629
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14630
+ "div",
14631
+ {
14632
+ className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
14633
+ style: { backgroundColor: `${colors2.primary}20` },
14634
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14635
+ "svg",
14636
+ {
14637
+ width: "40",
14638
+ height: "40",
14639
+ viewBox: "0 0 24 24",
14640
+ fill: "none",
14641
+ className: "uf-animate-spin",
14642
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14643
+ "path",
14644
+ {
14645
+ d: "M21 12a9 9 0 1 1-6.22-8.56",
14646
+ stroke: colors2.primary,
14647
+ strokeWidth: "2.5",
14648
+ strokeLinecap: "round"
14649
+ }
14650
+ )
14651
+ }
14652
+ )
14653
+ }
14654
+ ),
14655
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14656
+ "h3",
14657
+ {
14658
+ className: "uf-text-xl uf-mb-2",
14659
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
14660
+ children: "Checking Withdrawal"
14661
+ }
14662
+ ),
14663
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
14664
+ "p",
14665
+ {
14666
+ className: "uf-text-sm uf-text-center",
14667
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
14668
+ children: [
14669
+ txInfo.amount,
14670
+ " ",
14671
+ txInfo.sourceTokenSymbol,
14672
+ " to",
14673
+ " ",
14674
+ truncateAddress4(txInfo.recipientAddress)
14675
+ ]
14676
+ }
14677
+ )
14678
+ ] }),
14679
+ showButton && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-px-1 uf-pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14680
+ "button",
14681
+ {
14682
+ type: "button",
14683
+ onClick: onViewTracker,
14684
+ className: "uf-w-full uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
14685
+ style: {
14686
+ backgroundColor: components.button.secondaryBackground,
14687
+ color: components.button.secondaryText,
14688
+ fontFamily: fonts.medium,
14689
+ borderRadius: btnRadius,
14690
+ border: btnBorder
14691
+ },
14692
+ children: "Withdrawal History"
14693
+ }
14694
+ ) }),
14695
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
14696
+ PoweredByUnifold,
14697
+ {
14698
+ color: colors2.foregroundMuted,
14699
+ className: "uf-flex uf-justify-center uf-shrink-0"
14700
+ }
14701
+ ) })
14702
+ ] });
14703
+ }
14704
+
14705
+ // src/components/withdrawals/WithdrawModal.tsx
14706
+ var import_core34 = require("@unifold/core");
14707
+ var import_jsx_runtime57 = require("react/jsx-runtime");
14708
+ var t9 = i18n.withdrawModal;
14709
+ var getChainKey5 = (chainId, chainType) => `${chainType}:${chainId}`;
14710
+ function WithdrawModal({
14711
+ open,
14712
+ onOpenChange,
14713
+ publishableKey,
14714
+ modalTitle,
14715
+ externalUserId,
14716
+ sourceChainType,
14717
+ sourceChainId,
14718
+ sourceTokenAddress,
14719
+ sourceTokenSymbol,
14720
+ recipientAddress: recipientAddressProp,
14721
+ senderAddress,
14722
+ onWithdraw,
14723
+ onWithdrawSuccess,
14724
+ onWithdrawError,
14725
+ theme = "dark",
14726
+ hideOverlay = false
14727
+ }) {
14728
+ const { colors: colors2, fonts, components } = useTheme();
14729
+ const [containerEl, setContainerEl] = (0, import_react23.useState)(null);
14730
+ const containerCallbackRef = (0, import_react23.useCallback)((el) => {
14731
+ setContainerEl(el);
14732
+ }, []);
14733
+ const [resolvedTheme, setResolvedTheme] = (0, import_react23.useState)(
14734
+ theme === "auto" ? "dark" : theme
14735
+ );
14736
+ (0, import_react23.useEffect)(() => {
14737
+ if (theme === "auto") {
14738
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
14739
+ setResolvedTheme(mq.matches ? "dark" : "light");
14740
+ const h = (e) => setResolvedTheme(e.matches ? "dark" : "light");
14741
+ mq.addEventListener("change", h);
14742
+ return () => mq.removeEventListener("change", h);
14743
+ }
14744
+ setResolvedTheme(theme);
14745
+ }, [theme]);
14746
+ const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
14747
+ const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDestinationTokens(publishableKey, open);
14748
+ const destinationTokens = tokensResponse?.data ?? [];
14749
+ const { data: sourceValidation, isLoading: isCheckingSourceToken } = useSourceTokenValidation({
14750
+ sourceChainType,
14751
+ sourceChainId,
14752
+ sourceTokenAddress,
14753
+ sourceTokenSymbol,
14754
+ publishableKey,
14755
+ enabled: open
14756
+ });
14757
+ const { data: balanceData, isLoading: isLoadingBalance } = useAddressBalance({
14758
+ address: senderAddress,
14759
+ chainType: sourceChainType,
14760
+ chainId: sourceChainId,
14761
+ tokenAddress: sourceTokenAddress,
14762
+ publishableKey,
14763
+ enabled: open
14764
+ });
14765
+ const [selectedToken, setSelectedToken] = (0, import_react23.useState)(null);
14766
+ const [selectedChain, setSelectedChain] = (0, import_react23.useState)(null);
14767
+ const [detectedWallet, setDetectedWallet] = (0, import_react23.useState)(null);
14768
+ const connectedWalletName = detectedWallet?.name ?? null;
14769
+ const isWalletMatch = !!detectedWallet;
14770
+ (0, import_react23.useEffect)(() => {
14771
+ if (!senderAddress || !open) {
14772
+ setDetectedWallet(null);
14773
+ return;
14774
+ }
14775
+ let cancelled = false;
14776
+ detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
14777
+ if (!cancelled) setDetectedWallet(wallet);
14778
+ });
14779
+ return () => {
14780
+ cancelled = true;
14781
+ };
14782
+ }, [senderAddress, sourceChainType, open]);
14783
+ const [view, setView] = (0, import_react23.useState)("form");
14784
+ const [withdrawDepositWalletId, setWithdrawDepositWalletId] = (0, import_react23.useState)();
14785
+ const [selectedExecution, setSelectedExecution] = (0, import_react23.useState)(null);
14786
+ const [submittedTxInfo, setSubmittedTxInfo] = (0, import_react23.useState)(null);
14787
+ const { executions: realtimeExecutions } = useWithdrawPolling({
14788
+ userId: externalUserId,
14789
+ publishableKey,
14790
+ depositWalletId: withdrawDepositWalletId,
14791
+ enabled: !!withdrawDepositWalletId && open,
14792
+ onWithdrawSuccess: onWithdrawSuccess ? (d) => onWithdrawSuccess({ message: d.message, transaction: d.transaction }) : void 0,
14793
+ onWithdrawError
14794
+ });
14795
+ const { data: allWithdrawalsData } = useExecutions(externalUserId, publishableKey, {
14796
+ actionType: import_core34.ActionType.Withdraw,
14797
+ enabled: open,
14798
+ refetchInterval: view === "tracker" || view === "detail" ? 5e3 : 15e3
14799
+ });
14800
+ const allWithdrawals = allWithdrawalsData?.data ?? [];
14801
+ const handleDepositWalletCreation = (0, import_react23.useCallback)(async (params) => {
14802
+ const { data: wallets } = await (0, import_core34.createDepositAddress)(
14803
+ {
14804
+ external_user_id: externalUserId,
14805
+ destination_chain_type: params.destinationChainType,
14806
+ destination_chain_id: params.destinationChainId,
14807
+ destination_token_address: params.destinationTokenAddress,
14808
+ recipient_address: params.recipientAddress,
14809
+ action_type: import_core34.ActionType.Withdraw
14810
+ },
14811
+ publishableKey
14812
+ );
14813
+ const depositWallet = (0, import_core34.getWalletByChainType)(wallets, sourceChainType);
14814
+ if (!depositWallet) {
14815
+ throw new Error(`No deposit wallet available for ${sourceChainType}`);
14816
+ }
14817
+ setWithdrawDepositWalletId(depositWallet.id);
14818
+ return depositWallet;
14819
+ }, [externalUserId, publishableKey, sourceChainType]);
14820
+ const handleWithdrawSubmitted = (0, import_react23.useCallback)((txInfo) => {
14821
+ setSubmittedTxInfo(txInfo);
14822
+ setView("confirming");
14823
+ }, []);
14824
+ (0, import_react23.useEffect)(() => {
14825
+ if (!destinationTokens.length || selectedToken) return;
14826
+ const first = destinationTokens[0];
14827
+ if (first?.chains.length > 0) {
14828
+ setSelectedToken(first);
14829
+ setSelectedChain(first.chains[0]);
14830
+ }
14831
+ }, [destinationTokens, selectedToken]);
14832
+ const resetViewTimeoutRef = (0, import_react23.useRef)(null);
14833
+ const handleClose = (0, import_react23.useCallback)(() => {
14834
+ onOpenChange(false);
14835
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
14836
+ resetViewTimeoutRef.current = setTimeout(() => {
14837
+ setSelectedToken(null);
14838
+ setSelectedChain(null);
14839
+ setView("form");
14840
+ setSelectedExecution(null);
14841
+ setSubmittedTxInfo(null);
14842
+ setWithdrawDepositWalletId(void 0);
14843
+ resetViewTimeoutRef.current = null;
14844
+ }, 200);
14845
+ }, [onOpenChange]);
14846
+ (0, import_react23.useLayoutEffect)(() => {
14847
+ if (!open) return;
14848
+ if (resetViewTimeoutRef.current) {
14849
+ clearTimeout(resetViewTimeoutRef.current);
14850
+ resetViewTimeoutRef.current = null;
14851
+ }
14852
+ setSelectedToken(null);
14853
+ setSelectedChain(null);
14854
+ setView("form");
14855
+ setSelectedExecution(null);
14856
+ setSubmittedTxInfo(null);
14857
+ setWithdrawDepositWalletId(void 0);
14858
+ }, [open]);
14859
+ (0, import_react23.useEffect)(() => () => {
14860
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
14861
+ }, []);
14862
+ const handleTokenSymbolChange = (0, import_react23.useCallback)((symbol) => {
14863
+ const tok = destinationTokens.find((t11) => t11.symbol === symbol);
14864
+ if (tok) {
14865
+ setSelectedToken(tok);
14866
+ if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
14867
+ }
14868
+ }, [destinationTokens]);
14869
+ const handleChainKeyChange = (0, import_react23.useCallback)((chainKey) => {
14870
+ if (!selectedToken) return;
14871
+ const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
14872
+ if (chain) setSelectedChain(chain);
14873
+ }, [selectedToken]);
14874
+ const isSourceSupported = sourceValidation?.isSupported ?? null;
14875
+ const canWithdraw = !!onWithdraw || isWalletMatch;
14876
+ const isAnyLoading = tokensLoading || isCheckingSourceToken;
14877
+ const withdrawPoweredByFooter = /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
14878
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Dialog, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14879
+ DialogContent,
14880
+ {
14881
+ ref: hideOverlay ? containerCallbackRef : void 0,
14882
+ hideOverlay,
14883
+ className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden ${hideOverlay ? `uf-p-6 uf-overflow-hidden ${themeClass}` : `uf-p-0 uf-overflow-visible !uf-top-auto !uf-h-auto !uf-max-h-[90vh] sm:!uf-max-h-none sm:!uf-top-[50%] ${themeClass}`}`,
14884
+ style: { backgroundColor: colors2.background },
14885
+ onPointerDownOutside: (e) => e.preventDefault(),
14886
+ onInteractOutside: (e) => e.preventDefault(),
14887
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ThemeStyleInjector, { children: view === "confirming" && submittedTxInfo ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14888
+ WithdrawConfirmingView,
14889
+ {
14890
+ txInfo: submittedTxInfo,
14891
+ executions: realtimeExecutions,
14892
+ onClose: handleClose,
14893
+ onViewTracker: () => setView("tracker")
14894
+ }
14895
+ ) : view === "detail" && selectedExecution ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
14896
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositHeader, { title: "Withdrawal Details", showBack: true, showClose: !hideOverlay, onBack: () => {
14897
+ setSelectedExecution(null);
14898
+ setView("tracker");
14899
+ }, onClose: handleClose }),
14900
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositDetailContent, { execution: selectedExecution, variant: "withdraw" }),
14901
+ withdrawPoweredByFooter
14902
+ ] }) : view === "tracker" ? (
14903
+ /* ---------- Tracker view: execution list ---------- */
14904
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
14905
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
14906
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14907
+ WithdrawExecutionItem,
14908
+ {
14909
+ execution: ex,
14910
+ onClick: () => {
14911
+ setSelectedExecution(ex);
14912
+ setView("detail");
14913
+ }
14914
+ },
14915
+ ex.id
14916
+ )) }),
14917
+ withdrawPoweredByFooter
14918
+ ] })
14919
+ ) : (
14920
+ /* ---------- Form view (default) ---------- */
14921
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
14922
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositHeader, { title: modalTitle || t9.title, showClose: !hideOverlay, onClose: handleClose }),
14923
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-3", children: [
14924
+ isAnyLoading ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-animate-pulse", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-bg-muted uf-rounded-lg uf-w-full uf-h-10" }) }, i)) }) : isSourceSupported === false ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
14925
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react27.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
14926
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-mb-2", style: { color: colors2.foreground, fontFamily: fonts.medium }, children: "Unsupported Source Token" }),
14927
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "uf-text-sm uf-max-w-[280px]", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: sourceValidation?.errorMessage })
14928
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
14929
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14930
+ WithdrawDoubleInput,
14931
+ {
14932
+ tokens: destinationTokens,
14933
+ selectedTokenSymbol: selectedToken?.symbol ?? null,
14934
+ selectedChainKey: selectedChain ? getChainKey5(selectedChain.chain_id, selectedChain.chain_type) : null,
14935
+ onTokenChange: handleTokenSymbolChange,
14936
+ onChainChange: handleChainKeyChange,
14937
+ isLoading: tokensLoading
14938
+ }
14939
+ ),
14940
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14941
+ WithdrawForm,
14942
+ {
14943
+ publishableKey,
14944
+ externalUserId,
14945
+ sourceChainType,
14946
+ selectedToken,
14947
+ selectedChain,
14948
+ sourceTokenSymbol,
14949
+ recipientAddressProp,
14950
+ balanceData: balanceData ?? null,
14951
+ isLoadingBalance,
14952
+ minimumWithdrawAmountUsd: sourceValidation?.minimumAmountUsd ?? null,
14953
+ estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
14954
+ maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
14955
+ priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
14956
+ detectedWallet,
14957
+ sourceChainId,
14958
+ sourceTokenAddress,
14959
+ isWalletMatch,
14960
+ connectedWalletName,
14961
+ canWithdraw,
14962
+ onWithdraw,
14963
+ onWithdrawError,
14964
+ onDepositWalletCreation: handleDepositWalletCreation,
14965
+ onWithdrawSubmitted: handleWithdrawSubmitted,
14966
+ footerLeft: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
14967
+ "button",
14968
+ {
14969
+ onClick: () => setView("tracker"),
14970
+ className: "uf-flex uf-items-center uf-gap-1 uf-transition-colors hover:uf-opacity-70",
14971
+ style: { color: colors2.foregroundMuted },
14972
+ children: [
14973
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react27.Clock, { className: "uf-w-3.5 uf-h-3.5" }),
14974
+ "Withdrawal History",
14975
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react27.ChevronRight, { className: "uf-w-3 uf-h-3" })
14976
+ ]
14977
+ }
14978
+ )
14979
+ }
14980
+ )
14981
+ ] }),
14982
+ withdrawPoweredByFooter
14983
+ ] })
14984
+ ] })
14985
+ ) })
14986
+ }
14987
+ ) }) });
14988
+ }
14989
+
14990
+ // src/components/withdrawals/WithdrawTokenSelector.tsx
14991
+ var import_react24 = require("react");
14992
+ var import_lucide_react28 = require("lucide-react");
14993
+ var import_jsx_runtime58 = require("react/jsx-runtime");
14994
+ var t10 = i18n.withdrawModal;
14995
+ function WithdrawTokenSelector({
14996
+ tokens,
14997
+ onSelect,
14998
+ onBack
14999
+ }) {
15000
+ const { themeClass, colors: colors2, fonts, components } = useTheme();
15001
+ const [searchQuery, setSearchQuery] = (0, import_react24.useState)("");
15002
+ const [hoveredKey, setHoveredKey] = (0, import_react24.useState)(null);
15003
+ const allOptions = (0, import_react24.useMemo)(() => {
15004
+ const options = [];
15005
+ tokens.forEach((token) => {
15006
+ token.chains.forEach((chain) => {
15007
+ options.push({ token, chain });
15008
+ });
15009
+ });
15010
+ return options;
15011
+ }, [tokens]);
15012
+ const filteredOptions = (0, import_react24.useMemo)(() => {
15013
+ if (!searchQuery.trim()) return allOptions;
15014
+ const query = searchQuery.toLowerCase();
15015
+ return allOptions.filter(
15016
+ ({ token, chain }) => token.symbol.toLowerCase().includes(query) || token.name.toLowerCase().includes(query) || chain.chain_name.toLowerCase().includes(query)
15017
+ );
15018
+ }, [allOptions, searchQuery]);
15019
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
15020
+ "div",
15021
+ {
15022
+ className: "uf-flex uf-flex-col",
15023
+ style: { minHeight: 0, flex: 1 },
15024
+ children: [
15025
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uf-pb-3", children: [
15026
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15027
+ "style",
15028
+ {
15029
+ dangerouslySetInnerHTML: {
15030
+ __html: `.uf-withdraw-token-search::placeholder { color: ${components.search.placeholderColor}; }`
15031
+ }
15032
+ }
15033
+ ),
15034
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { position: "relative" }, children: [
15035
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15036
+ import_lucide_react28.Search,
15037
+ {
15038
+ className: "uf-absolute uf-left-3 uf-top-1/2 uf--translate-y-1/2 uf-w-4 uf-h-4",
15039
+ style: { color: components.search.placeholderColor }
15040
+ }
15041
+ ),
15042
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15043
+ "input",
15044
+ {
15045
+ type: "text",
15046
+ placeholder: "Search token or network",
15047
+ value: searchQuery,
15048
+ onChange: (e) => setSearchQuery(e.target.value),
15049
+ className: "uf-withdraw-token-search uf-w-full uf-pl-10 uf-pr-4 uf-py-2.5 uf-text-sm uf-outline-none focus:uf-ring-2 focus:uf-ring-ring/30",
15050
+ style: {
15051
+ backgroundColor: components.search.backgroundColor,
15052
+ color: components.search.inputColor,
15053
+ fontFamily: fonts.regular,
15054
+ borderRadius: components.input.borderRadius,
15055
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
15056
+ }
15057
+ }
15058
+ )
15059
+ ] })
15060
+ ] }),
15061
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15062
+ "div",
15063
+ {
15064
+ className: "uf-text-xs uf-mb-2",
15065
+ style: {
15066
+ color: components.list.titleSectionColor,
15067
+ fontFamily: fonts.medium
15068
+ },
15069
+ children: t10.selectToken
15070
+ }
15071
+ ),
15072
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15073
+ "div",
15074
+ {
15075
+ className: "uf-flex-1 uf-overflow-y-auto uf-min-h-0 uf--mx-6 uf-px-6 uf-pb-3",
15076
+ style: { scrollbarWidth: "none" },
15077
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15078
+ "div",
15079
+ {
15080
+ style: {
15081
+ textAlign: "center",
15082
+ padding: "2rem 0",
15083
+ fontSize: 14,
15084
+ color: components.container.subtitleColor,
15085
+ fontFamily: fonts.regular
15086
+ },
15087
+ children: t10.noTokensAvailable
15088
+ }
15089
+ ) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: filteredOptions.map(({ token, chain }) => {
15090
+ const key = `${token.symbol}-${chain.chain_type}:${chain.chain_id}`;
15091
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
15092
+ "button",
15093
+ {
15094
+ type: "button",
15095
+ onClick: () => onSelect(token, chain),
15096
+ onMouseEnter: () => setHoveredKey(key),
15097
+ onMouseLeave: () => setHoveredKey(null),
15098
+ className: "uf-transition-colors",
15099
+ style: {
15100
+ width: "100%",
15101
+ display: "flex",
15102
+ alignItems: "center",
15103
+ gap: 12,
15104
+ padding: 12,
15105
+ borderRadius: 12,
15106
+ border: "none",
15107
+ cursor: "pointer",
15108
+ textAlign: "left",
15109
+ backgroundColor: hoveredKey === key ? colors2.cardHover : "transparent"
15110
+ },
15111
+ children: [
15112
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { position: "relative", flexShrink: 0 }, children: [
15113
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15114
+ "img",
15115
+ {
15116
+ src: token.icon_url,
15117
+ alt: token.symbol,
15118
+ width: 40,
15119
+ height: 40,
15120
+ loading: "lazy",
15121
+ className: "uf-rounded-full"
15122
+ }
15123
+ ),
15124
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15125
+ "div",
15126
+ {
15127
+ style: {
15128
+ position: "absolute",
15129
+ bottom: -4,
15130
+ right: -4
15131
+ },
15132
+ children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15133
+ "img",
15134
+ {
15135
+ src: chain.icon_url,
15136
+ alt: chain.chain_name,
15137
+ width: 20,
15138
+ height: 20,
15139
+ loading: "lazy",
15140
+ className: "uf-rounded-full uf-border-2"
15141
+ }
15142
+ )
15143
+ }
15144
+ )
15145
+ ] }),
15146
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
15147
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15148
+ "div",
15149
+ {
15150
+ style: {
15151
+ fontSize: 14,
15152
+ fontWeight: 500,
15153
+ color: components.card.titleColor,
15154
+ fontFamily: fonts.medium
15155
+ },
15156
+ children: token.symbol
15157
+ }
15158
+ ),
15159
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
15160
+ "div",
15161
+ {
15162
+ style: {
15163
+ fontSize: 12,
15164
+ color: components.card.subtitleColor,
15165
+ fontFamily: fonts.regular
15166
+ },
15167
+ children: [
15168
+ token.name,
15169
+ " \u2022 ",
15170
+ chain.chain_name
15171
+ ]
15172
+ }
15173
+ )
15174
+ ] })
15175
+ ]
15176
+ },
15177
+ key
15178
+ );
15179
+ }) })
15180
+ }
15181
+ ),
15182
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "uf-pt-3 uf-pb-2 uf-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
15183
+ PoweredByUnifold,
15184
+ {
15185
+ color: colors2.foregroundMuted,
15186
+ className: "uf-flex uf-justify-center uf-shrink-0"
15187
+ }
15188
+ ) })
15189
+ ]
15190
+ }
15191
+ );
15192
+ }
12146
15193
  // Annotate the CommonJS export names for ESM import in node:
12147
15194
  0 && (module.exports = {
12148
15195
  Button,
12149
15196
  BuyWithCard,
15197
+ CheckoutModal,
12150
15198
  ConfirmingView,
12151
15199
  CurrencyListItem,
12152
15200
  CurrencyListSection,
@@ -12170,6 +15218,7 @@ function DepositModal({
12170
15218
  DialogPortal,
12171
15219
  DialogTitle,
12172
15220
  DialogTrigger,
15221
+ HYPERCORE_CHAIN_ID,
12173
15222
  Select,
12174
15223
  SelectContent,
12175
15224
  SelectGroup,
@@ -12189,15 +15238,33 @@ function DepositModal({
12189
15238
  TransferCryptoButton,
12190
15239
  TransferCryptoDoubleInput,
12191
15240
  TransferCryptoSingleInput,
15241
+ WithdrawConfirmingView,
15242
+ WithdrawDoubleInput,
15243
+ WithdrawExecutionItem,
15244
+ WithdrawForm,
15245
+ WithdrawModal,
15246
+ WithdrawTokenSelector,
12192
15247
  buttonVariants,
12193
15248
  cn,
12194
15249
  colors,
12195
15250
  defaultColors,
15251
+ detectBrowserWallet,
12196
15252
  getColors,
15253
+ isHypercoreChain,
12197
15254
  mergeColors,
12198
15255
  resolveComponentTokens,
15256
+ sendEvmWithdraw,
15257
+ sendHypercoreWithdraw,
15258
+ sendSolanaWithdraw,
12199
15259
  truncateAddress,
15260
+ useAddressBalance,
12200
15261
  useAllowedCountry,
12201
15262
  useDepositPolling,
12202
- useTheme
15263
+ useDepositQuote,
15264
+ usePaymentIntent,
15265
+ useSourceTokenValidation,
15266
+ useSupportedDestinationTokens,
15267
+ useTheme,
15268
+ useVerifyRecipientAddress,
15269
+ useWithdrawPolling
12203
15270
  });