@unifold/connect-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
@@ -1145,7 +1145,7 @@ ${new this._window.XMLSerializer().serializeToString(e3)}`;
1145
1145
 
1146
1146
  // src/provider.tsx
1147
1147
  import React38, {
1148
- useState as useState22,
1148
+ useState as useState23,
1149
1149
  useCallback as useCallback10,
1150
1150
  useMemo as useMemo13
1151
1151
  } from "react";
@@ -1217,7 +1217,7 @@ function useUnifold() {
1217
1217
  }
1218
1218
 
1219
1219
  // ../ui-react/dist/index.mjs
1220
- import { useState as useState16, useEffect as useEffect132 } from "react";
1220
+ import { useState as useState17, useEffect as useEffect142 } from "react";
1221
1221
 
1222
1222
  // ../../node_modules/.pnpm/lucide-react@0.454.0_react@18.3.1/node_modules/lucide-react/dist/esm/createLucideIcon.js
1223
1223
  import { forwardRef as forwardRef2, createElement as createElement2 } from "react";
@@ -6007,7 +6007,7 @@ var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);
6007
6007
  import * as React36 from "react";
6008
6008
  import { jsx as jsx17 } from "react/jsx-runtime";
6009
6009
  import { jsx as jsx23, jsxs as jsxs4 } from "react/jsx-runtime";
6010
- import { useState as useState82, useEffect as useEffect42, useRef as useRef22 } from "react";
6010
+ import { useState as useState92, useEffect as useEffect52, useRef as useRef22 } from "react";
6011
6011
 
6012
6012
  // ../core/dist/index.mjs
6013
6013
  import { useQuery } from "@tanstack/react-query";
@@ -6294,12 +6294,14 @@ async function getTokenChains() {
6294
6294
  return response.json();
6295
6295
  }
6296
6296
  function getChainName(chains, chainType, chainId) {
6297
+ if (!chainType && !chainId) return "Unknown";
6297
6298
  const target = chains.find((c) => c.chain_id === chainId && c.chain_type === chainType);
6298
6299
  if (target) return target.chain_name;
6299
6300
  const byId = chains.find((c) => c.chain_id === chainId);
6300
6301
  if (byId) return byId.chain_name;
6301
6302
  const byType = chains.find((c) => c.chain_type === chainType);
6302
6303
  if (byType) return byType.chain_name;
6304
+ if (!chainType) return chainId || "Unknown";
6303
6305
  return chainType.charAt(0).toUpperCase() + chainType.slice(1);
6304
6306
  }
6305
6307
  async function getProjectConfig(publishableKey) {
@@ -6333,6 +6335,49 @@ async function getIpAddress() {
6333
6335
  }
6334
6336
  return response.json();
6335
6337
  }
6338
+ async function getAddressBalance(address, chainType, chainId, tokenAddress, publishableKey) {
6339
+ const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6340
+ validatePublishableKey(pk);
6341
+ const url = `${API_BASE_URL}/v1/public/addresses/balance`;
6342
+ const response = await fetch(url, {
6343
+ method: "POST",
6344
+ headers: {
6345
+ "Content-Type": "application/json",
6346
+ accept: "application/json",
6347
+ "x-publishable-key": pk
6348
+ },
6349
+ body: JSON.stringify({
6350
+ address,
6351
+ chain_type: chainType,
6352
+ chain_id: chainId,
6353
+ token_address: tokenAddress
6354
+ })
6355
+ });
6356
+ if (!response.ok) {
6357
+ throw new Error(`Failed to fetch address balance: ${response.statusText}`);
6358
+ }
6359
+ const data = await response.json();
6360
+ return data;
6361
+ }
6362
+ async function verifyRecipientAddress(request, publishableKey) {
6363
+ const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6364
+ validatePublishableKey(pk);
6365
+ const response = await fetch(`${API_BASE_URL}/v1/public/addresses/verify`, {
6366
+ method: "POST",
6367
+ headers: {
6368
+ accept: "application/json",
6369
+ "x-publishable-key": pk,
6370
+ "Content-Type": "application/json"
6371
+ },
6372
+ body: JSON.stringify(request)
6373
+ });
6374
+ if (!response.ok) {
6375
+ throw new Error(
6376
+ `Failed to verify recipient address: ${response.statusText}`
6377
+ );
6378
+ }
6379
+ return response.json();
6380
+ }
6336
6381
  function useUserIp() {
6337
6382
  const {
6338
6383
  data: userIpInfo,
@@ -6432,22 +6477,23 @@ var en_default = {
6432
6477
  var i18n = en_default;
6433
6478
 
6434
6479
  // ../ui-react/dist/index.mjs
6435
- import { useState as useState32 } from "react";
6480
+ import { useState as useState42 } from "react";
6481
+ import { useEffect as useEffect22, useState as useState22 } from "react";
6436
6482
  import { jsx as jsx32, jsxs as jsxs22 } from "react/jsx-runtime";
6437
6483
  import * as React37 from "react";
6438
6484
  import { jsx as jsx42, jsxs as jsxs32 } from "react/jsx-runtime";
6439
6485
  import { Fragment as Fragment8, jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
6440
6486
  import { jsx as jsx62, jsxs as jsxs5 } from "react/jsx-runtime";
6441
6487
  import { useQuery as useQuery2 } from "@tanstack/react-query";
6442
- import { useState as useState42, useEffect as useEffect22, useRef as useRef16 } from "react";
6488
+ import { useState as useState52, useEffect as useEffect32, useRef as useRef16 } from "react";
6489
+ import { useState as useState82 } from "react";
6443
6490
  import { useState as useState72 } from "react";
6444
- import { useState as useState62 } from "react";
6445
- import { useEffect as useEffect32, useState as useState52 } from "react";
6491
+ import { useEffect as useEffect42, useState as useState62 } from "react";
6446
6492
  import { jsx as jsx72, jsxs as jsxs6 } from "react/jsx-runtime";
6447
6493
  import { Fragment as Fragment23, jsx as jsx82, jsxs as jsxs7 } from "react/jsx-runtime";
6448
6494
  import { jsx as jsx92 } from "react/jsx-runtime";
6449
6495
  import { jsx as jsx102, jsxs as jsxs8 } from "react/jsx-runtime";
6450
- import { useEffect as useEffect52, useState as useState92 } from "react";
6496
+ import { useEffect as useEffect62, useState as useState102 } from "react";
6451
6497
  import { jsx as jsx112, jsxs as jsxs9 } from "react/jsx-runtime";
6452
6498
  import * as React42 from "react";
6453
6499
  import { jsx as jsx122 } from "react/jsx-runtime";
@@ -6459,11 +6505,12 @@ import { jsx as jsx152, jsxs as jsxs12 } from "react/jsx-runtime";
6459
6505
  import * as React72 from "react";
6460
6506
  import { jsx as jsx162, jsxs as jsxs13 } from "react/jsx-runtime";
6461
6507
  import { useQuery as useQuery22 } from "@tanstack/react-query";
6462
- import { useState as useState142, useEffect as useEffect112 } from "react";
6508
+ import { useQuery as useQuery3 } from "@tanstack/react-query";
6509
+ import { useState as useState152, useEffect as useEffect122 } from "react";
6463
6510
  var import_qr_code_styling = __toESM(require_qr_code_styling(), 1);
6464
- import { useEffect as useEffect92, useRef as useRef32 } from "react";
6511
+ import { useEffect as useEffect102, useRef as useRef32 } from "react";
6465
6512
  import { jsx as jsx172 } from "react/jsx-runtime";
6466
- import { useState as useState132, useMemo as useMemo32, useEffect as useEffect102 } from "react";
6513
+ import { useState as useState142, useMemo as useMemo32, useEffect as useEffect112 } from "react";
6467
6514
  import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
6468
6515
  import * as React82 from "react";
6469
6516
 
@@ -9205,7 +9252,7 @@ var Content22 = TooltipContent;
9205
9252
  // ../ui-react/dist/index.mjs
9206
9253
  import { jsx as jsx19 } from "react/jsx-runtime";
9207
9254
  import { Fragment as Fragment42, jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
9208
- import { useState as useState152, useEffect as useEffect122 } from "react";
9255
+ import { useState as useState162, useEffect as useEffect132 } from "react";
9209
9256
  import * as React92 from "react";
9210
9257
 
9211
9258
  // ../../node_modules/.pnpm/@radix-ui+react-select@2.2.6_@types+react-dom@19.2.3_@types+react@19.2.9__@types+react@19.2.9_5n4syhs66qrtkkphe44qzgdimq/node_modules/@radix-ui/react-select/dist/index.mjs
@@ -10594,6 +10641,29 @@ import { jsx as jsx24 } from "react/jsx-runtime";
10594
10641
  function cn(...inputs) {
10595
10642
  return twMerge(clsx(inputs));
10596
10643
  }
10644
+ function formatEstimatedTime(seconds) {
10645
+ if (seconds == null) {
10646
+ return "< 1 min";
10647
+ }
10648
+ if (seconds < 60) {
10649
+ return `< ${seconds} sec${seconds > 1 ? "s" : ""}`;
10650
+ } else if (seconds < 3600) {
10651
+ const mins = Math.ceil(seconds / 60);
10652
+ return `< ${mins} min${mins > 1 ? "s" : ""}`;
10653
+ } else {
10654
+ let hrs = Math.floor(seconds / 3600);
10655
+ let mins = Math.ceil(seconds % 3600 / 60);
10656
+ if (mins === 60) {
10657
+ hrs += 1;
10658
+ mins = 0;
10659
+ }
10660
+ const hrLabel = hrs > 1 ? "hrs" : "hr";
10661
+ if (mins === 0) {
10662
+ return `< ${hrs} ${hrLabel}`;
10663
+ }
10664
+ return `< ${hrs} ${hrLabel} ${mins} min${mins > 1 ? "s" : ""}`;
10665
+ }
10666
+ }
10597
10667
  var defaultColors = {
10598
10668
  light: {
10599
10669
  // Background colors
@@ -11035,10 +11105,83 @@ function DepositHeader({
11035
11105
  showClose = true,
11036
11106
  onBack,
11037
11107
  onClose,
11038
- badge
11108
+ badge,
11109
+ showBalance = false,
11110
+ balanceAddress,
11111
+ balanceChainType,
11112
+ balanceChainId,
11113
+ balanceTokenAddress,
11114
+ publishableKey
11039
11115
  }) {
11040
11116
  const { colors: colors2, fonts, components } = useTheme();
11041
- return /* @__PURE__ */ jsxs22("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
11117
+ const [balance, setBalance] = useState22(null);
11118
+ const [isLoadingBalance, setIsLoadingBalance] = useState22(false);
11119
+ useEffect22(() => {
11120
+ if (!showBalance || !balanceAddress || !balanceChainType || !balanceChainId || !balanceTokenAddress || !publishableKey) {
11121
+ setBalance(null);
11122
+ setIsLoadingBalance(false);
11123
+ return;
11124
+ }
11125
+ let cancelled = false;
11126
+ setIsLoadingBalance(true);
11127
+ getAddressBalance(
11128
+ balanceAddress,
11129
+ balanceChainType,
11130
+ balanceChainId,
11131
+ balanceTokenAddress,
11132
+ publishableKey
11133
+ ).then((response) => {
11134
+ if (cancelled) return;
11135
+ if (response.balance && response.balance.amount !== "0") {
11136
+ const value = Number(response.balance.amount) / 10 ** response.balance.token.decimals;
11137
+ let formatted;
11138
+ let maxDecimals = 4;
11139
+ const symbol = response.balance.token.symbol?.toUpperCase() || "";
11140
+ if (symbol === "BTC" || symbol === "WBTC") {
11141
+ maxDecimals = 8;
11142
+ } else if (symbol === "ETH" || symbol === "WETH") {
11143
+ maxDecimals = 6;
11144
+ }
11145
+ if (value >= 1) {
11146
+ formatted = value.toLocaleString(void 0, {
11147
+ minimumFractionDigits: 2,
11148
+ maximumFractionDigits: maxDecimals
11149
+ });
11150
+ } else if (value > 0) {
11151
+ formatted = value.toLocaleString(void 0, {
11152
+ minimumFractionDigits: 2,
11153
+ maximumFractionDigits: maxDecimals,
11154
+ minimumSignificantDigits: 2,
11155
+ maximumSignificantDigits: 6
11156
+ });
11157
+ } else {
11158
+ formatted = value.toExponential(2);
11159
+ }
11160
+ const balanceText = response.balance.amount_usd ? `Balance: $${response.balance.amount_usd} (${formatted} ${response.balance.token.symbol})` : `Balance: ${formatted} ${response.balance.token.symbol}`;
11161
+ setBalance(balanceText);
11162
+ } else {
11163
+ setBalance(null);
11164
+ }
11165
+ }).catch((error) => {
11166
+ if (cancelled) return;
11167
+ console.error("Error fetching balance:", error);
11168
+ setBalance(null);
11169
+ }).finally(() => {
11170
+ if (cancelled) return;
11171
+ setIsLoadingBalance(false);
11172
+ });
11173
+ return () => {
11174
+ cancelled = true;
11175
+ };
11176
+ }, [
11177
+ showBalance,
11178
+ balanceAddress,
11179
+ balanceChainType,
11180
+ balanceChainId,
11181
+ balanceTokenAddress,
11182
+ publishableKey
11183
+ ]);
11184
+ return /* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsxs22("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
11042
11185
  showBack ? /* @__PURE__ */ jsx32(
11043
11186
  "button",
11044
11187
  {
@@ -11048,8 +11191,32 @@ function DepositHeader({
11048
11191
  children: /* @__PURE__ */ jsx32(ArrowLeft, { className: "uf-w-5 uf-h-5" })
11049
11192
  }
11050
11193
  ) : /* @__PURE__ */ jsx32("div", { className: "uf-w-5 uf-h-5 uf-invisible" }),
11051
- badge ? /* @__PURE__ */ jsxs22("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
11052
- /* @__PURE__ */ jsx32(
11194
+ /* @__PURE__ */ jsxs22("div", { className: "uf-flex uf-flex-col uf-items-center", children: [
11195
+ badge ? /* @__PURE__ */ jsxs22("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
11196
+ /* @__PURE__ */ jsx32(
11197
+ DialogTitle2,
11198
+ {
11199
+ className: "uf-text-center uf-text-base",
11200
+ style: {
11201
+ color: components.header.titleColor,
11202
+ fontFamily: fonts.medium
11203
+ },
11204
+ children: title
11205
+ }
11206
+ ),
11207
+ /* @__PURE__ */ jsx32(
11208
+ "div",
11209
+ {
11210
+ className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
11211
+ style: {
11212
+ backgroundColor: colors2.card,
11213
+ color: colors2.foregroundMuted,
11214
+ fontFamily: fonts.regular
11215
+ },
11216
+ children: badge.count
11217
+ }
11218
+ )
11219
+ ] }) : /* @__PURE__ */ jsx32(
11053
11220
  DialogTitle2,
11054
11221
  {
11055
11222
  className: "uf-text-center uf-text-base",
@@ -11060,29 +11227,19 @@ function DepositHeader({
11060
11227
  children: title
11061
11228
  }
11062
11229
  ),
11063
- /* @__PURE__ */ jsx32(
11230
+ showBalance && (isLoadingBalance ? /* @__PURE__ */ jsx32("div", { className: "uf-h-3 uf-w-32 uf-bg-muted uf-rounded uf-animate-pulse uf-mt-2" }) : balance ? /* @__PURE__ */ jsx32(
11064
11231
  "div",
11065
11232
  {
11066
- className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
11233
+ className: "uf-text-xs uf-mt-2",
11067
11234
  style: {
11068
- backgroundColor: colors2.card,
11069
- color: colors2.foregroundMuted,
11070
- fontFamily: fonts.regular
11235
+ color: colors2.foreground,
11236
+ fontFamily: fonts.regular,
11237
+ opacity: 0.7
11071
11238
  },
11072
- children: badge.count
11239
+ children: balance
11073
11240
  }
11074
- )
11075
- ] }) : /* @__PURE__ */ jsx32(
11076
- DialogTitle2,
11077
- {
11078
- className: "uf-text-center uf-text-base",
11079
- style: {
11080
- color: components.header.titleColor,
11081
- fontFamily: fonts.medium
11082
- },
11083
- children: title
11084
- }
11085
- ),
11241
+ ) : null)
11242
+ ] }),
11086
11243
  showClose ? /* @__PURE__ */ jsx32(
11087
11244
  "button",
11088
11245
  {
@@ -11092,7 +11249,7 @@ function DepositHeader({
11092
11249
  children: /* @__PURE__ */ jsx32(X, { className: "uf-w-5 uf-h-5" })
11093
11250
  }
11094
11251
  ) : /* @__PURE__ */ jsx32("div", { className: "uf-w-5 uf-h-5 uf-invisible" })
11095
- ] });
11252
+ ] }) });
11096
11253
  }
11097
11254
  function CurrencyListItem({
11098
11255
  currency,
@@ -11193,7 +11350,7 @@ function CurrencyModal({
11193
11350
  themeClass = ""
11194
11351
  }) {
11195
11352
  const { colors: colors2, fonts, components } = useTheme();
11196
- const [searchQuery, setSearchQuery] = useState32("");
11353
+ const [searchQuery, setSearchQuery] = useState42("");
11197
11354
  const preferredCurrencies = preferredCurrencyCodes.map(
11198
11355
  (code) => currencies.find(
11199
11356
  (currency) => currency.currency_code.toLowerCase() === code.toLowerCase()
@@ -11363,7 +11520,19 @@ var en_default2 = {
11363
11520
  minimumDeposit: "Minimum: {{amount}}",
11364
11521
  minimumDepositTooltip: "The minimum amount you can deposit on the selected network.",
11365
11522
  selectTokenDeposit: "Your deposit token",
11366
- selectTokenDepositTooltip: "Select the token you want to deposit with in order to begin the deposit process."
11523
+ selectTokenDepositTooltip: "Select the token you want to deposit with in order to begin the deposit process.",
11524
+ addressValidation: {
11525
+ validating: "Verifying recipient address...",
11526
+ unableToReceiveFunds: "Unable to Receive Funds",
11527
+ errors: {
11528
+ token_not_supported: "The destination token is not supported",
11529
+ not_opted_in: "Please make sure you opt-in {{token_symbol}}({{chain_name}}) before receiving funds",
11530
+ insufficient_balance: "Recipient account does not meet the minimum balance requirement",
11531
+ account_not_found: "Recipient account does not exist on {{chain_name}}",
11532
+ validation_error: "Unable to verify recipient address on {{chain_name}}"
11533
+ },
11534
+ defaultError: "The recipient address cannot receive funds for the selected token"
11535
+ }
11367
11536
  },
11368
11537
  depositModal: {
11369
11538
  transferCrypto: {
@@ -11372,7 +11541,7 @@ var en_default2 = {
11372
11541
  },
11373
11542
  depositWithCard: {
11374
11543
  title: "Deposit with Card",
11375
- subtitle: "$50,000 limit \u2022 2 min"
11544
+ subtitle: "$50,000 limit"
11376
11545
  },
11377
11546
  quotes: "Quotes"
11378
11547
  },
@@ -11388,6 +11557,13 @@ var en_default2 = {
11388
11557
  }
11389
11558
  };
11390
11559
  var i18n2 = en_default2;
11560
+ function interpolate(template, params) {
11561
+ if (!params) return template;
11562
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
11563
+ const value = params[key];
11564
+ return value !== void 0 ? String(value) : `{{${key}}}`;
11565
+ });
11566
+ }
11391
11567
  function useDepositPolling({
11392
11568
  userId,
11393
11569
  publishableKey,
@@ -11395,14 +11571,14 @@ function useDepositPolling({
11395
11571
  onDepositSuccess,
11396
11572
  onDepositError
11397
11573
  }) {
11398
- const [executions, setExecutions] = useState42([]);
11399
- const [isPolling, setIsPolling] = useState42(false);
11574
+ const [executions, setExecutions] = useState52([]);
11575
+ const [isPolling, setIsPolling] = useState52(false);
11400
11576
  const pollingIntervalRef = useRef16(
11401
11577
  null
11402
11578
  );
11403
- const [modalOpenedAt] = useState42(/* @__PURE__ */ new Date());
11404
- const [trackedExecutions, setTrackedExecutions] = useState42(/* @__PURE__ */ new Map());
11405
- useEffect22(() => {
11579
+ const [modalOpenedAt] = useState52(/* @__PURE__ */ new Date());
11580
+ const [trackedExecutions, setTrackedExecutions] = useState52(/* @__PURE__ */ new Map());
11581
+ useEffect32(() => {
11406
11582
  if (!userId || !modalOpenedAt || !enabled) return;
11407
11583
  const pollInterval = setInterval(async () => {
11408
11584
  try {
@@ -11513,12 +11689,12 @@ function formatCurrency(currency) {
11513
11689
  }
11514
11690
  function DepositDetailContent({ execution }) {
11515
11691
  const { colors: colors2, fonts, components } = useTheme();
11516
- const [chains, setChains] = useState52([]);
11517
- const [showNetworkDetails, setShowNetworkDetails] = useState52(false);
11518
- useEffect32(() => {
11692
+ const [chains, setChains] = useState62([]);
11693
+ const [showNetworkDetails, setShowNetworkDetails] = useState62(false);
11694
+ useEffect42(() => {
11519
11695
  getTokenChains().then((response) => setChains(response.data)).catch((err) => console.error("Failed to fetch chains:", err));
11520
11696
  }, []);
11521
- useEffect32(() => {
11697
+ useEffect42(() => {
11522
11698
  setShowNetworkDetails(false);
11523
11699
  }, [execution?.id]);
11524
11700
  const isPending = execution.status === ExecutionStatus.PENDING || execution.status === ExecutionStatus.WAITING || execution.status === ExecutionStatus.DELAYED;
@@ -11813,6 +11989,37 @@ function DepositDetailContent({ execution }) {
11813
11989
  ]
11814
11990
  }
11815
11991
  ),
11992
+ isPending && /* @__PURE__ */ jsxs6(
11993
+ "div",
11994
+ {
11995
+ className: "uf-flex uf-justify-between uf-items-center uf-px-4 uf-py-3 uf-border-b",
11996
+ style: { borderColor: colors2.border },
11997
+ children: [
11998
+ /* @__PURE__ */ jsx72(
11999
+ "span",
12000
+ {
12001
+ className: "uf-text-sm",
12002
+ style: {
12003
+ color: components.card.labelColor,
12004
+ fontFamily: fonts.regular
12005
+ },
12006
+ children: "Estimated delivery time"
12007
+ }
12008
+ ),
12009
+ /* @__PURE__ */ jsx72(
12010
+ "span",
12011
+ {
12012
+ style: {
12013
+ color: components.card.titleColor,
12014
+ fontFamily: fonts.regular,
12015
+ fontSize: "14px"
12016
+ },
12017
+ children: formatEstimatedTime(execution?.estimated_processing_time)
12018
+ }
12019
+ )
12020
+ ]
12021
+ }
12022
+ ),
11816
12023
  /* @__PURE__ */ jsxs6(
11817
12024
  "div",
11818
12025
  {
@@ -11996,7 +12203,7 @@ function DepositSuccessToast({
11996
12203
  onClose,
11997
12204
  execution
11998
12205
  }) {
11999
- const [detailModalOpen, setDetailModalOpen] = useState62(false);
12206
+ const [detailModalOpen, setDetailModalOpen] = useState72(false);
12000
12207
  const { themeClass, colors: colors2, fonts, components } = useTheme();
12001
12208
  const isPending = status === ExecutionStatus.PENDING || status === ExecutionStatus.WAITING || status === ExecutionStatus.DELAYED;
12002
12209
  const formatDateTime = (timestamp) => {
@@ -12130,14 +12337,27 @@ function DepositSuccessToast({
12130
12337
  }
12131
12338
  )
12132
12339
  ] }),
12133
- /* @__PURE__ */ jsx82(
12134
- "div",
12135
- {
12136
- className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
12137
- style: { color: colors2.background },
12138
- children: formatUsdAmount(sourceAmountUsd)
12139
- }
12140
- ),
12340
+ /* @__PURE__ */ jsxs7("div", { className: "uf-flex-shrink-0 uf-text-right", children: [
12341
+ /* @__PURE__ */ jsx82(
12342
+ "div",
12343
+ {
12344
+ className: "uf-font-medium uf-text-sm",
12345
+ style: { color: colors2.background },
12346
+ children: formatUsdAmount(sourceAmountUsd)
12347
+ }
12348
+ ),
12349
+ isPending && execution?.estimated_processing_time && /* @__PURE__ */ jsxs7(
12350
+ "p",
12351
+ {
12352
+ className: "uf-text-xs",
12353
+ style: { color: colors2.foregroundMuted },
12354
+ children: [
12355
+ "Est. ",
12356
+ formatEstimatedTime(execution.estimated_processing_time)
12357
+ ]
12358
+ }
12359
+ )
12360
+ ] }),
12141
12361
  /* @__PURE__ */ jsx82(
12142
12362
  "button",
12143
12363
  {
@@ -12183,7 +12403,7 @@ function DepositPollingToasts({
12183
12403
  executions,
12184
12404
  horizontalPadding = "24px"
12185
12405
  }) {
12186
- const [closedExecutionIds, setClosedExecutionIds] = useState72(
12406
+ const [closedExecutionIds, setClosedExecutionIds] = useState82(
12187
12407
  /* @__PURE__ */ new Set()
12188
12408
  );
12189
12409
  const handleClose = (executionId) => {
@@ -12261,28 +12481,28 @@ function BuyWithCard({
12261
12481
  assetCdnUrl
12262
12482
  }) {
12263
12483
  const { colors: colors2, fonts, components } = useTheme();
12264
- const [amount, setAmount] = useState82("");
12265
- const [currency, setCurrency] = useState82("usd");
12266
- const [hasManualCurrencySelection, setHasManualCurrencySelection] = useState82(false);
12267
- const [hasManualAmountEntry, setHasManualAmountEntry] = useState82(false);
12268
- const [showCurrencyModal, setShowCurrencyModal] = useState82(false);
12269
- const [quotes, setQuotes] = useState82([]);
12270
- const [quotesLoading, setQuotesLoading] = useState82(false);
12271
- const [quotesError, setQuotesError] = useState82(null);
12272
- const [amountValidationError, setAmountValidationError] = useState82(null);
12273
- const [internalView, setInternalView] = useState82("amount");
12274
- const [defaultToken, setDefaultToken] = useState82(
12484
+ const [amount, setAmount] = useState92("");
12485
+ const [currency, setCurrency] = useState92("usd");
12486
+ const [hasManualCurrencySelection, setHasManualCurrencySelection] = useState92(false);
12487
+ const [hasManualAmountEntry, setHasManualAmountEntry] = useState92(false);
12488
+ const [showCurrencyModal, setShowCurrencyModal] = useState92(false);
12489
+ const [quotes, setQuotes] = useState92([]);
12490
+ const [quotesLoading, setQuotesLoading] = useState92(false);
12491
+ const [quotesError, setQuotesError] = useState92(null);
12492
+ const [amountValidationError, setAmountValidationError] = useState92(null);
12493
+ const [internalView, setInternalView] = useState92("amount");
12494
+ const [defaultToken, setDefaultToken] = useState92(
12275
12495
  null
12276
12496
  );
12277
- const [defaultTokenLoading, setDefaultTokenLoading] = useState82(false);
12497
+ const [defaultTokenLoading, setDefaultTokenLoading] = useState92(false);
12278
12498
  const { userIpInfo, isLoading: isLoadingIp } = useUserIp2();
12279
- const [onrampSession, setOnrampSession] = useState82(
12499
+ const [onrampSession, setOnrampSession] = useState92(
12280
12500
  null
12281
12501
  );
12282
12502
  const currentView = externalView ?? internalView;
12283
12503
  const showQuotesView = currentView === "quotes";
12284
12504
  const showOnrampView = currentView === "onramp";
12285
- useEffect42(() => {
12505
+ useEffect52(() => {
12286
12506
  if (externalView) {
12287
12507
  setInternalView(externalView);
12288
12508
  }
@@ -12295,31 +12515,31 @@ function BuyWithCard({
12295
12515
  onViewChange?.(newView);
12296
12516
  }
12297
12517
  };
12298
- const [selectedProvider, setSelectedProvider] = useState82(
12518
+ const [selectedProvider, setSelectedProvider] = useState92(
12299
12519
  null
12300
12520
  );
12301
- const [isAutoSelected, setIsAutoSelected] = useState82(true);
12302
- const [autoSelectedProvider, setAutoSelectedProvider] = useState82(null);
12303
- const [hoveredProviderIndex, setHoveredProviderIndex] = useState82(null);
12304
- const [hasManualSelection, setHasManualSelection] = useState82(false);
12521
+ const [isAutoSelected, setIsAutoSelected] = useState92(true);
12522
+ const [autoSelectedProvider, setAutoSelectedProvider] = useState92(null);
12523
+ const [hoveredProviderIndex, setHoveredProviderIndex] = useState92(null);
12524
+ const [hasManualSelection, setHasManualSelection] = useState92(false);
12305
12525
  const selectedProviderRef = useRef22(null);
12306
12526
  const hasManualSelectionRef = useRef22(false);
12307
- useEffect42(() => {
12527
+ useEffect52(() => {
12308
12528
  selectedProviderRef.current = selectedProvider;
12309
12529
  }, [selectedProvider]);
12310
- useEffect42(() => {
12530
+ useEffect52(() => {
12311
12531
  hasManualSelectionRef.current = hasManualSelection;
12312
12532
  }, [hasManualSelection]);
12313
- const [internalWallets, setInternalWallets] = useState82([]);
12314
- const [walletsLoading, setWalletsLoading] = useState82(
12533
+ const [internalWallets, setInternalWallets] = useState92([]);
12534
+ const [walletsLoading, setWalletsLoading] = useState92(
12315
12535
  !externalWallets?.length
12316
12536
  );
12317
12537
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
12318
- const [countdown, setCountdown] = useState82(60);
12319
- const [fiatCurrencies, setFiatCurrencies] = useState82([]);
12320
- const [preferredCurrencyCodes, setPreferredCurrencyCodes] = useState82([]);
12321
- const [currenciesLoading, setCurrenciesLoading] = useState82(true);
12322
- const [destinationToken, setDestinationToken] = useState82(null);
12538
+ const [countdown, setCountdown] = useState92(60);
12539
+ const [fiatCurrencies, setFiatCurrencies] = useState92([]);
12540
+ const [preferredCurrencyCodes, setPreferredCurrencyCodes] = useState92([]);
12541
+ const [currenciesLoading, setCurrenciesLoading] = useState92(true);
12542
+ const [destinationToken, setDestinationToken] = useState92(null);
12323
12543
  const { executions, isPolling } = useDepositPolling({
12324
12544
  userId,
12325
12545
  publishableKey,
@@ -12331,7 +12551,7 @@ function BuyWithCard({
12331
12551
  const destinationTokenIcon = destinationToken?.icon_url;
12332
12552
  const destinationChainIcon = destinationToken?.chain_icon_url;
12333
12553
  const destinationChainName = destinationToken?.chain_name;
12334
- useEffect42(() => {
12554
+ useEffect52(() => {
12335
12555
  async function fetchFiatCurrencies() {
12336
12556
  try {
12337
12557
  const response = await getFiatCurrencies(publishableKey);
@@ -12345,7 +12565,7 @@ function BuyWithCard({
12345
12565
  }
12346
12566
  fetchFiatCurrencies();
12347
12567
  }, [publishableKey]);
12348
- useEffect42(() => {
12568
+ useEffect52(() => {
12349
12569
  if (hasManualCurrencySelection) return;
12350
12570
  if (fiatCurrencies.length === 0 || !userIpInfo?.alpha2) return;
12351
12571
  const userCountryCode = userIpInfo.alpha2.toUpperCase();
@@ -12373,7 +12593,7 @@ function BuyWithCard({
12373
12593
  hasManualAmountEntry
12374
12594
  ]);
12375
12595
  const prevCurrencyRef = useRef22(null);
12376
- useEffect42(() => {
12596
+ useEffect52(() => {
12377
12597
  if (fiatCurrencies.length === 0) return;
12378
12598
  if (prevCurrencyRef.current !== null && prevCurrencyRef.current !== currency) {
12379
12599
  const currentCurrency = fiatCurrencies.find(
@@ -12385,7 +12605,7 @@ function BuyWithCard({
12385
12605
  }
12386
12606
  prevCurrencyRef.current = currency;
12387
12607
  }, [currency]);
12388
- useEffect42(() => {
12608
+ useEffect52(() => {
12389
12609
  if (externalWallets?.length) {
12390
12610
  setWalletsLoading(false);
12391
12611
  return;
@@ -12438,7 +12658,7 @@ function BuyWithCard({
12438
12658
  publishableKey,
12439
12659
  externalWallets
12440
12660
  ]);
12441
- useEffect42(() => {
12661
+ useEffect52(() => {
12442
12662
  async function fetchDestinationToken() {
12443
12663
  try {
12444
12664
  const response = await getTokenMetadata(
@@ -12456,7 +12676,7 @@ function BuyWithCard({
12456
12676
  }
12457
12677
  fetchDestinationToken();
12458
12678
  }, [publishableKey]);
12459
- useEffect42(() => {
12679
+ useEffect52(() => {
12460
12680
  async function fetchDefaultToken() {
12461
12681
  if (!destinationTokenAddress || !destinationChainId || !destinationChainType) {
12462
12682
  return;
@@ -12492,7 +12712,7 @@ function BuyWithCard({
12492
12712
  isLoadingIp,
12493
12713
  publishableKey
12494
12714
  ]);
12495
- useEffect42(() => {
12715
+ useEffect52(() => {
12496
12716
  const amountNum = parseFloat(amount);
12497
12717
  if (isNaN(amountNum) || amountNum <= 0) {
12498
12718
  setQuotes([]);
@@ -12601,7 +12821,7 @@ function BuyWithCard({
12601
12821
  setQuotesLoading(false);
12602
12822
  }
12603
12823
  };
12604
- useEffect42(() => {
12824
+ useEffect52(() => {
12605
12825
  if (quotes.length === 0) return;
12606
12826
  const timer = setInterval(() => {
12607
12827
  setCountdown((prev) => {
@@ -12936,6 +13156,20 @@ function BuyWithCard({
12936
13156
  },
12937
13157
  children: quotesError
12938
13158
  }
13159
+ ),
13160
+ defaultToken?.estimated_processing_time && !quotesLoading && selectedProvider && /* @__PURE__ */ jsxs8(
13161
+ "div",
13162
+ {
13163
+ className: "uf-text-xs uf-mt-2 uf-px-1",
13164
+ style: {
13165
+ color: components.card.subtitleColor,
13166
+ fontFamily: fonts.regular
13167
+ },
13168
+ children: [
13169
+ "Estimated delivery time: ",
13170
+ formatEstimatedTime(defaultToken.estimated_processing_time)
13171
+ ]
13172
+ }
12939
13173
  )
12940
13174
  ] }),
12941
13175
  /* @__PURE__ */ jsx102(
@@ -13379,9 +13613,9 @@ function DepositsModal({
13379
13613
  themeClass = ""
13380
13614
  }) {
13381
13615
  const { colors: colors2 } = useTheme();
13382
- const [allExecutions, setAllExecutions] = useState92(sessionExecutions);
13383
- const [selectedExecution, setSelectedExecution] = useState92(null);
13384
- useEffect52(() => {
13616
+ const [allExecutions, setAllExecutions] = useState102(sessionExecutions);
13617
+ const [selectedExecution, setSelectedExecution] = useState102(null);
13618
+ useEffect62(() => {
13385
13619
  if (!open || !userId) return;
13386
13620
  const fetchExecutions = async () => {
13387
13621
  try {
@@ -13403,7 +13637,7 @@ function DepositsModal({
13403
13637
  clearInterval(pollInterval);
13404
13638
  };
13405
13639
  }, [open, userId, publishableKey, sessionExecutions]);
13406
- useEffect52(() => {
13640
+ useEffect62(() => {
13407
13641
  if (!open) {
13408
13642
  setSelectedExecution(null);
13409
13643
  }
@@ -13762,6 +13996,60 @@ function useAllowedCountry(publishableKey) {
13762
13996
  error
13763
13997
  };
13764
13998
  }
13999
+ function useAddressValidation({
14000
+ recipientAddress,
14001
+ destinationChainType,
14002
+ destinationChainId,
14003
+ destinationTokenAddress,
14004
+ publishableKey,
14005
+ enabled = true,
14006
+ refetchOnMount = false
14007
+ }) {
14008
+ const shouldValidate = enabled && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
14009
+ const { data, isLoading, error } = useQuery3({
14010
+ queryKey: [
14011
+ "unifold",
14012
+ "addressValidation",
14013
+ recipientAddress,
14014
+ destinationChainType,
14015
+ destinationChainId,
14016
+ destinationTokenAddress
14017
+ ],
14018
+ queryFn: () => verifyRecipientAddress(
14019
+ {
14020
+ chain_type: destinationChainType,
14021
+ chain_id: destinationChainId,
14022
+ token_address: destinationTokenAddress,
14023
+ recipient_address: recipientAddress
14024
+ },
14025
+ publishableKey
14026
+ ),
14027
+ enabled: shouldValidate,
14028
+ refetchOnMount,
14029
+ refetchOnReconnect: false,
14030
+ refetchOnWindowFocus: false,
14031
+ staleTime: 1e3 * 60 * 5,
14032
+ // 5 minutes - address state can change
14033
+ gcTime: 1e3 * 60 * 30
14034
+ // 30 minutes
14035
+ });
14036
+ if (!shouldValidate) {
14037
+ return {
14038
+ isValid: null,
14039
+ failureCode: null,
14040
+ metadata: null,
14041
+ isLoading: false,
14042
+ error: null
14043
+ };
14044
+ }
14045
+ return {
14046
+ isValid: data?.valid ?? null,
14047
+ failureCode: data?.failure_code ?? null,
14048
+ metadata: data?.metadata ?? null,
14049
+ isLoading,
14050
+ error: error ?? null
14051
+ };
14052
+ }
13765
14053
  function StyledQRCode({
13766
14054
  value,
13767
14055
  size: size4 = 200,
@@ -13771,7 +14059,7 @@ function StyledQRCode({
13771
14059
  }) {
13772
14060
  const ref = useRef32(null);
13773
14061
  const qrCodeRef = useRef32(null);
13774
- useEffect92(() => {
14062
+ useEffect102(() => {
13775
14063
  if (!ref.current) return;
13776
14064
  if (!qrCodeRef.current) {
13777
14065
  qrCodeRef.current = new import_qr_code_styling.default({
@@ -13811,7 +14099,7 @@ function StyledQRCode({
13811
14099
  qrCodeRef.current.append(ref.current);
13812
14100
  }
13813
14101
  }, []);
13814
- useEffect92(() => {
14102
+ useEffect102(() => {
13815
14103
  if (qrCodeRef.current) {
13816
14104
  qrCodeRef.current.update({
13817
14105
  data: value,
@@ -13905,10 +14193,10 @@ function TokenSelectorSheet({
13905
14193
  }) {
13906
14194
  const { themeClass, colors: colors2, fonts, components } = useTheme();
13907
14195
  const isDarkMode = themeClass.includes("uf-dark");
13908
- const [searchQuery, setSearchQuery] = useState132("");
13909
- const [recentTokens, setRecentTokens] = useState132([]);
13910
- const [hoveredTokenKey, setHoveredTokenKey] = useState132(null);
13911
- useEffect102(() => {
14196
+ const [searchQuery, setSearchQuery] = useState142("");
14197
+ const [recentTokens, setRecentTokens] = useState142([]);
14198
+ const [hoveredTokenKey, setHoveredTokenKey] = useState142(null);
14199
+ useEffect112(() => {
13912
14200
  setRecentTokens(getRecentTokens());
13913
14201
  }, []);
13914
14202
  const allOptions = useMemo32(() => {
@@ -14337,13 +14625,13 @@ function TransferCryptoSingleInput({
14337
14625
  }) {
14338
14626
  const { themeClass, colors: colors2, fonts, components } = useTheme();
14339
14627
  const isDarkMode = themeClass.includes("uf-dark");
14340
- const [token, setToken] = useState142("USDC");
14341
- const [chain, setChain] = useState142("solana:mainnet");
14342
- const [copied, setCopied] = useState142(false);
14343
- const [internalWallets, setInternalWallets] = useState142([]);
14344
- const [loading, setLoading] = useState142(!externalWallets?.length);
14628
+ const [token, setToken] = useState152("USDC");
14629
+ const [chain, setChain] = useState152("solana:mainnet");
14630
+ const [copied, setCopied] = useState152(false);
14631
+ const [internalWallets, setInternalWallets] = useState152([]);
14632
+ const [loading, setLoading] = useState152(!externalWallets?.length);
14345
14633
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
14346
- const [error, setError] = useState142(null);
14634
+ const [error, setError] = useState152(null);
14347
14635
  const { executions: depositExecutions, isPolling } = useDepositPolling({
14348
14636
  userId,
14349
14637
  publishableKey,
@@ -14351,11 +14639,11 @@ function TransferCryptoSingleInput({
14351
14639
  onDepositSuccess,
14352
14640
  onDepositError
14353
14641
  });
14354
- const [supportedTokens, setSupportedTokens] = useState142([]);
14355
- const [tokensLoading, setTokensLoading] = useState142(true);
14356
- const [detailsExpanded, setDetailsExpanded] = useState142(false);
14357
- const [depositsModalOpen, setDepositsModalOpen] = useState142(false);
14358
- const [tokenSelectorOpen, setTokenSelectorOpen] = useState142(false);
14642
+ const [supportedTokens, setSupportedTokens] = useState152([]);
14643
+ const [tokensLoading, setTokensLoading] = useState152(true);
14644
+ const [detailsExpanded, setDetailsExpanded] = useState152(false);
14645
+ const [depositsModalOpen, setDepositsModalOpen] = useState152(false);
14646
+ const [tokenSelectorOpen, setTokenSelectorOpen] = useState152(false);
14359
14647
  const allChainsMap = /* @__PURE__ */ new Map();
14360
14648
  supportedTokens.forEach((t5) => {
14361
14649
  t5.chains.forEach((c) => {
@@ -14373,7 +14661,7 @@ function TransferCryptoSingleInput({
14373
14661
  const currentChainType = currentChainData?.chain_type || "ethereum";
14374
14662
  const currentWallet = getWalletByChainType(wallets, currentChainType);
14375
14663
  const depositAddress = currentWallet?.address || "";
14376
- useEffect112(() => {
14664
+ useEffect122(() => {
14377
14665
  async function fetchSupportedTokens() {
14378
14666
  try {
14379
14667
  setTokensLoading(true);
@@ -14445,12 +14733,12 @@ function TransferCryptoSingleInput({
14445
14733
  destinationChainId,
14446
14734
  destinationChainType
14447
14735
  ]);
14448
- useEffect112(() => {
14736
+ useEffect122(() => {
14449
14737
  if (onExecutionsChange) {
14450
14738
  onExecutionsChange(depositExecutions);
14451
14739
  }
14452
14740
  }, [depositExecutions, onExecutionsChange]);
14453
- useEffect112(() => {
14741
+ useEffect122(() => {
14454
14742
  if (externalWallets?.length) {
14455
14743
  setLoading(false);
14456
14744
  return;
@@ -14507,7 +14795,7 @@ function TransferCryptoSingleInput({
14507
14795
  publishableKey,
14508
14796
  externalWallets
14509
14797
  ]);
14510
- useEffect112(() => {
14798
+ useEffect122(() => {
14511
14799
  if (!supportedTokens.length) return;
14512
14800
  const currentToken = supportedTokens.find((t5) => t5.symbol === token);
14513
14801
  if (!currentToken || currentToken.chains.length === 0) return;
@@ -15019,13 +15307,13 @@ function TransferCryptoDoubleInput({
15019
15307
  }) {
15020
15308
  const { themeClass, colors: colors2, fonts, components } = useTheme();
15021
15309
  const isDarkMode = themeClass.includes("uf-dark");
15022
- const [token, setToken] = useState152("USDC");
15023
- const [chain, setChain] = useState152("solana:mainnet");
15024
- const [copied, setCopied] = useState152(false);
15025
- const [internalWallets, setInternalWallets] = useState152([]);
15026
- const [loading, setLoading] = useState152(!externalWallets?.length);
15310
+ const [token, setToken] = useState162("USDC");
15311
+ const [chain, setChain] = useState162("solana:mainnet");
15312
+ const [copied, setCopied] = useState162(false);
15313
+ const [internalWallets, setInternalWallets] = useState162([]);
15314
+ const [loading, setLoading] = useState162(!externalWallets?.length);
15027
15315
  const wallets = externalWallets?.length ? externalWallets : internalWallets;
15028
- const [error, setError] = useState152(null);
15316
+ const [error, setError] = useState162(null);
15029
15317
  const { executions: depositExecutions, isPolling } = useDepositPolling({
15030
15318
  userId,
15031
15319
  publishableKey,
@@ -15033,10 +15321,10 @@ function TransferCryptoDoubleInput({
15033
15321
  onDepositSuccess,
15034
15322
  onDepositError
15035
15323
  });
15036
- const [supportedTokens, setSupportedTokens] = useState152([]);
15037
- const [tokensLoading, setTokensLoading] = useState152(true);
15038
- const [detailsExpanded, setDetailsExpanded] = useState152(false);
15039
- const [depositsModalOpen, setDepositsModalOpen] = useState152(false);
15324
+ const [supportedTokens, setSupportedTokens] = useState162([]);
15325
+ const [tokensLoading, setTokensLoading] = useState162(true);
15326
+ const [detailsExpanded, setDetailsExpanded] = useState162(false);
15327
+ const [depositsModalOpen, setDepositsModalOpen] = useState162(false);
15040
15328
  const allChainsMap = /* @__PURE__ */ new Map();
15041
15329
  supportedTokens.forEach((t5) => {
15042
15330
  t5.chains.forEach((c) => {
@@ -15054,7 +15342,7 @@ function TransferCryptoDoubleInput({
15054
15342
  const currentChainType = currentChainData?.chain_type || "ethereum";
15055
15343
  const currentWallet = getWalletByChainType(wallets, currentChainType);
15056
15344
  const depositAddress = currentWallet?.address || "";
15057
- useEffect122(() => {
15345
+ useEffect132(() => {
15058
15346
  async function fetchSupportedTokens() {
15059
15347
  try {
15060
15348
  setTokensLoading(true);
@@ -15097,12 +15385,12 @@ function TransferCryptoDoubleInput({
15097
15385
  destinationChainId,
15098
15386
  destinationChainType
15099
15387
  ]);
15100
- useEffect122(() => {
15388
+ useEffect132(() => {
15101
15389
  if (onExecutionsChange) {
15102
15390
  onExecutionsChange(depositExecutions);
15103
15391
  }
15104
15392
  }, [depositExecutions, onExecutionsChange]);
15105
- useEffect122(() => {
15393
+ useEffect132(() => {
15106
15394
  if (externalWallets?.length) {
15107
15395
  setLoading(false);
15108
15396
  return;
@@ -15159,7 +15447,7 @@ function TransferCryptoDoubleInput({
15159
15447
  publishableKey,
15160
15448
  externalWallets
15161
15449
  ]);
15162
- useEffect122(() => {
15450
+ useEffect132(() => {
15163
15451
  if (!supportedTokens.length) return;
15164
15452
  const currentToken = supportedTokens.find((t5) => t5.symbol === token);
15165
15453
  if (!currentToken || currentToken.chains.length === 0) return;
@@ -15607,26 +15895,27 @@ function DepositModal({
15607
15895
  destinationChainId,
15608
15896
  destinationTokenAddress,
15609
15897
  hideDepositTracker = false,
15898
+ showBalanceHeader = false,
15610
15899
  transferInputVariant = "double_input",
15611
15900
  onDepositSuccess,
15612
15901
  onDepositError,
15613
15902
  theme = "dark"
15614
15903
  }) {
15615
- const { colors: colors2 } = useTheme();
15616
- const [view, setView] = useState16("main");
15617
- const [cardView, setCardView] = useState16(
15904
+ const { colors: colors2, fonts } = useTheme();
15905
+ const [view, setView] = useState17("main");
15906
+ const [cardView, setCardView] = useState17(
15618
15907
  "amount"
15619
15908
  );
15620
- const [quotesCount, setQuotesCount] = useState16(0);
15621
- const [depositsModalOpen, setDepositsModalOpen] = useState16(false);
15622
- const [depositExecutions, setDepositExecutions] = useState16([]);
15623
- const [projectConfig, setProjectConfig] = useState16(null);
15624
- const [wallets, setWallets] = useState16([]);
15625
- const [walletsLoading, setWalletsLoading] = useState16(false);
15626
- useEffect132(() => {
15909
+ const [quotesCount, setQuotesCount] = useState17(0);
15910
+ const [depositsModalOpen, setDepositsModalOpen] = useState17(false);
15911
+ const [depositExecutions, setDepositExecutions] = useState17([]);
15912
+ const [projectConfig, setProjectConfig] = useState17(null);
15913
+ const [wallets, setWallets] = useState17([]);
15914
+ const [walletsLoading, setWalletsLoading] = useState17(false);
15915
+ useEffect142(() => {
15627
15916
  setProjectConfig(null);
15628
15917
  }, [publishableKey]);
15629
- useEffect132(() => {
15918
+ useEffect142(() => {
15630
15919
  setWallets([]);
15631
15920
  }, [
15632
15921
  userId,
@@ -15636,10 +15925,10 @@ function DepositModal({
15636
15925
  destinationTokenAddress,
15637
15926
  publishableKey
15638
15927
  ]);
15639
- const [resolvedTheme, setResolvedTheme] = useState16(
15928
+ const [resolvedTheme, setResolvedTheme] = useState17(
15640
15929
  theme === "auto" ? "dark" : theme
15641
15930
  );
15642
- useEffect132(() => {
15931
+ useEffect142(() => {
15643
15932
  if (theme === "auto") {
15644
15933
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
15645
15934
  setResolvedTheme(mediaQuery.matches ? "dark" : "light");
@@ -15652,7 +15941,7 @@ function DepositModal({
15652
15941
  setResolvedTheme(theme);
15653
15942
  }
15654
15943
  }, [theme]);
15655
- useEffect132(() => {
15944
+ useEffect142(() => {
15656
15945
  if (open && !projectConfig) {
15657
15946
  getProjectConfig(publishableKey).then(setProjectConfig).catch(console.error);
15658
15947
  }
@@ -15662,7 +15951,29 @@ function DepositModal({
15662
15951
  isLoading: isCountryLoading,
15663
15952
  error: countryError
15664
15953
  } = useAllowedCountry(publishableKey);
15665
- useEffect132(() => {
15954
+ const {
15955
+ isValid: isAddressValid,
15956
+ failureCode: addressFailureCode,
15957
+ metadata: addressFailureMetadata,
15958
+ isLoading: isAddressValidationLoading
15959
+ } = useAddressValidation({
15960
+ recipientAddress,
15961
+ destinationChainType,
15962
+ destinationChainId,
15963
+ destinationTokenAddress,
15964
+ publishableKey,
15965
+ enabled: open,
15966
+ // Only validate when modal is open
15967
+ refetchOnMount: "always"
15968
+ });
15969
+ const addressValidationMessages = i18n2.transferCrypto.addressValidation;
15970
+ const getAddressValidationErrorMessage = (code, metadata) => {
15971
+ if (!code) return addressValidationMessages.defaultError;
15972
+ const errors = addressValidationMessages.errors;
15973
+ const template = errors[code] ?? addressValidationMessages.defaultError;
15974
+ return interpolate(template, metadata);
15975
+ };
15976
+ useEffect142(() => {
15666
15977
  if (!open || wallets.length > 0) return;
15667
15978
  let retryTimeout = null;
15668
15979
  let isCancelled = false;
@@ -15746,10 +16057,16 @@ function DepositModal({
15746
16057
  DepositHeader,
15747
16058
  {
15748
16059
  title: modalTitle || "Deposit",
15749
- onClose: handleClose
16060
+ onClose: handleClose,
16061
+ showBalance: showBalanceHeader,
16062
+ balanceAddress: recipientAddress,
16063
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
16064
+ balanceChainId: destinationChainId,
16065
+ balanceTokenAddress: destinationTokenAddress,
16066
+ publishableKey
15750
16067
  }
15751
16068
  ),
15752
- /* @__PURE__ */ jsx232("div", { className: "uf-pb-4 uf-space-y-3", children: isCountryLoading || !projectConfig ? /* @__PURE__ */ jsxs18(Fragment52, { children: [
16069
+ /* @__PURE__ */ jsx232("div", { className: "uf-pb-4 uf-space-y-3", children: isCountryLoading || isAddressValidationLoading || !projectConfig ? /* @__PURE__ */ jsxs18(Fragment52, { children: [
15753
16070
  /* @__PURE__ */ jsx232(SkeletonButton, { variant: "with-icons" }),
15754
16071
  /* @__PURE__ */ jsx232(SkeletonButton, { variant: "with-icons" }),
15755
16072
  !hideDepositTracker && /* @__PURE__ */ jsx232(SkeletonButton, {})
@@ -15767,6 +16084,16 @@ function DepositModal({
15767
16084
  /* @__PURE__ */ jsx232("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: "No Tokens Available" }),
15768
16085
  /* @__PURE__ */ jsx232("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: "There are no supported tokens available from your current location." })
15769
16086
  ] })
16087
+ ) : isAddressValid === false ? (
16088
+ /* Invalid recipient address state (e.g., Algorand not opted in) */
16089
+ /* @__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: [
16090
+ /* @__PURE__ */ jsx232("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__ */ jsx232(TriangleAlert, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
16091
+ /* @__PURE__ */ jsx232("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: addressValidationMessages.unableToReceiveFunds }),
16092
+ /* @__PURE__ */ jsx232("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: getAddressValidationErrorMessage(
16093
+ addressFailureCode,
16094
+ addressFailureMetadata
16095
+ ) })
16096
+ ] })
15770
16097
  ) : (
15771
16098
  /* Normal deposit options */
15772
16099
  /* @__PURE__ */ jsxs18(Fragment52, { children: [
@@ -15948,8 +16275,8 @@ function UnifoldProvider2({
15948
16275
  publishableKey,
15949
16276
  config
15950
16277
  }) {
15951
- const [isOpen, setIsOpen] = useState22(false);
15952
- const [depositConfig, setDepositConfig] = useState22(
16278
+ const [isOpen, setIsOpen] = useState23(false);
16279
+ const [depositConfig, setDepositConfig] = useState23(
15953
16280
  null
15954
16281
  );
15955
16282
  const [resolvedTheme, setResolvedTheme] = React38.useState("dark");
@@ -16057,6 +16384,7 @@ function UnifoldProvider2({
16057
16384
  destinationChainId: depositConfig.destinationChainId,
16058
16385
  destinationTokenAddress: depositConfig.destinationTokenAddress,
16059
16386
  hideDepositTracker: config?.hideDepositTracker,
16387
+ showBalanceHeader: config?.showBalanceHeader,
16060
16388
  transferInputVariant: config?.transferInputVariant,
16061
16389
  onDepositSuccess: handleDepositSuccess,
16062
16390
  onDepositError: handleDepositError,