@compass-labs/widgets 0.1.38 → 0.1.40

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,9 +1,10 @@
1
- import { createContext, forwardRef, useState, useCallback, useImperativeHandle, useContext, useEffect, useRef, useMemo } from 'react';
1
+ import { createContext, forwardRef, useState, useCallback, useImperativeHandle, useContext, useRef, useEffect, useMemo } from 'react';
2
2
  import { useQueryClient, useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
3
  import { CompassApiSDK } from '@compass-labs/api-sdk';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import { arbitrum, base, mainnet } from 'viem/chains';
6
- import { Wallet, Loader2, ArrowDownLeft, ArrowUpRight, X, ChevronDown, Check, Copy, LogOut, AlertCircle, ArrowRight, ExternalLink, ArrowDownUp, ArrowLeftRight, CheckCircle, TrendingUp, Plus, Minus, Circle, AlertTriangle, XCircle, TrendingDown, ChevronRight, ArrowUpCircle, ArrowDownCircle, RotateCcw, Equal, ChevronUp, Inbox, Percent, Clock, Calendar } from 'lucide-react';
6
+ import { Wallet, Loader2, ArrowDownLeft, ArrowUpRight, Send, ArrowRight, X, CheckCircle, AlertCircle, CreditCard, ExternalLink, XCircle, Check, Copy, LogOut, ChevronDown, ArrowDownUp, ArrowLeftRight, TrendingUp, Plus, Minus, Circle, AlertTriangle, TrendingDown, ChevronRight, ArrowUpCircle, ArrowDownCircle, RotateCcw, Equal, ChevronUp, Inbox, Percent, Clock, Calendar } from 'lucide-react';
7
+ import { isAddress, encodeFunctionData, parseUnits } from 'viem';
7
8
 
8
9
  // src/provider/CompassProvider.tsx
9
10
  var ApiContext = createContext(null);
@@ -90,7 +91,10 @@ var disconnectedWallet = {
90
91
  },
91
92
  switchChain: null,
92
93
  login: null,
93
- logout: null
94
+ logout: null,
95
+ fundWallet: null,
96
+ hasExternalWallet: true,
97
+ sendTransaction: null
94
98
  };
95
99
  function WalletProvider({ children, wallet }) {
96
100
  const value = wallet ? {
@@ -100,7 +104,10 @@ function WalletProvider({ children, wallet }) {
100
104
  signTypedData: wallet.signTypedData,
101
105
  switchChain: wallet.switchChain ?? null,
102
106
  login: wallet.login ?? null,
103
- logout: wallet.logout ?? null
107
+ logout: wallet.logout ?? null,
108
+ fundWallet: wallet.fundWallet ?? null,
109
+ hasExternalWallet: wallet.hasExternalWallet ?? true,
110
+ sendTransaction: wallet.sendTransaction ?? null
104
111
  } : disconnectedWallet;
105
112
  return /* @__PURE__ */ jsx(WalletContext.Provider, { value, children });
106
113
  }
@@ -1158,9 +1165,9 @@ function CopyableAddress({
1158
1165
  title: copied ? "Copied!" : `Copy: ${address}`,
1159
1166
  children: [
1160
1167
  label && /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: label }),
1161
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
1168
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
1162
1169
  /* @__PURE__ */ jsx("span", { className: "text-xs font-mono", style: { color: "var(--compass-color-text)" }, children: displayAddr }),
1163
- copied ? /* @__PURE__ */ jsx(Check, { size: 12, className: "flex-shrink-0", style: { color: "var(--compass-color-success)" } }) : /* @__PURE__ */ jsx(Copy, { size: 12, className: "flex-shrink-0", style: { color: "var(--compass-color-text-tertiary)" } })
1170
+ copied ? /* @__PURE__ */ jsx(Check, { size: 14, className: "flex-shrink-0", style: { color: "var(--compass-color-success)" } }) : /* @__PURE__ */ jsx(Copy, { size: 14, className: "flex-shrink-0", style: { color: "var(--compass-color-text-secondary)" } })
1164
1171
  ] })
1165
1172
  ]
1166
1173
  }
@@ -1269,25 +1276,29 @@ function WalletStatus({
1269
1276
  );
1270
1277
  }
1271
1278
  function ActionModal({ isOpen, onClose, title, children }) {
1279
+ const modalRef = useRef(null);
1272
1280
  useEffect(() => {
1273
1281
  const handleEscape = (e) => {
1274
1282
  if (e.key === "Escape") onClose();
1275
1283
  };
1276
1284
  if (isOpen) {
1277
1285
  document.addEventListener("keydown", handleEscape);
1278
- document.body.style.overflow = "hidden";
1279
1286
  }
1280
1287
  return () => {
1281
1288
  document.removeEventListener("keydown", handleEscape);
1282
- document.body.style.overflow = "";
1283
1289
  };
1284
1290
  }, [isOpen, onClose]);
1291
+ const handleOverlayWheel = useCallback((e) => {
1292
+ if (modalRef.current && !modalRef.current.contains(e.target)) {
1293
+ window.scrollBy(0, e.deltaY);
1294
+ }
1295
+ }, []);
1285
1296
  if (!isOpen) return null;
1286
1297
  return /* @__PURE__ */ jsxs(
1287
1298
  "div",
1288
1299
  {
1289
1300
  className: "fixed inset-0 z-50 flex items-center justify-center p-4",
1290
- style: { overflowY: "auto", scrollbarWidth: "none" },
1301
+ onWheel: handleOverlayWheel,
1291
1302
  children: [
1292
1303
  /* @__PURE__ */ jsx(
1293
1304
  "div",
@@ -1300,21 +1311,27 @@ function ActionModal({ isOpen, onClose, title, children }) {
1300
1311
  /* @__PURE__ */ jsxs(
1301
1312
  "div",
1302
1313
  {
1314
+ ref: modalRef,
1303
1315
  className: "relative w-full max-w-md",
1304
1316
  style: {
1305
1317
  backgroundColor: "var(--compass-color-surface)",
1306
1318
  boxShadow: "var(--compass-shadow-lg)",
1307
1319
  borderRadius: "var(--compass-border-radius-xl)",
1308
- fontFamily: "var(--compass-font-family)"
1320
+ fontFamily: "var(--compass-font-family)",
1321
+ maxHeight: "85vh",
1322
+ overflowY: "auto",
1323
+ overscrollBehavior: "contain",
1324
+ scrollbarWidth: "none"
1309
1325
  },
1310
1326
  children: [
1311
1327
  /* @__PURE__ */ jsxs(
1312
1328
  "div",
1313
1329
  {
1314
- className: "flex items-center justify-between border-b",
1330
+ className: "flex items-center justify-between border-b sticky top-0 z-10",
1315
1331
  style: {
1316
1332
  borderColor: "var(--compass-color-border)",
1317
- padding: "calc(var(--compass-spacing-card) * 0.75) var(--compass-spacing-card)"
1333
+ padding: "calc(var(--compass-spacing-card) * 0.75) var(--compass-spacing-card)",
1334
+ backgroundColor: "var(--compass-color-surface)"
1318
1335
  },
1319
1336
  children: [
1320
1337
  /* @__PURE__ */ jsx(
@@ -2571,114 +2588,731 @@ function CreditAccountGuard({
2571
2588
  }
2572
2589
  );
2573
2590
  }
2574
- function AccountBalancesModal({
2575
- isOpen,
2576
- onClose,
2577
- balances,
2578
- totalUsdValue,
2579
- isLoading = false,
2580
- earnAccountAddress,
2581
- walletAddress
2582
- }) {
2583
- return /* @__PURE__ */ jsx(ActionModal, { isOpen, onClose, title: "Balance Breakdown", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
2584
- (walletAddress || earnAccountAddress) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
2585
- walletAddress && /* @__PURE__ */ jsx(CopyableAddress, { address: walletAddress, label: "Wallet" }),
2586
- earnAccountAddress && /* @__PURE__ */ jsx(CopyableAddress, { address: earnAccountAddress, label: "Product Account" })
2587
- ] }),
2588
- isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-4", children: /* @__PURE__ */ jsx(
2589
- Loader2,
2590
- {
2591
- size: 24,
2592
- className: "animate-spin",
2593
- style: { color: "var(--compass-color-primary)" }
2594
- }
2595
- ) }) : balances.length === 0 ? /* @__PURE__ */ jsx(
2596
- "div",
2591
+ var EVM_CHAIN_IDS = {
2592
+ ethereum: 1,
2593
+ base: 8453,
2594
+ arbitrum: 42161
2595
+ };
2596
+ function BuyForm({ targetAddress, defaultAsset = "USDC", onComplete }) {
2597
+ const { fundWallet } = useEmbeddableWallet();
2598
+ const { chainId } = useChain();
2599
+ const [amount, setAmount] = useState("");
2600
+ const [state, setState] = useState("idle");
2601
+ const [error, setError] = useState(null);
2602
+ const numericChainId = EVM_CHAIN_IDS[chainId] || 8453;
2603
+ const handleBuy = useCallback(async () => {
2604
+ if (!fundWallet || !amount || parseFloat(amount) <= 0) {
2605
+ return;
2606
+ }
2607
+ setState("buying");
2608
+ setError(null);
2609
+ try {
2610
+ await fundWallet({
2611
+ address: targetAddress,
2612
+ chainId: numericChainId,
2613
+ asset: defaultAsset,
2614
+ amount
2615
+ });
2616
+ setState("success");
2617
+ onComplete?.();
2618
+ setTimeout(() => setState("idle"), 3e3);
2619
+ } catch (err) {
2620
+ setState("error");
2621
+ setError(err instanceof Error ? err.message : "Purchase failed. Please try again.");
2622
+ }
2623
+ }, [fundWallet, amount, targetAddress, numericChainId, defaultAsset, onComplete]);
2624
+ const chainName = chainId.charAt(0).toUpperCase() + chainId.slice(1);
2625
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
2626
+ /* @__PURE__ */ jsxs(
2627
+ "p",
2597
2628
  {
2598
- className: "text-center py-4",
2599
- style: { color: "var(--compass-color-text-tertiary)" },
2600
- children: "No tokens in account"
2629
+ className: "text-sm font-medium",
2630
+ style: { color: "var(--compass-color-text)", fontFamily: "var(--compass-font-family)" },
2631
+ children: [
2632
+ "Buy ",
2633
+ defaultAsset,
2634
+ " on ",
2635
+ chainName
2636
+ ]
2601
2637
  }
2602
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2603
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2638
+ ),
2639
+ /* @__PURE__ */ jsxs("div", { children: [
2640
+ /* @__PURE__ */ jsx(
2641
+ "label",
2642
+ {
2643
+ className: "block text-sm mb-1.5",
2644
+ style: { color: "var(--compass-color-text-secondary)", fontFamily: "var(--compass-font-family)" },
2645
+ children: "Amount (USD)"
2646
+ }
2647
+ ),
2648
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2604
2649
  /* @__PURE__ */ jsx(
2605
2650
  "span",
2606
2651
  {
2607
- className: "text-xs font-medium uppercase tracking-wide",
2652
+ className: "absolute left-3 top-1/2 -translate-y-1/2 text-sm",
2608
2653
  style: { color: "var(--compass-color-text-tertiary)" },
2609
- children: "Available in Account"
2654
+ children: "$"
2610
2655
  }
2611
2656
  ),
2612
2657
  /* @__PURE__ */ jsx(
2613
- "div",
2658
+ "input",
2614
2659
  {
2615
- className: "flex flex-col gap-2",
2616
- style: {
2617
- maxHeight: "50vh",
2618
- overflowY: "auto",
2619
- scrollbarWidth: "none"
2660
+ type: "number",
2661
+ value: amount,
2662
+ onChange: (e) => {
2663
+ setAmount(e.target.value);
2664
+ if (state === "error") {
2665
+ setState("idle");
2666
+ setError(null);
2667
+ }
2620
2668
  },
2621
- children: balances.filter((token) => parseFloat(token.balance) >= 5e-3).map((token) => /* @__PURE__ */ jsxs(
2622
- "div",
2669
+ disabled: state === "buying",
2670
+ placeholder: "0.00",
2671
+ className: "w-full border px-3 py-2.5 pl-7 text-sm focus:outline-none disabled:opacity-50",
2672
+ style: {
2673
+ backgroundColor: "var(--compass-color-surface)",
2674
+ borderColor: "var(--compass-color-border)",
2675
+ borderRadius: "var(--compass-border-radius-lg)",
2676
+ color: "var(--compass-color-text)",
2677
+ fontFamily: "var(--compass-font-family)"
2678
+ }
2679
+ }
2680
+ )
2681
+ ] })
2682
+ ] }),
2683
+ /* @__PURE__ */ jsx(
2684
+ "p",
2685
+ {
2686
+ className: "text-xs",
2687
+ style: { color: "var(--compass-color-text-tertiary)", fontFamily: "var(--compass-font-family)" },
2688
+ children: "Buy crypto with card or bank transfer. Funds are sent directly to your account."
2689
+ }
2690
+ ),
2691
+ state === "success" && /* @__PURE__ */ jsxs(
2692
+ "div",
2693
+ {
2694
+ className: "flex items-center gap-2 p-3 text-sm",
2695
+ style: {
2696
+ backgroundColor: "var(--compass-color-success-muted, rgba(34,197,94,0.1))",
2697
+ color: "var(--compass-color-success)",
2698
+ borderRadius: "var(--compass-border-radius-lg)",
2699
+ fontFamily: "var(--compass-font-family)"
2700
+ },
2701
+ children: [
2702
+ /* @__PURE__ */ jsx(CheckCircle, { size: 16 }),
2703
+ "Purchase initiated. Funds may take a few minutes to arrive."
2704
+ ]
2705
+ }
2706
+ ),
2707
+ state === "error" && error && /* @__PURE__ */ jsxs(
2708
+ "div",
2709
+ {
2710
+ className: "flex items-center gap-2 p-3 text-sm",
2711
+ style: {
2712
+ backgroundColor: "var(--compass-color-error-muted, rgba(239,68,68,0.1))",
2713
+ color: "var(--compass-color-error)",
2714
+ borderRadius: "var(--compass-border-radius-lg)",
2715
+ fontFamily: "var(--compass-font-family)"
2716
+ },
2717
+ children: [
2718
+ /* @__PURE__ */ jsx(AlertCircle, { size: 16 }),
2719
+ error
2720
+ ]
2721
+ }
2722
+ ),
2723
+ /* @__PURE__ */ jsx(
2724
+ "button",
2725
+ {
2726
+ onClick: handleBuy,
2727
+ disabled: state === "buying" || !amount || parseFloat(amount) <= 0,
2728
+ className: "w-full py-3 px-4 text-sm font-medium flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
2729
+ style: {
2730
+ backgroundColor: "var(--compass-color-primary)",
2731
+ color: "white",
2732
+ borderRadius: "var(--compass-border-radius-xl)",
2733
+ fontFamily: "var(--compass-font-family)",
2734
+ transition: "var(--compass-transition-normal)"
2735
+ },
2736
+ children: state === "buying" ? /* @__PURE__ */ jsxs(Fragment, { children: [
2737
+ /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
2738
+ "Processing..."
2739
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2740
+ /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
2741
+ "Buy with card / bank"
2742
+ ] })
2743
+ }
2744
+ )
2745
+ ] });
2746
+ }
2747
+ var BLOCK_EXPLORERS = {
2748
+ ethereum: "https://etherscan.io",
2749
+ base: "https://basescan.org",
2750
+ arbitrum: "https://arbiscan.io"
2751
+ };
2752
+ function TxStatus({ state }) {
2753
+ const { chainId } = useChain();
2754
+ if (state.status === "idle") return null;
2755
+ const explorer = BLOCK_EXPLORERS[chainId] || BLOCK_EXPLORERS.ethereum;
2756
+ return /* @__PURE__ */ jsxs(
2757
+ "div",
2758
+ {
2759
+ className: "mt-4 p-4 border",
2760
+ style: {
2761
+ borderColor: "var(--compass-color-border)",
2762
+ borderRadius: "var(--compass-border-radius-xl)",
2763
+ fontFamily: "var(--compass-font-family)"
2764
+ },
2765
+ children: [
2766
+ state.status === "preparing" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
2767
+ /* @__PURE__ */ jsx(
2768
+ Loader2,
2769
+ {
2770
+ className: "h-4 w-4 animate-spin",
2771
+ style: { color: "var(--compass-color-primary)" }
2772
+ }
2773
+ ),
2774
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Preparing transaction..." })
2775
+ ] }),
2776
+ state.status === "signing" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
2777
+ /* @__PURE__ */ jsx(
2778
+ Loader2,
2779
+ {
2780
+ className: "h-4 w-4 animate-spin",
2781
+ style: { color: "var(--compass-color-warning)" }
2782
+ }
2783
+ ),
2784
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Waiting for signature..." })
2785
+ ] }),
2786
+ state.status === "broadcasting" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
2787
+ /* @__PURE__ */ jsx(
2788
+ Loader2,
2789
+ {
2790
+ className: "h-4 w-4 animate-spin",
2791
+ style: { color: "var(--compass-color-primary)" }
2792
+ }
2793
+ ),
2794
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Broadcasting transaction..." })
2795
+ ] }),
2796
+ state.status === "submitted" && /* @__PURE__ */ jsxs("div", { children: [
2797
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2798
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
2799
+ /* @__PURE__ */ jsx(
2800
+ Loader2,
2801
+ {
2802
+ className: "h-4 w-4 animate-spin",
2803
+ style: { color: "var(--compass-color-primary)" }
2804
+ }
2805
+ ),
2806
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text)" }, children: "Transaction submitted" })
2807
+ ] }),
2808
+ /* @__PURE__ */ jsxs(
2809
+ "a",
2623
2810
  {
2624
- className: "flex items-center justify-between p-3 rounded-lg",
2625
- style: {
2626
- backgroundColor: "var(--compass-color-surface)",
2627
- border: "1px solid var(--compass-color-border)",
2628
- flexShrink: 0
2629
- },
2811
+ href: `${explorer}/tx/${state.txHash}`,
2812
+ target: "_blank",
2813
+ rel: "noopener noreferrer",
2814
+ className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
2815
+ style: { color: "var(--compass-color-text-secondary)" },
2630
2816
  children: [
2631
- /* @__PURE__ */ jsx("span", { className: "font-medium", style: { color: "var(--compass-color-text)" }, children: token.symbol }),
2632
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end", children: [
2633
- /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", style: { color: "var(--compass-color-text)" }, children: formatAmount(token.balance) }),
2634
- /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: formatUSD(token.usdValue) })
2635
- ] })
2817
+ "View on explorer",
2818
+ /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3" })
2636
2819
  ]
2637
- },
2638
- token.symbol
2639
- ))
2640
- }
2641
- )
2642
- ] }),
2643
- /* @__PURE__ */ jsxs(
2644
- "div",
2645
- {
2646
- className: "flex items-center justify-between pt-3 mt-2",
2647
- style: { borderTop: "2px solid var(--compass-color-border)" },
2648
- children: [
2649
- /* @__PURE__ */ jsx("span", { className: "font-semibold", style: { color: "var(--compass-color-text)" }, children: "Total" }),
2820
+ }
2821
+ )
2822
+ ] }),
2823
+ /* @__PURE__ */ jsx(
2824
+ "p",
2825
+ {
2826
+ className: "text-xs mt-2",
2827
+ style: { color: "var(--compass-color-text-tertiary)" },
2828
+ children: "Waiting for on-chain confirmation. Balances will update automatically."
2829
+ }
2830
+ )
2831
+ ] }),
2832
+ state.status === "confirmed" && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2833
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
2650
2834
  /* @__PURE__ */ jsx(
2651
- "span",
2835
+ CheckCircle,
2652
2836
  {
2653
- className: "font-bold text-xl",
2654
- style: { color: "var(--compass-color-text)" },
2655
- children: formatUSD(totalUsdValue)
2837
+ className: "h-4 w-4",
2838
+ style: { color: "var(--compass-color-success)" }
2656
2839
  }
2657
- )
2658
- ]
2659
- }
2660
- )
2661
- ] })
2662
- ] }) });
2663
- }
2664
- var TRANSFER_TOKENS = ["USDC", "SBC"];
2665
- var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2666
- compact = false,
2667
- hideVisual = false,
2668
- onTransferComplete
2669
- }, ref) {
2670
- const [isModalOpen, setIsModalOpen] = useState(false);
2671
- const [activeAction, setActiveAction] = useState("deposit");
2672
- const [selectedToken, setSelectedToken] = useState(TRANSFER_TOKENS[0]);
2840
+ ),
2841
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-success)" }, children: "Transaction confirmed" })
2842
+ ] }),
2843
+ /* @__PURE__ */ jsxs(
2844
+ "a",
2845
+ {
2846
+ href: `${explorer}/tx/${state.txHash}`,
2847
+ target: "_blank",
2848
+ rel: "noopener noreferrer",
2849
+ className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
2850
+ style: { color: "var(--compass-color-text-secondary)" },
2851
+ children: [
2852
+ "View on explorer",
2853
+ /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3" })
2854
+ ]
2855
+ }
2856
+ )
2857
+ ] }),
2858
+ state.status === "failed" && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 text-sm", children: [
2859
+ /* @__PURE__ */ jsx(
2860
+ XCircle,
2861
+ {
2862
+ className: "h-4 w-4 mt-0.5 shrink-0",
2863
+ style: { color: "var(--compass-color-error)" }
2864
+ }
2865
+ ),
2866
+ /* @__PURE__ */ jsx(
2867
+ "span",
2868
+ {
2869
+ className: "break-all",
2870
+ style: { color: "var(--compass-color-error)" },
2871
+ children: state.error
2872
+ }
2873
+ )
2874
+ ] })
2875
+ ]
2876
+ }
2877
+ );
2878
+ }
2879
+ function useTxPolling(options = {}) {
2880
+ const { chainId } = useChain();
2881
+ const queryClient = useQueryClient();
2882
+ const pollIntervalRef = useRef(null);
2883
+ const clearPolling = useCallback(() => {
2884
+ if (pollIntervalRef.current) {
2885
+ clearInterval(pollIntervalRef.current);
2886
+ pollIntervalRef.current = null;
2887
+ }
2888
+ }, []);
2889
+ useEffect(() => {
2890
+ return () => clearPolling();
2891
+ }, [clearPolling]);
2892
+ const startPolling = useCallback(
2893
+ (txHash, setTxState) => {
2894
+ clearPolling();
2895
+ let polls = 0;
2896
+ pollIntervalRef.current = setInterval(async () => {
2897
+ polls++;
2898
+ for (const key of options.queryKeysToInvalidate ?? []) {
2899
+ queryClient.invalidateQueries({ queryKey: key });
2900
+ }
2901
+ try {
2902
+ const res = await fetch(
2903
+ `/api/compass/tx/receipt?hash=${txHash}&chain=${chainId}`
2904
+ );
2905
+ const data = await res.json();
2906
+ if (data.status === "success") {
2907
+ clearPolling();
2908
+ setTxState({ status: "confirmed", txHash });
2909
+ return;
2910
+ } else if (data.status === "reverted") {
2911
+ clearPolling();
2912
+ setTxState({ status: "failed", error: "Transaction reverted" });
2913
+ return;
2914
+ }
2915
+ } catch (err) {
2916
+ if (err instanceof TypeError && err.message.includes("fetch")) ; else {
2917
+ console.warn("[useTxPolling] Unexpected error polling tx receipt:", err);
2918
+ }
2919
+ }
2920
+ if (polls >= 24) {
2921
+ clearPolling();
2922
+ setTxState({ status: "failed", error: "Unable to confirm transaction. Please check a block explorer to verify." });
2923
+ }
2924
+ }, 5e3);
2925
+ },
2926
+ [chainId, clearPolling, queryClient, options.queryKeysToInvalidate]
2927
+ );
2928
+ return { startPolling, clearPolling };
2929
+ }
2930
+ var USDC_ADDRESSES = {
2931
+ ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
2932
+ base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
2933
+ arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
2934
+ };
2935
+ var ERC20_TRANSFER_ABI = [
2936
+ {
2937
+ type: "function",
2938
+ name: "transfer",
2939
+ inputs: [
2940
+ { name: "to", type: "address" },
2941
+ { name: "amount", type: "uint256" }
2942
+ ],
2943
+ outputs: [{ name: "", type: "bool" }],
2944
+ stateMutability: "nonpayable"
2945
+ }
2946
+ ];
2947
+ async function waitForReceipt(txHash, chainId) {
2948
+ const maxPolls = 60;
2949
+ for (let i = 0; i < maxPolls; i++) {
2950
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
2951
+ try {
2952
+ const res = await fetch(`/api/compass/tx/receipt?hash=${txHash}&chain=${chainId}`);
2953
+ const data = await res.json();
2954
+ if (data.status === "success") return;
2955
+ if (data.status === "reverted") throw new Error("Withdrawal transaction reverted");
2956
+ } catch (err) {
2957
+ if (err instanceof Error && err.message.includes("reverted")) throw err;
2958
+ }
2959
+ }
2960
+ throw new Error("Unable to confirm withdrawal. Please check a block explorer to verify.");
2961
+ }
2962
+ function SendForm({ onComplete, product = "earn", productAccountAddress }) {
2963
+ const { sendTransaction, signTypedData, address } = useEmbeddableWallet();
2964
+ const { chainId } = useChain();
2965
+ const { earnAccountAddress, isDeployed } = useEarnAccount();
2966
+ const [recipient, setRecipient] = useState("");
2673
2967
  const [amount, setAmount] = useState("");
2674
- const [transferState, setTransferState] = useState("idle");
2675
- const [statusMessage, setStatusMessage] = useState("");
2676
- const [error, setError] = useState(null);
2677
- const [isBalancesModalOpen, setIsBalancesModalOpen] = useState(false);
2678
- const { address, isConnected, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
2968
+ const [txState, setTxState] = useState({ status: "idle" });
2969
+ const { startPolling } = useTxPolling({
2970
+ queryKeysToInvalidate: product === "credit" ? [["creditBalances"], ["creditPositions"], ["eoaBalances"]] : [["earnAccountBalances"], ["eoaBalances"]]
2971
+ });
2972
+ const { data: earnBalanceData } = useQuery({
2973
+ queryKey: ["earnAccountBalances", chainId, address],
2974
+ queryFn: async () => {
2975
+ if (!address) return null;
2976
+ const response = await fetch(
2977
+ `/api/compass/earn-account/balances?owner=${address}&chain=${chainId}`
2978
+ );
2979
+ if (!response.ok) return null;
2980
+ return response.json();
2981
+ },
2982
+ enabled: !!address && isDeployed && product === "earn",
2983
+ staleTime: 30 * 1e3
2984
+ });
2985
+ const { data: creditBalanceData } = useQuery({
2986
+ queryKey: ["creditBalances", productAccountAddress, chainId],
2987
+ queryFn: async () => {
2988
+ if (!productAccountAddress) return null;
2989
+ const response = await fetch(
2990
+ `/api/compass/credit/balances?owner=${productAccountAddress}&chain=${chainId}`
2991
+ );
2992
+ if (!response.ok) return null;
2993
+ return response.json();
2994
+ },
2995
+ enabled: !!productAccountAddress && product === "credit",
2996
+ staleTime: 30 * 1e3
2997
+ });
2998
+ const availableBalance = product === "credit" ? creditBalanceData?.find((b) => b.tokenSymbol === "USDC")?.amount || "0" : earnBalanceData?.balances?.["USDC"]?.balance || "0";
2999
+ const tokenAddress = USDC_ADDRESSES[chainId];
3000
+ const isValidAddress = recipient.length > 0 && isAddress(recipient);
3001
+ const isValidAmount = amount.length > 0 && parseFloat(amount) > 0;
3002
+ const exceedsBalance = isValidAmount && parseFloat(amount) > parseFloat(availableBalance);
3003
+ const isBusy = txState.status !== "idle" && txState.status !== "confirmed" && txState.status !== "failed";
3004
+ const canSend = isValidAddress && isValidAmount && !exceedsBalance && !!sendTransaction && !!signTypedData && !isBusy;
3005
+ const handleSend = useCallback(async () => {
3006
+ if (!sendTransaction || !signTypedData || !isValidAddress || !isValidAmount || !tokenAddress) return;
3007
+ try {
3008
+ setTxState({ status: "preparing" });
3009
+ const prepareRes = await fetch("/api/compass/transfer/prepare", {
3010
+ method: "POST",
3011
+ headers: { "Content-Type": "application/json" },
3012
+ body: JSON.stringify({
3013
+ owner: address,
3014
+ chain: chainId,
3015
+ token: "USDC",
3016
+ amount,
3017
+ action: "WITHDRAW",
3018
+ ...product === "credit" ? { product: "credit" } : {}
3019
+ })
3020
+ });
3021
+ if (!prepareRes.ok) {
3022
+ const errData = await prepareRes.json();
3023
+ throw new Error(errData.error || "Failed to prepare withdrawal");
3024
+ }
3025
+ const prepareData = await prepareRes.json();
3026
+ setTxState({ status: "signing" });
3027
+ const withdrawSig = await signTypedData({
3028
+ domain: prepareData.domain,
3029
+ types: prepareData.normalizedTypes,
3030
+ primaryType: prepareData.primaryType,
3031
+ message: prepareData.message
3032
+ });
3033
+ setTxState({ status: "broadcasting" });
3034
+ const executeRes = await fetch("/api/compass/transfer/execute", {
3035
+ method: "POST",
3036
+ headers: { "Content-Type": "application/json" },
3037
+ body: JSON.stringify({
3038
+ owner: address,
3039
+ chain: chainId,
3040
+ eip712: prepareData.eip712,
3041
+ signature: withdrawSig,
3042
+ ...product === "credit" ? { product: "credit" } : {}
3043
+ })
3044
+ });
3045
+ if (!executeRes.ok) {
3046
+ const errData = await executeRes.json();
3047
+ throw new Error(errData.error || "Withdrawal failed");
3048
+ }
3049
+ const { txHash: withdrawHash } = await executeRes.json();
3050
+ await waitForReceipt(withdrawHash, chainId);
3051
+ setTxState({ status: "signing" });
3052
+ const data = encodeFunctionData({
3053
+ abi: ERC20_TRANSFER_ABI,
3054
+ functionName: "transfer",
3055
+ args: [recipient, parseUnits(amount, 6)]
3056
+ });
3057
+ const sendHash = await sendTransaction({ to: tokenAddress, data });
3058
+ setTxState({ status: "submitted", txHash: sendHash });
3059
+ startPolling(sendHash, setTxState);
3060
+ setAmount("");
3061
+ setRecipient("");
3062
+ onComplete?.();
3063
+ } catch (err) {
3064
+ setTxState({ status: "failed", error: err instanceof Error ? err.message : "Transaction failed" });
3065
+ }
3066
+ }, [sendTransaction, signTypedData, recipient, amount, address, chainId, tokenAddress, isValidAddress, isValidAmount, onComplete, startPolling, product]);
3067
+ const chainName = chainId.charAt(0).toUpperCase() + chainId.slice(1);
3068
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
3069
+ /* @__PURE__ */ jsxs(
3070
+ "p",
3071
+ {
3072
+ className: "text-sm font-medium",
3073
+ style: { color: "var(--compass-color-text)", fontFamily: "var(--compass-font-family)" },
3074
+ children: [
3075
+ "Send USDC on ",
3076
+ chainName
3077
+ ]
3078
+ }
3079
+ ),
3080
+ /* @__PURE__ */ jsxs("div", { children: [
3081
+ /* @__PURE__ */ jsx(
3082
+ "label",
3083
+ {
3084
+ className: "block text-sm mb-1.5",
3085
+ style: { color: "var(--compass-color-text-secondary)", fontFamily: "var(--compass-font-family)" },
3086
+ children: "Recipient Address"
3087
+ }
3088
+ ),
3089
+ /* @__PURE__ */ jsx(
3090
+ "input",
3091
+ {
3092
+ type: "text",
3093
+ value: recipient,
3094
+ onChange: (e) => {
3095
+ setRecipient(e.target.value);
3096
+ if (txState.status === "failed") setTxState({ status: "idle" });
3097
+ },
3098
+ disabled: isBusy,
3099
+ placeholder: "0x...",
3100
+ className: "w-full border px-3 py-2.5 text-sm focus:outline-none disabled:opacity-50 font-mono",
3101
+ style: {
3102
+ backgroundColor: "var(--compass-color-surface)",
3103
+ borderColor: recipient && !isValidAddress ? "var(--compass-color-error)" : "var(--compass-color-border)",
3104
+ borderRadius: "var(--compass-border-radius-lg)",
3105
+ color: "var(--compass-color-text)",
3106
+ fontFamily: "var(--compass-font-family)"
3107
+ }
3108
+ }
3109
+ ),
3110
+ recipient && !isValidAddress && /* @__PURE__ */ jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-error)" }, children: "Invalid Ethereum address" }),
3111
+ isValidAddress && recipient.toLowerCase() === address?.toLowerCase() && /* @__PURE__ */ jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-warning, #f59e0b)" }, children: "This is your own wallet address" }),
3112
+ isValidAddress && earnAccountAddress && recipient.toLowerCase() === earnAccountAddress.toLowerCase() && /* @__PURE__ */ jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-warning, #f59e0b)" }, children: "This is your savings account address" })
3113
+ ] }),
3114
+ /* @__PURE__ */ jsxs("div", { children: [
3115
+ /* @__PURE__ */ jsx(
3116
+ "label",
3117
+ {
3118
+ className: "block text-sm mb-1.5",
3119
+ style: { color: "var(--compass-color-text-secondary)", fontFamily: "var(--compass-font-family)" },
3120
+ children: "Amount"
3121
+ }
3122
+ ),
3123
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3124
+ /* @__PURE__ */ jsx(
3125
+ "input",
3126
+ {
3127
+ type: "number",
3128
+ value: amount,
3129
+ onChange: (e) => {
3130
+ setAmount(e.target.value);
3131
+ if (txState.status === "failed") setTxState({ status: "idle" });
3132
+ },
3133
+ disabled: isBusy,
3134
+ placeholder: "0.00",
3135
+ className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
3136
+ style: {
3137
+ backgroundColor: "var(--compass-color-surface)",
3138
+ borderColor: "var(--compass-color-border)",
3139
+ borderRadius: "var(--compass-border-radius-lg)",
3140
+ color: "var(--compass-color-text)",
3141
+ fontFamily: "var(--compass-font-family)"
3142
+ }
3143
+ }
3144
+ ),
3145
+ /* @__PURE__ */ jsx(
3146
+ "span",
3147
+ {
3148
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
3149
+ style: { color: "var(--compass-color-text-tertiary)" },
3150
+ children: "USDC"
3151
+ }
3152
+ )
3153
+ ] }),
3154
+ /* @__PURE__ */ jsxs(
3155
+ "button",
3156
+ {
3157
+ onClick: () => setAmount(availableBalance),
3158
+ className: "text-xs mt-1",
3159
+ style: { color: "var(--compass-color-primary)", cursor: "pointer", background: "none", border: "none", padding: 0 },
3160
+ children: [
3161
+ "Available: ",
3162
+ parseFloat(availableBalance).toFixed(2),
3163
+ " USDC"
3164
+ ]
3165
+ }
3166
+ ),
3167
+ exceedsBalance && /* @__PURE__ */ jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-error)" }, children: "Amount exceeds available balance" })
3168
+ ] }),
3169
+ /* @__PURE__ */ jsx(
3170
+ "p",
3171
+ {
3172
+ className: "text-xs",
3173
+ style: { color: "var(--compass-color-text-tertiary)", fontFamily: "var(--compass-font-family)" },
3174
+ children: "Send USDC from your account to any address. Requires 2 signatures. Gas fees are sponsored."
3175
+ }
3176
+ ),
3177
+ /* @__PURE__ */ jsx(TxStatus, { state: txState }),
3178
+ /* @__PURE__ */ jsx(
3179
+ "button",
3180
+ {
3181
+ onClick: handleSend,
3182
+ disabled: !canSend,
3183
+ className: "w-full py-3 px-4 text-sm font-medium flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
3184
+ style: {
3185
+ backgroundColor: "var(--compass-color-primary)",
3186
+ color: "white",
3187
+ borderRadius: "var(--compass-border-radius-xl)",
3188
+ fontFamily: "var(--compass-font-family)",
3189
+ transition: "var(--compass-transition-normal)"
3190
+ },
3191
+ children: isBusy ? /* @__PURE__ */ jsxs(Fragment, { children: [
3192
+ /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
3193
+ "Sending..."
3194
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3195
+ /* @__PURE__ */ jsx(Send, { className: "h-4 w-4" }),
3196
+ "Send USDC"
3197
+ ] })
3198
+ }
3199
+ )
3200
+ ] });
3201
+ }
3202
+ function AccountBalancesModal({
3203
+ isOpen,
3204
+ onClose,
3205
+ balances,
3206
+ totalUsdValue,
3207
+ isLoading = false,
3208
+ earnAccountAddress,
3209
+ walletAddress
3210
+ }) {
3211
+ return /* @__PURE__ */ jsx(ActionModal, { isOpen, onClose, title: "Balance Breakdown", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
3212
+ (walletAddress || earnAccountAddress) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
3213
+ walletAddress && /* @__PURE__ */ jsx(CopyableAddress, { address: walletAddress, label: "Wallet" }),
3214
+ earnAccountAddress && /* @__PURE__ */ jsx(CopyableAddress, { address: earnAccountAddress, label: "Product Account" })
3215
+ ] }),
3216
+ isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-4", children: /* @__PURE__ */ jsx(
3217
+ Loader2,
3218
+ {
3219
+ size: 24,
3220
+ className: "animate-spin",
3221
+ style: { color: "var(--compass-color-primary)" }
3222
+ }
3223
+ ) }) : balances.length === 0 ? /* @__PURE__ */ jsx(
3224
+ "div",
3225
+ {
3226
+ className: "text-center py-4",
3227
+ style: { color: "var(--compass-color-text-tertiary)" },
3228
+ children: "No tokens in account"
3229
+ }
3230
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
3231
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3232
+ /* @__PURE__ */ jsx(
3233
+ "span",
3234
+ {
3235
+ className: "text-xs font-medium uppercase tracking-wide",
3236
+ style: { color: "var(--compass-color-text-tertiary)" },
3237
+ children: "Available in Account"
3238
+ }
3239
+ ),
3240
+ /* @__PURE__ */ jsx(
3241
+ "div",
3242
+ {
3243
+ className: "flex flex-col gap-2",
3244
+ style: {
3245
+ maxHeight: "50vh",
3246
+ overflowY: "auto",
3247
+ scrollbarWidth: "none"
3248
+ },
3249
+ children: balances.filter((token) => parseFloat(token.balance) >= 5e-3).map((token) => /* @__PURE__ */ jsxs(
3250
+ "div",
3251
+ {
3252
+ className: "flex items-center justify-between p-3 rounded-lg",
3253
+ style: {
3254
+ backgroundColor: "var(--compass-color-surface)",
3255
+ border: "1px solid var(--compass-color-border)",
3256
+ flexShrink: 0
3257
+ },
3258
+ children: [
3259
+ /* @__PURE__ */ jsx("span", { className: "font-medium", style: { color: "var(--compass-color-text)" }, children: token.symbol }),
3260
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end", children: [
3261
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", style: { color: "var(--compass-color-text)" }, children: formatAmount(token.balance) }),
3262
+ /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: formatUSD(token.usdValue) })
3263
+ ] })
3264
+ ]
3265
+ },
3266
+ token.symbol
3267
+ ))
3268
+ }
3269
+ )
3270
+ ] }),
3271
+ /* @__PURE__ */ jsxs(
3272
+ "div",
3273
+ {
3274
+ className: "flex items-center justify-between pt-3 mt-2",
3275
+ style: { borderTop: "2px solid var(--compass-color-border)" },
3276
+ children: [
3277
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", style: { color: "var(--compass-color-text)" }, children: "Total" }),
3278
+ /* @__PURE__ */ jsx(
3279
+ "span",
3280
+ {
3281
+ className: "font-bold text-xl",
3282
+ style: { color: "var(--compass-color-text)" },
3283
+ children: formatUSD(totalUsdValue)
3284
+ }
3285
+ )
3286
+ ]
3287
+ }
3288
+ )
3289
+ ] })
3290
+ ] }) });
3291
+ }
3292
+ var TRANSFER_TOKEN = "USDC";
3293
+ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
3294
+ compact = false,
3295
+ hideVisual = false,
3296
+ onTransferComplete
3297
+ }, ref) {
3298
+ const { address, isConnected, signTypedData, switchChain, walletChainId, fundWallet, hasExternalWallet, sendTransaction } = useEmbeddableWallet();
2679
3299
  const { chainId, chain } = useChain();
2680
3300
  const { earnAccountAddress, isDeployed } = useEarnAccount();
2681
3301
  const queryClient = useQueryClient();
3302
+ const showBuyTab = !!fundWallet;
3303
+ const showSendTab = !!sendTransaction && !hasExternalWallet;
3304
+ const buyOnly = !hasExternalWallet && showBuyTab && !sendTransaction;
3305
+ const [isModalOpen, setIsModalOpen] = useState(false);
3306
+ const [activeAction, setActiveAction] = useState(
3307
+ !hasExternalWallet && fundWallet ? "buy" : "deposit"
3308
+ );
3309
+ const selectedToken = TRANSFER_TOKEN;
3310
+ const [amount, setAmount] = useState("");
3311
+ const [txState, setTxState] = useState({ status: "idle" });
3312
+ const [isBalancesModalOpen, setIsBalancesModalOpen] = useState(false);
3313
+ const { startPolling, clearPolling } = useTxPolling({
3314
+ queryKeysToInvalidate: [["earnAccountBalances"], ["eoaBalances"]]
3315
+ });
2682
3316
  const { data: balanceData, isLoading: balancesLoading } = useQuery({
2683
3317
  queryKey: ["earnAccountBalances", chainId, address],
2684
3318
  queryFn: async () => {
@@ -2695,25 +3329,22 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2695
3329
  staleTime: 30 * 1e3
2696
3330
  });
2697
3331
  const { data: eoaBalances } = useQuery({
2698
- queryKey: ["eoaBalances", chainId, address, TRANSFER_TOKENS.join(",")],
3332
+ queryKey: ["eoaBalances", chainId, address, TRANSFER_TOKEN],
2699
3333
  queryFn: async () => {
2700
3334
  if (!address) return {};
2701
- const balances = {};
2702
- for (const token of TRANSFER_TOKENS) {
2703
- try {
2704
- const response = await fetch(
2705
- `/api/compass/token/balance?chain=${chainId}&token=${token}&address=${address}`
2706
- );
2707
- if (response.ok) {
2708
- const data = await response.json();
2709
- balances[token] = data.balance || "0";
2710
- }
2711
- } catch {
3335
+ try {
3336
+ const response = await fetch(
3337
+ `/api/compass/token/balance?chain=${chainId}&token=${TRANSFER_TOKEN}&address=${address}`
3338
+ );
3339
+ if (response.ok) {
3340
+ const data = await response.json();
3341
+ return { [TRANSFER_TOKEN]: data.balance || "0" };
2712
3342
  }
3343
+ } catch {
2713
3344
  }
2714
- return balances;
3345
+ return {};
2715
3346
  },
2716
- enabled: !!address && activeAction === "deposit",
3347
+ enabled: !!address && hasExternalWallet && activeAction === "deposit",
2717
3348
  staleTime: 30 * 1e3
2718
3349
  });
2719
3350
  const earnBalances = balanceData?.balances || {};
@@ -2732,10 +3363,9 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2732
3363
  }
2733
3364
  const resetForm = useCallback(() => {
2734
3365
  setAmount("");
2735
- setTransferState("idle");
2736
- setStatusMessage("");
2737
- setError(null);
2738
- }, []);
3366
+ setTxState({ status: "idle" });
3367
+ clearPolling();
3368
+ }, [clearPolling]);
2739
3369
  const handleOpenModal = () => {
2740
3370
  resetForm();
2741
3371
  setIsModalOpen(true);
@@ -2750,7 +3380,8 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2750
3380
  const handleActionChange = (action) => {
2751
3381
  setActiveAction(action);
2752
3382
  setAmount("");
2753
- setError(null);
3383
+ setTxState({ status: "idle" });
3384
+ clearPolling();
2754
3385
  };
2755
3386
  const getMaxBalance = () => {
2756
3387
  if (activeAction === "deposit") {
@@ -2758,37 +3389,28 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2758
3389
  }
2759
3390
  return earnBalanceAmounts[selectedToken] || "0";
2760
3391
  };
2761
- const handleQuickAmount = (percentage) => {
2762
- const max = parseFloat(getMaxBalance());
2763
- if (isNaN(max)) return;
2764
- setAmount(formatAmount(max * percentage));
2765
- };
2766
3392
  const handleTransfer = useCallback(async () => {
2767
3393
  if (!address || !amount || !signTypedData) return;
2768
- setError(null);
3394
+ setTxState({ status: "preparing" });
2769
3395
  try {
2770
3396
  const targetChainId = chain.viemChain.id;
2771
3397
  if (walletChainId !== void 0 && walletChainId !== targetChainId) {
2772
3398
  if (!switchChain) {
2773
3399
  throw new Error(`Please switch your wallet to ${chain.name} (chain ID ${targetChainId}) to continue. Your wallet is currently on chain ID ${walletChainId}.`);
2774
3400
  }
2775
- setStatusMessage(`Switching network to ${chain.name}...`);
2776
3401
  try {
2777
3402
  await switchChain(targetChainId);
2778
- } catch (switchError) {
3403
+ } catch {
2779
3404
  throw new Error(`Please switch your wallet to ${chain.name} to continue. Your wallet is on chain ID ${walletChainId}, but ${chain.name} requires chain ID ${targetChainId}.`);
2780
3405
  }
2781
3406
  } else if (switchChain && walletChainId === void 0) {
2782
- setStatusMessage("Switching network...");
2783
3407
  try {
2784
3408
  await switchChain(targetChainId);
2785
- } catch (switchError) {
3409
+ } catch {
2786
3410
  throw new Error(`Please switch your wallet to ${chain.name} to continue`);
2787
3411
  }
2788
3412
  }
2789
3413
  if (activeAction === "deposit") {
2790
- setTransferState("checking_approval");
2791
- setStatusMessage("Checking token approval...");
2792
3414
  const approveResponse = await fetch("/api/compass/transfer/approve", {
2793
3415
  method: "POST",
2794
3416
  headers: { "Content-Type": "application/json" },
@@ -2807,16 +3429,14 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2807
3429
  if (approvalData.requiresTransaction) {
2808
3430
  throw new Error("This token requires a transaction-based approval. Please approve manually.");
2809
3431
  }
2810
- setTransferState("awaiting_approval_signature");
2811
- setStatusMessage("Please sign the approval...");
3432
+ setTxState({ status: "signing" });
2812
3433
  const approvalSignature = await signTypedData({
2813
3434
  domain: approvalData.domain,
2814
3435
  types: approvalData.normalizedTypes,
2815
3436
  primaryType: "Permit",
2816
3437
  message: approvalData.message
2817
3438
  });
2818
- setTransferState("approving");
2819
- setStatusMessage("Executing approval...");
3439
+ setTxState({ status: "broadcasting" });
2820
3440
  const executeApprovalResponse = await fetch("/api/compass/transfer/execute", {
2821
3441
  method: "POST",
2822
3442
  headers: { "Content-Type": "application/json" },
@@ -2833,8 +3453,7 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2833
3453
  }
2834
3454
  }
2835
3455
  }
2836
- setTransferState("awaiting_transfer_signature");
2837
- setStatusMessage("Preparing transfer...");
3456
+ setTxState({ status: "signing" });
2838
3457
  const prepareResponse = await fetch("/api/compass/transfer/prepare", {
2839
3458
  method: "POST",
2840
3459
  headers: { "Content-Type": "application/json" },
@@ -2851,15 +3470,13 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2851
3470
  throw new Error(errData.error || "Failed to prepare transfer");
2852
3471
  }
2853
3472
  const prepareData = await prepareResponse.json();
2854
- setStatusMessage("Please sign the transfer...");
2855
3473
  const transferSignature = await signTypedData({
2856
3474
  domain: prepareData.domain,
2857
3475
  types: prepareData.normalizedTypes,
2858
3476
  primaryType: prepareData.primaryType,
2859
3477
  message: prepareData.message
2860
3478
  });
2861
- setTransferState("transferring");
2862
- setStatusMessage("Executing transfer...");
3479
+ setTxState({ status: "broadcasting" });
2863
3480
  const executeResponse = await fetch("/api/compass/transfer/execute", {
2864
3481
  method: "POST",
2865
3482
  headers: { "Content-Type": "application/json" },
@@ -2875,17 +3492,12 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2875
3492
  throw new Error(errData.error || "Transfer failed");
2876
3493
  }
2877
3494
  const { txHash } = await executeResponse.json();
2878
- setTransferState("success");
2879
- setStatusMessage("Transfer successful!");
3495
+ setTxState({ status: "submitted", txHash });
3496
+ startPolling(txHash, setTxState);
2880
3497
  onTransferComplete?.(activeAction, selectedToken, amount, txHash);
2881
- queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
2882
- queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
2883
- setTimeout(() => {
2884
- resetForm();
2885
- }, 2e3);
3498
+ setAmount("");
2886
3499
  } catch (err) {
2887
- setTransferState("error");
2888
- setError(err instanceof Error ? err.message : "Transfer failed");
3500
+ setTxState({ status: "failed", error: err instanceof Error ? err.message : "Transfer failed" });
2889
3501
  }
2890
3502
  }, [
2891
3503
  address,
@@ -2897,14 +3509,13 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2897
3509
  walletChainId,
2898
3510
  signTypedData,
2899
3511
  switchChain,
2900
- queryClient,
2901
3512
  onTransferComplete,
2902
- resetForm
3513
+ startPolling
2903
3514
  ]);
2904
3515
  if (!isConnected) {
2905
3516
  return null;
2906
3517
  }
2907
- const isProcessing = transferState !== "idle" && transferState !== "success" && transferState !== "error";
3518
+ const isProcessing = txState.status !== "idle" && txState.status !== "confirmed" && txState.status !== "failed";
2908
3519
  if (!isDeployed && !hideVisual) {
2909
3520
  return /* @__PURE__ */ jsxs(
2910
3521
  "div",
@@ -2986,178 +3597,151 @@ var EarnAccountBalance = forwardRef(function EarnAccountBalance2({
2986
3597
  /* @__PURE__ */ jsx(
2987
3598
  ActionModal,
2988
3599
  {
2989
- isOpen: isModalOpen,
2990
- onClose: handleCloseModal,
2991
- title: "Transfer Funds",
2992
- children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
2993
- /* @__PURE__ */ jsx(
2994
- "div",
2995
- {
2996
- className: "flex gap-1 p-1",
2997
- style: {
2998
- backgroundColor: "var(--compass-color-background)",
2999
- borderRadius: "var(--compass-border-radius-lg)",
3000
- fontFamily: "var(--compass-font-family)"
3001
- },
3002
- children: ["deposit", "withdraw"].map((action) => /* @__PURE__ */ jsxs(
3003
- "button",
3004
- {
3005
- onClick: () => handleActionChange(action),
3006
- disabled: isProcessing,
3007
- className: "flex-1 py-2 text-sm font-medium capitalize transition-all flex items-center justify-center gap-2",
3008
- style: {
3009
- backgroundColor: activeAction === action ? "var(--compass-color-surface)" : "transparent",
3010
- color: activeAction === action ? "var(--compass-color-text)" : "var(--compass-color-text-secondary)",
3011
- borderRadius: "var(--compass-border-radius-md)"
3012
- },
3013
- children: [
3014
- action === "deposit" ? /* @__PURE__ */ jsx(ArrowDownLeft, { size: 14 }) : /* @__PURE__ */ jsx(ArrowUpRight, { size: 14 }),
3015
- action
3016
- ]
3017
- },
3018
- action
3019
- ))
3020
- }
3021
- ),
3022
- /* @__PURE__ */ jsxs("div", { children: [
3023
- /* @__PURE__ */ jsx(
3024
- "label",
3025
- {
3026
- className: "text-sm font-medium mb-1 block",
3027
- style: { color: "var(--compass-color-text-secondary)" },
3028
- children: "Token"
3029
- }
3030
- ),
3031
- /* @__PURE__ */ jsx(
3032
- TokenSelector,
3033
- {
3034
- tokens: TRANSFER_TOKENS,
3035
- selectedToken,
3036
- onSelect: setSelectedToken,
3037
- balances: activeAction === "deposit" ? eoaBalances : earnBalanceAmounts,
3038
- disabled: isProcessing
3039
- }
3040
- )
3041
- ] }),
3042
- /* @__PURE__ */ jsxs("div", { children: [
3043
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
3044
- /* @__PURE__ */ jsx(
3045
- "label",
3046
- {
3047
- className: "text-sm font-medium",
3048
- style: { color: "var(--compass-color-text-secondary)" },
3049
- children: "Amount"
3050
- }
3051
- ),
3052
- /* @__PURE__ */ jsxs("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: [
3053
- "Available: ",
3054
- formatAmount(getMaxBalance()),
3055
- " ",
3056
- selectedToken
3057
- ] })
3058
- ] }),
3059
- /* @__PURE__ */ jsxs(
3060
- "div",
3061
- {
3062
- className: "flex items-center gap-2 p-3 border",
3063
- style: {
3064
- backgroundColor: "var(--compass-color-background)",
3065
- borderColor: "var(--compass-color-border)",
3066
- borderRadius: "var(--compass-border-radius-lg)"
3067
- },
3068
- children: [
3069
- /* @__PURE__ */ jsx(
3070
- "input",
3071
- {
3072
- type: "number",
3073
- value: amount,
3074
- onChange: (e) => {
3075
- setAmount(e.target.value);
3076
- setError(null);
3077
- },
3078
- placeholder: "0.00",
3079
- disabled: isProcessing,
3080
- className: "flex-1 bg-transparent outline-none text-lg font-mono",
3081
- style: { color: "var(--compass-color-text)" }
3082
- }
3083
- ),
3084
- /* @__PURE__ */ jsx(
3085
- "span",
3086
- {
3087
- className: "text-sm font-medium",
3088
- style: { color: "var(--compass-color-text-secondary)" },
3089
- children: selectedToken
3090
- }
3091
- )
3092
- ]
3093
- }
3094
- )
3095
- ] }),
3096
- /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: [0.25, 0.5, 1].map((pct) => /* @__PURE__ */ jsx(
3097
- "button",
3098
- {
3099
- onClick: () => handleQuickAmount(pct),
3100
- disabled: isProcessing,
3101
- className: "flex-1 py-1.5 text-xs font-medium transition-colors",
3102
- style: {
3103
- backgroundColor: "var(--compass-color-secondary)",
3104
- color: "var(--compass-color-text-secondary)",
3105
- borderRadius: "var(--compass-border-radius-md)"
3106
- },
3107
- children: pct === 1 ? "Max" : `${pct * 100}%`
3108
- },
3109
- pct
3110
- )) }),
3111
- error && /* @__PURE__ */ jsx(
3112
- "div",
3113
- {
3114
- className: "p-3 text-sm",
3115
- style: {
3116
- backgroundColor: "var(--compass-color-error-muted)",
3117
- color: "var(--compass-color-error)",
3118
- borderRadius: "var(--compass-border-radius-lg)"
3119
- },
3120
- children: error
3121
- }
3122
- ),
3123
- statusMessage && !error && /* @__PURE__ */ jsx(
3124
- "div",
3125
- {
3126
- className: "p-3 text-sm text-center",
3127
- style: {
3128
- backgroundColor: transferState === "success" ? "var(--compass-color-success-muted)" : "var(--compass-color-primary-muted)",
3129
- color: transferState === "success" ? "var(--compass-color-success)" : "var(--compass-color-primary)",
3130
- borderRadius: "var(--compass-border-radius-lg)"
3131
- },
3132
- children: statusMessage
3133
- }
3134
- ),
3135
- /* @__PURE__ */ jsxs(
3136
- "button",
3600
+ isOpen: isModalOpen,
3601
+ onClose: handleCloseModal,
3602
+ title: showSendTab ? "Manage Funds" : buyOnly ? "Add Funds" : "Transfer Funds",
3603
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
3604
+ buyOnly ? null : /* @__PURE__ */ jsx(
3605
+ "div",
3137
3606
  {
3138
- onClick: handleTransfer,
3139
- disabled: isProcessing || !amount || parseFloat(amount) <= 0,
3140
- className: "w-full py-3 font-medium transition-colors flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
3607
+ className: "flex gap-1 p-1",
3141
3608
  style: {
3142
- backgroundColor: "var(--compass-color-primary)",
3143
- color: "var(--compass-color-primary-text)",
3609
+ backgroundColor: "var(--compass-color-background)",
3144
3610
  borderRadius: "var(--compass-border-radius-lg)",
3145
3611
  fontFamily: "var(--compass-font-family)"
3146
3612
  },
3147
3613
  children: [
3148
- isProcessing && /* @__PURE__ */ jsx(Loader2, { size: 18, className: "animate-spin" }),
3149
- isProcessing ? "Processing..." : activeAction === "deposit" ? "Deposit to Earn Account" : "Withdraw to Wallet"
3150
- ]
3614
+ ...showSendTab ? ["buy", "send"] : ["deposit", "withdraw", ...showBuyTab ? ["buy"] : []]
3615
+ ].map((action) => /* @__PURE__ */ jsxs(
3616
+ "button",
3617
+ {
3618
+ onClick: () => handleActionChange(action),
3619
+ disabled: isProcessing,
3620
+ className: "flex-1 py-2 text-sm font-medium capitalize transition-all flex items-center justify-center gap-2",
3621
+ style: {
3622
+ backgroundColor: activeAction === action ? "var(--compass-color-surface)" : "transparent",
3623
+ color: activeAction === action ? "var(--compass-color-text)" : "var(--compass-color-text-secondary)",
3624
+ borderRadius: "var(--compass-border-radius-md)"
3625
+ },
3626
+ children: [
3627
+ action === "deposit" ? /* @__PURE__ */ jsx(ArrowDownLeft, { size: 14 }) : action === "withdraw" ? /* @__PURE__ */ jsx(ArrowUpRight, { size: 14 }) : action === "send" ? /* @__PURE__ */ jsx(Send, { size: 14 }) : /* @__PURE__ */ jsx(ArrowRight, { size: 14 }),
3628
+ action
3629
+ ]
3630
+ },
3631
+ action
3632
+ ))
3151
3633
  }
3152
3634
  ),
3153
- /* @__PURE__ */ jsx(
3154
- "p",
3635
+ activeAction === "send" ? /* @__PURE__ */ jsx(
3636
+ SendForm,
3155
3637
  {
3156
- className: "text-xs text-center",
3157
- style: { color: "var(--compass-color-text-tertiary)" },
3158
- children: "Gas fees are sponsored by Compass"
3638
+ onComplete: () => {
3639
+ queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
3640
+ queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
3641
+ }
3159
3642
  }
3160
- )
3643
+ ) : activeAction === "buy" || buyOnly ? /* @__PURE__ */ jsx(
3644
+ BuyForm,
3645
+ {
3646
+ targetAddress: earnAccountAddress || "",
3647
+ onComplete: () => {
3648
+ queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
3649
+ queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
3650
+ }
3651
+ }
3652
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
3653
+ /* @__PURE__ */ jsxs("div", { children: [
3654
+ /* @__PURE__ */ jsx(
3655
+ "label",
3656
+ {
3657
+ className: "text-sm font-medium mb-1 block",
3658
+ style: { color: "var(--compass-color-text-secondary)" },
3659
+ children: "Amount"
3660
+ }
3661
+ ),
3662
+ /* @__PURE__ */ jsxs(
3663
+ "div",
3664
+ {
3665
+ className: "flex items-center gap-2 p-3 border",
3666
+ style: {
3667
+ backgroundColor: "var(--compass-color-background)",
3668
+ borderColor: "var(--compass-color-border)",
3669
+ borderRadius: "var(--compass-border-radius-lg)"
3670
+ },
3671
+ children: [
3672
+ /* @__PURE__ */ jsx(
3673
+ "input",
3674
+ {
3675
+ type: "number",
3676
+ value: amount,
3677
+ onChange: (e) => {
3678
+ setAmount(e.target.value);
3679
+ if (txState.status === "failed") setTxState({ status: "idle" });
3680
+ },
3681
+ placeholder: "0.00",
3682
+ disabled: isProcessing,
3683
+ className: "flex-1 bg-transparent outline-none text-lg font-mono",
3684
+ style: { color: "var(--compass-color-text)" }
3685
+ }
3686
+ ),
3687
+ /* @__PURE__ */ jsx(
3688
+ "span",
3689
+ {
3690
+ className: "text-sm font-medium",
3691
+ style: { color: "var(--compass-color-text-secondary)" },
3692
+ children: "USDC"
3693
+ }
3694
+ )
3695
+ ]
3696
+ }
3697
+ ),
3698
+ /* @__PURE__ */ jsxs(
3699
+ "button",
3700
+ {
3701
+ onClick: () => setAmount(formatAmount(getMaxBalance())),
3702
+ className: "text-xs mt-1",
3703
+ style: { color: "var(--compass-color-primary)", cursor: "pointer", background: "none", border: "none", padding: 0 },
3704
+ children: [
3705
+ "Available: ",
3706
+ formatAmount(getMaxBalance()),
3707
+ " USDC"
3708
+ ]
3709
+ }
3710
+ )
3711
+ ] }),
3712
+ /* @__PURE__ */ jsx("p", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: activeAction === "deposit" ? `Approves the token transfer, then transfers USDC from your ${!hasExternalWallet ? "embedded " : ""}wallet into your savings account. Requires 2 signatures.${!hasExternalWallet ? " Note: deposit and withdraw use your embedded wallet, not your bank account." : ""}` : `Moves USDC from your savings account back to your ${!hasExternalWallet ? "embedded " : ""}wallet. Requires 1 signature.${!hasExternalWallet ? " Gas fees are sponsored." : ""}` }),
3713
+ /* @__PURE__ */ jsx(TxStatus, { state: txState }),
3714
+ /* @__PURE__ */ jsx(
3715
+ "button",
3716
+ {
3717
+ onClick: handleTransfer,
3718
+ disabled: isProcessing || !amount || parseFloat(amount) <= 0,
3719
+ className: "w-full py-3 font-medium transition-colors flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
3720
+ style: {
3721
+ backgroundColor: "var(--compass-color-primary)",
3722
+ color: "var(--compass-color-primary-text)",
3723
+ borderRadius: "var(--compass-border-radius-lg)",
3724
+ fontFamily: "var(--compass-font-family)"
3725
+ },
3726
+ children: isProcessing ? /* @__PURE__ */ jsxs(Fragment, { children: [
3727
+ /* @__PURE__ */ jsx(Loader2, { size: 18, className: "animate-spin" }),
3728
+ " Processing..."
3729
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3730
+ /* @__PURE__ */ jsx(ArrowUpRight, { size: 16 }),
3731
+ " ",
3732
+ activeAction === "deposit" ? "Transfer to Savings Account" : "Withdraw to Wallet"
3733
+ ] })
3734
+ }
3735
+ ),
3736
+ /* @__PURE__ */ jsx(
3737
+ "p",
3738
+ {
3739
+ className: "text-xs text-center",
3740
+ style: { color: "var(--compass-color-text-tertiary)" },
3741
+ children: "Gas fees are sponsored by Compass"
3742
+ }
3743
+ )
3744
+ ] })
3161
3745
  ] })
3162
3746
  }
3163
3747
  )
@@ -3212,7 +3796,7 @@ function truncate(value, decimals) {
3212
3796
  const factor = Math.pow(10, decimals);
3213
3797
  return (Math.floor(value * factor) / factor).toFixed(decimals);
3214
3798
  }
3215
- var BLOCK_EXPLORERS = {
3799
+ var BLOCK_EXPLORERS2 = {
3216
3800
  ethereum: "https://etherscan.io",
3217
3801
  base: "https://basescan.org",
3218
3802
  arbitrum: "https://arbiscan.io"
@@ -3683,7 +4267,7 @@ function SwapForm({
3683
4267
  /* @__PURE__ */ jsxs(
3684
4268
  "a",
3685
4269
  {
3686
- href: `${BLOCK_EXPLORERS[chainId] || BLOCK_EXPLORERS.ethereum}/tx/${lastTxHash}`,
4270
+ href: `${BLOCK_EXPLORERS2[chainId] || BLOCK_EXPLORERS2.ethereum}/tx/${lastTxHash}`,
3687
4271
  target: "_blank",
3688
4272
  rel: "noopener noreferrer",
3689
4273
  style: { display: "flex", alignItems: "center", gap: "4px", color: "var(--compass-color-text-secondary)", fontSize: "0.75rem", textDecoration: "none" },
@@ -3873,8 +4457,7 @@ function MarketSelector({
3873
4457
  },
3874
4458
  children: [
3875
4459
  getTypeLabel(selectedMarket.type),
3876
- " \xB7 ",
3877
- formatTvl(selectedMarket.tvl)
4460
+ selectedMarket.type !== "aave" ? ` \xB7 ${formatTvl(selectedMarket.tvl)}` : ""
3878
4461
  ]
3879
4462
  }
3880
4463
  )
@@ -3980,8 +4563,7 @@ function MarketSelector({
3980
4563
  },
3981
4564
  children: [
3982
4565
  getTypeLabel(market.type),
3983
- " \xB7 ",
3984
- formatTvl(market.tvl)
4566
+ market.type !== "aave" ? ` \xB7 ${formatTvl(market.tvl)}` : ""
3985
4567
  ]
3986
4568
  }
3987
4569
  )
@@ -4010,7 +4592,7 @@ function MarketSelector({
4010
4592
  )
4011
4593
  ] });
4012
4594
  }
4013
- var BLOCK_EXPLORERS2 = {
4595
+ var BLOCK_EXPLORERS3 = {
4014
4596
  ethereum: "https://etherscan.io",
4015
4597
  base: "https://basescan.org",
4016
4598
  arbitrum: "https://arbiscan.io"
@@ -4172,7 +4754,7 @@ function PositionCard({ position, chainId }) {
4172
4754
  tx.txHash && /* @__PURE__ */ jsx(
4173
4755
  "a",
4174
4756
  {
4175
- href: `${BLOCK_EXPLORERS2[chainId || "ethereum"] || BLOCK_EXPLORERS2.ethereum}/tx/${tx.txHash}`,
4757
+ href: `${BLOCK_EXPLORERS3[chainId || "ethereum"] || BLOCK_EXPLORERS3.ethereum}/tx/${tx.txHash}`,
4176
4758
  target: "_blank",
4177
4759
  rel: "noopener noreferrer",
4178
4760
  style: { color: "var(--compass-color-text-tertiary)", lineHeight: 0 },
@@ -4306,161 +4888,29 @@ function EarningsModal({ isOpen, onClose, positions, totalEarned, isLoading, cha
4306
4888
  /* @__PURE__ */ jsxs("span", { style: {
4307
4889
  fontSize: "0.8125rem",
4308
4890
  fontWeight: 600,
4309
- color: totalRealized >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)"
4310
- }, children: [
4311
- totalRealized >= 0 ? "+" : "",
4312
- formatCurrency(totalRealized)
4313
- ] })
4314
- ] })
4315
- ] })
4316
- ] }),
4317
- /* @__PURE__ */ jsx("div", { style: {
4318
- flex: 1,
4319
- overflowY: "auto",
4320
- scrollbarWidth: "none",
4321
- padding: "16px",
4322
- display: "flex",
4323
- flexDirection: "column",
4324
- gap: "10px"
4325
- }, children: isLoading ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "32px 0", color: "var(--compass-color-text-tertiary)", fontSize: "0.875rem" }, children: "Loading positions..." }) : positions.length === 0 ? /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "32px 0" }, children: [
4326
- /* @__PURE__ */ jsx("p", { style: { color: "var(--compass-color-text-secondary)", fontSize: "0.9375rem", margin: "0 0 4px" }, children: "No active positions yet" }),
4327
- /* @__PURE__ */ jsx("p", { style: { color: "var(--compass-color-text-tertiary)", fontSize: "0.8125rem", margin: 0 }, children: "Deposit into a market to start earning" })
4328
- ] }) : positions.map((position) => /* @__PURE__ */ jsx(PositionCard, { position, chainId }, position.id)) })
4329
- ]
4330
- }
4331
- )
4332
- }
4333
- );
4334
- }
4335
- var BLOCK_EXPLORERS3 = {
4336
- ethereum: "https://etherscan.io",
4337
- base: "https://basescan.org",
4338
- arbitrum: "https://arbiscan.io"
4339
- };
4340
- function TxStatus({ state }) {
4341
- const { chainId } = useChain();
4342
- if (state.status === "idle") return null;
4343
- const explorer = BLOCK_EXPLORERS3[chainId] || BLOCK_EXPLORERS3.ethereum;
4344
- return /* @__PURE__ */ jsxs(
4345
- "div",
4346
- {
4347
- className: "mt-4 p-4 border",
4348
- style: {
4349
- borderColor: "var(--compass-color-border)",
4350
- borderRadius: "var(--compass-border-radius-xl)",
4351
- fontFamily: "var(--compass-font-family)"
4352
- },
4353
- children: [
4354
- state.status === "preparing" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
4355
- /* @__PURE__ */ jsx(
4356
- Loader2,
4357
- {
4358
- className: "h-4 w-4 animate-spin",
4359
- style: { color: "var(--compass-color-primary)" }
4360
- }
4361
- ),
4362
- /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Preparing transaction..." })
4363
- ] }),
4364
- state.status === "signing" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
4365
- /* @__PURE__ */ jsx(
4366
- Loader2,
4367
- {
4368
- className: "h-4 w-4 animate-spin",
4369
- style: { color: "var(--compass-color-warning)" }
4370
- }
4371
- ),
4372
- /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Waiting for signature..." })
4373
- ] }),
4374
- state.status === "broadcasting" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
4375
- /* @__PURE__ */ jsx(
4376
- Loader2,
4377
- {
4378
- className: "h-4 w-4 animate-spin",
4379
- style: { color: "var(--compass-color-primary)" }
4380
- }
4381
- ),
4382
- /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Broadcasting transaction..." })
4383
- ] }),
4384
- state.status === "submitted" && /* @__PURE__ */ jsxs("div", { children: [
4385
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4386
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
4387
- /* @__PURE__ */ jsx(
4388
- Loader2,
4389
- {
4390
- className: "h-4 w-4 animate-spin",
4391
- style: { color: "var(--compass-color-primary)" }
4392
- }
4393
- ),
4394
- /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text)" }, children: "Transaction submitted" })
4395
- ] }),
4396
- /* @__PURE__ */ jsxs(
4397
- "a",
4398
- {
4399
- href: `${explorer}/tx/${state.txHash}`,
4400
- target: "_blank",
4401
- rel: "noopener noreferrer",
4402
- className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
4403
- style: { color: "var(--compass-color-text-secondary)" },
4404
- children: [
4405
- "View on explorer",
4406
- /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3" })
4407
- ]
4408
- }
4409
- )
4410
- ] }),
4411
- /* @__PURE__ */ jsx(
4412
- "p",
4413
- {
4414
- className: "text-xs mt-2",
4415
- style: { color: "var(--compass-color-text-tertiary)" },
4416
- children: "Waiting for on-chain confirmation. Balances will update automatically."
4417
- }
4418
- )
4419
- ] }),
4420
- state.status === "confirmed" && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4421
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
4422
- /* @__PURE__ */ jsx(
4423
- CheckCircle,
4424
- {
4425
- className: "h-4 w-4",
4426
- style: { color: "var(--compass-color-success)" }
4427
- }
4428
- ),
4429
- /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-success)" }, children: "Transaction confirmed" })
4430
- ] }),
4431
- /* @__PURE__ */ jsxs(
4432
- "a",
4433
- {
4434
- href: `${explorer}/tx/${state.txHash}`,
4435
- target: "_blank",
4436
- rel: "noopener noreferrer",
4437
- className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
4438
- style: { color: "var(--compass-color-text-secondary)" },
4439
- children: [
4440
- "View on explorer",
4441
- /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3" })
4442
- ]
4443
- }
4444
- )
4445
- ] }),
4446
- state.status === "failed" && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 text-sm", children: [
4447
- /* @__PURE__ */ jsx(
4448
- XCircle,
4449
- {
4450
- className: "h-4 w-4 mt-0.5 shrink-0",
4451
- style: { color: "var(--compass-color-error)" }
4452
- }
4453
- ),
4454
- /* @__PURE__ */ jsx(
4455
- "span",
4456
- {
4457
- className: "break-all",
4458
- style: { color: "var(--compass-color-error)" },
4459
- children: state.error
4460
- }
4461
- )
4462
- ] })
4463
- ]
4891
+ color: totalRealized >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)"
4892
+ }, children: [
4893
+ totalRealized >= 0 ? "+" : "",
4894
+ formatCurrency(totalRealized)
4895
+ ] })
4896
+ ] })
4897
+ ] })
4898
+ ] }),
4899
+ /* @__PURE__ */ jsx("div", { style: {
4900
+ flex: 1,
4901
+ overflowY: "auto",
4902
+ scrollbarWidth: "none",
4903
+ padding: "16px",
4904
+ display: "flex",
4905
+ flexDirection: "column",
4906
+ gap: "10px"
4907
+ }, children: isLoading ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "32px 0", color: "var(--compass-color-text-tertiary)", fontSize: "0.875rem" }, children: "Loading positions..." }) : positions.length === 0 ? /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "32px 0" }, children: [
4908
+ /* @__PURE__ */ jsx("p", { style: { color: "var(--compass-color-text-secondary)", fontSize: "0.9375rem", margin: "0 0 4px" }, children: "No active positions yet" }),
4909
+ /* @__PURE__ */ jsx("p", { style: { color: "var(--compass-color-text-tertiary)", fontSize: "0.8125rem", margin: 0 }, children: "Deposit into a market to start earning" })
4910
+ ] }) : positions.map((position) => /* @__PURE__ */ jsx(PositionCard, { position, chainId }, position.id)) })
4911
+ ]
4912
+ }
4913
+ )
4464
4914
  }
4465
4915
  );
4466
4916
  }
@@ -4468,7 +4918,7 @@ function truncate2(value, decimals) {
4468
4918
  const factor = Math.pow(10, decimals);
4469
4919
  return (Math.floor(value * factor) / factor).toFixed(decimals);
4470
4920
  }
4471
- var EVM_CHAIN_IDS = {
4921
+ var EVM_CHAIN_IDS2 = {
4472
4922
  ethereum: 1,
4473
4923
  base: 8453,
4474
4924
  arbitrum: 42161
@@ -4509,8 +4959,8 @@ function EarnAccount({
4509
4959
  chain: chainProp,
4510
4960
  height = "600px"
4511
4961
  }) {
4512
- const { address, isConnected, login, logout, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
4513
- const { isDeployed } = useEarnAccount();
4962
+ const { address, isConnected, login, logout, signTypedData, switchChain, walletChainId, fundWallet, hasExternalWallet, sendTransaction } = useEmbeddableWallet();
4963
+ const { isDeployed, earnAccountAddress } = useEarnAccount();
4514
4964
  const { chainId: contextChainId } = useChain();
4515
4965
  const CHAIN_ID = chainProp || contextChainId;
4516
4966
  const queryClient = useQueryClient();
@@ -4524,10 +4974,15 @@ function EarnAccount({
4524
4974
  const [isTokenDropdownOpen, setIsTokenDropdownOpen] = useState(false);
4525
4975
  const [isFundModalOpen, setIsFundModalOpen] = useState(false);
4526
4976
  const [fundAmount, setFundAmount] = useState("");
4527
- const [fundAction, setFundAction] = useState("deposit");
4977
+ const [fundAction, setFundAction] = useState(
4978
+ !hasExternalWallet && fundWallet ? "buy" : "deposit"
4979
+ );
4528
4980
  const [fundStep, setFundStep] = useState("idle");
4529
4981
  const [fundTxState, setFundTxState] = useState({ status: "idle" });
4530
4982
  const fundPollRef = useRef(null);
4983
+ const showBuyTab = !!fundWallet;
4984
+ const showSendTab = !!sendTransaction && !hasExternalWallet;
4985
+ const fundBuyOnly = !hasExternalWallet && showBuyTab && !sendTransaction;
4531
4986
  const actionPollRef = useRef(null);
4532
4987
  const actionTimeoutRef = useRef(null);
4533
4988
  const [isBalancesModalOpen, setIsBalancesModalOpen] = useState(false);
@@ -4567,7 +5022,7 @@ function EarnAccount({
4567
5022
  const fundIsValid = Number(fundAmount) > 0 && !!address && isDeployed;
4568
5023
  const fundPhase = getFundPhase(fundStep);
4569
5024
  const ensureCorrectChain = useCallback(async () => {
4570
- const targetChainId = EVM_CHAIN_IDS[CHAIN_ID];
5025
+ const targetChainId = EVM_CHAIN_IDS2[CHAIN_ID];
4571
5026
  if (!targetChainId) return;
4572
5027
  if (walletChainId !== void 0 && walletChainId !== targetChainId) {
4573
5028
  if (!switchChain) {
@@ -4591,7 +5046,7 @@ function EarnAccount({
4591
5046
  return null;
4592
5047
  }
4593
5048
  },
4594
- enabled: !!address && isFundModalOpen && fundAction === "deposit",
5049
+ enabled: !!address && hasExternalWallet && isFundModalOpen && fundAction === "deposit",
4595
5050
  staleTime: 15 * 1e3
4596
5051
  });
4597
5052
  const walletBalance = walletBalanceQuery.data?.balance || "0";
@@ -4875,7 +5330,10 @@ function EarnAccount({
4875
5330
  setFundTxState({ status: "failed", error: "Transaction reverted" });
4876
5331
  return;
4877
5332
  }
4878
- } catch {
5333
+ } catch (err) {
5334
+ if (err instanceof TypeError && err.message.includes("fetch")) ; else {
5335
+ console.warn("[EarnAccount] Unexpected error polling tx receipt:", err);
5336
+ }
4879
5337
  }
4880
5338
  if (polls >= 24) {
4881
5339
  clearFundPolling();
@@ -5670,31 +6128,7 @@ function EarnAccount({
5670
6128
  ]
5671
6129
  }
5672
6130
  )
5673
- ] }),
5674
- /* @__PURE__ */ jsx("div", { className: "flex", style: { gap: "6px", marginTop: activeTab === "deposit" && maxAmount >= 10 ? "8px" : "0" }, children: activeTab === "deposit" && maxAmount > 0 && [10, 20, 30].filter((v) => v <= maxAmount).map((val) => /* @__PURE__ */ jsxs(
5675
- "button",
5676
- {
5677
- onClick: () => {
5678
- setAmount(val.toString());
5679
- setError(null);
5680
- },
5681
- disabled: isProcessing,
5682
- className: "text-xs font-medium",
5683
- style: {
5684
- padding: "4px 12px",
5685
- backgroundColor: parseFloat(amount) === val ? "transparent" : "var(--compass-color-surface)",
5686
- border: parseFloat(amount) === val ? "1.5px solid var(--compass-color-primary)" : "1.5px solid var(--compass-color-border)",
5687
- color: parseFloat(amount) === val ? "var(--compass-color-primary)" : "var(--compass-color-text-secondary)",
5688
- borderRadius: "var(--compass-border-radius-xl)",
5689
- transition: "all 150ms ease"
5690
- },
5691
- children: [
5692
- "$",
5693
- val
5694
- ]
5695
- },
5696
- val
5697
- )) })
6131
+ ] })
5698
6132
  ]
5699
6133
  }
5700
6134
  ),
@@ -5790,13 +6224,13 @@ function EarnAccount({
5790
6224
  onClose: () => {
5791
6225
  setIsFundModalOpen(false);
5792
6226
  setFundAmount("");
5793
- setFundAction("deposit");
6227
+ setFundAction(fundBuyOnly ? "buy" : showSendTab ? "buy" : "deposit");
5794
6228
  setFundStep("idle");
5795
6229
  setFundTxState({ status: "idle" });
5796
6230
  },
5797
- title: "Transfer Funds",
6231
+ title: showSendTab ? "Manage Funds" : fundBuyOnly ? "Add Funds" : "Transfer Funds",
5798
6232
  children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
5799
- /* @__PURE__ */ jsx(
6233
+ fundBuyOnly ? null : /* @__PURE__ */ jsx(
5800
6234
  "div",
5801
6235
  {
5802
6236
  className: "flex gap-1 p-1",
@@ -5805,7 +6239,9 @@ function EarnAccount({
5805
6239
  borderRadius: "var(--compass-border-radius-lg)",
5806
6240
  fontFamily: "var(--compass-font-family)"
5807
6241
  },
5808
- children: ["deposit", "withdraw"].map((tab) => /* @__PURE__ */ jsxs(
6242
+ children: [
6243
+ ...showSendTab ? ["buy", "send"] : ["deposit", "withdraw", ...showBuyTab ? ["buy"] : []]
6244
+ ].map((tab) => /* @__PURE__ */ jsxs(
5809
6245
  "button",
5810
6246
  {
5811
6247
  onClick: () => handleFundActionChange(tab),
@@ -5818,7 +6254,7 @@ function EarnAccount({
5818
6254
  border: "none"
5819
6255
  },
5820
6256
  children: [
5821
- tab === "deposit" ? /* @__PURE__ */ jsx(ArrowDownLeft, { size: 14 }) : /* @__PURE__ */ jsx(ArrowUpRight, { size: 14 }),
6257
+ tab === "deposit" ? /* @__PURE__ */ jsx(ArrowDownLeft, { size: 14 }) : tab === "withdraw" ? /* @__PURE__ */ jsx(ArrowUpRight, { size: 14 }) : tab === "send" ? /* @__PURE__ */ jsx(Send, { size: 14 }) : /* @__PURE__ */ jsx(ArrowRight, { size: 14 }),
5822
6258
  tab
5823
6259
  ]
5824
6260
  },
@@ -5826,137 +6262,158 @@ function EarnAccount({
5826
6262
  ))
5827
6263
  }
5828
6264
  ),
5829
- (fundIsBusy || fundStep === "confirmed") && fundAction === "deposit" && /* @__PURE__ */ jsxs(
5830
- "div",
6265
+ fundAction === "send" ? /* @__PURE__ */ jsx(
6266
+ SendForm,
5831
6267
  {
5832
- className: "flex gap-3 p-3 text-xs",
5833
- style: {
5834
- backgroundColor: "var(--compass-color-surface)",
5835
- borderRadius: "var(--compass-border-radius-lg)",
5836
- fontFamily: "var(--compass-font-family)"
5837
- },
5838
- children: [
5839
- /* @__PURE__ */ jsx(
5840
- FundStepIndicator,
5841
- {
5842
- number: 1,
5843
- label: "Approve",
5844
- state: fundPhase > 1 ? "done" : fundPhase === 1 ? "active" : "pending"
5845
- }
5846
- ),
5847
- /* @__PURE__ */ jsx(
5848
- FundStepIndicator,
5849
- {
5850
- number: 2,
5851
- label: "Transfer",
5852
- state: fundStep === "confirmed" ? "done" : fundPhase > 1 ? "active" : "pending"
5853
- }
5854
- )
5855
- ]
6268
+ onComplete: () => {
6269
+ queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
6270
+ queryClient.invalidateQueries({ queryKey: ["walletBalance"] });
6271
+ queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
6272
+ }
5856
6273
  }
5857
- ),
5858
- /* @__PURE__ */ jsxs("div", { children: [
5859
- /* @__PURE__ */ jsx(
5860
- "label",
6274
+ ) : fundAction === "buy" || fundBuyOnly ? /* @__PURE__ */ jsx(
6275
+ BuyForm,
6276
+ {
6277
+ targetAddress: earnAccountAddress || "",
6278
+ onComplete: () => {
6279
+ queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
6280
+ queryClient.invalidateQueries({ queryKey: ["walletBalance"] });
6281
+ queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
6282
+ }
6283
+ }
6284
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
6285
+ (fundIsBusy || fundStep === "confirmed") && fundAction === "deposit" && /* @__PURE__ */ jsxs(
6286
+ "div",
5861
6287
  {
5862
- className: "block text-sm mb-1.5",
6288
+ className: "flex gap-3 p-3 text-xs",
5863
6289
  style: {
5864
- color: "var(--compass-color-text-secondary)",
6290
+ backgroundColor: "var(--compass-color-surface)",
6291
+ borderRadius: "var(--compass-border-radius-lg)",
5865
6292
  fontFamily: "var(--compass-font-family)"
5866
6293
  },
5867
- children: "Amount"
6294
+ children: [
6295
+ /* @__PURE__ */ jsx(
6296
+ FundStepIndicator,
6297
+ {
6298
+ number: 1,
6299
+ label: "Approve",
6300
+ state: fundPhase > 1 ? "done" : fundPhase === 1 ? "active" : "pending"
6301
+ }
6302
+ ),
6303
+ /* @__PURE__ */ jsx(
6304
+ FundStepIndicator,
6305
+ {
6306
+ number: 2,
6307
+ label: "Transfer",
6308
+ state: fundStep === "confirmed" ? "done" : fundPhase > 1 ? "active" : "pending"
6309
+ }
6310
+ )
6311
+ ]
5868
6312
  }
5869
6313
  ),
5870
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
6314
+ /* @__PURE__ */ jsxs("div", { children: [
5871
6315
  /* @__PURE__ */ jsx(
5872
- "input",
6316
+ "label",
5873
6317
  {
5874
- type: "number",
5875
- value: fundAmount,
5876
- onChange: (e) => {
5877
- setFundAmount(e.target.value);
5878
- setFundTxState({ status: "idle" });
5879
- },
5880
- disabled: fundIsBusy,
5881
- placeholder: "0.00",
5882
- className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
6318
+ className: "block text-sm mb-1.5",
5883
6319
  style: {
5884
- backgroundColor: "var(--compass-color-surface)",
5885
- borderColor: "var(--compass-color-border)",
5886
- borderRadius: "var(--compass-border-radius-lg)",
5887
- color: "var(--compass-color-text)",
6320
+ color: "var(--compass-color-text-secondary)",
5888
6321
  fontFamily: "var(--compass-font-family)"
5889
- }
6322
+ },
6323
+ children: "Amount"
5890
6324
  }
5891
6325
  ),
5892
- /* @__PURE__ */ jsx(
5893
- "span",
6326
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
6327
+ /* @__PURE__ */ jsx(
6328
+ "input",
6329
+ {
6330
+ type: "number",
6331
+ value: fundAmount,
6332
+ onChange: (e) => {
6333
+ setFundAmount(e.target.value);
6334
+ setFundTxState({ status: "idle" });
6335
+ },
6336
+ disabled: fundIsBusy,
6337
+ placeholder: "0.00",
6338
+ className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
6339
+ style: {
6340
+ backgroundColor: "var(--compass-color-surface)",
6341
+ borderColor: "var(--compass-color-border)",
6342
+ borderRadius: "var(--compass-border-radius-lg)",
6343
+ color: "var(--compass-color-text)",
6344
+ fontFamily: "var(--compass-font-family)"
6345
+ }
6346
+ }
6347
+ ),
6348
+ /* @__PURE__ */ jsx(
6349
+ "span",
6350
+ {
6351
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
6352
+ style: { color: "var(--compass-color-text-tertiary)" },
6353
+ children: "USDC"
6354
+ }
6355
+ )
6356
+ ] }),
6357
+ fundMaxBalance !== "0" && /* @__PURE__ */ jsxs(
6358
+ "p",
5894
6359
  {
5895
- className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
6360
+ className: "text-xs mt-1",
5896
6361
  style: { color: "var(--compass-color-text-tertiary)" },
5897
- children: "USDC"
6362
+ children: [
6363
+ "Available:",
6364
+ " ",
6365
+ /* @__PURE__ */ jsxs(
6366
+ "button",
6367
+ {
6368
+ onClick: () => setFundAmount(truncate2(parseFloat(fundMaxBalance), 2)),
6369
+ disabled: fundIsBusy,
6370
+ style: { color: "var(--compass-color-primary)", background: "none", border: "none", padding: 0, cursor: "pointer", fontSize: "inherit" },
6371
+ children: [
6372
+ truncate2(parseFloat(fundMaxBalance), 2),
6373
+ " USDC"
6374
+ ]
6375
+ }
6376
+ )
6377
+ ]
5898
6378
  }
5899
6379
  )
5900
6380
  ] }),
5901
- fundMaxBalance !== "0" && /* @__PURE__ */ jsxs(
6381
+ !fundIsBusy && fundStep !== "confirmed" && fundStep !== "failed" && fundTxState.status === "idle" && /* @__PURE__ */ jsx(
5902
6382
  "p",
5903
6383
  {
5904
- className: "text-xs mt-1",
5905
- style: { color: "var(--compass-color-text-tertiary)" },
5906
- children: [
5907
- "Available:",
5908
- " ",
5909
- /* @__PURE__ */ jsxs(
5910
- "button",
5911
- {
5912
- onClick: () => setFundAmount(truncate2(parseFloat(fundMaxBalance), 2)),
5913
- disabled: fundIsBusy,
5914
- style: { color: "var(--compass-color-primary)", background: "none", border: "none", padding: 0, cursor: "pointer", fontSize: "inherit" },
5915
- children: [
5916
- truncate2(parseFloat(fundMaxBalance), 2),
5917
- " USDC"
5918
- ]
5919
- }
5920
- )
5921
- ]
6384
+ className: "text-xs",
6385
+ style: {
6386
+ color: "var(--compass-color-text-tertiary)",
6387
+ fontFamily: "var(--compass-font-family)"
6388
+ },
6389
+ children: fundAction === "deposit" ? `Approves the token transfer, then transfers USDC from your ${!hasExternalWallet ? "embedded " : ""}wallet into your savings account. Requires 2 signatures.${!hasExternalWallet ? " Note: deposit and withdraw use your embedded wallet, not your bank account." : ""}` : `Moves USDC from your savings account back to your ${!hasExternalWallet ? "embedded " : ""}wallet. Requires 1 signature.${!hasExternalWallet ? " Gas fees are sponsored." : ""}`
5922
6390
  }
5923
- )
5924
- ] }),
5925
- !fundIsBusy && fundStep !== "confirmed" && fundStep !== "failed" && fundTxState.status === "idle" && /* @__PURE__ */ jsx(
5926
- "p",
5927
- {
5928
- className: "text-xs",
5929
- style: {
5930
- color: "var(--compass-color-text-tertiary)",
5931
- fontFamily: "var(--compass-font-family)"
5932
- },
5933
- children: fundAction === "deposit" ? "Approves the token transfer, then transfers USDC from your wallet into your savings account. Requires 2 signatures." : "Transfers USDC from your savings account back to your wallet. Requires 1 signature."
5934
- }
5935
- ),
5936
- /* @__PURE__ */ jsx(
5937
- "button",
5938
- {
5939
- onClick: handleFundTransfer,
5940
- disabled: !fundIsValid || fundIsBusy,
5941
- className: "w-full py-3 px-4 text-sm font-medium flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
5942
- style: {
5943
- backgroundColor: "var(--compass-color-primary)",
5944
- color: "var(--compass-color-primary-text)",
5945
- borderRadius: "var(--compass-border-radius-xl)",
5946
- fontFamily: "var(--compass-font-family)",
5947
- transition: "all 200ms ease",
5948
- border: "none"
5949
- },
5950
- children: fundIsBusy ? /* @__PURE__ */ jsxs(Fragment, { children: [
5951
- /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
5952
- fundButtonLabel()
5953
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5954
- /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" }),
5955
- fundAction === "deposit" ? "Transfer to Savings Account" : "Withdraw to Wallet"
5956
- ] })
5957
- }
5958
- ),
5959
- /* @__PURE__ */ jsx(TxStatus, { state: fundTxState })
6391
+ ),
6392
+ /* @__PURE__ */ jsx(
6393
+ "button",
6394
+ {
6395
+ onClick: handleFundTransfer,
6396
+ disabled: !fundIsValid || fundIsBusy,
6397
+ className: "w-full py-3 px-4 text-sm font-medium flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
6398
+ style: {
6399
+ backgroundColor: "var(--compass-color-primary)",
6400
+ color: "var(--compass-color-primary-text)",
6401
+ borderRadius: "var(--compass-border-radius-xl)",
6402
+ fontFamily: "var(--compass-font-family)",
6403
+ transition: "all 200ms ease",
6404
+ border: "none"
6405
+ },
6406
+ children: fundIsBusy ? /* @__PURE__ */ jsxs(Fragment, { children: [
6407
+ /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
6408
+ fundButtonLabel()
6409
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
6410
+ /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" }),
6411
+ fundAction === "deposit" ? "Transfer to Savings Account" : "Withdraw to Wallet"
6412
+ ] })
6413
+ }
6414
+ ),
6415
+ /* @__PURE__ */ jsx(TxStatus, { state: fundTxState })
6416
+ ] })
5960
6417
  ] })
5961
6418
  }
5962
6419
  ),
@@ -7763,19 +8220,24 @@ function getPhase(step) {
7763
8220
  if (step === "approving" || step === "signing-approval") return 1;
7764
8221
  return 2;
7765
8222
  }
7766
- var EVM_CHAIN_IDS2 = {
8223
+ var EVM_CHAIN_IDS3 = {
7767
8224
  ethereum: 1,
7768
8225
  base: 8453,
7769
8226
  arbitrum: 42161
7770
8227
  };
7771
8228
  function TopUpModal({ isOpen, onClose }) {
7772
- const { address, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
8229
+ const { address, signTypedData, switchChain, walletChainId, fundWallet, hasExternalWallet, sendTransaction } = useEmbeddableWallet();
7773
8230
  const { chainId } = useChain();
7774
- const { isDeployed } = useCreditAccount();
8231
+ const { isDeployed, creditAccountAddress } = useCreditAccount();
7775
8232
  const queryClient = useQueryClient();
7776
8233
  const prices = useTokenPrices();
7777
8234
  const token = "USDC";
7778
- const [action, setAction] = useState("deposit");
8235
+ const [action, setAction] = useState(
8236
+ !hasExternalWallet && fundWallet ? "buy" : "deposit"
8237
+ );
8238
+ const showBuyTab = !!fundWallet;
8239
+ const showSendTab = !!sendTransaction && !hasExternalWallet;
8240
+ const buyOnly = !hasExternalWallet && showBuyTab && !sendTransaction;
7779
8241
  const [amount, setAmount] = useState("");
7780
8242
  const [step, setStep] = useState("idle");
7781
8243
  const [txState, setTxState] = useState({ status: "idle" });
@@ -7824,7 +8286,7 @@ function TopUpModal({ isOpen, onClose }) {
7824
8286
  const isValid = Number(amount) > 0 && !!address && isDeployed;
7825
8287
  const isBusy = step === "approving" || step === "signing-approval" || step === "preparing-transfer" || step === "signing-transfer" || step === "executing";
7826
8288
  const ensureCorrectChain = useCallback(async () => {
7827
- const targetChainId = EVM_CHAIN_IDS2[CHAIN_ID];
8289
+ const targetChainId = EVM_CHAIN_IDS3[CHAIN_ID];
7828
8290
  if (!targetChainId) return;
7829
8291
  if (walletChainId !== void 0 && walletChainId !== targetChainId) {
7830
8292
  if (!switchChain) {
@@ -8026,7 +8488,10 @@ function TopUpModal({ isOpen, onClose }) {
8026
8488
  setTxState({ status: "failed", error: "Transaction reverted" });
8027
8489
  return;
8028
8490
  }
8029
- } catch {
8491
+ } catch (err) {
8492
+ if (err instanceof TypeError && err.message.includes("fetch")) ; else {
8493
+ console.warn("[TopUpModal] Unexpected error polling tx receipt:", err);
8494
+ }
8030
8495
  }
8031
8496
  if (polls >= 24) {
8032
8497
  clearPolling();
@@ -8062,8 +8527,8 @@ function TopUpModal({ isOpen, onClose }) {
8062
8527
  color: "var(--compass-color-text-secondary)",
8063
8528
  fontFamily: "var(--compass-font-family)"
8064
8529
  };
8065
- return /* @__PURE__ */ jsx(ActionModal, { isOpen, onClose, title: "Transfer Funds", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8066
- /* @__PURE__ */ jsx(
8530
+ return /* @__PURE__ */ jsx(ActionModal, { isOpen, onClose, title: showSendTab ? "Manage Funds" : buyOnly ? "Add Funds" : "Transfer Funds", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8531
+ !buyOnly && /* @__PURE__ */ jsx(
8067
8532
  "div",
8068
8533
  {
8069
8534
  className: "flex gap-1 p-1",
@@ -8072,7 +8537,9 @@ function TopUpModal({ isOpen, onClose }) {
8072
8537
  borderRadius: "var(--compass-border-radius-lg)",
8073
8538
  fontFamily: "var(--compass-font-family)"
8074
8539
  },
8075
- children: ["deposit", "withdraw"].map((tab) => /* @__PURE__ */ jsxs(
8540
+ children: [
8541
+ ...showSendTab ? ["buy", "send"] : showBuyTab ? ["deposit", "withdraw", "buy"] : ["deposit", "withdraw"]
8542
+ ].map((tab) => /* @__PURE__ */ jsxs(
8076
8543
  "button",
8077
8544
  {
8078
8545
  onClick: () => handleActionChange(tab),
@@ -8084,7 +8551,7 @@ function TopUpModal({ isOpen, onClose }) {
8084
8551
  borderRadius: "var(--compass-border-radius-md)"
8085
8552
  },
8086
8553
  children: [
8087
- tab === "deposit" ? /* @__PURE__ */ jsx(ArrowDownLeft, { size: 14 }) : /* @__PURE__ */ jsx(ArrowUpRight, { size: 14 }),
8554
+ tab === "deposit" ? /* @__PURE__ */ jsx(ArrowDownLeft, { size: 14 }) : tab === "withdraw" ? /* @__PURE__ */ jsx(ArrowUpRight, { size: 14 }) : tab === "send" ? /* @__PURE__ */ jsx(Send, { size: 14 }) : /* @__PURE__ */ jsx(ArrowRight, { size: 14 }),
8088
8555
  tab
8089
8556
  ]
8090
8557
  },
@@ -8092,122 +8559,143 @@ function TopUpModal({ isOpen, onClose }) {
8092
8559
  ))
8093
8560
  }
8094
8561
  ),
8095
- (isBusy || step === "confirmed") && action === "deposit" && /* @__PURE__ */ jsxs(
8096
- "div",
8562
+ action === "send" ? /* @__PURE__ */ jsx(
8563
+ SendForm,
8097
8564
  {
8098
- className: "flex gap-3 p-3 text-xs",
8099
- style: {
8100
- backgroundColor: "var(--compass-color-surface)",
8101
- borderRadius: "var(--compass-border-radius-lg)",
8102
- fontFamily: "var(--compass-font-family)"
8103
- },
8104
- children: [
8565
+ product: "credit",
8566
+ productAccountAddress: creditAccountAddress || void 0,
8567
+ onComplete: () => {
8568
+ queryClient.invalidateQueries({ queryKey: ["creditBalances"] });
8569
+ queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
8570
+ }
8571
+ }
8572
+ ) : action === "buy" || buyOnly ? /* @__PURE__ */ jsx(
8573
+ BuyForm,
8574
+ {
8575
+ targetAddress: creditAccountAddress || "",
8576
+ onComplete: () => {
8577
+ queryClient.invalidateQueries({ queryKey: ["creditBalances"] });
8578
+ queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
8579
+ }
8580
+ }
8581
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
8582
+ (isBusy || step === "confirmed") && action === "deposit" && /* @__PURE__ */ jsxs(
8583
+ "div",
8584
+ {
8585
+ className: "flex gap-3 p-3 text-xs",
8586
+ style: {
8587
+ backgroundColor: "var(--compass-color-surface)",
8588
+ borderRadius: "var(--compass-border-radius-lg)",
8589
+ fontFamily: "var(--compass-font-family)"
8590
+ },
8591
+ children: [
8592
+ /* @__PURE__ */ jsx(
8593
+ StepIndicator,
8594
+ {
8595
+ number: 1,
8596
+ label: "Approve",
8597
+ state: phase > 1 ? "done" : phase === 1 ? "active" : "pending"
8598
+ }
8599
+ ),
8600
+ /* @__PURE__ */ jsx(
8601
+ StepIndicator,
8602
+ {
8603
+ number: 2,
8604
+ label: "Transfer",
8605
+ state: step === "confirmed" ? "done" : phase > 1 ? "active" : "pending"
8606
+ }
8607
+ )
8608
+ ]
8609
+ }
8610
+ ),
8611
+ /* @__PURE__ */ jsxs("div", { children: [
8612
+ /* @__PURE__ */ jsx("label", { className: "block text-sm mb-1.5", style: labelStyle, children: "Amount" }),
8613
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
8105
8614
  /* @__PURE__ */ jsx(
8106
- StepIndicator,
8615
+ "input",
8107
8616
  {
8108
- number: 1,
8109
- label: "Approve",
8110
- state: phase > 1 ? "done" : phase === 1 ? "active" : "pending"
8617
+ type: "number",
8618
+ value: amount,
8619
+ onChange: (e) => {
8620
+ setAmount(e.target.value);
8621
+ setTxState({ status: "idle" });
8622
+ },
8623
+ disabled: isBusy,
8624
+ placeholder: "0.00",
8625
+ className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
8626
+ style: inputStyle
8111
8627
  }
8112
8628
  ),
8113
8629
  /* @__PURE__ */ jsx(
8114
- StepIndicator,
8630
+ "span",
8115
8631
  {
8116
- number: 2,
8117
- label: "Transfer",
8118
- state: step === "confirmed" ? "done" : phase > 1 ? "active" : "pending"
8632
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
8633
+ style: { color: "var(--compass-color-text-tertiary)" },
8634
+ children: token
8119
8635
  }
8120
8636
  )
8121
- ]
8122
- }
8123
- ),
8124
- /* @__PURE__ */ jsxs("div", { children: [
8125
- /* @__PURE__ */ jsx("label", { className: "block text-sm mb-1.5", style: labelStyle, children: "Amount" }),
8126
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
8127
- /* @__PURE__ */ jsx(
8128
- "input",
8637
+ ] }),
8638
+ formatUsdEstimate(amount, token, prices) && /* @__PURE__ */ jsxs(
8639
+ "p",
8129
8640
  {
8130
- type: "number",
8131
- value: amount,
8132
- onChange: (e) => {
8133
- setAmount(e.target.value);
8134
- setTxState({ status: "idle" });
8135
- },
8136
- disabled: isBusy,
8137
- placeholder: "0.00",
8138
- className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
8139
- style: inputStyle
8641
+ className: "text-xs mt-1",
8642
+ style: { color: "var(--compass-color-text-tertiary)" },
8643
+ children: [
8644
+ "\u2248",
8645
+ " ",
8646
+ formatUsdEstimate(amount, token, prices)
8647
+ ]
8140
8648
  }
8141
8649
  ),
8142
- /* @__PURE__ */ jsx(
8143
- "span",
8650
+ maxBalance && maxBalance !== "0" && /* @__PURE__ */ jsxs(
8651
+ "p",
8144
8652
  {
8145
- className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
8653
+ className: "text-xs mt-1",
8146
8654
  style: { color: "var(--compass-color-text-tertiary)" },
8147
- children: token
8655
+ children: [
8656
+ "Available: ",
8657
+ truncate6(parseFloat(maxBalance), 2),
8658
+ " ",
8659
+ token
8660
+ ]
8148
8661
  }
8149
8662
  )
8150
8663
  ] }),
8151
- formatUsdEstimate(amount, token, prices) && /* @__PURE__ */ jsxs(
8664
+ !isBusy && step !== "confirmed" && step !== "failed" && txState.status === "idle" && /* @__PURE__ */ jsx(
8152
8665
  "p",
8153
8666
  {
8154
- className: "text-xs mt-1",
8155
- style: { color: "var(--compass-color-text-tertiary)" },
8156
- children: [
8157
- "\u2248",
8158
- " ",
8159
- formatUsdEstimate(amount, token, prices)
8160
- ]
8667
+ className: "text-xs",
8668
+ style: {
8669
+ color: "var(--compass-color-text-tertiary)",
8670
+ fontFamily: "var(--compass-font-family)"
8671
+ },
8672
+ children: action === "deposit" ? `Approves the token transfer, then transfers tokens from your ${!hasExternalWallet ? "embedded " : ""}wallet into your credit account. Requires 2 signatures.${!hasExternalWallet ? " Note: deposit and withdraw use your embedded wallet, not your bank account." : ""}` : `Moves tokens from your credit account back to your ${!hasExternalWallet ? "embedded " : ""}wallet. Requires 1 signature.${!hasExternalWallet ? " Gas fees are sponsored." : ""}`
8161
8673
  }
8162
8674
  ),
8163
- maxBalance && maxBalance !== "0" && /* @__PURE__ */ jsxs(
8164
- "p",
8675
+ /* @__PURE__ */ jsx(
8676
+ "button",
8165
8677
  {
8166
- className: "text-xs mt-1",
8167
- style: { color: "var(--compass-color-text-tertiary)" },
8168
- children: [
8169
- "Available: ",
8170
- truncate6(parseFloat(maxBalance), 2),
8171
- " ",
8172
- token
8173
- ]
8678
+ onClick: handleTransfer,
8679
+ disabled: !isValid || isBusy,
8680
+ className: "w-full py-3 px-4 text-sm font-medium flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
8681
+ style: {
8682
+ backgroundColor: "var(--compass-color-primary)",
8683
+ color: "white",
8684
+ borderRadius: "var(--compass-border-radius-xl)",
8685
+ fontFamily: "var(--compass-font-family)",
8686
+ transition: "var(--compass-transition-normal)"
8687
+ },
8688
+ children: isBusy ? /* @__PURE__ */ jsxs(Fragment, { children: [
8689
+ /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
8690
+ buttonLabel()
8691
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8692
+ /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" }),
8693
+ action === "deposit" ? "Transfer to Credit Account" : "Withdraw to Wallet"
8694
+ ] })
8174
8695
  }
8175
- )
8176
- ] }),
8177
- !isBusy && step !== "confirmed" && step !== "failed" && txState.status === "idle" && /* @__PURE__ */ jsx(
8178
- "p",
8179
- {
8180
- className: "text-xs",
8181
- style: {
8182
- color: "var(--compass-color-text-tertiary)",
8183
- fontFamily: "var(--compass-font-family)"
8184
- },
8185
- children: action === "deposit" ? "Approves the token transfer, then transfers tokens from your wallet into your credit account. Requires 2 signatures." : "Transfers tokens from your credit account back to your wallet. Requires 1 signature."
8186
- }
8187
- ),
8188
- /* @__PURE__ */ jsx(
8189
- "button",
8190
- {
8191
- onClick: handleTransfer,
8192
- disabled: !isValid || isBusy,
8193
- className: "w-full py-3 px-4 text-sm font-medium flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
8194
- style: {
8195
- backgroundColor: "var(--compass-color-primary)",
8196
- color: "white",
8197
- borderRadius: "var(--compass-border-radius-xl)",
8198
- fontFamily: "var(--compass-font-family)",
8199
- transition: "var(--compass-transition-normal)"
8200
- },
8201
- children: isBusy ? /* @__PURE__ */ jsxs(Fragment, { children: [
8202
- /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
8203
- buttonLabel()
8204
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8205
- /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" }),
8206
- action === "deposit" ? "Transfer to Credit Account" : "Withdraw to Wallet"
8207
- ] })
8208
- }
8209
- ),
8210
- /* @__PURE__ */ jsx(TxStatus, { state: txState })
8696
+ ),
8697
+ /* @__PURE__ */ jsx(TxStatus, { state: txState })
8698
+ ] })
8211
8699
  ] }) });
8212
8700
  }
8213
8701
  function StepIndicator({
@@ -8235,9 +8723,10 @@ function CreditSwapModal({ isOpen, onClose }) {
8235
8723
  const prices = useTokenPrices();
8236
8724
  const { txState, executeBundle, resetState } = useCreditBundle();
8237
8725
  const tokens = CREDIT_TOKENS;
8238
- const fromToken = "USDC";
8239
- const [toToken, setToToken] = useState(tokens.find((t) => t !== fromToken) || tokens[0] || "WETH");
8726
+ const [fromToken, setFromToken] = useState("USDC");
8727
+ const [toToken, setToToken] = useState(tokens.find((t) => t !== "USDC") || tokens[0] || "WETH");
8240
8728
  const [fromAmount, setFromAmount] = useState("");
8729
+ const [isFromOpen, setIsFromOpen] = useState(false);
8241
8730
  const [isToOpen, setIsToOpen] = useState(false);
8242
8731
  useEffect(() => {
8243
8732
  if (isOpen) {
@@ -8245,6 +8734,12 @@ function CreditSwapModal({ isOpen, onClose }) {
8245
8734
  resetState();
8246
8735
  }
8247
8736
  }, [isOpen]);
8737
+ useEffect(() => {
8738
+ if (fromToken === toToken) {
8739
+ const alt = tokens.find((t) => t !== fromToken);
8740
+ if (alt) setToToken(alt);
8741
+ }
8742
+ }, [fromToken, toToken, tokens]);
8248
8743
  const fromBalance = balances?.find((b) => b.tokenSymbol === fromToken);
8249
8744
  const fromBalanceAmount = fromBalance ? parseFloat(fromBalance.amount) : 0;
8250
8745
  const estimatedOutput = (() => {
@@ -8323,24 +8818,76 @@ function CreditSwapModal({ isOpen, onClose }) {
8323
8818
  }
8324
8819
  }
8325
8820
  ),
8326
- /* @__PURE__ */ jsx(
8327
- "div",
8328
- {
8329
- style: {
8330
- display: "flex",
8331
- alignItems: "center",
8332
- fontWeight: 500,
8333
- backgroundColor: "var(--compass-color-background)",
8334
- border: "1.5px solid var(--compass-color-border)",
8335
- color: "var(--compass-color-text)",
8336
- borderRadius: "var(--compass-border-radius-md)",
8337
- padding: "4px 8px",
8338
- fontSize: "0.8125rem",
8339
- flexShrink: 0
8340
- },
8341
- children: fromToken
8342
- }
8343
- )
8821
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flexShrink: 0 }, children: [
8822
+ /* @__PURE__ */ jsxs(
8823
+ "button",
8824
+ {
8825
+ onClick: () => setIsFromOpen(!isFromOpen),
8826
+ disabled: isBusy,
8827
+ style: {
8828
+ display: "flex",
8829
+ alignItems: "center",
8830
+ fontWeight: 500,
8831
+ backgroundColor: "var(--compass-color-background)",
8832
+ border: "1.5px solid var(--compass-color-border)",
8833
+ color: "var(--compass-color-text)",
8834
+ borderRadius: "var(--compass-border-radius-md)",
8835
+ padding: "4px 8px",
8836
+ gap: "4px",
8837
+ fontSize: "0.8125rem",
8838
+ cursor: isBusy ? "not-allowed" : "pointer"
8839
+ },
8840
+ children: [
8841
+ fromToken,
8842
+ /* @__PURE__ */ jsx(ChevronDown, { size: 12, style: { color: "var(--compass-color-text-tertiary)" } })
8843
+ ]
8844
+ }
8845
+ ),
8846
+ isFromOpen && /* @__PURE__ */ jsx(
8847
+ "div",
8848
+ {
8849
+ style: {
8850
+ position: "absolute",
8851
+ right: 0,
8852
+ top: "100%",
8853
+ marginTop: "4px",
8854
+ zIndex: 10,
8855
+ backgroundColor: "var(--compass-color-surface)",
8856
+ border: "1.5px solid var(--compass-color-border)",
8857
+ borderRadius: "var(--compass-border-radius-lg)",
8858
+ boxShadow: "var(--compass-shadow-md)",
8859
+ minWidth: "120px",
8860
+ maxHeight: "200px",
8861
+ overflowY: "auto",
8862
+ scrollbarWidth: "none"
8863
+ },
8864
+ children: tokens.filter((t) => t !== toToken).map((token) => /* @__PURE__ */ jsx(
8865
+ "button",
8866
+ {
8867
+ onClick: () => {
8868
+ setFromToken(token);
8869
+ setFromAmount("");
8870
+ setIsFromOpen(false);
8871
+ },
8872
+ style: {
8873
+ display: "block",
8874
+ width: "100%",
8875
+ textAlign: "left",
8876
+ padding: "6px 10px",
8877
+ fontSize: "0.8125rem",
8878
+ fontWeight: 500,
8879
+ color: token === fromToken ? "var(--compass-color-primary)" : "var(--compass-color-text)",
8880
+ backgroundColor: token === fromToken ? "var(--compass-color-primary-muted)" : "transparent",
8881
+ border: "none",
8882
+ cursor: "pointer"
8883
+ },
8884
+ children: token
8885
+ },
8886
+ token
8887
+ ))
8888
+ }
8889
+ )
8890
+ ] })
8344
8891
  ] })
8345
8892
  ]
8346
8893
  }
@@ -8547,7 +9094,7 @@ function CreditAccount({
8547
9094
  onBorrow: _onBorrow,
8548
9095
  onRepay: _onRepay
8549
9096
  }) {
8550
- const { address, isConnected, login, logout } = useEmbeddableWallet();
9097
+ const { address, isConnected, login, logout, hasExternalWallet } = useEmbeddableWallet();
8551
9098
  const { isDeployed, creditAccountAddress } = useCreditAccount();
8552
9099
  const { chainId } = useChain();
8553
9100
  const { data: positions, isLoading: positionsLoading } = useCreditPositions();
@@ -8573,6 +9120,25 @@ function CreditAccount({
8573
9120
  return { ...b, usdValue };
8574
9121
  }).filter((b) => b.usdValue >= 0.01).sort((a, b) => a.tokenSymbol.localeCompare(b.tokenSymbol));
8575
9122
  const totalIdleUsd = balancesWithUsd.reduce((sum, b) => sum + b.usdValue, 0);
9123
+ const { data: walletBalance } = useQuery({
9124
+ queryKey: ["embeddedWalletBalance", chainId, address, "USDC"],
9125
+ queryFn: async () => {
9126
+ if (!address) return "0";
9127
+ try {
9128
+ const response = await fetch(
9129
+ `/api/compass/token/balance?chain=${chainId}&token=USDC&address=${address}`
9130
+ );
9131
+ if (response.ok) {
9132
+ const data = await response.json();
9133
+ return data.balance || "0";
9134
+ }
9135
+ } catch {
9136
+ }
9137
+ return "0";
9138
+ },
9139
+ enabled: !!address && hasExternalWallet,
9140
+ staleTime: 30 * 1e3
9141
+ });
8576
9142
  const totalInterestEarnedUsd = (() => {
8577
9143
  if (!positions) return 0;
8578
9144
  let total = 0;
@@ -9573,6 +10139,7 @@ function PositionDetailModal({ position, onClose }) {
9573
10139
  const isPendle = position.venue === "pendle";
9574
10140
  const duration = formatDuration(position.entryTimestamp);
9575
10141
  const expiryDate = formatExpiryUTC(position.expiry);
10142
+ const modalRef = useRef(null);
9576
10143
  useEffect(() => {
9577
10144
  const handleKeyDown = (e) => {
9578
10145
  if (e.key === "Escape") onClose();
@@ -9580,296 +10147,312 @@ function PositionDetailModal({ position, onClose }) {
9580
10147
  document.addEventListener("keydown", handleKeyDown);
9581
10148
  return () => document.removeEventListener("keydown", handleKeyDown);
9582
10149
  }, [onClose]);
10150
+ const handleOverlayWheel = useCallback((e) => {
10151
+ if (modalRef.current && !modalRef.current.contains(e.target)) {
10152
+ window.scrollBy(0, e.deltaY);
10153
+ }
10154
+ }, []);
9583
10155
  const hasStats = position.apy || isPendle && (duration || expiryDate) || position.pnl;
9584
- return /* @__PURE__ */ jsx(
10156
+ return /* @__PURE__ */ jsxs(
9585
10157
  "div",
9586
10158
  {
9587
10159
  className: "fixed inset-0 z-50 flex items-center justify-center p-4",
9588
- style: { backgroundColor: "rgba(0, 0, 0, 0.7)" },
10160
+ onWheel: handleOverlayWheel,
9589
10161
  onClick: onClose,
9590
- children: /* @__PURE__ */ jsxs(
9591
- "div",
9592
- {
9593
- className: "relative w-full max-w-md rounded-xl border overflow-hidden max-h-[90vh] overflow-y-auto",
9594
- style: {
9595
- backgroundColor: "var(--compass-color-background)",
9596
- borderColor: "var(--compass-color-border)",
9597
- scrollbarWidth: "none"
9598
- },
9599
- onClick: (e) => e.stopPropagation(),
9600
- children: [
9601
- /* @__PURE__ */ jsxs(
9602
- "div",
9603
- {
9604
- className: "sticky top-0 flex items-center justify-between p-4 border-b",
9605
- style: {
9606
- backgroundColor: "var(--compass-color-surface)",
9607
- borderColor: "var(--compass-color-border)"
9608
- },
9609
- children: [
9610
- /* @__PURE__ */ jsxs("div", { children: [
9611
- /* @__PURE__ */ jsx(
9612
- "h2",
9613
- {
9614
- className: "font-semibold text-lg",
9615
- style: { color: "var(--compass-color-text)" },
9616
- children: position.name
9617
- }
9618
- ),
9619
- /* @__PURE__ */ jsx(
9620
- "p",
9621
- {
9622
- className: "text-sm",
9623
- style: { color: "var(--compass-color-text-secondary)" },
9624
- children: position.venueName
9625
- }
9626
- )
9627
- ] }),
9628
- /* @__PURE__ */ jsx(
9629
- "button",
9630
- {
9631
- onClick: onClose,
9632
- className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
9633
- style: { backgroundColor: "var(--compass-color-background)" },
9634
- children: /* @__PURE__ */ jsx(X, { size: 20, style: { color: "var(--compass-color-text-secondary)" } })
9635
- }
9636
- )
9637
- ]
9638
- }
9639
- ),
9640
- /* @__PURE__ */ jsx("div", { className: "p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
9641
- /* @__PURE__ */ jsx(
9642
- "p",
9643
- {
9644
- className: "text-sm mb-1",
9645
- style: { color: "var(--compass-color-text-secondary)" },
9646
- children: "Current Balance"
9647
- }
9648
- ),
9649
- /* @__PURE__ */ jsx(
9650
- "p",
9651
- {
9652
- className: "text-3xl font-bold",
9653
- style: { color: "var(--compass-color-text)" },
9654
- children: formatUSD(position.balanceUsd)
9655
- }
9656
- ),
9657
- /* @__PURE__ */ jsxs(
9658
- "p",
9659
- {
9660
- className: "text-sm font-mono mt-1",
9661
- style: { color: "var(--compass-color-text-secondary)" },
9662
- children: [
9663
- formatAmount(position.balance),
9664
- " ",
9665
- position.assetSymbol
9666
- ]
9667
- }
9668
- )
9669
- ] }) }),
9670
- hasStats && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: [
9671
- position.apy && /* @__PURE__ */ jsxs(
9672
- "div",
9673
- {
9674
- className: "p-3 rounded-lg",
9675
- style: { backgroundColor: "var(--compass-color-surface)" },
9676
- children: [
9677
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
9678
- /* @__PURE__ */ jsx(Percent, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
9679
- /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "APY" })
9680
- ] }),
9681
- /* @__PURE__ */ jsxs(
9682
- "p",
9683
- {
9684
- className: "font-semibold",
9685
- style: { color: "var(--compass-color-success)" },
9686
- children: [
9687
- parseFloat(position.apy).toFixed(2),
9688
- "%"
9689
- ]
9690
- }
9691
- )
9692
- ]
9693
- }
9694
- ),
9695
- isPendle && duration && /* @__PURE__ */ jsxs(
9696
- "div",
9697
- {
9698
- className: "p-3 rounded-lg",
9699
- style: { backgroundColor: "var(--compass-color-surface)" },
9700
- children: [
9701
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
9702
- /* @__PURE__ */ jsx(Clock, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
9703
- /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Duration" })
9704
- ] }),
9705
- /* @__PURE__ */ jsx(
9706
- "p",
9707
- {
9708
- className: "font-semibold",
9709
- style: { color: "var(--compass-color-text)" },
9710
- children: duration
9711
- }
9712
- )
9713
- ]
9714
- }
9715
- ),
9716
- isPendle && expiryDate && /* @__PURE__ */ jsxs(
10162
+ children: [
10163
+ /* @__PURE__ */ jsx(
10164
+ "div",
10165
+ {
10166
+ className: "absolute inset-0",
10167
+ style: { backgroundColor: "rgba(0, 0, 0, 0.7)" }
10168
+ }
10169
+ ),
10170
+ /* @__PURE__ */ jsxs(
10171
+ "div",
10172
+ {
10173
+ ref: modalRef,
10174
+ className: "relative w-full max-w-md rounded-xl border max-h-[85vh] overflow-y-auto",
10175
+ style: {
10176
+ backgroundColor: "var(--compass-color-background)",
10177
+ borderColor: "var(--compass-color-border)",
10178
+ scrollbarWidth: "none",
10179
+ overscrollBehavior: "contain"
10180
+ },
10181
+ onClick: (e) => e.stopPropagation(),
10182
+ children: [
10183
+ /* @__PURE__ */ jsxs(
9717
10184
  "div",
9718
10185
  {
9719
- className: "p-3 rounded-lg",
9720
- style: { backgroundColor: "var(--compass-color-surface)" },
10186
+ className: "sticky top-0 flex items-center justify-between p-4 border-b",
10187
+ style: {
10188
+ backgroundColor: "var(--compass-color-surface)",
10189
+ borderColor: "var(--compass-color-border)"
10190
+ },
9721
10191
  children: [
9722
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
9723
- /* @__PURE__ */ jsx(Calendar, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
9724
- /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Expiry (UTC)" })
10192
+ /* @__PURE__ */ jsxs("div", { children: [
10193
+ /* @__PURE__ */ jsx(
10194
+ "h2",
10195
+ {
10196
+ className: "font-semibold text-lg",
10197
+ style: { color: "var(--compass-color-text)" },
10198
+ children: position.name
10199
+ }
10200
+ ),
10201
+ /* @__PURE__ */ jsx(
10202
+ "p",
10203
+ {
10204
+ className: "text-sm",
10205
+ style: { color: "var(--compass-color-text-secondary)" },
10206
+ children: position.venueName
10207
+ }
10208
+ )
9725
10209
  ] }),
9726
10210
  /* @__PURE__ */ jsx(
9727
- "p",
10211
+ "button",
9728
10212
  {
9729
- className: "font-semibold",
9730
- style: { color: "var(--compass-color-text)" },
9731
- children: expiryDate
10213
+ onClick: onClose,
10214
+ className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
10215
+ style: { backgroundColor: "var(--compass-color-background)" },
10216
+ children: /* @__PURE__ */ jsx(X, { size: 20, style: { color: "var(--compass-color-text-secondary)" } })
9732
10217
  }
9733
10218
  )
9734
10219
  ]
9735
10220
  }
9736
10221
  ),
9737
- position.pnl && /* @__PURE__ */ jsxs(
9738
- "div",
9739
- {
9740
- className: "p-3 rounded-lg",
9741
- style: { backgroundColor: "var(--compass-color-surface)" },
9742
- children: [
9743
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
9744
- isPnlPositive ? /* @__PURE__ */ jsx(TrendingUp, { size: 14, style: { color: "var(--compass-color-success)" } }) : /* @__PURE__ */ jsx(TrendingDown, { size: 14, style: { color: "var(--compass-color-error)" } }),
9745
- /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Total P&L" })
9746
- ] }),
9747
- /* @__PURE__ */ jsxs(
9748
- "p",
10222
+ /* @__PURE__ */ jsx("div", { className: "p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
10223
+ /* @__PURE__ */ jsx(
10224
+ "p",
10225
+ {
10226
+ className: "text-sm mb-1",
10227
+ style: { color: "var(--compass-color-text-secondary)" },
10228
+ children: "Current Balance"
10229
+ }
10230
+ ),
10231
+ /* @__PURE__ */ jsx(
10232
+ "p",
10233
+ {
10234
+ className: "text-3xl font-bold",
10235
+ style: { color: "var(--compass-color-text)" },
10236
+ children: formatUSD(position.balanceUsd)
10237
+ }
10238
+ ),
10239
+ /* @__PURE__ */ jsxs(
10240
+ "p",
10241
+ {
10242
+ className: "text-sm font-mono mt-1",
10243
+ style: { color: "var(--compass-color-text-secondary)" },
10244
+ children: [
10245
+ formatAmount(position.balance),
10246
+ " ",
10247
+ position.assetSymbol
10248
+ ]
10249
+ }
10250
+ )
10251
+ ] }) }),
10252
+ hasStats && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: [
10253
+ position.apy && /* @__PURE__ */ jsxs(
10254
+ "div",
10255
+ {
10256
+ className: "p-3 rounded-lg",
10257
+ style: { backgroundColor: "var(--compass-color-surface)" },
10258
+ children: [
10259
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
10260
+ /* @__PURE__ */ jsx(Percent, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
10261
+ /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "APY" })
10262
+ ] }),
10263
+ /* @__PURE__ */ jsxs(
10264
+ "p",
10265
+ {
10266
+ className: "font-semibold",
10267
+ style: { color: "var(--compass-color-success)" },
10268
+ children: [
10269
+ parseFloat(position.apy).toFixed(2),
10270
+ "%"
10271
+ ]
10272
+ }
10273
+ )
10274
+ ]
10275
+ }
10276
+ ),
10277
+ isPendle && duration && /* @__PURE__ */ jsxs(
10278
+ "div",
10279
+ {
10280
+ className: "p-3 rounded-lg",
10281
+ style: { backgroundColor: "var(--compass-color-surface)" },
10282
+ children: [
10283
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
10284
+ /* @__PURE__ */ jsx(Clock, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
10285
+ /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Duration" })
10286
+ ] }),
10287
+ /* @__PURE__ */ jsx(
10288
+ "p",
10289
+ {
10290
+ className: "font-semibold",
10291
+ style: { color: "var(--compass-color-text)" },
10292
+ children: duration
10293
+ }
10294
+ )
10295
+ ]
10296
+ }
10297
+ ),
10298
+ isPendle && expiryDate && /* @__PURE__ */ jsxs(
10299
+ "div",
10300
+ {
10301
+ className: "p-3 rounded-lg",
10302
+ style: { backgroundColor: "var(--compass-color-surface)" },
10303
+ children: [
10304
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
10305
+ /* @__PURE__ */ jsx(Calendar, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
10306
+ /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Expiry (UTC)" })
10307
+ ] }),
10308
+ /* @__PURE__ */ jsx(
10309
+ "p",
10310
+ {
10311
+ className: "font-semibold",
10312
+ style: { color: "var(--compass-color-text)" },
10313
+ children: expiryDate
10314
+ }
10315
+ )
10316
+ ]
10317
+ }
10318
+ ),
10319
+ position.pnl && /* @__PURE__ */ jsxs(
10320
+ "div",
10321
+ {
10322
+ className: "p-3 rounded-lg",
10323
+ style: { backgroundColor: "var(--compass-color-surface)" },
10324
+ children: [
10325
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
10326
+ isPnlPositive ? /* @__PURE__ */ jsx(TrendingUp, { size: 14, style: { color: "var(--compass-color-success)" } }) : /* @__PURE__ */ jsx(TrendingDown, { size: 14, style: { color: "var(--compass-color-error)" } }),
10327
+ /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Total P&L" })
10328
+ ] }),
10329
+ /* @__PURE__ */ jsxs(
10330
+ "p",
10331
+ {
10332
+ className: "font-semibold",
10333
+ style: {
10334
+ color: isPnlPositive ? "var(--compass-color-success)" : "var(--compass-color-error)"
10335
+ },
10336
+ children: [
10337
+ isPnlPositive ? "+" : "",
10338
+ formatUSD(position.pnl.totalPnl)
10339
+ ]
10340
+ }
10341
+ )
10342
+ ]
10343
+ }
10344
+ )
10345
+ ] }),
10346
+ (position.deposits.length > 0 || position.withdrawals.length > 0) && /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
10347
+ /* @__PURE__ */ jsx(
10348
+ "h3",
10349
+ {
10350
+ className: "font-semibold mb-3",
10351
+ style: { color: "var(--compass-color-text)" },
10352
+ children: "Transaction History"
10353
+ }
10354
+ ),
10355
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
10356
+ position.deposits.map((tx, i) => {
10357
+ const date = formatDate(tx.timestamp);
10358
+ return /* @__PURE__ */ jsxs(
10359
+ "div",
9749
10360
  {
9750
- className: "font-semibold",
9751
- style: {
9752
- color: isPnlPositive ? "var(--compass-color-success)" : "var(--compass-color-error)"
9753
- },
10361
+ className: "flex items-center justify-between p-3 rounded-lg",
10362
+ style: { backgroundColor: "var(--compass-color-surface)" },
9754
10363
  children: [
9755
- isPnlPositive ? "+" : "",
9756
- formatUSD(position.pnl.totalPnl)
9757
- ]
9758
- }
9759
- )
9760
- ]
9761
- }
9762
- )
9763
- ] }),
9764
- (position.deposits.length > 0 || position.withdrawals.length > 0) && /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
9765
- /* @__PURE__ */ jsx(
9766
- "h3",
9767
- {
9768
- className: "font-semibold mb-3",
9769
- style: { color: "var(--compass-color-text)" },
9770
- children: "Transaction History"
9771
- }
9772
- ),
9773
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
9774
- position.deposits.map((tx, i) => {
9775
- const date = formatDate(tx.timestamp);
9776
- return /* @__PURE__ */ jsxs(
9777
- "div",
9778
- {
9779
- className: "flex items-center justify-between p-3 rounded-lg",
9780
- style: { backgroundColor: "var(--compass-color-surface)" },
9781
- children: [
9782
- /* @__PURE__ */ jsxs("div", { children: [
9783
- /* @__PURE__ */ jsxs(
9784
- "p",
9785
- {
9786
- className: "font-medium",
9787
- style: { color: "var(--compass-color-success)" },
9788
- children: [
9789
- "+",
9790
- formatAmount(tx.amount),
9791
- " ",
9792
- position.assetSymbol
9793
- ]
9794
- }
9795
- ),
9796
- /* @__PURE__ */ jsx(
9797
- "p",
10364
+ /* @__PURE__ */ jsxs("div", { children: [
10365
+ /* @__PURE__ */ jsxs(
10366
+ "p",
10367
+ {
10368
+ className: "font-medium",
10369
+ style: { color: "var(--compass-color-success)" },
10370
+ children: [
10371
+ "+",
10372
+ formatAmount(tx.amount),
10373
+ " ",
10374
+ position.assetSymbol
10375
+ ]
10376
+ }
10377
+ ),
10378
+ /* @__PURE__ */ jsx(
10379
+ "p",
10380
+ {
10381
+ className: "text-xs",
10382
+ style: { color: "var(--compass-color-text-tertiary)" },
10383
+ children: date ? `Deposit - ${date}` : "Deposit"
10384
+ }
10385
+ )
10386
+ ] }),
10387
+ tx.txHash && /* @__PURE__ */ jsx(
10388
+ "a",
9798
10389
  {
9799
- className: "text-xs",
9800
- style: { color: "var(--compass-color-text-tertiary)" },
9801
- children: date ? `Deposit - ${date}` : "Deposit"
10390
+ href: `https://etherscan.io/tx/${tx.txHash}`,
10391
+ target: "_blank",
10392
+ rel: "noopener noreferrer",
10393
+ className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
10394
+ style: { backgroundColor: "var(--compass-color-background)" },
10395
+ children: /* @__PURE__ */ jsx(ExternalLink, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
9802
10396
  }
9803
10397
  )
9804
- ] }),
9805
- tx.txHash && /* @__PURE__ */ jsx(
9806
- "a",
9807
- {
9808
- href: `https://etherscan.io/tx/${tx.txHash}`,
9809
- target: "_blank",
9810
- rel: "noopener noreferrer",
9811
- className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
9812
- style: { backgroundColor: "var(--compass-color-background)" },
9813
- children: /* @__PURE__ */ jsx(ExternalLink, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
9814
- }
9815
- )
9816
- ]
9817
- },
9818
- `deposit-${i}`
9819
- );
9820
- }),
9821
- position.withdrawals.map((tx, i) => {
9822
- const date = formatDate(tx.timestamp);
9823
- return /* @__PURE__ */ jsxs(
9824
- "div",
9825
- {
9826
- className: "flex items-center justify-between p-3 rounded-lg",
9827
- style: { backgroundColor: "var(--compass-color-surface)" },
9828
- children: [
9829
- /* @__PURE__ */ jsxs("div", { children: [
9830
- /* @__PURE__ */ jsxs(
9831
- "p",
9832
- {
9833
- className: "font-medium",
9834
- style: { color: "var(--compass-color-error)" },
9835
- children: [
9836
- "-",
9837
- formatAmount(tx.amount),
9838
- " ",
9839
- position.assetSymbol
9840
- ]
9841
- }
9842
- ),
9843
- /* @__PURE__ */ jsx(
9844
- "p",
10398
+ ]
10399
+ },
10400
+ `deposit-${i}`
10401
+ );
10402
+ }),
10403
+ position.withdrawals.map((tx, i) => {
10404
+ const date = formatDate(tx.timestamp);
10405
+ return /* @__PURE__ */ jsxs(
10406
+ "div",
10407
+ {
10408
+ className: "flex items-center justify-between p-3 rounded-lg",
10409
+ style: { backgroundColor: "var(--compass-color-surface)" },
10410
+ children: [
10411
+ /* @__PURE__ */ jsxs("div", { children: [
10412
+ /* @__PURE__ */ jsxs(
10413
+ "p",
10414
+ {
10415
+ className: "font-medium",
10416
+ style: { color: "var(--compass-color-error)" },
10417
+ children: [
10418
+ "-",
10419
+ formatAmount(tx.amount),
10420
+ " ",
10421
+ position.assetSymbol
10422
+ ]
10423
+ }
10424
+ ),
10425
+ /* @__PURE__ */ jsx(
10426
+ "p",
10427
+ {
10428
+ className: "text-xs",
10429
+ style: { color: "var(--compass-color-text-tertiary)" },
10430
+ children: date ? `Withdrawal - ${date}` : "Withdrawal"
10431
+ }
10432
+ )
10433
+ ] }),
10434
+ tx.txHash && /* @__PURE__ */ jsx(
10435
+ "a",
9845
10436
  {
9846
- className: "text-xs",
9847
- style: { color: "var(--compass-color-text-tertiary)" },
9848
- children: date ? `Withdrawal - ${date}` : "Withdrawal"
10437
+ href: `https://etherscan.io/tx/${tx.txHash}`,
10438
+ target: "_blank",
10439
+ rel: "noopener noreferrer",
10440
+ className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
10441
+ style: { backgroundColor: "var(--compass-color-background)" },
10442
+ children: /* @__PURE__ */ jsx(ExternalLink, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
9849
10443
  }
9850
10444
  )
9851
- ] }),
9852
- tx.txHash && /* @__PURE__ */ jsx(
9853
- "a",
9854
- {
9855
- href: `https://etherscan.io/tx/${tx.txHash}`,
9856
- target: "_blank",
9857
- rel: "noopener noreferrer",
9858
- className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
9859
- style: { backgroundColor: "var(--compass-color-background)" },
9860
- children: /* @__PURE__ */ jsx(ExternalLink, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
9861
- }
9862
- )
9863
- ]
9864
- },
9865
- `withdraw-${i}`
9866
- );
9867
- })
10445
+ ]
10446
+ },
10447
+ `withdraw-${i}`
10448
+ );
10449
+ })
10450
+ ] })
9868
10451
  ] })
9869
- ] })
9870
- ]
9871
- }
9872
- )
10452
+ ]
10453
+ }
10454
+ )
10455
+ ]
9873
10456
  }
9874
10457
  );
9875
10458
  }
@@ -10638,7 +11221,7 @@ function AllocationEditor({
10638
11221
  ) })
10639
11222
  ] });
10640
11223
  }
10641
- var EVM_CHAIN_IDS3 = {
11224
+ var EVM_CHAIN_IDS4 = {
10642
11225
  ethereum: 1,
10643
11226
  base: 8453,
10644
11227
  arbitrum: 42161
@@ -10672,7 +11255,7 @@ function RebalancingWidget({
10672
11255
  }) {
10673
11256
  const { chainId: contextChainId, setChainId } = useChain();
10674
11257
  const CHAIN_ID = chain || contextChainId;
10675
- const { address, signTypedData, isConnected, login, logout, switchChain, walletChainId } = useEmbeddableWallet();
11258
+ const { address, signTypedData, isConnected, login, logout, switchChain, walletChainId, fundWallet, hasExternalWallet } = useEmbeddableWallet();
10676
11259
  const { earnAccountAddress } = useEarnAccount();
10677
11260
  const queryClient = useQueryClient();
10678
11261
  const { portfolio, earnAccountMarkets, isMarketsLoading, isLoading, isError, error, refetch } = useRebalancingData(chain);
@@ -10708,6 +11291,7 @@ function RebalancingWidget({
10708
11291
  const [txHash, setTxHash] = useState(null);
10709
11292
  const [txConfirmed, setTxConfirmed] = useState(false);
10710
11293
  const [hasInitializedTargets, setHasInitializedTargets] = useState(false);
11294
+ const [originalAllocations, setOriginalAllocations] = useState({});
10711
11295
  const [isSwapModalOpen, setIsSwapModalOpen] = useState(false);
10712
11296
  const [isBalancesModalOpen, setIsBalancesModalOpen] = useState(false);
10713
11297
  const [isAddMarketExpanded, setIsAddMarketExpanded] = useState(false);
@@ -10720,12 +11304,14 @@ function RebalancingWidget({
10720
11304
  const [selectedToken, setSelectedToken] = useState("USDC");
10721
11305
  const [depositAmount, setDepositAmount] = useState("");
10722
11306
  const [isTokenDropdownOpen, setIsTokenDropdownOpen] = useState(false);
10723
- const [isProcessing, setIsProcessing] = useState(false);
10724
- const [depositError, setDepositError] = useState(null);
10725
- const [depositStatus, setDepositStatus] = useState("");
11307
+ const [depositTxState, setDepositTxState] = useState({ status: "idle" });
10726
11308
  const earnBalanceRef = useRef(null);
11309
+ const { startPolling: startDepositPolling, clearPolling: clearDepositPolling } = useTxPolling({
11310
+ queryKeysToInvalidate: [["earnAccountBalances"], ["rebalancing"]]
11311
+ });
10727
11312
  useEffect(() => {
10728
11313
  setTargets([]);
11314
+ setOriginalAllocations({});
10729
11315
  setPreviewPlan(null);
10730
11316
  setServerPreview(null);
10731
11317
  setWidgetState("editing");
@@ -10737,20 +11323,26 @@ function RebalancingWidget({
10737
11323
  setIsSwapModalOpen(false);
10738
11324
  setSelectedMarket(null);
10739
11325
  setDepositAmount("");
10740
- setDepositError(null);
10741
- setDepositStatus("");
10742
- }, [CHAIN_ID]);
11326
+ setDepositTxState({ status: "idle" });
11327
+ clearDepositPolling();
11328
+ }, [CHAIN_ID, clearDepositPolling]);
10743
11329
  useEffect(() => {
10744
11330
  if (portfolio && portfolio.positions.length > 0 && !hasInitializedTargets && !isLoading) {
11331
+ const origAllocs = {};
10745
11332
  setTargets(
10746
- portfolio.positions.map((p) => ({
10747
- venueType: p.venueType,
10748
- venueAddress: p.venueAddress,
10749
- venueName: p.venueName,
10750
- token: p.token,
10751
- targetPercent: parseFloat(p.allocationPercent.toFixed(2))
10752
- }))
11333
+ portfolio.positions.map((p) => {
11334
+ const pct = parseFloat(p.allocationPercent.toFixed(2));
11335
+ origAllocs[`${p.venueType}-${p.venueAddress.toLowerCase()}`] = pct;
11336
+ return {
11337
+ venueType: p.venueType,
11338
+ venueAddress: p.venueAddress,
11339
+ venueName: p.venueName,
11340
+ token: p.token,
11341
+ targetPercent: pct
11342
+ };
11343
+ })
10753
11344
  );
11345
+ setOriginalAllocations(origAllocs);
10754
11346
  setHasInitializedTargets(true);
10755
11347
  }
10756
11348
  }, [portfolio, hasInitializedTargets, isLoading]);
@@ -10782,15 +11374,21 @@ function RebalancingWidget({
10782
11374
  }, [portfolio, targets, hasChanges, defaultSlippage, minRebalanceThresholdUsd]);
10783
11375
  const handleResetToCurrent = useCallback(() => {
10784
11376
  if (!portfolio) return;
11377
+ const origAllocs = {};
10785
11378
  setTargets(
10786
- portfolio.positions.map((p) => ({
10787
- venueType: p.venueType,
10788
- venueAddress: p.venueAddress,
10789
- venueName: p.venueName,
10790
- token: p.token,
10791
- targetPercent: parseFloat(p.allocationPercent.toFixed(2))
10792
- }))
11379
+ portfolio.positions.map((p) => {
11380
+ const pct = parseFloat(p.allocationPercent.toFixed(2));
11381
+ origAllocs[`${p.venueType}-${p.venueAddress.toLowerCase()}`] = pct;
11382
+ return {
11383
+ venueType: p.venueType,
11384
+ venueAddress: p.venueAddress,
11385
+ venueName: p.venueName,
11386
+ token: p.token,
11387
+ targetPercent: pct
11388
+ };
11389
+ })
10793
11390
  );
11391
+ setOriginalAllocations(origAllocs);
10794
11392
  setPreviewPlan(null);
10795
11393
  setServerPreview(null);
10796
11394
  setWidgetState("editing");
@@ -10808,7 +11406,7 @@ function RebalancingWidget({
10808
11406
  setTargets((prev) => prev.map((t, i) => i === index ? { ...t, targetPercent: rounded } : t));
10809
11407
  }, []);
10810
11408
  const ensureCorrectChain = useCallback(async () => {
10811
- const targetChainId = EVM_CHAIN_IDS3[CHAIN_ID];
11409
+ const targetChainId = EVM_CHAIN_IDS4[CHAIN_ID];
10812
11410
  if (!targetChainId) return;
10813
11411
  if (walletChainId !== void 0 && walletChainId !== targetChainId) {
10814
11412
  if (!switchChain) {
@@ -10833,7 +11431,8 @@ function RebalancingWidget({
10833
11431
  venueType: t.venueType === "vault" ? "VAULT" : t.venueType === "aave" ? "AAVE" : "PENDLE_PT",
10834
11432
  venueAddress: t.venueAddress,
10835
11433
  targetPercent: t.targetPercent,
10836
- token: t.token
11434
+ token: t.token,
11435
+ originalPercent: originalAllocations[`${t.venueType}-${t.venueAddress.toLowerCase()}`] ?? 0
10837
11436
  })),
10838
11437
  slippage: defaultSlippage
10839
11438
  })
@@ -10851,7 +11450,7 @@ function RebalancingWidget({
10851
11450
  setWidgetState("error");
10852
11451
  onError?.(err instanceof Error ? err : new Error("Preview failed"));
10853
11452
  }
10854
- }, [portfolio, hasChanges, address, CHAIN_ID, targets, defaultSlippage, clientPreview, onError, ensureCorrectChain]);
11453
+ }, [portfolio, hasChanges, address, CHAIN_ID, targets, defaultSlippage, clientPreview, onError, ensureCorrectChain, originalAllocations]);
10855
11454
  const handleExecute = useCallback(async () => {
10856
11455
  if (!serverPreview?.eip712 || !address) return;
10857
11456
  setWidgetState("signing");
@@ -10939,13 +11538,11 @@ function RebalancingWidget({
10939
11538
  };
10940
11539
  const handleDeposit = useCallback(async () => {
10941
11540
  if (!selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || !address || !signTypedData) return;
10942
- setIsProcessing(true);
10943
- setDepositError(null);
11541
+ setDepositTxState({ status: "preparing" });
10944
11542
  const underlyingToken = selectedMarket.underlyingToken;
10945
11543
  try {
10946
11544
  let resultTxHash;
10947
11545
  if (needsSwap) {
10948
- setDepositStatus("Getting swap quote...");
10949
11546
  const quoteResponse = await fetch(
10950
11547
  `/api/compass/swap/quote?owner=${address}&chain=${CHAIN_ID}&tokenIn=${selectedToken}&tokenOut=${underlyingToken}&amountIn=${depositAmount}`
10951
11548
  );
@@ -10959,7 +11556,6 @@ function RebalancingWidget({
10959
11556
  throw new Error("Invalid swap quote - no output amount");
10960
11557
  }
10961
11558
  const actualDepositAmount = (parseFloat(estimatedOutput) * 0.99999).toString();
10962
- setDepositStatus("Preparing swap and deposit...");
10963
11559
  const bundleActions = [
10964
11560
  {
10965
11561
  body: {
@@ -10993,7 +11589,7 @@ function RebalancingWidget({
10993
11589
  throw new Error(errorData.error || "Failed to prepare bundle");
10994
11590
  }
10995
11591
  const { eip712, normalizedTypes, domain, message } = await prepareResponse.json();
10996
- setDepositStatus("Please sign the transaction...");
11592
+ setDepositTxState({ status: "signing" });
10997
11593
  await ensureCorrectChain();
10998
11594
  const signature = await signTypedData({
10999
11595
  domain,
@@ -11001,7 +11597,7 @@ function RebalancingWidget({
11001
11597
  primaryType: "SafeTx",
11002
11598
  message
11003
11599
  });
11004
- setDepositStatus("Executing swap and deposit...");
11600
+ setDepositTxState({ status: "broadcasting" });
11005
11601
  const executeResponse = await fetch("/api/compass/bundle/execute", {
11006
11602
  method: "POST",
11007
11603
  headers: { "Content-Type": "application/json" },
@@ -11019,7 +11615,6 @@ function RebalancingWidget({
11019
11615
  const result = await executeResponse.json();
11020
11616
  resultTxHash = result.txHash;
11021
11617
  } else {
11022
- setDepositStatus("Preparing deposit...");
11023
11618
  const venueParams = buildVenueParamsFromMarket(selectedMarket);
11024
11619
  const prepareResponse = await fetch("/api/compass/deposit/prepare", {
11025
11620
  method: "POST",
@@ -11036,7 +11631,7 @@ function RebalancingWidget({
11036
11631
  throw new Error(errData.error || "Failed to prepare deposit");
11037
11632
  }
11038
11633
  const prepareData = await prepareResponse.json();
11039
- setDepositStatus("Please sign the transaction...");
11634
+ setDepositTxState({ status: "signing" });
11040
11635
  await ensureCorrectChain();
11041
11636
  const signature = await signTypedData({
11042
11637
  domain: prepareData.domain,
@@ -11044,7 +11639,7 @@ function RebalancingWidget({
11044
11639
  primaryType: "SafeTx",
11045
11640
  message: prepareData.message
11046
11641
  });
11047
- setDepositStatus("Executing deposit...");
11642
+ setDepositTxState({ status: "broadcasting" });
11048
11643
  const executeResponse = await fetch("/api/compass/deposit/execute", {
11049
11644
  method: "POST",
11050
11645
  headers: { "Content-Type": "application/json" },
@@ -11062,7 +11657,8 @@ function RebalancingWidget({
11062
11657
  const result = await executeResponse.json();
11063
11658
  resultTxHash = result.txHash;
11064
11659
  }
11065
- setDepositStatus("Deposit successful!");
11660
+ setDepositTxState({ status: "submitted", txHash: resultTxHash });
11661
+ startDepositPolling(resultTxHash, setDepositTxState);
11066
11662
  setDepositAmount("");
11067
11663
  queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
11068
11664
  queryClient.invalidateQueries({ queryKey: ["rebalancing"] });
@@ -11074,15 +11670,11 @@ function RebalancingWidget({
11074
11670
  refetch();
11075
11671
  }, delay);
11076
11672
  }
11077
- setTimeout(() => setDepositStatus(""), 3e3);
11078
11673
  } catch (err) {
11079
- setDepositError(err instanceof Error ? err.message : "Deposit failed");
11080
- setDepositStatus("");
11674
+ setDepositTxState({ status: "failed", error: err instanceof Error ? err.message : "Deposit failed" });
11081
11675
  onError?.(err instanceof Error ? err : new Error("Deposit failed"));
11082
- } finally {
11083
- setIsProcessing(false);
11084
11676
  }
11085
- }, [selectedMarket, depositAmount, address, signTypedData, selectedToken, needsSwap, CHAIN_ID, ensureCorrectChain, queryClient, refetch, onError]);
11677
+ }, [selectedMarket, depositAmount, address, signTypedData, selectedToken, needsSwap, CHAIN_ID, ensureCorrectChain, queryClient, refetch, onError, startDepositPolling]);
11086
11678
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col w-full", style: { gap: "0", fontFamily: "var(--compass-font-family)", height, overflow: "hidden", borderRadius: "var(--compass-border-radius-xl)" }, children: [
11087
11679
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, minHeight: 0, overflowY: "auto", scrollbarWidth: "none", display: "flex", flexDirection: "column" }, children: [
11088
11680
  showChainSwitcher && !chain && /* @__PURE__ */ jsx("div", { style: { padding: "0 4px", marginBottom: "8px" }, children: /* @__PURE__ */ jsx(ChainSwitcher, {}) }),
@@ -11111,8 +11703,19 @@ function RebalancingWidget({
11111
11703
  }
11112
11704
  )
11113
11705
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
11114
- /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold mb-2", style: { color: "var(--compass-color-text)" }, children: "No positions found" }),
11115
- /* @__PURE__ */ jsx("p", { className: "text-sm", style: { color: "var(--compass-color-text-secondary)" }, children: "Deposit into a vault, Aave market, or Pendle market to start rebalancing." })
11706
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold mb-2", style: { color: "var(--compass-color-text)" }, children: fundWallet && !hasExternalWallet ? "Fund your account to start" : "No positions found" }),
11707
+ /* @__PURE__ */ jsx("p", { className: "text-sm mb-4", style: { color: "var(--compass-color-text-secondary)" }, children: fundWallet && !hasExternalWallet ? "Buy crypto to get started with your DeFi portfolio." : "Deposit into a vault, Aave market, or Pendle market to start rebalancing." }),
11708
+ fundWallet && earnAccountAddress && /* @__PURE__ */ jsx("div", { style: { width: "100%", maxWidth: "320px" }, children: /* @__PURE__ */ jsx(
11709
+ BuyForm,
11710
+ {
11711
+ targetAddress: earnAccountAddress,
11712
+ onComplete: () => {
11713
+ queryClient.invalidateQueries({ queryKey: ["rebalancingPortfolio"] });
11714
+ queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
11715
+ refetch();
11716
+ }
11717
+ }
11718
+ ) })
11116
11719
  ] }) }),
11117
11720
  state !== "loading" && state !== "empty" && portfolio && /* @__PURE__ */ jsxs(Fragment, { children: [
11118
11721
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center", style: { padding: "16px 16px 12px" }, children: [
@@ -11279,7 +11882,7 @@ function RebalancingWidget({
11279
11882
  selectedMarket,
11280
11883
  onMarketSelect: (market) => {
11281
11884
  setSelectedMarket(market);
11282
- setDepositError(null);
11885
+ if (depositTxState.status === "failed") setDepositTxState({ status: "idle" });
11283
11886
  },
11284
11887
  isLoading: isMarketsLoading
11285
11888
  }
@@ -11302,10 +11905,10 @@ function RebalancingWidget({
11302
11905
  value: depositAmount,
11303
11906
  onChange: (e) => {
11304
11907
  setDepositAmount(e.target.value);
11305
- setDepositError(null);
11908
+ if (depositTxState.status === "failed") setDepositTxState({ status: "idle" });
11306
11909
  },
11307
11910
  placeholder: "0.00",
11308
- disabled: isProcessing,
11911
+ disabled: depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed",
11309
11912
  className: "flex-1 font-bold bg-transparent outline-none",
11310
11913
  style: {
11311
11914
  color: "var(--compass-color-text)",
@@ -11321,7 +11924,7 @@ function RebalancingWidget({
11321
11924
  "button",
11322
11925
  {
11323
11926
  onClick: () => setIsTokenDropdownOpen(!isTokenDropdownOpen),
11324
- disabled: isProcessing,
11927
+ disabled: depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed",
11325
11928
  className: "flex items-center font-semibold",
11326
11929
  style: {
11327
11930
  backgroundColor: "var(--compass-color-surface-hover, var(--compass-color-surface))",
@@ -11358,7 +11961,7 @@ function RebalancingWidget({
11358
11961
  onClick: () => {
11359
11962
  setSelectedToken(token);
11360
11963
  setIsTokenDropdownOpen(false);
11361
- setDepositError(null);
11964
+ if (depositTxState.status === "failed") setDepositTxState({ status: "idle" });
11362
11965
  },
11363
11966
  className: "w-full text-left font-medium",
11364
11967
  style: {
@@ -11384,7 +11987,7 @@ function RebalancingWidget({
11384
11987
  "button",
11385
11988
  {
11386
11989
  onClick: () => setDepositAmount(earnBalancesQuery.toString()),
11387
- disabled: isProcessing,
11990
+ disabled: depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed",
11388
11991
  className: "font-semibold",
11389
11992
  style: { color: "var(--compass-color-primary)", fontSize: "0.8125rem", background: "none", border: "none", padding: 0 },
11390
11993
  children: [
@@ -11421,26 +12024,12 @@ function RebalancingWidget({
11421
12024
  ]
11422
12025
  }
11423
12026
  ),
11424
- depositError && /* @__PURE__ */ jsx(
11425
- "div",
11426
- {
11427
- className: "flex items-center",
11428
- style: {
11429
- backgroundColor: "var(--compass-color-error-muted)",
11430
- color: "var(--compass-color-error)",
11431
- borderRadius: "var(--compass-border-radius-lg)",
11432
- padding: "12px 14px",
11433
- gap: "8px",
11434
- fontSize: "0.875rem"
11435
- },
11436
- children: depositError
11437
- }
11438
- ),
12027
+ /* @__PURE__ */ jsx(TxStatus, { state: depositTxState }),
11439
12028
  /* @__PURE__ */ jsx(
11440
12029
  "button",
11441
12030
  {
11442
12031
  onClick: !isConnected && login ? login : handleDeposit,
11443
- disabled: isConnected && (isProcessing || !selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || parseFloat(depositAmount) > earnBalancesQuery),
12032
+ disabled: isConnected && (depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed" || !selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || parseFloat(depositAmount) > earnBalancesQuery),
11444
12033
  className: "w-full font-bold",
11445
12034
  style: {
11446
12035
  backgroundColor: "var(--compass-color-primary)",
@@ -11451,26 +12040,13 @@ function RebalancingWidget({
11451
12040
  fontSize: "1rem",
11452
12041
  transition: "all 200ms ease",
11453
12042
  border: "none",
11454
- opacity: isConnected && (isProcessing || !selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || parseFloat(depositAmount) > earnBalancesQuery) ? 0.4 : 1
12043
+ opacity: isConnected && (depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed" || !selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || parseFloat(depositAmount) > earnBalancesQuery) ? 0.4 : 1
11455
12044
  },
11456
- children: !isConnected ? "Connect Wallet" : isProcessing ? /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-center", style: { gap: "8px" }, children: [
12045
+ children: !isConnected ? "Connect Wallet" : depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed" ? /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-center", style: { gap: "8px" }, children: [
11457
12046
  /* @__PURE__ */ jsx(Loader2, { size: 16, className: "animate-spin" }),
11458
12047
  "Processing..."
11459
12048
  ] }) : !selectedMarket ? "Select a market" : needsSwap ? "Swap & Deposit" : "Deposit"
11460
12049
  }
11461
- ),
11462
- depositStatus && !depositError && /* @__PURE__ */ jsx(
11463
- "div",
11464
- {
11465
- className: "text-sm text-center",
11466
- style: {
11467
- backgroundColor: depositStatus.includes("successful") ? "var(--compass-color-success-muted)" : "var(--compass-color-primary-muted, rgba(99, 102, 241, 0.1))",
11468
- color: depositStatus.includes("successful") ? "var(--compass-color-success)" : "var(--compass-color-primary)",
11469
- borderRadius: "var(--compass-border-radius-lg)",
11470
- padding: "10px 12px"
11471
- },
11472
- children: depositStatus
11473
- }
11474
12050
  )
11475
12051
  ] }),
11476
12052
  clientPreview && clientPreview.actions.length > 0 && state === "editing" && /* @__PURE__ */ jsxs(
@@ -11487,11 +12063,7 @@ function RebalancingWidget({
11487
12063
  clientPreview.warnings.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-col gap-1", children: clientPreview.warnings.map((w, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs", style: { color: "var(--compass-color-warning, #eab308)" }, children: [
11488
12064
  /* @__PURE__ */ jsx(AlertTriangle, { size: 12, className: "flex-shrink-0 mt-0.5" }),
11489
12065
  /* @__PURE__ */ jsx("span", { children: w })
11490
- ] }, i)) }),
11491
- /* @__PURE__ */ jsxs("p", { className: "text-xs mt-2", style: { color: "var(--compass-color-text-tertiary)" }, children: [
11492
- "Estimated gas savings: ",
11493
- clientPreview.estimatedGasSavings
11494
- ] })
12066
+ ] }, i)) })
11495
12067
  ]
11496
12068
  }
11497
12069
  ),
@@ -11734,46 +12306,8 @@ function RebalancingWidget({
11734
12306
  onClose: () => setIsBalancesModalOpen(false),
11735
12307
  title: "Balance Breakdown",
11736
12308
  children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", style: { gap: "12px" }, children: [
11737
- address && /* @__PURE__ */ jsxs(
11738
- "div",
11739
- {
11740
- className: "flex items-center justify-between",
11741
- style: {
11742
- backgroundColor: "var(--compass-color-surface)",
11743
- borderRadius: "var(--compass-border-radius-lg)",
11744
- padding: "10px 16px",
11745
- border: "1.5px solid var(--compass-color-border)"
11746
- },
11747
- children: [
11748
- /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-tertiary)", fontSize: "0.8125rem" }, children: "Wallet" }),
11749
- /* @__PURE__ */ jsxs("span", { style: { color: "var(--compass-color-text)", fontSize: "0.8125rem", fontFamily: "monospace" }, children: [
11750
- address.slice(0, 6),
11751
- "...",
11752
- address.slice(-4)
11753
- ] })
11754
- ]
11755
- }
11756
- ),
11757
- earnAccountAddress && /* @__PURE__ */ jsxs(
11758
- "div",
11759
- {
11760
- className: "flex items-center justify-between",
11761
- style: {
11762
- backgroundColor: "var(--compass-color-surface)",
11763
- borderRadius: "var(--compass-border-radius-lg)",
11764
- padding: "10px 16px",
11765
- border: "1.5px solid var(--compass-color-border)"
11766
- },
11767
- children: [
11768
- /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-tertiary)", fontSize: "0.8125rem" }, children: "Product Account" }),
11769
- /* @__PURE__ */ jsxs("span", { style: { color: "var(--compass-color-text)", fontSize: "0.8125rem", fontFamily: "monospace" }, children: [
11770
- earnAccountAddress.slice(0, 6),
11771
- "...",
11772
- earnAccountAddress.slice(-4)
11773
- ] })
11774
- ]
11775
- }
11776
- ),
12309
+ address && /* @__PURE__ */ jsx(CopyableAddress, { address, label: "Wallet" }),
12310
+ earnAccountAddress && /* @__PURE__ */ jsx(CopyableAddress, { address: earnAccountAddress, label: "Product Account" }),
11777
12311
  portfolio && portfolio.idleBalances.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
11778
12312
  /* @__PURE__ */ jsx(
11779
12313
  "span",