@compass-labs/widgets 0.1.1 → 0.1.3
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 +42 -24
- package/dist/index.d.ts +42 -24
- package/dist/index.js +705 -249
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +706 -251
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.js +238 -32
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +238 -32
- package/dist/server/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -81,6 +81,7 @@ var WalletContext = react.createContext(null);
|
|
|
81
81
|
var disconnectedWallet = {
|
|
82
82
|
address: null,
|
|
83
83
|
isConnected: false,
|
|
84
|
+
walletChainId: void 0,
|
|
84
85
|
signTypedData: async () => {
|
|
85
86
|
throw new Error("No wallet connected. Please connect a wallet first.");
|
|
86
87
|
},
|
|
@@ -92,6 +93,7 @@ function WalletProvider({ children, wallet }) {
|
|
|
92
93
|
const value = wallet ? {
|
|
93
94
|
address: wallet.address,
|
|
94
95
|
isConnected: wallet.address !== null,
|
|
96
|
+
walletChainId: wallet.chainId,
|
|
95
97
|
signTypedData: wallet.signTypedData,
|
|
96
98
|
switchChain: wallet.switchChain ?? null,
|
|
97
99
|
login: wallet.login ?? null,
|
|
@@ -1263,6 +1265,16 @@ function formatAmount(value) {
|
|
|
1263
1265
|
if (isNaN(num)) return "0";
|
|
1264
1266
|
return parseFloat(num.toFixed(6)).toString();
|
|
1265
1267
|
}
|
|
1268
|
+
function formatUSD(value) {
|
|
1269
|
+
const num = typeof value === "string" ? parseFloat(value) : value;
|
|
1270
|
+
if (isNaN(num)) return "$0.00";
|
|
1271
|
+
return new Intl.NumberFormat("en-US", {
|
|
1272
|
+
style: "currency",
|
|
1273
|
+
currency: "USD",
|
|
1274
|
+
minimumFractionDigits: 2,
|
|
1275
|
+
maximumFractionDigits: 2
|
|
1276
|
+
}).format(num);
|
|
1277
|
+
}
|
|
1266
1278
|
function TokenSelector({
|
|
1267
1279
|
tokens,
|
|
1268
1280
|
selectedToken,
|
|
@@ -1384,8 +1396,8 @@ function DepositWithdrawForm({
|
|
|
1384
1396
|
const [isSubmitting, setIsSubmitting] = react.useState(false);
|
|
1385
1397
|
const [statusMessage, setStatusMessage] = react.useState("");
|
|
1386
1398
|
const [error, setError] = react.useState(null);
|
|
1387
|
-
const { address, isConnected, signTypedData } = useCompassWallet();
|
|
1388
|
-
const { chainId } = useChain();
|
|
1399
|
+
const { address, isConnected, signTypedData, switchChain } = useCompassWallet();
|
|
1400
|
+
const { chainId, chain } = useChain();
|
|
1389
1401
|
const { earnAccountAddress } = useEarnAccount();
|
|
1390
1402
|
const queryClient = reactQuery.useQueryClient();
|
|
1391
1403
|
const needsSwap = activeTab === "deposit" && selectedToken !== venueToken;
|
|
@@ -1399,7 +1411,7 @@ function DepositWithdrawForm({
|
|
|
1399
1411
|
);
|
|
1400
1412
|
if (!response.ok) return "0";
|
|
1401
1413
|
const data = await response.json();
|
|
1402
|
-
return data.balances?.[selectedToken] || "0";
|
|
1414
|
+
return data.balances?.[selectedToken]?.balance || "0";
|
|
1403
1415
|
} catch {
|
|
1404
1416
|
return "0";
|
|
1405
1417
|
}
|
|
@@ -1423,6 +1435,15 @@ function DepositWithdrawForm({
|
|
|
1423
1435
|
setStatusMessage("Preparing transaction...");
|
|
1424
1436
|
setError(null);
|
|
1425
1437
|
try {
|
|
1438
|
+
const targetChainId = chain.viemChain.id;
|
|
1439
|
+
if (switchChain) {
|
|
1440
|
+
setStatusMessage("Switching network...");
|
|
1441
|
+
try {
|
|
1442
|
+
await switchChain(targetChainId);
|
|
1443
|
+
} catch {
|
|
1444
|
+
throw new Error(`Please switch your wallet to ${chain.name} to continue`);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1426
1447
|
const isDeposit = activeTab === "deposit";
|
|
1427
1448
|
if (isDeposit && needsSwap) {
|
|
1428
1449
|
setStatusMessage("Getting swap quote...");
|
|
@@ -1570,6 +1591,7 @@ function DepositWithdrawForm({
|
|
|
1570
1591
|
address,
|
|
1571
1592
|
amount,
|
|
1572
1593
|
chainId,
|
|
1594
|
+
chain,
|
|
1573
1595
|
activeTab,
|
|
1574
1596
|
needsSwap,
|
|
1575
1597
|
selectedToken,
|
|
@@ -1577,6 +1599,7 @@ function DepositWithdrawForm({
|
|
|
1577
1599
|
venueType,
|
|
1578
1600
|
venueAddress,
|
|
1579
1601
|
signTypedData,
|
|
1602
|
+
switchChain,
|
|
1580
1603
|
queryClient,
|
|
1581
1604
|
onSuccess,
|
|
1582
1605
|
onError
|
|
@@ -2076,51 +2099,221 @@ function EarnAccountGuard({
|
|
|
2076
2099
|
}
|
|
2077
2100
|
);
|
|
2078
2101
|
}
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2102
|
+
function AccountBalancesModal({
|
|
2103
|
+
isOpen,
|
|
2104
|
+
onClose,
|
|
2105
|
+
balances,
|
|
2106
|
+
totalUsdValue,
|
|
2107
|
+
isLoading = false,
|
|
2108
|
+
earnAccountAddress
|
|
2109
|
+
}) {
|
|
2110
|
+
react.useEffect(() => {
|
|
2111
|
+
const handleEscape = (e) => {
|
|
2112
|
+
if (e.key === "Escape") onClose();
|
|
2113
|
+
};
|
|
2114
|
+
if (isOpen) {
|
|
2115
|
+
document.addEventListener("keydown", handleEscape);
|
|
2116
|
+
document.body.style.overflow = "hidden";
|
|
2117
|
+
}
|
|
2118
|
+
return () => {
|
|
2119
|
+
document.removeEventListener("keydown", handleEscape);
|
|
2120
|
+
document.body.style.overflow = "";
|
|
2121
|
+
};
|
|
2122
|
+
}, [isOpen, onClose]);
|
|
2123
|
+
if (!isOpen) return null;
|
|
2124
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
|
|
2125
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2126
|
+
"div",
|
|
2127
|
+
{
|
|
2128
|
+
className: "absolute inset-0",
|
|
2129
|
+
style: { backgroundColor: "var(--compass-color-overlay)" },
|
|
2130
|
+
onClick: onClose
|
|
2131
|
+
}
|
|
2132
|
+
),
|
|
2133
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2134
|
+
"div",
|
|
2135
|
+
{
|
|
2136
|
+
className: "relative w-full max-w-md mx-4 rounded-xl overflow-hidden",
|
|
2137
|
+
style: {
|
|
2138
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
2139
|
+
boxShadow: "var(--compass-shadow-lg)"
|
|
2140
|
+
},
|
|
2141
|
+
children: [
|
|
2142
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2143
|
+
"div",
|
|
2144
|
+
{
|
|
2145
|
+
className: "flex items-center justify-between px-4 py-3 border-b",
|
|
2146
|
+
style: { borderColor: "var(--compass-color-border)" },
|
|
2147
|
+
children: [
|
|
2148
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2149
|
+
"h2",
|
|
2150
|
+
{
|
|
2151
|
+
className: "font-semibold flex items-center gap-2",
|
|
2152
|
+
style: {
|
|
2153
|
+
fontSize: "var(--compass-font-size-subheading)",
|
|
2154
|
+
color: "var(--compass-color-text)"
|
|
2155
|
+
},
|
|
2156
|
+
children: [
|
|
2157
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Coins, { size: 20 }),
|
|
2158
|
+
"Account Balances"
|
|
2159
|
+
]
|
|
2160
|
+
}
|
|
2161
|
+
),
|
|
2162
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2163
|
+
"button",
|
|
2164
|
+
{
|
|
2165
|
+
onClick: onClose,
|
|
2166
|
+
className: "p-1 rounded-md transition-colors hover:opacity-70",
|
|
2167
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
2168
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 20 })
|
|
2169
|
+
}
|
|
2170
|
+
)
|
|
2171
|
+
]
|
|
2172
|
+
}
|
|
2173
|
+
),
|
|
2174
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
|
|
2175
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2176
|
+
lucideReact.Loader2,
|
|
2177
|
+
{
|
|
2178
|
+
size: 24,
|
|
2179
|
+
className: "animate-spin",
|
|
2180
|
+
style: { color: "var(--compass-color-primary)" }
|
|
2181
|
+
}
|
|
2182
|
+
) }) : balances.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2183
|
+
"div",
|
|
2184
|
+
{
|
|
2185
|
+
className: "text-center py-8",
|
|
2186
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
2187
|
+
children: "No token balances found"
|
|
2188
|
+
}
|
|
2189
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2190
|
+
balances.map((token) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2191
|
+
"div",
|
|
2192
|
+
{
|
|
2193
|
+
className: "flex items-center justify-between p-3 rounded-lg",
|
|
2194
|
+
style: { backgroundColor: "var(--compass-color-background)" },
|
|
2195
|
+
children: [
|
|
2196
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2197
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2198
|
+
"div",
|
|
2199
|
+
{
|
|
2200
|
+
className: "w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold",
|
|
2201
|
+
style: {
|
|
2202
|
+
backgroundColor: "var(--compass-color-primary-muted)",
|
|
2203
|
+
color: "var(--compass-color-primary)"
|
|
2204
|
+
},
|
|
2205
|
+
children: token.symbol.slice(0, 2)
|
|
2206
|
+
}
|
|
2207
|
+
),
|
|
2208
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2209
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2210
|
+
"div",
|
|
2211
|
+
{
|
|
2212
|
+
className: "font-medium",
|
|
2213
|
+
style: { color: "var(--compass-color-text)" },
|
|
2214
|
+
children: token.symbol
|
|
2215
|
+
}
|
|
2216
|
+
),
|
|
2217
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2218
|
+
"div",
|
|
2219
|
+
{
|
|
2220
|
+
className: "text-sm font-mono",
|
|
2221
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
2222
|
+
children: formatAmount(token.balance)
|
|
2223
|
+
}
|
|
2224
|
+
)
|
|
2225
|
+
] })
|
|
2226
|
+
] }),
|
|
2227
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2228
|
+
"div",
|
|
2229
|
+
{
|
|
2230
|
+
className: "font-medium",
|
|
2231
|
+
style: { color: "var(--compass-color-text)" },
|
|
2232
|
+
children: formatUSD(token.usdValue)
|
|
2233
|
+
}
|
|
2234
|
+
)
|
|
2235
|
+
]
|
|
2236
|
+
},
|
|
2237
|
+
token.symbol
|
|
2238
|
+
)),
|
|
2239
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2240
|
+
"div",
|
|
2241
|
+
{
|
|
2242
|
+
className: "flex items-center justify-between p-3 mt-2 rounded-lg border",
|
|
2243
|
+
style: {
|
|
2244
|
+
borderColor: "var(--compass-color-border)",
|
|
2245
|
+
backgroundColor: "var(--compass-color-surface)"
|
|
2246
|
+
},
|
|
2247
|
+
children: [
|
|
2248
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2249
|
+
"span",
|
|
2250
|
+
{
|
|
2251
|
+
className: "font-medium",
|
|
2252
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
2253
|
+
children: "Total Balance"
|
|
2254
|
+
}
|
|
2255
|
+
),
|
|
2256
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2257
|
+
"span",
|
|
2258
|
+
{
|
|
2259
|
+
className: "font-bold text-lg",
|
|
2260
|
+
style: { color: "var(--compass-color-text)" },
|
|
2261
|
+
children: formatUSD(totalUsdValue)
|
|
2262
|
+
}
|
|
2263
|
+
)
|
|
2264
|
+
]
|
|
2265
|
+
}
|
|
2266
|
+
)
|
|
2267
|
+
] }),
|
|
2268
|
+
earnAccountAddress && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2269
|
+
"div",
|
|
2270
|
+
{
|
|
2271
|
+
className: "mt-4 pt-4 border-t text-center",
|
|
2272
|
+
style: { borderColor: "var(--compass-color-border)" },
|
|
2273
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2274
|
+
"span",
|
|
2275
|
+
{
|
|
2276
|
+
className: "text-xs",
|
|
2277
|
+
style: { color: "var(--compass-color-text-tertiary)" },
|
|
2278
|
+
children: [
|
|
2279
|
+
"Earn Account: ",
|
|
2280
|
+
earnAccountAddress.slice(0, 6),
|
|
2281
|
+
"...",
|
|
2282
|
+
earnAccountAddress.slice(-4)
|
|
2283
|
+
]
|
|
2284
|
+
}
|
|
2285
|
+
)
|
|
2286
|
+
}
|
|
2287
|
+
)
|
|
2288
|
+
] })
|
|
2289
|
+
]
|
|
2290
|
+
}
|
|
2291
|
+
)
|
|
2292
|
+
] });
|
|
2101
2293
|
}
|
|
2294
|
+
var TRANSFER_TOKENS = ["USDC"];
|
|
2102
2295
|
function EarnAccountBalance({
|
|
2103
|
-
tokens = DEFAULT_TOKENS,
|
|
2104
2296
|
compact = false,
|
|
2105
2297
|
onTransferComplete
|
|
2106
2298
|
}) {
|
|
2107
2299
|
const [isModalOpen, setIsModalOpen] = react.useState(false);
|
|
2108
2300
|
const [activeAction, setActiveAction] = react.useState("deposit");
|
|
2109
|
-
const [selectedToken, setSelectedToken] = react.useState(
|
|
2301
|
+
const [selectedToken, setSelectedToken] = react.useState(TRANSFER_TOKENS[0]);
|
|
2110
2302
|
const [amount, setAmount] = react.useState("");
|
|
2111
2303
|
const [transferState, setTransferState] = react.useState("idle");
|
|
2112
2304
|
const [statusMessage, setStatusMessage] = react.useState("");
|
|
2113
2305
|
const [error, setError] = react.useState(null);
|
|
2114
|
-
const
|
|
2115
|
-
const {
|
|
2306
|
+
const [isBalancesModalOpen, setIsBalancesModalOpen] = react.useState(false);
|
|
2307
|
+
const { address, isConnected, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
|
|
2308
|
+
const { chainId, chain } = useChain();
|
|
2116
2309
|
const { earnAccountAddress, isDeployed } = useEarnAccount();
|
|
2117
2310
|
const queryClient = reactQuery.useQueryClient();
|
|
2118
2311
|
const { data: balanceData, isLoading: balancesLoading } = reactQuery.useQuery({
|
|
2119
|
-
queryKey: ["earnAccountBalances", chainId, address
|
|
2312
|
+
queryKey: ["earnAccountBalances", chainId, address],
|
|
2120
2313
|
queryFn: async () => {
|
|
2121
2314
|
if (!address) return null;
|
|
2122
2315
|
const response = await fetch(
|
|
2123
|
-
`/api/compass/earn-account/balances?owner=${address}&chain=${chainId}
|
|
2316
|
+
`/api/compass/earn-account/balances?owner=${address}&chain=${chainId}`
|
|
2124
2317
|
);
|
|
2125
2318
|
if (!response.ok) {
|
|
2126
2319
|
throw new Error("Failed to fetch balances");
|
|
@@ -2131,19 +2324,41 @@ function EarnAccountBalance({
|
|
|
2131
2324
|
staleTime: 30 * 1e3
|
|
2132
2325
|
});
|
|
2133
2326
|
const { data: eoaBalances } = reactQuery.useQuery({
|
|
2134
|
-
queryKey: ["eoaBalances", chainId, address,
|
|
2327
|
+
queryKey: ["eoaBalances", chainId, address, TRANSFER_TOKENS.join(",")],
|
|
2135
2328
|
queryFn: async () => {
|
|
2136
2329
|
if (!address) return {};
|
|
2137
2330
|
const balances = {};
|
|
2331
|
+
for (const token of TRANSFER_TOKENS) {
|
|
2332
|
+
try {
|
|
2333
|
+
const response = await fetch(
|
|
2334
|
+
`/api/compass/token/balance?chain=${chainId}&token=${token}&address=${address}`
|
|
2335
|
+
);
|
|
2336
|
+
if (response.ok) {
|
|
2337
|
+
const data = await response.json();
|
|
2338
|
+
balances[token] = data.balance || "0";
|
|
2339
|
+
}
|
|
2340
|
+
} catch {
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2138
2343
|
return balances;
|
|
2139
2344
|
},
|
|
2140
2345
|
enabled: !!address && activeAction === "deposit",
|
|
2141
2346
|
staleTime: 30 * 1e3
|
|
2142
2347
|
});
|
|
2143
2348
|
const earnBalances = balanceData?.balances || {};
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2349
|
+
const totalUsdValue = parseFloat(balanceData?.totalUsdValue || "0");
|
|
2350
|
+
const tokenBalances = Object.entries(earnBalances).filter(([, data]) => {
|
|
2351
|
+
const usdVal = parseFloat(data.usdValue || "0");
|
|
2352
|
+
return usdVal > 0;
|
|
2353
|
+
}).map(([symbol, data]) => ({
|
|
2354
|
+
symbol,
|
|
2355
|
+
balance: data.balance || "0",
|
|
2356
|
+
usdValue: data.usdValue || "0"
|
|
2357
|
+
}));
|
|
2358
|
+
const earnBalanceAmounts = {};
|
|
2359
|
+
for (const [symbol, data] of Object.entries(earnBalances)) {
|
|
2360
|
+
earnBalanceAmounts[symbol] = data.balance;
|
|
2361
|
+
}
|
|
2147
2362
|
const resetForm = react.useCallback(() => {
|
|
2148
2363
|
setAmount("");
|
|
2149
2364
|
setTransferState("idle");
|
|
@@ -2167,7 +2382,7 @@ function EarnAccountBalance({
|
|
|
2167
2382
|
if (activeAction === "deposit") {
|
|
2168
2383
|
return eoaBalances?.[selectedToken] || "0";
|
|
2169
2384
|
}
|
|
2170
|
-
return
|
|
2385
|
+
return earnBalanceAmounts[selectedToken] || "0";
|
|
2171
2386
|
};
|
|
2172
2387
|
const handleQuickAmount = (percentage) => {
|
|
2173
2388
|
const max = parseFloat(getMaxBalance());
|
|
@@ -2178,55 +2393,70 @@ function EarnAccountBalance({
|
|
|
2178
2393
|
if (!address || !amount || !signTypedData) return;
|
|
2179
2394
|
setError(null);
|
|
2180
2395
|
try {
|
|
2396
|
+
const targetChainId = chain.viemChain.id;
|
|
2397
|
+
if (walletChainId !== void 0 && walletChainId !== targetChainId) {
|
|
2398
|
+
if (!switchChain) {
|
|
2399
|
+
throw new Error(`Please switch your wallet to ${chain.name} (chain ID ${targetChainId}) to continue. Your wallet is currently on chain ID ${walletChainId}.`);
|
|
2400
|
+
}
|
|
2401
|
+
setStatusMessage(`Switching network to ${chain.name}...`);
|
|
2402
|
+
try {
|
|
2403
|
+
await switchChain(targetChainId);
|
|
2404
|
+
} catch (switchError) {
|
|
2405
|
+
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}.`);
|
|
2406
|
+
}
|
|
2407
|
+
} else if (switchChain && walletChainId === void 0) {
|
|
2408
|
+
setStatusMessage("Switching network...");
|
|
2409
|
+
try {
|
|
2410
|
+
await switchChain(targetChainId);
|
|
2411
|
+
} catch (switchError) {
|
|
2412
|
+
throw new Error(`Please switch your wallet to ${chain.name} to continue`);
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2181
2415
|
if (activeAction === "deposit") {
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2416
|
+
setTransferState("checking_approval");
|
|
2417
|
+
setStatusMessage("Checking token approval...");
|
|
2418
|
+
const approveResponse = await fetch("/api/compass/transfer/approve", {
|
|
2419
|
+
method: "POST",
|
|
2420
|
+
headers: { "Content-Type": "application/json" },
|
|
2421
|
+
body: JSON.stringify({
|
|
2422
|
+
owner: address,
|
|
2423
|
+
chain: chainId,
|
|
2424
|
+
token: selectedToken
|
|
2425
|
+
})
|
|
2426
|
+
});
|
|
2427
|
+
if (!approveResponse.ok) {
|
|
2428
|
+
const errData = await approveResponse.json();
|
|
2429
|
+
throw new Error(errData.error || "Failed to check approval");
|
|
2430
|
+
}
|
|
2431
|
+
const approvalData = await approveResponse.json();
|
|
2432
|
+
if (!approvalData.approved) {
|
|
2433
|
+
if (approvalData.requiresTransaction) {
|
|
2434
|
+
throw new Error("This token requires a transaction-based approval. Please approve manually.");
|
|
2435
|
+
}
|
|
2436
|
+
setTransferState("awaiting_approval_signature");
|
|
2437
|
+
setStatusMessage("Please sign the approval...");
|
|
2438
|
+
const approvalSignature = await signTypedData({
|
|
2439
|
+
domain: approvalData.domain,
|
|
2440
|
+
types: approvalData.normalizedTypes,
|
|
2441
|
+
primaryType: "Permit",
|
|
2442
|
+
message: approvalData.message
|
|
2443
|
+
});
|
|
2444
|
+
setTransferState("approving");
|
|
2445
|
+
setStatusMessage("Executing approval...");
|
|
2446
|
+
const executeApprovalResponse = await fetch("/api/compass/transfer/execute", {
|
|
2187
2447
|
method: "POST",
|
|
2188
2448
|
headers: { "Content-Type": "application/json" },
|
|
2189
2449
|
body: JSON.stringify({
|
|
2190
2450
|
owner: address,
|
|
2191
2451
|
chain: chainId,
|
|
2192
|
-
|
|
2452
|
+
eip712: approvalData.eip712,
|
|
2453
|
+
signature: approvalSignature
|
|
2193
2454
|
})
|
|
2194
2455
|
});
|
|
2195
|
-
if (!
|
|
2196
|
-
const errData = await
|
|
2197
|
-
throw new Error(errData.error || "
|
|
2198
|
-
}
|
|
2199
|
-
const approvalData = await approveResponse.json();
|
|
2200
|
-
if (!approvalData.approved) {
|
|
2201
|
-
if (approvalData.requiresTransaction) {
|
|
2202
|
-
throw new Error("This token requires a transaction-based approval. Please approve manually.");
|
|
2203
|
-
}
|
|
2204
|
-
setTransferState("awaiting_approval_signature");
|
|
2205
|
-
setStatusMessage("Please sign the approval...");
|
|
2206
|
-
const approvalSignature = await signTypedData({
|
|
2207
|
-
domain: approvalData.domain,
|
|
2208
|
-
types: approvalData.normalizedTypes,
|
|
2209
|
-
primaryType: "Permit",
|
|
2210
|
-
message: approvalData.message
|
|
2211
|
-
});
|
|
2212
|
-
setTransferState("approving");
|
|
2213
|
-
setStatusMessage("Executing approval...");
|
|
2214
|
-
const executeApprovalResponse = await fetch("/api/compass/transfer/execute", {
|
|
2215
|
-
method: "POST",
|
|
2216
|
-
headers: { "Content-Type": "application/json" },
|
|
2217
|
-
body: JSON.stringify({
|
|
2218
|
-
owner: address,
|
|
2219
|
-
chain: chainId,
|
|
2220
|
-
eip712: approvalData.eip712,
|
|
2221
|
-
signature: approvalSignature
|
|
2222
|
-
})
|
|
2223
|
-
});
|
|
2224
|
-
if (!executeApprovalResponse.ok) {
|
|
2225
|
-
const errData = await executeApprovalResponse.json();
|
|
2226
|
-
throw new Error(errData.error || "Approval failed");
|
|
2227
|
-
}
|
|
2456
|
+
if (!executeApprovalResponse.ok) {
|
|
2457
|
+
const errData = await executeApprovalResponse.json();
|
|
2458
|
+
throw new Error(errData.error || "Approval failed");
|
|
2228
2459
|
}
|
|
2229
|
-
cacheApproval(chainId, address, selectedToken);
|
|
2230
2460
|
}
|
|
2231
2461
|
}
|
|
2232
2462
|
setTransferState("awaiting_transfer_signature");
|
|
@@ -2290,7 +2520,10 @@ function EarnAccountBalance({
|
|
|
2290
2520
|
activeAction,
|
|
2291
2521
|
selectedToken,
|
|
2292
2522
|
chainId,
|
|
2523
|
+
chain,
|
|
2524
|
+
walletChainId,
|
|
2293
2525
|
signTypedData,
|
|
2526
|
+
switchChain,
|
|
2294
2527
|
queryClient,
|
|
2295
2528
|
onTransferComplete,
|
|
2296
2529
|
resetForm
|
|
@@ -2323,6 +2556,29 @@ function EarnAccountBalance({
|
|
|
2323
2556
|
);
|
|
2324
2557
|
}
|
|
2325
2558
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2559
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2560
|
+
"button",
|
|
2561
|
+
{
|
|
2562
|
+
onClick: () => setIsBalancesModalOpen(true),
|
|
2563
|
+
className: `flex items-center gap-2 rounded-lg border transition-colors hover:border-[var(--compass-color-primary)] ${compact ? "px-2 py-1.5" : "px-3 py-2"}`,
|
|
2564
|
+
style: {
|
|
2565
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
2566
|
+
borderColor: "var(--compass-color-border)",
|
|
2567
|
+
cursor: "pointer"
|
|
2568
|
+
},
|
|
2569
|
+
children: [
|
|
2570
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { size: compact ? 14 : 16, style: { color: "var(--compass-color-primary)" } }),
|
|
2571
|
+
balancesLoading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: compact ? 12 : 14, className: "animate-spin", style: { color: "var(--compass-color-text-secondary)" } }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2572
|
+
"span",
|
|
2573
|
+
{
|
|
2574
|
+
className: `font-medium ${compact ? "text-xs" : "text-sm"}`,
|
|
2575
|
+
style: { color: "var(--compass-color-text)" },
|
|
2576
|
+
children: formatUSD(totalUsdValue)
|
|
2577
|
+
}
|
|
2578
|
+
)
|
|
2579
|
+
]
|
|
2580
|
+
}
|
|
2581
|
+
),
|
|
2326
2582
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2327
2583
|
"button",
|
|
2328
2584
|
{
|
|
@@ -2332,7 +2588,18 @@ function EarnAccountBalance({
|
|
|
2332
2588
|
backgroundColor: "var(--compass-color-primary)",
|
|
2333
2589
|
color: "var(--compass-color-primary-text)"
|
|
2334
2590
|
},
|
|
2335
|
-
children: "
|
|
2591
|
+
children: "Fund"
|
|
2592
|
+
}
|
|
2593
|
+
),
|
|
2594
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2595
|
+
AccountBalancesModal,
|
|
2596
|
+
{
|
|
2597
|
+
isOpen: isBalancesModalOpen,
|
|
2598
|
+
onClose: () => setIsBalancesModalOpen(false),
|
|
2599
|
+
balances: tokenBalances,
|
|
2600
|
+
totalUsdValue: totalUsdValue.toString(),
|
|
2601
|
+
isLoading: balancesLoading,
|
|
2602
|
+
earnAccountAddress: earnAccountAddress ?? void 0
|
|
2336
2603
|
}
|
|
2337
2604
|
),
|
|
2338
2605
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2378,10 +2645,10 @@ function EarnAccountBalance({
|
|
|
2378
2645
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2379
2646
|
TokenSelector,
|
|
2380
2647
|
{
|
|
2381
|
-
tokens,
|
|
2648
|
+
tokens: TRANSFER_TOKENS,
|
|
2382
2649
|
selectedToken,
|
|
2383
2650
|
onSelect: setSelectedToken,
|
|
2384
|
-
balances: activeAction === "deposit" ? eoaBalances :
|
|
2651
|
+
balances: activeAction === "deposit" ? eoaBalances : earnBalanceAmounts,
|
|
2385
2652
|
disabled: isProcessing
|
|
2386
2653
|
}
|
|
2387
2654
|
)
|
|
@@ -2633,9 +2900,9 @@ function useVaultsData(options = {}) {
|
|
|
2633
2900
|
const { client } = useEmbeddableApi();
|
|
2634
2901
|
const { address } = useEmbeddableWallet();
|
|
2635
2902
|
const { chainId } = useChain();
|
|
2636
|
-
const { sortBy = "apy_7d", assetFilter, minApy } = options;
|
|
2903
|
+
const { sortBy = "apy_7d", assetFilter, minApy, minTvl } = options;
|
|
2637
2904
|
const vaultsQuery = reactQuery.useQuery({
|
|
2638
|
-
queryKey: ["vaults", chainId, sortBy, assetFilter, minApy],
|
|
2905
|
+
queryKey: ["vaults", chainId, sortBy, assetFilter, minApy, minTvl],
|
|
2639
2906
|
queryFn: async () => {
|
|
2640
2907
|
const assetSymbol = assetFilter && assetFilter.length === 1 ? assetFilter[0] : void 0;
|
|
2641
2908
|
const response = await client.earn.earnVaults({
|
|
@@ -2665,6 +2932,12 @@ function useVaultsData(options = {}) {
|
|
|
2665
2932
|
return apy >= minApy;
|
|
2666
2933
|
});
|
|
2667
2934
|
}
|
|
2935
|
+
if (minTvl !== void 0 && minTvl > 0) {
|
|
2936
|
+
vaults = vaults.filter((v) => {
|
|
2937
|
+
const tvl = parseFloat(v.tvlUsd || "0");
|
|
2938
|
+
return tvl >= minTvl;
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
2668
2941
|
return vaults;
|
|
2669
2942
|
},
|
|
2670
2943
|
staleTime: 30 * 1e3
|
|
@@ -2730,6 +3003,8 @@ function VaultsList({
|
|
|
2730
3003
|
defaultSort = "apy_7d",
|
|
2731
3004
|
assetFilter,
|
|
2732
3005
|
minApy,
|
|
3006
|
+
minTvl: initialMinTvl,
|
|
3007
|
+
showTvlFilter = true,
|
|
2733
3008
|
onVaultSelect,
|
|
2734
3009
|
onDeposit,
|
|
2735
3010
|
onWithdraw
|
|
@@ -2737,11 +3012,18 @@ function VaultsList({
|
|
|
2737
3012
|
const [searchQuery, setSearchQuery] = react.useState("");
|
|
2738
3013
|
const [sortBy, setSortBy] = react.useState(defaultSort);
|
|
2739
3014
|
const [selectedVault, setSelectedVault] = react.useState(null);
|
|
3015
|
+
const [minTvlFilter, setMinTvlFilter] = react.useState(initialMinTvl);
|
|
3016
|
+
const [showFilterPanel, setShowFilterPanel] = react.useState(false);
|
|
2740
3017
|
const { vaults, isLoading, isError, refetch } = useVaultsData({
|
|
2741
3018
|
sortBy,
|
|
2742
3019
|
assetFilter,
|
|
2743
|
-
minApy
|
|
3020
|
+
minApy,
|
|
3021
|
+
minTvl: minTvlFilter
|
|
2744
3022
|
});
|
|
3023
|
+
const handleMinTvlChange = react.useCallback((value) => {
|
|
3024
|
+
const num = parseFloat(value);
|
|
3025
|
+
setMinTvlFilter(isNaN(num) || num <= 0 ? void 0 : num);
|
|
3026
|
+
}, []);
|
|
2745
3027
|
const filteredVaults = react.useMemo(() => {
|
|
2746
3028
|
if (!searchQuery) return vaults;
|
|
2747
3029
|
const query = searchQuery.toLowerCase();
|
|
@@ -2769,49 +3051,116 @@ function VaultsList({
|
|
|
2769
3051
|
/* @__PURE__ */ jsxRuntime.jsx(WalletStatus, { compact: true })
|
|
2770
3052
|
] })
|
|
2771
3053
|
] }),
|
|
2772
|
-
(showSearch || showSort) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
2773
|
-
|
|
3054
|
+
(showSearch || showSort || showTvlFilter) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3055
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
3056
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3057
|
+
"div",
|
|
3058
|
+
{
|
|
3059
|
+
className: "flex-1 flex items-center gap-2 px-3 py-2 rounded-lg border",
|
|
3060
|
+
style: {
|
|
3061
|
+
backgroundColor: "var(--compass-color-background)",
|
|
3062
|
+
borderColor: "var(--compass-color-border)"
|
|
3063
|
+
},
|
|
3064
|
+
children: [
|
|
3065
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
3066
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3067
|
+
"input",
|
|
3068
|
+
{
|
|
3069
|
+
type: "text",
|
|
3070
|
+
placeholder: "Search vaults...",
|
|
3071
|
+
value: searchQuery,
|
|
3072
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
3073
|
+
className: "flex-1 bg-transparent outline-none text-sm",
|
|
3074
|
+
style: { color: "var(--compass-color-text)" }
|
|
3075
|
+
}
|
|
3076
|
+
)
|
|
3077
|
+
]
|
|
3078
|
+
}
|
|
3079
|
+
),
|
|
3080
|
+
showSort && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3081
|
+
"select",
|
|
3082
|
+
{
|
|
3083
|
+
value: sortBy,
|
|
3084
|
+
onChange: (e) => setSortBy(e.target.value),
|
|
3085
|
+
className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
|
|
3086
|
+
style: {
|
|
3087
|
+
backgroundColor: "var(--compass-color-background)",
|
|
3088
|
+
borderColor: "var(--compass-color-border)",
|
|
3089
|
+
color: "var(--compass-color-text)"
|
|
3090
|
+
},
|
|
3091
|
+
children: [
|
|
3092
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "apy_7d", children: "APY (7D)" }),
|
|
3093
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "apy_30d", children: "APY (30D)" }),
|
|
3094
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "apy_90d", children: "APY (90D)" }),
|
|
3095
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "tvl", children: "TVL" })
|
|
3096
|
+
]
|
|
3097
|
+
}
|
|
3098
|
+
),
|
|
3099
|
+
showTvlFilter && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3100
|
+
"button",
|
|
3101
|
+
{
|
|
3102
|
+
onClick: () => setShowFilterPanel(!showFilterPanel),
|
|
3103
|
+
className: "px-3 py-2 rounded-lg border text-sm flex items-center gap-2",
|
|
3104
|
+
style: {
|
|
3105
|
+
backgroundColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary-muted)" : "var(--compass-color-background)",
|
|
3106
|
+
borderColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-border)",
|
|
3107
|
+
color: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-text)"
|
|
3108
|
+
},
|
|
3109
|
+
children: [
|
|
3110
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SlidersHorizontal, { size: 14 }),
|
|
3111
|
+
"Filter"
|
|
3112
|
+
]
|
|
3113
|
+
}
|
|
3114
|
+
)
|
|
3115
|
+
] }),
|
|
3116
|
+
showTvlFilter && showFilterPanel && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2774
3117
|
"div",
|
|
2775
3118
|
{
|
|
2776
|
-
className: "flex
|
|
3119
|
+
className: "flex items-center gap-3 p-3 rounded-lg border",
|
|
2777
3120
|
style: {
|
|
2778
|
-
backgroundColor: "var(--compass-color-
|
|
3121
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
2779
3122
|
borderColor: "var(--compass-color-border)"
|
|
2780
3123
|
},
|
|
2781
3124
|
children: [
|
|
2782
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
2783
3125
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2784
|
-
"
|
|
3126
|
+
"label",
|
|
2785
3127
|
{
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
3128
|
+
className: "text-sm font-medium whitespace-nowrap",
|
|
3129
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
3130
|
+
children: "Min TVL:"
|
|
3131
|
+
}
|
|
3132
|
+
),
|
|
3133
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3134
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-tertiary)" }, children: "$" }),
|
|
3135
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3136
|
+
"input",
|
|
3137
|
+
{
|
|
3138
|
+
type: "number",
|
|
3139
|
+
placeholder: "0",
|
|
3140
|
+
value: minTvlFilter || "",
|
|
3141
|
+
onChange: (e) => handleMinTvlChange(e.target.value),
|
|
3142
|
+
className: "w-24 px-2 py-1 rounded border text-sm bg-transparent",
|
|
3143
|
+
style: {
|
|
3144
|
+
borderColor: "var(--compass-color-border)",
|
|
3145
|
+
color: "var(--compass-color-text)"
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
)
|
|
3149
|
+
] }),
|
|
3150
|
+
minTvlFilter && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3151
|
+
"button",
|
|
3152
|
+
{
|
|
3153
|
+
onClick: () => setMinTvlFilter(void 0),
|
|
3154
|
+
className: "text-xs px-2 py-1 rounded",
|
|
3155
|
+
style: {
|
|
3156
|
+
backgroundColor: "var(--compass-color-error-muted)",
|
|
3157
|
+
color: "var(--compass-color-error)"
|
|
3158
|
+
},
|
|
3159
|
+
children: "Clear"
|
|
2792
3160
|
}
|
|
2793
3161
|
)
|
|
2794
3162
|
]
|
|
2795
3163
|
}
|
|
2796
|
-
),
|
|
2797
|
-
showSort && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2798
|
-
"select",
|
|
2799
|
-
{
|
|
2800
|
-
value: sortBy,
|
|
2801
|
-
onChange: (e) => setSortBy(e.target.value),
|
|
2802
|
-
className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
|
|
2803
|
-
style: {
|
|
2804
|
-
backgroundColor: "var(--compass-color-background)",
|
|
2805
|
-
borderColor: "var(--compass-color-border)",
|
|
2806
|
-
color: "var(--compass-color-text)"
|
|
2807
|
-
},
|
|
2808
|
-
children: [
|
|
2809
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "apy_7d", children: "APY (7D)" }),
|
|
2810
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "apy_30d", children: "APY (30D)" }),
|
|
2811
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "apy_90d", children: "APY (90D)" }),
|
|
2812
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "tvl", children: "TVL" })
|
|
2813
|
-
]
|
|
2814
|
-
}
|
|
2815
3164
|
)
|
|
2816
3165
|
] }),
|
|
2817
3166
|
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 24, className: "animate-spin", style: { color: "var(--compass-color-primary)" } }) }) : isError ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3223,9 +3572,9 @@ function usePendleData(options = {}) {
|
|
|
3223
3572
|
const { client } = useEmbeddableApi();
|
|
3224
3573
|
const { address } = useEmbeddableWallet();
|
|
3225
3574
|
const { chainId } = useChain();
|
|
3226
|
-
const { sortBy = "fixed_apy", assetFilter } = options;
|
|
3575
|
+
const { sortBy = "fixed_apy", assetFilter, minTvl } = options;
|
|
3227
3576
|
const marketsQuery = reactQuery.useQuery({
|
|
3228
|
-
queryKey: ["pendleMarkets", chainId, sortBy, assetFilter],
|
|
3577
|
+
queryKey: ["pendleMarkets", chainId, sortBy, assetFilter, minTvl],
|
|
3229
3578
|
queryFn: async () => {
|
|
3230
3579
|
const underlyingSymbol = assetFilter && assetFilter.length === 1 ? assetFilter[0] : void 0;
|
|
3231
3580
|
const orderBy = sortBy === "tvl" ? "tvl_usd" : "implied_apy";
|
|
@@ -3254,6 +3603,12 @@ function usePendleData(options = {}) {
|
|
|
3254
3603
|
(m) => assetFilter.includes(m.underlyingSymbol.toUpperCase())
|
|
3255
3604
|
);
|
|
3256
3605
|
}
|
|
3606
|
+
if (minTvl !== void 0 && minTvl > 0) {
|
|
3607
|
+
markets = markets.filter((m) => {
|
|
3608
|
+
const tvl = parseFloat(m.tvlUsd || "0");
|
|
3609
|
+
return tvl >= minTvl;
|
|
3610
|
+
});
|
|
3611
|
+
}
|
|
3257
3612
|
if (sortBy === "expiry") {
|
|
3258
3613
|
markets.sort((a, b) => {
|
|
3259
3614
|
return new Date(a.expiry).getTime() - new Date(b.expiry).getTime();
|
|
@@ -3339,6 +3694,8 @@ function PendleMarketsList({
|
|
|
3339
3694
|
showSort = true,
|
|
3340
3695
|
defaultSort = "fixed_apy",
|
|
3341
3696
|
assetFilter,
|
|
3697
|
+
minTvl: initialMinTvl,
|
|
3698
|
+
showTvlFilter = true,
|
|
3342
3699
|
onMarketSelect,
|
|
3343
3700
|
onDeposit,
|
|
3344
3701
|
onWithdraw
|
|
@@ -3346,7 +3703,13 @@ function PendleMarketsList({
|
|
|
3346
3703
|
const [searchQuery, setSearchQuery] = react.useState("");
|
|
3347
3704
|
const [sortBy, setSortBy] = react.useState(defaultSort);
|
|
3348
3705
|
const [selectedMarket, setSelectedMarket] = react.useState(null);
|
|
3349
|
-
const
|
|
3706
|
+
const [minTvlFilter, setMinTvlFilter] = react.useState(initialMinTvl);
|
|
3707
|
+
const [showFilterPanel, setShowFilterPanel] = react.useState(false);
|
|
3708
|
+
const { markets, isLoading, isError, refetch } = usePendleData({ sortBy, assetFilter, minTvl: minTvlFilter });
|
|
3709
|
+
const handleMinTvlChange = react.useCallback((value) => {
|
|
3710
|
+
const num = parseFloat(value);
|
|
3711
|
+
setMinTvlFilter(isNaN(num) || num <= 0 ? void 0 : num);
|
|
3712
|
+
}, []);
|
|
3350
3713
|
const filteredMarkets = react.useMemo(() => {
|
|
3351
3714
|
if (!searchQuery) return markets;
|
|
3352
3715
|
const query = searchQuery.toLowerCase();
|
|
@@ -3374,48 +3737,115 @@ function PendleMarketsList({
|
|
|
3374
3737
|
/* @__PURE__ */ jsxRuntime.jsx(WalletStatus, { compact: true })
|
|
3375
3738
|
] })
|
|
3376
3739
|
] }),
|
|
3377
|
-
(showSearch || showSort) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
3378
|
-
|
|
3740
|
+
(showSearch || showSort || showTvlFilter) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3741
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
3742
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3743
|
+
"div",
|
|
3744
|
+
{
|
|
3745
|
+
className: "flex-1 flex items-center gap-2 px-3 py-2 rounded-lg border",
|
|
3746
|
+
style: {
|
|
3747
|
+
backgroundColor: "var(--compass-color-background)",
|
|
3748
|
+
borderColor: "var(--compass-color-border)"
|
|
3749
|
+
},
|
|
3750
|
+
children: [
|
|
3751
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
3752
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3753
|
+
"input",
|
|
3754
|
+
{
|
|
3755
|
+
type: "text",
|
|
3756
|
+
placeholder: "Search markets...",
|
|
3757
|
+
value: searchQuery,
|
|
3758
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
3759
|
+
className: "flex-1 bg-transparent outline-none text-sm",
|
|
3760
|
+
style: { color: "var(--compass-color-text)" }
|
|
3761
|
+
}
|
|
3762
|
+
)
|
|
3763
|
+
]
|
|
3764
|
+
}
|
|
3765
|
+
),
|
|
3766
|
+
showSort && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3767
|
+
"select",
|
|
3768
|
+
{
|
|
3769
|
+
value: sortBy,
|
|
3770
|
+
onChange: (e) => setSortBy(e.target.value),
|
|
3771
|
+
className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
|
|
3772
|
+
style: {
|
|
3773
|
+
backgroundColor: "var(--compass-color-background)",
|
|
3774
|
+
borderColor: "var(--compass-color-border)",
|
|
3775
|
+
color: "var(--compass-color-text)"
|
|
3776
|
+
},
|
|
3777
|
+
children: [
|
|
3778
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "fixed_apy", children: "Fixed APY" }),
|
|
3779
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "tvl", children: "TVL" }),
|
|
3780
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "expiry", children: "Expiry" })
|
|
3781
|
+
]
|
|
3782
|
+
}
|
|
3783
|
+
),
|
|
3784
|
+
showTvlFilter && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3785
|
+
"button",
|
|
3786
|
+
{
|
|
3787
|
+
onClick: () => setShowFilterPanel(!showFilterPanel),
|
|
3788
|
+
className: "px-3 py-2 rounded-lg border text-sm flex items-center gap-2",
|
|
3789
|
+
style: {
|
|
3790
|
+
backgroundColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary-muted)" : "var(--compass-color-background)",
|
|
3791
|
+
borderColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-border)",
|
|
3792
|
+
color: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-text)"
|
|
3793
|
+
},
|
|
3794
|
+
children: [
|
|
3795
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SlidersHorizontal, { size: 14 }),
|
|
3796
|
+
"Filter"
|
|
3797
|
+
]
|
|
3798
|
+
}
|
|
3799
|
+
)
|
|
3800
|
+
] }),
|
|
3801
|
+
showTvlFilter && showFilterPanel && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3379
3802
|
"div",
|
|
3380
3803
|
{
|
|
3381
|
-
className: "flex
|
|
3804
|
+
className: "flex items-center gap-3 p-3 rounded-lg border",
|
|
3382
3805
|
style: {
|
|
3383
|
-
backgroundColor: "var(--compass-color-
|
|
3806
|
+
backgroundColor: "var(--compass-color-surface)",
|
|
3384
3807
|
borderColor: "var(--compass-color-border)"
|
|
3385
3808
|
},
|
|
3386
3809
|
children: [
|
|
3387
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
|
|
3388
3810
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3389
|
-
"
|
|
3811
|
+
"label",
|
|
3390
3812
|
{
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3813
|
+
className: "text-sm font-medium whitespace-nowrap",
|
|
3814
|
+
style: { color: "var(--compass-color-text-secondary)" },
|
|
3815
|
+
children: "Min TVL:"
|
|
3816
|
+
}
|
|
3817
|
+
),
|
|
3818
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3819
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-tertiary)" }, children: "$" }),
|
|
3820
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3821
|
+
"input",
|
|
3822
|
+
{
|
|
3823
|
+
type: "number",
|
|
3824
|
+
placeholder: "0",
|
|
3825
|
+
value: minTvlFilter || "",
|
|
3826
|
+
onChange: (e) => handleMinTvlChange(e.target.value),
|
|
3827
|
+
className: "w-24 px-2 py-1 rounded border text-sm bg-transparent",
|
|
3828
|
+
style: {
|
|
3829
|
+
borderColor: "var(--compass-color-border)",
|
|
3830
|
+
color: "var(--compass-color-text)"
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
)
|
|
3834
|
+
] }),
|
|
3835
|
+
minTvlFilter && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3836
|
+
"button",
|
|
3837
|
+
{
|
|
3838
|
+
onClick: () => setMinTvlFilter(void 0),
|
|
3839
|
+
className: "text-xs px-2 py-1 rounded",
|
|
3840
|
+
style: {
|
|
3841
|
+
backgroundColor: "var(--compass-color-error-muted)",
|
|
3842
|
+
color: "var(--compass-color-error)"
|
|
3843
|
+
},
|
|
3844
|
+
children: "Clear"
|
|
3397
3845
|
}
|
|
3398
3846
|
)
|
|
3399
3847
|
]
|
|
3400
3848
|
}
|
|
3401
|
-
),
|
|
3402
|
-
showSort && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3403
|
-
"select",
|
|
3404
|
-
{
|
|
3405
|
-
value: sortBy,
|
|
3406
|
-
onChange: (e) => setSortBy(e.target.value),
|
|
3407
|
-
className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
|
|
3408
|
-
style: {
|
|
3409
|
-
backgroundColor: "var(--compass-color-background)",
|
|
3410
|
-
borderColor: "var(--compass-color-border)",
|
|
3411
|
-
color: "var(--compass-color-text)"
|
|
3412
|
-
},
|
|
3413
|
-
children: [
|
|
3414
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "fixed_apy", children: "Fixed APY" }),
|
|
3415
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "tvl", children: "TVL" }),
|
|
3416
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "expiry", children: "Expiry" })
|
|
3417
|
-
]
|
|
3418
|
-
}
|
|
3419
3849
|
)
|
|
3420
3850
|
] }),
|
|
3421
3851
|
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 24, className: "animate-spin", style: { color: "var(--compass-color-primary)" } }) }) : isError ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3589,51 +4019,63 @@ function PendleMarketsList({
|
|
|
3589
4019
|
] });
|
|
3590
4020
|
}
|
|
3591
4021
|
function useSwapQuote({ fromToken, toToken, amount, enabled = true }) {
|
|
3592
|
-
const { client } = useEmbeddableApi();
|
|
3593
4022
|
const { chainId } = useChain();
|
|
4023
|
+
const { address } = useCompassWallet();
|
|
3594
4024
|
const query = reactQuery.useQuery({
|
|
3595
|
-
queryKey: ["swapQuote", chainId, fromToken, toToken, amount],
|
|
4025
|
+
queryKey: ["swapQuote", chainId, fromToken, toToken, amount, address],
|
|
3596
4026
|
queryFn: async () => {
|
|
3597
|
-
if (!fromToken || !toToken || !amount || parseFloat(amount) <= 0) {
|
|
4027
|
+
if (!fromToken || !toToken || !amount || parseFloat(amount) <= 0 || !address) {
|
|
3598
4028
|
return null;
|
|
3599
4029
|
}
|
|
3600
4030
|
try {
|
|
3601
|
-
const
|
|
3602
|
-
|
|
4031
|
+
const params = new URLSearchParams({
|
|
4032
|
+
owner: address,
|
|
4033
|
+
chain: chainId,
|
|
4034
|
+
tokenIn: fromToken,
|
|
4035
|
+
tokenOut: toToken,
|
|
4036
|
+
amountIn: amount
|
|
4037
|
+
});
|
|
4038
|
+
const response = await fetch(`/api/compass/swap/quote?${params}`);
|
|
4039
|
+
if (!response.ok) {
|
|
4040
|
+
const errorData = await response.json();
|
|
4041
|
+
const errorMessage = errorData.message || errorData.error || "Failed to get swap quote";
|
|
4042
|
+
throw new Error(errorMessage);
|
|
4043
|
+
}
|
|
4044
|
+
const data = await response.json();
|
|
4045
|
+
const outputAmount = data.estimatedAmountOut || "0";
|
|
4046
|
+
const inputAmountNum = parseFloat(amount);
|
|
4047
|
+
const outputAmountNum = parseFloat(outputAmount);
|
|
3603
4048
|
return {
|
|
3604
4049
|
inputAmount: amount,
|
|
3605
4050
|
outputAmount,
|
|
3606
|
-
rate:
|
|
3607
|
-
priceImpact: "0",
|
|
3608
|
-
fee: "0"
|
|
4051
|
+
rate: inputAmountNum > 0 ? (outputAmountNum / inputAmountNum).toString() : "0"
|
|
3609
4052
|
};
|
|
3610
4053
|
} catch (error) {
|
|
3611
4054
|
console.error("Failed to get swap quote:", error);
|
|
3612
|
-
|
|
4055
|
+
throw error;
|
|
3613
4056
|
}
|
|
3614
4057
|
},
|
|
3615
|
-
enabled: enabled && !!fromToken && !!toToken && !!amount && parseFloat(amount) > 0,
|
|
4058
|
+
enabled: enabled && !!address && !!fromToken && !!toToken && !!amount && parseFloat(amount) > 0,
|
|
3616
4059
|
staleTime: 10 * 1e3,
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
// Refresh every 15 seconds
|
|
4060
|
+
refetchInterval: 15 * 1e3,
|
|
4061
|
+
retry: 1
|
|
3620
4062
|
});
|
|
3621
4063
|
return {
|
|
3622
4064
|
quote: query.data,
|
|
3623
4065
|
isLoading: query.isLoading,
|
|
3624
4066
|
isError: query.isError,
|
|
4067
|
+
error: query.error,
|
|
3625
4068
|
refetch: query.refetch
|
|
3626
4069
|
};
|
|
3627
4070
|
}
|
|
3628
|
-
var
|
|
4071
|
+
var DEFAULT_TOKENS = ["USDC", "ETH", "WETH", "WBTC", "DAI", "USDT", "AUSD", "SBC"];
|
|
3629
4072
|
function SwapWidget({
|
|
3630
4073
|
layout = "full",
|
|
3631
4074
|
defaultFromToken = "ETH",
|
|
3632
4075
|
defaultToToken = "USDC",
|
|
3633
|
-
allowedTokens =
|
|
4076
|
+
allowedTokens = DEFAULT_TOKENS,
|
|
3634
4077
|
showReverseButton = true,
|
|
3635
4078
|
showSettings = false,
|
|
3636
|
-
showPriceImpact = true,
|
|
3637
4079
|
onSwapSuccess,
|
|
3638
4080
|
onSwapError
|
|
3639
4081
|
}) {
|
|
@@ -3641,10 +4083,10 @@ function SwapWidget({
|
|
|
3641
4083
|
const [toToken, setToToken] = react.useState(defaultToToken);
|
|
3642
4084
|
const [fromAmount, setFromAmount] = react.useState("");
|
|
3643
4085
|
const [isSwapping, setIsSwapping] = react.useState(false);
|
|
3644
|
-
const
|
|
3645
|
-
const {
|
|
4086
|
+
const [swapStatus, setSwapStatus] = react.useState("");
|
|
4087
|
+
const { address, isConnected, signTypedData } = useCompassWallet();
|
|
3646
4088
|
const { chainId } = useChain();
|
|
3647
|
-
const { quote, isLoading: isQuoteLoading } = useSwapQuote({
|
|
4089
|
+
const { quote, isLoading: isQuoteLoading, error: quoteError } = useSwapQuote({
|
|
3648
4090
|
fromToken,
|
|
3649
4091
|
toToken,
|
|
3650
4092
|
amount: fromAmount,
|
|
@@ -3658,32 +4100,74 @@ function SwapWidget({
|
|
|
3658
4100
|
const handleSwap = react.useCallback(async () => {
|
|
3659
4101
|
if (!address || !fromAmount || !quote) return;
|
|
3660
4102
|
setIsSwapping(true);
|
|
4103
|
+
setSwapStatus("Preparing swap...");
|
|
3661
4104
|
try {
|
|
3662
|
-
const
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
4105
|
+
const prepareResponse = await fetch("/api/compass/swap/prepare", {
|
|
4106
|
+
method: "POST",
|
|
4107
|
+
headers: { "Content-Type": "application/json" },
|
|
4108
|
+
body: JSON.stringify({
|
|
4109
|
+
owner: address,
|
|
4110
|
+
chain: chainId,
|
|
4111
|
+
tokenIn: fromToken,
|
|
4112
|
+
tokenOut: toToken,
|
|
4113
|
+
amountIn: fromAmount
|
|
4114
|
+
})
|
|
4115
|
+
});
|
|
4116
|
+
if (!prepareResponse.ok) {
|
|
4117
|
+
const error = await prepareResponse.json();
|
|
4118
|
+
throw new Error(error.error || "Failed to prepare swap");
|
|
4119
|
+
}
|
|
4120
|
+
const prepareData = await prepareResponse.json();
|
|
4121
|
+
const { eip712, normalizedTypes } = prepareData;
|
|
4122
|
+
if (!eip712) {
|
|
4123
|
+
throw new Error("No EIP-712 data returned from prepare");
|
|
4124
|
+
}
|
|
4125
|
+
setSwapStatus("Please sign the transaction...");
|
|
4126
|
+
const signature = await signTypedData({
|
|
4127
|
+
domain: eip712.domain,
|
|
4128
|
+
types: normalizedTypes || eip712.types,
|
|
4129
|
+
primaryType: "SafeTx",
|
|
4130
|
+
message: eip712.message
|
|
4131
|
+
});
|
|
4132
|
+
setSwapStatus("Executing swap...");
|
|
4133
|
+
const executeResponse = await fetch("/api/compass/swap/execute", {
|
|
4134
|
+
method: "POST",
|
|
4135
|
+
headers: { "Content-Type": "application/json" },
|
|
4136
|
+
body: JSON.stringify({
|
|
4137
|
+
owner: address,
|
|
4138
|
+
chain: chainId,
|
|
4139
|
+
eip712,
|
|
4140
|
+
signature
|
|
4141
|
+
})
|
|
3668
4142
|
});
|
|
3669
|
-
|
|
3670
|
-
|
|
4143
|
+
if (!executeResponse.ok) {
|
|
4144
|
+
const error = await executeResponse.json();
|
|
4145
|
+
throw new Error(error.error || "Failed to execute swap");
|
|
4146
|
+
}
|
|
4147
|
+
const executeData = await executeResponse.json();
|
|
4148
|
+
const txHash = executeData.txHash;
|
|
4149
|
+
setSwapStatus("Swap successful!");
|
|
4150
|
+
onSwapSuccess?.(fromToken, toToken, fromAmount, quote.outputAmount, txHash);
|
|
3671
4151
|
setFromAmount("");
|
|
4152
|
+
setTimeout(() => setSwapStatus(""), 3e3);
|
|
3672
4153
|
} catch (error) {
|
|
3673
4154
|
console.error("Swap failed:", error);
|
|
4155
|
+
setSwapStatus("");
|
|
3674
4156
|
onSwapError?.(error);
|
|
3675
4157
|
} finally {
|
|
3676
4158
|
setIsSwapping(false);
|
|
3677
4159
|
}
|
|
3678
|
-
}, [address, fromAmount, quote,
|
|
3679
|
-
const isCompact = layout === "compact";
|
|
4160
|
+
}, [address, fromAmount, quote, chainId, fromToken, toToken, signTypedData, onSwapSuccess, onSwapError]);
|
|
3680
4161
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
3681
|
-
|
|
4162
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
|
|
3682
4163
|
/* @__PURE__ */ jsxRuntime.jsx(ChainSwitcher, {}),
|
|
3683
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4164
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4165
|
+
/* @__PURE__ */ jsxRuntime.jsx(EarnAccountBalance, { compact: true }),
|
|
4166
|
+
/* @__PURE__ */ jsxRuntime.jsx(WalletStatus, { compact: true })
|
|
4167
|
+
] })
|
|
3684
4168
|
] }),
|
|
3685
4169
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3686
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 rounded-xl border", style: { backgroundColor: "var(--compass-color-surface)", borderColor: "var(--compass-color-border)" }, children: [
|
|
4170
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 rounded-xl border relative", style: { backgroundColor: "var(--compass-color-surface)", borderColor: "var(--compass-color-border)" }, children: [
|
|
3687
4171
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "From" }) }),
|
|
3688
4172
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
3689
4173
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3693,7 +4177,7 @@ function SwapWidget({
|
|
|
3693
4177
|
value: fromAmount,
|
|
3694
4178
|
onChange: (e) => setFromAmount(e.target.value),
|
|
3695
4179
|
placeholder: "0.00",
|
|
3696
|
-
className: "flex-1 bg-transparent outline-none text-2xl font-mono",
|
|
4180
|
+
className: "flex-1 bg-transparent outline-none text-2xl font-mono min-w-0",
|
|
3697
4181
|
style: { color: "var(--compass-color-text)" }
|
|
3698
4182
|
}
|
|
3699
4183
|
),
|
|
@@ -3702,9 +4186,9 @@ function SwapWidget({
|
|
|
3702
4186
|
{
|
|
3703
4187
|
value: fromToken,
|
|
3704
4188
|
onChange: (e) => setFromToken(e.target.value),
|
|
3705
|
-
className: "px-3 py-2 rounded-lg border text-sm font-medium cursor-pointer",
|
|
4189
|
+
className: "px-3 py-2 rounded-lg border text-sm font-medium cursor-pointer flex-shrink-0",
|
|
3706
4190
|
style: { backgroundColor: "var(--compass-color-background)", borderColor: "var(--compass-color-border)", color: "var(--compass-color-text)" },
|
|
3707
|
-
children: allowedTokens.map((token) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: token, children: token }, token))
|
|
4191
|
+
children: allowedTokens.filter((t) => t !== toToken).map((token) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: token, children: token }, token))
|
|
3708
4192
|
}
|
|
3709
4193
|
)
|
|
3710
4194
|
] })
|
|
@@ -3724,7 +4208,7 @@ function SwapWidget({
|
|
|
3724
4208
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 text-2xl font-mono", style: { color: isQuoteLoading ? "var(--compass-color-text-tertiary)" : "var(--compass-color-text)" }, children: isQuoteLoading ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
|
|
3725
4209
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 16, className: "animate-spin" }),
|
|
3726
4210
|
"Loading..."
|
|
3727
|
-
] }) : quote?.outputAmount ? parseFloat(quote.outputAmount).toFixed(
|
|
4211
|
+
] }) : quote?.outputAmount ? parseFloat(quote.outputAmount).toFixed(8) : "0.00000000" }),
|
|
3728
4212
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3729
4213
|
"select",
|
|
3730
4214
|
{
|
|
@@ -3738,14 +4222,6 @@ function SwapWidget({
|
|
|
3738
4222
|
] })
|
|
3739
4223
|
] })
|
|
3740
4224
|
] }),
|
|
3741
|
-
showPriceImpact && quote && parseFloat(quote.priceImpact) > 0.01 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-3 rounded-lg", style: { backgroundColor: "var(--compass-color-warning-muted)" }, children: [
|
|
3742
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { size: 16, style: { color: "var(--compass-color-warning)" } }),
|
|
3743
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm", style: { color: "var(--compass-color-warning)" }, children: [
|
|
3744
|
-
"Price impact: ",
|
|
3745
|
-
(parseFloat(quote.priceImpact) * 100).toFixed(2),
|
|
3746
|
-
"%"
|
|
3747
|
-
] })
|
|
3748
|
-
] }),
|
|
3749
4225
|
quote && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-sm", style: { color: "var(--compass-color-text-secondary)" }, children: [
|
|
3750
4226
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Rate" }),
|
|
3751
4227
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
|
|
@@ -3757,6 +4233,34 @@ function SwapWidget({
|
|
|
3757
4233
|
toToken
|
|
3758
4234
|
] })
|
|
3759
4235
|
] }),
|
|
4236
|
+
quoteError && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4237
|
+
"div",
|
|
4238
|
+
{
|
|
4239
|
+
className: "flex items-center gap-2 p-3 rounded-lg text-sm",
|
|
4240
|
+
style: {
|
|
4241
|
+
backgroundColor: "var(--compass-color-error-muted)",
|
|
4242
|
+
color: "var(--compass-color-error)"
|
|
4243
|
+
},
|
|
4244
|
+
children: [
|
|
4245
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { size: 16 }),
|
|
4246
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: quoteError.message })
|
|
4247
|
+
]
|
|
4248
|
+
}
|
|
4249
|
+
),
|
|
4250
|
+
swapStatus && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4251
|
+
"div",
|
|
4252
|
+
{
|
|
4253
|
+
className: "flex items-center gap-2 p-3 rounded-lg text-sm",
|
|
4254
|
+
style: {
|
|
4255
|
+
backgroundColor: swapStatus.includes("successful") ? "var(--compass-color-success-muted)" : "var(--compass-color-surface)",
|
|
4256
|
+
color: swapStatus.includes("successful") ? "var(--compass-color-success)" : "var(--compass-color-text-secondary)"
|
|
4257
|
+
},
|
|
4258
|
+
children: [
|
|
4259
|
+
!swapStatus.includes("successful") && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 14, className: "animate-spin" }),
|
|
4260
|
+
swapStatus
|
|
4261
|
+
]
|
|
4262
|
+
}
|
|
4263
|
+
),
|
|
3760
4264
|
!isConnected ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3761
4265
|
"div",
|
|
3762
4266
|
{
|
|
@@ -3792,78 +4296,29 @@ function SwapWidget({
|
|
|
3792
4296
|
)
|
|
3793
4297
|
] });
|
|
3794
4298
|
}
|
|
3795
|
-
|
|
3796
|
-
// src/components/CompassEarnWidget/presets.ts
|
|
3797
|
-
var allTabs = [
|
|
4299
|
+
var tabs = [
|
|
3798
4300
|
{ id: "vaults", label: "Vaults", enabled: true },
|
|
3799
4301
|
{ id: "aave", label: "Aave", enabled: true },
|
|
3800
4302
|
{ id: "pendle", label: "Pendle", enabled: true },
|
|
3801
4303
|
{ id: "swap", label: "Swap", enabled: true }
|
|
3802
4304
|
];
|
|
3803
|
-
function getTabsForPreset(preset) {
|
|
3804
|
-
switch (preset) {
|
|
3805
|
-
case "full":
|
|
3806
|
-
return allTabs;
|
|
3807
|
-
case "earn-only":
|
|
3808
|
-
return allTabs.map((tab) => ({
|
|
3809
|
-
...tab,
|
|
3810
|
-
enabled: tab.id !== "swap"
|
|
3811
|
-
}));
|
|
3812
|
-
case "swap-only":
|
|
3813
|
-
return allTabs.map((tab) => ({
|
|
3814
|
-
...tab,
|
|
3815
|
-
enabled: tab.id === "swap"
|
|
3816
|
-
}));
|
|
3817
|
-
case "vaults-only":
|
|
3818
|
-
return allTabs.map((tab) => ({
|
|
3819
|
-
...tab,
|
|
3820
|
-
enabled: tab.id === "vaults"
|
|
3821
|
-
}));
|
|
3822
|
-
default:
|
|
3823
|
-
return allTabs;
|
|
3824
|
-
}
|
|
3825
|
-
}
|
|
3826
|
-
function getDefaultTab(tabs) {
|
|
3827
|
-
const enabledTab = tabs.find((t) => t.enabled);
|
|
3828
|
-
return enabledTab?.id || "vaults";
|
|
3829
|
-
}
|
|
3830
4305
|
function CompassEarnWidget({
|
|
3831
|
-
|
|
3832
|
-
enableVaults,
|
|
3833
|
-
enableAave,
|
|
3834
|
-
enablePendle,
|
|
3835
|
-
enableSwap,
|
|
3836
|
-
defaultTab,
|
|
3837
|
-
showHeader = true,
|
|
4306
|
+
defaultTab = "vaults",
|
|
3838
4307
|
onTabChange
|
|
3839
4308
|
}) {
|
|
3840
|
-
const
|
|
3841
|
-
const baseTabs = getTabsForPreset(preset);
|
|
3842
|
-
return baseTabs.map((tab) => {
|
|
3843
|
-
let enabled = tab.enabled;
|
|
3844
|
-
if (tab.id === "vaults" && enableVaults !== void 0) enabled = enableVaults;
|
|
3845
|
-
if (tab.id === "aave" && enableAave !== void 0) enabled = enableAave;
|
|
3846
|
-
if (tab.id === "pendle" && enablePendle !== void 0) enabled = enablePendle;
|
|
3847
|
-
if (tab.id === "swap" && enableSwap !== void 0) enabled = enableSwap;
|
|
3848
|
-
return { ...tab, enabled };
|
|
3849
|
-
});
|
|
3850
|
-
}, [preset, enableVaults, enableAave, enablePendle, enableSwap]);
|
|
3851
|
-
const enabledTabs = tabs.filter((t) => t.enabled);
|
|
3852
|
-
const initialTab = defaultTab && tabs.find((t) => t.id === defaultTab)?.enabled ? defaultTab : getDefaultTab(tabs);
|
|
3853
|
-
const [activeTab, setActiveTab] = react.useState(initialTab);
|
|
4309
|
+
const [activeTab, setActiveTab] = react.useState(defaultTab);
|
|
3854
4310
|
const handleTabChange = (tab) => {
|
|
3855
4311
|
setActiveTab(tab);
|
|
3856
4312
|
onTabChange?.(tab);
|
|
3857
4313
|
};
|
|
3858
|
-
const showTabs = enabledTabs.length > 1;
|
|
3859
4314
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
3860
|
-
|
|
3861
|
-
|
|
4315
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "font-bold text-xl", style: { color: "var(--compass-color-text)" }, children: "Compass Earn" }),
|
|
4316
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3862
4317
|
"div",
|
|
3863
4318
|
{
|
|
3864
4319
|
className: "flex gap-1 p-1 rounded-lg",
|
|
3865
4320
|
style: { backgroundColor: "var(--compass-color-surface)" },
|
|
3866
|
-
children:
|
|
4321
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3867
4322
|
"button",
|
|
3868
4323
|
{
|
|
3869
4324
|
onClick: () => handleTabChange(tab.id),
|
|
@@ -3879,10 +4334,10 @@ function CompassEarnWidget({
|
|
|
3879
4334
|
}
|
|
3880
4335
|
),
|
|
3881
4336
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3882
|
-
activeTab === "vaults" &&
|
|
3883
|
-
activeTab === "aave" &&
|
|
3884
|
-
activeTab === "pendle" &&
|
|
3885
|
-
activeTab === "swap" &&
|
|
4337
|
+
activeTab === "vaults" && /* @__PURE__ */ jsxRuntime.jsx(VaultsList, {}),
|
|
4338
|
+
activeTab === "aave" && /* @__PURE__ */ jsxRuntime.jsx(AaveMarketsList, {}),
|
|
4339
|
+
activeTab === "pendle" && /* @__PURE__ */ jsxRuntime.jsx(PendleMarketsList, {}),
|
|
4340
|
+
activeTab === "swap" && /* @__PURE__ */ jsxRuntime.jsx(SwapWidget, {})
|
|
3886
4341
|
] })
|
|
3887
4342
|
] });
|
|
3888
4343
|
}
|
|
@@ -3908,6 +4363,7 @@ var CHAINS = {
|
|
|
3908
4363
|
};
|
|
3909
4364
|
|
|
3910
4365
|
exports.AaveMarketsList = AaveMarketsList;
|
|
4366
|
+
exports.AccountBalancesModal = AccountBalancesModal;
|
|
3911
4367
|
exports.ActionModal = ActionModal;
|
|
3912
4368
|
exports.ApiProvider = ApiProvider;
|
|
3913
4369
|
exports.CHAINS = CHAINS;
|