@unifold/ui-react 0.1.21 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/deposits/DepositModal.tsx
2
- import { useState as useState16, useEffect as useEffect13 } from "react";
2
+ import { useState as useState17, useEffect as useEffect14 } from "react";
3
3
  import { ChevronRight as ChevronRight8, MapPinOff, AlertTriangle } from "lucide-react";
4
4
 
5
5
  // src/components/shared/dialog.tsx
@@ -13,6 +13,29 @@ import { twMerge } from "tailwind-merge";
13
13
  function cn(...inputs) {
14
14
  return twMerge(clsx(inputs));
15
15
  }
16
+ function formatEstimatedTime(seconds) {
17
+ if (seconds == null) {
18
+ return "< 1 min";
19
+ }
20
+ if (seconds < 60) {
21
+ return `< ${seconds} sec${seconds > 1 ? "s" : ""}`;
22
+ } else if (seconds < 3600) {
23
+ const mins = Math.ceil(seconds / 60);
24
+ return `< ${mins} min${mins > 1 ? "s" : ""}`;
25
+ } else {
26
+ let hrs = Math.floor(seconds / 3600);
27
+ let mins = Math.ceil(seconds % 3600 / 60);
28
+ if (mins === 60) {
29
+ hrs += 1;
30
+ mins = 0;
31
+ }
32
+ const hrLabel = hrs > 1 ? "hrs" : "hr";
33
+ if (mins === 0) {
34
+ return `< ${hrs} ${hrLabel}`;
35
+ }
36
+ return `< ${hrs} ${hrLabel} ${mins} min${mins > 1 ? "s" : ""}`;
37
+ }
38
+ }
16
39
 
17
40
  // src/context/ThemeContext.tsx
18
41
  import * as React from "react";
@@ -466,7 +489,7 @@ var DialogDescription = React2.forwardRef(({ className, ...props }, ref) => /* @
466
489
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
467
490
 
468
491
  // src/components/deposits/BuyWithCard.tsx
469
- import { useState as useState8, useEffect as useEffect4, useRef as useRef2 } from "react";
492
+ import { useState as useState9, useEffect as useEffect5, useRef as useRef2 } from "react";
470
493
  import { ChevronDown as ChevronDown2, ChevronRight } from "lucide-react";
471
494
  import {
472
495
  getOnrampQuotes,
@@ -481,10 +504,12 @@ import {
481
504
  } from "@unifold/core";
482
505
 
483
506
  // src/components/deposits/CurrencyModal.tsx
484
- import { useState as useState3 } from "react";
507
+ import { useState as useState4 } from "react";
485
508
 
486
509
  // src/components/deposits/DepositHeader.tsx
487
510
  import { ArrowLeft, X as X2 } from "lucide-react";
511
+ import { useEffect as useEffect2, useState as useState2 } from "react";
512
+ import { getAddressBalance } from "@unifold/core";
488
513
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
489
514
  function DepositHeader({
490
515
  title,
@@ -492,10 +517,83 @@ function DepositHeader({
492
517
  showClose = true,
493
518
  onBack,
494
519
  onClose,
495
- badge
520
+ badge,
521
+ showBalance = false,
522
+ balanceAddress,
523
+ balanceChainType,
524
+ balanceChainId,
525
+ balanceTokenAddress,
526
+ publishableKey
496
527
  }) {
497
528
  const { colors: colors2, fonts, components } = useTheme();
498
- return /* @__PURE__ */ jsxs2("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
529
+ const [balance, setBalance] = useState2(null);
530
+ const [isLoadingBalance, setIsLoadingBalance] = useState2(false);
531
+ useEffect2(() => {
532
+ if (!showBalance || !balanceAddress || !balanceChainType || !balanceChainId || !balanceTokenAddress || !publishableKey) {
533
+ setBalance(null);
534
+ setIsLoadingBalance(false);
535
+ return;
536
+ }
537
+ let cancelled = false;
538
+ setIsLoadingBalance(true);
539
+ getAddressBalance(
540
+ balanceAddress,
541
+ balanceChainType,
542
+ balanceChainId,
543
+ balanceTokenAddress,
544
+ publishableKey
545
+ ).then((response) => {
546
+ if (cancelled) return;
547
+ if (response.balance && response.balance.amount !== "0") {
548
+ const value = Number(response.balance.amount) / 10 ** response.balance.token.decimals;
549
+ let formatted;
550
+ let maxDecimals = 4;
551
+ const symbol = response.balance.token.symbol?.toUpperCase() || "";
552
+ if (symbol === "BTC" || symbol === "WBTC") {
553
+ maxDecimals = 8;
554
+ } else if (symbol === "ETH" || symbol === "WETH") {
555
+ maxDecimals = 6;
556
+ }
557
+ if (value >= 1) {
558
+ formatted = value.toLocaleString(void 0, {
559
+ minimumFractionDigits: 2,
560
+ maximumFractionDigits: maxDecimals
561
+ });
562
+ } else if (value > 0) {
563
+ formatted = value.toLocaleString(void 0, {
564
+ minimumFractionDigits: 2,
565
+ maximumFractionDigits: maxDecimals,
566
+ minimumSignificantDigits: 2,
567
+ maximumSignificantDigits: 6
568
+ });
569
+ } else {
570
+ formatted = value.toExponential(2);
571
+ }
572
+ const balanceText = response.balance.amount_usd ? `Balance: $${response.balance.amount_usd} (${formatted} ${response.balance.token.symbol})` : `Balance: ${formatted} ${response.balance.token.symbol}`;
573
+ setBalance(balanceText);
574
+ } else {
575
+ setBalance(null);
576
+ }
577
+ }).catch((error) => {
578
+ if (cancelled) return;
579
+ console.error("Error fetching balance:", error);
580
+ setBalance(null);
581
+ }).finally(() => {
582
+ if (cancelled) return;
583
+ setIsLoadingBalance(false);
584
+ });
585
+ return () => {
586
+ cancelled = true;
587
+ };
588
+ }, [
589
+ showBalance,
590
+ balanceAddress,
591
+ balanceChainType,
592
+ balanceChainId,
593
+ balanceTokenAddress,
594
+ publishableKey
595
+ ]);
596
+ return /* @__PURE__ */ jsx3("div", { children: /* @__PURE__ */ jsxs2("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
499
597
  showBack ? /* @__PURE__ */ jsx3(
500
598
  "button",
501
599
  {
@@ -505,8 +603,32 @@ function DepositHeader({
505
603
  children: /* @__PURE__ */ jsx3(ArrowLeft, { className: "uf-w-5 uf-h-5" })
506
604
  }
507
605
  ) : /* @__PURE__ */ jsx3("div", { className: "uf-w-5 uf-h-5 uf-invisible" }),
508
- badge ? /* @__PURE__ */ jsxs2("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
509
- /* @__PURE__ */ jsx3(
606
+ /* @__PURE__ */ jsxs2("div", { className: "uf-flex uf-flex-col uf-items-center", children: [
607
+ badge ? /* @__PURE__ */ jsxs2("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
608
+ /* @__PURE__ */ jsx3(
609
+ DialogTitle,
610
+ {
611
+ className: "uf-text-center uf-text-base",
612
+ style: {
613
+ color: components.header.titleColor,
614
+ fontFamily: fonts.medium
615
+ },
616
+ children: title
617
+ }
618
+ ),
619
+ /* @__PURE__ */ jsx3(
620
+ "div",
621
+ {
622
+ className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
623
+ style: {
624
+ backgroundColor: colors2.card,
625
+ color: colors2.foregroundMuted,
626
+ fontFamily: fonts.regular
627
+ },
628
+ children: badge.count
629
+ }
630
+ )
631
+ ] }) : /* @__PURE__ */ jsx3(
510
632
  DialogTitle,
511
633
  {
512
634
  className: "uf-text-center uf-text-base",
@@ -517,29 +639,19 @@ function DepositHeader({
517
639
  children: title
518
640
  }
519
641
  ),
520
- /* @__PURE__ */ jsx3(
642
+ showBalance && (isLoadingBalance ? /* @__PURE__ */ jsx3("div", { className: "uf-h-3 uf-w-32 uf-bg-muted uf-rounded uf-animate-pulse uf-mt-2" }) : balance ? /* @__PURE__ */ jsx3(
521
643
  "div",
522
644
  {
523
- className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
645
+ className: "uf-text-xs uf-mt-2",
524
646
  style: {
525
- backgroundColor: colors2.card,
526
- color: colors2.foregroundMuted,
527
- fontFamily: fonts.regular
647
+ color: colors2.foreground,
648
+ fontFamily: fonts.regular,
649
+ opacity: 0.7
528
650
  },
529
- children: badge.count
651
+ children: balance
530
652
  }
531
- )
532
- ] }) : /* @__PURE__ */ jsx3(
533
- DialogTitle,
534
- {
535
- className: "uf-text-center uf-text-base",
536
- style: {
537
- color: components.header.titleColor,
538
- fontFamily: fonts.medium
539
- },
540
- children: title
541
- }
542
- ),
653
+ ) : null)
654
+ ] }),
543
655
  showClose ? /* @__PURE__ */ jsx3(
544
656
  "button",
545
657
  {
@@ -549,7 +661,7 @@ function DepositHeader({
549
661
  children: /* @__PURE__ */ jsx3(X2, { className: "uf-w-5 uf-h-5" })
550
662
  }
551
663
  ) : /* @__PURE__ */ jsx3("div", { className: "uf-w-5 uf-h-5 uf-invisible" })
552
- ] });
664
+ ] }) });
553
665
  }
554
666
 
555
667
  // src/components/currency/CurrencyListItem.tsx
@@ -662,7 +774,7 @@ function CurrencyModal({
662
774
  themeClass = ""
663
775
  }) {
664
776
  const { colors: colors2, fonts, components } = useTheme();
665
- const [searchQuery, setSearchQuery] = useState3("");
777
+ const [searchQuery, setSearchQuery] = useState4("");
666
778
  const preferredCurrencies = preferredCurrencyCodes.map(
667
779
  (code) => currencies.find(
668
780
  (currency) => currency.currency_code.toLowerCase() === code.toLowerCase()
@@ -838,7 +950,19 @@ var en_default = {
838
950
  minimumDeposit: "Minimum: {{amount}}",
839
951
  minimumDepositTooltip: "The minimum amount you can deposit on the selected network.",
840
952
  selectTokenDeposit: "Your deposit token",
841
- selectTokenDepositTooltip: "Select the token you want to deposit with in order to begin the deposit process."
953
+ selectTokenDepositTooltip: "Select the token you want to deposit with in order to begin the deposit process.",
954
+ addressValidation: {
955
+ validating: "Verifying recipient address...",
956
+ unableToReceiveFunds: "Unable to Receive Funds",
957
+ errors: {
958
+ token_not_supported: "The destination token is not supported",
959
+ not_opted_in: "Please make sure you opt-in {{token_symbol}}({{chain_name}}) before receiving funds",
960
+ insufficient_balance: "Recipient account does not meet the minimum balance requirement",
961
+ account_not_found: "Recipient account does not exist on {{chain_name}}",
962
+ validation_error: "Unable to verify recipient address on {{chain_name}}"
963
+ },
964
+ defaultError: "The recipient address cannot receive funds for the selected token"
965
+ }
842
966
  },
843
967
  depositModal: {
844
968
  transferCrypto: {
@@ -847,7 +971,7 @@ var en_default = {
847
971
  },
848
972
  depositWithCard: {
849
973
  title: "Deposit with Card",
850
- subtitle: "$50,000 limit \u2022 2 min"
974
+ subtitle: "$50,000 limit"
851
975
  },
852
976
  quotes: "Quotes"
853
977
  },
@@ -865,9 +989,16 @@ var en_default = {
865
989
 
866
990
  // src/lib/i18n.ts
867
991
  var i18n = en_default;
992
+ function interpolate(template, params) {
993
+ if (!params) return template;
994
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
995
+ const value = params[key];
996
+ return value !== void 0 ? String(value) : `{{${key}}}`;
997
+ });
998
+ }
868
999
 
869
1000
  // src/hooks/use-deposit-polling.ts
870
- import { useState as useState4, useEffect as useEffect2, useRef } from "react";
1001
+ import { useState as useState5, useEffect as useEffect3, useRef } from "react";
871
1002
  import {
872
1003
  queryExecutions,
873
1004
  ExecutionStatus
@@ -879,14 +1010,14 @@ function useDepositPolling({
879
1010
  onDepositSuccess,
880
1011
  onDepositError
881
1012
  }) {
882
- const [executions, setExecutions] = useState4([]);
883
- const [isPolling, setIsPolling] = useState4(false);
1013
+ const [executions, setExecutions] = useState5([]);
1014
+ const [isPolling, setIsPolling] = useState5(false);
884
1015
  const pollingIntervalRef = useRef(
885
1016
  null
886
1017
  );
887
- const [modalOpenedAt] = useState4(/* @__PURE__ */ new Date());
888
- const [trackedExecutions, setTrackedExecutions] = useState4(/* @__PURE__ */ new Map());
889
- useEffect2(() => {
1018
+ const [modalOpenedAt] = useState5(/* @__PURE__ */ new Date());
1019
+ const [trackedExecutions, setTrackedExecutions] = useState5(/* @__PURE__ */ new Map());
1020
+ useEffect3(() => {
890
1021
  if (!userId || !modalOpenedAt || !enabled) return;
891
1022
  const pollInterval = setInterval(async () => {
892
1023
  try {
@@ -989,10 +1120,10 @@ function useDepositPolling({
989
1120
  }
990
1121
 
991
1122
  // src/components/deposits/DepositPollingToasts.tsx
992
- import { useState as useState7 } from "react";
1123
+ import { useState as useState8 } from "react";
993
1124
 
994
1125
  // src/components/deposits/DepositSuccessToast.tsx
995
- import { useState as useState6 } from "react";
1126
+ import { useState as useState7 } from "react";
996
1127
  import { X as X3 } from "lucide-react";
997
1128
  import {
998
1129
  ExecutionStatus as ExecutionStatus3,
@@ -1000,7 +1131,7 @@ import {
1000
1131
  } from "@unifold/core";
1001
1132
 
1002
1133
  // src/components/deposits/DepositDetailContent.tsx
1003
- import { useEffect as useEffect3, useState as useState5 } from "react";
1134
+ import { useEffect as useEffect4, useState as useState6 } from "react";
1004
1135
  import { ExternalLink, ChevronDown, ChevronUp } from "lucide-react";
1005
1136
  import {
1006
1137
  ExecutionStatus as ExecutionStatus2,
@@ -1019,12 +1150,12 @@ function formatCurrency(currency) {
1019
1150
  }
1020
1151
  function DepositDetailContent({ execution }) {
1021
1152
  const { colors: colors2, fonts, components } = useTheme();
1022
- const [chains, setChains] = useState5([]);
1023
- const [showNetworkDetails, setShowNetworkDetails] = useState5(false);
1024
- useEffect3(() => {
1153
+ const [chains, setChains] = useState6([]);
1154
+ const [showNetworkDetails, setShowNetworkDetails] = useState6(false);
1155
+ useEffect4(() => {
1025
1156
  getTokenChains().then((response) => setChains(response.data)).catch((err) => console.error("Failed to fetch chains:", err));
1026
1157
  }, []);
1027
- useEffect3(() => {
1158
+ useEffect4(() => {
1028
1159
  setShowNetworkDetails(false);
1029
1160
  }, [execution?.id]);
1030
1161
  const isPending = execution.status === ExecutionStatus2.PENDING || execution.status === ExecutionStatus2.WAITING || execution.status === ExecutionStatus2.DELAYED;
@@ -1319,6 +1450,37 @@ function DepositDetailContent({ execution }) {
1319
1450
  ]
1320
1451
  }
1321
1452
  ),
1453
+ isPending && /* @__PURE__ */ jsxs6(
1454
+ "div",
1455
+ {
1456
+ className: "uf-flex uf-justify-between uf-items-center uf-px-4 uf-py-3 uf-border-b",
1457
+ style: { borderColor: colors2.border },
1458
+ children: [
1459
+ /* @__PURE__ */ jsx7(
1460
+ "span",
1461
+ {
1462
+ className: "uf-text-sm",
1463
+ style: {
1464
+ color: components.card.labelColor,
1465
+ fontFamily: fonts.regular
1466
+ },
1467
+ children: "Estimated delivery time"
1468
+ }
1469
+ ),
1470
+ /* @__PURE__ */ jsx7(
1471
+ "span",
1472
+ {
1473
+ style: {
1474
+ color: components.card.titleColor,
1475
+ fontFamily: fonts.regular,
1476
+ fontSize: "14px"
1477
+ },
1478
+ children: formatEstimatedTime(execution?.estimated_processing_time)
1479
+ }
1480
+ )
1481
+ ]
1482
+ }
1483
+ ),
1322
1484
  /* @__PURE__ */ jsxs6(
1323
1485
  "div",
1324
1486
  {
@@ -1505,7 +1667,7 @@ function DepositSuccessToast({
1505
1667
  onClose,
1506
1668
  execution
1507
1669
  }) {
1508
- const [detailModalOpen, setDetailModalOpen] = useState6(false);
1670
+ const [detailModalOpen, setDetailModalOpen] = useState7(false);
1509
1671
  const { themeClass, colors: colors2, fonts, components } = useTheme();
1510
1672
  const isPending = status === ExecutionStatus3.PENDING || status === ExecutionStatus3.WAITING || status === ExecutionStatus3.DELAYED;
1511
1673
  const formatDateTime = (timestamp) => {
@@ -1639,14 +1801,27 @@ function DepositSuccessToast({
1639
1801
  }
1640
1802
  )
1641
1803
  ] }),
1642
- /* @__PURE__ */ jsx8(
1643
- "div",
1644
- {
1645
- className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
1646
- style: { color: colors2.background },
1647
- children: formatUsdAmount(sourceAmountUsd)
1648
- }
1649
- ),
1804
+ /* @__PURE__ */ jsxs7("div", { className: "uf-flex-shrink-0 uf-text-right", children: [
1805
+ /* @__PURE__ */ jsx8(
1806
+ "div",
1807
+ {
1808
+ className: "uf-font-medium uf-text-sm",
1809
+ style: { color: colors2.background },
1810
+ children: formatUsdAmount(sourceAmountUsd)
1811
+ }
1812
+ ),
1813
+ isPending && execution?.estimated_processing_time && /* @__PURE__ */ jsxs7(
1814
+ "p",
1815
+ {
1816
+ className: "uf-text-xs",
1817
+ style: { color: colors2.foregroundMuted },
1818
+ children: [
1819
+ "Est. ",
1820
+ formatEstimatedTime(execution.estimated_processing_time)
1821
+ ]
1822
+ }
1823
+ )
1824
+ ] }),
1650
1825
  /* @__PURE__ */ jsx8(
1651
1826
  "button",
1652
1827
  {
@@ -1695,7 +1870,7 @@ function DepositPollingToasts({
1695
1870
  executions,
1696
1871
  horizontalPadding = "24px"
1697
1872
  }) {
1698
- const [closedExecutionIds, setClosedExecutionIds] = useState7(
1873
+ const [closedExecutionIds, setClosedExecutionIds] = useState8(
1699
1874
  /* @__PURE__ */ new Set()
1700
1875
  );
1701
1876
  const handleClose = (executionId) => {
@@ -1776,28 +1951,28 @@ function BuyWithCard({
1776
1951
  assetCdnUrl
1777
1952
  }) {
1778
1953
  const { colors: colors2, fonts, components } = useTheme();
1779
- const [amount, setAmount] = useState8("");
1780
- const [currency, setCurrency] = useState8("usd");
1781
- const [hasManualCurrencySelection, setHasManualCurrencySelection] = useState8(false);
1782
- const [hasManualAmountEntry, setHasManualAmountEntry] = useState8(false);
1783
- const [showCurrencyModal, setShowCurrencyModal] = useState8(false);
1784
- const [quotes, setQuotes] = useState8([]);
1785
- const [quotesLoading, setQuotesLoading] = useState8(false);
1786
- const [quotesError, setQuotesError] = useState8(null);
1787
- const [amountValidationError, setAmountValidationError] = useState8(null);
1788
- const [internalView, setInternalView] = useState8("amount");
1789
- const [defaultToken, setDefaultToken] = useState8(
1954
+ const [amount, setAmount] = useState9("");
1955
+ const [currency, setCurrency] = useState9("usd");
1956
+ const [hasManualCurrencySelection, setHasManualCurrencySelection] = useState9(false);
1957
+ const [hasManualAmountEntry, setHasManualAmountEntry] = useState9(false);
1958
+ const [showCurrencyModal, setShowCurrencyModal] = useState9(false);
1959
+ const [quotes, setQuotes] = useState9([]);
1960
+ const [quotesLoading, setQuotesLoading] = useState9(false);
1961
+ const [quotesError, setQuotesError] = useState9(null);
1962
+ const [amountValidationError, setAmountValidationError] = useState9(null);
1963
+ const [internalView, setInternalView] = useState9("amount");
1964
+ const [defaultToken, setDefaultToken] = useState9(
1790
1965
  null
1791
1966
  );
1792
- const [defaultTokenLoading, setDefaultTokenLoading] = useState8(false);
1967
+ const [defaultTokenLoading, setDefaultTokenLoading] = useState9(false);
1793
1968
  const { userIpInfo, isLoading: isLoadingIp } = useUserIp();
1794
- const [onrampSession, setOnrampSession] = useState8(
1969
+ const [onrampSession, setOnrampSession] = useState9(
1795
1970
  null
1796
1971
  );
1797
1972
  const currentView = externalView ?? internalView;
1798
1973
  const showQuotesView = currentView === "quotes";
1799
1974
  const showOnrampView = currentView === "onramp";
1800
- useEffect4(() => {
1975
+ useEffect5(() => {
1801
1976
  if (externalView) {
1802
1977
  setInternalView(externalView);
1803
1978
  }
@@ -1810,31 +1985,31 @@ function BuyWithCard({
1810
1985
  onViewChange?.(newView);
1811
1986
  }
1812
1987
  };
1813
- const [selectedProvider, setSelectedProvider] = useState8(
1988
+ const [selectedProvider, setSelectedProvider] = useState9(
1814
1989
  null
1815
1990
  );
1816
- const [isAutoSelected, setIsAutoSelected] = useState8(true);
1817
- const [autoSelectedProvider, setAutoSelectedProvider] = useState8(null);
1818
- const [hoveredProviderIndex, setHoveredProviderIndex] = useState8(null);
1819
- const [hasManualSelection, setHasManualSelection] = useState8(false);
1991
+ const [isAutoSelected, setIsAutoSelected] = useState9(true);
1992
+ const [autoSelectedProvider, setAutoSelectedProvider] = useState9(null);
1993
+ const [hoveredProviderIndex, setHoveredProviderIndex] = useState9(null);
1994
+ const [hasManualSelection, setHasManualSelection] = useState9(false);
1820
1995
  const selectedProviderRef = useRef2(null);
1821
1996
  const hasManualSelectionRef = useRef2(false);
1822
- useEffect4(() => {
1997
+ useEffect5(() => {
1823
1998
  selectedProviderRef.current = selectedProvider;
1824
1999
  }, [selectedProvider]);
1825
- useEffect4(() => {
2000
+ useEffect5(() => {
1826
2001
  hasManualSelectionRef.current = hasManualSelection;
1827
2002
  }, [hasManualSelection]);
1828
- const [internalWallets, setInternalWallets] = useState8([]);
1829
- const [walletsLoading, setWalletsLoading] = useState8(
2003
+ const [internalWallets, setInternalWallets] = useState9([]);
2004
+ const [walletsLoading, setWalletsLoading] = useState9(
1830
2005
  !externalWallets?.length
1831
2006
  );
1832
2007
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
1833
- const [countdown, setCountdown] = useState8(60);
1834
- const [fiatCurrencies, setFiatCurrencies] = useState8([]);
1835
- const [preferredCurrencyCodes, setPreferredCurrencyCodes] = useState8([]);
1836
- const [currenciesLoading, setCurrenciesLoading] = useState8(true);
1837
- const [destinationToken, setDestinationToken] = useState8(null);
2008
+ const [countdown, setCountdown] = useState9(60);
2009
+ const [fiatCurrencies, setFiatCurrencies] = useState9([]);
2010
+ const [preferredCurrencyCodes, setPreferredCurrencyCodes] = useState9([]);
2011
+ const [currenciesLoading, setCurrenciesLoading] = useState9(true);
2012
+ const [destinationToken, setDestinationToken] = useState9(null);
1838
2013
  const { executions, isPolling } = useDepositPolling({
1839
2014
  userId,
1840
2015
  publishableKey,
@@ -1846,7 +2021,7 @@ function BuyWithCard({
1846
2021
  const destinationTokenIcon = destinationToken?.icon_url;
1847
2022
  const destinationChainIcon = destinationToken?.chain_icon_url;
1848
2023
  const destinationChainName = destinationToken?.chain_name;
1849
- useEffect4(() => {
2024
+ useEffect5(() => {
1850
2025
  async function fetchFiatCurrencies() {
1851
2026
  try {
1852
2027
  const response = await getFiatCurrencies(publishableKey);
@@ -1860,7 +2035,7 @@ function BuyWithCard({
1860
2035
  }
1861
2036
  fetchFiatCurrencies();
1862
2037
  }, [publishableKey]);
1863
- useEffect4(() => {
2038
+ useEffect5(() => {
1864
2039
  if (hasManualCurrencySelection) return;
1865
2040
  if (fiatCurrencies.length === 0 || !userIpInfo?.alpha2) return;
1866
2041
  const userCountryCode = userIpInfo.alpha2.toUpperCase();
@@ -1888,7 +2063,7 @@ function BuyWithCard({
1888
2063
  hasManualAmountEntry
1889
2064
  ]);
1890
2065
  const prevCurrencyRef = useRef2(null);
1891
- useEffect4(() => {
2066
+ useEffect5(() => {
1892
2067
  if (fiatCurrencies.length === 0) return;
1893
2068
  if (prevCurrencyRef.current !== null && prevCurrencyRef.current !== currency) {
1894
2069
  const currentCurrency = fiatCurrencies.find(
@@ -1900,7 +2075,7 @@ function BuyWithCard({
1900
2075
  }
1901
2076
  prevCurrencyRef.current = currency;
1902
2077
  }, [currency]);
1903
- useEffect4(() => {
2078
+ useEffect5(() => {
1904
2079
  if (externalWallets?.length) {
1905
2080
  setWalletsLoading(false);
1906
2081
  return;
@@ -1953,7 +2128,7 @@ function BuyWithCard({
1953
2128
  publishableKey,
1954
2129
  externalWallets
1955
2130
  ]);
1956
- useEffect4(() => {
2131
+ useEffect5(() => {
1957
2132
  async function fetchDestinationToken() {
1958
2133
  try {
1959
2134
  const response = await getTokenMetadata(
@@ -1971,7 +2146,7 @@ function BuyWithCard({
1971
2146
  }
1972
2147
  fetchDestinationToken();
1973
2148
  }, [publishableKey]);
1974
- useEffect4(() => {
2149
+ useEffect5(() => {
1975
2150
  async function fetchDefaultToken() {
1976
2151
  if (!destinationTokenAddress || !destinationChainId || !destinationChainType) {
1977
2152
  return;
@@ -2007,7 +2182,7 @@ function BuyWithCard({
2007
2182
  isLoadingIp,
2008
2183
  publishableKey
2009
2184
  ]);
2010
- useEffect4(() => {
2185
+ useEffect5(() => {
2011
2186
  const amountNum = parseFloat(amount);
2012
2187
  if (isNaN(amountNum) || amountNum <= 0) {
2013
2188
  setQuotes([]);
@@ -2116,7 +2291,7 @@ function BuyWithCard({
2116
2291
  setQuotesLoading(false);
2117
2292
  }
2118
2293
  };
2119
- useEffect4(() => {
2294
+ useEffect5(() => {
2120
2295
  if (quotes.length === 0) return;
2121
2296
  const timer = setInterval(() => {
2122
2297
  setCountdown((prev) => {
@@ -2451,6 +2626,20 @@ function BuyWithCard({
2451
2626
  },
2452
2627
  children: quotesError
2453
2628
  }
2629
+ ),
2630
+ defaultToken?.estimated_processing_time && !quotesLoading && selectedProvider && /* @__PURE__ */ jsxs8(
2631
+ "div",
2632
+ {
2633
+ className: "uf-text-xs uf-mt-2 uf-px-1",
2634
+ style: {
2635
+ color: components.card.subtitleColor,
2636
+ fontFamily: fonts.regular
2637
+ },
2638
+ children: [
2639
+ "Estimated delivery time: ",
2640
+ formatEstimatedTime(defaultToken.estimated_processing_time)
2641
+ ]
2642
+ }
2454
2643
  )
2455
2644
  ] }),
2456
2645
  /* @__PURE__ */ jsx10(
@@ -2668,7 +2857,7 @@ function BuyWithCard({
2668
2857
  }
2669
2858
 
2670
2859
  // src/components/deposits/DepositsModal.tsx
2671
- import { useEffect as useEffect5, useState as useState9 } from "react";
2860
+ import { useEffect as useEffect6, useState as useState10 } from "react";
2672
2861
 
2673
2862
  // src/components/deposits/DepositExecutionItem.tsx
2674
2863
  import { ChevronRight as ChevronRight2 } from "lucide-react";
@@ -2913,9 +3102,9 @@ function DepositsModal({
2913
3102
  themeClass = ""
2914
3103
  }) {
2915
3104
  const { colors: colors2 } = useTheme();
2916
- const [allExecutions, setAllExecutions] = useState9(sessionExecutions);
2917
- const [selectedExecution, setSelectedExecution] = useState9(null);
2918
- useEffect5(() => {
3105
+ const [allExecutions, setAllExecutions] = useState10(sessionExecutions);
3106
+ const [selectedExecution, setSelectedExecution] = useState10(null);
3107
+ useEffect6(() => {
2919
3108
  if (!open || !userId) return;
2920
3109
  const fetchExecutions = async () => {
2921
3110
  try {
@@ -2937,7 +3126,7 @@ function DepositsModal({
2937
3126
  clearInterval(pollInterval);
2938
3127
  };
2939
3128
  }, [open, userId, publishableKey, sessionExecutions]);
2940
- useEffect5(() => {
3129
+ useEffect6(() => {
2941
3130
  if (!open) {
2942
3131
  setSelectedExecution(null);
2943
3132
  }
@@ -3325,8 +3514,68 @@ function useAllowedCountry(publishableKey) {
3325
3514
  };
3326
3515
  }
3327
3516
 
3517
+ // src/hooks/use-address-validation.ts
3518
+ import { useQuery as useQuery3 } from "@tanstack/react-query";
3519
+ import {
3520
+ verifyRecipientAddress
3521
+ } from "@unifold/core";
3522
+ function useAddressValidation({
3523
+ recipientAddress,
3524
+ destinationChainType,
3525
+ destinationChainId,
3526
+ destinationTokenAddress,
3527
+ publishableKey,
3528
+ enabled = true,
3529
+ refetchOnMount = false
3530
+ }) {
3531
+ const shouldValidate = enabled && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
3532
+ const { data, isLoading, error } = useQuery3({
3533
+ queryKey: [
3534
+ "unifold",
3535
+ "addressValidation",
3536
+ recipientAddress,
3537
+ destinationChainType,
3538
+ destinationChainId,
3539
+ destinationTokenAddress
3540
+ ],
3541
+ queryFn: () => verifyRecipientAddress(
3542
+ {
3543
+ chain_type: destinationChainType,
3544
+ chain_id: destinationChainId,
3545
+ token_address: destinationTokenAddress,
3546
+ recipient_address: recipientAddress
3547
+ },
3548
+ publishableKey
3549
+ ),
3550
+ enabled: shouldValidate,
3551
+ refetchOnMount,
3552
+ refetchOnReconnect: false,
3553
+ refetchOnWindowFocus: false,
3554
+ staleTime: 1e3 * 60 * 5,
3555
+ // 5 minutes - address state can change
3556
+ gcTime: 1e3 * 60 * 30
3557
+ // 30 minutes
3558
+ });
3559
+ if (!shouldValidate) {
3560
+ return {
3561
+ isValid: null,
3562
+ failureCode: null,
3563
+ metadata: null,
3564
+ isLoading: false,
3565
+ error: null
3566
+ };
3567
+ }
3568
+ return {
3569
+ isValid: data?.valid ?? null,
3570
+ failureCode: data?.failure_code ?? null,
3571
+ metadata: data?.metadata ?? null,
3572
+ isLoading,
3573
+ error: error ?? null
3574
+ };
3575
+ }
3576
+
3328
3577
  // src/components/deposits/TransferCryptoSingleInput.tsx
3329
- import { useState as useState14, useEffect as useEffect11 } from "react";
3578
+ import { useState as useState15, useEffect as useEffect12 } from "react";
3330
3579
  import {
3331
3580
  ChevronDown as ChevronDown3,
3332
3581
  ChevronUp as ChevronUp2,
@@ -3342,7 +3591,7 @@ import {
3342
3591
  } from "lucide-react";
3343
3592
 
3344
3593
  // src/components/deposits/StyledQRCode.tsx
3345
- import { useEffect as useEffect9, useRef as useRef3 } from "react";
3594
+ import { useEffect as useEffect10, useRef as useRef3 } from "react";
3346
3595
  import QRCodeStyling from "qr-code-styling";
3347
3596
  import { jsx as jsx17 } from "react/jsx-runtime";
3348
3597
  function StyledQRCode({
@@ -3354,7 +3603,7 @@ function StyledQRCode({
3354
3603
  }) {
3355
3604
  const ref = useRef3(null);
3356
3605
  const qrCodeRef = useRef3(null);
3357
- useEffect9(() => {
3606
+ useEffect10(() => {
3358
3607
  if (!ref.current) return;
3359
3608
  if (!qrCodeRef.current) {
3360
3609
  qrCodeRef.current = new QRCodeStyling({
@@ -3394,7 +3643,7 @@ function StyledQRCode({
3394
3643
  qrCodeRef.current.append(ref.current);
3395
3644
  }
3396
3645
  }, []);
3397
- useEffect9(() => {
3646
+ useEffect10(() => {
3398
3647
  if (qrCodeRef.current) {
3399
3648
  qrCodeRef.current.update({
3400
3649
  data: value,
@@ -3435,7 +3684,7 @@ function StyledQRCode({
3435
3684
  }
3436
3685
 
3437
3686
  // src/components/deposits/TokenSelectorSheet.tsx
3438
- import { useState as useState13, useMemo as useMemo3, useEffect as useEffect10 } from "react";
3687
+ import { useState as useState14, useMemo as useMemo3, useEffect as useEffect11 } from "react";
3439
3688
  import { ArrowLeft as ArrowLeft2, X as X4 } from "lucide-react";
3440
3689
  import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
3441
3690
  var STORAGE_KEY = "unifold_recent_tokens";
@@ -3493,10 +3742,10 @@ function TokenSelectorSheet({
3493
3742
  }) {
3494
3743
  const { themeClass, colors: colors2, fonts, components } = useTheme();
3495
3744
  const isDarkMode = themeClass.includes("uf-dark");
3496
- const [searchQuery, setSearchQuery] = useState13("");
3497
- const [recentTokens, setRecentTokens] = useState13([]);
3498
- const [hoveredTokenKey, setHoveredTokenKey] = useState13(null);
3499
- useEffect10(() => {
3745
+ const [searchQuery, setSearchQuery] = useState14("");
3746
+ const [recentTokens, setRecentTokens] = useState14([]);
3747
+ const [hoveredTokenKey, setHoveredTokenKey] = useState14(null);
3748
+ useEffect11(() => {
3500
3749
  setRecentTokens(getRecentTokens());
3501
3750
  }, []);
3502
3751
  const allOptions = useMemo3(() => {
@@ -3938,13 +4187,13 @@ function TransferCryptoSingleInput({
3938
4187
  }) {
3939
4188
  const { themeClass, colors: colors2, fonts, components } = useTheme();
3940
4189
  const isDarkMode = themeClass.includes("uf-dark");
3941
- const [token, setToken] = useState14("USDC");
3942
- const [chain, setChain] = useState14("solana:mainnet");
3943
- const [copied, setCopied] = useState14(false);
3944
- const [internalWallets, setInternalWallets] = useState14([]);
3945
- const [loading, setLoading] = useState14(!externalWallets?.length);
4190
+ const [token, setToken] = useState15("USDC");
4191
+ const [chain, setChain] = useState15("solana:mainnet");
4192
+ const [copied, setCopied] = useState15(false);
4193
+ const [internalWallets, setInternalWallets] = useState15([]);
4194
+ const [loading, setLoading] = useState15(!externalWallets?.length);
3946
4195
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
3947
- const [error, setError] = useState14(null);
4196
+ const [error, setError] = useState15(null);
3948
4197
  const { executions: depositExecutions, isPolling } = useDepositPolling({
3949
4198
  userId,
3950
4199
  publishableKey,
@@ -3952,11 +4201,11 @@ function TransferCryptoSingleInput({
3952
4201
  onDepositSuccess,
3953
4202
  onDepositError
3954
4203
  });
3955
- const [supportedTokens, setSupportedTokens] = useState14([]);
3956
- const [tokensLoading, setTokensLoading] = useState14(true);
3957
- const [detailsExpanded, setDetailsExpanded] = useState14(false);
3958
- const [depositsModalOpen, setDepositsModalOpen] = useState14(false);
3959
- const [tokenSelectorOpen, setTokenSelectorOpen] = useState14(false);
4204
+ const [supportedTokens, setSupportedTokens] = useState15([]);
4205
+ const [tokensLoading, setTokensLoading] = useState15(true);
4206
+ const [detailsExpanded, setDetailsExpanded] = useState15(false);
4207
+ const [depositsModalOpen, setDepositsModalOpen] = useState15(false);
4208
+ const [tokenSelectorOpen, setTokenSelectorOpen] = useState15(false);
3960
4209
  const allChainsMap = /* @__PURE__ */ new Map();
3961
4210
  supportedTokens.forEach((t5) => {
3962
4211
  t5.chains.forEach((c) => {
@@ -3974,7 +4223,7 @@ function TransferCryptoSingleInput({
3974
4223
  const currentChainType = currentChainData?.chain_type || "ethereum";
3975
4224
  const currentWallet = getWalletByChainType2(wallets, currentChainType);
3976
4225
  const depositAddress = currentWallet?.address || "";
3977
- useEffect11(() => {
4226
+ useEffect12(() => {
3978
4227
  async function fetchSupportedTokens() {
3979
4228
  try {
3980
4229
  setTokensLoading(true);
@@ -4046,12 +4295,12 @@ function TransferCryptoSingleInput({
4046
4295
  destinationChainId,
4047
4296
  destinationChainType
4048
4297
  ]);
4049
- useEffect11(() => {
4298
+ useEffect12(() => {
4050
4299
  if (onExecutionsChange) {
4051
4300
  onExecutionsChange(depositExecutions);
4052
4301
  }
4053
4302
  }, [depositExecutions, onExecutionsChange]);
4054
- useEffect11(() => {
4303
+ useEffect12(() => {
4055
4304
  if (externalWallets?.length) {
4056
4305
  setLoading(false);
4057
4306
  return;
@@ -4108,7 +4357,7 @@ function TransferCryptoSingleInput({
4108
4357
  publishableKey,
4109
4358
  externalWallets
4110
4359
  ]);
4111
- useEffect11(() => {
4360
+ useEffect12(() => {
4112
4361
  if (!supportedTokens.length) return;
4113
4362
  const currentToken = supportedTokens.find((t5) => t5.symbol === token);
4114
4363
  if (!currentToken || currentToken.chains.length === 0) return;
@@ -4486,7 +4735,7 @@ function TransferCryptoSingleInput({
4486
4735
  }
4487
4736
 
4488
4737
  // src/components/deposits/TransferCryptoDoubleInput.tsx
4489
- import { useState as useState15, useEffect as useEffect12 } from "react";
4738
+ import { useState as useState16, useEffect as useEffect13 } from "react";
4490
4739
  import {
4491
4740
  ChevronDown as ChevronDown5,
4492
4741
  ChevronUp as ChevronUp4,
@@ -4651,13 +4900,13 @@ function TransferCryptoDoubleInput({
4651
4900
  }) {
4652
4901
  const { themeClass, colors: colors2, fonts, components } = useTheme();
4653
4902
  const isDarkMode = themeClass.includes("uf-dark");
4654
- const [token, setToken] = useState15("USDC");
4655
- const [chain, setChain] = useState15("solana:mainnet");
4656
- const [copied, setCopied] = useState15(false);
4657
- const [internalWallets, setInternalWallets] = useState15([]);
4658
- const [loading, setLoading] = useState15(!externalWallets?.length);
4903
+ const [token, setToken] = useState16("USDC");
4904
+ const [chain, setChain] = useState16("solana:mainnet");
4905
+ const [copied, setCopied] = useState16(false);
4906
+ const [internalWallets, setInternalWallets] = useState16([]);
4907
+ const [loading, setLoading] = useState16(!externalWallets?.length);
4659
4908
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
4660
- const [error, setError] = useState15(null);
4909
+ const [error, setError] = useState16(null);
4661
4910
  const { executions: depositExecutions, isPolling } = useDepositPolling({
4662
4911
  userId,
4663
4912
  publishableKey,
@@ -4665,10 +4914,10 @@ function TransferCryptoDoubleInput({
4665
4914
  onDepositSuccess,
4666
4915
  onDepositError
4667
4916
  });
4668
- const [supportedTokens, setSupportedTokens] = useState15([]);
4669
- const [tokensLoading, setTokensLoading] = useState15(true);
4670
- const [detailsExpanded, setDetailsExpanded] = useState15(false);
4671
- const [depositsModalOpen, setDepositsModalOpen] = useState15(false);
4917
+ const [supportedTokens, setSupportedTokens] = useState16([]);
4918
+ const [tokensLoading, setTokensLoading] = useState16(true);
4919
+ const [detailsExpanded, setDetailsExpanded] = useState16(false);
4920
+ const [depositsModalOpen, setDepositsModalOpen] = useState16(false);
4672
4921
  const allChainsMap = /* @__PURE__ */ new Map();
4673
4922
  supportedTokens.forEach((t5) => {
4674
4923
  t5.chains.forEach((c) => {
@@ -4686,7 +4935,7 @@ function TransferCryptoDoubleInput({
4686
4935
  const currentChainType = currentChainData?.chain_type || "ethereum";
4687
4936
  const currentWallet = getWalletByChainType3(wallets, currentChainType);
4688
4937
  const depositAddress = currentWallet?.address || "";
4689
- useEffect12(() => {
4938
+ useEffect13(() => {
4690
4939
  async function fetchSupportedTokens() {
4691
4940
  try {
4692
4941
  setTokensLoading(true);
@@ -4729,12 +4978,12 @@ function TransferCryptoDoubleInput({
4729
4978
  destinationChainId,
4730
4979
  destinationChainType
4731
4980
  ]);
4732
- useEffect12(() => {
4981
+ useEffect13(() => {
4733
4982
  if (onExecutionsChange) {
4734
4983
  onExecutionsChange(depositExecutions);
4735
4984
  }
4736
4985
  }, [depositExecutions, onExecutionsChange]);
4737
- useEffect12(() => {
4986
+ useEffect13(() => {
4738
4987
  if (externalWallets?.length) {
4739
4988
  setLoading(false);
4740
4989
  return;
@@ -4791,7 +5040,7 @@ function TransferCryptoDoubleInput({
4791
5040
  publishableKey,
4792
5041
  externalWallets
4793
5042
  ]);
4794
- useEffect12(() => {
5043
+ useEffect13(() => {
4795
5044
  if (!supportedTokens.length) return;
4796
5045
  const currentToken = supportedTokens.find((t5) => t5.symbol === token);
4797
5046
  if (!currentToken || currentToken.chains.length === 0) return;
@@ -5242,26 +5491,27 @@ function DepositModal({
5242
5491
  destinationChainId,
5243
5492
  destinationTokenAddress,
5244
5493
  hideDepositTracker = false,
5494
+ showBalanceHeader = false,
5245
5495
  transferInputVariant = "double_input",
5246
5496
  onDepositSuccess,
5247
5497
  onDepositError,
5248
5498
  theme = "dark"
5249
5499
  }) {
5250
- const { colors: colors2 } = useTheme();
5251
- const [view, setView] = useState16("main");
5252
- const [cardView, setCardView] = useState16(
5500
+ const { colors: colors2, fonts } = useTheme();
5501
+ const [view, setView] = useState17("main");
5502
+ const [cardView, setCardView] = useState17(
5253
5503
  "amount"
5254
5504
  );
5255
- const [quotesCount, setQuotesCount] = useState16(0);
5256
- const [depositsModalOpen, setDepositsModalOpen] = useState16(false);
5257
- const [depositExecutions, setDepositExecutions] = useState16([]);
5258
- const [projectConfig, setProjectConfig] = useState16(null);
5259
- const [wallets, setWallets] = useState16([]);
5260
- const [walletsLoading, setWalletsLoading] = useState16(false);
5261
- useEffect13(() => {
5505
+ const [quotesCount, setQuotesCount] = useState17(0);
5506
+ const [depositsModalOpen, setDepositsModalOpen] = useState17(false);
5507
+ const [depositExecutions, setDepositExecutions] = useState17([]);
5508
+ const [projectConfig, setProjectConfig] = useState17(null);
5509
+ const [wallets, setWallets] = useState17([]);
5510
+ const [walletsLoading, setWalletsLoading] = useState17(false);
5511
+ useEffect14(() => {
5262
5512
  setProjectConfig(null);
5263
5513
  }, [publishableKey]);
5264
- useEffect13(() => {
5514
+ useEffect14(() => {
5265
5515
  setWallets([]);
5266
5516
  }, [
5267
5517
  userId,
@@ -5271,10 +5521,10 @@ function DepositModal({
5271
5521
  destinationTokenAddress,
5272
5522
  publishableKey
5273
5523
  ]);
5274
- const [resolvedTheme, setResolvedTheme] = useState16(
5524
+ const [resolvedTheme, setResolvedTheme] = useState17(
5275
5525
  theme === "auto" ? "dark" : theme
5276
5526
  );
5277
- useEffect13(() => {
5527
+ useEffect14(() => {
5278
5528
  if (theme === "auto") {
5279
5529
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
5280
5530
  setResolvedTheme(mediaQuery.matches ? "dark" : "light");
@@ -5287,7 +5537,7 @@ function DepositModal({
5287
5537
  setResolvedTheme(theme);
5288
5538
  }
5289
5539
  }, [theme]);
5290
- useEffect13(() => {
5540
+ useEffect14(() => {
5291
5541
  if (open && !projectConfig) {
5292
5542
  getProjectConfig2(publishableKey).then(setProjectConfig).catch(console.error);
5293
5543
  }
@@ -5297,7 +5547,29 @@ function DepositModal({
5297
5547
  isLoading: isCountryLoading,
5298
5548
  error: countryError
5299
5549
  } = useAllowedCountry(publishableKey);
5300
- useEffect13(() => {
5550
+ const {
5551
+ isValid: isAddressValid,
5552
+ failureCode: addressFailureCode,
5553
+ metadata: addressFailureMetadata,
5554
+ isLoading: isAddressValidationLoading
5555
+ } = useAddressValidation({
5556
+ recipientAddress,
5557
+ destinationChainType,
5558
+ destinationChainId,
5559
+ destinationTokenAddress,
5560
+ publishableKey,
5561
+ enabled: open,
5562
+ // Only validate when modal is open
5563
+ refetchOnMount: "always"
5564
+ });
5565
+ const addressValidationMessages = i18n.transferCrypto.addressValidation;
5566
+ const getAddressValidationErrorMessage = (code, metadata) => {
5567
+ if (!code) return addressValidationMessages.defaultError;
5568
+ const errors = addressValidationMessages.errors;
5569
+ const template = errors[code] ?? addressValidationMessages.defaultError;
5570
+ return interpolate(template, metadata);
5571
+ };
5572
+ useEffect14(() => {
5301
5573
  if (!open || wallets.length > 0) return;
5302
5574
  let retryTimeout = null;
5303
5575
  let isCancelled = false;
@@ -5381,10 +5653,16 @@ function DepositModal({
5381
5653
  DepositHeader,
5382
5654
  {
5383
5655
  title: modalTitle || "Deposit",
5384
- onClose: handleClose
5656
+ onClose: handleClose,
5657
+ showBalance: showBalanceHeader,
5658
+ balanceAddress: recipientAddress,
5659
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
5660
+ balanceChainId: destinationChainId,
5661
+ balanceTokenAddress: destinationTokenAddress,
5662
+ publishableKey
5385
5663
  }
5386
5664
  ),
5387
- /* @__PURE__ */ jsx23("div", { className: "uf-pb-4 uf-space-y-3", children: isCountryLoading || !projectConfig ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
5665
+ /* @__PURE__ */ jsx23("div", { className: "uf-pb-4 uf-space-y-3", children: isCountryLoading || isAddressValidationLoading || !projectConfig ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
5388
5666
  /* @__PURE__ */ jsx23(SkeletonButton, { variant: "with-icons" }),
5389
5667
  /* @__PURE__ */ jsx23(SkeletonButton, { variant: "with-icons" }),
5390
5668
  !hideDepositTracker && /* @__PURE__ */ jsx23(SkeletonButton, {})
@@ -5402,6 +5680,16 @@ function DepositModal({
5402
5680
  /* @__PURE__ */ jsx23("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: "No Tokens Available" }),
5403
5681
  /* @__PURE__ */ jsx23("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: "There are no supported tokens available from your current location." })
5404
5682
  ] })
5683
+ ) : isAddressValid === false ? (
5684
+ /* Invalid recipient address state (e.g., Algorand not opted in) */
5685
+ /* @__PURE__ */ jsxs18("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
5686
+ /* @__PURE__ */ jsx23("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__ */ jsx23(AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
5687
+ /* @__PURE__ */ jsx23("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: addressValidationMessages.unableToReceiveFunds }),
5688
+ /* @__PURE__ */ jsx23("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: getAddressValidationErrorMessage(
5689
+ addressFailureCode,
5690
+ addressFailureMetadata
5691
+ ) })
5692
+ ] })
5405
5693
  ) : (
5406
5694
  /* Normal deposit options */
5407
5695
  /* @__PURE__ */ jsxs18(Fragment5, { children: [