@unifold/ui-react 0.1.40 → 0.1.42

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
- useState as useState26,
4
- useEffect as useEffect20,
3
+ useState as useState27,
4
+ useEffect as useEffect21,
5
5
  useLayoutEffect as useLayoutEffect2,
6
6
  useCallback as useCallback4,
7
- useRef as useRef5,
7
+ useRef as useRef6,
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
 
@@ -1372,7 +1399,8 @@ import { useState as useState5, useEffect as useEffect3, useRef } from "react";
1372
1399
  import {
1373
1400
  queryExecutions,
1374
1401
  pollDirectExecutions,
1375
- ExecutionStatus
1402
+ ExecutionStatus,
1403
+ ActionType
1376
1404
  } from "@unifold/core";
1377
1405
  var DEPOSIT_CONFIRM_DELAY_MS = 1e4;
1378
1406
  var POLL_INTERVAL_MS = 2500;
@@ -1442,7 +1470,7 @@ function useDepositPolling({
1442
1470
  const modalOpenedAt = modalOpenedAtRef.current;
1443
1471
  const poll = async () => {
1444
1472
  try {
1445
- const response = await queryExecutions(userId, publishableKey);
1473
+ const response = await queryExecutions(userId, publishableKey, ActionType.Deposit);
1446
1474
  const cutoff = new Date(modalOpenedAt.getTime() - CUTOFF_BUFFER_MS);
1447
1475
  const sortedExecutions = [...response.data].sort((a, b) => {
1448
1476
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
@@ -1586,7 +1614,8 @@ function formatCurrency(currency) {
1586
1614
  }
1587
1615
  function DepositDetailContent({
1588
1616
  execution,
1589
- className
1617
+ className,
1618
+ variant = "deposit"
1590
1619
  }) {
1591
1620
  const { colors: colors2, fonts, components } = useTheme();
1592
1621
  const [chains, setChains] = useState6([]);
@@ -1992,7 +2021,7 @@ function DepositDetailContent({
1992
2021
  color: components.card.rowLeftLabel,
1993
2022
  fontFamily: fonts.regular
1994
2023
  },
1995
- children: "Deposit Tx"
2024
+ children: variant === "withdraw" ? "Withdrawal Tx" : "Deposit Tx"
1996
2025
  }
1997
2026
  ),
1998
2027
  /* @__PURE__ */ jsx7(
@@ -6900,7 +6929,8 @@ function useProjectConfig({
6900
6929
 
6901
6930
  // src/components/deposits/DepositModal.tsx
6902
6931
  import {
6903
- queryExecutions as queryExecutions3
6932
+ queryExecutions as queryExecutions3,
6933
+ ActionType as ActionType3
6904
6934
  } from "@unifold/core";
6905
6935
 
6906
6936
  // src/hooks/use-allowed-country.ts
@@ -7051,7 +7081,7 @@ function useSupportedDepositTokens(publishableKey, options) {
7051
7081
  }
7052
7082
 
7053
7083
  // src/components/deposits/TransferCryptoSingleInput.tsx
7054
- import { useState as useState21, useEffect as useEffect16, useMemo as useMemo5 } from "react";
7084
+ import { useState as useState22, useEffect as useEffect17, useMemo as useMemo5 } from "react";
7055
7085
  import {
7056
7086
  ChevronDown as ChevronDown3,
7057
7087
  ChevronUp as ChevronUp2,
@@ -7287,7 +7317,7 @@ function PoweredByUnifold({
7287
7317
  }
7288
7318
 
7289
7319
  // src/components/deposits/DepositsModal.tsx
7290
- import { queryExecutions as queryExecutions2 } from "@unifold/core";
7320
+ import { queryExecutions as queryExecutions2, ActionType as ActionType2 } from "@unifold/core";
7291
7321
  import { Fragment as Fragment3, jsx as jsx35, jsxs as jsxs30 } from "react/jsx-runtime";
7292
7322
  function DepositsModal({
7293
7323
  open,
@@ -7305,7 +7335,7 @@ function DepositsModal({
7305
7335
  if (!open || !userId) return;
7306
7336
  const fetchExecutions = async () => {
7307
7337
  try {
7308
- const response = await queryExecutions2(userId, publishableKey);
7338
+ const response = await queryExecutions2(userId, publishableKey, ActionType2.Deposit);
7309
7339
  const sorted = [...response.data].sort((a, b) => {
7310
7340
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
7311
7341
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -7427,7 +7457,7 @@ function saveRecentToken(token) {
7427
7457
  try {
7428
7458
  const recent = getRecentTokens();
7429
7459
  const filtered = recent.filter(
7430
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7460
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7431
7461
  );
7432
7462
  filtered.unshift(token);
7433
7463
  const trimmed = filtered.slice(0, MAX_RECENT_TOKENS);
@@ -7440,7 +7470,7 @@ function removeRecentToken(token) {
7440
7470
  try {
7441
7471
  const recent = getRecentTokens();
7442
7472
  const filtered = recent.filter(
7443
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7473
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7444
7474
  );
7445
7475
  localStorage.setItem(STORAGE_KEY, JSON.stringify(filtered));
7446
7476
  return filtered;
@@ -7479,7 +7509,7 @@ function TokenSelectorSheet({
7479
7509
  const addOption = (symbol, chainType, chainId, isRecent) => {
7480
7510
  const key = `${symbol}-${chainType}:${chainId}`;
7481
7511
  if (seen.has(key)) return;
7482
- const tokenData = tokens.find((t7) => t7.symbol === symbol);
7512
+ const tokenData = tokens.find((t11) => t11.symbol === symbol);
7483
7513
  if (!tokenData) return;
7484
7514
  const chainData = tokenData.chains.find(
7485
7515
  (c) => c.chain_type === chainType && c.chain_id === chainId
@@ -7939,6 +7969,107 @@ function DepositPollingUi({
7939
7969
  return null;
7940
7970
  }
7941
7971
 
7972
+ // src/hooks/use-default-source-token.ts
7973
+ import { useState as useState19, useEffect as useEffect16, useRef as useRef5 } from "react";
7974
+ var getChainKey = (chainId, chainType) => {
7975
+ return `${chainType}:${chainId}`;
7976
+ };
7977
+ function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol) {
7978
+ if (!supportedTokens.length) return null;
7979
+ let selectedTokenData;
7980
+ let selectedChainData;
7981
+ const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
7982
+ if (defaultSourceTokenAddress && hasChainDefaults) {
7983
+ for (const t11 of supportedTokens) {
7984
+ const matchingChain = t11.chains.find(
7985
+ (c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
7986
+ );
7987
+ if (matchingChain) {
7988
+ selectedTokenData = t11;
7989
+ selectedChainData = matchingChain;
7990
+ break;
7991
+ }
7992
+ }
7993
+ }
7994
+ if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
7995
+ for (const t11 of supportedTokens) {
7996
+ if (t11.symbol !== defaultSourceSymbol) continue;
7997
+ const matchedChain = t11.chains.find(
7998
+ (c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
7999
+ );
8000
+ if (matchedChain) {
8001
+ selectedTokenData = t11;
8002
+ selectedChainData = matchedChain;
8003
+ break;
8004
+ }
8005
+ }
8006
+ }
8007
+ if (!selectedTokenData) {
8008
+ for (const t11 of supportedTokens) {
8009
+ if (t11.chains.length > 0) {
8010
+ selectedTokenData = t11;
8011
+ selectedChainData = t11.chains[0];
8012
+ break;
8013
+ }
8014
+ }
8015
+ }
8016
+ if (selectedTokenData && selectedChainData) {
8017
+ return { token: selectedTokenData, chain: selectedChainData };
8018
+ }
8019
+ return null;
8020
+ }
8021
+ function useDefaultSourceToken({
8022
+ supportedTokens,
8023
+ defaultSourceChainType,
8024
+ defaultSourceChainId,
8025
+ defaultSourceTokenAddress,
8026
+ defaultSourceSymbol
8027
+ }) {
8028
+ const [token, setToken] = useState19(null);
8029
+ const [chain, setChain] = useState19(null);
8030
+ const [initialSelectionDone, setInitialSelectionDone] = useState19(false);
8031
+ const appliedDefaultsRef = useRef5("");
8032
+ useEffect16(() => {
8033
+ if (!supportedTokens.length) return;
8034
+ const defaultsKey = `${defaultSourceTokenAddress ?? ""}|${defaultSourceSymbol ?? ""}|${defaultSourceChainType ?? ""}|${defaultSourceChainId ?? ""}`;
8035
+ const defaultsChanged = appliedDefaultsRef.current !== defaultsKey;
8036
+ if (initialSelectionDone && !defaultsChanged) return;
8037
+ const result = resolveSourceToken(
8038
+ supportedTokens,
8039
+ defaultSourceChainType,
8040
+ defaultSourceChainId,
8041
+ defaultSourceTokenAddress,
8042
+ defaultSourceSymbol
8043
+ );
8044
+ if (result) {
8045
+ setToken(result.token.symbol);
8046
+ setChain(getChainKey(result.chain.chain_id, result.chain.chain_type));
8047
+ appliedDefaultsRef.current = defaultsKey;
8048
+ setInitialSelectionDone(true);
8049
+ }
8050
+ }, [
8051
+ supportedTokens,
8052
+ defaultSourceTokenAddress,
8053
+ defaultSourceSymbol,
8054
+ defaultSourceChainType,
8055
+ defaultSourceChainId,
8056
+ initialSelectionDone
8057
+ ]);
8058
+ useEffect16(() => {
8059
+ if (!supportedTokens.length || !token) return;
8060
+ const currentToken = supportedTokens.find((t11) => t11.symbol === token);
8061
+ if (!currentToken || currentToken.chains.length === 0) return;
8062
+ const isChainAvailable = chain && currentToken.chains.some((c) => {
8063
+ return getChainKey(c.chain_id, c.chain_type) === chain;
8064
+ });
8065
+ if (!isChainAvailable) {
8066
+ const firstChain = currentToken.chains[0];
8067
+ setChain(getChainKey(firstChain.chain_id, firstChain.chain_type));
8068
+ }
8069
+ }, [token, supportedTokens, chain]);
8070
+ return { token, chain, setToken, setChain, initialSelectionDone };
8071
+ }
8072
+
7942
8073
  // src/components/deposits/shared/DepositFooterLinks.tsx
7943
8074
  import { jsx as jsx38, jsxs as jsxs33 } from "react/jsx-runtime";
7944
8075
  function DepositFooterLinks({
@@ -8105,9 +8236,9 @@ function GlossaryModal({
8105
8236
  }
8106
8237
 
8107
8238
  // src/components/deposits/shared/useCopyAddress.ts
8108
- import { useState as useState19 } from "react";
8239
+ import { useState as useState20 } from "react";
8109
8240
  function useCopyAddress() {
8110
- const [copied, setCopied] = useState19(false);
8241
+ const [copied, setCopied] = useState20(false);
8111
8242
  const handleCopy = (address) => {
8112
8243
  if (!address) return;
8113
8244
  navigator.clipboard.writeText(address);
@@ -8188,7 +8319,7 @@ import {
8188
8319
  } from "@unifold/core";
8189
8320
  import { Fragment as Fragment4, jsx as jsx41, jsxs as jsxs35 } from "react/jsx-runtime";
8190
8321
  var t4 = i18n.transferCrypto;
8191
- var getChainKey = (chainId, chainType) => {
8322
+ var getChainKey2 = (chainId, chainType) => {
8192
8323
  return `${chainType}:${chainId}`;
8193
8324
  };
8194
8325
  var parseChainKey = (chainKey) => {
@@ -8202,6 +8333,10 @@ function TransferCryptoSingleInput({
8202
8333
  destinationChainType,
8203
8334
  destinationChainId,
8204
8335
  destinationTokenAddress,
8336
+ defaultSourceChainType,
8337
+ defaultSourceChainId,
8338
+ defaultSourceTokenAddress,
8339
+ defaultSourceSymbol,
8205
8340
  depositConfirmationMode = "auto_ui",
8206
8341
  onExecutionsChange,
8207
8342
  onDepositSuccess,
@@ -8210,21 +8345,25 @@ function TransferCryptoSingleInput({
8210
8345
  }) {
8211
8346
  const { themeClass, colors: colors2, fonts, components } = useTheme();
8212
8347
  const isDarkMode = themeClass.includes("uf-dark");
8213
- const [token, setToken] = useState21("USDC");
8214
- const [chain, setChain] = useState21("solana:mainnet");
8215
- const [copied, setCopied] = useState21(false);
8348
+ const [copied, setCopied] = useState22(false);
8216
8349
  const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
8217
- const [glossaryOpen, setGlossaryOpen] = useState21(false);
8218
- const [detailsExpanded, setDetailsExpanded] = useState21(false);
8219
- const [depositsModalOpen, setDepositsModalOpen] = useState21(false);
8220
- const [tokenSelectorOpen, setTokenSelectorOpen] = useState21(false);
8221
- const [initialSelectionDone, setInitialSelectionDone] = useState21(false);
8350
+ const [glossaryOpen, setGlossaryOpen] = useState22(false);
8351
+ const [detailsExpanded, setDetailsExpanded] = useState22(false);
8352
+ const [depositsModalOpen, setDepositsModalOpen] = useState22(false);
8353
+ const [tokenSelectorOpen, setTokenSelectorOpen] = useState22(false);
8222
8354
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
8223
8355
  destination_token_address: destinationTokenAddress,
8224
8356
  destination_chain_id: destinationChainId,
8225
8357
  destination_chain_type: destinationChainType
8226
8358
  });
8227
8359
  const supportedTokens = tokensResponse?.data ?? [];
8360
+ const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
8361
+ supportedTokens,
8362
+ defaultSourceChainType,
8363
+ defaultSourceChainId,
8364
+ defaultSourceTokenAddress,
8365
+ defaultSourceSymbol
8366
+ });
8228
8367
  const {
8229
8368
  data: depositAddressResponse,
8230
8369
  isLoading: walletsLoading,
@@ -8244,8 +8383,8 @@ function TransferCryptoSingleInput({
8244
8383
  const error = walletsError?.message ?? null;
8245
8384
  const allAvailableChains = useMemo5(() => {
8246
8385
  const chainsMap = /* @__PURE__ */ new Map();
8247
- supportedTokens.forEach((t7) => {
8248
- t7.chains.forEach((c) => {
8386
+ supportedTokens.forEach((t11) => {
8387
+ t11.chains.forEach((c) => {
8249
8388
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8250
8389
  if (!chainsMap.has(comboKey)) {
8251
8390
  chainsMap.set(comboKey, c);
@@ -8254,10 +8393,10 @@ function TransferCryptoSingleInput({
8254
8393
  });
8255
8394
  return Array.from(chainsMap.values());
8256
8395
  }, [supportedTokens]);
8257
- const currentChainCombo = parseChainKey(chain);
8258
- const currentChainData = allAvailableChains.find(
8396
+ const currentChainCombo = chain ? parseChainKey(chain) : null;
8397
+ const currentChainData = currentChainCombo ? allAvailableChains.find(
8259
8398
  (c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
8260
- );
8399
+ ) : void 0;
8261
8400
  const currentChainType = currentChainData?.chain_type || "ethereum";
8262
8401
  const currentWallet = getWalletByChainType2(wallets, currentChainType);
8263
8402
  const depositAddress = currentWallet?.address || "";
@@ -8275,84 +8414,26 @@ function TransferCryptoSingleInput({
8275
8414
  onDepositSuccess,
8276
8415
  onDepositError
8277
8416
  });
8278
- useEffect16(() => {
8279
- if (!supportedTokens.length || initialSelectionDone) return;
8280
- let selectedTokenData;
8281
- let selectedChainData;
8282
- if (destinationTokenAddress) {
8283
- for (const t7 of supportedTokens) {
8284
- const matchingChain = t7.chains.find(
8285
- (c) => c.token_address.toLowerCase() === destinationTokenAddress.toLowerCase()
8286
- );
8287
- if (matchingChain) {
8288
- selectedTokenData = t7;
8289
- selectedChainData = matchingChain;
8290
- break;
8291
- }
8292
- }
8293
- }
8294
- if (!selectedTokenData) {
8295
- selectedTokenData = supportedTokens.find((t7) => t7.symbol === "USDC");
8296
- if (selectedTokenData && selectedTokenData.chains.length > 0) {
8297
- selectedChainData = selectedTokenData.chains[0];
8298
- }
8299
- }
8300
- if (!selectedTokenData) {
8301
- selectedTokenData = supportedTokens.find((t7) => t7.symbol === "USDT");
8302
- if (selectedTokenData && selectedTokenData.chains.length > 0) {
8303
- selectedChainData = selectedTokenData.chains[0];
8304
- }
8305
- }
8306
- if (!selectedTokenData) {
8307
- selectedTokenData = supportedTokens[0];
8308
- if (selectedTokenData.chains.length > 0) {
8309
- selectedChainData = selectedTokenData.chains[0];
8310
- }
8311
- }
8312
- if (selectedTokenData) {
8313
- setToken(selectedTokenData.symbol);
8314
- }
8315
- if (selectedChainData) {
8316
- setChain(
8317
- getChainKey(selectedChainData.chain_id, selectedChainData.chain_type)
8318
- );
8319
- }
8320
- setInitialSelectionDone(true);
8321
- }, [supportedTokens, destinationTokenAddress, initialSelectionDone]);
8322
- useEffect16(() => {
8417
+ useEffect17(() => {
8323
8418
  if (onExecutionsChange) {
8324
8419
  onExecutionsChange(depositExecutions);
8325
8420
  }
8326
8421
  }, [depositExecutions, onExecutionsChange]);
8327
- useEffect16(() => {
8328
- if (!supportedTokens.length) return;
8329
- const currentToken = supportedTokens.find((t7) => t7.symbol === token);
8330
- if (!currentToken || currentToken.chains.length === 0) return;
8331
- const isChainAvailable = currentToken.chains.some((c) => {
8332
- const key = getChainKey(c.chain_id, c.chain_type);
8333
- return key === chain;
8334
- });
8335
- if (!isChainAvailable) {
8336
- const firstChain = currentToken.chains[0];
8337
- const newChain = getChainKey(firstChain.chain_id, firstChain.chain_type);
8338
- setChain(newChain);
8339
- }
8340
- }, [token, supportedTokens, chain]);
8341
- const selectedToken = supportedTokens.find((t7) => t7.symbol === token);
8422
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8342
8423
  const availableChainsForToken = selectedToken?.chains || [];
8343
- const currentChainFromBackend = availableChainsForToken.find((c) => {
8344
- const key = getChainKey(c.chain_id, c.chain_type);
8424
+ const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
8425
+ const key = getChainKey2(c.chain_id, c.chain_type);
8345
8426
  return key === chain;
8346
8427
  }) || allAvailableChains.find((c) => {
8347
- const key = getChainKey(c.chain_id, c.chain_type);
8428
+ const key = getChainKey2(c.chain_id, c.chain_type);
8348
8429
  return key === chain;
8349
- });
8430
+ }) : void 0;
8350
8431
  const handleCopyAddress = () => {
8351
8432
  navigator.clipboard.writeText(depositAddress);
8352
8433
  setCopied(true);
8353
8434
  setTimeout(() => setCopied(false), 2e3);
8354
8435
  };
8355
- const formatProcessingTime2 = (seconds) => {
8436
+ const formatProcessingTime3 = (seconds) => {
8356
8437
  if (seconds === null) {
8357
8438
  return t4.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
8358
8439
  }
@@ -8381,10 +8462,10 @@ function TransferCryptoSingleInput({
8381
8462
  "button",
8382
8463
  {
8383
8464
  onClick: () => setTokenSelectorOpen(true),
8384
- disabled: tokensLoading || supportedTokens.length === 0,
8465
+ disabled: tokensLoading || !token || supportedTokens.length === 0,
8385
8466
  className: "uf-w-full hover:uf-bg-accent uf-p-3 uf-flex uf-items-center uf-gap-3 uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
8386
8467
  style: { backgroundColor: components.card.backgroundColor, borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` },
8387
- children: tokensLoading ? /* @__PURE__ */ jsxs35("div", { className: "uf-flex uf-items-center uf-gap-3 uf-animate-pulse", children: [
8468
+ children: tokensLoading || !token ? /* @__PURE__ */ jsxs35("div", { className: "uf-flex uf-items-center uf-gap-3 uf-animate-pulse", children: [
8388
8469
  /* @__PURE__ */ jsx41("div", { className: "uf-w-10 uf-h-10 uf-rounded-full uf-bg-muted" }),
8389
8470
  /* @__PURE__ */ jsxs35("div", { className: "uf-flex-1", children: [
8390
8471
  /* @__PURE__ */ jsx41("div", { className: "uf-h-4 uf-w-16 uf-bg-muted uf-rounded uf-mb-1" }),
@@ -8458,8 +8539,8 @@ function TransferCryptoSingleInput({
8458
8539
  open: tokenSelectorOpen,
8459
8540
  onOpenChange: setTokenSelectorOpen,
8460
8541
  tokens: supportedTokens,
8461
- selectedToken: token,
8462
- selectedChainKey: chain,
8542
+ selectedToken: token ?? "",
8543
+ selectedChainKey: chain ?? "",
8463
8544
  onSelect: (newToken, newChain) => {
8464
8545
  setToken(newToken);
8465
8546
  setChain(newChain);
@@ -8561,7 +8642,7 @@ function TransferCryptoSingleInput({
8561
8642
  t4.processingTime.label,
8562
8643
  ":",
8563
8644
  " ",
8564
- /* @__PURE__ */ jsx41("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
8645
+ /* @__PURE__ */ jsx41("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
8565
8646
  ] })
8566
8647
  ] }),
8567
8648
  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 } })
@@ -8671,7 +8752,7 @@ function TransferCryptoSingleInput({
8671
8752
  }
8672
8753
 
8673
8754
  // src/components/deposits/TransferCryptoDoubleInput.tsx
8674
- import { useState as useState22, useEffect as useEffect17, useMemo as useMemo6 } from "react";
8755
+ import { useState as useState23, useEffect as useEffect18, useMemo as useMemo6 } from "react";
8675
8756
  import {
8676
8757
  ChevronDown as ChevronDown5,
8677
8758
  ChevronUp as ChevronUp4,
@@ -8825,7 +8906,7 @@ import {
8825
8906
  } from "@unifold/core";
8826
8907
  import { jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
8827
8908
  var t5 = i18n.transferCrypto;
8828
- var getChainKey2 = (chainId, chainType) => {
8909
+ var getChainKey3 = (chainId, chainType) => {
8829
8910
  return `${chainType}:${chainId}`;
8830
8911
  };
8831
8912
  var parseChainKey2 = (chainKey) => {
@@ -8839,6 +8920,10 @@ function TransferCryptoDoubleInput({
8839
8920
  destinationChainType,
8840
8921
  destinationChainId,
8841
8922
  destinationTokenAddress,
8923
+ defaultSourceChainType,
8924
+ defaultSourceChainId,
8925
+ defaultSourceTokenAddress,
8926
+ defaultSourceSymbol,
8842
8927
  depositConfirmationMode = "auto_ui",
8843
8928
  onExecutionsChange,
8844
8929
  onDepositSuccess,
@@ -8847,20 +8932,24 @@ function TransferCryptoDoubleInput({
8847
8932
  }) {
8848
8933
  const { themeClass, colors: colors2, fonts, components } = useTheme();
8849
8934
  const isDarkMode = themeClass.includes("uf-dark");
8850
- const [token, setToken] = useState22("USDC");
8851
- const [chain, setChain] = useState22("solana:mainnet");
8852
- const [copied, setCopied] = useState22(false);
8935
+ const [copied, setCopied] = useState23(false);
8853
8936
  const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
8854
- const [glossaryOpen, setGlossaryOpen] = useState22(false);
8855
- const [detailsExpanded, setDetailsExpanded] = useState22(false);
8856
- const [depositsModalOpen, setDepositsModalOpen] = useState22(false);
8857
- const [initialSelectionDone, setInitialSelectionDone] = useState22(false);
8937
+ const [glossaryOpen, setGlossaryOpen] = useState23(false);
8938
+ const [detailsExpanded, setDetailsExpanded] = useState23(false);
8939
+ const [depositsModalOpen, setDepositsModalOpen] = useState23(false);
8858
8940
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
8859
8941
  destination_token_address: destinationTokenAddress,
8860
8942
  destination_chain_id: destinationChainId,
8861
8943
  destination_chain_type: destinationChainType
8862
8944
  });
8863
8945
  const supportedTokens = tokensResponse?.data ?? [];
8946
+ const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
8947
+ supportedTokens,
8948
+ defaultSourceChainType,
8949
+ defaultSourceChainId,
8950
+ defaultSourceTokenAddress,
8951
+ defaultSourceSymbol
8952
+ });
8864
8953
  const {
8865
8954
  data: depositAddressResponse,
8866
8955
  isLoading: walletsLoading,
@@ -8880,8 +8969,8 @@ function TransferCryptoDoubleInput({
8880
8969
  const error = walletsError?.message ?? null;
8881
8970
  const allAvailableChains = useMemo6(() => {
8882
8971
  const chainsMap = /* @__PURE__ */ new Map();
8883
- supportedTokens.forEach((t7) => {
8884
- t7.chains.forEach((c) => {
8972
+ supportedTokens.forEach((t11) => {
8973
+ t11.chains.forEach((c) => {
8885
8974
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8886
8975
  if (!chainsMap.has(comboKey)) {
8887
8976
  chainsMap.set(comboKey, c);
@@ -8890,10 +8979,10 @@ function TransferCryptoDoubleInput({
8890
8979
  });
8891
8980
  return Array.from(chainsMap.values());
8892
8981
  }, [supportedTokens]);
8893
- const currentChainCombo = parseChainKey2(chain);
8894
- const currentChainData = allAvailableChains.find(
8982
+ const currentChainCombo = chain ? parseChainKey2(chain) : null;
8983
+ const currentChainData = currentChainCombo ? allAvailableChains.find(
8895
8984
  (c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
8896
- );
8985
+ ) : void 0;
8897
8986
  const currentChainType = currentChainData?.chain_type || "ethereum";
8898
8987
  const currentWallet = getWalletByChainType3(wallets, currentChainType);
8899
8988
  const depositAddress = currentWallet?.address || "";
@@ -8911,57 +9000,26 @@ function TransferCryptoDoubleInput({
8911
9000
  onDepositSuccess,
8912
9001
  onDepositError
8913
9002
  });
8914
- useEffect17(() => {
8915
- if (!supportedTokens.length || initialSelectionDone) return;
8916
- const allChains = /* @__PURE__ */ new Set();
8917
- supportedTokens.forEach((t7) => {
8918
- t7.chains.forEach((c) => {
8919
- allChains.add(getChainKey2(c.chain_id, c.chain_type));
8920
- });
8921
- });
8922
- if (!allChains.has(chain)) {
8923
- const firstToken = supportedTokens[0];
8924
- if (firstToken.chains.length > 0) {
8925
- const firstChain = firstToken.chains[0];
8926
- setChain(getChainKey2(firstChain.chain_id, firstChain.chain_type));
8927
- }
8928
- }
8929
- setInitialSelectionDone(true);
8930
- }, [supportedTokens, chain, initialSelectionDone]);
8931
- useEffect17(() => {
9003
+ useEffect18(() => {
8932
9004
  if (onExecutionsChange) {
8933
9005
  onExecutionsChange(depositExecutions);
8934
9006
  }
8935
9007
  }, [depositExecutions, onExecutionsChange]);
8936
- useEffect17(() => {
8937
- if (!supportedTokens.length) return;
8938
- const currentToken = supportedTokens.find((t7) => t7.symbol === token);
8939
- if (!currentToken || currentToken.chains.length === 0) return;
8940
- const isChainAvailable = currentToken.chains.some((c) => {
8941
- const key = getChainKey2(c.chain_id, c.chain_type);
8942
- return key === chain;
8943
- });
8944
- if (!isChainAvailable) {
8945
- const firstChain = currentToken.chains[0];
8946
- const newChain = getChainKey2(firstChain.chain_id, firstChain.chain_type);
8947
- setChain(newChain);
8948
- }
8949
- }, [token, supportedTokens, chain]);
8950
- const selectedToken = supportedTokens.find((t7) => t7.symbol === token);
9008
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8951
9009
  const availableChainsForToken = selectedToken?.chains || [];
8952
- const currentChainFromBackend = availableChainsForToken.find((c) => {
8953
- const key = getChainKey2(c.chain_id, c.chain_type);
9010
+ const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
9011
+ const key = getChainKey3(c.chain_id, c.chain_type);
8954
9012
  return key === chain;
8955
9013
  }) || allAvailableChains.find((c) => {
8956
- const key = getChainKey2(c.chain_id, c.chain_type);
9014
+ const key = getChainKey3(c.chain_id, c.chain_type);
8957
9015
  return key === chain;
8958
- });
9016
+ }) : void 0;
8959
9017
  const handleCopyAddress = () => {
8960
9018
  navigator.clipboard.writeText(depositAddress);
8961
9019
  setCopied(true);
8962
9020
  setTimeout(() => setCopied(false), 2e3);
8963
9021
  };
8964
- const formatProcessingTime2 = (seconds) => {
9022
+ const formatProcessingTime3 = (seconds) => {
8965
9023
  if (seconds === null) {
8966
9024
  return t5.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
8967
9025
  }
@@ -9029,11 +9087,11 @@ function TransferCryptoDoubleInput({
9029
9087
  /* @__PURE__ */ jsxs37(
9030
9088
  Select,
9031
9089
  {
9032
- value: token,
9090
+ value: token ?? "",
9033
9091
  onValueChange: setToken,
9034
- disabled: tokensLoading || supportedTokens.length === 0,
9092
+ disabled: tokensLoading || !token || supportedTokens.length === 0,
9035
9093
  children: [
9036
- /* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: token }) }) }) }),
9094
+ /* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading || !token ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: token }) }) }) }),
9037
9095
  /* @__PURE__ */ jsx43(SelectContent, { className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]", style: { border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`, ...fonts.regular ? { "--uf-font-family": fonts.regular } : {} }, children: supportedTokens.map((tokenData) => /* @__PURE__ */ jsx43(
9038
9096
  SelectItem,
9039
9097
  {
@@ -9060,11 +9118,11 @@ function TransferCryptoDoubleInput({
9060
9118
  /* @__PURE__ */ jsxs37(
9061
9119
  Select,
9062
9120
  {
9063
- value: chain,
9121
+ value: chain ?? "",
9064
9122
  onValueChange: setChain,
9065
- disabled: tokensLoading || availableChainsForToken.length === 0,
9123
+ disabled: tokensLoading || !chain || availableChainsForToken.length === 0,
9066
9124
  children: [
9067
- /* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : currentChainFromBackend ? renderChainItem(currentChainFromBackend) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: chain }) }) }) }),
9125
+ /* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading || !chain ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : currentChainFromBackend ? renderChainItem(currentChainFromBackend) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: chain }) }) }) }),
9068
9126
  /* @__PURE__ */ jsx43(
9069
9127
  SelectContent,
9070
9128
  {
@@ -9072,7 +9130,7 @@ function TransferCryptoDoubleInput({
9072
9130
  className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
9073
9131
  style: { border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`, ...fonts.regular ? { "--uf-font-family": fonts.regular } : {} },
9074
9132
  children: availableChainsForToken.length === 0 ? /* @__PURE__ */ jsx43("div", { className: "uf-px-2 uf-py-3 uf-text-xs uf-text-muted-foreground uf-text-center", children: t5.noChainsAvailable }) : availableChainsForToken.map((chainData) => {
9075
- const chainKey = getChainKey2(
9133
+ const chainKey = getChainKey3(
9076
9134
  chainData.chain_id,
9077
9135
  chainData.chain_type
9078
9136
  );
@@ -9188,7 +9246,7 @@ function TransferCryptoDoubleInput({
9188
9246
  t5.processingTime.label,
9189
9247
  ":",
9190
9248
  " ",
9191
- /* @__PURE__ */ jsx43("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
9249
+ /* @__PURE__ */ jsx43("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
9192
9250
  ] })
9193
9251
  ] }),
9194
9252
  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 } })
@@ -10089,7 +10147,7 @@ function ReviewView({
10089
10147
  }
10090
10148
 
10091
10149
  // src/components/deposits/browser-wallets/ConfirmingView.tsx
10092
- import { useCallback as useCallback2, useState as useState23 } from "react";
10150
+ import { useCallback as useCallback2, useState as useState24 } from "react";
10093
10151
  import { Loader2 as Loader23, CheckCircle2 } from "lucide-react";
10094
10152
  import { Fragment as Fragment7, jsx as jsx48, jsxs as jsxs41 } from "react/jsx-runtime";
10095
10153
  function ConfirmingView({
@@ -10099,7 +10157,7 @@ function ConfirmingView({
10099
10157
  isPolling = false
10100
10158
  }) {
10101
10159
  const { colors: colors2, fonts } = useTheme();
10102
- const [containerEl, setContainerEl] = useState23(null);
10160
+ const [containerEl, setContainerEl] = useState24(null);
10103
10161
  const containerCallbackRef = useCallback2((el) => {
10104
10162
  setContainerEl(el);
10105
10163
  }, []);
@@ -10267,7 +10325,7 @@ function BrowserWalletModal({
10267
10325
  );
10268
10326
  if (cancelled) return;
10269
10327
  const supportedToken = response.data.find(
10270
- (t7) => t7.symbol.toLowerCase() === token.symbol.toLowerCase()
10328
+ (t11) => t11.symbol.toLowerCase() === token.symbol.toLowerCase()
10271
10329
  );
10272
10330
  if (supportedToken) {
10273
10331
  const chainDetail = supportedToken.chains.find(
@@ -11483,6 +11541,10 @@ function DepositModal({
11483
11541
  destinationChainType,
11484
11542
  destinationChainId,
11485
11543
  destinationTokenAddress,
11544
+ defaultSourceChainType,
11545
+ defaultSourceChainId,
11546
+ defaultSourceTokenAddress,
11547
+ defaultSourceSymbol,
11486
11548
  hideDepositTracker = false,
11487
11549
  showBalanceHeader = false,
11488
11550
  transferInputVariant = "double_input",
@@ -11509,28 +11571,28 @@ function DepositModal({
11509
11571
  if (s === "tracker" && hideDepositTracker) return "main";
11510
11572
  return s;
11511
11573
  }, [initialScreen, hideDepositTracker]);
11512
- const [containerEl, setContainerEl] = useState26(null);
11574
+ const [containerEl, setContainerEl] = useState27(null);
11513
11575
  const containerCallbackRef = useCallback4((el) => {
11514
11576
  setContainerEl(el);
11515
11577
  }, []);
11516
- const [view, setView] = useState26(
11578
+ const [view, setView] = useState27(
11517
11579
  effectiveInitialScreen
11518
11580
  );
11519
- const resetViewTimeoutRef = useRef5(null);
11520
- const [cardView, setCardView] = useState26(
11581
+ const resetViewTimeoutRef = useRef6(null);
11582
+ const [cardView, setCardView] = useState27(
11521
11583
  "amount"
11522
11584
  );
11523
- const [exchangeView, setExchangeView] = useState26(
11585
+ const [exchangeView, setExchangeView] = useState27(
11524
11586
  "providers"
11525
11587
  );
11526
- const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState26(false);
11527
- const [browserWalletInfo, setBrowserWalletInfo] = useState26(null);
11528
- const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState26(false);
11529
- const [browserWalletChainType, setBrowserWalletChainType] = useState26(() => getStoredWalletChainType());
11530
- const [quotesCount, setQuotesCount] = useState26(0);
11531
- const [allExecutions, setAllExecutions] = useState26([]);
11532
- const [selectedExecution, setSelectedExecution] = useState26(null);
11533
- const [depositExecutions, setDepositExecutions] = useState26([]);
11588
+ const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState27(false);
11589
+ const [browserWalletInfo, setBrowserWalletInfo] = useState27(null);
11590
+ const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState27(false);
11591
+ const [browserWalletChainType, setBrowserWalletChainType] = useState27(() => getStoredWalletChainType());
11592
+ const [quotesCount, setQuotesCount] = useState27(0);
11593
+ const [allExecutions, setAllExecutions] = useState27([]);
11594
+ const [selectedExecution, setSelectedExecution] = useState27(null);
11595
+ const [depositExecutions, setDepositExecutions] = useState27([]);
11534
11596
  const isMobileView = useIsMobileViewport();
11535
11597
  const { data: depositAddressResponse, isLoading: walletsLoading } = useDepositAddress({
11536
11598
  userId,
@@ -11543,10 +11605,10 @@ function DepositModal({
11543
11605
  // Only fetch when modal is open
11544
11606
  });
11545
11607
  const wallets = depositAddressResponse?.data ?? [];
11546
- const [resolvedTheme, setResolvedTheme] = useState26(
11608
+ const [resolvedTheme, setResolvedTheme] = useState27(
11547
11609
  theme === "auto" ? "dark" : theme
11548
11610
  );
11549
- useEffect20(() => {
11611
+ useEffect21(() => {
11550
11612
  if (theme === "auto") {
11551
11613
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
11552
11614
  setResolvedTheme(mediaQuery.matches ? "dark" : "light");
@@ -11575,11 +11637,11 @@ function DepositModal({
11575
11637
  chainType: destinationChainType,
11576
11638
  enabled: open
11577
11639
  });
11578
- useEffect20(() => {
11640
+ useEffect21(() => {
11579
11641
  if (view !== "tracker" || !userId) return;
11580
11642
  const fetchExecutions = async () => {
11581
11643
  try {
11582
- const response = await queryExecutions3(userId, publishableKey);
11644
+ const response = await queryExecutions3(userId, publishableKey, ActionType3.Deposit);
11583
11645
  const sorted = [...response.data].sort((a, b) => {
11584
11646
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
11585
11647
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -11596,7 +11658,7 @@ function DepositModal({
11596
11658
  clearInterval(pollInterval);
11597
11659
  };
11598
11660
  }, [view, userId, publishableKey]);
11599
- useEffect20(() => {
11661
+ useEffect21(() => {
11600
11662
  if (view !== "tracker") {
11601
11663
  setSelectedExecution(null);
11602
11664
  }
@@ -11706,7 +11768,7 @@ function DepositModal({
11706
11768
  setBrowserWalletInfo(null);
11707
11769
  setSelectedExecution(null);
11708
11770
  }, [open, effectiveInitialScreen]);
11709
- useEffect20(
11771
+ useEffect21(
11710
11772
  () => () => {
11711
11773
  if (resetViewTimeoutRef.current) {
11712
11774
  clearTimeout(resetViewTimeoutRef.current);
@@ -11915,6 +11977,10 @@ function DepositModal({
11915
11977
  destinationChainType,
11916
11978
  destinationChainId,
11917
11979
  destinationTokenAddress,
11980
+ defaultSourceChainType,
11981
+ defaultSourceChainId,
11982
+ defaultSourceTokenAddress,
11983
+ defaultSourceSymbol,
11918
11984
  depositConfirmationMode,
11919
11985
  onExecutionsChange: setDepositExecutions,
11920
11986
  onDepositSuccess,
@@ -11930,6 +11996,10 @@ function DepositModal({
11930
11996
  destinationChainType,
11931
11997
  destinationChainId,
11932
11998
  destinationTokenAddress,
11999
+ defaultSourceChainType,
12000
+ defaultSourceChainId,
12001
+ defaultSourceTokenAddress,
12002
+ defaultSourceSymbol,
11933
12003
  depositConfirmationMode,
11934
12004
  onExecutionsChange: setDepositExecutions,
11935
12005
  onDepositSuccess,
@@ -12090,6 +12160,2011 @@ function DepositModal({
12090
12160
  }
12091
12161
  ) });
12092
12162
  }
12163
+
12164
+ // src/components/withdrawals/WithdrawModal.tsx
12165
+ import {
12166
+ useState as useState31,
12167
+ useEffect as useEffect25,
12168
+ useLayoutEffect as useLayoutEffect3,
12169
+ useCallback as useCallback6,
12170
+ useRef as useRef8
12171
+ } from "react";
12172
+ import { AlertTriangle as AlertTriangle3, ChevronRight as ChevronRight13, Clock as Clock5 } from "lucide-react";
12173
+
12174
+ // src/hooks/use-supported-destination-tokens.ts
12175
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
12176
+ import {
12177
+ getSupportedDestinationTokens
12178
+ } from "@unifold/core";
12179
+ function useSupportedDestinationTokens(publishableKey, enabled = true) {
12180
+ return useQuery9({
12181
+ queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
12182
+ queryFn: () => getSupportedDestinationTokens(publishableKey),
12183
+ staleTime: 1e3 * 60 * 5,
12184
+ gcTime: 1e3 * 60 * 30,
12185
+ refetchOnMount: false,
12186
+ refetchOnWindowFocus: false,
12187
+ enabled
12188
+ });
12189
+ }
12190
+
12191
+ // src/hooks/use-source-token-validation.ts
12192
+ import { useQuery as useQuery10 } from "@tanstack/react-query";
12193
+ import { getSupportedDepositTokens as getSupportedDepositTokens3 } from "@unifold/core";
12194
+ function useSourceTokenValidation(params) {
12195
+ const {
12196
+ sourceChainType,
12197
+ sourceChainId,
12198
+ sourceTokenAddress,
12199
+ sourceTokenSymbol,
12200
+ publishableKey,
12201
+ enabled = true
12202
+ } = params;
12203
+ const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
12204
+ return useQuery10({
12205
+ queryKey: [
12206
+ "unifold",
12207
+ "sourceTokenValidation",
12208
+ sourceChainType ?? null,
12209
+ sourceChainId ?? null,
12210
+ sourceTokenAddress ?? null,
12211
+ publishableKey
12212
+ ],
12213
+ queryFn: async () => {
12214
+ const res = await getSupportedDepositTokens3(publishableKey);
12215
+ let matchedMinUsd = null;
12216
+ let matchedProcessingTime = null;
12217
+ let matchedSlippage = null;
12218
+ let matchedPriceImpact = null;
12219
+ const found = res.data.some(
12220
+ (token) => token.chains.some((chain) => {
12221
+ const match = chain.chain_type === sourceChainType && chain.chain_id === sourceChainId && chain.token_address.toLowerCase() === sourceTokenAddress.toLowerCase();
12222
+ if (match) {
12223
+ matchedMinUsd = chain.minimum_deposit_amount_usd;
12224
+ matchedProcessingTime = chain.estimated_processing_time;
12225
+ matchedSlippage = chain.max_slippage_percent;
12226
+ matchedPriceImpact = chain.estimated_price_impact_percent;
12227
+ }
12228
+ return match;
12229
+ })
12230
+ );
12231
+ return {
12232
+ isSupported: found,
12233
+ minimumAmountUsd: matchedMinUsd,
12234
+ estimatedProcessingTime: matchedProcessingTime,
12235
+ maxSlippagePercent: matchedSlippage,
12236
+ priceImpactPercent: matchedPriceImpact,
12237
+ errorMessage: found ? null : `${sourceTokenSymbol || "Source token"} is not a supported withdrawal token. Supported tokens include USDC, USDT, and other stablecoins.`
12238
+ };
12239
+ },
12240
+ enabled: enabled && hasParams,
12241
+ staleTime: 1e3 * 60 * 5,
12242
+ gcTime: 1e3 * 60 * 30,
12243
+ refetchOnMount: false,
12244
+ refetchOnWindowFocus: false
12245
+ });
12246
+ }
12247
+
12248
+ // src/hooks/use-address-balance.ts
12249
+ import { useQuery as useQuery11 } from "@tanstack/react-query";
12250
+ import { getAddressBalance as getAddressBalance2 } from "@unifold/core";
12251
+ function useAddressBalance(params) {
12252
+ const {
12253
+ address,
12254
+ chainType,
12255
+ chainId,
12256
+ tokenAddress,
12257
+ publishableKey,
12258
+ enabled = true
12259
+ } = params;
12260
+ const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
12261
+ return useQuery11({
12262
+ queryKey: [
12263
+ "unifold",
12264
+ "addressBalance",
12265
+ address ?? null,
12266
+ chainType ?? null,
12267
+ chainId ?? null,
12268
+ tokenAddress ?? null,
12269
+ publishableKey
12270
+ ],
12271
+ queryFn: async () => {
12272
+ const res = await getAddressBalance2(
12273
+ address,
12274
+ chainType,
12275
+ chainId,
12276
+ tokenAddress,
12277
+ publishableKey
12278
+ );
12279
+ if (res.balance) {
12280
+ const decimals = res.balance.token?.decimals ?? 6;
12281
+ const symbol = res.balance.token?.symbol ?? "";
12282
+ const baseUnit = res.balance.amount;
12283
+ const raw = BigInt(baseUnit);
12284
+ const divisor = BigInt(10 ** decimals);
12285
+ const whole = raw / divisor;
12286
+ const frac = raw % divisor;
12287
+ const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
12288
+ const balanceHuman = fracStr ? `${whole}.${fracStr}` : whole.toString();
12289
+ return {
12290
+ balanceBaseUnit: baseUnit,
12291
+ balanceHuman,
12292
+ balanceUsd: res.balance.amount_usd,
12293
+ exchangeRate: res.balance.exchange_rate,
12294
+ decimals,
12295
+ symbol
12296
+ };
12297
+ }
12298
+ return { balanceBaseUnit: "0", balanceHuman: "0", balanceUsd: "0", exchangeRate: null, decimals: 6, symbol: "" };
12299
+ },
12300
+ enabled: enabled && hasParams,
12301
+ staleTime: 1e3 * 30,
12302
+ gcTime: 1e3 * 60 * 5,
12303
+ refetchInterval: 1e3 * 30,
12304
+ refetchOnMount: "always",
12305
+ refetchOnWindowFocus: false
12306
+ });
12307
+ }
12308
+
12309
+ // src/hooks/use-executions.ts
12310
+ import { useQuery as useQuery12 } from "@tanstack/react-query";
12311
+ import { queryExecutions as queryExecutions4, ActionType as ActionType4 } from "@unifold/core";
12312
+ function useExecutions(userId, publishableKey, options) {
12313
+ const actionType = options?.actionType ?? ActionType4.Deposit;
12314
+ return useQuery12({
12315
+ queryKey: ["unifold", "executions", actionType, userId, publishableKey],
12316
+ queryFn: () => queryExecutions4(userId, publishableKey, actionType),
12317
+ enabled: (options?.enabled ?? true) && !!userId,
12318
+ refetchInterval: options?.refetchInterval ?? 3e3,
12319
+ staleTime: 0,
12320
+ gcTime: 1e3 * 60 * 5,
12321
+ refetchOnWindowFocus: false
12322
+ });
12323
+ }
12324
+
12325
+ // src/hooks/use-withdraw-polling.ts
12326
+ import { useState as useState28, useEffect as useEffect22, useRef as useRef7 } from "react";
12327
+ import {
12328
+ queryExecutions as queryExecutions5,
12329
+ pollDirectExecutions as pollDirectExecutions2,
12330
+ ExecutionStatus as ExecutionStatus5,
12331
+ ActionType as ActionType5
12332
+ } from "@unifold/core";
12333
+ var POLL_INTERVAL_MS2 = 2500;
12334
+ var POLL_ENDPOINT_INTERVAL_MS2 = 3e3;
12335
+ var CUTOFF_BUFFER_MS2 = 6e4;
12336
+ function useWithdrawPolling({
12337
+ userId,
12338
+ publishableKey,
12339
+ depositWalletId,
12340
+ enabled = false,
12341
+ onWithdrawSuccess,
12342
+ onWithdrawError
12343
+ }) {
12344
+ const [executions, setExecutions] = useState28([]);
12345
+ const [isPolling, setIsPolling] = useState28(false);
12346
+ const enabledAtRef = useRef7(/* @__PURE__ */ new Date());
12347
+ const trackedRef = useRef7(/* @__PURE__ */ new Map());
12348
+ const prevEnabledRef = useRef7(false);
12349
+ const onSuccessRef = useRef7(onWithdrawSuccess);
12350
+ const onErrorRef = useRef7(onWithdrawError);
12351
+ useEffect22(() => {
12352
+ onSuccessRef.current = onWithdrawSuccess;
12353
+ }, [onWithdrawSuccess]);
12354
+ useEffect22(() => {
12355
+ onErrorRef.current = onWithdrawError;
12356
+ }, [onWithdrawError]);
12357
+ useEffect22(() => {
12358
+ if (enabled && !prevEnabledRef.current) {
12359
+ enabledAtRef.current = /* @__PURE__ */ new Date();
12360
+ trackedRef.current.clear();
12361
+ }
12362
+ if (!enabled) {
12363
+ trackedRef.current.clear();
12364
+ }
12365
+ prevEnabledRef.current = enabled;
12366
+ }, [enabled]);
12367
+ useEffect22(() => {
12368
+ if (!userId || !enabled) return;
12369
+ const enabledAt = enabledAtRef.current;
12370
+ const poll = async () => {
12371
+ try {
12372
+ const response = await queryExecutions5(userId, publishableKey, ActionType5.Withdraw);
12373
+ const cutoff = new Date(enabledAt.getTime() - CUTOFF_BUFFER_MS2);
12374
+ const sorted = [...response.data].sort((a, b) => {
12375
+ const tA = a.created_at ? new Date(a.created_at).getTime() : 0;
12376
+ const tB = b.created_at ? new Date(b.created_at).getTime() : 0;
12377
+ return tB - tA;
12378
+ });
12379
+ const inProgress = [ExecutionStatus5.PENDING, ExecutionStatus5.WAITING, ExecutionStatus5.DELAYED];
12380
+ const terminal = [ExecutionStatus5.SUCCEEDED, ExecutionStatus5.FAILED];
12381
+ let target = null;
12382
+ for (const ex of sorted) {
12383
+ const t11 = ex.created_at ? new Date(ex.created_at) : null;
12384
+ if (!t11 || t11 < cutoff) continue;
12385
+ const prev = trackedRef.current.get(ex.id);
12386
+ if (!prev) {
12387
+ target = ex;
12388
+ break;
12389
+ }
12390
+ if (inProgress.includes(prev) && terminal.includes(ex.status)) {
12391
+ target = ex;
12392
+ break;
12393
+ }
12394
+ }
12395
+ if (target) {
12396
+ const ex = target;
12397
+ const exTime = ex.created_at ? new Date(ex.created_at) : null;
12398
+ if (!exTime || exTime < enabledAtRef.current) return;
12399
+ const prev = trackedRef.current.get(ex.id);
12400
+ trackedRef.current.set(ex.id, ex.status);
12401
+ setExecutions((list) => {
12402
+ const idx = list.findIndex((e) => e.id === ex.id);
12403
+ if (idx >= 0) {
12404
+ const u = [...list];
12405
+ u[idx] = ex;
12406
+ return u;
12407
+ }
12408
+ return [...list, ex];
12409
+ });
12410
+ if (ex.status === ExecutionStatus5.SUCCEEDED && (!prev || inProgress.includes(prev))) {
12411
+ onSuccessRef.current?.({ message: "Withdrawal completed successfully", executionId: ex.id, transaction: ex });
12412
+ } else if (ex.status === ExecutionStatus5.FAILED && prev !== ExecutionStatus5.FAILED) {
12413
+ onErrorRef.current?.({ message: "Withdrawal failed", code: "WITHDRAW_FAILED", error: ex });
12414
+ }
12415
+ }
12416
+ } catch (error) {
12417
+ console.error("Failed to fetch withdraw executions:", error);
12418
+ onErrorRef.current?.({ message: "Failed to fetch withdrawal status", code: "POLLING_ERROR", error });
12419
+ }
12420
+ };
12421
+ void poll();
12422
+ const interval = setInterval(poll, POLL_INTERVAL_MS2);
12423
+ setIsPolling(true);
12424
+ return () => {
12425
+ clearInterval(interval);
12426
+ setIsPolling(false);
12427
+ };
12428
+ }, [userId, publishableKey, enabled]);
12429
+ useEffect22(() => {
12430
+ if (!enabled || !depositWalletId) return;
12431
+ const trigger = async () => {
12432
+ try {
12433
+ await pollDirectExecutions2({ deposit_wallet_id: depositWalletId }, publishableKey);
12434
+ } catch {
12435
+ }
12436
+ };
12437
+ trigger();
12438
+ const interval = setInterval(trigger, POLL_ENDPOINT_INTERVAL_MS2);
12439
+ return () => clearInterval(interval);
12440
+ }, [enabled, depositWalletId, publishableKey]);
12441
+ return { executions, isPolling };
12442
+ }
12443
+
12444
+ // src/components/withdrawals/WithdrawDoubleInput.tsx
12445
+ import { jsx as jsx52, jsxs as jsxs45 } from "react/jsx-runtime";
12446
+ var t7 = i18n.withdrawModal;
12447
+ var getChainKey4 = (chainId, chainType) => `${chainType}:${chainId}`;
12448
+ function WithdrawDoubleInput({
12449
+ tokens,
12450
+ selectedTokenSymbol,
12451
+ selectedChainKey,
12452
+ onTokenChange,
12453
+ onChainChange,
12454
+ isLoading = false
12455
+ }) {
12456
+ const { fonts, components } = useTheme();
12457
+ const isDarkMode = useTheme().themeClass.includes("uf-dark");
12458
+ const selectedToken = selectedTokenSymbol ? tokens.find((t11) => t11.symbol === selectedTokenSymbol) : void 0;
12459
+ const availableChainsForToken = selectedToken?.chains || [];
12460
+ const renderTokenItem = (tokenData) => /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
12461
+ /* @__PURE__ */ jsx52(
12462
+ "img",
12463
+ {
12464
+ src: tokenData.icon_url,
12465
+ alt: tokenData.symbol,
12466
+ width: 20,
12467
+ height: 20,
12468
+ loading: "lazy",
12469
+ className: "uf-rounded-full uf-flex-shrink-0"
12470
+ }
12471
+ ),
12472
+ /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: tokenData.symbol })
12473
+ ] });
12474
+ const renderChainItem = (chainData) => /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
12475
+ /* @__PURE__ */ jsx52(
12476
+ "img",
12477
+ {
12478
+ src: chainData.icon_url,
12479
+ alt: chainData.chain_name,
12480
+ width: 20,
12481
+ height: 20,
12482
+ loading: "lazy",
12483
+ className: "uf-rounded-full uf-flex-shrink-0"
12484
+ }
12485
+ ),
12486
+ /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: chainData.chain_name })
12487
+ ] });
12488
+ const currentChainData = selectedChainKey ? availableChainsForToken.find(
12489
+ (c) => getChainKey4(c.chain_id, c.chain_type) === selectedChainKey
12490
+ ) : void 0;
12491
+ return /* @__PURE__ */ jsxs45("div", { className: "uf-grid uf-grid-cols-2 uf-gap-2.5", children: [
12492
+ /* @__PURE__ */ jsxs45("div", { children: [
12493
+ /* @__PURE__ */ jsx52(
12494
+ "div",
12495
+ {
12496
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
12497
+ style: { color: components.card.labelColor },
12498
+ children: t7.receiveToken
12499
+ }
12500
+ ),
12501
+ /* @__PURE__ */ jsxs45(
12502
+ Select,
12503
+ {
12504
+ value: selectedTokenSymbol ?? "",
12505
+ onValueChange: onTokenChange,
12506
+ disabled: isLoading || tokens.length === 0,
12507
+ children: [
12508
+ /* @__PURE__ */ jsx52(
12509
+ SelectTrigger,
12510
+ {
12511
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
12512
+ style: {
12513
+ backgroundColor: components.card.backgroundColor,
12514
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
12515
+ },
12516
+ children: /* @__PURE__ */ jsx52(SelectValue, { children: isLoading || !selectedTokenSymbol ? /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: selectedTokenSymbol }) })
12517
+ }
12518
+ ),
12519
+ /* @__PURE__ */ jsx52(
12520
+ SelectContent,
12521
+ {
12522
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]",
12523
+ style: {
12524
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
12525
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
12526
+ },
12527
+ children: tokens.map((tokenData) => /* @__PURE__ */ jsx52(
12528
+ SelectItem,
12529
+ {
12530
+ value: tokenData.symbol,
12531
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
12532
+ children: renderTokenItem(tokenData)
12533
+ },
12534
+ tokenData.symbol
12535
+ ))
12536
+ }
12537
+ )
12538
+ ]
12539
+ }
12540
+ )
12541
+ ] }),
12542
+ /* @__PURE__ */ jsxs45("div", { children: [
12543
+ /* @__PURE__ */ jsx52(
12544
+ "div",
12545
+ {
12546
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
12547
+ style: { color: components.card.labelColor },
12548
+ children: t7.receiveChain
12549
+ }
12550
+ ),
12551
+ /* @__PURE__ */ jsxs45(
12552
+ Select,
12553
+ {
12554
+ value: selectedChainKey ?? "",
12555
+ onValueChange: onChainChange,
12556
+ disabled: isLoading || availableChainsForToken.length === 0,
12557
+ children: [
12558
+ /* @__PURE__ */ jsx52(
12559
+ SelectTrigger,
12560
+ {
12561
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
12562
+ style: {
12563
+ backgroundColor: components.card.backgroundColor,
12564
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
12565
+ },
12566
+ children: /* @__PURE__ */ jsx52(SelectValue, { children: isLoading || !selectedChainKey ? /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: selectedChainKey }) })
12567
+ }
12568
+ ),
12569
+ /* @__PURE__ */ jsx52(
12570
+ SelectContent,
12571
+ {
12572
+ align: "end",
12573
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
12574
+ style: {
12575
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
12576
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
12577
+ },
12578
+ children: availableChainsForToken.length === 0 ? /* @__PURE__ */ jsx52("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) => {
12579
+ const chainKey = getChainKey4(chainData.chain_id, chainData.chain_type);
12580
+ return /* @__PURE__ */ jsx52(
12581
+ SelectItem,
12582
+ {
12583
+ value: chainKey,
12584
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
12585
+ children: renderChainItem(chainData)
12586
+ },
12587
+ chainKey
12588
+ );
12589
+ })
12590
+ }
12591
+ )
12592
+ ]
12593
+ }
12594
+ )
12595
+ ] })
12596
+ ] });
12597
+ }
12598
+
12599
+ // src/components/withdrawals/WithdrawForm.tsx
12600
+ import { useState as useState29, useCallback as useCallback5, useMemo as useMemo10, useEffect as useEffect23 } from "react";
12601
+ import {
12602
+ AlertTriangle as AlertTriangle2,
12603
+ ArrowUpDown,
12604
+ ChevronDown as ChevronDown7,
12605
+ ChevronUp as ChevronUp6,
12606
+ Clock as Clock4,
12607
+ ClipboardPaste,
12608
+ DollarSign as DollarSign3,
12609
+ Loader2 as Loader25,
12610
+ ShieldCheck as ShieldCheck3,
12611
+ Wallet as Wallet3
12612
+ } from "lucide-react";
12613
+
12614
+ // src/hooks/use-verify-recipient-address.ts
12615
+ import { useQuery as useQuery13 } from "@tanstack/react-query";
12616
+ import { verifyRecipientAddress as verifyRecipientAddress2 } from "@unifold/core";
12617
+ function useVerifyRecipientAddress(params) {
12618
+ const {
12619
+ chainType,
12620
+ chainId,
12621
+ tokenAddress,
12622
+ recipientAddress,
12623
+ publishableKey,
12624
+ enabled = true
12625
+ } = params;
12626
+ const trimmedAddress = recipientAddress?.trim() || "";
12627
+ const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
12628
+ return useQuery13({
12629
+ queryKey: [
12630
+ "unifold",
12631
+ "verifyRecipientAddress",
12632
+ chainType ?? null,
12633
+ chainId ?? null,
12634
+ tokenAddress ?? null,
12635
+ trimmedAddress,
12636
+ publishableKey
12637
+ ],
12638
+ queryFn: () => verifyRecipientAddress2(
12639
+ {
12640
+ chain_type: chainType,
12641
+ chain_id: chainId,
12642
+ token_address: tokenAddress,
12643
+ recipient_address: trimmedAddress
12644
+ },
12645
+ publishableKey
12646
+ ),
12647
+ enabled: enabled && hasAllParams,
12648
+ staleTime: 1e3 * 60 * 5,
12649
+ gcTime: 1e3 * 60 * 30,
12650
+ retry: 1,
12651
+ refetchOnMount: false,
12652
+ refetchOnWindowFocus: false
12653
+ });
12654
+ }
12655
+
12656
+ // src/components/withdrawals/send-withdraw.ts
12657
+ import {
12658
+ buildSolanaTransaction as buildSolanaTransaction2,
12659
+ sendSolanaTransaction as sendSolanaTransactionToBackend2
12660
+ } from "@unifold/core";
12661
+ async function sendEvmWithdraw(params) {
12662
+ const {
12663
+ provider,
12664
+ fromAddress,
12665
+ depositWalletAddress,
12666
+ sourceTokenAddress,
12667
+ sourceChainId,
12668
+ amountBaseUnit
12669
+ } = params;
12670
+ const currentChainIdHex = await provider.request({
12671
+ method: "eth_chainId",
12672
+ params: []
12673
+ });
12674
+ const currentChainId = parseInt(currentChainIdHex, 16).toString();
12675
+ if (currentChainId !== sourceChainId) {
12676
+ const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
12677
+ try {
12678
+ await provider.request({
12679
+ method: "wallet_switchEthereumChain",
12680
+ params: [{ chainId: requiredHex }]
12681
+ });
12682
+ const newHex = await provider.request({ method: "eth_chainId", params: [] });
12683
+ if (parseInt(newHex, 16).toString() !== sourceChainId) {
12684
+ throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
12685
+ }
12686
+ } catch (err) {
12687
+ if (err && typeof err === "object" && "code" in err) {
12688
+ const e = err;
12689
+ if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
12690
+ if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
12691
+ }
12692
+ throw err;
12693
+ }
12694
+ }
12695
+ const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
12696
+ const amountBig = BigInt(amountBaseUnit);
12697
+ const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
12698
+ from: fromAddress,
12699
+ to: sourceTokenAddress,
12700
+ data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
12701
+ };
12702
+ let gasEstimate;
12703
+ try {
12704
+ const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
12705
+ gasEstimate = BigInt(hex);
12706
+ } catch {
12707
+ gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
12708
+ }
12709
+ const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
12710
+ const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
12711
+ const gasCost = gasWithBuffer * gasPrice;
12712
+ const ethBalance = BigInt(
12713
+ await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
12714
+ );
12715
+ const totalRequired = isNative ? gasCost + amountBig : gasCost;
12716
+ if (ethBalance < totalRequired) {
12717
+ const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
12718
+ if (isNative) {
12719
+ throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
12720
+ }
12721
+ throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
12722
+ }
12723
+ const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
12724
+ return txHash;
12725
+ }
12726
+ async function sendSolanaWithdraw(params) {
12727
+ const {
12728
+ provider,
12729
+ fromAddress,
12730
+ depositWalletAddress,
12731
+ sourceTokenAddress,
12732
+ amountBaseUnit,
12733
+ publishableKey
12734
+ } = params;
12735
+ if (!provider.publicKey) {
12736
+ await provider.connect();
12737
+ }
12738
+ const buildResponse = await buildSolanaTransaction2(
12739
+ {
12740
+ chain_id: "mainnet",
12741
+ token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
12742
+ source_address: fromAddress,
12743
+ destination_address: depositWalletAddress,
12744
+ amount: amountBaseUnit
12745
+ },
12746
+ publishableKey
12747
+ );
12748
+ const { VersionedTransaction } = await import(
12749
+ /* @vite-ignore */
12750
+ "@solana/web3.js"
12751
+ );
12752
+ const binaryString = atob(buildResponse.transaction);
12753
+ const bytes = new Uint8Array(binaryString.length);
12754
+ for (let i = 0; i < binaryString.length; i++) {
12755
+ bytes[i] = binaryString.charCodeAt(i);
12756
+ }
12757
+ const transaction = VersionedTransaction.deserialize(bytes);
12758
+ const signedTransaction = await provider.signTransaction(transaction);
12759
+ const serialized = signedTransaction.serialize();
12760
+ let binaryStr = "";
12761
+ for (let i = 0; i < serialized.length; i++) {
12762
+ binaryStr += String.fromCharCode(serialized[i]);
12763
+ }
12764
+ const sendResponse = await sendSolanaTransactionToBackend2(
12765
+ { chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
12766
+ publishableKey
12767
+ );
12768
+ return sendResponse.signature;
12769
+ }
12770
+ async function detectBrowserWallet(chainType, senderAddress) {
12771
+ const win = typeof window !== "undefined" ? window : null;
12772
+ if (!win || !senderAddress) return null;
12773
+ const anyWin = win;
12774
+ if (chainType === "solana") {
12775
+ const solProviders = [];
12776
+ if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
12777
+ if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
12778
+ if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
12779
+ if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
12780
+ for (const { provider, name } of solProviders) {
12781
+ if (!provider) continue;
12782
+ try {
12783
+ let addr;
12784
+ if (provider.isConnected && provider.publicKey) {
12785
+ addr = provider.publicKey.toString();
12786
+ } else {
12787
+ const resp = await provider.connect({ onlyIfTrusted: true });
12788
+ if (resp?.publicKey) addr = resp.publicKey.toString();
12789
+ }
12790
+ if (addr && addr === senderAddress) {
12791
+ return { chainFamily: "solana", provider, name, address: addr };
12792
+ }
12793
+ } catch {
12794
+ }
12795
+ }
12796
+ }
12797
+ if (chainType === "ethereum") {
12798
+ const evmProviders = [];
12799
+ const seen = /* @__PURE__ */ new Set();
12800
+ const add = (p, name) => {
12801
+ if (p && typeof p.request === "function" && !seen.has(p)) {
12802
+ seen.add(p);
12803
+ evmProviders.push({ provider: p, name });
12804
+ }
12805
+ };
12806
+ add(anyWin.phantom?.ethereum, "Phantom");
12807
+ add(anyWin.coinbaseWalletExtension, "Coinbase");
12808
+ add(anyWin.trustwallet?.ethereum, "Trust Wallet");
12809
+ add(anyWin.okxwallet, "OKX Wallet");
12810
+ if (anyWin.__eip6963Providers) {
12811
+ for (const detail of anyWin.__eip6963Providers) {
12812
+ const rdns = detail.info?.rdns || "";
12813
+ let name = detail.info?.name || "Wallet";
12814
+ if (rdns.includes("metamask")) name = "MetaMask";
12815
+ else if (rdns.includes("rabby")) name = "Rabby";
12816
+ else if (rdns.includes("rainbow")) name = "Rainbow";
12817
+ add(detail.provider, name);
12818
+ }
12819
+ }
12820
+ if (win.ethereum) {
12821
+ const eth = win.ethereum;
12822
+ let name = "Wallet";
12823
+ if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
12824
+ else if (eth.isRabby) name = "Rabby";
12825
+ else if (eth.isRainbow) name = "Rainbow";
12826
+ else if (eth.isCoinbaseWallet) name = "Coinbase";
12827
+ add(eth, name);
12828
+ }
12829
+ for (const { provider, name } of evmProviders) {
12830
+ try {
12831
+ const accounts = await provider.request({ method: "eth_accounts" });
12832
+ if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
12833
+ return { chainFamily: "evm", provider, name, address: accounts[0] };
12834
+ }
12835
+ } catch {
12836
+ }
12837
+ }
12838
+ }
12839
+ return null;
12840
+ }
12841
+
12842
+ // src/components/withdrawals/WithdrawForm.tsx
12843
+ import { Fragment as Fragment10, jsx as jsx53, jsxs as jsxs46 } from "react/jsx-runtime";
12844
+ var t8 = i18n.withdrawModal;
12845
+ var tCrypto = i18n.transferCrypto;
12846
+ function formatProcessingTime2(seconds) {
12847
+ if (seconds === null) {
12848
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
12849
+ }
12850
+ const minutes = Math.ceil(seconds / 60);
12851
+ if (minutes < 60) {
12852
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", String(minutes));
12853
+ }
12854
+ const hours = Math.ceil(minutes / 60);
12855
+ return tCrypto.processingTime.lessThanHours.replace("{{hours}}", String(hours));
12856
+ }
12857
+ function computeBaseUnit(balanceBaseUnit, inputAmount, balanceAmount) {
12858
+ if (balanceAmount <= 0 || inputAmount <= 0) return "0";
12859
+ if (inputAmount >= balanceAmount) return balanceBaseUnit;
12860
+ const PRECISION = 10n ** 18n;
12861
+ const ratioScaled = BigInt(Math.round(inputAmount / balanceAmount * Number(PRECISION)));
12862
+ const result = BigInt(balanceBaseUnit) * ratioScaled / PRECISION;
12863
+ return result.toString();
12864
+ }
12865
+ function toSafeDecimalString(n, maxDecimals) {
12866
+ if (n === 0) return "0";
12867
+ return n.toFixed(maxDecimals).replace(/\.?0+$/, "");
12868
+ }
12869
+ function WithdrawForm({
12870
+ publishableKey,
12871
+ externalUserId,
12872
+ sourceChainType,
12873
+ selectedToken,
12874
+ selectedChain,
12875
+ sourceTokenSymbol,
12876
+ recipientAddressProp,
12877
+ balanceData,
12878
+ isLoadingBalance,
12879
+ minimumWithdrawAmountUsd,
12880
+ estimatedProcessingTime,
12881
+ maxSlippagePercent,
12882
+ priceImpactPercent,
12883
+ detectedWallet,
12884
+ sourceChainId,
12885
+ sourceTokenAddress,
12886
+ isWalletMatch,
12887
+ connectedWalletName,
12888
+ canWithdraw,
12889
+ onWithdraw,
12890
+ onWithdrawError,
12891
+ onDepositWalletCreation,
12892
+ onWithdrawSubmitted,
12893
+ footerLeft
12894
+ }) {
12895
+ const { colors: colors2, fonts, components } = useTheme();
12896
+ const [recipientAddress, setRecipientAddress] = useState29(recipientAddressProp || "");
12897
+ const [amount, setAmount] = useState29("");
12898
+ const [inputUnit, setInputUnit] = useState29("crypto");
12899
+ const [isSubmitting, setIsSubmitting] = useState29(false);
12900
+ const [submitError, setSubmitError] = useState29(null);
12901
+ const [detailsExpanded, setDetailsExpanded] = useState29(false);
12902
+ const [glossaryOpen, setGlossaryOpen] = useState29(false);
12903
+ useEffect23(() => {
12904
+ setRecipientAddress(recipientAddressProp || "");
12905
+ setAmount("");
12906
+ setInputUnit("crypto");
12907
+ setSubmitError(null);
12908
+ }, [recipientAddressProp]);
12909
+ const trimmedAddress = recipientAddress.trim();
12910
+ const [debouncedAddress, setDebouncedAddress] = useState29(trimmedAddress);
12911
+ useEffect23(() => {
12912
+ const id = setTimeout(() => setDebouncedAddress(trimmedAddress), 500);
12913
+ return () => clearTimeout(id);
12914
+ }, [trimmedAddress]);
12915
+ const {
12916
+ data: addressVerification,
12917
+ isLoading: isVerifyingAddress,
12918
+ error: verifyError
12919
+ } = useVerifyRecipientAddress({
12920
+ chainType: selectedChain?.chain_type,
12921
+ chainId: selectedChain?.chain_id,
12922
+ tokenAddress: selectedChain?.token_address,
12923
+ recipientAddress: debouncedAddress,
12924
+ publishableKey,
12925
+ enabled: debouncedAddress.length > 5 && !!selectedChain
12926
+ });
12927
+ const isDebouncing = trimmedAddress !== debouncedAddress;
12928
+ const addressError = useMemo10(() => {
12929
+ if (!trimmedAddress || trimmedAddress.length <= 5) return null;
12930
+ if (isDebouncing || isVerifyingAddress) return null;
12931
+ if (verifyError) return t8.invalidAddress;
12932
+ if (addressVerification && !addressVerification.valid) {
12933
+ if (addressVerification.failure_code === "account_not_found")
12934
+ return `Account not found on ${selectedChain?.chain_name}`;
12935
+ if (addressVerification.failure_code === "not_opted_in")
12936
+ return `Recipient has not opted in to ${selectedToken?.symbol} on ${selectedChain?.chain_name}`;
12937
+ return t8.invalidAddress;
12938
+ }
12939
+ return null;
12940
+ }, [trimmedAddress, isDebouncing, isVerifyingAddress, verifyError, addressVerification, selectedChain, selectedToken]);
12941
+ const isAddressValid = !isDebouncing && !!addressVerification?.valid && !addressError;
12942
+ const exchangeRate = useMemo10(() => {
12943
+ if (!balanceData?.exchangeRate) return 0;
12944
+ return parseFloat(balanceData.exchangeRate);
12945
+ }, [balanceData]);
12946
+ const balanceCrypto = useMemo10(() => {
12947
+ if (!balanceData?.balanceHuman) return 0;
12948
+ return parseFloat(balanceData.balanceHuman);
12949
+ }, [balanceData]);
12950
+ const balanceUsdNum = useMemo10(() => {
12951
+ if (!balanceData?.balanceUsd) return 0;
12952
+ return parseFloat(balanceData.balanceUsd);
12953
+ }, [balanceData]);
12954
+ const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
12955
+ const sourceDecimals = balanceData?.decimals ?? 6;
12956
+ const cryptoAmountFromInput = useMemo10(() => {
12957
+ const val = parseFloat(amount);
12958
+ if (!val || val <= 0) return 0;
12959
+ if (inputUnit === "crypto") return val;
12960
+ return exchangeRate > 0 ? val / exchangeRate : 0;
12961
+ }, [amount, inputUnit, exchangeRate]);
12962
+ const fiatAmountFromInput = useMemo10(() => {
12963
+ const val = parseFloat(amount);
12964
+ if (!val || val <= 0) return 0;
12965
+ if (inputUnit === "fiat") return val;
12966
+ return val * exchangeRate;
12967
+ }, [amount, inputUnit, exchangeRate]);
12968
+ const convertedDisplay = useMemo10(() => {
12969
+ if (!amount || parseFloat(amount) <= 0) return null;
12970
+ if (inputUnit === "crypto") {
12971
+ return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
12972
+ }
12973
+ return `${cryptoAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 6 })} ${tokenSymbol}`;
12974
+ }, [amount, inputUnit, fiatAmountFromInput, cryptoAmountFromInput, tokenSymbol]);
12975
+ const balanceDisplay = useMemo10(() => {
12976
+ if (isLoadingBalance || !balanceData) return null;
12977
+ if (inputUnit === "crypto") {
12978
+ return `${balanceCrypto.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${tokenSymbol}`;
12979
+ }
12980
+ return `$${balanceUsdNum.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
12981
+ }, [isLoadingBalance, balanceData, inputUnit, balanceCrypto, balanceUsdNum, tokenSymbol]);
12982
+ const handleSwitchUnit = useCallback5(() => {
12983
+ const val = parseFloat(amount);
12984
+ if (!val || val <= 0 || exchangeRate <= 0) {
12985
+ setInputUnit((u) => u === "crypto" ? "fiat" : "crypto");
12986
+ setAmount("");
12987
+ return;
12988
+ }
12989
+ if (inputUnit === "crypto") {
12990
+ const fiat = val * exchangeRate;
12991
+ setAmount(fiat.toFixed(2));
12992
+ setInputUnit("fiat");
12993
+ } else {
12994
+ const crypto = val / exchangeRate;
12995
+ setAmount(crypto.toFixed(sourceDecimals > 6 ? 6 : sourceDecimals));
12996
+ setInputUnit("crypto");
12997
+ }
12998
+ }, [amount, inputUnit, exchangeRate, sourceDecimals]);
12999
+ const handleMaxClick = useCallback5(() => {
13000
+ if (inputUnit === "crypto") {
13001
+ if (balanceCrypto <= 0) return;
13002
+ setAmount(balanceData?.balanceHuman ?? "0");
13003
+ } else {
13004
+ if (balanceUsdNum <= 0) return;
13005
+ setAmount((Math.floor(balanceUsdNum * 100) / 100).toFixed(2));
13006
+ }
13007
+ }, [inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
13008
+ const isBelowMinimum = minimumWithdrawAmountUsd !== null && fiatAmountFromInput > 0 && fiatAmountFromInput < minimumWithdrawAmountUsd;
13009
+ const isOverBalance = inputUnit === "crypto" ? cryptoAmountFromInput > 0 && balanceCrypto > 0 && cryptoAmountFromInput > balanceCrypto : fiatAmountFromInput > 0 && balanceUsdNum > 0 && fiatAmountFromInput > balanceUsdNum;
13010
+ const isFormValid = trimmedAddress.length > 0 && amount.trim().length > 0 && cryptoAmountFromInput > 0 && isAddressValid && !isBelowMinimum && !isOverBalance && !!balanceData;
13011
+ const handleWithdraw = useCallback5(async () => {
13012
+ if (!selectedToken || !selectedChain) return;
13013
+ if (!isFormValid) return;
13014
+ setIsSubmitting(true);
13015
+ setSubmitError(null);
13016
+ try {
13017
+ const depositWallet = await onDepositWalletCreation({
13018
+ destinationChainType: selectedChain.chain_type,
13019
+ destinationChainId: selectedChain.chain_id,
13020
+ destinationTokenAddress: selectedChain.token_address,
13021
+ recipientAddress: trimmedAddress
13022
+ });
13023
+ const amountBaseUnit = computeBaseUnit(
13024
+ balanceData.balanceBaseUnit,
13025
+ parseFloat(amount),
13026
+ inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
13027
+ );
13028
+ const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
13029
+ const txInfo = {
13030
+ sourceChainType,
13031
+ sourceChainId,
13032
+ sourceTokenAddress,
13033
+ sourceTokenSymbol: tokenSymbol,
13034
+ destinationChainType: selectedChain.chain_type,
13035
+ destinationChainId: selectedChain.chain_id,
13036
+ destinationTokenAddress: selectedChain.token_address,
13037
+ destinationTokenSymbol: selectedToken.symbol,
13038
+ amount: humanAmount,
13039
+ amountBaseUnit,
13040
+ withdrawIntentAddress: depositWallet.address,
13041
+ recipientAddress: trimmedAddress
13042
+ };
13043
+ if (detectedWallet) {
13044
+ if (detectedWallet.chainFamily === "evm") {
13045
+ await sendEvmWithdraw({
13046
+ provider: detectedWallet.provider,
13047
+ fromAddress: detectedWallet.address,
13048
+ depositWalletAddress: depositWallet.address,
13049
+ sourceTokenAddress,
13050
+ sourceChainId,
13051
+ amountBaseUnit
13052
+ });
13053
+ } else if (detectedWallet.chainFamily === "solana") {
13054
+ await sendSolanaWithdraw({
13055
+ provider: detectedWallet.provider,
13056
+ fromAddress: detectedWallet.address,
13057
+ depositWalletAddress: depositWallet.address,
13058
+ sourceTokenAddress,
13059
+ amountBaseUnit,
13060
+ publishableKey
13061
+ });
13062
+ }
13063
+ } else if (onWithdraw) {
13064
+ await onWithdraw(txInfo);
13065
+ } else {
13066
+ throw new Error("No withdrawal method available. Please connect a wallet.");
13067
+ }
13068
+ onWithdrawSubmitted?.(txInfo);
13069
+ } catch (err) {
13070
+ const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
13071
+ setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
13072
+ onWithdrawError?.({
13073
+ message: raw,
13074
+ error: err,
13075
+ code: "WITHDRAW_FAILED"
13076
+ });
13077
+ } finally {
13078
+ setIsSubmitting(false);
13079
+ }
13080
+ }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
13081
+ return /* @__PURE__ */ jsxs46(Fragment10, { children: [
13082
+ /* @__PURE__ */ jsxs46("div", { children: [
13083
+ /* @__PURE__ */ jsx53(
13084
+ "div",
13085
+ {
13086
+ className: "uf-text-xs uf-mb-1.5",
13087
+ style: { color: components.card.labelColor, fontFamily: fonts.medium },
13088
+ children: t8.recipientAddress
13089
+ }
13090
+ ),
13091
+ /* @__PURE__ */ jsx53(
13092
+ "style",
13093
+ {
13094
+ dangerouslySetInnerHTML: {
13095
+ __html: `.uf-withdraw-addr::placeholder { color: ${components.search.placeholderColor}; }`
13096
+ }
13097
+ }
13098
+ ),
13099
+ /* @__PURE__ */ jsxs46(
13100
+ "div",
13101
+ {
13102
+ className: "uf-flex uf-items-center uf-gap-1 uf-pr-2",
13103
+ style: {
13104
+ backgroundColor: components.search.backgroundColor,
13105
+ borderRadius: components.input.borderRadius,
13106
+ border: `${components.input.borderWidth}px solid ${addressError ? colors2.error : components.input.borderColor}`
13107
+ },
13108
+ children: [
13109
+ /* @__PURE__ */ jsx53(
13110
+ "input",
13111
+ {
13112
+ type: "text",
13113
+ placeholder: t8.recipientAddressPlaceholder,
13114
+ value: recipientAddress,
13115
+ onChange: (e) => {
13116
+ setRecipientAddress(e.target.value);
13117
+ setSubmitError(null);
13118
+ },
13119
+ 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",
13120
+ style: {
13121
+ color: components.search.inputColor,
13122
+ fontFamily: fonts.regular
13123
+ }
13124
+ }
13125
+ ),
13126
+ /* @__PURE__ */ jsx53(
13127
+ "button",
13128
+ {
13129
+ type: "button",
13130
+ onClick: async () => {
13131
+ try {
13132
+ const text = await navigator.clipboard.readText();
13133
+ if (text) {
13134
+ setRecipientAddress(text.trim());
13135
+ setSubmitError(null);
13136
+ }
13137
+ } catch {
13138
+ }
13139
+ },
13140
+ className: "uf-flex-shrink-0 uf-p-1 uf-rounded uf-transition-colors hover:uf-opacity-70",
13141
+ style: { color: colors2.foregroundMuted },
13142
+ title: "Paste from clipboard",
13143
+ children: /* @__PURE__ */ jsx53(ClipboardPaste, { className: "uf-w-4 uf-h-4" })
13144
+ }
13145
+ )
13146
+ ]
13147
+ }
13148
+ ),
13149
+ (isDebouncing || isVerifyingAddress) && trimmedAddress.length > 5 && /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
13150
+ /* @__PURE__ */ jsx53(Loader25, { className: "uf-w-3 uf-h-3 uf-animate-spin", style: { color: colors2.foregroundMuted } }),
13151
+ /* @__PURE__ */ jsx53("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: t8.verifyingAddress })
13152
+ ] }),
13153
+ addressError && /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
13154
+ /* @__PURE__ */ jsx53(AlertTriangle2, { className: "uf-w-3 uf-h-3", style: { color: colors2.error } }),
13155
+ /* @__PURE__ */ jsx53("span", { className: "uf-text-xs", style: { color: colors2.error, fontFamily: fonts.regular }, children: addressError })
13156
+ ] })
13157
+ ] }),
13158
+ /* @__PURE__ */ jsxs46("div", { children: [
13159
+ /* @__PURE__ */ jsxs46("div", { className: "uf-text-xs uf-mb-1.5", style: { color: components.card.labelColor, fontFamily: fonts.medium }, children: [
13160
+ t8.amount,
13161
+ minimumWithdrawAmountUsd != null && minimumWithdrawAmountUsd > 0 && /* @__PURE__ */ jsx53("span", { style: { color: colors2.warning, fontFamily: fonts.regular }, children: ` ($${minimumWithdrawAmountUsd.toFixed(2)} min)` })
13162
+ ] }),
13163
+ /* @__PURE__ */ jsx53(
13164
+ "style",
13165
+ {
13166
+ dangerouslySetInnerHTML: {
13167
+ __html: `.uf-withdraw-amt::placeholder { color: ${components.search.placeholderColor}; }`
13168
+ }
13169
+ }
13170
+ ),
13171
+ /* @__PURE__ */ jsxs46(
13172
+ "div",
13173
+ {
13174
+ className: "uf-flex uf-items-center uf-gap-2 uf-px-3 uf-py-2.5",
13175
+ style: {
13176
+ backgroundColor: components.search.backgroundColor,
13177
+ borderRadius: components.input.borderRadius,
13178
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
13179
+ },
13180
+ children: [
13181
+ /* @__PURE__ */ jsx53(
13182
+ "input",
13183
+ {
13184
+ type: "text",
13185
+ inputMode: "decimal",
13186
+ placeholder: "0.00",
13187
+ value: amount,
13188
+ onChange: (e) => {
13189
+ const val = e.target.value;
13190
+ if (val === "" || /^\d*\.?\d*$/.test(val)) {
13191
+ setAmount(val);
13192
+ setSubmitError(null);
13193
+ }
13194
+ },
13195
+ className: "uf-withdraw-amt uf-flex-1 uf-min-w-0 uf-bg-transparent uf-text-sm uf-outline-none",
13196
+ style: {
13197
+ color: components.search.inputColor,
13198
+ fontFamily: fonts.regular
13199
+ }
13200
+ }
13201
+ ),
13202
+ /* @__PURE__ */ jsx53("span", { className: "uf-text-sm uf-shrink-0", style: { color: colors2.foregroundMuted, fontFamily: fonts.medium }, children: inputUnit === "crypto" ? tokenSymbol : "USD" }),
13203
+ /* @__PURE__ */ jsx53(
13204
+ "button",
13205
+ {
13206
+ type: "button",
13207
+ onClick: handleMaxClick,
13208
+ 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",
13209
+ style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium },
13210
+ children: "Max"
13211
+ }
13212
+ )
13213
+ ]
13214
+ }
13215
+ ),
13216
+ /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-justify-between uf-mt-1.5 uf-px-3", children: [
13217
+ /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
13218
+ /* @__PURE__ */ jsx53("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: convertedDisplay || (inputUnit === "crypto" ? "$0.00" : `0.00 ${tokenSymbol}`) }),
13219
+ exchangeRate > 0 && /* @__PURE__ */ jsx53(
13220
+ "button",
13221
+ {
13222
+ type: "button",
13223
+ onClick: handleSwitchUnit,
13224
+ className: "uf-p-0.5 uf-rounded uf-transition-colors hover:uf-opacity-70",
13225
+ style: { color: colors2.foregroundMuted },
13226
+ title: "Switch unit",
13227
+ children: /* @__PURE__ */ jsx53(ArrowUpDown, { className: "uf-w-3 uf-h-3" })
13228
+ }
13229
+ )
13230
+ ] }),
13231
+ /* @__PURE__ */ jsxs46("div", { children: [
13232
+ balanceDisplay && /* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: [
13233
+ t8.balance,
13234
+ ": ",
13235
+ balanceDisplay
13236
+ ] }),
13237
+ isLoadingBalance && /* @__PURE__ */ jsx53("div", { className: "uf-h-3 uf-w-16 uf-bg-muted uf-rounded uf-animate-pulse" })
13238
+ ] })
13239
+ ] })
13240
+ ] }),
13241
+ /* @__PURE__ */ jsxs46("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: [
13242
+ /* @__PURE__ */ jsxs46(
13243
+ "button",
13244
+ {
13245
+ type: "button",
13246
+ onClick: () => setDetailsExpanded(!detailsExpanded),
13247
+ className: "uf-w-full uf-flex uf-items-center uf-justify-between uf-py-2.5",
13248
+ children: [
13249
+ /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13250
+ /* @__PURE__ */ jsx53("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx53(Clock4, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
13251
+ /* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
13252
+ tCrypto.processingTime.label,
13253
+ ":",
13254
+ " ",
13255
+ /* @__PURE__ */ jsx53("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(estimatedProcessingTime) })
13256
+ ] })
13257
+ ] }),
13258
+ detailsExpanded ? /* @__PURE__ */ jsx53(ChevronUp6, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ jsx53(ChevronDown7, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
13259
+ ]
13260
+ }
13261
+ ),
13262
+ detailsExpanded && /* @__PURE__ */ jsxs46("div", { className: "uf-pb-3 uf-space-y-2.5", children: [
13263
+ /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13264
+ /* @__PURE__ */ jsx53("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx53(ShieldCheck3, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
13265
+ /* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
13266
+ tCrypto.slippage.label,
13267
+ ":",
13268
+ " ",
13269
+ /* @__PURE__ */ jsxs46("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
13270
+ tCrypto.slippage.auto,
13271
+ " \u2022 ",
13272
+ (maxSlippagePercent ?? 0.25).toFixed(2),
13273
+ "%"
13274
+ ] })
13275
+ ] })
13276
+ ] }),
13277
+ /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13278
+ /* @__PURE__ */ jsx53("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx53(DollarSign3, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
13279
+ /* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
13280
+ tCrypto.priceImpact.label,
13281
+ ":",
13282
+ " ",
13283
+ /* @__PURE__ */ jsxs46("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
13284
+ (priceImpactPercent ?? 0).toFixed(2),
13285
+ "%"
13286
+ ] })
13287
+ ] })
13288
+ ] })
13289
+ ] })
13290
+ ] }),
13291
+ !canWithdraw && !submitError && /* @__PURE__ */ jsxs46(
13292
+ "div",
13293
+ {
13294
+ className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
13295
+ style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
13296
+ children: [
13297
+ /* @__PURE__ */ jsx53(Wallet3, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
13298
+ /* @__PURE__ */ jsx53("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." })
13299
+ ]
13300
+ }
13301
+ ),
13302
+ isWalletMatch && connectedWalletName ? /* @__PURE__ */ jsx53(
13303
+ "button",
13304
+ {
13305
+ type: "button",
13306
+ onClick: handleWithdraw,
13307
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
13308
+ 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",
13309
+ style: {
13310
+ backgroundColor: colors2.primary,
13311
+ color: colors2.primaryForeground,
13312
+ fontFamily: fonts.medium,
13313
+ borderRadius: components.button.borderRadius,
13314
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
13315
+ },
13316
+ children: isSubmitting ? /* @__PURE__ */ jsxs46(Fragment10, { children: [
13317
+ /* @__PURE__ */ jsx53(Loader25, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
13318
+ "Processing..."
13319
+ ] }) : isOverBalance ? /* @__PURE__ */ jsx53(Fragment10, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ jsx53(Fragment10, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ jsx53(Fragment10, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ jsxs46(Fragment10, { children: [
13320
+ /* @__PURE__ */ jsx53(Wallet3, { className: "uf-w-4 uf-h-4" }),
13321
+ "Withdraw from ",
13322
+ connectedWalletName
13323
+ ] })
13324
+ }
13325
+ ) : /* @__PURE__ */ jsx53(
13326
+ "button",
13327
+ {
13328
+ type: "button",
13329
+ onClick: handleWithdraw,
13330
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
13331
+ 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",
13332
+ style: {
13333
+ backgroundColor: colors2.primary,
13334
+ color: colors2.primaryForeground,
13335
+ fontFamily: fonts.medium,
13336
+ borderRadius: components.button.borderRadius,
13337
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
13338
+ },
13339
+ children: isSubmitting ? /* @__PURE__ */ jsxs46("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
13340
+ /* @__PURE__ */ jsx53(Loader25, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
13341
+ "Processing..."
13342
+ ] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
13343
+ }
13344
+ ),
13345
+ /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
13346
+ /* @__PURE__ */ jsx53("div", { children: footerLeft }),
13347
+ /* @__PURE__ */ jsx53(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) })
13348
+ ] }),
13349
+ /* @__PURE__ */ jsx53(
13350
+ GlossaryModal,
13351
+ {
13352
+ open: glossaryOpen,
13353
+ onOpenChange: setGlossaryOpen
13354
+ }
13355
+ )
13356
+ ] });
13357
+ }
13358
+
13359
+ // src/components/withdrawals/WithdrawExecutionItem.tsx
13360
+ import { ChevronRight as ChevronRight12 } from "lucide-react";
13361
+ import {
13362
+ ExecutionStatus as ExecutionStatus6,
13363
+ getIconUrl as getIconUrl5
13364
+ } from "@unifold/core";
13365
+ import { jsx as jsx54, jsxs as jsxs47 } from "react/jsx-runtime";
13366
+ function WithdrawExecutionItem({
13367
+ execution,
13368
+ onClick
13369
+ }) {
13370
+ const { colors: colors2, fonts, components } = useTheme();
13371
+ const isPending = execution.status === ExecutionStatus6.PENDING || execution.status === ExecutionStatus6.WAITING || execution.status === ExecutionStatus6.DELAYED;
13372
+ const formatDateTime = (timestamp) => {
13373
+ try {
13374
+ const date = new Date(timestamp);
13375
+ const monthDay = date.toLocaleDateString("en-US", {
13376
+ month: "short",
13377
+ day: "numeric",
13378
+ year: "numeric"
13379
+ });
13380
+ const time = date.toLocaleTimeString("en-US", {
13381
+ hour: "numeric",
13382
+ minute: "2-digit",
13383
+ hour12: true
13384
+ }).toLowerCase();
13385
+ return `${monthDay} at ${time}`;
13386
+ } catch {
13387
+ return timestamp;
13388
+ }
13389
+ };
13390
+ const formatUsdAmount2 = (sourceAmountUsd) => {
13391
+ try {
13392
+ const amount = Number(sourceAmountUsd);
13393
+ return new Intl.NumberFormat("en-US", {
13394
+ style: "currency",
13395
+ currency: "USD",
13396
+ minimumFractionDigits: 2,
13397
+ maximumFractionDigits: 2
13398
+ }).format(amount);
13399
+ } catch {
13400
+ return "$0.00";
13401
+ }
13402
+ };
13403
+ return /* @__PURE__ */ jsxs47(
13404
+ "button",
13405
+ {
13406
+ onClick,
13407
+ 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",
13408
+ style: {
13409
+ backgroundColor: components.card.backgroundColor,
13410
+ borderRadius: components.list.rowBorderRadius,
13411
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
13412
+ },
13413
+ children: [
13414
+ /* @__PURE__ */ jsxs47("div", { className: "uf-relative uf-flex-shrink-0 uf-w-9 uf-h-9", children: [
13415
+ /* @__PURE__ */ jsx54(
13416
+ "img",
13417
+ {
13418
+ src: execution.destination_token_metadata?.icon_url || getIconUrl5("/icons/tokens/svg/usdc.svg"),
13419
+ alt: "Token",
13420
+ width: 36,
13421
+ height: 36,
13422
+ loading: "lazy",
13423
+ className: "uf-rounded-full uf-w-9 uf-h-9"
13424
+ }
13425
+ ),
13426
+ isPending ? /* @__PURE__ */ jsx54(
13427
+ "div",
13428
+ {
13429
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
13430
+ style: { backgroundColor: colors2.warning },
13431
+ children: /* @__PURE__ */ jsx54(
13432
+ "svg",
13433
+ {
13434
+ width: "10",
13435
+ height: "10",
13436
+ viewBox: "0 0 12 12",
13437
+ fill: "none",
13438
+ className: "uf-animate-spin uf-block",
13439
+ children: /* @__PURE__ */ jsx54(
13440
+ "path",
13441
+ {
13442
+ d: "M6 1V3M6 9V11M1 6H3M9 6H11M2.5 2.5L4 4M8 8L9.5 9.5M2.5 9.5L4 8M8 4L9.5 2.5",
13443
+ stroke: "white",
13444
+ strokeWidth: "2",
13445
+ strokeLinecap: "round"
13446
+ }
13447
+ )
13448
+ }
13449
+ )
13450
+ }
13451
+ ) : /* @__PURE__ */ jsx54(
13452
+ "div",
13453
+ {
13454
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
13455
+ style: { backgroundColor: colors2.success },
13456
+ children: /* @__PURE__ */ jsx54(
13457
+ "svg",
13458
+ {
13459
+ width: "10",
13460
+ height: "10",
13461
+ viewBox: "0 0 12 12",
13462
+ fill: "none",
13463
+ className: "uf-block",
13464
+ children: /* @__PURE__ */ jsx54(
13465
+ "path",
13466
+ {
13467
+ d: "M10 3L4.5 8.5L2 6",
13468
+ stroke: "white",
13469
+ strokeWidth: "2",
13470
+ strokeLinecap: "round",
13471
+ strokeLinejoin: "round"
13472
+ }
13473
+ )
13474
+ }
13475
+ )
13476
+ }
13477
+ )
13478
+ ] }),
13479
+ /* @__PURE__ */ jsxs47("div", { className: "uf-flex-1 uf-min-w-0", children: [
13480
+ /* @__PURE__ */ jsx54(
13481
+ "h3",
13482
+ {
13483
+ className: "uf-font-medium uf-text-sm uf-leading-tight",
13484
+ style: {
13485
+ color: components.card.titleColor,
13486
+ fontFamily: fonts.medium
13487
+ },
13488
+ children: isPending ? "Withdrawal processing" : "Withdrawal completed"
13489
+ }
13490
+ ),
13491
+ /* @__PURE__ */ jsx54(
13492
+ "p",
13493
+ {
13494
+ className: "uf-text-xs uf-leading-tight",
13495
+ style: {
13496
+ color: components.card.subtitleColor,
13497
+ fontFamily: fonts.regular
13498
+ },
13499
+ children: formatDateTime(execution.created_at || (/* @__PURE__ */ new Date()).toISOString())
13500
+ }
13501
+ )
13502
+ ] }),
13503
+ /* @__PURE__ */ jsx54(
13504
+ "span",
13505
+ {
13506
+ className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
13507
+ style: {
13508
+ color: components.card.textRightColor,
13509
+ fontFamily: fonts.medium
13510
+ },
13511
+ children: formatUsdAmount2(execution.source_amount_usd || "0")
13512
+ }
13513
+ ),
13514
+ /* @__PURE__ */ jsx54(
13515
+ ChevronRight12,
13516
+ {
13517
+ className: "uf-w-4 uf-h-4 uf-flex-shrink-0",
13518
+ style: { color: components.card.actionColor }
13519
+ }
13520
+ )
13521
+ ]
13522
+ }
13523
+ );
13524
+ }
13525
+
13526
+ // src/components/withdrawals/WithdrawConfirmingView.tsx
13527
+ import { useState as useState30, useEffect as useEffect24 } from "react";
13528
+ import { Fragment as Fragment11, jsx as jsx55, jsxs as jsxs48 } from "react/jsx-runtime";
13529
+ function truncateAddress4(addr) {
13530
+ if (addr.length <= 12) return addr;
13531
+ return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
13532
+ }
13533
+ var SHOW_BUTTON_DELAY_MS = 5e3;
13534
+ function WithdrawConfirmingView({
13535
+ txInfo,
13536
+ executions,
13537
+ onClose,
13538
+ onViewTracker
13539
+ }) {
13540
+ const { colors: colors2, fonts, components } = useTheme();
13541
+ const [showButton, setShowButton] = useState30(false);
13542
+ const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
13543
+ useEffect24(() => {
13544
+ if (latestExecution) return;
13545
+ const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
13546
+ return () => clearTimeout(timer);
13547
+ }, [latestExecution]);
13548
+ const btnRadius = components.button.borderRadius;
13549
+ const btnBorder = `${components.button.borderWidth}px solid ${components.button.borderColor}`;
13550
+ if (latestExecution) {
13551
+ return /* @__PURE__ */ jsxs48(Fragment11, { children: [
13552
+ /* @__PURE__ */ jsx55(DepositHeader, { title: "Withdrawal Details", showClose: true, onClose }),
13553
+ /* @__PURE__ */ jsx55(DepositDetailContent, { execution: latestExecution, variant: "withdraw" }),
13554
+ /* @__PURE__ */ jsxs48("div", { className: "uf-flex uf-gap-2 uf-px-2 uf-pt-2", children: [
13555
+ /* @__PURE__ */ jsx55(
13556
+ "button",
13557
+ {
13558
+ type: "button",
13559
+ onClick: onViewTracker,
13560
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
13561
+ style: {
13562
+ backgroundColor: components.button.secondaryBackground,
13563
+ color: components.button.secondaryText,
13564
+ fontFamily: fonts.medium,
13565
+ borderRadius: btnRadius,
13566
+ border: btnBorder
13567
+ },
13568
+ children: "Withdrawal History"
13569
+ }
13570
+ ),
13571
+ /* @__PURE__ */ jsx55(
13572
+ "button",
13573
+ {
13574
+ type: "button",
13575
+ onClick: onClose,
13576
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
13577
+ style: {
13578
+ backgroundColor: components.button.primaryBackground,
13579
+ color: components.button.primaryText,
13580
+ fontFamily: fonts.medium,
13581
+ borderRadius: btnRadius,
13582
+ border: btnBorder
13583
+ },
13584
+ children: "Close"
13585
+ }
13586
+ )
13587
+ ] }),
13588
+ /* @__PURE__ */ jsx55("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx55(
13589
+ PoweredByUnifold,
13590
+ {
13591
+ color: colors2.foregroundMuted,
13592
+ className: "uf-flex uf-justify-center uf-shrink-0"
13593
+ }
13594
+ ) })
13595
+ ] });
13596
+ }
13597
+ return /* @__PURE__ */ jsxs48(Fragment11, { children: [
13598
+ /* @__PURE__ */ jsx55(DepositHeader, { title: "Withdrawal Status", showClose: true, onClose }),
13599
+ /* @__PURE__ */ jsxs48("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4", children: [
13600
+ /* @__PURE__ */ jsx55(
13601
+ "div",
13602
+ {
13603
+ className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
13604
+ style: { backgroundColor: `${colors2.primary}20` },
13605
+ children: /* @__PURE__ */ jsx55(
13606
+ "svg",
13607
+ {
13608
+ width: "40",
13609
+ height: "40",
13610
+ viewBox: "0 0 24 24",
13611
+ fill: "none",
13612
+ className: "uf-animate-spin",
13613
+ children: /* @__PURE__ */ jsx55(
13614
+ "path",
13615
+ {
13616
+ d: "M21 12a9 9 0 1 1-6.22-8.56",
13617
+ stroke: colors2.primary,
13618
+ strokeWidth: "2.5",
13619
+ strokeLinecap: "round"
13620
+ }
13621
+ )
13622
+ }
13623
+ )
13624
+ }
13625
+ ),
13626
+ /* @__PURE__ */ jsx55(
13627
+ "h3",
13628
+ {
13629
+ className: "uf-text-xl uf-mb-2",
13630
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
13631
+ children: "Checking Withdrawal"
13632
+ }
13633
+ ),
13634
+ /* @__PURE__ */ jsxs48(
13635
+ "p",
13636
+ {
13637
+ className: "uf-text-sm uf-text-center",
13638
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
13639
+ children: [
13640
+ txInfo.amount,
13641
+ " ",
13642
+ txInfo.sourceTokenSymbol,
13643
+ " to",
13644
+ " ",
13645
+ truncateAddress4(txInfo.recipientAddress)
13646
+ ]
13647
+ }
13648
+ )
13649
+ ] }),
13650
+ showButton && /* @__PURE__ */ jsx55("div", { className: "uf-px-1 uf-pb-1", children: /* @__PURE__ */ jsx55(
13651
+ "button",
13652
+ {
13653
+ type: "button",
13654
+ onClick: onViewTracker,
13655
+ className: "uf-w-full uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
13656
+ style: {
13657
+ backgroundColor: components.button.secondaryBackground,
13658
+ color: components.button.secondaryText,
13659
+ fontFamily: fonts.medium,
13660
+ borderRadius: btnRadius,
13661
+ border: btnBorder
13662
+ },
13663
+ children: "Withdrawal History"
13664
+ }
13665
+ ) }),
13666
+ /* @__PURE__ */ jsx55("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx55(
13667
+ PoweredByUnifold,
13668
+ {
13669
+ color: colors2.foregroundMuted,
13670
+ className: "uf-flex uf-justify-center uf-shrink-0"
13671
+ }
13672
+ ) })
13673
+ ] });
13674
+ }
13675
+
13676
+ // src/components/withdrawals/WithdrawModal.tsx
13677
+ import {
13678
+ createDepositAddress as createDepositAddress2,
13679
+ getWalletByChainType as getWalletByChainType4,
13680
+ ActionType as ActionType6
13681
+ } from "@unifold/core";
13682
+ import { Fragment as Fragment12, jsx as jsx56, jsxs as jsxs49 } from "react/jsx-runtime";
13683
+ var t9 = i18n.withdrawModal;
13684
+ var getChainKey5 = (chainId, chainType) => `${chainType}:${chainId}`;
13685
+ function WithdrawModal({
13686
+ open,
13687
+ onOpenChange,
13688
+ publishableKey,
13689
+ modalTitle,
13690
+ externalUserId,
13691
+ sourceChainType,
13692
+ sourceChainId,
13693
+ sourceTokenAddress,
13694
+ sourceTokenSymbol,
13695
+ recipientAddress: recipientAddressProp,
13696
+ senderAddress,
13697
+ onWithdraw,
13698
+ onWithdrawSuccess,
13699
+ onWithdrawError,
13700
+ theme = "dark",
13701
+ hideOverlay = false
13702
+ }) {
13703
+ const { colors: colors2, fonts, components } = useTheme();
13704
+ const [containerEl, setContainerEl] = useState31(null);
13705
+ const containerCallbackRef = useCallback6((el) => {
13706
+ setContainerEl(el);
13707
+ }, []);
13708
+ const [resolvedTheme, setResolvedTheme] = useState31(
13709
+ theme === "auto" ? "dark" : theme
13710
+ );
13711
+ useEffect25(() => {
13712
+ if (theme === "auto") {
13713
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
13714
+ setResolvedTheme(mq.matches ? "dark" : "light");
13715
+ const h = (e) => setResolvedTheme(e.matches ? "dark" : "light");
13716
+ mq.addEventListener("change", h);
13717
+ return () => mq.removeEventListener("change", h);
13718
+ }
13719
+ setResolvedTheme(theme);
13720
+ }, [theme]);
13721
+ const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
13722
+ const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDestinationTokens(publishableKey, open);
13723
+ const destinationTokens = tokensResponse?.data ?? [];
13724
+ const { data: sourceValidation, isLoading: isCheckingSourceToken } = useSourceTokenValidation({
13725
+ sourceChainType,
13726
+ sourceChainId,
13727
+ sourceTokenAddress,
13728
+ sourceTokenSymbol,
13729
+ publishableKey,
13730
+ enabled: open
13731
+ });
13732
+ const { data: balanceData, isLoading: isLoadingBalance } = useAddressBalance({
13733
+ address: senderAddress,
13734
+ chainType: sourceChainType,
13735
+ chainId: sourceChainId,
13736
+ tokenAddress: sourceTokenAddress,
13737
+ publishableKey,
13738
+ enabled: open
13739
+ });
13740
+ const [selectedToken, setSelectedToken] = useState31(null);
13741
+ const [selectedChain, setSelectedChain] = useState31(null);
13742
+ const [detectedWallet, setDetectedWallet] = useState31(null);
13743
+ const connectedWalletName = detectedWallet?.name ?? null;
13744
+ const isWalletMatch = !!detectedWallet;
13745
+ useEffect25(() => {
13746
+ if (!senderAddress || !open) {
13747
+ setDetectedWallet(null);
13748
+ return;
13749
+ }
13750
+ let cancelled = false;
13751
+ detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
13752
+ if (!cancelled) setDetectedWallet(wallet);
13753
+ });
13754
+ return () => {
13755
+ cancelled = true;
13756
+ };
13757
+ }, [senderAddress, sourceChainType, open]);
13758
+ const [view, setView] = useState31("form");
13759
+ const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState31();
13760
+ const [selectedExecution, setSelectedExecution] = useState31(null);
13761
+ const [submittedTxInfo, setSubmittedTxInfo] = useState31(null);
13762
+ const { executions: realtimeExecutions } = useWithdrawPolling({
13763
+ userId: externalUserId,
13764
+ publishableKey,
13765
+ depositWalletId: withdrawDepositWalletId,
13766
+ enabled: !!withdrawDepositWalletId && open,
13767
+ onWithdrawSuccess: onWithdrawSuccess ? (d) => onWithdrawSuccess({ message: d.message, transaction: d.transaction }) : void 0,
13768
+ onWithdrawError
13769
+ });
13770
+ const { data: allWithdrawalsData } = useExecutions(externalUserId, publishableKey, {
13771
+ actionType: ActionType6.Withdraw,
13772
+ enabled: open,
13773
+ refetchInterval: view === "tracker" || view === "detail" ? 5e3 : 15e3
13774
+ });
13775
+ const allWithdrawals = allWithdrawalsData?.data ?? [];
13776
+ const handleDepositWalletCreation = useCallback6(async (params) => {
13777
+ const { data: wallets } = await createDepositAddress2(
13778
+ {
13779
+ external_user_id: externalUserId,
13780
+ destination_chain_type: params.destinationChainType,
13781
+ destination_chain_id: params.destinationChainId,
13782
+ destination_token_address: params.destinationTokenAddress,
13783
+ recipient_address: params.recipientAddress,
13784
+ action_type: ActionType6.Withdraw
13785
+ },
13786
+ publishableKey
13787
+ );
13788
+ const depositWallet = getWalletByChainType4(wallets, sourceChainType);
13789
+ if (!depositWallet) {
13790
+ throw new Error(`No deposit wallet available for ${sourceChainType}`);
13791
+ }
13792
+ setWithdrawDepositWalletId(depositWallet.id);
13793
+ return depositWallet;
13794
+ }, [externalUserId, publishableKey, sourceChainType]);
13795
+ const handleWithdrawSubmitted = useCallback6((txInfo) => {
13796
+ setSubmittedTxInfo(txInfo);
13797
+ setView("confirming");
13798
+ }, []);
13799
+ useEffect25(() => {
13800
+ if (!destinationTokens.length || selectedToken) return;
13801
+ const first = destinationTokens[0];
13802
+ if (first?.chains.length > 0) {
13803
+ setSelectedToken(first);
13804
+ setSelectedChain(first.chains[0]);
13805
+ }
13806
+ }, [destinationTokens, selectedToken]);
13807
+ const resetViewTimeoutRef = useRef8(null);
13808
+ const handleClose = useCallback6(() => {
13809
+ onOpenChange(false);
13810
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
13811
+ resetViewTimeoutRef.current = setTimeout(() => {
13812
+ setSelectedToken(null);
13813
+ setSelectedChain(null);
13814
+ setView("form");
13815
+ setSelectedExecution(null);
13816
+ setSubmittedTxInfo(null);
13817
+ setWithdrawDepositWalletId(void 0);
13818
+ resetViewTimeoutRef.current = null;
13819
+ }, 200);
13820
+ }, [onOpenChange]);
13821
+ useLayoutEffect3(() => {
13822
+ if (!open) return;
13823
+ if (resetViewTimeoutRef.current) {
13824
+ clearTimeout(resetViewTimeoutRef.current);
13825
+ resetViewTimeoutRef.current = null;
13826
+ }
13827
+ setSelectedToken(null);
13828
+ setSelectedChain(null);
13829
+ setView("form");
13830
+ setSelectedExecution(null);
13831
+ setSubmittedTxInfo(null);
13832
+ setWithdrawDepositWalletId(void 0);
13833
+ }, [open]);
13834
+ useEffect25(() => () => {
13835
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
13836
+ }, []);
13837
+ const handleTokenSymbolChange = useCallback6((symbol) => {
13838
+ const tok = destinationTokens.find((t11) => t11.symbol === symbol);
13839
+ if (tok) {
13840
+ setSelectedToken(tok);
13841
+ if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
13842
+ }
13843
+ }, [destinationTokens]);
13844
+ const handleChainKeyChange = useCallback6((chainKey) => {
13845
+ if (!selectedToken) return;
13846
+ const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
13847
+ if (chain) setSelectedChain(chain);
13848
+ }, [selectedToken]);
13849
+ const isSourceSupported = sourceValidation?.isSupported ?? null;
13850
+ const canWithdraw = !!onWithdraw || isWalletMatch;
13851
+ const isAnyLoading = tokensLoading || isCheckingSourceToken;
13852
+ const withdrawPoweredByFooter = /* @__PURE__ */ jsx56("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx56(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
13853
+ return /* @__PURE__ */ jsx56(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ jsx56(Dialog, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ jsx56(
13854
+ DialogContent,
13855
+ {
13856
+ ref: hideOverlay ? containerCallbackRef : void 0,
13857
+ hideOverlay,
13858
+ 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}`}`,
13859
+ style: { backgroundColor: colors2.background },
13860
+ onPointerDownOutside: (e) => e.preventDefault(),
13861
+ onInteractOutside: (e) => e.preventDefault(),
13862
+ children: /* @__PURE__ */ jsx56(ThemeStyleInjector, { children: view === "confirming" && submittedTxInfo ? /* @__PURE__ */ jsx56(
13863
+ WithdrawConfirmingView,
13864
+ {
13865
+ txInfo: submittedTxInfo,
13866
+ executions: realtimeExecutions,
13867
+ onClose: handleClose,
13868
+ onViewTracker: () => setView("tracker")
13869
+ }
13870
+ ) : view === "detail" && selectedExecution ? /* @__PURE__ */ jsxs49(Fragment12, { children: [
13871
+ /* @__PURE__ */ jsx56(DepositHeader, { title: "Withdrawal Details", showBack: true, showClose: !hideOverlay, onBack: () => {
13872
+ setSelectedExecution(null);
13873
+ setView("tracker");
13874
+ }, onClose: handleClose }),
13875
+ /* @__PURE__ */ jsx56(DepositDetailContent, { execution: selectedExecution, variant: "withdraw" }),
13876
+ withdrawPoweredByFooter
13877
+ ] }) : view === "tracker" ? (
13878
+ /* ---------- Tracker view: execution list ---------- */
13879
+ /* @__PURE__ */ jsxs49(Fragment12, { children: [
13880
+ /* @__PURE__ */ jsx56(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
13881
+ /* @__PURE__ */ jsx56("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ jsx56("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ jsx56("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ jsx56(
13882
+ WithdrawExecutionItem,
13883
+ {
13884
+ execution: ex,
13885
+ onClick: () => {
13886
+ setSelectedExecution(ex);
13887
+ setView("detail");
13888
+ }
13889
+ },
13890
+ ex.id
13891
+ )) }),
13892
+ withdrawPoweredByFooter
13893
+ ] })
13894
+ ) : (
13895
+ /* ---------- Form view (default) ---------- */
13896
+ /* @__PURE__ */ jsxs49(Fragment12, { children: [
13897
+ /* @__PURE__ */ jsx56(DepositHeader, { title: modalTitle || t9.title, showClose: !hideOverlay, onClose: handleClose }),
13898
+ /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-gap-3", children: [
13899
+ isAnyLoading ? /* @__PURE__ */ jsx56("div", { className: "uf-space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsx56("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-animate-pulse", children: /* @__PURE__ */ jsx56("div", { className: "uf-bg-muted uf-rounded-lg uf-w-full uf-h-10" }) }, i)) }) : isSourceSupported === false ? /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
13900
+ /* @__PURE__ */ jsx56("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__ */ jsx56(AlertTriangle3, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
13901
+ /* @__PURE__ */ jsx56("h3", { className: "uf-text-lg uf-font-semibold uf-mb-2", style: { color: colors2.foreground, fontFamily: fonts.medium }, children: "Unsupported Source Token" }),
13902
+ /* @__PURE__ */ jsx56("p", { className: "uf-text-sm uf-max-w-[280px]", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: sourceValidation?.errorMessage })
13903
+ ] }) : /* @__PURE__ */ jsxs49(Fragment12, { children: [
13904
+ /* @__PURE__ */ jsx56(
13905
+ WithdrawDoubleInput,
13906
+ {
13907
+ tokens: destinationTokens,
13908
+ selectedTokenSymbol: selectedToken?.symbol ?? null,
13909
+ selectedChainKey: selectedChain ? getChainKey5(selectedChain.chain_id, selectedChain.chain_type) : null,
13910
+ onTokenChange: handleTokenSymbolChange,
13911
+ onChainChange: handleChainKeyChange,
13912
+ isLoading: tokensLoading
13913
+ }
13914
+ ),
13915
+ /* @__PURE__ */ jsx56(
13916
+ WithdrawForm,
13917
+ {
13918
+ publishableKey,
13919
+ externalUserId,
13920
+ sourceChainType,
13921
+ selectedToken,
13922
+ selectedChain,
13923
+ sourceTokenSymbol,
13924
+ recipientAddressProp,
13925
+ balanceData: balanceData ?? null,
13926
+ isLoadingBalance,
13927
+ minimumWithdrawAmountUsd: sourceValidation?.minimumAmountUsd ?? null,
13928
+ estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
13929
+ maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
13930
+ priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
13931
+ detectedWallet,
13932
+ sourceChainId,
13933
+ sourceTokenAddress,
13934
+ isWalletMatch,
13935
+ connectedWalletName,
13936
+ canWithdraw,
13937
+ onWithdraw,
13938
+ onWithdrawError,
13939
+ onDepositWalletCreation: handleDepositWalletCreation,
13940
+ onWithdrawSubmitted: handleWithdrawSubmitted,
13941
+ footerLeft: /* @__PURE__ */ jsxs49(
13942
+ "button",
13943
+ {
13944
+ onClick: () => setView("tracker"),
13945
+ className: "uf-flex uf-items-center uf-gap-1 uf-transition-colors hover:uf-opacity-70",
13946
+ style: { color: colors2.foregroundMuted },
13947
+ children: [
13948
+ /* @__PURE__ */ jsx56(Clock5, { className: "uf-w-3.5 uf-h-3.5" }),
13949
+ "Withdrawal History",
13950
+ /* @__PURE__ */ jsx56(ChevronRight13, { className: "uf-w-3 uf-h-3" })
13951
+ ]
13952
+ }
13953
+ )
13954
+ }
13955
+ )
13956
+ ] }),
13957
+ withdrawPoweredByFooter
13958
+ ] })
13959
+ ] })
13960
+ ) })
13961
+ }
13962
+ ) }) });
13963
+ }
13964
+
13965
+ // src/components/withdrawals/WithdrawTokenSelector.tsx
13966
+ import { useState as useState32, useMemo as useMemo11 } from "react";
13967
+ import { Search } from "lucide-react";
13968
+ import { jsx as jsx57, jsxs as jsxs50 } from "react/jsx-runtime";
13969
+ var t10 = i18n.withdrawModal;
13970
+ function WithdrawTokenSelector({
13971
+ tokens,
13972
+ onSelect,
13973
+ onBack
13974
+ }) {
13975
+ const { themeClass, colors: colors2, fonts, components } = useTheme();
13976
+ const [searchQuery, setSearchQuery] = useState32("");
13977
+ const [hoveredKey, setHoveredKey] = useState32(null);
13978
+ const allOptions = useMemo11(() => {
13979
+ const options = [];
13980
+ tokens.forEach((token) => {
13981
+ token.chains.forEach((chain) => {
13982
+ options.push({ token, chain });
13983
+ });
13984
+ });
13985
+ return options;
13986
+ }, [tokens]);
13987
+ const filteredOptions = useMemo11(() => {
13988
+ if (!searchQuery.trim()) return allOptions;
13989
+ const query = searchQuery.toLowerCase();
13990
+ return allOptions.filter(
13991
+ ({ token, chain }) => token.symbol.toLowerCase().includes(query) || token.name.toLowerCase().includes(query) || chain.chain_name.toLowerCase().includes(query)
13992
+ );
13993
+ }, [allOptions, searchQuery]);
13994
+ return /* @__PURE__ */ jsxs50(
13995
+ "div",
13996
+ {
13997
+ className: "uf-flex uf-flex-col",
13998
+ style: { minHeight: 0, flex: 1 },
13999
+ children: [
14000
+ /* @__PURE__ */ jsxs50("div", { className: "uf-pb-3", children: [
14001
+ /* @__PURE__ */ jsx57(
14002
+ "style",
14003
+ {
14004
+ dangerouslySetInnerHTML: {
14005
+ __html: `.uf-withdraw-token-search::placeholder { color: ${components.search.placeholderColor}; }`
14006
+ }
14007
+ }
14008
+ ),
14009
+ /* @__PURE__ */ jsxs50("div", { style: { position: "relative" }, children: [
14010
+ /* @__PURE__ */ jsx57(
14011
+ Search,
14012
+ {
14013
+ className: "uf-absolute uf-left-3 uf-top-1/2 uf--translate-y-1/2 uf-w-4 uf-h-4",
14014
+ style: { color: components.search.placeholderColor }
14015
+ }
14016
+ ),
14017
+ /* @__PURE__ */ jsx57(
14018
+ "input",
14019
+ {
14020
+ type: "text",
14021
+ placeholder: "Search token or network",
14022
+ value: searchQuery,
14023
+ onChange: (e) => setSearchQuery(e.target.value),
14024
+ 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",
14025
+ style: {
14026
+ backgroundColor: components.search.backgroundColor,
14027
+ color: components.search.inputColor,
14028
+ fontFamily: fonts.regular,
14029
+ borderRadius: components.input.borderRadius,
14030
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
14031
+ }
14032
+ }
14033
+ )
14034
+ ] })
14035
+ ] }),
14036
+ /* @__PURE__ */ jsx57(
14037
+ "div",
14038
+ {
14039
+ className: "uf-text-xs uf-mb-2",
14040
+ style: {
14041
+ color: components.list.titleSectionColor,
14042
+ fontFamily: fonts.medium
14043
+ },
14044
+ children: t10.selectToken
14045
+ }
14046
+ ),
14047
+ /* @__PURE__ */ jsx57(
14048
+ "div",
14049
+ {
14050
+ className: "uf-flex-1 uf-overflow-y-auto uf-min-h-0 uf--mx-6 uf-px-6 uf-pb-3",
14051
+ style: { scrollbarWidth: "none" },
14052
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx57(
14053
+ "div",
14054
+ {
14055
+ style: {
14056
+ textAlign: "center",
14057
+ padding: "2rem 0",
14058
+ fontSize: 14,
14059
+ color: components.container.subtitleColor,
14060
+ fontFamily: fonts.regular
14061
+ },
14062
+ children: t10.noTokensAvailable
14063
+ }
14064
+ ) : /* @__PURE__ */ jsx57("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: filteredOptions.map(({ token, chain }) => {
14065
+ const key = `${token.symbol}-${chain.chain_type}:${chain.chain_id}`;
14066
+ return /* @__PURE__ */ jsxs50(
14067
+ "button",
14068
+ {
14069
+ type: "button",
14070
+ onClick: () => onSelect(token, chain),
14071
+ onMouseEnter: () => setHoveredKey(key),
14072
+ onMouseLeave: () => setHoveredKey(null),
14073
+ className: "uf-transition-colors",
14074
+ style: {
14075
+ width: "100%",
14076
+ display: "flex",
14077
+ alignItems: "center",
14078
+ gap: 12,
14079
+ padding: 12,
14080
+ borderRadius: 12,
14081
+ border: "none",
14082
+ cursor: "pointer",
14083
+ textAlign: "left",
14084
+ backgroundColor: hoveredKey === key ? colors2.cardHover : "transparent"
14085
+ },
14086
+ children: [
14087
+ /* @__PURE__ */ jsxs50("div", { style: { position: "relative", flexShrink: 0 }, children: [
14088
+ /* @__PURE__ */ jsx57(
14089
+ "img",
14090
+ {
14091
+ src: token.icon_url,
14092
+ alt: token.symbol,
14093
+ width: 40,
14094
+ height: 40,
14095
+ loading: "lazy",
14096
+ className: "uf-rounded-full"
14097
+ }
14098
+ ),
14099
+ /* @__PURE__ */ jsx57(
14100
+ "div",
14101
+ {
14102
+ style: {
14103
+ position: "absolute",
14104
+ bottom: -4,
14105
+ right: -4
14106
+ },
14107
+ children: /* @__PURE__ */ jsx57(
14108
+ "img",
14109
+ {
14110
+ src: chain.icon_url,
14111
+ alt: chain.chain_name,
14112
+ width: 20,
14113
+ height: 20,
14114
+ loading: "lazy",
14115
+ className: "uf-rounded-full uf-border-2"
14116
+ }
14117
+ )
14118
+ }
14119
+ )
14120
+ ] }),
14121
+ /* @__PURE__ */ jsxs50("div", { style: { flex: 1, minWidth: 0 }, children: [
14122
+ /* @__PURE__ */ jsx57(
14123
+ "div",
14124
+ {
14125
+ style: {
14126
+ fontSize: 14,
14127
+ fontWeight: 500,
14128
+ color: components.card.titleColor,
14129
+ fontFamily: fonts.medium
14130
+ },
14131
+ children: token.symbol
14132
+ }
14133
+ ),
14134
+ /* @__PURE__ */ jsxs50(
14135
+ "div",
14136
+ {
14137
+ style: {
14138
+ fontSize: 12,
14139
+ color: components.card.subtitleColor,
14140
+ fontFamily: fonts.regular
14141
+ },
14142
+ children: [
14143
+ token.name,
14144
+ " \u2022 ",
14145
+ chain.chain_name
14146
+ ]
14147
+ }
14148
+ )
14149
+ ] })
14150
+ ]
14151
+ },
14152
+ key
14153
+ );
14154
+ }) })
14155
+ }
14156
+ ),
14157
+ /* @__PURE__ */ jsx57("div", { className: "uf-pt-3 uf-pb-2 uf-shrink-0", children: /* @__PURE__ */ jsx57(
14158
+ PoweredByUnifold,
14159
+ {
14160
+ color: colors2.foregroundMuted,
14161
+ className: "uf-flex uf-justify-center uf-shrink-0"
14162
+ }
14163
+ ) })
14164
+ ]
14165
+ }
14166
+ );
14167
+ }
12093
14168
  export {
12094
14169
  Button,
12095
14170
  BuyWithCard,
@@ -12135,15 +14210,29 @@ export {
12135
14210
  TransferCryptoButton,
12136
14211
  TransferCryptoDoubleInput,
12137
14212
  TransferCryptoSingleInput,
14213
+ WithdrawConfirmingView,
14214
+ WithdrawDoubleInput,
14215
+ WithdrawExecutionItem,
14216
+ WithdrawForm,
14217
+ WithdrawModal,
14218
+ WithdrawTokenSelector,
12138
14219
  buttonVariants,
12139
14220
  cn,
12140
14221
  colors,
12141
14222
  defaultColors,
14223
+ detectBrowserWallet,
12142
14224
  getColors,
12143
14225
  mergeColors,
12144
14226
  resolveComponentTokens,
14227
+ sendEvmWithdraw,
14228
+ sendSolanaWithdraw,
12145
14229
  truncateAddress,
14230
+ useAddressBalance,
12146
14231
  useAllowedCountry,
12147
14232
  useDepositPolling,
12148
- useTheme
14233
+ useSourceTokenValidation,
14234
+ useSupportedDestinationTokens,
14235
+ useTheme,
14236
+ useVerifyRecipientAddress,
14237
+ useWithdrawPolling
12149
14238
  };