@unifold/ui-react 0.1.26 → 0.1.28

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
@@ -39,6 +39,7 @@ __export(index_exports, {
39
39
  DepositExecutionItem: () => DepositExecutionItem,
40
40
  DepositHeader: () => DepositHeader,
41
41
  DepositModal: () => DepositModal,
42
+ DepositPollingUi: () => DepositPollingUi,
42
43
  DepositSuccessToast: () => DepositSuccessToast,
43
44
  DepositTrackerButton: () => DepositTrackerButton,
44
45
  DepositWithCardButton: () => DepositWithCardButton,
@@ -73,17 +74,15 @@ __export(index_exports, {
73
74
  TransferCryptoDoubleInput: () => TransferCryptoDoubleInput,
74
75
  TransferCryptoSingleInput: () => TransferCryptoSingleInput,
75
76
  buttonVariants: () => buttonVariants,
76
- clearQRCodeCache: () => clearQRCodeCache,
77
77
  cn: () => cn,
78
78
  colors: () => colors,
79
79
  defaultColors: () => defaultColors,
80
80
  getColors: () => getColors,
81
- isQRCodeCached: () => isQRCodeCached,
82
81
  mergeColors: () => mergeColors,
83
- preloadQRCode: () => preloadQRCode,
84
82
  resolveComponentTokens: () => resolveComponentTokens,
85
83
  truncateAddress: () => truncateAddress,
86
84
  useAllowedCountry: () => useAllowedCountry,
85
+ useDepositPolling: () => useDepositPolling,
87
86
  useTheme: () => useTheme
88
87
  });
89
88
  module.exports = __toCommonJS(index_exports);
@@ -104,6 +103,26 @@ function cn(...inputs) {
104
103
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
105
104
  }
106
105
  var WALLET_CHAIN_TYPE_STORAGE_KEY = "unifold_last_wallet_type";
106
+ var WALLET_USER_DISCONNECTED_KEY = "unifold_wallet_user_disconnected";
107
+ function getUserDisconnectedWallet() {
108
+ if (typeof window === "undefined") return false;
109
+ try {
110
+ return localStorage.getItem(WALLET_USER_DISCONNECTED_KEY) === "true";
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+ function setUserDisconnectedWallet(disconnected) {
116
+ if (typeof window === "undefined") return;
117
+ try {
118
+ if (disconnected) {
119
+ localStorage.setItem(WALLET_USER_DISCONNECTED_KEY, "true");
120
+ } else {
121
+ localStorage.removeItem(WALLET_USER_DISCONNECTED_KEY);
122
+ }
123
+ } catch {
124
+ }
125
+ }
107
126
  function getStoredWalletChainType() {
108
127
  if (typeof window === "undefined") return void 0;
109
128
  try {
@@ -616,7 +635,7 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
616
635
  // src/components/deposits/BuyWithCard.tsx
617
636
  var import_react7 = require("react");
618
637
  var import_lucide_react6 = require("lucide-react");
619
- var import_core8 = require("@unifold/core");
638
+ var import_core9 = require("@unifold/core");
620
639
 
621
640
  // src/hooks/use-deposit-address.ts
622
641
  var import_react_query = require("@tanstack/react-query");
@@ -671,10 +690,126 @@ var import_react2 = require("react");
671
690
  // src/components/deposits/DepositHeader.tsx
672
691
  var import_lucide_react2 = require("lucide-react");
673
692
  var import_react = require("react");
693
+ var import_core3 = require("@unifold/core");
694
+
695
+ // src/components/deposits/browser-wallets/utils.ts
674
696
  var import_core2 = require("@unifold/core");
697
+ function getIconUrl(iconUrl, assetCdnUrl) {
698
+ if (!iconUrl) return void 0;
699
+ if (iconUrl.startsWith("http://") || iconUrl.startsWith("https://")) {
700
+ return iconUrl;
701
+ }
702
+ if (assetCdnUrl) {
703
+ return `${assetCdnUrl}${iconUrl.startsWith("/") ? "" : "/"}${iconUrl}`;
704
+ }
705
+ return iconUrl;
706
+ }
707
+ function getTokenFromBalance(balance) {
708
+ if (balance.token) {
709
+ return balance.token;
710
+ }
711
+ const legacyBalance = balance;
712
+ if (legacyBalance.symbol && legacyBalance.decimals !== void 0) {
713
+ return {
714
+ symbol: legacyBalance.symbol,
715
+ name: legacyBalance.name,
716
+ icon_url: legacyBalance.icon_url,
717
+ icon_urls: [],
718
+ token_address: legacyBalance.token_address,
719
+ chain_id: legacyBalance.chain_id,
720
+ chain_name: legacyBalance.chain_name,
721
+ chain_type: legacyBalance.chain_type,
722
+ decimals: legacyBalance.decimals,
723
+ chain_icon_url: legacyBalance.chain_icon_url,
724
+ chain_icon_urls: [],
725
+ minimum_deposit_amount_usd: 0
726
+ };
727
+ }
728
+ return null;
729
+ }
730
+ function isBalanceEligible(balance) {
731
+ if (balance.is_eligible !== void 0) {
732
+ return balance.is_eligible;
733
+ }
734
+ const legacyBalance = balance;
735
+ if (legacyBalance.is_eligible !== void 0) {
736
+ return legacyBalance.is_eligible;
737
+ }
738
+ return true;
739
+ }
740
+ function getIneligibilityMessage(balance) {
741
+ if (isBalanceEligible(balance)) {
742
+ return null;
743
+ }
744
+ switch (balance.ineligibility_reason) {
745
+ case import_core2.IneligibilityReason.MINIMUM_NOT_MET:
746
+ return "Low balance";
747
+ case import_core2.IneligibilityReason.NOT_SUPPORTED_DEPOSIT_FROM:
748
+ return "Not supported";
749
+ default:
750
+ return "Not eligible";
751
+ }
752
+ }
753
+ function formatTokenAmount(amount, decimals, symbol) {
754
+ const value = Number(amount) / 10 ** decimals;
755
+ const upperSymbol = symbol.toUpperCase();
756
+ let maxDecimals = 4;
757
+ if (upperSymbol === "BTC" || upperSymbol === "WBTC") {
758
+ maxDecimals = 8;
759
+ } else if (upperSymbol === "ETH" || upperSymbol === "WETH" || upperSymbol === "SOL") {
760
+ maxDecimals = 6;
761
+ }
762
+ if (value >= 1) {
763
+ return value.toLocaleString(void 0, {
764
+ minimumFractionDigits: 2,
765
+ maximumFractionDigits: maxDecimals
766
+ });
767
+ } else if (value > 0) {
768
+ return value.toLocaleString(void 0, {
769
+ minimumFractionDigits: 2,
770
+ maximumFractionDigits: maxDecimals,
771
+ minimumSignificantDigits: 2,
772
+ maximumSignificantDigits: 6
773
+ });
774
+ }
775
+ return "0.00";
776
+ }
777
+ function formatUsdAmount(amountUsd) {
778
+ if (!amountUsd) return null;
779
+ const value = parseFloat(amountUsd);
780
+ if (value <= 0) return null;
781
+ return value.toLocaleString(void 0, {
782
+ minimumFractionDigits: 2,
783
+ maximumFractionDigits: 2
784
+ });
785
+ }
786
+ function truncateAddress2(address) {
787
+ if (address.length <= 13) return address;
788
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
789
+ }
790
+ function formatBalanceDisplay(balance, projectName) {
791
+ return projectName ? `${projectName} Balance: ${balance}` : `Balance: ${balance}`;
792
+ }
793
+ function formatProcessingTime(seconds) {
794
+ if (seconds === null || seconds === 0) {
795
+ return "< 1 min";
796
+ }
797
+ const minutes = Math.floor(seconds / 60);
798
+ const remainingSeconds = seconds % 60;
799
+ if (minutes === 0) {
800
+ return `< ${remainingSeconds} sec`;
801
+ } else if (remainingSeconds === 0) {
802
+ return `< ${minutes} min`;
803
+ } else {
804
+ return `< ${minutes} min ${remainingSeconds} sec`;
805
+ }
806
+ }
807
+
808
+ // src/components/deposits/DepositHeader.tsx
675
809
  var import_jsx_runtime3 = require("react/jsx-runtime");
676
810
  function DepositHeader({
677
811
  title,
812
+ subtitle,
678
813
  showBack = false,
679
814
  showClose = true,
680
815
  onBack,
@@ -685,20 +820,42 @@ function DepositHeader({
685
820
  balanceChainType,
686
821
  balanceChainId,
687
822
  balanceTokenAddress,
823
+ projectName,
688
824
  publishableKey
689
825
  }) {
690
826
  const { colors: colors2, fonts, components } = useTheme();
691
827
  const [balance, setBalance] = (0, import_react.useState)(null);
692
828
  const [isLoadingBalance, setIsLoadingBalance] = (0, import_react.useState)(false);
829
+ const [showBalanceSkeleton, setShowBalanceSkeleton] = (0, import_react.useState)(false);
830
+ const showBalanceBlock = showBalance === true;
831
+ (0, import_react.useLayoutEffect)(() => {
832
+ if (!showBalanceBlock) {
833
+ setBalance(null);
834
+ setIsLoadingBalance(false);
835
+ setShowBalanceSkeleton(false);
836
+ }
837
+ }, [showBalanceBlock]);
693
838
  (0, import_react.useEffect)(() => {
694
839
  if (!showBalance || !balanceAddress || !balanceChainType || !balanceChainId || !balanceTokenAddress || !publishableKey) {
695
840
  setBalance(null);
696
841
  setIsLoadingBalance(false);
842
+ setShowBalanceSkeleton(false);
843
+ return;
844
+ }
845
+ const supportedChainTypes = ["ethereum", "solana", "bitcoin"];
846
+ if (!supportedChainTypes.includes(balanceChainType)) {
847
+ setBalance(null);
848
+ setIsLoadingBalance(false);
849
+ setShowBalanceSkeleton(false);
697
850
  return;
698
851
  }
699
852
  let cancelled = false;
700
853
  setIsLoadingBalance(true);
701
- (0, import_core2.getAddressBalance)(
854
+ setShowBalanceSkeleton(false);
855
+ const skeletonTimer = window.setTimeout(() => {
856
+ if (!cancelled) setShowBalanceSkeleton(true);
857
+ }, 150);
858
+ (0, import_core3.getAddressBalance)(
702
859
  balanceAddress,
703
860
  balanceChainType,
704
861
  balanceChainId,
@@ -706,7 +863,7 @@ function DepositHeader({
706
863
  publishableKey
707
864
  ).then((response) => {
708
865
  if (cancelled) return;
709
- if (response.balance && response.balance.amount !== "0") {
866
+ if (response.balance) {
710
867
  const token = response.balance.token;
711
868
  if (!token) {
712
869
  setBalance(null);
@@ -734,12 +891,12 @@ function DepositHeader({
734
891
  maximumSignificantDigits: 6
735
892
  });
736
893
  } else {
737
- formatted = value.toExponential(2);
894
+ formatted = value === 0 ? "0.00" : value.toExponential(2);
738
895
  }
739
- const balanceText = response.balance.amount_usd ? `Balance: $${response.balance.amount_usd} (${formatted} ${response.balance.token.symbol})` : `Balance: ${formatted} ${response.balance.token.symbol}`;
740
- setBalance(balanceText);
896
+ const amountPart = response.balance.amount_usd != null && response.balance.amount_usd !== "" ? `$${response.balance.amount_usd} (${formatted} ${response.balance.token.symbol})` : `${formatted} ${response.balance.token.symbol}`;
897
+ setBalance(amountPart);
741
898
  } else {
742
- setBalance(null);
899
+ setBalance("$0.00");
743
900
  }
744
901
  }).catch((error) => {
745
902
  if (cancelled) return;
@@ -748,9 +905,11 @@ function DepositHeader({
748
905
  }).finally(() => {
749
906
  if (cancelled) return;
750
907
  setIsLoadingBalance(false);
908
+ setShowBalanceSkeleton(false);
751
909
  });
752
910
  return () => {
753
911
  cancelled = true;
912
+ window.clearTimeout(skeletonTimer);
754
913
  };
755
914
  }, [
756
915
  showBalance,
@@ -806,18 +965,27 @@ function DepositHeader({
806
965
  children: title
807
966
  }
808
967
  ),
809
- 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)(
968
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
810
969
  "div",
811
970
  {
812
- className: "uf-text-xs uf-mt-2",
971
+ className: "uf-text-xs uf-mt-1",
813
972
  style: {
814
- color: colors2.foreground,
815
- fontFamily: fonts.regular,
816
- opacity: 0.7
973
+ color: colors2.foregroundMuted,
974
+ fontFamily: fonts.regular
975
+ },
976
+ children: subtitle
977
+ }
978
+ ) : showBalanceBlock ? isLoadingBalance && showBalanceSkeleton ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "uf-h-3 uf-w-32 uf-bg-muted uf-rounded uf-animate-pulse uf-mt-1" }) : balance ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
979
+ "div",
980
+ {
981
+ className: "uf-text-xs uf-mt-1",
982
+ style: {
983
+ color: colors2.foregroundMuted,
984
+ fontFamily: fonts.regular
817
985
  },
818
- children: balance
986
+ children: formatBalanceDisplay(balance, projectName)
819
987
  }
820
- ) : null)
988
+ ) : null : null
821
989
  ] }),
822
990
  showClose ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
823
991
  "button",
@@ -834,7 +1002,7 @@ function DepositHeader({
834
1002
  // src/components/currency/CurrencyListItem.tsx
835
1003
  var React3 = __toESM(require("react"));
836
1004
  var import_lucide_react3 = require("lucide-react");
837
- var import_core3 = require("@unifold/core");
1005
+ var import_core4 = require("@unifold/core");
838
1006
  var import_jsx_runtime4 = require("react/jsx-runtime");
839
1007
  function CurrencyListItem({
840
1008
  currency,
@@ -843,7 +1011,7 @@ function CurrencyListItem({
843
1011
  }) {
844
1012
  const { colors: colors2, fonts, components } = useTheme();
845
1013
  const [isHovered, setIsHovered] = React3.useState(false);
846
- const iconUrl = (0, import_core3.getPreferredIconUrl)(currency.icon_urls, "png") || currency.icon_url;
1014
+ const iconUrl = (0, import_core4.getPreferredIconUrl)(currency.icon_urls, "png") || currency.icon_url;
847
1015
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
848
1016
  "button",
849
1017
  {
@@ -1047,7 +1215,7 @@ function CurrencyModal({
1047
1215
 
1048
1216
  // src/hooks/use-user-ip.ts
1049
1217
  var import_react_query2 = require("@tanstack/react-query");
1050
- var import_core4 = require("@unifold/core");
1218
+ var import_core5 = require("@unifold/core");
1051
1219
  function useUserIp() {
1052
1220
  const {
1053
1221
  data: userIpInfo,
@@ -1056,7 +1224,7 @@ function useUserIp() {
1056
1224
  } = (0, import_react_query2.useQuery)({
1057
1225
  queryKey: ["unifold", "userIpInfo"],
1058
1226
  queryFn: async () => {
1059
- const data = await (0, import_core4.getIpAddress)();
1227
+ const data = await (0, import_core5.getIpAddress)();
1060
1228
  return {
1061
1229
  alpha2: data.alpha2.toLowerCase(),
1062
1230
  alpha3: data.alpha3?.toLowerCase(),
@@ -1176,45 +1344,75 @@ function interpolate(template, params) {
1176
1344
 
1177
1345
  // src/hooks/use-deposit-polling.ts
1178
1346
  var import_react3 = require("react");
1179
- var import_core5 = require("@unifold/core");
1347
+ var import_core6 = require("@unifold/core");
1348
+ var DEPOSIT_CONFIRM_DELAY_MS = 1e4;
1349
+ var POLL_INTERVAL_MS = 2500;
1350
+ var POLL_ENDPOINT_INTERVAL_MS = 3e3;
1351
+ var CUTOFF_BUFFER_MS = 6e4;
1180
1352
  function useDepositPolling({
1181
1353
  userId,
1182
1354
  publishableKey,
1355
+ depositConfirmationMode = "auto_ui",
1356
+ depositWalletId,
1183
1357
  enabled = true,
1184
1358
  onDepositSuccess,
1185
1359
  onDepositError
1186
1360
  }) {
1187
1361
  const [executions, setExecutions] = (0, import_react3.useState)([]);
1188
1362
  const [isPolling, setIsPolling] = (0, import_react3.useState)(false);
1189
- const pollingIntervalRef = (0, import_react3.useRef)(
1190
- null
1191
- );
1192
- const [modalOpenedAt] = (0, import_react3.useState)(/* @__PURE__ */ new Date());
1193
- const [trackedExecutions, setTrackedExecutions] = (0, import_react3.useState)(/* @__PURE__ */ new Map());
1363
+ const [pollingEnabled, setPollingEnabled] = (0, import_react3.useState)(false);
1364
+ const [showWaitingUi, setShowWaitingUi] = (0, import_react3.useState)(false);
1365
+ const modalOpenedAtRef = (0, import_react3.useRef)(/* @__PURE__ */ new Date());
1366
+ const trackedExecutionsRef = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
1367
+ const onDepositSuccessRef = (0, import_react3.useRef)(onDepositSuccess);
1368
+ const onDepositErrorRef = (0, import_react3.useRef)(onDepositError);
1194
1369
  (0, import_react3.useEffect)(() => {
1195
- if (!userId || !modalOpenedAt || !enabled) return;
1196
- const pollInterval = setInterval(async () => {
1370
+ onDepositSuccessRef.current = onDepositSuccess;
1371
+ }, [onDepositSuccess]);
1372
+ (0, import_react3.useEffect)(() => {
1373
+ onDepositErrorRef.current = onDepositError;
1374
+ }, [onDepositError]);
1375
+ (0, import_react3.useEffect)(() => {
1376
+ if (depositConfirmationMode === "manual" || !enabled) return;
1377
+ const timeout = setTimeout(() => {
1378
+ setPollingEnabled(true);
1379
+ if (depositConfirmationMode === "auto_ui") {
1380
+ setShowWaitingUi(true);
1381
+ }
1382
+ }, DEPOSIT_CONFIRM_DELAY_MS);
1383
+ return () => clearTimeout(timeout);
1384
+ }, [depositConfirmationMode, enabled]);
1385
+ (0, import_react3.useEffect)(() => {
1386
+ if (!userId || !enabled) return;
1387
+ const modalOpenedAt = modalOpenedAtRef.current;
1388
+ const poll = async () => {
1197
1389
  try {
1198
- const response = await (0, import_core5.queryExecutions)(userId, publishableKey);
1390
+ const response = await (0, import_core6.queryExecutions)(userId, publishableKey);
1391
+ const cutoff = new Date(modalOpenedAt.getTime() - CUTOFF_BUFFER_MS);
1392
+ const sortedExecutions = [...response.data].sort((a, b) => {
1393
+ const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
1394
+ const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
1395
+ return timeB - timeA;
1396
+ });
1199
1397
  let executionToShow = null;
1200
- for (const execution of response.data) {
1398
+ for (const execution of sortedExecutions) {
1201
1399
  const executionTime = execution.created_at ? new Date(execution.created_at) : null;
1202
- if (!executionTime || executionTime <= modalOpenedAt) {
1400
+ if (!executionTime || executionTime < cutoff) {
1203
1401
  continue;
1204
1402
  }
1205
- const trackedStatus = trackedExecutions.get(execution.id);
1403
+ const trackedStatus = trackedExecutionsRef.current.get(execution.id);
1206
1404
  if (!trackedStatus) {
1207
1405
  executionToShow = execution;
1208
1406
  break;
1209
1407
  }
1210
1408
  const inProgressStatuses = [
1211
- import_core5.ExecutionStatus.PENDING,
1212
- import_core5.ExecutionStatus.WAITING,
1213
- import_core5.ExecutionStatus.DELAYED
1409
+ import_core6.ExecutionStatus.PENDING,
1410
+ import_core6.ExecutionStatus.WAITING,
1411
+ import_core6.ExecutionStatus.DELAYED
1214
1412
  ];
1215
1413
  const terminalStatuses = [
1216
- import_core5.ExecutionStatus.SUCCEEDED,
1217
- import_core5.ExecutionStatus.FAILED
1414
+ import_core6.ExecutionStatus.SUCCEEDED,
1415
+ import_core6.ExecutionStatus.FAILED
1218
1416
  ];
1219
1417
  if (inProgressStatuses.includes(trackedStatus) && terminalStatuses.includes(execution.status)) {
1220
1418
  executionToShow = execution;
@@ -1223,35 +1421,30 @@ function useDepositPolling({
1223
1421
  }
1224
1422
  if (executionToShow) {
1225
1423
  const execution = executionToShow;
1424
+ const previousStatus = trackedExecutionsRef.current.get(execution.id);
1425
+ trackedExecutionsRef.current.set(execution.id, execution.status);
1226
1426
  setExecutions((prev) => {
1227
1427
  const existingIndex = prev.findIndex((e) => e.id === execution.id);
1228
1428
  if (existingIndex >= 0) {
1229
1429
  const updated = [...prev];
1230
1430
  updated[existingIndex] = execution;
1231
1431
  return updated;
1232
- } else {
1233
- return [...prev, execution];
1234
1432
  }
1235
- });
1236
- const previousStatus = trackedExecutions.get(execution.id);
1237
- setTrackedExecutions((prev) => {
1238
- const updated = new Map(prev);
1239
- updated.set(execution.id, execution.status);
1240
- return updated;
1433
+ return [...prev, execution];
1241
1434
  });
1242
1435
  const inProgressStatuses = [
1243
- import_core5.ExecutionStatus.PENDING,
1244
- import_core5.ExecutionStatus.WAITING,
1245
- import_core5.ExecutionStatus.DELAYED
1436
+ import_core6.ExecutionStatus.PENDING,
1437
+ import_core6.ExecutionStatus.WAITING,
1438
+ import_core6.ExecutionStatus.DELAYED
1246
1439
  ];
1247
- if (execution.status === import_core5.ExecutionStatus.SUCCEEDED && onDepositSuccess && (!previousStatus || inProgressStatuses.includes(previousStatus))) {
1248
- onDepositSuccess({
1440
+ if (execution.status === import_core6.ExecutionStatus.SUCCEEDED && (!previousStatus || inProgressStatuses.includes(previousStatus))) {
1441
+ onDepositSuccessRef.current?.({
1249
1442
  message: "Deposit completed successfully",
1250
1443
  executionId: execution.id,
1251
1444
  transaction: execution
1252
1445
  });
1253
- } else if (execution.status === import_core5.ExecutionStatus.FAILED && onDepositError && previousStatus !== import_core5.ExecutionStatus.FAILED) {
1254
- onDepositError({
1446
+ } else if (execution.status === import_core6.ExecutionStatus.FAILED && previousStatus !== import_core6.ExecutionStatus.FAILED) {
1447
+ onDepositErrorRef.current?.({
1255
1448
  message: "Deposit failed",
1256
1449
  code: "DEPOSIT_FAILED",
1257
1450
  error: execution
@@ -1260,36 +1453,45 @@ function useDepositPolling({
1260
1453
  }
1261
1454
  } catch (error) {
1262
1455
  console.error("Failed to fetch executions:", error);
1263
- if (onDepositError) {
1264
- onDepositError({
1265
- message: "Failed to fetch deposit status",
1266
- code: "POLLING_ERROR",
1267
- error
1268
- });
1269
- }
1456
+ onDepositErrorRef.current?.({
1457
+ message: "Failed to fetch deposit status",
1458
+ code: "POLLING_ERROR",
1459
+ error
1460
+ });
1270
1461
  }
1271
- }, 3e3);
1462
+ };
1463
+ const pollInterval = setInterval(poll, POLL_INTERVAL_MS);
1272
1464
  setIsPolling(true);
1273
- pollingIntervalRef.current = pollInterval;
1274
1465
  return () => {
1275
- if (pollingIntervalRef.current) {
1276
- clearInterval(pollingIntervalRef.current);
1277
- pollingIntervalRef.current = null;
1278
- }
1466
+ clearInterval(pollInterval);
1279
1467
  setIsPolling(false);
1280
1468
  };
1281
- }, [
1282
- userId,
1283
- publishableKey,
1284
- modalOpenedAt,
1285
- trackedExecutions,
1286
- enabled,
1287
- onDepositSuccess,
1288
- onDepositError
1289
- ]);
1469
+ }, [userId, publishableKey, enabled]);
1470
+ (0, import_react3.useEffect)(() => {
1471
+ if (!pollingEnabled || !depositWalletId) return;
1472
+ const triggerPoll = async () => {
1473
+ try {
1474
+ await (0, import_core6.pollDirectExecutions)(
1475
+ { deposit_wallet_id: depositWalletId },
1476
+ publishableKey
1477
+ );
1478
+ } catch {
1479
+ }
1480
+ };
1481
+ triggerPoll();
1482
+ const interval = setInterval(triggerPoll, POLL_ENDPOINT_INTERVAL_MS);
1483
+ return () => clearInterval(interval);
1484
+ }, [pollingEnabled, depositWalletId, publishableKey]);
1485
+ const handleIveDeposited = () => {
1486
+ setPollingEnabled(true);
1487
+ setShowWaitingUi(true);
1488
+ };
1290
1489
  return {
1291
1490
  executions,
1292
- isPolling
1491
+ isPolling,
1492
+ pollingEnabled,
1493
+ showWaitingUi,
1494
+ handleIveDeposited
1293
1495
  };
1294
1496
  }
1295
1497
 
@@ -1299,12 +1501,12 @@ var import_react6 = require("react");
1299
1501
  // src/components/deposits/DepositSuccessToast.tsx
1300
1502
  var import_react5 = require("react");
1301
1503
  var import_lucide_react5 = require("lucide-react");
1302
- var import_core7 = require("@unifold/core");
1504
+ var import_core8 = require("@unifold/core");
1303
1505
 
1304
1506
  // src/components/deposits/DepositDetailContent.tsx
1305
1507
  var import_react4 = require("react");
1306
1508
  var import_lucide_react4 = require("lucide-react");
1307
- var import_core6 = require("@unifold/core");
1509
+ var import_core7 = require("@unifold/core");
1308
1510
  var import_jsx_runtime7 = require("react/jsx-runtime");
1309
1511
  function formatCurrency(currency) {
1310
1512
  if (!currency) return "";
@@ -1319,12 +1521,12 @@ function DepositDetailContent({ execution }) {
1319
1521
  const [chains, setChains] = (0, import_react4.useState)([]);
1320
1522
  const [showNetworkDetails, setShowNetworkDetails] = (0, import_react4.useState)(false);
1321
1523
  (0, import_react4.useEffect)(() => {
1322
- (0, import_core6.getTokenChains)().then((response) => setChains(response.data)).catch((err) => console.error("Failed to fetch chains:", err));
1524
+ (0, import_core7.getTokenChains)().then((response) => setChains(response.data)).catch((err) => console.error("Failed to fetch chains:", err));
1323
1525
  }, []);
1324
1526
  (0, import_react4.useEffect)(() => {
1325
1527
  setShowNetworkDetails(false);
1326
1528
  }, [execution?.id]);
1327
- const isPending = execution.status === import_core6.ExecutionStatus.PENDING || execution.status === import_core6.ExecutionStatus.WAITING || execution.status === import_core6.ExecutionStatus.DELAYED;
1529
+ const isPending = execution.status === import_core7.ExecutionStatus.PENDING || execution.status === import_core7.ExecutionStatus.WAITING || execution.status === import_core7.ExecutionStatus.DELAYED;
1328
1530
  const formatDateTime = (timestamp) => {
1329
1531
  try {
1330
1532
  const date = new Date(timestamp);
@@ -1394,7 +1596,7 @@ function DepositDetailContent({ execution }) {
1394
1596
  return "$0.00";
1395
1597
  };
1396
1598
  const getNetworkName = (chainType, chainId) => {
1397
- return (0, import_core6.getChainName)(chains, chainType, chainId);
1599
+ return (0, import_core7.getChainName)(chains, chainType, chainId);
1398
1600
  };
1399
1601
  const formatTransactionHash = (hash) => {
1400
1602
  if (!hash || hash.length < 12) return hash;
@@ -1406,7 +1608,7 @@ function DepositDetailContent({ execution }) {
1406
1608
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1407
1609
  "img",
1408
1610
  {
1409
- src: execution.destination_token_metadata?.icon_url || (0, import_core6.getIconUrl)("/icons/tokens/svg/usdc.svg"),
1611
+ src: execution.destination_token_metadata?.icon_url || (0, import_core7.getIconUrl)("/icons/tokens/svg/usdc.svg"),
1410
1612
  alt: "Token",
1411
1613
  width: 64,
1412
1614
  height: 64,
@@ -1835,7 +2037,7 @@ function DepositSuccessToast({
1835
2037
  }) {
1836
2038
  const [detailModalOpen, setDetailModalOpen] = (0, import_react5.useState)(false);
1837
2039
  const { themeClass, colors: colors2, fonts, components } = useTheme();
1838
- const isPending = status === import_core7.ExecutionStatus.PENDING || status === import_core7.ExecutionStatus.WAITING || status === import_core7.ExecutionStatus.DELAYED;
2040
+ const isPending = status === import_core8.ExecutionStatus.PENDING || status === import_core8.ExecutionStatus.WAITING || status === import_core8.ExecutionStatus.DELAYED;
1839
2041
  const formatDateTime = (timestamp) => {
1840
2042
  try {
1841
2043
  const date = new Date(timestamp);
@@ -1913,7 +2115,7 @@ function DepositSuccessToast({
1913
2115
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1914
2116
  "img",
1915
2117
  {
1916
- src: tokenIconUrl || (0, import_core7.getIconUrl)("/icons/tokens/svg/usdc.svg"),
2118
+ src: tokenIconUrl || (0, import_core8.getIconUrl)("/icons/tokens/svg/usdc.svg"),
1917
2119
  alt: "Token",
1918
2120
  width: 36,
1919
2121
  height: 36,
@@ -2204,7 +2406,7 @@ function BuyWithCard({
2204
2406
  (0, import_react7.useEffect)(() => {
2205
2407
  async function fetchFiatCurrencies() {
2206
2408
  try {
2207
- const response = await (0, import_core8.getFiatCurrencies)(publishableKey);
2409
+ const response = await (0, import_core9.getFiatCurrencies)(publishableKey);
2208
2410
  setFiatCurrencies(response.data);
2209
2411
  setPreferredCurrencyCodes(response.preferred || []);
2210
2412
  } catch (err) {
@@ -2258,7 +2460,7 @@ function BuyWithCard({
2258
2460
  (0, import_react7.useEffect)(() => {
2259
2461
  async function fetchDestinationToken() {
2260
2462
  try {
2261
- const response = await (0, import_core8.getTokenMetadata)(
2463
+ const response = await (0, import_core9.getTokenMetadata)(
2262
2464
  {
2263
2465
  chain_type: destinationChainType || "",
2264
2466
  chain_id: destinationChainId || "",
@@ -2283,7 +2485,7 @@ function BuyWithCard({
2283
2485
  }
2284
2486
  setDefaultTokenLoading(true);
2285
2487
  try {
2286
- const response = await (0, import_core8.getDefaultOnrampToken)(
2488
+ const response = await (0, import_core9.getDefaultOnrampToken)(
2287
2489
  {
2288
2490
  country_code: userIpInfo?.alpha2?.toUpperCase() || "US",
2289
2491
  subdivision_code: userIpInfo?.state || void 0,
@@ -2371,7 +2573,7 @@ function BuyWithCard({
2371
2573
  destination_network: defaultToken.destination_network,
2372
2574
  subdivision_code: userIpInfo?.state || void 0
2373
2575
  };
2374
- const response = await (0, import_core8.getOnrampQuotes)(request, publishableKey);
2576
+ const response = await (0, import_core9.getOnrampQuotes)(request, publishableKey);
2375
2577
  setQuotes(response.data);
2376
2578
  const currentHasManualSelection = hasManualSelectionRef.current;
2377
2579
  const currentSelectedProvider = selectedProviderRef.current;
@@ -2455,7 +2657,7 @@ function BuyWithCard({
2455
2657
  const handleContinue = () => {
2456
2658
  if (!selectedProvider) return;
2457
2659
  if (!defaultToken) return;
2458
- const wallet = (0, import_core8.getWalletByChainType)(
2660
+ const wallet = (0, import_core9.getWalletByChainType)(
2459
2661
  wallets,
2460
2662
  defaultToken.destination_token_metadata.chain_type
2461
2663
  );
@@ -2473,7 +2675,7 @@ function BuyWithCard({
2473
2675
  wallet_address: wallet.address,
2474
2676
  subdivision_code: userIpInfo?.state || void 0
2475
2677
  };
2476
- const sessionStartUrl = (0, import_core8.getOnrampSessionStartUrl)(
2678
+ const sessionStartUrl = (0, import_core9.getOnrampSessionStartUrl)(
2477
2679
  sessionRequest,
2478
2680
  publishableKey
2479
2681
  );
@@ -2523,7 +2725,7 @@ function BuyWithCard({
2523
2725
  selectedCurrencyData && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2524
2726
  "img",
2525
2727
  {
2526
- src: (0, import_core8.getPreferredIconUrl)(
2728
+ src: (0, import_core9.getPreferredIconUrl)(
2527
2729
  selectedCurrencyData.icon_urls,
2528
2730
  "png"
2529
2731
  ) || selectedCurrencyData.icon_url,
@@ -2885,7 +3087,7 @@ function BuyWithCard({
2885
3087
  /* @__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)(
2886
3088
  "img",
2887
3089
  {
2888
- src: (0, import_core8.getIconUrlWithCdn)(
3090
+ src: (0, import_core9.getIconUrlWithCdn)(
2889
3091
  `/icons/currencies/png/${onrampSession.sourceCurrency.toLowerCase()}.png`,
2890
3092
  assetCdnUrl
2891
3093
  ),
@@ -2902,7 +3104,7 @@ function BuyWithCard({
2902
3104
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2903
3105
  "img",
2904
3106
  {
2905
- src: defaultToken?.destination_token_metadata?.icon_url || (0, import_core8.getIconUrlWithCdn)(
3107
+ src: defaultToken?.destination_token_metadata?.icon_url || (0, import_core9.getIconUrlWithCdn)(
2906
3108
  "/icons/tokens/png/usdc.png",
2907
3109
  assetCdnUrl
2908
3110
  ),
@@ -2913,7 +3115,7 @@ function BuyWithCard({
2913
3115
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2914
3116
  "img",
2915
3117
  {
2916
- src: defaultToken?.destination_token_metadata?.chain.icon_url || (0, import_core8.getIconUrlWithCdn)(
3118
+ src: defaultToken?.destination_token_metadata?.chain.icon_url || (0, import_core9.getIconUrlWithCdn)(
2917
3119
  "/icons/networks/png/polygon.png",
2918
3120
  assetCdnUrl
2919
3121
  ),
@@ -2931,7 +3133,7 @@ function BuyWithCard({
2931
3133
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2932
3134
  "img",
2933
3135
  {
2934
- src: destinationTokenIcon || (0, import_core8.getIconUrlWithCdn)(
3136
+ src: destinationTokenIcon || (0, import_core9.getIconUrlWithCdn)(
2935
3137
  "/icons/tokens/png/usdc.png",
2936
3138
  assetCdnUrl
2937
3139
  ),
@@ -2989,14 +3191,14 @@ var import_react8 = require("react");
2989
3191
 
2990
3192
  // src/components/deposits/DepositExecutionItem.tsx
2991
3193
  var import_lucide_react7 = require("lucide-react");
2992
- var import_core9 = require("@unifold/core");
3194
+ var import_core10 = require("@unifold/core");
2993
3195
  var import_jsx_runtime11 = require("react/jsx-runtime");
2994
3196
  function DepositExecutionItem({
2995
3197
  execution,
2996
3198
  onClick
2997
3199
  }) {
2998
3200
  const { colors: colors2, fonts, components } = useTheme();
2999
- const isPending = execution.status === import_core9.ExecutionStatus.PENDING || execution.status === import_core9.ExecutionStatus.WAITING || execution.status === import_core9.ExecutionStatus.DELAYED;
3201
+ const isPending = execution.status === import_core10.ExecutionStatus.PENDING || execution.status === import_core10.ExecutionStatus.WAITING || execution.status === import_core10.ExecutionStatus.DELAYED;
3000
3202
  const formatDateTime = (timestamp) => {
3001
3203
  try {
3002
3204
  const date = new Date(timestamp);
@@ -3039,7 +3241,7 @@ function DepositExecutionItem({
3039
3241
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3040
3242
  "img",
3041
3243
  {
3042
- src: execution.destination_token_metadata?.icon_url || (0, import_core9.getIconUrl)("/icons/tokens/svg/usdc.svg"),
3244
+ src: execution.destination_token_metadata?.icon_url || (0, import_core10.getIconUrl)("/icons/tokens/svg/usdc.svg"),
3043
3245
  alt: "Token",
3044
3246
  width: 36,
3045
3247
  height: 36,
@@ -3216,7 +3418,7 @@ function ThemeStyleInjector({
3216
3418
  }
3217
3419
 
3218
3420
  // src/components/deposits/DepositsModal.tsx
3219
- var import_core10 = require("@unifold/core");
3421
+ var import_core11 = require("@unifold/core");
3220
3422
  var import_jsx_runtime13 = require("react/jsx-runtime");
3221
3423
  function DepositsModal({
3222
3424
  open,
@@ -3234,7 +3436,7 @@ function DepositsModal({
3234
3436
  if (!open || !userId) return;
3235
3437
  const fetchExecutions = async () => {
3236
3438
  try {
3237
- const response = await (0, import_core10.queryExecutions)(userId, publishableKey);
3439
+ const response = await (0, import_core11.queryExecutions)(userId, publishableKey);
3238
3440
  const sorted = [...response.data].sort((a, b) => {
3239
3441
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
3240
3442
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -3580,7 +3782,7 @@ function DepositTrackerButton({
3580
3782
  // src/components/deposits/buttons/BrowserWalletButton.tsx
3581
3783
  var React20 = __toESM(require("react"));
3582
3784
  var import_lucide_react11 = require("lucide-react");
3583
- var import_core11 = require("@unifold/core");
3785
+ var import_core12 = require("@unifold/core");
3584
3786
 
3585
3787
  // src/resources/icons/MetamaskIcon.tsx
3586
3788
  var React8 = __toESM(require("react"));
@@ -5150,10 +5352,48 @@ var WALLET_ICON_COMPONENTS = {
5150
5352
  backpack: BackpackIcon,
5151
5353
  glow: GlowIcon
5152
5354
  };
5153
- function truncateAddress2(address) {
5355
+ function truncateAddress3(address) {
5154
5356
  if (address.length <= 10) return address;
5155
5357
  return `${address.slice(0, 4)}...${address.slice(-4)}`;
5156
5358
  }
5359
+ function identifyEthWallet(provider, _win, hint) {
5360
+ switch (hint) {
5361
+ case "metamask":
5362
+ return { type: "metamask", name: "MetaMask", icon: "metamask" };
5363
+ case "phantom":
5364
+ return { type: "phantom-ethereum", name: "Phantom", icon: "phantom" };
5365
+ case "coinbase":
5366
+ return { type: "coinbase", name: "Coinbase Wallet", icon: "coinbase" };
5367
+ case "okx":
5368
+ return { type: "okx", name: "OKX Wallet", icon: "okx" };
5369
+ case "rabby":
5370
+ return { type: "rabby", name: "Rabby", icon: "rabby" };
5371
+ case "trust":
5372
+ return { type: "trust", name: "Trust Wallet", icon: "trust" };
5373
+ case "rainbow":
5374
+ return { type: "rainbow", name: "Rainbow", icon: "rainbow" };
5375
+ }
5376
+ const anyProvider = provider;
5377
+ if (provider.isPhantom) {
5378
+ return { type: "phantom-ethereum", name: "Phantom", icon: "phantom" };
5379
+ }
5380
+ if (anyProvider.isCoinbaseWallet) {
5381
+ return { type: "coinbase", name: "Coinbase Wallet", icon: "coinbase" };
5382
+ }
5383
+ if (anyProvider.isRabby) {
5384
+ return { type: "rabby", name: "Rabby", icon: "rabby" };
5385
+ }
5386
+ if (anyProvider.isTrust) {
5387
+ return { type: "trust", name: "Trust Wallet", icon: "trust" };
5388
+ }
5389
+ if (anyProvider.isRainbow) {
5390
+ return { type: "rainbow", name: "Rainbow", icon: "rainbow" };
5391
+ }
5392
+ if (provider.isMetaMask && !provider.isPhantom) {
5393
+ return { type: "metamask", name: "MetaMask", icon: "metamask" };
5394
+ }
5395
+ return { type: "metamask", name: "Wallet", icon: "metamask" };
5396
+ }
5157
5397
  function BrowserWalletButton({
5158
5398
  onClick,
5159
5399
  onConnectClick,
@@ -5170,9 +5410,35 @@ function BrowserWalletButton({
5170
5410
  const [balanceText, setBalanceText] = React20.useState(null);
5171
5411
  const [isLoadingBalance, setIsLoadingBalance] = React20.useState(false);
5172
5412
  const iconVariant = mode === "dark" ? "light" : "dark";
5413
+ const onDisconnectRef = React20.useRef(onDisconnect);
5414
+ onDisconnectRef.current = onDisconnect;
5173
5415
  React20.useEffect(() => {
5174
5416
  setIsTouchDevice("ontouchstart" in window || navigator.maxTouchPoints > 0);
5175
5417
  }, []);
5418
+ const [eip6963ProviderCount, setEip6963ProviderCount] = React20.useState(0);
5419
+ React20.useEffect(() => {
5420
+ if (typeof window === "undefined") return;
5421
+ const anyWin = window;
5422
+ if (!anyWin.__eip6963Providers) {
5423
+ anyWin.__eip6963Providers = [];
5424
+ }
5425
+ const handleAnnouncement = (event) => {
5426
+ const { detail } = event;
5427
+ if (!detail?.info || !detail?.provider) return;
5428
+ const exists = anyWin.__eip6963Providers.some(
5429
+ (p) => p.info.uuid === detail.info.uuid
5430
+ );
5431
+ if (!exists) {
5432
+ anyWin.__eip6963Providers.push(detail);
5433
+ setEip6963ProviderCount(anyWin.__eip6963Providers.length);
5434
+ }
5435
+ };
5436
+ window.addEventListener("eip6963:announceProvider", handleAnnouncement);
5437
+ window.dispatchEvent(new Event("eip6963:requestProvider"));
5438
+ return () => {
5439
+ window.removeEventListener("eip6963:announceProvider", handleAnnouncement);
5440
+ };
5441
+ }, []);
5176
5442
  React20.useEffect(() => {
5177
5443
  if (!wallet || !publishableKey) {
5178
5444
  setBalanceText(null);
@@ -5181,7 +5447,7 @@ function BrowserWalletButton({
5181
5447
  let cancelled = false;
5182
5448
  const walletChainType = wallet.type === "phantom-solana" || wallet.type === "solflare" || wallet.type === "backpack" || wallet.type === "glow" ? "solana" : "ethereum";
5183
5449
  setIsLoadingBalance(true);
5184
- (0, import_core11.getAddressBalances)(wallet.address, walletChainType, publishableKey).then((response) => {
5450
+ (0, import_core12.getAddressBalances)(wallet.address, walletChainType, publishableKey).then((response) => {
5185
5451
  if (cancelled) return;
5186
5452
  if (response.balances && response.balances.length > 0) {
5187
5453
  const totalUsd = response.balances.reduce((sum, balance) => {
@@ -5222,166 +5488,85 @@ function BrowserWalletButton({
5222
5488
  try {
5223
5489
  const win = typeof window !== "undefined" ? window : null;
5224
5490
  if (!win) return;
5491
+ if (getUserDisconnectedWallet()) {
5492
+ if (mounted) {
5493
+ setWallet(null);
5494
+ setIsLoading(false);
5495
+ }
5496
+ return;
5497
+ }
5225
5498
  if (!chainType || chainType === "solana") {
5226
- const phantomSolana = win.phantom?.solana;
5227
- if (phantomSolana?.isPhantom) {
5228
- if (phantomSolana.isConnected && phantomSolana.publicKey) {
5499
+ const anyWin2 = win;
5500
+ const trySilentSolana = async (provider, type, name, icon) => {
5501
+ if (!provider) return false;
5502
+ if (provider.isConnected && provider.publicKey) {
5229
5503
  if (mounted) {
5230
- setWallet({
5231
- type: "phantom-solana",
5232
- name: "Phantom",
5233
- address: phantomSolana.publicKey.toString(),
5234
- icon: "phantom"
5235
- });
5504
+ setWallet({ type, name, address: provider.publicKey.toString(), icon });
5236
5505
  setIsLoading(false);
5237
5506
  }
5238
- return;
5507
+ return true;
5239
5508
  }
5240
- }
5241
- const solflare = win.solflare;
5242
- if (solflare?.isConnected && solflare?.publicKey) {
5243
- if (mounted) {
5244
- setWallet({
5245
- type: "solflare",
5246
- name: "Solflare",
5247
- address: solflare.publicKey.toString(),
5248
- icon: "solflare"
5249
- });
5250
- setIsLoading(false);
5509
+ try {
5510
+ const resp = await provider.connect({ onlyIfTrusted: true });
5511
+ if (mounted && resp.publicKey) {
5512
+ setWallet({ type, name, address: resp.publicKey.toString(), icon });
5513
+ setIsLoading(false);
5514
+ return true;
5515
+ }
5516
+ } catch {
5251
5517
  }
5252
- return;
5518
+ return false;
5519
+ };
5520
+ if (await trySilentSolana(win.phantom?.solana, "phantom-solana", "Phantom", "phantom")) return;
5521
+ if (await trySilentSolana(anyWin2.solflare, "solflare", "Solflare", "solflare")) return;
5522
+ if (await trySilentSolana(anyWin2.backpack, "backpack", "Backpack", "backpack")) return;
5523
+ if (await trySilentSolana(anyWin2.glow, "glow", "Glow", "glow")) return;
5524
+ }
5525
+ if (!chainType || chainType === "ethereum") {
5526
+ const anyWin2 = win;
5527
+ const allProviders = [];
5528
+ const eip6963Providers = anyWin2.__eip6963Providers || [];
5529
+ for (const { info, provider } of eip6963Providers) {
5530
+ let walletId = "default";
5531
+ if (info.rdns.includes("metamask")) walletId = "metamask";
5532
+ else if (info.rdns.includes("phantom")) walletId = "phantom";
5533
+ else if (info.rdns.includes("coinbase")) walletId = "coinbase";
5534
+ else if (info.rdns.includes("okx")) walletId = "okx";
5535
+ else if (info.rdns.includes("rabby")) walletId = "rabby";
5536
+ else if (info.rdns.includes("trust")) walletId = "trust";
5537
+ else if (info.rdns.includes("rainbow")) walletId = "rainbow";
5538
+ allProviders.push({ provider, walletId });
5253
5539
  }
5254
- const backpack = win.backpack;
5255
- if (backpack?.isConnected && backpack?.publicKey) {
5256
- if (mounted) {
5257
- setWallet({
5258
- type: "backpack",
5259
- name: "Backpack",
5260
- address: backpack.publicKey.toString(),
5261
- icon: "backpack"
5262
- });
5263
- setIsLoading(false);
5540
+ if (allProviders.length === 0) {
5541
+ if (win.phantom?.ethereum) {
5542
+ allProviders.push({ provider: win.phantom.ethereum, walletId: "phantom" });
5264
5543
  }
5265
- return;
5266
- }
5267
- const glow = win.glow;
5268
- if (glow?.isConnected && glow?.publicKey) {
5269
- if (mounted) {
5270
- setWallet({
5271
- type: "glow",
5272
- name: "Glow",
5273
- address: glow.publicKey.toString(),
5274
- icon: "glow"
5275
- });
5276
- setIsLoading(false);
5544
+ if (anyWin2.okxwallet) {
5545
+ allProviders.push({ provider: anyWin2.okxwallet, walletId: "okx" });
5546
+ }
5547
+ if (anyWin2.coinbaseWalletExtension) {
5548
+ allProviders.push({ provider: anyWin2.coinbaseWalletExtension, walletId: "coinbase" });
5549
+ }
5550
+ if (win.ethereum) {
5551
+ const isDuplicate = allProviders.some((p) => p.provider === win.ethereum);
5552
+ if (!isDuplicate) {
5553
+ allProviders.push({ provider: win.ethereum, walletId: "default" });
5554
+ }
5277
5555
  }
5278
- return;
5279
5556
  }
5280
- }
5281
- if (!chainType || chainType === "ethereum") {
5282
- const ethProvider2 = win.ethereum;
5283
- if (ethProvider2) {
5557
+ for (const { provider, walletId } of allProviders) {
5558
+ if (!provider) continue;
5284
5559
  try {
5285
- const accounts = await ethProvider2.request({ method: "eth_accounts" });
5286
- if (accounts && accounts.length > 0) {
5287
- const address = accounts[0];
5288
- if (ethProvider2.isMetaMask && !ethProvider2.isPhantom) {
5289
- const providers = ethProvider2.providers;
5290
- if (win.okxwallet) {
5291
- if (mounted) {
5292
- setWallet({
5293
- type: "okx",
5294
- name: "OKX Wallet",
5295
- address,
5296
- icon: "okx"
5297
- });
5298
- setIsLoading(false);
5299
- }
5300
- return;
5301
- }
5302
- if (ethProvider2.isRabby) {
5303
- if (mounted) {
5304
- setWallet({
5305
- type: "rabby",
5306
- name: "Rabby",
5307
- address,
5308
- icon: "rabby"
5309
- });
5310
- setIsLoading(false);
5311
- }
5312
- return;
5313
- }
5314
- if (ethProvider2.isTrust || win.trustwallet) {
5315
- if (mounted) {
5316
- setWallet({
5317
- type: "trust",
5318
- name: "Trust Wallet",
5319
- address,
5320
- icon: "trust"
5321
- });
5322
- setIsLoading(false);
5323
- }
5324
- return;
5325
- }
5326
- if (ethProvider2.isRainbow) {
5327
- if (mounted) {
5328
- setWallet({
5329
- type: "rainbow",
5330
- name: "Rainbow",
5331
- address,
5332
- icon: "rainbow"
5333
- });
5334
- setIsLoading(false);
5335
- }
5336
- return;
5337
- }
5338
- if (mounted) {
5339
- setWallet({
5340
- type: "metamask",
5341
- name: "MetaMask",
5342
- address,
5343
- icon: "metamask"
5344
- });
5345
- setIsLoading(false);
5346
- }
5347
- return;
5348
- }
5349
- if (ethProvider2.isPhantom) {
5350
- if (mounted) {
5351
- setWallet({
5352
- type: "phantom-ethereum",
5353
- name: "Phantom",
5354
- address,
5355
- icon: "phantom"
5356
- });
5357
- setIsLoading(false);
5358
- }
5359
- return;
5360
- }
5361
- if (ethProvider2.isCoinbaseWallet) {
5362
- if (mounted) {
5363
- setWallet({
5364
- type: "coinbase",
5365
- name: "Coinbase Wallet",
5366
- address,
5367
- icon: "coinbase"
5368
- });
5369
- setIsLoading(false);
5370
- }
5371
- return;
5372
- }
5373
- if (mounted) {
5374
- setWallet({
5375
- type: "metamask",
5376
- name: "Wallet",
5377
- address,
5378
- icon: "metamask"
5379
- });
5380
- setIsLoading(false);
5381
- }
5382
- return;
5560
+ const accounts = await provider.request({ method: "eth_accounts" });
5561
+ if (!accounts || accounts.length === 0) continue;
5562
+ const address = accounts[0];
5563
+ const resolved = identifyEthWallet(provider, anyWin2, walletId);
5564
+ if (mounted) {
5565
+ setWallet({ ...resolved, address });
5566
+ setIsLoading(false);
5383
5567
  }
5384
- } catch (ethError) {
5568
+ return;
5569
+ } catch {
5385
5570
  }
5386
5571
  }
5387
5572
  }
@@ -5402,12 +5587,12 @@ function BrowserWalletButton({
5402
5587
  detectWallet();
5403
5588
  };
5404
5589
  const handleDisconnect = () => {
5405
- onDisconnect?.();
5590
+ onDisconnectRef.current?.();
5406
5591
  detectWallet();
5407
5592
  };
5408
5593
  const handleEthAccountsChanged = (accounts) => {
5409
5594
  if (Array.isArray(accounts) && accounts.length === 0) {
5410
- onDisconnect?.();
5595
+ onDisconnectRef.current?.();
5411
5596
  }
5412
5597
  detectWallet();
5413
5598
  };
@@ -5417,10 +5602,24 @@ function BrowserWalletButton({
5417
5602
  solanaProvider.on("disconnect", handleDisconnect);
5418
5603
  solanaProvider.on("accountChanged", handleAccountsChanged);
5419
5604
  }
5420
- const ethProvider = window.phantom?.ethereum || window.ethereum;
5421
- if (ethProvider) {
5422
- ethProvider.on("accountsChanged", handleEthAccountsChanged);
5423
- ethProvider.on("chainChanged", handleAccountsChanged);
5605
+ const anyWin = window;
5606
+ const ethProviders = [];
5607
+ if (anyWin.__eip6963Providers) {
5608
+ for (const { provider } of anyWin.__eip6963Providers) {
5609
+ if (provider && !ethProviders.includes(provider)) {
5610
+ ethProviders.push(provider);
5611
+ }
5612
+ }
5613
+ }
5614
+ if (window.ethereum && !ethProviders.includes(window.ethereum)) {
5615
+ ethProviders.push(window.ethereum);
5616
+ }
5617
+ if (window.phantom?.ethereum && !ethProviders.includes(window.phantom.ethereum)) {
5618
+ ethProviders.push(window.phantom.ethereum);
5619
+ }
5620
+ for (const provider of ethProviders) {
5621
+ provider.on("accountsChanged", handleEthAccountsChanged);
5622
+ provider.on("chainChanged", handleAccountsChanged);
5424
5623
  }
5425
5624
  return () => {
5426
5625
  mounted = false;
@@ -5429,12 +5628,12 @@ function BrowserWalletButton({
5429
5628
  solanaProvider.off("disconnect", handleDisconnect);
5430
5629
  solanaProvider.off("accountChanged", handleAccountsChanged);
5431
5630
  }
5432
- if (ethProvider) {
5433
- ethProvider.removeListener("accountsChanged", handleEthAccountsChanged);
5434
- ethProvider.removeListener("chainChanged", handleAccountsChanged);
5631
+ for (const provider of ethProviders) {
5632
+ provider.removeListener("accountsChanged", handleEthAccountsChanged);
5633
+ provider.removeListener("chainChanged", handleAccountsChanged);
5435
5634
  }
5436
5635
  };
5437
- }, [chainType]);
5636
+ }, [chainType, eip6963ProviderCount]);
5438
5637
  const handleConnect = async () => {
5439
5638
  if (wallet) {
5440
5639
  onClick(wallet);
@@ -5450,6 +5649,7 @@ function BrowserWalletButton({
5450
5649
  const solanaProvider = window.phantom?.solana || window.solana;
5451
5650
  if (solanaProvider?.isPhantom) {
5452
5651
  const { publicKey } = await solanaProvider.connect();
5652
+ setUserDisconnectedWallet(false);
5453
5653
  setWallet({
5454
5654
  type: "phantom-solana",
5455
5655
  name: "Phantom",
@@ -5467,6 +5667,7 @@ function BrowserWalletButton({
5467
5667
  method: "eth_requestAccounts"
5468
5668
  });
5469
5669
  if (accounts && accounts.length > 0) {
5670
+ setUserDisconnectedWallet(false);
5470
5671
  const isPhantom = ethProvider.isPhantom;
5471
5672
  setWallet({
5472
5673
  type: isPhantom ? "phantom-ethereum" : "metamask",
@@ -5478,7 +5679,10 @@ function BrowserWalletButton({
5478
5679
  }
5479
5680
  }
5480
5681
  } catch (error) {
5481
- console.error("Error connecting wallet:", error);
5682
+ if (error && typeof error === "object" && "code" in error && error.code === 4001) {
5683
+ } else {
5684
+ console.error("Error connecting wallet:", error);
5685
+ }
5482
5686
  } finally {
5483
5687
  setIsConnecting(false);
5484
5688
  }
@@ -5524,7 +5728,7 @@ function BrowserWalletButton({
5524
5728
  color: components.card.titleColor,
5525
5729
  fontFamily: fonts.regular
5526
5730
  },
5527
- children: wallet ? `${wallet.name} (${truncateAddress2(wallet.address)})` : "Connect Wallet"
5731
+ children: wallet ? `${wallet.name} (${truncateAddress3(wallet.address)})` : "Connect Wallet"
5528
5732
  }
5529
5733
  ),
5530
5734
  isLoadingBalance ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "uf-h-3 uf-w-24 uf-bg-muted uf-rounded uf-animate-pulse" }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
@@ -5577,7 +5781,7 @@ var import_core19 = require("@unifold/core");
5577
5781
 
5578
5782
  // src/hooks/use-allowed-country.ts
5579
5783
  var import_react_query3 = require("@tanstack/react-query");
5580
- var import_core12 = require("@unifold/core");
5784
+ var import_core13 = require("@unifold/core");
5581
5785
  function useAllowedCountry(publishableKey) {
5582
5786
  const {
5583
5787
  data: ipData,
@@ -5585,7 +5789,7 @@ function useAllowedCountry(publishableKey) {
5585
5789
  error: ipError
5586
5790
  } = (0, import_react_query3.useQuery)({
5587
5791
  queryKey: ["unifold", "ipAddress"],
5588
- queryFn: () => (0, import_core12.getIpAddress)(),
5792
+ queryFn: () => (0, import_core13.getIpAddress)(),
5589
5793
  refetchOnMount: false,
5590
5794
  refetchOnReconnect: true,
5591
5795
  refetchOnWindowFocus: false,
@@ -5600,7 +5804,7 @@ function useAllowedCountry(publishableKey) {
5600
5804
  error: configError
5601
5805
  } = (0, import_react_query3.useQuery)({
5602
5806
  queryKey: ["unifold", "projectConfig", publishableKey],
5603
- queryFn: () => (0, import_core12.getProjectConfig)(publishableKey),
5807
+ queryFn: () => (0, import_core13.getProjectConfig)(publishableKey),
5604
5808
  refetchOnMount: false,
5605
5809
  refetchOnReconnect: true,
5606
5810
  refetchOnWindowFocus: false,
@@ -5631,7 +5835,7 @@ function useAllowedCountry(publishableKey) {
5631
5835
 
5632
5836
  // src/hooks/use-address-validation.ts
5633
5837
  var import_react_query4 = require("@tanstack/react-query");
5634
- var import_core13 = require("@unifold/core");
5838
+ var import_core14 = require("@unifold/core");
5635
5839
  function useAddressValidation({
5636
5840
  recipientAddress,
5637
5841
  destinationChainType,
@@ -5651,7 +5855,7 @@ function useAddressValidation({
5651
5855
  destinationChainId,
5652
5856
  destinationTokenAddress
5653
5857
  ],
5654
- queryFn: () => (0, import_core13.verifyRecipientAddress)(
5858
+ queryFn: () => (0, import_core14.verifyRecipientAddress)(
5655
5859
  {
5656
5860
  chain_type: destinationChainType,
5657
5861
  chain_id: destinationChainId,
@@ -5689,7 +5893,7 @@ function useAddressValidation({
5689
5893
 
5690
5894
  // src/hooks/use-supported-deposit-tokens.ts
5691
5895
  var import_react_query5 = require("@tanstack/react-query");
5692
- var import_core14 = require("@unifold/core");
5896
+ var import_core15 = require("@unifold/core");
5693
5897
  function useSupportedDepositTokens(publishableKey, options) {
5694
5898
  const filteredOptions = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type ? {
5695
5899
  destination_token_address: options.destination_token_address,
@@ -5705,7 +5909,7 @@ function useSupportedDepositTokens(publishableKey, options) {
5705
5909
  filteredOptions?.destination_chain_id ?? null,
5706
5910
  filteredOptions?.destination_chain_type ?? null
5707
5911
  ],
5708
- queryFn: () => (0, import_core14.getSupportedDepositTokens)(publishableKey, filteredOptions),
5912
+ queryFn: () => (0, import_core15.getSupportedDepositTokens)(publishableKey, filteredOptions),
5709
5913
  staleTime: 1e3 * 60 * 5,
5710
5914
  // 5 minutes — token list rarely changes
5711
5915
  gcTime: 1e3 * 60 * 30,
@@ -5723,11 +5927,6 @@ var import_lucide_react14 = require("lucide-react");
5723
5927
  var import_react10 = require("react");
5724
5928
  var import_qr_code_styling = __toESM(require("qr-code-styling"));
5725
5929
  var import_jsx_runtime31 = require("react/jsx-runtime");
5726
- var qrCache = /* @__PURE__ */ new Map();
5727
- var imageCache = /* @__PURE__ */ new Map();
5728
- function getCacheKey(value, size, imageUrl, darkMode) {
5729
- return `${value}|${size}|${imageUrl || ""}|${darkMode}`;
5730
- }
5731
5930
  function createQRConfig(value, size, imageUrl, imageSize, darkMode) {
5732
5931
  return {
5733
5932
  type: "svg",
@@ -5764,79 +5963,6 @@ function createQRConfig(value, size, imageUrl, imageSize, darkMode) {
5764
5963
  }
5765
5964
  };
5766
5965
  }
5767
- async function preloadImageAsync(url) {
5768
- if (!url || imageCache.has(url)) return;
5769
- return new Promise((resolve) => {
5770
- const img = new Image();
5771
- img.crossOrigin = "anonymous";
5772
- img.onload = () => {
5773
- imageCache.set(url, true);
5774
- resolve();
5775
- };
5776
- img.onerror = () => {
5777
- imageCache.set(url, false);
5778
- resolve();
5779
- };
5780
- img.src = url;
5781
- });
5782
- }
5783
- function waitForStyledQR(container, maxAttempts = 20) {
5784
- return new Promise((resolve) => {
5785
- let attempts = 0;
5786
- const check = () => {
5787
- const svg = container.querySelector("svg");
5788
- if (!svg) {
5789
- if (attempts++ < maxAttempts) {
5790
- requestAnimationFrame(check);
5791
- } else {
5792
- resolve(null);
5793
- }
5794
- return;
5795
- }
5796
- const hasCircles = svg.querySelectorAll("circle").length > 0;
5797
- const hasPaths = svg.querySelectorAll("path").length > 0;
5798
- if (hasCircles || hasPaths) {
5799
- resolve(svg.outerHTML);
5800
- } else if (attempts++ < maxAttempts) {
5801
- requestAnimationFrame(check);
5802
- } else {
5803
- resolve(svg.outerHTML);
5804
- }
5805
- };
5806
- requestAnimationFrame(check);
5807
- });
5808
- }
5809
- async function preloadQRCode(value, size = 180, imageUrl, imageSize = 45, darkMode = false) {
5810
- if (!value) return;
5811
- const cacheKey = getCacheKey(value, size, imageUrl, darkMode);
5812
- if (qrCache.has(cacheKey)) return;
5813
- if (imageUrl) {
5814
- await preloadImageAsync(imageUrl);
5815
- }
5816
- const tempContainer = document.createElement("div");
5817
- tempContainer.style.position = "absolute";
5818
- tempContainer.style.left = "-9999px";
5819
- tempContainer.style.top = "-9999px";
5820
- document.body.appendChild(tempContainer);
5821
- try {
5822
- const config = createQRConfig(value, size, imageUrl, imageSize, darkMode);
5823
- const qrInstance = new import_qr_code_styling.default(config);
5824
- qrInstance.append(tempContainer);
5825
- const svgString = await waitForStyledQR(tempContainer);
5826
- if (svgString) {
5827
- qrCache.set(cacheKey, { svgString });
5828
- }
5829
- } finally {
5830
- document.body.removeChild(tempContainer);
5831
- }
5832
- }
5833
- function isQRCodeCached(value, size = 180, imageUrl, darkMode = false) {
5834
- const cacheKey = getCacheKey(value, size, imageUrl, darkMode);
5835
- return qrCache.has(cacheKey);
5836
- }
5837
- function clearQRCodeCache() {
5838
- qrCache.clear();
5839
- }
5840
5966
  function StyledQRCode({
5841
5967
  value,
5842
5968
  size = 180,
@@ -5845,107 +5971,28 @@ function StyledQRCode({
5845
5971
  darkMode = false
5846
5972
  }) {
5847
5973
  const containerRef = (0, import_react10.useRef)(null);
5848
- const [isReady, setIsReady] = (0, import_react10.useState)(false);
5849
- const currentKeyRef = (0, import_react10.useRef)("");
5850
- const cacheKey = getCacheKey(value, size, imageUrl, darkMode);
5851
- const cachedEntry = qrCache.get(cacheKey);
5852
- const renderQR = (0, import_react10.useCallback)(async () => {
5974
+ const qrRef = (0, import_react10.useRef)(null);
5975
+ (0, import_react10.useEffect)(() => {
5853
5976
  if (!containerRef.current || !value) return;
5854
- const key = getCacheKey(value, size, imageUrl, darkMode);
5855
- if (currentKeyRef.current === key) {
5856
- setIsReady(true);
5857
- return;
5858
- }
5859
- currentKeyRef.current = key;
5860
- containerRef.current.innerHTML = "";
5861
- const cached = qrCache.get(key);
5862
- if (cached?.svgString) {
5863
- containerRef.current.innerHTML = cached.svgString;
5864
- setIsReady(true);
5865
- return;
5866
- }
5867
- if (imageUrl) {
5868
- await preloadImageAsync(imageUrl);
5869
- }
5870
5977
  const config = createQRConfig(value, size, imageUrl, imageSize, darkMode);
5871
- const qrInstance = new import_qr_code_styling.default(config);
5872
- qrInstance.append(containerRef.current);
5873
- const svgString = await waitForStyledQR(containerRef.current);
5874
- if (svgString) {
5875
- qrCache.set(key, { svgString });
5978
+ if (!qrRef.current) {
5979
+ qrRef.current = new import_qr_code_styling.default(config);
5980
+ qrRef.current.append(containerRef.current);
5981
+ } else {
5982
+ qrRef.current.update(config);
5876
5983
  }
5877
- setIsReady(true);
5878
5984
  }, [value, size, imageUrl, imageSize, darkMode]);
5879
- (0, import_react10.useEffect)(() => {
5880
- let mounted = true;
5881
- const init = async () => {
5882
- if (!mounted) return;
5883
- await renderQR();
5884
- };
5885
- setIsReady(false);
5886
- init();
5887
- return () => {
5888
- mounted = false;
5889
- };
5890
- }, [renderQR]);
5891
- const showSkeleton = !isReady && !cachedEntry?.svgString;
5892
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
5985
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5893
5986
  "div",
5894
5987
  {
5988
+ ref: containerRef,
5895
5989
  style: {
5896
5990
  width: size,
5897
5991
  height: size,
5898
5992
  display: "flex",
5899
5993
  alignItems: "center",
5900
- justifyContent: "center",
5901
- position: "relative"
5902
- },
5903
- children: [
5904
- showSkeleton && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5905
- "div",
5906
- {
5907
- style: {
5908
- position: "absolute",
5909
- inset: 0,
5910
- display: "flex",
5911
- alignItems: "center",
5912
- justifyContent: "center",
5913
- background: darkMode ? "linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%)" : "linear-gradient(135deg, #f0f0f0 0%, #e0e0e0 100%)",
5914
- borderRadius: 8,
5915
- animation: "uf-qr-pulse 1.5s ease-in-out infinite"
5916
- },
5917
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5918
- "div",
5919
- {
5920
- style: {
5921
- width: size * 0.6,
5922
- height: size * 0.6,
5923
- background: darkMode ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.05)",
5924
- borderRadius: 4
5925
- }
5926
- }
5927
- )
5928
- }
5929
- ),
5930
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5931
- "div",
5932
- {
5933
- ref: containerRef,
5934
- style: {
5935
- width: size,
5936
- height: size,
5937
- opacity: isReady ? 1 : 0,
5938
- transition: "opacity 0.15s ease-out"
5939
- }
5940
- }
5941
- ),
5942
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("style", { children: `
5943
- @keyframes uf-qr-pulse {
5944
- 0%, 100% { opacity: 1; }
5945
- 50% { opacity: 0.6; }
5946
- }
5947
- ` })
5948
- ]
5994
+ justifyContent: "center"
5995
+ }
5949
5996
  }
5950
5997
  );
5951
5998
  }
@@ -5962,7 +6009,8 @@ var COMMON_TOKENS = [
5962
6009
  { symbol: "USDC", chainType: "solana", chainId: "mainnet" },
5963
6010
  { symbol: "POL", chainType: "ethereum", chainId: "137" },
5964
6011
  { symbol: "BNB", chainType: "ethereum", chainId: "56" },
5965
- { symbol: "BTC", chainType: "bitcoin", chainId: "mainnet" }
6012
+ { symbol: "BTC", chainType: "bitcoin", chainId: "mainnet" },
6013
+ { symbol: "XRP", chainType: "xrpl", chainId: "mainnet" }
5966
6014
  ];
5967
6015
  function getRecentTokens() {
5968
6016
  if (typeof window === "undefined") return [];
@@ -6411,50 +6459,34 @@ function TokenSelectorSheet({
6411
6459
  );
6412
6460
  }
6413
6461
 
6414
- // src/components/deposits/shared/PollCooldownButton.tsx
6415
- var import_core15 = require("@unifold/core");
6462
+ // src/components/deposits/DepositPollingUi.tsx
6416
6463
  var import_jsx_runtime33 = require("react/jsx-runtime");
6417
- function PollCooldownButton({
6418
- currentWalletId,
6419
- pollCooldown,
6420
- publishableKey,
6421
- onCooldownChange,
6422
- cooldownRef,
6423
- buttonText = "Check again"
6464
+ function DepositPollingUi({
6465
+ depositConfirmationMode,
6466
+ showWaitingUi,
6467
+ hasExecution,
6468
+ onIveDeposited
6424
6469
  }) {
6425
- const handleClick = async () => {
6426
- if (!currentWalletId || pollCooldown > 0) return;
6427
- try {
6428
- await (0, import_core15.pollDirectExecutions)(
6429
- { deposit_wallet_id: currentWalletId },
6430
- publishableKey
6431
- );
6432
- const cooldownSeconds = 5;
6433
- onCooldownChange(cooldownSeconds);
6434
- if (cooldownRef.current) clearInterval(cooldownRef.current);
6435
- cooldownRef.current = setInterval(() => {
6436
- onCooldownChange((prev) => {
6437
- if (prev <= 1) {
6438
- if (cooldownRef.current) clearInterval(cooldownRef.current);
6439
- cooldownRef.current = null;
6440
- return 0;
6441
- }
6442
- return prev - 1;
6443
- });
6444
- }, 1e3);
6445
- } catch (error) {
6446
- console.error("Failed to start poll workflow:", error);
6447
- }
6448
- };
6449
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6450
- "button",
6451
- {
6452
- onClick: handleClick,
6453
- disabled: !currentWalletId || pollCooldown > 0,
6454
- className: "uf-w-full uf-rounded-xl uf-py-2.5 uf-px-2 uf-flex uf-items-center uf-gap-3 uf-justify-center uf-text-center uf-text-sm uf-bg-primary hover:uf-bg-primary/80 uf-transition-colors uf-text-left disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
6455
- children: pollCooldown > 0 ? `${buttonText} in ${pollCooldown}s` : "I've made the deposit"
6456
- }
6457
- ) });
6470
+ if (depositConfirmationMode === "manual" && !showWaitingUi) {
6471
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6472
+ "button",
6473
+ {
6474
+ onClick: onIveDeposited,
6475
+ className: "uf-w-full uf-rounded-xl uf-py-2.5 uf-px-2 uf-flex uf-items-center uf-justify-center uf-text-sm uf-bg-primary hover:uf-bg-primary/80 uf-transition-colors",
6476
+ children: "I've made the deposit"
6477
+ }
6478
+ );
6479
+ }
6480
+ if (showWaitingUi && !hasExecution) {
6481
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-gap-3 uf-animate-in uf-fade-in uf-duration-500", children: [
6482
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "uf-flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "uf-w-9 uf-h-9 uf-rounded-full uf-border-2 uf-border-t-primary uf-border-primary/20 uf-animate-spin" }) }),
6483
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { children: [
6484
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "uf-text-sm uf-font-medium uf-text-foreground", children: "Processing deposit transactions" }),
6485
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "uf-text-xs uf-text-muted-foreground", children: "We're checking if your deposit has landed." })
6486
+ ] })
6487
+ ] });
6488
+ }
6489
+ return null;
6458
6490
  }
6459
6491
 
6460
6492
  // src/components/deposits/shared/DepositFooterLinks.tsx
@@ -6650,6 +6682,7 @@ function TransferCryptoSingleInput({
6650
6682
  destinationChainType,
6651
6683
  destinationChainId,
6652
6684
  destinationTokenAddress,
6685
+ depositConfirmationMode = "auto_ui",
6653
6686
  onExecutionsChange,
6654
6687
  onDepositSuccess,
6655
6688
  onDepositError,
@@ -6662,20 +6695,10 @@ function TransferCryptoSingleInput({
6662
6695
  const [copied, setCopied] = (0, import_react13.useState)(false);
6663
6696
  const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
6664
6697
  const [glossaryOpen, setGlossaryOpen] = (0, import_react13.useState)(false);
6665
- const [pollCooldown, setPollCooldown] = (0, import_react13.useState)(0);
6666
- const cooldownRef = (0, import_react13.useRef)(null);
6667
6698
  const [detailsExpanded, setDetailsExpanded] = (0, import_react13.useState)(false);
6668
6699
  const [depositsModalOpen, setDepositsModalOpen] = (0, import_react13.useState)(false);
6669
6700
  const [tokenSelectorOpen, setTokenSelectorOpen] = (0, import_react13.useState)(false);
6670
6701
  const [initialSelectionDone, setInitialSelectionDone] = (0, import_react13.useState)(false);
6671
- (0, import_react13.useEffect)(() => {
6672
- return () => {
6673
- if (cooldownRef.current) {
6674
- clearInterval(cooldownRef.current);
6675
- cooldownRef.current = null;
6676
- }
6677
- };
6678
- }, []);
6679
6702
  const {
6680
6703
  data: tokensResponse,
6681
6704
  isLoading: tokensLoading
@@ -6702,13 +6725,6 @@ function TransferCryptoSingleInput({
6702
6725
  const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
6703
6726
  const loading = externalWallets?.length ? false : walletsLoading;
6704
6727
  const error = walletsError?.message ?? null;
6705
- const { executions: depositExecutions, isPolling } = useDepositPolling({
6706
- userId,
6707
- publishableKey,
6708
- enabled: true,
6709
- onDepositSuccess,
6710
- onDepositError
6711
- });
6712
6728
  const allAvailableChains = (0, import_react13.useMemo)(() => {
6713
6729
  const chainsMap = /* @__PURE__ */ new Map();
6714
6730
  supportedTokens.forEach((t6) => {
@@ -6728,6 +6744,15 @@ function TransferCryptoSingleInput({
6728
6744
  const currentChainType = currentChainData?.chain_type || "ethereum";
6729
6745
  const currentWallet = (0, import_core16.getWalletByChainType)(wallets, currentChainType);
6730
6746
  const depositAddress = currentWallet?.address || "";
6747
+ const { executions: depositExecutions, isPolling, showWaitingUi, handleIveDeposited } = useDepositPolling({
6748
+ userId,
6749
+ publishableKey,
6750
+ depositConfirmationMode,
6751
+ depositWalletId: currentWallet?.id,
6752
+ enabled: true,
6753
+ onDepositSuccess,
6754
+ onDepositError
6755
+ });
6731
6756
  (0, import_react13.useEffect)(() => {
6732
6757
  if (!supportedTokens.length || initialSelectionDone) return;
6733
6758
  let selectedTokenData;
@@ -6777,28 +6802,6 @@ function TransferCryptoSingleInput({
6777
6802
  onExecutionsChange(depositExecutions);
6778
6803
  }
6779
6804
  }, [depositExecutions, onExecutionsChange]);
6780
- (0, import_react13.useEffect)(() => {
6781
- if (!wallets.length || !allAvailableChains.length) return;
6782
- const preloadAllQRCodes = async () => {
6783
- for (const wallet of wallets) {
6784
- if (!wallet.address) continue;
6785
- const chainData = allAvailableChains.find(
6786
- (c) => c.chain_type === wallet.chain_type
6787
- );
6788
- const chainIconUrl = chainData?.icon_url;
6789
- await preloadQRCode(
6790
- wallet.address,
6791
- 180,
6792
- // size
6793
- chainIconUrl,
6794
- 45,
6795
- // imageSize
6796
- isDarkMode
6797
- );
6798
- }
6799
- };
6800
- preloadAllQRCodes();
6801
- }, [wallets, allAvailableChains, isDarkMode]);
6802
6805
  (0, import_react13.useEffect)(() => {
6803
6806
  if (!supportedTokens.length) return;
6804
6807
  const currentToken = supportedTokens.find((t6) => t6.symbol === token);
@@ -7071,14 +7074,12 @@ function TransferCryptoSingleInput({
7071
7074
  ] })
7072
7075
  ] }),
7073
7076
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
7074
- PollCooldownButton,
7077
+ DepositPollingUi,
7075
7078
  {
7076
- currentWalletId: currentWallet?.id,
7077
- pollCooldown,
7078
- publishableKey,
7079
- onCooldownChange: setPollCooldown,
7080
- cooldownRef,
7081
- buttonText: "Try again"
7079
+ depositConfirmationMode,
7080
+ showWaitingUi,
7081
+ hasExecution: depositExecutions.length > 0,
7082
+ onIveDeposited: handleIveDeposited
7082
7083
  }
7083
7084
  ),
7084
7085
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) }),
@@ -7271,6 +7272,7 @@ function TransferCryptoDoubleInput({
7271
7272
  destinationChainType,
7272
7273
  destinationChainId,
7273
7274
  destinationTokenAddress,
7275
+ depositConfirmationMode = "auto_ui",
7274
7276
  onExecutionsChange,
7275
7277
  onDepositSuccess,
7276
7278
  onDepositError,
@@ -7283,19 +7285,9 @@ function TransferCryptoDoubleInput({
7283
7285
  const [copied, setCopied] = (0, import_react14.useState)(false);
7284
7286
  const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
7285
7287
  const [glossaryOpen, setGlossaryOpen] = (0, import_react14.useState)(false);
7286
- const [pollCooldown, setPollCooldown] = (0, import_react14.useState)(0);
7287
- const cooldownRef = (0, import_react14.useRef)(null);
7288
7288
  const [detailsExpanded, setDetailsExpanded] = (0, import_react14.useState)(false);
7289
7289
  const [depositsModalOpen, setDepositsModalOpen] = (0, import_react14.useState)(false);
7290
7290
  const [initialSelectionDone, setInitialSelectionDone] = (0, import_react14.useState)(false);
7291
- (0, import_react14.useEffect)(() => {
7292
- return () => {
7293
- if (cooldownRef.current) {
7294
- clearInterval(cooldownRef.current);
7295
- cooldownRef.current = null;
7296
- }
7297
- };
7298
- }, []);
7299
7291
  const {
7300
7292
  data: tokensResponse,
7301
7293
  isLoading: tokensLoading
@@ -7322,13 +7314,6 @@ function TransferCryptoDoubleInput({
7322
7314
  const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
7323
7315
  const loading = externalWallets?.length ? false : walletsLoading;
7324
7316
  const error = walletsError?.message ?? null;
7325
- const { executions: depositExecutions, isPolling } = useDepositPolling({
7326
- userId,
7327
- publishableKey,
7328
- enabled: true,
7329
- onDepositSuccess,
7330
- onDepositError
7331
- });
7332
7317
  const allAvailableChains = (0, import_react14.useMemo)(() => {
7333
7318
  const chainsMap = /* @__PURE__ */ new Map();
7334
7319
  supportedTokens.forEach((t6) => {
@@ -7348,6 +7333,15 @@ function TransferCryptoDoubleInput({
7348
7333
  const currentChainType = currentChainData?.chain_type || "ethereum";
7349
7334
  const currentWallet = (0, import_core17.getWalletByChainType)(wallets, currentChainType);
7350
7335
  const depositAddress = currentWallet?.address || "";
7336
+ const { executions: depositExecutions, isPolling, showWaitingUi, handleIveDeposited } = useDepositPolling({
7337
+ userId,
7338
+ publishableKey,
7339
+ depositConfirmationMode,
7340
+ depositWalletId: currentWallet?.id,
7341
+ enabled: true,
7342
+ onDepositSuccess,
7343
+ onDepositError
7344
+ });
7351
7345
  (0, import_react14.useEffect)(() => {
7352
7346
  if (!supportedTokens.length || initialSelectionDone) return;
7353
7347
  const allChains = /* @__PURE__ */ new Set();
@@ -7370,28 +7364,6 @@ function TransferCryptoDoubleInput({
7370
7364
  onExecutionsChange(depositExecutions);
7371
7365
  }
7372
7366
  }, [depositExecutions, onExecutionsChange]);
7373
- (0, import_react14.useEffect)(() => {
7374
- if (!wallets.length || !allAvailableChains.length) return;
7375
- const preloadAllQRCodes = async () => {
7376
- for (const wallet of wallets) {
7377
- if (!wallet.address) continue;
7378
- const chainData = allAvailableChains.find(
7379
- (c) => c.chain_type === wallet.chain_type
7380
- );
7381
- const chainIconUrl = chainData?.icon_url;
7382
- await preloadQRCode(
7383
- wallet.address,
7384
- 180,
7385
- // size
7386
- chainIconUrl,
7387
- 45,
7388
- // imageSize
7389
- isDarkMode
7390
- );
7391
- }
7392
- };
7393
- preloadAllQRCodes();
7394
- }, [wallets, allAvailableChains, isDarkMode]);
7395
7367
  (0, import_react14.useEffect)(() => {
7396
7368
  if (!supportedTokens.length) return;
7397
7369
  const currentToken = supportedTokens.find((t6) => t6.symbol === token);
@@ -7698,14 +7670,12 @@ function TransferCryptoDoubleInput({
7698
7670
  ] })
7699
7671
  ] }),
7700
7672
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7701
- PollCooldownButton,
7673
+ DepositPollingUi,
7702
7674
  {
7703
- currentWalletId: currentWallet?.id,
7704
- pollCooldown,
7705
- publishableKey,
7706
- onCooldownChange: setPollCooldown,
7707
- cooldownRef,
7708
- buttonText: "Check again"
7675
+ depositConfirmationMode,
7676
+ showWaitingUi,
7677
+ hasExecution: depositExecutions.length > 0,
7678
+ onIveDeposited: handleIveDeposited
7709
7679
  }
7710
7680
  ),
7711
7681
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) }),
@@ -7759,110 +7729,10 @@ function TransferCryptoDoubleInput({
7759
7729
  var React24 = __toESM(require("react"));
7760
7730
  var import_core18 = require("@unifold/core");
7761
7731
 
7762
- // src/components/deposits/browser-wallets/utils.ts
7763
- function getIconUrl4(iconUrl, assetCdnUrl) {
7764
- if (!iconUrl) return void 0;
7765
- if (iconUrl.startsWith("http://") || iconUrl.startsWith("https://")) {
7766
- return iconUrl;
7767
- }
7768
- if (assetCdnUrl) {
7769
- return `${assetCdnUrl}${iconUrl.startsWith("/") ? "" : "/"}${iconUrl}`;
7770
- }
7771
- return iconUrl;
7772
- }
7773
- function getTokenFromBalance(balance) {
7774
- if (balance.token) {
7775
- return balance.token;
7776
- }
7777
- const legacyBalance = balance;
7778
- if (legacyBalance.symbol && legacyBalance.decimals !== void 0) {
7779
- return {
7780
- symbol: legacyBalance.symbol,
7781
- name: legacyBalance.name,
7782
- icon_url: legacyBalance.icon_url,
7783
- icon_urls: [],
7784
- token_address: legacyBalance.token_address,
7785
- chain_id: legacyBalance.chain_id,
7786
- chain_name: legacyBalance.chain_name,
7787
- chain_type: legacyBalance.chain_type,
7788
- decimals: legacyBalance.decimals,
7789
- chain_icon_url: legacyBalance.chain_icon_url,
7790
- chain_icon_urls: [],
7791
- minimum_deposit_amount_usd: 0
7792
- };
7793
- }
7794
- return null;
7795
- }
7796
- function isBalanceEligible(balance) {
7797
- if (balance.is_eligible !== void 0) {
7798
- return balance.is_eligible;
7799
- }
7800
- const legacyBalance = balance;
7801
- if (legacyBalance.is_eligible !== void 0) {
7802
- return legacyBalance.is_eligible;
7803
- }
7804
- return true;
7805
- }
7806
- function formatTokenAmount(amount, decimals, symbol) {
7807
- const value = Number(amount) / 10 ** decimals;
7808
- const upperSymbol = symbol.toUpperCase();
7809
- let maxDecimals = 4;
7810
- if (upperSymbol === "BTC" || upperSymbol === "WBTC") {
7811
- maxDecimals = 8;
7812
- } else if (upperSymbol === "ETH" || upperSymbol === "WETH" || upperSymbol === "SOL") {
7813
- maxDecimals = 6;
7814
- }
7815
- if (value >= 1) {
7816
- return value.toLocaleString(void 0, {
7817
- minimumFractionDigits: 2,
7818
- maximumFractionDigits: maxDecimals
7819
- });
7820
- } else if (value > 0) {
7821
- return value.toLocaleString(void 0, {
7822
- minimumFractionDigits: 2,
7823
- maximumFractionDigits: maxDecimals,
7824
- minimumSignificantDigits: 2,
7825
- maximumSignificantDigits: 6
7826
- });
7827
- }
7828
- return "0.00";
7829
- }
7830
- function formatUsdAmount(amountUsd) {
7831
- if (!amountUsd) return null;
7832
- const value = parseFloat(amountUsd);
7833
- if (value <= 0) return null;
7834
- return value.toLocaleString(void 0, {
7835
- minimumFractionDigits: 2,
7836
- maximumFractionDigits: 2
7837
- });
7838
- }
7839
- function truncateAddress3(address) {
7840
- if (address.length <= 13) return address;
7841
- return `${address.slice(0, 6)}...${address.slice(-4)}`;
7842
- }
7843
- function formatBalanceDisplay(balance, projectName) {
7844
- return projectName ? `${projectName} Balance: ${balance}` : `Balance: ${balance}`;
7845
- }
7846
- function formatProcessingTime(seconds) {
7847
- if (seconds === null || seconds === 0) {
7848
- return "< 1 min";
7849
- }
7850
- const minutes = Math.floor(seconds / 60);
7851
- const remainingSeconds = seconds % 60;
7852
- if (minutes === 0) {
7853
- return `< ${remainingSeconds} sec`;
7854
- } else if (remainingSeconds === 0) {
7855
- return `< ${minutes} min`;
7856
- } else {
7857
- return `< ${minutes} min ${remainingSeconds} sec`;
7858
- }
7859
- }
7860
-
7861
7732
  // src/components/deposits/browser-wallets/SelectTokenView.tsx
7862
7733
  var import_lucide_react17 = require("lucide-react");
7863
7734
  var import_jsx_runtime40 = require("react/jsx-runtime");
7864
7735
  function SelectTokenView({
7865
- walletInfo,
7866
7736
  projectName,
7867
7737
  assetCdnUrl,
7868
7738
  balances,
@@ -7881,27 +7751,12 @@ function SelectTokenView({
7881
7751
  DepositHeader,
7882
7752
  {
7883
7753
  title: "Select Token",
7754
+ subtitle: formatBalanceDisplay(`$${totalBalanceUsd || "0.00"}`, projectName),
7884
7755
  showBack: true,
7885
7756
  onBack,
7886
7757
  onClose
7887
7758
  }
7888
7759
  ),
7889
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
7890
- "div",
7891
- {
7892
- className: "uf-flex uf-flex-col uf-w-full uf-items-center uf-pb-3",
7893
- style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
7894
- children: [
7895
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "uf-text-xs", children: [
7896
- walletInfo.name,
7897
- " (",
7898
- truncateAddress3(walletInfo.address),
7899
- ")"
7900
- ] }),
7901
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uf-text-xs", children: formatBalanceDisplay(`$${totalBalanceUsd || "0.00"}`, projectName) })
7902
- ]
7903
- }
7904
- ),
7905
7760
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uf-h-[300px] uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uf-space-y-2", children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-12", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7906
7761
  import_lucide_react17.Loader2,
7907
7762
  {
@@ -7912,6 +7767,7 @@ function SelectTokenView({
7912
7767
  const token = getTokenFromBalance(balance);
7913
7768
  if (!token) return null;
7914
7769
  const isEligible = isBalanceEligible(balance);
7770
+ const ineligibilityMessage = getIneligibilityMessage(balance);
7915
7771
  const isSelected = selectedBalance && getTokenFromBalance(selectedBalance)?.token_address === token.token_address && getTokenFromBalance(selectedBalance)?.chain_id === token.chain_id;
7916
7772
  const formattedAmount = formatTokenAmount(balance.amount, token.decimals, token.symbol);
7917
7773
  const formattedUsd = formatUsdAmount(balance.amount_usd);
@@ -7929,10 +7785,10 @@ function SelectTokenView({
7929
7785
  children: [
7930
7786
  /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
7931
7787
  /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "uf-relative uf-w-9 uf-h-9", children: [
7932
- getIconUrl4(token.icon_url, assetCdnUrl) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7788
+ getIconUrl(token.icon_url, assetCdnUrl) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7933
7789
  "img",
7934
7790
  {
7935
- src: getIconUrl4(token.icon_url, assetCdnUrl),
7791
+ src: getIconUrl(token.icon_url, assetCdnUrl),
7936
7792
  alt: token.symbol,
7937
7793
  width: 36,
7938
7794
  height: 36,
@@ -7947,10 +7803,10 @@ function SelectTokenView({
7947
7803
  children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "uf-text-xs uf-font-medium", style: { color: colors2.foreground }, children: token.symbol.slice(0, 2) })
7948
7804
  }
7949
7805
  ),
7950
- getIconUrl4(token.chain_icon_url, assetCdnUrl) && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7806
+ getIconUrl(token.chain_icon_url, assetCdnUrl) && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7951
7807
  "img",
7952
7808
  {
7953
- src: getIconUrl4(token.chain_icon_url, assetCdnUrl),
7809
+ src: getIconUrl(token.chain_icon_url, assetCdnUrl),
7954
7810
  alt: token.chain_name,
7955
7811
  width: 16,
7956
7812
  height: 16,
@@ -7981,7 +7837,7 @@ function SelectTokenView({
7981
7837
  style: { color: components.card.subtitleColor, fontFamily: fonts.regular },
7982
7838
  children: [
7983
7839
  token.chain_name,
7984
- !isEligible && " \u2022 Minimum not met"
7840
+ ineligibilityMessage && ` \u2022 ${ineligibilityMessage}`
7985
7841
  ]
7986
7842
  }
7987
7843
  )
@@ -8040,8 +7896,6 @@ function SelectTokenView({
8040
7896
  // src/components/deposits/browser-wallets/EnterAmountView.tsx
8041
7897
  var import_jsx_runtime41 = require("react/jsx-runtime");
8042
7898
  function EnterAmountView({
8043
- walletInfo,
8044
- projectName,
8045
7899
  selectedBalance,
8046
7900
  selectedToken,
8047
7901
  amountUsd,
@@ -8058,54 +7912,20 @@ function EnterAmountView({
8058
7912
  onClose
8059
7913
  }) {
8060
7914
  const { colors: colors2, fonts, components } = useTheme();
8061
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex uf-flex-col uf-h-[420px]", children: [
7915
+ const balanceSubtitle = selectedBalance?.amount_usd ? `Balance: $${parseFloat(selectedBalance.amount_usd).toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (${formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol)} ${selectedToken.symbol})` : `Balance: ${formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol)} ${selectedToken.symbol}`;
7916
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
8062
7917
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8063
7918
  DepositHeader,
8064
7919
  {
8065
7920
  title: "Enter Amount",
7921
+ subtitle: balanceSubtitle,
8066
7922
  showBack: true,
8067
7923
  onBack,
8068
7924
  onClose
8069
7925
  }
8070
7926
  ),
8071
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-text-center uf-pb-2", children: [
8072
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8073
- "div",
8074
- {
8075
- className: "uf-text-xs",
8076
- style: { color: colors2.foreground, fontFamily: fonts.regular },
8077
- children: [
8078
- walletInfo.name,
8079
- " (",
8080
- truncateAddress3(walletInfo.address),
8081
- ")"
8082
- ]
8083
- }
8084
- ),
8085
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8086
- "div",
8087
- {
8088
- className: "uf-text-sm uf-mt-1",
8089
- style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
8090
- children: selectedBalance?.amount_usd ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
8091
- "Balance: $",
8092
- parseFloat(selectedBalance.amount_usd).toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
8093
- " (",
8094
- formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol),
8095
- " ",
8096
- selectedToken.symbol,
8097
- ")"
8098
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
8099
- "Balance: ",
8100
- formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol),
8101
- " ",
8102
- selectedToken.symbol
8103
- ] })
8104
- }
8105
- )
8106
- ] }),
8107
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex-1 uf-overflow-y-auto", children: [
8108
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-text-center uf-h-[100px] uf-flex uf-flex-col uf-justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-center", children: [
7927
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-text-center uf-py-6", children: [
7928
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-center", children: [
8109
7929
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8110
7930
  "span",
8111
7931
  {
@@ -8141,60 +7961,57 @@ function EnterAmountView({
8141
7961
  }
8142
7962
  }
8143
7963
  )
8144
- ] }) }),
8145
- formattedTokenAmount && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-text-sm uf-text-center", style: { color: colors2.foregroundMuted }, children: [
7964
+ ] }),
7965
+ formattedTokenAmount && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-text-sm uf-mt-2", style: { color: colors2.foregroundMuted }, children: [
8146
7966
  "\u2248 ",
8147
7967
  formattedTokenAmount
8148
- ] }),
8149
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex uf-gap-2 uf-mt-4 uf-mb-4", children: [
8150
- [25, 50, 100, 500].map((quickAmount) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8151
- "button",
8152
- {
8153
- onClick: () => onAmountChange(quickAmount.toString()),
8154
- className: "uf-flex-1 uf-py-2 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-colors hover:uf-opacity-80",
8155
- style: {
8156
- backgroundColor: components.card.backgroundColor,
8157
- color: colors2.foreground,
8158
- fontFamily: fonts.medium
8159
- },
8160
- children: [
8161
- "$",
8162
- quickAmount
8163
- ]
8164
- },
8165
- quickAmount
8166
- )),
8167
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8168
- "button",
8169
- {
8170
- onClick: onMaxClick,
8171
- className: "uf-flex-1 uf-py-2 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-colors hover:uf-opacity-80",
8172
- style: {
8173
- backgroundColor: colors2.primary + "20",
8174
- color: colors2.primary,
8175
- fontFamily: fonts.medium
8176
- },
8177
- children: "MAX"
8178
- }
8179
- )
8180
- ] }),
8181
- tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8182
- "div",
7968
+ ] })
7969
+ ] }),
7970
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex uf-gap-2 uf-mb-4", children: [
7971
+ [25, 50, 100, 500].map((quickAmount) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7972
+ "button",
8183
7973
  {
8184
- className: "uf-text-center uf-text-xs uf-mb-2",
7974
+ onClick: () => onAmountChange(quickAmount.toString()),
7975
+ className: "uf-flex-1 uf-py-2 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-colors hover:uf-opacity-80",
8185
7976
  style: {
8186
- color: colors2.warning,
8187
- fontFamily: fonts.regular
7977
+ backgroundColor: components.card.backgroundColor,
7978
+ color: colors2.foreground,
7979
+ fontFamily: fonts.medium
8188
7980
  },
8189
7981
  children: [
8190
- "Minimum deposit: $",
8191
- tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
7982
+ "$",
7983
+ quickAmount
8192
7984
  ]
7985
+ },
7986
+ quickAmount
7987
+ )),
7988
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7989
+ "button",
7990
+ {
7991
+ onClick: onMaxClick,
7992
+ className: "uf-flex-1 uf-py-2 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-colors hover:uf-opacity-80",
7993
+ style: {
7994
+ backgroundColor: colors2.primary + "20",
7995
+ color: colors2.primary,
7996
+ fontFamily: fonts.medium
7997
+ },
7998
+ children: "MAX"
8193
7999
  }
8194
- ),
8195
- inputUsdNum > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_jsx_runtime41.Fragment, { children: inputUsdNum > maxUsdAmount ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-text-center uf-text-sm uf-mb-2", style: { color: colors2.error }, children: "Insufficient balance" }) : error && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-text-center uf-text-sm uf-mb-2 uf-px-2", style: { color: colors2.error }, children: error }) })
8000
+ )
8196
8001
  ] }),
8197
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8002
+ tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8003
+ "div",
8004
+ {
8005
+ className: "uf-text-center uf-text-xs uf-mb-3",
8006
+ style: { color: colors2.warning, fontFamily: fonts.regular },
8007
+ children: [
8008
+ "Minimum deposit: $",
8009
+ tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
8010
+ ]
8011
+ }
8012
+ ),
8013
+ inputUsdNum > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_jsx_runtime41.Fragment, { children: inputUsdNum > maxUsdAmount ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-text-center uf-text-sm uf-mb-3", style: { color: colors2.error }, children: "Insufficient balance" }) : error && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-text-center uf-text-sm uf-mb-3 uf-px-2", style: { color: colors2.error }, children: error }) }),
8014
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8198
8015
  "button",
8199
8016
  {
8200
8017
  onClick: onReview,
@@ -8207,7 +8024,7 @@ function EnterAmountView({
8207
8024
  },
8208
8025
  children: "Review"
8209
8026
  }
8210
- ) })
8027
+ )
8211
8028
  ] });
8212
8029
  }
8213
8030
 
@@ -8275,10 +8092,10 @@ function ReviewView({
8275
8092
  }
8276
8093
  ),
8277
8094
  /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
8278
- getIconUrl4(selectedToken.icon_url, assetCdnUrl) && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8095
+ getIconUrl(selectedToken.icon_url, assetCdnUrl) && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
8279
8096
  "img",
8280
8097
  {
8281
- src: getIconUrl4(selectedToken.icon_url, assetCdnUrl),
8098
+ src: getIconUrl(selectedToken.icon_url, assetCdnUrl),
8282
8099
  alt: selectedToken.symbol,
8283
8100
  className: "uf-w-5 uf-h-5 uf-rounded-full"
8284
8101
  }
@@ -8291,7 +8108,7 @@ function ReviewView({
8291
8108
  children: [
8292
8109
  walletInfo.name,
8293
8110
  " (",
8294
- truncateAddress3(walletInfo.address),
8111
+ truncateAddress2(walletInfo.address),
8295
8112
  ")"
8296
8113
  ]
8297
8114
  }
@@ -8312,7 +8129,7 @@ function ReviewView({
8312
8129
  {
8313
8130
  className: "uf-text-sm uf-font-medium",
8314
8131
  style: { color: colors2.foreground, fontFamily: fonts.medium },
8315
- children: truncateAddress3(recipientAddress)
8132
+ children: truncateAddress2(recipientAddress)
8316
8133
  }
8317
8134
  )
8318
8135
  ] }),
@@ -8516,7 +8333,7 @@ function BrowserWalletModal({
8516
8333
  const themeClass = theme === "dark" ? "uf-dark" : "";
8517
8334
  const chainType = depositWallet.chain_type;
8518
8335
  const recipientAddress = depositWallet.address;
8519
- const supportedChainType = chainType === "algorand" ? "ethereum" : chainType;
8336
+ const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
8520
8337
  const { executions: depositExecutions, isPolling } = useDepositPolling({
8521
8338
  userId,
8522
8339
  publishableKey,
@@ -8927,20 +8744,6 @@ function BrowserWalletModal({
8927
8744
  if (tokenAmount === 0 || !selectedToken) return null;
8928
8745
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(/\.?0+$/, "");
8929
8746
  }, [tokenAmount, selectedToken]);
8930
- const getTitle = () => {
8931
- switch (step) {
8932
- case "select-token":
8933
- return "Select Token";
8934
- case "input-amount":
8935
- return "Enter Amount";
8936
- case "review":
8937
- return "Review";
8938
- case "confirming":
8939
- return "Confirming...";
8940
- default:
8941
- return "Browser Wallet";
8942
- }
8943
- };
8944
8747
  return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_jsx_runtime44.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8945
8748
  Dialog,
8946
8749
  {
@@ -8962,7 +8765,6 @@ function BrowserWalletModal({
8962
8765
  step === "select-token" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8963
8766
  SelectTokenView,
8964
8767
  {
8965
- walletInfo,
8966
8768
  projectName,
8967
8769
  assetCdnUrl,
8968
8770
  balances,
@@ -8979,8 +8781,6 @@ function BrowserWalletModal({
8979
8781
  step === "input-amount" && selectedToken && selectedBalance && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
8980
8782
  EnterAmountView,
8981
8783
  {
8982
- walletInfo,
8983
- projectName,
8984
8784
  selectedBalance,
8985
8785
  selectedToken,
8986
8786
  amountUsd,
@@ -9332,6 +9132,7 @@ function WalletSelectionModal({
9332
9132
  if (!accounts || accounts.length === 0) {
9333
9133
  throw new Error("No accounts returned from wallet");
9334
9134
  }
9135
+ setUserDisconnectedWallet(false);
9335
9136
  const address = accounts[0];
9336
9137
  const walletType = wallet.id === "phantom" ? "phantom-ethereum" : wallet.id === "coinbase" ? "coinbase" : "metamask";
9337
9138
  onWalletConnected({
@@ -9371,6 +9172,7 @@ function WalletSelectionModal({
9371
9172
  }
9372
9173
  const response = await provider.connect();
9373
9174
  const address = response.publicKey.toString();
9175
+ setUserDisconnectedWallet(false);
9374
9176
  const walletType = wallet.id === "solflare" ? "solflare" : wallet.id === "backpack" ? "backpack" : wallet.id === "glow" ? "glow" : "phantom-solana";
9375
9177
  onWalletConnected({
9376
9178
  type: walletType,
@@ -9678,6 +9480,7 @@ function DepositModal({
9678
9480
  hideDepositTracker = false,
9679
9481
  showBalanceHeader = false,
9680
9482
  transferInputVariant = "double_input",
9483
+ depositConfirmationMode = "auto_ui",
9681
9484
  enableConnectWallet = false,
9682
9485
  onDepositSuccess,
9683
9486
  onDepositError,
@@ -9769,6 +9572,7 @@ function DepositModal({
9769
9572
  };
9770
9573
  const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
9771
9574
  const handleWalletDisconnect = () => {
9575
+ setUserDisconnectedWallet(true);
9772
9576
  clearStoredWalletChainType();
9773
9577
  setBrowserWalletChainType(void 0);
9774
9578
  setBrowserWalletInfo(null);
@@ -9860,6 +9664,7 @@ function DepositModal({
9860
9664
  balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
9861
9665
  balanceChainId: destinationChainId,
9862
9666
  balanceTokenAddress: destinationTokenAddress,
9667
+ projectName: projectConfig?.project_name,
9863
9668
  publishableKey
9864
9669
  }
9865
9670
  ),
@@ -9940,7 +9745,14 @@ function DepositModal({
9940
9745
  title: t5.transferCrypto.title,
9941
9746
  showBack: true,
9942
9747
  onBack: handleBack,
9943
- onClose: handleClose
9748
+ onClose: handleClose,
9749
+ showBalance: showBalanceHeader,
9750
+ balanceAddress: recipientAddress,
9751
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
9752
+ balanceChainId: destinationChainId,
9753
+ balanceTokenAddress: destinationTokenAddress,
9754
+ projectName: projectConfig?.project_name,
9755
+ publishableKey
9944
9756
  }
9945
9757
  ),
9946
9758
  transferInputVariant === "single_input" ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
@@ -9952,6 +9764,7 @@ function DepositModal({
9952
9764
  destinationChainType,
9953
9765
  destinationChainId,
9954
9766
  destinationTokenAddress,
9767
+ depositConfirmationMode,
9955
9768
  onExecutionsChange: setDepositExecutions,
9956
9769
  onDepositSuccess,
9957
9770
  onDepositError,
@@ -9966,6 +9779,7 @@ function DepositModal({
9966
9779
  destinationChainType,
9967
9780
  destinationChainId,
9968
9781
  destinationTokenAddress,
9782
+ depositConfirmationMode,
9969
9783
  onExecutionsChange: setDepositExecutions,
9970
9784
  onDepositSuccess,
9971
9785
  onDepositError,
@@ -9980,7 +9794,14 @@ function DepositModal({
9980
9794
  showBack: true,
9981
9795
  onBack: handleBack,
9982
9796
  onClose: handleClose,
9983
- badge: cardView === "quotes" ? { count: quotesCount } : void 0
9797
+ badge: cardView === "quotes" ? { count: quotesCount } : void 0,
9798
+ showBalance: showBalanceHeader,
9799
+ balanceAddress: recipientAddress,
9800
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
9801
+ balanceChainId: destinationChainId,
9802
+ balanceTokenAddress: destinationTokenAddress,
9803
+ projectName: projectConfig?.project_name,
9804
+ publishableKey
9984
9805
  }
9985
9806
  ),
9986
9807
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
@@ -10131,6 +9952,7 @@ Button.displayName = "Button";
10131
9952
  DepositExecutionItem,
10132
9953
  DepositHeader,
10133
9954
  DepositModal,
9955
+ DepositPollingUi,
10134
9956
  DepositSuccessToast,
10135
9957
  DepositTrackerButton,
10136
9958
  DepositWithCardButton,
@@ -10165,16 +9987,14 @@ Button.displayName = "Button";
10165
9987
  TransferCryptoDoubleInput,
10166
9988
  TransferCryptoSingleInput,
10167
9989
  buttonVariants,
10168
- clearQRCodeCache,
10169
9990
  cn,
10170
9991
  colors,
10171
9992
  defaultColors,
10172
9993
  getColors,
10173
- isQRCodeCached,
10174
9994
  mergeColors,
10175
- preloadQRCode,
10176
9995
  resolveComponentTokens,
10177
9996
  truncateAddress,
10178
9997
  useAllowedCountry,
9998
+ useDepositPolling,
10179
9999
  useTheme
10180
10000
  });