@unifold/ui-react 0.1.41 → 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.js CHANGED
@@ -74,17 +74,31 @@ __export(index_exports, {
74
74
  TransferCryptoButton: () => TransferCryptoButton,
75
75
  TransferCryptoDoubleInput: () => TransferCryptoDoubleInput,
76
76
  TransferCryptoSingleInput: () => TransferCryptoSingleInput,
77
+ WithdrawConfirmingView: () => WithdrawConfirmingView,
78
+ WithdrawDoubleInput: () => WithdrawDoubleInput,
79
+ WithdrawExecutionItem: () => WithdrawExecutionItem,
80
+ WithdrawForm: () => WithdrawForm,
81
+ WithdrawModal: () => WithdrawModal,
82
+ WithdrawTokenSelector: () => WithdrawTokenSelector,
77
83
  buttonVariants: () => buttonVariants,
78
84
  cn: () => cn,
79
85
  colors: () => colors,
80
86
  defaultColors: () => defaultColors,
87
+ detectBrowserWallet: () => detectBrowserWallet,
81
88
  getColors: () => getColors,
82
89
  mergeColors: () => mergeColors,
83
90
  resolveComponentTokens: () => resolveComponentTokens,
91
+ sendEvmWithdraw: () => sendEvmWithdraw,
92
+ sendSolanaWithdraw: () => sendSolanaWithdraw,
84
93
  truncateAddress: () => truncateAddress,
94
+ useAddressBalance: () => useAddressBalance,
85
95
  useAllowedCountry: () => useAllowedCountry,
86
96
  useDepositPolling: () => useDepositPolling,
87
- useTheme: () => useTheme
97
+ useSourceTokenValidation: () => useSourceTokenValidation,
98
+ useSupportedDestinationTokens: () => useSupportedDestinationTokens,
99
+ useTheme: () => useTheme,
100
+ useVerifyRecipientAddress: () => useVerifyRecipientAddress,
101
+ useWithdrawPolling: () => useWithdrawPolling
88
102
  });
89
103
  module.exports = __toCommonJS(index_exports);
90
104
 
@@ -693,6 +707,7 @@ function useDepositAddress(params) {
693
707
  destinationChainType,
694
708
  destinationChainId,
695
709
  destinationTokenAddress,
710
+ actionType,
696
711
  enabled = true
697
712
  } = params;
698
713
  return (0, import_react_query.useQuery)({
@@ -704,6 +719,7 @@ function useDepositAddress(params) {
704
719
  destinationChainType ?? null,
705
720
  destinationChainId ?? null,
706
721
  destinationTokenAddress ?? null,
722
+ actionType ?? null,
707
723
  publishableKey
708
724
  ],
709
725
  queryFn: () => (0, import_core.createDepositAddress)(
@@ -712,7 +728,8 @@ function useDepositAddress(params) {
712
728
  recipient_address: recipientAddress,
713
729
  destination_chain_type: destinationChainType,
714
730
  destination_chain_id: destinationChainId,
715
- destination_token_address: destinationTokenAddress
731
+ destination_token_address: destinationTokenAddress,
732
+ action_type: actionType
716
733
  },
717
734
  publishableKey
718
735
  ),
@@ -1426,6 +1443,30 @@ var en_default = {
1426
1443
  youReceive: "You receive",
1427
1444
  intentAddressNote: "The wallet address displayed in the payment provider is a temporary deposit address. Your funds will be automatically converted and deposited into your account."
1428
1445
  }
1446
+ },
1447
+ withdrawModal: {
1448
+ title: "Withdraw",
1449
+ withdrawCrypto: {
1450
+ title: "Withdraw with Crypto",
1451
+ subtitle: "Send to any wallet address"
1452
+ },
1453
+ selectToken: "Select withdrawal token",
1454
+ receiveToken: "Receive token",
1455
+ receiveChain: "Receive chain",
1456
+ recipientAddress: "Recipient address",
1457
+ recipientAddressPlaceholder: "Enter wallet address",
1458
+ amount: "Amount",
1459
+ amountPlaceholder: "0.00",
1460
+ balance: "Balance",
1461
+ minimum: "min",
1462
+ withdraw: "Withdraw",
1463
+ invalidAddress: "Please enter a valid address",
1464
+ invalidAmount: "Please enter a valid amount",
1465
+ verifyingAddress: "Verifying address...",
1466
+ loading: "Loading...",
1467
+ noTokensAvailable: "No tokens available",
1468
+ review: "Review Withdrawal",
1469
+ back: "Back"
1429
1470
  }
1430
1471
  };
1431
1472
 
@@ -1510,7 +1551,7 @@ function useDepositPolling({
1510
1551
  const modalOpenedAt = modalOpenedAtRef.current;
1511
1552
  const poll = async () => {
1512
1553
  try {
1513
- const response = await (0, import_core6.queryExecutions)(userId, publishableKey);
1554
+ const response = await (0, import_core6.queryExecutions)(userId, publishableKey, import_core6.ActionType.Deposit);
1514
1555
  const cutoff = new Date(modalOpenedAt.getTime() - CUTOFF_BUFFER_MS);
1515
1556
  const sortedExecutions = [...response.data].sort((a, b) => {
1516
1557
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
@@ -1646,7 +1687,8 @@ function formatCurrency(currency) {
1646
1687
  }
1647
1688
  function DepositDetailContent({
1648
1689
  execution,
1649
- className
1690
+ className,
1691
+ variant = "deposit"
1650
1692
  }) {
1651
1693
  const { colors: colors2, fonts, components } = useTheme();
1652
1694
  const [chains, setChains] = (0, import_react4.useState)([]);
@@ -2052,7 +2094,7 @@ function DepositDetailContent({
2052
2094
  color: components.card.rowLeftLabel,
2053
2095
  fontFamily: fonts.regular
2054
2096
  },
2055
- children: "Deposit Tx"
2097
+ children: variant === "withdraw" ? "Withdrawal Tx" : "Deposit Tx"
2056
2098
  }
2057
2099
  ),
2058
2100
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -7338,7 +7380,7 @@ function DepositsModal({
7338
7380
  if (!open || !userId) return;
7339
7381
  const fetchExecutions = async () => {
7340
7382
  try {
7341
- const response = await (0, import_core19.queryExecutions)(userId, publishableKey);
7383
+ const response = await (0, import_core19.queryExecutions)(userId, publishableKey, import_core19.ActionType.Deposit);
7342
7384
  const sorted = [...response.data].sort((a, b) => {
7343
7385
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
7344
7386
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -7460,7 +7502,7 @@ function saveRecentToken(token) {
7460
7502
  try {
7461
7503
  const recent = getRecentTokens();
7462
7504
  const filtered = recent.filter(
7463
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7505
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7464
7506
  );
7465
7507
  filtered.unshift(token);
7466
7508
  const trimmed = filtered.slice(0, MAX_RECENT_TOKENS);
@@ -7473,7 +7515,7 @@ function removeRecentToken(token) {
7473
7515
  try {
7474
7516
  const recent = getRecentTokens();
7475
7517
  const filtered = recent.filter(
7476
- (t7) => !(t7.symbol === token.symbol && t7.chainType === token.chainType && t7.chainId === token.chainId)
7518
+ (t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
7477
7519
  );
7478
7520
  localStorage.setItem(STORAGE_KEY, JSON.stringify(filtered));
7479
7521
  return filtered;
@@ -7512,7 +7554,7 @@ function TokenSelectorSheet({
7512
7554
  const addOption = (symbol, chainType, chainId, isRecent) => {
7513
7555
  const key = `${symbol}-${chainType}:${chainId}`;
7514
7556
  if (seen.has(key)) return;
7515
- const tokenData = tokens.find((t7) => t7.symbol === symbol);
7557
+ const tokenData = tokens.find((t11) => t11.symbol === symbol);
7516
7558
  if (!tokenData) return;
7517
7559
  const chainData = tokenData.chains.find(
7518
7560
  (c) => c.chain_type === chainType && c.chain_id === chainId
@@ -7983,35 +8025,35 @@ function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSour
7983
8025
  let selectedChainData;
7984
8026
  const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
7985
8027
  if (defaultSourceTokenAddress && hasChainDefaults) {
7986
- for (const t7 of supportedTokens) {
7987
- const matchingChain = t7.chains.find(
8028
+ for (const t11 of supportedTokens) {
8029
+ const matchingChain = t11.chains.find(
7988
8030
  (c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
7989
8031
  );
7990
8032
  if (matchingChain) {
7991
- selectedTokenData = t7;
8033
+ selectedTokenData = t11;
7992
8034
  selectedChainData = matchingChain;
7993
8035
  break;
7994
8036
  }
7995
8037
  }
7996
8038
  }
7997
8039
  if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
7998
- for (const t7 of supportedTokens) {
7999
- if (t7.symbol !== defaultSourceSymbol) continue;
8000
- const matchedChain = t7.chains.find(
8040
+ for (const t11 of supportedTokens) {
8041
+ if (t11.symbol !== defaultSourceSymbol) continue;
8042
+ const matchedChain = t11.chains.find(
8001
8043
  (c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
8002
8044
  );
8003
8045
  if (matchedChain) {
8004
- selectedTokenData = t7;
8046
+ selectedTokenData = t11;
8005
8047
  selectedChainData = matchedChain;
8006
8048
  break;
8007
8049
  }
8008
8050
  }
8009
8051
  }
8010
8052
  if (!selectedTokenData) {
8011
- for (const t7 of supportedTokens) {
8012
- if (t7.chains.length > 0) {
8013
- selectedTokenData = t7;
8014
- selectedChainData = t7.chains[0];
8053
+ for (const t11 of supportedTokens) {
8054
+ if (t11.chains.length > 0) {
8055
+ selectedTokenData = t11;
8056
+ selectedChainData = t11.chains[0];
8015
8057
  break;
8016
8058
  }
8017
8059
  }
@@ -8060,7 +8102,7 @@ function useDefaultSourceToken({
8060
8102
  ]);
8061
8103
  (0, import_react13.useEffect)(() => {
8062
8104
  if (!supportedTokens.length || !token) return;
8063
- const currentToken = supportedTokens.find((t7) => t7.symbol === token);
8105
+ const currentToken = supportedTokens.find((t11) => t11.symbol === token);
8064
8106
  if (!currentToken || currentToken.chains.length === 0) return;
8065
8107
  const isChainAvailable = chain && currentToken.chains.some((c) => {
8066
8108
  return getChainKey(c.chain_id, c.chain_type) === chain;
@@ -8384,8 +8426,8 @@ function TransferCryptoSingleInput({
8384
8426
  const error = walletsError?.message ?? null;
8385
8427
  const allAvailableChains = (0, import_react15.useMemo)(() => {
8386
8428
  const chainsMap = /* @__PURE__ */ new Map();
8387
- supportedTokens.forEach((t7) => {
8388
- t7.chains.forEach((c) => {
8429
+ supportedTokens.forEach((t11) => {
8430
+ t11.chains.forEach((c) => {
8389
8431
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8390
8432
  if (!chainsMap.has(comboKey)) {
8391
8433
  chainsMap.set(comboKey, c);
@@ -8420,7 +8462,7 @@ function TransferCryptoSingleInput({
8420
8462
  onExecutionsChange(depositExecutions);
8421
8463
  }
8422
8464
  }, [depositExecutions, onExecutionsChange]);
8423
- const selectedToken = token ? supportedTokens.find((t7) => t7.symbol === token) : void 0;
8465
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8424
8466
  const availableChainsForToken = selectedToken?.chains || [];
8425
8467
  const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
8426
8468
  const key = getChainKey2(c.chain_id, c.chain_type);
@@ -8434,7 +8476,7 @@ function TransferCryptoSingleInput({
8434
8476
  setCopied(true);
8435
8477
  setTimeout(() => setCopied(false), 2e3);
8436
8478
  };
8437
- const formatProcessingTime2 = (seconds) => {
8479
+ const formatProcessingTime3 = (seconds) => {
8438
8480
  if (seconds === null) {
8439
8481
  return t4.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
8440
8482
  }
@@ -8643,7 +8685,7 @@ function TransferCryptoSingleInput({
8643
8685
  t4.processingTime.label,
8644
8686
  ":",
8645
8687
  " ",
8646
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
8688
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
8647
8689
  ] })
8648
8690
  ] }),
8649
8691
  detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react16.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react16.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
@@ -8957,8 +8999,8 @@ function TransferCryptoDoubleInput({
8957
8999
  const error = walletsError?.message ?? null;
8958
9000
  const allAvailableChains = (0, import_react16.useMemo)(() => {
8959
9001
  const chainsMap = /* @__PURE__ */ new Map();
8960
- supportedTokens.forEach((t7) => {
8961
- t7.chains.forEach((c) => {
9002
+ supportedTokens.forEach((t11) => {
9003
+ t11.chains.forEach((c) => {
8962
9004
  const comboKey = `${c.chain_type}:${c.chain_id}`;
8963
9005
  if (!chainsMap.has(comboKey)) {
8964
9006
  chainsMap.set(comboKey, c);
@@ -8993,7 +9035,7 @@ function TransferCryptoDoubleInput({
8993
9035
  onExecutionsChange(depositExecutions);
8994
9036
  }
8995
9037
  }, [depositExecutions, onExecutionsChange]);
8996
- const selectedToken = token ? supportedTokens.find((t7) => t7.symbol === token) : void 0;
9038
+ const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
8997
9039
  const availableChainsForToken = selectedToken?.chains || [];
8998
9040
  const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
8999
9041
  const key = getChainKey3(c.chain_id, c.chain_type);
@@ -9007,7 +9049,7 @@ function TransferCryptoDoubleInput({
9007
9049
  setCopied(true);
9008
9050
  setTimeout(() => setCopied(false), 2e3);
9009
9051
  };
9010
- const formatProcessingTime2 = (seconds) => {
9052
+ const formatProcessingTime3 = (seconds) => {
9011
9053
  if (seconds === null) {
9012
9054
  return t5.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
9013
9055
  }
@@ -9234,7 +9276,7 @@ function TransferCryptoDoubleInput({
9234
9276
  t5.processingTime.label,
9235
9277
  ":",
9236
9278
  " ",
9237
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(processingTime) })
9279
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
9238
9280
  ] })
9239
9281
  ] }),
9240
9282
  detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react18.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react18.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
@@ -10308,7 +10350,7 @@ function BrowserWalletModal({
10308
10350
  );
10309
10351
  if (cancelled) return;
10310
10352
  const supportedToken = response.data.find(
10311
- (t7) => t7.symbol.toLowerCase() === token.symbol.toLowerCase()
10353
+ (t11) => t11.symbol.toLowerCase() === token.symbol.toLowerCase()
10312
10354
  );
10313
10355
  if (supportedToken) {
10314
10356
  const chainDetail = supportedToken.chains.find(
@@ -11624,7 +11666,7 @@ function DepositModal({
11624
11666
  if (view !== "tracker" || !userId) return;
11625
11667
  const fetchExecutions = async () => {
11626
11668
  try {
11627
- const response = await (0, import_core23.queryExecutions)(userId, publishableKey);
11669
+ const response = await (0, import_core23.queryExecutions)(userId, publishableKey, import_core23.ActionType.Deposit);
11628
11670
  const sorted = [...response.data].sort((a, b) => {
11629
11671
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
11630
11672
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -12143,6 +12185,1977 @@ function DepositModal({
12143
12185
  }
12144
12186
  ) });
12145
12187
  }
12188
+
12189
+ // src/components/withdrawals/WithdrawModal.tsx
12190
+ var import_react22 = require("react");
12191
+ var import_lucide_react26 = require("lucide-react");
12192
+
12193
+ // src/hooks/use-supported-destination-tokens.ts
12194
+ var import_react_query9 = require("@tanstack/react-query");
12195
+ var import_core24 = require("@unifold/core");
12196
+ function useSupportedDestinationTokens(publishableKey, enabled = true) {
12197
+ return (0, import_react_query9.useQuery)({
12198
+ queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
12199
+ queryFn: () => (0, import_core24.getSupportedDestinationTokens)(publishableKey),
12200
+ staleTime: 1e3 * 60 * 5,
12201
+ gcTime: 1e3 * 60 * 30,
12202
+ refetchOnMount: false,
12203
+ refetchOnWindowFocus: false,
12204
+ enabled
12205
+ });
12206
+ }
12207
+
12208
+ // src/hooks/use-source-token-validation.ts
12209
+ var import_react_query10 = require("@tanstack/react-query");
12210
+ var import_core25 = require("@unifold/core");
12211
+ function useSourceTokenValidation(params) {
12212
+ const {
12213
+ sourceChainType,
12214
+ sourceChainId,
12215
+ sourceTokenAddress,
12216
+ sourceTokenSymbol,
12217
+ publishableKey,
12218
+ enabled = true
12219
+ } = params;
12220
+ const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
12221
+ return (0, import_react_query10.useQuery)({
12222
+ queryKey: [
12223
+ "unifold",
12224
+ "sourceTokenValidation",
12225
+ sourceChainType ?? null,
12226
+ sourceChainId ?? null,
12227
+ sourceTokenAddress ?? null,
12228
+ publishableKey
12229
+ ],
12230
+ queryFn: async () => {
12231
+ const res = await (0, import_core25.getSupportedDepositTokens)(publishableKey);
12232
+ let matchedMinUsd = null;
12233
+ let matchedProcessingTime = null;
12234
+ let matchedSlippage = null;
12235
+ let matchedPriceImpact = null;
12236
+ const found = res.data.some(
12237
+ (token) => token.chains.some((chain) => {
12238
+ const match = chain.chain_type === sourceChainType && chain.chain_id === sourceChainId && chain.token_address.toLowerCase() === sourceTokenAddress.toLowerCase();
12239
+ if (match) {
12240
+ matchedMinUsd = chain.minimum_deposit_amount_usd;
12241
+ matchedProcessingTime = chain.estimated_processing_time;
12242
+ matchedSlippage = chain.max_slippage_percent;
12243
+ matchedPriceImpact = chain.estimated_price_impact_percent;
12244
+ }
12245
+ return match;
12246
+ })
12247
+ );
12248
+ return {
12249
+ isSupported: found,
12250
+ minimumAmountUsd: matchedMinUsd,
12251
+ estimatedProcessingTime: matchedProcessingTime,
12252
+ maxSlippagePercent: matchedSlippage,
12253
+ priceImpactPercent: matchedPriceImpact,
12254
+ errorMessage: found ? null : `${sourceTokenSymbol || "Source token"} is not a supported withdrawal token. Supported tokens include USDC, USDT, and other stablecoins.`
12255
+ };
12256
+ },
12257
+ enabled: enabled && hasParams,
12258
+ staleTime: 1e3 * 60 * 5,
12259
+ gcTime: 1e3 * 60 * 30,
12260
+ refetchOnMount: false,
12261
+ refetchOnWindowFocus: false
12262
+ });
12263
+ }
12264
+
12265
+ // src/hooks/use-address-balance.ts
12266
+ var import_react_query11 = require("@tanstack/react-query");
12267
+ var import_core26 = require("@unifold/core");
12268
+ function useAddressBalance(params) {
12269
+ const {
12270
+ address,
12271
+ chainType,
12272
+ chainId,
12273
+ tokenAddress,
12274
+ publishableKey,
12275
+ enabled = true
12276
+ } = params;
12277
+ const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
12278
+ return (0, import_react_query11.useQuery)({
12279
+ queryKey: [
12280
+ "unifold",
12281
+ "addressBalance",
12282
+ address ?? null,
12283
+ chainType ?? null,
12284
+ chainId ?? null,
12285
+ tokenAddress ?? null,
12286
+ publishableKey
12287
+ ],
12288
+ queryFn: async () => {
12289
+ const res = await (0, import_core26.getAddressBalance)(
12290
+ address,
12291
+ chainType,
12292
+ chainId,
12293
+ tokenAddress,
12294
+ publishableKey
12295
+ );
12296
+ if (res.balance) {
12297
+ const decimals = res.balance.token?.decimals ?? 6;
12298
+ const symbol = res.balance.token?.symbol ?? "";
12299
+ const baseUnit = res.balance.amount;
12300
+ const raw = BigInt(baseUnit);
12301
+ const divisor = BigInt(10 ** decimals);
12302
+ const whole = raw / divisor;
12303
+ const frac = raw % divisor;
12304
+ const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
12305
+ const balanceHuman = fracStr ? `${whole}.${fracStr}` : whole.toString();
12306
+ return {
12307
+ balanceBaseUnit: baseUnit,
12308
+ balanceHuman,
12309
+ balanceUsd: res.balance.amount_usd,
12310
+ exchangeRate: res.balance.exchange_rate,
12311
+ decimals,
12312
+ symbol
12313
+ };
12314
+ }
12315
+ return { balanceBaseUnit: "0", balanceHuman: "0", balanceUsd: "0", exchangeRate: null, decimals: 6, symbol: "" };
12316
+ },
12317
+ enabled: enabled && hasParams,
12318
+ staleTime: 1e3 * 30,
12319
+ gcTime: 1e3 * 60 * 5,
12320
+ refetchInterval: 1e3 * 30,
12321
+ refetchOnMount: "always",
12322
+ refetchOnWindowFocus: false
12323
+ });
12324
+ }
12325
+
12326
+ // src/hooks/use-executions.ts
12327
+ var import_react_query12 = require("@tanstack/react-query");
12328
+ var import_core27 = require("@unifold/core");
12329
+ function useExecutions(userId, publishableKey, options) {
12330
+ const actionType = options?.actionType ?? import_core27.ActionType.Deposit;
12331
+ return (0, import_react_query12.useQuery)({
12332
+ queryKey: ["unifold", "executions", actionType, userId, publishableKey],
12333
+ queryFn: () => (0, import_core27.queryExecutions)(userId, publishableKey, actionType),
12334
+ enabled: (options?.enabled ?? true) && !!userId,
12335
+ refetchInterval: options?.refetchInterval ?? 3e3,
12336
+ staleTime: 0,
12337
+ gcTime: 1e3 * 60 * 5,
12338
+ refetchOnWindowFocus: false
12339
+ });
12340
+ }
12341
+
12342
+ // src/hooks/use-withdraw-polling.ts
12343
+ var import_react19 = require("react");
12344
+ var import_core28 = require("@unifold/core");
12345
+ var POLL_INTERVAL_MS2 = 2500;
12346
+ var POLL_ENDPOINT_INTERVAL_MS2 = 3e3;
12347
+ var CUTOFF_BUFFER_MS2 = 6e4;
12348
+ function useWithdrawPolling({
12349
+ userId,
12350
+ publishableKey,
12351
+ depositWalletId,
12352
+ enabled = false,
12353
+ onWithdrawSuccess,
12354
+ onWithdrawError
12355
+ }) {
12356
+ const [executions, setExecutions] = (0, import_react19.useState)([]);
12357
+ const [isPolling, setIsPolling] = (0, import_react19.useState)(false);
12358
+ const enabledAtRef = (0, import_react19.useRef)(/* @__PURE__ */ new Date());
12359
+ const trackedRef = (0, import_react19.useRef)(/* @__PURE__ */ new Map());
12360
+ const prevEnabledRef = (0, import_react19.useRef)(false);
12361
+ const onSuccessRef = (0, import_react19.useRef)(onWithdrawSuccess);
12362
+ const onErrorRef = (0, import_react19.useRef)(onWithdrawError);
12363
+ (0, import_react19.useEffect)(() => {
12364
+ onSuccessRef.current = onWithdrawSuccess;
12365
+ }, [onWithdrawSuccess]);
12366
+ (0, import_react19.useEffect)(() => {
12367
+ onErrorRef.current = onWithdrawError;
12368
+ }, [onWithdrawError]);
12369
+ (0, import_react19.useEffect)(() => {
12370
+ if (enabled && !prevEnabledRef.current) {
12371
+ enabledAtRef.current = /* @__PURE__ */ new Date();
12372
+ trackedRef.current.clear();
12373
+ }
12374
+ if (!enabled) {
12375
+ trackedRef.current.clear();
12376
+ }
12377
+ prevEnabledRef.current = enabled;
12378
+ }, [enabled]);
12379
+ (0, import_react19.useEffect)(() => {
12380
+ if (!userId || !enabled) return;
12381
+ const enabledAt = enabledAtRef.current;
12382
+ const poll = async () => {
12383
+ try {
12384
+ const response = await (0, import_core28.queryExecutions)(userId, publishableKey, import_core28.ActionType.Withdraw);
12385
+ const cutoff = new Date(enabledAt.getTime() - CUTOFF_BUFFER_MS2);
12386
+ const sorted = [...response.data].sort((a, b) => {
12387
+ const tA = a.created_at ? new Date(a.created_at).getTime() : 0;
12388
+ const tB = b.created_at ? new Date(b.created_at).getTime() : 0;
12389
+ return tB - tA;
12390
+ });
12391
+ const inProgress = [import_core28.ExecutionStatus.PENDING, import_core28.ExecutionStatus.WAITING, import_core28.ExecutionStatus.DELAYED];
12392
+ const terminal = [import_core28.ExecutionStatus.SUCCEEDED, import_core28.ExecutionStatus.FAILED];
12393
+ let target = null;
12394
+ for (const ex of sorted) {
12395
+ const t11 = ex.created_at ? new Date(ex.created_at) : null;
12396
+ if (!t11 || t11 < cutoff) continue;
12397
+ const prev = trackedRef.current.get(ex.id);
12398
+ if (!prev) {
12399
+ target = ex;
12400
+ break;
12401
+ }
12402
+ if (inProgress.includes(prev) && terminal.includes(ex.status)) {
12403
+ target = ex;
12404
+ break;
12405
+ }
12406
+ }
12407
+ if (target) {
12408
+ const ex = target;
12409
+ const exTime = ex.created_at ? new Date(ex.created_at) : null;
12410
+ if (!exTime || exTime < enabledAtRef.current) return;
12411
+ const prev = trackedRef.current.get(ex.id);
12412
+ trackedRef.current.set(ex.id, ex.status);
12413
+ setExecutions((list) => {
12414
+ const idx = list.findIndex((e) => e.id === ex.id);
12415
+ if (idx >= 0) {
12416
+ const u = [...list];
12417
+ u[idx] = ex;
12418
+ return u;
12419
+ }
12420
+ return [...list, ex];
12421
+ });
12422
+ if (ex.status === import_core28.ExecutionStatus.SUCCEEDED && (!prev || inProgress.includes(prev))) {
12423
+ onSuccessRef.current?.({ message: "Withdrawal completed successfully", executionId: ex.id, transaction: ex });
12424
+ } else if (ex.status === import_core28.ExecutionStatus.FAILED && prev !== import_core28.ExecutionStatus.FAILED) {
12425
+ onErrorRef.current?.({ message: "Withdrawal failed", code: "WITHDRAW_FAILED", error: ex });
12426
+ }
12427
+ }
12428
+ } catch (error) {
12429
+ console.error("Failed to fetch withdraw executions:", error);
12430
+ onErrorRef.current?.({ message: "Failed to fetch withdrawal status", code: "POLLING_ERROR", error });
12431
+ }
12432
+ };
12433
+ void poll();
12434
+ const interval = setInterval(poll, POLL_INTERVAL_MS2);
12435
+ setIsPolling(true);
12436
+ return () => {
12437
+ clearInterval(interval);
12438
+ setIsPolling(false);
12439
+ };
12440
+ }, [userId, publishableKey, enabled]);
12441
+ (0, import_react19.useEffect)(() => {
12442
+ if (!enabled || !depositWalletId) return;
12443
+ const trigger = async () => {
12444
+ try {
12445
+ await (0, import_core28.pollDirectExecutions)({ deposit_wallet_id: depositWalletId }, publishableKey);
12446
+ } catch {
12447
+ }
12448
+ };
12449
+ trigger();
12450
+ const interval = setInterval(trigger, POLL_ENDPOINT_INTERVAL_MS2);
12451
+ return () => clearInterval(interval);
12452
+ }, [enabled, depositWalletId, publishableKey]);
12453
+ return { executions, isPolling };
12454
+ }
12455
+
12456
+ // src/components/withdrawals/WithdrawDoubleInput.tsx
12457
+ var import_jsx_runtime52 = require("react/jsx-runtime");
12458
+ var t7 = i18n.withdrawModal;
12459
+ var getChainKey4 = (chainId, chainType) => `${chainType}:${chainId}`;
12460
+ function WithdrawDoubleInput({
12461
+ tokens,
12462
+ selectedTokenSymbol,
12463
+ selectedChainKey,
12464
+ onTokenChange,
12465
+ onChainChange,
12466
+ isLoading = false
12467
+ }) {
12468
+ const { fonts, components } = useTheme();
12469
+ const isDarkMode = useTheme().themeClass.includes("uf-dark");
12470
+ const selectedToken = selectedTokenSymbol ? tokens.find((t11) => t11.symbol === selectedTokenSymbol) : void 0;
12471
+ const availableChainsForToken = selectedToken?.chains || [];
12472
+ const renderTokenItem = (tokenData) => /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
12473
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12474
+ "img",
12475
+ {
12476
+ src: tokenData.icon_url,
12477
+ alt: tokenData.symbol,
12478
+ width: 20,
12479
+ height: 20,
12480
+ loading: "lazy",
12481
+ className: "uf-rounded-full uf-flex-shrink-0"
12482
+ }
12483
+ ),
12484
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "uf-text-xs uf-font-normal", children: tokenData.symbol })
12485
+ ] });
12486
+ const renderChainItem = (chainData) => /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
12487
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12488
+ "img",
12489
+ {
12490
+ src: chainData.icon_url,
12491
+ alt: chainData.chain_name,
12492
+ width: 20,
12493
+ height: 20,
12494
+ loading: "lazy",
12495
+ className: "uf-rounded-full uf-flex-shrink-0"
12496
+ }
12497
+ ),
12498
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "uf-text-xs uf-font-normal", children: chainData.chain_name })
12499
+ ] });
12500
+ const currentChainData = selectedChainKey ? availableChainsForToken.find(
12501
+ (c) => getChainKey4(c.chain_id, c.chain_type) === selectedChainKey
12502
+ ) : void 0;
12503
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-grid uf-grid-cols-2 uf-gap-2.5", children: [
12504
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { children: [
12505
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12506
+ "div",
12507
+ {
12508
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
12509
+ style: { color: components.card.labelColor },
12510
+ children: t7.receiveToken
12511
+ }
12512
+ ),
12513
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
12514
+ Select,
12515
+ {
12516
+ value: selectedTokenSymbol ?? "",
12517
+ onValueChange: onTokenChange,
12518
+ disabled: isLoading || tokens.length === 0,
12519
+ children: [
12520
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12521
+ SelectTrigger,
12522
+ {
12523
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
12524
+ style: {
12525
+ backgroundColor: components.card.backgroundColor,
12526
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
12527
+ },
12528
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SelectValue, { children: isLoading || !selectedTokenSymbol ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "uf-text-xs uf-font-normal", children: selectedTokenSymbol }) })
12529
+ }
12530
+ ),
12531
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12532
+ SelectContent,
12533
+ {
12534
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]",
12535
+ style: {
12536
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
12537
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
12538
+ },
12539
+ children: tokens.map((tokenData) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12540
+ SelectItem,
12541
+ {
12542
+ value: tokenData.symbol,
12543
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
12544
+ children: renderTokenItem(tokenData)
12545
+ },
12546
+ tokenData.symbol
12547
+ ))
12548
+ }
12549
+ )
12550
+ ]
12551
+ }
12552
+ )
12553
+ ] }),
12554
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { children: [
12555
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12556
+ "div",
12557
+ {
12558
+ className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
12559
+ style: { color: components.card.labelColor },
12560
+ children: t7.receiveChain
12561
+ }
12562
+ ),
12563
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
12564
+ Select,
12565
+ {
12566
+ value: selectedChainKey ?? "",
12567
+ onValueChange: onChainChange,
12568
+ disabled: isLoading || availableChainsForToken.length === 0,
12569
+ children: [
12570
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12571
+ SelectTrigger,
12572
+ {
12573
+ className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
12574
+ style: {
12575
+ backgroundColor: components.card.backgroundColor,
12576
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
12577
+ },
12578
+ children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SelectValue, { children: isLoading || !selectedChainKey ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "uf-text-xs uf-font-normal", children: selectedChainKey }) })
12579
+ }
12580
+ ),
12581
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12582
+ SelectContent,
12583
+ {
12584
+ align: "end",
12585
+ className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
12586
+ style: {
12587
+ border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
12588
+ ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
12589
+ },
12590
+ children: availableChainsForToken.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-px-2 uf-py-3 uf-text-xs uf-text-muted-foreground uf-text-center", children: "No chains available" }) : availableChainsForToken.map((chainData) => {
12591
+ const chainKey = getChainKey4(chainData.chain_id, chainData.chain_type);
12592
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
12593
+ SelectItem,
12594
+ {
12595
+ value: chainKey,
12596
+ className: "focus:uf-bg-accent focus:uf-text-foreground",
12597
+ children: renderChainItem(chainData)
12598
+ },
12599
+ chainKey
12600
+ );
12601
+ })
12602
+ }
12603
+ )
12604
+ ]
12605
+ }
12606
+ )
12607
+ ] })
12608
+ ] });
12609
+ }
12610
+
12611
+ // src/components/withdrawals/WithdrawForm.tsx
12612
+ var import_react20 = require("react");
12613
+ var import_lucide_react24 = require("lucide-react");
12614
+
12615
+ // src/hooks/use-verify-recipient-address.ts
12616
+ var import_react_query13 = require("@tanstack/react-query");
12617
+ var import_core29 = require("@unifold/core");
12618
+ function useVerifyRecipientAddress(params) {
12619
+ const {
12620
+ chainType,
12621
+ chainId,
12622
+ tokenAddress,
12623
+ recipientAddress,
12624
+ publishableKey,
12625
+ enabled = true
12626
+ } = params;
12627
+ const trimmedAddress = recipientAddress?.trim() || "";
12628
+ const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
12629
+ return (0, import_react_query13.useQuery)({
12630
+ queryKey: [
12631
+ "unifold",
12632
+ "verifyRecipientAddress",
12633
+ chainType ?? null,
12634
+ chainId ?? null,
12635
+ tokenAddress ?? null,
12636
+ trimmedAddress,
12637
+ publishableKey
12638
+ ],
12639
+ queryFn: () => (0, import_core29.verifyRecipientAddress)(
12640
+ {
12641
+ chain_type: chainType,
12642
+ chain_id: chainId,
12643
+ token_address: tokenAddress,
12644
+ recipient_address: trimmedAddress
12645
+ },
12646
+ publishableKey
12647
+ ),
12648
+ enabled: enabled && hasAllParams,
12649
+ staleTime: 1e3 * 60 * 5,
12650
+ gcTime: 1e3 * 60 * 30,
12651
+ retry: 1,
12652
+ refetchOnMount: false,
12653
+ refetchOnWindowFocus: false
12654
+ });
12655
+ }
12656
+
12657
+ // src/components/withdrawals/send-withdraw.ts
12658
+ var import_core30 = require("@unifold/core");
12659
+ async function sendEvmWithdraw(params) {
12660
+ const {
12661
+ provider,
12662
+ fromAddress,
12663
+ depositWalletAddress,
12664
+ sourceTokenAddress,
12665
+ sourceChainId,
12666
+ amountBaseUnit
12667
+ } = params;
12668
+ const currentChainIdHex = await provider.request({
12669
+ method: "eth_chainId",
12670
+ params: []
12671
+ });
12672
+ const currentChainId = parseInt(currentChainIdHex, 16).toString();
12673
+ if (currentChainId !== sourceChainId) {
12674
+ const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
12675
+ try {
12676
+ await provider.request({
12677
+ method: "wallet_switchEthereumChain",
12678
+ params: [{ chainId: requiredHex }]
12679
+ });
12680
+ const newHex = await provider.request({ method: "eth_chainId", params: [] });
12681
+ if (parseInt(newHex, 16).toString() !== sourceChainId) {
12682
+ throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
12683
+ }
12684
+ } catch (err) {
12685
+ if (err && typeof err === "object" && "code" in err) {
12686
+ const e = err;
12687
+ if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
12688
+ if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
12689
+ }
12690
+ throw err;
12691
+ }
12692
+ }
12693
+ const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
12694
+ const amountBig = BigInt(amountBaseUnit);
12695
+ const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
12696
+ from: fromAddress,
12697
+ to: sourceTokenAddress,
12698
+ data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
12699
+ };
12700
+ let gasEstimate;
12701
+ try {
12702
+ const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
12703
+ gasEstimate = BigInt(hex);
12704
+ } catch {
12705
+ gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
12706
+ }
12707
+ const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
12708
+ const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
12709
+ const gasCost = gasWithBuffer * gasPrice;
12710
+ const ethBalance = BigInt(
12711
+ await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
12712
+ );
12713
+ const totalRequired = isNative ? gasCost + amountBig : gasCost;
12714
+ if (ethBalance < totalRequired) {
12715
+ const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
12716
+ if (isNative) {
12717
+ throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
12718
+ }
12719
+ throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
12720
+ }
12721
+ const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
12722
+ return txHash;
12723
+ }
12724
+ async function sendSolanaWithdraw(params) {
12725
+ const {
12726
+ provider,
12727
+ fromAddress,
12728
+ depositWalletAddress,
12729
+ sourceTokenAddress,
12730
+ amountBaseUnit,
12731
+ publishableKey
12732
+ } = params;
12733
+ if (!provider.publicKey) {
12734
+ await provider.connect();
12735
+ }
12736
+ const buildResponse = await (0, import_core30.buildSolanaTransaction)(
12737
+ {
12738
+ chain_id: "mainnet",
12739
+ token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
12740
+ source_address: fromAddress,
12741
+ destination_address: depositWalletAddress,
12742
+ amount: amountBaseUnit
12743
+ },
12744
+ publishableKey
12745
+ );
12746
+ const { VersionedTransaction } = await import(
12747
+ /* @vite-ignore */
12748
+ "@solana/web3.js"
12749
+ );
12750
+ const binaryString = atob(buildResponse.transaction);
12751
+ const bytes = new Uint8Array(binaryString.length);
12752
+ for (let i = 0; i < binaryString.length; i++) {
12753
+ bytes[i] = binaryString.charCodeAt(i);
12754
+ }
12755
+ const transaction = VersionedTransaction.deserialize(bytes);
12756
+ const signedTransaction = await provider.signTransaction(transaction);
12757
+ const serialized = signedTransaction.serialize();
12758
+ let binaryStr = "";
12759
+ for (let i = 0; i < serialized.length; i++) {
12760
+ binaryStr += String.fromCharCode(serialized[i]);
12761
+ }
12762
+ const sendResponse = await (0, import_core30.sendSolanaTransaction)(
12763
+ { chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
12764
+ publishableKey
12765
+ );
12766
+ return sendResponse.signature;
12767
+ }
12768
+ async function detectBrowserWallet(chainType, senderAddress) {
12769
+ const win = typeof window !== "undefined" ? window : null;
12770
+ if (!win || !senderAddress) return null;
12771
+ const anyWin = win;
12772
+ if (chainType === "solana") {
12773
+ const solProviders = [];
12774
+ if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
12775
+ if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
12776
+ if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
12777
+ if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
12778
+ for (const { provider, name } of solProviders) {
12779
+ if (!provider) continue;
12780
+ try {
12781
+ let addr;
12782
+ if (provider.isConnected && provider.publicKey) {
12783
+ addr = provider.publicKey.toString();
12784
+ } else {
12785
+ const resp = await provider.connect({ onlyIfTrusted: true });
12786
+ if (resp?.publicKey) addr = resp.publicKey.toString();
12787
+ }
12788
+ if (addr && addr === senderAddress) {
12789
+ return { chainFamily: "solana", provider, name, address: addr };
12790
+ }
12791
+ } catch {
12792
+ }
12793
+ }
12794
+ }
12795
+ if (chainType === "ethereum") {
12796
+ const evmProviders = [];
12797
+ const seen = /* @__PURE__ */ new Set();
12798
+ const add = (p, name) => {
12799
+ if (p && typeof p.request === "function" && !seen.has(p)) {
12800
+ seen.add(p);
12801
+ evmProviders.push({ provider: p, name });
12802
+ }
12803
+ };
12804
+ add(anyWin.phantom?.ethereum, "Phantom");
12805
+ add(anyWin.coinbaseWalletExtension, "Coinbase");
12806
+ add(anyWin.trustwallet?.ethereum, "Trust Wallet");
12807
+ add(anyWin.okxwallet, "OKX Wallet");
12808
+ if (anyWin.__eip6963Providers) {
12809
+ for (const detail of anyWin.__eip6963Providers) {
12810
+ const rdns = detail.info?.rdns || "";
12811
+ let name = detail.info?.name || "Wallet";
12812
+ if (rdns.includes("metamask")) name = "MetaMask";
12813
+ else if (rdns.includes("rabby")) name = "Rabby";
12814
+ else if (rdns.includes("rainbow")) name = "Rainbow";
12815
+ add(detail.provider, name);
12816
+ }
12817
+ }
12818
+ if (win.ethereum) {
12819
+ const eth = win.ethereum;
12820
+ let name = "Wallet";
12821
+ if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
12822
+ else if (eth.isRabby) name = "Rabby";
12823
+ else if (eth.isRainbow) name = "Rainbow";
12824
+ else if (eth.isCoinbaseWallet) name = "Coinbase";
12825
+ add(eth, name);
12826
+ }
12827
+ for (const { provider, name } of evmProviders) {
12828
+ try {
12829
+ const accounts = await provider.request({ method: "eth_accounts" });
12830
+ if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
12831
+ return { chainFamily: "evm", provider, name, address: accounts[0] };
12832
+ }
12833
+ } catch {
12834
+ }
12835
+ }
12836
+ }
12837
+ return null;
12838
+ }
12839
+
12840
+ // src/components/withdrawals/WithdrawForm.tsx
12841
+ var import_jsx_runtime53 = require("react/jsx-runtime");
12842
+ var t8 = i18n.withdrawModal;
12843
+ var tCrypto = i18n.transferCrypto;
12844
+ function formatProcessingTime2(seconds) {
12845
+ if (seconds === null) {
12846
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
12847
+ }
12848
+ const minutes = Math.ceil(seconds / 60);
12849
+ if (minutes < 60) {
12850
+ return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", String(minutes));
12851
+ }
12852
+ const hours = Math.ceil(minutes / 60);
12853
+ return tCrypto.processingTime.lessThanHours.replace("{{hours}}", String(hours));
12854
+ }
12855
+ function computeBaseUnit(balanceBaseUnit, inputAmount, balanceAmount) {
12856
+ if (balanceAmount <= 0 || inputAmount <= 0) return "0";
12857
+ if (inputAmount >= balanceAmount) return balanceBaseUnit;
12858
+ const PRECISION = 10n ** 18n;
12859
+ const ratioScaled = BigInt(Math.round(inputAmount / balanceAmount * Number(PRECISION)));
12860
+ const result = BigInt(balanceBaseUnit) * ratioScaled / PRECISION;
12861
+ return result.toString();
12862
+ }
12863
+ function toSafeDecimalString(n, maxDecimals) {
12864
+ if (n === 0) return "0";
12865
+ return n.toFixed(maxDecimals).replace(/\.?0+$/, "");
12866
+ }
12867
+ function WithdrawForm({
12868
+ publishableKey,
12869
+ externalUserId,
12870
+ sourceChainType,
12871
+ selectedToken,
12872
+ selectedChain,
12873
+ sourceTokenSymbol,
12874
+ recipientAddressProp,
12875
+ balanceData,
12876
+ isLoadingBalance,
12877
+ minimumWithdrawAmountUsd,
12878
+ estimatedProcessingTime,
12879
+ maxSlippagePercent,
12880
+ priceImpactPercent,
12881
+ detectedWallet,
12882
+ sourceChainId,
12883
+ sourceTokenAddress,
12884
+ isWalletMatch,
12885
+ connectedWalletName,
12886
+ canWithdraw,
12887
+ onWithdraw,
12888
+ onWithdrawError,
12889
+ onDepositWalletCreation,
12890
+ onWithdrawSubmitted,
12891
+ footerLeft
12892
+ }) {
12893
+ const { colors: colors2, fonts, components } = useTheme();
12894
+ const [recipientAddress, setRecipientAddress] = (0, import_react20.useState)(recipientAddressProp || "");
12895
+ const [amount, setAmount] = (0, import_react20.useState)("");
12896
+ const [inputUnit, setInputUnit] = (0, import_react20.useState)("crypto");
12897
+ const [isSubmitting, setIsSubmitting] = (0, import_react20.useState)(false);
12898
+ const [submitError, setSubmitError] = (0, import_react20.useState)(null);
12899
+ const [detailsExpanded, setDetailsExpanded] = (0, import_react20.useState)(false);
12900
+ const [glossaryOpen, setGlossaryOpen] = (0, import_react20.useState)(false);
12901
+ (0, import_react20.useEffect)(() => {
12902
+ setRecipientAddress(recipientAddressProp || "");
12903
+ setAmount("");
12904
+ setInputUnit("crypto");
12905
+ setSubmitError(null);
12906
+ }, [recipientAddressProp]);
12907
+ const trimmedAddress = recipientAddress.trim();
12908
+ const [debouncedAddress, setDebouncedAddress] = (0, import_react20.useState)(trimmedAddress);
12909
+ (0, import_react20.useEffect)(() => {
12910
+ const id = setTimeout(() => setDebouncedAddress(trimmedAddress), 500);
12911
+ return () => clearTimeout(id);
12912
+ }, [trimmedAddress]);
12913
+ const {
12914
+ data: addressVerification,
12915
+ isLoading: isVerifyingAddress,
12916
+ error: verifyError
12917
+ } = useVerifyRecipientAddress({
12918
+ chainType: selectedChain?.chain_type,
12919
+ chainId: selectedChain?.chain_id,
12920
+ tokenAddress: selectedChain?.token_address,
12921
+ recipientAddress: debouncedAddress,
12922
+ publishableKey,
12923
+ enabled: debouncedAddress.length > 5 && !!selectedChain
12924
+ });
12925
+ const isDebouncing = trimmedAddress !== debouncedAddress;
12926
+ const addressError = (0, import_react20.useMemo)(() => {
12927
+ if (!trimmedAddress || trimmedAddress.length <= 5) return null;
12928
+ if (isDebouncing || isVerifyingAddress) return null;
12929
+ if (verifyError) return t8.invalidAddress;
12930
+ if (addressVerification && !addressVerification.valid) {
12931
+ if (addressVerification.failure_code === "account_not_found")
12932
+ return `Account not found on ${selectedChain?.chain_name}`;
12933
+ if (addressVerification.failure_code === "not_opted_in")
12934
+ return `Recipient has not opted in to ${selectedToken?.symbol} on ${selectedChain?.chain_name}`;
12935
+ return t8.invalidAddress;
12936
+ }
12937
+ return null;
12938
+ }, [trimmedAddress, isDebouncing, isVerifyingAddress, verifyError, addressVerification, selectedChain, selectedToken]);
12939
+ const isAddressValid = !isDebouncing && !!addressVerification?.valid && !addressError;
12940
+ const exchangeRate = (0, import_react20.useMemo)(() => {
12941
+ if (!balanceData?.exchangeRate) return 0;
12942
+ return parseFloat(balanceData.exchangeRate);
12943
+ }, [balanceData]);
12944
+ const balanceCrypto = (0, import_react20.useMemo)(() => {
12945
+ if (!balanceData?.balanceHuman) return 0;
12946
+ return parseFloat(balanceData.balanceHuman);
12947
+ }, [balanceData]);
12948
+ const balanceUsdNum = (0, import_react20.useMemo)(() => {
12949
+ if (!balanceData?.balanceUsd) return 0;
12950
+ return parseFloat(balanceData.balanceUsd);
12951
+ }, [balanceData]);
12952
+ const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
12953
+ const sourceDecimals = balanceData?.decimals ?? 6;
12954
+ const cryptoAmountFromInput = (0, import_react20.useMemo)(() => {
12955
+ const val = parseFloat(amount);
12956
+ if (!val || val <= 0) return 0;
12957
+ if (inputUnit === "crypto") return val;
12958
+ return exchangeRate > 0 ? val / exchangeRate : 0;
12959
+ }, [amount, inputUnit, exchangeRate]);
12960
+ const fiatAmountFromInput = (0, import_react20.useMemo)(() => {
12961
+ const val = parseFloat(amount);
12962
+ if (!val || val <= 0) return 0;
12963
+ if (inputUnit === "fiat") return val;
12964
+ return val * exchangeRate;
12965
+ }, [amount, inputUnit, exchangeRate]);
12966
+ const convertedDisplay = (0, import_react20.useMemo)(() => {
12967
+ if (!amount || parseFloat(amount) <= 0) return null;
12968
+ if (inputUnit === "crypto") {
12969
+ return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
12970
+ }
12971
+ return `${cryptoAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 6 })} ${tokenSymbol}`;
12972
+ }, [amount, inputUnit, fiatAmountFromInput, cryptoAmountFromInput, tokenSymbol]);
12973
+ const balanceDisplay = (0, import_react20.useMemo)(() => {
12974
+ if (isLoadingBalance || !balanceData) return null;
12975
+ if (inputUnit === "crypto") {
12976
+ return `${balanceCrypto.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${tokenSymbol}`;
12977
+ }
12978
+ return `$${balanceUsdNum.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
12979
+ }, [isLoadingBalance, balanceData, inputUnit, balanceCrypto, balanceUsdNum, tokenSymbol]);
12980
+ const handleSwitchUnit = (0, import_react20.useCallback)(() => {
12981
+ const val = parseFloat(amount);
12982
+ if (!val || val <= 0 || exchangeRate <= 0) {
12983
+ setInputUnit((u) => u === "crypto" ? "fiat" : "crypto");
12984
+ setAmount("");
12985
+ return;
12986
+ }
12987
+ if (inputUnit === "crypto") {
12988
+ const fiat = val * exchangeRate;
12989
+ setAmount(fiat.toFixed(2));
12990
+ setInputUnit("fiat");
12991
+ } else {
12992
+ const crypto = val / exchangeRate;
12993
+ setAmount(crypto.toFixed(sourceDecimals > 6 ? 6 : sourceDecimals));
12994
+ setInputUnit("crypto");
12995
+ }
12996
+ }, [amount, inputUnit, exchangeRate, sourceDecimals]);
12997
+ const handleMaxClick = (0, import_react20.useCallback)(() => {
12998
+ if (inputUnit === "crypto") {
12999
+ if (balanceCrypto <= 0) return;
13000
+ setAmount(balanceData?.balanceHuman ?? "0");
13001
+ } else {
13002
+ if (balanceUsdNum <= 0) return;
13003
+ setAmount((Math.floor(balanceUsdNum * 100) / 100).toFixed(2));
13004
+ }
13005
+ }, [inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
13006
+ const isBelowMinimum = minimumWithdrawAmountUsd !== null && fiatAmountFromInput > 0 && fiatAmountFromInput < minimumWithdrawAmountUsd;
13007
+ const isOverBalance = inputUnit === "crypto" ? cryptoAmountFromInput > 0 && balanceCrypto > 0 && cryptoAmountFromInput > balanceCrypto : fiatAmountFromInput > 0 && balanceUsdNum > 0 && fiatAmountFromInput > balanceUsdNum;
13008
+ const isFormValid = trimmedAddress.length > 0 && amount.trim().length > 0 && cryptoAmountFromInput > 0 && isAddressValid && !isBelowMinimum && !isOverBalance && !!balanceData;
13009
+ const handleWithdraw = (0, import_react20.useCallback)(async () => {
13010
+ if (!selectedToken || !selectedChain) return;
13011
+ if (!isFormValid) return;
13012
+ setIsSubmitting(true);
13013
+ setSubmitError(null);
13014
+ try {
13015
+ const depositWallet = await onDepositWalletCreation({
13016
+ destinationChainType: selectedChain.chain_type,
13017
+ destinationChainId: selectedChain.chain_id,
13018
+ destinationTokenAddress: selectedChain.token_address,
13019
+ recipientAddress: trimmedAddress
13020
+ });
13021
+ const amountBaseUnit = computeBaseUnit(
13022
+ balanceData.balanceBaseUnit,
13023
+ parseFloat(amount),
13024
+ inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
13025
+ );
13026
+ const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
13027
+ const txInfo = {
13028
+ sourceChainType,
13029
+ sourceChainId,
13030
+ sourceTokenAddress,
13031
+ sourceTokenSymbol: tokenSymbol,
13032
+ destinationChainType: selectedChain.chain_type,
13033
+ destinationChainId: selectedChain.chain_id,
13034
+ destinationTokenAddress: selectedChain.token_address,
13035
+ destinationTokenSymbol: selectedToken.symbol,
13036
+ amount: humanAmount,
13037
+ amountBaseUnit,
13038
+ withdrawIntentAddress: depositWallet.address,
13039
+ recipientAddress: trimmedAddress
13040
+ };
13041
+ if (detectedWallet) {
13042
+ if (detectedWallet.chainFamily === "evm") {
13043
+ await sendEvmWithdraw({
13044
+ provider: detectedWallet.provider,
13045
+ fromAddress: detectedWallet.address,
13046
+ depositWalletAddress: depositWallet.address,
13047
+ sourceTokenAddress,
13048
+ sourceChainId,
13049
+ amountBaseUnit
13050
+ });
13051
+ } else if (detectedWallet.chainFamily === "solana") {
13052
+ await sendSolanaWithdraw({
13053
+ provider: detectedWallet.provider,
13054
+ fromAddress: detectedWallet.address,
13055
+ depositWalletAddress: depositWallet.address,
13056
+ sourceTokenAddress,
13057
+ amountBaseUnit,
13058
+ publishableKey
13059
+ });
13060
+ }
13061
+ } else if (onWithdraw) {
13062
+ await onWithdraw(txInfo);
13063
+ } else {
13064
+ throw new Error("No withdrawal method available. Please connect a wallet.");
13065
+ }
13066
+ onWithdrawSubmitted?.(txInfo);
13067
+ } catch (err) {
13068
+ const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
13069
+ setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
13070
+ onWithdrawError?.({
13071
+ message: raw,
13072
+ error: err,
13073
+ code: "WITHDRAW_FAILED"
13074
+ });
13075
+ } finally {
13076
+ setIsSubmitting(false);
13077
+ }
13078
+ }, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
13079
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
13080
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
13081
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13082
+ "div",
13083
+ {
13084
+ className: "uf-text-xs uf-mb-1.5",
13085
+ style: { color: components.card.labelColor, fontFamily: fonts.medium },
13086
+ children: t8.recipientAddress
13087
+ }
13088
+ ),
13089
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13090
+ "style",
13091
+ {
13092
+ dangerouslySetInnerHTML: {
13093
+ __html: `.uf-withdraw-addr::placeholder { color: ${components.search.placeholderColor}; }`
13094
+ }
13095
+ }
13096
+ ),
13097
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
13098
+ "div",
13099
+ {
13100
+ className: "uf-flex uf-items-center uf-gap-1 uf-pr-2",
13101
+ style: {
13102
+ backgroundColor: components.search.backgroundColor,
13103
+ borderRadius: components.input.borderRadius,
13104
+ border: `${components.input.borderWidth}px solid ${addressError ? colors2.error : components.input.borderColor}`
13105
+ },
13106
+ children: [
13107
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13108
+ "input",
13109
+ {
13110
+ type: "text",
13111
+ placeholder: t8.recipientAddressPlaceholder,
13112
+ value: recipientAddress,
13113
+ onChange: (e) => {
13114
+ setRecipientAddress(e.target.value);
13115
+ setSubmitError(null);
13116
+ },
13117
+ 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",
13118
+ style: {
13119
+ color: components.search.inputColor,
13120
+ fontFamily: fonts.regular
13121
+ }
13122
+ }
13123
+ ),
13124
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13125
+ "button",
13126
+ {
13127
+ type: "button",
13128
+ onClick: async () => {
13129
+ try {
13130
+ const text = await navigator.clipboard.readText();
13131
+ if (text) {
13132
+ setRecipientAddress(text.trim());
13133
+ setSubmitError(null);
13134
+ }
13135
+ } catch {
13136
+ }
13137
+ },
13138
+ className: "uf-flex-shrink-0 uf-p-1 uf-rounded uf-transition-colors hover:uf-opacity-70",
13139
+ style: { color: colors2.foregroundMuted },
13140
+ title: "Paste from clipboard",
13141
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.ClipboardPaste, { className: "uf-w-4 uf-h-4" })
13142
+ }
13143
+ )
13144
+ ]
13145
+ }
13146
+ ),
13147
+ (isDebouncing || isVerifyingAddress) && trimmedAddress.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
13148
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.Loader2, { className: "uf-w-3 uf-h-3 uf-animate-spin", style: { color: colors2.foregroundMuted } }),
13149
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: t8.verifyingAddress })
13150
+ ] }),
13151
+ addressError && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
13152
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.AlertTriangle, { className: "uf-w-3 uf-h-3", style: { color: colors2.error } }),
13153
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs", style: { color: colors2.error, fontFamily: fonts.regular }, children: addressError })
13154
+ ] })
13155
+ ] }),
13156
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
13157
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-text-xs uf-mb-1.5", style: { color: components.card.labelColor, fontFamily: fonts.medium }, children: [
13158
+ t8.amount,
13159
+ minimumWithdrawAmountUsd != null && minimumWithdrawAmountUsd > 0 && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { style: { color: colors2.warning, fontFamily: fonts.regular }, children: ` ($${minimumWithdrawAmountUsd.toFixed(2)} min)` })
13160
+ ] }),
13161
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13162
+ "style",
13163
+ {
13164
+ dangerouslySetInnerHTML: {
13165
+ __html: `.uf-withdraw-amt::placeholder { color: ${components.search.placeholderColor}; }`
13166
+ }
13167
+ }
13168
+ ),
13169
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
13170
+ "div",
13171
+ {
13172
+ className: "uf-flex uf-items-center uf-gap-2 uf-px-3 uf-py-2.5",
13173
+ style: {
13174
+ backgroundColor: components.search.backgroundColor,
13175
+ borderRadius: components.input.borderRadius,
13176
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
13177
+ },
13178
+ children: [
13179
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13180
+ "input",
13181
+ {
13182
+ type: "text",
13183
+ inputMode: "decimal",
13184
+ placeholder: "0.00",
13185
+ value: amount,
13186
+ onChange: (e) => {
13187
+ const val = e.target.value;
13188
+ if (val === "" || /^\d*\.?\d*$/.test(val)) {
13189
+ setAmount(val);
13190
+ setSubmitError(null);
13191
+ }
13192
+ },
13193
+ className: "uf-withdraw-amt uf-flex-1 uf-min-w-0 uf-bg-transparent uf-text-sm uf-outline-none",
13194
+ style: {
13195
+ color: components.search.inputColor,
13196
+ fontFamily: fonts.regular
13197
+ }
13198
+ }
13199
+ ),
13200
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-sm uf-shrink-0", style: { color: colors2.foregroundMuted, fontFamily: fonts.medium }, children: inputUnit === "crypto" ? tokenSymbol : "USD" }),
13201
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13202
+ "button",
13203
+ {
13204
+ type: "button",
13205
+ onClick: handleMaxClick,
13206
+ 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",
13207
+ style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium },
13208
+ children: "Max"
13209
+ }
13210
+ )
13211
+ ]
13212
+ }
13213
+ ),
13214
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-mt-1.5 uf-px-3", children: [
13215
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
13216
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: convertedDisplay || (inputUnit === "crypto" ? "$0.00" : `0.00 ${tokenSymbol}`) }),
13217
+ exchangeRate > 0 && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13218
+ "button",
13219
+ {
13220
+ type: "button",
13221
+ onClick: handleSwitchUnit,
13222
+ className: "uf-p-0.5 uf-rounded uf-transition-colors hover:uf-opacity-70",
13223
+ style: { color: colors2.foregroundMuted },
13224
+ title: "Switch unit",
13225
+ children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.ArrowUpDown, { className: "uf-w-3 uf-h-3" })
13226
+ }
13227
+ )
13228
+ ] }),
13229
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
13230
+ balanceDisplay && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: [
13231
+ t8.balance,
13232
+ ": ",
13233
+ balanceDisplay
13234
+ ] }),
13235
+ isLoadingBalance && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uf-h-3 uf-w-16 uf-bg-muted uf-rounded uf-animate-pulse" })
13236
+ ] })
13237
+ ] })
13238
+ ] }),
13239
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-px-2.5", style: { backgroundColor: components.card.backgroundColor, borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: [
13240
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
13241
+ "button",
13242
+ {
13243
+ type: "button",
13244
+ onClick: () => setDetailsExpanded(!detailsExpanded),
13245
+ className: "uf-w-full uf-flex uf-items-center uf-justify-between uf-py-2.5",
13246
+ children: [
13247
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13248
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.Clock, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
13249
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
13250
+ tCrypto.processingTime.label,
13251
+ ":",
13252
+ " ",
13253
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(estimatedProcessingTime) })
13254
+ ] })
13255
+ ] }),
13256
+ detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
13257
+ ]
13258
+ }
13259
+ ),
13260
+ detailsExpanded && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-pb-3 uf-space-y-2.5", children: [
13261
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13262
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.ShieldCheck, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
13263
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
13264
+ tCrypto.slippage.label,
13265
+ ":",
13266
+ " ",
13267
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
13268
+ tCrypto.slippage.auto,
13269
+ " \u2022 ",
13270
+ (maxSlippagePercent ?? 0.25).toFixed(2),
13271
+ "%"
13272
+ ] })
13273
+ ] })
13274
+ ] }),
13275
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
13276
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.DollarSign, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
13277
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
13278
+ tCrypto.priceImpact.label,
13279
+ ":",
13280
+ " ",
13281
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
13282
+ (priceImpactPercent ?? 0).toFixed(2),
13283
+ "%"
13284
+ ] })
13285
+ ] })
13286
+ ] })
13287
+ ] })
13288
+ ] }),
13289
+ !canWithdraw && !submitError && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
13290
+ "div",
13291
+ {
13292
+ className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
13293
+ style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
13294
+ children: [
13295
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.Wallet, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
13296
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No connected wallet detected. Please connect a wallet that matches your account to withdraw." })
13297
+ ]
13298
+ }
13299
+ ),
13300
+ isWalletMatch && connectedWalletName ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13301
+ "button",
13302
+ {
13303
+ type: "button",
13304
+ onClick: handleWithdraw,
13305
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
13306
+ 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",
13307
+ style: {
13308
+ backgroundColor: colors2.primary,
13309
+ color: colors2.primaryForeground,
13310
+ fontFamily: fonts.medium,
13311
+ borderRadius: components.button.borderRadius,
13312
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
13313
+ },
13314
+ children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
13315
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
13316
+ "Processing..."
13317
+ ] }) : isOverBalance ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_jsx_runtime53.Fragment, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_jsx_runtime53.Fragment, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_jsx_runtime53.Fragment, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
13318
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.Wallet, { className: "uf-w-4 uf-h-4" }),
13319
+ "Withdraw from ",
13320
+ connectedWalletName
13321
+ ] })
13322
+ }
13323
+ ) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13324
+ "button",
13325
+ {
13326
+ type: "button",
13327
+ onClick: handleWithdraw,
13328
+ disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
13329
+ 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",
13330
+ style: {
13331
+ backgroundColor: colors2.primary,
13332
+ color: colors2.primaryForeground,
13333
+ fontFamily: fonts.medium,
13334
+ borderRadius: components.button.borderRadius,
13335
+ border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
13336
+ },
13337
+ children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
13338
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react24.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
13339
+ "Processing..."
13340
+ ] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
13341
+ }
13342
+ ),
13343
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
13344
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { children: footerLeft }),
13345
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) })
13346
+ ] }),
13347
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
13348
+ GlossaryModal,
13349
+ {
13350
+ open: glossaryOpen,
13351
+ onOpenChange: setGlossaryOpen
13352
+ }
13353
+ )
13354
+ ] });
13355
+ }
13356
+
13357
+ // src/components/withdrawals/WithdrawExecutionItem.tsx
13358
+ var import_lucide_react25 = require("lucide-react");
13359
+ var import_core31 = require("@unifold/core");
13360
+ var import_jsx_runtime54 = require("react/jsx-runtime");
13361
+ function WithdrawExecutionItem({
13362
+ execution,
13363
+ onClick
13364
+ }) {
13365
+ const { colors: colors2, fonts, components } = useTheme();
13366
+ const isPending = execution.status === import_core31.ExecutionStatus.PENDING || execution.status === import_core31.ExecutionStatus.WAITING || execution.status === import_core31.ExecutionStatus.DELAYED;
13367
+ const formatDateTime = (timestamp) => {
13368
+ try {
13369
+ const date = new Date(timestamp);
13370
+ const monthDay = date.toLocaleDateString("en-US", {
13371
+ month: "short",
13372
+ day: "numeric",
13373
+ year: "numeric"
13374
+ });
13375
+ const time = date.toLocaleTimeString("en-US", {
13376
+ hour: "numeric",
13377
+ minute: "2-digit",
13378
+ hour12: true
13379
+ }).toLowerCase();
13380
+ return `${monthDay} at ${time}`;
13381
+ } catch {
13382
+ return timestamp;
13383
+ }
13384
+ };
13385
+ const formatUsdAmount2 = (sourceAmountUsd) => {
13386
+ try {
13387
+ const amount = Number(sourceAmountUsd);
13388
+ return new Intl.NumberFormat("en-US", {
13389
+ style: "currency",
13390
+ currency: "USD",
13391
+ minimumFractionDigits: 2,
13392
+ maximumFractionDigits: 2
13393
+ }).format(amount);
13394
+ } catch {
13395
+ return "$0.00";
13396
+ }
13397
+ };
13398
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
13399
+ "button",
13400
+ {
13401
+ onClick,
13402
+ 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",
13403
+ style: {
13404
+ backgroundColor: components.card.backgroundColor,
13405
+ borderRadius: components.list.rowBorderRadius,
13406
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
13407
+ },
13408
+ children: [
13409
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-relative uf-flex-shrink-0 uf-w-9 uf-h-9", children: [
13410
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13411
+ "img",
13412
+ {
13413
+ src: execution.destination_token_metadata?.icon_url || (0, import_core31.getIconUrl)("/icons/tokens/svg/usdc.svg"),
13414
+ alt: "Token",
13415
+ width: 36,
13416
+ height: 36,
13417
+ loading: "lazy",
13418
+ className: "uf-rounded-full uf-w-9 uf-h-9"
13419
+ }
13420
+ ),
13421
+ isPending ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13422
+ "div",
13423
+ {
13424
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
13425
+ style: { backgroundColor: colors2.warning },
13426
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13427
+ "svg",
13428
+ {
13429
+ width: "10",
13430
+ height: "10",
13431
+ viewBox: "0 0 12 12",
13432
+ fill: "none",
13433
+ className: "uf-animate-spin uf-block",
13434
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13435
+ "path",
13436
+ {
13437
+ d: "M6 1V3M6 9V11M1 6H3M9 6H11M2.5 2.5L4 4M8 8L9.5 9.5M2.5 9.5L4 8M8 4L9.5 2.5",
13438
+ stroke: "white",
13439
+ strokeWidth: "2",
13440
+ strokeLinecap: "round"
13441
+ }
13442
+ )
13443
+ }
13444
+ )
13445
+ }
13446
+ ) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13447
+ "div",
13448
+ {
13449
+ className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
13450
+ style: { backgroundColor: colors2.success },
13451
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13452
+ "svg",
13453
+ {
13454
+ width: "10",
13455
+ height: "10",
13456
+ viewBox: "0 0 12 12",
13457
+ fill: "none",
13458
+ className: "uf-block",
13459
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13460
+ "path",
13461
+ {
13462
+ d: "M10 3L4.5 8.5L2 6",
13463
+ stroke: "white",
13464
+ strokeWidth: "2",
13465
+ strokeLinecap: "round",
13466
+ strokeLinejoin: "round"
13467
+ }
13468
+ )
13469
+ }
13470
+ )
13471
+ }
13472
+ )
13473
+ ] }),
13474
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex-1 uf-min-w-0", children: [
13475
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13476
+ "h3",
13477
+ {
13478
+ className: "uf-font-medium uf-text-sm uf-leading-tight",
13479
+ style: {
13480
+ color: components.card.titleColor,
13481
+ fontFamily: fonts.medium
13482
+ },
13483
+ children: isPending ? "Withdrawal processing" : "Withdrawal completed"
13484
+ }
13485
+ ),
13486
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13487
+ "p",
13488
+ {
13489
+ className: "uf-text-xs uf-leading-tight",
13490
+ style: {
13491
+ color: components.card.subtitleColor,
13492
+ fontFamily: fonts.regular
13493
+ },
13494
+ children: formatDateTime(execution.created_at || (/* @__PURE__ */ new Date()).toISOString())
13495
+ }
13496
+ )
13497
+ ] }),
13498
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13499
+ "span",
13500
+ {
13501
+ className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
13502
+ style: {
13503
+ color: components.card.textRightColor,
13504
+ fontFamily: fonts.medium
13505
+ },
13506
+ children: formatUsdAmount2(execution.source_amount_usd || "0")
13507
+ }
13508
+ ),
13509
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
13510
+ import_lucide_react25.ChevronRight,
13511
+ {
13512
+ className: "uf-w-4 uf-h-4 uf-flex-shrink-0",
13513
+ style: { color: components.card.actionColor }
13514
+ }
13515
+ )
13516
+ ]
13517
+ }
13518
+ );
13519
+ }
13520
+
13521
+ // src/components/withdrawals/WithdrawConfirmingView.tsx
13522
+ var import_react21 = require("react");
13523
+ var import_jsx_runtime55 = require("react/jsx-runtime");
13524
+ function truncateAddress4(addr) {
13525
+ if (addr.length <= 12) return addr;
13526
+ return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
13527
+ }
13528
+ var SHOW_BUTTON_DELAY_MS = 5e3;
13529
+ function WithdrawConfirmingView({
13530
+ txInfo,
13531
+ executions,
13532
+ onClose,
13533
+ onViewTracker
13534
+ }) {
13535
+ const { colors: colors2, fonts, components } = useTheme();
13536
+ const [showButton, setShowButton] = (0, import_react21.useState)(false);
13537
+ const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
13538
+ (0, import_react21.useEffect)(() => {
13539
+ if (latestExecution) return;
13540
+ const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
13541
+ return () => clearTimeout(timer);
13542
+ }, [latestExecution]);
13543
+ const btnRadius = components.button.borderRadius;
13544
+ const btnBorder = `${components.button.borderWidth}px solid ${components.button.borderColor}`;
13545
+ if (latestExecution) {
13546
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, { children: [
13547
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(DepositHeader, { title: "Withdrawal Details", showClose: true, onClose }),
13548
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(DepositDetailContent, { execution: latestExecution, variant: "withdraw" }),
13549
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uf-flex uf-gap-2 uf-px-2 uf-pt-2", children: [
13550
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13551
+ "button",
13552
+ {
13553
+ type: "button",
13554
+ onClick: onViewTracker,
13555
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
13556
+ style: {
13557
+ backgroundColor: components.button.secondaryBackground,
13558
+ color: components.button.secondaryText,
13559
+ fontFamily: fonts.medium,
13560
+ borderRadius: btnRadius,
13561
+ border: btnBorder
13562
+ },
13563
+ children: "Withdrawal History"
13564
+ }
13565
+ ),
13566
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13567
+ "button",
13568
+ {
13569
+ type: "button",
13570
+ onClick: onClose,
13571
+ className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
13572
+ style: {
13573
+ backgroundColor: components.button.primaryBackground,
13574
+ color: components.button.primaryText,
13575
+ fontFamily: fonts.medium,
13576
+ borderRadius: btnRadius,
13577
+ border: btnBorder
13578
+ },
13579
+ children: "Close"
13580
+ }
13581
+ )
13582
+ ] }),
13583
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13584
+ PoweredByUnifold,
13585
+ {
13586
+ color: colors2.foregroundMuted,
13587
+ className: "uf-flex uf-justify-center uf-shrink-0"
13588
+ }
13589
+ ) })
13590
+ ] });
13591
+ }
13592
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, { children: [
13593
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(DepositHeader, { title: "Withdrawal Status", showClose: true, onClose }),
13594
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4", children: [
13595
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13596
+ "div",
13597
+ {
13598
+ className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
13599
+ style: { backgroundColor: `${colors2.primary}20` },
13600
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13601
+ "svg",
13602
+ {
13603
+ width: "40",
13604
+ height: "40",
13605
+ viewBox: "0 0 24 24",
13606
+ fill: "none",
13607
+ className: "uf-animate-spin",
13608
+ children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13609
+ "path",
13610
+ {
13611
+ d: "M21 12a9 9 0 1 1-6.22-8.56",
13612
+ stroke: colors2.primary,
13613
+ strokeWidth: "2.5",
13614
+ strokeLinecap: "round"
13615
+ }
13616
+ )
13617
+ }
13618
+ )
13619
+ }
13620
+ ),
13621
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13622
+ "h3",
13623
+ {
13624
+ className: "uf-text-xl uf-mb-2",
13625
+ style: { color: colors2.foreground, fontFamily: fonts.medium },
13626
+ children: "Checking Withdrawal"
13627
+ }
13628
+ ),
13629
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
13630
+ "p",
13631
+ {
13632
+ className: "uf-text-sm uf-text-center",
13633
+ style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
13634
+ children: [
13635
+ txInfo.amount,
13636
+ " ",
13637
+ txInfo.sourceTokenSymbol,
13638
+ " to",
13639
+ " ",
13640
+ truncateAddress4(txInfo.recipientAddress)
13641
+ ]
13642
+ }
13643
+ )
13644
+ ] }),
13645
+ showButton && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uf-px-1 uf-pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13646
+ "button",
13647
+ {
13648
+ type: "button",
13649
+ onClick: onViewTracker,
13650
+ className: "uf-w-full uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
13651
+ style: {
13652
+ backgroundColor: components.button.secondaryBackground,
13653
+ color: components.button.secondaryText,
13654
+ fontFamily: fonts.medium,
13655
+ borderRadius: btnRadius,
13656
+ border: btnBorder
13657
+ },
13658
+ children: "Withdrawal History"
13659
+ }
13660
+ ) }),
13661
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
13662
+ PoweredByUnifold,
13663
+ {
13664
+ color: colors2.foregroundMuted,
13665
+ className: "uf-flex uf-justify-center uf-shrink-0"
13666
+ }
13667
+ ) })
13668
+ ] });
13669
+ }
13670
+
13671
+ // src/components/withdrawals/WithdrawModal.tsx
13672
+ var import_core32 = require("@unifold/core");
13673
+ var import_jsx_runtime56 = require("react/jsx-runtime");
13674
+ var t9 = i18n.withdrawModal;
13675
+ var getChainKey5 = (chainId, chainType) => `${chainType}:${chainId}`;
13676
+ function WithdrawModal({
13677
+ open,
13678
+ onOpenChange,
13679
+ publishableKey,
13680
+ modalTitle,
13681
+ externalUserId,
13682
+ sourceChainType,
13683
+ sourceChainId,
13684
+ sourceTokenAddress,
13685
+ sourceTokenSymbol,
13686
+ recipientAddress: recipientAddressProp,
13687
+ senderAddress,
13688
+ onWithdraw,
13689
+ onWithdrawSuccess,
13690
+ onWithdrawError,
13691
+ theme = "dark",
13692
+ hideOverlay = false
13693
+ }) {
13694
+ const { colors: colors2, fonts, components } = useTheme();
13695
+ const [containerEl, setContainerEl] = (0, import_react22.useState)(null);
13696
+ const containerCallbackRef = (0, import_react22.useCallback)((el) => {
13697
+ setContainerEl(el);
13698
+ }, []);
13699
+ const [resolvedTheme, setResolvedTheme] = (0, import_react22.useState)(
13700
+ theme === "auto" ? "dark" : theme
13701
+ );
13702
+ (0, import_react22.useEffect)(() => {
13703
+ if (theme === "auto") {
13704
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
13705
+ setResolvedTheme(mq.matches ? "dark" : "light");
13706
+ const h = (e) => setResolvedTheme(e.matches ? "dark" : "light");
13707
+ mq.addEventListener("change", h);
13708
+ return () => mq.removeEventListener("change", h);
13709
+ }
13710
+ setResolvedTheme(theme);
13711
+ }, [theme]);
13712
+ const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
13713
+ const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDestinationTokens(publishableKey, open);
13714
+ const destinationTokens = tokensResponse?.data ?? [];
13715
+ const { data: sourceValidation, isLoading: isCheckingSourceToken } = useSourceTokenValidation({
13716
+ sourceChainType,
13717
+ sourceChainId,
13718
+ sourceTokenAddress,
13719
+ sourceTokenSymbol,
13720
+ publishableKey,
13721
+ enabled: open
13722
+ });
13723
+ const { data: balanceData, isLoading: isLoadingBalance } = useAddressBalance({
13724
+ address: senderAddress,
13725
+ chainType: sourceChainType,
13726
+ chainId: sourceChainId,
13727
+ tokenAddress: sourceTokenAddress,
13728
+ publishableKey,
13729
+ enabled: open
13730
+ });
13731
+ const [selectedToken, setSelectedToken] = (0, import_react22.useState)(null);
13732
+ const [selectedChain, setSelectedChain] = (0, import_react22.useState)(null);
13733
+ const [detectedWallet, setDetectedWallet] = (0, import_react22.useState)(null);
13734
+ const connectedWalletName = detectedWallet?.name ?? null;
13735
+ const isWalletMatch = !!detectedWallet;
13736
+ (0, import_react22.useEffect)(() => {
13737
+ if (!senderAddress || !open) {
13738
+ setDetectedWallet(null);
13739
+ return;
13740
+ }
13741
+ let cancelled = false;
13742
+ detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
13743
+ if (!cancelled) setDetectedWallet(wallet);
13744
+ });
13745
+ return () => {
13746
+ cancelled = true;
13747
+ };
13748
+ }, [senderAddress, sourceChainType, open]);
13749
+ const [view, setView] = (0, import_react22.useState)("form");
13750
+ const [withdrawDepositWalletId, setWithdrawDepositWalletId] = (0, import_react22.useState)();
13751
+ const [selectedExecution, setSelectedExecution] = (0, import_react22.useState)(null);
13752
+ const [submittedTxInfo, setSubmittedTxInfo] = (0, import_react22.useState)(null);
13753
+ const { executions: realtimeExecutions } = useWithdrawPolling({
13754
+ userId: externalUserId,
13755
+ publishableKey,
13756
+ depositWalletId: withdrawDepositWalletId,
13757
+ enabled: !!withdrawDepositWalletId && open,
13758
+ onWithdrawSuccess: onWithdrawSuccess ? (d) => onWithdrawSuccess({ message: d.message, transaction: d.transaction }) : void 0,
13759
+ onWithdrawError
13760
+ });
13761
+ const { data: allWithdrawalsData } = useExecutions(externalUserId, publishableKey, {
13762
+ actionType: import_core32.ActionType.Withdraw,
13763
+ enabled: open,
13764
+ refetchInterval: view === "tracker" || view === "detail" ? 5e3 : 15e3
13765
+ });
13766
+ const allWithdrawals = allWithdrawalsData?.data ?? [];
13767
+ const handleDepositWalletCreation = (0, import_react22.useCallback)(async (params) => {
13768
+ const { data: wallets } = await (0, import_core32.createDepositAddress)(
13769
+ {
13770
+ external_user_id: externalUserId,
13771
+ destination_chain_type: params.destinationChainType,
13772
+ destination_chain_id: params.destinationChainId,
13773
+ destination_token_address: params.destinationTokenAddress,
13774
+ recipient_address: params.recipientAddress,
13775
+ action_type: import_core32.ActionType.Withdraw
13776
+ },
13777
+ publishableKey
13778
+ );
13779
+ const depositWallet = (0, import_core32.getWalletByChainType)(wallets, sourceChainType);
13780
+ if (!depositWallet) {
13781
+ throw new Error(`No deposit wallet available for ${sourceChainType}`);
13782
+ }
13783
+ setWithdrawDepositWalletId(depositWallet.id);
13784
+ return depositWallet;
13785
+ }, [externalUserId, publishableKey, sourceChainType]);
13786
+ const handleWithdrawSubmitted = (0, import_react22.useCallback)((txInfo) => {
13787
+ setSubmittedTxInfo(txInfo);
13788
+ setView("confirming");
13789
+ }, []);
13790
+ (0, import_react22.useEffect)(() => {
13791
+ if (!destinationTokens.length || selectedToken) return;
13792
+ const first = destinationTokens[0];
13793
+ if (first?.chains.length > 0) {
13794
+ setSelectedToken(first);
13795
+ setSelectedChain(first.chains[0]);
13796
+ }
13797
+ }, [destinationTokens, selectedToken]);
13798
+ const resetViewTimeoutRef = (0, import_react22.useRef)(null);
13799
+ const handleClose = (0, import_react22.useCallback)(() => {
13800
+ onOpenChange(false);
13801
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
13802
+ resetViewTimeoutRef.current = setTimeout(() => {
13803
+ setSelectedToken(null);
13804
+ setSelectedChain(null);
13805
+ setView("form");
13806
+ setSelectedExecution(null);
13807
+ setSubmittedTxInfo(null);
13808
+ setWithdrawDepositWalletId(void 0);
13809
+ resetViewTimeoutRef.current = null;
13810
+ }, 200);
13811
+ }, [onOpenChange]);
13812
+ (0, import_react22.useLayoutEffect)(() => {
13813
+ if (!open) return;
13814
+ if (resetViewTimeoutRef.current) {
13815
+ clearTimeout(resetViewTimeoutRef.current);
13816
+ resetViewTimeoutRef.current = null;
13817
+ }
13818
+ setSelectedToken(null);
13819
+ setSelectedChain(null);
13820
+ setView("form");
13821
+ setSelectedExecution(null);
13822
+ setSubmittedTxInfo(null);
13823
+ setWithdrawDepositWalletId(void 0);
13824
+ }, [open]);
13825
+ (0, import_react22.useEffect)(() => () => {
13826
+ if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
13827
+ }, []);
13828
+ const handleTokenSymbolChange = (0, import_react22.useCallback)((symbol) => {
13829
+ const tok = destinationTokens.find((t11) => t11.symbol === symbol);
13830
+ if (tok) {
13831
+ setSelectedToken(tok);
13832
+ if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
13833
+ }
13834
+ }, [destinationTokens]);
13835
+ const handleChainKeyChange = (0, import_react22.useCallback)((chainKey) => {
13836
+ if (!selectedToken) return;
13837
+ const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
13838
+ if (chain) setSelectedChain(chain);
13839
+ }, [selectedToken]);
13840
+ const isSourceSupported = sourceValidation?.isSupported ?? null;
13841
+ const canWithdraw = !!onWithdraw || isWalletMatch;
13842
+ const isAnyLoading = tokensLoading || isCheckingSourceToken;
13843
+ const withdrawPoweredByFooter = /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
13844
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Dialog, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
13845
+ DialogContent,
13846
+ {
13847
+ ref: hideOverlay ? containerCallbackRef : void 0,
13848
+ hideOverlay,
13849
+ 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}`}`,
13850
+ style: { backgroundColor: colors2.background },
13851
+ onPointerDownOutside: (e) => e.preventDefault(),
13852
+ onInteractOutside: (e) => e.preventDefault(),
13853
+ children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ThemeStyleInjector, { children: view === "confirming" && submittedTxInfo ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
13854
+ WithdrawConfirmingView,
13855
+ {
13856
+ txInfo: submittedTxInfo,
13857
+ executions: realtimeExecutions,
13858
+ onClose: handleClose,
13859
+ onViewTracker: () => setView("tracker")
13860
+ }
13861
+ ) : view === "detail" && selectedExecution ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
13862
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositHeader, { title: "Withdrawal Details", showBack: true, showClose: !hideOverlay, onBack: () => {
13863
+ setSelectedExecution(null);
13864
+ setView("tracker");
13865
+ }, onClose: handleClose }),
13866
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositDetailContent, { execution: selectedExecution, variant: "withdraw" }),
13867
+ withdrawPoweredByFooter
13868
+ ] }) : view === "tracker" ? (
13869
+ /* ---------- Tracker view: execution list ---------- */
13870
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
13871
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
13872
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
13873
+ WithdrawExecutionItem,
13874
+ {
13875
+ execution: ex,
13876
+ onClick: () => {
13877
+ setSelectedExecution(ex);
13878
+ setView("detail");
13879
+ }
13880
+ },
13881
+ ex.id
13882
+ )) }),
13883
+ withdrawPoweredByFooter
13884
+ ] })
13885
+ ) : (
13886
+ /* ---------- Form view (default) ---------- */
13887
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
13888
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositHeader, { title: modalTitle || t9.title, showClose: !hideOverlay, onClose: handleClose }),
13889
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-3", children: [
13890
+ isAnyLoading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-animate-pulse", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-bg-muted uf-rounded-lg uf-w-full uf-h-10" }) }, i)) }) : isSourceSupported === false ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
13891
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react26.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
13892
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-mb-2", style: { color: colors2.foreground, fontFamily: fonts.medium }, children: "Unsupported Source Token" }),
13893
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "uf-text-sm uf-max-w-[280px]", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: sourceValidation?.errorMessage })
13894
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
13895
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
13896
+ WithdrawDoubleInput,
13897
+ {
13898
+ tokens: destinationTokens,
13899
+ selectedTokenSymbol: selectedToken?.symbol ?? null,
13900
+ selectedChainKey: selectedChain ? getChainKey5(selectedChain.chain_id, selectedChain.chain_type) : null,
13901
+ onTokenChange: handleTokenSymbolChange,
13902
+ onChainChange: handleChainKeyChange,
13903
+ isLoading: tokensLoading
13904
+ }
13905
+ ),
13906
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
13907
+ WithdrawForm,
13908
+ {
13909
+ publishableKey,
13910
+ externalUserId,
13911
+ sourceChainType,
13912
+ selectedToken,
13913
+ selectedChain,
13914
+ sourceTokenSymbol,
13915
+ recipientAddressProp,
13916
+ balanceData: balanceData ?? null,
13917
+ isLoadingBalance,
13918
+ minimumWithdrawAmountUsd: sourceValidation?.minimumAmountUsd ?? null,
13919
+ estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
13920
+ maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
13921
+ priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
13922
+ detectedWallet,
13923
+ sourceChainId,
13924
+ sourceTokenAddress,
13925
+ isWalletMatch,
13926
+ connectedWalletName,
13927
+ canWithdraw,
13928
+ onWithdraw,
13929
+ onWithdrawError,
13930
+ onDepositWalletCreation: handleDepositWalletCreation,
13931
+ onWithdrawSubmitted: handleWithdrawSubmitted,
13932
+ footerLeft: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
13933
+ "button",
13934
+ {
13935
+ onClick: () => setView("tracker"),
13936
+ className: "uf-flex uf-items-center uf-gap-1 uf-transition-colors hover:uf-opacity-70",
13937
+ style: { color: colors2.foregroundMuted },
13938
+ children: [
13939
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react26.Clock, { className: "uf-w-3.5 uf-h-3.5" }),
13940
+ "Withdrawal History",
13941
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react26.ChevronRight, { className: "uf-w-3 uf-h-3" })
13942
+ ]
13943
+ }
13944
+ )
13945
+ }
13946
+ )
13947
+ ] }),
13948
+ withdrawPoweredByFooter
13949
+ ] })
13950
+ ] })
13951
+ ) })
13952
+ }
13953
+ ) }) });
13954
+ }
13955
+
13956
+ // src/components/withdrawals/WithdrawTokenSelector.tsx
13957
+ var import_react23 = require("react");
13958
+ var import_lucide_react27 = require("lucide-react");
13959
+ var import_jsx_runtime57 = require("react/jsx-runtime");
13960
+ var t10 = i18n.withdrawModal;
13961
+ function WithdrawTokenSelector({
13962
+ tokens,
13963
+ onSelect,
13964
+ onBack
13965
+ }) {
13966
+ const { themeClass, colors: colors2, fonts, components } = useTheme();
13967
+ const [searchQuery, setSearchQuery] = (0, import_react23.useState)("");
13968
+ const [hoveredKey, setHoveredKey] = (0, import_react23.useState)(null);
13969
+ const allOptions = (0, import_react23.useMemo)(() => {
13970
+ const options = [];
13971
+ tokens.forEach((token) => {
13972
+ token.chains.forEach((chain) => {
13973
+ options.push({ token, chain });
13974
+ });
13975
+ });
13976
+ return options;
13977
+ }, [tokens]);
13978
+ const filteredOptions = (0, import_react23.useMemo)(() => {
13979
+ if (!searchQuery.trim()) return allOptions;
13980
+ const query = searchQuery.toLowerCase();
13981
+ return allOptions.filter(
13982
+ ({ token, chain }) => token.symbol.toLowerCase().includes(query) || token.name.toLowerCase().includes(query) || chain.chain_name.toLowerCase().includes(query)
13983
+ );
13984
+ }, [allOptions, searchQuery]);
13985
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
13986
+ "div",
13987
+ {
13988
+ className: "uf-flex uf-flex-col",
13989
+ style: { minHeight: 0, flex: 1 },
13990
+ children: [
13991
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "uf-pb-3", children: [
13992
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
13993
+ "style",
13994
+ {
13995
+ dangerouslySetInnerHTML: {
13996
+ __html: `.uf-withdraw-token-search::placeholder { color: ${components.search.placeholderColor}; }`
13997
+ }
13998
+ }
13999
+ ),
14000
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { style: { position: "relative" }, children: [
14001
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14002
+ import_lucide_react27.Search,
14003
+ {
14004
+ className: "uf-absolute uf-left-3 uf-top-1/2 uf--translate-y-1/2 uf-w-4 uf-h-4",
14005
+ style: { color: components.search.placeholderColor }
14006
+ }
14007
+ ),
14008
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14009
+ "input",
14010
+ {
14011
+ type: "text",
14012
+ placeholder: "Search token or network",
14013
+ value: searchQuery,
14014
+ onChange: (e) => setSearchQuery(e.target.value),
14015
+ 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",
14016
+ style: {
14017
+ backgroundColor: components.search.backgroundColor,
14018
+ color: components.search.inputColor,
14019
+ fontFamily: fonts.regular,
14020
+ borderRadius: components.input.borderRadius,
14021
+ border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
14022
+ }
14023
+ }
14024
+ )
14025
+ ] })
14026
+ ] }),
14027
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14028
+ "div",
14029
+ {
14030
+ className: "uf-text-xs uf-mb-2",
14031
+ style: {
14032
+ color: components.list.titleSectionColor,
14033
+ fontFamily: fonts.medium
14034
+ },
14035
+ children: t10.selectToken
14036
+ }
14037
+ ),
14038
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14039
+ "div",
14040
+ {
14041
+ className: "uf-flex-1 uf-overflow-y-auto uf-min-h-0 uf--mx-6 uf-px-6 uf-pb-3",
14042
+ style: { scrollbarWidth: "none" },
14043
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14044
+ "div",
14045
+ {
14046
+ style: {
14047
+ textAlign: "center",
14048
+ padding: "2rem 0",
14049
+ fontSize: 14,
14050
+ color: components.container.subtitleColor,
14051
+ fontFamily: fonts.regular
14052
+ },
14053
+ children: t10.noTokensAvailable
14054
+ }
14055
+ ) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: filteredOptions.map(({ token, chain }) => {
14056
+ const key = `${token.symbol}-${chain.chain_type}:${chain.chain_id}`;
14057
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
14058
+ "button",
14059
+ {
14060
+ type: "button",
14061
+ onClick: () => onSelect(token, chain),
14062
+ onMouseEnter: () => setHoveredKey(key),
14063
+ onMouseLeave: () => setHoveredKey(null),
14064
+ className: "uf-transition-colors",
14065
+ style: {
14066
+ width: "100%",
14067
+ display: "flex",
14068
+ alignItems: "center",
14069
+ gap: 12,
14070
+ padding: 12,
14071
+ borderRadius: 12,
14072
+ border: "none",
14073
+ cursor: "pointer",
14074
+ textAlign: "left",
14075
+ backgroundColor: hoveredKey === key ? colors2.cardHover : "transparent"
14076
+ },
14077
+ children: [
14078
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { style: { position: "relative", flexShrink: 0 }, children: [
14079
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14080
+ "img",
14081
+ {
14082
+ src: token.icon_url,
14083
+ alt: token.symbol,
14084
+ width: 40,
14085
+ height: 40,
14086
+ loading: "lazy",
14087
+ className: "uf-rounded-full"
14088
+ }
14089
+ ),
14090
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14091
+ "div",
14092
+ {
14093
+ style: {
14094
+ position: "absolute",
14095
+ bottom: -4,
14096
+ right: -4
14097
+ },
14098
+ children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14099
+ "img",
14100
+ {
14101
+ src: chain.icon_url,
14102
+ alt: chain.chain_name,
14103
+ width: 20,
14104
+ height: 20,
14105
+ loading: "lazy",
14106
+ className: "uf-rounded-full uf-border-2"
14107
+ }
14108
+ )
14109
+ }
14110
+ )
14111
+ ] }),
14112
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
14113
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14114
+ "div",
14115
+ {
14116
+ style: {
14117
+ fontSize: 14,
14118
+ fontWeight: 500,
14119
+ color: components.card.titleColor,
14120
+ fontFamily: fonts.medium
14121
+ },
14122
+ children: token.symbol
14123
+ }
14124
+ ),
14125
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
14126
+ "div",
14127
+ {
14128
+ style: {
14129
+ fontSize: 12,
14130
+ color: components.card.subtitleColor,
14131
+ fontFamily: fonts.regular
14132
+ },
14133
+ children: [
14134
+ token.name,
14135
+ " \u2022 ",
14136
+ chain.chain_name
14137
+ ]
14138
+ }
14139
+ )
14140
+ ] })
14141
+ ]
14142
+ },
14143
+ key
14144
+ );
14145
+ }) })
14146
+ }
14147
+ ),
14148
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-pt-3 uf-pb-2 uf-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
14149
+ PoweredByUnifold,
14150
+ {
14151
+ color: colors2.foregroundMuted,
14152
+ className: "uf-flex uf-justify-center uf-shrink-0"
14153
+ }
14154
+ ) })
14155
+ ]
14156
+ }
14157
+ );
14158
+ }
12146
14159
  // Annotate the CommonJS export names for ESM import in node:
12147
14160
  0 && (module.exports = {
12148
14161
  Button,
@@ -12189,15 +14202,29 @@ function DepositModal({
12189
14202
  TransferCryptoButton,
12190
14203
  TransferCryptoDoubleInput,
12191
14204
  TransferCryptoSingleInput,
14205
+ WithdrawConfirmingView,
14206
+ WithdrawDoubleInput,
14207
+ WithdrawExecutionItem,
14208
+ WithdrawForm,
14209
+ WithdrawModal,
14210
+ WithdrawTokenSelector,
12192
14211
  buttonVariants,
12193
14212
  cn,
12194
14213
  colors,
12195
14214
  defaultColors,
14215
+ detectBrowserWallet,
12196
14216
  getColors,
12197
14217
  mergeColors,
12198
14218
  resolveComponentTokens,
14219
+ sendEvmWithdraw,
14220
+ sendSolanaWithdraw,
12199
14221
  truncateAddress,
14222
+ useAddressBalance,
12200
14223
  useAllowedCountry,
12201
14224
  useDepositPolling,
12202
- useTheme
14225
+ useSourceTokenValidation,
14226
+ useSupportedDestinationTokens,
14227
+ useTheme,
14228
+ useVerifyRecipientAddress,
14229
+ useWithdrawPolling
12203
14230
  });