@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.d.mts +50 -2
- package/dist/index.d.ts +50 -2
- package/dist/index.js +1668 -1134
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1670 -1136
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +6 -0
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { createContext, forwardRef, useState, useCallback, useImperativeHandle, useContext,
|
|
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,
|
|
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-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
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-
|
|
2599
|
-
style: { color: "var(--compass-color-text-
|
|
2600
|
-
children:
|
|
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
|
-
)
|
|
2603
|
-
|
|
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: "
|
|
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: "
|
|
2654
|
+
children: "$"
|
|
2610
2655
|
}
|
|
2611
2656
|
),
|
|
2612
2657
|
/* @__PURE__ */ jsx(
|
|
2613
|
-
"
|
|
2658
|
+
"input",
|
|
2614
2659
|
{
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
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
|
-
|
|
2622
|
-
|
|
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
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
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
|
-
|
|
2632
|
-
/* @__PURE__ */
|
|
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
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
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
|
-
|
|
2835
|
+
CheckCircle,
|
|
2652
2836
|
{
|
|
2653
|
-
className: "
|
|
2654
|
-
style: { color: "var(--compass-color-
|
|
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
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
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 [
|
|
2675
|
-
const
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
const {
|
|
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,
|
|
3332
|
+
queryKey: ["eoaBalances", chainId, address, TRANSFER_TOKEN],
|
|
2699
3333
|
queryFn: async () => {
|
|
2700
3334
|
if (!address) return {};
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
);
|
|
2707
|
-
|
|
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
|
|
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
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2879
|
-
|
|
3495
|
+
setTxState({ status: "submitted", txHash });
|
|
3496
|
+
startPolling(txHash, setTxState);
|
|
2880
3497
|
onTransferComplete?.(activeAction, selectedToken, amount, txHash);
|
|
2881
|
-
|
|
2882
|
-
queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
|
|
2883
|
-
setTimeout(() => {
|
|
2884
|
-
resetForm();
|
|
2885
|
-
}, 2e3);
|
|
3498
|
+
setAmount("");
|
|
2886
3499
|
} catch (err) {
|
|
2887
|
-
|
|
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
|
-
|
|
3513
|
+
startPolling
|
|
2903
3514
|
]);
|
|
2904
3515
|
if (!isConnected) {
|
|
2905
3516
|
return null;
|
|
2906
3517
|
}
|
|
2907
|
-
const isProcessing =
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
3149
|
-
|
|
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
|
-
|
|
3635
|
+
activeAction === "send" ? /* @__PURE__ */ jsx(
|
|
3636
|
+
SendForm,
|
|
3155
3637
|
{
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
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
|
|
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: `${
|
|
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
|
|
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: `${
|
|
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
|
|
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(
|
|
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 =
|
|
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: [
|
|
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
|
-
|
|
5830
|
-
|
|
6265
|
+
fundAction === "send" ? /* @__PURE__ */ jsx(
|
|
6266
|
+
SendForm,
|
|
5831
6267
|
{
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
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
|
-
|
|
5859
|
-
|
|
5860
|
-
"
|
|
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: "
|
|
6288
|
+
className: "flex gap-3 p-3 text-xs",
|
|
5863
6289
|
style: {
|
|
5864
|
-
|
|
6290
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
6291
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
5865
6292
|
fontFamily: "var(--compass-font-family)"
|
|
5866
6293
|
},
|
|
5867
|
-
children:
|
|
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", {
|
|
6314
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5871
6315
|
/* @__PURE__ */ jsx(
|
|
5872
|
-
"
|
|
6316
|
+
"label",
|
|
5873
6317
|
{
|
|
5874
|
-
|
|
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
|
-
|
|
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__ */
|
|
5893
|
-
|
|
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: "
|
|
6360
|
+
className: "text-xs mt-1",
|
|
5896
6361
|
style: { color: "var(--compass-color-text-tertiary)" },
|
|
5897
|
-
children:
|
|
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
|
-
|
|
6381
|
+
!fundIsBusy && fundStep !== "confirmed" && fundStep !== "failed" && fundTxState.status === "idle" && /* @__PURE__ */ jsx(
|
|
5902
6382
|
"p",
|
|
5903
6383
|
{
|
|
5904
|
-
className: "text-xs
|
|
5905
|
-
style: {
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
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
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
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
|
|
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(
|
|
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 =
|
|
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: [
|
|
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
|
-
|
|
8096
|
-
|
|
8562
|
+
action === "send" ? /* @__PURE__ */ jsx(
|
|
8563
|
+
SendForm,
|
|
8097
8564
|
{
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
}
|
|
8104
|
-
|
|
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
|
-
|
|
8615
|
+
"input",
|
|
8107
8616
|
{
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
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
|
-
|
|
8630
|
+
"span",
|
|
8115
8631
|
{
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
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
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
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__ */
|
|
8143
|
-
"
|
|
8650
|
+
maxBalance && maxBalance !== "0" && /* @__PURE__ */ jsxs(
|
|
8651
|
+
"p",
|
|
8144
8652
|
{
|
|
8145
|
-
className: "
|
|
8653
|
+
className: "text-xs mt-1",
|
|
8146
8654
|
style: { color: "var(--compass-color-text-tertiary)" },
|
|
8147
|
-
children:
|
|
8655
|
+
children: [
|
|
8656
|
+
"Available: ",
|
|
8657
|
+
truncate6(parseFloat(maxBalance), 2),
|
|
8658
|
+
" ",
|
|
8659
|
+
token
|
|
8660
|
+
]
|
|
8148
8661
|
}
|
|
8149
8662
|
)
|
|
8150
8663
|
] }),
|
|
8151
|
-
|
|
8664
|
+
!isBusy && step !== "confirmed" && step !== "failed" && txState.status === "idle" && /* @__PURE__ */ jsx(
|
|
8152
8665
|
"p",
|
|
8153
8666
|
{
|
|
8154
|
-
className: "text-xs
|
|
8155
|
-
style: {
|
|
8156
|
-
|
|
8157
|
-
"
|
|
8158
|
-
|
|
8159
|
-
|
|
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
|
-
|
|
8164
|
-
"
|
|
8675
|
+
/* @__PURE__ */ jsx(
|
|
8676
|
+
"button",
|
|
8165
8677
|
{
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
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
|
-
|
|
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 !==
|
|
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__ */
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
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__ */
|
|
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
|
-
|
|
10160
|
+
onWheel: handleOverlayWheel,
|
|
9589
10161
|
onClick: onClose,
|
|
9590
|
-
children:
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
|
|
9594
|
-
|
|
9595
|
-
backgroundColor: "
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
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-
|
|
9720
|
-
style: {
|
|
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", {
|
|
9723
|
-
/* @__PURE__ */ jsx(
|
|
9724
|
-
|
|
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
|
-
"
|
|
10211
|
+
"button",
|
|
9728
10212
|
{
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
|
|
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
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
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: "
|
|
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
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
|
|
9765
|
-
|
|
9766
|
-
|
|
9767
|
-
|
|
9768
|
-
|
|
9769
|
-
|
|
9770
|
-
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
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
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
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
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
)
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
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
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
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
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
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
|
|
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 [
|
|
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
|
-
|
|
10741
|
-
|
|
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
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
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
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11908
|
+
if (depositTxState.status === "failed") setDepositTxState({ status: "idle" });
|
|
11306
11909
|
},
|
|
11307
11910
|
placeholder: "0.00",
|
|
11308
|
-
disabled:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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 && (
|
|
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 && (
|
|
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" :
|
|
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__ */
|
|
11738
|
-
|
|
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",
|