@unifold/ui-react 0.1.64 → 0.1.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  useRef as useRef9,
8
8
  useMemo as useMemo10
9
9
  } from "react";
10
- import { ChevronRight as ChevronRight14, MapPinOff, AlertTriangle as AlertTriangle2 } from "lucide-react";
10
+ import { ChevronRight as ChevronRight14, MapPinOff, AlertTriangle as AlertTriangle2, Bitcoin, DollarSign as DollarSign3 } from "lucide-react";
11
11
 
12
12
  // src/components/shared/dialog.tsx
13
13
  import * as React3 from "react";
@@ -97,6 +97,22 @@ function clearStoredWalletState() {
97
97
  } catch {
98
98
  }
99
99
  }
100
+ var LAST_OPENED_WALLET_KEY = "unifold_last_opened_wallet";
101
+ function getLastOpenedWallet() {
102
+ if (typeof window === "undefined") return void 0;
103
+ try {
104
+ return localStorage.getItem(LAST_OPENED_WALLET_KEY) ?? void 0;
105
+ } catch {
106
+ return void 0;
107
+ }
108
+ }
109
+ function setLastOpenedWallet(walletId) {
110
+ if (typeof window === "undefined") return;
111
+ try {
112
+ localStorage.setItem(LAST_OPENED_WALLET_KEY, walletId);
113
+ } catch {
114
+ }
115
+ }
100
116
  var MOBILE_VIEWPORT_MEDIA_QUERY = "(max-width: 768px)";
101
117
  function isMobileViewport() {
102
118
  if (typeof window === "undefined") return false;
@@ -959,7 +975,7 @@ function DepositHeader({
959
975
  setShowBalanceSkeleton(false);
960
976
  return;
961
977
  }
962
- const supportedChainTypes = ["ethereum", "solana", "bitcoin"];
978
+ const supportedChainTypes = ["ethereum", "solana", "bitcoin", "n1"];
963
979
  if (!supportedChainTypes.includes(
964
980
  balanceChainType
965
981
  )) {
@@ -11365,7 +11381,7 @@ function useHypercoreActivation(params) {
11365
11381
  publishableKey,
11366
11382
  enabled = true
11367
11383
  } = params;
11368
- const isHypercore2 = destinationChainId === HYPERCORE_CHAIN_ID;
11384
+ const isHypercore2 = String(destinationChainId) === HYPERCORE_CHAIN_ID;
11369
11385
  const recipient = recipientAddress?.trim() ?? "";
11370
11386
  const source = sourceAddress?.trim() ?? "";
11371
11387
  const hasAddresses = !!recipient && !!source;
@@ -12556,9 +12572,56 @@ import {
12556
12572
  ExecutionStatus as ExecutionStatus5,
12557
12573
  buildSolanaTransaction,
12558
12574
  sendSolanaTransaction as sendSolanaTransactionToBackend,
12559
- getWalletMobileDeepLink
12575
+ getWalletMobileDeepLink,
12576
+ checkHypercoreActivation as checkHypercoreActivation2
12560
12577
  } from "@unifold/core";
12561
12578
 
12579
+ // src/lib/send-hypercore.ts
12580
+ import {
12581
+ buildHypercoreTransaction as buildHypercoreTransactionFromBackend,
12582
+ sendHypercoreTransaction as sendHypercoreTransactionToBackend
12583
+ } from "@unifold/core";
12584
+ function isHypercoreChain(chainId) {
12585
+ return chainId === HYPERCORE_CHAIN_ID;
12586
+ }
12587
+ async function sendHypercoreEvmTransfer(params) {
12588
+ const {
12589
+ provider,
12590
+ fromAddress,
12591
+ recipientAddress,
12592
+ sourceTokenAddress,
12593
+ amount,
12594
+ publishableKey
12595
+ } = params;
12596
+ const currentChainHex = await provider.request({
12597
+ method: "eth_chainId",
12598
+ params: []
12599
+ });
12600
+ const activeChainId = String(parseInt(currentChainHex, 16));
12601
+ const buildResult = await buildHypercoreTransactionFromBackend(
12602
+ {
12603
+ signature_chain_id: activeChainId,
12604
+ recipient_address: recipientAddress,
12605
+ token_address: sourceTokenAddress,
12606
+ amount
12607
+ },
12608
+ publishableKey
12609
+ );
12610
+ const signature = await provider.request({
12611
+ method: "eth_signTypedData_v4",
12612
+ params: [fromAddress, JSON.stringify(buildResult.typed_data)]
12613
+ });
12614
+ await sendHypercoreTransactionToBackend(
12615
+ {
12616
+ action_payload: buildResult.action_payload,
12617
+ signature,
12618
+ nonce: buildResult.nonce
12619
+ },
12620
+ publishableKey
12621
+ );
12622
+ return { signature };
12623
+ }
12624
+
12562
12625
  // src/hooks/use-deposit-quote.ts
12563
12626
  import { useQuery as useQuery12 } from "@tanstack/react-query";
12564
12627
  import {
@@ -12991,7 +13054,8 @@ function EnterAmountView({
12991
13054
  onClose,
12992
13055
  quickSelectMode,
12993
13056
  checkoutAmountUsd,
12994
- checkoutReceivedUsd
13057
+ checkoutReceivedUsd,
13058
+ footer
12995
13059
  }) {
12996
13060
  const { colors: colors2, fonts, components } = useTheme();
12997
13061
  const isCheckout = !!checkoutAmountUsd;
@@ -13247,6 +13311,7 @@ function EnterAmountView({
13247
13311
  )
13248
13312
  ] })
13249
13313
  ] }),
13314
+ footer && /* @__PURE__ */ jsx51("div", { className: "uf-shrink-0 uf-pt-2", children: footer }),
13250
13315
  /* @__PURE__ */ jsx51("div", { className: "uf-shrink-0 uf-pt-2", children: /* @__PURE__ */ jsx51(
13251
13316
  "button",
13252
13317
  {
@@ -13708,7 +13773,7 @@ var WALLET_ICONS3 = {
13708
13773
  };
13709
13774
  var FALLBACK_WALLET_DEFINITIONS = [
13710
13775
  { id: "phantom", name: "Phantom", networks: ["ethereum", "solana"], installUrl: "https://phantom.app/", supportsMobileBrowse: true },
13711
- { id: "coinbase", name: "Coinbase Wallet", networks: ["ethereum", "solana"], installUrl: "https://www.coinbase.com/wallet", supportsMobileBrowse: true },
13776
+ { id: "coinbase", name: "Coinbase Wallet", networks: ["ethereum"], installUrl: "https://www.coinbase.com/wallet", supportsMobileBrowse: true },
13712
13777
  { id: "trust", name: "Trust Wallet", networks: ["ethereum", "solana"], installUrl: "https://trustwallet.com/", supportsMobileBrowse: true },
13713
13778
  { id: "metamask", name: "MetaMask", networks: ["ethereum"], installUrl: "https://metamask.io/download/", supportsMobileBrowse: true },
13714
13779
  { id: "rainbow", name: "Rainbow", networks: ["ethereum"], installUrl: "https://rainbow.me/", supportsMobileBrowse: true },
@@ -13768,7 +13833,7 @@ function getLegacyEvmProviders() {
13768
13833
  okxEthereum: win.okxwallet
13769
13834
  };
13770
13835
  }
13771
- function detectAvailableWallets(definitions, filterChainType) {
13836
+ function detectAvailableWallets(definitions, recentWalletId, filterChainType) {
13772
13837
  const solProviders = getSolanaProviders();
13773
13838
  const legacyEvm = getLegacyEvmProviders();
13774
13839
  const eip6963List = getEip6963Providers();
@@ -13794,7 +13859,7 @@ function detectAvailableWallets(definitions, filterChainType) {
13794
13859
  return false;
13795
13860
  }
13796
13861
  });
13797
- return definitions.filter((w) => !filterChainType || w.networks.includes(filterChainType)).map((wallet) => {
13862
+ const sorted = definitions.filter((w) => !filterChainType || w.networks.includes(filterChainType)).map((wallet) => {
13798
13863
  let isInstalled = false;
13799
13864
  const detectedNetworks = [];
13800
13865
  switch (wallet.id) {
@@ -13817,8 +13882,6 @@ function detectAvailableWallets(definitions, filterChainType) {
13817
13882
  isInstalled = true;
13818
13883
  detectedNetworks.push("ethereum");
13819
13884
  }
13820
- if (solProviders.coinbaseSolana || win?.coinbaseWalletExtension?.solana) detectedNetworks.push("solana");
13821
- if (isInstalled && wallet.networks.includes("solana") && !detectedNetworks.includes("solana")) detectedNetworks.push("solana");
13822
13885
  break;
13823
13886
  case "trust":
13824
13887
  if (hasEip6963("trust") || legacyEvm.trustEthereum || legacyEvm.ethereum?.isTrust || win?.trustwallet) {
@@ -13855,11 +13918,17 @@ function detectAvailableWallets(definitions, filterChainType) {
13855
13918
  }
13856
13919
  return { ...wallet, isInstalled, detectedNetworks };
13857
13920
  }).sort((a, b) => {
13921
+ if (recentWalletId) {
13922
+ const aRecent = a.id === recentWalletId ? 1 : 0;
13923
+ const bRecent = b.id === recentWalletId ? 1 : 0;
13924
+ if (aRecent !== bRecent) return bRecent - aRecent;
13925
+ }
13858
13926
  if (a.isInstalled && !b.isInstalled) return -1;
13859
13927
  if (!a.isInstalled && b.isInstalled) return 1;
13860
13928
  if (a.isInstalled && b.isInstalled) return b.networks.length - a.networks.length;
13861
13929
  return 0;
13862
13930
  });
13931
+ return sorted;
13863
13932
  }
13864
13933
  function WalletConnect({
13865
13934
  walletInfo: initialWalletInfo,
@@ -13934,9 +14003,15 @@ function WalletConnect({
13934
14003
  })) : FALLBACK_WALLET_DEFINITIONS,
13935
14004
  [backendWallets]
13936
14005
  );
14006
+ const [recentWalletId, setRecentWalletIdState] = React30.useState(getLastOpenedWallet);
14007
+ React30.useEffect(() => {
14008
+ if (view === "select_wallet") {
14009
+ setRecentWalletIdState(getLastOpenedWallet());
14010
+ }
14011
+ }, [view]);
13937
14012
  const availableWallets = React30.useMemo(
13938
- () => detectAvailableWallets(walletDefinitions),
13939
- [walletDefinitions, eip6963ProviderCount]
14013
+ () => detectAvailableWallets(walletDefinitions, recentWalletId),
14014
+ [walletDefinitions, eip6963ProviderCount, recentWalletId]
13940
14015
  );
13941
14016
  const [isMobile, setIsMobile] = React30.useState(false);
13942
14017
  React30.useEffect(() => {
@@ -13996,7 +14071,7 @@ function WalletConnect({
13996
14071
  const chainType = activeDepositWallet?.chain_type ?? "ethereum";
13997
14072
  const recipientAddress = activeDepositWallet?.address ?? "";
13998
14073
  const isCheckoutMode = !!checkoutAmountUsd;
13999
- const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
14074
+ const supportedChainType = chainType === "algorand" || chainType === "xrpl" || chainType === "cardano" || chainType === "n1" ? "ethereum" : chainType;
14000
14075
  const transitionTo = React30.useCallback((nextView) => {
14001
14076
  if (nextView === viewRef.current) return;
14002
14077
  setIsTransitioning(true);
@@ -14020,6 +14095,8 @@ function WalletConnect({
14020
14095
  );
14021
14096
  if (res.deeplink) {
14022
14097
  setMobileRedirect({ walletId: wallet.id, walletName: wallet.name, deeplink: res.deeplink });
14098
+ setLastOpenedWallet(wallet.id);
14099
+ setRecentWalletIdState(wallet.id);
14023
14100
  setAwaitingMobileDeposit(true);
14024
14101
  transitionTo("mobile_redirect");
14025
14102
  window.location.href = res.deeplink;
@@ -14080,6 +14157,8 @@ function WalletConnect({
14080
14157
  const handleConnectWallet = async (wallet, network) => {
14081
14158
  setConnectingNetwork(network);
14082
14159
  transitionTo("connecting");
14160
+ setLastOpenedWallet(wallet.id);
14161
+ setRecentWalletIdState(wallet.id);
14083
14162
  setWalletError(null);
14084
14163
  setIsWalletConnecting(true);
14085
14164
  try {
@@ -14184,6 +14263,13 @@ function WalletConnect({
14184
14263
  }
14185
14264
  };
14186
14265
  const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
14266
+ const { needsActivation: hypercoreNeedsActivation, activationFee: hypercoreActivationFee, sponsored: hypercoreActivationSponsored } = useHypercoreActivation({
14267
+ recipientAddress,
14268
+ sourceAddress: activeWalletInfo?.address,
14269
+ destinationChainId: selectedToken?.chain_id,
14270
+ publishableKey,
14271
+ enabled: !!activeWalletInfo && !!recipientAddress
14272
+ });
14187
14273
  const effectiveDestinationAmount = React30.useMemo(() => {
14188
14274
  if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
14189
14275
  if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
@@ -14288,7 +14374,7 @@ function WalletConnect({
14288
14374
  let cancelled = false;
14289
14375
  setIsLoading(true);
14290
14376
  setError(null);
14291
- const sct = activeDepositWallet.chain_type === "algorand" || activeDepositWallet.chain_type === "xrpl" ? "ethereum" : activeDepositWallet.chain_type;
14377
+ const sct = activeDepositWallet.chain_type === "algorand" || activeDepositWallet.chain_type === "xrpl" || activeDepositWallet.chain_type === "cardano" || activeDepositWallet.chain_type === "n1" ? "ethereum" : activeDepositWallet.chain_type;
14292
14378
  getAddressBalances2(activeWalletInfo.address, sct, publishableKey).then((response) => {
14293
14379
  if (cancelled) return;
14294
14380
  const nonZero = response.balances.filter((b) => b.amount !== "0");
@@ -14454,9 +14540,16 @@ function WalletConnect({
14454
14540
  const [integerPart = "0", decimalPart = ""] = amountStr.trim().split(".");
14455
14541
  return (integerPart + decimalPart.padEnd(decimals, "0").slice(0, decimals)).replace(/^0+/, "") || "0";
14456
14542
  };
14457
- const sendEthereumTransaction = async (token, amountStr) => {
14458
- if (!recipientAddress || !/^0x[a-fA-F0-9]{40}$/.test(recipientAddress)) throw new Error(`Invalid recipient address.`);
14459
- const walletIdMap = { "phantom-ethereum": "phantom", coinbase: "coinbase", trust: "trust", okx: "okx", rainbow: "rainbow", rabby: "rabby", metamask: "metamask" };
14543
+ const resolveEvmProvider = () => {
14544
+ const walletIdMap = {
14545
+ "phantom-ethereum": "phantom",
14546
+ coinbase: "coinbase",
14547
+ trust: "trust",
14548
+ okx: "okx",
14549
+ rainbow: "rainbow",
14550
+ rabby: "rabby",
14551
+ metamask: "metamask"
14552
+ };
14460
14553
  const lookupId = walletIdMap[walletInfo.type] || walletInfo.type;
14461
14554
  const eip6963Match = findProviderByWalletId(lookupId);
14462
14555
  let provider = eip6963Match?.provider;
@@ -14465,6 +14558,11 @@ function WalletConnect({
14465
14558
  else if (walletInfo.type === "coinbase") provider = window.coinbaseWalletExtension || window.ethereum;
14466
14559
  else provider = window.ethereum;
14467
14560
  }
14561
+ return provider;
14562
+ };
14563
+ const sendEthereumTransaction = async (token, amountStr) => {
14564
+ if (!recipientAddress || !/^0x[a-fA-F0-9]{40}$/.test(recipientAddress)) throw new Error(`Invalid recipient address.`);
14565
+ const provider = resolveEvmProvider();
14468
14566
  if (!provider) throw new Error("Ethereum wallet not found");
14469
14567
  const currentChainIdHex = await provider.request({ method: "eth_chainId", params: [] });
14470
14568
  if (parseInt(currentChainIdHex, 16).toString() !== token.chain_id) {
@@ -14529,6 +14627,19 @@ function WalletConnect({
14529
14627
  const resp = await sendSolanaTransactionToBackend({ chain_id: "mainnet", signed_transaction: btoa(bs) }, publishableKey);
14530
14628
  return resp.signature;
14531
14629
  };
14630
+ const sendHypercoreDeposit = async (token, amountStr) => {
14631
+ const provider = resolveEvmProvider();
14632
+ if (!provider) throw new Error("Ethereum wallet not found");
14633
+ const { signature } = await sendHypercoreEvmTransfer({
14634
+ provider,
14635
+ fromAddress: walletInfo.address,
14636
+ recipientAddress,
14637
+ sourceTokenAddress: token.token_address,
14638
+ amount: amountStr,
14639
+ publishableKey
14640
+ });
14641
+ return signature;
14642
+ };
14532
14643
  const handleConfirm = async () => {
14533
14644
  if (!hasWallet || !selectedBalance || !amountUsd || tokenAmount === 0 || !recipientAddress) return;
14534
14645
  const token = getTokenFromBalance(selectedBalance);
@@ -14548,7 +14659,33 @@ function WalletConnect({
14548
14659
  setIsConfirming(true);
14549
14660
  setError(null);
14550
14661
  try {
14551
- const txHash = token.chain_type === "solana" ? await sendSolanaTransaction(token, tokenAmount.toString()) : await sendEthereumTransaction(token, tokenAmount.toString());
14662
+ const isHypercoreToken = String(token.chain_id) === HYPERCORE_CHAIN_ID;
14663
+ let txHash;
14664
+ if (token.chain_type === "solana") {
14665
+ txHash = await sendSolanaTransaction(token, tokenAmount.toString());
14666
+ } else if (isHypercoreToken) {
14667
+ let sendAmount = tokenAmount;
14668
+ try {
14669
+ const activation = await checkHypercoreActivation2(
14670
+ { source_address: walletInfo.address, recipient_address: recipientAddress },
14671
+ publishableKey
14672
+ );
14673
+ if (!activation.user_exists) {
14674
+ const fee = activation.activation_fee;
14675
+ if (!Number.isFinite(tokenAmount) || tokenAmount <= fee) {
14676
+ throw new Error(
14677
+ `Insufficient amount. A ${fee} USDC activation fee is required for the first transfer to this address.`
14678
+ );
14679
+ }
14680
+ sendAmount = tokenAmount - fee;
14681
+ }
14682
+ } catch (e) {
14683
+ if (e instanceof Error && e.message.includes("activation fee")) throw e;
14684
+ }
14685
+ txHash = await sendHypercoreDeposit(token, sendAmount.toString());
14686
+ } else {
14687
+ txHash = await sendEthereumTransaction(token, tokenAmount.toString());
14688
+ }
14552
14689
  setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
14553
14690
  setHasSignedTransaction(true);
14554
14691
  handleIveDeposited();
@@ -14587,7 +14724,10 @@ function WalletConnect({
14587
14724
  children: [
14588
14725
  /* @__PURE__ */ jsxs48("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
14589
14726
  WALLET_ICONS3[wallet.id] ? /* @__PURE__ */ jsx54(WalletIconWithNetwork, { WalletIcon: WALLET_ICONS3[wallet.id], networks: wallet.networks, size: 40, className: "uf-rounded-lg" }) : /* @__PURE__ */ jsx54("div", { className: "uf-w-10 uf-h-10 uf-rounded-lg uf-bg-gray-500" }),
14590
- /* @__PURE__ */ jsx54("div", { className: "uf-text-sm uf-font-medium", style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: wallet.name })
14727
+ /* @__PURE__ */ jsxs48("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
14728
+ /* @__PURE__ */ jsx54("div", { className: "uf-text-sm uf-font-medium", style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: wallet.name }),
14729
+ wallet.id === recentWalletId && /* @__PURE__ */ jsx54("span", { className: "uf-text-xs uf-px-2 uf-py-0.5 uf-rounded-full", style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium }, children: "Last used" })
14730
+ ] })
14591
14731
  ] }),
14592
14732
  isPending ? /* @__PURE__ */ jsx54(Loader28, { className: "uf-w-4 uf-h-4 uf-animate-spin", style: { color: colors2.primary } }) : wallet.isInstalled ? /* @__PURE__ */ jsx54("span", { className: "uf-text-xs uf-px-2 uf-py-1 uf-rounded-full", style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium }, children: "Detected" }) : /* @__PURE__ */ jsxs48("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
14593
14733
  /* @__PURE__ */ jsx54("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: showOpenInApp ? "Open" : "Install" }),
@@ -14766,7 +14906,7 @@ function WalletConnect({
14766
14906
  }
14767
14907
  if (view === "enter_amount" && selectedToken && selectedBalance) {
14768
14908
  return /* @__PURE__ */ jsx54(AccentColorOverride, { accentColor: walletAccent, accentForeground: walletAccentForeground, children: /* @__PURE__ */ jsx54("div", { style: viewTransitionStyle, children: /* @__PURE__ */ jsx54(EnterAmountView, { walletInfo, selectedBalance, selectedToken, amountUsd, formattedTokenAmount, tokenChainDetails, inputUsdNum, maxUsdAmount, isValidAmount, error, onAmountChange: setAmountUsd, onMaxClick: handleMaxClick, onReview: handleReview, onBack: handleBack, onClose: onClose ?? (() => {
14769
- }), quickSelectMode: amountQuickSelect, checkoutAmountUsd, checkoutReceivedUsd }) }) });
14909
+ }), quickSelectMode: amountQuickSelect, checkoutAmountUsd, checkoutReceivedUsd, footer: hypercoreNeedsActivation && !hypercoreActivationSponsored ? /* @__PURE__ */ jsx54(HypercoreActivationWarning, { activationFee: hypercoreActivationFee }) : void 0 }) }) });
14770
14910
  }
14771
14911
  if (view === "review" && selectedToken) {
14772
14912
  return /* @__PURE__ */ jsx54(AccentColorOverride, { accentColor: walletAccent, accentForeground: walletAccentForeground, children: /* @__PURE__ */ jsx54("div", { style: viewTransitionStyle, children: /* @__PURE__ */ jsx54(ReviewView, { walletInfo, recipientAddress, assetCdnUrl, selectedToken, amountUsd, formattedTokenAmount, tokenChainDetails, loadingTokenDetails, showTransactionDetails, isConfirming, error, onToggleDetails: () => setShowTransactionDetails(!showTransactionDetails), onConfirm: handleConfirm, onBack: handleBack, onClose: onClose ?? (() => {
@@ -14805,6 +14945,9 @@ function SkeletonButton({
14805
14945
  ] });
14806
14946
  }
14807
14947
  var t7 = i18n.depositModal;
14948
+ function depositTabForScreen(screen) {
14949
+ return screen === "card" || screen === "cashapp" ? "cash" : "crypto";
14950
+ }
14808
14951
  function DepositModal({
14809
14952
  open,
14810
14953
  onOpenChange,
@@ -14840,6 +14983,7 @@ function DepositModal({
14840
14983
  theme = "dark",
14841
14984
  hideOverlay = false,
14842
14985
  initialScreen = "main",
14986
+ displayMode = "stacked",
14843
14987
  transferCryptoTitle = t7.transferCrypto.title,
14844
14988
  depositWithCardTitle = t7.depositWithCard.title,
14845
14989
  payWithExchangeTitle = t7.payWithExchange.title,
@@ -14874,6 +15018,9 @@ function DepositModal({
14874
15018
  effectiveInitialScreen
14875
15019
  );
14876
15020
  const [coinbaseSkipToHoldings, setCoinbaseSkipToHoldings] = useState32(false);
15021
+ const [depositTab, setDepositTab] = useState32(
15022
+ () => depositTabForScreen(effectiveInitialScreen)
15023
+ );
14877
15024
  const resetViewTimeoutRef = useRef9(null);
14878
15025
  const [cardView, setCardView] = useState32(
14879
15026
  "amount"
@@ -15171,6 +15318,7 @@ function DepositModal({
15171
15318
  resetViewTimeoutRef.current = null;
15172
15319
  }
15173
15320
  setView(effectiveInitialScreen);
15321
+ setDepositTab(depositTabForScreen(effectiveInitialScreen));
15174
15322
  setCardView("amount");
15175
15323
  setExchangeView("providers");
15176
15324
  setBrowserWalletInfo(null);
@@ -15199,6 +15347,7 @@ function DepositModal({
15199
15347
  } else if (view === "cashapp" && cashAppView !== "amount") {
15200
15348
  setCashAppView("amount");
15201
15349
  } else {
15350
+ setDepositTab(depositTabForScreen(view));
15202
15351
  setView("main");
15203
15352
  setCardView("amount");
15204
15353
  setExchangeView("providers");
@@ -15278,6 +15427,184 @@ function DepositModal({
15278
15427
  className: "uf-flex uf-justify-center uf-shrink-0"
15279
15428
  }
15280
15429
  ) });
15430
+ const transferCryptoMenuButton = showTransferCrypto ? /* @__PURE__ */ jsx55(
15431
+ TransferCryptoButton,
15432
+ {
15433
+ onClick: () => setView("transfer"),
15434
+ title: transferCryptoTitle,
15435
+ subtitle: t7.transferCrypto.subtitle,
15436
+ featuredTokens: projectConfig?.transfer_crypto.networks
15437
+ },
15438
+ "transfer"
15439
+ ) : null;
15440
+ const connectWalletMenuButton = showConnectWallet ? /* @__PURE__ */ jsx55(
15441
+ BrowserWalletButton,
15442
+ {
15443
+ onClick: handleBrowserWalletClick,
15444
+ onConnectClick: handleWalletConnectClick,
15445
+ onDisconnect: handleWalletDisconnect,
15446
+ chainType: browserWalletChainType,
15447
+ publishableKey,
15448
+ featuredWallets: projectConfig?.connect_wallet?.wallets
15449
+ },
15450
+ "wallet"
15451
+ ) : null;
15452
+ const depositWithCardMenuButton = showFiatOnramp ? /* @__PURE__ */ jsx55(
15453
+ DepositWithCardButton,
15454
+ {
15455
+ onClick: () => setView("card"),
15456
+ title: depositWithCardTitle,
15457
+ subtitle: t7.depositWithCard.subtitle,
15458
+ paymentNetworks: projectConfig?.payment_networks.networks
15459
+ },
15460
+ "card"
15461
+ ) : null;
15462
+ const payWithExchangeMenuButton = showPayWithExchange ? /* @__PURE__ */ jsx55(
15463
+ PayWithExchangeButton,
15464
+ {
15465
+ onClick: () => setView("exchange"),
15466
+ title: payWithExchangeTitle,
15467
+ subtitle: t7.payWithExchange.subtitle,
15468
+ exchanges,
15469
+ loading: exchangesLoading
15470
+ },
15471
+ "exchange"
15472
+ ) : null;
15473
+ const connectExchangeMenuButton = showConnectExchange && connectedExchange ? /* @__PURE__ */ jsx55(
15474
+ ConnectExchangeButton,
15475
+ {
15476
+ onClick: () => {
15477
+ setCoinbaseSkipToHoldings(true);
15478
+ setView("coinbase_connect");
15479
+ },
15480
+ onDisconnect: handleExchangeDisconnect,
15481
+ title: i18n.connectExchange.title,
15482
+ subtitle: i18n.connectExchange.subtitle,
15483
+ exchanges: integrationExchanges,
15484
+ connectedExchange
15485
+ },
15486
+ "connect-exchange"
15487
+ ) : showConnectExchange && !connectedExchange ? /* @__PURE__ */ jsx55(
15488
+ ConnectExchangeButton,
15489
+ {
15490
+ onClick: () => {
15491
+ setCoinbaseSkipToHoldings(false);
15492
+ setView("coinbase_connect");
15493
+ },
15494
+ title: i18n.connectExchange.title,
15495
+ subtitle: i18n.connectExchange.subtitle,
15496
+ exchanges: integrationExchanges
15497
+ },
15498
+ "connect-exchange"
15499
+ ) : null;
15500
+ const cashAppMenuButton = showCashApp ? /* @__PURE__ */ jsx55(
15501
+ CashAppButton,
15502
+ {
15503
+ onClick: () => setView("cashapp"),
15504
+ title: "Pay with Cash App",
15505
+ subtitle: "Deposit via Cash App",
15506
+ iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0
15507
+ },
15508
+ "cashapp"
15509
+ ) : null;
15510
+ const depositTrackerMenuButton = showDepositTracker ? /* @__PURE__ */ jsx55(
15511
+ DepositTrackerButton,
15512
+ {
15513
+ onClick: () => {
15514
+ setAllExecutions(depositExecutions);
15515
+ setView("tracker");
15516
+ },
15517
+ title: depositTrackerTitle,
15518
+ subtitle: depositTrackerSubTitle,
15519
+ badge: depositExecutions.length > 0 ? depositExecutions.length : void 0
15520
+ },
15521
+ "tracker"
15522
+ ) : null;
15523
+ const cryptoMenuButtons = [
15524
+ transferCryptoMenuButton,
15525
+ connectWalletMenuButton,
15526
+ payWithExchangeMenuButton,
15527
+ connectExchangeMenuButton
15528
+ ].filter(Boolean);
15529
+ const cashMenuButtons = [
15530
+ depositWithCardMenuButton,
15531
+ cashAppMenuButton
15532
+ ].filter(Boolean);
15533
+ const depositTabs = [
15534
+ { id: "crypto", label: "Use Crypto", icon: Bitcoin, buttons: cryptoMenuButtons },
15535
+ { id: "cash", label: "Use Cash", icon: DollarSign3, buttons: cashMenuButtons }
15536
+ ].filter((tab) => tab.buttons.length > 0);
15537
+ const activeDepositTab = depositTabs.find((tab) => tab.id === depositTab) ?? depositTabs[0];
15538
+ const renderMainMenuBody = () => {
15539
+ if (depositPrerequisiteBody) {
15540
+ return /* @__PURE__ */ jsx55("div", { className: "uf-space-y-3", children: depositPrerequisiteBody });
15541
+ }
15542
+ if (displayMode === "tabs" && activeDepositTab) {
15543
+ return /* @__PURE__ */ jsxs49("div", { children: [
15544
+ depositTabs.length > 1 && /* @__PURE__ */ jsx55(
15545
+ "div",
15546
+ {
15547
+ className: "uf-flex uf-gap-1 uf-p-1 uf-rounded-xl uf-mb-3",
15548
+ style: {
15549
+ // Frosted-glass track: a translucent fill plus a backdrop blur so
15550
+ // the control reads as a soft surface rather than a solid bar.
15551
+ backgroundColor: `color-mix(in srgb, ${colors2.card} 55%, transparent)`,
15552
+ backdropFilter: "blur(12px)",
15553
+ WebkitBackdropFilter: "blur(12px)"
15554
+ },
15555
+ role: "tablist",
15556
+ children: depositTabs.map((tab) => {
15557
+ const active = activeDepositTab.id === tab.id;
15558
+ const TabIcon = tab.icon;
15559
+ return /* @__PURE__ */ jsxs49(
15560
+ "button",
15561
+ {
15562
+ type: "button",
15563
+ role: "tab",
15564
+ "aria-selected": active,
15565
+ onClick: () => setDepositTab(tab.id),
15566
+ className: "uf-flex-1 uf-py-2 uf-px-3 uf-rounded-lg uf-text-sm uf-transition-all uf-flex uf-items-center uf-justify-center uf-gap-1.5",
15567
+ style: {
15568
+ backgroundColor: active ? `color-mix(in srgb, ${colors2.primary} 22%, transparent)` : "transparent",
15569
+ backdropFilter: active ? "blur(8px)" : void 0,
15570
+ WebkitBackdropFilter: active ? "blur(8px)" : void 0,
15571
+ boxShadow: active ? `0 1px 8px color-mix(in srgb, ${colors2.primary} 25%, transparent)` : void 0,
15572
+ color: active ? colors2.foreground : colors2.foregroundMuted,
15573
+ fontFamily: fonts.medium
15574
+ },
15575
+ children: [
15576
+ /* @__PURE__ */ jsx55(
15577
+ "span",
15578
+ {
15579
+ className: "uf-inline-flex uf-items-center uf-justify-center uf-rounded-full uf-w-5 uf-h-5 uf-flex-shrink-0",
15580
+ style: {
15581
+ backgroundColor: active ? colors2.foreground : colors2.foregroundMuted
15582
+ },
15583
+ children: /* @__PURE__ */ jsx55(TabIcon, { size: 12, style: { color: active ? colors2.background : colors2.background }, strokeWidth: 2.5 })
15584
+ }
15585
+ ),
15586
+ tab.label
15587
+ ]
15588
+ },
15589
+ tab.id
15590
+ );
15591
+ })
15592
+ }
15593
+ ),
15594
+ /* @__PURE__ */ jsx55("div", { className: "uf-space-y-3", children: activeDepositTab.buttons }),
15595
+ depositTrackerMenuButton && /* @__PURE__ */ jsx55("div", { className: "uf-mt-3", children: depositTrackerMenuButton })
15596
+ ] });
15597
+ }
15598
+ return /* @__PURE__ */ jsxs49("div", { className: "uf-space-y-3", children: [
15599
+ transferCryptoMenuButton,
15600
+ connectWalletMenuButton,
15601
+ depositWithCardMenuButton,
15602
+ payWithExchangeMenuButton,
15603
+ connectExchangeMenuButton,
15604
+ cashAppMenuButton,
15605
+ depositTrackerMenuButton
15606
+ ] });
15607
+ };
15281
15608
  return /* @__PURE__ */ jsx55(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ jsx55(
15282
15609
  Dialog,
15283
15610
  {
@@ -15304,7 +15631,7 @@ function DepositModal({
15304
15631
  onClose: handleClose,
15305
15632
  showBalance: showBalanceHeader,
15306
15633
  balanceAddress: recipientAddress,
15307
- balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
15634
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
15308
15635
  balanceChainId: destinationChainId,
15309
15636
  balanceTokenAddress: destinationTokenAddress,
15310
15637
  projectName: projectConfig?.project_name,
@@ -15312,94 +15639,7 @@ function DepositModal({
15312
15639
  }
15313
15640
  ),
15314
15641
  /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
15315
- /* @__PURE__ */ jsx55("div", { className: "uf-space-y-3", children: depositPrerequisiteBody ?? /* @__PURE__ */ jsxs49(Fragment11, { children: [
15316
- showTransferCrypto && /* @__PURE__ */ jsx55(
15317
- TransferCryptoButton,
15318
- {
15319
- onClick: () => setView("transfer"),
15320
- title: transferCryptoTitle,
15321
- subtitle: t7.transferCrypto.subtitle,
15322
- featuredTokens: projectConfig?.transfer_crypto.networks
15323
- }
15324
- ),
15325
- showConnectWallet && /* @__PURE__ */ jsx55(
15326
- BrowserWalletButton,
15327
- {
15328
- onClick: handleBrowserWalletClick,
15329
- onConnectClick: handleWalletConnectClick,
15330
- onDisconnect: handleWalletDisconnect,
15331
- chainType: browserWalletChainType,
15332
- publishableKey,
15333
- featuredWallets: projectConfig?.connect_wallet?.wallets
15334
- }
15335
- ),
15336
- showFiatOnramp && /* @__PURE__ */ jsx55(
15337
- DepositWithCardButton,
15338
- {
15339
- onClick: () => setView("card"),
15340
- title: depositWithCardTitle,
15341
- subtitle: t7.depositWithCard.subtitle,
15342
- paymentNetworks: projectConfig?.payment_networks.networks
15343
- }
15344
- ),
15345
- showPayWithExchange && /* @__PURE__ */ jsx55(
15346
- PayWithExchangeButton,
15347
- {
15348
- onClick: () => setView("exchange"),
15349
- title: payWithExchangeTitle,
15350
- subtitle: t7.payWithExchange.subtitle,
15351
- exchanges,
15352
- loading: exchangesLoading
15353
- }
15354
- ),
15355
- showConnectExchange && connectedExchange && /* @__PURE__ */ jsx55(
15356
- ConnectExchangeButton,
15357
- {
15358
- onClick: () => {
15359
- setCoinbaseSkipToHoldings(true);
15360
- setView("coinbase_connect");
15361
- },
15362
- onDisconnect: handleExchangeDisconnect,
15363
- title: i18n.connectExchange.title,
15364
- subtitle: i18n.connectExchange.subtitle,
15365
- exchanges: integrationExchanges,
15366
- connectedExchange
15367
- }
15368
- ),
15369
- showConnectExchange && !connectedExchange && /* @__PURE__ */ jsx55(
15370
- ConnectExchangeButton,
15371
- {
15372
- onClick: () => {
15373
- setCoinbaseSkipToHoldings(false);
15374
- setView("coinbase_connect");
15375
- },
15376
- title: i18n.connectExchange.title,
15377
- subtitle: i18n.connectExchange.subtitle,
15378
- exchanges: integrationExchanges
15379
- }
15380
- ),
15381
- showCashApp && /* @__PURE__ */ jsx55(
15382
- CashAppButton,
15383
- {
15384
- onClick: () => setView("cashapp"),
15385
- title: "Pay with Cash App",
15386
- subtitle: "Deposit via Cash App",
15387
- iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0
15388
- }
15389
- ),
15390
- showDepositTracker && /* @__PURE__ */ jsx55(
15391
- DepositTrackerButton,
15392
- {
15393
- onClick: () => {
15394
- setAllExecutions(depositExecutions);
15395
- setView("tracker");
15396
- },
15397
- title: depositTrackerTitle,
15398
- subtitle: depositTrackerSubTitle,
15399
- badge: depositExecutions.length > 0 ? depositExecutions.length : void 0
15400
- }
15401
- )
15402
- ] }) }),
15642
+ renderMainMenuBody(),
15403
15643
  depositPoweredByFooter
15404
15644
  ] })
15405
15645
  ] }) : view === "transfer" ? /* @__PURE__ */ jsxs49(Fragment11, { children: [
@@ -15412,7 +15652,7 @@ function DepositModal({
15412
15652
  onClose: handleClose,
15413
15653
  showBalance: showBalanceHeader,
15414
15654
  balanceAddress: recipientAddress,
15415
- balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
15655
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
15416
15656
  balanceChainId: destinationChainId,
15417
15657
  balanceTokenAddress: destinationTokenAddress,
15418
15658
  projectName: projectConfig?.project_name,
@@ -15500,7 +15740,7 @@ function DepositModal({
15500
15740
  badge: cardView === "quotes" ? { count: quotesCount } : void 0,
15501
15741
  showBalance: showBalanceHeader,
15502
15742
  balanceAddress: recipientAddress,
15503
- balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
15743
+ balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" || destinationChainType === "n1" ? destinationChainType : void 0,
15504
15744
  balanceChainId: destinationChainId,
15505
15745
  balanceTokenAddress: destinationTokenAddress,
15506
15746
  projectName: projectConfig?.project_name,
@@ -16828,13 +17068,13 @@ import {
16828
17068
  ChevronUp as ChevronUp7,
16829
17069
  Clock as Clock5,
16830
17070
  ClipboardPaste,
16831
- DollarSign as DollarSign3,
17071
+ DollarSign as DollarSign4,
16832
17072
  Loader2 as Loader29,
16833
17073
  ShieldCheck as ShieldCheck3,
16834
17074
  Wallet as Wallet3
16835
17075
  } from "lucide-react";
16836
17076
  import {
16837
- checkHypercoreActivation as checkHypercoreActivation2
17077
+ checkHypercoreActivation as checkHypercoreActivation3
16838
17078
  } from "@unifold/core";
16839
17079
 
16840
17080
  // src/hooks/use-verify-recipient-address.ts
@@ -16882,9 +17122,7 @@ function useVerifyRecipientAddress(params) {
16882
17122
  // src/components/withdrawals/send-withdraw.ts
16883
17123
  import {
16884
17124
  buildSolanaTransaction as buildSolanaTransaction2,
16885
- sendSolanaTransaction as sendSolanaTransactionToBackend2,
16886
- buildHypercoreTransaction as buildHypercoreTransactionFromBackend,
16887
- sendHypercoreTransaction as sendHypercoreTransactionToBackend
17125
+ sendSolanaTransaction as sendSolanaTransactionToBackend2
16888
17126
  } from "@unifold/core";
16889
17127
  async function sendEvmWithdraw(params) {
16890
17128
  const {
@@ -16995,50 +17233,15 @@ async function sendSolanaWithdraw(params) {
16995
17233
  );
16996
17234
  return sendResponse.signature;
16997
17235
  }
16998
- var HYPERCORE_SPOT_USDC_ADDRESS = "0x6d1e7cde53ba9467b783cb7c530ce054";
16999
- function isHypercoreChain(chainId) {
17000
- return chainId === HYPERCORE_CHAIN_ID;
17001
- }
17002
17236
  async function sendHypercoreWithdraw(params) {
17003
- const {
17004
- provider,
17005
- fromAddress,
17006
- depositWalletAddress,
17007
- sourceTokenAddress,
17008
- amount,
17009
- tokenSymbol,
17010
- publishableKey
17011
- } = params;
17012
- const isSpot = sourceTokenAddress.toLowerCase() === HYPERCORE_SPOT_USDC_ADDRESS;
17013
- const currentChainHex = await provider.request({
17014
- method: "eth_chainId",
17015
- params: []
17237
+ await sendHypercoreEvmTransfer({
17238
+ provider: params.provider,
17239
+ fromAddress: params.fromAddress,
17240
+ recipientAddress: params.depositWalletAddress,
17241
+ sourceTokenAddress: params.sourceTokenAddress,
17242
+ amount: params.amount,
17243
+ publishableKey: params.publishableKey
17016
17244
  });
17017
- const activeChainId = String(parseInt(currentChainHex, 16));
17018
- const buildResult = await buildHypercoreTransactionFromBackend(
17019
- {
17020
- action_type: isSpot ? "spot_send" : "usd_send",
17021
- signature_chain_type: "ethereum",
17022
- signature_chain_id: activeChainId,
17023
- recipient_address: depositWalletAddress,
17024
- token_address: sourceTokenAddress,
17025
- token_symbol: tokenSymbol || void 0,
17026
- amount
17027
- },
17028
- publishableKey
17029
- );
17030
- const signature = await provider.request({
17031
- method: "eth_signTypedData_v4",
17032
- params: [fromAddress, JSON.stringify(buildResult.typed_data)]
17033
- });
17034
- await sendHypercoreTransactionToBackend(
17035
- {
17036
- action_payload: buildResult.action_payload,
17037
- signature,
17038
- nonce: buildResult.nonce
17039
- },
17040
- publishableKey
17041
- );
17042
17245
  }
17043
17246
  async function detectBrowserWallet(chainType, senderAddress) {
17044
17247
  const win = typeof window !== "undefined" ? window : null;
@@ -17474,7 +17677,7 @@ function WithdrawForm({
17474
17677
  let humanAmount = isMaxed ? balanceData.balanceHuman : toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
17475
17678
  if (isHypercoreChain(sourceChainId)) {
17476
17679
  try {
17477
- const check = await checkHypercoreActivation2(
17680
+ const check = await checkHypercoreActivation3(
17478
17681
  {
17479
17682
  source_address: senderAddress,
17480
17683
  recipient_address: depositWallet.address
@@ -17738,7 +17941,7 @@ function WithdrawForm({
17738
17941
  ] })
17739
17942
  ] }),
17740
17943
  /* @__PURE__ */ jsxs52("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
17741
- /* @__PURE__ */ jsx58("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx58(DollarSign3, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
17944
+ /* @__PURE__ */ jsx58("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx58(DollarSign4, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
17742
17945
  /* @__PURE__ */ jsxs52("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
17743
17946
  tCrypto.priceImpact.label,
17744
17947
  ":",
@@ -18070,8 +18273,6 @@ function WithdrawConfirmingView({
18070
18273
  className: "uf-text-sm uf-text-center",
18071
18274
  style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
18072
18275
  children: [
18073
- txInfo.amount,
18074
- " ",
18075
18276
  txInfo.sourceTokenSymbol,
18076
18277
  " to",
18077
18278
  " ",