@unifold/ui-react 0.1.61 → 0.1.63

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
@@ -1,10 +1,10 @@
1
1
  // src/components/deposits/DepositModal.tsx
2
2
  import {
3
- useState as useState31,
4
- useEffect as useEffect25,
3
+ useState as useState32,
4
+ useEffect as useEffect26,
5
5
  useLayoutEffect as useLayoutEffect2,
6
6
  useCallback as useCallback5,
7
- useRef as useRef8,
7
+ useRef as useRef9,
8
8
  useMemo as useMemo10
9
9
  } from "react";
10
10
  import { ChevronRight as ChevronRight14, MapPinOff, AlertTriangle as AlertTriangle2 } from "lucide-react";
@@ -20,8 +20,32 @@ import { twMerge } from "tailwind-merge";
20
20
  function cn(...inputs) {
21
21
  return twMerge(clsx(inputs));
22
22
  }
23
- var WALLET_CHAIN_TYPE_STORAGE_KEY = "unifold_last_wallet_type";
23
+ var WALLET_STATE_STORAGE_KEY = "unifold_wallet_state";
24
+ var LEGACY_WALLET_KEYS = [
25
+ "unifold_last_wallet_type",
26
+ "unifold_last_connected_wallet"
27
+ ];
24
28
  var WALLET_USER_DISCONNECTED_KEY = "unifold_wallet_user_disconnected";
29
+ var SOLANA_WALLET_TYPES = /* @__PURE__ */ new Set([
30
+ "phantom-solana",
31
+ "solflare",
32
+ "backpack",
33
+ "glow"
34
+ ]);
35
+ var ETHEREUM_WALLET_TYPES = /* @__PURE__ */ new Set([
36
+ "metamask",
37
+ "phantom-ethereum",
38
+ "coinbase",
39
+ "trust",
40
+ "rainbow",
41
+ "rabby",
42
+ "okx"
43
+ ]);
44
+ function walletTypeToChain(t12) {
45
+ if (SOLANA_WALLET_TYPES.has(t12)) return "solana";
46
+ if (ETHEREUM_WALLET_TYPES.has(t12)) return "ethereum";
47
+ return void 0;
48
+ }
25
49
  function getUserDisconnectedWallet() {
26
50
  if (typeof window === "undefined") return false;
27
51
  try {
@@ -41,26 +65,35 @@ function setUserDisconnectedWallet(disconnected) {
41
65
  } catch {
42
66
  }
43
67
  }
44
- function getStoredWalletChainType() {
68
+ function getStoredWalletState() {
45
69
  if (typeof window === "undefined") return void 0;
46
70
  try {
47
- const stored = localStorage.getItem(WALLET_CHAIN_TYPE_STORAGE_KEY);
48
- if (stored === "ethereum" || stored === "solana") return stored;
71
+ const raw = localStorage.getItem(WALLET_STATE_STORAGE_KEY);
72
+ if (!raw) return void 0;
73
+ const chainType = walletTypeToChain(raw);
74
+ if (!chainType) {
75
+ localStorage.removeItem(WALLET_STATE_STORAGE_KEY);
76
+ return void 0;
77
+ }
78
+ return { walletType: raw, chainType };
49
79
  } catch {
80
+ return void 0;
50
81
  }
51
- return void 0;
52
82
  }
53
- function setStoredWalletChainType(chainType) {
83
+ function setStoredWalletState(walletType) {
54
84
  if (typeof window === "undefined") return;
85
+ if (!walletTypeToChain(walletType)) return;
55
86
  try {
56
- localStorage.setItem(WALLET_CHAIN_TYPE_STORAGE_KEY, chainType);
87
+ localStorage.setItem(WALLET_STATE_STORAGE_KEY, walletType);
88
+ for (const key of LEGACY_WALLET_KEYS) localStorage.removeItem(key);
57
89
  } catch {
58
90
  }
59
91
  }
60
- function clearStoredWalletChainType() {
92
+ function clearStoredWalletState() {
61
93
  if (typeof window === "undefined") return;
62
94
  try {
63
- localStorage.removeItem(WALLET_CHAIN_TYPE_STORAGE_KEY);
95
+ localStorage.removeItem(WALLET_STATE_STORAGE_KEY);
96
+ for (const key of LEGACY_WALLET_KEYS) localStorage.removeItem(key);
64
97
  } catch {
65
98
  }
66
99
  }
@@ -674,7 +707,63 @@ import { useEffect as useEffect2, useLayoutEffect, useState as useState2 } from
674
707
  import { getAddressBalance } from "@unifold/core";
675
708
 
676
709
  // src/components/deposits/browser-wallets/utils.ts
677
- import { IneligibilityReason } from "@unifold/core";
710
+ import {
711
+ IneligibilityReason
712
+ } from "@unifold/core";
713
+ var normalize = (value) => value?.toLowerCase();
714
+ function sourceTokenMatchesDefaultSource(token, defaultSource) {
715
+ if (!token || !defaultSource.defaultSourceChainType || !defaultSource.defaultSourceChainId) {
716
+ return false;
717
+ }
718
+ if (token.chain_type !== defaultSource.defaultSourceChainType || token.chain_id !== defaultSource.defaultSourceChainId) {
719
+ return false;
720
+ }
721
+ if (defaultSource.defaultSourceTokenAddress && normalize(token.token_address) === normalize(defaultSource.defaultSourceTokenAddress)) {
722
+ return true;
723
+ }
724
+ if (defaultSource.defaultSourceTokenAddress) {
725
+ return false;
726
+ }
727
+ return !!defaultSource.defaultSourceSymbol && normalize(token.symbol) === normalize(defaultSource.defaultSourceSymbol);
728
+ }
729
+ function isDefaultSourceBalance(balance, defaultSource) {
730
+ return isBalanceEligible(balance) && sourceTokenMatchesDefaultSource(getTokenFromBalance(balance), defaultSource);
731
+ }
732
+ function compareBalancesWithDefaultSource(a, b, defaultSource) {
733
+ const aDefault = isDefaultSourceBalance(a, defaultSource);
734
+ const bDefault = isDefaultSourceBalance(b, defaultSource);
735
+ if (aDefault && !bDefault) return -1;
736
+ if (!aDefault && bDefault) return 1;
737
+ const aEligible = isBalanceEligible(a);
738
+ const bEligible = isBalanceEligible(b);
739
+ if (aEligible && !bEligible) return -1;
740
+ if (!aEligible && bEligible) return 1;
741
+ return 0;
742
+ }
743
+ function resolveDefaultSourceSymbol(supportedTokens, defaultSource) {
744
+ if (!supportedTokens?.length || !defaultSource.defaultSourceChainType || !defaultSource.defaultSourceChainId) {
745
+ return null;
746
+ }
747
+ if (defaultSource.defaultSourceTokenAddress) {
748
+ for (const token of supportedTokens) {
749
+ const matchingChain = token.chains.find(
750
+ (chain) => chain.chain_type === defaultSource.defaultSourceChainType && chain.chain_id === defaultSource.defaultSourceChainId && normalize(chain.token_address) === normalize(defaultSource.defaultSourceTokenAddress)
751
+ );
752
+ if (matchingChain) return token.symbol;
753
+ }
754
+ }
755
+ if (!defaultSource.defaultSourceSymbol) return null;
756
+ for (const token of supportedTokens) {
757
+ if (normalize(token.symbol) !== normalize(defaultSource.defaultSourceSymbol)) {
758
+ continue;
759
+ }
760
+ const matchingChain = token.chains.find(
761
+ (chain) => chain.chain_type === defaultSource.defaultSourceChainType && chain.chain_id === defaultSource.defaultSourceChainId
762
+ );
763
+ if (matchingChain) return token.symbol;
764
+ }
765
+ return null;
766
+ }
678
767
  function formatUsdFromBalancePercent(maxUsdAmount, percent) {
679
768
  if (maxUsdAmount <= 0 || percent < 0) return "";
680
769
  const raw = maxUsdAmount * percent / 100;
@@ -5252,7 +5341,7 @@ function CashAppButton({
5252
5341
  }
5253
5342
 
5254
5343
  // src/components/deposits/buttons/BrowserWalletButton.tsx
5255
- import * as React24 from "react";
5344
+ import * as React25 from "react";
5256
5345
  import { Wallet, ChevronRight as ChevronRight10, Loader2 as Loader23 } from "lucide-react";
5257
5346
  import { getAddressBalances } from "@unifold/core";
5258
5347
 
@@ -5306,6 +5395,233 @@ function collectAllEip6963EthProviders() {
5306
5395
  return store.getProviders().map((d) => d.provider);
5307
5396
  }
5308
5397
 
5398
+ // src/components/deposits/browser-wallets/useDetectedBrowserWallet.ts
5399
+ import * as React12 from "react";
5400
+
5401
+ // src/components/deposits/browser-wallets/detectConnectedWallet.ts
5402
+ function identifyEthWallet(provider, hint) {
5403
+ switch (hint) {
5404
+ case "metamask":
5405
+ return { type: "metamask", name: "MetaMask", icon: "metamask" };
5406
+ case "phantom":
5407
+ return { type: "phantom-ethereum", name: "Phantom", icon: "phantom" };
5408
+ case "coinbase":
5409
+ return { type: "coinbase", name: "Coinbase Wallet", icon: "coinbase" };
5410
+ case "okx":
5411
+ return { type: "okx", name: "OKX Wallet", icon: "okx" };
5412
+ case "rabby":
5413
+ return { type: "rabby", name: "Rabby", icon: "rabby" };
5414
+ case "trust":
5415
+ return { type: "trust", name: "Trust Wallet", icon: "trust" };
5416
+ case "rainbow":
5417
+ return { type: "rainbow", name: "Rainbow", icon: "rainbow" };
5418
+ }
5419
+ const anyProvider = provider;
5420
+ if (provider.isPhantom) {
5421
+ return { type: "phantom-ethereum", name: "Phantom", icon: "phantom" };
5422
+ }
5423
+ if (anyProvider.isCoinbaseWallet) {
5424
+ return { type: "coinbase", name: "Coinbase Wallet", icon: "coinbase" };
5425
+ }
5426
+ if (anyProvider.isRabby) {
5427
+ return { type: "rabby", name: "Rabby", icon: "rabby" };
5428
+ }
5429
+ if (anyProvider.isTrust) {
5430
+ return { type: "trust", name: "Trust Wallet", icon: "trust" };
5431
+ }
5432
+ if (anyProvider.isRainbow) {
5433
+ return { type: "rainbow", name: "Rainbow", icon: "rainbow" };
5434
+ }
5435
+ if (provider.isMetaMask && !provider.isPhantom) {
5436
+ return { type: "metamask", name: "MetaMask", icon: "metamask" };
5437
+ }
5438
+ return { type: "metamask", name: "Wallet", icon: "metamask" };
5439
+ }
5440
+ var EIP6963_ID_TO_WALLET_TYPE = {
5441
+ metamask: "metamask",
5442
+ phantom: "phantom-ethereum",
5443
+ coinbase: "coinbase",
5444
+ trust: "trust",
5445
+ rainbow: "rainbow",
5446
+ rabby: "rabby",
5447
+ okx: "okx"
5448
+ };
5449
+ function inferEthWalletType(provider, walletId) {
5450
+ if (EIP6963_ID_TO_WALLET_TYPE[walletId]) return EIP6963_ID_TO_WALLET_TYPE[walletId];
5451
+ const any = provider;
5452
+ if (provider.isPhantom) return "phantom-ethereum";
5453
+ if (any.isCoinbaseWallet) return "coinbase";
5454
+ if (any.isRabby) return "rabby";
5455
+ if (any.isTrust) return "trust";
5456
+ if (any.isRainbow) return "rainbow";
5457
+ if (any.isOkxWallet) return "okx";
5458
+ if (provider.isMetaMask && !provider.isPhantom) return "metamask";
5459
+ return null;
5460
+ }
5461
+ function solanaCandidate(provider, type, name, icon) {
5462
+ return {
5463
+ walletType: type,
5464
+ detect: async () => {
5465
+ if (!provider) return null;
5466
+ if (provider.isConnected && provider.publicKey) {
5467
+ return { type, name, address: provider.publicKey.toString(), icon };
5468
+ }
5469
+ try {
5470
+ const resp = await provider.connect({ onlyIfTrusted: true });
5471
+ if (resp.publicKey) {
5472
+ return { type, name, address: resp.publicKey.toString(), icon };
5473
+ }
5474
+ } catch {
5475
+ }
5476
+ return null;
5477
+ }
5478
+ };
5479
+ }
5480
+ function ethereumCandidate(provider, walletId) {
5481
+ return {
5482
+ walletType: inferEthWalletType(provider, walletId),
5483
+ detect: async () => {
5484
+ try {
5485
+ const accounts = await provider.request({ method: "eth_accounts" });
5486
+ if (!accounts?.length) return null;
5487
+ const resolved = identifyEthWallet(provider, walletId);
5488
+ return { ...resolved, address: accounts[0] };
5489
+ } catch {
5490
+ return null;
5491
+ }
5492
+ }
5493
+ };
5494
+ }
5495
+ function buildCandidates(win, chainType) {
5496
+ const candidates = [];
5497
+ if (!chainType || chainType === "solana") {
5498
+ candidates.push(
5499
+ solanaCandidate(win.phantom?.solana, "phantom-solana", "Phantom", "phantom"),
5500
+ solanaCandidate(win.solflare, "solflare", "Solflare", "solflare"),
5501
+ solanaCandidate(win.backpack, "backpack", "Backpack", "backpack"),
5502
+ solanaCandidate(win.glow, "glow", "Glow", "glow")
5503
+ );
5504
+ }
5505
+ if (!chainType || chainType === "ethereum") {
5506
+ const seen = /* @__PURE__ */ new Set();
5507
+ const addEth = (provider, walletId) => {
5508
+ if (!provider || seen.has(provider)) return;
5509
+ seen.add(provider);
5510
+ candidates.push(ethereumCandidate(provider, walletId));
5511
+ };
5512
+ for (const { provider, walletId } of getEip6963Providers()) {
5513
+ addEth(
5514
+ provider,
5515
+ walletId === "unknown" ? "default" : walletId
5516
+ );
5517
+ }
5518
+ addEth(win.phantom?.ethereum, "phantom");
5519
+ addEth(win.coinbaseWalletExtension, "coinbase");
5520
+ addEth(win.okxwallet, "okx");
5521
+ addEth(win.trustwallet?.ethereum, "trust");
5522
+ addEth(win.ethereum, "default");
5523
+ }
5524
+ return candidates;
5525
+ }
5526
+ async function detectConnectedBrowserWallet(chainType) {
5527
+ if (typeof window === "undefined") return null;
5528
+ if (getUserDisconnectedWallet()) return null;
5529
+ try {
5530
+ const win = window;
5531
+ const candidates = buildCandidates(win, chainType);
5532
+ const preferred = getStoredWalletState();
5533
+ if (preferred && (!chainType || preferred.chainType === chainType)) {
5534
+ const idx = candidates.findIndex((c) => c.walletType === preferred.walletType);
5535
+ if (idx > 0) candidates.unshift(...candidates.splice(idx, 1));
5536
+ }
5537
+ for (const c of candidates) {
5538
+ const found = await c.detect();
5539
+ if (found) return found;
5540
+ }
5541
+ } catch (error) {
5542
+ console.error("[detectConnectedBrowserWallet] detection error:", error);
5543
+ }
5544
+ return null;
5545
+ }
5546
+
5547
+ // src/components/deposits/browser-wallets/useDetectedBrowserWallet.ts
5548
+ function useDetectedBrowserWallet(opts = {}) {
5549
+ const { chainType, enabled = true, onDisconnect } = opts;
5550
+ const [wallet, setWallet] = React12.useState(null);
5551
+ const [isLoading, setIsLoading] = React12.useState(enabled);
5552
+ const [eip6963ProviderCount, setEip6963ProviderCount] = React12.useState(0);
5553
+ const onDisconnectRef = React12.useRef(onDisconnect);
5554
+ onDisconnectRef.current = onDisconnect;
5555
+ React12.useEffect(() => {
5556
+ const store = getEip6963Store();
5557
+ if (!store) return;
5558
+ setEip6963ProviderCount(store.getProviders().length);
5559
+ return store.subscribe((providers) => setEip6963ProviderCount(providers.length));
5560
+ }, []);
5561
+ React12.useEffect(() => {
5562
+ if (!enabled) {
5563
+ setWallet(null);
5564
+ setIsLoading(false);
5565
+ return;
5566
+ }
5567
+ let mounted = true;
5568
+ const detect = async () => {
5569
+ if (!mounted) return;
5570
+ setIsLoading(true);
5571
+ const detected = await detectConnectedBrowserWallet(chainType);
5572
+ if (!mounted) return;
5573
+ setWallet(detected);
5574
+ setIsLoading(false);
5575
+ };
5576
+ detect();
5577
+ const onChange = () => detect();
5578
+ const onDisc = () => {
5579
+ onDisconnectRef.current?.();
5580
+ detect();
5581
+ };
5582
+ const onEthAccounts = (accounts) => {
5583
+ if (Array.isArray(accounts) && accounts.length === 0) onDisconnectRef.current?.();
5584
+ detect();
5585
+ };
5586
+ const win = typeof window !== "undefined" ? window : void 0;
5587
+ const solanaProvider = win?.phantom?.solana || win?.solana;
5588
+ if (solanaProvider) {
5589
+ solanaProvider.on("connect", onChange);
5590
+ solanaProvider.on("disconnect", onDisc);
5591
+ solanaProvider.on("accountChanged", onChange);
5592
+ }
5593
+ const ethProviders = [];
5594
+ for (const { provider } of getEip6963Providers()) {
5595
+ const p = provider;
5596
+ if (p && !ethProviders.includes(p)) ethProviders.push(p);
5597
+ }
5598
+ if (win?.ethereum && !ethProviders.includes(win.ethereum)) ethProviders.push(win.ethereum);
5599
+ if (win?.phantom?.ethereum && !ethProviders.includes(win.phantom.ethereum)) {
5600
+ ethProviders.push(win.phantom.ethereum);
5601
+ }
5602
+ for (const p of ethProviders) {
5603
+ p.on("accountsChanged", onEthAccounts);
5604
+ p.on("chainChanged", onChange);
5605
+ }
5606
+ return () => {
5607
+ mounted = false;
5608
+ if (solanaProvider) {
5609
+ solanaProvider.off?.("connect", onChange);
5610
+ solanaProvider.off?.("disconnect", onDisc);
5611
+ solanaProvider.off?.("accountChanged", onChange);
5612
+ }
5613
+ for (const p of ethProviders) {
5614
+ const off = p.off?.bind(p) ?? p.removeListener?.bind(p);
5615
+ if (off) {
5616
+ off("accountsChanged", onEthAccounts);
5617
+ off("chainChanged", onChange);
5618
+ }
5619
+ }
5620
+ };
5621
+ }, [chainType, eip6963ProviderCount, enabled]);
5622
+ return { wallet, isLoading, setWallet };
5623
+ }
5624
+
5309
5625
  // src/components/deposits/browser-wallets/disconnectInjectedBrowserWallet.ts
5310
5626
  var SOLANA_DISCONNECT_TYPES = [
5311
5627
  "phantom-solana",
@@ -5391,14 +5707,14 @@ async function disconnectInjectedBrowserWallet(wallet) {
5391
5707
  }
5392
5708
 
5393
5709
  // src/resources/icons/MetamaskIcon.tsx
5394
- import * as React12 from "react";
5710
+ import * as React13 from "react";
5395
5711
  import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
5396
5712
  function MetamaskIcon({
5397
5713
  size = 24,
5398
5714
  className,
5399
5715
  variant = "color"
5400
5716
  }) {
5401
- const id = React12.useId();
5717
+ const id = React13.useId();
5402
5718
  if (variant === "light" || variant === "dark") {
5403
5719
  return /* @__PURE__ */ jsxs20(
5404
5720
  "svg",
@@ -5520,14 +5836,14 @@ function MetamaskIcon({
5520
5836
  }
5521
5837
 
5522
5838
  // src/resources/icons/PhantomIcon.tsx
5523
- import * as React13 from "react";
5839
+ import * as React14 from "react";
5524
5840
  import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
5525
5841
  function PhantomIcon({
5526
5842
  size = 24,
5527
5843
  className,
5528
5844
  variant = "color"
5529
5845
  }) {
5530
- const id = React13.useId();
5846
+ const id = React14.useId();
5531
5847
  if (variant === "light") {
5532
5848
  return /* @__PURE__ */ jsx24(
5533
5849
  "svg",
@@ -5595,14 +5911,14 @@ function PhantomIcon({
5595
5911
  }
5596
5912
 
5597
5913
  // src/resources/icons/CoinbaseIcon.tsx
5598
- import * as React14 from "react";
5914
+ import * as React15 from "react";
5599
5915
  import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
5600
5916
  function CoinbaseIcon({
5601
5917
  size = 24,
5602
5918
  className,
5603
5919
  variant = "color"
5604
5920
  }) {
5605
- const id = React14.useId();
5921
+ const id = React15.useId();
5606
5922
  if (variant === "light") {
5607
5923
  return /* @__PURE__ */ jsxs22(
5608
5924
  "svg",
@@ -5683,14 +5999,14 @@ function CoinbaseIcon({
5683
5999
  }
5684
6000
 
5685
6001
  // src/resources/icons/RabbyIcon.tsx
5686
- import * as React15 from "react";
6002
+ import * as React16 from "react";
5687
6003
  import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
5688
6004
  function RabbyIcon({
5689
6005
  size = 24,
5690
6006
  className,
5691
6007
  variant = "color"
5692
6008
  }) {
5693
- const id = React15.useId();
6009
+ const id = React16.useId();
5694
6010
  if (variant === "light") {
5695
6011
  return /* @__PURE__ */ jsxs23(
5696
6012
  "svg",
@@ -6038,14 +6354,14 @@ function RabbyIcon({
6038
6354
  }
6039
6355
 
6040
6356
  // src/resources/icons/RainbowIcon.tsx
6041
- import * as React16 from "react";
6357
+ import * as React17 from "react";
6042
6358
  import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
6043
6359
  function RainbowIcon({
6044
6360
  size = 24,
6045
6361
  className,
6046
6362
  variant = "color"
6047
6363
  }) {
6048
- const id = React16.useId();
6364
+ const id = React17.useId();
6049
6365
  if (variant === "light") {
6050
6366
  return /* @__PURE__ */ jsxs24(
6051
6367
  "svg",
@@ -6508,14 +6824,14 @@ function RainbowIcon({
6508
6824
  }
6509
6825
 
6510
6826
  // src/resources/icons/TrustIcon.tsx
6511
- import * as React17 from "react";
6827
+ import * as React18 from "react";
6512
6828
  import { jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
6513
6829
  function TrustIcon({
6514
6830
  size = 24,
6515
6831
  className,
6516
6832
  variant = "color"
6517
6833
  }) {
6518
- const id = React17.useId();
6834
+ const id = React18.useId();
6519
6835
  if (variant === "light") {
6520
6836
  return /* @__PURE__ */ jsx28(
6521
6837
  "svg",
@@ -6605,14 +6921,14 @@ function TrustIcon({
6605
6921
  }
6606
6922
 
6607
6923
  // src/resources/icons/OkxIcon.tsx
6608
- import * as React18 from "react";
6924
+ import * as React19 from "react";
6609
6925
  import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
6610
6926
  function OkxIcon({
6611
6927
  size = 24,
6612
6928
  className,
6613
6929
  variant = "color"
6614
6930
  }) {
6615
- const id = React18.useId();
6931
+ const id = React19.useId();
6616
6932
  if (variant === "light") {
6617
6933
  return /* @__PURE__ */ jsx29(
6618
6934
  "svg",
@@ -6680,14 +6996,14 @@ function OkxIcon({
6680
6996
  }
6681
6997
 
6682
6998
  // src/resources/icons/GlowIcon.tsx
6683
- import * as React19 from "react";
6999
+ import * as React20 from "react";
6684
7000
  import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
6685
7001
  function GlowIcon({
6686
7002
  size = 24,
6687
7003
  className,
6688
7004
  variant = "color"
6689
7005
  }) {
6690
- const id = React19.useId();
7006
+ const id = React20.useId();
6691
7007
  if (variant === "light") {
6692
7008
  return /* @__PURE__ */ jsx30(
6693
7009
  "svg",
@@ -6789,14 +7105,14 @@ function GlowIcon({
6789
7105
  }
6790
7106
 
6791
7107
  // src/resources/icons/BackpackIcon.tsx
6792
- import * as React20 from "react";
7108
+ import * as React21 from "react";
6793
7109
  import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
6794
7110
  function BackpackIcon({
6795
7111
  size = 24,
6796
7112
  className,
6797
7113
  variant = "color"
6798
7114
  }) {
6799
- const id = React20.useId();
7115
+ const id = React21.useId();
6800
7116
  if (variant === "light") {
6801
7117
  return /* @__PURE__ */ jsx31(
6802
7118
  "svg",
@@ -6870,14 +7186,14 @@ function BackpackIcon({
6870
7186
  }
6871
7187
 
6872
7188
  // src/resources/icons/SolflareIcon.tsx
6873
- import * as React21 from "react";
7189
+ import * as React22 from "react";
6874
7190
  import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
6875
7191
  function SolflareIcon({
6876
7192
  size = 24,
6877
7193
  className,
6878
7194
  variant = "color"
6879
7195
  }) {
6880
- const id = React21.useId();
7196
+ const id = React22.useId();
6881
7197
  if (variant === "light") {
6882
7198
  return /* @__PURE__ */ jsx32(
6883
7199
  "svg",
@@ -6945,14 +7261,14 @@ function SolflareIcon({
6945
7261
  }
6946
7262
 
6947
7263
  // src/resources/icons/EthereumIcon.tsx
6948
- import * as React22 from "react";
7264
+ import * as React23 from "react";
6949
7265
  import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
6950
7266
  function EthereumIcon({
6951
7267
  size = 24,
6952
7268
  className,
6953
7269
  variant = "color"
6954
7270
  }) {
6955
- const id = React22.useId();
7271
+ const id = React23.useId();
6956
7272
  if (variant === "light") {
6957
7273
  return /* @__PURE__ */ jsxs30(
6958
7274
  "svg",
@@ -7083,14 +7399,14 @@ function EthereumIcon({
7083
7399
  }
7084
7400
 
7085
7401
  // src/resources/icons/SolanaIcon.tsx
7086
- import * as React23 from "react";
7402
+ import * as React24 from "react";
7087
7403
  import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
7088
7404
  function SolanaIcon({
7089
7405
  size = 24,
7090
7406
  className,
7091
7407
  variant = "color"
7092
7408
  }) {
7093
- const id = React23.useId();
7409
+ const id = React24.useId();
7094
7410
  if (variant === "light") {
7095
7411
  return /* @__PURE__ */ jsx34(
7096
7412
  "svg",
@@ -7345,44 +7661,6 @@ function truncateAddress3(address) {
7345
7661
  if (address.length <= 10) return address;
7346
7662
  return `${address.slice(0, 4)}...${address.slice(-4)}`;
7347
7663
  }
7348
- function identifyEthWallet(provider, _win, hint) {
7349
- switch (hint) {
7350
- case "metamask":
7351
- return { type: "metamask", name: "MetaMask", icon: "metamask" };
7352
- case "phantom":
7353
- return { type: "phantom-ethereum", name: "Phantom", icon: "phantom" };
7354
- case "coinbase":
7355
- return { type: "coinbase", name: "Coinbase Wallet", icon: "coinbase" };
7356
- case "okx":
7357
- return { type: "okx", name: "OKX Wallet", icon: "okx" };
7358
- case "rabby":
7359
- return { type: "rabby", name: "Rabby", icon: "rabby" };
7360
- case "trust":
7361
- return { type: "trust", name: "Trust Wallet", icon: "trust" };
7362
- case "rainbow":
7363
- return { type: "rainbow", name: "Rainbow", icon: "rainbow" };
7364
- }
7365
- const anyProvider = provider;
7366
- if (provider.isPhantom) {
7367
- return { type: "phantom-ethereum", name: "Phantom", icon: "phantom" };
7368
- }
7369
- if (anyProvider.isCoinbaseWallet) {
7370
- return { type: "coinbase", name: "Coinbase Wallet", icon: "coinbase" };
7371
- }
7372
- if (anyProvider.isRabby) {
7373
- return { type: "rabby", name: "Rabby", icon: "rabby" };
7374
- }
7375
- if (anyProvider.isTrust) {
7376
- return { type: "trust", name: "Trust Wallet", icon: "trust" };
7377
- }
7378
- if (anyProvider.isRainbow) {
7379
- return { type: "rainbow", name: "Rainbow", icon: "rainbow" };
7380
- }
7381
- if (provider.isMetaMask && !provider.isPhantom) {
7382
- return { type: "metamask", name: "MetaMask", icon: "metamask" };
7383
- }
7384
- return { type: "metamask", name: "Wallet", icon: "metamask" };
7385
- }
7386
7664
  function BrowserWalletButton({
7387
7665
  onClick,
7388
7666
  onConnectClick,
@@ -7393,30 +7671,19 @@ function BrowserWalletButton({
7393
7671
  subtitle = i18n.depositModal.browserWallet.subtitle
7394
7672
  }) {
7395
7673
  const { colors: colors2, fonts, components } = useTheme();
7396
- const [isHovered, setIsHovered] = React24.useState(false);
7397
- const [isTouchDevice, setIsTouchDevice] = React24.useState(false);
7398
- const [wallet, setWallet] = React24.useState(null);
7399
- const [isLoading, setIsLoading] = React24.useState(true);
7400
- const [isConnecting, setIsConnecting] = React24.useState(false);
7401
- const [balanceText, setBalanceText] = React24.useState(null);
7402
- const [isLoadingBalance, setIsLoadingBalance] = React24.useState(false);
7403
- const [isDisconnecting, setIsDisconnecting] = React24.useState(false);
7404
- const onDisconnectRef = React24.useRef(onDisconnect);
7674
+ const [isHovered, setIsHovered] = React25.useState(false);
7675
+ const [isTouchDevice, setIsTouchDevice] = React25.useState(false);
7676
+ const { wallet, isLoading, setWallet } = useDetectedBrowserWallet({ chainType, onDisconnect });
7677
+ const [isConnecting, setIsConnecting] = React25.useState(false);
7678
+ const [balanceText, setBalanceText] = React25.useState(null);
7679
+ const [isLoadingBalance, setIsLoadingBalance] = React25.useState(false);
7680
+ const [isDisconnecting, setIsDisconnecting] = React25.useState(false);
7681
+ const onDisconnectRef = React25.useRef(onDisconnect);
7405
7682
  onDisconnectRef.current = onDisconnect;
7406
- React24.useEffect(() => {
7683
+ React25.useEffect(() => {
7407
7684
  setIsTouchDevice("ontouchstart" in window || navigator.maxTouchPoints > 0);
7408
7685
  }, []);
7409
- const [eip6963ProviderCount, setEip6963ProviderCount] = React24.useState(0);
7410
- React24.useEffect(() => {
7411
- const store = getEip6963Store();
7412
- if (!store) return;
7413
- setEip6963ProviderCount(store.getProviders().length);
7414
- const unsubscribe = store.subscribe((providers) => {
7415
- setEip6963ProviderCount(providers.length);
7416
- });
7417
- return unsubscribe;
7418
- }, []);
7419
- React24.useEffect(() => {
7686
+ React25.useEffect(() => {
7420
7687
  if (!wallet || !publishableKey) {
7421
7688
  setBalanceText(null);
7422
7689
  return;
@@ -7457,206 +7724,6 @@ function BrowserWalletButton({
7457
7724
  cancelled = true;
7458
7725
  };
7459
7726
  }, [wallet, publishableKey]);
7460
- React24.useEffect(() => {
7461
- let mounted = true;
7462
- const detectWallet = async () => {
7463
- if (!mounted) return;
7464
- setIsLoading(true);
7465
- try {
7466
- const win = typeof window !== "undefined" ? window : null;
7467
- if (!win) return;
7468
- if (getUserDisconnectedWallet()) {
7469
- if (mounted) {
7470
- setWallet(null);
7471
- setIsLoading(false);
7472
- }
7473
- return;
7474
- }
7475
- if (!chainType || chainType === "solana") {
7476
- const anyWin = win;
7477
- const trySilentSolana = async (provider, type, name, icon) => {
7478
- if (!provider) return false;
7479
- if (provider.isConnected && provider.publicKey) {
7480
- if (mounted) {
7481
- setWallet({
7482
- type,
7483
- name,
7484
- address: provider.publicKey.toString(),
7485
- icon
7486
- });
7487
- setIsLoading(false);
7488
- }
7489
- return true;
7490
- }
7491
- try {
7492
- const resp = await provider.connect({ onlyIfTrusted: true });
7493
- if (mounted && resp.publicKey) {
7494
- setWallet({
7495
- type,
7496
- name,
7497
- address: resp.publicKey.toString(),
7498
- icon
7499
- });
7500
- setIsLoading(false);
7501
- return true;
7502
- }
7503
- } catch {
7504
- }
7505
- return false;
7506
- };
7507
- if (await trySilentSolana(
7508
- win.phantom?.solana,
7509
- "phantom-solana",
7510
- "Phantom",
7511
- "phantom"
7512
- ))
7513
- return;
7514
- if (await trySilentSolana(
7515
- anyWin.solflare,
7516
- "solflare",
7517
- "Solflare",
7518
- "solflare"
7519
- ))
7520
- return;
7521
- if (await trySilentSolana(
7522
- anyWin.backpack,
7523
- "backpack",
7524
- "Backpack",
7525
- "backpack"
7526
- ))
7527
- return;
7528
- if (await trySilentSolana(
7529
- anyWin.glow,
7530
- "glow",
7531
- "Glow",
7532
- "glow"
7533
- ))
7534
- return;
7535
- }
7536
- if (!chainType || chainType === "ethereum") {
7537
- const anyWin = win;
7538
- const allProviders = [];
7539
- const eip6963 = getEip6963Providers();
7540
- for (const { provider, walletId } of eip6963) {
7541
- allProviders.push({
7542
- provider,
7543
- walletId: walletId === "unknown" ? "default" : walletId
7544
- });
7545
- }
7546
- if (allProviders.length === 0) {
7547
- if (win.phantom?.ethereum) {
7548
- allProviders.push({
7549
- provider: win.phantom.ethereum,
7550
- walletId: "phantom"
7551
- });
7552
- }
7553
- if (anyWin.okxwallet) {
7554
- allProviders.push({
7555
- provider: anyWin.okxwallet,
7556
- walletId: "okx"
7557
- });
7558
- }
7559
- if (anyWin.coinbaseWalletExtension) {
7560
- allProviders.push({
7561
- provider: anyWin.coinbaseWalletExtension,
7562
- walletId: "coinbase"
7563
- });
7564
- }
7565
- if (win.ethereum) {
7566
- const isDuplicate = allProviders.some(
7567
- (p) => p.provider === win.ethereum
7568
- );
7569
- if (!isDuplicate) {
7570
- allProviders.push({
7571
- provider: win.ethereum,
7572
- walletId: "default"
7573
- });
7574
- }
7575
- }
7576
- }
7577
- for (const { provider, walletId } of allProviders) {
7578
- if (!provider) continue;
7579
- try {
7580
- const accounts = await provider.request({
7581
- method: "eth_accounts"
7582
- });
7583
- if (!accounts || accounts.length === 0) continue;
7584
- const address = accounts[0];
7585
- const resolved = identifyEthWallet(provider, anyWin, walletId);
7586
- if (mounted) {
7587
- setWallet({ ...resolved, address });
7588
- setIsLoading(false);
7589
- }
7590
- return;
7591
- } catch {
7592
- }
7593
- }
7594
- }
7595
- if (mounted) {
7596
- setWallet(null);
7597
- setIsLoading(false);
7598
- }
7599
- } catch (error) {
7600
- console.error("[BrowserWalletButton] Error detecting wallet:", error);
7601
- if (mounted) {
7602
- setWallet(null);
7603
- setIsLoading(false);
7604
- }
7605
- }
7606
- };
7607
- detectWallet();
7608
- const handleAccountsChanged = () => {
7609
- detectWallet();
7610
- };
7611
- const handleDisconnect = () => {
7612
- onDisconnectRef.current?.();
7613
- detectWallet();
7614
- };
7615
- const handleEthAccountsChanged = (accounts) => {
7616
- if (Array.isArray(accounts) && accounts.length === 0) {
7617
- onDisconnectRef.current?.();
7618
- }
7619
- detectWallet();
7620
- };
7621
- const solanaProvider = window.phantom?.solana || window.solana;
7622
- if (solanaProvider) {
7623
- solanaProvider.on("connect", handleAccountsChanged);
7624
- solanaProvider.on("disconnect", handleDisconnect);
7625
- solanaProvider.on("accountChanged", handleAccountsChanged);
7626
- }
7627
- const ethProviders = [];
7628
- for (const { provider } of getEip6963Providers()) {
7629
- const p = provider;
7630
- if (p && !ethProviders.includes(p)) {
7631
- ethProviders.push(p);
7632
- }
7633
- }
7634
- if (window.ethereum && !ethProviders.includes(window.ethereum)) {
7635
- ethProviders.push(window.ethereum);
7636
- }
7637
- if (window.phantom?.ethereum && !ethProviders.includes(window.phantom.ethereum)) {
7638
- ethProviders.push(window.phantom.ethereum);
7639
- }
7640
- for (const provider of ethProviders) {
7641
- provider.on("accountsChanged", handleEthAccountsChanged);
7642
- provider.on("chainChanged", handleAccountsChanged);
7643
- }
7644
- return () => {
7645
- mounted = false;
7646
- if (solanaProvider) {
7647
- solanaProvider.off("connect", handleAccountsChanged);
7648
- solanaProvider.off("disconnect", handleDisconnect);
7649
- solanaProvider.off("accountChanged", handleAccountsChanged);
7650
- }
7651
- for (const provider of ethProviders) {
7652
- const off = provider.off?.bind(provider) ?? provider.removeListener?.bind(provider);
7653
- if (off) {
7654
- off("accountsChanged", handleEthAccountsChanged);
7655
- off("chainChanged", handleAccountsChanged);
7656
- }
7657
- }
7658
- };
7659
- }, [chainType, eip6963ProviderCount]);
7660
7727
  const handleConnect = async () => {
7661
7728
  if (wallet) {
7662
7729
  onClick(wallet);
@@ -7673,6 +7740,7 @@ function BrowserWalletButton({
7673
7740
  if (solanaProvider?.isPhantom) {
7674
7741
  const { publicKey } = await solanaProvider.connect();
7675
7742
  setUserDisconnectedWallet(false);
7743
+ setStoredWalletState("phantom-solana");
7676
7744
  setWallet({
7677
7745
  type: "phantom-solana",
7678
7746
  name: "Phantom",
@@ -7692,8 +7760,10 @@ function BrowserWalletButton({
7692
7760
  if (accounts && accounts.length > 0) {
7693
7761
  setUserDisconnectedWallet(false);
7694
7762
  const isPhantom = ethProvider.isPhantom;
7763
+ const walletType = isPhantom ? "phantom-ethereum" : "metamask";
7764
+ setStoredWalletState(walletType);
7695
7765
  setWallet({
7696
- type: isPhantom ? "phantom-ethereum" : "metamask",
7766
+ type: walletType,
7697
7767
  name: isPhantom ? "Phantom" : "MetaMask",
7698
7768
  address: accounts[0],
7699
7769
  icon: isPhantom ? "phantom" : "metamask"
@@ -7740,7 +7810,7 @@ function BrowserWalletButton({
7740
7810
  border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
7741
7811
  };
7742
7812
  const sortedWallets = featuredWallets ? [...featuredWallets].sort((a, b) => a.position - b.position) : [];
7743
- const walletIconBlock = wallet ? WALLET_ICON_COMPONENTS[wallet.icon] ? React24.createElement(WALLET_ICON_COMPONENTS[wallet.icon], {
7813
+ const walletIconBlock = wallet ? WALLET_ICON_COMPONENTS[wallet.icon] ? React25.createElement(WALLET_ICON_COMPONENTS[wallet.icon], {
7744
7814
  size: 36,
7745
7815
  className: "uf-rounded-lg",
7746
7816
  variant: "color"
@@ -7891,7 +7961,7 @@ function BrowserWalletButton({
7891
7961
  }
7892
7962
 
7893
7963
  // src/components/deposits/CoinbaseConnect.tsx
7894
- import { useState as useState21, useEffect as useEffect16, useCallback as useCallback2, useMemo as useMemo4, useRef as useRef5 } from "react";
7964
+ import { useState as useState22, useEffect as useEffect17, useCallback as useCallback2, useMemo as useMemo4, useRef as useRef6 } from "react";
7895
7965
  import {
7896
7966
  ChevronRight as ChevronRight11,
7897
7967
  ChevronDown as ChevronDown3,
@@ -8046,7 +8116,12 @@ function CoinbaseConnect({
8046
8116
  onBack: parentOnBack,
8047
8117
  onDisconnect,
8048
8118
  skipToHoldings,
8049
- onExecutionsChange
8119
+ canGoBack = true,
8120
+ onExecutionsChange,
8121
+ defaultSourceChainType,
8122
+ defaultSourceChainId,
8123
+ defaultSourceTokenAddress,
8124
+ defaultSourceSymbol
8050
8125
  }) {
8051
8126
  const { colors: colors2, fonts, components } = useTheme();
8052
8127
  const { projectConfig } = useProjectConfig({ publishableKey });
@@ -8071,25 +8146,25 @@ function CoinbaseConnect({
8071
8146
  const appName = projectConfig?.project_name ?? "Unifold";
8072
8147
  const t12 = i18n.connectExchange;
8073
8148
  const initialView = skipToHoldings && getStoredIntegrationToken(IntegrationProvider.COINBASE) ? "holdings" : "select_exchange";
8074
- const [view, setView] = useState21(initialView);
8075
- const [prevView, setPrevView] = useState21(initialView);
8076
- const [isTransitioning, setIsTransitioning] = useState21(false);
8077
- const [exchanges, setExchanges] = useState21([]);
8078
- const [exchangesLoading, setExchangesLoading] = useState21(true);
8079
- const [selectedExchange, setSelectedExchange] = useState21(null);
8080
- const [accessToken, setAccessToken] = useState21(null);
8081
- const [holdings, setHoldings] = useState21([]);
8082
- const [selectedHolding, setSelectedHolding] = useState21(null);
8083
- const [selectedAsset, setSelectedAsset] = useState21(null);
8084
- const [sendAmount, setSendAmount] = useState21("");
8085
- const [transferIntent, setTransferIntent] = useState21(null);
8086
- const [mfaCode, setMfaCode] = useState21("");
8087
- const [mfaError, setMfaError] = useState21(false);
8088
- const [errorMessage, setErrorMessage] = useState21("");
8089
- const [isLoading, setIsLoading] = useState21(initialView === "holdings");
8090
- const [confirmResult, setConfirmResult] = useState21(null);
8091
- const [showTransferDetails, setShowTransferDetails] = useState21(false);
8092
- const [transferDepositWalletId, setTransferDepositWalletId] = useState21(void 0);
8149
+ const [view, setView] = useState22(initialView);
8150
+ const [prevView, setPrevView] = useState22(initialView);
8151
+ const [isTransitioning, setIsTransitioning] = useState22(false);
8152
+ const [exchanges, setExchanges] = useState22([]);
8153
+ const [exchangesLoading, setExchangesLoading] = useState22(true);
8154
+ const [selectedExchange, setSelectedExchange] = useState22(null);
8155
+ const [accessToken, setAccessToken] = useState22(null);
8156
+ const [holdings, setHoldings] = useState22([]);
8157
+ const [selectedHolding, setSelectedHolding] = useState22(null);
8158
+ const [selectedAsset, setSelectedAsset] = useState22(null);
8159
+ const [sendAmount, setSendAmount] = useState22("");
8160
+ const [transferIntent, setTransferIntent] = useState22(null);
8161
+ const [mfaCode, setMfaCode] = useState22("");
8162
+ const [mfaError, setMfaError] = useState22(false);
8163
+ const [errorMessage, setErrorMessage] = useState22("");
8164
+ const [isLoading, setIsLoading] = useState22(initialView === "holdings");
8165
+ const [confirmResult, setConfirmResult] = useState22(null);
8166
+ const [showTransferDetails, setShowTransferDetails] = useState22(false);
8167
+ const [transferDepositWalletId, setTransferDepositWalletId] = useState22(void 0);
8093
8168
  const exchangeSupportedCurrencies = useMemo4(() => {
8094
8169
  const set = /* @__PURE__ */ new Set();
8095
8170
  selectedExchange?.supported_currencies.forEach((c) => set.add(c.toLowerCase()));
@@ -8111,6 +8186,21 @@ function CoinbaseConnect({
8111
8186
  params: defaultTokenParams,
8112
8187
  publishableKey
8113
8188
  });
8189
+ const defaultSourceCurrency = useMemo4(
8190
+ () => resolveDefaultSourceSymbol(supportedTokensData?.data, {
8191
+ defaultSourceChainType,
8192
+ defaultSourceChainId,
8193
+ defaultSourceTokenAddress,
8194
+ defaultSourceSymbol
8195
+ })?.toLowerCase() ?? null,
8196
+ [
8197
+ supportedTokensData,
8198
+ defaultSourceChainType,
8199
+ defaultSourceChainId,
8200
+ defaultSourceTokenAddress,
8201
+ defaultSourceSymbol
8202
+ ]
8203
+ );
8114
8204
  const sortedHoldings = useMemo4(() => {
8115
8205
  const supported = [];
8116
8206
  const unsupported = [];
@@ -8120,13 +8210,42 @@ function CoinbaseConnect({
8120
8210
  if (isSupported) supported.push(account);
8121
8211
  else unsupported.push(account);
8122
8212
  });
8213
+ if (defaultSourceCurrency) {
8214
+ const defaultIndex = supported.findIndex(
8215
+ (account) => account.currency.toLowerCase() === defaultSourceCurrency
8216
+ );
8217
+ if (defaultIndex > 0) {
8218
+ const [defaultHolding] = supported.splice(defaultIndex, 1);
8219
+ supported.unshift(defaultHolding);
8220
+ }
8221
+ }
8123
8222
  return [...supported, ...unsupported];
8124
- }, [holdings, supportedSymbols, exchangeSupportedCurrencies]);
8223
+ }, [
8224
+ holdings,
8225
+ supportedSymbols,
8226
+ exchangeSupportedCurrencies,
8227
+ defaultSourceCurrency
8228
+ ]);
8125
8229
  const selectedHoldingIsSupported = useMemo4(() => {
8126
8230
  if (!selectedHolding) return false;
8127
8231
  const currencyLower = selectedHolding.currency.toLowerCase();
8128
8232
  return (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
8129
8233
  }, [selectedHolding, supportedSymbols, exchangeSupportedCurrencies]);
8234
+ useEffect17(() => {
8235
+ if (!defaultSourceCurrency || selectedHolding) return;
8236
+ const defaultHolding = sortedHoldings.find((account) => {
8237
+ const currencyLower = account.currency.toLowerCase();
8238
+ return currencyLower === defaultSourceCurrency && (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
8239
+ });
8240
+ if (!defaultHolding) return;
8241
+ setSelectedHolding(defaultHolding);
8242
+ }, [
8243
+ defaultSourceCurrency,
8244
+ selectedHolding,
8245
+ sortedHoldings,
8246
+ supportedSymbols,
8247
+ exchangeSupportedCurrencies
8248
+ ]);
8130
8249
  const exchangeName = selectedExchange?.service_provider_display_name || "Exchange";
8131
8250
  const {
8132
8251
  executions: depositExecutions,
@@ -8144,12 +8263,12 @@ function CoinbaseConnect({
8144
8263
  } : void 0,
8145
8264
  onDepositError: onTransferError
8146
8265
  });
8147
- useEffect16(() => {
8266
+ useEffect17(() => {
8148
8267
  onExecutionsChange?.(depositExecutions);
8149
8268
  }, [depositExecutions, onExecutionsChange]);
8150
- const pollRef = useRef5(null);
8151
- const popupRef = useRef5(null);
8152
- const viewRef = useRef5(initialView);
8269
+ const pollRef = useRef6(null);
8270
+ const popupRef = useRef6(null);
8271
+ const viewRef = useRef6(initialView);
8153
8272
  const transitionTo = useCallback2((nextView) => {
8154
8273
  if (nextView === viewRef.current) return;
8155
8274
  setIsTransitioning(true);
@@ -8179,7 +8298,7 @@ function CoinbaseConnect({
8179
8298
  },
8180
8299
  [publishableKey]
8181
8300
  );
8182
- useEffect16(() => {
8301
+ useEffect17(() => {
8183
8302
  getIntegrationExchanges(publishableKey).then((res) => {
8184
8303
  setExchanges(res.data);
8185
8304
  if (!selectedExchange) {
@@ -8237,7 +8356,7 @@ function CoinbaseConnect({
8237
8356
  },
8238
8357
  [publishableKey, transitionTo, tryRefreshToken]
8239
8358
  );
8240
- useEffect16(() => {
8359
+ useEffect17(() => {
8241
8360
  return () => {
8242
8361
  if (pollRef.current) clearInterval(pollRef.current);
8243
8362
  };
@@ -8433,6 +8552,16 @@ function CoinbaseConnect({
8433
8552
  setIsLoading(false);
8434
8553
  }
8435
8554
  };
8555
+ const handleDisconnect = () => {
8556
+ onDisconnect?.();
8557
+ if (!canGoBack) {
8558
+ setAccessToken(null);
8559
+ setHoldings([]);
8560
+ setSelectedHolding(null);
8561
+ setSelectedAsset(null);
8562
+ transitionTo("select_exchange");
8563
+ }
8564
+ };
8436
8565
  const handleBack = () => {
8437
8566
  switch (view) {
8438
8567
  case "select_exchange":
@@ -8493,7 +8622,7 @@ function CoinbaseConnect({
8493
8622
  DepositHeader,
8494
8623
  {
8495
8624
  title: t12.title,
8496
- showBack: true,
8625
+ showBack: canGoBack,
8497
8626
  onBack: handleBack,
8498
8627
  onClose
8499
8628
  }
@@ -8506,7 +8635,7 @@ function CoinbaseConnect({
8506
8635
  DepositHeader,
8507
8636
  {
8508
8637
  title: t12.title,
8509
- showBack: true,
8638
+ showBack: canGoBack,
8510
8639
  onBack: handleBack,
8511
8640
  onClose
8512
8641
  }
@@ -9218,7 +9347,7 @@ function CoinbaseConnect({
9218
9347
  borderRadius: components.button.borderRadius,
9219
9348
  fontFamily: fonts.medium
9220
9349
  },
9221
- onClick: onDisconnect,
9350
+ onClick: handleDisconnect,
9222
9351
  children: t12.disconnect
9223
9352
  }
9224
9353
  )
@@ -10036,7 +10165,7 @@ function useAddressValidation({
10036
10165
  }
10037
10166
 
10038
10167
  // src/components/deposits/TransferCryptoSingleInput.tsx
10039
- import { useState as useState27, useEffect as useEffect21, useMemo as useMemo7 } from "react";
10168
+ import { useState as useState28, useEffect as useEffect22, useMemo as useMemo7 } from "react";
10040
10169
  import {
10041
10170
  ChevronDown as ChevronDown4,
10042
10171
  ChevronUp as ChevronUp3,
@@ -10051,17 +10180,17 @@ import {
10051
10180
  } from "lucide-react";
10052
10181
 
10053
10182
  // src/components/deposits/DepositsModal.tsx
10054
- import { useEffect as useEffect18, useState as useState22 } from "react";
10183
+ import { useEffect as useEffect19, useState as useState23 } from "react";
10055
10184
 
10056
10185
  // src/components/shared/ThemeStyleInjector.tsx
10057
- import * as React26 from "react";
10186
+ import * as React27 from "react";
10058
10187
  import { jsx as jsx38 } from "react/jsx-runtime";
10059
10188
  function ThemeStyleInjector({
10060
10189
  children,
10061
10190
  className
10062
10191
  }) {
10063
10192
  const { colors: colors2, fonts, mode } = useTheme();
10064
- const cssVars = React26.useMemo(() => {
10193
+ const cssVars = React27.useMemo(() => {
10065
10194
  const hexToHSL = (hex) => {
10066
10195
  hex = hex.replace("#", "");
10067
10196
  const r = parseInt(hex.slice(0, 2), 16) / 255;
@@ -10121,7 +10250,7 @@ function ThemeStyleInjector({
10121
10250
  ...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
10122
10251
  };
10123
10252
  }, [colors2, fonts.regular]);
10124
- React26.useEffect(() => {
10253
+ React27.useEffect(() => {
10125
10254
  if (typeof document === "undefined") return;
10126
10255
  if (fonts.regular) {
10127
10256
  document.documentElement.style.setProperty(
@@ -10210,9 +10339,9 @@ function DepositsModal({
10210
10339
  themeClass = ""
10211
10340
  }) {
10212
10341
  const { colors: colors2, fonts, components } = useTheme();
10213
- const [allExecutions, setAllExecutions] = useState22(sessionExecutions);
10214
- const [selectedExecution, setSelectedExecution] = useState22(null);
10215
- useEffect18(() => {
10342
+ const [allExecutions, setAllExecutions] = useState23(sessionExecutions);
10343
+ const [selectedExecution, setSelectedExecution] = useState23(null);
10344
+ useEffect19(() => {
10216
10345
  if (!open || !userId) return;
10217
10346
  const fetchExecutions = async () => {
10218
10347
  try {
@@ -10234,7 +10363,7 @@ function DepositsModal({
10234
10363
  clearInterval(pollInterval);
10235
10364
  };
10236
10365
  }, [open, userId, publishableKey, sessionExecutions]);
10237
- useEffect18(() => {
10366
+ useEffect19(() => {
10238
10367
  if (!open) {
10239
10368
  setSelectedExecution(null);
10240
10369
  }
@@ -10310,7 +10439,7 @@ function DepositsModal({
10310
10439
  }
10311
10440
 
10312
10441
  // src/components/deposits/TokenSelectorSheet.tsx
10313
- import { useState as useState23, useMemo as useMemo6, useEffect as useEffect19 } from "react";
10442
+ import { useState as useState24, useMemo as useMemo6, useEffect as useEffect20 } from "react";
10314
10443
  import { ArrowLeft as ArrowLeft2, X as X4 } from "lucide-react";
10315
10444
  import Fuse from "fuse.js";
10316
10445
  import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
@@ -10371,10 +10500,10 @@ function TokenSelectorSheet({
10371
10500
  }) {
10372
10501
  const { themeClass, colors: colors2, fonts, components } = useTheme();
10373
10502
  const isDarkMode = themeClass.includes("uf-dark");
10374
- const [searchQuery, setSearchQuery] = useState23("");
10375
- const [recentTokens, setRecentTokens] = useState23([]);
10376
- const [hoveredTokenKey, setHoveredTokenKey] = useState23(null);
10377
- useEffect19(() => {
10503
+ const [searchQuery, setSearchQuery] = useState24("");
10504
+ const [recentTokens, setRecentTokens] = useState24([]);
10505
+ const [hoveredTokenKey, setHoveredTokenKey] = useState24(null);
10506
+ useEffect20(() => {
10378
10507
  setRecentTokens(getRecentTokens());
10379
10508
  }, []);
10380
10509
  const allOptions = useMemo6(() => {
@@ -10806,7 +10935,7 @@ function TokenSelectorSheet({
10806
10935
  }
10807
10936
 
10808
10937
  // src/hooks/use-default-token.ts
10809
- import { useState as useState24, useEffect as useEffect20, useRef as useRef6 } from "react";
10938
+ import { useState as useState25, useEffect as useEffect21, useRef as useRef7 } from "react";
10810
10939
  var getChainKey = (chainId, chainType) => {
10811
10940
  return `${chainType}:${chainId}`;
10812
10941
  };
@@ -10861,11 +10990,11 @@ function useDefaultToken({
10861
10990
  defaultTokenAddress,
10862
10991
  defaultSymbol
10863
10992
  }) {
10864
- const [token, setToken] = useState24(null);
10865
- const [chain, setChain] = useState24(null);
10866
- const [initialSelectionDone, setInitialSelectionDone] = useState24(false);
10867
- const appliedDefaultsRef = useRef6("");
10868
- useEffect20(() => {
10993
+ const [token, setToken] = useState25(null);
10994
+ const [chain, setChain] = useState25(null);
10995
+ const [initialSelectionDone, setInitialSelectionDone] = useState25(false);
10996
+ const appliedDefaultsRef = useRef7("");
10997
+ useEffect21(() => {
10869
10998
  if (!tokens.length) return;
10870
10999
  const defaultsKey = `${defaultTokenAddress ?? ""}|${defaultSymbol ?? ""}|${defaultChainType ?? ""}|${defaultChainId ?? ""}`;
10871
11000
  const defaultsChanged = appliedDefaultsRef.current !== defaultsKey;
@@ -10891,7 +11020,7 @@ function useDefaultToken({
10891
11020
  defaultChainId,
10892
11021
  initialSelectionDone
10893
11022
  ]);
10894
- useEffect20(() => {
11023
+ useEffect21(() => {
10895
11024
  if (!tokens.length || !token) return;
10896
11025
  const currentToken = tokens.find((t12) => t12.symbol === token);
10897
11026
  if (!currentToken || currentToken.chains.length === 0) return;
@@ -11096,9 +11225,9 @@ function GlossaryModal({
11096
11225
  }
11097
11226
 
11098
11227
  // src/components/deposits/shared/useCopyAddress.ts
11099
- import { useState as useState25 } from "react";
11228
+ import { useState as useState26 } from "react";
11100
11229
  function useCopyAddress() {
11101
- const [copied, setCopied] = useState25(false);
11230
+ const [copied, setCopied] = useState26(false);
11102
11231
  const handleCopy = (address) => {
11103
11232
  if (!address) return;
11104
11233
  navigator.clipboard.writeText(address);
@@ -11109,7 +11238,7 @@ function useCopyAddress() {
11109
11238
  }
11110
11239
 
11111
11240
  // src/components/shared/tooltip.tsx
11112
- import * as React27 from "react";
11241
+ import * as React28 from "react";
11113
11242
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
11114
11243
  import { jsx as jsx44 } from "react/jsx-runtime";
11115
11244
  var TooltipProvider = TooltipPrimitive.Provider;
@@ -11117,7 +11246,7 @@ function Tooltip({
11117
11246
  children,
11118
11247
  ...props
11119
11248
  }) {
11120
- const [open, setOpen] = React27.useState(props.defaultOpen ?? false);
11249
+ const [open, setOpen] = React28.useState(props.defaultOpen ?? false);
11121
11250
  const isControlled = props.open !== void 0;
11122
11251
  const isOpen = isControlled ? props.open : open;
11123
11252
  const onOpenChange = isControlled ? props.onOpenChange : (nextOpen) => setOpen(nextOpen);
@@ -11137,14 +11266,14 @@ function Tooltip({
11137
11266
  }
11138
11267
  );
11139
11268
  }
11140
- var TooltipContext = React27.createContext({
11269
+ var TooltipContext = React28.createContext({
11141
11270
  open: false,
11142
11271
  onOpenChange: () => {
11143
11272
  }
11144
11273
  });
11145
- var TooltipTrigger = React27.forwardRef(({ onClick, ...props }, ref) => {
11146
- const { open, onOpenChange } = React27.useContext(TooltipContext);
11147
- const handleClick = React27.useCallback(
11274
+ var TooltipTrigger = React28.forwardRef(({ onClick, ...props }, ref) => {
11275
+ const { open, onOpenChange } = React28.useContext(TooltipContext);
11276
+ const handleClick = React28.useCallback(
11148
11277
  (e) => {
11149
11278
  onOpenChange(!open);
11150
11279
  onClick?.(e);
@@ -11154,7 +11283,7 @@ var TooltipTrigger = React27.forwardRef(({ onClick, ...props }, ref) => {
11154
11283
  return /* @__PURE__ */ jsx44(TooltipPrimitive.Trigger, { ref, onClick: handleClick, ...props });
11155
11284
  });
11156
11285
  TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName;
11157
- var TooltipContent = React27.forwardRef(({ className, sideOffset = 4, ...props }, ref) => {
11286
+ var TooltipContent = React28.forwardRef(({ className, sideOffset = 4, ...props }, ref) => {
11158
11287
  const { themeClass, colors: colors2 } = useTheme();
11159
11288
  return /* @__PURE__ */ jsx44(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx44(
11160
11289
  TooltipPrimitive.Content,
@@ -11300,12 +11429,12 @@ function TransferCryptoSingleInput({
11300
11429
  }) {
11301
11430
  const { themeClass, colors: colors2, fonts, components } = useTheme();
11302
11431
  const isDarkMode = themeClass.includes("uf-dark");
11303
- const [copied, setCopied] = useState27(false);
11432
+ const [copied, setCopied] = useState28(false);
11304
11433
  const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
11305
- const [glossaryOpen, setGlossaryOpen] = useState27(false);
11306
- const [detailsExpanded, setDetailsExpanded] = useState27(false);
11307
- const [depositsModalOpen, setDepositsModalOpen] = useState27(false);
11308
- const [tokenSelectorOpen, setTokenSelectorOpen] = useState27(false);
11434
+ const [glossaryOpen, setGlossaryOpen] = useState28(false);
11435
+ const [detailsExpanded, setDetailsExpanded] = useState28(false);
11436
+ const [depositsModalOpen, setDepositsModalOpen] = useState28(false);
11437
+ const [tokenSelectorOpen, setTokenSelectorOpen] = useState28(false);
11309
11438
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
11310
11439
  destination_token_address: destinationTokenAddress,
11311
11440
  destination_chain_id: destinationChainId,
@@ -11378,7 +11507,7 @@ function TransferCryptoSingleInput({
11378
11507
  publishableKey,
11379
11508
  enabled: !!depositAddress && !!recipientAddress
11380
11509
  });
11381
- useEffect21(() => {
11510
+ useEffect22(() => {
11382
11511
  if (!onSourceTokenChange || !token || !chain || !initialSelectionDone) return;
11383
11512
  const { chainType, chainId } = parseChainKey(chain);
11384
11513
  const matchedToken = supportedTokens.find((t12) => t12.symbol === token);
@@ -11395,7 +11524,7 @@ function TransferCryptoSingleInput({
11395
11524
  isStablecoin: matchedToken?.is_stablecoin ?? false
11396
11525
  });
11397
11526
  }, [token, chain, initialSelectionDone, onSourceTokenChange, supportedTokens]);
11398
- useEffect21(() => {
11527
+ useEffect22(() => {
11399
11528
  if (onExecutionsChange) {
11400
11529
  onExecutionsChange(depositExecutions);
11401
11530
  }
@@ -11782,7 +11911,7 @@ function TransferCryptoSingleInput({
11782
11911
  }
11783
11912
 
11784
11913
  // src/components/deposits/TransferCryptoDoubleInput.tsx
11785
- import { useState as useState28, useEffect as useEffect22, useMemo as useMemo8 } from "react";
11914
+ import { useState as useState29, useEffect as useEffect23, useMemo as useMemo8 } from "react";
11786
11915
  import {
11787
11916
  ChevronDown as ChevronDown6,
11788
11917
  ChevronUp as ChevronUp5,
@@ -11797,14 +11926,14 @@ import {
11797
11926
  } from "lucide-react";
11798
11927
 
11799
11928
  // src/components/shared/select.tsx
11800
- import * as React28 from "react";
11929
+ import * as React29 from "react";
11801
11930
  import * as SelectPrimitive from "@radix-ui/react-select";
11802
11931
  import { Check as Check5, ChevronDown as ChevronDown5, ChevronUp as ChevronUp4 } from "lucide-react";
11803
11932
  import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
11804
11933
  var Select = SelectPrimitive.Root;
11805
11934
  var SelectGroup = SelectPrimitive.Group;
11806
11935
  var SelectValue = SelectPrimitive.Value;
11807
- var SelectTrigger = React28.forwardRef(({ className, style, children, ...props }, ref) => {
11936
+ var SelectTrigger = React29.forwardRef(({ className, style, children, ...props }, ref) => {
11808
11937
  const { components } = useTheme();
11809
11938
  return /* @__PURE__ */ jsxs42(
11810
11939
  SelectPrimitive.Trigger,
@@ -11828,7 +11957,7 @@ var SelectTrigger = React28.forwardRef(({ className, style, children, ...props }
11828
11957
  );
11829
11958
  });
11830
11959
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
11831
- var SelectScrollUpButton = React28.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
11960
+ var SelectScrollUpButton = React29.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
11832
11961
  SelectPrimitive.ScrollUpButton,
11833
11962
  {
11834
11963
  ref,
@@ -11841,7 +11970,7 @@ var SelectScrollUpButton = React28.forwardRef(({ className, ...props }, ref) =>
11841
11970
  }
11842
11971
  ));
11843
11972
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
11844
- var SelectScrollDownButton = React28.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
11973
+ var SelectScrollDownButton = React29.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
11845
11974
  SelectPrimitive.ScrollDownButton,
11846
11975
  {
11847
11976
  ref,
@@ -11854,7 +11983,7 @@ var SelectScrollDownButton = React28.forwardRef(({ className, ...props }, ref) =
11854
11983
  }
11855
11984
  ));
11856
11985
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
11857
- var SelectContent = React28.forwardRef(({ className, style, children, position = "popper", ...props }, ref) => {
11986
+ var SelectContent = React29.forwardRef(({ className, style, children, position = "popper", ...props }, ref) => {
11858
11987
  const { themeClass, colors: colors2, components } = useTheme();
11859
11988
  return /* @__PURE__ */ jsx47(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs42(
11860
11989
  SelectPrimitive.Content,
@@ -11892,7 +12021,7 @@ var SelectContent = React28.forwardRef(({ className, style, children, position =
11892
12021
  ) });
11893
12022
  });
11894
12023
  SelectContent.displayName = SelectPrimitive.Content.displayName;
11895
- var SelectLabel = React28.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
12024
+ var SelectLabel = React29.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
11896
12025
  SelectPrimitive.Label,
11897
12026
  {
11898
12027
  ref,
@@ -11904,7 +12033,7 @@ var SelectLabel = React28.forwardRef(({ className, ...props }, ref) => /* @__PUR
11904
12033
  }
11905
12034
  ));
11906
12035
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
11907
- var SelectItem = React28.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs42(
12036
+ var SelectItem = React29.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs42(
11908
12037
  SelectPrimitive.Item,
11909
12038
  {
11910
12039
  ref,
@@ -11920,7 +12049,7 @@ var SelectItem = React28.forwardRef(({ className, children, ...props }, ref) =>
11920
12049
  }
11921
12050
  ));
11922
12051
  SelectItem.displayName = SelectPrimitive.Item.displayName;
11923
- var SelectSeparator = React28.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
12052
+ var SelectSeparator = React29.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx47(
11924
12053
  SelectPrimitive.Separator,
11925
12054
  {
11926
12055
  ref,
@@ -11962,11 +12091,11 @@ function TransferCryptoDoubleInput({
11962
12091
  }) {
11963
12092
  const { themeClass, colors: colors2, fonts, components } = useTheme();
11964
12093
  const isDarkMode = themeClass.includes("uf-dark");
11965
- const [copied, setCopied] = useState28(false);
12094
+ const [copied, setCopied] = useState29(false);
11966
12095
  const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
11967
- const [glossaryOpen, setGlossaryOpen] = useState28(false);
11968
- const [detailsExpanded, setDetailsExpanded] = useState28(false);
11969
- const [depositsModalOpen, setDepositsModalOpen] = useState28(false);
12096
+ const [glossaryOpen, setGlossaryOpen] = useState29(false);
12097
+ const [detailsExpanded, setDetailsExpanded] = useState29(false);
12098
+ const [depositsModalOpen, setDepositsModalOpen] = useState29(false);
11970
12099
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
11971
12100
  destination_token_address: destinationTokenAddress,
11972
12101
  destination_chain_id: destinationChainId,
@@ -12037,7 +12166,7 @@ function TransferCryptoDoubleInput({
12037
12166
  publishableKey,
12038
12167
  enabled: !!depositAddress && !!recipientAddress
12039
12168
  });
12040
- useEffect22(() => {
12169
+ useEffect23(() => {
12041
12170
  if (onExecutionsChange) {
12042
12171
  onExecutionsChange(depositExecutions);
12043
12172
  }
@@ -12380,7 +12509,7 @@ function TransferCryptoDoubleInput({
12380
12509
  }
12381
12510
 
12382
12511
  // src/components/deposits/WalletConnect.tsx
12383
- import * as React29 from "react";
12512
+ import * as React30 from "react";
12384
12513
  import { ExternalLink as ExternalLink3, Loader2 as Loader28 } from "lucide-react";
12385
12514
  import {
12386
12515
  getAddressBalances as getAddressBalances2,
@@ -13332,7 +13461,7 @@ function ReviewView({
13332
13461
  }
13333
13462
 
13334
13463
  // src/components/deposits/browser-wallets/ConfirmingView.tsx
13335
- import { useEffect as useEffect23, useState as useState29 } from "react";
13464
+ import { useEffect as useEffect24, useState as useState30 } from "react";
13336
13465
  import { Loader2 as Loader27, CheckCircle2 as CheckCircle23 } from "lucide-react";
13337
13466
  import { Fragment as Fragment10, jsx as jsx53, jsxs as jsxs47 } from "react/jsx-runtime";
13338
13467
  var SETTLE_FALLBACK_MS = 15e3;
@@ -13348,13 +13477,13 @@ function ConfirmingView({
13348
13477
  amountReceivedUsdAtSubmission
13349
13478
  }) {
13350
13479
  const { colors: colors2, fonts, components } = useTheme();
13351
- const [fallbackSettled, setFallbackSettled] = useState29(false);
13480
+ const [fallbackSettled, setFallbackSettled] = useState30(false);
13352
13481
  const hasExecution = executions.length > 0;
13353
13482
  const isCheckoutMode = paymentIntentStatus != null;
13354
13483
  const isPaymentComplete = paymentIntentStatus === "succeeded";
13355
13484
  const amountChanged = amountReceivedUsdAtSubmission != null && amountReceivedUsd != null && amountReceivedUsd !== amountReceivedUsdAtSubmission;
13356
13485
  const piSettled = !isCheckoutMode || isPaymentComplete || amountChanged || fallbackSettled;
13357
- useEffect23(() => {
13486
+ useEffect24(() => {
13358
13487
  if (!hasExecution || piSettled) return;
13359
13488
  const timeout = setTimeout(() => setFallbackSettled(true), SETTLE_FALLBACK_MS);
13360
13489
  return () => clearTimeout(timeout);
@@ -13486,6 +13615,19 @@ var WALLET_DEFINITIONS = [
13486
13615
  { id: "backpack", name: "Backpack", networks: ["solana"], installUrl: "https://backpack.app/" },
13487
13616
  { id: "glow", name: "Glow", networks: ["solana"], installUrl: "https://glow.app/" }
13488
13617
  ];
13618
+ function normalizeTokenAddress(address) {
13619
+ const normalized = (address ?? "").toLowerCase();
13620
+ if (normalized === "" || normalized === "native" || normalized === "0x0000000000000000000000000000000000000000") {
13621
+ return "native";
13622
+ }
13623
+ return normalized;
13624
+ }
13625
+ function balancesRepresentSameToken(a, b) {
13626
+ const tokenA = getTokenFromBalance(a);
13627
+ const tokenB = getTokenFromBalance(b);
13628
+ if (!tokenA || !tokenB) return false;
13629
+ return tokenA.chain_type === tokenB.chain_type && tokenA.chain_id === tokenB.chain_id && normalizeTokenAddress(tokenA.token_address) === normalizeTokenAddress(tokenB.token_address);
13630
+ }
13489
13631
  function getSolanaProviders() {
13490
13632
  if (typeof window === "undefined") return {};
13491
13633
  const win = window;
@@ -13628,24 +13770,33 @@ function WalletConnect({
13628
13770
  checkoutRemainingBaseUnits,
13629
13771
  stablecoinParity = false,
13630
13772
  productType,
13773
+ defaultSourceChainType,
13774
+ defaultSourceChainId,
13775
+ defaultSourceTokenAddress,
13776
+ defaultSourceSymbol,
13631
13777
  onBack: parentOnBack,
13632
13778
  onClose,
13779
+ canGoBack = true,
13780
+ depositWalletsLoading = false,
13633
13781
  onExecutionsChange
13634
13782
  }) {
13635
13783
  const { colors: colors2, fonts, components } = useTheme();
13636
- const walletProvidedAtMount = React29.useRef(!!initialWalletInfo && !!initialDepositWallet);
13637
- const [activeWalletInfo, setActiveWalletInfo] = React29.useState(initialWalletInfo ?? null);
13638
- const [activeDepositWallet, setActiveDepositWallet] = React29.useState(initialDepositWallet ?? null);
13784
+ const walletProvidedAtMount = React30.useRef(!!initialWalletInfo && !!initialDepositWallet);
13785
+ const [activeWalletInfo, setActiveWalletInfo] = React30.useState(initialWalletInfo ?? null);
13786
+ const [activeDepositWallet, setActiveDepositWallet] = React30.useState(initialDepositWallet ?? null);
13639
13787
  const initialView = initialWalletInfo && initialDepositWallet ? "select_token" : "select_wallet";
13640
- const [view, setView] = React29.useState(initialView);
13641
- const [isTransitioning, setIsTransitioning] = React29.useState(false);
13642
- const viewRef = React29.useRef(initialView);
13643
- const [selectedWalletDef, setSelectedWalletDef] = React29.useState(null);
13644
- const [connectingNetwork, setConnectingNetwork] = React29.useState(null);
13645
- const [walletError, setWalletError] = React29.useState(null);
13646
- const [isWalletConnecting, setIsWalletConnecting] = React29.useState(false);
13647
- const [eip6963ProviderCount, setEip6963ProviderCount] = React29.useState(0);
13648
- React29.useEffect(() => {
13788
+ const [view, setView] = React30.useState(initialView);
13789
+ const [isTransitioning, setIsTransitioning] = React30.useState(false);
13790
+ const viewRef = React30.useRef(initialView);
13791
+ const standalone = !canGoBack && !walletProvidedAtMount.current;
13792
+ const { wallet: detectedWallet, isLoading: detectingWallet } = useDetectedBrowserWallet({ enabled: standalone });
13793
+ const [autoResolved, setAutoResolved] = React30.useState(false);
13794
+ const [selectedWalletDef, setSelectedWalletDef] = React30.useState(null);
13795
+ const [connectingNetwork, setConnectingNetwork] = React30.useState(null);
13796
+ const [walletError, setWalletError] = React30.useState(null);
13797
+ const [isWalletConnecting, setIsWalletConnecting] = React30.useState(false);
13798
+ const [eip6963ProviderCount, setEip6963ProviderCount] = React30.useState(0);
13799
+ React30.useEffect(() => {
13649
13800
  const store = getEip6963Store();
13650
13801
  if (!store) return;
13651
13802
  setEip6963ProviderCount(store.getProviders().length);
@@ -13653,20 +13804,44 @@ function WalletConnect({
13653
13804
  setEip6963ProviderCount(providers.length);
13654
13805
  });
13655
13806
  }, []);
13656
- const availableWallets = React29.useMemo(() => detectAvailableWallets(), [eip6963ProviderCount]);
13657
- const [balances, setBalances] = React29.useState([]);
13658
- const [isLoading, setIsLoading] = React29.useState(false);
13659
- const [selectedBalance, setSelectedBalance] = React29.useState(null);
13660
- const [totalBalanceUsd, setTotalBalanceUsd] = React29.useState(null);
13661
- const [error, setError] = React29.useState(null);
13662
- const [isDisconnectingWallet, setIsDisconnectingWallet] = React29.useState(false);
13663
- const [amountUsd, setAmountUsd] = React29.useState(prefillAmountUsd ?? "");
13664
- const [isConfirming, setIsConfirming] = React29.useState(false);
13665
- const [hasSignedTransaction, setHasSignedTransaction] = React29.useState(false);
13666
- const [tokenChainDetails, setTokenChainDetails] = React29.useState(null);
13667
- const [loadingTokenDetails, setLoadingTokenDetails] = React29.useState(false);
13668
- const [showTransactionDetails, setShowTransactionDetails] = React29.useState(false);
13669
- const [receivedUsdAtSubmission, setReceivedUsdAtSubmission] = React29.useState(null);
13807
+ const availableWallets = React30.useMemo(() => detectAvailableWallets(), [eip6963ProviderCount]);
13808
+ React30.useEffect(() => {
13809
+ if (!standalone || autoResolved || detectingWallet) return;
13810
+ if (!detectedWallet) {
13811
+ setAutoResolved(true);
13812
+ return;
13813
+ }
13814
+ const wct = detectedWallet.type === "phantom-solana" || detectedWallet.type === "solflare" || detectedWallet.type === "backpack" || detectedWallet.type === "glow" ? "solana" : "ethereum";
13815
+ const matching = depositWallets?.find((w) => w.chain_type === wct);
13816
+ if (!matching) {
13817
+ if (!depositWalletsLoading) setAutoResolved(true);
13818
+ return;
13819
+ }
13820
+ setActiveWalletInfo(detectedWallet);
13821
+ setActiveDepositWallet(matching);
13822
+ onWalletConnected?.(detectedWallet, matching);
13823
+ setView("select_token");
13824
+ viewRef.current = "select_token";
13825
+ setAutoResolved(true);
13826
+ }, [standalone, autoResolved, detectingWallet, detectedWallet, depositWallets, depositWalletsLoading]);
13827
+ React30.useEffect(() => {
13828
+ if (!standalone || autoResolved) return;
13829
+ const t12 = setTimeout(() => setAutoResolved(true), 5e3);
13830
+ return () => clearTimeout(t12);
13831
+ }, [standalone, autoResolved]);
13832
+ const [balances, setBalances] = React30.useState([]);
13833
+ const [isLoading, setIsLoading] = React30.useState(false);
13834
+ const [selectedBalance, setSelectedBalance] = React30.useState(null);
13835
+ const [totalBalanceUsd, setTotalBalanceUsd] = React30.useState(null);
13836
+ const [error, setError] = React30.useState(null);
13837
+ const [isDisconnectingWallet, setIsDisconnectingWallet] = React30.useState(false);
13838
+ const [amountUsd, setAmountUsd] = React30.useState(prefillAmountUsd ?? "");
13839
+ const [isConfirming, setIsConfirming] = React30.useState(false);
13840
+ const [hasSignedTransaction, setHasSignedTransaction] = React30.useState(false);
13841
+ const [tokenChainDetails, setTokenChainDetails] = React30.useState(null);
13842
+ const [loadingTokenDetails, setLoadingTokenDetails] = React30.useState(false);
13843
+ const [showTransactionDetails, setShowTransactionDetails] = React30.useState(false);
13844
+ const [receivedUsdAtSubmission, setReceivedUsdAtSubmission] = React30.useState(null);
13670
13845
  const walletInfo = activeWalletInfo;
13671
13846
  const depositWallet = activeDepositWallet;
13672
13847
  const hasWallet = !!activeWalletInfo && !!activeDepositWallet;
@@ -13674,7 +13849,7 @@ function WalletConnect({
13674
13849
  const recipientAddress = activeDepositWallet?.address ?? "";
13675
13850
  const isCheckoutMode = !!checkoutAmountUsd;
13676
13851
  const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
13677
- const transitionTo = React29.useCallback((nextView) => {
13852
+ const transitionTo = React30.useCallback((nextView) => {
13678
13853
  if (nextView === viewRef.current) return;
13679
13854
  setIsTransitioning(true);
13680
13855
  setTimeout(() => {
@@ -13759,6 +13934,7 @@ function WalletConnect({
13759
13934
  metamask: "metamask"
13760
13935
  };
13761
13936
  const walletType = walletIdToType[wallet.id] || "metamask";
13937
+ setStoredWalletState(walletType);
13762
13938
  connectedInfo = { type: walletType, name: wallet.name, address: accounts[0], icon: wallet.id };
13763
13939
  } else {
13764
13940
  const solProviders = getSolanaProviders();
@@ -13787,6 +13963,7 @@ function WalletConnect({
13787
13963
  const response = await provider.connect();
13788
13964
  setUserDisconnectedWallet(false);
13789
13965
  const walletType = wallet.id === "solflare" ? "solflare" : wallet.id === "backpack" ? "backpack" : wallet.id === "glow" ? "glow" : "phantom-solana";
13966
+ setStoredWalletState(walletType);
13790
13967
  connectedInfo = { type: walletType, name: wallet.name, address: response.publicKey.toString(), icon: wallet.id };
13791
13968
  }
13792
13969
  const walletChainType = network === "solana" ? "solana" : "ethereum";
@@ -13811,7 +13988,7 @@ function WalletConnect({
13811
13988
  }
13812
13989
  };
13813
13990
  const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
13814
- const effectiveDestinationAmount = React29.useMemo(() => {
13991
+ const effectiveDestinationAmount = React30.useMemo(() => {
13815
13992
  if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
13816
13993
  if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
13817
13994
  const remaining = BigInt(checkoutRemainingBaseUnits);
@@ -13839,7 +14016,7 @@ function WalletConnect({
13839
14016
  stablecoinParity,
13840
14017
  enabled: isCheckoutMode && !!selectedToken && !!checkoutDestination && effectiveDestinationAmount !== "0"
13841
14018
  });
13842
- const activeCheckoutQuote = React29.useMemo(() => {
14019
+ const activeCheckoutQuote = React30.useMemo(() => {
13843
14020
  if (!isCheckoutMode) return null;
13844
14021
  if (walletCheckoutQuote) return { sourceAmount: walletCheckoutQuote.source_amount, sourceTokenDecimals: walletCheckoutQuote.source_token_decimals, sourceTokenSymbol: walletCheckoutQuote.source_token_symbol, sourceAmountUsd: walletCheckoutQuote.source_amount_usd, slippageBufferPercent: walletCheckoutQuote.slippage_buffer_percent ?? null };
13845
14022
  return checkoutQuote ?? null;
@@ -13853,19 +14030,19 @@ function WalletConnect({
13853
14030
  onDepositSuccess,
13854
14031
  onDepositError
13855
14032
  });
13856
- React29.useEffect(() => {
14033
+ React30.useEffect(() => {
13857
14034
  onExecutionsChange?.(depositExecutions);
13858
14035
  }, [depositExecutions, onExecutionsChange]);
13859
- React29.useEffect(() => {
14036
+ React30.useEffect(() => {
13860
14037
  if (!prefillAmountUsd || !tokenChainDetails || view !== "enter_amount") return;
13861
14038
  const minDeposit = tokenChainDetails.minimum_deposit_amount_usd || 0;
13862
14039
  const currentAmount = parseFloat(amountUsd) || 0;
13863
14040
  if (currentAmount > 0 && currentAmount < minDeposit) setAmountUsd(minDeposit.toFixed(2));
13864
14041
  }, [tokenChainDetails, view, prefillAmountUsd]);
13865
- React29.useEffect(() => {
14042
+ React30.useEffect(() => {
13866
14043
  if (view === "review") setShowTransactionDetails(false);
13867
14044
  }, [view]);
13868
- React29.useEffect(() => {
14045
+ React30.useEffect(() => {
13869
14046
  if (view !== "enter_amount" && view !== "review" || !selectedBalance || !activeDepositWallet) return;
13870
14047
  let cancelled = false;
13871
14048
  const fetchTokenDetails = async () => {
@@ -13892,7 +14069,7 @@ function WalletConnect({
13892
14069
  cancelled = true;
13893
14070
  };
13894
14071
  }, [view, selectedBalance, publishableKey, activeDepositWallet]);
13895
- React29.useEffect(() => {
14072
+ React30.useEffect(() => {
13896
14073
  if (!activeWalletInfo || !activeDepositWallet) return;
13897
14074
  let cancelled = false;
13898
14075
  setIsLoading(true);
@@ -13901,18 +14078,33 @@ function WalletConnect({
13901
14078
  getAddressBalances2(activeWalletInfo.address, sct, publishableKey).then((response) => {
13902
14079
  if (cancelled) return;
13903
14080
  const nonZero = response.balances.filter((b) => b.amount !== "0");
13904
- const sorted = [...nonZero].sort((a, b) => {
13905
- const ae = isBalanceEligible(a);
13906
- const be = isBalanceEligible(b);
13907
- if (ae && !be) return -1;
13908
- if (!ae && be) return 1;
13909
- return 0;
13910
- });
14081
+ const defaultSource = {
14082
+ defaultSourceChainType,
14083
+ defaultSourceChainId,
14084
+ defaultSourceTokenAddress,
14085
+ defaultSourceSymbol
14086
+ };
14087
+ const sorted = [...nonZero].sort(
14088
+ (a, b) => compareBalancesWithDefaultSource(a, b, defaultSource)
14089
+ );
13911
14090
  setBalances(sorted);
13912
14091
  const totalUsd = nonZero.reduce((sum, b) => b.amount_usd ? sum + parseFloat(b.amount_usd) : sum, 0);
13913
14092
  if (totalUsd > 0) setTotalBalanceUsd(totalUsd.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
13914
14093
  const eligible = sorted.filter(isBalanceEligible);
13915
- if (eligible.length === 1) setSelectedBalance(eligible[0]);
14094
+ const defaultBalance = sorted.find(
14095
+ (balance) => isDefaultSourceBalance(balance, defaultSource)
14096
+ );
14097
+ setSelectedBalance((current) => {
14098
+ if (current) {
14099
+ const currentInNewBalances = sorted.find(
14100
+ (balance) => balancesRepresentSameToken(balance, current)
14101
+ );
14102
+ if (currentInNewBalances) return currentInNewBalances;
14103
+ }
14104
+ if (defaultBalance) return defaultBalance;
14105
+ if (eligible.length === 1) return eligible[0];
14106
+ return null;
14107
+ });
13916
14108
  }).catch((err) => {
13917
14109
  if (!cancelled) {
13918
14110
  console.error("[WalletConnect] Error fetching balances:", err);
@@ -13924,21 +14116,29 @@ function WalletConnect({
13924
14116
  return () => {
13925
14117
  cancelled = true;
13926
14118
  };
13927
- }, [activeWalletInfo?.address, activeDepositWallet?.chain_type, publishableKey]);
13928
- const usdToTokenRate = React29.useMemo(() => {
14119
+ }, [
14120
+ activeWalletInfo?.address,
14121
+ activeDepositWallet?.chain_type,
14122
+ publishableKey,
14123
+ defaultSourceChainType,
14124
+ defaultSourceChainId,
14125
+ defaultSourceTokenAddress,
14126
+ defaultSourceSymbol
14127
+ ]);
14128
+ const usdToTokenRate = React30.useMemo(() => {
13929
14129
  if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken) return 0;
13930
14130
  const balanceAmount = Number(selectedBalance.amount) / 10 ** selectedToken.decimals;
13931
14131
  const balanceUsd = parseFloat(selectedBalance.amount_usd);
13932
14132
  if (balanceAmount === 0 || balanceUsd === 0) return 0;
13933
14133
  return balanceAmount / balanceUsd;
13934
14134
  }, [selectedBalance, selectedToken]);
13935
- const tokenAmount = React29.useMemo(() => {
14135
+ const tokenAmount = React30.useMemo(() => {
13936
14136
  if (isCheckoutMode && activeCheckoutQuote && selectedToken) return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
13937
14137
  const usdNum = parseFloat(amountUsd) || 0;
13938
14138
  if (usdNum === 0 || usdToTokenRate === 0) return 0;
13939
14139
  return usdNum * usdToTokenRate;
13940
14140
  }, [amountUsd, usdToTokenRate, isCheckoutMode, activeCheckoutQuote, selectedToken]);
13941
- React29.useEffect(() => {
14141
+ React30.useEffect(() => {
13942
14142
  if (isCheckoutMode && activeCheckoutQuote?.sourceAmountUsd && view === "enter_amount") setAmountUsd(activeCheckoutQuote.sourceAmountUsd);
13943
14143
  }, [isCheckoutMode, activeCheckoutQuote, view]);
13944
14144
  const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
@@ -13946,7 +14146,7 @@ function WalletConnect({
13946
14146
  const inputUsdNum = parseFloat(amountUsd) || 0;
13947
14147
  const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
13948
14148
  const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
13949
- const formattedTokenAmount = React29.useMemo(() => {
14149
+ const formattedTokenAmount = React30.useMemo(() => {
13950
14150
  if (tokenAmount === 0 || !selectedToken) return null;
13951
14151
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(/\.?0+$/, "");
13952
14152
  }, [tokenAmount, selectedToken]);
@@ -13994,16 +14194,25 @@ function WalletConnect({
13994
14194
  } catch (err) {
13995
14195
  console.warn("[WalletConnect] disconnect error:", err);
13996
14196
  } finally {
13997
- setActiveWalletInfo(null);
13998
- setActiveDepositWallet(null);
13999
- setSelectedBalance(null);
14000
- setBalances([]);
14001
- setTotalBalanceUsd(null);
14002
- setAmountUsd(prefillAmountUsd ?? "");
14003
- setError(null);
14004
14197
  setIsDisconnectingWallet(false);
14005
- if (onWalletDisconnect) onWalletDisconnect();
14006
- else parentOnBack?.();
14198
+ const clearWalletState = () => {
14199
+ setActiveWalletInfo(null);
14200
+ setActiveDepositWallet(null);
14201
+ setSelectedBalance(null);
14202
+ setBalances([]);
14203
+ setTotalBalanceUsd(null);
14204
+ setAmountUsd(prefillAmountUsd ?? "");
14205
+ setError(null);
14206
+ };
14207
+ if (standalone) {
14208
+ onWalletDisconnect?.();
14209
+ transitionTo("select_wallet");
14210
+ setTimeout(clearWalletState, 160);
14211
+ } else {
14212
+ clearWalletState();
14213
+ if (onWalletDisconnect) onWalletDisconnect();
14214
+ else parentOnBack?.();
14215
+ }
14007
14216
  }
14008
14217
  };
14009
14218
  const handleReview = () => {
@@ -14129,9 +14338,15 @@ function WalletConnect({
14129
14338
  setIsConfirming(false);
14130
14339
  }
14131
14340
  };
14341
+ if (standalone && !autoResolved) {
14342
+ return /* @__PURE__ */ jsxs48("div", { style: viewTransitionStyle, children: [
14343
+ /* @__PURE__ */ jsx54(DepositHeader, { title: "Connect Wallet", showBack: canGoBack, onBack: handleBack, onClose }),
14344
+ /* @__PURE__ */ jsx54("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16", children: /* @__PURE__ */ jsx54(Loader28, { className: "uf-w-8 uf-h-8 uf-animate-spin", style: { color: colors2.primary } }) })
14345
+ ] });
14346
+ }
14132
14347
  if (view === "select_wallet") {
14133
14348
  return /* @__PURE__ */ jsxs48("div", { style: viewTransitionStyle, children: [
14134
- /* @__PURE__ */ jsx54(DepositHeader, { title: "Connect Wallet", showBack: true, onBack: handleBack, onClose }),
14349
+ /* @__PURE__ */ jsx54(DepositHeader, { title: "Connect Wallet", showBack: canGoBack, onBack: handleBack, onClose }),
14135
14350
  /* @__PURE__ */ jsxs48("div", { className: "uf-pb-4", children: [
14136
14351
  /* @__PURE__ */ jsx54("p", { className: "uf-text-sm uf-text-center uf-pb-4", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "Select a wallet to connect" }),
14137
14352
  /* @__PURE__ */ jsx54("div", { className: "uf-space-y-2", style: { maxHeight: 330, overflowY: "auto" }, children: availableWallets.map((wallet) => /* @__PURE__ */ jsxs48(
@@ -14267,16 +14482,17 @@ function DepositModal({
14267
14482
  defaultSourceChainId,
14268
14483
  defaultSourceTokenAddress,
14269
14484
  defaultSourceSymbol,
14270
- hideDepositTracker = false,
14485
+ hideDepositTracker,
14271
14486
  showBalanceHeader = false,
14272
14487
  transferInputVariant = "double_input",
14273
14488
  depositConfirmationMode = "auto_ui",
14274
- enableConnectWallet = false,
14489
+ enableTransferCrypto,
14490
+ enableConnectWallet,
14275
14491
  browserWalletAmountQuickSelect = "percentage",
14276
14492
  enablePayWithExchange,
14277
14493
  enableFiatOnramp,
14278
- enableConnectExchange = false,
14279
- enableCashApp = false,
14494
+ enableConnectExchange,
14495
+ enableCashApp,
14280
14496
  hideDepositFlowInfo = false,
14281
14497
  hideDisplayDescription = false,
14282
14498
  onDepositSuccess,
@@ -14294,49 +14510,72 @@ function DepositModal({
14294
14510
  const { colors: colors2, fonts, components } = useTheme();
14295
14511
  const effectiveInitialScreen = useMemo10(() => {
14296
14512
  const s = initialScreen ?? "main";
14297
- if (s === "tracker" && hideDepositTracker) return "main";
14298
- if (s === "cashapp" && !enableCashApp) return "main";
14513
+ if (s === "tracker" && hideDepositTracker === true) return "main";
14514
+ if (s === "cashapp" && enableCashApp === false) return "main";
14299
14515
  if (s === "card" && enableFiatOnramp === false) return "main";
14516
+ if (s === "pay_with_exchange") return enablePayWithExchange === false ? "main" : "exchange";
14517
+ if (s === "exchange_connect")
14518
+ return enableConnectExchange === false ? "main" : "coinbase_connect";
14519
+ if (s === "wallet_connect") return enableConnectWallet === false ? "main" : "wallet_connect";
14300
14520
  return s;
14301
- }, [initialScreen, hideDepositTracker, enableCashApp, enableFiatOnramp]);
14302
- const [containerEl, setContainerEl] = useState31(null);
14521
+ }, [
14522
+ initialScreen,
14523
+ hideDepositTracker,
14524
+ enableCashApp,
14525
+ enableFiatOnramp,
14526
+ enablePayWithExchange,
14527
+ enableConnectExchange,
14528
+ enableConnectWallet
14529
+ ]);
14530
+ const [containerEl, setContainerEl] = useState32(null);
14303
14531
  const containerCallbackRef = useCallback5((el) => {
14304
14532
  setContainerEl(el);
14305
14533
  }, []);
14306
- const [view, setView] = useState31(
14534
+ const [view, setView] = useState32(
14307
14535
  effectiveInitialScreen
14308
14536
  );
14309
- const [coinbaseSkipToHoldings, setCoinbaseSkipToHoldings] = useState31(false);
14310
- const resetViewTimeoutRef = useRef8(null);
14311
- const [cardView, setCardView] = useState31(
14537
+ const [coinbaseSkipToHoldings, setCoinbaseSkipToHoldings] = useState32(false);
14538
+ const resetViewTimeoutRef = useRef9(null);
14539
+ const [cardView, setCardView] = useState32(
14312
14540
  "amount"
14313
14541
  );
14314
- const [exchangeView, setExchangeView] = useState31(
14542
+ const [exchangeView, setExchangeView] = useState32(
14315
14543
  "providers"
14316
14544
  );
14317
- const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState31(false);
14318
- const [browserWalletInfo, setBrowserWalletInfo] = useState31(null);
14319
- const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState31(false);
14320
- const [browserWalletChainType, setBrowserWalletChainType] = useState31(() => getStoredWalletChainType());
14321
- const [quotesCount, setQuotesCount] = useState31(0);
14322
- const [allExecutions, setAllExecutions] = useState31([]);
14323
- const [selectedExecution, setSelectedExecution] = useState31(null);
14324
- const [depositExecutions, setDepositExecutions] = useState31([]);
14545
+ const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState32(false);
14546
+ const [browserWalletInfo, setBrowserWalletInfo] = useState32(null);
14547
+ const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState32(false);
14548
+ const [browserWalletChainType, setBrowserWalletChainType] = useState32(() => getStoredWalletState()?.chainType);
14549
+ const [quotesCount, setQuotesCount] = useState32(0);
14550
+ const [allExecutions, setAllExecutions] = useState32([]);
14551
+ const [selectedExecution, setSelectedExecution] = useState32(null);
14552
+ const [depositExecutions, setDepositExecutions] = useState32([]);
14325
14553
  const isMobileView = useIsMobileViewport();
14326
- const [integrationExchanges, setIntegrationExchanges] = useState31([]);
14327
- useEffect25(() => {
14328
- if (!enableConnectExchange || !open) return;
14554
+ const { projectConfig } = useProjectConfig({
14555
+ publishableKey,
14556
+ enabled: open
14557
+ });
14558
+ const showTransferCrypto = enableTransferCrypto ?? projectConfig?.transfer_crypto?.enabled ?? true;
14559
+ const showConnectWallet = enableConnectWallet ?? projectConfig?.connect_wallet?.enabled ?? true;
14560
+ const showPayWithExchange = enablePayWithExchange ?? projectConfig?.pay_with_exchange?.enabled ?? true;
14561
+ const showFiatOnramp = enableFiatOnramp ?? projectConfig?.fiat_onramp?.enabled ?? true;
14562
+ const showConnectExchange = enableConnectExchange ?? projectConfig?.connect_exchange?.enabled ?? true;
14563
+ const showCashApp = enableCashApp ?? projectConfig?.cash_app?.enabled ?? true;
14564
+ const showDepositTracker = hideDepositTracker ? false : projectConfig?.deposit_tracker?.enabled ?? true;
14565
+ const [integrationExchanges, setIntegrationExchanges] = useState32([]);
14566
+ useEffect26(() => {
14567
+ if (!showConnectExchange || !open) return;
14329
14568
  getIntegrationExchanges2(publishableKey).then((res) => setIntegrationExchanges(res.data)).catch(() => {
14330
14569
  });
14331
- }, [enableConnectExchange, open, publishableKey]);
14332
- const [connectedExchange, setConnectedExchange] = useState31(() => {
14333
- if (!enableConnectExchange) return null;
14570
+ }, [showConnectExchange, open, publishableKey]);
14571
+ const [connectedExchange, setConnectedExchange] = useState32(() => {
14572
+ if (!showConnectExchange) return null;
14334
14573
  const stored = getStoredIntegrationToken(IntegrationProvider2.COINBASE);
14335
14574
  if (!stored) return null;
14336
14575
  return { name: "Coinbase", iconUrl: void 0, balanceUsd: null, isLoading: true };
14337
14576
  });
14338
- useEffect25(() => {
14339
- if (!enableConnectExchange || !open || view !== "main") return;
14577
+ useEffect26(() => {
14578
+ if (!showConnectExchange || !open || view !== "main") return;
14340
14579
  const stored = getStoredIntegrationToken(IntegrationProvider2.COINBASE);
14341
14580
  if (!stored) {
14342
14581
  setConnectedExchange(null);
@@ -14371,8 +14610,8 @@ function DepositModal({
14371
14610
  setConnectedExchange(null);
14372
14611
  }
14373
14612
  });
14374
- }, [enableConnectExchange, open, view, publishableKey]);
14375
- useEffect25(() => {
14613
+ }, [showConnectExchange, open, view, publishableKey]);
14614
+ useEffect26(() => {
14376
14615
  if (!connectedExchange || integrationExchanges.length === 0) return;
14377
14616
  const cbExchange = integrationExchanges.find(
14378
14617
  (e) => e.service_provider === IntegrationProvider2.COINBASE
@@ -14394,10 +14633,10 @@ function DepositModal({
14394
14633
  // Only fetch when modal is open
14395
14634
  });
14396
14635
  const wallets = depositAddressResponse?.data ?? [];
14397
- const [resolvedTheme, setResolvedTheme] = useState31(
14636
+ const [resolvedTheme, setResolvedTheme] = useState32(
14398
14637
  theme === "auto" ? "dark" : theme
14399
14638
  );
14400
- useEffect25(() => {
14639
+ useEffect26(() => {
14401
14640
  if (theme === "auto") {
14402
14641
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
14403
14642
  setResolvedTheme(mediaQuery.matches ? "dark" : "light");
@@ -14410,18 +14649,39 @@ function DepositModal({
14410
14649
  setResolvedTheme(theme);
14411
14650
  }
14412
14651
  }, [theme]);
14413
- const { projectConfig } = useProjectConfig({
14414
- publishableKey,
14415
- enabled: open
14416
- });
14417
- const showPayWithExchange = enablePayWithExchange ?? projectConfig?.pay_with_exchange?.enabled ?? true;
14418
- const showFiatOnramp = enableFiatOnramp ?? projectConfig?.fiat_onramp?.enabled ?? true;
14419
- useEffect25(() => {
14652
+ useEffect26(() => {
14420
14653
  if (view === "card" && !showFiatOnramp) {
14421
14654
  setView("main");
14422
14655
  setCardView("amount");
14656
+ } else if (view === "transfer" && !showTransferCrypto) {
14657
+ setView("main");
14658
+ } else if (view === "exchange" && !showPayWithExchange) {
14659
+ setView("main");
14660
+ } else if (view === "cashapp" && !showCashApp) {
14661
+ setView("main");
14662
+ } else if (view === "tracker" && !showDepositTracker) {
14663
+ setView("main");
14664
+ } else if (view === "coinbase_connect" && !showConnectExchange) {
14665
+ setView("main");
14666
+ } else if (view === "wallet_connect" && !showConnectWallet) {
14667
+ setView("main");
14423
14668
  }
14424
- }, [view, showFiatOnramp]);
14669
+ }, [
14670
+ view,
14671
+ showFiatOnramp,
14672
+ showTransferCrypto,
14673
+ showPayWithExchange,
14674
+ showCashApp,
14675
+ showDepositTracker,
14676
+ showConnectExchange,
14677
+ showConnectWallet
14678
+ ]);
14679
+ useEffect26(() => {
14680
+ if (view === "exchange" && !showPayWithExchange) {
14681
+ setView("main");
14682
+ setExchangeView("providers");
14683
+ }
14684
+ }, [view, showPayWithExchange]);
14425
14685
  const { exchanges, isLoading: exchangesLoading } = useExchanges({
14426
14686
  publishableKey,
14427
14687
  enabled: open && showPayWithExchange
@@ -14436,7 +14696,7 @@ function DepositModal({
14436
14696
  subdivisionCode: userIpInfo?.subdivisionCode ?? void 0,
14437
14697
  enabled: open && !isLoadingIp
14438
14698
  });
14439
- useEffect25(() => {
14699
+ useEffect26(() => {
14440
14700
  if (view !== "tracker" || !userId) return;
14441
14701
  const fetchExecutions = async () => {
14442
14702
  try {
@@ -14457,7 +14717,7 @@ function DepositModal({
14457
14717
  clearInterval(pollInterval);
14458
14718
  };
14459
14719
  }, [view, userId, publishableKey]);
14460
- useEffect25(() => {
14720
+ useEffect26(() => {
14461
14721
  if (view !== "tracker") {
14462
14722
  setSelectedExecution(null);
14463
14723
  }
@@ -14505,7 +14765,7 @@ function DepositModal({
14505
14765
  depositPrerequisiteBody = standaloneNeedsDepositPrereq ? /* @__PURE__ */ jsx55(SkeletonButton, { variant: "with-icons" }) : /* @__PURE__ */ jsxs49(Fragment11, { children: [
14506
14766
  /* @__PURE__ */ jsx55(SkeletonButton, { variant: "with-icons" }),
14507
14767
  /* @__PURE__ */ jsx55(SkeletonButton, { variant: "with-icons" }),
14508
- !hideDepositTracker && /* @__PURE__ */ jsx55(SkeletonButton, {})
14768
+ showDepositTracker && /* @__PURE__ */ jsx55(SkeletonButton, {})
14509
14769
  ] });
14510
14770
  } else if (countryError) {
14511
14771
  depositPrerequisiteBody = /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
@@ -14537,11 +14797,11 @@ function DepositModal({
14537
14797
  const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
14538
14798
  const handleWalletDisconnect = () => {
14539
14799
  setUserDisconnectedWallet(true);
14540
- clearStoredWalletChainType();
14800
+ clearStoredWalletState();
14541
14801
  setBrowserWalletChainType(void 0);
14542
14802
  setBrowserWalletInfo(null);
14543
14803
  setBrowserWalletModalOpen(false);
14544
- if (view === "wallet_connect") setView("main");
14804
+ if (view === "wallet_connect" && sessionOpenedFromMenu) setView("main");
14545
14805
  };
14546
14806
  const handleExchangeDisconnect = () => {
14547
14807
  const stored = getStoredIntegrationToken(IntegrationProvider2.COINBASE);
@@ -14550,7 +14810,7 @@ function DepositModal({
14550
14810
  }
14551
14811
  clearStoredIntegrationToken(IntegrationProvider2.COINBASE);
14552
14812
  setConnectedExchange(null);
14553
- if (view === "coinbase_connect") setView("main");
14813
+ if (view === "coinbase_connect" && sessionOpenedFromMenu) setView("main");
14554
14814
  };
14555
14815
  const handleClose = () => {
14556
14816
  onOpenChange(false);
@@ -14562,6 +14822,7 @@ function DepositModal({
14562
14822
  setCardView("amount");
14563
14823
  setExchangeView("providers");
14564
14824
  setBrowserWalletInfo(null);
14825
+ setCoinbaseSkipToHoldings(false);
14565
14826
  resetViewTimeoutRef.current = null;
14566
14827
  }, 200);
14567
14828
  };
@@ -14576,8 +14837,9 @@ function DepositModal({
14576
14837
  setExchangeView("providers");
14577
14838
  setBrowserWalletInfo(null);
14578
14839
  setSelectedExecution(null);
14840
+ setCoinbaseSkipToHoldings(false);
14579
14841
  }, [open, effectiveInitialScreen]);
14580
- useEffect25(
14842
+ useEffect26(
14581
14843
  () => () => {
14582
14844
  if (resetViewTimeoutRef.current) {
14583
14845
  clearTimeout(resetViewTimeoutRef.current);
@@ -14585,8 +14847,8 @@ function DepositModal({
14585
14847
  },
14586
14848
  []
14587
14849
  );
14588
- const [cashAppView, setCashAppView] = useState31("amount");
14589
- const [cashAppAmount, setCashAppAmount] = useState31("");
14850
+ const [cashAppView, setCashAppView] = useState32("amount");
14851
+ const [cashAppAmount, setCashAppAmount] = useState32("");
14590
14852
  const handleBack = () => {
14591
14853
  if (view === "card" && cardView === "quotes") {
14592
14854
  setCardView("amount");
@@ -14613,7 +14875,7 @@ function DepositModal({
14613
14875
  };
14614
14876
  const handleBrowserWalletClick = (walletInfo) => {
14615
14877
  const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
14616
- setStoredWalletChainType(walletChainType);
14878
+ setStoredWalletState(walletInfo.type);
14617
14879
  setBrowserWalletChainType(walletChainType);
14618
14880
  const matchingDepositWallet = wallets.find(
14619
14881
  (w) => w.chain_type === walletChainType
@@ -14644,7 +14906,7 @@ function DepositModal({
14644
14906
  };
14645
14907
  const handleWalletConnected = (walletInfo) => {
14646
14908
  const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
14647
- setStoredWalletChainType(walletChainType);
14909
+ setStoredWalletState(walletInfo.type);
14648
14910
  setBrowserWalletChainType(walletChainType);
14649
14911
  const matchingDepositWallet = wallets.find(
14650
14912
  (w) => w.chain_type === walletChainType
@@ -14711,7 +14973,7 @@ function DepositModal({
14711
14973
  ),
14712
14974
  /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
14713
14975
  /* @__PURE__ */ jsx55("div", { className: "uf-space-y-3", children: depositPrerequisiteBody ?? /* @__PURE__ */ jsxs49(Fragment11, { children: [
14714
- /* @__PURE__ */ jsx55(
14976
+ showTransferCrypto && /* @__PURE__ */ jsx55(
14715
14977
  TransferCryptoButton,
14716
14978
  {
14717
14979
  onClick: () => setView("transfer"),
@@ -14720,7 +14982,7 @@ function DepositModal({
14720
14982
  featuredTokens: projectConfig?.transfer_crypto.networks
14721
14983
  }
14722
14984
  ),
14723
- enableConnectWallet && !isMobileView && /* @__PURE__ */ jsx55(
14985
+ showConnectWallet && !isMobileView && /* @__PURE__ */ jsx55(
14724
14986
  BrowserWalletButton,
14725
14987
  {
14726
14988
  onClick: handleBrowserWalletClick,
@@ -14750,7 +15012,7 @@ function DepositModal({
14750
15012
  loading: exchangesLoading
14751
15013
  }
14752
15014
  ),
14753
- enableConnectExchange && connectedExchange && /* @__PURE__ */ jsx55(
15015
+ showConnectExchange && connectedExchange && /* @__PURE__ */ jsx55(
14754
15016
  ConnectExchangeButton,
14755
15017
  {
14756
15018
  onClick: () => {
@@ -14764,7 +15026,7 @@ function DepositModal({
14764
15026
  connectedExchange
14765
15027
  }
14766
15028
  ),
14767
- enableConnectExchange && !connectedExchange && /* @__PURE__ */ jsx55(
15029
+ showConnectExchange && !connectedExchange && /* @__PURE__ */ jsx55(
14768
15030
  ConnectExchangeButton,
14769
15031
  {
14770
15032
  onClick: () => {
@@ -14776,7 +15038,7 @@ function DepositModal({
14776
15038
  exchanges: integrationExchanges
14777
15039
  }
14778
15040
  ),
14779
- enableCashApp && /* @__PURE__ */ jsx55(
15041
+ showCashApp && /* @__PURE__ */ jsx55(
14780
15042
  CashAppButton,
14781
15043
  {
14782
15044
  onClick: () => setView("cashapp"),
@@ -14785,7 +15047,7 @@ function DepositModal({
14785
15047
  iconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0
14786
15048
  }
14787
15049
  ),
14788
- !hideDepositTracker && /* @__PURE__ */ jsx55(
15050
+ showDepositTracker && /* @__PURE__ */ jsx55(
14789
15051
  DepositTrackerButton,
14790
15052
  {
14791
15053
  onClick: () => {
@@ -14935,7 +15197,7 @@ function DepositModal({
14935
15197
  DepositHeader,
14936
15198
  {
14937
15199
  title: payWithExchangeTitle,
14938
- showBack: true,
15200
+ showBack: exchangeView === "pending" || sessionOpenedFromMenu,
14939
15201
  onBack: handleBack,
14940
15202
  onClose: handleClose
14941
15203
  }
@@ -14989,7 +15251,12 @@ function DepositModal({
14989
15251
  onClose: handleClose,
14990
15252
  onDisconnect: handleExchangeDisconnect,
14991
15253
  skipToHoldings: coinbaseSkipToHoldings,
14992
- onExecutionsChange: setDepositExecutions
15254
+ canGoBack: sessionOpenedFromMenu,
15255
+ onExecutionsChange: setDepositExecutions,
15256
+ defaultSourceChainType,
15257
+ defaultSourceChainId,
15258
+ defaultSourceTokenAddress,
15259
+ defaultSourceSymbol
14993
15260
  }
14994
15261
  ),
14995
15262
  depositPoweredByFooter
@@ -15022,11 +15289,17 @@ function DepositModal({
15022
15289
  onWalletDisconnect: handleWalletDisconnect,
15023
15290
  onWalletConnected: (info, dw) => {
15024
15291
  setBrowserWalletInfo({ ...info, depositWallet: dw });
15025
- setStoredWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
15292
+ setStoredWalletState(info.type);
15026
15293
  setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
15027
15294
  },
15028
15295
  onBack: handleBack,
15029
- onClose: handleClose
15296
+ onClose: handleClose,
15297
+ defaultSourceChainType,
15298
+ defaultSourceChainId,
15299
+ defaultSourceTokenAddress,
15300
+ defaultSourceSymbol,
15301
+ canGoBack: sessionOpenedFromMenu,
15302
+ depositWalletsLoading: walletsLoading
15030
15303
  }
15031
15304
  ),
15032
15305
  depositPoweredByFooter
@@ -15035,7 +15308,7 @@ function DepositModal({
15035
15308
  DepositHeader,
15036
15309
  {
15037
15310
  title: cashAppView !== "amount" && cashAppAmount ? `Pay $${cashAppAmount} via Cash App` : "Pay with Cash App",
15038
- showBack: true,
15311
+ showBack: cashAppView !== "amount" || sessionOpenedFromMenu,
15039
15312
  onBack: handleBack,
15040
15313
  onClose: handleClose
15041
15314
  }
@@ -15070,11 +15343,11 @@ function DepositModal({
15070
15343
 
15071
15344
  // src/components/checkout/CheckoutModal.tsx
15072
15345
  import {
15073
- useState as useState32,
15074
- useEffect as useEffect26,
15346
+ useState as useState33,
15347
+ useEffect as useEffect27,
15075
15348
  useLayoutEffect as useLayoutEffect3,
15076
15349
  useCallback as useCallback6,
15077
- useRef as useRef9,
15350
+ useRef as useRef10,
15078
15351
  useMemo as useMemo11
15079
15352
  } from "react";
15080
15353
  import { AlertTriangle as AlertTriangle3, ChevronRight as ChevronRight15 } from "lucide-react";
@@ -15145,7 +15418,8 @@ function CheckoutModal({
15145
15418
  clientSecret,
15146
15419
  publishableKey,
15147
15420
  modalTitle,
15148
- enableConnectWallet = false,
15421
+ enableTransferCrypto,
15422
+ enableConnectWallet,
15149
15423
  defaultSourceChainType,
15150
15424
  defaultSourceChainId,
15151
15425
  defaultSourceTokenAddress,
@@ -15155,19 +15429,19 @@ function CheckoutModal({
15155
15429
  onCheckoutError
15156
15430
  }) {
15157
15431
  const { colors: colors2, fonts, components } = useTheme();
15158
- const [view, setView] = useState32("main");
15159
- const resetViewTimeoutRef = useRef9(
15432
+ const [view, setView] = useState33("main");
15433
+ const resetViewTimeoutRef = useRef10(
15160
15434
  null
15161
15435
  );
15162
- const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState32(false);
15163
- const [browserWalletInfo, setBrowserWalletInfo] = useState32(null);
15164
- const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState32(false);
15165
- const [browserWalletChainType, setBrowserWalletChainType] = useState32(() => getStoredWalletChainType());
15436
+ const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState33(false);
15437
+ const [browserWalletInfo, setBrowserWalletInfo] = useState33(null);
15438
+ const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState33(false);
15439
+ const [browserWalletChainType, setBrowserWalletChainType] = useState33(() => getStoredWalletState()?.chainType);
15166
15440
  const isMobileView = useIsMobileViewport();
15167
- const [resolvedTheme, setResolvedTheme] = useState32(
15441
+ const [resolvedTheme, setResolvedTheme] = useState33(
15168
15442
  theme === "auto" ? "dark" : theme
15169
15443
  );
15170
- useEffect26(() => {
15444
+ useEffect27(() => {
15171
15445
  if (theme === "auto") {
15172
15446
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
15173
15447
  setResolvedTheme(mediaQuery.matches ? "dark" : "light");
@@ -15195,8 +15469,17 @@ function CheckoutModal({
15195
15469
  publishableKey,
15196
15470
  enabled: open
15197
15471
  });
15198
- const prevStatusRef = useRef9(null);
15199
- useEffect26(() => {
15472
+ const showTransferCrypto = enableTransferCrypto ?? projectConfig?.transfer_crypto?.enabled ?? true;
15473
+ const showConnectWallet = enableConnectWallet ?? projectConfig?.connect_wallet?.enabled ?? true;
15474
+ useEffect27(() => {
15475
+ if (view === "transfer" && !showTransferCrypto) {
15476
+ setView("main");
15477
+ } else if (view === "wallet_connect" && !showConnectWallet) {
15478
+ setView("main");
15479
+ }
15480
+ }, [showConnectWallet, showTransferCrypto, view]);
15481
+ const prevStatusRef = useRef10(null);
15482
+ useEffect27(() => {
15200
15483
  if (!paymentIntent) return;
15201
15484
  const prev = prevStatusRef.current;
15202
15485
  prevStatusRef.current = paymentIntent.status;
@@ -15242,7 +15525,7 @@ function CheckoutModal({
15242
15525
  const remaining = total - received;
15243
15526
  return remaining > 0n ? remaining.toString() : "0";
15244
15527
  }, [paymentIntent]);
15245
- const [selectedSource, setSelectedSource] = useState32(null);
15528
+ const [selectedSource, setSelectedSource] = useState33(null);
15246
15529
  const remainingDestinationAmount = useMemo11(() => {
15247
15530
  if (!paymentIntent) return "0";
15248
15531
  const remaining = BigInt(paymentIntent.destination_amount) - BigInt(paymentIntent.destination_amount_received);
@@ -15285,7 +15568,7 @@ function CheckoutModal({
15285
15568
  const handleBrowserWalletClick = useCallback6(
15286
15569
  (walletInfo) => {
15287
15570
  const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
15288
- setStoredWalletChainType(walletChainType);
15571
+ setStoredWalletState(walletInfo.type);
15289
15572
  setBrowserWalletChainType(walletChainType);
15290
15573
  const matchingDepositWallet = wallets.find(
15291
15574
  (w) => w.chain_type === walletChainType
@@ -15312,7 +15595,7 @@ function CheckoutModal({
15312
15595
  const handleWalletConnected = useCallback6(
15313
15596
  (walletInfo) => {
15314
15597
  const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
15315
- setStoredWalletChainType(walletChainType);
15598
+ setStoredWalletState(walletInfo.type);
15316
15599
  setBrowserWalletChainType(walletChainType);
15317
15600
  const matchingDepositWallet = wallets.find(
15318
15601
  (w) => w.chain_type === walletChainType
@@ -15336,7 +15619,7 @@ function CheckoutModal({
15336
15619
  );
15337
15620
  const handleWalletDisconnect = useCallback6(() => {
15338
15621
  setUserDisconnectedWallet(true);
15339
- clearStoredWalletChainType();
15622
+ clearStoredWalletState();
15340
15623
  setBrowserWalletChainType(void 0);
15341
15624
  setBrowserWalletInfo(null);
15342
15625
  setBrowserWalletModalOpen(false);
@@ -15362,7 +15645,7 @@ function CheckoutModal({
15362
15645
  setView("main");
15363
15646
  setBrowserWalletInfo(null);
15364
15647
  }, [open]);
15365
- useEffect26(
15648
+ useEffect27(
15366
15649
  () => () => {
15367
15650
  if (resetViewTimeoutRef.current) {
15368
15651
  clearTimeout(resetViewTimeoutRef.current);
@@ -15571,7 +15854,7 @@ function CheckoutModal({
15571
15854
  ] }) : paymentIntent ? /* @__PURE__ */ jsxs50("div", { className: "uf-space-y-3", children: [
15572
15855
  progressSection,
15573
15856
  (paymentIntent.status === "requires_payment" || paymentIntent.status === "processing") && /* @__PURE__ */ jsxs50(Fragment12, { children: [
15574
- /* @__PURE__ */ jsx56(
15857
+ showTransferCrypto && /* @__PURE__ */ jsx56(
15575
15858
  TransferCryptoButton,
15576
15859
  {
15577
15860
  onClick: () => setView("transfer"),
@@ -15580,7 +15863,7 @@ function CheckoutModal({
15580
15863
  featuredTokens: projectConfig?.transfer_crypto.networks
15581
15864
  }
15582
15865
  ),
15583
- enableConnectWallet && !isMobileView && /* @__PURE__ */ jsx56(
15866
+ showConnectWallet && !isMobileView && /* @__PURE__ */ jsx56(
15584
15867
  BrowserWalletButton,
15585
15868
  {
15586
15869
  onClick: handleBrowserWalletClick,
@@ -15721,14 +16004,18 @@ function CheckoutModal({
15721
16004
  onWalletDisconnect: handleWalletDisconnect,
15722
16005
  onWalletConnected: (info, dw) => {
15723
16006
  setBrowserWalletInfo({ ...info, depositWallet: dw });
15724
- setStoredWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
16007
+ setStoredWalletState(info.type);
15725
16008
  setBrowserWalletChainType(dw.chain_type === "solana" ? "solana" : "ethereum");
15726
16009
  },
15727
16010
  onNewDeposit: () => setView("main"),
15728
16011
  onDone: () => setView("main"),
15729
16012
  paymentIntentStatus: paymentIntent.status,
15730
16013
  onBack: handleBack,
15731
- onClose: handleClose
16014
+ onClose: handleClose,
16015
+ defaultSourceChainType,
16016
+ defaultSourceChainId,
16017
+ defaultSourceTokenAddress,
16018
+ defaultSourceSymbol
15732
16019
  }
15733
16020
  ),
15734
16021
  poweredByFooter
@@ -15739,11 +16026,11 @@ function CheckoutModal({
15739
16026
 
15740
16027
  // src/components/withdrawals/WithdrawModal.tsx
15741
16028
  import {
15742
- useState as useState36,
15743
- useEffect as useEffect30,
16029
+ useState as useState37,
16030
+ useEffect as useEffect31,
15744
16031
  useLayoutEffect as useLayoutEffect4,
15745
16032
  useCallback as useCallback8,
15746
- useRef as useRef11
16033
+ useRef as useRef12
15747
16034
  } from "react";
15748
16035
  import { AlertTriangle as AlertTriangle5, ChevronRight as ChevronRight17, Clock as Clock6 } from "lucide-react";
15749
16036
 
@@ -15919,7 +16206,7 @@ function useExecutions(userId, publishableKey, options) {
15919
16206
  }
15920
16207
 
15921
16208
  // src/hooks/use-withdraw-polling.ts
15922
- import { useState as useState33, useEffect as useEffect27, useRef as useRef10 } from "react";
16209
+ import { useState as useState34, useEffect as useEffect28, useRef as useRef11 } from "react";
15923
16210
  import {
15924
16211
  queryExecutions as queryExecutions5,
15925
16212
  pollDirectExecutions as pollDirectExecutions2,
@@ -15937,20 +16224,20 @@ function useWithdrawPolling({
15937
16224
  onWithdrawSuccess,
15938
16225
  onWithdrawError
15939
16226
  }) {
15940
- const [executions, setExecutions] = useState33([]);
15941
- const [isPolling, setIsPolling] = useState33(false);
15942
- const enabledAtRef = useRef10(/* @__PURE__ */ new Date());
15943
- const trackedRef = useRef10(/* @__PURE__ */ new Map());
15944
- const prevEnabledRef = useRef10(false);
15945
- const onSuccessRef = useRef10(onWithdrawSuccess);
15946
- const onErrorRef = useRef10(onWithdrawError);
15947
- useEffect27(() => {
16227
+ const [executions, setExecutions] = useState34([]);
16228
+ const [isPolling, setIsPolling] = useState34(false);
16229
+ const enabledAtRef = useRef11(/* @__PURE__ */ new Date());
16230
+ const trackedRef = useRef11(/* @__PURE__ */ new Map());
16231
+ const prevEnabledRef = useRef11(false);
16232
+ const onSuccessRef = useRef11(onWithdrawSuccess);
16233
+ const onErrorRef = useRef11(onWithdrawError);
16234
+ useEffect28(() => {
15948
16235
  onSuccessRef.current = onWithdrawSuccess;
15949
16236
  }, [onWithdrawSuccess]);
15950
- useEffect27(() => {
16237
+ useEffect28(() => {
15951
16238
  onErrorRef.current = onWithdrawError;
15952
16239
  }, [onWithdrawError]);
15953
- useEffect27(() => {
16240
+ useEffect28(() => {
15954
16241
  if (enabled && !prevEnabledRef.current) {
15955
16242
  enabledAtRef.current = /* @__PURE__ */ new Date();
15956
16243
  trackedRef.current.clear();
@@ -15960,7 +16247,7 @@ function useWithdrawPolling({
15960
16247
  }
15961
16248
  prevEnabledRef.current = enabled;
15962
16249
  }, [enabled]);
15963
- useEffect27(() => {
16250
+ useEffect28(() => {
15964
16251
  if (!userId || !enabled) return;
15965
16252
  const enabledAt = enabledAtRef.current;
15966
16253
  const poll = async () => {
@@ -16022,7 +16309,7 @@ function useWithdrawPolling({
16022
16309
  setIsPolling(false);
16023
16310
  };
16024
16311
  }, [userId, publishableKey, enabled]);
16025
- useEffect27(() => {
16312
+ useEffect28(() => {
16026
16313
  if (!enabled || !depositWalletId) return;
16027
16314
  const trigger = async () => {
16028
16315
  try {
@@ -16193,7 +16480,7 @@ function WithdrawDoubleInput({
16193
16480
  }
16194
16481
 
16195
16482
  // src/components/withdrawals/WithdrawForm.tsx
16196
- import { useState as useState34, useCallback as useCallback7, useMemo as useMemo13, useEffect as useEffect28 } from "react";
16483
+ import { useState as useState35, useCallback as useCallback7, useMemo as useMemo13, useEffect as useEffect29 } from "react";
16197
16484
  import {
16198
16485
  AlertTriangle as AlertTriangle4,
16199
16486
  ArrowUpDown,
@@ -16670,27 +16957,27 @@ function WithdrawForm({
16670
16957
  footerLeft
16671
16958
  }) {
16672
16959
  const { colors: colors2, fonts, components } = useTheme();
16673
- const [recipientAddress, setRecipientAddress] = useState34(recipientAddressProp || "");
16674
- const [amount, setAmount] = useState34("");
16675
- const [inputUnit, setInputUnit] = useState34("fiat");
16676
- const [isSubmitting, setIsSubmitting] = useState34(false);
16677
- const [submitError, setSubmitError] = useState34(null);
16678
- const [detailsExpanded, setDetailsExpanded] = useState34(false);
16679
- const [glossaryOpen, setGlossaryOpen] = useState34(false);
16680
- const [isMaxed, setIsMaxed] = useState34(false);
16681
- useEffect28(() => {
16960
+ const [recipientAddress, setRecipientAddress] = useState35(recipientAddressProp || "");
16961
+ const [amount, setAmount] = useState35("");
16962
+ const [inputUnit, setInputUnit] = useState35("fiat");
16963
+ const [isSubmitting, setIsSubmitting] = useState35(false);
16964
+ const [submitError, setSubmitError] = useState35(null);
16965
+ const [detailsExpanded, setDetailsExpanded] = useState35(false);
16966
+ const [glossaryOpen, setGlossaryOpen] = useState35(false);
16967
+ const [isMaxed, setIsMaxed] = useState35(false);
16968
+ useEffect29(() => {
16682
16969
  setRecipientAddress(recipientAddressProp || "");
16683
16970
  setAmount("");
16684
16971
  setInputUnit("fiat");
16685
16972
  setSubmitError(null);
16686
16973
  setIsMaxed(false);
16687
16974
  }, [recipientAddressProp]);
16688
- useEffect28(() => {
16975
+ useEffect29(() => {
16689
16976
  setIsMaxed(false);
16690
16977
  }, [balanceData?.balanceBaseUnit]);
16691
16978
  const trimmedAddress = recipientAddress.trim();
16692
- const [debouncedAddress, setDebouncedAddress] = useState34(trimmedAddress);
16693
- useEffect28(() => {
16979
+ const [debouncedAddress, setDebouncedAddress] = useState35(trimmedAddress);
16980
+ useEffect29(() => {
16694
16981
  const id = setTimeout(() => setDebouncedAddress(trimmedAddress), 500);
16695
16982
  return () => clearTimeout(id);
16696
16983
  }, [trimmedAddress]);
@@ -17330,7 +17617,7 @@ function WithdrawExecutionItem({
17330
17617
  }
17331
17618
 
17332
17619
  // src/components/withdrawals/WithdrawConfirmingView.tsx
17333
- import { useState as useState35, useEffect as useEffect29 } from "react";
17620
+ import { useState as useState36, useEffect as useEffect30 } from "react";
17334
17621
  import { Fragment as Fragment14, jsx as jsx60, jsxs as jsxs54 } from "react/jsx-runtime";
17335
17622
  function truncateAddress4(addr) {
17336
17623
  if (addr.length <= 12) return addr;
@@ -17344,9 +17631,9 @@ function WithdrawConfirmingView({
17344
17631
  onViewTracker
17345
17632
  }) {
17346
17633
  const { colors: colors2, fonts, components } = useTheme();
17347
- const [showButton, setShowButton] = useState35(false);
17634
+ const [showButton, setShowButton] = useState36(false);
17348
17635
  const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
17349
- useEffect29(() => {
17636
+ useEffect30(() => {
17350
17637
  if (latestExecution) return;
17351
17638
  const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
17352
17639
  return () => clearTimeout(timer);
@@ -17511,14 +17798,14 @@ function WithdrawModal({
17511
17798
  hideOverlay = false
17512
17799
  }) {
17513
17800
  const { colors: colors2, fonts, components } = useTheme();
17514
- const [containerEl, setContainerEl] = useState36(null);
17801
+ const [containerEl, setContainerEl] = useState37(null);
17515
17802
  const containerCallbackRef = useCallback8((el) => {
17516
17803
  setContainerEl(el);
17517
17804
  }, []);
17518
- const [resolvedTheme, setResolvedTheme] = useState36(
17805
+ const [resolvedTheme, setResolvedTheme] = useState37(
17519
17806
  theme === "auto" ? "dark" : theme
17520
17807
  );
17521
- useEffect30(() => {
17808
+ useEffect31(() => {
17522
17809
  if (theme === "auto") {
17523
17810
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
17524
17811
  setResolvedTheme(mq.matches ? "dark" : "light");
@@ -17562,10 +17849,10 @@ function WithdrawModal({
17562
17849
  });
17563
17850
  const selectedToken = selectedTokenSymbol ? destinationTokens.find((t12) => t12.symbol === selectedTokenSymbol) ?? null : null;
17564
17851
  const selectedChain = selectedToken && selectedChainKey ? selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === selectedChainKey) ?? null : null;
17565
- const [view, setView] = useState36("form");
17566
- const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState36();
17567
- const [selectedExecution, setSelectedExecution] = useState36(null);
17568
- const [submittedTxInfo, setSubmittedTxInfo] = useState36(null);
17852
+ const [view, setView] = useState37("form");
17853
+ const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState37();
17854
+ const [selectedExecution, setSelectedExecution] = useState37(null);
17855
+ const [submittedTxInfo, setSubmittedTxInfo] = useState37(null);
17569
17856
  const { executions: realtimeExecutions } = useWithdrawPolling({
17570
17857
  userId: externalUserId,
17571
17858
  publishableKey,
@@ -17604,7 +17891,7 @@ function WithdrawModal({
17604
17891
  setSubmittedTxInfo(txInfo);
17605
17892
  setView("confirming");
17606
17893
  }, []);
17607
- const resetViewTimeoutRef = useRef11(null);
17894
+ const resetViewTimeoutRef = useRef12(null);
17608
17895
  const handleClose = useCallback8(() => {
17609
17896
  onOpenChange(false);
17610
17897
  if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
@@ -17627,7 +17914,7 @@ function WithdrawModal({
17627
17914
  setSubmittedTxInfo(null);
17628
17915
  setWithdrawDepositWalletId(void 0);
17629
17916
  }, [open]);
17630
- useEffect30(() => () => {
17917
+ useEffect31(() => () => {
17631
17918
  if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
17632
17919
  }, []);
17633
17920
  const handleTokenSymbolChange = useCallback8((symbol) => {
@@ -17750,7 +18037,7 @@ function WithdrawModal({
17750
18037
  }
17751
18038
 
17752
18039
  // src/components/withdrawals/WithdrawTokenSelector.tsx
17753
- import { useState as useState37, useMemo as useMemo14 } from "react";
18040
+ import { useState as useState38, useMemo as useMemo14 } from "react";
17754
18041
  import { Search } from "lucide-react";
17755
18042
  import Fuse2 from "fuse.js";
17756
18043
  import { jsx as jsx62, jsxs as jsxs56 } from "react/jsx-runtime";
@@ -17761,8 +18048,8 @@ function WithdrawTokenSelector({
17761
18048
  onBack
17762
18049
  }) {
17763
18050
  const { themeClass, colors: colors2, fonts, components } = useTheme();
17764
- const [searchQuery, setSearchQuery] = useState37("");
17765
- const [hoveredKey, setHoveredKey] = useState37(null);
18051
+ const [searchQuery, setSearchQuery] = useState38("");
18052
+ const [hoveredKey, setHoveredKey] = useState38(null);
17766
18053
  const allOptions = useMemo14(() => {
17767
18054
  const options = [];
17768
18055
  tokens.forEach((token) => {