@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.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  // src/components/deposits/DepositModal.tsx
2
2
  import {
3
3
  useState as useState27,
4
- useEffect as useEffect21,
4
+ useEffect as useEffect22,
5
5
  useLayoutEffect as useLayoutEffect2,
6
6
  useCallback as useCallback4,
7
- useRef as useRef6,
7
+ useRef as useRef7,
8
8
  useMemo as useMemo9
9
9
  } from "react";
10
10
  import { ChevronRight as ChevronRight11, MapPinOff, AlertTriangle } from "lucide-react";
@@ -621,6 +621,7 @@ function useDepositAddress(params) {
621
621
  destinationChainType,
622
622
  destinationChainId,
623
623
  destinationTokenAddress,
624
+ actionType,
624
625
  enabled = true
625
626
  } = params;
626
627
  return useQuery({
@@ -632,6 +633,7 @@ function useDepositAddress(params) {
632
633
  destinationChainType ?? null,
633
634
  destinationChainId ?? null,
634
635
  destinationTokenAddress ?? null,
636
+ actionType ?? null,
635
637
  publishableKey
636
638
  ],
637
639
  queryFn: () => createDepositAddress(
@@ -640,7 +642,8 @@ function useDepositAddress(params) {
640
642
  recipient_address: recipientAddress,
641
643
  destination_chain_type: destinationChainType,
642
644
  destination_chain_id: destinationChainId,
643
- destination_token_address: destinationTokenAddress
645
+ destination_token_address: destinationTokenAddress,
646
+ action_type: actionType
644
647
  },
645
648
  publishableKey
646
649
  ),
@@ -1354,6 +1357,30 @@ var en_default = {
1354
1357
  youReceive: "You receive",
1355
1358
  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."
1356
1359
  }
1360
+ },
1361
+ withdrawModal: {
1362
+ title: "Withdraw",
1363
+ withdrawCrypto: {
1364
+ title: "Withdraw with Crypto",
1365
+ subtitle: "Send to any wallet address"
1366
+ },
1367
+ selectToken: "Select withdrawal token",
1368
+ receiveToken: "Receive token",
1369
+ receiveChain: "Receive chain",
1370
+ recipientAddress: "Recipient address",
1371
+ recipientAddressPlaceholder: "Enter wallet address",
1372
+ amount: "Amount",
1373
+ amountPlaceholder: "0.00",
1374
+ balance: "Balance",
1375
+ minimum: "min",
1376
+ withdraw: "Withdraw",
1377
+ invalidAddress: "Please enter a valid address",
1378
+ invalidAmount: "Please enter a valid amount",
1379
+ verifyingAddress: "Verifying address...",
1380
+ loading: "Loading...",
1381
+ noTokensAvailable: "No tokens available",
1382
+ review: "Review Withdrawal",
1383
+ back: "Back"
1357
1384
  }
1358
1385
  };
1359
1386
 
@@ -1371,8 +1398,10 @@ function interpolate(template, params) {
1371
1398
  import { useState as useState5, useEffect as useEffect3, useRef } from "react";
1372
1399
  import {
1373
1400
  queryExecutions,
1401
+ listPaymentIntentExecutions,
1374
1402
  pollDirectExecutions,
1375
- ExecutionStatus
1403
+ ExecutionStatus,
1404
+ ActionType
1376
1405
  } from "@unifold/core";
1377
1406
  var DEPOSIT_CONFIRM_DELAY_MS = 1e4;
1378
1407
  var POLL_INTERVAL_MS = 2500;
@@ -1381,6 +1410,7 @@ var CUTOFF_BUFFER_MS = 6e4;
1381
1410
  function useDepositPolling({
1382
1411
  userId,
1383
1412
  publishableKey,
1413
+ clientSecret,
1384
1414
  depositConfirmationMode = "auto_ui",
1385
1415
  depositWalletId,
1386
1416
  enabled = true,
@@ -1438,11 +1468,12 @@ function useDepositPolling({
1438
1468
  depositWalletId
1439
1469
  ]);
1440
1470
  useEffect3(() => {
1441
- if (!userId || !enabled) return;
1471
+ if (!enabled) return;
1472
+ if (!clientSecret && !userId) return;
1442
1473
  const modalOpenedAt = modalOpenedAtRef.current;
1443
1474
  const poll = async () => {
1444
1475
  try {
1445
- const response = await queryExecutions(userId, publishableKey);
1476
+ const response = clientSecret ? await listPaymentIntentExecutions(clientSecret, publishableKey) : await queryExecutions(userId, publishableKey, ActionType.Deposit);
1446
1477
  const cutoff = new Date(modalOpenedAt.getTime() - CUTOFF_BUFFER_MS);
1447
1478
  const sortedExecutions = [...response.data].sort((a, b) => {
1448
1479
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
@@ -1526,7 +1557,7 @@ function useDepositPolling({
1526
1557
  clearInterval(pollInterval);
1527
1558
  setIsPolling(false);
1528
1559
  };
1529
- }, [userId, publishableKey, enabled]);
1560
+ }, [userId, publishableKey, clientSecret, enabled]);
1530
1561
  useEffect3(() => {
1531
1562
  if (!pollingEnabled || !depositWalletId) return;
1532
1563
  const triggerPoll = async () => {
@@ -1586,7 +1617,8 @@ function formatCurrency(currency) {
1586
1617
  }
1587
1618
  function DepositDetailContent({
1588
1619
  execution,
1589
- className
1620
+ className,
1621
+ variant = "deposit"
1590
1622
  }) {
1591
1623
  const { colors: colors2, fonts, components } = useTheme();
1592
1624
  const [chains, setChains] = useState6([]);
@@ -1992,7 +2024,7 @@ function DepositDetailContent({
1992
2024
  color: components.card.rowLeftLabel,
1993
2025
  fontFamily: fonts.regular
1994
2026
  },
1995
- children: "Deposit Tx"
2027
+ children: variant === "withdraw" ? "Withdrawal Tx" : "Deposit Tx"
1996
2028
  }
1997
2029
  ),
1998
2030
  /* @__PURE__ */ jsx7(
@@ -6900,7 +6932,8 @@ function useProjectConfig({
6900
6932
 
6901
6933
  // src/components/deposits/DepositModal.tsx
6902
6934
  import {
6903
- queryExecutions as queryExecutions3
6935
+ queryExecutions as queryExecutions3,
6936
+ ActionType as ActionType3
6904
6937
  } from "@unifold/core";
6905
6938
 
6906
6939
  // src/hooks/use-allowed-country.ts
@@ -7287,7 +7320,7 @@ function PoweredByUnifold({
7287
7320
  }
7288
7321
 
7289
7322
  // src/components/deposits/DepositsModal.tsx
7290
- import { queryExecutions as queryExecutions2 } from "@unifold/core";
7323
+ import { queryExecutions as queryExecutions2, ActionType as ActionType2 } from "@unifold/core";
7291
7324
  import { Fragment as Fragment3, jsx as jsx35, jsxs as jsxs30 } from "react/jsx-runtime";
7292
7325
  function DepositsModal({
7293
7326
  open,
@@ -7305,7 +7338,7 @@ function DepositsModal({
7305
7338
  if (!open || !userId) return;
7306
7339
  const fetchExecutions = async () => {
7307
7340
  try {
7308
- const response = await queryExecutions2(userId, publishableKey);
7341
+ const response = await queryExecutions2(userId, publishableKey, ActionType2.Deposit);
7309
7342
  const sorted = [...response.data].sort((a, b) => {
7310
7343
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
7311
7344
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -7427,7 +7460,7 @@ function saveRecentToken(token) {
7427
7460
  try {
7428
7461
  const recent = getRecentTokens();
7429
7462
  const filtered = recent.filter(
7430
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7463
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7431
7464
  );
7432
7465
  filtered.unshift(token);
7433
7466
  const trimmed = filtered.slice(0, MAX_RECENT_TOKENS);
@@ -7440,7 +7473,7 @@ function removeRecentToken(token) {
7440
7473
  try {
7441
7474
  const recent = getRecentTokens();
7442
7475
  const filtered = recent.filter(
7443
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7476
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7444
7477
  );
7445
7478
  localStorage.setItem(STORAGE_KEY, JSON.stringify(filtered));
7446
7479
  return filtered;
@@ -7479,7 +7512,7 @@ function TokenSelectorSheet({
7479
7512
  const addOption = (symbol, chainType, chainId, isRecent) => {
7480
7513
  const key = `${symbol}-${chainType}:${chainId}`;
7481
7514
  if (seen.has(key)) return;
7482
- const tokenData = tokens.find((t7) => t7.symbol === symbol);
7515
+ const tokenData = tokens.find((t11) => t11.symbol === symbol);
7483
7516
  if (!tokenData) return;
7484
7517
  const chainData = tokenData.chains.find(
7485
7518
  (c) => c.chain_type === chainType && c.chain_id === chainId
@@ -7950,35 +7983,35 @@ function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSour
7950
7983
  let selectedChainData;
7951
7984
  const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
7952
7985
  if (defaultSourceTokenAddress && hasChainDefaults) {
7953
- for (const t7 of supportedTokens) {
7954
- const matchingChain = t7.chains.find(
7986
+ for (const t11 of supportedTokens) {
7987
+ const matchingChain = t11.chains.find(
7955
7988
  (c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
7956
7989
  );
7957
7990
  if (matchingChain) {
7958
- selectedTokenData = t7;
7991
+ selectedTokenData = t11;
7959
7992
  selectedChainData = matchingChain;
7960
7993
  break;
7961
7994
  }
7962
7995
  }
7963
7996
  }
7964
7997
  if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
7965
- for (const t7 of supportedTokens) {
7966
- if (t7.symbol !== defaultSourceSymbol) continue;
7967
- const matchedChain = t7.chains.find(
7998
+ for (const t11 of supportedTokens) {
7999
+ if (t11.symbol !== defaultSourceSymbol) continue;
8000
+ const matchedChain = t11.chains.find(
7968
8001
  (c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
7969
8002
  );
7970
8003
  if (matchedChain) {
7971
- selectedTokenData = t7;
8004
+ selectedTokenData = t11;
7972
8005
  selectedChainData = matchedChain;
7973
8006
  break;
7974
8007
  }
7975
8008
  }
7976
8009
  }
7977
8010
  if (!selectedTokenData) {
7978
- for (const t7 of supportedTokens) {
7979
- if (t7.chains.length > 0) {
7980
- selectedTokenData = t7;
7981
- selectedChainData = t7.chains[0];
8011
+ for (const t11 of supportedTokens) {
8012
+ if (t11.chains.length > 0) {
8013
+ selectedTokenData = t11;
8014
+ selectedChainData = t11.chains[0];
7982
8015
  break;
7983
8016
  }
7984
8017
  }
@@ -8027,7 +8060,7 @@ function useDefaultSourceToken({
8027
8060
  ]);
8028
8061
  useEffect16(() => {
8029
8062
  if (!supportedTokens.length || !token) return;
8030
- const currentToken = supportedTokens.find((t7) => t7.symbol === token);
8063
+ const currentToken = supportedTokens.find((t11) => t11.symbol === token);
8031
8064
  if (!currentToken || currentToken.chains.length === 0) return;
8032
8065
  const isChainAvailable = chain && currentToken.chains.some((c) => {
8033
8066
  return getChainKey(c.chain_id, c.chain_type) === chain;
@@ -8299,6 +8332,7 @@ var parseChainKey = (chainKey) => {
8299
8332
  function TransferCryptoSingleInput({
8300
8333
  userId,
8301
8334
  publishableKey,
8335
+ clientSecret,
8302
8336
  recipientAddress,
8303
8337
  destinationChainType,
8304
8338
  destinationChainId,
@@ -8311,7 +8345,9 @@ function TransferCryptoSingleInput({
8311
8345
  onExecutionsChange,
8312
8346
  onDepositSuccess,
8313
8347
  onDepositError,
8314
- wallets: externalWallets
8348
+ wallets: externalWallets,
8349
+ onSourceTokenChange,
8350
+ checkoutQuote
8315
8351
  }) {
8316
8352
  const { themeClass, colors: colors2, fonts, components } = useTheme();
8317
8353
  const isDarkMode = themeClass.includes("uf-dark");
@@ -8353,8 +8389,8 @@ function TransferCryptoSingleInput({
8353
8389
  const error = walletsError?.message ?? null;
8354
8390
  const allAvailableChains = useMemo5(() => {
8355
8391
  const chainsMap = /* @__PURE__ */ new Map();
8356
- supportedTokens.forEach((t7) => {
8357
- t7.chains.forEach((c) => {
8392
+ supportedTokens.forEach((t11) => {
8393
+ t11.chains.forEach((c) => {
8358
8394
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8359
8395
  if (!chainsMap.has(comboKey)) {
8360
8396
  chainsMap.set(comboKey, c);
@@ -8378,18 +8414,34 @@ function TransferCryptoSingleInput({
8378
8414
  } = useDepositPolling({
8379
8415
  userId,
8380
8416
  publishableKey,
8417
+ clientSecret,
8381
8418
  depositConfirmationMode,
8382
8419
  depositWalletId: currentWallet?.id,
8383
8420
  enabled: true,
8384
8421
  onDepositSuccess,
8385
8422
  onDepositError
8386
8423
  });
8424
+ useEffect17(() => {
8425
+ if (!onSourceTokenChange || !token || !chain || !initialSelectionDone) return;
8426
+ const { chainType, chainId } = parseChainKey(chain);
8427
+ const matchedToken = supportedTokens.find((t11) => t11.symbol === token);
8428
+ const matchedChain = matchedToken?.chains.find(
8429
+ (c) => c.chain_type === chainType && c.chain_id === chainId
8430
+ );
8431
+ onSourceTokenChange({
8432
+ symbol: token,
8433
+ chainType,
8434
+ chainId,
8435
+ tokenAddress: matchedChain?.token_address ?? "",
8436
+ minimumDepositAmountUsd: matchedChain?.minimum_deposit_amount_usd ?? 0
8437
+ });
8438
+ }, [token, chain, initialSelectionDone, onSourceTokenChange, supportedTokens]);
8387
8439
  useEffect17(() => {
8388
8440
  if (onExecutionsChange) {
8389
8441
  onExecutionsChange(depositExecutions);
8390
8442
  }
8391
8443
  }, [depositExecutions, onExecutionsChange]);
8392
- const selectedToken = token ? supportedTokens.find((t7) => t7.symbol === token) : void 0;
8444
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8393
8445
  const availableChainsForToken = selectedToken?.chains || [];
8394
8446
  const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
8395
8447
  const key = getChainKey2(c.chain_id, c.chain_type);
@@ -8403,7 +8455,7 @@ function TransferCryptoSingleInput({
8403
8455
  setCopied(true);
8404
8456
  setTimeout(() => setCopied(false), 2e3);
8405
8457
  };
8406
- const formatProcessingTime2 = (seconds) => {
8458
+ const formatProcessingTime3 = (seconds) => {
8407
8459
  if (seconds === null) {
8408
8460
  return t4.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
8409
8461
  }
@@ -8530,6 +8582,53 @@ function TransferCryptoSingleInput({
8530
8582
  /* @__PURE__ */ jsx41("span", { children: "Retrying automatically every 5 seconds..." })
8531
8583
  ] })
8532
8584
  ] }),
8585
+ checkoutQuote && /* @__PURE__ */ jsxs35(
8586
+ "div",
8587
+ {
8588
+ className: "uf-rounded-xl uf-px-3 uf-py-2 uf-flex uf-items-center uf-justify-between",
8589
+ style: {
8590
+ backgroundColor: components.card.backgroundColor,
8591
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`,
8592
+ borderRadius: components.card.borderRadius
8593
+ },
8594
+ children: [
8595
+ /* @__PURE__ */ jsx41(
8596
+ "span",
8597
+ {
8598
+ className: "uf-text-xs",
8599
+ style: { color: components.card.subtitleColor, fontFamily: fonts.regular },
8600
+ children: "You send"
8601
+ }
8602
+ ),
8603
+ /* @__PURE__ */ jsxs35(
8604
+ "span",
8605
+ {
8606
+ className: "uf-text-sm uf-font-semibold",
8607
+ style: { color: components.card.titleColor, fontFamily: fonts.semibold },
8608
+ children: [
8609
+ (Number(checkoutQuote.sourceAmount) / 10 ** checkoutQuote.sourceTokenDecimals).toFixed(
8610
+ Math.min(checkoutQuote.sourceTokenDecimals, 6)
8611
+ ),
8612
+ " ",
8613
+ checkoutQuote.sourceTokenSymbol,
8614
+ checkoutQuote.sourceAmountUsd && /* @__PURE__ */ jsxs35(
8615
+ "span",
8616
+ {
8617
+ className: "uf-text-xs uf-font-normal uf-ml-1.5",
8618
+ style: { color: components.card.subtitleColor },
8619
+ children: [
8620
+ "($",
8621
+ checkoutQuote.sourceAmountUsd,
8622
+ ")"
8623
+ ]
8624
+ }
8625
+ )
8626
+ ]
8627
+ }
8628
+ )
8629
+ ]
8630
+ }
8631
+ ),
8533
8632
  /* @__PURE__ */ jsxs35("div", { className: "uf-flex uf-flex-col uf-items-center uf-pt-2", children: [
8534
8633
  /* @__PURE__ */ jsx41("div", { className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1", style: { color: components.card.labelColor }, children: "Intent address" }),
8535
8634
  /* @__PURE__ */ jsx41("div", { className: "uf-shadow-lg", style: { borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: loading || tokensLoading || !initialSelectionDone ? (
@@ -8612,7 +8711,7 @@ function TransferCryptoSingleInput({
8612
8711
  t4.processingTime.label,
8613
8712
  ":",
8614
8713
  " ",
8615
- /* @__PURE__ */ jsx41("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
8714
+ /* @__PURE__ */ jsx41("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
8616
8715
  ] })
8617
8716
  ] }),
8618
8717
  detailsExpanded ? /* @__PURE__ */ jsx41(ChevronUp2, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ jsx41(ChevronDown3, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
@@ -8939,8 +9038,8 @@ function TransferCryptoDoubleInput({
8939
9038
  const error = walletsError?.message ?? null;
8940
9039
  const allAvailableChains = useMemo6(() => {
8941
9040
  const chainsMap = /* @__PURE__ */ new Map();
8942
- supportedTokens.forEach((t7) => {
8943
- t7.chains.forEach((c) => {
9041
+ supportedTokens.forEach((t11) => {
9042
+ t11.chains.forEach((c) => {
8944
9043
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8945
9044
  if (!chainsMap.has(comboKey)) {
8946
9045
  chainsMap.set(comboKey, c);
@@ -8975,7 +9074,7 @@ function TransferCryptoDoubleInput({
8975
9074
  onExecutionsChange(depositExecutions);
8976
9075
  }
8977
9076
  }, [depositExecutions, onExecutionsChange]);
8978
- const selectedToken = token ? supportedTokens.find((t7) => t7.symbol === token) : void 0;
9077
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8979
9078
  const availableChainsForToken = selectedToken?.chains || [];
8980
9079
  const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
8981
9080
  const key = getChainKey3(c.chain_id, c.chain_type);
@@ -8989,7 +9088,7 @@ function TransferCryptoDoubleInput({
8989
9088
  setCopied(true);
8990
9089
  setTimeout(() => setCopied(false), 2e3);
8991
9090
  };
8992
- const formatProcessingTime2 = (seconds) => {
9091
+ const formatProcessingTime3 = (seconds) => {
8993
9092
  if (seconds === null) {
8994
9093
  return t5.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
8995
9094
  }
@@ -9216,7 +9315,7 @@ function TransferCryptoDoubleInput({
9216
9315
  t5.processingTime.label,
9217
9316
  ":",
9218
9317
  " ",
9219
- /* @__PURE__ */ jsx43("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
9318
+ /* @__PURE__ */ jsx43("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
9220
9319
  ] })
9221
9320
  ] }),
9222
9321
  detailsExpanded ? /* @__PURE__ */ jsx43(ChevronUp4, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ jsx43(ChevronDown5, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
@@ -9399,9 +9498,16 @@ function SelectTokenView({
9399
9498
  onBack,
9400
9499
  onClose,
9401
9500
  onDisconnectWallet,
9402
- isDisconnectingWallet = false
9501
+ isDisconnectingWallet = false,
9502
+ checkoutAmountUsd,
9503
+ checkoutReceivedUsd
9403
9504
  }) {
9404
9505
  const { colors: colors2, fonts, components } = useTheme();
9506
+ const isCheckout = !!checkoutAmountUsd;
9507
+ const headerSubtitle = isCheckout ? parseFloat(checkoutReceivedUsd || "0") > 0 ? `$${checkoutReceivedUsd} / $${checkoutAmountUsd} received` : `Amount due: $${checkoutAmountUsd}` : formatBalanceDisplay(
9508
+ `$${totalBalanceUsd || "0.00"}`,
9509
+ projectName
9510
+ );
9405
9511
  return /* @__PURE__ */ jsxs38(
9406
9512
  "div",
9407
9513
  {
@@ -9410,11 +9516,8 @@ function SelectTokenView({
9410
9516
  /* @__PURE__ */ jsx45(
9411
9517
  DepositHeader,
9412
9518
  {
9413
- title: "Select Token",
9414
- subtitle: formatBalanceDisplay(
9415
- `$${totalBalanceUsd || "0.00"}`,
9416
- projectName
9417
- ),
9519
+ title: isCheckout ? "Select Token" : "Select Token",
9520
+ subtitle: headerSubtitle,
9418
9521
  showBack: true,
9419
9522
  onBack,
9420
9523
  onClose
@@ -9645,10 +9748,19 @@ function EnterAmountView({
9645
9748
  onReview,
9646
9749
  onBack,
9647
9750
  onClose,
9648
- quickSelectMode
9751
+ quickSelectMode,
9752
+ checkoutAmountUsd,
9753
+ checkoutReceivedUsd
9649
9754
  }) {
9650
9755
  const { colors: colors2, fonts, components } = useTheme();
9756
+ const isCheckout = !!checkoutAmountUsd;
9651
9757
  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}`;
9758
+ const checkoutRemainingUsd = isCheckout ? Math.max(
9759
+ parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0"),
9760
+ 0
9761
+ ).toFixed(2) : null;
9762
+ const headerTitle = isCheckout ? `Pay $${checkoutRemainingUsd}` : "Enter Amount";
9763
+ const headerSubtitle = isCheckout ? parseFloat(checkoutReceivedUsd || "0") > 0 ? `$${checkoutReceivedUsd} / $${checkoutAmountUsd} received` : null : balanceSubtitle;
9652
9764
  const usePercentageChips = quickSelectMode === "percentage" && maxUsdAmount > 0;
9653
9765
  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";
9654
9766
  return /* @__PURE__ */ jsxs39(
@@ -9662,14 +9774,27 @@ function EnterAmountView({
9662
9774
  /* @__PURE__ */ jsx46(
9663
9775
  DepositHeader,
9664
9776
  {
9665
- title: "Enter Amount",
9666
- subtitle: balanceSubtitle,
9777
+ title: headerTitle,
9778
+ subtitle: headerSubtitle ?? void 0,
9667
9779
  showBack: true,
9668
9780
  onBack,
9669
9781
  onClose
9670
9782
  }
9671
9783
  ),
9672
- walletInfoProp ? /* @__PURE__ */ jsx46("div", { className: "uf-flex uf-w-full uf-justify-center uf-mb-3", children: /* @__PURE__ */ jsx46(WalletWithNetworkBadge, { walletInfo: walletInfoProp }) }) : null,
9784
+ walletInfoProp ? /* @__PURE__ */ jsx46("div", { className: "uf-flex uf-w-full uf-justify-center uf-mb-3", children: /* @__PURE__ */ jsxs39("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-1", children: [
9785
+ /* @__PURE__ */ jsx46(WalletWithNetworkBadge, { walletInfo: walletInfoProp }),
9786
+ isCheckout && /* @__PURE__ */ jsx46(
9787
+ "span",
9788
+ {
9789
+ className: "uf-text-xs",
9790
+ style: {
9791
+ color: colors2.foregroundMuted,
9792
+ fontFamily: fonts.regular
9793
+ },
9794
+ children: balanceSubtitle
9795
+ }
9796
+ )
9797
+ ] }) }) : null,
9673
9798
  /* @__PURE__ */ jsxs39("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: [
9674
9799
  /* @__PURE__ */ jsxs39("div", { className: "uf-min-h-0 uf-flex-1", children: [
9675
9800
  /* @__PURE__ */ jsxs39("div", { className: "uf-text-center uf-py-8", children: [
@@ -9692,7 +9817,9 @@ function EnterAmountView({
9692
9817
  inputMode: "decimal",
9693
9818
  placeholder: "0",
9694
9819
  value: amountUsd,
9820
+ readOnly: isCheckout,
9695
9821
  onChange: (e) => {
9822
+ if (isCheckout) return;
9696
9823
  const value = e.target.value;
9697
9824
  if (value === "" || /^\d*\.?\d*$/.test(value)) {
9698
9825
  const decimalIndex = value.indexOf(".");
@@ -9703,7 +9830,7 @@ function EnterAmountView({
9703
9830
  onAmountChange(value);
9704
9831
  }
9705
9832
  },
9706
- className: "uf-bg-transparent uf-outline-none uf-text-center uf-font-normal uf-w-auto uf-min-w-[60px]",
9833
+ className: `uf-bg-transparent uf-outline-none uf-text-center uf-font-normal uf-w-auto uf-min-w-[60px] ${isCheckout ? "uf-cursor-default" : ""}`,
9707
9834
  style: {
9708
9835
  fontSize: `${Math.max(3.75 - (amountUsd || "0").length * 0.15, 2)}rem`,
9709
9836
  color: components.input.textColor,
@@ -9725,7 +9852,7 @@ function EnterAmountView({
9725
9852
  }
9726
9853
  )
9727
9854
  ] }),
9728
- /* @__PURE__ */ jsx46("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__ */ jsxs39(Fragment5, { children: [
9855
+ !isCheckout && /* @__PURE__ */ jsx46("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__ */ jsxs39(Fragment5, { children: [
9729
9856
  PERCENT_QUICK_AMOUNTS.map((pct) => /* @__PURE__ */ jsxs39(
9730
9857
  "button",
9731
9858
  {
@@ -9794,7 +9921,46 @@ function EnterAmountView({
9794
9921
  }
9795
9922
  )
9796
9923
  ] }) }),
9797
- tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && /* @__PURE__ */ jsxs39(
9924
+ tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && inputUsdNum > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ jsxs39(
9925
+ "div",
9926
+ {
9927
+ className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
9928
+ style: {
9929
+ backgroundColor: colors2.warning + "15",
9930
+ border: `1px solid ${colors2.warning}30`,
9931
+ borderRadius: components.card.borderRadius,
9932
+ animation: "uf-fadeSlideIn 0.4s ease-out"
9933
+ },
9934
+ children: [
9935
+ /* @__PURE__ */ jsxs39(
9936
+ "div",
9937
+ {
9938
+ className: "uf-text-xs uf-font-medium",
9939
+ style: { color: colors2.warning, fontFamily: fonts.medium },
9940
+ children: [
9941
+ "Minimum for ",
9942
+ selectedToken.symbol,
9943
+ " on ",
9944
+ selectedToken.chain_name,
9945
+ " is $",
9946
+ tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
9947
+ ]
9948
+ }
9949
+ ),
9950
+ /* @__PURE__ */ jsxs39(
9951
+ "div",
9952
+ {
9953
+ className: "uf-text-xs uf-mt-0.5",
9954
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
9955
+ children: [
9956
+ "Amount adjusted from remaining $",
9957
+ (parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0")).toFixed(2)
9958
+ ]
9959
+ }
9960
+ )
9961
+ ]
9962
+ }
9963
+ ) : /* @__PURE__ */ jsxs39(
9798
9964
  "div",
9799
9965
  {
9800
9966
  className: "uf-text-center uf-text-xs uf-mb-3",
@@ -9804,7 +9970,7 @@ function EnterAmountView({
9804
9970
  tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
9805
9971
  ]
9806
9972
  }
9807
- ),
9973
+ )),
9808
9974
  inputUsdNum > 0 && /* @__PURE__ */ jsx46(Fragment5, { children: inputUsdNum > maxUsdAmount ? /* @__PURE__ */ jsx46(
9809
9975
  "div",
9810
9976
  {
@@ -9819,7 +9985,44 @@ function EnterAmountView({
9819
9985
  style: { color: colors2.error },
9820
9986
  children: error
9821
9987
  }
9822
- ) })
9988
+ ) }),
9989
+ isCheckout && selectedToken.icon_url && /* @__PURE__ */ jsxs39("div", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2 uf-py-2", children: [
9990
+ /* @__PURE__ */ jsxs39("div", { className: "uf-relative", children: [
9991
+ /* @__PURE__ */ jsx46(
9992
+ "img",
9993
+ {
9994
+ src: selectedToken.icon_url,
9995
+ alt: selectedToken.symbol,
9996
+ width: 20,
9997
+ height: 20,
9998
+ className: "uf-w-5 uf-h-5 uf-rounded-full"
9999
+ }
10000
+ ),
10001
+ selectedToken.chain_icon_url && /* @__PURE__ */ jsx46(
10002
+ "img",
10003
+ {
10004
+ src: selectedToken.chain_icon_url,
10005
+ alt: selectedToken.chain_name,
10006
+ width: 10,
10007
+ height: 10,
10008
+ className: "uf-w-2.5 uf-h-2.5 uf-rounded-full uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-border",
10009
+ style: { borderColor: colors2.background }
10010
+ }
10011
+ )
10012
+ ] }),
10013
+ /* @__PURE__ */ jsxs39(
10014
+ "span",
10015
+ {
10016
+ className: "uf-text-xs",
10017
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
10018
+ children: [
10019
+ selectedToken.symbol,
10020
+ " on ",
10021
+ selectedToken.chain_name
10022
+ ]
10023
+ }
10024
+ )
10025
+ ] })
9823
10026
  ] }),
9824
10027
  /* @__PURE__ */ jsx46("div", { className: "uf-shrink-0 uf-pt-2", children: /* @__PURE__ */ jsx46(
9825
10028
  "button",
@@ -9845,8 +10048,20 @@ function EnterAmountView({
9845
10048
  }
9846
10049
 
9847
10050
  // src/components/deposits/browser-wallets/ReviewView.tsx
9848
- import { ChevronDown as ChevronDown6, ChevronUp as ChevronUp5 } from "lucide-react";
10051
+ import { ChevronDown as ChevronDown6, ChevronUp as ChevronUp5, Loader2 as Loader23 } from "lucide-react";
9849
10052
  import { Fragment as Fragment6, jsx as jsx47, jsxs as jsxs40 } from "react/jsx-runtime";
10053
+ var WALLET_ICONS2 = {
10054
+ metamask: MetamaskIcon,
10055
+ phantom: PhantomIcon,
10056
+ coinbase: CoinbaseIcon,
10057
+ trust: TrustIcon,
10058
+ rainbow: RainbowIcon,
10059
+ rabby: RabbyIcon,
10060
+ okx: OkxIcon,
10061
+ solflare: SolflareIcon,
10062
+ backpack: BackpackIcon,
10063
+ glow: GlowIcon
10064
+ };
9850
10065
  function ReviewView({
9851
10066
  walletInfo,
9852
10067
  recipientAddress,
@@ -9881,30 +10096,17 @@ function ReviewView({
9881
10096
  ),
9882
10097
  /* @__PURE__ */ jsxs40("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: [
9883
10098
  /* @__PURE__ */ jsxs40("div", { className: "uf-min-h-0 uf-flex-1 uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: [
9884
- /* @__PURE__ */ jsxs40("div", { className: "uf-text-center", children: [
9885
- /* @__PURE__ */ jsxs40(
9886
- "div",
9887
- {
9888
- className: "uf-text-4xl uf-font-medium",
9889
- style: { color: colors2.foreground, fontFamily: fonts.medium },
9890
- children: [
9891
- "$",
9892
- amountUsd || "0"
9893
- ]
9894
- }
9895
- ),
9896
- formattedTokenAmount && /* @__PURE__ */ jsxs40(
9897
- "div",
9898
- {
9899
- className: "uf-text-sm uf-mt-2",
9900
- style: { color: colors2.foregroundMuted },
9901
- children: [
9902
- "\u2248 ",
9903
- formattedTokenAmount
9904
- ]
9905
- }
9906
- )
9907
- ] }),
10099
+ /* @__PURE__ */ jsx47("div", { className: "uf-text-center", children: /* @__PURE__ */ jsxs40(
10100
+ "div",
10101
+ {
10102
+ className: "uf-text-4xl uf-font-medium",
10103
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
10104
+ children: [
10105
+ "$",
10106
+ amountUsd || "0"
10107
+ ]
10108
+ }
10109
+ ) }),
9908
10110
  /* @__PURE__ */ jsxs40(
9909
10111
  "div",
9910
10112
  {
@@ -9921,7 +10123,31 @@ function ReviewView({
9921
10123
  {
9922
10124
  className: "uf-text-sm",
9923
10125
  style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
9924
- children: "Source"
10126
+ children: "From"
10127
+ }
10128
+ ),
10129
+ /* @__PURE__ */ jsxs40("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
10130
+ WALLET_ICONS2[walletInfo.icon] && (() => {
10131
+ const Icon2 = WALLET_ICONS2[walletInfo.icon];
10132
+ return /* @__PURE__ */ jsx47("div", { className: "uf-w-5 uf-h-5 uf-rounded-full uf-overflow-hidden uf-flex-shrink-0", children: /* @__PURE__ */ jsx47(Icon2, { size: 20, variant: "color" }) });
10133
+ })(),
10134
+ /* @__PURE__ */ jsx47(
10135
+ "span",
10136
+ {
10137
+ className: "uf-text-sm uf-font-medium",
10138
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
10139
+ children: walletInfo.name
10140
+ }
10141
+ )
10142
+ ] })
10143
+ ] }),
10144
+ /* @__PURE__ */ jsxs40("div", { className: "uf-flex uf-justify-between uf-items-center", children: [
10145
+ /* @__PURE__ */ jsx47(
10146
+ "span",
10147
+ {
10148
+ className: "uf-text-sm",
10149
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
10150
+ children: "You send"
9925
10151
  }
9926
10152
  ),
9927
10153
  /* @__PURE__ */ jsxs40("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
@@ -9933,17 +10159,12 @@ function ReviewView({
9933
10159
  className: "uf-w-5 uf-h-5 uf-rounded-full"
9934
10160
  }
9935
10161
  ),
9936
- /* @__PURE__ */ jsxs40(
10162
+ /* @__PURE__ */ jsx47(
9937
10163
  "span",
9938
10164
  {
9939
10165
  className: "uf-text-sm uf-font-medium",
9940
10166
  style: { color: colors2.foreground, fontFamily: fonts.medium },
9941
- children: [
9942
- walletInfo.name,
9943
- " (",
9944
- truncateAddress2(walletInfo.address),
9945
- ")"
9946
- ]
10167
+ children: formattedTokenAmount || `$${amountUsd}`
9947
10168
  }
9948
10169
  )
9949
10170
  ] })
@@ -10106,7 +10327,10 @@ function ReviewView({
10106
10327
  borderRadius: components.button.borderRadius,
10107
10328
  border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
10108
10329
  },
10109
- children: isConfirming ? "Confirming..." : "Confirm Order"
10330
+ children: isConfirming ? /* @__PURE__ */ jsxs40("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
10331
+ /* @__PURE__ */ jsx47(Loader23, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
10332
+ "Confirming..."
10333
+ ] }) : "Confirm Order"
10110
10334
  }
10111
10335
  ) })
10112
10336
  ] })
@@ -10117,20 +10341,38 @@ function ReviewView({
10117
10341
  }
10118
10342
 
10119
10343
  // src/components/deposits/browser-wallets/ConfirmingView.tsx
10120
- import { useCallback as useCallback2, useState as useState24 } from "react";
10121
- import { Loader2 as Loader23, CheckCircle2 } from "lucide-react";
10344
+ import { useCallback as useCallback2, useEffect as useEffect19, useState as useState24 } from "react";
10345
+ import { Loader2 as Loader24, CheckCircle2, ArrowRight } from "lucide-react";
10122
10346
  import { Fragment as Fragment7, jsx as jsx48, jsxs as jsxs41 } from "react/jsx-runtime";
10347
+ var SETTLE_FALLBACK_MS = 15e3;
10123
10348
  function ConfirmingView({
10124
10349
  isConfirming,
10125
10350
  onClose,
10126
10351
  executions = [],
10127
- isPolling = false
10352
+ isPolling = false,
10353
+ onNewDeposit,
10354
+ onDone,
10355
+ paymentIntentStatus,
10356
+ amountReceivedUsd,
10357
+ amountReceivedUsdAtSubmission
10128
10358
  }) {
10129
- const { colors: colors2, fonts } = useTheme();
10359
+ const { colors: colors2, fonts, components } = useTheme();
10130
10360
  const [containerEl, setContainerEl] = useState24(null);
10131
10361
  const containerCallbackRef = useCallback2((el) => {
10132
10362
  setContainerEl(el);
10133
10363
  }, []);
10364
+ const [fallbackSettled, setFallbackSettled] = useState24(false);
10365
+ const hasExecution = executions.length > 0;
10366
+ const isCheckoutMode = paymentIntentStatus != null;
10367
+ const isPaymentComplete = paymentIntentStatus === "succeeded";
10368
+ const amountChanged = amountReceivedUsdAtSubmission != null && amountReceivedUsd != null && amountReceivedUsd !== amountReceivedUsdAtSubmission;
10369
+ const piSettled = !isCheckoutMode || isPaymentComplete || amountChanged || fallbackSettled;
10370
+ useEffect19(() => {
10371
+ if (!hasExecution || piSettled) return;
10372
+ const timeout = setTimeout(() => setFallbackSettled(true), SETTLE_FALLBACK_MS);
10373
+ return () => clearTimeout(timeout);
10374
+ }, [hasExecution, piSettled]);
10375
+ const showButtons = hasExecution && piSettled;
10134
10376
  return /* @__PURE__ */ jsx48(PortalContainerProvider, { value: containerEl, children: /* @__PURE__ */ jsxs41(
10135
10377
  "div",
10136
10378
  {
@@ -10143,13 +10385,13 @@ function ConfirmingView({
10143
10385
  /* @__PURE__ */ jsx48(
10144
10386
  DepositHeader,
10145
10387
  {
10146
- title: isConfirming ? "Confirming..." : "Processing",
10147
- onClose
10388
+ title: isConfirming ? "Confirming..." : hasExecution && isPaymentComplete ? "Payment Complete" : hasExecution ? "Deposit Received" : "Processing",
10389
+ onClose: isPaymentComplete && onDone ? onDone : onClose
10148
10390
  }
10149
10391
  ),
10150
10392
  /* @__PURE__ */ jsx48("div", { className: "uf-flex uf-flex-1 uf-flex-col uf-items-center uf-justify-center uf-py-8", children: isConfirming ? /* @__PURE__ */ jsxs41(Fragment7, { children: [
10151
10393
  /* @__PURE__ */ jsx48(
10152
- Loader23,
10394
+ Loader24,
10153
10395
  {
10154
10396
  className: "uf-w-12 uf-h-12 uf-animate-spin uf-mb-4",
10155
10397
  style: { color: colors2.primary }
@@ -10171,11 +10413,70 @@ function ConfirmingView({
10171
10413
  children: "Please confirm the transaction in your wallet"
10172
10414
  }
10173
10415
  )
10174
- ] }) : /* @__PURE__ */ jsxs41(Fragment7, { children: [
10416
+ ] }) : hasExecution ? /* @__PURE__ */ jsxs41(Fragment7, { children: [
10175
10417
  /* @__PURE__ */ jsx48(
10176
10418
  CheckCircle2,
10177
10419
  {
10178
10420
  className: "uf-w-12 uf-h-12 uf-mb-4",
10421
+ style: { color: "rgb(34, 197, 94)" }
10422
+ }
10423
+ ),
10424
+ /* @__PURE__ */ jsx48(
10425
+ "div",
10426
+ {
10427
+ className: "uf-text-lg uf-font-medium",
10428
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
10429
+ children: isPaymentComplete ? "Payment Complete" : "Deposit Received"
10430
+ }
10431
+ ),
10432
+ /* @__PURE__ */ jsx48(
10433
+ "div",
10434
+ {
10435
+ className: "uf-text-sm uf-mt-2 uf-text-center uf-px-6",
10436
+ style: { color: colors2.foregroundMuted },
10437
+ children: isPaymentComplete ? "Your payment has been fulfilled." : showButtons ? "Your deposit is being processed." : "Checking payment status..."
10438
+ }
10439
+ ),
10440
+ /* @__PURE__ */ jsx48("div", { className: "uf-mt-6 uf-flex uf-flex-col uf-items-center uf-gap-3", children: !showButtons ? /* @__PURE__ */ jsx48(
10441
+ Loader24,
10442
+ {
10443
+ className: "uf-w-5 uf-h-5 uf-animate-spin",
10444
+ style: { color: colors2.foregroundMuted }
10445
+ }
10446
+ ) : isPaymentComplete && onDone ? /* @__PURE__ */ jsx48(
10447
+ "button",
10448
+ {
10449
+ onClick: onDone,
10450
+ className: "uf-w-full uf-py-3 uf-px-8 uf-text-sm uf-font-medium uf-transition-opacity hover:uf-opacity-80",
10451
+ style: {
10452
+ backgroundColor: colors2.primary,
10453
+ color: colors2.primaryForeground,
10454
+ fontFamily: fonts.medium,
10455
+ borderRadius: components.button.borderRadius
10456
+ },
10457
+ children: "Done"
10458
+ }
10459
+ ) : onNewDeposit ? /* @__PURE__ */ jsxs41(
10460
+ "button",
10461
+ {
10462
+ onClick: onNewDeposit,
10463
+ 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",
10464
+ style: {
10465
+ backgroundColor: colors2.primary,
10466
+ color: colors2.primaryForeground,
10467
+ fontFamily: fonts.medium
10468
+ },
10469
+ children: [
10470
+ "Make another deposit",
10471
+ /* @__PURE__ */ jsx48(ArrowRight, { className: "uf-w-4 uf-h-4" })
10472
+ ]
10473
+ }
10474
+ ) : null })
10475
+ ] }) : /* @__PURE__ */ jsxs41(Fragment7, { children: [
10476
+ /* @__PURE__ */ jsx48(
10477
+ Loader24,
10478
+ {
10479
+ className: "uf-w-12 uf-h-12 uf-animate-spin uf-mb-4",
10179
10480
  style: { color: colors2.primary }
10180
10481
  }
10181
10482
  ),
@@ -10192,7 +10493,7 @@ function ConfirmingView({
10192
10493
  {
10193
10494
  className: "uf-text-sm uf-mt-2 uf-text-center uf-px-6",
10194
10495
  style: { color: colors2.foregroundMuted },
10195
- children: "You can close this window or wait for confirmation."
10496
+ children: "Waiting for your deposit to be detected..."
10196
10497
  }
10197
10498
  )
10198
10499
  ] }) }),
@@ -10219,6 +10520,7 @@ function BrowserWalletModal({
10219
10520
  depositWallet,
10220
10521
  userId,
10221
10522
  publishableKey,
10523
+ clientSecret,
10222
10524
  assetCdnUrl,
10223
10525
  projectName,
10224
10526
  theme = "dark",
@@ -10227,7 +10529,13 @@ function BrowserWalletModal({
10227
10529
  onDepositSuccess,
10228
10530
  onDepositError,
10229
10531
  amountQuickSelect = "percentage",
10230
- onWalletDisconnect
10532
+ onWalletDisconnect,
10533
+ prefillAmountUsd,
10534
+ checkoutAmountUsd,
10535
+ checkoutReceivedUsd,
10536
+ onNewDeposit,
10537
+ onDone,
10538
+ paymentIntentStatus
10231
10539
  }) {
10232
10540
  const { colors: colors2, fonts, components } = useTheme();
10233
10541
  const [step, setStep] = React26.useState("select-token");
@@ -10245,6 +10553,7 @@ function BrowserWalletModal({
10245
10553
  const [tokenChainDetails, setTokenChainDetails] = React26.useState(null);
10246
10554
  const [loadingTokenDetails, setLoadingTokenDetails] = React26.useState(false);
10247
10555
  const [showTransactionDetails, setShowTransactionDetails] = React26.useState(false);
10556
+ const [receivedUsdAtSubmission, setReceivedUsdAtSubmission] = React26.useState(null);
10248
10557
  const themeClass = theme === "dark" ? "uf-dark" : "";
10249
10558
  const chainType = depositWallet.chain_type;
10250
10559
  const recipientAddress = depositWallet.address;
@@ -10252,15 +10561,19 @@ function BrowserWalletModal({
10252
10561
  const { executions: depositExecutions, isPolling } = useDepositPolling({
10253
10562
  userId,
10254
10563
  publishableKey,
10564
+ clientSecret,
10255
10565
  enabled: open && hasSignedTransaction,
10256
10566
  onDepositSuccess,
10257
10567
  onDepositError
10258
10568
  });
10569
+ const prevOpenRef = React26.useRef(false);
10259
10570
  React26.useEffect(() => {
10260
- if (open) {
10571
+ const wasOpen = prevOpenRef.current;
10572
+ prevOpenRef.current = open;
10573
+ if (open && !wasOpen) {
10261
10574
  setStep("select-token");
10262
10575
  setSelectedBalance(null);
10263
- setAmountUsd("");
10576
+ setAmountUsd(prefillAmountUsd ?? "");
10264
10577
  setError(null);
10265
10578
  setIsConfirming(false);
10266
10579
  setTokenChainDetails(null);
@@ -10268,7 +10581,15 @@ function BrowserWalletModal({
10268
10581
  setHasSignedTransaction(false);
10269
10582
  setIsDisconnectingWallet(false);
10270
10583
  }
10271
- }, [open]);
10584
+ }, [open, prefillAmountUsd]);
10585
+ React26.useEffect(() => {
10586
+ if (!prefillAmountUsd || !tokenChainDetails || step !== "input-amount") return;
10587
+ const minDeposit = tokenChainDetails.minimum_deposit_amount_usd || 0;
10588
+ const currentAmount = parseFloat(amountUsd) || 0;
10589
+ if (currentAmount > 0 && currentAmount < minDeposit) {
10590
+ setAmountUsd(minDeposit.toFixed(2));
10591
+ }
10592
+ }, [tokenChainDetails, step, prefillAmountUsd]);
10272
10593
  React26.useEffect(() => {
10273
10594
  if (step === "review") {
10274
10595
  setShowTransactionDetails(false);
@@ -10295,7 +10616,7 @@ function BrowserWalletModal({
10295
10616
  );
10296
10617
  if (cancelled) return;
10297
10618
  const supportedToken = response.data.find(
10298
- (t7) => t7.symbol.toLowerCase() === token.symbol.toLowerCase()
10619
+ (t11) => t11.symbol.toLowerCase() === token.symbol.toLowerCase()
10299
10620
  );
10300
10621
  if (supportedToken) {
10301
10622
  const chainDetail = supportedToken.chains.find(
@@ -10386,7 +10707,7 @@ function BrowserWalletModal({
10386
10707
  setError(null);
10387
10708
  if (step === "input-amount") {
10388
10709
  setStep("select-token");
10389
- setAmountUsd("");
10710
+ setAmountUsd(prefillAmountUsd ?? "");
10390
10711
  setTokenChainDetails(null);
10391
10712
  } else if (step === "review") {
10392
10713
  setStep("input-amount");
@@ -10472,7 +10793,6 @@ function BrowserWalletModal({
10472
10793
  }
10473
10794
  }
10474
10795
  setIsConfirming(true);
10475
- setStep("confirming");
10476
10796
  setError(null);
10477
10797
  try {
10478
10798
  let txHash;
@@ -10490,16 +10810,17 @@ function BrowserWalletModal({
10490
10810
  } else {
10491
10811
  txHash = await sendEthereumTransaction(token, tokenAmount.toString());
10492
10812
  }
10813
+ setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
10493
10814
  setHasSignedTransaction(true);
10494
- onSuccess?.(txHash);
10495
10815
  setIsConfirming(false);
10816
+ setStep("confirming");
10817
+ onSuccess?.(txHash);
10496
10818
  } catch (err) {
10497
10819
  console.error("[BrowserWalletModal] Transaction error:", err);
10498
10820
  const errorMessage = err instanceof Error ? err.message : "Transaction failed";
10499
10821
  setError(errorMessage);
10500
10822
  onError?.(err instanceof Error ? err : new Error(errorMessage));
10501
10823
  setIsConfirming(false);
10502
- setStep("review");
10503
10824
  }
10504
10825
  };
10505
10826
  const sendEthereumTransaction = async (token, amountStr) => {
@@ -10748,7 +11069,9 @@ function BrowserWalletModal({
10748
11069
  onBack: handleClose,
10749
11070
  onClose: handleFullClose,
10750
11071
  onDisconnectWallet: onWalletDisconnect ? () => void handleDisconnectFromSelectToken() : void 0,
10751
- isDisconnectingWallet
11072
+ isDisconnectingWallet,
11073
+ checkoutAmountUsd,
11074
+ checkoutReceivedUsd
10752
11075
  }
10753
11076
  ),
10754
11077
  step === "input-amount" && selectedToken && selectedBalance && /* @__PURE__ */ jsx49(
@@ -10769,7 +11092,9 @@ function BrowserWalletModal({
10769
11092
  onReview: handleReview,
10770
11093
  onBack: handleBack,
10771
11094
  onClose: handleFullClose,
10772
- quickSelectMode: amountQuickSelect
11095
+ quickSelectMode: amountQuickSelect,
11096
+ checkoutAmountUsd,
11097
+ checkoutReceivedUsd
10773
11098
  }
10774
11099
  ),
10775
11100
  step === "review" && selectedToken && /* @__PURE__ */ jsx49(
@@ -10798,7 +11123,12 @@ function BrowserWalletModal({
10798
11123
  isConfirming,
10799
11124
  onClose: handleFullClose,
10800
11125
  executions: depositExecutions,
10801
- isPolling
11126
+ isPolling,
11127
+ onNewDeposit,
11128
+ onDone,
11129
+ paymentIntentStatus,
11130
+ amountReceivedUsd: checkoutReceivedUsd,
11131
+ amountReceivedUsdAtSubmission: receivedUsdAtSubmission
10802
11132
  }
10803
11133
  )
10804
11134
  ] })
@@ -10810,9 +11140,9 @@ function BrowserWalletModal({
10810
11140
 
10811
11141
  // src/components/deposits/WalletSelectionModal.tsx
10812
11142
  import * as React27 from "react";
10813
- import { ExternalLink as ExternalLink3, Loader2 as Loader24 } from "lucide-react";
11143
+ import { ExternalLink as ExternalLink3, Loader2 as Loader25 } from "lucide-react";
10814
11144
  import { jsx as jsx50, jsxs as jsxs43 } from "react/jsx-runtime";
10815
- var WALLET_ICONS2 = {
11145
+ var WALLET_ICONS3 = {
10816
11146
  metamask: MetamaskIcon,
10817
11147
  phantom: PhantomIcon,
10818
11148
  coinbase: CoinbaseIcon,
@@ -11251,10 +11581,10 @@ function WalletSelectionModal({
11251
11581
  },
11252
11582
  children: [
11253
11583
  /* @__PURE__ */ jsxs43("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
11254
- WALLET_ICONS2[wallet.id] ? /* @__PURE__ */ jsx50(
11584
+ WALLET_ICONS3[wallet.id] ? /* @__PURE__ */ jsx50(
11255
11585
  WalletIconWithNetwork,
11256
11586
  {
11257
- WalletIcon: WALLET_ICONS2[wallet.id],
11587
+ WalletIcon: WALLET_ICONS3[wallet.id],
11258
11588
  networks: wallet.networks,
11259
11589
  size: 40,
11260
11590
  className: "uf-rounded-lg"
@@ -11325,10 +11655,10 @@ function WalletSelectionModal({
11325
11655
  style: { minHeight: WALLET_STEP_BODY_MIN_HEIGHT },
11326
11656
  children: [
11327
11657
  /* @__PURE__ */ jsxs43("div", { className: "uf-flex uf-flex-col uf-items-center uf-pb-4 uf-shrink-0", children: [
11328
- /* @__PURE__ */ jsx50("div", { className: "uf-mb-2", children: WALLET_ICONS2[selectedWallet.id] ? /* @__PURE__ */ jsx50(
11658
+ /* @__PURE__ */ jsx50("div", { className: "uf-mb-2", children: WALLET_ICONS3[selectedWallet.id] ? /* @__PURE__ */ jsx50(
11329
11659
  WalletIconWithNetwork,
11330
11660
  {
11331
- WalletIcon: WALLET_ICONS2[selectedWallet.id],
11661
+ WalletIcon: WALLET_ICONS3[selectedWallet.id],
11332
11662
  networks: selectedWallet.networks,
11333
11663
  size: 48,
11334
11664
  className: "uf-rounded-lg"
@@ -11403,7 +11733,7 @@ function WalletSelectionModal({
11403
11733
  ] })
11404
11734
  ] }),
11405
11735
  connectingNetwork === network && /* @__PURE__ */ jsx50(
11406
- Loader24,
11736
+ Loader25,
11407
11737
  {
11408
11738
  className: "uf-w-4 uf-h-4 uf-animate-spin",
11409
11739
  style: { color: colors2.primary }
@@ -11426,7 +11756,7 @@ function WalletSelectionModal({
11426
11756
  ),
11427
11757
  step === "connecting" && /* @__PURE__ */ jsx50("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: /* @__PURE__ */ jsxs43("div", { className: "uf-flex uf-flex-1 uf-flex-col uf-items-center uf-justify-center uf-py-8", children: [
11428
11758
  /* @__PURE__ */ jsx50(
11429
- Loader24,
11759
+ Loader25,
11430
11760
  {
11431
11761
  className: "uf-w-12 uf-h-12 uf-animate-spin uf-mb-4",
11432
11762
  style: { color: colors2.primary }
@@ -11548,7 +11878,7 @@ function DepositModal({
11548
11878
  const [view, setView] = useState27(
11549
11879
  effectiveInitialScreen
11550
11880
  );
11551
- const resetViewTimeoutRef = useRef6(null);
11881
+ const resetViewTimeoutRef = useRef7(null);
11552
11882
  const [cardView, setCardView] = useState27(
11553
11883
  "amount"
11554
11884
  );
@@ -11578,7 +11908,7 @@ function DepositModal({
11578
11908
  const [resolvedTheme, setResolvedTheme] = useState27(
11579
11909
  theme === "auto" ? "dark" : theme
11580
11910
  );
11581
- useEffect21(() => {
11911
+ useEffect22(() => {
11582
11912
  if (theme === "auto") {
11583
11913
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
11584
11914
  setResolvedTheme(mediaQuery.matches ? "dark" : "light");
@@ -11607,11 +11937,11 @@ function DepositModal({
11607
11937
  chainType: destinationChainType,
11608
11938
  enabled: open
11609
11939
  });
11610
- useEffect21(() => {
11940
+ useEffect22(() => {
11611
11941
  if (view !== "tracker" || !userId) return;
11612
11942
  const fetchExecutions = async () => {
11613
11943
  try {
11614
- const response = await queryExecutions3(userId, publishableKey);
11944
+ const response = await queryExecutions3(userId, publishableKey, ActionType3.Deposit);
11615
11945
  const sorted = [...response.data].sort((a, b) => {
11616
11946
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
11617
11947
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -11628,7 +11958,7 @@ function DepositModal({
11628
11958
  clearInterval(pollInterval);
11629
11959
  };
11630
11960
  }, [view, userId, publishableKey]);
11631
- useEffect21(() => {
11961
+ useEffect22(() => {
11632
11962
  if (view !== "tracker") {
11633
11963
  setSelectedExecution(null);
11634
11964
  }
@@ -11738,7 +12068,7 @@ function DepositModal({
11738
12068
  setBrowserWalletInfo(null);
11739
12069
  setSelectedExecution(null);
11740
12070
  }, [open, effectiveInitialScreen]);
11741
- useEffect21(
12071
+ useEffect22(
11742
12072
  () => () => {
11743
12073
  if (resetViewTimeoutRef.current) {
11744
12074
  clearTimeout(resetViewTimeoutRef.current);
@@ -12130,9 +12460,2755 @@ function DepositModal({
12130
12460
  }
12131
12461
  ) });
12132
12462
  }
12463
+
12464
+ // src/components/checkout/CheckoutModal.tsx
12465
+ import {
12466
+ useState as useState28,
12467
+ useEffect as useEffect23,
12468
+ useLayoutEffect as useLayoutEffect3,
12469
+ useCallback as useCallback5,
12470
+ useRef as useRef8,
12471
+ useMemo as useMemo10
12472
+ } from "react";
12473
+ import { AlertTriangle as AlertTriangle2, ChevronRight as ChevronRight12 } from "lucide-react";
12474
+
12475
+ // src/hooks/use-payment-intent.ts
12476
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
12477
+ import { retrievePaymentIntent } from "@unifold/core";
12478
+ function usePaymentIntent(params) {
12479
+ const {
12480
+ clientSecret,
12481
+ publishableKey,
12482
+ enabled = true,
12483
+ pollingInterval = 5e3
12484
+ } = params;
12485
+ return useQuery9({
12486
+ queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
12487
+ queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
12488
+ enabled: enabled && !!clientSecret && !!publishableKey,
12489
+ staleTime: 0,
12490
+ refetchInterval: pollingInterval || false,
12491
+ refetchOnWindowFocus: true,
12492
+ retry: 3,
12493
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
12494
+ });
12495
+ }
12496
+
12497
+ // src/hooks/use-deposit-quote.ts
12498
+ import { useQuery as useQuery10 } from "@tanstack/react-query";
12499
+ import {
12500
+ getDepositQuote
12501
+ } from "@unifold/core";
12502
+ function useDepositQuote(params) {
12503
+ const {
12504
+ publishableKey,
12505
+ sourceChainType,
12506
+ sourceChainId,
12507
+ sourceTokenAddress,
12508
+ destinationAmount,
12509
+ destinationChainType,
12510
+ destinationChainId,
12511
+ destinationTokenAddress,
12512
+ enabled = true
12513
+ } = params;
12514
+ const request = {
12515
+ source_chain_type: sourceChainType,
12516
+ source_chain_id: sourceChainId,
12517
+ source_token_address: sourceTokenAddress,
12518
+ destination_amount: destinationAmount,
12519
+ destination_chain_type: destinationChainType,
12520
+ destination_chain_id: destinationChainId,
12521
+ destination_token_address: destinationTokenAddress
12522
+ };
12523
+ return useQuery10({
12524
+ queryKey: [
12525
+ "unifold",
12526
+ "depositQuote",
12527
+ sourceChainType,
12528
+ sourceChainId,
12529
+ sourceTokenAddress,
12530
+ destinationAmount,
12531
+ destinationChainType,
12532
+ destinationChainId,
12533
+ destinationTokenAddress,
12534
+ publishableKey
12535
+ ],
12536
+ queryFn: () => getDepositQuote(request, publishableKey),
12537
+ enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
12538
+ staleTime: 6e4,
12539
+ gcTime: 5 * 6e4,
12540
+ refetchOnWindowFocus: false,
12541
+ retry: 2,
12542
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
12543
+ });
12544
+ }
12545
+
12546
+ // src/components/checkout/CheckoutModal.tsx
12547
+ import { Fragment as Fragment10, jsx as jsx52, jsxs as jsxs45 } from "react/jsx-runtime";
12548
+ function mapDepositAddressesToWallets(depositAddresses, pi) {
12549
+ return depositAddresses.map((da, idx) => ({
12550
+ id: da.id,
12551
+ chain_type: da.chain_type,
12552
+ address_type: da.address_type,
12553
+ address: da.address,
12554
+ destination_chain_type: pi.destination_chain_type,
12555
+ destination_chain_id: pi.destination_chain_id,
12556
+ destination_token_address: pi.destination_token_address,
12557
+ recipient_address: pi.recipient_address,
12558
+ is_primary: idx === 0
12559
+ }));
12560
+ }
12561
+ function SkeletonButton2() {
12562
+ return /* @__PURE__ */ jsxs45("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: [
12563
+ /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
12564
+ /* @__PURE__ */ jsx52("div", { className: "uf-bg-muted uf-rounded-lg uf-w-9 uf-h-9" }),
12565
+ /* @__PURE__ */ jsxs45("div", { className: "uf-space-y-1.5", children: [
12566
+ /* @__PURE__ */ jsx52("div", { className: "uf-h-3.5 uf-w-24 uf-bg-muted uf-rounded" }),
12567
+ /* @__PURE__ */ jsx52("div", { className: "uf-h-3 uf-w-32 uf-bg-muted uf-rounded" })
12568
+ ] })
12569
+ ] }),
12570
+ /* @__PURE__ */ jsx52("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx52(ChevronRight12, { className: "uf-w-4 uf-h-4 uf-text-muted" }) })
12571
+ ] });
12572
+ }
12573
+ function CheckoutModal({
12574
+ open,
12575
+ onOpenChange,
12576
+ clientSecret,
12577
+ publishableKey,
12578
+ modalTitle,
12579
+ enableConnectWallet = false,
12580
+ theme = "dark",
12581
+ onCheckoutSuccess,
12582
+ onCheckoutError
12583
+ }) {
12584
+ const { colors: colors2, fonts, components } = useTheme();
12585
+ const [view, setView] = useState28("main");
12586
+ const resetViewTimeoutRef = useRef8(
12587
+ null
12588
+ );
12589
+ const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState28(false);
12590
+ const [browserWalletInfo, setBrowserWalletInfo] = useState28(null);
12591
+ const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState28(false);
12592
+ const [browserWalletChainType, setBrowserWalletChainType] = useState28(() => getStoredWalletChainType());
12593
+ const isMobileView = useIsMobileViewport();
12594
+ const [resolvedTheme, setResolvedTheme] = useState28(
12595
+ theme === "auto" ? "dark" : theme
12596
+ );
12597
+ useEffect23(() => {
12598
+ if (theme === "auto") {
12599
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
12600
+ setResolvedTheme(mediaQuery.matches ? "dark" : "light");
12601
+ const handler = (e) => {
12602
+ setResolvedTheme(e.matches ? "dark" : "light");
12603
+ };
12604
+ mediaQuery.addEventListener("change", handler);
12605
+ return () => mediaQuery.removeEventListener("change", handler);
12606
+ } else {
12607
+ setResolvedTheme(theme);
12608
+ }
12609
+ }, [theme]);
12610
+ const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
12611
+ const {
12612
+ data: paymentIntent,
12613
+ isLoading: piLoading,
12614
+ error: piError
12615
+ } = usePaymentIntent({
12616
+ clientSecret,
12617
+ publishableKey,
12618
+ enabled: open && !!clientSecret,
12619
+ pollingInterval: 5e3
12620
+ });
12621
+ const { projectConfig } = useProjectConfig({
12622
+ publishableKey,
12623
+ enabled: open
12624
+ });
12625
+ const prevStatusRef = useRef8(null);
12626
+ useEffect23(() => {
12627
+ if (!paymentIntent) return;
12628
+ const prev = prevStatusRef.current;
12629
+ prevStatusRef.current = paymentIntent.status;
12630
+ if (prev && prev !== paymentIntent.status && paymentIntent.status === "succeeded") {
12631
+ if (!browserWalletModalOpen) {
12632
+ setView("main");
12633
+ }
12634
+ onCheckoutSuccess?.({
12635
+ paymentIntentId: paymentIntent.id,
12636
+ status: paymentIntent.status
12637
+ });
12638
+ }
12639
+ }, [paymentIntent, onCheckoutSuccess, browserWalletModalOpen]);
12640
+ const wallets = useMemo10(() => {
12641
+ if (!paymentIntent) return [];
12642
+ return mapDepositAddressesToWallets(
12643
+ paymentIntent.deposit_addresses,
12644
+ paymentIntent
12645
+ );
12646
+ }, [paymentIntent]);
12647
+ const formatCryptoAmount = useMemo10(() => {
12648
+ if (!paymentIntent) return (_) => "";
12649
+ const decimals = paymentIntent.destination_token_decimals ?? 6;
12650
+ const symbol = paymentIntent.currency.toUpperCase();
12651
+ return (baseUnits) => {
12652
+ const num = Number(baseUnits) / 10 ** decimals;
12653
+ const formatted = num % 1 === 0 ? num.toFixed(0) : num.toFixed(2);
12654
+ return `${formatted} ${symbol}`;
12655
+ };
12656
+ }, [paymentIntent]);
12657
+ const remainingAmountUsd = useMemo10(() => {
12658
+ if (!paymentIntent) return void 0;
12659
+ const total = parseFloat(paymentIntent.amount_usd);
12660
+ const received = parseFloat(paymentIntent.amount_received_usd);
12661
+ if (isNaN(total) || isNaN(received)) return paymentIntent.amount_usd;
12662
+ const remaining = total - received;
12663
+ return remaining > 0 ? remaining.toFixed(2) : "0.00";
12664
+ }, [paymentIntent]);
12665
+ const remainingCrypto = useMemo10(() => {
12666
+ if (!paymentIntent) return void 0;
12667
+ const total = BigInt(paymentIntent.amount);
12668
+ const received = BigInt(paymentIntent.amount_received);
12669
+ const remaining = total - received;
12670
+ return remaining > 0n ? remaining.toString() : "0";
12671
+ }, [paymentIntent]);
12672
+ const [selectedSource, setSelectedSource] = useState28(null);
12673
+ const quoteDestinationAmount = useMemo10(() => {
12674
+ if (!paymentIntent || !selectedSource) return "0";
12675
+ const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
12676
+ const totalBaseUnits = Number(paymentIntent.amount);
12677
+ const totalUsd = parseFloat(paymentIntent.amount_usd);
12678
+ const baseUnitsPerUsd = totalUsd > 0 ? totalBaseUnits / totalUsd : 0;
12679
+ const minUsd = Math.max(selectedSource.minimumDepositAmountUsd, 3);
12680
+ const minDepositBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
12681
+ const effective = remaining > minDepositBaseUnits ? remaining : minDepositBaseUnits;
12682
+ return effective > 0n ? effective.toString() : "0";
12683
+ }, [paymentIntent, selectedSource]);
12684
+ const { data: sourceQuote } = useDepositQuote({
12685
+ publishableKey,
12686
+ sourceChainType: selectedSource?.chainType ?? "",
12687
+ sourceChainId: selectedSource?.chainId ?? "",
12688
+ sourceTokenAddress: selectedSource?.tokenAddress ?? "",
12689
+ destinationAmount: quoteDestinationAmount,
12690
+ destinationChainType: paymentIntent?.destination_chain_type ?? "",
12691
+ destinationChainId: paymentIntent?.destination_chain_id ?? "",
12692
+ destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
12693
+ enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
12694
+ });
12695
+ const handleBrowserWalletClick = useCallback5(
12696
+ (walletInfo) => {
12697
+ const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
12698
+ setStoredWalletChainType(walletChainType);
12699
+ setBrowserWalletChainType(walletChainType);
12700
+ const matchingDepositWallet = wallets.find(
12701
+ (w) => w.chain_type === walletChainType
12702
+ );
12703
+ if (!matchingDepositWallet) {
12704
+ onCheckoutError?.({
12705
+ message: `Unable to pay from ${walletChainType}. Please try a different wallet.`,
12706
+ code: "NO_DEPOSIT_ADDRESS"
12707
+ });
12708
+ return;
12709
+ }
12710
+ setBrowserWalletInfo({
12711
+ ...walletInfo,
12712
+ depositWallet: matchingDepositWallet
12713
+ });
12714
+ setBrowserWalletModalOpen(true);
12715
+ },
12716
+ [wallets, onCheckoutError]
12717
+ );
12718
+ const handleWalletConnectClick = useCallback5(() => {
12719
+ setWalletSelectionModalOpen(true);
12720
+ }, []);
12721
+ const handleWalletConnected = useCallback5(
12722
+ (walletInfo) => {
12723
+ const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
12724
+ setStoredWalletChainType(walletChainType);
12725
+ setBrowserWalletChainType(walletChainType);
12726
+ const matchingDepositWallet = wallets.find(
12727
+ (w) => w.chain_type === walletChainType
12728
+ );
12729
+ if (!matchingDepositWallet) {
12730
+ onCheckoutError?.({
12731
+ message: `Unable to pay from ${walletChainType}. Please try a different wallet.`,
12732
+ code: "NO_DEPOSIT_ADDRESS"
12733
+ });
12734
+ setWalletSelectionModalOpen(false);
12735
+ return;
12736
+ }
12737
+ setBrowserWalletInfo({
12738
+ ...walletInfo,
12739
+ depositWallet: matchingDepositWallet
12740
+ });
12741
+ setWalletSelectionModalOpen(false);
12742
+ setBrowserWalletModalOpen(true);
12743
+ },
12744
+ [wallets, onCheckoutError]
12745
+ );
12746
+ const handleWalletDisconnect = useCallback5(() => {
12747
+ setUserDisconnectedWallet(true);
12748
+ clearStoredWalletChainType();
12749
+ setBrowserWalletChainType(void 0);
12750
+ setBrowserWalletInfo(null);
12751
+ setBrowserWalletModalOpen(false);
12752
+ }, []);
12753
+ const handleClose = useCallback5(() => {
12754
+ onOpenChange(false);
12755
+ if (resetViewTimeoutRef.current) {
12756
+ clearTimeout(resetViewTimeoutRef.current);
12757
+ }
12758
+ resetViewTimeoutRef.current = setTimeout(() => {
12759
+ setView("main");
12760
+ setBrowserWalletInfo(null);
12761
+ resetViewTimeoutRef.current = null;
12762
+ }, 200);
12763
+ }, [onOpenChange]);
12764
+ useLayoutEffect3(() => {
12765
+ if (!open) return;
12766
+ if (resetViewTimeoutRef.current) {
12767
+ clearTimeout(resetViewTimeoutRef.current);
12768
+ resetViewTimeoutRef.current = null;
12769
+ }
12770
+ setView("main");
12771
+ setBrowserWalletInfo(null);
12772
+ }, [open]);
12773
+ useEffect23(
12774
+ () => () => {
12775
+ if (resetViewTimeoutRef.current) {
12776
+ clearTimeout(resetViewTimeoutRef.current);
12777
+ }
12778
+ },
12779
+ []
12780
+ );
12781
+ const handleBack = useCallback5(() => {
12782
+ setView("main");
12783
+ }, []);
12784
+ const poweredByFooter = /* @__PURE__ */ jsx52("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx52(
12785
+ PoweredByUnifold,
12786
+ {
12787
+ color: colors2.foregroundMuted,
12788
+ className: "uf-flex uf-justify-center uf-shrink-0"
12789
+ }
12790
+ ) });
12791
+ const progressSection = paymentIntent ? (() => {
12792
+ const received = parseFloat(paymentIntent.amount_received_usd);
12793
+ const total = parseFloat(paymentIntent.amount_usd);
12794
+ const remaining = Math.max(total - received, 0);
12795
+ const pct = total > 0 ? Math.min(received / total * 100, 100) : 0;
12796
+ const hasPartial = received > 0;
12797
+ const amountStr = paymentIntent.amount_usd;
12798
+ const dynamicFontSize = `${Math.max(3.75 - amountStr.length * 0.15, 2)}rem`;
12799
+ return /* @__PURE__ */ jsxs45("div", { className: "uf-text-center uf-py-2 uf-space-y-1", children: [
12800
+ paymentIntent.description && /* @__PURE__ */ jsx52(
12801
+ "div",
12802
+ {
12803
+ className: "uf-text-xs",
12804
+ style: {
12805
+ color: colors2.foregroundMuted,
12806
+ fontFamily: fonts.regular
12807
+ },
12808
+ children: paymentIntent.description
12809
+ }
12810
+ ),
12811
+ /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-items-center uf-justify-center", children: [
12812
+ /* @__PURE__ */ jsx52(
12813
+ "span",
12814
+ {
12815
+ className: "uf-mr-1",
12816
+ style: {
12817
+ fontSize: `calc(${dynamicFontSize} * 0.6)`,
12818
+ color: colors2.foregroundMuted,
12819
+ fontFamily: fonts.regular
12820
+ },
12821
+ children: "$"
12822
+ }
12823
+ ),
12824
+ /* @__PURE__ */ jsx52(
12825
+ "span",
12826
+ {
12827
+ style: {
12828
+ fontSize: dynamicFontSize,
12829
+ color: colors2.foreground,
12830
+ fontFamily: fonts.regular,
12831
+ lineHeight: 1.1
12832
+ },
12833
+ children: amountStr
12834
+ }
12835
+ )
12836
+ ] }),
12837
+ /* @__PURE__ */ jsx52(
12838
+ "div",
12839
+ {
12840
+ className: "uf-text-xs",
12841
+ style: {
12842
+ color: colors2.foregroundMuted,
12843
+ fontFamily: fonts.regular
12844
+ },
12845
+ children: paymentIntent.currency.toUpperCase()
12846
+ }
12847
+ ),
12848
+ hasPartial && /* @__PURE__ */ jsxs45("div", { className: "uf-pt-2 uf-space-y-1.5", children: [
12849
+ /* @__PURE__ */ jsx52(
12850
+ "div",
12851
+ {
12852
+ className: "uf-w-full uf-h-1.5 uf-rounded-full uf-overflow-hidden",
12853
+ style: { backgroundColor: colors2.border },
12854
+ children: /* @__PURE__ */ jsx52(
12855
+ "div",
12856
+ {
12857
+ className: "uf-h-full uf-rounded-full uf-transition-all uf-duration-500",
12858
+ style: {
12859
+ width: `${pct}%`,
12860
+ backgroundColor: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : colors2.primary
12861
+ }
12862
+ }
12863
+ )
12864
+ }
12865
+ ),
12866
+ /* @__PURE__ */ jsxs45(
12867
+ "div",
12868
+ {
12869
+ className: "uf-text-xs",
12870
+ style: {
12871
+ color: colors2.foregroundMuted,
12872
+ fontFamily: fonts.regular
12873
+ },
12874
+ children: [
12875
+ "$",
12876
+ paymentIntent.amount_received_usd,
12877
+ " / $",
12878
+ amountStr,
12879
+ " received",
12880
+ remaining > 0 && paymentIntent.status !== "succeeded" && /* @__PURE__ */ jsxs45("span", { style: { color: colors2.foreground, fontFamily: fonts.medium }, children: [
12881
+ " ",
12882
+ "\xB7 $",
12883
+ remaining.toFixed(2),
12884
+ " remaining"
12885
+ ] })
12886
+ ]
12887
+ }
12888
+ )
12889
+ ] }),
12890
+ paymentIntent.status !== "requires_payment" && /* @__PURE__ */ jsx52("div", { className: "uf-pt-1", children: /* @__PURE__ */ jsx52(
12891
+ "span",
12892
+ {
12893
+ className: "uf-text-xs uf-font-medium uf-px-2.5 uf-py-1 uf-rounded-full uf-inline-block",
12894
+ style: {
12895
+ 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)",
12896
+ color: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : paymentIntent.status === "processing" ? "rgb(59, 130, 246)" : "rgb(239, 68, 68)",
12897
+ fontFamily: fonts.medium
12898
+ },
12899
+ children: paymentIntent.status === "succeeded" ? "Payment Complete" : paymentIntent.status === "processing" ? "Partial Payment Received" : paymentIntent.status === "canceled" ? "Canceled" : paymentIntent.status === "expired" ? "Expired" : paymentIntent.status
12900
+ }
12901
+ ) })
12902
+ ] });
12903
+ })() : null;
12904
+ return /* @__PURE__ */ jsx52(PortalContainerProvider, { value: null, children: /* @__PURE__ */ jsxs45(Dialog, { open, onOpenChange: handleClose, modal: true, children: [
12905
+ /* @__PURE__ */ jsx52(
12906
+ DialogContent,
12907
+ {
12908
+ 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}`,
12909
+ style: { backgroundColor: colors2.background },
12910
+ onPointerDownOutside: (e) => e.preventDefault(),
12911
+ onInteractOutside: (e) => e.preventDefault(),
12912
+ children: /* @__PURE__ */ jsx52(ThemeStyleInjector, { children: view === "main" ? /* @__PURE__ */ jsxs45(Fragment10, { children: [
12913
+ /* @__PURE__ */ jsx52(
12914
+ DepositHeader,
12915
+ {
12916
+ title: modalTitle || "Checkout",
12917
+ showClose: true,
12918
+ onClose: handleClose
12919
+ }
12920
+ ),
12921
+ /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
12922
+ piLoading ? /* @__PURE__ */ jsxs45("div", { className: "uf-space-y-3", children: [
12923
+ /* @__PURE__ */ jsx52(
12924
+ "div",
12925
+ {
12926
+ className: "uf-rounded-xl uf-p-4 uf-animate-pulse",
12927
+ style: {
12928
+ backgroundColor: components.card.backgroundColor,
12929
+ borderRadius: components.card.borderRadius,
12930
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
12931
+ },
12932
+ children: /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-2", children: [
12933
+ /* @__PURE__ */ jsx52(
12934
+ "div",
12935
+ {
12936
+ className: "uf-h-8 uf-w-24 uf-rounded",
12937
+ style: {
12938
+ backgroundColor: components.card.borderColor
12939
+ }
12940
+ }
12941
+ ),
12942
+ /* @__PURE__ */ jsx52(
12943
+ "div",
12944
+ {
12945
+ className: "uf-h-4 uf-w-16 uf-rounded",
12946
+ style: {
12947
+ backgroundColor: components.card.borderColor
12948
+ }
12949
+ }
12950
+ )
12951
+ ] })
12952
+ }
12953
+ ),
12954
+ /* @__PURE__ */ jsx52(SkeletonButton2, {}),
12955
+ /* @__PURE__ */ jsx52(SkeletonButton2, {})
12956
+ ] }) : piError ? /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
12957
+ /* @__PURE__ */ jsx52("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__ */ jsx52(AlertTriangle2, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
12958
+ /* @__PURE__ */ jsx52(
12959
+ "h3",
12960
+ {
12961
+ className: "uf-text-lg uf-font-semibold uf-mb-2",
12962
+ style: {
12963
+ color: colors2.foreground,
12964
+ fontFamily: fonts.semibold
12965
+ },
12966
+ children: "Unable to Load Checkout"
12967
+ }
12968
+ ),
12969
+ /* @__PURE__ */ jsx52(
12970
+ "p",
12971
+ {
12972
+ className: "uf-text-sm uf-max-w-[280px]",
12973
+ style: {
12974
+ color: colors2.foregroundMuted,
12975
+ fontFamily: fonts.regular
12976
+ },
12977
+ children: piError instanceof Error ? piError.message : "Something went wrong. Please try again."
12978
+ }
12979
+ )
12980
+ ] }) : paymentIntent ? /* @__PURE__ */ jsxs45("div", { className: "uf-space-y-3", children: [
12981
+ progressSection,
12982
+ (paymentIntent.status === "requires_payment" || paymentIntent.status === "processing") && /* @__PURE__ */ jsxs45(Fragment10, { children: [
12983
+ /* @__PURE__ */ jsx52(
12984
+ TransferCryptoButton,
12985
+ {
12986
+ onClick: () => setView("transfer"),
12987
+ title: "Transfer Crypto",
12988
+ subtitle: "Send from any wallet or exchange",
12989
+ featuredTokens: projectConfig?.transfer_crypto.networks
12990
+ }
12991
+ ),
12992
+ enableConnectWallet && !isMobileView && /* @__PURE__ */ jsx52(
12993
+ BrowserWalletButton,
12994
+ {
12995
+ onClick: handleBrowserWalletClick,
12996
+ onConnectClick: handleWalletConnectClick,
12997
+ onDisconnect: handleWalletDisconnect,
12998
+ chainType: browserWalletChainType,
12999
+ publishableKey
13000
+ }
13001
+ )
13002
+ ] })
13003
+ ] }) : null,
13004
+ poweredByFooter
13005
+ ] })
13006
+ ] }) : view === "transfer" ? /* @__PURE__ */ jsxs45(Fragment10, { children: [
13007
+ /* @__PURE__ */ jsx52(
13008
+ DepositHeader,
13009
+ {
13010
+ title: `Pay $${remainingAmountUsd ?? paymentIntent?.amount_usd ?? ""}`,
13011
+ showBack: true,
13012
+ onBack: handleBack,
13013
+ onClose: handleClose
13014
+ }
13015
+ ),
13016
+ /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
13017
+ paymentIntent ? /* @__PURE__ */ jsxs45(Fragment10, { children: [
13018
+ /* @__PURE__ */ jsxs45(
13019
+ "div",
13020
+ {
13021
+ className: "uf-rounded-lg uf-px-3 uf-py-2 uf-flex uf-items-center uf-justify-between",
13022
+ style: {
13023
+ backgroundColor: components.card.backgroundColor,
13024
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`,
13025
+ borderRadius: components.card.borderRadius
13026
+ },
13027
+ children: [
13028
+ /* @__PURE__ */ jsx52(
13029
+ "span",
13030
+ {
13031
+ className: "uf-text-xs",
13032
+ style: {
13033
+ color: colors2.foregroundMuted,
13034
+ fontFamily: fonts.regular
13035
+ },
13036
+ children: parseFloat(paymentIntent.amount_received_usd) > 0 ? `$${paymentIntent.amount_received_usd} / $${paymentIntent.amount_usd} received` : "Amount due"
13037
+ }
13038
+ ),
13039
+ /* @__PURE__ */ jsxs45(
13040
+ "span",
13041
+ {
13042
+ className: "uf-text-sm uf-font-semibold",
13043
+ style: {
13044
+ color: colors2.foreground,
13045
+ fontFamily: fonts.semibold
13046
+ },
13047
+ children: [
13048
+ formatCryptoAmount(remainingCrypto ?? paymentIntent.amount),
13049
+ /* @__PURE__ */ jsxs45(
13050
+ "span",
13051
+ {
13052
+ className: "uf-text-xs uf-font-normal uf-ml-1",
13053
+ style: { color: colors2.foregroundMuted },
13054
+ children: [
13055
+ "($",
13056
+ remainingAmountUsd ?? paymentIntent.amount_usd,
13057
+ ")"
13058
+ ]
13059
+ }
13060
+ )
13061
+ ]
13062
+ }
13063
+ )
13064
+ ]
13065
+ }
13066
+ ),
13067
+ /* @__PURE__ */ jsx52(
13068
+ TransferCryptoSingleInput,
13069
+ {
13070
+ userId: paymentIntent.user_id || "",
13071
+ publishableKey,
13072
+ clientSecret,
13073
+ recipientAddress: paymentIntent.recipient_address,
13074
+ destinationChainType: paymentIntent.destination_chain_type,
13075
+ destinationChainId: paymentIntent.destination_chain_id,
13076
+ destinationTokenAddress: paymentIntent.destination_token_address,
13077
+ depositConfirmationMode: "auto_ui",
13078
+ wallets,
13079
+ onSourceTokenChange: setSelectedSource,
13080
+ checkoutQuote: sourceQuote ? {
13081
+ sourceAmount: sourceQuote.source_amount,
13082
+ sourceTokenDecimals: sourceQuote.source_token_decimals,
13083
+ sourceTokenSymbol: sourceQuote.source_token_symbol,
13084
+ sourceAmountUsd: sourceQuote.source_amount_usd
13085
+ } : null
13086
+ }
13087
+ )
13088
+ ] }) : /* @__PURE__ */ jsx52(SkeletonButton2, {}),
13089
+ poweredByFooter
13090
+ ] })
13091
+ ] }) : null })
13092
+ }
13093
+ ),
13094
+ /* @__PURE__ */ jsx52(
13095
+ WalletSelectionModal,
13096
+ {
13097
+ open: walletSelectionModalOpen,
13098
+ onOpenChange: setWalletSelectionModalOpen,
13099
+ onWalletConnected: handleWalletConnected,
13100
+ onClose: () => setWalletSelectionModalOpen(false),
13101
+ theme: resolvedTheme
13102
+ }
13103
+ ),
13104
+ browserWalletInfo && browserWalletInfo.depositWallet && /* @__PURE__ */ jsx52(
13105
+ BrowserWalletModal,
13106
+ {
13107
+ open: browserWalletModalOpen,
13108
+ onOpenChange: setBrowserWalletModalOpen,
13109
+ onFullClose: handleClose,
13110
+ walletInfo: browserWalletInfo,
13111
+ depositWallet: browserWalletInfo.depositWallet,
13112
+ userId: paymentIntent?.user_id || "",
13113
+ publishableKey,
13114
+ clientSecret,
13115
+ theme: resolvedTheme,
13116
+ prefillAmountUsd: remainingAmountUsd,
13117
+ checkoutAmountUsd: paymentIntent?.amount_usd,
13118
+ checkoutReceivedUsd: paymentIntent?.amount_received_usd,
13119
+ onSuccess: (txHash) => {
13120
+ onCheckoutSuccess?.({
13121
+ paymentIntentId: paymentIntent?.id || "",
13122
+ status: "processing"
13123
+ });
13124
+ },
13125
+ onError: (error) => {
13126
+ onCheckoutError?.({
13127
+ message: error.message,
13128
+ error
13129
+ });
13130
+ },
13131
+ onWalletDisconnect: handleWalletDisconnect,
13132
+ onNewDeposit: () => {
13133
+ setBrowserWalletModalOpen(false);
13134
+ setView("main");
13135
+ },
13136
+ onDone: () => {
13137
+ setBrowserWalletModalOpen(false);
13138
+ setView("main");
13139
+ },
13140
+ paymentIntentStatus: paymentIntent?.status
13141
+ }
13142
+ )
13143
+ ] }) });
13144
+ }
13145
+
13146
+ // src/components/withdrawals/WithdrawModal.tsx
13147
+ import {
13148
+ useState as useState32,
13149
+ useEffect as useEffect27,
13150
+ useLayoutEffect as useLayoutEffect4,
13151
+ useCallback as useCallback7,
13152
+ useRef as useRef10
13153
+ } from "react";
13154
+ import { AlertTriangle as AlertTriangle4, ChevronRight as ChevronRight14, Clock as Clock5 } from "lucide-react";
13155
+
13156
+ // src/hooks/use-supported-destination-tokens.ts
13157
+ import { useQuery as useQuery11 } from "@tanstack/react-query";
13158
+ import {
13159
+ getSupportedDestinationTokens
13160
+ } from "@unifold/core";
13161
+ function useSupportedDestinationTokens(publishableKey, enabled = true) {
13162
+ return useQuery11({
13163
+ queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
13164
+ queryFn: () => getSupportedDestinationTokens(publishableKey),
13165
+ staleTime: 1e3 * 60 * 5,
13166
+ gcTime: 1e3 * 60 * 30,
13167
+ refetchOnMount: false,
13168
+ refetchOnWindowFocus: false,
13169
+ enabled
13170
+ });
13171
+ }
13172
+
13173
+ // src/hooks/use-source-token-validation.ts
13174
+ import { useQuery as useQuery12 } from "@tanstack/react-query";
13175
+ import { getSupportedDepositTokens as getSupportedDepositTokens3 } from "@unifold/core";
13176
+ function useSourceTokenValidation(params) {
13177
+ const {
13178
+ sourceChainType,
13179
+ sourceChainId,
13180
+ sourceTokenAddress,
13181
+ sourceTokenSymbol,
13182
+ publishableKey,
13183
+ enabled = true
13184
+ } = params;
13185
+ const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
13186
+ return useQuery12({
13187
+ queryKey: [
13188
+ "unifold",
13189
+ "sourceTokenValidation",
13190
+ sourceChainType ?? null,
13191
+ sourceChainId ?? null,
13192
+ sourceTokenAddress ?? null,
13193
+ publishableKey
13194
+ ],
13195
+ queryFn: async () => {
13196
+ const res = await getSupportedDepositTokens3(publishableKey);
13197
+ let matchedMinUsd = null;
13198
+ let matchedProcessingTime = null;
13199
+ let matchedSlippage = null;
13200
+ let matchedPriceImpact = null;
13201
+ const found = res.data.some(
13202
+ (token) => token.chains.some((chain) => {
13203
+ const match = chain.chain_type === sourceChainType && chain.chain_id === sourceChainId && chain.token_address.toLowerCase() === sourceTokenAddress.toLowerCase();
13204
+ if (match) {
13205
+ matchedMinUsd = chain.minimum_deposit_amount_usd;
13206
+ matchedProcessingTime = chain.estimated_processing_time;
13207
+ matchedSlippage = chain.max_slippage_percent;
13208
+ matchedPriceImpact = chain.estimated_price_impact_percent;
13209
+ }
13210
+ return match;
13211
+ })
13212
+ );
13213
+ return {
13214
+ isSupported: found,
13215
+ minimumAmountUsd: matchedMinUsd,
13216
+ estimatedProcessingTime: matchedProcessingTime,
13217
+ maxSlippagePercent: matchedSlippage,
13218
+ priceImpactPercent: matchedPriceImpact,
13219
+ errorMessage: found ? null : `${sourceTokenSymbol || "Source token"} is not a supported withdrawal token. Supported tokens include USDC, USDT, and other stablecoins.`
13220
+ };
13221
+ },
13222
+ enabled: enabled && hasParams,
13223
+ staleTime: 1e3 * 60 * 5,
13224
+ gcTime: 1e3 * 60 * 30,
13225
+ refetchOnMount: false,
13226
+ refetchOnWindowFocus: false
13227
+ });
13228
+ }
13229
+
13230
+ // src/hooks/use-address-balance.ts
13231
+ import { useQuery as useQuery13 } from "@tanstack/react-query";
13232
+ import { getAddressBalance as getAddressBalance2 } from "@unifold/core";
13233
+ function useAddressBalance(params) {
13234
+ const {
13235
+ address,
13236
+ chainType,
13237
+ chainId,
13238
+ tokenAddress,
13239
+ publishableKey,
13240
+ enabled = true
13241
+ } = params;
13242
+ const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
13243
+ return useQuery13({
13244
+ queryKey: [
13245
+ "unifold",
13246
+ "addressBalance",
13247
+ address ?? null,
13248
+ chainType ?? null,
13249
+ chainId ?? null,
13250
+ tokenAddress ?? null,
13251
+ publishableKey
13252
+ ],
13253
+ queryFn: async () => {
13254
+ const res = await getAddressBalance2(
13255
+ address,
13256
+ chainType,
13257
+ chainId,
13258
+ tokenAddress,
13259
+ publishableKey
13260
+ );
13261
+ if (res.balance) {
13262
+ const decimals = res.balance.token?.decimals ?? 6;
13263
+ const symbol = res.balance.token?.symbol ?? "";
13264
+ const baseUnit = res.balance.amount;
13265
+ const raw = BigInt(baseUnit);
13266
+ const divisor = BigInt(10 ** decimals);
13267
+ const whole = raw / divisor;
13268
+ const frac = raw % divisor;
13269
+ const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
13270
+ const balanceHuman = fracStr ? `${whole}.${fracStr}` : whole.toString();
13271
+ return {
13272
+ balanceBaseUnit: baseUnit,
13273
+ balanceHuman,
13274
+ balanceUsd: res.balance.amount_usd,
13275
+ exchangeRate: res.balance.exchange_rate,
13276
+ decimals,
13277
+ symbol
13278
+ };
13279
+ }
13280
+ return { balanceBaseUnit: "0", balanceHuman: "0", balanceUsd: "0", exchangeRate: null, decimals: 6, symbol: "" };
13281
+ },
13282
+ enabled: enabled && hasParams,
13283
+ staleTime: 1e3 * 30,
13284
+ gcTime: 1e3 * 60 * 5,
13285
+ refetchInterval: 1e3 * 30,
13286
+ refetchOnMount: "always",
13287
+ refetchOnWindowFocus: false
13288
+ });
13289
+ }
13290
+
13291
+ // src/hooks/use-executions.ts
13292
+ import { useQuery as useQuery14 } from "@tanstack/react-query";
13293
+ import { queryExecutions as queryExecutions4, ActionType as ActionType4 } from "@unifold/core";
13294
+ function useExecutions(userId, publishableKey, options) {
13295
+ const actionType = options?.actionType ?? ActionType4.Deposit;
13296
+ return useQuery14({
13297
+ queryKey: ["unifold", "executions", actionType, userId, publishableKey],
13298
+ queryFn: () => queryExecutions4(userId, publishableKey, actionType),
13299
+ enabled: (options?.enabled ?? true) && !!userId,
13300
+ refetchInterval: options?.refetchInterval ?? 3e3,
13301
+ staleTime: 0,
13302
+ gcTime: 1e3 * 60 * 5,
13303
+ refetchOnWindowFocus: false
13304
+ });
13305
+ }
13306
+
13307
+ // src/hooks/use-withdraw-polling.ts
13308
+ import { useState as useState29, useEffect as useEffect24, useRef as useRef9 } from "react";
13309
+ import {
13310
+ queryExecutions as queryExecutions5,
13311
+ pollDirectExecutions as pollDirectExecutions2,
13312
+ ExecutionStatus as ExecutionStatus5,
13313
+ ActionType as ActionType5
13314
+ } from "@unifold/core";
13315
+ var POLL_INTERVAL_MS2 = 2500;
13316
+ var POLL_ENDPOINT_INTERVAL_MS2 = 3e3;
13317
+ var CUTOFF_BUFFER_MS2 = 6e4;
13318
+ function useWithdrawPolling({
13319
+ userId,
13320
+ publishableKey,
13321
+ depositWalletId,
13322
+ enabled = false,
13323
+ onWithdrawSuccess,
13324
+ onWithdrawError
13325
+ }) {
13326
+ const [executions, setExecutions] = useState29([]);
13327
+ const [isPolling, setIsPolling] = useState29(false);
13328
+ const enabledAtRef = useRef9(/* @__PURE__ */ new Date());
13329
+ const trackedRef = useRef9(/* @__PURE__ */ new Map());
13330
+ const prevEnabledRef = useRef9(false);
13331
+ const onSuccessRef = useRef9(onWithdrawSuccess);
13332
+ const onErrorRef = useRef9(onWithdrawError);
13333
+ useEffect24(() => {
13334
+ onSuccessRef.current = onWithdrawSuccess;
13335
+ }, [onWithdrawSuccess]);
13336
+ useEffect24(() => {
13337
+ onErrorRef.current = onWithdrawError;
13338
+ }, [onWithdrawError]);
13339
+ useEffect24(() => {
13340
+ if (enabled && !prevEnabledRef.current) {
13341
+ enabledAtRef.current = /* @__PURE__ */ new Date();
13342
+ trackedRef.current.clear();
13343
+ }
13344
+ if (!enabled) {
13345
+ trackedRef.current.clear();
13346
+ }
13347
+ prevEnabledRef.current = enabled;
13348
+ }, [enabled]);
13349
+ useEffect24(() => {
13350
+ if (!userId || !enabled) return;
13351
+ const enabledAt = enabledAtRef.current;
13352
+ const poll = async () => {
13353
+ try {
13354
+ const response = await queryExecutions5(userId, publishableKey, ActionType5.Withdraw);
13355
+ const cutoff = new Date(enabledAt.getTime() - CUTOFF_BUFFER_MS2);
13356
+ const sorted = [...response.data].sort((a, b) => {
13357
+ const tA = a.created_at ? new Date(a.created_at).getTime() : 0;
13358
+ const tB = b.created_at ? new Date(b.created_at).getTime() : 0;
13359
+ return tB - tA;
13360
+ });
13361
+ const inProgress = [ExecutionStatus5.PENDING, ExecutionStatus5.WAITING, ExecutionStatus5.DELAYED];
13362
+ const terminal = [ExecutionStatus5.SUCCEEDED, ExecutionStatus5.FAILED];
13363
+ let target = null;
13364
+ for (const ex of sorted) {
13365
+ const t11 = ex.created_at ? new Date(ex.created_at) : null;
13366
+ if (!t11 || t11 < cutoff) continue;
13367
+ const prev = trackedRef.current.get(ex.id);
13368
+ if (!prev) {
13369
+ target = ex;
13370
+ break;
13371
+ }
13372
+ if (inProgress.includes(prev) && terminal.includes(ex.status)) {
13373
+ target = ex;
13374
+ break;
13375
+ }
13376
+ }
13377
+ if (target) {
13378
+ const ex = target;
13379
+ const exTime = ex.created_at ? new Date(ex.created_at) : null;
13380
+ if (!exTime || exTime < enabledAtRef.current) return;
13381
+ const prev = trackedRef.current.get(ex.id);
13382
+ trackedRef.current.set(ex.id, ex.status);
13383
+ setExecutions((list) => {
13384
+ const idx = list.findIndex((e) => e.id === ex.id);
13385
+ if (idx >= 0) {
13386
+ const u = [...list];
13387
+ u[idx] = ex;
13388
+ return u;
13389
+ }
13390
+ return [...list, ex];
13391
+ });
13392
+ if (ex.status === ExecutionStatus5.SUCCEEDED && (!prev || inProgress.includes(prev))) {
13393
+ onSuccessRef.current?.({ message: "Withdrawal completed successfully", executionId: ex.id, transaction: ex });
13394
+ } else if (ex.status === ExecutionStatus5.FAILED && prev !== ExecutionStatus5.FAILED) {
13395
+ onErrorRef.current?.({ message: "Withdrawal failed", code: "WITHDRAW_FAILED", error: ex });
13396
+ }
13397
+ }
13398
+ } catch (error) {
13399
+ console.error("Failed to fetch withdraw executions:", error);
13400
+ onErrorRef.current?.({ message: "Failed to fetch withdrawal status", code: "POLLING_ERROR", error });
13401
+ }
13402
+ };
13403
+ void poll();
13404
+ const interval = setInterval(poll, POLL_INTERVAL_MS2);
13405
+ setIsPolling(true);
13406
+ return () => {
13407
+ clearInterval(interval);
13408
+ setIsPolling(false);
13409
+ };
13410
+ }, [userId, publishableKey, enabled]);
13411
+ useEffect24(() => {
13412
+ if (!enabled || !depositWalletId) return;
13413
+ const trigger = async () => {
13414
+ try {
13415
+ await pollDirectExecutions2({ deposit_wallet_id: depositWalletId }, publishableKey);
13416
+ } catch {
13417
+ }
13418
+ };
13419
+ trigger();
13420
+ const interval = setInterval(trigger, POLL_ENDPOINT_INTERVAL_MS2);
13421
+ return () => clearInterval(interval);
13422
+ }, [enabled, depositWalletId, publishableKey]);
13423
+ return { executions, isPolling };
13424
+ }
13425
+
13426
+ // src/components/withdrawals/WithdrawDoubleInput.tsx
13427
+ import { jsx as jsx53, jsxs as jsxs46 } from "react/jsx-runtime";
13428
+ var t7 = i18n.withdrawModal;
13429
+ var getChainKey4 = (chainId, chainType) => `${chainType}:${chainId}`;
13430
+ function WithdrawDoubleInput({
13431
+ tokens,
13432
+ selectedTokenSymbol,
13433
+ selectedChainKey,
13434
+ onTokenChange,
13435
+ onChainChange,
13436
+ isLoading = false
13437
+ }) {
13438
+ const { fonts, components } = useTheme();
13439
+ const isDarkMode = useTheme().themeClass.includes("uf-dark");
13440
+ const selectedToken = selectedTokenSymbol ? tokens.find((t11) => t11.symbol === selectedTokenSymbol) : void 0;
13441
+ const availableChainsForToken = selectedToken?.chains || [];
13442
+ const renderTokenItem = (tokenData) => /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13443
+ /* @__PURE__ */ jsx53(
13444
+ "img",
13445
+ {
13446
+ src: tokenData.icon_url,
13447
+ alt: tokenData.symbol,
13448
+ width: 20,
13449
+ height: 20,
13450
+ loading: "lazy",
13451
+ className: "uf-rounded-full uf-flex-shrink-0"
13452
+ }
13453
+ ),
13454
+ /* @__PURE__ */ jsx53("span", { className: "uf-text-xs uf-font-normal", children: tokenData.symbol })
13455
+ ] });
13456
+ const renderChainItem = (chainData) => /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13457
+ /* @__PURE__ */ jsx53(
13458
+ "img",
13459
+ {
13460
+ src: chainData.icon_url,
13461
+ alt: chainData.chain_name,
13462
+ width: 20,
13463
+ height: 20,
13464
+ loading: "lazy",
13465
+ className: "uf-rounded-full uf-flex-shrink-0"
13466
+ }
13467
+ ),
13468
+ /* @__PURE__ */ jsx53("span", { className: "uf-text-xs uf-font-normal", children: chainData.chain_name })
13469
+ ] });
13470
+ const currentChainData = selectedChainKey ? availableChainsForToken.find(
13471
+ (c) => getChainKey4(c.chain_id, c.chain_type) === selectedChainKey
13472
+ ) : void 0;
13473
+ return /* @__PURE__ */ jsxs46("div", { className: "uf-grid uf-grid-cols-2 uf-gap-2.5", children: [
13474
+ /* @__PURE__ */ jsxs46("div", { children: [
13475
+ /* @__PURE__ */ jsx53(
13476
+ "div",
13477
+ {
13478
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
13479
+ style: { color: components.card.labelColor },
13480
+ children: t7.receiveToken
13481
+ }
13482
+ ),
13483
+ /* @__PURE__ */ jsxs46(
13484
+ Select,
13485
+ {
13486
+ value: selectedTokenSymbol ?? "",
13487
+ onValueChange: onTokenChange,
13488
+ disabled: isLoading || tokens.length === 0,
13489
+ children: [
13490
+ /* @__PURE__ */ jsx53(
13491
+ SelectTrigger,
13492
+ {
13493
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
13494
+ style: {
13495
+ backgroundColor: components.card.backgroundColor,
13496
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
13497
+ },
13498
+ children: /* @__PURE__ */ jsx53(SelectValue, { children: isLoading || !selectedTokenSymbol ? /* @__PURE__ */ jsx53("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ jsx53("span", { className: "uf-text-xs uf-font-normal", children: selectedTokenSymbol }) })
13499
+ }
13500
+ ),
13501
+ /* @__PURE__ */ jsx53(
13502
+ SelectContent,
13503
+ {
13504
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]",
13505
+ style: {
13506
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
13507
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
13508
+ },
13509
+ children: tokens.map((tokenData) => /* @__PURE__ */ jsx53(
13510
+ SelectItem,
13511
+ {
13512
+ value: tokenData.symbol,
13513
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
13514
+ children: renderTokenItem(tokenData)
13515
+ },
13516
+ tokenData.symbol
13517
+ ))
13518
+ }
13519
+ )
13520
+ ]
13521
+ }
13522
+ )
13523
+ ] }),
13524
+ /* @__PURE__ */ jsxs46("div", { children: [
13525
+ /* @__PURE__ */ jsx53(
13526
+ "div",
13527
+ {
13528
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
13529
+ style: { color: components.card.labelColor },
13530
+ children: t7.receiveChain
13531
+ }
13532
+ ),
13533
+ /* @__PURE__ */ jsxs46(
13534
+ Select,
13535
+ {
13536
+ value: selectedChainKey ?? "",
13537
+ onValueChange: onChainChange,
13538
+ disabled: isLoading || availableChainsForToken.length === 0,
13539
+ children: [
13540
+ /* @__PURE__ */ jsx53(
13541
+ SelectTrigger,
13542
+ {
13543
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
13544
+ style: {
13545
+ backgroundColor: components.card.backgroundColor,
13546
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
13547
+ },
13548
+ children: /* @__PURE__ */ jsx53(SelectValue, { children: isLoading || !selectedChainKey ? /* @__PURE__ */ jsx53("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ jsx53("span", { className: "uf-text-xs uf-font-normal", children: selectedChainKey }) })
13549
+ }
13550
+ ),
13551
+ /* @__PURE__ */ jsx53(
13552
+ SelectContent,
13553
+ {
13554
+ align: "end",
13555
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
13556
+ style: {
13557
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
13558
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
13559
+ },
13560
+ children: availableChainsForToken.length === 0 ? /* @__PURE__ */ jsx53("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) => {
13561
+ const chainKey = getChainKey4(chainData.chain_id, chainData.chain_type);
13562
+ return /* @__PURE__ */ jsx53(
13563
+ SelectItem,
13564
+ {
13565
+ value: chainKey,
13566
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
13567
+ children: renderChainItem(chainData)
13568
+ },
13569
+ chainKey
13570
+ );
13571
+ })
13572
+ }
13573
+ )
13574
+ ]
13575
+ }
13576
+ )
13577
+ ] })
13578
+ ] });
13579
+ }
13580
+
13581
+ // src/components/withdrawals/WithdrawForm.tsx
13582
+ import { useState as useState30, useCallback as useCallback6, useMemo as useMemo11, useEffect as useEffect25 } from "react";
13583
+ import {
13584
+ AlertTriangle as AlertTriangle3,
13585
+ ArrowUpDown,
13586
+ ChevronDown as ChevronDown7,
13587
+ ChevronUp as ChevronUp6,
13588
+ Clock as Clock4,
13589
+ ClipboardPaste,
13590
+ DollarSign as DollarSign3,
13591
+ Loader2 as Loader26,
13592
+ ShieldCheck as ShieldCheck3,
13593
+ Wallet as Wallet3
13594
+ } from "lucide-react";
13595
+
13596
+ // src/hooks/use-verify-recipient-address.ts
13597
+ import { useQuery as useQuery15 } from "@tanstack/react-query";
13598
+ import { verifyRecipientAddress as verifyRecipientAddress2 } from "@unifold/core";
13599
+ function useVerifyRecipientAddress(params) {
13600
+ const {
13601
+ chainType,
13602
+ chainId,
13603
+ tokenAddress,
13604
+ recipientAddress,
13605
+ publishableKey,
13606
+ enabled = true
13607
+ } = params;
13608
+ const trimmedAddress = recipientAddress?.trim() || "";
13609
+ const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
13610
+ return useQuery15({
13611
+ queryKey: [
13612
+ "unifold",
13613
+ "verifyRecipientAddress",
13614
+ chainType ?? null,
13615
+ chainId ?? null,
13616
+ tokenAddress ?? null,
13617
+ trimmedAddress,
13618
+ publishableKey
13619
+ ],
13620
+ queryFn: () => verifyRecipientAddress2(
13621
+ {
13622
+ chain_type: chainType,
13623
+ chain_id: chainId,
13624
+ token_address: tokenAddress,
13625
+ recipient_address: trimmedAddress
13626
+ },
13627
+ publishableKey
13628
+ ),
13629
+ enabled: enabled && hasAllParams,
13630
+ staleTime: 1e3 * 60 * 5,
13631
+ gcTime: 1e3 * 60 * 30,
13632
+ retry: 1,
13633
+ refetchOnMount: false,
13634
+ refetchOnWindowFocus: false
13635
+ });
13636
+ }
13637
+
13638
+ // src/components/withdrawals/send-withdraw.ts
13639
+ import {
13640
+ buildSolanaTransaction as buildSolanaTransaction2,
13641
+ sendSolanaTransaction as sendSolanaTransactionToBackend2,
13642
+ buildHypercoreTransaction as buildHypercoreTransactionFromBackend,
13643
+ sendHypercoreTransaction as sendHypercoreTransactionToBackend
13644
+ } from "@unifold/core";
13645
+ async function sendEvmWithdraw(params) {
13646
+ const {
13647
+ provider,
13648
+ fromAddress,
13649
+ depositWalletAddress,
13650
+ sourceTokenAddress,
13651
+ sourceChainId,
13652
+ amountBaseUnit
13653
+ } = params;
13654
+ const currentChainIdHex = await provider.request({
13655
+ method: "eth_chainId",
13656
+ params: []
13657
+ });
13658
+ const currentChainId = parseInt(currentChainIdHex, 16).toString();
13659
+ if (currentChainId !== sourceChainId) {
13660
+ const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
13661
+ try {
13662
+ await provider.request({
13663
+ method: "wallet_switchEthereumChain",
13664
+ params: [{ chainId: requiredHex }]
13665
+ });
13666
+ const newHex = await provider.request({ method: "eth_chainId", params: [] });
13667
+ if (parseInt(newHex, 16).toString() !== sourceChainId) {
13668
+ throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
13669
+ }
13670
+ } catch (err) {
13671
+ if (err && typeof err === "object" && "code" in err) {
13672
+ const e = err;
13673
+ if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
13674
+ if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
13675
+ }
13676
+ throw err;
13677
+ }
13678
+ }
13679
+ const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
13680
+ const amountBig = BigInt(amountBaseUnit);
13681
+ const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
13682
+ from: fromAddress,
13683
+ to: sourceTokenAddress,
13684
+ data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
13685
+ };
13686
+ let gasEstimate;
13687
+ try {
13688
+ const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
13689
+ gasEstimate = BigInt(hex);
13690
+ } catch {
13691
+ gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
13692
+ }
13693
+ const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
13694
+ const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
13695
+ const gasCost = gasWithBuffer * gasPrice;
13696
+ const ethBalance = BigInt(
13697
+ await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
13698
+ );
13699
+ const totalRequired = isNative ? gasCost + amountBig : gasCost;
13700
+ if (ethBalance < totalRequired) {
13701
+ const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
13702
+ if (isNative) {
13703
+ throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
13704
+ }
13705
+ throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
13706
+ }
13707
+ const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
13708
+ return txHash;
13709
+ }
13710
+ async function sendSolanaWithdraw(params) {
13711
+ const {
13712
+ provider,
13713
+ fromAddress,
13714
+ depositWalletAddress,
13715
+ sourceTokenAddress,
13716
+ amountBaseUnit,
13717
+ publishableKey
13718
+ } = params;
13719
+ if (!provider.publicKey) {
13720
+ await provider.connect();
13721
+ }
13722
+ const buildResponse = await buildSolanaTransaction2(
13723
+ {
13724
+ chain_id: "mainnet",
13725
+ token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
13726
+ source_address: fromAddress,
13727
+ destination_address: depositWalletAddress,
13728
+ amount: amountBaseUnit
13729
+ },
13730
+ publishableKey
13731
+ );
13732
+ const { VersionedTransaction } = await import(
13733
+ /* @vite-ignore */
13734
+ "@solana/web3.js"
13735
+ );
13736
+ const binaryString = atob(buildResponse.transaction);
13737
+ const bytes = new Uint8Array(binaryString.length);
13738
+ for (let i = 0; i < binaryString.length; i++) {
13739
+ bytes[i] = binaryString.charCodeAt(i);
13740
+ }
13741
+ const transaction = VersionedTransaction.deserialize(bytes);
13742
+ const signedTransaction = await provider.signTransaction(transaction);
13743
+ const serialized = signedTransaction.serialize();
13744
+ let binaryStr = "";
13745
+ for (let i = 0; i < serialized.length; i++) {
13746
+ binaryStr += String.fromCharCode(serialized[i]);
13747
+ }
13748
+ const sendResponse = await sendSolanaTransactionToBackend2(
13749
+ { chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
13750
+ publishableKey
13751
+ );
13752
+ return sendResponse.signature;
13753
+ }
13754
+ var HYPERCORE_CHAIN_ID = "1337";
13755
+ var HYPERCORE_SPOT_USDC_ADDRESS = "0x6d1e7cde53ba9467b783cb7c530ce054";
13756
+ function isHypercoreChain(chainId) {
13757
+ return chainId === HYPERCORE_CHAIN_ID;
13758
+ }
13759
+ async function sendHypercoreWithdraw(params) {
13760
+ const {
13761
+ provider,
13762
+ fromAddress,
13763
+ depositWalletAddress,
13764
+ sourceTokenAddress,
13765
+ amount,
13766
+ tokenSymbol,
13767
+ publishableKey
13768
+ } = params;
13769
+ const isSpot = sourceTokenAddress.toLowerCase() === HYPERCORE_SPOT_USDC_ADDRESS;
13770
+ const currentChainHex = await provider.request({
13771
+ method: "eth_chainId",
13772
+ params: []
13773
+ });
13774
+ const activeChainId = String(parseInt(currentChainHex, 16));
13775
+ const buildResult = await buildHypercoreTransactionFromBackend(
13776
+ {
13777
+ action_type: isSpot ? "spot_send" : "usd_send",
13778
+ signature_chain_type: "ethereum",
13779
+ signature_chain_id: activeChainId,
13780
+ recipient_address: depositWalletAddress,
13781
+ token_address: sourceTokenAddress,
13782
+ token_symbol: tokenSymbol || void 0,
13783
+ amount
13784
+ },
13785
+ publishableKey
13786
+ );
13787
+ const signature = await provider.request({
13788
+ method: "eth_signTypedData_v4",
13789
+ params: [fromAddress, JSON.stringify(buildResult.typed_data)]
13790
+ });
13791
+ await sendHypercoreTransactionToBackend(
13792
+ {
13793
+ action_payload: buildResult.action_payload,
13794
+ signature,
13795
+ nonce: buildResult.nonce
13796
+ },
13797
+ publishableKey
13798
+ );
13799
+ }
13800
+ async function detectBrowserWallet(chainType, senderAddress) {
13801
+ const win = typeof window !== "undefined" ? window : null;
13802
+ if (!win || !senderAddress) return null;
13803
+ const anyWin = win;
13804
+ if (chainType === "solana") {
13805
+ const solProviders = [];
13806
+ if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
13807
+ if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
13808
+ if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
13809
+ if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
13810
+ for (const { provider, name } of solProviders) {
13811
+ if (!provider) continue;
13812
+ try {
13813
+ let addr;
13814
+ if (provider.isConnected && provider.publicKey) {
13815
+ addr = provider.publicKey.toString();
13816
+ } else {
13817
+ const resp = await provider.connect({ onlyIfTrusted: true });
13818
+ if (resp?.publicKey) addr = resp.publicKey.toString();
13819
+ }
13820
+ if (addr && addr === senderAddress) {
13821
+ return { chainFamily: "solana", provider, name, address: addr };
13822
+ }
13823
+ } catch {
13824
+ }
13825
+ }
13826
+ }
13827
+ if (chainType === "ethereum") {
13828
+ const evmProviders = [];
13829
+ const seen = /* @__PURE__ */ new Set();
13830
+ const add = (p, name) => {
13831
+ if (p && typeof p.request === "function" && !seen.has(p)) {
13832
+ seen.add(p);
13833
+ evmProviders.push({ provider: p, name });
13834
+ }
13835
+ };
13836
+ add(anyWin.phantom?.ethereum, "Phantom");
13837
+ add(anyWin.coinbaseWalletExtension, "Coinbase");
13838
+ add(anyWin.trustwallet?.ethereum, "Trust Wallet");
13839
+ add(anyWin.okxwallet, "OKX Wallet");
13840
+ if (anyWin.__eip6963Providers) {
13841
+ for (const detail of anyWin.__eip6963Providers) {
13842
+ const rdns = detail.info?.rdns || "";
13843
+ let name = detail.info?.name || "Wallet";
13844
+ if (rdns.includes("metamask")) name = "MetaMask";
13845
+ else if (rdns.includes("rabby")) name = "Rabby";
13846
+ else if (rdns.includes("rainbow")) name = "Rainbow";
13847
+ add(detail.provider, name);
13848
+ }
13849
+ }
13850
+ if (win.ethereum) {
13851
+ const eth = win.ethereum;
13852
+ let name = "Wallet";
13853
+ if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
13854
+ else if (eth.isRabby) name = "Rabby";
13855
+ else if (eth.isRainbow) name = "Rainbow";
13856
+ else if (eth.isCoinbaseWallet) name = "Coinbase";
13857
+ add(eth, name);
13858
+ }
13859
+ for (const { provider, name } of evmProviders) {
13860
+ try {
13861
+ const accounts = await provider.request({ method: "eth_accounts" });
13862
+ if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
13863
+ return { chainFamily: "evm", provider, name, address: accounts[0] };
13864
+ }
13865
+ } catch {
13866
+ }
13867
+ }
13868
+ }
13869
+ return null;
13870
+ }
13871
+
13872
+ // src/components/withdrawals/WithdrawForm.tsx
13873
+ import { Fragment as Fragment11, jsx as jsx54, jsxs as jsxs47 } from "react/jsx-runtime";
13874
+ var t8 = i18n.withdrawModal;
13875
+ var tCrypto = i18n.transferCrypto;
13876
+ function formatProcessingTime2(seconds) {
13877
+ if (seconds === null) {
13878
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
13879
+ }
13880
+ const minutes = Math.ceil(seconds / 60);
13881
+ if (minutes < 60) {
13882
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", String(minutes));
13883
+ }
13884
+ const hours = Math.ceil(minutes / 60);
13885
+ return tCrypto.processingTime.lessThanHours.replace("{{hours}}", String(hours));
13886
+ }
13887
+ function computeBaseUnit(balanceBaseUnit, inputAmount, balanceAmount) {
13888
+ if (balanceAmount <= 0 || inputAmount <= 0) return "0";
13889
+ if (inputAmount >= balanceAmount) return balanceBaseUnit;
13890
+ const PRECISION = 10n ** 18n;
13891
+ const ratioScaled = BigInt(Math.round(inputAmount / balanceAmount * Number(PRECISION)));
13892
+ const result = BigInt(balanceBaseUnit) * ratioScaled / PRECISION;
13893
+ return result.toString();
13894
+ }
13895
+ function toSafeDecimalString(n, maxDecimals) {
13896
+ if (n === 0) return "0";
13897
+ return n.toFixed(maxDecimals).replace(/\.?0+$/, "");
13898
+ }
13899
+ function WithdrawForm({
13900
+ publishableKey,
13901
+ externalUserId,
13902
+ sourceChainType,
13903
+ selectedToken,
13904
+ selectedChain,
13905
+ sourceTokenSymbol,
13906
+ recipientAddressProp,
13907
+ balanceData,
13908
+ isLoadingBalance,
13909
+ minimumWithdrawAmountUsd,
13910
+ estimatedProcessingTime,
13911
+ maxSlippagePercent,
13912
+ priceImpactPercent,
13913
+ detectedWallet,
13914
+ sourceChainId,
13915
+ sourceTokenAddress,
13916
+ isWalletMatch,
13917
+ connectedWalletName,
13918
+ canWithdraw,
13919
+ onWithdraw,
13920
+ onWithdrawError,
13921
+ onDepositWalletCreation,
13922
+ onWithdrawSubmitted,
13923
+ footerLeft
13924
+ }) {
13925
+ const { colors: colors2, fonts, components } = useTheme();
13926
+ const [recipientAddress, setRecipientAddress] = useState30(recipientAddressProp || "");
13927
+ const [amount, setAmount] = useState30("");
13928
+ const [inputUnit, setInputUnit] = useState30("crypto");
13929
+ const [isSubmitting, setIsSubmitting] = useState30(false);
13930
+ const [submitError, setSubmitError] = useState30(null);
13931
+ const [detailsExpanded, setDetailsExpanded] = useState30(false);
13932
+ const [glossaryOpen, setGlossaryOpen] = useState30(false);
13933
+ useEffect25(() => {
13934
+ setRecipientAddress(recipientAddressProp || "");
13935
+ setAmount("");
13936
+ setInputUnit("crypto");
13937
+ setSubmitError(null);
13938
+ }, [recipientAddressProp]);
13939
+ const trimmedAddress = recipientAddress.trim();
13940
+ const [debouncedAddress, setDebouncedAddress] = useState30(trimmedAddress);
13941
+ useEffect25(() => {
13942
+ const id = setTimeout(() => setDebouncedAddress(trimmedAddress), 500);
13943
+ return () => clearTimeout(id);
13944
+ }, [trimmedAddress]);
13945
+ const {
13946
+ data: addressVerification,
13947
+ isLoading: isVerifyingAddress,
13948
+ error: verifyError
13949
+ } = useVerifyRecipientAddress({
13950
+ chainType: selectedChain?.chain_type,
13951
+ chainId: selectedChain?.chain_id,
13952
+ tokenAddress: selectedChain?.token_address,
13953
+ recipientAddress: debouncedAddress,
13954
+ publishableKey,
13955
+ enabled: debouncedAddress.length > 5 && !!selectedChain
13956
+ });
13957
+ const isDebouncing = trimmedAddress !== debouncedAddress;
13958
+ const addressError = useMemo11(() => {
13959
+ if (!trimmedAddress || trimmedAddress.length <= 5) return null;
13960
+ if (isDebouncing || isVerifyingAddress) return null;
13961
+ if (verifyError) return t8.invalidAddress;
13962
+ if (addressVerification && !addressVerification.valid) {
13963
+ if (addressVerification.failure_code === "account_not_found")
13964
+ return `Account not found on ${selectedChain?.chain_name}`;
13965
+ if (addressVerification.failure_code === "not_opted_in")
13966
+ return `Recipient has not opted in to ${selectedToken?.symbol} on ${selectedChain?.chain_name}`;
13967
+ return t8.invalidAddress;
13968
+ }
13969
+ return null;
13970
+ }, [trimmedAddress, isDebouncing, isVerifyingAddress, verifyError, addressVerification, selectedChain, selectedToken]);
13971
+ const isAddressValid = !isDebouncing && !!addressVerification?.valid && !addressError;
13972
+ const exchangeRate = useMemo11(() => {
13973
+ if (!balanceData?.exchangeRate) return 0;
13974
+ return parseFloat(balanceData.exchangeRate);
13975
+ }, [balanceData]);
13976
+ const balanceCrypto = useMemo11(() => {
13977
+ if (!balanceData?.balanceHuman) return 0;
13978
+ return parseFloat(balanceData.balanceHuman);
13979
+ }, [balanceData]);
13980
+ const balanceUsdNum = useMemo11(() => {
13981
+ if (!balanceData?.balanceUsd) return 0;
13982
+ return parseFloat(balanceData.balanceUsd);
13983
+ }, [balanceData]);
13984
+ const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
13985
+ const sourceDecimals = balanceData?.decimals ?? 6;
13986
+ const cryptoAmountFromInput = useMemo11(() => {
13987
+ const val = parseFloat(amount);
13988
+ if (!val || val <= 0) return 0;
13989
+ if (inputUnit === "crypto") return val;
13990
+ return exchangeRate > 0 ? val / exchangeRate : 0;
13991
+ }, [amount, inputUnit, exchangeRate]);
13992
+ const fiatAmountFromInput = useMemo11(() => {
13993
+ const val = parseFloat(amount);
13994
+ if (!val || val <= 0) return 0;
13995
+ if (inputUnit === "fiat") return val;
13996
+ return val * exchangeRate;
13997
+ }, [amount, inputUnit, exchangeRate]);
13998
+ const convertedDisplay = useMemo11(() => {
13999
+ if (!amount || parseFloat(amount) <= 0) return null;
14000
+ if (inputUnit === "crypto") {
14001
+ return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
14002
+ }
14003
+ return `${cryptoAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 6 })} ${tokenSymbol}`;
14004
+ }, [amount, inputUnit, fiatAmountFromInput, cryptoAmountFromInput, tokenSymbol]);
14005
+ const balanceDisplay = useMemo11(() => {
14006
+ if (isLoadingBalance || !balanceData) return null;
14007
+ if (inputUnit === "crypto") {
14008
+ return `${balanceCrypto.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${tokenSymbol}`;
14009
+ }
14010
+ return `$${balanceUsdNum.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
14011
+ }, [isLoadingBalance, balanceData, inputUnit, balanceCrypto, balanceUsdNum, tokenSymbol]);
14012
+ const handleSwitchUnit = useCallback6(() => {
14013
+ const val = parseFloat(amount);
14014
+ if (!val || val <= 0 || exchangeRate <= 0) {
14015
+ setInputUnit((u) => u === "crypto" ? "fiat" : "crypto");
14016
+ setAmount("");
14017
+ return;
14018
+ }
14019
+ if (inputUnit === "crypto") {
14020
+ const fiat = val * exchangeRate;
14021
+ setAmount(fiat.toFixed(2));
14022
+ setInputUnit("fiat");
14023
+ } else {
14024
+ const crypto = val / exchangeRate;
14025
+ setAmount(crypto.toFixed(sourceDecimals > 6 ? 6 : sourceDecimals));
14026
+ setInputUnit("crypto");
14027
+ }
14028
+ }, [amount, inputUnit, exchangeRate, sourceDecimals]);
14029
+ const handleMaxClick = useCallback6(() => {
14030
+ if (inputUnit === "crypto") {
14031
+ if (balanceCrypto <= 0) return;
14032
+ setAmount(balanceData?.balanceHuman ?? "0");
14033
+ } else {
14034
+ if (balanceUsdNum <= 0) return;
14035
+ setAmount((Math.floor(balanceUsdNum * 100) / 100).toFixed(2));
14036
+ }
14037
+ }, [inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
14038
+ const isBelowMinimum = minimumWithdrawAmountUsd !== null && fiatAmountFromInput > 0 && fiatAmountFromInput < minimumWithdrawAmountUsd;
14039
+ const isOverBalance = inputUnit === "crypto" ? cryptoAmountFromInput > 0 && balanceCrypto > 0 && cryptoAmountFromInput > balanceCrypto : fiatAmountFromInput > 0 && balanceUsdNum > 0 && fiatAmountFromInput > balanceUsdNum;
14040
+ const isFormValid = trimmedAddress.length > 0 && amount.trim().length > 0 && cryptoAmountFromInput > 0 && isAddressValid && !isBelowMinimum && !isOverBalance && !!balanceData;
14041
+ const handleWithdraw = useCallback6(async () => {
14042
+ if (!selectedToken || !selectedChain) return;
14043
+ if (!isFormValid) return;
14044
+ setIsSubmitting(true);
14045
+ setSubmitError(null);
14046
+ try {
14047
+ const depositWallet = await onDepositWalletCreation({
14048
+ destinationChainType: selectedChain.chain_type,
14049
+ destinationChainId: selectedChain.chain_id,
14050
+ destinationTokenAddress: selectedChain.token_address,
14051
+ recipientAddress: trimmedAddress
14052
+ });
14053
+ const amountBaseUnit = computeBaseUnit(
14054
+ balanceData.balanceBaseUnit,
14055
+ parseFloat(amount),
14056
+ inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
14057
+ );
14058
+ const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
14059
+ const txInfo = {
14060
+ sourceChainType,
14061
+ sourceChainId,
14062
+ sourceTokenAddress,
14063
+ sourceTokenSymbol: tokenSymbol,
14064
+ destinationChainType: selectedChain.chain_type,
14065
+ destinationChainId: selectedChain.chain_id,
14066
+ destinationTokenAddress: selectedChain.token_address,
14067
+ destinationTokenSymbol: selectedToken.symbol,
14068
+ amount: humanAmount,
14069
+ amountBaseUnit,
14070
+ withdrawIntentAddress: depositWallet.address,
14071
+ recipientAddress: trimmedAddress
14072
+ };
14073
+ if (detectedWallet) {
14074
+ if (detectedWallet.chainFamily === "evm" && isHypercoreChain(sourceChainId)) {
14075
+ await sendHypercoreWithdraw({
14076
+ provider: detectedWallet.provider,
14077
+ fromAddress: detectedWallet.address,
14078
+ depositWalletAddress: depositWallet.address,
14079
+ sourceTokenAddress,
14080
+ amount: humanAmount,
14081
+ tokenSymbol,
14082
+ publishableKey
14083
+ });
14084
+ } else if (detectedWallet.chainFamily === "evm") {
14085
+ await sendEvmWithdraw({
14086
+ provider: detectedWallet.provider,
14087
+ fromAddress: detectedWallet.address,
14088
+ depositWalletAddress: depositWallet.address,
14089
+ sourceTokenAddress,
14090
+ sourceChainId,
14091
+ amountBaseUnit
14092
+ });
14093
+ } else if (detectedWallet.chainFamily === "solana") {
14094
+ await sendSolanaWithdraw({
14095
+ provider: detectedWallet.provider,
14096
+ fromAddress: detectedWallet.address,
14097
+ depositWalletAddress: depositWallet.address,
14098
+ sourceTokenAddress,
14099
+ amountBaseUnit,
14100
+ publishableKey
14101
+ });
14102
+ }
14103
+ } else if (onWithdraw) {
14104
+ await onWithdraw(txInfo);
14105
+ } else {
14106
+ throw new Error("No withdrawal method available. Please connect a wallet.");
14107
+ }
14108
+ onWithdrawSubmitted?.(txInfo);
14109
+ } catch (err) {
14110
+ const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
14111
+ setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
14112
+ onWithdrawError?.({
14113
+ message: raw,
14114
+ error: err,
14115
+ code: "WITHDRAW_FAILED"
14116
+ });
14117
+ } finally {
14118
+ setIsSubmitting(false);
14119
+ }
14120
+ }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
14121
+ return /* @__PURE__ */ jsxs47(Fragment11, { children: [
14122
+ /* @__PURE__ */ jsxs47("div", { children: [
14123
+ /* @__PURE__ */ jsx54(
14124
+ "div",
14125
+ {
14126
+ className: "uf-text-xs uf-mb-1.5",
14127
+ style: { color: components.card.labelColor, fontFamily: fonts.medium },
14128
+ children: t8.recipientAddress
14129
+ }
14130
+ ),
14131
+ /* @__PURE__ */ jsx54(
14132
+ "style",
14133
+ {
14134
+ dangerouslySetInnerHTML: {
14135
+ __html: `.uf-withdraw-addr::placeholder { color: ${components.search.placeholderColor}; }`
14136
+ }
14137
+ }
14138
+ ),
14139
+ /* @__PURE__ */ jsxs47(
14140
+ "div",
14141
+ {
14142
+ className: "uf-flex uf-items-center uf-gap-1 uf-pr-2",
14143
+ style: {
14144
+ backgroundColor: components.search.backgroundColor,
14145
+ borderRadius: components.input.borderRadius,
14146
+ border: `${components.input.borderWidth}px solid ${addressError ? colors2.error : components.input.borderColor}`
14147
+ },
14148
+ children: [
14149
+ /* @__PURE__ */ jsx54(
14150
+ "input",
14151
+ {
14152
+ type: "text",
14153
+ placeholder: t8.recipientAddressPlaceholder,
14154
+ value: recipientAddress,
14155
+ onChange: (e) => {
14156
+ setRecipientAddress(e.target.value);
14157
+ setSubmitError(null);
14158
+ },
14159
+ 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",
14160
+ style: {
14161
+ color: components.search.inputColor,
14162
+ fontFamily: fonts.regular
14163
+ }
14164
+ }
14165
+ ),
14166
+ /* @__PURE__ */ jsx54(
14167
+ "button",
14168
+ {
14169
+ type: "button",
14170
+ onClick: async () => {
14171
+ try {
14172
+ const text = await navigator.clipboard.readText();
14173
+ if (text) {
14174
+ setRecipientAddress(text.trim());
14175
+ setSubmitError(null);
14176
+ }
14177
+ } catch {
14178
+ }
14179
+ },
14180
+ className: "uf-flex-shrink-0 uf-p-1 uf-rounded uf-transition-colors hover:uf-opacity-70",
14181
+ style: { color: colors2.foregroundMuted },
14182
+ title: "Paste from clipboard",
14183
+ children: /* @__PURE__ */ jsx54(ClipboardPaste, { className: "uf-w-4 uf-h-4" })
14184
+ }
14185
+ )
14186
+ ]
14187
+ }
14188
+ ),
14189
+ (isDebouncing || isVerifyingAddress) && trimmedAddress.length > 5 && /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
14190
+ /* @__PURE__ */ jsx54(Loader26, { className: "uf-w-3 uf-h-3 uf-animate-spin", style: { color: colors2.foregroundMuted } }),
14191
+ /* @__PURE__ */ jsx54("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: t8.verifyingAddress })
14192
+ ] }),
14193
+ addressError && /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
14194
+ /* @__PURE__ */ jsx54(AlertTriangle3, { className: "uf-w-3 uf-h-3", style: { color: colors2.error } }),
14195
+ /* @__PURE__ */ jsx54("span", { className: "uf-text-xs", style: { color: colors2.error, fontFamily: fonts.regular }, children: addressError })
14196
+ ] })
14197
+ ] }),
14198
+ /* @__PURE__ */ jsxs47("div", { children: [
14199
+ /* @__PURE__ */ jsxs47("div", { className: "uf-text-xs uf-mb-1.5", style: { color: components.card.labelColor, fontFamily: fonts.medium }, children: [
14200
+ t8.amount,
14201
+ minimumWithdrawAmountUsd != null && minimumWithdrawAmountUsd > 0 && /* @__PURE__ */ jsx54("span", { style: { color: colors2.warning, fontFamily: fonts.regular }, children: ` ($${minimumWithdrawAmountUsd.toFixed(2)} min)` })
14202
+ ] }),
14203
+ /* @__PURE__ */ jsx54(
14204
+ "style",
14205
+ {
14206
+ dangerouslySetInnerHTML: {
14207
+ __html: `.uf-withdraw-amt::placeholder { color: ${components.search.placeholderColor}; }`
14208
+ }
14209
+ }
14210
+ ),
14211
+ /* @__PURE__ */ jsxs47(
14212
+ "div",
14213
+ {
14214
+ className: "uf-flex uf-items-center uf-gap-2 uf-px-3 uf-py-2.5",
14215
+ style: {
14216
+ backgroundColor: components.search.backgroundColor,
14217
+ borderRadius: components.input.borderRadius,
14218
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
14219
+ },
14220
+ children: [
14221
+ /* @__PURE__ */ jsx54(
14222
+ "input",
14223
+ {
14224
+ type: "text",
14225
+ inputMode: "decimal",
14226
+ placeholder: "0.00",
14227
+ value: amount,
14228
+ onChange: (e) => {
14229
+ const val = e.target.value;
14230
+ if (val === "" || /^\d*\.?\d*$/.test(val)) {
14231
+ setAmount(val);
14232
+ setSubmitError(null);
14233
+ }
14234
+ },
14235
+ className: "uf-withdraw-amt uf-flex-1 uf-min-w-0 uf-bg-transparent uf-text-sm uf-outline-none",
14236
+ style: {
14237
+ color: components.search.inputColor,
14238
+ fontFamily: fonts.regular
14239
+ }
14240
+ }
14241
+ ),
14242
+ /* @__PURE__ */ jsx54("span", { className: "uf-text-sm uf-shrink-0", style: { color: colors2.foregroundMuted, fontFamily: fonts.medium }, children: inputUnit === "crypto" ? tokenSymbol : "USD" }),
14243
+ /* @__PURE__ */ jsx54(
14244
+ "button",
14245
+ {
14246
+ type: "button",
14247
+ onClick: handleMaxClick,
14248
+ 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",
14249
+ style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium },
14250
+ children: "Max"
14251
+ }
14252
+ )
14253
+ ]
14254
+ }
14255
+ ),
14256
+ /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-justify-between uf-mt-1.5 uf-px-3", children: [
14257
+ /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
14258
+ /* @__PURE__ */ jsx54("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: convertedDisplay || (inputUnit === "crypto" ? "$0.00" : `0.00 ${tokenSymbol}`) }),
14259
+ exchangeRate > 0 && /* @__PURE__ */ jsx54(
14260
+ "button",
14261
+ {
14262
+ type: "button",
14263
+ onClick: handleSwitchUnit,
14264
+ className: "uf-p-0.5 uf-rounded uf-transition-colors hover:uf-opacity-70",
14265
+ style: { color: colors2.foregroundMuted },
14266
+ title: "Switch unit",
14267
+ children: /* @__PURE__ */ jsx54(ArrowUpDown, { className: "uf-w-3 uf-h-3" })
14268
+ }
14269
+ )
14270
+ ] }),
14271
+ /* @__PURE__ */ jsxs47("div", { children: [
14272
+ balanceDisplay && /* @__PURE__ */ jsxs47("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: [
14273
+ t8.balance,
14274
+ ": ",
14275
+ balanceDisplay
14276
+ ] }),
14277
+ isLoadingBalance && /* @__PURE__ */ jsx54("div", { className: "uf-h-3 uf-w-16 uf-bg-muted uf-rounded uf-animate-pulse" })
14278
+ ] })
14279
+ ] })
14280
+ ] }),
14281
+ /* @__PURE__ */ jsxs47("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: [
14282
+ /* @__PURE__ */ jsxs47(
14283
+ "button",
14284
+ {
14285
+ type: "button",
14286
+ onClick: () => setDetailsExpanded(!detailsExpanded),
14287
+ className: "uf-w-full uf-flex uf-items-center uf-justify-between uf-py-2.5",
14288
+ children: [
14289
+ /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
14290
+ /* @__PURE__ */ jsx54("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx54(Clock4, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
14291
+ /* @__PURE__ */ jsxs47("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
14292
+ tCrypto.processingTime.label,
14293
+ ":",
14294
+ " ",
14295
+ /* @__PURE__ */ jsx54("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(estimatedProcessingTime) })
14296
+ ] })
14297
+ ] }),
14298
+ detailsExpanded ? /* @__PURE__ */ jsx54(ChevronUp6, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ jsx54(ChevronDown7, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
14299
+ ]
14300
+ }
14301
+ ),
14302
+ detailsExpanded && /* @__PURE__ */ jsxs47("div", { className: "uf-pb-3 uf-space-y-2.5", children: [
14303
+ /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
14304
+ /* @__PURE__ */ jsx54("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx54(ShieldCheck3, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
14305
+ /* @__PURE__ */ jsxs47("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
14306
+ tCrypto.slippage.label,
14307
+ ":",
14308
+ " ",
14309
+ /* @__PURE__ */ jsxs47("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
14310
+ tCrypto.slippage.auto,
14311
+ " \u2022 ",
14312
+ (maxSlippagePercent ?? 0.25).toFixed(2),
14313
+ "%"
14314
+ ] })
14315
+ ] })
14316
+ ] }),
14317
+ /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
14318
+ /* @__PURE__ */ jsx54("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx54(DollarSign3, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
14319
+ /* @__PURE__ */ jsxs47("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
14320
+ tCrypto.priceImpact.label,
14321
+ ":",
14322
+ " ",
14323
+ /* @__PURE__ */ jsxs47("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
14324
+ (priceImpactPercent ?? 0).toFixed(2),
14325
+ "%"
14326
+ ] })
14327
+ ] })
14328
+ ] })
14329
+ ] })
14330
+ ] }),
14331
+ !canWithdraw && !submitError && /* @__PURE__ */ jsxs47(
14332
+ "div",
14333
+ {
14334
+ className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
14335
+ style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
14336
+ children: [
14337
+ /* @__PURE__ */ jsx54(Wallet3, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
14338
+ /* @__PURE__ */ jsx54("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." })
14339
+ ]
14340
+ }
14341
+ ),
14342
+ isWalletMatch && connectedWalletName ? /* @__PURE__ */ jsx54(
14343
+ "button",
14344
+ {
14345
+ type: "button",
14346
+ onClick: handleWithdraw,
14347
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
14348
+ 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",
14349
+ style: {
14350
+ backgroundColor: colors2.primary,
14351
+ color: colors2.primaryForeground,
14352
+ fontFamily: fonts.medium,
14353
+ borderRadius: components.button.borderRadius,
14354
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
14355
+ },
14356
+ children: isSubmitting ? /* @__PURE__ */ jsxs47(Fragment11, { children: [
14357
+ /* @__PURE__ */ jsx54(Loader26, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
14358
+ "Processing..."
14359
+ ] }) : isOverBalance ? /* @__PURE__ */ jsx54(Fragment11, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ jsx54(Fragment11, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ jsx54(Fragment11, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ jsxs47(Fragment11, { children: [
14360
+ /* @__PURE__ */ jsx54(Wallet3, { className: "uf-w-4 uf-h-4" }),
14361
+ "Withdraw from ",
14362
+ connectedWalletName
14363
+ ] })
14364
+ }
14365
+ ) : /* @__PURE__ */ jsx54(
14366
+ "button",
14367
+ {
14368
+ type: "button",
14369
+ onClick: handleWithdraw,
14370
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
14371
+ 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",
14372
+ style: {
14373
+ backgroundColor: colors2.primary,
14374
+ color: colors2.primaryForeground,
14375
+ fontFamily: fonts.medium,
14376
+ borderRadius: components.button.borderRadius,
14377
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
14378
+ },
14379
+ children: isSubmitting ? /* @__PURE__ */ jsxs47("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
14380
+ /* @__PURE__ */ jsx54(Loader26, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
14381
+ "Processing..."
14382
+ ] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
14383
+ }
14384
+ ),
14385
+ /* @__PURE__ */ jsxs47("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
14386
+ /* @__PURE__ */ jsx54("div", { children: footerLeft }),
14387
+ /* @__PURE__ */ jsx54(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) })
14388
+ ] }),
14389
+ /* @__PURE__ */ jsx54(
14390
+ GlossaryModal,
14391
+ {
14392
+ open: glossaryOpen,
14393
+ onOpenChange: setGlossaryOpen
14394
+ }
14395
+ )
14396
+ ] });
14397
+ }
14398
+
14399
+ // src/components/withdrawals/WithdrawExecutionItem.tsx
14400
+ import { ChevronRight as ChevronRight13 } from "lucide-react";
14401
+ import {
14402
+ ExecutionStatus as ExecutionStatus6,
14403
+ getIconUrl as getIconUrl5
14404
+ } from "@unifold/core";
14405
+ import { jsx as jsx55, jsxs as jsxs48 } from "react/jsx-runtime";
14406
+ function WithdrawExecutionItem({
14407
+ execution,
14408
+ onClick
14409
+ }) {
14410
+ const { colors: colors2, fonts, components } = useTheme();
14411
+ const isPending = execution.status === ExecutionStatus6.PENDING || execution.status === ExecutionStatus6.WAITING || execution.status === ExecutionStatus6.DELAYED;
14412
+ const formatDateTime = (timestamp) => {
14413
+ try {
14414
+ const date = new Date(timestamp);
14415
+ const monthDay = date.toLocaleDateString("en-US", {
14416
+ month: "short",
14417
+ day: "numeric",
14418
+ year: "numeric"
14419
+ });
14420
+ const time = date.toLocaleTimeString("en-US", {
14421
+ hour: "numeric",
14422
+ minute: "2-digit",
14423
+ hour12: true
14424
+ }).toLowerCase();
14425
+ return `${monthDay} at ${time}`;
14426
+ } catch {
14427
+ return timestamp;
14428
+ }
14429
+ };
14430
+ const formatUsdAmount2 = (sourceAmountUsd) => {
14431
+ try {
14432
+ const amount = Number(sourceAmountUsd);
14433
+ return new Intl.NumberFormat("en-US", {
14434
+ style: "currency",
14435
+ currency: "USD",
14436
+ minimumFractionDigits: 2,
14437
+ maximumFractionDigits: 2
14438
+ }).format(amount);
14439
+ } catch {
14440
+ return "$0.00";
14441
+ }
14442
+ };
14443
+ return /* @__PURE__ */ jsxs48(
14444
+ "button",
14445
+ {
14446
+ onClick,
14447
+ 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",
14448
+ style: {
14449
+ backgroundColor: components.card.backgroundColor,
14450
+ borderRadius: components.list.rowBorderRadius,
14451
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
14452
+ },
14453
+ children: [
14454
+ /* @__PURE__ */ jsxs48("div", { className: "uf-relative uf-flex-shrink-0 uf-w-9 uf-h-9", children: [
14455
+ /* @__PURE__ */ jsx55(
14456
+ "img",
14457
+ {
14458
+ src: execution.destination_token_metadata?.icon_url || getIconUrl5("/icons/tokens/svg/usdc.svg"),
14459
+ alt: "Token",
14460
+ width: 36,
14461
+ height: 36,
14462
+ loading: "lazy",
14463
+ className: "uf-rounded-full uf-w-9 uf-h-9"
14464
+ }
14465
+ ),
14466
+ isPending ? /* @__PURE__ */ jsx55(
14467
+ "div",
14468
+ {
14469
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
14470
+ style: { backgroundColor: colors2.warning },
14471
+ children: /* @__PURE__ */ jsx55(
14472
+ "svg",
14473
+ {
14474
+ width: "10",
14475
+ height: "10",
14476
+ viewBox: "0 0 12 12",
14477
+ fill: "none",
14478
+ className: "uf-animate-spin uf-block",
14479
+ children: /* @__PURE__ */ jsx55(
14480
+ "path",
14481
+ {
14482
+ d: "M6 1V3M6 9V11M1 6H3M9 6H11M2.5 2.5L4 4M8 8L9.5 9.5M2.5 9.5L4 8M8 4L9.5 2.5",
14483
+ stroke: "white",
14484
+ strokeWidth: "2",
14485
+ strokeLinecap: "round"
14486
+ }
14487
+ )
14488
+ }
14489
+ )
14490
+ }
14491
+ ) : /* @__PURE__ */ jsx55(
14492
+ "div",
14493
+ {
14494
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
14495
+ style: { backgroundColor: colors2.success },
14496
+ children: /* @__PURE__ */ jsx55(
14497
+ "svg",
14498
+ {
14499
+ width: "10",
14500
+ height: "10",
14501
+ viewBox: "0 0 12 12",
14502
+ fill: "none",
14503
+ className: "uf-block",
14504
+ children: /* @__PURE__ */ jsx55(
14505
+ "path",
14506
+ {
14507
+ d: "M10 3L4.5 8.5L2 6",
14508
+ stroke: "white",
14509
+ strokeWidth: "2",
14510
+ strokeLinecap: "round",
14511
+ strokeLinejoin: "round"
14512
+ }
14513
+ )
14514
+ }
14515
+ )
14516
+ }
14517
+ )
14518
+ ] }),
14519
+ /* @__PURE__ */ jsxs48("div", { className: "uf-flex-1 uf-min-w-0", children: [
14520
+ /* @__PURE__ */ jsx55(
14521
+ "h3",
14522
+ {
14523
+ className: "uf-font-medium uf-text-sm uf-leading-tight",
14524
+ style: {
14525
+ color: components.card.titleColor,
14526
+ fontFamily: fonts.medium
14527
+ },
14528
+ children: isPending ? "Withdrawal processing" : "Withdrawal completed"
14529
+ }
14530
+ ),
14531
+ /* @__PURE__ */ jsx55(
14532
+ "p",
14533
+ {
14534
+ className: "uf-text-xs uf-leading-tight",
14535
+ style: {
14536
+ color: components.card.subtitleColor,
14537
+ fontFamily: fonts.regular
14538
+ },
14539
+ children: formatDateTime(execution.created_at || (/* @__PURE__ */ new Date()).toISOString())
14540
+ }
14541
+ )
14542
+ ] }),
14543
+ /* @__PURE__ */ jsx55(
14544
+ "span",
14545
+ {
14546
+ className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
14547
+ style: {
14548
+ color: components.card.textRightColor,
14549
+ fontFamily: fonts.medium
14550
+ },
14551
+ children: formatUsdAmount2(execution.source_amount_usd || "0")
14552
+ }
14553
+ ),
14554
+ /* @__PURE__ */ jsx55(
14555
+ ChevronRight13,
14556
+ {
14557
+ className: "uf-w-4 uf-h-4 uf-flex-shrink-0",
14558
+ style: { color: components.card.actionColor }
14559
+ }
14560
+ )
14561
+ ]
14562
+ }
14563
+ );
14564
+ }
14565
+
14566
+ // src/components/withdrawals/WithdrawConfirmingView.tsx
14567
+ import { useState as useState31, useEffect as useEffect26 } from "react";
14568
+ import { Fragment as Fragment12, jsx as jsx56, jsxs as jsxs49 } from "react/jsx-runtime";
14569
+ function truncateAddress4(addr) {
14570
+ if (addr.length <= 12) return addr;
14571
+ return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
14572
+ }
14573
+ var SHOW_BUTTON_DELAY_MS = 5e3;
14574
+ function WithdrawConfirmingView({
14575
+ txInfo,
14576
+ executions,
14577
+ onClose,
14578
+ onViewTracker
14579
+ }) {
14580
+ const { colors: colors2, fonts, components } = useTheme();
14581
+ const [showButton, setShowButton] = useState31(false);
14582
+ const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
14583
+ useEffect26(() => {
14584
+ if (latestExecution) return;
14585
+ const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
14586
+ return () => clearTimeout(timer);
14587
+ }, [latestExecution]);
14588
+ const btnRadius = components.button.borderRadius;
14589
+ const btnBorder = `${components.button.borderWidth}px solid ${components.button.borderColor}`;
14590
+ if (latestExecution) {
14591
+ return /* @__PURE__ */ jsxs49(Fragment12, { children: [
14592
+ /* @__PURE__ */ jsx56(DepositHeader, { title: "Withdrawal Details", showClose: true, onClose }),
14593
+ /* @__PURE__ */ jsx56(DepositDetailContent, { execution: latestExecution, variant: "withdraw" }),
14594
+ /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-gap-2 uf-px-2 uf-pt-2", children: [
14595
+ /* @__PURE__ */ jsx56(
14596
+ "button",
14597
+ {
14598
+ type: "button",
14599
+ onClick: onViewTracker,
14600
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
14601
+ style: {
14602
+ backgroundColor: components.button.secondaryBackground,
14603
+ color: components.button.secondaryText,
14604
+ fontFamily: fonts.medium,
14605
+ borderRadius: btnRadius,
14606
+ border: btnBorder
14607
+ },
14608
+ children: "Withdrawal History"
14609
+ }
14610
+ ),
14611
+ /* @__PURE__ */ jsx56(
14612
+ "button",
14613
+ {
14614
+ type: "button",
14615
+ onClick: onClose,
14616
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
14617
+ style: {
14618
+ backgroundColor: components.button.primaryBackground,
14619
+ color: components.button.primaryText,
14620
+ fontFamily: fonts.medium,
14621
+ borderRadius: btnRadius,
14622
+ border: btnBorder
14623
+ },
14624
+ children: "Close"
14625
+ }
14626
+ )
14627
+ ] }),
14628
+ /* @__PURE__ */ jsx56("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx56(
14629
+ PoweredByUnifold,
14630
+ {
14631
+ color: colors2.foregroundMuted,
14632
+ className: "uf-flex uf-justify-center uf-shrink-0"
14633
+ }
14634
+ ) })
14635
+ ] });
14636
+ }
14637
+ return /* @__PURE__ */ jsxs49(Fragment12, { children: [
14638
+ /* @__PURE__ */ jsx56(DepositHeader, { title: "Withdrawal Status", showClose: true, onClose }),
14639
+ /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4", children: [
14640
+ /* @__PURE__ */ jsx56(
14641
+ "div",
14642
+ {
14643
+ className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
14644
+ style: { backgroundColor: `${colors2.primary}20` },
14645
+ children: /* @__PURE__ */ jsx56(
14646
+ "svg",
14647
+ {
14648
+ width: "40",
14649
+ height: "40",
14650
+ viewBox: "0 0 24 24",
14651
+ fill: "none",
14652
+ className: "uf-animate-spin",
14653
+ children: /* @__PURE__ */ jsx56(
14654
+ "path",
14655
+ {
14656
+ d: "M21 12a9 9 0 1 1-6.22-8.56",
14657
+ stroke: colors2.primary,
14658
+ strokeWidth: "2.5",
14659
+ strokeLinecap: "round"
14660
+ }
14661
+ )
14662
+ }
14663
+ )
14664
+ }
14665
+ ),
14666
+ /* @__PURE__ */ jsx56(
14667
+ "h3",
14668
+ {
14669
+ className: "uf-text-xl uf-mb-2",
14670
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
14671
+ children: "Checking Withdrawal"
14672
+ }
14673
+ ),
14674
+ /* @__PURE__ */ jsxs49(
14675
+ "p",
14676
+ {
14677
+ className: "uf-text-sm uf-text-center",
14678
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
14679
+ children: [
14680
+ txInfo.amount,
14681
+ " ",
14682
+ txInfo.sourceTokenSymbol,
14683
+ " to",
14684
+ " ",
14685
+ truncateAddress4(txInfo.recipientAddress)
14686
+ ]
14687
+ }
14688
+ )
14689
+ ] }),
14690
+ showButton && /* @__PURE__ */ jsx56("div", { className: "uf-px-1 uf-pb-1", children: /* @__PURE__ */ jsx56(
14691
+ "button",
14692
+ {
14693
+ type: "button",
14694
+ onClick: onViewTracker,
14695
+ className: "uf-w-full uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
14696
+ style: {
14697
+ backgroundColor: components.button.secondaryBackground,
14698
+ color: components.button.secondaryText,
14699
+ fontFamily: fonts.medium,
14700
+ borderRadius: btnRadius,
14701
+ border: btnBorder
14702
+ },
14703
+ children: "Withdrawal History"
14704
+ }
14705
+ ) }),
14706
+ /* @__PURE__ */ jsx56("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx56(
14707
+ PoweredByUnifold,
14708
+ {
14709
+ color: colors2.foregroundMuted,
14710
+ className: "uf-flex uf-justify-center uf-shrink-0"
14711
+ }
14712
+ ) })
14713
+ ] });
14714
+ }
14715
+
14716
+ // src/components/withdrawals/WithdrawModal.tsx
14717
+ import {
14718
+ createDepositAddress as createDepositAddress2,
14719
+ getWalletByChainType as getWalletByChainType4,
14720
+ ActionType as ActionType6
14721
+ } from "@unifold/core";
14722
+ import { Fragment as Fragment13, jsx as jsx57, jsxs as jsxs50 } from "react/jsx-runtime";
14723
+ var t9 = i18n.withdrawModal;
14724
+ var getChainKey5 = (chainId, chainType) => `${chainType}:${chainId}`;
14725
+ function WithdrawModal({
14726
+ open,
14727
+ onOpenChange,
14728
+ publishableKey,
14729
+ modalTitle,
14730
+ externalUserId,
14731
+ sourceChainType,
14732
+ sourceChainId,
14733
+ sourceTokenAddress,
14734
+ sourceTokenSymbol,
14735
+ recipientAddress: recipientAddressProp,
14736
+ senderAddress,
14737
+ onWithdraw,
14738
+ onWithdrawSuccess,
14739
+ onWithdrawError,
14740
+ theme = "dark",
14741
+ hideOverlay = false
14742
+ }) {
14743
+ const { colors: colors2, fonts, components } = useTheme();
14744
+ const [containerEl, setContainerEl] = useState32(null);
14745
+ const containerCallbackRef = useCallback7((el) => {
14746
+ setContainerEl(el);
14747
+ }, []);
14748
+ const [resolvedTheme, setResolvedTheme] = useState32(
14749
+ theme === "auto" ? "dark" : theme
14750
+ );
14751
+ useEffect27(() => {
14752
+ if (theme === "auto") {
14753
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
14754
+ setResolvedTheme(mq.matches ? "dark" : "light");
14755
+ const h = (e) => setResolvedTheme(e.matches ? "dark" : "light");
14756
+ mq.addEventListener("change", h);
14757
+ return () => mq.removeEventListener("change", h);
14758
+ }
14759
+ setResolvedTheme(theme);
14760
+ }, [theme]);
14761
+ const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
14762
+ const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDestinationTokens(publishableKey, open);
14763
+ const destinationTokens = tokensResponse?.data ?? [];
14764
+ const { data: sourceValidation, isLoading: isCheckingSourceToken } = useSourceTokenValidation({
14765
+ sourceChainType,
14766
+ sourceChainId,
14767
+ sourceTokenAddress,
14768
+ sourceTokenSymbol,
14769
+ publishableKey,
14770
+ enabled: open
14771
+ });
14772
+ const { data: balanceData, isLoading: isLoadingBalance } = useAddressBalance({
14773
+ address: senderAddress,
14774
+ chainType: sourceChainType,
14775
+ chainId: sourceChainId,
14776
+ tokenAddress: sourceTokenAddress,
14777
+ publishableKey,
14778
+ enabled: open
14779
+ });
14780
+ const [selectedToken, setSelectedToken] = useState32(null);
14781
+ const [selectedChain, setSelectedChain] = useState32(null);
14782
+ const [detectedWallet, setDetectedWallet] = useState32(null);
14783
+ const connectedWalletName = detectedWallet?.name ?? null;
14784
+ const isWalletMatch = !!detectedWallet;
14785
+ useEffect27(() => {
14786
+ if (!senderAddress || !open) {
14787
+ setDetectedWallet(null);
14788
+ return;
14789
+ }
14790
+ let cancelled = false;
14791
+ detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
14792
+ if (!cancelled) setDetectedWallet(wallet);
14793
+ });
14794
+ return () => {
14795
+ cancelled = true;
14796
+ };
14797
+ }, [senderAddress, sourceChainType, open]);
14798
+ const [view, setView] = useState32("form");
14799
+ const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState32();
14800
+ const [selectedExecution, setSelectedExecution] = useState32(null);
14801
+ const [submittedTxInfo, setSubmittedTxInfo] = useState32(null);
14802
+ const { executions: realtimeExecutions } = useWithdrawPolling({
14803
+ userId: externalUserId,
14804
+ publishableKey,
14805
+ depositWalletId: withdrawDepositWalletId,
14806
+ enabled: !!withdrawDepositWalletId && open,
14807
+ onWithdrawSuccess: onWithdrawSuccess ? (d) => onWithdrawSuccess({ message: d.message, transaction: d.transaction }) : void 0,
14808
+ onWithdrawError
14809
+ });
14810
+ const { data: allWithdrawalsData } = useExecutions(externalUserId, publishableKey, {
14811
+ actionType: ActionType6.Withdraw,
14812
+ enabled: open,
14813
+ refetchInterval: view === "tracker" || view === "detail" ? 5e3 : 15e3
14814
+ });
14815
+ const allWithdrawals = allWithdrawalsData?.data ?? [];
14816
+ const handleDepositWalletCreation = useCallback7(async (params) => {
14817
+ const { data: wallets } = await createDepositAddress2(
14818
+ {
14819
+ external_user_id: externalUserId,
14820
+ destination_chain_type: params.destinationChainType,
14821
+ destination_chain_id: params.destinationChainId,
14822
+ destination_token_address: params.destinationTokenAddress,
14823
+ recipient_address: params.recipientAddress,
14824
+ action_type: ActionType6.Withdraw
14825
+ },
14826
+ publishableKey
14827
+ );
14828
+ const depositWallet = getWalletByChainType4(wallets, sourceChainType);
14829
+ if (!depositWallet) {
14830
+ throw new Error(`No deposit wallet available for ${sourceChainType}`);
14831
+ }
14832
+ setWithdrawDepositWalletId(depositWallet.id);
14833
+ return depositWallet;
14834
+ }, [externalUserId, publishableKey, sourceChainType]);
14835
+ const handleWithdrawSubmitted = useCallback7((txInfo) => {
14836
+ setSubmittedTxInfo(txInfo);
14837
+ setView("confirming");
14838
+ }, []);
14839
+ useEffect27(() => {
14840
+ if (!destinationTokens.length || selectedToken) return;
14841
+ const first = destinationTokens[0];
14842
+ if (first?.chains.length > 0) {
14843
+ setSelectedToken(first);
14844
+ setSelectedChain(first.chains[0]);
14845
+ }
14846
+ }, [destinationTokens, selectedToken]);
14847
+ const resetViewTimeoutRef = useRef10(null);
14848
+ const handleClose = useCallback7(() => {
14849
+ onOpenChange(false);
14850
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
14851
+ resetViewTimeoutRef.current = setTimeout(() => {
14852
+ setSelectedToken(null);
14853
+ setSelectedChain(null);
14854
+ setView("form");
14855
+ setSelectedExecution(null);
14856
+ setSubmittedTxInfo(null);
14857
+ setWithdrawDepositWalletId(void 0);
14858
+ resetViewTimeoutRef.current = null;
14859
+ }, 200);
14860
+ }, [onOpenChange]);
14861
+ useLayoutEffect4(() => {
14862
+ if (!open) return;
14863
+ if (resetViewTimeoutRef.current) {
14864
+ clearTimeout(resetViewTimeoutRef.current);
14865
+ resetViewTimeoutRef.current = null;
14866
+ }
14867
+ setSelectedToken(null);
14868
+ setSelectedChain(null);
14869
+ setView("form");
14870
+ setSelectedExecution(null);
14871
+ setSubmittedTxInfo(null);
14872
+ setWithdrawDepositWalletId(void 0);
14873
+ }, [open]);
14874
+ useEffect27(() => () => {
14875
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
14876
+ }, []);
14877
+ const handleTokenSymbolChange = useCallback7((symbol) => {
14878
+ const tok = destinationTokens.find((t11) => t11.symbol === symbol);
14879
+ if (tok) {
14880
+ setSelectedToken(tok);
14881
+ if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
14882
+ }
14883
+ }, [destinationTokens]);
14884
+ const handleChainKeyChange = useCallback7((chainKey) => {
14885
+ if (!selectedToken) return;
14886
+ const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
14887
+ if (chain) setSelectedChain(chain);
14888
+ }, [selectedToken]);
14889
+ const isSourceSupported = sourceValidation?.isSupported ?? null;
14890
+ const canWithdraw = !!onWithdraw || isWalletMatch;
14891
+ const isAnyLoading = tokensLoading || isCheckingSourceToken;
14892
+ const withdrawPoweredByFooter = /* @__PURE__ */ jsx57("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx57(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
14893
+ return /* @__PURE__ */ jsx57(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ jsx57(Dialog, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ jsx57(
14894
+ DialogContent,
14895
+ {
14896
+ ref: hideOverlay ? containerCallbackRef : void 0,
14897
+ hideOverlay,
14898
+ 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}`}`,
14899
+ style: { backgroundColor: colors2.background },
14900
+ onPointerDownOutside: (e) => e.preventDefault(),
14901
+ onInteractOutside: (e) => e.preventDefault(),
14902
+ children: /* @__PURE__ */ jsx57(ThemeStyleInjector, { children: view === "confirming" && submittedTxInfo ? /* @__PURE__ */ jsx57(
14903
+ WithdrawConfirmingView,
14904
+ {
14905
+ txInfo: submittedTxInfo,
14906
+ executions: realtimeExecutions,
14907
+ onClose: handleClose,
14908
+ onViewTracker: () => setView("tracker")
14909
+ }
14910
+ ) : view === "detail" && selectedExecution ? /* @__PURE__ */ jsxs50(Fragment13, { children: [
14911
+ /* @__PURE__ */ jsx57(DepositHeader, { title: "Withdrawal Details", showBack: true, showClose: !hideOverlay, onBack: () => {
14912
+ setSelectedExecution(null);
14913
+ setView("tracker");
14914
+ }, onClose: handleClose }),
14915
+ /* @__PURE__ */ jsx57(DepositDetailContent, { execution: selectedExecution, variant: "withdraw" }),
14916
+ withdrawPoweredByFooter
14917
+ ] }) : view === "tracker" ? (
14918
+ /* ---------- Tracker view: execution list ---------- */
14919
+ /* @__PURE__ */ jsxs50(Fragment13, { children: [
14920
+ /* @__PURE__ */ jsx57(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
14921
+ /* @__PURE__ */ jsx57("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ jsx57("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ jsx57("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ jsx57(
14922
+ WithdrawExecutionItem,
14923
+ {
14924
+ execution: ex,
14925
+ onClick: () => {
14926
+ setSelectedExecution(ex);
14927
+ setView("detail");
14928
+ }
14929
+ },
14930
+ ex.id
14931
+ )) }),
14932
+ withdrawPoweredByFooter
14933
+ ] })
14934
+ ) : (
14935
+ /* ---------- Form view (default) ---------- */
14936
+ /* @__PURE__ */ jsxs50(Fragment13, { children: [
14937
+ /* @__PURE__ */ jsx57(DepositHeader, { title: modalTitle || t9.title, showClose: !hideOverlay, onClose: handleClose }),
14938
+ /* @__PURE__ */ jsxs50("div", { className: "uf-flex uf-flex-col uf-gap-3", children: [
14939
+ isAnyLoading ? /* @__PURE__ */ jsx57("div", { className: "uf-space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsx57("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-animate-pulse", children: /* @__PURE__ */ jsx57("div", { className: "uf-bg-muted uf-rounded-lg uf-w-full uf-h-10" }) }, i)) }) : isSourceSupported === false ? /* @__PURE__ */ jsxs50("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
14940
+ /* @__PURE__ */ jsx57("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__ */ jsx57(AlertTriangle4, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
14941
+ /* @__PURE__ */ jsx57("h3", { className: "uf-text-lg uf-font-semibold uf-mb-2", style: { color: colors2.foreground, fontFamily: fonts.medium }, children: "Unsupported Source Token" }),
14942
+ /* @__PURE__ */ jsx57("p", { className: "uf-text-sm uf-max-w-[280px]", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: sourceValidation?.errorMessage })
14943
+ ] }) : /* @__PURE__ */ jsxs50(Fragment13, { children: [
14944
+ /* @__PURE__ */ jsx57(
14945
+ WithdrawDoubleInput,
14946
+ {
14947
+ tokens: destinationTokens,
14948
+ selectedTokenSymbol: selectedToken?.symbol ?? null,
14949
+ selectedChainKey: selectedChain ? getChainKey5(selectedChain.chain_id, selectedChain.chain_type) : null,
14950
+ onTokenChange: handleTokenSymbolChange,
14951
+ onChainChange: handleChainKeyChange,
14952
+ isLoading: tokensLoading
14953
+ }
14954
+ ),
14955
+ /* @__PURE__ */ jsx57(
14956
+ WithdrawForm,
14957
+ {
14958
+ publishableKey,
14959
+ externalUserId,
14960
+ sourceChainType,
14961
+ selectedToken,
14962
+ selectedChain,
14963
+ sourceTokenSymbol,
14964
+ recipientAddressProp,
14965
+ balanceData: balanceData ?? null,
14966
+ isLoadingBalance,
14967
+ minimumWithdrawAmountUsd: sourceValidation?.minimumAmountUsd ?? null,
14968
+ estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
14969
+ maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
14970
+ priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
14971
+ detectedWallet,
14972
+ sourceChainId,
14973
+ sourceTokenAddress,
14974
+ isWalletMatch,
14975
+ connectedWalletName,
14976
+ canWithdraw,
14977
+ onWithdraw,
14978
+ onWithdrawError,
14979
+ onDepositWalletCreation: handleDepositWalletCreation,
14980
+ onWithdrawSubmitted: handleWithdrawSubmitted,
14981
+ footerLeft: /* @__PURE__ */ jsxs50(
14982
+ "button",
14983
+ {
14984
+ onClick: () => setView("tracker"),
14985
+ className: "uf-flex uf-items-center uf-gap-1 uf-transition-colors hover:uf-opacity-70",
14986
+ style: { color: colors2.foregroundMuted },
14987
+ children: [
14988
+ /* @__PURE__ */ jsx57(Clock5, { className: "uf-w-3.5 uf-h-3.5" }),
14989
+ "Withdrawal History",
14990
+ /* @__PURE__ */ jsx57(ChevronRight14, { className: "uf-w-3 uf-h-3" })
14991
+ ]
14992
+ }
14993
+ )
14994
+ }
14995
+ )
14996
+ ] }),
14997
+ withdrawPoweredByFooter
14998
+ ] })
14999
+ ] })
15000
+ ) })
15001
+ }
15002
+ ) }) });
15003
+ }
15004
+
15005
+ // src/components/withdrawals/WithdrawTokenSelector.tsx
15006
+ import { useState as useState33, useMemo as useMemo12 } from "react";
15007
+ import { Search } from "lucide-react";
15008
+ import { jsx as jsx58, jsxs as jsxs51 } from "react/jsx-runtime";
15009
+ var t10 = i18n.withdrawModal;
15010
+ function WithdrawTokenSelector({
15011
+ tokens,
15012
+ onSelect,
15013
+ onBack
15014
+ }) {
15015
+ const { themeClass, colors: colors2, fonts, components } = useTheme();
15016
+ const [searchQuery, setSearchQuery] = useState33("");
15017
+ const [hoveredKey, setHoveredKey] = useState33(null);
15018
+ const allOptions = useMemo12(() => {
15019
+ const options = [];
15020
+ tokens.forEach((token) => {
15021
+ token.chains.forEach((chain) => {
15022
+ options.push({ token, chain });
15023
+ });
15024
+ });
15025
+ return options;
15026
+ }, [tokens]);
15027
+ const filteredOptions = useMemo12(() => {
15028
+ if (!searchQuery.trim()) return allOptions;
15029
+ const query = searchQuery.toLowerCase();
15030
+ return allOptions.filter(
15031
+ ({ token, chain }) => token.symbol.toLowerCase().includes(query) || token.name.toLowerCase().includes(query) || chain.chain_name.toLowerCase().includes(query)
15032
+ );
15033
+ }, [allOptions, searchQuery]);
15034
+ return /* @__PURE__ */ jsxs51(
15035
+ "div",
15036
+ {
15037
+ className: "uf-flex uf-flex-col",
15038
+ style: { minHeight: 0, flex: 1 },
15039
+ children: [
15040
+ /* @__PURE__ */ jsxs51("div", { className: "uf-pb-3", children: [
15041
+ /* @__PURE__ */ jsx58(
15042
+ "style",
15043
+ {
15044
+ dangerouslySetInnerHTML: {
15045
+ __html: `.uf-withdraw-token-search::placeholder { color: ${components.search.placeholderColor}; }`
15046
+ }
15047
+ }
15048
+ ),
15049
+ /* @__PURE__ */ jsxs51("div", { style: { position: "relative" }, children: [
15050
+ /* @__PURE__ */ jsx58(
15051
+ Search,
15052
+ {
15053
+ className: "uf-absolute uf-left-3 uf-top-1/2 uf--translate-y-1/2 uf-w-4 uf-h-4",
15054
+ style: { color: components.search.placeholderColor }
15055
+ }
15056
+ ),
15057
+ /* @__PURE__ */ jsx58(
15058
+ "input",
15059
+ {
15060
+ type: "text",
15061
+ placeholder: "Search token or network",
15062
+ value: searchQuery,
15063
+ onChange: (e) => setSearchQuery(e.target.value),
15064
+ 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",
15065
+ style: {
15066
+ backgroundColor: components.search.backgroundColor,
15067
+ color: components.search.inputColor,
15068
+ fontFamily: fonts.regular,
15069
+ borderRadius: components.input.borderRadius,
15070
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
15071
+ }
15072
+ }
15073
+ )
15074
+ ] })
15075
+ ] }),
15076
+ /* @__PURE__ */ jsx58(
15077
+ "div",
15078
+ {
15079
+ className: "uf-text-xs uf-mb-2",
15080
+ style: {
15081
+ color: components.list.titleSectionColor,
15082
+ fontFamily: fonts.medium
15083
+ },
15084
+ children: t10.selectToken
15085
+ }
15086
+ ),
15087
+ /* @__PURE__ */ jsx58(
15088
+ "div",
15089
+ {
15090
+ className: "uf-flex-1 uf-overflow-y-auto uf-min-h-0 uf--mx-6 uf-px-6 uf-pb-3",
15091
+ style: { scrollbarWidth: "none" },
15092
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx58(
15093
+ "div",
15094
+ {
15095
+ style: {
15096
+ textAlign: "center",
15097
+ padding: "2rem 0",
15098
+ fontSize: 14,
15099
+ color: components.container.subtitleColor,
15100
+ fontFamily: fonts.regular
15101
+ },
15102
+ children: t10.noTokensAvailable
15103
+ }
15104
+ ) : /* @__PURE__ */ jsx58("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: filteredOptions.map(({ token, chain }) => {
15105
+ const key = `${token.symbol}-${chain.chain_type}:${chain.chain_id}`;
15106
+ return /* @__PURE__ */ jsxs51(
15107
+ "button",
15108
+ {
15109
+ type: "button",
15110
+ onClick: () => onSelect(token, chain),
15111
+ onMouseEnter: () => setHoveredKey(key),
15112
+ onMouseLeave: () => setHoveredKey(null),
15113
+ className: "uf-transition-colors",
15114
+ style: {
15115
+ width: "100%",
15116
+ display: "flex",
15117
+ alignItems: "center",
15118
+ gap: 12,
15119
+ padding: 12,
15120
+ borderRadius: 12,
15121
+ border: "none",
15122
+ cursor: "pointer",
15123
+ textAlign: "left",
15124
+ backgroundColor: hoveredKey === key ? colors2.cardHover : "transparent"
15125
+ },
15126
+ children: [
15127
+ /* @__PURE__ */ jsxs51("div", { style: { position: "relative", flexShrink: 0 }, children: [
15128
+ /* @__PURE__ */ jsx58(
15129
+ "img",
15130
+ {
15131
+ src: token.icon_url,
15132
+ alt: token.symbol,
15133
+ width: 40,
15134
+ height: 40,
15135
+ loading: "lazy",
15136
+ className: "uf-rounded-full"
15137
+ }
15138
+ ),
15139
+ /* @__PURE__ */ jsx58(
15140
+ "div",
15141
+ {
15142
+ style: {
15143
+ position: "absolute",
15144
+ bottom: -4,
15145
+ right: -4
15146
+ },
15147
+ children: /* @__PURE__ */ jsx58(
15148
+ "img",
15149
+ {
15150
+ src: chain.icon_url,
15151
+ alt: chain.chain_name,
15152
+ width: 20,
15153
+ height: 20,
15154
+ loading: "lazy",
15155
+ className: "uf-rounded-full uf-border-2"
15156
+ }
15157
+ )
15158
+ }
15159
+ )
15160
+ ] }),
15161
+ /* @__PURE__ */ jsxs51("div", { style: { flex: 1, minWidth: 0 }, children: [
15162
+ /* @__PURE__ */ jsx58(
15163
+ "div",
15164
+ {
15165
+ style: {
15166
+ fontSize: 14,
15167
+ fontWeight: 500,
15168
+ color: components.card.titleColor,
15169
+ fontFamily: fonts.medium
15170
+ },
15171
+ children: token.symbol
15172
+ }
15173
+ ),
15174
+ /* @__PURE__ */ jsxs51(
15175
+ "div",
15176
+ {
15177
+ style: {
15178
+ fontSize: 12,
15179
+ color: components.card.subtitleColor,
15180
+ fontFamily: fonts.regular
15181
+ },
15182
+ children: [
15183
+ token.name,
15184
+ " \u2022 ",
15185
+ chain.chain_name
15186
+ ]
15187
+ }
15188
+ )
15189
+ ] })
15190
+ ]
15191
+ },
15192
+ key
15193
+ );
15194
+ }) })
15195
+ }
15196
+ ),
15197
+ /* @__PURE__ */ jsx58("div", { className: "uf-pt-3 uf-pb-2 uf-shrink-0", children: /* @__PURE__ */ jsx58(
15198
+ PoweredByUnifold,
15199
+ {
15200
+ color: colors2.foregroundMuted,
15201
+ className: "uf-flex uf-justify-center uf-shrink-0"
15202
+ }
15203
+ ) })
15204
+ ]
15205
+ }
15206
+ );
15207
+ }
12133
15208
  export {
12134
15209
  Button,
12135
15210
  BuyWithCard,
15211
+ CheckoutModal,
12136
15212
  ConfirmingView,
12137
15213
  CurrencyListItem,
12138
15214
  CurrencyListSection,
@@ -12156,6 +15232,7 @@ export {
12156
15232
  DialogPortal,
12157
15233
  DialogTitle,
12158
15234
  DialogTrigger,
15235
+ HYPERCORE_CHAIN_ID,
12159
15236
  Select,
12160
15237
  SelectContent,
12161
15238
  SelectGroup,
@@ -12175,15 +15252,33 @@ export {
12175
15252
  TransferCryptoButton,
12176
15253
  TransferCryptoDoubleInput,
12177
15254
  TransferCryptoSingleInput,
15255
+ WithdrawConfirmingView,
15256
+ WithdrawDoubleInput,
15257
+ WithdrawExecutionItem,
15258
+ WithdrawForm,
15259
+ WithdrawModal,
15260
+ WithdrawTokenSelector,
12178
15261
  buttonVariants,
12179
15262
  cn,
12180
15263
  colors,
12181
15264
  defaultColors,
15265
+ detectBrowserWallet,
12182
15266
  getColors,
15267
+ isHypercoreChain,
12183
15268
  mergeColors,
12184
15269
  resolveComponentTokens,
15270
+ sendEvmWithdraw,
15271
+ sendHypercoreWithdraw,
15272
+ sendSolanaWithdraw,
12185
15273
  truncateAddress,
15274
+ useAddressBalance,
12186
15275
  useAllowedCountry,
12187
15276
  useDepositPolling,
12188
- useTheme
15277
+ useDepositQuote,
15278
+ usePaymentIntent,
15279
+ useSourceTokenValidation,
15280
+ useSupportedDestinationTokens,
15281
+ useTheme,
15282
+ useVerifyRecipientAddress,
15283
+ useWithdrawPolling
12189
15284
  };