@compass-labs/widgets 0.1.27 → 0.1.29
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.js +197 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +197 -56
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.js +7 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +7 -3
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -6475,7 +6475,7 @@ function useRebalancingData(chainOverride) {
|
|
|
6475
6475
|
if (usdValue <= 0) continue;
|
|
6476
6476
|
balances.push({
|
|
6477
6477
|
token: symbol,
|
|
6478
|
-
balance: parseFloat(td.
|
|
6478
|
+
balance: parseFloat(td.balanceFormatted || td.balance_formatted || "0"),
|
|
6479
6479
|
usdValue
|
|
6480
6480
|
});
|
|
6481
6481
|
}
|
|
@@ -6757,9 +6757,9 @@ function PortfolioBalanceCard({
|
|
|
6757
6757
|
totalIdleUsd,
|
|
6758
6758
|
idleBalances,
|
|
6759
6759
|
earnAccountAddress,
|
|
6760
|
-
|
|
6761
|
-
onTogglePositions,
|
|
6760
|
+
onViewPositions,
|
|
6762
6761
|
positionCount,
|
|
6762
|
+
totalEarned = 0,
|
|
6763
6763
|
showTopUp = true,
|
|
6764
6764
|
onTopUp
|
|
6765
6765
|
}) {
|
|
@@ -6857,27 +6857,43 @@ function PortfolioBalanceCard({
|
|
|
6857
6857
|
/* @__PURE__ */ jsx(
|
|
6858
6858
|
"button",
|
|
6859
6859
|
{
|
|
6860
|
-
onClick:
|
|
6861
|
-
|
|
6860
|
+
onClick: onViewPositions,
|
|
6861
|
+
disabled: positionCount === 0,
|
|
6862
|
+
className: "flex items-center justify-between w-full text-left transition-opacity hover:opacity-80 disabled:hover:opacity-100 disabled:cursor-default",
|
|
6862
6863
|
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", style: { gap: "calc(var(--compass-spacing-unit) * 0.25)" }, children: [
|
|
6863
6864
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center", style: { gap: "calc(var(--compass-spacing-unit) * 0.5)" }, children: [
|
|
6864
6865
|
/* @__PURE__ */ jsxs("span", { className: "text-sm", style: { color: "var(--compass-color-text-tertiary)" }, children: [
|
|
6865
6866
|
"Earning interest",
|
|
6866
|
-
positionCount >
|
|
6867
|
+
positionCount > 1 ? ` \xB7 ${positionCount} positions` : ""
|
|
6867
6868
|
] }),
|
|
6868
|
-
positionCount > 0 &&
|
|
6869
|
+
positionCount > 0 && /* @__PURE__ */ jsx(ChevronRight, { size: 14, style: { color: "var(--compass-color-text-tertiary)" } })
|
|
6869
6870
|
] }),
|
|
6870
|
-
/* @__PURE__ */
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6871
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center", style: { gap: "calc(var(--compass-spacing-unit) * 0.75)" }, children: [
|
|
6872
|
+
/* @__PURE__ */ jsx(
|
|
6873
|
+
"span",
|
|
6874
|
+
{
|
|
6875
|
+
className: "font-semibold",
|
|
6876
|
+
style: {
|
|
6877
|
+
color: "var(--compass-color-text)",
|
|
6878
|
+
fontSize: "1rem"
|
|
6879
|
+
},
|
|
6880
|
+
children: formatUSD(earningInterestUsd)
|
|
6881
|
+
}
|
|
6882
|
+
),
|
|
6883
|
+
positionCount > 0 && totalEarned !== 0 && /* @__PURE__ */ jsxs(
|
|
6884
|
+
"span",
|
|
6885
|
+
{
|
|
6886
|
+
className: "text-sm font-medium",
|
|
6887
|
+
style: {
|
|
6888
|
+
color: totalEarned >= 0 ? "var(--compass-color-success)" : "var(--compass-color-error)"
|
|
6889
|
+
},
|
|
6890
|
+
children: [
|
|
6891
|
+
totalEarned >= 0 ? "+" : "",
|
|
6892
|
+
formatUSD(totalEarned)
|
|
6893
|
+
]
|
|
6894
|
+
}
|
|
6895
|
+
)
|
|
6896
|
+
] })
|
|
6881
6897
|
] })
|
|
6882
6898
|
}
|
|
6883
6899
|
)
|
|
@@ -6908,6 +6924,55 @@ var VENUE_LABELS = {
|
|
|
6908
6924
|
aave: "Aave",
|
|
6909
6925
|
pendle_pt: "Pendle PT"
|
|
6910
6926
|
};
|
|
6927
|
+
function formatPercent(value) {
|
|
6928
|
+
if (value === 0) return "0%";
|
|
6929
|
+
if (Number.isInteger(value)) return `${value}%`;
|
|
6930
|
+
const str = value.toFixed(2).replace(/0+$/, "").replace(/\.$/, "");
|
|
6931
|
+
return `${str}%`;
|
|
6932
|
+
}
|
|
6933
|
+
function PercentInput({ value, onChange }) {
|
|
6934
|
+
const [localValue, setLocalValue] = useState(value.toString());
|
|
6935
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
6936
|
+
if (!isFocused && localValue !== value.toString()) {
|
|
6937
|
+
const parsed = parseFloat(localValue);
|
|
6938
|
+
if (isNaN(parsed) || Math.abs(parsed - value) > 1e-3) {
|
|
6939
|
+
setLocalValue(value.toString());
|
|
6940
|
+
}
|
|
6941
|
+
}
|
|
6942
|
+
return /* @__PURE__ */ jsx(
|
|
6943
|
+
"input",
|
|
6944
|
+
{
|
|
6945
|
+
type: "text",
|
|
6946
|
+
inputMode: "decimal",
|
|
6947
|
+
value: isFocused ? localValue : formatPercent(value).replace("%", ""),
|
|
6948
|
+
onFocus: () => {
|
|
6949
|
+
setIsFocused(true);
|
|
6950
|
+
setLocalValue(value.toString());
|
|
6951
|
+
},
|
|
6952
|
+
onChange: (e) => {
|
|
6953
|
+
const raw = e.target.value;
|
|
6954
|
+
setLocalValue(raw);
|
|
6955
|
+
const parsed = parseFloat(raw);
|
|
6956
|
+
if (!isNaN(parsed)) {
|
|
6957
|
+
onChange(Math.max(0, Math.min(100, parsed)));
|
|
6958
|
+
}
|
|
6959
|
+
},
|
|
6960
|
+
onBlur: () => {
|
|
6961
|
+
setIsFocused(false);
|
|
6962
|
+
const parsed = parseFloat(localValue);
|
|
6963
|
+
if (!isNaN(parsed)) {
|
|
6964
|
+
onChange(Math.max(0, Math.min(100, parsed)));
|
|
6965
|
+
}
|
|
6966
|
+
},
|
|
6967
|
+
className: "w-16 text-center text-xs font-mono rounded bg-transparent outline-none",
|
|
6968
|
+
style: {
|
|
6969
|
+
color: "var(--compass-color-text)",
|
|
6970
|
+
border: "1px solid var(--compass-color-border)",
|
|
6971
|
+
padding: "2px 0"
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6974
|
+
);
|
|
6975
|
+
}
|
|
6911
6976
|
function AllocationEditor({
|
|
6912
6977
|
portfolio,
|
|
6913
6978
|
targets,
|
|
@@ -7044,20 +7109,10 @@ function AllocationEditor({
|
|
|
7044
7109
|
),
|
|
7045
7110
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 flex-shrink-0", children: [
|
|
7046
7111
|
/* @__PURE__ */ jsx(
|
|
7047
|
-
|
|
7112
|
+
PercentInput,
|
|
7048
7113
|
{
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
onChange: (e) => onUpdatePercent(index, parseFloat(e.target.value) || 0),
|
|
7052
|
-
className: "w-16 text-center text-xs font-mono rounded bg-transparent outline-none",
|
|
7053
|
-
style: {
|
|
7054
|
-
color: "var(--compass-color-text)",
|
|
7055
|
-
border: "1px solid var(--compass-color-border)",
|
|
7056
|
-
padding: "2px 0"
|
|
7057
|
-
},
|
|
7058
|
-
min: 0,
|
|
7059
|
-
max: 100,
|
|
7060
|
-
step: 1e-3
|
|
7114
|
+
value: target.targetPercent,
|
|
7115
|
+
onChange: (val) => onUpdatePercent(index, val)
|
|
7061
7116
|
}
|
|
7062
7117
|
),
|
|
7063
7118
|
/* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)", width: "12px" }, children: "%" })
|
|
@@ -7069,10 +7124,9 @@ function AllocationEditor({
|
|
|
7069
7124
|
className: "text-xs font-mono",
|
|
7070
7125
|
style: { color: diff > 0 ? "var(--compass-color-success)" : "var(--compass-color-error)", fontSize: "10px" },
|
|
7071
7126
|
children: [
|
|
7072
|
-
currentPercent
|
|
7073
|
-
"
|
|
7074
|
-
target.targetPercent
|
|
7075
|
-
"%"
|
|
7127
|
+
formatPercent(currentPercent),
|
|
7128
|
+
" \u2192 ",
|
|
7129
|
+
formatPercent(target.targetPercent)
|
|
7076
7130
|
]
|
|
7077
7131
|
}
|
|
7078
7132
|
) })
|
|
@@ -7114,8 +7168,8 @@ function AllocationEditor({
|
|
|
7114
7168
|
color: "var(--compass-color-text-secondary)"
|
|
7115
7169
|
},
|
|
7116
7170
|
children: [
|
|
7117
|
-
targetSum
|
|
7118
|
-
"
|
|
7171
|
+
formatPercent(targetSum),
|
|
7172
|
+
" allocated"
|
|
7119
7173
|
]
|
|
7120
7174
|
}
|
|
7121
7175
|
) })
|
|
@@ -7181,7 +7235,8 @@ function RebalancingWidget({
|
|
|
7181
7235
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
7182
7236
|
const [txHash, setTxHash] = useState(null);
|
|
7183
7237
|
const [hasInitializedTargets, setHasInitializedTargets] = useState(false);
|
|
7184
|
-
const [
|
|
7238
|
+
const [isEarningsModalOpen, setIsEarningsModalOpen] = useState(false);
|
|
7239
|
+
const [isAddMarketExpanded, setIsAddMarketExpanded] = useState(false);
|
|
7185
7240
|
const [marketTab, setMarketTab] = useState("variable");
|
|
7186
7241
|
const [selectedMarket, setSelectedMarket] = useState(null);
|
|
7187
7242
|
const [selectedToken, setSelectedToken] = useState("USDC");
|
|
@@ -7199,7 +7254,7 @@ function RebalancingWidget({
|
|
|
7199
7254
|
setErrorMessage(null);
|
|
7200
7255
|
setTxHash(null);
|
|
7201
7256
|
setHasInitializedTargets(false);
|
|
7202
|
-
|
|
7257
|
+
setIsAddMarketExpanded(false);
|
|
7203
7258
|
setSelectedMarket(null);
|
|
7204
7259
|
setDepositAmount("");
|
|
7205
7260
|
setDepositError(null);
|
|
@@ -7271,11 +7326,22 @@ function RebalancingWidget({
|
|
|
7271
7326
|
const handleUpdatePercent = useCallback((index, value) => {
|
|
7272
7327
|
setTargets((prev) => prev.map((t, i) => i === index ? { ...t, targetPercent: Math.max(0, Math.min(100, value)) } : t));
|
|
7273
7328
|
}, []);
|
|
7329
|
+
const ensureCorrectChain = useCallback(async () => {
|
|
7330
|
+
const targetChainId = EVM_CHAIN_IDS2[CHAIN_ID];
|
|
7331
|
+
if (!targetChainId) return;
|
|
7332
|
+
if (walletChainId !== void 0 && walletChainId !== targetChainId) {
|
|
7333
|
+
if (!switchChain) {
|
|
7334
|
+
throw new Error(`Please switch your wallet to ${CHAIN_ID} (chain ${targetChainId})`);
|
|
7335
|
+
}
|
|
7336
|
+
await switchChain(targetChainId);
|
|
7337
|
+
}
|
|
7338
|
+
}, [walletChainId, switchChain, CHAIN_ID]);
|
|
7274
7339
|
const handlePreview = useCallback(async () => {
|
|
7275
7340
|
if (!portfolio || !hasChanges || !address) return;
|
|
7276
7341
|
setWidgetState("previewing");
|
|
7277
7342
|
setErrorMessage(null);
|
|
7278
7343
|
try {
|
|
7344
|
+
await ensureCorrectChain();
|
|
7279
7345
|
const response = await fetch("/api/compass/rebalance/preview", {
|
|
7280
7346
|
method: "POST",
|
|
7281
7347
|
headers: { "Content-Type": "application/json" },
|
|
@@ -7304,7 +7370,7 @@ function RebalancingWidget({
|
|
|
7304
7370
|
setWidgetState("error");
|
|
7305
7371
|
onError?.(err instanceof Error ? err : new Error("Preview failed"));
|
|
7306
7372
|
}
|
|
7307
|
-
}, [portfolio, hasChanges, address, CHAIN_ID, targets, defaultSlippage, clientPreview, onError]);
|
|
7373
|
+
}, [portfolio, hasChanges, address, CHAIN_ID, targets, defaultSlippage, clientPreview, onError, ensureCorrectChain]);
|
|
7308
7374
|
const handleExecute = useCallback(async () => {
|
|
7309
7375
|
if (!serverPreview?.eip712 || !address) return;
|
|
7310
7376
|
setWidgetState("signing");
|
|
@@ -7351,16 +7417,59 @@ function RebalancingWidget({
|
|
|
7351
7417
|
return idleBalance?.balance ?? 0;
|
|
7352
7418
|
}, [portfolio, selectedToken]);
|
|
7353
7419
|
const needsSwap = selectedMarket ? selectedToken !== selectedMarket.underlyingToken : false;
|
|
7354
|
-
const
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
}
|
|
7363
|
-
|
|
7420
|
+
const rawPositionsQuery = useQuery({
|
|
7421
|
+
queryKey: ["rebalancingRawPositions", CHAIN_ID, address],
|
|
7422
|
+
queryFn: async () => {
|
|
7423
|
+
if (!address) return [];
|
|
7424
|
+
const response = await fetch(`/api/compass/positions?chain=${CHAIN_ID}&owner=${address}`);
|
|
7425
|
+
if (!response.ok) return [];
|
|
7426
|
+
const data = await response.json();
|
|
7427
|
+
return data.positions || [];
|
|
7428
|
+
},
|
|
7429
|
+
enabled: !!address,
|
|
7430
|
+
staleTime: 3e4
|
|
7431
|
+
});
|
|
7432
|
+
const earningsPositions = useMemo(() => {
|
|
7433
|
+
return (rawPositionsQuery.data || []).map((pos, index) => ({
|
|
7434
|
+
id: `pos-${index}`,
|
|
7435
|
+
marketType: pos.protocol,
|
|
7436
|
+
marketName: pos.name,
|
|
7437
|
+
marketId: `${pos.protocol}-${index}`,
|
|
7438
|
+
amount: parseFloat(pos.balance || "0"),
|
|
7439
|
+
token: pos.symbol,
|
|
7440
|
+
apy: pos.apy || 0,
|
|
7441
|
+
performance: parseFloat(pos.pnl?.totalPnl || "0"),
|
|
7442
|
+
pnl: pos.pnl ? {
|
|
7443
|
+
unrealizedPnl: parseFloat(pos.pnl.unrealizedPnl || "0"),
|
|
7444
|
+
realizedPnl: parseFloat(pos.pnl.realizedPnl || "0"),
|
|
7445
|
+
totalPnl: parseFloat(pos.pnl.totalPnl || "0")
|
|
7446
|
+
} : void 0,
|
|
7447
|
+
transactions: [
|
|
7448
|
+
...(pos.deposits || []).map((d, i) => ({
|
|
7449
|
+
id: `dep-${index}-${i}`,
|
|
7450
|
+
type: "deposit",
|
|
7451
|
+
amount: parseFloat(d.amount || "0"),
|
|
7452
|
+
token: pos.symbol,
|
|
7453
|
+
txHash: d.txHash || "",
|
|
7454
|
+
timestamp: d.timestamp || void 0
|
|
7455
|
+
})),
|
|
7456
|
+
...(pos.withdrawals || []).map((w, i) => ({
|
|
7457
|
+
id: `wit-${index}-${i}`,
|
|
7458
|
+
type: "withdraw",
|
|
7459
|
+
amount: parseFloat(w.amount || "0"),
|
|
7460
|
+
token: pos.symbol,
|
|
7461
|
+
txHash: w.txHash || "",
|
|
7462
|
+
timestamp: w.timestamp || void 0
|
|
7463
|
+
}))
|
|
7464
|
+
].sort((a, b) => {
|
|
7465
|
+
if (a.timestamp && b.timestamp) return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
|
|
7466
|
+
if (a.timestamp) return -1;
|
|
7467
|
+
if (b.timestamp) return 1;
|
|
7468
|
+
return 0;
|
|
7469
|
+
})
|
|
7470
|
+
}));
|
|
7471
|
+
}, [rawPositionsQuery.data]);
|
|
7472
|
+
const totalEarned = useMemo(() => earningsPositions.reduce((sum, p) => sum + p.performance, 0), [earningsPositions]);
|
|
7364
7473
|
const buildVenueParamsFromMarket = (market) => {
|
|
7365
7474
|
switch (market.type) {
|
|
7366
7475
|
case "aave":
|
|
@@ -7615,14 +7724,14 @@ function RebalancingWidget({
|
|
|
7615
7724
|
totalUsd: portfolio.totalUsd,
|
|
7616
7725
|
totalIdleUsd: portfolio.totalIdleUsd,
|
|
7617
7726
|
idleBalances: portfolio.idleBalances,
|
|
7618
|
-
|
|
7619
|
-
onTogglePositions: () => setIsPositionsExpanded((prev) => !prev),
|
|
7727
|
+
onViewPositions: () => setIsEarningsModalOpen(true),
|
|
7620
7728
|
positionCount: portfolio.positions.length,
|
|
7729
|
+
totalEarned,
|
|
7621
7730
|
showTopUp,
|
|
7622
7731
|
onTopUp: () => earnBalanceRef.current?.openTransferModal()
|
|
7623
7732
|
}
|
|
7624
7733
|
),
|
|
7625
|
-
|
|
7734
|
+
/* @__PURE__ */ jsx(
|
|
7626
7735
|
AllocationEditor,
|
|
7627
7736
|
{
|
|
7628
7737
|
portfolio,
|
|
@@ -7635,8 +7744,30 @@ function RebalancingWidget({
|
|
|
7635
7744
|
onResetToCurrent: handleResetToCurrent,
|
|
7636
7745
|
onEqualSplit: handleEqualSplit
|
|
7637
7746
|
}
|
|
7638
|
-
)
|
|
7639
|
-
|
|
7747
|
+
),
|
|
7748
|
+
/* @__PURE__ */ jsxs(
|
|
7749
|
+
"button",
|
|
7750
|
+
{
|
|
7751
|
+
onClick: () => setIsAddMarketExpanded((prev) => !prev),
|
|
7752
|
+
className: "flex items-center font-medium transition-all hover:opacity-80",
|
|
7753
|
+
style: {
|
|
7754
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
7755
|
+
border: "1px solid var(--compass-color-border)",
|
|
7756
|
+
color: "var(--compass-color-text-secondary)",
|
|
7757
|
+
borderRadius: "var(--compass-border-radius-lg)",
|
|
7758
|
+
padding: "calc(var(--compass-spacing-unit) * 0.75) calc(var(--compass-spacing-unit) * 1)",
|
|
7759
|
+
gap: "calc(var(--compass-spacing-unit) * 0.5)",
|
|
7760
|
+
fontSize: "0.8125rem",
|
|
7761
|
+
width: "100%",
|
|
7762
|
+
justifyContent: "center"
|
|
7763
|
+
},
|
|
7764
|
+
children: [
|
|
7765
|
+
isAddMarketExpanded ? /* @__PURE__ */ jsx(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(Plus, { size: 14 }),
|
|
7766
|
+
isAddMarketExpanded ? "Hide" : "Add new market"
|
|
7767
|
+
]
|
|
7768
|
+
}
|
|
7769
|
+
),
|
|
7770
|
+
isAddMarketExpanded && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7640
7771
|
/* @__PURE__ */ jsx(
|
|
7641
7772
|
MarketSelector,
|
|
7642
7773
|
{
|
|
@@ -8056,7 +8187,17 @@ function RebalancingWidget({
|
|
|
8056
8187
|
]
|
|
8057
8188
|
}
|
|
8058
8189
|
) }),
|
|
8059
|
-
/* @__PURE__ */ jsx(EarnAccountBalance, { ref: earnBalanceRef, compact: true, hideVisual: true, onTransferComplete: () => refetch() })
|
|
8190
|
+
/* @__PURE__ */ jsx(EarnAccountBalance, { ref: earnBalanceRef, compact: true, hideVisual: true, onTransferComplete: () => refetch() }),
|
|
8191
|
+
/* @__PURE__ */ jsx(
|
|
8192
|
+
EarningsModal,
|
|
8193
|
+
{
|
|
8194
|
+
isOpen: isEarningsModalOpen,
|
|
8195
|
+
onClose: () => setIsEarningsModalOpen(false),
|
|
8196
|
+
positions: earningsPositions,
|
|
8197
|
+
totalEarned,
|
|
8198
|
+
isLoading: rawPositionsQuery.isLoading
|
|
8199
|
+
}
|
|
8200
|
+
)
|
|
8060
8201
|
]
|
|
8061
8202
|
}
|
|
8062
8203
|
);
|