@unifold/ui-react 0.1.69 → 0.1.70-beta.1

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
@@ -114,6 +114,7 @@ __export(index_exports, {
114
114
  useDepositPolling: () => useDepositPolling,
115
115
  useDepositQuote: () => useDepositQuote,
116
116
  usePaymentIntent: () => usePaymentIntent,
117
+ usePublicIncident: () => usePublicIncident,
117
118
  useSourceTokenValidation: () => useSourceTokenValidation,
118
119
  useSupportedDepositTokens: () => useSupportedDepositTokens,
119
120
  useSupportedDestinationTokens: () => useSupportedDestinationTokens,
@@ -750,7 +751,13 @@ function useDepositAddress(params) {
750
751
  // 24 hours in cache
751
752
  refetchOnMount: false,
752
753
  refetchOnWindowFocus: false,
753
- retry: 3,
754
+ // Don't retry recipient-address validation errors — they're deterministic
755
+ // (a 400 won't succeed on retry) and we want to surface the invalid-address
756
+ // screen immediately rather than after 3 backoff attempts.
757
+ retry: (failureCount, error) => {
758
+ if ((0, import_core.isDepositAddressValidationError)(error)) return false;
759
+ return failureCount < 3;
760
+ },
754
761
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
755
762
  // 1s, 2s, 4s (max 10s)
756
763
  });
@@ -975,7 +982,8 @@ function DepositHeader({
975
982
  balanceChainId,
976
983
  balanceTokenAddress,
977
984
  projectName,
978
- publishableKey
985
+ publishableKey,
986
+ incident
979
987
  }) {
980
988
  const { colors: colors2, fonts, components } = useTheme();
981
989
  const [balance, setBalance] = (0, import_react2.useState)(null);
@@ -1073,19 +1081,64 @@ function DepositHeader({
1073
1081
  balanceTokenAddress,
1074
1082
  publishableKey
1075
1083
  ]);
1076
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
1077
- showBack ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1078
- "button",
1079
- {
1080
- onClick: onBack,
1081
- className: "hover:uf-bg-secondary uf-rounded-lg uf-p-1 uf-transition-colors",
1082
- style: { color: components.header.buttonColor },
1083
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.ArrowLeft, { className: "uf-w-5 uf-h-5" })
1084
- }
1085
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "uf-w-5 uf-h-5 uf-invisible" }),
1086
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center", children: [
1087
- badge ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
1088
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1084
+ const incidentMessages = incident?.messages ?? [];
1085
+ const showIncident = incident?.enabled && incidentMessages.length > 0;
1086
+ const incidentSeverity = incident?.severity ?? "degraded";
1087
+ const incidentSeverityLabel = incidentSeverity === "outage" ? "Outage" : incidentSeverity === "info" ? "Info" : "Degraded service";
1088
+ const incidentStyles = incidentSeverity === "outage" ? {
1089
+ bg: "rgba(239, 68, 68, 0.12)",
1090
+ border: "rgba(239, 68, 68, 0.35)",
1091
+ text: "#fca5a5",
1092
+ link: "#fca5a5"
1093
+ } : incidentSeverity === "info" ? {
1094
+ bg: "rgba(59, 130, 246, 0.12)",
1095
+ border: "rgba(59, 130, 246, 0.35)",
1096
+ text: "#93c5fd",
1097
+ link: "#93c5fd"
1098
+ } : {
1099
+ bg: "rgba(245, 158, 11, 0.12)",
1100
+ border: "rgba(245, 158, 11, 0.35)",
1101
+ text: "#fcd34d",
1102
+ link: "#fcd34d"
1103
+ };
1104
+ const IncidentIcon = incidentSeverity === "info" ? import_lucide_react3.Info : import_lucide_react3.AlertTriangle;
1105
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1106
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-pb-6", children: [
1107
+ showBack ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1108
+ "button",
1109
+ {
1110
+ onClick: onBack,
1111
+ className: "hover:uf-bg-secondary uf-rounded-lg uf-p-1 uf-transition-colors",
1112
+ style: { color: components.header.buttonColor },
1113
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.ArrowLeft, { className: "uf-w-5 uf-h-5" })
1114
+ }
1115
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "uf-w-5 uf-h-5 uf-invisible" }),
1116
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center", children: [
1117
+ badge ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1119
+ DialogTitle,
1120
+ {
1121
+ className: "uf-text-center uf-text-base",
1122
+ style: {
1123
+ color: components.header.titleColor,
1124
+ fontFamily: fonts.medium
1125
+ },
1126
+ children: title
1127
+ }
1128
+ ),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1130
+ "div",
1131
+ {
1132
+ className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
1133
+ style: {
1134
+ backgroundColor: colors2.card,
1135
+ color: colors2.foregroundMuted,
1136
+ fontFamily: fonts.regular
1137
+ },
1138
+ children: badge.count
1139
+ }
1140
+ )
1141
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1089
1142
  DialogTitle,
1090
1143
  {
1091
1144
  className: "uf-text-center uf-text-base",
@@ -1096,61 +1149,91 @@ function DepositHeader({
1096
1149
  children: title
1097
1150
  }
1098
1151
  ),
1099
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1152
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1100
1153
  "div",
1101
1154
  {
1102
- className: "uf-px-2 uf-py-0.5 uf-rounded-full uf-text-[10px]",
1155
+ className: "uf-text-xs uf-mt-1",
1103
1156
  style: {
1104
- backgroundColor: colors2.card,
1105
1157
  color: colors2.foregroundMuted,
1106
1158
  fontFamily: fonts.regular
1107
1159
  },
1108
- children: badge.count
1160
+ children: subtitle
1109
1161
  }
1110
- )
1111
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1112
- DialogTitle,
1113
- {
1114
- className: "uf-text-center uf-text-base",
1115
- style: {
1116
- color: components.header.titleColor,
1117
- fontFamily: fonts.medium
1118
- },
1119
- children: title
1120
- }
1121
- ),
1122
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1123
- "div",
1124
- {
1125
- className: "uf-text-xs uf-mt-1",
1126
- style: {
1127
- color: colors2.foregroundMuted,
1128
- fontFamily: fonts.regular
1129
- },
1130
- children: subtitle
1131
- }
1132
- ) : showBalanceBlock ? isLoadingBalance && showBalanceSkeleton ? /* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)(
1133
- "div",
1162
+ ) : showBalanceBlock ? isLoadingBalance && showBalanceSkeleton ? /* @__PURE__ */ (0, import_jsx_runtime4.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_runtime4.jsx)(
1163
+ "div",
1164
+ {
1165
+ className: "uf-text-xs uf-mt-1",
1166
+ style: {
1167
+ color: colors2.foregroundMuted,
1168
+ fontFamily: fonts.regular
1169
+ },
1170
+ children: formatBalanceDisplay(balance, projectName)
1171
+ }
1172
+ ) : null : null
1173
+ ] }),
1174
+ showClose ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1175
+ "button",
1134
1176
  {
1135
- className: "uf-text-xs uf-mt-1",
1136
- style: {
1137
- color: colors2.foregroundMuted,
1138
- fontFamily: fonts.regular
1139
- },
1140
- children: formatBalanceDisplay(balance, projectName)
1177
+ onClick: onClose,
1178
+ className: "hover:uf-bg-secondary uf-rounded-lg uf-p-1 uf-transition-colors",
1179
+ style: { color: components.header.buttonColor },
1180
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.X, { className: "uf-w-5 uf-h-5" })
1141
1181
  }
1142
- ) : null : null
1182
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "uf-w-5 uf-h-5 uf-invisible" })
1143
1183
  ] }),
1144
- showClose ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1145
- "button",
1184
+ showIncident && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1185
+ "div",
1146
1186
  {
1147
- onClick: onClose,
1148
- className: "hover:uf-bg-secondary uf-rounded-lg uf-p-1 uf-transition-colors",
1149
- style: { color: components.header.buttonColor },
1150
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.X, { className: "uf-w-5 uf-h-5" })
1187
+ className: "uf-rounded-lg uf-px-3 uf-py-2.5 uf-mb-4",
1188
+ style: {
1189
+ backgroundColor: incidentStyles.bg,
1190
+ border: `1px solid ${incidentStyles.border}`
1191
+ },
1192
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-flex uf-items-start uf-gap-2.5", children: [
1193
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1194
+ IncidentIcon,
1195
+ {
1196
+ className: "uf-w-4 uf-h-4 uf-mt-0.5 uf-shrink-0",
1197
+ style: { color: incidentStyles.text }
1198
+ }
1199
+ ),
1200
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "uf-min-w-0 uf-flex-1", children: [
1201
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "uf-flex uf-items-center uf-gap-2 uf-mb-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1202
+ "span",
1203
+ {
1204
+ className: "uf-text-[11px] uf-leading-none uf-px-1.5 uf-py-1 uf-rounded-md",
1205
+ style: {
1206
+ color: incidentStyles.text,
1207
+ border: `1px solid ${incidentStyles.border}`,
1208
+ fontFamily: fonts.medium
1209
+ },
1210
+ children: incidentSeverityLabel
1211
+ }
1212
+ ) }),
1213
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1214
+ "div",
1215
+ {
1216
+ className: "uf-space-y-1",
1217
+ style: { color: incidentStyles.text, fontFamily: fonts.regular },
1218
+ children: incidentMessages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "uf-text-xs uf-leading-relaxed", children: message }, `${message}-${index}`))
1219
+ }
1220
+ ),
1221
+ incident.statusPageUrl && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1222
+ "a",
1223
+ {
1224
+ href: incident.statusPageUrl,
1225
+ target: "_blank",
1226
+ rel: "noreferrer",
1227
+ className: "uf-inline-block uf-mt-1.5 uf-text-xs uf-underline uf-underline-offset-2",
1228
+ style: { color: incidentStyles.link, fontFamily: fonts.medium },
1229
+ children: "View status"
1230
+ }
1231
+ )
1232
+ ] })
1233
+ ] })
1151
1234
  }
1152
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "uf-w-5 uf-h-5 uf-invisible" })
1153
- ] }) });
1235
+ )
1236
+ ] });
1154
1237
  }
1155
1238
 
1156
1239
  // src/components/currency/CurrencyListItem.tsx
@@ -1488,7 +1571,8 @@ var en_default = {
1488
1571
  },
1489
1572
  stripeLink: {
1490
1573
  title: "Pay with Link",
1491
- subtitle: "Buy with card or bank"
1574
+ subtitle: "Buy with card or bank",
1575
+ unavailableInRegionMessage: "Pay with Link is currently unavailable in your region."
1492
1576
  },
1493
1577
  browserWallet: {
1494
1578
  title: "Connect Wallet",
@@ -7949,7 +8033,7 @@ function AppleLogo({ className, style }) {
7949
8033
  }
7950
8034
  );
7951
8035
  }
7952
- function ApplePayButton({ onClick, title, subtitle }) {
8036
+ function ApplePayButton({ onClick, title, subtitle, iconUrl }) {
7953
8037
  const { colors: colors2, fonts, components } = useTheme();
7954
8038
  const [isHovered, setIsHovered] = React14.useState(false);
7955
8039
  const [isTouchDevice, setIsTouchDevice] = React14.useState(false);
@@ -7971,7 +8055,14 @@ function ApplePayButton({ onClick, title, subtitle }) {
7971
8055
  },
7972
8056
  children: [
7973
8057
  /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
7974
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "uf-rounded-lg uf-p-2", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AppleLogo, { className: "uf-w-5 uf-h-5", style: { color: components.card.iconColor } }) }),
8058
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "uf-rounded-lg uf-overflow-hidden uf-w-9 uf-h-9 uf-flex uf-items-center uf-justify-center", children: iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("img", { src: iconUrl, alt: "Apple Pay", width: 36, height: 36, className: "uf-rounded-lg" }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8059
+ "div",
8060
+ {
8061
+ className: "uf-w-9 uf-h-9 uf-rounded-lg uf-flex uf-items-center uf-justify-center",
8062
+ style: { backgroundColor: "#000" },
8063
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AppleLogo, { className: "uf-w-5 uf-h-5", style: { color: "#fff" } })
8064
+ }
8065
+ ) }),
7975
8066
  /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "uf-text-left", children: [
7976
8067
  /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7977
8068
  "div",
@@ -8205,13 +8296,6 @@ function solanaCandidate(provider, type, name, icon) {
8205
8296
  if (provider.isConnected && provider.publicKey) {
8206
8297
  return { type, name, address: provider.publicKey.toString(), icon };
8207
8298
  }
8208
- try {
8209
- const resp = await provider.connect({ onlyIfTrusted: true });
8210
- if (resp.publicKey) {
8211
- return { type, name, address: resp.publicKey.toString(), icon };
8212
- }
8213
- } catch {
8214
- }
8215
8299
  return null;
8216
8300
  }
8217
8301
  };
@@ -8440,6 +8524,180 @@ async function disconnectInjectedBrowserWallet(wallet) {
8440
8524
  );
8441
8525
  }
8442
8526
 
8527
+ // src/components/deposits/browser-wallets/providerResolvers.ts
8528
+ var STORED_TYPE_TO_EIP6963_WALLET_ID = {
8529
+ metamask: "metamask",
8530
+ "phantom-ethereum": "phantom",
8531
+ coinbase: "coinbase",
8532
+ trust: "trust",
8533
+ rainbow: "rainbow",
8534
+ rabby: "rabby",
8535
+ okx: "okx"
8536
+ };
8537
+ var EIP6963_WALLET_ID_TO_INFO = {
8538
+ metamask: { walletType: "metamask", name: "MetaMask", icon: "metamask" },
8539
+ phantom: { walletType: "phantom-ethereum", name: "Phantom", icon: "phantom" },
8540
+ coinbase: { walletType: "coinbase", name: "Coinbase Wallet", icon: "coinbase" },
8541
+ trust: { walletType: "trust", name: "Trust Wallet", icon: "trust" },
8542
+ rainbow: { walletType: "rainbow", name: "Rainbow", icon: "rainbow" },
8543
+ rabby: { walletType: "rabby", name: "Rabby", icon: "rabby" },
8544
+ okx: { walletType: "okx", name: "OKX Wallet", icon: "okx" }
8545
+ };
8546
+ var WALLET_ID_TO_WALLET_TYPE = {
8547
+ phantom: "phantom-ethereum",
8548
+ coinbase: "coinbase",
8549
+ trust: "trust",
8550
+ rainbow: "rainbow",
8551
+ rabby: "rabby",
8552
+ okx: "okx",
8553
+ metamask: "metamask"
8554
+ };
8555
+ var WALLET_TYPE_TO_WALLET_ID = {
8556
+ "phantom-ethereum": "phantom",
8557
+ coinbase: "coinbase",
8558
+ trust: "trust",
8559
+ okx: "okx",
8560
+ rainbow: "rainbow",
8561
+ rabby: "rabby",
8562
+ metamask: "metamask"
8563
+ };
8564
+ function isWalletType(value) {
8565
+ return value === "phantom-solana" || value === "phantom-ethereum" || value === "metamask" || value === "coinbase" || value === "solflare" || value === "backpack" || value === "glow" || value === "trust" || value === "rainbow" || value === "rabby" || value === "okx";
8566
+ }
8567
+ function walletIdToWalletType(walletId) {
8568
+ return WALLET_ID_TO_WALLET_TYPE[walletId] || "metamask";
8569
+ }
8570
+ function walletTypeToWalletId(walletType) {
8571
+ return WALLET_TYPE_TO_WALLET_ID[walletType] || walletType;
8572
+ }
8573
+ function getLegacyEvmProviders(win) {
8574
+ if (!win) return {};
8575
+ const anyWin = win;
8576
+ return {
8577
+ ethereum: anyWin.ethereum,
8578
+ phantomEthereum: anyWin.phantom?.ethereum,
8579
+ coinbaseEthereum: anyWin.coinbaseWalletExtension,
8580
+ trustEthereum: anyWin.trustwallet?.ethereum,
8581
+ okxEthereum: anyWin.okxwallet
8582
+ };
8583
+ }
8584
+ function getInjectedSolanaProviders(win) {
8585
+ if (!win) return {};
8586
+ const anyWin = win;
8587
+ return {
8588
+ phantomSolana: anyWin.phantom?.solana,
8589
+ solflare: anyWin.solflare,
8590
+ backpack: anyWin.backpack,
8591
+ glow: anyWin.glow,
8592
+ coinbaseSolana: anyWin.coinbaseSolana || anyWin.coinbaseWalletExtension?.solana,
8593
+ trustSolana: anyWin.trustwallet?.solana
8594
+ };
8595
+ }
8596
+ function describeEip6963Provider(wp) {
8597
+ const mapped = EIP6963_WALLET_ID_TO_INFO[wp.walletId];
8598
+ return {
8599
+ provider: wp.provider,
8600
+ walletType: mapped?.walletType ?? "metamask",
8601
+ name: mapped?.name ?? wp.info.name,
8602
+ icon: mapped?.icon ?? wp.info.icon
8603
+ };
8604
+ }
8605
+ function resolveQuickConnectEvmProvider(win) {
8606
+ const eip6963Providers = getEip6963Providers();
8607
+ if (eip6963Providers.length > 0) {
8608
+ const stored = getStoredWalletState();
8609
+ const preferredWalletId = stored?.walletType && isWalletType(stored.walletType) ? STORED_TYPE_TO_EIP6963_WALLET_ID[stored.walletType] : void 0;
8610
+ if (preferredWalletId) {
8611
+ const preferred = findProviderByWalletId(preferredWalletId);
8612
+ if (preferred) return describeEip6963Provider(preferred);
8613
+ }
8614
+ if (eip6963Providers.length === 1) {
8615
+ return describeEip6963Provider(eip6963Providers[0]);
8616
+ }
8617
+ return void 0;
8618
+ }
8619
+ const anyWin = win;
8620
+ const legacy = anyWin.phantom?.ethereum || anyWin.ethereum;
8621
+ if (!legacy) return void 0;
8622
+ const isPhantom = legacy.isPhantom;
8623
+ return {
8624
+ provider: legacy,
8625
+ walletType: isPhantom ? "phantom-ethereum" : "metamask",
8626
+ name: isPhantom ? "Phantom" : "MetaMask",
8627
+ icon: isPhantom ? "phantom" : "metamask"
8628
+ };
8629
+ }
8630
+ function resolveSolanaPublicKey(provider, response) {
8631
+ if (response?.publicKey) return { publicKey: response.publicKey };
8632
+ if (provider.publicKey) return { publicKey: provider.publicKey };
8633
+ return null;
8634
+ }
8635
+ function isUserRejectedSolanaConnectError(error) {
8636
+ if (!error || typeof error !== "object") return false;
8637
+ const maybeCode = "code" in error ? error.code : void 0;
8638
+ if (maybeCode === 4001) return true;
8639
+ const msg = "message" in error && typeof error.message === "string" ? error.message.toLowerCase() : "";
8640
+ return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("rejected the request") || msg.includes("declined");
8641
+ }
8642
+ function isSolanaConnectTimeoutError(error) {
8643
+ return error instanceof Error && error.message.toLowerCase().includes("did not respond to the connection request");
8644
+ }
8645
+ async function connectSolanaProviderWithRecovery(provider, walletId, walletName) {
8646
+ if (provider.isConnected && provider.publicKey) {
8647
+ return { publicKey: provider.publicKey };
8648
+ }
8649
+ const connectOnce = () => provider.connect(walletId === "solflare" ? { onlyIfTrusted: false } : void 0);
8650
+ const withTimeout = async (ms = 2e4) => await Promise.race([
8651
+ connectOnce(),
8652
+ new Promise(
8653
+ (resolve, reject) => setTimeout(() => {
8654
+ const connected = resolveSolanaPublicKey(provider);
8655
+ if (connected) {
8656
+ resolve(connected);
8657
+ return;
8658
+ }
8659
+ reject(
8660
+ new Error(
8661
+ `${walletName} did not respond to the connection request. Please unlock the wallet and try again.`
8662
+ )
8663
+ );
8664
+ }, ms)
8665
+ )
8666
+ ]);
8667
+ if (walletId === "solflare") {
8668
+ await provider.disconnect?.().catch(() => {
8669
+ });
8670
+ }
8671
+ const connectAndResolve = async () => {
8672
+ try {
8673
+ const response = await withTimeout();
8674
+ const resolved = resolveSolanaPublicKey(provider, response);
8675
+ if (resolved) return resolved;
8676
+ await new Promise((resolve) => setTimeout(resolve, 120));
8677
+ const delayedResolved = resolveSolanaPublicKey(provider);
8678
+ if (delayedResolved) return delayedResolved;
8679
+ throw new Error(`${walletName} connected but did not expose a public key.`);
8680
+ } catch (error) {
8681
+ const connected = resolveSolanaPublicKey(provider);
8682
+ if (connected) return connected;
8683
+ throw error;
8684
+ }
8685
+ };
8686
+ try {
8687
+ return await connectAndResolve();
8688
+ } catch (err) {
8689
+ if (isUserRejectedSolanaConnectError(err)) throw err;
8690
+ if (isSolanaConnectTimeoutError(err)) throw err;
8691
+ if (walletId === "solflare") {
8692
+ await provider.disconnect?.().catch(() => {
8693
+ });
8694
+ await new Promise((resolve) => setTimeout(resolve, 150));
8695
+ return await connectAndResolve();
8696
+ }
8697
+ throw err;
8698
+ }
8699
+ }
8700
+
8443
8701
  // src/resources/icons/MetamaskIcon.tsx
8444
8702
  var React17 = __toESM(require("react"));
8445
8703
  var import_jsx_runtime28 = require("react/jsx-runtime");
@@ -10244,7 +10502,11 @@ function WalletIconWithNetwork({
10244
10502
  }
10245
10503
 
10246
10504
  // src/components/deposits/buttons/BrowserWalletButton.tsx
10247
- var import_jsx_runtime41 = require("react/jsx-runtime");
10505
+ var import_jsx_runtime41 = (
10506
+ // Wallet announced via EIP-6963 with no internal icon component: render its
10507
+ // own advertised icon (`info.icon`) rather than a generic placeholder.
10508
+ require("react/jsx-runtime")
10509
+ );
10248
10510
  var WALLET_ICON_COMPONENTS = {
10249
10511
  metamask: MetamaskIcon,
10250
10512
  phantom: PhantomIcon,
@@ -10352,21 +10614,19 @@ function BrowserWalletButton({
10352
10614
  }
10353
10615
  }
10354
10616
  if (!chainType || chainType === "ethereum") {
10355
- const ethProvider = window.phantom?.ethereum || window.ethereum;
10356
- if (ethProvider) {
10357
- const accounts = await ethProvider.request({
10617
+ const resolved = resolveQuickConnectEvmProvider(window);
10618
+ if (resolved) {
10619
+ const accounts = await resolved.provider.request({
10358
10620
  method: "eth_requestAccounts"
10359
10621
  });
10360
10622
  if (accounts && accounts.length > 0) {
10361
10623
  setUserDisconnectedWallet(false);
10362
- const isPhantom = ethProvider.isPhantom;
10363
- const walletType = isPhantom ? "phantom-ethereum" : "metamask";
10364
- setStoredWalletState(walletType);
10624
+ setStoredWalletState(resolved.walletType);
10365
10625
  setWallet({
10366
- type: walletType,
10367
- name: isPhantom ? "Phantom" : "MetaMask",
10626
+ type: resolved.walletType,
10627
+ name: resolved.name,
10368
10628
  address: accounts[0],
10369
- icon: isPhantom ? "phantom" : "metamask"
10629
+ icon: resolved.icon
10370
10630
  });
10371
10631
  }
10372
10632
  }
@@ -10400,7 +10660,10 @@ function BrowserWalletButton({
10400
10660
  if (isLoading) {
10401
10661
  return null;
10402
10662
  }
10403
- const hasWalletExtension = (!chainType || chainType === "ethereum") && getEip6963Providers().length > 0 || (!chainType || chainType === "solana") && (window.phantom?.solana?.isPhantom || window.solana?.isPhantom) || (!chainType || chainType === "ethereum") && (window.phantom?.ethereum || window.ethereum);
10663
+ const eip6963EvmProviderCount = getEip6963Providers().length;
10664
+ const legacyEvmProviders = getLegacyEvmProviders(window);
10665
+ const hasLegacyEvmProvider = eip6963EvmProviderCount === 0 && !!(legacyEvmProviders.ethereum || legacyEvmProviders.phantomEthereum || legacyEvmProviders.coinbaseEthereum || legacyEvmProviders.trustEthereum || legacyEvmProviders.okxEthereum);
10666
+ const hasWalletExtension = (!chainType || chainType === "ethereum") && eip6963EvmProviderCount > 0 || (!chainType || chainType === "solana") && (window.phantom?.solana?.isPhantom || window.solana?.isPhantom) || (!chainType || chainType === "ethereum") && hasLegacyEvmProvider;
10404
10667
  if (!onConnectClick && !wallet && !hasWalletExtension) {
10405
10668
  return null;
10406
10669
  }
@@ -10410,11 +10673,21 @@ function BrowserWalletButton({
10410
10673
  border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
10411
10674
  };
10412
10675
  const sortedWallets = featuredWallets ? [...featuredWallets].sort((a, b) => a.position - b.position) : [];
10676
+ const isImageIcon = !!wallet && (wallet.icon.startsWith("data:") || wallet.icon.startsWith("http"));
10413
10677
  const walletIconBlock = wallet ? WALLET_ICON_COMPONENTS[wallet.icon] ? React29.createElement(WALLET_ICON_COMPONENTS[wallet.icon], {
10414
10678
  size: 36,
10415
10679
  className: "uf-rounded-lg",
10416
10680
  variant: "color"
10417
- }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-w-9 uf-h-9 uf-rounded-lg uf-bg-gray-500" }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-rounded-lg uf-p-2", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react22.Wallet, { className: "uf-w-5 uf-h-5", style: { color: components.card.iconColor } }) });
10681
+ }) : isImageIcon ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
10682
+ "img",
10683
+ {
10684
+ src: wallet.icon,
10685
+ alt: wallet.name,
10686
+ width: 36,
10687
+ height: 36,
10688
+ className: "uf-rounded-lg uf-w-9 uf-h-9"
10689
+ }
10690
+ ) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-w-9 uf-h-9 uf-rounded-lg uf-bg-gray-500" }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-rounded-lg uf-p-2", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react22.Wallet, { className: "uf-w-5 uf-h-5", style: { color: components.card.iconColor } }) });
10418
10691
  const titleSubtitleBlock = /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-text-left uf-min-w-0", children: [
10419
10692
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
10420
10693
  "div",
@@ -16423,16 +16696,38 @@ function useExchanges({
16423
16696
  return { exchanges, isLoading };
16424
16697
  }
16425
16698
 
16426
- // src/hooks/use-apple-pay-providers.ts
16699
+ // src/hooks/use-public-incident.ts
16427
16700
  var import_react_query13 = require("@tanstack/react-query");
16428
16701
  var import_core27 = require("@unifold/core");
16702
+ function usePublicIncident({
16703
+ publishableKey,
16704
+ enabled = true
16705
+ }) {
16706
+ const {
16707
+ data: incident,
16708
+ isLoading,
16709
+ error
16710
+ } = (0, import_react_query13.useQuery)({
16711
+ queryKey: ["unifold", "publicIncident", publishableKey],
16712
+ queryFn: () => (0, import_core27.getPublicIncident)(publishableKey),
16713
+ enabled,
16714
+ staleTime: 1e3 * 30,
16715
+ refetchInterval: 1e3 * 30,
16716
+ refetchOnWindowFocus: true
16717
+ });
16718
+ return { incident, isLoading, error: error ?? null };
16719
+ }
16720
+
16721
+ // src/hooks/use-apple-pay-providers.ts
16722
+ var import_react_query14 = require("@tanstack/react-query");
16723
+ var import_core28 = require("@unifold/core");
16429
16724
  function useApplePayProviders({
16430
16725
  publishableKey,
16431
16726
  enabled = true
16432
16727
  }) {
16433
- const { data: providers, isLoading } = (0, import_react_query13.useQuery)({
16728
+ const { data: providers, isLoading } = (0, import_react_query14.useQuery)({
16434
16729
  queryKey: ["unifold", "applePayProviders", publishableKey],
16435
- queryFn: () => (0, import_core27.getApplePayProviders)(publishableKey),
16730
+ queryFn: () => (0, import_core28.getApplePayProviders)(publishableKey),
16436
16731
  enabled,
16437
16732
  staleTime: 1e3 * 60 * 30,
16438
16733
  refetchOnMount: true,
@@ -16442,7 +16737,7 @@ function useApplePayProviders({
16442
16737
  }
16443
16738
 
16444
16739
  // src/components/deposits/DepositModal.tsx
16445
- var import_core37 = require("@unifold/core");
16740
+ var import_core38 = require("@unifold/core");
16446
16741
 
16447
16742
  // src/hooks/use-allowed-country.ts
16448
16743
  function useAllowedCountry(publishableKey) {
@@ -16487,8 +16782,8 @@ function useAllowedCountry(publishableKey) {
16487
16782
  }
16488
16783
 
16489
16784
  // src/hooks/use-address-validation.ts
16490
- var import_react_query14 = require("@tanstack/react-query");
16491
- var import_core28 = require("@unifold/core");
16785
+ var import_react_query15 = require("@tanstack/react-query");
16786
+ var import_core29 = require("@unifold/core");
16492
16787
  function useAddressValidation({
16493
16788
  recipientAddress,
16494
16789
  destinationChainType,
@@ -16499,7 +16794,7 @@ function useAddressValidation({
16499
16794
  refetchOnMount = false
16500
16795
  }) {
16501
16796
  const shouldValidate = enabled && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
16502
- const { data, isLoading, error } = (0, import_react_query14.useQuery)({
16797
+ const { data, isLoading, error } = (0, import_react_query15.useQuery)({
16503
16798
  queryKey: [
16504
16799
  "unifold",
16505
16800
  "addressValidation",
@@ -16508,7 +16803,7 @@ function useAddressValidation({
16508
16803
  destinationChainId,
16509
16804
  destinationTokenAddress
16510
16805
  ],
16511
- queryFn: () => (0, import_core28.verifyRecipientAddress)(
16806
+ queryFn: () => (0, import_core29.verifyRecipientAddress)(
16512
16807
  {
16513
16808
  chain_type: destinationChainType,
16514
16809
  chain_id: destinationChainId,
@@ -16530,6 +16825,7 @@ function useAddressValidation({
16530
16825
  return {
16531
16826
  isValid: null,
16532
16827
  failureCode: null,
16828
+ message: null,
16533
16829
  metadata: null,
16534
16830
  isLoading: false,
16535
16831
  error: null
@@ -16538,6 +16834,7 @@ function useAddressValidation({
16538
16834
  return {
16539
16835
  isValid: data?.valid ?? null,
16540
16836
  failureCode: data?.failure_code ?? null,
16837
+ message: data?.message ?? null,
16541
16838
  metadata: data?.metadata ?? null,
16542
16839
  isLoading,
16543
16840
  error: error ?? null
@@ -16789,7 +17086,7 @@ function PoweredByUnifold({
16789
17086
  }
16790
17087
 
16791
17088
  // src/components/deposits/DepositsModal.tsx
16792
- var import_core29 = require("@unifold/core");
17089
+ var import_core30 = require("@unifold/core");
16793
17090
  var import_jsx_runtime48 = require("react/jsx-runtime");
16794
17091
  function DepositsModal({
16795
17092
  open,
@@ -16807,7 +17104,7 @@ function DepositsModal({
16807
17104
  if (!open || !userId) return;
16808
17105
  const fetchExecutions = async () => {
16809
17106
  try {
16810
- const response = await (0, import_core29.queryExecutions)(userId, publishableKey, import_core29.ActionType.Deposit);
17107
+ const response = await (0, import_core30.queryExecutions)(userId, publishableKey, import_core30.ActionType.Deposit);
16811
17108
  const sorted = [...response.data].sort((a, b) => {
16812
17109
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
16813
17110
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -17390,6 +17687,37 @@ var import_react21 = require("react");
17390
17687
  var getChainKey = (chainId, chainType) => {
17391
17688
  return `${chainType}:${chainId}`;
17392
17689
  };
17690
+ function getStoredSelection(key) {
17691
+ if (typeof window === "undefined") return null;
17692
+ try {
17693
+ const raw = localStorage.getItem(key);
17694
+ if (!raw) return null;
17695
+ const parsed = JSON.parse(raw);
17696
+ if (parsed && typeof parsed.symbol === "string" && typeof parsed.chainType === "string" && typeof parsed.chainId === "string") {
17697
+ return parsed;
17698
+ }
17699
+ } catch {
17700
+ }
17701
+ return null;
17702
+ }
17703
+ function saveStoredSelection(key, symbol, chainType, chainId) {
17704
+ if (typeof window === "undefined") return;
17705
+ try {
17706
+ localStorage.setItem(key, JSON.stringify({ symbol, chainType, chainId }));
17707
+ } catch {
17708
+ }
17709
+ }
17710
+ function resolveFromStorage(tokens, stored) {
17711
+ for (const t13 of tokens) {
17712
+ if (t13.symbol !== stored.symbol) continue;
17713
+ const matchedChain = t13.chains.find(
17714
+ (c) => c.chain_type === stored.chainType && c.chain_id === stored.chainId
17715
+ );
17716
+ if (matchedChain) return { token: t13, chain: matchedChain };
17717
+ if (t13.chains.length > 0) return { token: t13, chain: t13.chains[0] };
17718
+ }
17719
+ return null;
17720
+ }
17393
17721
  function resolveToken(tokens, defaultChainType, defaultChainId, defaultTokenAddress, defaultSymbol) {
17394
17722
  if (!tokens.length) return null;
17395
17723
  let selectedToken;
@@ -17439,27 +17767,73 @@ function useDefaultToken({
17439
17767
  defaultChainType,
17440
17768
  defaultChainId,
17441
17769
  defaultTokenAddress,
17442
- defaultSymbol
17770
+ defaultSymbol,
17771
+ storageKey: storageKey2
17443
17772
  }) {
17444
- const [token, setToken] = (0, import_react21.useState)(null);
17445
- const [chain, setChain] = (0, import_react21.useState)(null);
17773
+ const [token, setTokenState] = (0, import_react21.useState)(null);
17774
+ const [chain, setChainState] = (0, import_react21.useState)(null);
17446
17775
  const [initialSelectionDone, setInitialSelectionDone] = (0, import_react21.useState)(false);
17447
17776
  const appliedDefaultsRef = (0, import_react21.useRef)("");
17777
+ const tokenRef = (0, import_react21.useRef)(null);
17778
+ const chainRef = (0, import_react21.useRef)(null);
17779
+ tokenRef.current = token;
17780
+ chainRef.current = chain;
17781
+ const setToken = (0, import_react21.useCallback)(
17782
+ (newToken) => {
17783
+ tokenRef.current = newToken;
17784
+ setTokenState(newToken);
17785
+ if (storageKey2 && chainRef.current) {
17786
+ const [chainType, chainId] = chainRef.current.split(":");
17787
+ saveStoredSelection(storageKey2, newToken, chainType, chainId);
17788
+ }
17789
+ },
17790
+ [storageKey2]
17791
+ );
17792
+ const setChain = (0, import_react21.useCallback)(
17793
+ (newChain) => {
17794
+ chainRef.current = newChain;
17795
+ setChainState(newChain);
17796
+ if (storageKey2 && tokenRef.current) {
17797
+ const [chainType, chainId] = newChain.split(":");
17798
+ saveStoredSelection(storageKey2, tokenRef.current, chainType, chainId);
17799
+ }
17800
+ },
17801
+ [storageKey2]
17802
+ );
17448
17803
  (0, import_react21.useEffect)(() => {
17449
17804
  if (!tokens.length) return;
17450
17805
  const defaultsKey = `${defaultTokenAddress ?? ""}|${defaultSymbol ?? ""}|${defaultChainType ?? ""}|${defaultChainId ?? ""}`;
17451
17806
  const defaultsChanged = appliedDefaultsRef.current !== defaultsKey;
17452
17807
  if (initialSelectionDone && !defaultsChanged) return;
17453
- const result = resolveToken(
17454
- tokens,
17455
- defaultChainType,
17456
- defaultChainId,
17457
- defaultTokenAddress,
17458
- defaultSymbol
17459
- );
17808
+ const hasExplicitDefaults = defaultTokenAddress && defaultChainType && defaultChainId || defaultSymbol && defaultChainType && defaultChainId;
17809
+ let result = null;
17810
+ if (hasExplicitDefaults) {
17811
+ result = resolveToken(
17812
+ tokens,
17813
+ defaultChainType,
17814
+ defaultChainId,
17815
+ defaultTokenAddress,
17816
+ defaultSymbol
17817
+ );
17818
+ if (result) {
17819
+ const matched = defaultTokenAddress && result.chain.token_address.toLowerCase() === defaultTokenAddress.toLowerCase() && result.chain.chain_type === defaultChainType && result.chain.chain_id === defaultChainId || defaultSymbol && result.token.symbol === defaultSymbol && result.chain.chain_type === defaultChainType && result.chain.chain_id === defaultChainId;
17820
+ if (!matched) {
17821
+ result = null;
17822
+ }
17823
+ }
17824
+ }
17825
+ if (!result && storageKey2) {
17826
+ const stored = getStoredSelection(storageKey2);
17827
+ if (stored) {
17828
+ result = resolveFromStorage(tokens, stored);
17829
+ }
17830
+ }
17831
+ if (!result) {
17832
+ result = resolveToken(tokens);
17833
+ }
17460
17834
  if (result) {
17461
- setToken(result.token.symbol);
17462
- setChain(getChainKey(result.chain.chain_id, result.chain.chain_type));
17835
+ setTokenState(result.token.symbol);
17836
+ setChainState(getChainKey(result.chain.chain_id, result.chain.chain_type));
17463
17837
  appliedDefaultsRef.current = defaultsKey;
17464
17838
  setInitialSelectionDone(true);
17465
17839
  }
@@ -17469,7 +17843,8 @@ function useDefaultToken({
17469
17843
  defaultSymbol,
17470
17844
  defaultChainType,
17471
17845
  defaultChainId,
17472
- initialSelectionDone
17846
+ initialSelectionDone,
17847
+ storageKey2
17473
17848
  ]);
17474
17849
  (0, import_react21.useEffect)(() => {
17475
17850
  if (!tokens.length || !token) return;
@@ -17480,13 +17855,14 @@ function useDefaultToken({
17480
17855
  });
17481
17856
  if (!isChainAvailable) {
17482
17857
  const firstChain = currentToken.chains[0];
17483
- setChain(getChainKey(firstChain.chain_id, firstChain.chain_type));
17858
+ setChainState(getChainKey(firstChain.chain_id, firstChain.chain_type));
17484
17859
  }
17485
17860
  }, [token, tokens, chain]);
17486
17861
  return { token, chain, setToken, setChain, initialSelectionDone };
17487
17862
  }
17488
17863
 
17489
17864
  // src/hooks/use-default-source-token.ts
17865
+ var STORAGE_KEY2 = "unifold_last_deposit_from_token";
17490
17866
  function useDefaultSourceToken({
17491
17867
  supportedTokens,
17492
17868
  defaultSourceChainType,
@@ -17499,7 +17875,8 @@ function useDefaultSourceToken({
17499
17875
  defaultChainType: defaultSourceChainType,
17500
17876
  defaultChainId: defaultSourceChainId,
17501
17877
  defaultTokenAddress: defaultSourceTokenAddress,
17502
- defaultSymbol: defaultSourceSymbol
17878
+ defaultSymbol: defaultSourceSymbol,
17879
+ storageKey: STORAGE_KEY2
17503
17880
  });
17504
17881
  }
17505
17882
 
@@ -17844,11 +18221,11 @@ var TooltipContent = React33.forwardRef(({ className, sideOffset = 4, ...props }
17844
18221
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
17845
18222
 
17846
18223
  // src/components/deposits/TransferCryptoSingleInput.tsx
17847
- var import_core31 = require("@unifold/core");
18224
+ var import_core32 = require("@unifold/core");
17848
18225
 
17849
18226
  // src/hooks/use-hypercore-activation.ts
17850
- var import_react_query15 = require("@tanstack/react-query");
17851
- var import_core30 = require("@unifold/core");
18227
+ var import_react_query16 = require("@tanstack/react-query");
18228
+ var import_core31 = require("@unifold/core");
17852
18229
 
17853
18230
  // src/lib/constants.ts
17854
18231
  var HYPERCORE_CHAIN_ID = "1337";
@@ -17866,9 +18243,9 @@ function useHypercoreActivation(params) {
17866
18243
  const recipient = recipientAddress?.trim() ?? "";
17867
18244
  const source = sourceAddress?.trim() ?? "";
17868
18245
  const hasAddresses = !!recipient && !!source;
17869
- const { data, isLoading } = (0, import_react_query15.useQuery)({
18246
+ const { data, isLoading } = (0, import_react_query16.useQuery)({
17870
18247
  queryKey: ["unifold", "hypercoreActivation", source, recipient, publishableKey],
17871
- queryFn: () => (0, import_core30.checkHypercoreActivation)(
18248
+ queryFn: () => (0, import_core31.checkHypercoreActivation)(
17872
18249
  {
17873
18250
  source_address: source,
17874
18251
  recipient_address: recipient
@@ -18017,7 +18394,7 @@ function TransferCryptoSingleInput({
18017
18394
  (c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
18018
18395
  ) : void 0;
18019
18396
  const currentChainType = currentChainData?.chain_type || "ethereum";
18020
- const currentWallet = (0, import_core31.getWalletByChainType)(wallets, currentChainType);
18397
+ const currentWallet = (0, import_core32.getWalletByChainType)(wallets, currentChainType);
18021
18398
  const depositAddress = currentWallet?.address || "";
18022
18399
  const {
18023
18400
  executions: depositExecutions,
@@ -18262,7 +18639,7 @@ function TransferCryptoSingleInput({
18262
18639
  className: "uf-text-sm uf-font-semibold",
18263
18640
  style: { color: components.card.titleColor, fontFamily: fonts.semibold },
18264
18641
  children: [
18265
- checkoutQuote.isStablecoin ? (0, import_core31.formatStablecoinAmount)(
18642
+ checkoutQuote.isStablecoin ? (0, import_core32.formatStablecoinAmount)(
18266
18643
  checkoutQuote.sourceAmount,
18267
18644
  checkoutQuote.sourceTokenDecimals
18268
18645
  ) : (Number(checkoutQuote.sourceAmount) / 10 ** checkoutQuote.sourceTokenDecimals).toFixed(Math.min(checkoutQuote.sourceTokenDecimals, 6)),
@@ -18747,7 +19124,7 @@ var SelectSeparator = React34.forwardRef(({ className, ...props }, ref) => /* @_
18747
19124
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
18748
19125
 
18749
19126
  // src/components/deposits/TransferCryptoDoubleInput.tsx
18750
- var import_core32 = require("@unifold/core");
19127
+ var import_core33 = require("@unifold/core");
18751
19128
  var import_jsx_runtime56 = require("react/jsx-runtime");
18752
19129
  var t7 = i18n.transferCrypto;
18753
19130
  var getChainKey3 = (chainId, chainType) => {
@@ -18832,7 +19209,7 @@ function TransferCryptoDoubleInput({
18832
19209
  (c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
18833
19210
  ) : void 0;
18834
19211
  const currentChainType = currentChainData?.chain_type || "ethereum";
18835
- const currentWallet = (0, import_core32.getWalletByChainType)(wallets, currentChainType);
19212
+ const currentWallet = (0, import_core33.getWalletByChainType)(wallets, currentChainType);
18836
19213
  const depositAddress = currentWallet?.address || "";
18837
19214
  const {
18838
19215
  executions: depositExecutions,
@@ -19402,10 +19779,10 @@ function TransferCryptoDoubleInput({
19402
19779
  // src/components/deposits/WalletConnect.tsx
19403
19780
  var React35 = __toESM(require("react"));
19404
19781
  var import_lucide_react36 = require("lucide-react");
19405
- var import_core36 = require("@unifold/core");
19782
+ var import_core37 = require("@unifold/core");
19406
19783
 
19407
19784
  // src/lib/send-hypercore.ts
19408
- var import_core33 = require("@unifold/core");
19785
+ var import_core34 = require("@unifold/core");
19409
19786
  function isHypercoreChain(chainId) {
19410
19787
  return chainId === HYPERCORE_CHAIN_ID;
19411
19788
  }
@@ -19416,7 +19793,7 @@ async function sendHypercoreEvmTransfer(params) {
19416
19793
  params: []
19417
19794
  });
19418
19795
  const activeChainId = String(parseInt(currentChainHex, 16));
19419
- const buildResult = await (0, import_core33.buildHypercoreTransaction)(
19796
+ const buildResult = await (0, import_core34.buildHypercoreTransaction)(
19420
19797
  {
19421
19798
  signature_chain_id: activeChainId,
19422
19799
  recipient_address: recipientAddress,
@@ -19429,7 +19806,7 @@ async function sendHypercoreEvmTransfer(params) {
19429
19806
  method: "eth_signTypedData_v4",
19430
19807
  params: [fromAddress, JSON.stringify(buildResult.typed_data)]
19431
19808
  });
19432
- await (0, import_core33.sendHypercoreTransaction)(
19809
+ await (0, import_core34.sendHypercoreTransaction)(
19433
19810
  {
19434
19811
  action_payload: buildResult.action_payload,
19435
19812
  signature,
@@ -19441,8 +19818,8 @@ async function sendHypercoreEvmTransfer(params) {
19441
19818
  }
19442
19819
 
19443
19820
  // src/hooks/use-deposit-quote.ts
19444
- var import_react_query16 = require("@tanstack/react-query");
19445
- var import_core34 = require("@unifold/core");
19821
+ var import_react_query17 = require("@tanstack/react-query");
19822
+ var import_core35 = require("@unifold/core");
19446
19823
  function useDepositQuote(params) {
19447
19824
  const {
19448
19825
  publishableKey,
@@ -19468,7 +19845,7 @@ function useDepositQuote(params) {
19468
19845
  ...adjustForSlippage ? { adjust_for_slippage: true } : {},
19469
19846
  ...stablecoinParity ? { stablecoin_parity: true } : {}
19470
19847
  };
19471
- return (0, import_react_query16.useQuery)({
19848
+ return (0, import_react_query17.useQuery)({
19472
19849
  queryKey: [
19473
19850
  "unifold",
19474
19851
  "depositQuote",
@@ -19483,7 +19860,7 @@ function useDepositQuote(params) {
19483
19860
  stablecoinParity,
19484
19861
  publishableKey
19485
19862
  ],
19486
- queryFn: () => (0, import_core34.getDepositQuote)(request, publishableKey),
19863
+ queryFn: () => (0, import_core35.getDepositQuote)(request, publishableKey),
19487
19864
  enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
19488
19865
  staleTime: 3e4,
19489
19866
  gcTime: 5 * 6e4,
@@ -19496,15 +19873,15 @@ function useDepositQuote(params) {
19496
19873
  }
19497
19874
 
19498
19875
  // src/hooks/use-external-wallets.ts
19499
- var import_react_query17 = require("@tanstack/react-query");
19500
- var import_core35 = require("@unifold/core");
19876
+ var import_react_query18 = require("@tanstack/react-query");
19877
+ var import_core36 = require("@unifold/core");
19501
19878
  function useExternalWallets({
19502
19879
  publishableKey,
19503
19880
  enabled = true
19504
19881
  }) {
19505
- const { data: wallets = [], isLoading } = (0, import_react_query17.useQuery)({
19882
+ const { data: wallets = [], isLoading } = (0, import_react_query18.useQuery)({
19506
19883
  queryKey: ["unifold", "external-wallets", publishableKey],
19507
- queryFn: () => (0, import_core35.getExternalWallets)(publishableKey).then((res) => res.data),
19884
+ queryFn: () => (0, import_core36.getExternalWallets)(publishableKey).then((res) => res.data),
19508
19885
  enabled: enabled && !!publishableKey,
19509
19886
  staleTime: 1e3 * 60 * 30,
19510
19887
  refetchOnMount: false,
@@ -20613,33 +20990,11 @@ function balancesRepresentSameToken(a, b) {
20613
20990
  if (!tokenA || !tokenB) return false;
20614
20991
  return tokenA.chain_type === tokenB.chain_type && tokenA.chain_id === tokenB.chain_id && normalizeTokenAddress(tokenA.token_address) === normalizeTokenAddress(tokenB.token_address);
20615
20992
  }
20616
- function getSolanaProviders() {
20617
- if (typeof window === "undefined") return {};
20618
- const win = window;
20619
- return {
20620
- phantomSolana: win.phantom?.solana,
20621
- solflare: win.solflare,
20622
- backpack: win.backpack,
20623
- glow: win.glow,
20624
- coinbaseSolana: win.coinbaseSolana || win.coinbaseWalletExtension?.solana
20625
- };
20626
- }
20627
- function getLegacyEvmProviders() {
20628
- if (typeof window === "undefined") return {};
20629
- const win = window;
20630
- return {
20631
- ethereum: win.ethereum,
20632
- phantomEthereum: win.phantom?.ethereum,
20633
- coinbaseEthereum: win.coinbaseWalletExtension,
20634
- trustEthereum: win.trustwallet?.ethereum,
20635
- okxEthereum: win.okxwallet
20636
- };
20637
- }
20638
20993
  function detectAvailableWallets(definitions, recentWalletId, filterChainType) {
20639
- const solProviders = getSolanaProviders();
20640
- const legacyEvm = getLegacyEvmProviders();
20641
- const eip6963List = getEip6963Providers();
20642
20994
  const win = typeof window !== "undefined" ? window : null;
20995
+ const solProviders = getInjectedSolanaProviders(win);
20996
+ const legacyEvm = getLegacyEvmProviders(win);
20997
+ const eip6963List = getEip6963Providers();
20643
20998
  const hasEip6963 = (walletId) => eip6963List.some((d) => {
20644
20999
  const rdns = d.info?.rdns || "";
20645
21000
  switch (walletId) {
@@ -20908,10 +21263,13 @@ function WalletConnect({
20908
21263
  };
20909
21264
  const openMobileWalletBrowse = async (wallet, depositAddresses) => {
20910
21265
  try {
20911
- const res = await (0, import_core36.getWalletMobileDeepLink)(
21266
+ const cleanedAmountUsd = amountUsd?.replace(/[^0-9.]/g, "") ?? "";
21267
+ const forwardedAmountUsd = parseFloat(cleanedAmountUsd) > 0 ? cleanedAmountUsd : void 0;
21268
+ const res = await (0, import_core37.getWalletMobileDeepLink)(
20912
21269
  wallet.id,
20913
21270
  depositAddresses,
20914
- publishableKey
21271
+ publishableKey,
21272
+ forwardedAmountUsd
20915
21273
  );
20916
21274
  if (res.deeplink) {
20917
21275
  setMobileRedirect({ walletId: wallet.id, walletName: wallet.name, deeplink: res.deeplink });
@@ -21000,7 +21358,7 @@ function WalletConnect({
21000
21358
  const eip6963Match = findProviderByWalletId(wallet.id);
21001
21359
  let provider = eip6963Match?.provider;
21002
21360
  if (!provider) {
21003
- const legacyEvm = getLegacyEvmProviders();
21361
+ const legacyEvm = getLegacyEvmProviders(win);
21004
21362
  switch (wallet.id) {
21005
21363
  case "metamask":
21006
21364
  if (legacyEvm.ethereum?.isMetaMask && !legacyEvm.ethereum?.isPhantom)
@@ -21032,16 +21390,7 @@ function WalletConnect({
21032
21390
  const accounts = await provider.request({ method: "eth_requestAccounts" });
21033
21391
  if (!accounts?.length) throw new Error("No accounts returned from wallet");
21034
21392
  setUserDisconnectedWallet(false);
21035
- const walletIdToType = {
21036
- phantom: "phantom-ethereum",
21037
- coinbase: "coinbase",
21038
- trust: "trust",
21039
- rainbow: "rainbow",
21040
- rabby: "rabby",
21041
- okx: "okx",
21042
- metamask: "metamask"
21043
- };
21044
- const walletType = walletIdToType[wallet.id] || "metamask";
21393
+ const walletType = walletIdToWalletType(wallet.id);
21045
21394
  setStoredWalletState(walletType);
21046
21395
  connectedInfo = {
21047
21396
  type: walletType,
@@ -21050,7 +21399,7 @@ function WalletConnect({
21050
21399
  icon: wallet.id
21051
21400
  };
21052
21401
  } else {
21053
- const solProviders = getSolanaProviders();
21402
+ const solProviders = getInjectedSolanaProviders(win);
21054
21403
  let provider;
21055
21404
  switch (wallet.id) {
21056
21405
  case "phantom":
@@ -21069,11 +21418,11 @@ function WalletConnect({
21069
21418
  provider = solProviders.coinbaseSolana || win?.coinbaseWalletExtension?.solana;
21070
21419
  break;
21071
21420
  case "trust":
21072
- provider = win?.trustwallet?.solana;
21421
+ provider = solProviders.trustSolana;
21073
21422
  break;
21074
21423
  }
21075
21424
  if (!provider) throw new Error(`${wallet.name} Solana wallet not found.`);
21076
- const response = await provider.connect();
21425
+ const response = await connectSolanaProviderWithRecovery(provider, wallet.id, wallet.name);
21077
21426
  setUserDisconnectedWallet(false);
21078
21427
  const walletType = wallet.id === "solflare" ? "solflare" : wallet.id === "backpack" ? "backpack" : wallet.id === "glow" ? "glow" : "phantom-solana";
21079
21428
  setStoredWalletState(walletType);
@@ -21219,7 +21568,7 @@ function WalletConnect({
21219
21568
  destination_chain_type: activeDepositWallet.destination_chain_type,
21220
21569
  ...productType ? { product_type: productType } : {}
21221
21570
  };
21222
- const response = await (0, import_core36.getSupportedDepositTokens)(publishableKey, options);
21571
+ const response = await (0, import_core37.getSupportedDepositTokens)(publishableKey, options);
21223
21572
  if (cancelled) return;
21224
21573
  const supportedToken = response.data.find(
21225
21574
  (t13) => t13.symbol.toLowerCase() === token.symbol.toLowerCase()
@@ -21247,7 +21596,7 @@ function WalletConnect({
21247
21596
  setIsLoading(true);
21248
21597
  setError(null);
21249
21598
  const sct = activeDepositWallet.chain_type === "algorand" || activeDepositWallet.chain_type === "xrpl" || activeDepositWallet.chain_type === "cardano" || activeDepositWallet.chain_type === "n1" ? "ethereum" : activeDepositWallet.chain_type;
21250
- (0, import_core36.getAddressBalances)(activeWalletInfo.address, sct, publishableKey).then((response) => {
21599
+ (0, import_core37.getAddressBalances)(activeWalletInfo.address, sct, publishableKey).then((response) => {
21251
21600
  if (cancelled) return;
21252
21601
  const nonZero = response.balances.filter((b) => b.amount !== "0");
21253
21602
  const defaultSource = {
@@ -21424,16 +21773,7 @@ function WalletConnect({
21424
21773
  return (integerPart + decimalPart.padEnd(decimals, "0").slice(0, decimals)).replace(/^0+/, "") || "0";
21425
21774
  };
21426
21775
  const resolveEvmProvider = () => {
21427
- const walletIdMap = {
21428
- "phantom-ethereum": "phantom",
21429
- coinbase: "coinbase",
21430
- trust: "trust",
21431
- okx: "okx",
21432
- rainbow: "rainbow",
21433
- rabby: "rabby",
21434
- metamask: "metamask"
21435
- };
21436
- const lookupId = walletIdMap[walletInfo.type] || walletInfo.type;
21776
+ const lookupId = walletTypeToWalletId(walletInfo.type);
21437
21777
  const eip6963Match = findProviderByWalletId(lookupId);
21438
21778
  let provider = eip6963Match?.provider;
21439
21779
  if (!provider) {
@@ -21523,7 +21863,7 @@ function WalletConnect({
21523
21863
  if (!provider.publicKey) await provider.connect();
21524
21864
  const isNative = token.token_address === "native" || token.token_address === "So11111111111111111111111111111111111111112" || token.token_address === "";
21525
21865
  const smallestUnit = isNative ? decimalToSmallestUnit(amountStr, 9) : decimalToSmallestUnit(amountStr, token.decimals);
21526
- const buildResp = await (0, import_core36.buildSolanaTransaction)(
21866
+ const buildResp = await (0, import_core37.buildSolanaTransaction)(
21527
21867
  {
21528
21868
  chain_id: "mainnet",
21529
21869
  token_address: token.token_address === "" ? "native" : token.token_address,
@@ -21545,7 +21885,7 @@ function WalletConnect({
21545
21885
  const ser = signed.serialize();
21546
21886
  let bs = "";
21547
21887
  for (let i = 0; i < ser.length; i++) bs += String.fromCharCode(ser[i]);
21548
- const resp = await (0, import_core36.sendSolanaTransaction)(
21888
+ const resp = await (0, import_core37.sendSolanaTransaction)(
21549
21889
  { chain_id: "mainnet", signed_transaction: btoa(bs) },
21550
21890
  publishableKey
21551
21891
  );
@@ -21591,7 +21931,7 @@ function WalletConnect({
21591
21931
  } else if (isHypercoreToken) {
21592
21932
  let sendAmount = tokenAmount;
21593
21933
  try {
21594
- const activation = await (0, import_core36.checkHypercoreActivation)(
21934
+ const activation = await (0, import_core37.checkHypercoreActivation)(
21595
21935
  { source_address: walletInfo.address, recipient_address: recipientAddress },
21596
21936
  publishableKey
21597
21937
  );
@@ -21968,8 +22308,8 @@ function WalletConnect({
21968
22308
  ] }) });
21969
22309
  }
21970
22310
  if (view === "mobile_deposit_status" && latestDepositExecution) {
21971
- const isComplete = latestDepositExecution.status === import_core36.ExecutionStatus.SUCCEEDED;
21972
- const isFailed = latestDepositExecution.status === import_core36.ExecutionStatus.FAILED;
22311
+ const isComplete = latestDepositExecution.status === import_core37.ExecutionStatus.SUCCEEDED;
22312
+ const isFailed = latestDepositExecution.status === import_core37.ExecutionStatus.FAILED;
21973
22313
  const title = isComplete ? "Payment Complete" : isFailed ? "Payment Failed" : "Payment Processing";
21974
22314
  return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(AccentColorOverride, { accentColor: preConnectAccent, accentForeground: preConnectFg, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { style: viewTransitionStyle, children: [
21975
22315
  /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
@@ -22165,6 +22505,7 @@ function DepositModal({
22165
22505
  applePayTitle = "Pay with Apple Pay",
22166
22506
  applePaySubTitle = "Instant",
22167
22507
  enableBankTransfer,
22508
+ enableIncidentBanner = false,
22168
22509
  // No default: left undefined so the backend `stripe_link.enabled` can govern
22169
22510
  // (via the `??` chain in showStripeLink) once a dashboard toggle exists.
22170
22511
  enableStripeLink,
@@ -22210,7 +22551,7 @@ function DepositModal({
22210
22551
  const s = initialScreen ?? "main";
22211
22552
  if (s === "tracker" && hideDepositTracker === true) return "main";
22212
22553
  if (s === "cashapp" && enableCashApp === false) return "main";
22213
- if (s === "stripe_link" && !enableStripeLink) return "main";
22554
+ if (s === "stripe_link" && enableStripeLink === false) return "main";
22214
22555
  if (s === "apple_pay" && enableApplePay === false) return "main";
22215
22556
  if (s === "card" && enableFiatOnramp === false) return "main";
22216
22557
  if (s === "pay_with_exchange") return enablePayWithExchange === false ? "main" : "exchange";
@@ -22269,21 +22610,31 @@ function DepositModal({
22269
22610
  const showApplePay = enableApplePay ?? projectConfig?.apple_pay?.enabled ?? true;
22270
22611
  const showBankTransfer = enableBankTransfer ?? projectConfig?.bank_transfer?.enabled ?? true;
22271
22612
  const showDepositTracker = hideDepositTracker ? false : projectConfig?.deposit_tracker?.enabled ?? true;
22613
+ const { incident: publicIncident } = usePublicIncident({
22614
+ publishableKey,
22615
+ enabled: open && enableIncidentBanner
22616
+ });
22617
+ const activeIncident = enableIncidentBanner && publicIncident?.enabled && (publicIncident.messages?.length ?? 0) > 0 ? {
22618
+ enabled: true,
22619
+ messages: publicIncident.messages,
22620
+ severity: publicIncident.severity,
22621
+ statusPageUrl: publicIncident.status_page_url
22622
+ } : void 0;
22272
22623
  const [integrationExchanges, setIntegrationExchanges] = (0, import_react26.useState)([]);
22273
22624
  (0, import_react26.useEffect)(() => {
22274
22625
  if (!showConnectExchange || !open) return;
22275
- (0, import_core37.getIntegrationExchanges)(publishableKey).then((res) => setIntegrationExchanges(res.data)).catch(() => {
22626
+ (0, import_core38.getIntegrationExchanges)(publishableKey).then((res) => setIntegrationExchanges(res.data)).catch(() => {
22276
22627
  });
22277
22628
  }, [showConnectExchange, open, publishableKey]);
22278
22629
  const [connectedExchange, setConnectedExchange] = (0, import_react26.useState)(() => {
22279
22630
  if (!showConnectExchange) return null;
22280
- const stored = getStoredIntegrationToken(import_core37.IntegrationProvider.COINBASE);
22631
+ const stored = getStoredIntegrationToken(import_core38.IntegrationProvider.COINBASE);
22281
22632
  if (!stored) return null;
22282
22633
  return { name: "Coinbase", iconUrl: void 0, balanceUsd: null, isLoading: true };
22283
22634
  });
22284
22635
  (0, import_react26.useEffect)(() => {
22285
22636
  if (!showConnectExchange || !open || view !== "main") return;
22286
- const stored = getStoredIntegrationToken(import_core37.IntegrationProvider.COINBASE);
22637
+ const stored = getStoredIntegrationToken(import_core38.IntegrationProvider.COINBASE);
22287
22638
  if (!stored) {
22288
22639
  setConnectedExchange(null);
22289
22640
  return;
@@ -22303,24 +22654,24 @@ function DepositModal({
22303
22654
  }) : null;
22304
22655
  setConnectedExchange((prev) => prev ? { ...prev, balanceUsd, isLoading: false } : null);
22305
22656
  };
22306
- (0, import_core37.getIntegrationHoldings)(import_core37.IntegrationProvider.COINBASE, stored.access_token, publishableKey).then(processHoldings).catch(async () => {
22657
+ (0, import_core38.getIntegrationHoldings)(import_core38.IntegrationProvider.COINBASE, stored.access_token, publishableKey).then(processHoldings).catch(async () => {
22307
22658
  try {
22308
- const refreshResult = await (0, import_core37.refreshIntegrationToken)(stored.access_token, publishableKey);
22309
- if (!getStoredIntegrationToken(import_core37.IntegrationProvider.COINBASE)) return;
22659
+ const refreshResult = await (0, import_core38.refreshIntegrationToken)(stored.access_token, publishableKey);
22660
+ if (!getStoredIntegrationToken(import_core38.IntegrationProvider.COINBASE)) return;
22310
22661
  setStoredIntegrationToken({
22311
- integration_provider: import_core37.IntegrationProvider.COINBASE,
22662
+ integration_provider: import_core38.IntegrationProvider.COINBASE,
22312
22663
  access_token: refreshResult.access_token,
22313
22664
  expires_at: refreshResult.expires_at
22314
22665
  });
22315
- const retryResult = await (0, import_core37.getIntegrationHoldings)(
22316
- import_core37.IntegrationProvider.COINBASE,
22666
+ const retryResult = await (0, import_core38.getIntegrationHoldings)(
22667
+ import_core38.IntegrationProvider.COINBASE,
22317
22668
  refreshResult.access_token,
22318
22669
  publishableKey
22319
22670
  );
22320
22671
  processHoldings(retryResult);
22321
22672
  } catch {
22322
- if (!getStoredIntegrationToken(import_core37.IntegrationProvider.COINBASE)) return;
22323
- clearStoredIntegrationToken(import_core37.IntegrationProvider.COINBASE);
22673
+ if (!getStoredIntegrationToken(import_core38.IntegrationProvider.COINBASE)) return;
22674
+ clearStoredIntegrationToken(import_core38.IntegrationProvider.COINBASE);
22324
22675
  setConnectedExchange(null);
22325
22676
  }
22326
22677
  });
@@ -22328,14 +22679,18 @@ function DepositModal({
22328
22679
  (0, import_react26.useEffect)(() => {
22329
22680
  if (!connectedExchange || integrationExchanges.length === 0) return;
22330
22681
  const cbExchange = integrationExchanges.find(
22331
- (e) => e.service_provider === import_core37.IntegrationProvider.COINBASE
22682
+ (e) => e.service_provider === import_core38.IntegrationProvider.COINBASE
22332
22683
  );
22333
22684
  const iconUrl = cbExchange?.icon_urls?.find((u) => u.format === "svg")?.url || cbExchange?.icon_urls?.find((u) => u.format === "png")?.url || cbExchange?.icon_url;
22334
22685
  if (iconUrl && iconUrl !== connectedExchange.iconUrl) {
22335
22686
  setConnectedExchange((prev) => prev ? { ...prev, iconUrl } : prev);
22336
22687
  }
22337
22688
  }, [integrationExchanges, connectedExchange]);
22338
- const { data: depositAddressResponse, isLoading: walletsLoading } = useDepositAddress({
22689
+ const {
22690
+ data: depositAddressResponse,
22691
+ isLoading: walletsLoading,
22692
+ error: walletsError
22693
+ } = useDepositAddress({
22339
22694
  userId,
22340
22695
  publishableKey,
22341
22696
  recipientAddress,
@@ -22433,7 +22788,7 @@ function DepositModal({
22433
22788
  if (view !== "tracker" || !userId) return;
22434
22789
  const fetchExecutions = async () => {
22435
22790
  try {
22436
- const response = await (0, import_core37.queryExecutions)(userId, publishableKey, import_core37.ActionType.Deposit);
22791
+ const response = await (0, import_core38.queryExecutions)(userId, publishableKey, import_core38.ActionType.Deposit);
22437
22792
  const sorted = [...response.data].sort((a, b) => {
22438
22793
  const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
22439
22794
  const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
@@ -22468,6 +22823,7 @@ function DepositModal({
22468
22823
  const {
22469
22824
  isValid: isAddressValid,
22470
22825
  failureCode: addressFailureCode,
22826
+ message: addressFailureMessage,
22471
22827
  metadata: addressFailureMetadata,
22472
22828
  isLoading: isAddressValidationLoading
22473
22829
  } = useAddressValidation({
@@ -22481,17 +22837,31 @@ function DepositModal({
22481
22837
  refetchOnMount: "always"
22482
22838
  });
22483
22839
  const addressValidationMessages = i18n.transferCrypto.addressValidation;
22484
- const getAddressValidationErrorMessage = (code, metadata) => {
22840
+ const getAddressValidationErrorMessage = (message, code, metadata) => {
22841
+ if (message && message.trim().length > 0) return message;
22485
22842
  if (!code) return addressValidationMessages.defaultError;
22486
22843
  const errors = addressValidationMessages.errors;
22487
22844
  const template = errors[code] ?? addressValidationMessages.defaultError;
22488
22845
  return interpolate(template, metadata);
22489
22846
  };
22847
+ const walletsRecipientError = (0, import_core38.isDepositAddressValidationError)(walletsError) ? walletsError.message : null;
22848
+ const isRecipientAddressInvalid = isAddressValid === false || walletsRecipientError !== null;
22849
+ const recipientInvalidMessage = getAddressValidationErrorMessage(
22850
+ addressFailureMessage ?? walletsRecipientError,
22851
+ addressFailureCode,
22852
+ addressFailureMetadata
22853
+ );
22490
22854
  const openingScreen = effectiveInitialScreen;
22491
22855
  const sessionOpenedFromMenu = openingScreen === "main";
22492
22856
  const standaloneNeedsDepositPrereq = openingScreen !== "main" && (view === "transfer" || view === "card");
22493
22857
  let depositPrerequisiteBody;
22494
- if (isCountryLoading || isAddressValidationLoading || tokensLoading || walletsLoading || !projectConfig || // Bank-transfer row visibility depends on the country-gated providers
22858
+ if (isRecipientAddressInvalid) {
22859
+ depositPrerequisiteBody = /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
22860
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react37.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
22861
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: addressValidationMessages.unableToReceiveFunds }),
22862
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: recipientInvalidMessage })
22863
+ ] });
22864
+ } else if (isCountryLoading || isAddressValidationLoading || tokensLoading || walletsLoading || !projectConfig || // Bank-transfer row visibility depends on the country-gated providers
22495
22865
  // fetch — block the menu on it so the row never flashes in or out.
22496
22866
  showBankTransfer && bankTransferProvidersLoading || // Same for Apple Pay: row visibility depends on the geo/platform-gated
22497
22867
  // providers fetch — block the menu so the row doesn't pop in or out.
@@ -22513,12 +22883,6 @@ function DepositModal({
22513
22883
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: "No Tokens Available" }),
22514
22884
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: "There are no supported tokens available from your current location." })
22515
22885
  ] });
22516
- } else if (isAddressValid === false) {
22517
- depositPrerequisiteBody = /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
22518
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react37.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
22519
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-text-foreground uf-mb-2", children: addressValidationMessages.unableToReceiveFunds }),
22520
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "uf-text-sm uf-text-muted-foreground uf-max-w-[280px]", children: getAddressValidationErrorMessage(addressFailureCode, addressFailureMetadata) })
22521
- ] });
22522
22886
  } else {
22523
22887
  depositPrerequisiteBody = null;
22524
22888
  }
@@ -22535,11 +22899,11 @@ function DepositModal({
22535
22899
  if (view === "wallet_connect" && sessionOpenedFromMenu) setView("main");
22536
22900
  };
22537
22901
  const handleExchangeDisconnect = () => {
22538
- const stored = getStoredIntegrationToken(import_core37.IntegrationProvider.COINBASE);
22902
+ const stored = getStoredIntegrationToken(import_core38.IntegrationProvider.COINBASE);
22539
22903
  if (stored) {
22540
- (0, import_core37.revokeIntegrationToken)(stored.access_token, publishableKey);
22904
+ (0, import_core38.revokeIntegrationToken)(stored.access_token, publishableKey);
22541
22905
  }
22542
- clearStoredIntegrationToken(import_core37.IntegrationProvider.COINBASE);
22906
+ clearStoredIntegrationToken(import_core38.IntegrationProvider.COINBASE);
22543
22907
  setConnectedExchange(null);
22544
22908
  if (view === "coinbase_connect" && sessionOpenedFromMenu) setView("main");
22545
22909
  };
@@ -23012,6 +23376,7 @@ function DepositModal({
23012
23376
  title: modalTitle || "Deposit",
23013
23377
  showClose: !hideOverlay,
23014
23378
  onClose: handleClose,
23379
+ incident: activeIncident,
23015
23380
  showBalance: showBalanceHeader,
23016
23381
  balanceAddress: recipientAddress,
23017
23382
  balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
@@ -23031,6 +23396,7 @@ function DepositModal({
23031
23396
  showBack: showBackTransfer,
23032
23397
  onBack: handleBack,
23033
23398
  onClose: handleClose,
23399
+ incident: activeIncident,
23034
23400
  showBalance: showBalanceHeader,
23035
23401
  balanceAddress: recipientAddress,
23036
23402
  balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
@@ -23091,7 +23457,8 @@ function DepositModal({
23091
23457
  title: selectedExecution ? "Deposit Details" : depositTrackerTitle,
23092
23458
  showBack: showBackTracker,
23093
23459
  onBack: handleBack,
23094
- onClose: handleClose
23460
+ onClose: handleClose,
23461
+ incident: activeIncident
23095
23462
  }
23096
23463
  ),
23097
23464
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
@@ -23123,6 +23490,7 @@ function DepositModal({
23123
23490
  showBack: showBackCard,
23124
23491
  onBack: handleBack,
23125
23492
  onClose: handleClose,
23493
+ incident: activeIncident,
23126
23494
  badge: cardView === "quotes" ? { count: quotesCount } : void 0,
23127
23495
  showBalance: showBalanceHeader,
23128
23496
  balanceAddress: recipientAddress,
@@ -23172,7 +23540,8 @@ function DepositModal({
23172
23540
  title: payWithExchangeTitle,
23173
23541
  showBack: exchangeView === "pending" || sessionOpenedFromMenu,
23174
23542
  onBack: handleBack,
23175
- onClose: handleClose
23543
+ onClose: handleClose,
23544
+ incident: activeIncident
23176
23545
  }
23177
23546
  ),
23178
23547
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
@@ -23286,7 +23655,8 @@ function DepositModal({
23286
23655
  title: t8.bankTransfer.title,
23287
23656
  showBack: bankTransferView !== "providers" || sessionOpenedFromMenu,
23288
23657
  onBack: handleBack,
23289
- onClose: handleClose
23658
+ onClose: handleClose,
23659
+ incident: activeIncident
23290
23660
  }
23291
23661
  ),
23292
23662
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
@@ -23320,26 +23690,24 @@ function DepositModal({
23320
23690
  title: "Deposit with Link",
23321
23691
  showBack: stripeLinkStep !== "checkout" && stripeLinkStep !== "success",
23322
23692
  onBack: handleBack,
23693
+ incident: activeIncident,
23323
23694
  showClose: stripeLinkStep !== "checkout" && stripeLinkStep !== "auth",
23324
23695
  onClose: handleClose
23325
23696
  }
23326
23697
  ),
23327
23698
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
23328
23699
  isLoadingIp ? (
23329
- // Hold the geo decision until IP resolves so we don't mount
23330
- // PayWithStripeLink (which kicks off config/OAuth work) for a
23331
- // deep-link user who turns out to be outside the US.
23700
+ // Wait for location so the first config fetch is region-aware.
23332
23701
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(SkeletonButton, { variant: "with-icons" })
23333
23702
  ) : !showStripeLink ? (
23334
- // Stripe Link's crypto on-ramp is US-only. On a direct open
23335
- // (initialScreen="stripe_link") the row isn't in a menu to
23336
- // fall back to, so show a geo-restriction screen rather than
23337
- // the Link UI.
23703
+ // Direct opens (initialScreen="stripe_link") have no menu row
23704
+ // to fall back to, so render an unavailable state when backend
23705
+ // config resolves Stripe Link disabled/hidden.
23338
23706
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
23339
23707
  GeoRestrictionScreen,
23340
23708
  {
23341
23709
  methodName: t8.stripeLink.title,
23342
- message: "Pay with Link is only available in the US."
23710
+ message: t8.stripeLink.unavailableInRegionMessage
23343
23711
  }
23344
23712
  )
23345
23713
  ) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
@@ -23372,7 +23740,8 @@ function DepositModal({
23372
23740
  title: cashAppView !== "amount" && cashAppAmount ? `Pay $${cashAppAmount} via Cash App` : "Pay with Cash App",
23373
23741
  showBack: cashAppView !== "amount" || sessionOpenedFromMenu,
23374
23742
  onBack: handleBack,
23375
- onClose: handleClose
23743
+ onClose: handleClose,
23744
+ incident: activeIncident
23376
23745
  }
23377
23746
  ),
23378
23747
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
@@ -23408,7 +23777,8 @@ function DepositModal({
23408
23777
  const handled = applePayHandleRef.current?.requestBack() ?? false;
23409
23778
  if (!handled) handleBack();
23410
23779
  },
23411
- onClose: handleClose
23780
+ onClose: handleClose,
23781
+ incident: activeIncident
23412
23782
  }
23413
23783
  ),
23414
23784
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
@@ -23454,14 +23824,14 @@ var import_react27 = require("react");
23454
23824
  var import_lucide_react38 = require("lucide-react");
23455
23825
 
23456
23826
  // src/hooks/use-payment-intent.ts
23457
- var import_react_query18 = require("@tanstack/react-query");
23458
- var import_core38 = require("@unifold/core");
23827
+ var import_react_query19 = require("@tanstack/react-query");
23828
+ var import_core39 = require("@unifold/core");
23459
23829
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["succeeded", "expired", "refunded", "canceled"]);
23460
23830
  function usePaymentIntent(params) {
23461
23831
  const { clientSecret, publishableKey, enabled = true, pollingInterval = 3e3 } = params;
23462
- return (0, import_react_query18.useQuery)({
23832
+ return (0, import_react_query19.useQuery)({
23463
23833
  queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
23464
- queryFn: () => (0, import_core38.retrievePaymentIntent)(clientSecret, publishableKey),
23834
+ queryFn: () => (0, import_core39.retrievePaymentIntent)(clientSecret, publishableKey),
23465
23835
  enabled: enabled && !!clientSecret && !!publishableKey,
23466
23836
  staleTime: 0,
23467
23837
  refetchInterval: (query) => {
@@ -23477,7 +23847,7 @@ function usePaymentIntent(params) {
23477
23847
  }
23478
23848
 
23479
23849
  // src/components/checkout/CheckoutModal.tsx
23480
- var import_core39 = require("@unifold/core");
23850
+ var import_core40 = require("@unifold/core");
23481
23851
  var import_jsx_runtime64 = require("react/jsx-runtime");
23482
23852
  function mapToCheckoutPaymentIntent(pi) {
23483
23853
  return {
@@ -23535,6 +23905,7 @@ function CheckoutModal({
23535
23905
  modalTitle,
23536
23906
  enableTransferCrypto,
23537
23907
  enableConnectWallet,
23908
+ enableIncidentBanner = false,
23538
23909
  defaultSourceChainType,
23539
23910
  defaultSourceChainId,
23540
23911
  defaultSourceTokenAddress,
@@ -23563,8 +23934,8 @@ function CheckoutModal({
23563
23934
  if (isSucceeded && richIntent) {
23564
23935
  const createdSec = data.paymentIntent?.updated_at ? Math.floor(new Date(data.paymentIntent.updated_at).getTime() / 1e3) : Math.floor(Date.now() / 1e3);
23565
23936
  onEvent?.({
23566
- id: (0, import_core39.generatePrefixedKSUID)("sevt"),
23567
- type: import_core39.CheckoutEventType.PAYMENT_INTENT_SUCCEEDED,
23937
+ id: (0, import_core40.generatePrefixedKSUID)("sevt"),
23938
+ type: import_core40.CheckoutEventType.PAYMENT_INTENT_SUCCEEDED,
23568
23939
  created: createdSec,
23569
23940
  method,
23570
23941
  data: { object: richIntent }
@@ -23606,6 +23977,16 @@ function CheckoutModal({
23606
23977
  });
23607
23978
  const showTransferCrypto = enableTransferCrypto ?? projectConfig?.transfer_crypto?.enabled ?? true;
23608
23979
  const showConnectWallet = enableConnectWallet ?? projectConfig?.connect_wallet?.enabled ?? true;
23980
+ const { incident: publicIncident } = usePublicIncident({
23981
+ publishableKey,
23982
+ enabled: open && enableIncidentBanner
23983
+ });
23984
+ const activeIncident = enableIncidentBanner && publicIncident?.enabled && (publicIncident.messages?.length ?? 0) > 0 ? {
23985
+ enabled: true,
23986
+ messages: publicIncident.messages,
23987
+ severity: publicIncident.severity,
23988
+ statusPageUrl: publicIncident.status_page_url
23989
+ } : void 0;
23609
23990
  (0, import_react27.useEffect)(() => {
23610
23991
  if (view === "transfer" && !showTransferCrypto) {
23611
23992
  setView("main");
@@ -23907,7 +24288,15 @@ function CheckoutModal({
23907
24288
  {
23908
24289
  className: view === "wallet_connect" ? "uf-flex uf-min-h-0 uf-flex-col" : void 0,
23909
24290
  children: view === "main" ? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(import_jsx_runtime64.Fragment, { children: [
23910
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(DepositHeader, { title: modalTitle || "Checkout", showClose: true, onClose: handleClose }),
24291
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
24292
+ DepositHeader,
24293
+ {
24294
+ title: modalTitle || "Checkout",
24295
+ showClose: true,
24296
+ onClose: handleClose,
24297
+ incident: activeIncident
24298
+ }
24299
+ ),
23911
24300
  /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
23912
24301
  piLoading ? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "uf-space-y-3", children: [
23913
24302
  /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
@@ -24005,7 +24394,8 @@ function CheckoutModal({
24005
24394
  title: modalTitle || "Checkout",
24006
24395
  showBack: true,
24007
24396
  onBack: handleBack,
24008
- onClose: handleClose
24397
+ onClose: handleClose,
24398
+ incident: activeIncident
24009
24399
  }
24010
24400
  ),
24011
24401
  /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
@@ -24170,12 +24560,12 @@ var import_react32 = require("react");
24170
24560
  var import_lucide_react41 = require("lucide-react");
24171
24561
 
24172
24562
  // src/hooks/use-supported-destination-tokens.ts
24173
- var import_react_query19 = require("@tanstack/react-query");
24174
- var import_core40 = require("@unifold/core");
24563
+ var import_react_query20 = require("@tanstack/react-query");
24564
+ var import_core41 = require("@unifold/core");
24175
24565
  function useSupportedDestinationTokens(publishableKey, enabled = true) {
24176
- return (0, import_react_query19.useQuery)({
24566
+ return (0, import_react_query20.useQuery)({
24177
24567
  queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
24178
- queryFn: () => (0, import_core40.getSupportedDestinationTokens)(publishableKey),
24568
+ queryFn: () => (0, import_core41.getSupportedDestinationTokens)(publishableKey),
24179
24569
  staleTime: 1e3 * 60 * 5,
24180
24570
  gcTime: 1e3 * 60 * 30,
24181
24571
  refetchOnMount: false,
@@ -24185,6 +24575,7 @@ function useSupportedDestinationTokens(publishableKey, enabled = true) {
24185
24575
  }
24186
24576
 
24187
24577
  // src/hooks/use-default-destination-token.ts
24578
+ var STORAGE_KEY3 = "unifold_last_withdraw_to_token";
24188
24579
  function useDefaultDestinationToken({
24189
24580
  destinationTokens,
24190
24581
  defaultDestinationChainType,
@@ -24197,13 +24588,14 @@ function useDefaultDestinationToken({
24197
24588
  defaultChainType: defaultDestinationChainType,
24198
24589
  defaultChainId: defaultDestinationChainId,
24199
24590
  defaultTokenAddress: defaultDestinationTokenAddress,
24200
- defaultSymbol: defaultDestinationSymbol
24591
+ defaultSymbol: defaultDestinationSymbol,
24592
+ storageKey: STORAGE_KEY3
24201
24593
  });
24202
24594
  }
24203
24595
 
24204
24596
  // src/hooks/use-source-token-validation.ts
24205
- var import_react_query20 = require("@tanstack/react-query");
24206
- var import_core41 = require("@unifold/core");
24597
+ var import_react_query21 = require("@tanstack/react-query");
24598
+ var import_core42 = require("@unifold/core");
24207
24599
  function useSourceTokenValidation(params) {
24208
24600
  const {
24209
24601
  sourceChainType,
@@ -24214,7 +24606,7 @@ function useSourceTokenValidation(params) {
24214
24606
  enabled = true
24215
24607
  } = params;
24216
24608
  const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
24217
- return (0, import_react_query20.useQuery)({
24609
+ return (0, import_react_query21.useQuery)({
24218
24610
  queryKey: [
24219
24611
  "unifold",
24220
24612
  "sourceTokenValidation",
@@ -24224,7 +24616,7 @@ function useSourceTokenValidation(params) {
24224
24616
  publishableKey
24225
24617
  ],
24226
24618
  queryFn: async () => {
24227
- const res = await (0, import_core41.getSupportedDepositTokens)(publishableKey);
24619
+ const res = await (0, import_core42.getSupportedDepositTokens)(publishableKey);
24228
24620
  let matchedMinUsd = null;
24229
24621
  let matchedProcessingTime = null;
24230
24622
  let matchedSlippage = null;
@@ -24262,12 +24654,12 @@ function useSourceTokenValidation(params) {
24262
24654
  }
24263
24655
 
24264
24656
  // src/hooks/use-address-balance.ts
24265
- var import_react_query21 = require("@tanstack/react-query");
24266
- var import_core42 = require("@unifold/core");
24657
+ var import_react_query22 = require("@tanstack/react-query");
24658
+ var import_core43 = require("@unifold/core");
24267
24659
  function useAddressBalance(params) {
24268
24660
  const { address, chainType, chainId, tokenAddress, publishableKey, enabled = true } = params;
24269
24661
  const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
24270
- return (0, import_react_query21.useQuery)({
24662
+ return (0, import_react_query22.useQuery)({
24271
24663
  queryKey: [
24272
24664
  "unifold",
24273
24665
  "addressBalance",
@@ -24278,7 +24670,7 @@ function useAddressBalance(params) {
24278
24670
  publishableKey
24279
24671
  ],
24280
24672
  queryFn: async () => {
24281
- const res = await (0, import_core42.getAddressBalance)(
24673
+ const res = await (0, import_core43.getAddressBalance)(
24282
24674
  address,
24283
24675
  chainType,
24284
24676
  chainId,
@@ -24323,13 +24715,13 @@ function useAddressBalance(params) {
24323
24715
  }
24324
24716
 
24325
24717
  // src/hooks/use-executions.ts
24326
- var import_react_query22 = require("@tanstack/react-query");
24327
- var import_core43 = require("@unifold/core");
24718
+ var import_react_query23 = require("@tanstack/react-query");
24719
+ var import_core44 = require("@unifold/core");
24328
24720
  function useExecutions(userId, publishableKey, options) {
24329
- const actionType = options?.actionType ?? import_core43.ActionType.Deposit;
24330
- return (0, import_react_query22.useQuery)({
24721
+ const actionType = options?.actionType ?? import_core44.ActionType.Deposit;
24722
+ return (0, import_react_query23.useQuery)({
24331
24723
  queryKey: ["unifold", "executions", actionType, userId, publishableKey],
24332
- queryFn: () => (0, import_core43.queryExecutions)(userId, publishableKey, actionType),
24724
+ queryFn: () => (0, import_core44.queryExecutions)(userId, publishableKey, actionType),
24333
24725
  enabled: (options?.enabled ?? true) && !!userId,
24334
24726
  refetchInterval: options?.refetchInterval ?? 3e3,
24335
24727
  staleTime: 0,
@@ -24340,7 +24732,7 @@ function useExecutions(userId, publishableKey, options) {
24340
24732
 
24341
24733
  // src/hooks/use-withdraw-polling.ts
24342
24734
  var import_react28 = require("react");
24343
- var import_core44 = require("@unifold/core");
24735
+ var import_core45 = require("@unifold/core");
24344
24736
  var POLL_INTERVAL_MS3 = 2500;
24345
24737
  var POLL_ENDPOINT_INTERVAL_MS2 = 5e3;
24346
24738
  var CUTOFF_BUFFER_MS2 = 6e4;
@@ -24353,8 +24745,8 @@ function useWithdrawPolling({
24353
24745
  onWithdrawError
24354
24746
  }) {
24355
24747
  const createExecutionSuccessEvent = (execution) => ({
24356
- id: (0, import_core44.generatePrefixedKSUID)("sevt"),
24357
- type: import_core44.WithdrawEventType.DIRECT_EXECUTION_SUCCEEDED,
24748
+ id: (0, import_core45.generatePrefixedKSUID)("sevt"),
24749
+ type: import_core45.WithdrawEventType.DIRECT_EXECUTION_SUCCEEDED,
24358
24750
  created: execution.updated_at ? Math.floor(new Date(execution.updated_at).getTime() / 1e3) : execution.created_at ? Math.floor(new Date(execution.created_at).getTime() / 1e3) : Math.floor(Date.now() / 1e3),
24359
24751
  data: { object: mapToDirectExecution(execution) }
24360
24752
  });
@@ -24405,7 +24797,7 @@ function useWithdrawPolling({
24405
24797
  const enabledAt = enabledAtRef.current;
24406
24798
  const poll = async () => {
24407
24799
  try {
24408
- const response = await (0, import_core44.queryExecutions)(userId, publishableKey, import_core44.ActionType.Withdraw);
24800
+ const response = await (0, import_core45.queryExecutions)(userId, publishableKey, import_core45.ActionType.Withdraw);
24409
24801
  const cutoff = new Date(enabledAt.getTime() - CUTOFF_BUFFER_MS2);
24410
24802
  const sorted = [...response.data].sort((a, b) => {
24411
24803
  const tA = a.created_at ? new Date(a.created_at).getTime() : 0;
@@ -24413,11 +24805,11 @@ function useWithdrawPolling({
24413
24805
  return tB - tA;
24414
24806
  });
24415
24807
  const inProgress = [
24416
- import_core44.ExecutionStatus.PENDING,
24417
- import_core44.ExecutionStatus.WAITING,
24418
- import_core44.ExecutionStatus.DELAYED
24808
+ import_core45.ExecutionStatus.PENDING,
24809
+ import_core45.ExecutionStatus.WAITING,
24810
+ import_core45.ExecutionStatus.DELAYED
24419
24811
  ];
24420
- const terminal = [import_core44.ExecutionStatus.SUCCEEDED, import_core44.ExecutionStatus.FAILED];
24812
+ const terminal = [import_core45.ExecutionStatus.SUCCEEDED, import_core45.ExecutionStatus.FAILED];
24421
24813
  let target = null;
24422
24814
  for (const ex of sorted) {
24423
24815
  const t13 = ex.created_at ? new Date(ex.created_at) : null;
@@ -24447,7 +24839,7 @@ function useWithdrawPolling({
24447
24839
  }
24448
24840
  return [...list, ex];
24449
24841
  });
24450
- if (ex.status === import_core44.ExecutionStatus.SUCCEEDED && (!prev || inProgress.includes(prev))) {
24842
+ if (ex.status === import_core45.ExecutionStatus.SUCCEEDED && (!prev || inProgress.includes(prev))) {
24451
24843
  onSuccessRef.current?.({
24452
24844
  message: "Withdrawal completed successfully",
24453
24845
  executionId: ex.id,
@@ -24455,7 +24847,7 @@ function useWithdrawPolling({
24455
24847
  transaction: ex,
24456
24848
  execution: createExecutionSuccessEvent(ex)
24457
24849
  });
24458
- } else if (ex.status === import_core44.ExecutionStatus.FAILED && prev !== import_core44.ExecutionStatus.FAILED) {
24850
+ } else if (ex.status === import_core45.ExecutionStatus.FAILED && prev !== import_core45.ExecutionStatus.FAILED) {
24459
24851
  onErrorRef.current?.({
24460
24852
  message: "Withdrawal failed",
24461
24853
  code: "WITHDRAW_FAILED",
@@ -24484,7 +24876,7 @@ function useWithdrawPolling({
24484
24876
  if (!enabled || !depositWalletId) return;
24485
24877
  const trigger = async () => {
24486
24878
  try {
24487
- await (0, import_core44.pollDirectExecutions)({ deposit_wallet_id: depositWalletId }, publishableKey);
24879
+ await (0, import_core45.pollDirectExecutions)({ deposit_wallet_id: depositWalletId }, publishableKey);
24488
24880
  } catch {
24489
24881
  }
24490
24882
  };
@@ -24653,11 +25045,11 @@ function WithdrawDoubleInput({
24653
25045
  // src/components/withdrawals/WithdrawForm.tsx
24654
25046
  var import_react30 = require("react");
24655
25047
  var import_lucide_react39 = require("lucide-react");
24656
- var import_core49 = require("@unifold/core");
25048
+ var import_core50 = require("@unifold/core");
24657
25049
 
24658
25050
  // src/hooks/use-verify-recipient-address.ts
24659
- var import_react_query23 = require("@tanstack/react-query");
24660
- var import_core45 = require("@unifold/core");
25051
+ var import_react_query24 = require("@tanstack/react-query");
25052
+ var import_core46 = require("@unifold/core");
24661
25053
  function useVerifyRecipientAddress(params) {
24662
25054
  const {
24663
25055
  chainType,
@@ -24669,7 +25061,7 @@ function useVerifyRecipientAddress(params) {
24669
25061
  } = params;
24670
25062
  const trimmedAddress = recipientAddress?.trim() || "";
24671
25063
  const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
24672
- return (0, import_react_query23.useQuery)({
25064
+ return (0, import_react_query24.useQuery)({
24673
25065
  queryKey: [
24674
25066
  "unifold",
24675
25067
  "verifyRecipientAddress",
@@ -24679,7 +25071,7 @@ function useVerifyRecipientAddress(params) {
24679
25071
  trimmedAddress,
24680
25072
  publishableKey
24681
25073
  ],
24682
- queryFn: () => (0, import_core45.verifyRecipientAddress)(
25074
+ queryFn: () => (0, import_core46.verifyRecipientAddress)(
24683
25075
  {
24684
25076
  chain_type: chainType,
24685
25077
  chain_id: chainId,
@@ -24698,7 +25090,7 @@ function useVerifyRecipientAddress(params) {
24698
25090
  }
24699
25091
 
24700
25092
  // src/components/withdrawals/send-withdraw.ts
24701
- var import_core46 = require("@unifold/core");
25093
+ var import_core47 = require("@unifold/core");
24702
25094
  async function sendEvmWithdraw(params) {
24703
25095
  const {
24704
25096
  provider,
@@ -24787,7 +25179,7 @@ async function sendSolanaWithdraw(params) {
24787
25179
  if (!provider.publicKey) {
24788
25180
  await provider.connect();
24789
25181
  }
24790
- const buildResponse = await (0, import_core46.buildSolanaTransaction)(
25182
+ const buildResponse = await (0, import_core47.buildSolanaTransaction)(
24791
25183
  {
24792
25184
  chain_id: "mainnet",
24793
25185
  token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
@@ -24813,7 +25205,7 @@ async function sendSolanaWithdraw(params) {
24813
25205
  for (let i = 0; i < serialized.length; i++) {
24814
25206
  binaryStr += String.fromCharCode(serialized[i]);
24815
25207
  }
24816
- const sendResponse = await (0, import_core46.sendSolanaTransaction)(
25208
+ const sendResponse = await (0, import_core47.sendSolanaTransaction)(
24817
25209
  { chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
24818
25210
  publishableKey
24819
25211
  );
@@ -24914,11 +25306,11 @@ async function detectBrowserWallet(chainType, senderAddress) {
24914
25306
 
24915
25307
  // src/hooks/use-hypercore-withdraw-activation.ts
24916
25308
  var import_react29 = require("react");
24917
- var import_core48 = require("@unifold/core");
25309
+ var import_core49 = require("@unifold/core");
24918
25310
 
24919
25311
  // src/hooks/use-get-deposit-address.ts
24920
- var import_react_query24 = require("@tanstack/react-query");
24921
- var import_core47 = require("@unifold/core");
25312
+ var import_react_query25 = require("@tanstack/react-query");
25313
+ var import_core48 = require("@unifold/core");
24922
25314
  function useGetDepositAddress(params) {
24923
25315
  const {
24924
25316
  userId,
@@ -24931,7 +25323,7 @@ function useGetDepositAddress(params) {
24931
25323
  enabled = true
24932
25324
  } = params;
24933
25325
  const canFire = !!userId && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
24934
- return (0, import_react_query24.useQuery)({
25326
+ return (0, import_react_query25.useQuery)({
24935
25327
  queryKey: [
24936
25328
  "unifold",
24937
25329
  "getDepositAddress",
@@ -24943,7 +25335,7 @@ function useGetDepositAddress(params) {
24943
25335
  actionType ?? null,
24944
25336
  publishableKey
24945
25337
  ],
24946
- queryFn: () => (0, import_core47.getDepositAddress)(
25338
+ queryFn: () => (0, import_core48.getDepositAddress)(
24947
25339
  {
24948
25340
  external_user_id: userId,
24949
25341
  recipient_address: recipientAddress,
@@ -24997,7 +25389,7 @@ function useHypercoreWithdrawActivation(params) {
24997
25389
  destinationChainType,
24998
25390
  destinationChainId,
24999
25391
  destinationTokenAddress,
25000
- actionType: import_core48.ActionType.Withdraw,
25392
+ actionType: import_core49.ActionType.Withdraw,
25001
25393
  enabled: enabled && isHypercore(sourceChainId)
25002
25394
  });
25003
25395
  const depositWalletAddress = (0, import_react29.useMemo)(() => {
@@ -25127,6 +25519,9 @@ function WithdrawForm({
25127
25519
  if (isDebouncing || isVerifyingAddress) return null;
25128
25520
  if (verifyError) return t10.invalidAddress;
25129
25521
  if (addressVerification && !addressVerification.valid) {
25522
+ if (addressVerification.message && addressVerification.message.trim().length > 0) {
25523
+ return addressVerification.message;
25524
+ }
25130
25525
  if (addressVerification.failure_code === "account_not_found")
25131
25526
  return `Account not found on ${selectedChain?.chain_name}`;
25132
25527
  if (addressVerification.failure_code === "not_opted_in")
@@ -25288,7 +25683,7 @@ function WithdrawForm({
25288
25683
  let humanAmount = isMaxed ? balanceData.balanceHuman : toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
25289
25684
  if (isHypercoreChain(sourceChainId)) {
25290
25685
  try {
25291
- const check = await (0, import_core49.checkHypercoreActivation)(
25686
+ const check = await (0, import_core50.checkHypercoreActivation)(
25292
25687
  {
25293
25688
  source_address: senderAddress,
25294
25689
  recipient_address: depositWallet.address
@@ -25737,11 +26132,11 @@ function WithdrawForm({
25737
26132
 
25738
26133
  // src/components/withdrawals/WithdrawExecutionItem.tsx
25739
26134
  var import_lucide_react40 = require("lucide-react");
25740
- var import_core50 = require("@unifold/core");
26135
+ var import_core51 = require("@unifold/core");
25741
26136
  var import_jsx_runtime67 = require("react/jsx-runtime");
25742
26137
  function WithdrawExecutionItem({ execution, onClick }) {
25743
26138
  const { colors: colors2, fonts, components } = useTheme();
25744
- const isPending = execution.status === import_core50.ExecutionStatus.PENDING || execution.status === import_core50.ExecutionStatus.WAITING || execution.status === import_core50.ExecutionStatus.DELAYED;
26139
+ const isPending = execution.status === import_core51.ExecutionStatus.PENDING || execution.status === import_core51.ExecutionStatus.WAITING || execution.status === import_core51.ExecutionStatus.DELAYED;
25745
26140
  const formatDateTime = (timestamp) => {
25746
26141
  try {
25747
26142
  const date = new Date(timestamp);
@@ -25788,7 +26183,7 @@ function WithdrawExecutionItem({ execution, onClick }) {
25788
26183
  /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
25789
26184
  "img",
25790
26185
  {
25791
- src: execution.destination_token_metadata?.icon_url || (0, import_core50.getIconUrl)("/icons/tokens/svg/usdc.svg"),
26186
+ src: execution.destination_token_metadata?.icon_url || (0, import_core51.getIconUrl)("/icons/tokens/svg/usdc.svg"),
25792
26187
  alt: "Token",
25793
26188
  width: 36,
25794
26189
  height: 36,
@@ -26024,7 +26419,7 @@ function WithdrawConfirmingView({
26024
26419
  }
26025
26420
 
26026
26421
  // src/components/withdrawals/WithdrawModal.tsx
26027
- var import_core51 = require("@unifold/core");
26422
+ var import_core52 = require("@unifold/core");
26028
26423
  var import_jsx_runtime69 = require("react/jsx-runtime");
26029
26424
  var t11 = i18n.withdrawModal;
26030
26425
  var getChainKey5 = (chainId, chainType) => `${chainType}:${chainId}`;
@@ -26130,26 +26525,26 @@ function WithdrawModal({
26130
26525
  onWithdrawError
26131
26526
  });
26132
26527
  const { data: allWithdrawalsData } = useExecutions(externalUserId, publishableKey, {
26133
- actionType: import_core51.ActionType.Withdraw,
26528
+ actionType: import_core52.ActionType.Withdraw,
26134
26529
  enabled: open,
26135
26530
  refetchInterval: view === "tracker" || view === "detail" ? 5e3 : 15e3
26136
26531
  });
26137
26532
  const allWithdrawals = allWithdrawalsData?.data ?? [];
26138
26533
  const handleDepositWalletCreation = (0, import_react32.useCallback)(
26139
26534
  async (params) => {
26140
- const { data: wallets } = await (0, import_core51.createDepositAddress)(
26535
+ const { data: wallets } = await (0, import_core52.createDepositAddress)(
26141
26536
  {
26142
26537
  external_user_id: externalUserId,
26143
26538
  destination_chain_type: params.destinationChainType,
26144
26539
  destination_chain_id: params.destinationChainId,
26145
26540
  destination_token_address: params.destinationTokenAddress,
26146
26541
  recipient_address: params.recipientAddress,
26147
- action_type: import_core51.ActionType.Withdraw,
26542
+ action_type: import_core52.ActionType.Withdraw,
26148
26543
  source_chain_type: sourceChainType
26149
26544
  },
26150
26545
  publishableKey
26151
26546
  );
26152
- const depositWallet = (0, import_core51.getWalletByChainType)(wallets, sourceChainType);
26547
+ const depositWallet = (0, import_core52.getWalletByChainType)(wallets, sourceChainType);
26153
26548
  if (!depositWallet) {
26154
26549
  throw new Error(`No deposit wallet available for ${sourceChainType}`);
26155
26550
  }
@@ -26674,6 +27069,7 @@ function WithdrawTokenSelector({ tokens, onSelect, onBack }) {
26674
27069
  useDepositPolling,
26675
27070
  useDepositQuote,
26676
27071
  usePaymentIntent,
27072
+ usePublicIncident,
26677
27073
  useSourceTokenValidation,
26678
27074
  useSupportedDepositTokens,
26679
27075
  useSupportedDestinationTokens,