@compass-labs/widgets 0.1.39 → 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 +1650 -1032
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1652 -1034
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ var apiSdk = require('@compass-labs/api-sdk');
|
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var chains = require('viem/chains');
|
|
8
8
|
var lucideReact = require('lucide-react');
|
|
9
|
+
var viem = require('viem');
|
|
9
10
|
|
|
10
11
|
// src/provider/CompassProvider.tsx
|
|
11
12
|
var ApiContext = react.createContext(null);
|
|
@@ -92,7 +93,10 @@ var disconnectedWallet = {
|
|
|
92
93
|
},
|
|
93
94
|
switchChain: null,
|
|
94
95
|
login: null,
|
|
95
|
-
logout: null
|
|
96
|
+
logout: null,
|
|
97
|
+
fundWallet: null,
|
|
98
|
+
hasExternalWallet: true,
|
|
99
|
+
sendTransaction: null
|
|
96
100
|
};
|
|
97
101
|
function WalletProvider({ children, wallet }) {
|
|
98
102
|
const value = wallet ? {
|
|
@@ -102,7 +106,10 @@ function WalletProvider({ children, wallet }) {
|
|
|
102
106
|
signTypedData: wallet.signTypedData,
|
|
103
107
|
switchChain: wallet.switchChain ?? null,
|
|
104
108
|
login: wallet.login ?? null,
|
|
105
|
-
logout: wallet.logout ?? null
|
|
109
|
+
logout: wallet.logout ?? null,
|
|
110
|
+
fundWallet: wallet.fundWallet ?? null,
|
|
111
|
+
hasExternalWallet: wallet.hasExternalWallet ?? true,
|
|
112
|
+
sendTransaction: wallet.sendTransaction ?? null
|
|
106
113
|
} : disconnectedWallet;
|
|
107
114
|
return /* @__PURE__ */ jsxRuntime.jsx(WalletContext.Provider, { value, children });
|
|
108
115
|
}
|
|
@@ -1271,25 +1278,29 @@ function WalletStatus({
|
|
|
1271
1278
|
);
|
|
1272
1279
|
}
|
|
1273
1280
|
function ActionModal({ isOpen, onClose, title, children }) {
|
|
1281
|
+
const modalRef = react.useRef(null);
|
|
1274
1282
|
react.useEffect(() => {
|
|
1275
1283
|
const handleEscape = (e) => {
|
|
1276
1284
|
if (e.key === "Escape") onClose();
|
|
1277
1285
|
};
|
|
1278
1286
|
if (isOpen) {
|
|
1279
1287
|
document.addEventListener("keydown", handleEscape);
|
|
1280
|
-
document.body.style.overflow = "hidden";
|
|
1281
1288
|
}
|
|
1282
1289
|
return () => {
|
|
1283
1290
|
document.removeEventListener("keydown", handleEscape);
|
|
1284
|
-
document.body.style.overflow = "";
|
|
1285
1291
|
};
|
|
1286
1292
|
}, [isOpen, onClose]);
|
|
1293
|
+
const handleOverlayWheel = react.useCallback((e) => {
|
|
1294
|
+
if (modalRef.current && !modalRef.current.contains(e.target)) {
|
|
1295
|
+
window.scrollBy(0, e.deltaY);
|
|
1296
|
+
}
|
|
1297
|
+
}, []);
|
|
1287
1298
|
if (!isOpen) return null;
|
|
1288
1299
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1289
1300
|
"div",
|
|
1290
1301
|
{
|
|
1291
1302
|
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
1292
|
-
|
|
1303
|
+
onWheel: handleOverlayWheel,
|
|
1293
1304
|
children: [
|
|
1294
1305
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1295
1306
|
"div",
|
|
@@ -1302,21 +1313,27 @@ function ActionModal({ isOpen, onClose, title, children }) {
|
|
|
1302
1313
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1303
1314
|
"div",
|
|
1304
1315
|
{
|
|
1316
|
+
ref: modalRef,
|
|
1305
1317
|
className: "relative w-full max-w-md",
|
|
1306
1318
|
style: {
|
|
1307
1319
|
backgroundColor: "var(--compass-color-surface)",
|
|
1308
1320
|
boxShadow: "var(--compass-shadow-lg)",
|
|
1309
1321
|
borderRadius: "var(--compass-border-radius-xl)",
|
|
1310
|
-
fontFamily: "var(--compass-font-family)"
|
|
1322
|
+
fontFamily: "var(--compass-font-family)",
|
|
1323
|
+
maxHeight: "85vh",
|
|
1324
|
+
overflowY: "auto",
|
|
1325
|
+
overscrollBehavior: "contain",
|
|
1326
|
+
scrollbarWidth: "none"
|
|
1311
1327
|
},
|
|
1312
1328
|
children: [
|
|
1313
1329
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1314
1330
|
"div",
|
|
1315
1331
|
{
|
|
1316
|
-
className: "flex items-center justify-between border-b",
|
|
1332
|
+
className: "flex items-center justify-between border-b sticky top-0 z-10",
|
|
1317
1333
|
style: {
|
|
1318
1334
|
borderColor: "var(--compass-color-border)",
|
|
1319
|
-
padding: "calc(var(--compass-spacing-card) * 0.75) var(--compass-spacing-card)"
|
|
1335
|
+
padding: "calc(var(--compass-spacing-card) * 0.75) var(--compass-spacing-card)",
|
|
1336
|
+
backgroundColor: "var(--compass-color-surface)"
|
|
1320
1337
|
},
|
|
1321
1338
|
children: [
|
|
1322
1339
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2573,114 +2590,731 @@ function CreditAccountGuard({
|
|
|
2573
2590
|
}
|
|
2574
2591
|
);
|
|
2575
2592
|
}
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2593
|
+
var EVM_CHAIN_IDS = {
|
|
2594
|
+
ethereum: 1,
|
|
2595
|
+
base: 8453,
|
|
2596
|
+
arbitrum: 42161
|
|
2597
|
+
};
|
|
2598
|
+
function BuyForm({ targetAddress, defaultAsset = "USDC", onComplete }) {
|
|
2599
|
+
const { fundWallet } = useEmbeddableWallet();
|
|
2600
|
+
const { chainId } = useChain();
|
|
2601
|
+
const [amount, setAmount] = react.useState("");
|
|
2602
|
+
const [state, setState] = react.useState("idle");
|
|
2603
|
+
const [error, setError] = react.useState(null);
|
|
2604
|
+
const numericChainId = EVM_CHAIN_IDS[chainId] || 8453;
|
|
2605
|
+
const handleBuy = react.useCallback(async () => {
|
|
2606
|
+
if (!fundWallet || !amount || parseFloat(amount) <= 0) {
|
|
2607
|
+
return;
|
|
2608
|
+
}
|
|
2609
|
+
setState("buying");
|
|
2610
|
+
setError(null);
|
|
2611
|
+
try {
|
|
2612
|
+
await fundWallet({
|
|
2613
|
+
address: targetAddress,
|
|
2614
|
+
chainId: numericChainId,
|
|
2615
|
+
asset: defaultAsset,
|
|
2616
|
+
amount
|
|
2617
|
+
});
|
|
2618
|
+
setState("success");
|
|
2619
|
+
onComplete?.();
|
|
2620
|
+
setTimeout(() => setState("idle"), 3e3);
|
|
2621
|
+
} catch (err) {
|
|
2622
|
+
setState("error");
|
|
2623
|
+
setError(err instanceof Error ? err.message : "Purchase failed. Please try again.");
|
|
2624
|
+
}
|
|
2625
|
+
}, [fundWallet, amount, targetAddress, numericChainId, defaultAsset, onComplete]);
|
|
2626
|
+
const chainName = chainId.charAt(0).toUpperCase() + chainId.slice(1);
|
|
2627
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
2628
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2629
|
+
"p",
|
|
2599
2630
|
{
|
|
2600
|
-
className: "text-
|
|
2601
|
-
style: { color: "var(--compass-color-text-
|
|
2602
|
-
children:
|
|
2631
|
+
className: "text-sm font-medium",
|
|
2632
|
+
style: { color: "var(--compass-color-text)", fontFamily: "var(--compass-font-family)" },
|
|
2633
|
+
children: [
|
|
2634
|
+
"Buy ",
|
|
2635
|
+
defaultAsset,
|
|
2636
|
+
" on ",
|
|
2637
|
+
chainName
|
|
2638
|
+
]
|
|
2603
2639
|
}
|
|
2604
|
-
)
|
|
2605
|
-
|
|
2640
|
+
),
|
|
2641
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2642
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2643
|
+
"label",
|
|
2644
|
+
{
|
|
2645
|
+
className: "block text-sm mb-1.5",
|
|
2646
|
+
style: { color: "var(--compass-color-text-secondary)", fontFamily: "var(--compass-font-family)" },
|
|
2647
|
+
children: "Amount (USD)"
|
|
2648
|
+
}
|
|
2649
|
+
),
|
|
2650
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
2606
2651
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2607
2652
|
"span",
|
|
2608
2653
|
{
|
|
2609
|
-
className: "
|
|
2654
|
+
className: "absolute left-3 top-1/2 -translate-y-1/2 text-sm",
|
|
2610
2655
|
style: { color: "var(--compass-color-text-tertiary)" },
|
|
2611
|
-
children: "
|
|
2656
|
+
children: "$"
|
|
2612
2657
|
}
|
|
2613
2658
|
),
|
|
2614
2659
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2615
|
-
"
|
|
2660
|
+
"input",
|
|
2616
2661
|
{
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2662
|
+
type: "number",
|
|
2663
|
+
value: amount,
|
|
2664
|
+
onChange: (e) => {
|
|
2665
|
+
setAmount(e.target.value);
|
|
2666
|
+
if (state === "error") {
|
|
2667
|
+
setState("idle");
|
|
2668
|
+
setError(null);
|
|
2669
|
+
}
|
|
2622
2670
|
},
|
|
2623
|
-
|
|
2624
|
-
|
|
2671
|
+
disabled: state === "buying",
|
|
2672
|
+
placeholder: "0.00",
|
|
2673
|
+
className: "w-full border px-3 py-2.5 pl-7 text-sm focus:outline-none disabled:opacity-50",
|
|
2674
|
+
style: {
|
|
2675
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
2676
|
+
borderColor: "var(--compass-color-border)",
|
|
2677
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
2678
|
+
color: "var(--compass-color-text)",
|
|
2679
|
+
fontFamily: "var(--compass-font-family)"
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
)
|
|
2683
|
+
] })
|
|
2684
|
+
] }),
|
|
2685
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2686
|
+
"p",
|
|
2687
|
+
{
|
|
2688
|
+
className: "text-xs",
|
|
2689
|
+
style: { color: "var(--compass-color-text-tertiary)", fontFamily: "var(--compass-font-family)" },
|
|
2690
|
+
children: "Buy crypto with card or bank transfer. Funds are sent directly to your account."
|
|
2691
|
+
}
|
|
2692
|
+
),
|
|
2693
|
+
state === "success" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2694
|
+
"div",
|
|
2695
|
+
{
|
|
2696
|
+
className: "flex items-center gap-2 p-3 text-sm",
|
|
2697
|
+
style: {
|
|
2698
|
+
backgroundColor: "var(--compass-color-success-muted, rgba(34,197,94,0.1))",
|
|
2699
|
+
color: "var(--compass-color-success)",
|
|
2700
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
2701
|
+
fontFamily: "var(--compass-font-family)"
|
|
2702
|
+
},
|
|
2703
|
+
children: [
|
|
2704
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { size: 16 }),
|
|
2705
|
+
"Purchase initiated. Funds may take a few minutes to arrive."
|
|
2706
|
+
]
|
|
2707
|
+
}
|
|
2708
|
+
),
|
|
2709
|
+
state === "error" && error && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2710
|
+
"div",
|
|
2711
|
+
{
|
|
2712
|
+
className: "flex items-center gap-2 p-3 text-sm",
|
|
2713
|
+
style: {
|
|
2714
|
+
backgroundColor: "var(--compass-color-error-muted, rgba(239,68,68,0.1))",
|
|
2715
|
+
color: "var(--compass-color-error)",
|
|
2716
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
2717
|
+
fontFamily: "var(--compass-font-family)"
|
|
2718
|
+
},
|
|
2719
|
+
children: [
|
|
2720
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { size: 16 }),
|
|
2721
|
+
error
|
|
2722
|
+
]
|
|
2723
|
+
}
|
|
2724
|
+
),
|
|
2725
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2726
|
+
"button",
|
|
2727
|
+
{
|
|
2728
|
+
onClick: handleBuy,
|
|
2729
|
+
disabled: state === "buying" || !amount || parseFloat(amount) <= 0,
|
|
2730
|
+
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",
|
|
2731
|
+
style: {
|
|
2732
|
+
backgroundColor: "var(--compass-color-primary)",
|
|
2733
|
+
color: "white",
|
|
2734
|
+
borderRadius: "var(--compass-border-radius-xl)",
|
|
2735
|
+
fontFamily: "var(--compass-font-family)",
|
|
2736
|
+
transition: "var(--compass-transition-normal)"
|
|
2737
|
+
},
|
|
2738
|
+
children: state === "buying" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2739
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
2740
|
+
"Processing..."
|
|
2741
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2742
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }),
|
|
2743
|
+
"Buy with card / bank"
|
|
2744
|
+
] })
|
|
2745
|
+
}
|
|
2746
|
+
)
|
|
2747
|
+
] });
|
|
2748
|
+
}
|
|
2749
|
+
var BLOCK_EXPLORERS = {
|
|
2750
|
+
ethereum: "https://etherscan.io",
|
|
2751
|
+
base: "https://basescan.org",
|
|
2752
|
+
arbitrum: "https://arbiscan.io"
|
|
2753
|
+
};
|
|
2754
|
+
function TxStatus({ state }) {
|
|
2755
|
+
const { chainId } = useChain();
|
|
2756
|
+
if (state.status === "idle") return null;
|
|
2757
|
+
const explorer = BLOCK_EXPLORERS[chainId] || BLOCK_EXPLORERS.ethereum;
|
|
2758
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2759
|
+
"div",
|
|
2760
|
+
{
|
|
2761
|
+
className: "mt-4 p-4 border",
|
|
2762
|
+
style: {
|
|
2763
|
+
borderColor: "var(--compass-color-border)",
|
|
2764
|
+
borderRadius: "var(--compass-border-radius-xl)",
|
|
2765
|
+
fontFamily: "var(--compass-font-family)"
|
|
2766
|
+
},
|
|
2767
|
+
children: [
|
|
2768
|
+
state.status === "preparing" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
2769
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2770
|
+
lucideReact.Loader2,
|
|
2771
|
+
{
|
|
2772
|
+
className: "h-4 w-4 animate-spin",
|
|
2773
|
+
style: { color: "var(--compass-color-primary)" }
|
|
2774
|
+
}
|
|
2775
|
+
),
|
|
2776
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Preparing transaction..." })
|
|
2777
|
+
] }),
|
|
2778
|
+
state.status === "signing" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
2779
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2780
|
+
lucideReact.Loader2,
|
|
2781
|
+
{
|
|
2782
|
+
className: "h-4 w-4 animate-spin",
|
|
2783
|
+
style: { color: "var(--compass-color-warning)" }
|
|
2784
|
+
}
|
|
2785
|
+
),
|
|
2786
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Waiting for signature..." })
|
|
2787
|
+
] }),
|
|
2788
|
+
state.status === "broadcasting" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
2789
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2790
|
+
lucideReact.Loader2,
|
|
2791
|
+
{
|
|
2792
|
+
className: "h-4 w-4 animate-spin",
|
|
2793
|
+
style: { color: "var(--compass-color-primary)" }
|
|
2794
|
+
}
|
|
2795
|
+
),
|
|
2796
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Broadcasting transaction..." })
|
|
2797
|
+
] }),
|
|
2798
|
+
state.status === "submitted" && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2799
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2800
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
2801
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2802
|
+
lucideReact.Loader2,
|
|
2803
|
+
{
|
|
2804
|
+
className: "h-4 w-4 animate-spin",
|
|
2805
|
+
style: { color: "var(--compass-color-primary)" }
|
|
2806
|
+
}
|
|
2807
|
+
),
|
|
2808
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text)" }, children: "Transaction submitted" })
|
|
2809
|
+
] }),
|
|
2810
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2811
|
+
"a",
|
|
2625
2812
|
{
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
},
|
|
2813
|
+
href: `${explorer}/tx/${state.txHash}`,
|
|
2814
|
+
target: "_blank",
|
|
2815
|
+
rel: "noopener noreferrer",
|
|
2816
|
+
className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
|
|
2817
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
2632
2818
|
children: [
|
|
2633
|
-
|
|
2634
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2635
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-medium", style: { color: "var(--compass-color-text)" }, children: formatAmount(token.balance) }),
|
|
2636
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: formatUSD(token.usdValue) })
|
|
2637
|
-
] })
|
|
2819
|
+
"View on explorer",
|
|
2820
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
|
|
2638
2821
|
]
|
|
2639
|
-
}
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2822
|
+
}
|
|
2823
|
+
)
|
|
2824
|
+
] }),
|
|
2825
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2826
|
+
"p",
|
|
2827
|
+
{
|
|
2828
|
+
className: "text-xs mt-2",
|
|
2829
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
2830
|
+
children: "Waiting for on-chain confirmation. Balances will update automatically."
|
|
2831
|
+
}
|
|
2832
|
+
)
|
|
2833
|
+
] }),
|
|
2834
|
+
state.status === "confirmed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2835
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
2652
2836
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2653
|
-
|
|
2837
|
+
lucideReact.CheckCircle,
|
|
2654
2838
|
{
|
|
2655
|
-
className: "
|
|
2656
|
-
style: { color: "var(--compass-color-
|
|
2657
|
-
children: formatUSD(totalUsdValue)
|
|
2839
|
+
className: "h-4 w-4",
|
|
2840
|
+
style: { color: "var(--compass-color-success)" }
|
|
2658
2841
|
}
|
|
2659
|
-
)
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
}
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2842
|
+
),
|
|
2843
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-success)" }, children: "Transaction confirmed" })
|
|
2844
|
+
] }),
|
|
2845
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2846
|
+
"a",
|
|
2847
|
+
{
|
|
2848
|
+
href: `${explorer}/tx/${state.txHash}`,
|
|
2849
|
+
target: "_blank",
|
|
2850
|
+
rel: "noopener noreferrer",
|
|
2851
|
+
className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
|
|
2852
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
2853
|
+
children: [
|
|
2854
|
+
"View on explorer",
|
|
2855
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
|
|
2856
|
+
]
|
|
2857
|
+
}
|
|
2858
|
+
)
|
|
2859
|
+
] }),
|
|
2860
|
+
state.status === "failed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 text-sm", children: [
|
|
2861
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2862
|
+
lucideReact.XCircle,
|
|
2863
|
+
{
|
|
2864
|
+
className: "h-4 w-4 mt-0.5 shrink-0",
|
|
2865
|
+
style: { color: "var(--compass-color-error)" }
|
|
2866
|
+
}
|
|
2867
|
+
),
|
|
2868
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2869
|
+
"span",
|
|
2870
|
+
{
|
|
2871
|
+
className: "break-all",
|
|
2872
|
+
style: { color: "var(--compass-color-error)" },
|
|
2873
|
+
children: state.error
|
|
2874
|
+
}
|
|
2875
|
+
)
|
|
2876
|
+
] })
|
|
2877
|
+
]
|
|
2878
|
+
}
|
|
2879
|
+
);
|
|
2880
|
+
}
|
|
2881
|
+
function useTxPolling(options = {}) {
|
|
2882
|
+
const { chainId } = useChain();
|
|
2883
|
+
const queryClient = reactQuery.useQueryClient();
|
|
2884
|
+
const pollIntervalRef = react.useRef(null);
|
|
2885
|
+
const clearPolling = react.useCallback(() => {
|
|
2886
|
+
if (pollIntervalRef.current) {
|
|
2887
|
+
clearInterval(pollIntervalRef.current);
|
|
2888
|
+
pollIntervalRef.current = null;
|
|
2889
|
+
}
|
|
2890
|
+
}, []);
|
|
2891
|
+
react.useEffect(() => {
|
|
2892
|
+
return () => clearPolling();
|
|
2893
|
+
}, [clearPolling]);
|
|
2894
|
+
const startPolling = react.useCallback(
|
|
2895
|
+
(txHash, setTxState) => {
|
|
2896
|
+
clearPolling();
|
|
2897
|
+
let polls = 0;
|
|
2898
|
+
pollIntervalRef.current = setInterval(async () => {
|
|
2899
|
+
polls++;
|
|
2900
|
+
for (const key of options.queryKeysToInvalidate ?? []) {
|
|
2901
|
+
queryClient.invalidateQueries({ queryKey: key });
|
|
2902
|
+
}
|
|
2903
|
+
try {
|
|
2904
|
+
const res = await fetch(
|
|
2905
|
+
`/api/compass/tx/receipt?hash=${txHash}&chain=${chainId}`
|
|
2906
|
+
);
|
|
2907
|
+
const data = await res.json();
|
|
2908
|
+
if (data.status === "success") {
|
|
2909
|
+
clearPolling();
|
|
2910
|
+
setTxState({ status: "confirmed", txHash });
|
|
2911
|
+
return;
|
|
2912
|
+
} else if (data.status === "reverted") {
|
|
2913
|
+
clearPolling();
|
|
2914
|
+
setTxState({ status: "failed", error: "Transaction reverted" });
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2917
|
+
} catch (err) {
|
|
2918
|
+
if (err instanceof TypeError && err.message.includes("fetch")) ; else {
|
|
2919
|
+
console.warn("[useTxPolling] Unexpected error polling tx receipt:", err);
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
if (polls >= 24) {
|
|
2923
|
+
clearPolling();
|
|
2924
|
+
setTxState({ status: "failed", error: "Unable to confirm transaction. Please check a block explorer to verify." });
|
|
2925
|
+
}
|
|
2926
|
+
}, 5e3);
|
|
2927
|
+
},
|
|
2928
|
+
[chainId, clearPolling, queryClient, options.queryKeysToInvalidate]
|
|
2929
|
+
);
|
|
2930
|
+
return { startPolling, clearPolling };
|
|
2931
|
+
}
|
|
2932
|
+
var USDC_ADDRESSES = {
|
|
2933
|
+
ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
2934
|
+
base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
2935
|
+
arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
|
|
2936
|
+
};
|
|
2937
|
+
var ERC20_TRANSFER_ABI = [
|
|
2938
|
+
{
|
|
2939
|
+
type: "function",
|
|
2940
|
+
name: "transfer",
|
|
2941
|
+
inputs: [
|
|
2942
|
+
{ name: "to", type: "address" },
|
|
2943
|
+
{ name: "amount", type: "uint256" }
|
|
2944
|
+
],
|
|
2945
|
+
outputs: [{ name: "", type: "bool" }],
|
|
2946
|
+
stateMutability: "nonpayable"
|
|
2947
|
+
}
|
|
2948
|
+
];
|
|
2949
|
+
async function waitForReceipt(txHash, chainId) {
|
|
2950
|
+
const maxPolls = 60;
|
|
2951
|
+
for (let i = 0; i < maxPolls; i++) {
|
|
2952
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
2953
|
+
try {
|
|
2954
|
+
const res = await fetch(`/api/compass/tx/receipt?hash=${txHash}&chain=${chainId}`);
|
|
2955
|
+
const data = await res.json();
|
|
2956
|
+
if (data.status === "success") return;
|
|
2957
|
+
if (data.status === "reverted") throw new Error("Withdrawal transaction reverted");
|
|
2958
|
+
} catch (err) {
|
|
2959
|
+
if (err instanceof Error && err.message.includes("reverted")) throw err;
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
throw new Error("Unable to confirm withdrawal. Please check a block explorer to verify.");
|
|
2963
|
+
}
|
|
2964
|
+
function SendForm({ onComplete, product = "earn", productAccountAddress }) {
|
|
2965
|
+
const { sendTransaction, signTypedData, address } = useEmbeddableWallet();
|
|
2966
|
+
const { chainId } = useChain();
|
|
2967
|
+
const { earnAccountAddress, isDeployed } = useEarnAccount();
|
|
2968
|
+
const [recipient, setRecipient] = react.useState("");
|
|
2969
|
+
const [amount, setAmount] = react.useState("");
|
|
2970
|
+
const [txState, setTxState] = react.useState({ status: "idle" });
|
|
2971
|
+
const { startPolling } = useTxPolling({
|
|
2972
|
+
queryKeysToInvalidate: product === "credit" ? [["creditBalances"], ["creditPositions"], ["eoaBalances"]] : [["earnAccountBalances"], ["eoaBalances"]]
|
|
2973
|
+
});
|
|
2974
|
+
const { data: earnBalanceData } = reactQuery.useQuery({
|
|
2975
|
+
queryKey: ["earnAccountBalances", chainId, address],
|
|
2976
|
+
queryFn: async () => {
|
|
2977
|
+
if (!address) return null;
|
|
2978
|
+
const response = await fetch(
|
|
2979
|
+
`/api/compass/earn-account/balances?owner=${address}&chain=${chainId}`
|
|
2980
|
+
);
|
|
2981
|
+
if (!response.ok) return null;
|
|
2982
|
+
return response.json();
|
|
2983
|
+
},
|
|
2984
|
+
enabled: !!address && isDeployed && product === "earn",
|
|
2985
|
+
staleTime: 30 * 1e3
|
|
2986
|
+
});
|
|
2987
|
+
const { data: creditBalanceData } = reactQuery.useQuery({
|
|
2988
|
+
queryKey: ["creditBalances", productAccountAddress, chainId],
|
|
2989
|
+
queryFn: async () => {
|
|
2990
|
+
if (!productAccountAddress) return null;
|
|
2991
|
+
const response = await fetch(
|
|
2992
|
+
`/api/compass/credit/balances?owner=${productAccountAddress}&chain=${chainId}`
|
|
2993
|
+
);
|
|
2994
|
+
if (!response.ok) return null;
|
|
2995
|
+
return response.json();
|
|
2996
|
+
},
|
|
2997
|
+
enabled: !!productAccountAddress && product === "credit",
|
|
2998
|
+
staleTime: 30 * 1e3
|
|
2999
|
+
});
|
|
3000
|
+
const availableBalance = product === "credit" ? creditBalanceData?.find((b) => b.tokenSymbol === "USDC")?.amount || "0" : earnBalanceData?.balances?.["USDC"]?.balance || "0";
|
|
3001
|
+
const tokenAddress = USDC_ADDRESSES[chainId];
|
|
3002
|
+
const isValidAddress = recipient.length > 0 && viem.isAddress(recipient);
|
|
3003
|
+
const isValidAmount = amount.length > 0 && parseFloat(amount) > 0;
|
|
3004
|
+
const exceedsBalance = isValidAmount && parseFloat(amount) > parseFloat(availableBalance);
|
|
3005
|
+
const isBusy = txState.status !== "idle" && txState.status !== "confirmed" && txState.status !== "failed";
|
|
3006
|
+
const canSend = isValidAddress && isValidAmount && !exceedsBalance && !!sendTransaction && !!signTypedData && !isBusy;
|
|
3007
|
+
const handleSend = react.useCallback(async () => {
|
|
3008
|
+
if (!sendTransaction || !signTypedData || !isValidAddress || !isValidAmount || !tokenAddress) return;
|
|
3009
|
+
try {
|
|
3010
|
+
setTxState({ status: "preparing" });
|
|
3011
|
+
const prepareRes = await fetch("/api/compass/transfer/prepare", {
|
|
3012
|
+
method: "POST",
|
|
3013
|
+
headers: { "Content-Type": "application/json" },
|
|
3014
|
+
body: JSON.stringify({
|
|
3015
|
+
owner: address,
|
|
3016
|
+
chain: chainId,
|
|
3017
|
+
token: "USDC",
|
|
3018
|
+
amount,
|
|
3019
|
+
action: "WITHDRAW",
|
|
3020
|
+
...product === "credit" ? { product: "credit" } : {}
|
|
3021
|
+
})
|
|
3022
|
+
});
|
|
3023
|
+
if (!prepareRes.ok) {
|
|
3024
|
+
const errData = await prepareRes.json();
|
|
3025
|
+
throw new Error(errData.error || "Failed to prepare withdrawal");
|
|
3026
|
+
}
|
|
3027
|
+
const prepareData = await prepareRes.json();
|
|
3028
|
+
setTxState({ status: "signing" });
|
|
3029
|
+
const withdrawSig = await signTypedData({
|
|
3030
|
+
domain: prepareData.domain,
|
|
3031
|
+
types: prepareData.normalizedTypes,
|
|
3032
|
+
primaryType: prepareData.primaryType,
|
|
3033
|
+
message: prepareData.message
|
|
3034
|
+
});
|
|
3035
|
+
setTxState({ status: "broadcasting" });
|
|
3036
|
+
const executeRes = await fetch("/api/compass/transfer/execute", {
|
|
3037
|
+
method: "POST",
|
|
3038
|
+
headers: { "Content-Type": "application/json" },
|
|
3039
|
+
body: JSON.stringify({
|
|
3040
|
+
owner: address,
|
|
3041
|
+
chain: chainId,
|
|
3042
|
+
eip712: prepareData.eip712,
|
|
3043
|
+
signature: withdrawSig,
|
|
3044
|
+
...product === "credit" ? { product: "credit" } : {}
|
|
3045
|
+
})
|
|
3046
|
+
});
|
|
3047
|
+
if (!executeRes.ok) {
|
|
3048
|
+
const errData = await executeRes.json();
|
|
3049
|
+
throw new Error(errData.error || "Withdrawal failed");
|
|
3050
|
+
}
|
|
3051
|
+
const { txHash: withdrawHash } = await executeRes.json();
|
|
3052
|
+
await waitForReceipt(withdrawHash, chainId);
|
|
3053
|
+
setTxState({ status: "signing" });
|
|
3054
|
+
const data = viem.encodeFunctionData({
|
|
3055
|
+
abi: ERC20_TRANSFER_ABI,
|
|
3056
|
+
functionName: "transfer",
|
|
3057
|
+
args: [recipient, viem.parseUnits(amount, 6)]
|
|
3058
|
+
});
|
|
3059
|
+
const sendHash = await sendTransaction({ to: tokenAddress, data });
|
|
3060
|
+
setTxState({ status: "submitted", txHash: sendHash });
|
|
3061
|
+
startPolling(sendHash, setTxState);
|
|
3062
|
+
setAmount("");
|
|
3063
|
+
setRecipient("");
|
|
3064
|
+
onComplete?.();
|
|
3065
|
+
} catch (err) {
|
|
3066
|
+
setTxState({ status: "failed", error: err instanceof Error ? err.message : "Transaction failed" });
|
|
3067
|
+
}
|
|
3068
|
+
}, [sendTransaction, signTypedData, recipient, amount, address, chainId, tokenAddress, isValidAddress, isValidAmount, onComplete, startPolling, product]);
|
|
3069
|
+
const chainName = chainId.charAt(0).toUpperCase() + chainId.slice(1);
|
|
3070
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
3071
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3072
|
+
"p",
|
|
3073
|
+
{
|
|
3074
|
+
className: "text-sm font-medium",
|
|
3075
|
+
style: { color: "var(--compass-color-text)", fontFamily: "var(--compass-font-family)" },
|
|
3076
|
+
children: [
|
|
3077
|
+
"Send USDC on ",
|
|
3078
|
+
chainName
|
|
3079
|
+
]
|
|
3080
|
+
}
|
|
3081
|
+
),
|
|
3082
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3083
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3084
|
+
"label",
|
|
3085
|
+
{
|
|
3086
|
+
className: "block text-sm mb-1.5",
|
|
3087
|
+
style: { color: "var(--compass-color-text-secondary)", fontFamily: "var(--compass-font-family)" },
|
|
3088
|
+
children: "Recipient Address"
|
|
3089
|
+
}
|
|
3090
|
+
),
|
|
3091
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3092
|
+
"input",
|
|
3093
|
+
{
|
|
3094
|
+
type: "text",
|
|
3095
|
+
value: recipient,
|
|
3096
|
+
onChange: (e) => {
|
|
3097
|
+
setRecipient(e.target.value);
|
|
3098
|
+
if (txState.status === "failed") setTxState({ status: "idle" });
|
|
3099
|
+
},
|
|
3100
|
+
disabled: isBusy,
|
|
3101
|
+
placeholder: "0x...",
|
|
3102
|
+
className: "w-full border px-3 py-2.5 text-sm focus:outline-none disabled:opacity-50 font-mono",
|
|
3103
|
+
style: {
|
|
3104
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
3105
|
+
borderColor: recipient && !isValidAddress ? "var(--compass-color-error)" : "var(--compass-color-border)",
|
|
3106
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
3107
|
+
color: "var(--compass-color-text)",
|
|
3108
|
+
fontFamily: "var(--compass-font-family)"
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
),
|
|
3112
|
+
recipient && !isValidAddress && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-error)" }, children: "Invalid Ethereum address" }),
|
|
3113
|
+
isValidAddress && recipient.toLowerCase() === address?.toLowerCase() && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-warning, #f59e0b)" }, children: "This is your own wallet address" }),
|
|
3114
|
+
isValidAddress && earnAccountAddress && recipient.toLowerCase() === earnAccountAddress.toLowerCase() && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-warning, #f59e0b)" }, children: "This is your savings account address" })
|
|
3115
|
+
] }),
|
|
3116
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3117
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3118
|
+
"label",
|
|
3119
|
+
{
|
|
3120
|
+
className: "block text-sm mb-1.5",
|
|
3121
|
+
style: { color: "var(--compass-color-text-secondary)", fontFamily: "var(--compass-font-family)" },
|
|
3122
|
+
children: "Amount"
|
|
3123
|
+
}
|
|
3124
|
+
),
|
|
3125
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
3126
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3127
|
+
"input",
|
|
3128
|
+
{
|
|
3129
|
+
type: "number",
|
|
3130
|
+
value: amount,
|
|
3131
|
+
onChange: (e) => {
|
|
3132
|
+
setAmount(e.target.value);
|
|
3133
|
+
if (txState.status === "failed") setTxState({ status: "idle" });
|
|
3134
|
+
},
|
|
3135
|
+
disabled: isBusy,
|
|
3136
|
+
placeholder: "0.00",
|
|
3137
|
+
className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
|
|
3138
|
+
style: {
|
|
3139
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
3140
|
+
borderColor: "var(--compass-color-border)",
|
|
3141
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
3142
|
+
color: "var(--compass-color-text)",
|
|
3143
|
+
fontFamily: "var(--compass-font-family)"
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
),
|
|
3147
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3148
|
+
"span",
|
|
3149
|
+
{
|
|
3150
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
|
|
3151
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
3152
|
+
children: "USDC"
|
|
3153
|
+
}
|
|
3154
|
+
)
|
|
3155
|
+
] }),
|
|
3156
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3157
|
+
"button",
|
|
3158
|
+
{
|
|
3159
|
+
onClick: () => setAmount(availableBalance),
|
|
3160
|
+
className: "text-xs mt-1",
|
|
3161
|
+
style: { color: "var(--compass-color-primary)", cursor: "pointer", background: "none", border: "none", padding: 0 },
|
|
3162
|
+
children: [
|
|
3163
|
+
"Available: ",
|
|
3164
|
+
parseFloat(availableBalance).toFixed(2),
|
|
3165
|
+
" USDC"
|
|
3166
|
+
]
|
|
3167
|
+
}
|
|
3168
|
+
),
|
|
3169
|
+
exceedsBalance && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs mt-1", style: { color: "var(--compass-color-error)" }, children: "Amount exceeds available balance" })
|
|
3170
|
+
] }),
|
|
3171
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3172
|
+
"p",
|
|
3173
|
+
{
|
|
3174
|
+
className: "text-xs",
|
|
3175
|
+
style: { color: "var(--compass-color-text-tertiary)", fontFamily: "var(--compass-font-family)" },
|
|
3176
|
+
children: "Send USDC from your account to any address. Requires 2 signatures. Gas fees are sponsored."
|
|
3177
|
+
}
|
|
3178
|
+
),
|
|
3179
|
+
/* @__PURE__ */ jsxRuntime.jsx(TxStatus, { state: txState }),
|
|
3180
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3181
|
+
"button",
|
|
3182
|
+
{
|
|
3183
|
+
onClick: handleSend,
|
|
3184
|
+
disabled: !canSend,
|
|
3185
|
+
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",
|
|
3186
|
+
style: {
|
|
3187
|
+
backgroundColor: "var(--compass-color-primary)",
|
|
3188
|
+
color: "white",
|
|
3189
|
+
borderRadius: "var(--compass-border-radius-xl)",
|
|
3190
|
+
fontFamily: "var(--compass-font-family)",
|
|
3191
|
+
transition: "var(--compass-transition-normal)"
|
|
3192
|
+
},
|
|
3193
|
+
children: isBusy ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3194
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
3195
|
+
"Sending..."
|
|
3196
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3197
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-4 w-4" }),
|
|
3198
|
+
"Send USDC"
|
|
3199
|
+
] })
|
|
3200
|
+
}
|
|
3201
|
+
)
|
|
3202
|
+
] });
|
|
3203
|
+
}
|
|
3204
|
+
function AccountBalancesModal({
|
|
3205
|
+
isOpen,
|
|
3206
|
+
onClose,
|
|
3207
|
+
balances,
|
|
3208
|
+
totalUsdValue,
|
|
3209
|
+
isLoading = false,
|
|
3210
|
+
earnAccountAddress,
|
|
3211
|
+
walletAddress
|
|
3212
|
+
}) {
|
|
3213
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ActionModal, { isOpen, onClose, title: "Balance Breakdown", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
3214
|
+
(walletAddress || earnAccountAddress) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
3215
|
+
walletAddress && /* @__PURE__ */ jsxRuntime.jsx(CopyableAddress, { address: walletAddress, label: "Wallet" }),
|
|
3216
|
+
earnAccountAddress && /* @__PURE__ */ jsxRuntime.jsx(CopyableAddress, { address: earnAccountAddress, label: "Product Account" })
|
|
3217
|
+
] }),
|
|
3218
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3219
|
+
lucideReact.Loader2,
|
|
3220
|
+
{
|
|
3221
|
+
size: 24,
|
|
3222
|
+
className: "animate-spin",
|
|
3223
|
+
style: { color: "var(--compass-color-primary)" }
|
|
3224
|
+
}
|
|
3225
|
+
) }) : balances.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3226
|
+
"div",
|
|
3227
|
+
{
|
|
3228
|
+
className: "text-center py-4",
|
|
3229
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
3230
|
+
children: "No tokens in account"
|
|
3231
|
+
}
|
|
3232
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3233
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3234
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3235
|
+
"span",
|
|
3236
|
+
{
|
|
3237
|
+
className: "text-xs font-medium uppercase tracking-wide",
|
|
3238
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
3239
|
+
children: "Available in Account"
|
|
3240
|
+
}
|
|
3241
|
+
),
|
|
3242
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3243
|
+
"div",
|
|
3244
|
+
{
|
|
3245
|
+
className: "flex flex-col gap-2",
|
|
3246
|
+
style: {
|
|
3247
|
+
maxHeight: "50vh",
|
|
3248
|
+
overflowY: "auto",
|
|
3249
|
+
scrollbarWidth: "none"
|
|
3250
|
+
},
|
|
3251
|
+
children: balances.filter((token) => parseFloat(token.balance) >= 5e-3).map((token) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3252
|
+
"div",
|
|
3253
|
+
{
|
|
3254
|
+
className: "flex items-center justify-between p-3 rounded-lg",
|
|
3255
|
+
style: {
|
|
3256
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
3257
|
+
border: "1px solid var(--compass-color-border)",
|
|
3258
|
+
flexShrink: 0
|
|
3259
|
+
},
|
|
3260
|
+
children: [
|
|
3261
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", style: { color: "var(--compass-color-text)" }, children: token.symbol }),
|
|
3262
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-end", children: [
|
|
3263
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-medium", style: { color: "var(--compass-color-text)" }, children: formatAmount(token.balance) }),
|
|
3264
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: formatUSD(token.usdValue) })
|
|
3265
|
+
] })
|
|
3266
|
+
]
|
|
3267
|
+
},
|
|
3268
|
+
token.symbol
|
|
3269
|
+
))
|
|
3270
|
+
}
|
|
3271
|
+
)
|
|
3272
|
+
] }),
|
|
3273
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3274
|
+
"div",
|
|
3275
|
+
{
|
|
3276
|
+
className: "flex items-center justify-between pt-3 mt-2",
|
|
3277
|
+
style: { borderTop: "2px solid var(--compass-color-border)" },
|
|
3278
|
+
children: [
|
|
3279
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", style: { color: "var(--compass-color-text)" }, children: "Total" }),
|
|
3280
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3281
|
+
"span",
|
|
3282
|
+
{
|
|
3283
|
+
className: "font-bold text-xl",
|
|
3284
|
+
style: { color: "var(--compass-color-text)" },
|
|
3285
|
+
children: formatUSD(totalUsdValue)
|
|
3286
|
+
}
|
|
3287
|
+
)
|
|
3288
|
+
]
|
|
3289
|
+
}
|
|
3290
|
+
)
|
|
3291
|
+
] })
|
|
3292
|
+
] }) });
|
|
3293
|
+
}
|
|
3294
|
+
var TRANSFER_TOKEN = "USDC";
|
|
3295
|
+
var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
3296
|
+
compact = false,
|
|
3297
|
+
hideVisual = false,
|
|
2670
3298
|
onTransferComplete
|
|
2671
3299
|
}, ref) {
|
|
3300
|
+
const { address, isConnected, signTypedData, switchChain, walletChainId, fundWallet, hasExternalWallet, sendTransaction } = useEmbeddableWallet();
|
|
3301
|
+
const { chainId, chain } = useChain();
|
|
3302
|
+
const { earnAccountAddress, isDeployed } = useEarnAccount();
|
|
3303
|
+
const queryClient = reactQuery.useQueryClient();
|
|
3304
|
+
const showBuyTab = !!fundWallet;
|
|
3305
|
+
const showSendTab = !!sendTransaction && !hasExternalWallet;
|
|
3306
|
+
const buyOnly = !hasExternalWallet && showBuyTab && !sendTransaction;
|
|
2672
3307
|
const [isModalOpen, setIsModalOpen] = react.useState(false);
|
|
2673
|
-
const [activeAction, setActiveAction] = react.useState(
|
|
3308
|
+
const [activeAction, setActiveAction] = react.useState(
|
|
3309
|
+
!hasExternalWallet && fundWallet ? "buy" : "deposit"
|
|
3310
|
+
);
|
|
2674
3311
|
const selectedToken = TRANSFER_TOKEN;
|
|
2675
3312
|
const [amount, setAmount] = react.useState("");
|
|
2676
|
-
const [
|
|
2677
|
-
const [statusMessage, setStatusMessage] = react.useState("");
|
|
2678
|
-
const [error, setError] = react.useState(null);
|
|
3313
|
+
const [txState, setTxState] = react.useState({ status: "idle" });
|
|
2679
3314
|
const [isBalancesModalOpen, setIsBalancesModalOpen] = react.useState(false);
|
|
2680
|
-
const {
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
const queryClient = reactQuery.useQueryClient();
|
|
3315
|
+
const { startPolling, clearPolling } = useTxPolling({
|
|
3316
|
+
queryKeysToInvalidate: [["earnAccountBalances"], ["eoaBalances"]]
|
|
3317
|
+
});
|
|
2684
3318
|
const { data: balanceData, isLoading: balancesLoading } = reactQuery.useQuery({
|
|
2685
3319
|
queryKey: ["earnAccountBalances", chainId, address],
|
|
2686
3320
|
queryFn: async () => {
|
|
@@ -2712,7 +3346,7 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2712
3346
|
}
|
|
2713
3347
|
return {};
|
|
2714
3348
|
},
|
|
2715
|
-
enabled: !!address && activeAction === "deposit",
|
|
3349
|
+
enabled: !!address && hasExternalWallet && activeAction === "deposit",
|
|
2716
3350
|
staleTime: 30 * 1e3
|
|
2717
3351
|
});
|
|
2718
3352
|
const earnBalances = balanceData?.balances || {};
|
|
@@ -2731,10 +3365,9 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2731
3365
|
}
|
|
2732
3366
|
const resetForm = react.useCallback(() => {
|
|
2733
3367
|
setAmount("");
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
}, []);
|
|
3368
|
+
setTxState({ status: "idle" });
|
|
3369
|
+
clearPolling();
|
|
3370
|
+
}, [clearPolling]);
|
|
2738
3371
|
const handleOpenModal = () => {
|
|
2739
3372
|
resetForm();
|
|
2740
3373
|
setIsModalOpen(true);
|
|
@@ -2749,7 +3382,8 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2749
3382
|
const handleActionChange = (action) => {
|
|
2750
3383
|
setActiveAction(action);
|
|
2751
3384
|
setAmount("");
|
|
2752
|
-
|
|
3385
|
+
setTxState({ status: "idle" });
|
|
3386
|
+
clearPolling();
|
|
2753
3387
|
};
|
|
2754
3388
|
const getMaxBalance = () => {
|
|
2755
3389
|
if (activeAction === "deposit") {
|
|
@@ -2759,30 +3393,26 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2759
3393
|
};
|
|
2760
3394
|
const handleTransfer = react.useCallback(async () => {
|
|
2761
3395
|
if (!address || !amount || !signTypedData) return;
|
|
2762
|
-
|
|
3396
|
+
setTxState({ status: "preparing" });
|
|
2763
3397
|
try {
|
|
2764
3398
|
const targetChainId = chain.viemChain.id;
|
|
2765
3399
|
if (walletChainId !== void 0 && walletChainId !== targetChainId) {
|
|
2766
3400
|
if (!switchChain) {
|
|
2767
3401
|
throw new Error(`Please switch your wallet to ${chain.name} (chain ID ${targetChainId}) to continue. Your wallet is currently on chain ID ${walletChainId}.`);
|
|
2768
3402
|
}
|
|
2769
|
-
setStatusMessage(`Switching network to ${chain.name}...`);
|
|
2770
3403
|
try {
|
|
2771
3404
|
await switchChain(targetChainId);
|
|
2772
|
-
} catch
|
|
3405
|
+
} catch {
|
|
2773
3406
|
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}.`);
|
|
2774
3407
|
}
|
|
2775
3408
|
} else if (switchChain && walletChainId === void 0) {
|
|
2776
|
-
setStatusMessage("Switching network...");
|
|
2777
3409
|
try {
|
|
2778
3410
|
await switchChain(targetChainId);
|
|
2779
|
-
} catch
|
|
3411
|
+
} catch {
|
|
2780
3412
|
throw new Error(`Please switch your wallet to ${chain.name} to continue`);
|
|
2781
3413
|
}
|
|
2782
3414
|
}
|
|
2783
3415
|
if (activeAction === "deposit") {
|
|
2784
|
-
setTransferState("checking_approval");
|
|
2785
|
-
setStatusMessage("Checking token approval...");
|
|
2786
3416
|
const approveResponse = await fetch("/api/compass/transfer/approve", {
|
|
2787
3417
|
method: "POST",
|
|
2788
3418
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2801,16 +3431,14 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2801
3431
|
if (approvalData.requiresTransaction) {
|
|
2802
3432
|
throw new Error("This token requires a transaction-based approval. Please approve manually.");
|
|
2803
3433
|
}
|
|
2804
|
-
|
|
2805
|
-
setStatusMessage("Please sign the approval...");
|
|
3434
|
+
setTxState({ status: "signing" });
|
|
2806
3435
|
const approvalSignature = await signTypedData({
|
|
2807
3436
|
domain: approvalData.domain,
|
|
2808
3437
|
types: approvalData.normalizedTypes,
|
|
2809
3438
|
primaryType: "Permit",
|
|
2810
3439
|
message: approvalData.message
|
|
2811
3440
|
});
|
|
2812
|
-
|
|
2813
|
-
setStatusMessage("Executing approval...");
|
|
3441
|
+
setTxState({ status: "broadcasting" });
|
|
2814
3442
|
const executeApprovalResponse = await fetch("/api/compass/transfer/execute", {
|
|
2815
3443
|
method: "POST",
|
|
2816
3444
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2827,8 +3455,7 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2827
3455
|
}
|
|
2828
3456
|
}
|
|
2829
3457
|
}
|
|
2830
|
-
|
|
2831
|
-
setStatusMessage("Preparing transfer...");
|
|
3458
|
+
setTxState({ status: "signing" });
|
|
2832
3459
|
const prepareResponse = await fetch("/api/compass/transfer/prepare", {
|
|
2833
3460
|
method: "POST",
|
|
2834
3461
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2845,15 +3472,13 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2845
3472
|
throw new Error(errData.error || "Failed to prepare transfer");
|
|
2846
3473
|
}
|
|
2847
3474
|
const prepareData = await prepareResponse.json();
|
|
2848
|
-
setStatusMessage("Please sign the transfer...");
|
|
2849
3475
|
const transferSignature = await signTypedData({
|
|
2850
3476
|
domain: prepareData.domain,
|
|
2851
3477
|
types: prepareData.normalizedTypes,
|
|
2852
3478
|
primaryType: prepareData.primaryType,
|
|
2853
3479
|
message: prepareData.message
|
|
2854
3480
|
});
|
|
2855
|
-
|
|
2856
|
-
setStatusMessage("Executing transfer...");
|
|
3481
|
+
setTxState({ status: "broadcasting" });
|
|
2857
3482
|
const executeResponse = await fetch("/api/compass/transfer/execute", {
|
|
2858
3483
|
method: "POST",
|
|
2859
3484
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2869,17 +3494,12 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2869
3494
|
throw new Error(errData.error || "Transfer failed");
|
|
2870
3495
|
}
|
|
2871
3496
|
const { txHash } = await executeResponse.json();
|
|
2872
|
-
|
|
2873
|
-
|
|
3497
|
+
setTxState({ status: "submitted", txHash });
|
|
3498
|
+
startPolling(txHash, setTxState);
|
|
2874
3499
|
onTransferComplete?.(activeAction, selectedToken, amount, txHash);
|
|
2875
|
-
|
|
2876
|
-
queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
|
|
2877
|
-
setTimeout(() => {
|
|
2878
|
-
resetForm();
|
|
2879
|
-
}, 2e3);
|
|
3500
|
+
setAmount("");
|
|
2880
3501
|
} catch (err) {
|
|
2881
|
-
|
|
2882
|
-
setError(err instanceof Error ? err.message : "Transfer failed");
|
|
3502
|
+
setTxState({ status: "failed", error: err instanceof Error ? err.message : "Transfer failed" });
|
|
2883
3503
|
}
|
|
2884
3504
|
}, [
|
|
2885
3505
|
address,
|
|
@@ -2891,14 +3511,13 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2891
3511
|
walletChainId,
|
|
2892
3512
|
signTypedData,
|
|
2893
3513
|
switchChain,
|
|
2894
|
-
queryClient,
|
|
2895
3514
|
onTransferComplete,
|
|
2896
|
-
|
|
3515
|
+
startPolling
|
|
2897
3516
|
]);
|
|
2898
3517
|
if (!isConnected) {
|
|
2899
3518
|
return null;
|
|
2900
3519
|
}
|
|
2901
|
-
const isProcessing =
|
|
3520
|
+
const isProcessing = txState.status !== "idle" && txState.status !== "confirmed" && txState.status !== "failed";
|
|
2902
3521
|
if (!isDeployed && !hideVisual) {
|
|
2903
3522
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2904
3523
|
"div",
|
|
@@ -2982,9 +3601,9 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2982
3601
|
{
|
|
2983
3602
|
isOpen: isModalOpen,
|
|
2984
3603
|
onClose: handleCloseModal,
|
|
2985
|
-
title: "Transfer Funds",
|
|
3604
|
+
title: showSendTab ? "Manage Funds" : buyOnly ? "Add Funds" : "Transfer Funds",
|
|
2986
3605
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
2987
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3606
|
+
buyOnly ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2988
3607
|
"div",
|
|
2989
3608
|
{
|
|
2990
3609
|
className: "flex gap-1 p-1",
|
|
@@ -2993,7 +3612,9 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
2993
3612
|
borderRadius: "var(--compass-border-radius-lg)",
|
|
2994
3613
|
fontFamily: "var(--compass-font-family)"
|
|
2995
3614
|
},
|
|
2996
|
-
children: [
|
|
3615
|
+
children: [
|
|
3616
|
+
...showSendTab ? ["buy", "send"] : ["deposit", "withdraw", ...showBuyTab ? ["buy"] : []]
|
|
3617
|
+
].map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2997
3618
|
"button",
|
|
2998
3619
|
{
|
|
2999
3620
|
onClick: () => handleActionChange(action),
|
|
@@ -3005,7 +3626,7 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
3005
3626
|
borderRadius: "var(--compass-border-radius-md)"
|
|
3006
3627
|
},
|
|
3007
3628
|
children: [
|
|
3008
|
-
action === "deposit" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 14 }),
|
|
3629
|
+
action === "deposit" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 14 }) : action === "withdraw" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 14 }) : action === "send" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { size: 14 }),
|
|
3009
3630
|
action
|
|
3010
3631
|
]
|
|
3011
3632
|
},
|
|
@@ -3013,120 +3634,116 @@ var EarnAccountBalance = react.forwardRef(function EarnAccountBalance2({
|
|
|
3013
3634
|
))
|
|
3014
3635
|
}
|
|
3015
3636
|
),
|
|
3016
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
{
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
children: "Amount"
|
|
3637
|
+
activeAction === "send" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3638
|
+
SendForm,
|
|
3639
|
+
{
|
|
3640
|
+
onComplete: () => {
|
|
3641
|
+
queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
|
|
3642
|
+
queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
|
|
3023
3643
|
}
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3644
|
+
}
|
|
3645
|
+
) : activeAction === "buy" || buyOnly ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3646
|
+
BuyForm,
|
|
3647
|
+
{
|
|
3648
|
+
targetAddress: earnAccountAddress || "",
|
|
3649
|
+
onComplete: () => {
|
|
3650
|
+
queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
|
|
3651
|
+
queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3655
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3656
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3657
|
+
"label",
|
|
3658
|
+
{
|
|
3659
|
+
className: "text-sm font-medium mb-1 block",
|
|
3660
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
3661
|
+
children: "Amount"
|
|
3662
|
+
}
|
|
3663
|
+
),
|
|
3664
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3665
|
+
"div",
|
|
3666
|
+
{
|
|
3667
|
+
className: "flex items-center gap-2 p-3 border",
|
|
3668
|
+
style: {
|
|
3669
|
+
backgroundColor: "var(--compass-color-background)",
|
|
3670
|
+
borderColor: "var(--compass-color-border)",
|
|
3671
|
+
borderRadius: "var(--compass-border-radius-lg)"
|
|
3672
|
+
},
|
|
3673
|
+
children: [
|
|
3674
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3675
|
+
"input",
|
|
3676
|
+
{
|
|
3677
|
+
type: "number",
|
|
3678
|
+
value: amount,
|
|
3679
|
+
onChange: (e) => {
|
|
3680
|
+
setAmount(e.target.value);
|
|
3681
|
+
if (txState.status === "failed") setTxState({ status: "idle" });
|
|
3682
|
+
},
|
|
3683
|
+
placeholder: "0.00",
|
|
3684
|
+
disabled: isProcessing,
|
|
3685
|
+
className: "flex-1 bg-transparent outline-none text-lg font-mono",
|
|
3686
|
+
style: { color: "var(--compass-color-text)" }
|
|
3687
|
+
}
|
|
3688
|
+
),
|
|
3689
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3690
|
+
"span",
|
|
3691
|
+
{
|
|
3692
|
+
className: "text-sm font-medium",
|
|
3693
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
3694
|
+
children: "USDC"
|
|
3695
|
+
}
|
|
3696
|
+
)
|
|
3697
|
+
]
|
|
3698
|
+
}
|
|
3699
|
+
),
|
|
3700
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3701
|
+
"button",
|
|
3702
|
+
{
|
|
3703
|
+
onClick: () => setAmount(formatAmount(getMaxBalance())),
|
|
3704
|
+
className: "text-xs mt-1",
|
|
3705
|
+
style: { color: "var(--compass-color-primary)", cursor: "pointer", background: "none", border: "none", padding: 0 },
|
|
3706
|
+
children: [
|
|
3707
|
+
"Available: ",
|
|
3708
|
+
formatAmount(getMaxBalance()),
|
|
3709
|
+
" USDC"
|
|
3710
|
+
]
|
|
3711
|
+
}
|
|
3712
|
+
)
|
|
3713
|
+
] }),
|
|
3714
|
+
/* @__PURE__ */ jsxRuntime.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." : ""}` }),
|
|
3715
|
+
/* @__PURE__ */ jsxRuntime.jsx(TxStatus, { state: txState }),
|
|
3716
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3717
|
+
"button",
|
|
3027
3718
|
{
|
|
3028
|
-
|
|
3719
|
+
onClick: handleTransfer,
|
|
3720
|
+
disabled: isProcessing || !amount || parseFloat(amount) <= 0,
|
|
3721
|
+
className: "w-full py-3 font-medium transition-colors flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
3029
3722
|
style: {
|
|
3030
|
-
backgroundColor: "var(--compass-color-
|
|
3031
|
-
|
|
3032
|
-
borderRadius: "var(--compass-border-radius-lg)"
|
|
3723
|
+
backgroundColor: "var(--compass-color-primary)",
|
|
3724
|
+
color: "var(--compass-color-primary-text)",
|
|
3725
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
3726
|
+
fontFamily: "var(--compass-font-family)"
|
|
3033
3727
|
},
|
|
3034
|
-
children: [
|
|
3035
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
setError(null);
|
|
3043
|
-
},
|
|
3044
|
-
placeholder: "0.00",
|
|
3045
|
-
disabled: isProcessing,
|
|
3046
|
-
className: "flex-1 bg-transparent outline-none text-lg font-mono",
|
|
3047
|
-
style: { color: "var(--compass-color-text)" }
|
|
3048
|
-
}
|
|
3049
|
-
),
|
|
3050
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3051
|
-
"span",
|
|
3052
|
-
{
|
|
3053
|
-
className: "text-sm font-medium",
|
|
3054
|
-
style: { color: "var(--compass-color-text-secondary)" },
|
|
3055
|
-
children: "USDC"
|
|
3056
|
-
}
|
|
3057
|
-
)
|
|
3058
|
-
]
|
|
3728
|
+
children: isProcessing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3729
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 18, className: "animate-spin" }),
|
|
3730
|
+
" Processing..."
|
|
3731
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3732
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 16 }),
|
|
3733
|
+
" ",
|
|
3734
|
+
activeAction === "deposit" ? "Transfer to Savings Account" : "Withdraw to Wallet"
|
|
3735
|
+
] })
|
|
3059
3736
|
}
|
|
3060
|
-
),
|
|
3061
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3062
|
-
"
|
|
3737
|
+
),
|
|
3738
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3739
|
+
"p",
|
|
3063
3740
|
{
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
children: [
|
|
3068
|
-
"Available: ",
|
|
3069
|
-
formatAmount(getMaxBalance()),
|
|
3070
|
-
" USDC"
|
|
3071
|
-
]
|
|
3741
|
+
className: "text-xs text-center",
|
|
3742
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
3743
|
+
children: "Gas fees are sponsored by Compass"
|
|
3072
3744
|
}
|
|
3073
3745
|
)
|
|
3074
|
-
] })
|
|
3075
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: activeAction === "deposit" ? "Approves the token transfer, then transfers USDC from your wallet into your savings account. Requires 2 signatures." : "Withdraws USDC from your savings account back to your wallet. Requires 1 signature." }),
|
|
3076
|
-
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3077
|
-
"div",
|
|
3078
|
-
{
|
|
3079
|
-
className: "p-3 text-sm",
|
|
3080
|
-
style: {
|
|
3081
|
-
backgroundColor: "var(--compass-color-error-muted)",
|
|
3082
|
-
color: "var(--compass-color-error)",
|
|
3083
|
-
borderRadius: "var(--compass-border-radius-lg)"
|
|
3084
|
-
},
|
|
3085
|
-
children: error
|
|
3086
|
-
}
|
|
3087
|
-
),
|
|
3088
|
-
statusMessage && !error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3089
|
-
"div",
|
|
3090
|
-
{
|
|
3091
|
-
className: "p-3 text-sm text-center",
|
|
3092
|
-
style: {
|
|
3093
|
-
backgroundColor: transferState === "success" ? "var(--compass-color-success-muted)" : "var(--compass-color-primary-muted)",
|
|
3094
|
-
color: transferState === "success" ? "var(--compass-color-success)" : "var(--compass-color-primary)",
|
|
3095
|
-
borderRadius: "var(--compass-border-radius-lg)"
|
|
3096
|
-
},
|
|
3097
|
-
children: statusMessage
|
|
3098
|
-
}
|
|
3099
|
-
),
|
|
3100
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3101
|
-
"button",
|
|
3102
|
-
{
|
|
3103
|
-
onClick: handleTransfer,
|
|
3104
|
-
disabled: isProcessing || !amount || parseFloat(amount) <= 0,
|
|
3105
|
-
className: "w-full py-3 font-medium transition-colors flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
3106
|
-
style: {
|
|
3107
|
-
backgroundColor: "var(--compass-color-primary)",
|
|
3108
|
-
color: "var(--compass-color-primary-text)",
|
|
3109
|
-
borderRadius: "var(--compass-border-radius-lg)",
|
|
3110
|
-
fontFamily: "var(--compass-font-family)"
|
|
3111
|
-
},
|
|
3112
|
-
children: isProcessing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3113
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 18, className: "animate-spin" }),
|
|
3114
|
-
" Processing..."
|
|
3115
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3116
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 16 }),
|
|
3117
|
-
" ",
|
|
3118
|
-
activeAction === "deposit" ? "Transfer to Savings Account" : "Withdraw to Wallet"
|
|
3119
|
-
] })
|
|
3120
|
-
}
|
|
3121
|
-
),
|
|
3122
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3123
|
-
"p",
|
|
3124
|
-
{
|
|
3125
|
-
className: "text-xs text-center",
|
|
3126
|
-
style: { color: "var(--compass-color-text-tertiary)" },
|
|
3127
|
-
children: "Gas fees are sponsored by Compass"
|
|
3128
|
-
}
|
|
3129
|
-
)
|
|
3746
|
+
] })
|
|
3130
3747
|
] })
|
|
3131
3748
|
}
|
|
3132
3749
|
)
|
|
@@ -3181,7 +3798,7 @@ function truncate(value, decimals) {
|
|
|
3181
3798
|
const factor = Math.pow(10, decimals);
|
|
3182
3799
|
return (Math.floor(value * factor) / factor).toFixed(decimals);
|
|
3183
3800
|
}
|
|
3184
|
-
var
|
|
3801
|
+
var BLOCK_EXPLORERS2 = {
|
|
3185
3802
|
ethereum: "https://etherscan.io",
|
|
3186
3803
|
base: "https://basescan.org",
|
|
3187
3804
|
arbitrum: "https://arbiscan.io"
|
|
@@ -3652,7 +4269,7 @@ function SwapForm({
|
|
|
3652
4269
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3653
4270
|
"a",
|
|
3654
4271
|
{
|
|
3655
|
-
href: `${
|
|
4272
|
+
href: `${BLOCK_EXPLORERS2[chainId] || BLOCK_EXPLORERS2.ethereum}/tx/${lastTxHash}`,
|
|
3656
4273
|
target: "_blank",
|
|
3657
4274
|
rel: "noopener noreferrer",
|
|
3658
4275
|
style: { display: "flex", alignItems: "center", gap: "4px", color: "var(--compass-color-text-secondary)", fontSize: "0.75rem", textDecoration: "none" },
|
|
@@ -3842,8 +4459,7 @@ function MarketSelector({
|
|
|
3842
4459
|
},
|
|
3843
4460
|
children: [
|
|
3844
4461
|
getTypeLabel(selectedMarket.type),
|
|
3845
|
-
" \xB7 "
|
|
3846
|
-
formatTvl(selectedMarket.tvl)
|
|
4462
|
+
selectedMarket.type !== "aave" ? ` \xB7 ${formatTvl(selectedMarket.tvl)}` : ""
|
|
3847
4463
|
]
|
|
3848
4464
|
}
|
|
3849
4465
|
)
|
|
@@ -3949,8 +4565,7 @@ function MarketSelector({
|
|
|
3949
4565
|
},
|
|
3950
4566
|
children: [
|
|
3951
4567
|
getTypeLabel(market.type),
|
|
3952
|
-
" \xB7 "
|
|
3953
|
-
formatTvl(market.tvl)
|
|
4568
|
+
market.type !== "aave" ? ` \xB7 ${formatTvl(market.tvl)}` : ""
|
|
3954
4569
|
]
|
|
3955
4570
|
}
|
|
3956
4571
|
)
|
|
@@ -3979,7 +4594,7 @@ function MarketSelector({
|
|
|
3979
4594
|
)
|
|
3980
4595
|
] });
|
|
3981
4596
|
}
|
|
3982
|
-
var
|
|
4597
|
+
var BLOCK_EXPLORERS3 = {
|
|
3983
4598
|
ethereum: "https://etherscan.io",
|
|
3984
4599
|
base: "https://basescan.org",
|
|
3985
4600
|
arbitrum: "https://arbiscan.io"
|
|
@@ -4141,7 +4756,7 @@ function PositionCard({ position, chainId }) {
|
|
|
4141
4756
|
tx.txHash && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4142
4757
|
"a",
|
|
4143
4758
|
{
|
|
4144
|
-
href: `${
|
|
4759
|
+
href: `${BLOCK_EXPLORERS3[chainId || "ethereum"] || BLOCK_EXPLORERS3.ethereum}/tx/${tx.txHash}`,
|
|
4145
4760
|
target: "_blank",
|
|
4146
4761
|
rel: "noopener noreferrer",
|
|
4147
4762
|
style: { color: "var(--compass-color-text-tertiary)", lineHeight: 0 },
|
|
@@ -4216,220 +4831,88 @@ function EarningsModal({ isOpen, onClose, positions, totalEarned, isLoading, cha
|
|
|
4216
4831
|
padding: "6px",
|
|
4217
4832
|
color: "var(--compass-color-text-secondary)",
|
|
4218
4833
|
borderRadius: "8px",
|
|
4219
|
-
display: "flex",
|
|
4220
|
-
alignItems: "center",
|
|
4221
|
-
justifyContent: "center"
|
|
4222
|
-
},
|
|
4223
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16 })
|
|
4224
|
-
}
|
|
4225
|
-
)
|
|
4226
|
-
] }),
|
|
4227
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
4228
|
-
padding: "16px 20px",
|
|
4229
|
-
margin: "0 16px",
|
|
4230
|
-
backgroundColor: "var(--compass-color-surface)",
|
|
4231
|
-
borderRadius: "14px"
|
|
4232
|
-
}, children: [
|
|
4233
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
4234
|
-
display: "flex",
|
|
4235
|
-
alignItems: "center",
|
|
4236
|
-
gap: "8px",
|
|
4237
|
-
marginBottom: "8px"
|
|
4238
|
-
}, children: [
|
|
4239
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
4240
|
-
width: "28px",
|
|
4241
|
-
height: "28px",
|
|
4242
|
-
borderRadius: "50%",
|
|
4243
|
-
backgroundColor: totalEarned >= 0 ? "var(--compass-color-success-muted)" : "var(--compass-color-error-muted)",
|
|
4244
|
-
display: "flex",
|
|
4245
|
-
alignItems: "center",
|
|
4246
|
-
justifyContent: "center"
|
|
4247
|
-
}, children: totalEarned >= 0 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { size: 14, style: { color: "var(--compass-color-success)" } }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { size: 14, style: { color: "var(--compass-color-error)" } }) }),
|
|
4248
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4249
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.6875rem", color: "var(--compass-color-text-tertiary)" }, children: "Total P&L" }),
|
|
4250
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
4251
|
-
fontSize: "1.25rem",
|
|
4252
|
-
fontWeight: 700,
|
|
4253
|
-
color: totalEarned >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)",
|
|
4254
|
-
letterSpacing: "-0.02em"
|
|
4255
|
-
}, children: [
|
|
4256
|
-
totalEarned >= 0 ? "+" : "",
|
|
4257
|
-
formatCurrency(totalEarned)
|
|
4258
|
-
] })
|
|
4259
|
-
] })
|
|
4260
|
-
] }),
|
|
4261
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "16px" }, children: [
|
|
4262
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4263
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.6875rem", color: "var(--compass-color-text-tertiary)" }, children: "Unrealised " }),
|
|
4264
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
|
|
4265
|
-
fontSize: "0.8125rem",
|
|
4266
|
-
fontWeight: 600,
|
|
4267
|
-
color: totalUnrealized >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)"
|
|
4268
|
-
}, children: [
|
|
4269
|
-
totalUnrealized >= 0 ? "+" : "",
|
|
4270
|
-
formatCurrency(totalUnrealized)
|
|
4271
|
-
] })
|
|
4272
|
-
] }),
|
|
4273
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4274
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.6875rem", color: "var(--compass-color-text-tertiary)" }, children: "Realised " }),
|
|
4275
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
|
|
4276
|
-
fontSize: "0.8125rem",
|
|
4277
|
-
fontWeight: 600,
|
|
4278
|
-
color: totalRealized >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)"
|
|
4279
|
-
}, children: [
|
|
4280
|
-
totalRealized >= 0 ? "+" : "",
|
|
4281
|
-
formatCurrency(totalRealized)
|
|
4282
|
-
] })
|
|
4283
|
-
] })
|
|
4284
|
-
] })
|
|
4285
|
-
] }),
|
|
4286
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
4287
|
-
flex: 1,
|
|
4288
|
-
overflowY: "auto",
|
|
4289
|
-
scrollbarWidth: "none",
|
|
4290
|
-
padding: "16px",
|
|
4291
|
-
display: "flex",
|
|
4292
|
-
flexDirection: "column",
|
|
4293
|
-
gap: "10px"
|
|
4294
|
-
}, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "32px 0", color: "var(--compass-color-text-tertiary)", fontSize: "0.875rem" }, children: "Loading positions..." }) : positions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "32px 0" }, children: [
|
|
4295
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--compass-color-text-secondary)", fontSize: "0.9375rem", margin: "0 0 4px" }, children: "No active positions yet" }),
|
|
4296
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--compass-color-text-tertiary)", fontSize: "0.8125rem", margin: 0 }, children: "Deposit into a market to start earning" })
|
|
4297
|
-
] }) : positions.map((position) => /* @__PURE__ */ jsxRuntime.jsx(PositionCard, { position, chainId }, position.id)) })
|
|
4298
|
-
]
|
|
4299
|
-
}
|
|
4300
|
-
)
|
|
4301
|
-
}
|
|
4302
|
-
);
|
|
4303
|
-
}
|
|
4304
|
-
var BLOCK_EXPLORERS3 = {
|
|
4305
|
-
ethereum: "https://etherscan.io",
|
|
4306
|
-
base: "https://basescan.org",
|
|
4307
|
-
arbitrum: "https://arbiscan.io"
|
|
4308
|
-
};
|
|
4309
|
-
function TxStatus({ state }) {
|
|
4310
|
-
const { chainId } = useChain();
|
|
4311
|
-
if (state.status === "idle") return null;
|
|
4312
|
-
const explorer = BLOCK_EXPLORERS3[chainId] || BLOCK_EXPLORERS3.ethereum;
|
|
4313
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4314
|
-
"div",
|
|
4315
|
-
{
|
|
4316
|
-
className: "mt-4 p-4 border",
|
|
4317
|
-
style: {
|
|
4318
|
-
borderColor: "var(--compass-color-border)",
|
|
4319
|
-
borderRadius: "var(--compass-border-radius-xl)",
|
|
4320
|
-
fontFamily: "var(--compass-font-family)"
|
|
4321
|
-
},
|
|
4322
|
-
children: [
|
|
4323
|
-
state.status === "preparing" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
4324
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4325
|
-
lucideReact.Loader2,
|
|
4326
|
-
{
|
|
4327
|
-
className: "h-4 w-4 animate-spin",
|
|
4328
|
-
style: { color: "var(--compass-color-primary)" }
|
|
4329
|
-
}
|
|
4330
|
-
),
|
|
4331
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Preparing transaction..." })
|
|
4332
|
-
] }),
|
|
4333
|
-
state.status === "signing" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
4334
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4335
|
-
lucideReact.Loader2,
|
|
4336
|
-
{
|
|
4337
|
-
className: "h-4 w-4 animate-spin",
|
|
4338
|
-
style: { color: "var(--compass-color-warning)" }
|
|
4339
|
-
}
|
|
4340
|
-
),
|
|
4341
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Waiting for signature..." })
|
|
4342
|
-
] }),
|
|
4343
|
-
state.status === "broadcasting" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
4344
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4345
|
-
lucideReact.Loader2,
|
|
4346
|
-
{
|
|
4347
|
-
className: "h-4 w-4 animate-spin",
|
|
4348
|
-
style: { color: "var(--compass-color-primary)" }
|
|
4349
|
-
}
|
|
4350
|
-
),
|
|
4351
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Broadcasting transaction..." })
|
|
4352
|
-
] }),
|
|
4353
|
-
state.status === "submitted" && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4354
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
4355
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
4356
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4357
|
-
lucideReact.Loader2,
|
|
4358
|
-
{
|
|
4359
|
-
className: "h-4 w-4 animate-spin",
|
|
4360
|
-
style: { color: "var(--compass-color-primary)" }
|
|
4361
|
-
}
|
|
4362
|
-
),
|
|
4363
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text)" }, children: "Transaction submitted" })
|
|
4364
|
-
] }),
|
|
4365
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4366
|
-
"a",
|
|
4367
|
-
{
|
|
4368
|
-
href: `${explorer}/tx/${state.txHash}`,
|
|
4369
|
-
target: "_blank",
|
|
4370
|
-
rel: "noopener noreferrer",
|
|
4371
|
-
className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
|
|
4372
|
-
style: { color: "var(--compass-color-text-secondary)" },
|
|
4373
|
-
children: [
|
|
4374
|
-
"View on explorer",
|
|
4375
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
|
|
4376
|
-
]
|
|
4377
|
-
}
|
|
4378
|
-
)
|
|
4379
|
-
] }),
|
|
4380
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4381
|
-
"p",
|
|
4382
|
-
{
|
|
4383
|
-
className: "text-xs mt-2",
|
|
4384
|
-
style: { color: "var(--compass-color-text-tertiary)" },
|
|
4385
|
-
children: "Waiting for on-chain confirmation. Balances will update automatically."
|
|
4386
|
-
}
|
|
4387
|
-
)
|
|
4388
|
-
] }),
|
|
4389
|
-
state.status === "confirmed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
4390
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
4391
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4392
|
-
lucideReact.CheckCircle,
|
|
4393
|
-
{
|
|
4394
|
-
className: "h-4 w-4",
|
|
4395
|
-
style: { color: "var(--compass-color-success)" }
|
|
4396
|
-
}
|
|
4397
|
-
),
|
|
4398
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-success)" }, children: "Transaction confirmed" })
|
|
4399
|
-
] }),
|
|
4400
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4401
|
-
"a",
|
|
4402
|
-
{
|
|
4403
|
-
href: `${explorer}/tx/${state.txHash}`,
|
|
4404
|
-
target: "_blank",
|
|
4405
|
-
rel: "noopener noreferrer",
|
|
4406
|
-
className: "flex items-center gap-1.5 text-xs hover:opacity-70 transition-opacity",
|
|
4407
|
-
style: { color: "var(--compass-color-text-secondary)" },
|
|
4408
|
-
children: [
|
|
4409
|
-
"View on explorer",
|
|
4410
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
|
|
4411
|
-
]
|
|
4412
|
-
}
|
|
4413
|
-
)
|
|
4414
|
-
] }),
|
|
4415
|
-
state.status === "failed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 text-sm", children: [
|
|
4416
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4417
|
-
lucideReact.XCircle,
|
|
4418
|
-
{
|
|
4419
|
-
className: "h-4 w-4 mt-0.5 shrink-0",
|
|
4420
|
-
style: { color: "var(--compass-color-error)" }
|
|
4421
|
-
}
|
|
4422
|
-
),
|
|
4423
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4424
|
-
"span",
|
|
4425
|
-
{
|
|
4426
|
-
className: "break-all",
|
|
4427
|
-
style: { color: "var(--compass-color-error)" },
|
|
4428
|
-
children: state.error
|
|
4429
|
-
}
|
|
4430
|
-
)
|
|
4431
|
-
] })
|
|
4432
|
-
]
|
|
4834
|
+
display: "flex",
|
|
4835
|
+
alignItems: "center",
|
|
4836
|
+
justifyContent: "center"
|
|
4837
|
+
},
|
|
4838
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16 })
|
|
4839
|
+
}
|
|
4840
|
+
)
|
|
4841
|
+
] }),
|
|
4842
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
4843
|
+
padding: "16px 20px",
|
|
4844
|
+
margin: "0 16px",
|
|
4845
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
4846
|
+
borderRadius: "14px"
|
|
4847
|
+
}, children: [
|
|
4848
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
4849
|
+
display: "flex",
|
|
4850
|
+
alignItems: "center",
|
|
4851
|
+
gap: "8px",
|
|
4852
|
+
marginBottom: "8px"
|
|
4853
|
+
}, children: [
|
|
4854
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
4855
|
+
width: "28px",
|
|
4856
|
+
height: "28px",
|
|
4857
|
+
borderRadius: "50%",
|
|
4858
|
+
backgroundColor: totalEarned >= 0 ? "var(--compass-color-success-muted)" : "var(--compass-color-error-muted)",
|
|
4859
|
+
display: "flex",
|
|
4860
|
+
alignItems: "center",
|
|
4861
|
+
justifyContent: "center"
|
|
4862
|
+
}, children: totalEarned >= 0 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { size: 14, style: { color: "var(--compass-color-success)" } }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { size: 14, style: { color: "var(--compass-color-error)" } }) }),
|
|
4863
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4864
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.6875rem", color: "var(--compass-color-text-tertiary)" }, children: "Total P&L" }),
|
|
4865
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
4866
|
+
fontSize: "1.25rem",
|
|
4867
|
+
fontWeight: 700,
|
|
4868
|
+
color: totalEarned >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)",
|
|
4869
|
+
letterSpacing: "-0.02em"
|
|
4870
|
+
}, children: [
|
|
4871
|
+
totalEarned >= 0 ? "+" : "",
|
|
4872
|
+
formatCurrency(totalEarned)
|
|
4873
|
+
] })
|
|
4874
|
+
] })
|
|
4875
|
+
] }),
|
|
4876
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "16px" }, children: [
|
|
4877
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4878
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.6875rem", color: "var(--compass-color-text-tertiary)" }, children: "Unrealised " }),
|
|
4879
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
|
|
4880
|
+
fontSize: "0.8125rem",
|
|
4881
|
+
fontWeight: 600,
|
|
4882
|
+
color: totalUnrealized >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)"
|
|
4883
|
+
}, children: [
|
|
4884
|
+
totalUnrealized >= 0 ? "+" : "",
|
|
4885
|
+
formatCurrency(totalUnrealized)
|
|
4886
|
+
] })
|
|
4887
|
+
] }),
|
|
4888
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4889
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.6875rem", color: "var(--compass-color-text-tertiary)" }, children: "Realised " }),
|
|
4890
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
|
|
4891
|
+
fontSize: "0.8125rem",
|
|
4892
|
+
fontWeight: 600,
|
|
4893
|
+
color: totalRealized >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)"
|
|
4894
|
+
}, children: [
|
|
4895
|
+
totalRealized >= 0 ? "+" : "",
|
|
4896
|
+
formatCurrency(totalRealized)
|
|
4897
|
+
] })
|
|
4898
|
+
] })
|
|
4899
|
+
] })
|
|
4900
|
+
] }),
|
|
4901
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
4902
|
+
flex: 1,
|
|
4903
|
+
overflowY: "auto",
|
|
4904
|
+
scrollbarWidth: "none",
|
|
4905
|
+
padding: "16px",
|
|
4906
|
+
display: "flex",
|
|
4907
|
+
flexDirection: "column",
|
|
4908
|
+
gap: "10px"
|
|
4909
|
+
}, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "32px 0", color: "var(--compass-color-text-tertiary)", fontSize: "0.875rem" }, children: "Loading positions..." }) : positions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "32px 0" }, children: [
|
|
4910
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--compass-color-text-secondary)", fontSize: "0.9375rem", margin: "0 0 4px" }, children: "No active positions yet" }),
|
|
4911
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--compass-color-text-tertiary)", fontSize: "0.8125rem", margin: 0 }, children: "Deposit into a market to start earning" })
|
|
4912
|
+
] }) : positions.map((position) => /* @__PURE__ */ jsxRuntime.jsx(PositionCard, { position, chainId }, position.id)) })
|
|
4913
|
+
]
|
|
4914
|
+
}
|
|
4915
|
+
)
|
|
4433
4916
|
}
|
|
4434
4917
|
);
|
|
4435
4918
|
}
|
|
@@ -4437,7 +4920,7 @@ function truncate2(value, decimals) {
|
|
|
4437
4920
|
const factor = Math.pow(10, decimals);
|
|
4438
4921
|
return (Math.floor(value * factor) / factor).toFixed(decimals);
|
|
4439
4922
|
}
|
|
4440
|
-
var
|
|
4923
|
+
var EVM_CHAIN_IDS2 = {
|
|
4441
4924
|
ethereum: 1,
|
|
4442
4925
|
base: 8453,
|
|
4443
4926
|
arbitrum: 42161
|
|
@@ -4478,8 +4961,8 @@ function EarnAccount({
|
|
|
4478
4961
|
chain: chainProp,
|
|
4479
4962
|
height = "600px"
|
|
4480
4963
|
}) {
|
|
4481
|
-
const { address, isConnected, login, logout, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
|
|
4482
|
-
const { isDeployed } = useEarnAccount();
|
|
4964
|
+
const { address, isConnected, login, logout, signTypedData, switchChain, walletChainId, fundWallet, hasExternalWallet, sendTransaction } = useEmbeddableWallet();
|
|
4965
|
+
const { isDeployed, earnAccountAddress } = useEarnAccount();
|
|
4483
4966
|
const { chainId: contextChainId } = useChain();
|
|
4484
4967
|
const CHAIN_ID = chainProp || contextChainId;
|
|
4485
4968
|
const queryClient = reactQuery.useQueryClient();
|
|
@@ -4493,10 +4976,15 @@ function EarnAccount({
|
|
|
4493
4976
|
const [isTokenDropdownOpen, setIsTokenDropdownOpen] = react.useState(false);
|
|
4494
4977
|
const [isFundModalOpen, setIsFundModalOpen] = react.useState(false);
|
|
4495
4978
|
const [fundAmount, setFundAmount] = react.useState("");
|
|
4496
|
-
const [fundAction, setFundAction] = react.useState(
|
|
4979
|
+
const [fundAction, setFundAction] = react.useState(
|
|
4980
|
+
!hasExternalWallet && fundWallet ? "buy" : "deposit"
|
|
4981
|
+
);
|
|
4497
4982
|
const [fundStep, setFundStep] = react.useState("idle");
|
|
4498
4983
|
const [fundTxState, setFundTxState] = react.useState({ status: "idle" });
|
|
4499
4984
|
const fundPollRef = react.useRef(null);
|
|
4985
|
+
const showBuyTab = !!fundWallet;
|
|
4986
|
+
const showSendTab = !!sendTransaction && !hasExternalWallet;
|
|
4987
|
+
const fundBuyOnly = !hasExternalWallet && showBuyTab && !sendTransaction;
|
|
4500
4988
|
const actionPollRef = react.useRef(null);
|
|
4501
4989
|
const actionTimeoutRef = react.useRef(null);
|
|
4502
4990
|
const [isBalancesModalOpen, setIsBalancesModalOpen] = react.useState(false);
|
|
@@ -4536,7 +5024,7 @@ function EarnAccount({
|
|
|
4536
5024
|
const fundIsValid = Number(fundAmount) > 0 && !!address && isDeployed;
|
|
4537
5025
|
const fundPhase = getFundPhase(fundStep);
|
|
4538
5026
|
const ensureCorrectChain = react.useCallback(async () => {
|
|
4539
|
-
const targetChainId =
|
|
5027
|
+
const targetChainId = EVM_CHAIN_IDS2[CHAIN_ID];
|
|
4540
5028
|
if (!targetChainId) return;
|
|
4541
5029
|
if (walletChainId !== void 0 && walletChainId !== targetChainId) {
|
|
4542
5030
|
if (!switchChain) {
|
|
@@ -4560,7 +5048,7 @@ function EarnAccount({
|
|
|
4560
5048
|
return null;
|
|
4561
5049
|
}
|
|
4562
5050
|
},
|
|
4563
|
-
enabled: !!address && isFundModalOpen && fundAction === "deposit",
|
|
5051
|
+
enabled: !!address && hasExternalWallet && isFundModalOpen && fundAction === "deposit",
|
|
4564
5052
|
staleTime: 15 * 1e3
|
|
4565
5053
|
});
|
|
4566
5054
|
const walletBalance = walletBalanceQuery.data?.balance || "0";
|
|
@@ -4844,7 +5332,10 @@ function EarnAccount({
|
|
|
4844
5332
|
setFundTxState({ status: "failed", error: "Transaction reverted" });
|
|
4845
5333
|
return;
|
|
4846
5334
|
}
|
|
4847
|
-
} catch {
|
|
5335
|
+
} catch (err) {
|
|
5336
|
+
if (err instanceof TypeError && err.message.includes("fetch")) ; else {
|
|
5337
|
+
console.warn("[EarnAccount] Unexpected error polling tx receipt:", err);
|
|
5338
|
+
}
|
|
4848
5339
|
}
|
|
4849
5340
|
if (polls >= 24) {
|
|
4850
5341
|
clearFundPolling();
|
|
@@ -5735,13 +6226,13 @@ function EarnAccount({
|
|
|
5735
6226
|
onClose: () => {
|
|
5736
6227
|
setIsFundModalOpen(false);
|
|
5737
6228
|
setFundAmount("");
|
|
5738
|
-
setFundAction("deposit");
|
|
6229
|
+
setFundAction(fundBuyOnly ? "buy" : showSendTab ? "buy" : "deposit");
|
|
5739
6230
|
setFundStep("idle");
|
|
5740
6231
|
setFundTxState({ status: "idle" });
|
|
5741
6232
|
},
|
|
5742
|
-
title: "Transfer Funds",
|
|
6233
|
+
title: showSendTab ? "Manage Funds" : fundBuyOnly ? "Add Funds" : "Transfer Funds",
|
|
5743
6234
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
5744
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6235
|
+
fundBuyOnly ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
5745
6236
|
"div",
|
|
5746
6237
|
{
|
|
5747
6238
|
className: "flex gap-1 p-1",
|
|
@@ -5750,7 +6241,9 @@ function EarnAccount({
|
|
|
5750
6241
|
borderRadius: "var(--compass-border-radius-lg)",
|
|
5751
6242
|
fontFamily: "var(--compass-font-family)"
|
|
5752
6243
|
},
|
|
5753
|
-
children: [
|
|
6244
|
+
children: [
|
|
6245
|
+
...showSendTab ? ["buy", "send"] : ["deposit", "withdraw", ...showBuyTab ? ["buy"] : []]
|
|
6246
|
+
].map((tab) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5754
6247
|
"button",
|
|
5755
6248
|
{
|
|
5756
6249
|
onClick: () => handleFundActionChange(tab),
|
|
@@ -5763,7 +6256,7 @@ function EarnAccount({
|
|
|
5763
6256
|
border: "none"
|
|
5764
6257
|
},
|
|
5765
6258
|
children: [
|
|
5766
|
-
tab === "deposit" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 14 }),
|
|
6259
|
+
tab === "deposit" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 14 }) : tab === "withdraw" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 14 }) : tab === "send" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { size: 14 }),
|
|
5767
6260
|
tab
|
|
5768
6261
|
]
|
|
5769
6262
|
},
|
|
@@ -5771,137 +6264,158 @@ function EarnAccount({
|
|
|
5771
6264
|
))
|
|
5772
6265
|
}
|
|
5773
6266
|
),
|
|
5774
|
-
|
|
5775
|
-
|
|
6267
|
+
fundAction === "send" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6268
|
+
SendForm,
|
|
5776
6269
|
{
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
},
|
|
5783
|
-
children: [
|
|
5784
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5785
|
-
FundStepIndicator,
|
|
5786
|
-
{
|
|
5787
|
-
number: 1,
|
|
5788
|
-
label: "Approve",
|
|
5789
|
-
state: fundPhase > 1 ? "done" : fundPhase === 1 ? "active" : "pending"
|
|
5790
|
-
}
|
|
5791
|
-
),
|
|
5792
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5793
|
-
FundStepIndicator,
|
|
5794
|
-
{
|
|
5795
|
-
number: 2,
|
|
5796
|
-
label: "Transfer",
|
|
5797
|
-
state: fundStep === "confirmed" ? "done" : fundPhase > 1 ? "active" : "pending"
|
|
5798
|
-
}
|
|
5799
|
-
)
|
|
5800
|
-
]
|
|
6270
|
+
onComplete: () => {
|
|
6271
|
+
queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
|
|
6272
|
+
queryClient.invalidateQueries({ queryKey: ["walletBalance"] });
|
|
6273
|
+
queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
|
|
6274
|
+
}
|
|
5801
6275
|
}
|
|
5802
|
-
)
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
"
|
|
6276
|
+
) : fundAction === "buy" || fundBuyOnly ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6277
|
+
BuyForm,
|
|
6278
|
+
{
|
|
6279
|
+
targetAddress: earnAccountAddress || "",
|
|
6280
|
+
onComplete: () => {
|
|
6281
|
+
queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
|
|
6282
|
+
queryClient.invalidateQueries({ queryKey: ["walletBalance"] });
|
|
6283
|
+
queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6287
|
+
(fundIsBusy || fundStep === "confirmed") && fundAction === "deposit" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6288
|
+
"div",
|
|
5806
6289
|
{
|
|
5807
|
-
className: "
|
|
6290
|
+
className: "flex gap-3 p-3 text-xs",
|
|
5808
6291
|
style: {
|
|
5809
|
-
|
|
6292
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
6293
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
5810
6294
|
fontFamily: "var(--compass-font-family)"
|
|
5811
6295
|
},
|
|
5812
|
-
children:
|
|
6296
|
+
children: [
|
|
6297
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6298
|
+
FundStepIndicator,
|
|
6299
|
+
{
|
|
6300
|
+
number: 1,
|
|
6301
|
+
label: "Approve",
|
|
6302
|
+
state: fundPhase > 1 ? "done" : fundPhase === 1 ? "active" : "pending"
|
|
6303
|
+
}
|
|
6304
|
+
),
|
|
6305
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6306
|
+
FundStepIndicator,
|
|
6307
|
+
{
|
|
6308
|
+
number: 2,
|
|
6309
|
+
label: "Transfer",
|
|
6310
|
+
state: fundStep === "confirmed" ? "done" : fundPhase > 1 ? "active" : "pending"
|
|
6311
|
+
}
|
|
6312
|
+
)
|
|
6313
|
+
]
|
|
5813
6314
|
}
|
|
5814
6315
|
),
|
|
5815
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
6316
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5816
6317
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5817
|
-
"
|
|
6318
|
+
"label",
|
|
5818
6319
|
{
|
|
5819
|
-
|
|
5820
|
-
value: fundAmount,
|
|
5821
|
-
onChange: (e) => {
|
|
5822
|
-
setFundAmount(e.target.value);
|
|
5823
|
-
setFundTxState({ status: "idle" });
|
|
5824
|
-
},
|
|
5825
|
-
disabled: fundIsBusy,
|
|
5826
|
-
placeholder: "0.00",
|
|
5827
|
-
className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
|
|
6320
|
+
className: "block text-sm mb-1.5",
|
|
5828
6321
|
style: {
|
|
5829
|
-
|
|
5830
|
-
borderColor: "var(--compass-color-border)",
|
|
5831
|
-
borderRadius: "var(--compass-border-radius-lg)",
|
|
5832
|
-
color: "var(--compass-color-text)",
|
|
6322
|
+
color: "var(--compass-color-text-secondary)",
|
|
5833
6323
|
fontFamily: "var(--compass-font-family)"
|
|
5834
|
-
}
|
|
6324
|
+
},
|
|
6325
|
+
children: "Amount"
|
|
5835
6326
|
}
|
|
5836
6327
|
),
|
|
5837
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5838
|
-
|
|
6328
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
6329
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6330
|
+
"input",
|
|
6331
|
+
{
|
|
6332
|
+
type: "number",
|
|
6333
|
+
value: fundAmount,
|
|
6334
|
+
onChange: (e) => {
|
|
6335
|
+
setFundAmount(e.target.value);
|
|
6336
|
+
setFundTxState({ status: "idle" });
|
|
6337
|
+
},
|
|
6338
|
+
disabled: fundIsBusy,
|
|
6339
|
+
placeholder: "0.00",
|
|
6340
|
+
className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
|
|
6341
|
+
style: {
|
|
6342
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
6343
|
+
borderColor: "var(--compass-color-border)",
|
|
6344
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
6345
|
+
color: "var(--compass-color-text)",
|
|
6346
|
+
fontFamily: "var(--compass-font-family)"
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6349
|
+
),
|
|
6350
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6351
|
+
"span",
|
|
6352
|
+
{
|
|
6353
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
|
|
6354
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
6355
|
+
children: "USDC"
|
|
6356
|
+
}
|
|
6357
|
+
)
|
|
6358
|
+
] }),
|
|
6359
|
+
fundMaxBalance !== "0" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6360
|
+
"p",
|
|
5839
6361
|
{
|
|
5840
|
-
className: "
|
|
6362
|
+
className: "text-xs mt-1",
|
|
5841
6363
|
style: { color: "var(--compass-color-text-tertiary)" },
|
|
5842
|
-
children:
|
|
6364
|
+
children: [
|
|
6365
|
+
"Available:",
|
|
6366
|
+
" ",
|
|
6367
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6368
|
+
"button",
|
|
6369
|
+
{
|
|
6370
|
+
onClick: () => setFundAmount(truncate2(parseFloat(fundMaxBalance), 2)),
|
|
6371
|
+
disabled: fundIsBusy,
|
|
6372
|
+
style: { color: "var(--compass-color-primary)", background: "none", border: "none", padding: 0, cursor: "pointer", fontSize: "inherit" },
|
|
6373
|
+
children: [
|
|
6374
|
+
truncate2(parseFloat(fundMaxBalance), 2),
|
|
6375
|
+
" USDC"
|
|
6376
|
+
]
|
|
6377
|
+
}
|
|
6378
|
+
)
|
|
6379
|
+
]
|
|
5843
6380
|
}
|
|
5844
6381
|
)
|
|
5845
6382
|
] }),
|
|
5846
|
-
|
|
6383
|
+
!fundIsBusy && fundStep !== "confirmed" && fundStep !== "failed" && fundTxState.status === "idle" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5847
6384
|
"p",
|
|
5848
6385
|
{
|
|
5849
|
-
className: "text-xs
|
|
5850
|
-
style: {
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
"button",
|
|
5856
|
-
{
|
|
5857
|
-
onClick: () => setFundAmount(truncate2(parseFloat(fundMaxBalance), 2)),
|
|
5858
|
-
disabled: fundIsBusy,
|
|
5859
|
-
style: { color: "var(--compass-color-primary)", background: "none", border: "none", padding: 0, cursor: "pointer", fontSize: "inherit" },
|
|
5860
|
-
children: [
|
|
5861
|
-
truncate2(parseFloat(fundMaxBalance), 2),
|
|
5862
|
-
" USDC"
|
|
5863
|
-
]
|
|
5864
|
-
}
|
|
5865
|
-
)
|
|
5866
|
-
]
|
|
6386
|
+
className: "text-xs",
|
|
6387
|
+
style: {
|
|
6388
|
+
color: "var(--compass-color-text-tertiary)",
|
|
6389
|
+
fontFamily: "var(--compass-font-family)"
|
|
6390
|
+
},
|
|
6391
|
+
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." : ""}`
|
|
5867
6392
|
}
|
|
5868
|
-
)
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
},
|
|
5895
|
-
children: fundIsBusy ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5896
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
5897
|
-
fundButtonLabel()
|
|
5898
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5899
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "h-4 w-4" }),
|
|
5900
|
-
fundAction === "deposit" ? "Transfer to Savings Account" : "Withdraw to Wallet"
|
|
5901
|
-
] })
|
|
5902
|
-
}
|
|
5903
|
-
),
|
|
5904
|
-
/* @__PURE__ */ jsxRuntime.jsx(TxStatus, { state: fundTxState })
|
|
6393
|
+
),
|
|
6394
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6395
|
+
"button",
|
|
6396
|
+
{
|
|
6397
|
+
onClick: handleFundTransfer,
|
|
6398
|
+
disabled: !fundIsValid || fundIsBusy,
|
|
6399
|
+
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",
|
|
6400
|
+
style: {
|
|
6401
|
+
backgroundColor: "var(--compass-color-primary)",
|
|
6402
|
+
color: "var(--compass-color-primary-text)",
|
|
6403
|
+
borderRadius: "var(--compass-border-radius-xl)",
|
|
6404
|
+
fontFamily: "var(--compass-font-family)",
|
|
6405
|
+
transition: "all 200ms ease",
|
|
6406
|
+
border: "none"
|
|
6407
|
+
},
|
|
6408
|
+
children: fundIsBusy ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6409
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
6410
|
+
fundButtonLabel()
|
|
6411
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6412
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "h-4 w-4" }),
|
|
6413
|
+
fundAction === "deposit" ? "Transfer to Savings Account" : "Withdraw to Wallet"
|
|
6414
|
+
] })
|
|
6415
|
+
}
|
|
6416
|
+
),
|
|
6417
|
+
/* @__PURE__ */ jsxRuntime.jsx(TxStatus, { state: fundTxState })
|
|
6418
|
+
] })
|
|
5905
6419
|
] })
|
|
5906
6420
|
}
|
|
5907
6421
|
),
|
|
@@ -7708,19 +8222,24 @@ function getPhase(step) {
|
|
|
7708
8222
|
if (step === "approving" || step === "signing-approval") return 1;
|
|
7709
8223
|
return 2;
|
|
7710
8224
|
}
|
|
7711
|
-
var
|
|
8225
|
+
var EVM_CHAIN_IDS3 = {
|
|
7712
8226
|
ethereum: 1,
|
|
7713
8227
|
base: 8453,
|
|
7714
8228
|
arbitrum: 42161
|
|
7715
8229
|
};
|
|
7716
8230
|
function TopUpModal({ isOpen, onClose }) {
|
|
7717
|
-
const { address, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
|
|
8231
|
+
const { address, signTypedData, switchChain, walletChainId, fundWallet, hasExternalWallet, sendTransaction } = useEmbeddableWallet();
|
|
7718
8232
|
const { chainId } = useChain();
|
|
7719
|
-
const { isDeployed } = useCreditAccount();
|
|
8233
|
+
const { isDeployed, creditAccountAddress } = useCreditAccount();
|
|
7720
8234
|
const queryClient = reactQuery.useQueryClient();
|
|
7721
8235
|
const prices = useTokenPrices();
|
|
7722
8236
|
const token = "USDC";
|
|
7723
|
-
const [action, setAction] = react.useState(
|
|
8237
|
+
const [action, setAction] = react.useState(
|
|
8238
|
+
!hasExternalWallet && fundWallet ? "buy" : "deposit"
|
|
8239
|
+
);
|
|
8240
|
+
const showBuyTab = !!fundWallet;
|
|
8241
|
+
const showSendTab = !!sendTransaction && !hasExternalWallet;
|
|
8242
|
+
const buyOnly = !hasExternalWallet && showBuyTab && !sendTransaction;
|
|
7724
8243
|
const [amount, setAmount] = react.useState("");
|
|
7725
8244
|
const [step, setStep] = react.useState("idle");
|
|
7726
8245
|
const [txState, setTxState] = react.useState({ status: "idle" });
|
|
@@ -7769,7 +8288,7 @@ function TopUpModal({ isOpen, onClose }) {
|
|
|
7769
8288
|
const isValid = Number(amount) > 0 && !!address && isDeployed;
|
|
7770
8289
|
const isBusy = step === "approving" || step === "signing-approval" || step === "preparing-transfer" || step === "signing-transfer" || step === "executing";
|
|
7771
8290
|
const ensureCorrectChain = react.useCallback(async () => {
|
|
7772
|
-
const targetChainId =
|
|
8291
|
+
const targetChainId = EVM_CHAIN_IDS3[CHAIN_ID];
|
|
7773
8292
|
if (!targetChainId) return;
|
|
7774
8293
|
if (walletChainId !== void 0 && walletChainId !== targetChainId) {
|
|
7775
8294
|
if (!switchChain) {
|
|
@@ -7971,7 +8490,10 @@ function TopUpModal({ isOpen, onClose }) {
|
|
|
7971
8490
|
setTxState({ status: "failed", error: "Transaction reverted" });
|
|
7972
8491
|
return;
|
|
7973
8492
|
}
|
|
7974
|
-
} catch {
|
|
8493
|
+
} catch (err) {
|
|
8494
|
+
if (err instanceof TypeError && err.message.includes("fetch")) ; else {
|
|
8495
|
+
console.warn("[TopUpModal] Unexpected error polling tx receipt:", err);
|
|
8496
|
+
}
|
|
7975
8497
|
}
|
|
7976
8498
|
if (polls >= 24) {
|
|
7977
8499
|
clearPolling();
|
|
@@ -8007,8 +8529,8 @@ function TopUpModal({ isOpen, onClose }) {
|
|
|
8007
8529
|
color: "var(--compass-color-text-secondary)",
|
|
8008
8530
|
fontFamily: "var(--compass-font-family)"
|
|
8009
8531
|
};
|
|
8010
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ActionModal, { isOpen, onClose, title: "Transfer Funds", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
8011
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8532
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ActionModal, { isOpen, onClose, title: showSendTab ? "Manage Funds" : buyOnly ? "Add Funds" : "Transfer Funds", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
8533
|
+
!buyOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8012
8534
|
"div",
|
|
8013
8535
|
{
|
|
8014
8536
|
className: "flex gap-1 p-1",
|
|
@@ -8017,7 +8539,9 @@ function TopUpModal({ isOpen, onClose }) {
|
|
|
8017
8539
|
borderRadius: "var(--compass-border-radius-lg)",
|
|
8018
8540
|
fontFamily: "var(--compass-font-family)"
|
|
8019
8541
|
},
|
|
8020
|
-
children: [
|
|
8542
|
+
children: [
|
|
8543
|
+
...showSendTab ? ["buy", "send"] : showBuyTab ? ["deposit", "withdraw", "buy"] : ["deposit", "withdraw"]
|
|
8544
|
+
].map((tab) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8021
8545
|
"button",
|
|
8022
8546
|
{
|
|
8023
8547
|
onClick: () => handleActionChange(tab),
|
|
@@ -8029,7 +8553,7 @@ function TopUpModal({ isOpen, onClose }) {
|
|
|
8029
8553
|
borderRadius: "var(--compass-border-radius-md)"
|
|
8030
8554
|
},
|
|
8031
8555
|
children: [
|
|
8032
|
-
tab === "deposit" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 14 }),
|
|
8556
|
+
tab === "deposit" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 14 }) : tab === "withdraw" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { size: 14 }) : tab === "send" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { size: 14 }),
|
|
8033
8557
|
tab
|
|
8034
8558
|
]
|
|
8035
8559
|
},
|
|
@@ -8037,122 +8561,143 @@ function TopUpModal({ isOpen, onClose }) {
|
|
|
8037
8561
|
))
|
|
8038
8562
|
}
|
|
8039
8563
|
),
|
|
8040
|
-
|
|
8041
|
-
|
|
8564
|
+
action === "send" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8565
|
+
SendForm,
|
|
8042
8566
|
{
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
}
|
|
8049
|
-
|
|
8567
|
+
product: "credit",
|
|
8568
|
+
productAccountAddress: creditAccountAddress || void 0,
|
|
8569
|
+
onComplete: () => {
|
|
8570
|
+
queryClient.invalidateQueries({ queryKey: ["creditBalances"] });
|
|
8571
|
+
queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
|
|
8572
|
+
}
|
|
8573
|
+
}
|
|
8574
|
+
) : action === "buy" || buyOnly ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8575
|
+
BuyForm,
|
|
8576
|
+
{
|
|
8577
|
+
targetAddress: creditAccountAddress || "",
|
|
8578
|
+
onComplete: () => {
|
|
8579
|
+
queryClient.invalidateQueries({ queryKey: ["creditBalances"] });
|
|
8580
|
+
queryClient.invalidateQueries({ queryKey: ["walletTokenBalance"] });
|
|
8581
|
+
}
|
|
8582
|
+
}
|
|
8583
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8584
|
+
(isBusy || step === "confirmed") && action === "deposit" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8585
|
+
"div",
|
|
8586
|
+
{
|
|
8587
|
+
className: "flex gap-3 p-3 text-xs",
|
|
8588
|
+
style: {
|
|
8589
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
8590
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
8591
|
+
fontFamily: "var(--compass-font-family)"
|
|
8592
|
+
},
|
|
8593
|
+
children: [
|
|
8594
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8595
|
+
StepIndicator,
|
|
8596
|
+
{
|
|
8597
|
+
number: 1,
|
|
8598
|
+
label: "Approve",
|
|
8599
|
+
state: phase > 1 ? "done" : phase === 1 ? "active" : "pending"
|
|
8600
|
+
}
|
|
8601
|
+
),
|
|
8602
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8603
|
+
StepIndicator,
|
|
8604
|
+
{
|
|
8605
|
+
number: 2,
|
|
8606
|
+
label: "Transfer",
|
|
8607
|
+
state: step === "confirmed" ? "done" : phase > 1 ? "active" : "pending"
|
|
8608
|
+
}
|
|
8609
|
+
)
|
|
8610
|
+
]
|
|
8611
|
+
}
|
|
8612
|
+
),
|
|
8613
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
8614
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm mb-1.5", style: labelStyle, children: "Amount" }),
|
|
8615
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
8050
8616
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8051
|
-
|
|
8617
|
+
"input",
|
|
8052
8618
|
{
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8619
|
+
type: "number",
|
|
8620
|
+
value: amount,
|
|
8621
|
+
onChange: (e) => {
|
|
8622
|
+
setAmount(e.target.value);
|
|
8623
|
+
setTxState({ status: "idle" });
|
|
8624
|
+
},
|
|
8625
|
+
disabled: isBusy,
|
|
8626
|
+
placeholder: "0.00",
|
|
8627
|
+
className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
|
|
8628
|
+
style: inputStyle
|
|
8056
8629
|
}
|
|
8057
8630
|
),
|
|
8058
8631
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8059
|
-
|
|
8632
|
+
"span",
|
|
8060
8633
|
{
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8634
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-xs",
|
|
8635
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
8636
|
+
children: token
|
|
8064
8637
|
}
|
|
8065
8638
|
)
|
|
8066
|
-
]
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
8070
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm mb-1.5", style: labelStyle, children: "Amount" }),
|
|
8071
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
8072
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8073
|
-
"input",
|
|
8639
|
+
] }),
|
|
8640
|
+
formatUsdEstimate(amount, token, prices) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8641
|
+
"p",
|
|
8074
8642
|
{
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
placeholder: "0.00",
|
|
8083
|
-
className: "w-full border px-3 py-2.5 pr-14 text-sm focus:outline-none disabled:opacity-50",
|
|
8084
|
-
style: inputStyle
|
|
8643
|
+
className: "text-xs mt-1",
|
|
8644
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
8645
|
+
children: [
|
|
8646
|
+
"\u2248",
|
|
8647
|
+
" ",
|
|
8648
|
+
formatUsdEstimate(amount, token, prices)
|
|
8649
|
+
]
|
|
8085
8650
|
}
|
|
8086
8651
|
),
|
|
8087
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8088
|
-
"
|
|
8652
|
+
maxBalance && maxBalance !== "0" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8653
|
+
"p",
|
|
8089
8654
|
{
|
|
8090
|
-
className: "
|
|
8655
|
+
className: "text-xs mt-1",
|
|
8091
8656
|
style: { color: "var(--compass-color-text-tertiary)" },
|
|
8092
|
-
children:
|
|
8657
|
+
children: [
|
|
8658
|
+
"Available: ",
|
|
8659
|
+
truncate6(parseFloat(maxBalance), 2),
|
|
8660
|
+
" ",
|
|
8661
|
+
token
|
|
8662
|
+
]
|
|
8093
8663
|
}
|
|
8094
8664
|
)
|
|
8095
8665
|
] }),
|
|
8096
|
-
|
|
8666
|
+
!isBusy && step !== "confirmed" && step !== "failed" && txState.status === "idle" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8097
8667
|
"p",
|
|
8098
8668
|
{
|
|
8099
|
-
className: "text-xs
|
|
8100
|
-
style: {
|
|
8101
|
-
|
|
8102
|
-
"
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
]
|
|
8669
|
+
className: "text-xs",
|
|
8670
|
+
style: {
|
|
8671
|
+
color: "var(--compass-color-text-tertiary)",
|
|
8672
|
+
fontFamily: "var(--compass-font-family)"
|
|
8673
|
+
},
|
|
8674
|
+
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." : ""}`
|
|
8106
8675
|
}
|
|
8107
8676
|
),
|
|
8108
|
-
|
|
8109
|
-
"
|
|
8677
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8678
|
+
"button",
|
|
8110
8679
|
{
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8680
|
+
onClick: handleTransfer,
|
|
8681
|
+
disabled: !isValid || isBusy,
|
|
8682
|
+
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",
|
|
8683
|
+
style: {
|
|
8684
|
+
backgroundColor: "var(--compass-color-primary)",
|
|
8685
|
+
color: "white",
|
|
8686
|
+
borderRadius: "var(--compass-border-radius-xl)",
|
|
8687
|
+
fontFamily: "var(--compass-font-family)",
|
|
8688
|
+
transition: "var(--compass-transition-normal)"
|
|
8689
|
+
},
|
|
8690
|
+
children: isBusy ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8691
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
8692
|
+
buttonLabel()
|
|
8693
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8694
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "h-4 w-4" }),
|
|
8695
|
+
action === "deposit" ? "Transfer to Credit Account" : "Withdraw to Wallet"
|
|
8696
|
+
] })
|
|
8119
8697
|
}
|
|
8120
|
-
)
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
"p",
|
|
8124
|
-
{
|
|
8125
|
-
className: "text-xs",
|
|
8126
|
-
style: {
|
|
8127
|
-
color: "var(--compass-color-text-tertiary)",
|
|
8128
|
-
fontFamily: "var(--compass-font-family)"
|
|
8129
|
-
},
|
|
8130
|
-
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."
|
|
8131
|
-
}
|
|
8132
|
-
),
|
|
8133
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8134
|
-
"button",
|
|
8135
|
-
{
|
|
8136
|
-
onClick: handleTransfer,
|
|
8137
|
-
disabled: !isValid || isBusy,
|
|
8138
|
-
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",
|
|
8139
|
-
style: {
|
|
8140
|
-
backgroundColor: "var(--compass-color-primary)",
|
|
8141
|
-
color: "white",
|
|
8142
|
-
borderRadius: "var(--compass-border-radius-xl)",
|
|
8143
|
-
fontFamily: "var(--compass-font-family)",
|
|
8144
|
-
transition: "var(--compass-transition-normal)"
|
|
8145
|
-
},
|
|
8146
|
-
children: isBusy ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8147
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
8148
|
-
buttonLabel()
|
|
8149
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8150
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "h-4 w-4" }),
|
|
8151
|
-
action === "deposit" ? "Transfer to Credit Account" : "Withdraw to Wallet"
|
|
8152
|
-
] })
|
|
8153
|
-
}
|
|
8154
|
-
),
|
|
8155
|
-
/* @__PURE__ */ jsxRuntime.jsx(TxStatus, { state: txState })
|
|
8698
|
+
),
|
|
8699
|
+
/* @__PURE__ */ jsxRuntime.jsx(TxStatus, { state: txState })
|
|
8700
|
+
] })
|
|
8156
8701
|
] }) });
|
|
8157
8702
|
}
|
|
8158
8703
|
function StepIndicator({
|
|
@@ -8180,9 +8725,10 @@ function CreditSwapModal({ isOpen, onClose }) {
|
|
|
8180
8725
|
const prices = useTokenPrices();
|
|
8181
8726
|
const { txState, executeBundle, resetState } = useCreditBundle();
|
|
8182
8727
|
const tokens = CREDIT_TOKENS;
|
|
8183
|
-
const fromToken = "USDC";
|
|
8184
|
-
const [toToken, setToToken] = react.useState(tokens.find((t) => t !==
|
|
8728
|
+
const [fromToken, setFromToken] = react.useState("USDC");
|
|
8729
|
+
const [toToken, setToToken] = react.useState(tokens.find((t) => t !== "USDC") || tokens[0] || "WETH");
|
|
8185
8730
|
const [fromAmount, setFromAmount] = react.useState("");
|
|
8731
|
+
const [isFromOpen, setIsFromOpen] = react.useState(false);
|
|
8186
8732
|
const [isToOpen, setIsToOpen] = react.useState(false);
|
|
8187
8733
|
react.useEffect(() => {
|
|
8188
8734
|
if (isOpen) {
|
|
@@ -8190,6 +8736,12 @@ function CreditSwapModal({ isOpen, onClose }) {
|
|
|
8190
8736
|
resetState();
|
|
8191
8737
|
}
|
|
8192
8738
|
}, [isOpen]);
|
|
8739
|
+
react.useEffect(() => {
|
|
8740
|
+
if (fromToken === toToken) {
|
|
8741
|
+
const alt = tokens.find((t) => t !== fromToken);
|
|
8742
|
+
if (alt) setToToken(alt);
|
|
8743
|
+
}
|
|
8744
|
+
}, [fromToken, toToken, tokens]);
|
|
8193
8745
|
const fromBalance = balances?.find((b) => b.tokenSymbol === fromToken);
|
|
8194
8746
|
const fromBalanceAmount = fromBalance ? parseFloat(fromBalance.amount) : 0;
|
|
8195
8747
|
const estimatedOutput = (() => {
|
|
@@ -8268,24 +8820,76 @@ function CreditSwapModal({ isOpen, onClose }) {
|
|
|
8268
8820
|
}
|
|
8269
8821
|
}
|
|
8270
8822
|
),
|
|
8271
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8823
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
8824
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8825
|
+
"button",
|
|
8826
|
+
{
|
|
8827
|
+
onClick: () => setIsFromOpen(!isFromOpen),
|
|
8828
|
+
disabled: isBusy,
|
|
8829
|
+
style: {
|
|
8830
|
+
display: "flex",
|
|
8831
|
+
alignItems: "center",
|
|
8832
|
+
fontWeight: 500,
|
|
8833
|
+
backgroundColor: "var(--compass-color-background)",
|
|
8834
|
+
border: "1.5px solid var(--compass-color-border)",
|
|
8835
|
+
color: "var(--compass-color-text)",
|
|
8836
|
+
borderRadius: "var(--compass-border-radius-md)",
|
|
8837
|
+
padding: "4px 8px",
|
|
8838
|
+
gap: "4px",
|
|
8839
|
+
fontSize: "0.8125rem",
|
|
8840
|
+
cursor: isBusy ? "not-allowed" : "pointer"
|
|
8841
|
+
},
|
|
8842
|
+
children: [
|
|
8843
|
+
fromToken,
|
|
8844
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 12, style: { color: "var(--compass-color-text-tertiary)" } })
|
|
8845
|
+
]
|
|
8846
|
+
}
|
|
8847
|
+
),
|
|
8848
|
+
isFromOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8849
|
+
"div",
|
|
8850
|
+
{
|
|
8851
|
+
style: {
|
|
8852
|
+
position: "absolute",
|
|
8853
|
+
right: 0,
|
|
8854
|
+
top: "100%",
|
|
8855
|
+
marginTop: "4px",
|
|
8856
|
+
zIndex: 10,
|
|
8857
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
8858
|
+
border: "1.5px solid var(--compass-color-border)",
|
|
8859
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
8860
|
+
boxShadow: "var(--compass-shadow-md)",
|
|
8861
|
+
minWidth: "120px",
|
|
8862
|
+
maxHeight: "200px",
|
|
8863
|
+
overflowY: "auto",
|
|
8864
|
+
scrollbarWidth: "none"
|
|
8865
|
+
},
|
|
8866
|
+
children: tokens.filter((t) => t !== toToken).map((token) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8867
|
+
"button",
|
|
8868
|
+
{
|
|
8869
|
+
onClick: () => {
|
|
8870
|
+
setFromToken(token);
|
|
8871
|
+
setFromAmount("");
|
|
8872
|
+
setIsFromOpen(false);
|
|
8873
|
+
},
|
|
8874
|
+
style: {
|
|
8875
|
+
display: "block",
|
|
8876
|
+
width: "100%",
|
|
8877
|
+
textAlign: "left",
|
|
8878
|
+
padding: "6px 10px",
|
|
8879
|
+
fontSize: "0.8125rem",
|
|
8880
|
+
fontWeight: 500,
|
|
8881
|
+
color: token === fromToken ? "var(--compass-color-primary)" : "var(--compass-color-text)",
|
|
8882
|
+
backgroundColor: token === fromToken ? "var(--compass-color-primary-muted)" : "transparent",
|
|
8883
|
+
border: "none",
|
|
8884
|
+
cursor: "pointer"
|
|
8885
|
+
},
|
|
8886
|
+
children: token
|
|
8887
|
+
},
|
|
8888
|
+
token
|
|
8889
|
+
))
|
|
8890
|
+
}
|
|
8891
|
+
)
|
|
8892
|
+
] })
|
|
8289
8893
|
] })
|
|
8290
8894
|
]
|
|
8291
8895
|
}
|
|
@@ -8492,7 +9096,7 @@ function CreditAccount({
|
|
|
8492
9096
|
onBorrow: _onBorrow,
|
|
8493
9097
|
onRepay: _onRepay
|
|
8494
9098
|
}) {
|
|
8495
|
-
const { address, isConnected, login, logout } = useEmbeddableWallet();
|
|
9099
|
+
const { address, isConnected, login, logout, hasExternalWallet } = useEmbeddableWallet();
|
|
8496
9100
|
const { isDeployed, creditAccountAddress } = useCreditAccount();
|
|
8497
9101
|
const { chainId } = useChain();
|
|
8498
9102
|
const { data: positions, isLoading: positionsLoading } = useCreditPositions();
|
|
@@ -8518,6 +9122,25 @@ function CreditAccount({
|
|
|
8518
9122
|
return { ...b, usdValue };
|
|
8519
9123
|
}).filter((b) => b.usdValue >= 0.01).sort((a, b) => a.tokenSymbol.localeCompare(b.tokenSymbol));
|
|
8520
9124
|
const totalIdleUsd = balancesWithUsd.reduce((sum, b) => sum + b.usdValue, 0);
|
|
9125
|
+
const { data: walletBalance } = reactQuery.useQuery({
|
|
9126
|
+
queryKey: ["embeddedWalletBalance", chainId, address, "USDC"],
|
|
9127
|
+
queryFn: async () => {
|
|
9128
|
+
if (!address) return "0";
|
|
9129
|
+
try {
|
|
9130
|
+
const response = await fetch(
|
|
9131
|
+
`/api/compass/token/balance?chain=${chainId}&token=USDC&address=${address}`
|
|
9132
|
+
);
|
|
9133
|
+
if (response.ok) {
|
|
9134
|
+
const data = await response.json();
|
|
9135
|
+
return data.balance || "0";
|
|
9136
|
+
}
|
|
9137
|
+
} catch {
|
|
9138
|
+
}
|
|
9139
|
+
return "0";
|
|
9140
|
+
},
|
|
9141
|
+
enabled: !!address && hasExternalWallet,
|
|
9142
|
+
staleTime: 30 * 1e3
|
|
9143
|
+
});
|
|
8521
9144
|
const totalInterestEarnedUsd = (() => {
|
|
8522
9145
|
if (!positions) return 0;
|
|
8523
9146
|
let total = 0;
|
|
@@ -9518,6 +10141,7 @@ function PositionDetailModal({ position, onClose }) {
|
|
|
9518
10141
|
const isPendle = position.venue === "pendle";
|
|
9519
10142
|
const duration = formatDuration(position.entryTimestamp);
|
|
9520
10143
|
const expiryDate = formatExpiryUTC(position.expiry);
|
|
10144
|
+
const modalRef = react.useRef(null);
|
|
9521
10145
|
react.useEffect(() => {
|
|
9522
10146
|
const handleKeyDown = (e) => {
|
|
9523
10147
|
if (e.key === "Escape") onClose();
|
|
@@ -9525,296 +10149,312 @@ function PositionDetailModal({ position, onClose }) {
|
|
|
9525
10149
|
document.addEventListener("keydown", handleKeyDown);
|
|
9526
10150
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
9527
10151
|
}, [onClose]);
|
|
10152
|
+
const handleOverlayWheel = react.useCallback((e) => {
|
|
10153
|
+
if (modalRef.current && !modalRef.current.contains(e.target)) {
|
|
10154
|
+
window.scrollBy(0, e.deltaY);
|
|
10155
|
+
}
|
|
10156
|
+
}, []);
|
|
9528
10157
|
const hasStats = position.apy || isPendle && (duration || expiryDate) || position.pnl;
|
|
9529
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
10158
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9530
10159
|
"div",
|
|
9531
10160
|
{
|
|
9532
10161
|
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
9533
|
-
|
|
10162
|
+
onWheel: handleOverlayWheel,
|
|
9534
10163
|
onClick: onClose,
|
|
9535
|
-
children:
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
backgroundColor: "
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9557
|
-
"h2",
|
|
9558
|
-
{
|
|
9559
|
-
className: "font-semibold text-lg",
|
|
9560
|
-
style: { color: "var(--compass-color-text)" },
|
|
9561
|
-
children: position.name
|
|
9562
|
-
}
|
|
9563
|
-
),
|
|
9564
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9565
|
-
"p",
|
|
9566
|
-
{
|
|
9567
|
-
className: "text-sm",
|
|
9568
|
-
style: { color: "var(--compass-color-text-secondary)" },
|
|
9569
|
-
children: position.venueName
|
|
9570
|
-
}
|
|
9571
|
-
)
|
|
9572
|
-
] }),
|
|
9573
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9574
|
-
"button",
|
|
9575
|
-
{
|
|
9576
|
-
onClick: onClose,
|
|
9577
|
-
className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
|
|
9578
|
-
style: { backgroundColor: "var(--compass-color-background)" },
|
|
9579
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 20, style: { color: "var(--compass-color-text-secondary)" } })
|
|
9580
|
-
}
|
|
9581
|
-
)
|
|
9582
|
-
]
|
|
9583
|
-
}
|
|
9584
|
-
),
|
|
9585
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
9586
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9587
|
-
"p",
|
|
9588
|
-
{
|
|
9589
|
-
className: "text-sm mb-1",
|
|
9590
|
-
style: { color: "var(--compass-color-text-secondary)" },
|
|
9591
|
-
children: "Current Balance"
|
|
9592
|
-
}
|
|
9593
|
-
),
|
|
9594
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9595
|
-
"p",
|
|
9596
|
-
{
|
|
9597
|
-
className: "text-3xl font-bold",
|
|
9598
|
-
style: { color: "var(--compass-color-text)" },
|
|
9599
|
-
children: formatUSD(position.balanceUsd)
|
|
9600
|
-
}
|
|
9601
|
-
),
|
|
10164
|
+
children: [
|
|
10165
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10166
|
+
"div",
|
|
10167
|
+
{
|
|
10168
|
+
className: "absolute inset-0",
|
|
10169
|
+
style: { backgroundColor: "rgba(0, 0, 0, 0.7)" }
|
|
10170
|
+
}
|
|
10171
|
+
),
|
|
10172
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10173
|
+
"div",
|
|
10174
|
+
{
|
|
10175
|
+
ref: modalRef,
|
|
10176
|
+
className: "relative w-full max-w-md rounded-xl border max-h-[85vh] overflow-y-auto",
|
|
10177
|
+
style: {
|
|
10178
|
+
backgroundColor: "var(--compass-color-background)",
|
|
10179
|
+
borderColor: "var(--compass-color-border)",
|
|
10180
|
+
scrollbarWidth: "none",
|
|
10181
|
+
overscrollBehavior: "contain"
|
|
10182
|
+
},
|
|
10183
|
+
onClick: (e) => e.stopPropagation(),
|
|
10184
|
+
children: [
|
|
9602
10185
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9603
|
-
"p",
|
|
9604
|
-
{
|
|
9605
|
-
className: "text-sm font-mono mt-1",
|
|
9606
|
-
style: { color: "var(--compass-color-text-secondary)" },
|
|
9607
|
-
children: [
|
|
9608
|
-
formatAmount(position.balance),
|
|
9609
|
-
" ",
|
|
9610
|
-
position.assetSymbol
|
|
9611
|
-
]
|
|
9612
|
-
}
|
|
9613
|
-
)
|
|
9614
|
-
] }) }),
|
|
9615
|
-
hasStats && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: [
|
|
9616
|
-
position.apy && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9617
|
-
"div",
|
|
9618
|
-
{
|
|
9619
|
-
className: "p-3 rounded-lg",
|
|
9620
|
-
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
9621
|
-
children: [
|
|
9622
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
9623
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Percent, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
9624
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "APY" })
|
|
9625
|
-
] }),
|
|
9626
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9627
|
-
"p",
|
|
9628
|
-
{
|
|
9629
|
-
className: "font-semibold",
|
|
9630
|
-
style: { color: "var(--compass-color-success)" },
|
|
9631
|
-
children: [
|
|
9632
|
-
parseFloat(position.apy).toFixed(2),
|
|
9633
|
-
"%"
|
|
9634
|
-
]
|
|
9635
|
-
}
|
|
9636
|
-
)
|
|
9637
|
-
]
|
|
9638
|
-
}
|
|
9639
|
-
),
|
|
9640
|
-
isPendle && duration && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9641
|
-
"div",
|
|
9642
|
-
{
|
|
9643
|
-
className: "p-3 rounded-lg",
|
|
9644
|
-
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
9645
|
-
children: [
|
|
9646
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
9647
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
9648
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Duration" })
|
|
9649
|
-
] }),
|
|
9650
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9651
|
-
"p",
|
|
9652
|
-
{
|
|
9653
|
-
className: "font-semibold",
|
|
9654
|
-
style: { color: "var(--compass-color-text)" },
|
|
9655
|
-
children: duration
|
|
9656
|
-
}
|
|
9657
|
-
)
|
|
9658
|
-
]
|
|
9659
|
-
}
|
|
9660
|
-
),
|
|
9661
|
-
isPendle && expiryDate && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9662
10186
|
"div",
|
|
9663
10187
|
{
|
|
9664
|
-
className: "p-
|
|
9665
|
-
style: {
|
|
10188
|
+
className: "sticky top-0 flex items-center justify-between p-4 border-b",
|
|
10189
|
+
style: {
|
|
10190
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
10191
|
+
borderColor: "var(--compass-color-border)"
|
|
10192
|
+
},
|
|
9666
10193
|
children: [
|
|
9667
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
9668
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9669
|
-
|
|
10194
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
10195
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10196
|
+
"h2",
|
|
10197
|
+
{
|
|
10198
|
+
className: "font-semibold text-lg",
|
|
10199
|
+
style: { color: "var(--compass-color-text)" },
|
|
10200
|
+
children: position.name
|
|
10201
|
+
}
|
|
10202
|
+
),
|
|
10203
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10204
|
+
"p",
|
|
10205
|
+
{
|
|
10206
|
+
className: "text-sm",
|
|
10207
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
10208
|
+
children: position.venueName
|
|
10209
|
+
}
|
|
10210
|
+
)
|
|
9670
10211
|
] }),
|
|
9671
10212
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9672
|
-
"
|
|
10213
|
+
"button",
|
|
9673
10214
|
{
|
|
9674
|
-
|
|
9675
|
-
|
|
9676
|
-
|
|
10215
|
+
onClick: onClose,
|
|
10216
|
+
className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
|
|
10217
|
+
style: { backgroundColor: "var(--compass-color-background)" },
|
|
10218
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 20, style: { color: "var(--compass-color-text-secondary)" } })
|
|
9677
10219
|
}
|
|
9678
10220
|
)
|
|
9679
10221
|
]
|
|
9680
10222
|
}
|
|
9681
10223
|
),
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
10224
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
10225
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10226
|
+
"p",
|
|
10227
|
+
{
|
|
10228
|
+
className: "text-sm mb-1",
|
|
10229
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
10230
|
+
children: "Current Balance"
|
|
10231
|
+
}
|
|
10232
|
+
),
|
|
10233
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10234
|
+
"p",
|
|
10235
|
+
{
|
|
10236
|
+
className: "text-3xl font-bold",
|
|
10237
|
+
style: { color: "var(--compass-color-text)" },
|
|
10238
|
+
children: formatUSD(position.balanceUsd)
|
|
10239
|
+
}
|
|
10240
|
+
),
|
|
10241
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10242
|
+
"p",
|
|
10243
|
+
{
|
|
10244
|
+
className: "text-sm font-mono mt-1",
|
|
10245
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
10246
|
+
children: [
|
|
10247
|
+
formatAmount(position.balance),
|
|
10248
|
+
" ",
|
|
10249
|
+
position.assetSymbol
|
|
10250
|
+
]
|
|
10251
|
+
}
|
|
10252
|
+
)
|
|
10253
|
+
] }) }),
|
|
10254
|
+
hasStats && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 p-4 border-b", style: { borderColor: "var(--compass-color-border)" }, children: [
|
|
10255
|
+
position.apy && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10256
|
+
"div",
|
|
10257
|
+
{
|
|
10258
|
+
className: "p-3 rounded-lg",
|
|
10259
|
+
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
10260
|
+
children: [
|
|
10261
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
10262
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Percent, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
10263
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "APY" })
|
|
10264
|
+
] }),
|
|
10265
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10266
|
+
"p",
|
|
10267
|
+
{
|
|
10268
|
+
className: "font-semibold",
|
|
10269
|
+
style: { color: "var(--compass-color-success)" },
|
|
10270
|
+
children: [
|
|
10271
|
+
parseFloat(position.apy).toFixed(2),
|
|
10272
|
+
"%"
|
|
10273
|
+
]
|
|
10274
|
+
}
|
|
10275
|
+
)
|
|
10276
|
+
]
|
|
10277
|
+
}
|
|
10278
|
+
),
|
|
10279
|
+
isPendle && duration && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10280
|
+
"div",
|
|
10281
|
+
{
|
|
10282
|
+
className: "p-3 rounded-lg",
|
|
10283
|
+
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
10284
|
+
children: [
|
|
10285
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
10286
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
10287
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Duration" })
|
|
10288
|
+
] }),
|
|
10289
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10290
|
+
"p",
|
|
10291
|
+
{
|
|
10292
|
+
className: "font-semibold",
|
|
10293
|
+
style: { color: "var(--compass-color-text)" },
|
|
10294
|
+
children: duration
|
|
10295
|
+
}
|
|
10296
|
+
)
|
|
10297
|
+
]
|
|
10298
|
+
}
|
|
10299
|
+
),
|
|
10300
|
+
isPendle && expiryDate && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10301
|
+
"div",
|
|
10302
|
+
{
|
|
10303
|
+
className: "p-3 rounded-lg",
|
|
10304
|
+
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
10305
|
+
children: [
|
|
10306
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
10307
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
10308
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Expiry (UTC)" })
|
|
10309
|
+
] }),
|
|
10310
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10311
|
+
"p",
|
|
10312
|
+
{
|
|
10313
|
+
className: "font-semibold",
|
|
10314
|
+
style: { color: "var(--compass-color-text)" },
|
|
10315
|
+
children: expiryDate
|
|
10316
|
+
}
|
|
10317
|
+
)
|
|
10318
|
+
]
|
|
10319
|
+
}
|
|
10320
|
+
),
|
|
10321
|
+
position.pnl && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10322
|
+
"div",
|
|
10323
|
+
{
|
|
10324
|
+
className: "p-3 rounded-lg",
|
|
10325
|
+
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
10326
|
+
children: [
|
|
10327
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
10328
|
+
isPnlPositive ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { size: 14, style: { color: "var(--compass-color-success)" } }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingDown, { size: 14, style: { color: "var(--compass-color-error)" } }),
|
|
10329
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "Total P&L" })
|
|
10330
|
+
] }),
|
|
10331
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10332
|
+
"p",
|
|
10333
|
+
{
|
|
10334
|
+
className: "font-semibold",
|
|
10335
|
+
style: {
|
|
10336
|
+
color: isPnlPositive ? "var(--compass-color-success)" : "var(--compass-color-error)"
|
|
10337
|
+
},
|
|
10338
|
+
children: [
|
|
10339
|
+
isPnlPositive ? "+" : "",
|
|
10340
|
+
formatUSD(position.pnl.totalPnl)
|
|
10341
|
+
]
|
|
10342
|
+
}
|
|
10343
|
+
)
|
|
10344
|
+
]
|
|
10345
|
+
}
|
|
10346
|
+
)
|
|
10347
|
+
] }),
|
|
10348
|
+
(position.deposits.length > 0 || position.withdrawals.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
|
|
10349
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10350
|
+
"h3",
|
|
10351
|
+
{
|
|
10352
|
+
className: "font-semibold mb-3",
|
|
10353
|
+
style: { color: "var(--compass-color-text)" },
|
|
10354
|
+
children: "Transaction History"
|
|
10355
|
+
}
|
|
10356
|
+
),
|
|
10357
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
10358
|
+
position.deposits.map((tx, i) => {
|
|
10359
|
+
const date = formatDate(tx.timestamp);
|
|
10360
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10361
|
+
"div",
|
|
9694
10362
|
{
|
|
9695
|
-
className: "
|
|
9696
|
-
style: {
|
|
9697
|
-
color: isPnlPositive ? "var(--compass-color-success)" : "var(--compass-color-error)"
|
|
9698
|
-
},
|
|
10363
|
+
className: "flex items-center justify-between p-3 rounded-lg",
|
|
10364
|
+
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
9699
10365
|
children: [
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
|
|
9708
|
-
|
|
9709
|
-
|
|
9710
|
-
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
|
|
9717
|
-
|
|
9718
|
-
|
|
9719
|
-
|
|
9720
|
-
|
|
9721
|
-
|
|
9722
|
-
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
9726
|
-
children: [
|
|
9727
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
9728
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9729
|
-
"p",
|
|
9730
|
-
{
|
|
9731
|
-
className: "font-medium",
|
|
9732
|
-
style: { color: "var(--compass-color-success)" },
|
|
9733
|
-
children: [
|
|
9734
|
-
"+",
|
|
9735
|
-
formatAmount(tx.amount),
|
|
9736
|
-
" ",
|
|
9737
|
-
position.assetSymbol
|
|
9738
|
-
]
|
|
9739
|
-
}
|
|
9740
|
-
),
|
|
9741
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9742
|
-
"p",
|
|
10366
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
10367
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10368
|
+
"p",
|
|
10369
|
+
{
|
|
10370
|
+
className: "font-medium",
|
|
10371
|
+
style: { color: "var(--compass-color-success)" },
|
|
10372
|
+
children: [
|
|
10373
|
+
"+",
|
|
10374
|
+
formatAmount(tx.amount),
|
|
10375
|
+
" ",
|
|
10376
|
+
position.assetSymbol
|
|
10377
|
+
]
|
|
10378
|
+
}
|
|
10379
|
+
),
|
|
10380
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10381
|
+
"p",
|
|
10382
|
+
{
|
|
10383
|
+
className: "text-xs",
|
|
10384
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
10385
|
+
children: date ? `Deposit - ${date}` : "Deposit"
|
|
10386
|
+
}
|
|
10387
|
+
)
|
|
10388
|
+
] }),
|
|
10389
|
+
tx.txHash && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10390
|
+
"a",
|
|
9743
10391
|
{
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
10392
|
+
href: `https://etherscan.io/tx/${tx.txHash}`,
|
|
10393
|
+
target: "_blank",
|
|
10394
|
+
rel: "noopener noreferrer",
|
|
10395
|
+
className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
|
|
10396
|
+
style: { backgroundColor: "var(--compass-color-background)" },
|
|
10397
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
|
|
9747
10398
|
}
|
|
9748
10399
|
)
|
|
9749
|
-
]
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
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
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
|
|
9787
|
-
),
|
|
9788
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9789
|
-
"p",
|
|
10400
|
+
]
|
|
10401
|
+
},
|
|
10402
|
+
`deposit-${i}`
|
|
10403
|
+
);
|
|
10404
|
+
}),
|
|
10405
|
+
position.withdrawals.map((tx, i) => {
|
|
10406
|
+
const date = formatDate(tx.timestamp);
|
|
10407
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10408
|
+
"div",
|
|
10409
|
+
{
|
|
10410
|
+
className: "flex items-center justify-between p-3 rounded-lg",
|
|
10411
|
+
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
10412
|
+
children: [
|
|
10413
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
10414
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10415
|
+
"p",
|
|
10416
|
+
{
|
|
10417
|
+
className: "font-medium",
|
|
10418
|
+
style: { color: "var(--compass-color-error)" },
|
|
10419
|
+
children: [
|
|
10420
|
+
"-",
|
|
10421
|
+
formatAmount(tx.amount),
|
|
10422
|
+
" ",
|
|
10423
|
+
position.assetSymbol
|
|
10424
|
+
]
|
|
10425
|
+
}
|
|
10426
|
+
),
|
|
10427
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10428
|
+
"p",
|
|
10429
|
+
{
|
|
10430
|
+
className: "text-xs",
|
|
10431
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
10432
|
+
children: date ? `Withdrawal - ${date}` : "Withdrawal"
|
|
10433
|
+
}
|
|
10434
|
+
)
|
|
10435
|
+
] }),
|
|
10436
|
+
tx.txHash && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10437
|
+
"a",
|
|
9790
10438
|
{
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
10439
|
+
href: `https://etherscan.io/tx/${tx.txHash}`,
|
|
10440
|
+
target: "_blank",
|
|
10441
|
+
rel: "noopener noreferrer",
|
|
10442
|
+
className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
|
|
10443
|
+
style: { backgroundColor: "var(--compass-color-background)" },
|
|
10444
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
|
|
9794
10445
|
}
|
|
9795
10446
|
)
|
|
9796
|
-
]
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9802
|
-
rel: "noopener noreferrer",
|
|
9803
|
-
className: "p-2 rounded-lg hover:opacity-80 transition-opacity",
|
|
9804
|
-
style: { backgroundColor: "var(--compass-color-background)" },
|
|
9805
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
|
|
9806
|
-
}
|
|
9807
|
-
)
|
|
9808
|
-
]
|
|
9809
|
-
},
|
|
9810
|
-
`withdraw-${i}`
|
|
9811
|
-
);
|
|
9812
|
-
})
|
|
10447
|
+
]
|
|
10448
|
+
},
|
|
10449
|
+
`withdraw-${i}`
|
|
10450
|
+
);
|
|
10451
|
+
})
|
|
10452
|
+
] })
|
|
9813
10453
|
] })
|
|
9814
|
-
]
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
10454
|
+
]
|
|
10455
|
+
}
|
|
10456
|
+
)
|
|
10457
|
+
]
|
|
9818
10458
|
}
|
|
9819
10459
|
);
|
|
9820
10460
|
}
|
|
@@ -10583,7 +11223,7 @@ function AllocationEditor({
|
|
|
10583
11223
|
) })
|
|
10584
11224
|
] });
|
|
10585
11225
|
}
|
|
10586
|
-
var
|
|
11226
|
+
var EVM_CHAIN_IDS4 = {
|
|
10587
11227
|
ethereum: 1,
|
|
10588
11228
|
base: 8453,
|
|
10589
11229
|
arbitrum: 42161
|
|
@@ -10617,7 +11257,7 @@ function RebalancingWidget({
|
|
|
10617
11257
|
}) {
|
|
10618
11258
|
const { chainId: contextChainId, setChainId } = useChain();
|
|
10619
11259
|
const CHAIN_ID = chain || contextChainId;
|
|
10620
|
-
const { address, signTypedData, isConnected, login, logout, switchChain, walletChainId } = useEmbeddableWallet();
|
|
11260
|
+
const { address, signTypedData, isConnected, login, logout, switchChain, walletChainId, fundWallet, hasExternalWallet } = useEmbeddableWallet();
|
|
10621
11261
|
const { earnAccountAddress } = useEarnAccount();
|
|
10622
11262
|
const queryClient = reactQuery.useQueryClient();
|
|
10623
11263
|
const { portfolio, earnAccountMarkets, isMarketsLoading, isLoading, isError, error, refetch } = useRebalancingData(chain);
|
|
@@ -10666,10 +11306,11 @@ function RebalancingWidget({
|
|
|
10666
11306
|
const [selectedToken, setSelectedToken] = react.useState("USDC");
|
|
10667
11307
|
const [depositAmount, setDepositAmount] = react.useState("");
|
|
10668
11308
|
const [isTokenDropdownOpen, setIsTokenDropdownOpen] = react.useState(false);
|
|
10669
|
-
const [
|
|
10670
|
-
const [depositError, setDepositError] = react.useState(null);
|
|
10671
|
-
const [depositStatus, setDepositStatus] = react.useState("");
|
|
11309
|
+
const [depositTxState, setDepositTxState] = react.useState({ status: "idle" });
|
|
10672
11310
|
const earnBalanceRef = react.useRef(null);
|
|
11311
|
+
const { startPolling: startDepositPolling, clearPolling: clearDepositPolling } = useTxPolling({
|
|
11312
|
+
queryKeysToInvalidate: [["earnAccountBalances"], ["rebalancing"]]
|
|
11313
|
+
});
|
|
10673
11314
|
react.useEffect(() => {
|
|
10674
11315
|
setTargets([]);
|
|
10675
11316
|
setOriginalAllocations({});
|
|
@@ -10684,9 +11325,9 @@ function RebalancingWidget({
|
|
|
10684
11325
|
setIsSwapModalOpen(false);
|
|
10685
11326
|
setSelectedMarket(null);
|
|
10686
11327
|
setDepositAmount("");
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
}, [CHAIN_ID]);
|
|
11328
|
+
setDepositTxState({ status: "idle" });
|
|
11329
|
+
clearDepositPolling();
|
|
11330
|
+
}, [CHAIN_ID, clearDepositPolling]);
|
|
10690
11331
|
react.useEffect(() => {
|
|
10691
11332
|
if (portfolio && portfolio.positions.length > 0 && !hasInitializedTargets && !isLoading) {
|
|
10692
11333
|
const origAllocs = {};
|
|
@@ -10767,7 +11408,7 @@ function RebalancingWidget({
|
|
|
10767
11408
|
setTargets((prev) => prev.map((t, i) => i === index ? { ...t, targetPercent: rounded } : t));
|
|
10768
11409
|
}, []);
|
|
10769
11410
|
const ensureCorrectChain = react.useCallback(async () => {
|
|
10770
|
-
const targetChainId =
|
|
11411
|
+
const targetChainId = EVM_CHAIN_IDS4[CHAIN_ID];
|
|
10771
11412
|
if (!targetChainId) return;
|
|
10772
11413
|
if (walletChainId !== void 0 && walletChainId !== targetChainId) {
|
|
10773
11414
|
if (!switchChain) {
|
|
@@ -10899,13 +11540,11 @@ function RebalancingWidget({
|
|
|
10899
11540
|
};
|
|
10900
11541
|
const handleDeposit = react.useCallback(async () => {
|
|
10901
11542
|
if (!selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || !address || !signTypedData) return;
|
|
10902
|
-
|
|
10903
|
-
setDepositError(null);
|
|
11543
|
+
setDepositTxState({ status: "preparing" });
|
|
10904
11544
|
const underlyingToken = selectedMarket.underlyingToken;
|
|
10905
11545
|
try {
|
|
10906
11546
|
let resultTxHash;
|
|
10907
11547
|
if (needsSwap) {
|
|
10908
|
-
setDepositStatus("Getting swap quote...");
|
|
10909
11548
|
const quoteResponse = await fetch(
|
|
10910
11549
|
`/api/compass/swap/quote?owner=${address}&chain=${CHAIN_ID}&tokenIn=${selectedToken}&tokenOut=${underlyingToken}&amountIn=${depositAmount}`
|
|
10911
11550
|
);
|
|
@@ -10919,7 +11558,6 @@ function RebalancingWidget({
|
|
|
10919
11558
|
throw new Error("Invalid swap quote - no output amount");
|
|
10920
11559
|
}
|
|
10921
11560
|
const actualDepositAmount = (parseFloat(estimatedOutput) * 0.99999).toString();
|
|
10922
|
-
setDepositStatus("Preparing swap and deposit...");
|
|
10923
11561
|
const bundleActions = [
|
|
10924
11562
|
{
|
|
10925
11563
|
body: {
|
|
@@ -10953,7 +11591,7 @@ function RebalancingWidget({
|
|
|
10953
11591
|
throw new Error(errorData.error || "Failed to prepare bundle");
|
|
10954
11592
|
}
|
|
10955
11593
|
const { eip712, normalizedTypes, domain, message } = await prepareResponse.json();
|
|
10956
|
-
|
|
11594
|
+
setDepositTxState({ status: "signing" });
|
|
10957
11595
|
await ensureCorrectChain();
|
|
10958
11596
|
const signature = await signTypedData({
|
|
10959
11597
|
domain,
|
|
@@ -10961,7 +11599,7 @@ function RebalancingWidget({
|
|
|
10961
11599
|
primaryType: "SafeTx",
|
|
10962
11600
|
message
|
|
10963
11601
|
});
|
|
10964
|
-
|
|
11602
|
+
setDepositTxState({ status: "broadcasting" });
|
|
10965
11603
|
const executeResponse = await fetch("/api/compass/bundle/execute", {
|
|
10966
11604
|
method: "POST",
|
|
10967
11605
|
headers: { "Content-Type": "application/json" },
|
|
@@ -10979,7 +11617,6 @@ function RebalancingWidget({
|
|
|
10979
11617
|
const result = await executeResponse.json();
|
|
10980
11618
|
resultTxHash = result.txHash;
|
|
10981
11619
|
} else {
|
|
10982
|
-
setDepositStatus("Preparing deposit...");
|
|
10983
11620
|
const venueParams = buildVenueParamsFromMarket(selectedMarket);
|
|
10984
11621
|
const prepareResponse = await fetch("/api/compass/deposit/prepare", {
|
|
10985
11622
|
method: "POST",
|
|
@@ -10996,7 +11633,7 @@ function RebalancingWidget({
|
|
|
10996
11633
|
throw new Error(errData.error || "Failed to prepare deposit");
|
|
10997
11634
|
}
|
|
10998
11635
|
const prepareData = await prepareResponse.json();
|
|
10999
|
-
|
|
11636
|
+
setDepositTxState({ status: "signing" });
|
|
11000
11637
|
await ensureCorrectChain();
|
|
11001
11638
|
const signature = await signTypedData({
|
|
11002
11639
|
domain: prepareData.domain,
|
|
@@ -11004,7 +11641,7 @@ function RebalancingWidget({
|
|
|
11004
11641
|
primaryType: "SafeTx",
|
|
11005
11642
|
message: prepareData.message
|
|
11006
11643
|
});
|
|
11007
|
-
|
|
11644
|
+
setDepositTxState({ status: "broadcasting" });
|
|
11008
11645
|
const executeResponse = await fetch("/api/compass/deposit/execute", {
|
|
11009
11646
|
method: "POST",
|
|
11010
11647
|
headers: { "Content-Type": "application/json" },
|
|
@@ -11022,7 +11659,8 @@ function RebalancingWidget({
|
|
|
11022
11659
|
const result = await executeResponse.json();
|
|
11023
11660
|
resultTxHash = result.txHash;
|
|
11024
11661
|
}
|
|
11025
|
-
|
|
11662
|
+
setDepositTxState({ status: "submitted", txHash: resultTxHash });
|
|
11663
|
+
startDepositPolling(resultTxHash, setDepositTxState);
|
|
11026
11664
|
setDepositAmount("");
|
|
11027
11665
|
queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
|
|
11028
11666
|
queryClient.invalidateQueries({ queryKey: ["rebalancing"] });
|
|
@@ -11034,15 +11672,11 @@ function RebalancingWidget({
|
|
|
11034
11672
|
refetch();
|
|
11035
11673
|
}, delay);
|
|
11036
11674
|
}
|
|
11037
|
-
setTimeout(() => setDepositStatus(""), 3e3);
|
|
11038
11675
|
} catch (err) {
|
|
11039
|
-
|
|
11040
|
-
setDepositStatus("");
|
|
11676
|
+
setDepositTxState({ status: "failed", error: err instanceof Error ? err.message : "Deposit failed" });
|
|
11041
11677
|
onError?.(err instanceof Error ? err : new Error("Deposit failed"));
|
|
11042
|
-
} finally {
|
|
11043
|
-
setIsProcessing(false);
|
|
11044
11678
|
}
|
|
11045
|
-
}, [selectedMarket, depositAmount, address, signTypedData, selectedToken, needsSwap, CHAIN_ID, ensureCorrectChain, queryClient, refetch, onError]);
|
|
11679
|
+
}, [selectedMarket, depositAmount, address, signTypedData, selectedToken, needsSwap, CHAIN_ID, ensureCorrectChain, queryClient, refetch, onError, startDepositPolling]);
|
|
11046
11680
|
return /* @__PURE__ */ jsxRuntime.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: [
|
|
11047
11681
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minHeight: 0, overflowY: "auto", scrollbarWidth: "none", display: "flex", flexDirection: "column" }, children: [
|
|
11048
11682
|
showChainSwitcher && !chain && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "0 4px", marginBottom: "8px" }, children: /* @__PURE__ */ jsxRuntime.jsx(ChainSwitcher, {}) }),
|
|
@@ -11071,8 +11705,19 @@ function RebalancingWidget({
|
|
|
11071
11705
|
}
|
|
11072
11706
|
)
|
|
11073
11707
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11074
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-semibold mb-2", style: { color: "var(--compass-color-text)" }, children: "No positions found" }),
|
|
11075
|
-
/* @__PURE__ */ jsxRuntime.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." })
|
|
11708
|
+
/* @__PURE__ */ jsxRuntime.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" }),
|
|
11709
|
+
/* @__PURE__ */ jsxRuntime.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." }),
|
|
11710
|
+
fundWallet && earnAccountAddress && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "100%", maxWidth: "320px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11711
|
+
BuyForm,
|
|
11712
|
+
{
|
|
11713
|
+
targetAddress: earnAccountAddress,
|
|
11714
|
+
onComplete: () => {
|
|
11715
|
+
queryClient.invalidateQueries({ queryKey: ["rebalancingPortfolio"] });
|
|
11716
|
+
queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
|
|
11717
|
+
refetch();
|
|
11718
|
+
}
|
|
11719
|
+
}
|
|
11720
|
+
) })
|
|
11076
11721
|
] }) }),
|
|
11077
11722
|
state !== "loading" && state !== "empty" && portfolio && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11078
11723
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center text-center", style: { padding: "16px 16px 12px" }, children: [
|
|
@@ -11239,7 +11884,7 @@ function RebalancingWidget({
|
|
|
11239
11884
|
selectedMarket,
|
|
11240
11885
|
onMarketSelect: (market) => {
|
|
11241
11886
|
setSelectedMarket(market);
|
|
11242
|
-
|
|
11887
|
+
if (depositTxState.status === "failed") setDepositTxState({ status: "idle" });
|
|
11243
11888
|
},
|
|
11244
11889
|
isLoading: isMarketsLoading
|
|
11245
11890
|
}
|
|
@@ -11262,10 +11907,10 @@ function RebalancingWidget({
|
|
|
11262
11907
|
value: depositAmount,
|
|
11263
11908
|
onChange: (e) => {
|
|
11264
11909
|
setDepositAmount(e.target.value);
|
|
11265
|
-
|
|
11910
|
+
if (depositTxState.status === "failed") setDepositTxState({ status: "idle" });
|
|
11266
11911
|
},
|
|
11267
11912
|
placeholder: "0.00",
|
|
11268
|
-
disabled:
|
|
11913
|
+
disabled: depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed",
|
|
11269
11914
|
className: "flex-1 font-bold bg-transparent outline-none",
|
|
11270
11915
|
style: {
|
|
11271
11916
|
color: "var(--compass-color-text)",
|
|
@@ -11281,7 +11926,7 @@ function RebalancingWidget({
|
|
|
11281
11926
|
"button",
|
|
11282
11927
|
{
|
|
11283
11928
|
onClick: () => setIsTokenDropdownOpen(!isTokenDropdownOpen),
|
|
11284
|
-
disabled:
|
|
11929
|
+
disabled: depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed",
|
|
11285
11930
|
className: "flex items-center font-semibold",
|
|
11286
11931
|
style: {
|
|
11287
11932
|
backgroundColor: "var(--compass-color-surface-hover, var(--compass-color-surface))",
|
|
@@ -11318,7 +11963,7 @@ function RebalancingWidget({
|
|
|
11318
11963
|
onClick: () => {
|
|
11319
11964
|
setSelectedToken(token);
|
|
11320
11965
|
setIsTokenDropdownOpen(false);
|
|
11321
|
-
|
|
11966
|
+
if (depositTxState.status === "failed") setDepositTxState({ status: "idle" });
|
|
11322
11967
|
},
|
|
11323
11968
|
className: "w-full text-left font-medium",
|
|
11324
11969
|
style: {
|
|
@@ -11344,7 +11989,7 @@ function RebalancingWidget({
|
|
|
11344
11989
|
"button",
|
|
11345
11990
|
{
|
|
11346
11991
|
onClick: () => setDepositAmount(earnBalancesQuery.toString()),
|
|
11347
|
-
disabled:
|
|
11992
|
+
disabled: depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed",
|
|
11348
11993
|
className: "font-semibold",
|
|
11349
11994
|
style: { color: "var(--compass-color-primary)", fontSize: "0.8125rem", background: "none", border: "none", padding: 0 },
|
|
11350
11995
|
children: [
|
|
@@ -11381,26 +12026,12 @@ function RebalancingWidget({
|
|
|
11381
12026
|
]
|
|
11382
12027
|
}
|
|
11383
12028
|
),
|
|
11384
|
-
|
|
11385
|
-
"div",
|
|
11386
|
-
{
|
|
11387
|
-
className: "flex items-center",
|
|
11388
|
-
style: {
|
|
11389
|
-
backgroundColor: "var(--compass-color-error-muted)",
|
|
11390
|
-
color: "var(--compass-color-error)",
|
|
11391
|
-
borderRadius: "var(--compass-border-radius-lg)",
|
|
11392
|
-
padding: "12px 14px",
|
|
11393
|
-
gap: "8px",
|
|
11394
|
-
fontSize: "0.875rem"
|
|
11395
|
-
},
|
|
11396
|
-
children: depositError
|
|
11397
|
-
}
|
|
11398
|
-
),
|
|
12029
|
+
/* @__PURE__ */ jsxRuntime.jsx(TxStatus, { state: depositTxState }),
|
|
11399
12030
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11400
12031
|
"button",
|
|
11401
12032
|
{
|
|
11402
12033
|
onClick: !isConnected && login ? login : handleDeposit,
|
|
11403
|
-
disabled: isConnected && (
|
|
12034
|
+
disabled: isConnected && (depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed" || !selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || parseFloat(depositAmount) > earnBalancesQuery),
|
|
11404
12035
|
className: "w-full font-bold",
|
|
11405
12036
|
style: {
|
|
11406
12037
|
backgroundColor: "var(--compass-color-primary)",
|
|
@@ -11411,26 +12042,13 @@ function RebalancingWidget({
|
|
|
11411
12042
|
fontSize: "1rem",
|
|
11412
12043
|
transition: "all 200ms ease",
|
|
11413
12044
|
border: "none",
|
|
11414
|
-
opacity: isConnected && (
|
|
12045
|
+
opacity: isConnected && (depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed" || !selectedMarket || !depositAmount || parseFloat(depositAmount) <= 0 || parseFloat(depositAmount) > earnBalancesQuery) ? 0.4 : 1
|
|
11415
12046
|
},
|
|
11416
|
-
children: !isConnected ? "Connect Wallet" :
|
|
12047
|
+
children: !isConnected ? "Connect Wallet" : depositTxState.status !== "idle" && depositTxState.status !== "confirmed" && depositTxState.status !== "failed" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-center", style: { gap: "8px" }, children: [
|
|
11417
12048
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 16, className: "animate-spin" }),
|
|
11418
12049
|
"Processing..."
|
|
11419
12050
|
] }) : !selectedMarket ? "Select a market" : needsSwap ? "Swap & Deposit" : "Deposit"
|
|
11420
12051
|
}
|
|
11421
|
-
),
|
|
11422
|
-
depositStatus && !depositError && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11423
|
-
"div",
|
|
11424
|
-
{
|
|
11425
|
-
className: "text-sm text-center",
|
|
11426
|
-
style: {
|
|
11427
|
-
backgroundColor: depositStatus.includes("successful") ? "var(--compass-color-success-muted)" : "var(--compass-color-primary-muted, rgba(99, 102, 241, 0.1))",
|
|
11428
|
-
color: depositStatus.includes("successful") ? "var(--compass-color-success)" : "var(--compass-color-primary)",
|
|
11429
|
-
borderRadius: "var(--compass-border-radius-lg)",
|
|
11430
|
-
padding: "10px 12px"
|
|
11431
|
-
},
|
|
11432
|
-
children: depositStatus
|
|
11433
|
-
}
|
|
11434
12052
|
)
|
|
11435
12053
|
] }),
|
|
11436
12054
|
clientPreview && clientPreview.actions.length > 0 && state === "editing" && /* @__PURE__ */ jsxRuntime.jsxs(
|