@unifold/ui-react 0.1.21 → 0.1.23

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
@@ -79,13 +79,14 @@ __export(index_exports, {
79
79
  getColors: () => getColors,
80
80
  mergeColors: () => mergeColors,
81
81
  resolveComponentTokens: () => resolveComponentTokens,
82
+ truncateAddress: () => truncateAddress,
82
83
  useAllowedCountry: () => useAllowedCountry,
83
84
  useTheme: () => useTheme
84
85
  });
85
86
  module.exports = __toCommonJS(index_exports);
86
87
 
87
88
  // src/components/deposits/DepositModal.tsx
88
- var import_react12 = require("react");
89
+ var import_react13 = require("react");
89
90
  var import_lucide_react15 = require("lucide-react");
90
91
 
91
92
  // src/components/shared/dialog.tsx
@@ -99,6 +100,35 @@ var import_tailwind_merge = require("tailwind-merge");
99
100
  function cn(...inputs) {
100
101
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
101
102
  }
103
+ function truncateAddress(address, startChars = 10, endChars = 8) {
104
+ if (!address) return "";
105
+ const totalChars = startChars + endChars + 3;
106
+ if (address.length <= totalChars) return address;
107
+ return `${address.slice(0, startChars)}...${address.slice(-endChars)}`;
108
+ }
109
+ function formatEstimatedTime(seconds) {
110
+ if (seconds == null) {
111
+ return "< 1 min";
112
+ }
113
+ if (seconds < 60) {
114
+ return `< ${seconds} sec${seconds > 1 ? "s" : ""}`;
115
+ } else if (seconds < 3600) {
116
+ const mins = Math.ceil(seconds / 60);
117
+ return `< ${mins} min${mins > 1 ? "s" : ""}`;
118
+ } else {
119
+ let hrs = Math.floor(seconds / 3600);
120
+ let mins = Math.ceil(seconds % 3600 / 60);
121
+ if (mins === 60) {
122
+ hrs += 1;
123
+ mins = 0;
124
+ }
125
+ const hrLabel = hrs > 1 ? "hrs" : "hr";
126
+ if (mins === 0) {
127
+ return `< ${hrs} ${hrLabel}`;
128
+ }
129
+ return `< ${hrs} ${hrLabel} ${mins} min${mins > 1 ? "s" : ""}`;
130
+ }
131
+ }
102
132
 
103
133
  // src/context/ThemeContext.tsx
104
134
  var React = __toESM(require("react"));
@@ -552,15 +582,17 @@ var DialogDescription = React2.forwardRef(({ className, ...props }, ref) => /* @
552
582
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
553
583
 
554
584
  // src/components/deposits/BuyWithCard.tsx
555
- var import_react6 = require("react");
585
+ var import_react7 = require("react");
556
586
  var import_lucide_react6 = require("lucide-react");
557
- var import_core6 = require("@unifold/core");
587
+ var import_core7 = require("@unifold/core");
558
588
 
559
589
  // src/components/deposits/CurrencyModal.tsx
560
- var import_react = require("react");
590
+ var import_react2 = require("react");
561
591
 
562
592
  // src/components/deposits/DepositHeader.tsx
563
593
  var import_lucide_react2 = require("lucide-react");
594
+ var import_react = require("react");
595
+ var import_core = require("@unifold/core");
564
596
  var import_jsx_runtime3 = require("react/jsx-runtime");
565
597
  function DepositHeader({
566
598
  title,
@@ -568,10 +600,83 @@ function DepositHeader({
568
600
  showClose = true,
569
601
  onBack,
570
602
  onClose,
571
- badge
603
+ badge,
604
+ showBalance = false,
605
+ balanceAddress,
606
+ balanceChainType,
607
+ balanceChainId,
608
+ balanceTokenAddress,
609
+ publishableKey
572
610
  }) {
573
611
  const { colors: colors2, fonts, components } = useTheme();
574
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
612
+ const [balance, setBalance] = (0, import_react.useState)(null);
613
+ const [isLoadingBalance, setIsLoadingBalance] = (0, import_react.useState)(false);
614
+ (0, import_react.useEffect)(() => {
615
+ if (!showBalance || !balanceAddress || !balanceChainType || !balanceChainId || !balanceTokenAddress || !publishableKey) {
616
+ setBalance(null);
617
+ setIsLoadingBalance(false);
618
+ return;
619
+ }
620
+ let cancelled = false;
621
+ setIsLoadingBalance(true);
622
+ (0, import_core.getAddressBalance)(
623
+ balanceAddress,
624
+ balanceChainType,
625
+ balanceChainId,
626
+ balanceTokenAddress,
627
+ publishableKey
628
+ ).then((response) => {
629
+ if (cancelled) return;
630
+ if (response.balance && response.balance.amount !== "0") {
631
+ const value = Number(response.balance.amount) / 10 ** response.balance.token.decimals;
632
+ let formatted;
633
+ let maxDecimals = 4;
634
+ const symbol = response.balance.token.symbol?.toUpperCase() || "";
635
+ if (symbol === "BTC" || symbol === "WBTC") {
636
+ maxDecimals = 8;
637
+ } else if (symbol === "ETH" || symbol === "WETH") {
638
+ maxDecimals = 6;
639
+ }
640
+ if (value >= 1) {
641
+ formatted = value.toLocaleString(void 0, {
642
+ minimumFractionDigits: 2,
643
+ maximumFractionDigits: maxDecimals
644
+ });
645
+ } else if (value > 0) {
646
+ formatted = value.toLocaleString(void 0, {
647
+ minimumFractionDigits: 2,
648
+ maximumFractionDigits: maxDecimals,
649
+ minimumSignificantDigits: 2,
650
+ maximumSignificantDigits: 6
651
+ });
652
+ } else {
653
+ formatted = value.toExponential(2);
654
+ }
655
+ const balanceText = response.balance.amount_usd ? `Balance: $${response.balance.amount_usd} (${formatted} ${response.balance.token.symbol})` : `Balance: ${formatted} ${response.balance.token.symbol}`;
656
+ setBalance(balanceText);
657
+ } else {
658
+ setBalance(null);
659
+ }
660
+ }).catch((error) => {
661
+ if (cancelled) return;
662
+ console.error("Error fetching balance:", error);
663
+ setBalance(null);
664
+ }).finally(() => {
665
+ if (cancelled) return;
666
+ setIsLoadingBalance(false);
667
+ });
668
+ return () => {
669
+ cancelled = true;
670
+ };
671
+ }, [
672
+ showBalance,
673
+ balanceAddress,
674
+ balanceChainType,
675
+ balanceChainId,
676
+ balanceTokenAddress,
677
+ publishableKey
678
+ ]);
679
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
575
680
  showBack ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
576
681
  "button",
577
682
  {
@@ -581,8 +686,32 @@ function DepositHeader({
581
686
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ArrowLeft, { className: "uf-w-5 uf-h-5" })
582
687
  }
583
688
  ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "uf-w-5 uf-h-5 uf-invisible" }),
584
- badge ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
585
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
689
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center", children: [
690
+ badge ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
691
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
692
+ DialogTitle,
693
+ {
694
+ className: "uf-text-center uf-text-base",
695
+ style: {
696
+ color: components.header.titleColor,
697
+ fontFamily: fonts.medium
698
+ },
699
+ children: title
700
+ }
701
+ ),
702
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
703
+ "div",
704
+ {
705
+ className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
706
+ style: {
707
+ backgroundColor: colors2.card,
708
+ color: colors2.foregroundMuted,
709
+ fontFamily: fonts.regular
710
+ },
711
+ children: badge.count
712
+ }
713
+ )
714
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
586
715
  DialogTitle,
587
716
  {
588
717
  className: "uf-text-center uf-text-base",
@@ -593,29 +722,19 @@ function DepositHeader({
593
722
  children: title
594
723
  }
595
724
  ),
596
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
725
+ showBalance && (isLoadingBalance ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "uf-h-3 uf-w-32 uf-bg-muted uf-rounded uf-animate-pulse uf-mt-2" }) : balance ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
597
726
  "div",
598
727
  {
599
- className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
728
+ className: "uf-text-xs uf-mt-2",
600
729
  style: {
601
- backgroundColor: colors2.card,
602
- color: colors2.foregroundMuted,
603
- fontFamily: fonts.regular
730
+ color: colors2.foreground,
731
+ fontFamily: fonts.regular,
732
+ opacity: 0.7
604
733
  },
605
- children: badge.count
734
+ children: balance
606
735
  }
607
- )
608
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
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
- ),
736
+ ) : null)
737
+ ] }),
619
738
  showClose ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
620
739
  "button",
621
740
  {
@@ -625,13 +744,13 @@ function DepositHeader({
625
744
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.X, { className: "uf-w-5 uf-h-5" })
626
745
  }
627
746
  ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "uf-w-5 uf-h-5 uf-invisible" })
628
- ] });
747
+ ] }) });
629
748
  }
630
749
 
631
750
  // src/components/currency/CurrencyListItem.tsx
632
751
  var React3 = __toESM(require("react"));
633
752
  var import_lucide_react3 = require("lucide-react");
634
- var import_core = require("@unifold/core");
753
+ var import_core2 = require("@unifold/core");
635
754
  var import_jsx_runtime4 = require("react/jsx-runtime");
636
755
  function CurrencyListItem({
637
756
  currency,
@@ -640,7 +759,7 @@ function CurrencyListItem({
640
759
  }) {
641
760
  const { colors: colors2, fonts, components } = useTheme();
642
761
  const [isHovered, setIsHovered] = React3.useState(false);
643
- const iconUrl = (0, import_core.getPreferredIconUrl)(currency.icon_urls, "png") || currency.icon_url;
762
+ const iconUrl = (0, import_core2.getPreferredIconUrl)(currency.icon_urls, "png") || currency.icon_url;
644
763
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
645
764
  "button",
646
765
  {
@@ -738,7 +857,7 @@ function CurrencyModal({
738
857
  themeClass = ""
739
858
  }) {
740
859
  const { colors: colors2, fonts, components } = useTheme();
741
- const [searchQuery, setSearchQuery] = (0, import_react.useState)("");
860
+ const [searchQuery, setSearchQuery] = (0, import_react2.useState)("");
742
861
  const preferredCurrencies = preferredCurrencyCodes.map(
743
862
  (code) => currencies.find(
744
863
  (currency) => currency.currency_code.toLowerCase() === code.toLowerCase()
@@ -834,7 +953,7 @@ function CurrencyModal({
834
953
 
835
954
  // src/hooks/use-user-ip.ts
836
955
  var import_react_query = require("@tanstack/react-query");
837
- var import_core2 = require("@unifold/core");
956
+ var import_core3 = require("@unifold/core");
838
957
  function useUserIp() {
839
958
  const {
840
959
  data: userIpInfo,
@@ -843,7 +962,7 @@ function useUserIp() {
843
962
  } = (0, import_react_query.useQuery)({
844
963
  queryKey: ["unifold", "userIpInfo"],
845
964
  queryFn: async () => {
846
- const data = await (0, import_core2.getIpAddress)();
965
+ const data = await (0, import_core3.getIpAddress)();
847
966
  return {
848
967
  alpha2: data.alpha2.toLowerCase(),
849
968
  alpha3: data.alpha3?.toLowerCase(),
@@ -899,8 +1018,8 @@ var en_default = {
899
1018
  seeTerms: "See terms",
900
1019
  termsApply: "Terms apply"
901
1020
  },
902
- supportedToken: "Supported token",
903
- supportedChain: "Supported chain",
1021
+ selectedToken: "Selected token",
1022
+ selectedChain: "Selected chain",
904
1023
  depositAddress: {
905
1024
  label: "Your deposit address",
906
1025
  tooltip: "Send any supported token to this address, and it will be automatically converted to {{token}} in your account."
@@ -914,7 +1033,19 @@ var en_default = {
914
1033
  minimumDeposit: "Minimum: {{amount}}",
915
1034
  minimumDepositTooltip: "The minimum amount you can deposit on the selected network.",
916
1035
  selectTokenDeposit: "Your deposit token",
917
- selectTokenDepositTooltip: "Select the token you want to deposit with in order to begin the deposit process."
1036
+ selectTokenDepositTooltip: "Select the token you want to deposit with in order to begin the deposit process.",
1037
+ addressValidation: {
1038
+ validating: "Verifying recipient address...",
1039
+ unableToReceiveFunds: "Unable to Receive Funds",
1040
+ errors: {
1041
+ token_not_supported: "The destination token is not supported",
1042
+ not_opted_in: "Please make sure you opt-in {{token_symbol}}({{chain_name}}) before receiving funds",
1043
+ insufficient_balance: "Recipient account does not meet the minimum balance requirement",
1044
+ account_not_found: "Recipient account does not exist on {{chain_name}}",
1045
+ validation_error: "Unable to verify recipient address on {{chain_name}}"
1046
+ },
1047
+ defaultError: "The recipient address cannot receive funds for the selected token"
1048
+ }
918
1049
  },
919
1050
  depositModal: {
920
1051
  transferCrypto: {
@@ -923,7 +1054,7 @@ var en_default = {
923
1054
  },
924
1055
  depositWithCard: {
925
1056
  title: "Deposit with Card",
926
- subtitle: "$50,000 limit \u2022 2 min"
1057
+ subtitle: "$50,000 limit"
927
1058
  },
928
1059
  quotes: "Quotes"
929
1060
  },
@@ -941,10 +1072,17 @@ var en_default = {
941
1072
 
942
1073
  // src/lib/i18n.ts
943
1074
  var i18n = en_default;
1075
+ function interpolate(template, params) {
1076
+ if (!params) return template;
1077
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
1078
+ const value = params[key];
1079
+ return value !== void 0 ? String(value) : `{{${key}}}`;
1080
+ });
1081
+ }
944
1082
 
945
1083
  // src/hooks/use-deposit-polling.ts
946
- var import_react2 = require("react");
947
- var import_core3 = require("@unifold/core");
1084
+ var import_react3 = require("react");
1085
+ var import_core4 = require("@unifold/core");
948
1086
  function useDepositPolling({
949
1087
  userId,
950
1088
  publishableKey,
@@ -952,18 +1090,18 @@ function useDepositPolling({
952
1090
  onDepositSuccess,
953
1091
  onDepositError
954
1092
  }) {
955
- const [executions, setExecutions] = (0, import_react2.useState)([]);
956
- const [isPolling, setIsPolling] = (0, import_react2.useState)(false);
957
- const pollingIntervalRef = (0, import_react2.useRef)(
1093
+ const [executions, setExecutions] = (0, import_react3.useState)([]);
1094
+ const [isPolling, setIsPolling] = (0, import_react3.useState)(false);
1095
+ const pollingIntervalRef = (0, import_react3.useRef)(
958
1096
  null
959
1097
  );
960
- const [modalOpenedAt] = (0, import_react2.useState)(/* @__PURE__ */ new Date());
961
- const [trackedExecutions, setTrackedExecutions] = (0, import_react2.useState)(/* @__PURE__ */ new Map());
962
- (0, import_react2.useEffect)(() => {
1098
+ const [modalOpenedAt] = (0, import_react3.useState)(/* @__PURE__ */ new Date());
1099
+ const [trackedExecutions, setTrackedExecutions] = (0, import_react3.useState)(/* @__PURE__ */ new Map());
1100
+ (0, import_react3.useEffect)(() => {
963
1101
  if (!userId || !modalOpenedAt || !enabled) return;
964
1102
  const pollInterval = setInterval(async () => {
965
1103
  try {
966
- const response = await (0, import_core3.queryExecutions)(userId, publishableKey);
1104
+ const response = await (0, import_core4.queryExecutions)(userId, publishableKey);
967
1105
  let executionToShow = null;
968
1106
  for (const execution of response.data) {
969
1107
  const executionTime = execution.created_at ? new Date(execution.created_at) : null;
@@ -976,13 +1114,13 @@ function useDepositPolling({
976
1114
  break;
977
1115
  }
978
1116
  const inProgressStatuses = [
979
- import_core3.ExecutionStatus.PENDING,
980
- import_core3.ExecutionStatus.WAITING,
981
- import_core3.ExecutionStatus.DELAYED
1117
+ import_core4.ExecutionStatus.PENDING,
1118
+ import_core4.ExecutionStatus.WAITING,
1119
+ import_core4.ExecutionStatus.DELAYED
982
1120
  ];
983
1121
  const terminalStatuses = [
984
- import_core3.ExecutionStatus.SUCCEEDED,
985
- import_core3.ExecutionStatus.FAILED
1122
+ import_core4.ExecutionStatus.SUCCEEDED,
1123
+ import_core4.ExecutionStatus.FAILED
986
1124
  ];
987
1125
  if (inProgressStatuses.includes(trackedStatus) && terminalStatuses.includes(execution.status)) {
988
1126
  executionToShow = execution;
@@ -1008,17 +1146,17 @@ function useDepositPolling({
1008
1146
  return updated;
1009
1147
  });
1010
1148
  const inProgressStatuses = [
1011
- import_core3.ExecutionStatus.PENDING,
1012
- import_core3.ExecutionStatus.WAITING,
1013
- import_core3.ExecutionStatus.DELAYED
1149
+ import_core4.ExecutionStatus.PENDING,
1150
+ import_core4.ExecutionStatus.WAITING,
1151
+ import_core4.ExecutionStatus.DELAYED
1014
1152
  ];
1015
- if (execution.status === import_core3.ExecutionStatus.SUCCEEDED && onDepositSuccess && (!previousStatus || inProgressStatuses.includes(previousStatus))) {
1153
+ if (execution.status === import_core4.ExecutionStatus.SUCCEEDED && onDepositSuccess && (!previousStatus || inProgressStatuses.includes(previousStatus))) {
1016
1154
  onDepositSuccess({
1017
1155
  message: "Deposit completed successfully",
1018
1156
  executionId: execution.id,
1019
1157
  transaction: execution
1020
1158
  });
1021
- } else if (execution.status === import_core3.ExecutionStatus.FAILED && onDepositError && previousStatus !== import_core3.ExecutionStatus.FAILED) {
1159
+ } else if (execution.status === import_core4.ExecutionStatus.FAILED && onDepositError && previousStatus !== import_core4.ExecutionStatus.FAILED) {
1022
1160
  onDepositError({
1023
1161
  message: "Deposit failed",
1024
1162
  code: "DEPOSIT_FAILED",
@@ -1062,17 +1200,17 @@ function useDepositPolling({
1062
1200
  }
1063
1201
 
1064
1202
  // src/components/deposits/DepositPollingToasts.tsx
1065
- var import_react5 = require("react");
1203
+ var import_react6 = require("react");
1066
1204
 
1067
1205
  // src/components/deposits/DepositSuccessToast.tsx
1068
- var import_react4 = require("react");
1206
+ var import_react5 = require("react");
1069
1207
  var import_lucide_react5 = require("lucide-react");
1070
- var import_core5 = require("@unifold/core");
1208
+ var import_core6 = require("@unifold/core");
1071
1209
 
1072
1210
  // src/components/deposits/DepositDetailContent.tsx
1073
- var import_react3 = require("react");
1211
+ var import_react4 = require("react");
1074
1212
  var import_lucide_react4 = require("lucide-react");
1075
- var import_core4 = require("@unifold/core");
1213
+ var import_core5 = require("@unifold/core");
1076
1214
  var import_jsx_runtime7 = require("react/jsx-runtime");
1077
1215
  function formatCurrency(currency) {
1078
1216
  if (!currency) return "";
@@ -1084,15 +1222,15 @@ function formatCurrency(currency) {
1084
1222
  }
1085
1223
  function DepositDetailContent({ execution }) {
1086
1224
  const { colors: colors2, fonts, components } = useTheme();
1087
- const [chains, setChains] = (0, import_react3.useState)([]);
1088
- const [showNetworkDetails, setShowNetworkDetails] = (0, import_react3.useState)(false);
1089
- (0, import_react3.useEffect)(() => {
1090
- (0, import_core4.getTokenChains)().then((response) => setChains(response.data)).catch((err) => console.error("Failed to fetch chains:", err));
1225
+ const [chains, setChains] = (0, import_react4.useState)([]);
1226
+ const [showNetworkDetails, setShowNetworkDetails] = (0, import_react4.useState)(false);
1227
+ (0, import_react4.useEffect)(() => {
1228
+ (0, import_core5.getTokenChains)().then((response) => setChains(response.data)).catch((err) => console.error("Failed to fetch chains:", err));
1091
1229
  }, []);
1092
- (0, import_react3.useEffect)(() => {
1230
+ (0, import_react4.useEffect)(() => {
1093
1231
  setShowNetworkDetails(false);
1094
1232
  }, [execution?.id]);
1095
- const isPending = execution.status === import_core4.ExecutionStatus.PENDING || execution.status === import_core4.ExecutionStatus.WAITING || execution.status === import_core4.ExecutionStatus.DELAYED;
1233
+ const isPending = execution.status === import_core5.ExecutionStatus.PENDING || execution.status === import_core5.ExecutionStatus.WAITING || execution.status === import_core5.ExecutionStatus.DELAYED;
1096
1234
  const formatDateTime = (timestamp) => {
1097
1235
  try {
1098
1236
  const date = new Date(timestamp);
@@ -1162,7 +1300,7 @@ function DepositDetailContent({ execution }) {
1162
1300
  return "$0.00";
1163
1301
  };
1164
1302
  const getNetworkName = (chainType, chainId) => {
1165
- return (0, import_core4.getChainName)(chains, chainType, chainId);
1303
+ return (0, import_core5.getChainName)(chains, chainType, chainId);
1166
1304
  };
1167
1305
  const formatTransactionHash = (hash) => {
1168
1306
  if (!hash || hash.length < 12) return hash;
@@ -1174,7 +1312,7 @@ function DepositDetailContent({ execution }) {
1174
1312
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1175
1313
  "img",
1176
1314
  {
1177
- src: execution.destination_token_metadata?.icon_url || (0, import_core4.getIconUrl)("/icons/tokens/svg/usdc.svg"),
1315
+ src: execution.destination_token_metadata?.icon_url || (0, import_core5.getIconUrl)("/icons/tokens/svg/usdc.svg"),
1178
1316
  alt: "Token",
1179
1317
  width: 64,
1180
1318
  height: 64,
@@ -1384,6 +1522,37 @@ function DepositDetailContent({ execution }) {
1384
1522
  ]
1385
1523
  }
1386
1524
  ),
1525
+ isPending && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1526
+ "div",
1527
+ {
1528
+ className: "uf-flex uf-justify-between uf-items-center uf-px-4 uf-py-3 uf-border-b",
1529
+ style: { borderColor: colors2.border },
1530
+ children: [
1531
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1532
+ "span",
1533
+ {
1534
+ className: "uf-text-sm",
1535
+ style: {
1536
+ color: components.card.labelColor,
1537
+ fontFamily: fonts.regular
1538
+ },
1539
+ children: "Estimated delivery time"
1540
+ }
1541
+ ),
1542
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1543
+ "span",
1544
+ {
1545
+ style: {
1546
+ color: components.card.titleColor,
1547
+ fontFamily: fonts.regular,
1548
+ fontSize: "14px"
1549
+ },
1550
+ children: formatEstimatedTime(execution?.estimated_processing_time)
1551
+ }
1552
+ )
1553
+ ]
1554
+ }
1555
+ ),
1387
1556
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1388
1557
  "div",
1389
1558
  {
@@ -1570,9 +1739,9 @@ function DepositSuccessToast({
1570
1739
  onClose,
1571
1740
  execution
1572
1741
  }) {
1573
- const [detailModalOpen, setDetailModalOpen] = (0, import_react4.useState)(false);
1742
+ const [detailModalOpen, setDetailModalOpen] = (0, import_react5.useState)(false);
1574
1743
  const { themeClass, colors: colors2, fonts, components } = useTheme();
1575
- const isPending = status === import_core5.ExecutionStatus.PENDING || status === import_core5.ExecutionStatus.WAITING || status === import_core5.ExecutionStatus.DELAYED;
1744
+ const isPending = status === import_core6.ExecutionStatus.PENDING || status === import_core6.ExecutionStatus.WAITING || status === import_core6.ExecutionStatus.DELAYED;
1576
1745
  const formatDateTime = (timestamp) => {
1577
1746
  try {
1578
1747
  const date = new Date(timestamp);
@@ -1650,7 +1819,7 @@ function DepositSuccessToast({
1650
1819
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1651
1820
  "img",
1652
1821
  {
1653
- src: tokenIconUrl || (0, import_core5.getIconUrl)("/icons/tokens/svg/usdc.svg"),
1822
+ src: tokenIconUrl || (0, import_core6.getIconUrl)("/icons/tokens/svg/usdc.svg"),
1654
1823
  alt: "Token",
1655
1824
  width: 36,
1656
1825
  height: 36,
@@ -1704,14 +1873,28 @@ function DepositSuccessToast({
1704
1873
  }
1705
1874
  )
1706
1875
  ] }),
1707
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1708
- "div",
1709
- {
1710
- className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
1711
- style: { color: colors2.background },
1712
- children: formatUsdAmount(sourceAmountUsd)
1713
- }
1714
- ),
1876
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "uf-flex-shrink-0 uf-text-right", children: [
1877
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1878
+ "div",
1879
+ {
1880
+ className: "uf-font-medium uf-text-sm",
1881
+ style: { color: colors2.background },
1882
+ children: formatUsdAmount(sourceAmountUsd)
1883
+ }
1884
+ ),
1885
+ isPending && execution?.estimated_processing_time && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1886
+ "p",
1887
+ {
1888
+ className: "uf-text-xs",
1889
+ style: { color: colors2.foregroundMuted },
1890
+ children: [
1891
+ "Est.",
1892
+ " ",
1893
+ formatEstimatedTime(execution.estimated_processing_time)
1894
+ ]
1895
+ }
1896
+ )
1897
+ ] }),
1715
1898
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1716
1899
  "button",
1717
1900
  {
@@ -1760,7 +1943,7 @@ function DepositPollingToasts({
1760
1943
  executions,
1761
1944
  horizontalPadding = "24px"
1762
1945
  }) {
1763
- const [closedExecutionIds, setClosedExecutionIds] = (0, import_react5.useState)(
1946
+ const [closedExecutionIds, setClosedExecutionIds] = (0, import_react6.useState)(
1764
1947
  /* @__PURE__ */ new Set()
1765
1948
  );
1766
1949
  const handleClose = (executionId) => {
@@ -1841,28 +2024,28 @@ function BuyWithCard({
1841
2024
  assetCdnUrl
1842
2025
  }) {
1843
2026
  const { colors: colors2, fonts, components } = useTheme();
1844
- const [amount, setAmount] = (0, import_react6.useState)("");
1845
- const [currency, setCurrency] = (0, import_react6.useState)("usd");
1846
- const [hasManualCurrencySelection, setHasManualCurrencySelection] = (0, import_react6.useState)(false);
1847
- const [hasManualAmountEntry, setHasManualAmountEntry] = (0, import_react6.useState)(false);
1848
- const [showCurrencyModal, setShowCurrencyModal] = (0, import_react6.useState)(false);
1849
- const [quotes, setQuotes] = (0, import_react6.useState)([]);
1850
- const [quotesLoading, setQuotesLoading] = (0, import_react6.useState)(false);
1851
- const [quotesError, setQuotesError] = (0, import_react6.useState)(null);
1852
- const [amountValidationError, setAmountValidationError] = (0, import_react6.useState)(null);
1853
- const [internalView, setInternalView] = (0, import_react6.useState)("amount");
1854
- const [defaultToken, setDefaultToken] = (0, import_react6.useState)(
2027
+ const [amount, setAmount] = (0, import_react7.useState)("");
2028
+ const [currency, setCurrency] = (0, import_react7.useState)("usd");
2029
+ const [hasManualCurrencySelection, setHasManualCurrencySelection] = (0, import_react7.useState)(false);
2030
+ const [hasManualAmountEntry, setHasManualAmountEntry] = (0, import_react7.useState)(false);
2031
+ const [showCurrencyModal, setShowCurrencyModal] = (0, import_react7.useState)(false);
2032
+ const [quotes, setQuotes] = (0, import_react7.useState)([]);
2033
+ const [quotesLoading, setQuotesLoading] = (0, import_react7.useState)(false);
2034
+ const [quotesError, setQuotesError] = (0, import_react7.useState)(null);
2035
+ const [amountValidationError, setAmountValidationError] = (0, import_react7.useState)(null);
2036
+ const [internalView, setInternalView] = (0, import_react7.useState)("amount");
2037
+ const [defaultToken, setDefaultToken] = (0, import_react7.useState)(
1855
2038
  null
1856
2039
  );
1857
- const [defaultTokenLoading, setDefaultTokenLoading] = (0, import_react6.useState)(false);
2040
+ const [defaultTokenLoading, setDefaultTokenLoading] = (0, import_react7.useState)(false);
1858
2041
  const { userIpInfo, isLoading: isLoadingIp } = useUserIp();
1859
- const [onrampSession, setOnrampSession] = (0, import_react6.useState)(
2042
+ const [onrampSession, setOnrampSession] = (0, import_react7.useState)(
1860
2043
  null
1861
2044
  );
1862
2045
  const currentView = externalView ?? internalView;
1863
2046
  const showQuotesView = currentView === "quotes";
1864
2047
  const showOnrampView = currentView === "onramp";
1865
- (0, import_react6.useEffect)(() => {
2048
+ (0, import_react7.useEffect)(() => {
1866
2049
  if (externalView) {
1867
2050
  setInternalView(externalView);
1868
2051
  }
@@ -1875,31 +2058,31 @@ function BuyWithCard({
1875
2058
  onViewChange?.(newView);
1876
2059
  }
1877
2060
  };
1878
- const [selectedProvider, setSelectedProvider] = (0, import_react6.useState)(
2061
+ const [selectedProvider, setSelectedProvider] = (0, import_react7.useState)(
1879
2062
  null
1880
2063
  );
1881
- const [isAutoSelected, setIsAutoSelected] = (0, import_react6.useState)(true);
1882
- const [autoSelectedProvider, setAutoSelectedProvider] = (0, import_react6.useState)(null);
1883
- const [hoveredProviderIndex, setHoveredProviderIndex] = (0, import_react6.useState)(null);
1884
- const [hasManualSelection, setHasManualSelection] = (0, import_react6.useState)(false);
1885
- const selectedProviderRef = (0, import_react6.useRef)(null);
1886
- const hasManualSelectionRef = (0, import_react6.useRef)(false);
1887
- (0, import_react6.useEffect)(() => {
2064
+ const [isAutoSelected, setIsAutoSelected] = (0, import_react7.useState)(true);
2065
+ const [autoSelectedProvider, setAutoSelectedProvider] = (0, import_react7.useState)(null);
2066
+ const [hoveredProviderIndex, setHoveredProviderIndex] = (0, import_react7.useState)(null);
2067
+ const [hasManualSelection, setHasManualSelection] = (0, import_react7.useState)(false);
2068
+ const selectedProviderRef = (0, import_react7.useRef)(null);
2069
+ const hasManualSelectionRef = (0, import_react7.useRef)(false);
2070
+ (0, import_react7.useEffect)(() => {
1888
2071
  selectedProviderRef.current = selectedProvider;
1889
2072
  }, [selectedProvider]);
1890
- (0, import_react6.useEffect)(() => {
2073
+ (0, import_react7.useEffect)(() => {
1891
2074
  hasManualSelectionRef.current = hasManualSelection;
1892
2075
  }, [hasManualSelection]);
1893
- const [internalWallets, setInternalWallets] = (0, import_react6.useState)([]);
1894
- const [walletsLoading, setWalletsLoading] = (0, import_react6.useState)(
2076
+ const [internalWallets, setInternalWallets] = (0, import_react7.useState)([]);
2077
+ const [walletsLoading, setWalletsLoading] = (0, import_react7.useState)(
1895
2078
  !externalWallets?.length
1896
2079
  );
1897
2080
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
1898
- const [countdown, setCountdown] = (0, import_react6.useState)(60);
1899
- const [fiatCurrencies, setFiatCurrencies] = (0, import_react6.useState)([]);
1900
- const [preferredCurrencyCodes, setPreferredCurrencyCodes] = (0, import_react6.useState)([]);
1901
- const [currenciesLoading, setCurrenciesLoading] = (0, import_react6.useState)(true);
1902
- const [destinationToken, setDestinationToken] = (0, import_react6.useState)(null);
2081
+ const [countdown, setCountdown] = (0, import_react7.useState)(60);
2082
+ const [fiatCurrencies, setFiatCurrencies] = (0, import_react7.useState)([]);
2083
+ const [preferredCurrencyCodes, setPreferredCurrencyCodes] = (0, import_react7.useState)([]);
2084
+ const [currenciesLoading, setCurrenciesLoading] = (0, import_react7.useState)(true);
2085
+ const [destinationToken, setDestinationToken] = (0, import_react7.useState)(null);
1903
2086
  const { executions, isPolling } = useDepositPolling({
1904
2087
  userId,
1905
2088
  publishableKey,
@@ -1911,10 +2094,10 @@ function BuyWithCard({
1911
2094
  const destinationTokenIcon = destinationToken?.icon_url;
1912
2095
  const destinationChainIcon = destinationToken?.chain_icon_url;
1913
2096
  const destinationChainName = destinationToken?.chain_name;
1914
- (0, import_react6.useEffect)(() => {
2097
+ (0, import_react7.useEffect)(() => {
1915
2098
  async function fetchFiatCurrencies() {
1916
2099
  try {
1917
- const response = await (0, import_core6.getFiatCurrencies)(publishableKey);
2100
+ const response = await (0, import_core7.getFiatCurrencies)(publishableKey);
1918
2101
  setFiatCurrencies(response.data);
1919
2102
  setPreferredCurrencyCodes(response.preferred || []);
1920
2103
  } catch (err) {
@@ -1925,7 +2108,7 @@ function BuyWithCard({
1925
2108
  }
1926
2109
  fetchFiatCurrencies();
1927
2110
  }, [publishableKey]);
1928
- (0, import_react6.useEffect)(() => {
2111
+ (0, import_react7.useEffect)(() => {
1929
2112
  if (hasManualCurrencySelection) return;
1930
2113
  if (fiatCurrencies.length === 0 || !userIpInfo?.alpha2) return;
1931
2114
  const userCountryCode = userIpInfo.alpha2.toUpperCase();
@@ -1952,8 +2135,8 @@ function BuyWithCard({
1952
2135
  amount,
1953
2136
  hasManualAmountEntry
1954
2137
  ]);
1955
- const prevCurrencyRef = (0, import_react6.useRef)(null);
1956
- (0, import_react6.useEffect)(() => {
2138
+ const prevCurrencyRef = (0, import_react7.useRef)(null);
2139
+ (0, import_react7.useEffect)(() => {
1957
2140
  if (fiatCurrencies.length === 0) return;
1958
2141
  if (prevCurrencyRef.current !== null && prevCurrencyRef.current !== currency) {
1959
2142
  const currentCurrency = fiatCurrencies.find(
@@ -1965,7 +2148,7 @@ function BuyWithCard({
1965
2148
  }
1966
2149
  prevCurrencyRef.current = currency;
1967
2150
  }, [currency]);
1968
- (0, import_react6.useEffect)(() => {
2151
+ (0, import_react7.useEffect)(() => {
1969
2152
  if (externalWallets?.length) {
1970
2153
  setWalletsLoading(false);
1971
2154
  return;
@@ -1980,7 +2163,7 @@ function BuyWithCard({
1980
2163
  if (isCancelled) return;
1981
2164
  setWalletsLoading(true);
1982
2165
  try {
1983
- const response = await (0, import_core6.createDepositAddress)(
2166
+ const response = await (0, import_core7.createDepositAddress)(
1984
2167
  {
1985
2168
  external_user_id: userId,
1986
2169
  recipient_address: recipientAddress,
@@ -2018,10 +2201,10 @@ function BuyWithCard({
2018
2201
  publishableKey,
2019
2202
  externalWallets
2020
2203
  ]);
2021
- (0, import_react6.useEffect)(() => {
2204
+ (0, import_react7.useEffect)(() => {
2022
2205
  async function fetchDestinationToken() {
2023
2206
  try {
2024
- const response = await (0, import_core6.getTokenMetadata)(
2207
+ const response = await (0, import_core7.getTokenMetadata)(
2025
2208
  {
2026
2209
  chain_type: destinationChainType || "",
2027
2210
  chain_id: destinationChainId || "",
@@ -2036,7 +2219,7 @@ function BuyWithCard({
2036
2219
  }
2037
2220
  fetchDestinationToken();
2038
2221
  }, [publishableKey]);
2039
- (0, import_react6.useEffect)(() => {
2222
+ (0, import_react7.useEffect)(() => {
2040
2223
  async function fetchDefaultToken() {
2041
2224
  if (!destinationTokenAddress || !destinationChainId || !destinationChainType) {
2042
2225
  return;
@@ -2046,7 +2229,7 @@ function BuyWithCard({
2046
2229
  }
2047
2230
  setDefaultTokenLoading(true);
2048
2231
  try {
2049
- const response = await (0, import_core6.getDefaultOnrampToken)(
2232
+ const response = await (0, import_core7.getDefaultOnrampToken)(
2050
2233
  {
2051
2234
  country_code: userIpInfo?.alpha2?.toUpperCase() || "US",
2052
2235
  subdivision_code: userIpInfo?.state || void 0,
@@ -2072,7 +2255,7 @@ function BuyWithCard({
2072
2255
  isLoadingIp,
2073
2256
  publishableKey
2074
2257
  ]);
2075
- (0, import_react6.useEffect)(() => {
2258
+ (0, import_react7.useEffect)(() => {
2076
2259
  const amountNum = parseFloat(amount);
2077
2260
  if (isNaN(amountNum) || amountNum <= 0) {
2078
2261
  setQuotes([]);
@@ -2134,7 +2317,7 @@ function BuyWithCard({
2134
2317
  destination_network: defaultToken.destination_network,
2135
2318
  subdivision_code: userIpInfo?.state || void 0
2136
2319
  };
2137
- const response = await (0, import_core6.getOnrampQuotes)(request, publishableKey);
2320
+ const response = await (0, import_core7.getOnrampQuotes)(request, publishableKey);
2138
2321
  setQuotes(response.data);
2139
2322
  const currentHasManualSelection = hasManualSelectionRef.current;
2140
2323
  const currentSelectedProvider = selectedProviderRef.current;
@@ -2181,7 +2364,7 @@ function BuyWithCard({
2181
2364
  setQuotesLoading(false);
2182
2365
  }
2183
2366
  };
2184
- (0, import_react6.useEffect)(() => {
2367
+ (0, import_react7.useEffect)(() => {
2185
2368
  if (quotes.length === 0) return;
2186
2369
  const timer = setInterval(() => {
2187
2370
  setCountdown((prev) => {
@@ -2218,7 +2401,7 @@ function BuyWithCard({
2218
2401
  const handleContinue = () => {
2219
2402
  if (!selectedProvider) return;
2220
2403
  if (!defaultToken) return;
2221
- const wallet = (0, import_core6.getWalletByChainType)(
2404
+ const wallet = (0, import_core7.getWalletByChainType)(
2222
2405
  wallets,
2223
2406
  defaultToken.destination_token_metadata.chain_type
2224
2407
  );
@@ -2236,7 +2419,7 @@ function BuyWithCard({
2236
2419
  wallet_address: wallet.address,
2237
2420
  subdivision_code: userIpInfo?.state || void 0
2238
2421
  };
2239
- const sessionStartUrl = (0, import_core6.getOnrampSessionStartUrl)(
2422
+ const sessionStartUrl = (0, import_core7.getOnrampSessionStartUrl)(
2240
2423
  sessionRequest,
2241
2424
  publishableKey
2242
2425
  );
@@ -2286,7 +2469,7 @@ function BuyWithCard({
2286
2469
  selectedCurrencyData && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2287
2470
  "img",
2288
2471
  {
2289
- src: (0, import_core6.getPreferredIconUrl)(
2472
+ src: (0, import_core7.getPreferredIconUrl)(
2290
2473
  selectedCurrencyData.icon_urls,
2291
2474
  "png"
2292
2475
  ) || selectedCurrencyData.icon_url,
@@ -2516,6 +2699,21 @@ function BuyWithCard({
2516
2699
  },
2517
2700
  children: quotesError
2518
2701
  }
2702
+ ),
2703
+ defaultToken?.estimated_processing_time && !quotesLoading && selectedProvider && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2704
+ "div",
2705
+ {
2706
+ className: "uf-text-xs uf-mt-2 uf-px-1",
2707
+ style: {
2708
+ color: components.card.subtitleColor,
2709
+ fontFamily: fonts.regular
2710
+ },
2711
+ children: [
2712
+ "Estimated delivery time:",
2713
+ " ",
2714
+ formatEstimatedTime(defaultToken.estimated_processing_time)
2715
+ ]
2716
+ }
2519
2717
  )
2520
2718
  ] }),
2521
2719
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -2633,7 +2831,7 @@ function BuyWithCard({
2633
2831
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "uf-h-8 uf-flex uf-items-center uf-justify-center uf-mb-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2634
2832
  "img",
2635
2833
  {
2636
- src: (0, import_core6.getIconUrlWithCdn)(
2834
+ src: (0, import_core7.getIconUrlWithCdn)(
2637
2835
  `/icons/currencies/png/${onrampSession.sourceCurrency.toLowerCase()}.png`,
2638
2836
  assetCdnUrl
2639
2837
  ),
@@ -2650,7 +2848,7 @@ function BuyWithCard({
2650
2848
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2651
2849
  "img",
2652
2850
  {
2653
- src: defaultToken?.destination_token_metadata?.icon_url || (0, import_core6.getIconUrlWithCdn)(
2851
+ src: defaultToken?.destination_token_metadata?.icon_url || (0, import_core7.getIconUrlWithCdn)(
2654
2852
  "/icons/tokens/png/usdc.png",
2655
2853
  assetCdnUrl
2656
2854
  ),
@@ -2661,7 +2859,7 @@ function BuyWithCard({
2661
2859
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2662
2860
  "img",
2663
2861
  {
2664
- src: defaultToken?.destination_token_metadata?.chain.icon_url || (0, import_core6.getIconUrlWithCdn)(
2862
+ src: defaultToken?.destination_token_metadata?.chain.icon_url || (0, import_core7.getIconUrlWithCdn)(
2665
2863
  "/icons/networks/png/polygon.png",
2666
2864
  assetCdnUrl
2667
2865
  ),
@@ -2679,7 +2877,7 @@ function BuyWithCard({
2679
2877
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2680
2878
  "img",
2681
2879
  {
2682
- src: destinationTokenIcon || (0, import_core6.getIconUrlWithCdn)(
2880
+ src: destinationTokenIcon || (0, import_core7.getIconUrlWithCdn)(
2683
2881
  "/icons/tokens/png/usdc.png",
2684
2882
  assetCdnUrl
2685
2883
  ),
@@ -2733,18 +2931,18 @@ function BuyWithCard({
2733
2931
  }
2734
2932
 
2735
2933
  // src/components/deposits/DepositsModal.tsx
2736
- var import_react7 = require("react");
2934
+ var import_react8 = require("react");
2737
2935
 
2738
2936
  // src/components/deposits/DepositExecutionItem.tsx
2739
2937
  var import_lucide_react7 = require("lucide-react");
2740
- var import_core7 = require("@unifold/core");
2938
+ var import_core8 = require("@unifold/core");
2741
2939
  var import_jsx_runtime11 = require("react/jsx-runtime");
2742
2940
  function DepositExecutionItem({
2743
2941
  execution,
2744
2942
  onClick
2745
2943
  }) {
2746
2944
  const { colors: colors2, fonts, components } = useTheme();
2747
- const isPending = execution.status === import_core7.ExecutionStatus.PENDING || execution.status === import_core7.ExecutionStatus.WAITING || execution.status === import_core7.ExecutionStatus.DELAYED;
2945
+ const isPending = execution.status === import_core8.ExecutionStatus.PENDING || execution.status === import_core8.ExecutionStatus.WAITING || execution.status === import_core8.ExecutionStatus.DELAYED;
2748
2946
  const formatDateTime = (timestamp) => {
2749
2947
  try {
2750
2948
  const date = new Date(timestamp);
@@ -2787,7 +2985,7 @@ function DepositExecutionItem({
2787
2985
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2788
2986
  "img",
2789
2987
  {
2790
- src: execution.destination_token_metadata?.icon_url || (0, import_core7.getIconUrl)("/icons/tokens/svg/usdc.svg"),
2988
+ src: execution.destination_token_metadata?.icon_url || (0, import_core8.getIconUrl)("/icons/tokens/svg/usdc.svg"),
2791
2989
  alt: "Token",
2792
2990
  width: 36,
2793
2991
  height: 36,
@@ -2963,7 +3161,7 @@ function ThemeStyleInjector({
2963
3161
  }
2964
3162
 
2965
3163
  // src/components/deposits/DepositsModal.tsx
2966
- var import_core8 = require("@unifold/core");
3164
+ var import_core9 = require("@unifold/core");
2967
3165
  var import_jsx_runtime13 = require("react/jsx-runtime");
2968
3166
  function DepositsModal({
2969
3167
  open,
@@ -2975,13 +3173,13 @@ function DepositsModal({
2975
3173
  themeClass = ""
2976
3174
  }) {
2977
3175
  const { colors: colors2 } = useTheme();
2978
- const [allExecutions, setAllExecutions] = (0, import_react7.useState)(sessionExecutions);
2979
- const [selectedExecution, setSelectedExecution] = (0, import_react7.useState)(null);
2980
- (0, import_react7.useEffect)(() => {
3176
+ const [allExecutions, setAllExecutions] = (0, import_react8.useState)(sessionExecutions);
3177
+ const [selectedExecution, setSelectedExecution] = (0, import_react8.useState)(null);
3178
+ (0, import_react8.useEffect)(() => {
2981
3179
  if (!open || !userId) return;
2982
3180
  const fetchExecutions = async () => {
2983
3181
  try {
2984
- const response = await (0, import_core8.queryExecutions)(userId, publishableKey);
3182
+ const response = await (0, import_core9.queryExecutions)(userId, publishableKey);
2985
3183
  const sorted = [...response.data].sort((a, b) => {
2986
3184
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
2987
3185
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -2999,7 +3197,7 @@ function DepositsModal({
2999
3197
  clearInterval(pollInterval);
3000
3198
  };
3001
3199
  }, [open, userId, publishableKey, sessionExecutions]);
3002
- (0, import_react7.useEffect)(() => {
3200
+ (0, import_react8.useEffect)(() => {
3003
3201
  if (!open) {
3004
3202
  setSelectedExecution(null);
3005
3203
  }
@@ -3325,11 +3523,11 @@ function DepositTrackerButton({
3325
3523
  }
3326
3524
 
3327
3525
  // src/components/deposits/DepositModal.tsx
3328
- var import_core12 = require("@unifold/core");
3526
+ var import_core14 = require("@unifold/core");
3329
3527
 
3330
3528
  // src/hooks/use-allowed-country.ts
3331
3529
  var import_react_query2 = require("@tanstack/react-query");
3332
- var import_core9 = require("@unifold/core");
3530
+ var import_core10 = require("@unifold/core");
3333
3531
  function useAllowedCountry(publishableKey) {
3334
3532
  const {
3335
3533
  data: ipData,
@@ -3337,7 +3535,7 @@ function useAllowedCountry(publishableKey) {
3337
3535
  error: ipError
3338
3536
  } = (0, import_react_query2.useQuery)({
3339
3537
  queryKey: ["unifold", "ipAddress"],
3340
- queryFn: () => (0, import_core9.getIpAddress)(),
3538
+ queryFn: () => (0, import_core10.getIpAddress)(),
3341
3539
  refetchOnMount: false,
3342
3540
  refetchOnReconnect: true,
3343
3541
  refetchOnWindowFocus: false,
@@ -3352,7 +3550,7 @@ function useAllowedCountry(publishableKey) {
3352
3550
  error: configError
3353
3551
  } = (0, import_react_query2.useQuery)({
3354
3552
  queryKey: ["unifold", "projectConfig", publishableKey],
3355
- queryFn: () => (0, import_core9.getProjectConfig)(publishableKey),
3553
+ queryFn: () => (0, import_core10.getProjectConfig)(publishableKey),
3356
3554
  refetchOnMount: false,
3357
3555
  refetchOnReconnect: true,
3358
3556
  refetchOnWindowFocus: false,
@@ -3381,12 +3579,70 @@ function useAllowedCountry(publishableKey) {
3381
3579
  };
3382
3580
  }
3383
3581
 
3582
+ // src/hooks/use-address-validation.ts
3583
+ var import_react_query3 = require("@tanstack/react-query");
3584
+ var import_core11 = require("@unifold/core");
3585
+ function useAddressValidation({
3586
+ recipientAddress,
3587
+ destinationChainType,
3588
+ destinationChainId,
3589
+ destinationTokenAddress,
3590
+ publishableKey,
3591
+ enabled = true,
3592
+ refetchOnMount = false
3593
+ }) {
3594
+ const shouldValidate = enabled && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
3595
+ const { data, isLoading, error } = (0, import_react_query3.useQuery)({
3596
+ queryKey: [
3597
+ "unifold",
3598
+ "addressValidation",
3599
+ recipientAddress,
3600
+ destinationChainType,
3601
+ destinationChainId,
3602
+ destinationTokenAddress
3603
+ ],
3604
+ queryFn: () => (0, import_core11.verifyRecipientAddress)(
3605
+ {
3606
+ chain_type: destinationChainType,
3607
+ chain_id: destinationChainId,
3608
+ token_address: destinationTokenAddress,
3609
+ recipient_address: recipientAddress
3610
+ },
3611
+ publishableKey
3612
+ ),
3613
+ enabled: shouldValidate,
3614
+ refetchOnMount,
3615
+ refetchOnReconnect: false,
3616
+ refetchOnWindowFocus: false,
3617
+ staleTime: 1e3 * 60 * 5,
3618
+ // 5 minutes - address state can change
3619
+ gcTime: 1e3 * 60 * 30
3620
+ // 30 minutes
3621
+ });
3622
+ if (!shouldValidate) {
3623
+ return {
3624
+ isValid: null,
3625
+ failureCode: null,
3626
+ metadata: null,
3627
+ isLoading: false,
3628
+ error: null
3629
+ };
3630
+ }
3631
+ return {
3632
+ isValid: data?.valid ?? null,
3633
+ failureCode: data?.failure_code ?? null,
3634
+ metadata: data?.metadata ?? null,
3635
+ isLoading,
3636
+ error: error ?? null
3637
+ };
3638
+ }
3639
+
3384
3640
  // src/components/deposits/TransferCryptoSingleInput.tsx
3385
- var import_react10 = require("react");
3641
+ var import_react11 = require("react");
3386
3642
  var import_lucide_react12 = require("lucide-react");
3387
3643
 
3388
3644
  // src/components/deposits/StyledQRCode.tsx
3389
- var import_react8 = require("react");
3645
+ var import_react9 = require("react");
3390
3646
  var import_qr_code_styling = __toESM(require("qr-code-styling"));
3391
3647
  var import_jsx_runtime17 = require("react/jsx-runtime");
3392
3648
  function StyledQRCode({
@@ -3396,9 +3652,9 @@ function StyledQRCode({
3396
3652
  imageSize = 50,
3397
3653
  darkMode = false
3398
3654
  }) {
3399
- const ref = (0, import_react8.useRef)(null);
3400
- const qrCodeRef = (0, import_react8.useRef)(null);
3401
- (0, import_react8.useEffect)(() => {
3655
+ const ref = (0, import_react9.useRef)(null);
3656
+ const qrCodeRef = (0, import_react9.useRef)(null);
3657
+ (0, import_react9.useEffect)(() => {
3402
3658
  if (!ref.current) return;
3403
3659
  if (!qrCodeRef.current) {
3404
3660
  qrCodeRef.current = new import_qr_code_styling.default({
@@ -3438,7 +3694,7 @@ function StyledQRCode({
3438
3694
  qrCodeRef.current.append(ref.current);
3439
3695
  }
3440
3696
  }, []);
3441
- (0, import_react8.useEffect)(() => {
3697
+ (0, import_react9.useEffect)(() => {
3442
3698
  if (qrCodeRef.current) {
3443
3699
  qrCodeRef.current.update({
3444
3700
  data: value,
@@ -3479,7 +3735,7 @@ function StyledQRCode({
3479
3735
  }
3480
3736
 
3481
3737
  // src/components/deposits/TokenSelectorSheet.tsx
3482
- var import_react9 = require("react");
3738
+ var import_react10 = require("react");
3483
3739
  var import_lucide_react11 = require("lucide-react");
3484
3740
  var import_jsx_runtime18 = require("react/jsx-runtime");
3485
3741
  var STORAGE_KEY = "unifold_recent_tokens";
@@ -3537,13 +3793,13 @@ function TokenSelectorSheet({
3537
3793
  }) {
3538
3794
  const { themeClass, colors: colors2, fonts, components } = useTheme();
3539
3795
  const isDarkMode = themeClass.includes("uf-dark");
3540
- const [searchQuery, setSearchQuery] = (0, import_react9.useState)("");
3541
- const [recentTokens, setRecentTokens] = (0, import_react9.useState)([]);
3542
- const [hoveredTokenKey, setHoveredTokenKey] = (0, import_react9.useState)(null);
3543
- (0, import_react9.useEffect)(() => {
3796
+ const [searchQuery, setSearchQuery] = (0, import_react10.useState)("");
3797
+ const [recentTokens, setRecentTokens] = (0, import_react10.useState)([]);
3798
+ const [hoveredTokenKey, setHoveredTokenKey] = (0, import_react10.useState)(null);
3799
+ (0, import_react10.useEffect)(() => {
3544
3800
  setRecentTokens(getRecentTokens());
3545
3801
  }, []);
3546
- const allOptions = (0, import_react9.useMemo)(() => {
3802
+ const allOptions = (0, import_react10.useMemo)(() => {
3547
3803
  const options = [];
3548
3804
  tokens.forEach((token) => {
3549
3805
  token.chains.forEach((chain) => {
@@ -3552,7 +3808,7 @@ function TokenSelectorSheet({
3552
3808
  });
3553
3809
  return options;
3554
3810
  }, [tokens]);
3555
- const quickSelectOptions = (0, import_react9.useMemo)(() => {
3811
+ const quickSelectOptions = (0, import_react10.useMemo)(() => {
3556
3812
  const result = [];
3557
3813
  const seen = /* @__PURE__ */ new Set();
3558
3814
  const addOption = (symbol, chainType, chainId, isRecent) => {
@@ -3584,7 +3840,7 @@ function TokenSelectorSheet({
3584
3840
  });
3585
3841
  setRecentTokens(updated);
3586
3842
  };
3587
- const filteredOptions = (0, import_react9.useMemo)(() => {
3843
+ const filteredOptions = (0, import_react10.useMemo)(() => {
3588
3844
  if (!searchQuery.trim()) return allOptions;
3589
3845
  const query = searchQuery.toLowerCase();
3590
3846
  return allOptions.filter(
@@ -3954,7 +4210,7 @@ var TooltipContent = React8.forwardRef(({ className, sideOffset = 4, ...props },
3954
4210
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
3955
4211
 
3956
4212
  // src/components/deposits/TransferCryptoSingleInput.tsx
3957
- var import_core10 = require("@unifold/core");
4213
+ var import_core12 = require("@unifold/core");
3958
4214
  var import_jsx_runtime20 = require("react/jsx-runtime");
3959
4215
  var t2 = i18n.transferCrypto;
3960
4216
  var getChainKey = (chainId, chainType) => {
@@ -3978,13 +4234,13 @@ function TransferCryptoSingleInput({
3978
4234
  }) {
3979
4235
  const { themeClass, colors: colors2, fonts, components } = useTheme();
3980
4236
  const isDarkMode = themeClass.includes("uf-dark");
3981
- const [token, setToken] = (0, import_react10.useState)("USDC");
3982
- const [chain, setChain] = (0, import_react10.useState)("solana:mainnet");
3983
- const [copied, setCopied] = (0, import_react10.useState)(false);
3984
- const [internalWallets, setInternalWallets] = (0, import_react10.useState)([]);
3985
- const [loading, setLoading] = (0, import_react10.useState)(!externalWallets?.length);
4237
+ const [token, setToken] = (0, import_react11.useState)("USDC");
4238
+ const [chain, setChain] = (0, import_react11.useState)("solana:mainnet");
4239
+ const [copied, setCopied] = (0, import_react11.useState)(false);
4240
+ const [internalWallets, setInternalWallets] = (0, import_react11.useState)([]);
4241
+ const [loading, setLoading] = (0, import_react11.useState)(!externalWallets?.length);
3986
4242
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
3987
- const [error, setError] = (0, import_react10.useState)(null);
4243
+ const [error, setError] = (0, import_react11.useState)(null);
3988
4244
  const { executions: depositExecutions, isPolling } = useDepositPolling({
3989
4245
  userId,
3990
4246
  publishableKey,
@@ -3992,11 +4248,11 @@ function TransferCryptoSingleInput({
3992
4248
  onDepositSuccess,
3993
4249
  onDepositError
3994
4250
  });
3995
- const [supportedTokens, setSupportedTokens] = (0, import_react10.useState)([]);
3996
- const [tokensLoading, setTokensLoading] = (0, import_react10.useState)(true);
3997
- const [detailsExpanded, setDetailsExpanded] = (0, import_react10.useState)(false);
3998
- const [depositsModalOpen, setDepositsModalOpen] = (0, import_react10.useState)(false);
3999
- const [tokenSelectorOpen, setTokenSelectorOpen] = (0, import_react10.useState)(false);
4251
+ const [supportedTokens, setSupportedTokens] = (0, import_react11.useState)([]);
4252
+ const [tokensLoading, setTokensLoading] = (0, import_react11.useState)(true);
4253
+ const [detailsExpanded, setDetailsExpanded] = (0, import_react11.useState)(false);
4254
+ const [depositsModalOpen, setDepositsModalOpen] = (0, import_react11.useState)(false);
4255
+ const [tokenSelectorOpen, setTokenSelectorOpen] = (0, import_react11.useState)(false);
4000
4256
  const allChainsMap = /* @__PURE__ */ new Map();
4001
4257
  supportedTokens.forEach((t5) => {
4002
4258
  t5.chains.forEach((c) => {
@@ -4012,9 +4268,9 @@ function TransferCryptoSingleInput({
4012
4268
  (c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
4013
4269
  );
4014
4270
  const currentChainType = currentChainData?.chain_type || "ethereum";
4015
- const currentWallet = (0, import_core10.getWalletByChainType)(wallets, currentChainType);
4271
+ const currentWallet = (0, import_core12.getWalletByChainType)(wallets, currentChainType);
4016
4272
  const depositAddress = currentWallet?.address || "";
4017
- (0, import_react10.useEffect)(() => {
4273
+ (0, import_react11.useEffect)(() => {
4018
4274
  async function fetchSupportedTokens() {
4019
4275
  try {
4020
4276
  setTokensLoading(true);
@@ -4023,7 +4279,7 @@ function TransferCryptoSingleInput({
4023
4279
  destination_chain_id: destinationChainId,
4024
4280
  destination_chain_type: destinationChainType
4025
4281
  } : void 0;
4026
- const response = await (0, import_core10.getSupportedDepositTokens)(
4282
+ const response = await (0, import_core12.getSupportedDepositTokens)(
4027
4283
  publishableKey,
4028
4284
  options
4029
4285
  );
@@ -4086,12 +4342,12 @@ function TransferCryptoSingleInput({
4086
4342
  destinationChainId,
4087
4343
  destinationChainType
4088
4344
  ]);
4089
- (0, import_react10.useEffect)(() => {
4345
+ (0, import_react11.useEffect)(() => {
4090
4346
  if (onExecutionsChange) {
4091
4347
  onExecutionsChange(depositExecutions);
4092
4348
  }
4093
4349
  }, [depositExecutions, onExecutionsChange]);
4094
- (0, import_react10.useEffect)(() => {
4350
+ (0, import_react11.useEffect)(() => {
4095
4351
  if (externalWallets?.length) {
4096
4352
  setLoading(false);
4097
4353
  return;
@@ -4106,7 +4362,7 @@ function TransferCryptoSingleInput({
4106
4362
  if (isCancelled) return;
4107
4363
  setLoading(true);
4108
4364
  try {
4109
- const response = await (0, import_core10.createDepositAddress)(
4365
+ const response = await (0, import_core12.createDepositAddress)(
4110
4366
  {
4111
4367
  external_user_id: userId,
4112
4368
  recipient_address: recipientAddress,
@@ -4148,7 +4404,7 @@ function TransferCryptoSingleInput({
4148
4404
  publishableKey,
4149
4405
  externalWallets
4150
4406
  ]);
4151
- (0, import_react10.useEffect)(() => {
4407
+ (0, import_react11.useEffect)(() => {
4152
4408
  if (!supportedTokens.length) return;
4153
4409
  const currentToken = supportedTokens.find((t5) => t5.symbol === token);
4154
4410
  if (!currentToken || currentToken.chains.length === 0) return;
@@ -4340,24 +4596,24 @@ function TransferCryptoSingleInput({
4340
4596
  )
4341
4597
  ] })
4342
4598
  ] }),
4343
- loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-muted-foreground uf-animate-pulse", children: t2.loading }) : error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-red-400", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "uf-relative", children: [
4344
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4345
- "button",
4346
- {
4347
- onClick: handleCopyAddress,
4348
- disabled: !depositAddress,
4349
- className: "uf-w-full uf-bg-secondary hover:uf-bg-accent uf-rounded-lg uf-px-2.5 uf-py-2.5 uf-text-xs uf-font-mono uf-break-all uf-text-left uf-transition-colors uf-cursor-pointer disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
4350
- children: depositAddress || t2.noAddressAvailable
4351
- }
4352
- ),
4353
- depositAddress && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4354
- "span",
4355
- {
4356
- className: `uf-absolute uf-inset-y-0 uf-right-3 uf-flex uf-items-center uf-pointer-events-none uf-transition-colors ${copied ? "uf-text-green-500" : "uf-text-muted-foreground"}`,
4357
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react12.Check, { className: "uf-w-3 uf-h-3" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react12.Copy, { className: "uf-w-3 uf-h-3" })
4358
- }
4359
- )
4360
- ] })
4599
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-muted-foreground uf-animate-pulse", children: t2.loading }) : error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-red-400", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4600
+ "button",
4601
+ {
4602
+ onClick: handleCopyAddress,
4603
+ disabled: !depositAddress,
4604
+ className: "uf-w-full uf-bg-secondary hover:uf-bg-accent uf-rounded-lg uf-px-3 uf-py-2.5 uf-flex uf-items-center uf-justify-between uf-gap-2 uf-transition-colors uf-cursor-pointer disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
4605
+ children: [
4606
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "uf-text-xs uf-font-mono uf-truncate uf-min-w-0", children: depositAddress ? truncateAddress(depositAddress, 18, 12) : t2.noAddressAvailable }),
4607
+ depositAddress && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4608
+ "span",
4609
+ {
4610
+ className: `uf-flex-shrink-0 uf-transition-colors ${copied ? "uf-text-green-500" : "uf-text-muted-foreground"}`,
4611
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react12.Check, { className: "uf-w-3.5 uf-h-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react12.Copy, { className: "uf-w-3.5 uf-h-3.5" })
4612
+ }
4613
+ )
4614
+ ]
4615
+ }
4616
+ )
4361
4617
  ] }),
4362
4618
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "uf-bg-secondary uf-rounded-xl uf-px-2.5", children: [
4363
4619
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
@@ -4526,7 +4782,7 @@ function TransferCryptoSingleInput({
4526
4782
  }
4527
4783
 
4528
4784
  // src/components/deposits/TransferCryptoDoubleInput.tsx
4529
- var import_react11 = require("react");
4785
+ var import_react12 = require("react");
4530
4786
  var import_lucide_react14 = require("lucide-react");
4531
4787
 
4532
4788
  // src/components/shared/select.tsx
@@ -4651,7 +4907,7 @@ var SelectSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__
4651
4907
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
4652
4908
 
4653
4909
  // src/components/deposits/TransferCryptoDoubleInput.tsx
4654
- var import_core11 = require("@unifold/core");
4910
+ var import_core13 = require("@unifold/core");
4655
4911
  var import_jsx_runtime22 = require("react/jsx-runtime");
4656
4912
  var t3 = i18n.transferCrypto;
4657
4913
  var getChainKey2 = (chainId, chainType) => {
@@ -4675,13 +4931,13 @@ function TransferCryptoDoubleInput({
4675
4931
  }) {
4676
4932
  const { themeClass, colors: colors2, fonts, components } = useTheme();
4677
4933
  const isDarkMode = themeClass.includes("uf-dark");
4678
- const [token, setToken] = (0, import_react11.useState)("USDC");
4679
- const [chain, setChain] = (0, import_react11.useState)("solana:mainnet");
4680
- const [copied, setCopied] = (0, import_react11.useState)(false);
4681
- const [internalWallets, setInternalWallets] = (0, import_react11.useState)([]);
4682
- const [loading, setLoading] = (0, import_react11.useState)(!externalWallets?.length);
4934
+ const [token, setToken] = (0, import_react12.useState)("USDC");
4935
+ const [chain, setChain] = (0, import_react12.useState)("solana:mainnet");
4936
+ const [copied, setCopied] = (0, import_react12.useState)(false);
4937
+ const [internalWallets, setInternalWallets] = (0, import_react12.useState)([]);
4938
+ const [loading, setLoading] = (0, import_react12.useState)(!externalWallets?.length);
4683
4939
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
4684
- const [error, setError] = (0, import_react11.useState)(null);
4940
+ const [error, setError] = (0, import_react12.useState)(null);
4685
4941
  const { executions: depositExecutions, isPolling } = useDepositPolling({
4686
4942
  userId,
4687
4943
  publishableKey,
@@ -4689,10 +4945,10 @@ function TransferCryptoDoubleInput({
4689
4945
  onDepositSuccess,
4690
4946
  onDepositError
4691
4947
  });
4692
- const [supportedTokens, setSupportedTokens] = (0, import_react11.useState)([]);
4693
- const [tokensLoading, setTokensLoading] = (0, import_react11.useState)(true);
4694
- const [detailsExpanded, setDetailsExpanded] = (0, import_react11.useState)(false);
4695
- const [depositsModalOpen, setDepositsModalOpen] = (0, import_react11.useState)(false);
4948
+ const [supportedTokens, setSupportedTokens] = (0, import_react12.useState)([]);
4949
+ const [tokensLoading, setTokensLoading] = (0, import_react12.useState)(true);
4950
+ const [detailsExpanded, setDetailsExpanded] = (0, import_react12.useState)(false);
4951
+ const [depositsModalOpen, setDepositsModalOpen] = (0, import_react12.useState)(false);
4696
4952
  const allChainsMap = /* @__PURE__ */ new Map();
4697
4953
  supportedTokens.forEach((t5) => {
4698
4954
  t5.chains.forEach((c) => {
@@ -4708,9 +4964,9 @@ function TransferCryptoDoubleInput({
4708
4964
  (c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
4709
4965
  );
4710
4966
  const currentChainType = currentChainData?.chain_type || "ethereum";
4711
- const currentWallet = (0, import_core11.getWalletByChainType)(wallets, currentChainType);
4967
+ const currentWallet = (0, import_core13.getWalletByChainType)(wallets, currentChainType);
4712
4968
  const depositAddress = currentWallet?.address || "";
4713
- (0, import_react11.useEffect)(() => {
4969
+ (0, import_react12.useEffect)(() => {
4714
4970
  async function fetchSupportedTokens() {
4715
4971
  try {
4716
4972
  setTokensLoading(true);
@@ -4719,7 +4975,7 @@ function TransferCryptoDoubleInput({
4719
4975
  destination_chain_id: destinationChainId,
4720
4976
  destination_chain_type: destinationChainType
4721
4977
  } : void 0;
4722
- const response = await (0, import_core11.getSupportedDepositTokens)(
4978
+ const response = await (0, import_core13.getSupportedDepositTokens)(
4723
4979
  publishableKey,
4724
4980
  options
4725
4981
  );
@@ -4753,12 +5009,12 @@ function TransferCryptoDoubleInput({
4753
5009
  destinationChainId,
4754
5010
  destinationChainType
4755
5011
  ]);
4756
- (0, import_react11.useEffect)(() => {
5012
+ (0, import_react12.useEffect)(() => {
4757
5013
  if (onExecutionsChange) {
4758
5014
  onExecutionsChange(depositExecutions);
4759
5015
  }
4760
5016
  }, [depositExecutions, onExecutionsChange]);
4761
- (0, import_react11.useEffect)(() => {
5017
+ (0, import_react12.useEffect)(() => {
4762
5018
  if (externalWallets?.length) {
4763
5019
  setLoading(false);
4764
5020
  return;
@@ -4773,7 +5029,7 @@ function TransferCryptoDoubleInput({
4773
5029
  if (isCancelled) return;
4774
5030
  setLoading(true);
4775
5031
  try {
4776
- const response = await (0, import_core11.createDepositAddress)(
5032
+ const response = await (0, import_core13.createDepositAddress)(
4777
5033
  {
4778
5034
  external_user_id: userId,
4779
5035
  recipient_address: recipientAddress,
@@ -4815,7 +5071,7 @@ function TransferCryptoDoubleInput({
4815
5071
  publishableKey,
4816
5072
  externalWallets
4817
5073
  ]);
4818
- (0, import_react11.useEffect)(() => {
5074
+ (0, import_react12.useEffect)(() => {
4819
5075
  if (!supportedTokens.length) return;
4820
5076
  const currentToken = supportedTokens.find((t5) => t5.symbol === token);
4821
5077
  if (!currentToken || currentToken.chains.length === 0) return;
@@ -4905,7 +5161,7 @@ function TransferCryptoDoubleInput({
4905
5161
  children: [
4906
5162
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "uf-grid uf-grid-cols-2 uf-gap-2.5", children: [
4907
5163
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
4908
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "uf-text-xs uf-text-muted-foreground uf-mb-2 uf-flex uf-items-center uf-gap-1", children: t3.supportedToken }),
5164
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "uf-text-xs uf-text-muted-foreground uf-mb-2 uf-flex uf-items-center uf-gap-1", children: t3.selectedToken }),
4909
5165
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4910
5166
  Select,
4911
5167
  {
@@ -4929,7 +5185,7 @@ function TransferCryptoDoubleInput({
4929
5185
  ] }),
4930
5186
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
4931
5187
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "uf-text-xs uf-text-muted-foreground uf-mb-2 uf-flex uf-items-center uf-gap-1", children: [
4932
- t3.supportedChain,
5188
+ t3.selectedChain,
4933
5189
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "uf-text-amber-400 uf-font-medium", children: [
4934
5190
  "$",
4935
5191
  minDepositUsd,
@@ -5043,24 +5299,24 @@ function TransferCryptoDoubleInput({
5043
5299
  )
5044
5300
  ] })
5045
5301
  ] }),
5046
- loading ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-muted-foreground uf-animate-pulse", children: t3.loading }) : error ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-red-400", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "uf-relative", children: [
5047
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5048
- "button",
5049
- {
5050
- onClick: handleCopyAddress,
5051
- disabled: !depositAddress,
5052
- className: "uf-w-full uf-bg-secondary hover:uf-bg-accent uf-rounded-lg uf-px-2.5 uf-py-2.5 uf-text-xs uf-font-mono uf-break-all uf-text-left uf-transition-colors uf-cursor-pointer disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
5053
- children: depositAddress || t3.noAddressAvailable
5054
- }
5055
- ),
5056
- depositAddress && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5057
- "span",
5058
- {
5059
- className: `uf-absolute uf-inset-y-0 uf-right-3 uf-flex uf-items-center uf-pointer-events-none uf-transition-colors ${copied ? "uf-text-green-500" : "uf-text-muted-foreground"}`,
5060
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react14.Check, { className: "uf-w-3 uf-h-3" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react14.Copy, { className: "uf-w-3 uf-h-3" })
5061
- }
5062
- )
5063
- ] })
5302
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-muted-foreground uf-animate-pulse", children: t3.loading }) : error ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "uf-bg-secondary uf-rounded-lg uf-px-3 uf-py-2.5 uf-text-xs uf-text-red-400", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5303
+ "button",
5304
+ {
5305
+ onClick: handleCopyAddress,
5306
+ disabled: !depositAddress,
5307
+ className: "uf-w-full uf-bg-secondary hover:uf-bg-accent uf-rounded-lg uf-px-3 uf-py-2.5 uf-flex uf-items-center uf-justify-between uf-gap-2 uf-transition-colors uf-cursor-pointer disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
5308
+ children: [
5309
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "uf-text-xs uf-font-mono uf-truncate uf-min-w-0", children: depositAddress ? truncateAddress(depositAddress, 18, 12) : t3.noAddressAvailable }),
5310
+ depositAddress && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5311
+ "span",
5312
+ {
5313
+ className: `uf-flex-shrink-0 uf-transition-colors ${copied ? "uf-text-green-500" : "uf-text-muted-foreground"}`,
5314
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react14.Check, { className: "uf-w-3.5 uf-h-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react14.Copy, { className: "uf-w-3.5 uf-h-3.5" })
5315
+ }
5316
+ )
5317
+ ]
5318
+ }
5319
+ )
5064
5320
  ] }),
5065
5321
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "uf-bg-secondary uf-rounded-xl uf-px-2.5", children: [
5066
5322
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
@@ -5266,26 +5522,27 @@ function DepositModal({
5266
5522
  destinationChainId,
5267
5523
  destinationTokenAddress,
5268
5524
  hideDepositTracker = false,
5525
+ showBalanceHeader = false,
5269
5526
  transferInputVariant = "double_input",
5270
5527
  onDepositSuccess,
5271
5528
  onDepositError,
5272
5529
  theme = "dark"
5273
5530
  }) {
5274
- const { colors: colors2 } = useTheme();
5275
- const [view, setView] = (0, import_react12.useState)("main");
5276
- const [cardView, setCardView] = (0, import_react12.useState)(
5531
+ const { colors: colors2, fonts } = useTheme();
5532
+ const [view, setView] = (0, import_react13.useState)("main");
5533
+ const [cardView, setCardView] = (0, import_react13.useState)(
5277
5534
  "amount"
5278
5535
  );
5279
- const [quotesCount, setQuotesCount] = (0, import_react12.useState)(0);
5280
- const [depositsModalOpen, setDepositsModalOpen] = (0, import_react12.useState)(false);
5281
- const [depositExecutions, setDepositExecutions] = (0, import_react12.useState)([]);
5282
- const [projectConfig, setProjectConfig] = (0, import_react12.useState)(null);
5283
- const [wallets, setWallets] = (0, import_react12.useState)([]);
5284
- const [walletsLoading, setWalletsLoading] = (0, import_react12.useState)(false);
5285
- (0, import_react12.useEffect)(() => {
5536
+ const [quotesCount, setQuotesCount] = (0, import_react13.useState)(0);
5537
+ const [depositsModalOpen, setDepositsModalOpen] = (0, import_react13.useState)(false);
5538
+ const [depositExecutions, setDepositExecutions] = (0, import_react13.useState)([]);
5539
+ const [projectConfig, setProjectConfig] = (0, import_react13.useState)(null);
5540
+ const [wallets, setWallets] = (0, import_react13.useState)([]);
5541
+ const [walletsLoading, setWalletsLoading] = (0, import_react13.useState)(false);
5542
+ (0, import_react13.useEffect)(() => {
5286
5543
  setProjectConfig(null);
5287
5544
  }, [publishableKey]);
5288
- (0, import_react12.useEffect)(() => {
5545
+ (0, import_react13.useEffect)(() => {
5289
5546
  setWallets([]);
5290
5547
  }, [
5291
5548
  userId,
@@ -5295,10 +5552,10 @@ function DepositModal({
5295
5552
  destinationTokenAddress,
5296
5553
  publishableKey
5297
5554
  ]);
5298
- const [resolvedTheme, setResolvedTheme] = (0, import_react12.useState)(
5555
+ const [resolvedTheme, setResolvedTheme] = (0, import_react13.useState)(
5299
5556
  theme === "auto" ? "dark" : theme
5300
5557
  );
5301
- (0, import_react12.useEffect)(() => {
5558
+ (0, import_react13.useEffect)(() => {
5302
5559
  if (theme === "auto") {
5303
5560
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
5304
5561
  setResolvedTheme(mediaQuery.matches ? "dark" : "light");
@@ -5311,9 +5568,9 @@ function DepositModal({
5311
5568
  setResolvedTheme(theme);
5312
5569
  }
5313
5570
  }, [theme]);
5314
- (0, import_react12.useEffect)(() => {
5571
+ (0, import_react13.useEffect)(() => {
5315
5572
  if (open && !projectConfig) {
5316
- (0, import_core12.getProjectConfig)(publishableKey).then(setProjectConfig).catch(console.error);
5573
+ (0, import_core14.getProjectConfig)(publishableKey).then(setProjectConfig).catch(console.error);
5317
5574
  }
5318
5575
  }, [open, publishableKey, projectConfig]);
5319
5576
  const {
@@ -5321,7 +5578,29 @@ function DepositModal({
5321
5578
  isLoading: isCountryLoading,
5322
5579
  error: countryError
5323
5580
  } = useAllowedCountry(publishableKey);
5324
- (0, import_react12.useEffect)(() => {
5581
+ const {
5582
+ isValid: isAddressValid,
5583
+ failureCode: addressFailureCode,
5584
+ metadata: addressFailureMetadata,
5585
+ isLoading: isAddressValidationLoading
5586
+ } = useAddressValidation({
5587
+ recipientAddress,
5588
+ destinationChainType,
5589
+ destinationChainId,
5590
+ destinationTokenAddress,
5591
+ publishableKey,
5592
+ enabled: open,
5593
+ // Only validate when modal is open
5594
+ refetchOnMount: "always"
5595
+ });
5596
+ const addressValidationMessages = i18n.transferCrypto.addressValidation;
5597
+ const getAddressValidationErrorMessage = (code, metadata) => {
5598
+ if (!code) return addressValidationMessages.defaultError;
5599
+ const errors = addressValidationMessages.errors;
5600
+ const template = errors[code] ?? addressValidationMessages.defaultError;
5601
+ return interpolate(template, metadata);
5602
+ };
5603
+ (0, import_react13.useEffect)(() => {
5325
5604
  if (!open || wallets.length > 0) return;
5326
5605
  let retryTimeout = null;
5327
5606
  let isCancelled = false;
@@ -5329,7 +5608,7 @@ function DepositModal({
5329
5608
  if (isCancelled) return;
5330
5609
  setWalletsLoading(true);
5331
5610
  try {
5332
- const response = await (0, import_core12.createDepositAddress)(
5611
+ const response = await (0, import_core14.createDepositAddress)(
5333
5612
  {
5334
5613
  external_user_id: userId,
5335
5614
  recipient_address: recipientAddress,
@@ -5405,10 +5684,16 @@ function DepositModal({
5405
5684
  DepositHeader,
5406
5685
  {
5407
5686
  title: modalTitle || "Deposit",
5408
- onClose: handleClose
5687
+ onClose: handleClose,
5688
+ showBalance: showBalanceHeader,
5689
+ balanceAddress: recipientAddress,
5690
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
5691
+ balanceChainId: destinationChainId,
5692
+ balanceTokenAddress: destinationTokenAddress,
5693
+ publishableKey
5409
5694
  }
5410
5695
  ),
5411
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "uf-pb-4 uf-space-y-3", children: isCountryLoading || !projectConfig ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5696
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "uf-pb-4 uf-space-y-3", children: isCountryLoading || isAddressValidationLoading || !projectConfig ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5412
5697
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SkeletonButton, { variant: "with-icons" }),
5413
5698
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SkeletonButton, { variant: "with-icons" }),
5414
5699
  !hideDepositTracker && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SkeletonButton, {})
@@ -5426,6 +5711,16 @@ function DepositModal({
5426
5711
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: "No Tokens Available" }),
5427
5712
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: "There are no supported tokens available from your current location." })
5428
5713
  ] })
5714
+ ) : isAddressValid === false ? (
5715
+ /* Invalid recipient address state (e.g., Algorand not opted in) */
5716
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
5717
+ /* @__PURE__ */ (0, import_jsx_runtime23.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_runtime23.jsx)(import_lucide_react15.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
5718
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: addressValidationMessages.unableToReceiveFunds }),
5719
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: getAddressValidationErrorMessage(
5720
+ addressFailureCode,
5721
+ addressFailureMetadata
5722
+ ) })
5723
+ ] })
5429
5724
  ) : (
5430
5725
  /* Normal deposit options */
5431
5726
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
@@ -5656,6 +5951,7 @@ Button.displayName = "Button";
5656
5951
  getColors,
5657
5952
  mergeColors,
5658
5953
  resolveComponentTokens,
5954
+ truncateAddress,
5659
5955
  useAllowedCountry,
5660
5956
  useTheme
5661
5957
  });