@compass-labs/widgets 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { createContext, useMemo, useContext, useState, useEffect, useCallback } from 'react';
1
+ import { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
2
  import { QueryClient, QueryClientProvider, useQueryClient, useQuery } from '@tanstack/react-query';
3
3
  import { CompassApiSDK } from '@compass-labs/api-sdk';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { arbitrum, base, mainnet } from 'viem/chains';
6
- import { Wallet, LogOut, X, ChevronDown, AlertCircle, Loader2, ArrowDownLeft, ArrowUpRight, ExternalLink, Search, TrendingUp, Calendar, ArrowDownUp } from 'lucide-react';
6
+ import { Wallet, LogOut, X, ChevronDown, AlertCircle, ArrowRight, Loader2, ArrowDownLeft, ArrowUpRight, ExternalLink, Coins, Search, SlidersHorizontal, TrendingUp, Calendar, ArrowDownUp } from 'lucide-react';
7
7
 
8
8
  // src/provider/CompassProvider.tsx
9
9
  var ApiContext = createContext(null);
@@ -79,6 +79,7 @@ var WalletContext = createContext(null);
79
79
  var disconnectedWallet = {
80
80
  address: null,
81
81
  isConnected: false,
82
+ walletChainId: void 0,
82
83
  signTypedData: async () => {
83
84
  throw new Error("No wallet connected. Please connect a wallet first.");
84
85
  },
@@ -90,6 +91,7 @@ function WalletProvider({ children, wallet }) {
90
91
  const value = wallet ? {
91
92
  address: wallet.address,
92
93
  isConnected: wallet.address !== null,
94
+ walletChainId: wallet.chainId,
93
95
  signTypedData: wallet.signTypedData,
94
96
  switchChain: wallet.switchChain ?? null,
95
97
  login: wallet.login ?? null,
@@ -1121,7 +1123,7 @@ function PnLSummary({ pnl, tokenSymbol, tokenPrice }) {
1121
1123
  const prefix = value >= 0 ? "+" : "";
1122
1124
  return `${prefix}${value.toFixed(4)}`;
1123
1125
  };
1124
- const formatUSD = (value) => {
1126
+ const formatUSD2 = (value) => {
1125
1127
  const usdValue = value * tokenPrice;
1126
1128
  const prefix = usdValue >= 0 ? "+$" : "-$";
1127
1129
  return `${prefix}${Math.abs(usdValue).toFixed(2)}`;
@@ -1198,7 +1200,7 @@ function PnLSummary({ pnl, tokenSymbol, tokenPrice }) {
1198
1200
  children: formatPnL(unrealizedPnl)
1199
1201
  }
1200
1202
  ),
1201
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono", style: { color: pnlColor(unrealizedPnl) }, children: formatUSD(unrealizedPnl) })
1203
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono", style: { color: pnlColor(unrealizedPnl) }, children: formatUSD2(unrealizedPnl) })
1202
1204
  ] }),
1203
1205
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
1204
1206
  /* @__PURE__ */ jsx(
@@ -1217,7 +1219,7 @@ function PnLSummary({ pnl, tokenSymbol, tokenPrice }) {
1217
1219
  children: formatPnL(realizedPnl)
1218
1220
  }
1219
1221
  ),
1220
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono", style: { color: pnlColor(realizedPnl) }, children: formatUSD(realizedPnl) })
1222
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono", style: { color: pnlColor(realizedPnl) }, children: formatUSD2(realizedPnl) })
1221
1223
  ] })
1222
1224
  ] }),
1223
1225
  /* @__PURE__ */ jsxs(
@@ -1242,7 +1244,7 @@ function PnLSummary({ pnl, tokenSymbol, tokenPrice }) {
1242
1244
  ] }),
1243
1245
  /* @__PURE__ */ jsxs("span", { className: "text-xs font-mono", style: { color: pnlColor(totalPnl) }, children: [
1244
1246
  "(",
1245
- formatUSD(totalPnl),
1247
+ formatUSD2(totalPnl),
1246
1248
  ")"
1247
1249
  ] })
1248
1250
  ] })
@@ -1254,161 +1256,327 @@ function PnLSummary({ pnl, tokenSymbol, tokenPrice }) {
1254
1256
  )
1255
1257
  ] });
1256
1258
  }
1257
- var CHAINS = {
1258
- ethereum: {
1259
- id: "ethereum",
1260
- name: "Ethereum",
1261
- viemChain: mainnet,
1262
- icon: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png"
1263
- },
1264
- base: {
1265
- id: "base",
1266
- name: "Base",
1267
- viemChain: base,
1268
- icon: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/base/info/logo.png"
1269
- },
1270
- arbitrum: {
1271
- id: "arbitrum",
1272
- name: "Arbitrum",
1273
- viemChain: arbitrum,
1274
- icon: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/arbitrum/info/logo.png"
1275
- }
1276
- };
1277
- var TOKEN_DECIMALS = {
1278
- USDC: 6,
1279
- USDT: 6,
1280
- DAI: 18,
1281
- ETH: 18,
1282
- WETH: 18,
1283
- WBTC: 8,
1284
- cbBTC: 8
1285
- };
1259
+
1260
+ // src/utils/format.ts
1261
+ function formatAmount(value) {
1262
+ const num = typeof value === "string" ? parseFloat(value) : value;
1263
+ if (isNaN(num)) return "0";
1264
+ return parseFloat(num.toFixed(6)).toString();
1265
+ }
1266
+ function formatUSD(value) {
1267
+ const num = typeof value === "string" ? parseFloat(value) : value;
1268
+ if (isNaN(num)) return "$0.00";
1269
+ return new Intl.NumberFormat("en-US", {
1270
+ style: "currency",
1271
+ currency: "USD",
1272
+ minimumFractionDigits: 2,
1273
+ maximumFractionDigits: 2
1274
+ }).format(num);
1275
+ }
1276
+ function TokenSelector({
1277
+ tokens,
1278
+ selectedToken,
1279
+ onSelect,
1280
+ balances,
1281
+ showBalances = true,
1282
+ disabled = false
1283
+ }) {
1284
+ const [isOpen, setIsOpen] = useState(false);
1285
+ const dropdownRef = useRef(null);
1286
+ useEffect(() => {
1287
+ function handleClickOutside(event) {
1288
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
1289
+ setIsOpen(false);
1290
+ }
1291
+ }
1292
+ document.addEventListener("mousedown", handleClickOutside);
1293
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1294
+ }, []);
1295
+ const handleSelect = (token) => {
1296
+ onSelect(token);
1297
+ setIsOpen(false);
1298
+ };
1299
+ return /* @__PURE__ */ jsxs("div", { className: "relative", ref: dropdownRef, children: [
1300
+ /* @__PURE__ */ jsxs(
1301
+ "button",
1302
+ {
1303
+ type: "button",
1304
+ onClick: () => !disabled && setIsOpen(!isOpen),
1305
+ disabled,
1306
+ className: "flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors min-w-[120px]",
1307
+ style: {
1308
+ backgroundColor: "var(--compass-color-background)",
1309
+ borderColor: isOpen ? "var(--compass-color-primary)" : "var(--compass-color-border)",
1310
+ color: "var(--compass-color-text)",
1311
+ cursor: disabled ? "not-allowed" : "pointer",
1312
+ opacity: disabled ? 0.5 : 1
1313
+ },
1314
+ children: [
1315
+ /* @__PURE__ */ jsx("span", { className: "font-medium flex-1 text-left", children: selectedToken }),
1316
+ /* @__PURE__ */ jsx(
1317
+ ChevronDown,
1318
+ {
1319
+ size: 16,
1320
+ style: {
1321
+ color: "var(--compass-color-text-secondary)",
1322
+ transform: isOpen ? "rotate(180deg)" : "rotate(0deg)",
1323
+ transition: "transform 0.2s"
1324
+ }
1325
+ }
1326
+ )
1327
+ ]
1328
+ }
1329
+ ),
1330
+ isOpen && /* @__PURE__ */ jsx(
1331
+ "div",
1332
+ {
1333
+ className: "absolute z-50 mt-1 w-full min-w-[160px] rounded-lg border overflow-y-auto",
1334
+ style: {
1335
+ backgroundColor: "var(--compass-color-surface)",
1336
+ borderColor: "var(--compass-color-border)",
1337
+ boxShadow: "var(--compass-shadow-lg)",
1338
+ maxHeight: "200px"
1339
+ },
1340
+ children: tokens.map((token) => {
1341
+ const balance = balances?.[token];
1342
+ const isSelected = token === selectedToken;
1343
+ return /* @__PURE__ */ jsxs(
1344
+ "button",
1345
+ {
1346
+ type: "button",
1347
+ onClick: () => handleSelect(token),
1348
+ className: "w-full px-3 py-2 flex items-center justify-between transition-colors",
1349
+ style: {
1350
+ backgroundColor: isSelected ? "var(--compass-color-primary-muted)" : "transparent",
1351
+ color: "var(--compass-color-text)"
1352
+ },
1353
+ onMouseEnter: (e) => {
1354
+ if (!isSelected) {
1355
+ e.currentTarget.style.backgroundColor = "var(--compass-color-surface-hover)";
1356
+ }
1357
+ },
1358
+ onMouseLeave: (e) => {
1359
+ if (!isSelected) {
1360
+ e.currentTarget.style.backgroundColor = "transparent";
1361
+ }
1362
+ },
1363
+ children: [
1364
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: token }),
1365
+ showBalances && balance && /* @__PURE__ */ jsx(
1366
+ "span",
1367
+ {
1368
+ className: "text-sm font-mono",
1369
+ style: { color: "var(--compass-color-text-secondary)" },
1370
+ children: formatAmount(balance)
1371
+ }
1372
+ )
1373
+ ]
1374
+ },
1375
+ token
1376
+ );
1377
+ })
1378
+ }
1379
+ )
1380
+ ] });
1381
+ }
1286
1382
  function DepositWithdrawForm({
1287
1383
  venueType,
1288
1384
  venueAddress,
1289
- tokenSymbol,
1290
- tokenDecimals,
1385
+ venueToken,
1386
+ depositTokens = ["SBC", "AUSD", "USDC", "USDT", "WETH", "DAI"],
1291
1387
  positionBalance = "0",
1292
1388
  onSuccess,
1293
1389
  onError
1294
1390
  }) {
1295
1391
  const [activeTab, setActiveTab] = useState("deposit");
1392
+ const [selectedToken, setSelectedToken] = useState(venueToken);
1296
1393
  const [amount, setAmount] = useState("");
1297
1394
  const [isSubmitting, setIsSubmitting] = useState(false);
1298
1395
  const [statusMessage, setStatusMessage] = useState("");
1299
1396
  const [error, setError] = useState(null);
1300
1397
  const { address, isConnected, signTypedData, switchChain } = useCompassWallet();
1301
- const { client } = useEmbeddableApi();
1302
- const { chainId } = useChain();
1398
+ const { chainId, chain } = useChain();
1303
1399
  const { earnAccountAddress } = useEarnAccount();
1304
1400
  const queryClient = useQueryClient();
1305
- const chainConfig = CHAINS[chainId];
1306
- const targetChainId = chainConfig?.viemChain?.id;
1401
+ const needsSwap = activeTab === "deposit" && selectedToken !== venueToken;
1307
1402
  const { data: tokenBalance } = useQuery({
1308
- queryKey: ["earnAccountTokenBalance", chainId, earnAccountAddress, tokenSymbol],
1403
+ queryKey: ["earnAccountTokenBalance", chainId, earnAccountAddress, selectedToken],
1309
1404
  queryFn: async () => {
1310
1405
  if (!earnAccountAddress) return "0";
1311
1406
  try {
1312
- const response = await client.token.tokenBalance({
1313
- chain: chainId,
1314
- user: earnAccountAddress,
1315
- token: tokenSymbol
1316
- });
1317
- return response.amount || "0";
1318
- } catch (error2) {
1319
- console.error("Error fetching earn account token balance:", error2);
1407
+ const response = await fetch(
1408
+ `/api/compass/earn-account/balances?owner=${address}&chain=${chainId}&tokens=${selectedToken}`
1409
+ );
1410
+ if (!response.ok) return "0";
1411
+ const data = await response.json();
1412
+ return data.balances?.[selectedToken]?.balance || "0";
1413
+ } catch {
1320
1414
  return "0";
1321
1415
  }
1322
1416
  },
1323
- enabled: !!earnAccountAddress,
1417
+ enabled: !!earnAccountAddress && !!address,
1324
1418
  staleTime: 10 * 1e3
1325
1419
  });
1326
1420
  const availableBalance = tokenBalance || "0";
1327
1421
  const maxBalance = activeTab === "deposit" ? availableBalance : positionBalance;
1328
- const handleQuickAmount = useCallback((percentage) => {
1329
- const max = parseFloat(maxBalance);
1330
- if (isNaN(max)) return;
1331
- setAmount((max * percentage).toFixed(tokenDecimals > 6 ? 6 : tokenDecimals));
1332
- }, [maxBalance, tokenDecimals]);
1422
+ const handleQuickAmount = useCallback(
1423
+ (percentage) => {
1424
+ const max = parseFloat(maxBalance);
1425
+ if (isNaN(max)) return;
1426
+ setAmount(formatAmount(max * percentage));
1427
+ },
1428
+ [maxBalance]
1429
+ );
1333
1430
  const handleSubmit = useCallback(async () => {
1334
1431
  if (!address || !amount) return;
1335
1432
  setIsSubmitting(true);
1336
1433
  setStatusMessage("Preparing transaction...");
1337
1434
  setError(null);
1338
1435
  try {
1339
- if (switchChain && targetChainId) {
1340
- setStatusMessage("Checking network...");
1436
+ const targetChainId = chain.viemChain.id;
1437
+ if (switchChain) {
1438
+ setStatusMessage("Switching network...");
1341
1439
  try {
1342
1440
  await switchChain(targetChainId);
1343
1441
  } catch {
1442
+ throw new Error(`Please switch your wallet to ${chain.name} to continue`);
1344
1443
  }
1345
1444
  }
1346
1445
  const isDeposit = activeTab === "deposit";
1347
- const prepareEndpoint = isDeposit ? "/api/compass/deposit/prepare" : "/api/compass/withdraw/prepare";
1348
- const executeEndpoint = isDeposit ? "/api/compass/deposit/execute" : "/api/compass/withdraw/execute";
1349
- const prepareBody = {
1350
- amount,
1351
- token: tokenSymbol,
1352
- owner: address,
1353
- chain: chainId,
1354
- venueType
1355
- };
1356
- if (venueType === "VAULT") {
1357
- prepareBody.vaultAddress = venueAddress;
1358
- } else if (venueType === "PENDLE_PT") {
1359
- prepareBody.marketAddress = venueAddress;
1360
- prepareBody.maxSlippagePercent = 1;
1361
- }
1362
- setStatusMessage("Getting transaction data...");
1363
- const prepareResponse = await fetch(prepareEndpoint, {
1364
- method: "POST",
1365
- headers: { "Content-Type": "application/json" },
1366
- body: JSON.stringify(prepareBody)
1367
- });
1368
- if (!prepareResponse.ok) {
1369
- const errorData = await prepareResponse.json();
1370
- throw new Error(errorData.error || "Failed to prepare transaction");
1371
- }
1372
- const { eip712, normalizedTypes, domain, message } = await prepareResponse.json();
1373
- setStatusMessage("Please sign the transaction...");
1374
- const signature = await signTypedData({
1375
- domain,
1376
- types: normalizedTypes,
1377
- primaryType: "SafeTx",
1378
- message
1379
- });
1380
- setStatusMessage("Executing transaction...");
1381
- const executeResponse = await fetch(executeEndpoint, {
1382
- method: "POST",
1383
- headers: { "Content-Type": "application/json" },
1384
- body: JSON.stringify({
1446
+ if (isDeposit && needsSwap) {
1447
+ setStatusMessage("Getting swap quote...");
1448
+ const quoteResponse = await fetch(
1449
+ `/api/compass/swap/quote?owner=${address}&chain=${chainId}&tokenIn=${selectedToken}&tokenOut=${venueToken}&amountIn=${amount}`
1450
+ );
1451
+ if (!quoteResponse.ok) {
1452
+ const errorData = await quoteResponse.json();
1453
+ throw new Error(errorData.error || "Failed to get swap quote");
1454
+ }
1455
+ const quoteData = await quoteResponse.json();
1456
+ const estimatedOutput = quoteData.estimatedAmountOut;
1457
+ if (!estimatedOutput || parseFloat(estimatedOutput) <= 0) {
1458
+ throw new Error("Invalid swap quote - no output amount");
1459
+ }
1460
+ const depositAmount = (parseFloat(estimatedOutput) * 0.99).toString();
1461
+ setStatusMessage("Preparing swap and deposit...");
1462
+ const bundleActions = [
1463
+ {
1464
+ body: {
1465
+ actionType: "V2_SWAP",
1466
+ tokenIn: selectedToken,
1467
+ tokenOut: venueToken,
1468
+ amountIn: amount,
1469
+ maxSlippagePercent: 1
1470
+ }
1471
+ },
1472
+ {
1473
+ body: {
1474
+ actionType: "V2_MANAGE",
1475
+ action: "DEPOSIT",
1476
+ venue: venueType === "VAULT" ? { type: "VAULT", vaultAddress: venueAddress } : venueType === "AAVE" ? { type: "AAVE", token: venueToken } : { type: "PENDLE_PT", marketAddress: venueAddress },
1477
+ amount: depositAmount
1478
+ }
1479
+ }
1480
+ ];
1481
+ const prepareResponse = await fetch("/api/compass/bundle/prepare", {
1482
+ method: "POST",
1483
+ headers: { "Content-Type": "application/json" },
1484
+ body: JSON.stringify({
1485
+ owner: address,
1486
+ chain: chainId,
1487
+ actions: bundleActions
1488
+ })
1489
+ });
1490
+ if (!prepareResponse.ok) {
1491
+ const errorData = await prepareResponse.json();
1492
+ throw new Error(errorData.error || "Failed to prepare bundle");
1493
+ }
1494
+ const { eip712, normalizedTypes, domain, message } = await prepareResponse.json();
1495
+ setStatusMessage("Please sign the transaction...");
1496
+ const signature = await signTypedData({
1497
+ domain,
1498
+ types: normalizedTypes,
1499
+ primaryType: "SafeTx",
1500
+ message
1501
+ });
1502
+ setStatusMessage("Executing swap and deposit...");
1503
+ const executeResponse = await fetch("/api/compass/bundle/execute", {
1504
+ method: "POST",
1505
+ headers: { "Content-Type": "application/json" },
1506
+ body: JSON.stringify({
1507
+ owner: address,
1508
+ eip712,
1509
+ signature,
1510
+ chain: chainId
1511
+ })
1512
+ });
1513
+ if (!executeResponse.ok) {
1514
+ const errorData = await executeResponse.json();
1515
+ throw new Error(errorData.error || "Failed to execute bundle");
1516
+ }
1517
+ const { txHash } = await executeResponse.json();
1518
+ setStatusMessage("Transaction successful!");
1519
+ onSuccess?.(activeTab, amount, txHash);
1520
+ setAmount("");
1521
+ } else {
1522
+ const prepareEndpoint = isDeposit ? "/api/compass/deposit/prepare" : "/api/compass/withdraw/prepare";
1523
+ const executeEndpoint = isDeposit ? "/api/compass/deposit/execute" : "/api/compass/withdraw/execute";
1524
+ const prepareBody = {
1525
+ amount,
1526
+ token: venueToken,
1385
1527
  owner: address,
1386
- eip712,
1387
- signature,
1388
- chain: chainId
1389
- })
1390
- });
1391
- if (!executeResponse.ok) {
1392
- const errorData = await executeResponse.json();
1393
- throw new Error(errorData.error || "Failed to execute transaction");
1528
+ chain: chainId,
1529
+ venueType
1530
+ };
1531
+ if (venueType === "VAULT") {
1532
+ prepareBody.vaultAddress = venueAddress;
1533
+ } else if (venueType === "PENDLE_PT") {
1534
+ prepareBody.marketAddress = venueAddress;
1535
+ prepareBody.maxSlippagePercent = 1;
1536
+ }
1537
+ setStatusMessage("Getting transaction data...");
1538
+ const prepareResponse = await fetch(prepareEndpoint, {
1539
+ method: "POST",
1540
+ headers: { "Content-Type": "application/json" },
1541
+ body: JSON.stringify(prepareBody)
1542
+ });
1543
+ if (!prepareResponse.ok) {
1544
+ const errorData = await prepareResponse.json();
1545
+ throw new Error(errorData.error || "Failed to prepare transaction");
1546
+ }
1547
+ const { eip712, normalizedTypes, domain, message } = await prepareResponse.json();
1548
+ setStatusMessage("Please sign the transaction...");
1549
+ const signature = await signTypedData({
1550
+ domain,
1551
+ types: normalizedTypes,
1552
+ primaryType: "SafeTx",
1553
+ message
1554
+ });
1555
+ setStatusMessage("Executing transaction...");
1556
+ const executeResponse = await fetch(executeEndpoint, {
1557
+ method: "POST",
1558
+ headers: { "Content-Type": "application/json" },
1559
+ body: JSON.stringify({
1560
+ owner: address,
1561
+ eip712,
1562
+ signature,
1563
+ chain: chainId
1564
+ })
1565
+ });
1566
+ if (!executeResponse.ok) {
1567
+ const errorData = await executeResponse.json();
1568
+ throw new Error(errorData.error || "Failed to execute transaction");
1569
+ }
1570
+ const { txHash } = await executeResponse.json();
1571
+ setStatusMessage("Transaction successful!");
1572
+ onSuccess?.(activeTab, amount, txHash);
1573
+ setAmount("");
1394
1574
  }
1395
- const { txHash } = await executeResponse.json();
1396
- setStatusMessage("Transaction successful!");
1397
- onSuccess?.(activeTab, amount, txHash);
1398
- setAmount("");
1399
1575
  queryClient.invalidateQueries({ queryKey: ["earnAccountTokenBalance"] });
1400
1576
  queryClient.invalidateQueries({ queryKey: ["vaults"] });
1401
- queryClient.invalidateQueries({ queryKey: ["vaultPositions"] });
1402
1577
  queryClient.invalidateQueries({ queryKey: ["aaveMarkets"] });
1403
- queryClient.invalidateQueries({ queryKey: ["aavePositions"] });
1404
1578
  queryClient.invalidateQueries({ queryKey: ["pendleMarkets"] });
1405
- queryClient.invalidateQueries({ queryKey: ["pendlePositions"] });
1406
1579
  setTimeout(() => setStatusMessage(""), 3e3);
1407
- setTimeout(() => {
1408
- queryClient.invalidateQueries({ queryKey: ["earnAccountTokenBalance"] });
1409
- queryClient.invalidateQueries({ queryKey: ["vaults"] });
1410
- queryClient.invalidateQueries({ queryKey: ["vaultPositions"] });
1411
- }, 5e3);
1412
1580
  } catch (err) {
1413
1581
  console.error("Transaction failed:", err);
1414
1582
  const errorMessage = err instanceof Error ? err.message : "Transaction failed";
@@ -1421,11 +1589,13 @@ function DepositWithdrawForm({
1421
1589
  address,
1422
1590
  amount,
1423
1591
  chainId,
1424
- targetChainId,
1592
+ chain,
1425
1593
  activeTab,
1594
+ needsSwap,
1595
+ selectedToken,
1596
+ venueToken,
1426
1597
  venueType,
1427
1598
  venueAddress,
1428
- tokenSymbol,
1429
1599
  signTypedData,
1430
1600
  switchChain,
1431
1601
  queryClient,
@@ -1466,6 +1636,7 @@ function DepositWithdrawForm({
1466
1636
  {
1467
1637
  onClick: () => {
1468
1638
  setActiveTab(tab);
1639
+ setSelectedToken(venueToken);
1469
1640
  setError(null);
1470
1641
  setStatusMessage("");
1471
1642
  },
@@ -1480,6 +1651,45 @@ function DepositWithdrawForm({
1480
1651
  ))
1481
1652
  }
1482
1653
  ),
1654
+ activeTab === "deposit" && /* @__PURE__ */ jsxs("div", { children: [
1655
+ /* @__PURE__ */ jsx(
1656
+ "label",
1657
+ {
1658
+ className: "text-sm font-medium mb-1 block",
1659
+ style: { color: "var(--compass-color-text-secondary)" },
1660
+ children: "From Token"
1661
+ }
1662
+ ),
1663
+ /* @__PURE__ */ jsx(
1664
+ TokenSelector,
1665
+ {
1666
+ tokens: depositTokens,
1667
+ selectedToken,
1668
+ onSelect: setSelectedToken,
1669
+ disabled: isSubmitting
1670
+ }
1671
+ )
1672
+ ] }),
1673
+ needsSwap && /* @__PURE__ */ jsxs(
1674
+ "div",
1675
+ {
1676
+ className: "flex items-center gap-2 p-2 rounded-lg text-sm",
1677
+ style: {
1678
+ backgroundColor: "var(--compass-color-primary-muted)",
1679
+ color: "var(--compass-color-primary)"
1680
+ },
1681
+ children: [
1682
+ /* @__PURE__ */ jsx(ArrowRight, { size: 14 }),
1683
+ /* @__PURE__ */ jsxs("span", { children: [
1684
+ "Swaps ",
1685
+ selectedToken,
1686
+ " to ",
1687
+ venueToken,
1688
+ ", then deposits"
1689
+ ] })
1690
+ ]
1691
+ }
1692
+ ),
1483
1693
  /* @__PURE__ */ jsxs("div", { children: [
1484
1694
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
1485
1695
  /* @__PURE__ */ jsx(
@@ -1492,9 +1702,9 @@ function DepositWithdrawForm({
1492
1702
  ),
1493
1703
  /* @__PURE__ */ jsxs("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: [
1494
1704
  "Available: ",
1495
- parseFloat(maxBalance).toFixed(4),
1705
+ formatAmount(maxBalance),
1496
1706
  " ",
1497
- tokenSymbol
1707
+ activeTab === "deposit" ? selectedToken : venueToken
1498
1708
  ] })
1499
1709
  ] }),
1500
1710
  /* @__PURE__ */ jsxs(
@@ -1525,7 +1735,7 @@ function DepositWithdrawForm({
1525
1735
  {
1526
1736
  className: "text-sm font-medium",
1527
1737
  style: { color: "var(--compass-color-text-secondary)" },
1528
- children: tokenSymbol
1738
+ children: activeTab === "deposit" ? selectedToken : venueToken
1529
1739
  }
1530
1740
  )
1531
1741
  ]
@@ -1550,8 +1760,8 @@ function DepositWithdrawForm({
1550
1760
  {
1551
1761
  className: "p-3 rounded-lg text-sm",
1552
1762
  style: {
1553
- backgroundColor: "var(--compass-color-error-muted, rgba(239, 68, 68, 0.1))",
1554
- color: "var(--compass-color-error, #ef4444)"
1763
+ backgroundColor: "var(--compass-color-error-muted)",
1764
+ color: "var(--compass-color-error)"
1555
1765
  },
1556
1766
  children: error
1557
1767
  }
@@ -1561,8 +1771,8 @@ function DepositWithdrawForm({
1561
1771
  {
1562
1772
  className: "p-3 rounded-lg text-sm text-center",
1563
1773
  style: {
1564
- backgroundColor: "var(--compass-color-success-muted, rgba(34, 197, 94, 0.1))",
1565
- color: "var(--compass-color-success, #22c55e)"
1774
+ backgroundColor: "var(--compass-color-success-muted)",
1775
+ color: "var(--compass-color-success)"
1566
1776
  },
1567
1777
  children: statusMessage
1568
1778
  }
@@ -1579,7 +1789,7 @@ function DepositWithdrawForm({
1579
1789
  },
1580
1790
  children: [
1581
1791
  isSubmitting && /* @__PURE__ */ jsx(Loader2, { size: 18, className: "animate-spin" }),
1582
- isSubmitting ? "Processing..." : activeTab === "deposit" ? "Deposit" : "Withdraw"
1792
+ isSubmitting ? "Processing..." : needsSwap ? `Swap & ${activeTab === "deposit" ? "Deposit" : "Withdraw"}` : activeTab === "deposit" ? "Deposit" : "Withdraw"
1583
1793
  ]
1584
1794
  }
1585
1795
  )
@@ -1887,6 +2097,678 @@ function EarnAccountGuard({
1887
2097
  }
1888
2098
  );
1889
2099
  }
2100
+ function AccountBalancesModal({
2101
+ isOpen,
2102
+ onClose,
2103
+ balances,
2104
+ totalUsdValue,
2105
+ isLoading = false,
2106
+ earnAccountAddress
2107
+ }) {
2108
+ useEffect(() => {
2109
+ const handleEscape = (e) => {
2110
+ if (e.key === "Escape") onClose();
2111
+ };
2112
+ if (isOpen) {
2113
+ document.addEventListener("keydown", handleEscape);
2114
+ document.body.style.overflow = "hidden";
2115
+ }
2116
+ return () => {
2117
+ document.removeEventListener("keydown", handleEscape);
2118
+ document.body.style.overflow = "";
2119
+ };
2120
+ }, [isOpen, onClose]);
2121
+ if (!isOpen) return null;
2122
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2123
+ /* @__PURE__ */ jsx(
2124
+ "div",
2125
+ {
2126
+ className: "absolute inset-0",
2127
+ style: { backgroundColor: "var(--compass-color-overlay)" },
2128
+ onClick: onClose
2129
+ }
2130
+ ),
2131
+ /* @__PURE__ */ jsxs(
2132
+ "div",
2133
+ {
2134
+ className: "relative w-full max-w-md mx-4 rounded-xl overflow-hidden",
2135
+ style: {
2136
+ backgroundColor: "var(--compass-color-surface)",
2137
+ boxShadow: "var(--compass-shadow-lg)"
2138
+ },
2139
+ children: [
2140
+ /* @__PURE__ */ jsxs(
2141
+ "div",
2142
+ {
2143
+ className: "flex items-center justify-between px-4 py-3 border-b",
2144
+ style: { borderColor: "var(--compass-color-border)" },
2145
+ children: [
2146
+ /* @__PURE__ */ jsxs(
2147
+ "h2",
2148
+ {
2149
+ className: "font-semibold flex items-center gap-2",
2150
+ style: {
2151
+ fontSize: "var(--compass-font-size-subheading)",
2152
+ color: "var(--compass-color-text)"
2153
+ },
2154
+ children: [
2155
+ /* @__PURE__ */ jsx(Coins, { size: 20 }),
2156
+ "Account Balances"
2157
+ ]
2158
+ }
2159
+ ),
2160
+ /* @__PURE__ */ jsx(
2161
+ "button",
2162
+ {
2163
+ onClick: onClose,
2164
+ className: "p-1 rounded-md transition-colors hover:opacity-70",
2165
+ style: { color: "var(--compass-color-text-secondary)" },
2166
+ children: /* @__PURE__ */ jsx(X, { size: 20 })
2167
+ }
2168
+ )
2169
+ ]
2170
+ }
2171
+ ),
2172
+ /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
2173
+ isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(
2174
+ Loader2,
2175
+ {
2176
+ size: 24,
2177
+ className: "animate-spin",
2178
+ style: { color: "var(--compass-color-primary)" }
2179
+ }
2180
+ ) }) : balances.length === 0 ? /* @__PURE__ */ jsx(
2181
+ "div",
2182
+ {
2183
+ className: "text-center py-8",
2184
+ style: { color: "var(--compass-color-text-secondary)" },
2185
+ children: "No token balances found"
2186
+ }
2187
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2188
+ balances.map((token) => /* @__PURE__ */ jsxs(
2189
+ "div",
2190
+ {
2191
+ className: "flex items-center justify-between p-3 rounded-lg",
2192
+ style: { backgroundColor: "var(--compass-color-background)" },
2193
+ children: [
2194
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2195
+ /* @__PURE__ */ jsx(
2196
+ "div",
2197
+ {
2198
+ className: "w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold",
2199
+ style: {
2200
+ backgroundColor: "var(--compass-color-primary-muted)",
2201
+ color: "var(--compass-color-primary)"
2202
+ },
2203
+ children: token.symbol.slice(0, 2)
2204
+ }
2205
+ ),
2206
+ /* @__PURE__ */ jsxs("div", { children: [
2207
+ /* @__PURE__ */ jsx(
2208
+ "div",
2209
+ {
2210
+ className: "font-medium",
2211
+ style: { color: "var(--compass-color-text)" },
2212
+ children: token.symbol
2213
+ }
2214
+ ),
2215
+ /* @__PURE__ */ jsx(
2216
+ "div",
2217
+ {
2218
+ className: "text-sm font-mono",
2219
+ style: { color: "var(--compass-color-text-secondary)" },
2220
+ children: formatAmount(token.balance)
2221
+ }
2222
+ )
2223
+ ] })
2224
+ ] }),
2225
+ /* @__PURE__ */ jsx(
2226
+ "div",
2227
+ {
2228
+ className: "font-medium",
2229
+ style: { color: "var(--compass-color-text)" },
2230
+ children: formatUSD(token.usdValue)
2231
+ }
2232
+ )
2233
+ ]
2234
+ },
2235
+ token.symbol
2236
+ )),
2237
+ /* @__PURE__ */ jsxs(
2238
+ "div",
2239
+ {
2240
+ className: "flex items-center justify-between p-3 mt-2 rounded-lg border",
2241
+ style: {
2242
+ borderColor: "var(--compass-color-border)",
2243
+ backgroundColor: "var(--compass-color-surface)"
2244
+ },
2245
+ children: [
2246
+ /* @__PURE__ */ jsx(
2247
+ "span",
2248
+ {
2249
+ className: "font-medium",
2250
+ style: { color: "var(--compass-color-text-secondary)" },
2251
+ children: "Total Balance"
2252
+ }
2253
+ ),
2254
+ /* @__PURE__ */ jsx(
2255
+ "span",
2256
+ {
2257
+ className: "font-bold text-lg",
2258
+ style: { color: "var(--compass-color-text)" },
2259
+ children: formatUSD(totalUsdValue)
2260
+ }
2261
+ )
2262
+ ]
2263
+ }
2264
+ )
2265
+ ] }),
2266
+ earnAccountAddress && /* @__PURE__ */ jsx(
2267
+ "div",
2268
+ {
2269
+ className: "mt-4 pt-4 border-t text-center",
2270
+ style: { borderColor: "var(--compass-color-border)" },
2271
+ children: /* @__PURE__ */ jsxs(
2272
+ "span",
2273
+ {
2274
+ className: "text-xs",
2275
+ style: { color: "var(--compass-color-text-tertiary)" },
2276
+ children: [
2277
+ "Earn Account: ",
2278
+ earnAccountAddress.slice(0, 6),
2279
+ "...",
2280
+ earnAccountAddress.slice(-4)
2281
+ ]
2282
+ }
2283
+ )
2284
+ }
2285
+ )
2286
+ ] })
2287
+ ]
2288
+ }
2289
+ )
2290
+ ] });
2291
+ }
2292
+ var TRANSFER_TOKENS = ["USDC"];
2293
+ function EarnAccountBalance({
2294
+ compact = false,
2295
+ onTransferComplete
2296
+ }) {
2297
+ const [isModalOpen, setIsModalOpen] = useState(false);
2298
+ const [activeAction, setActiveAction] = useState("deposit");
2299
+ const [selectedToken, setSelectedToken] = useState(TRANSFER_TOKENS[0]);
2300
+ const [amount, setAmount] = useState("");
2301
+ const [transferState, setTransferState] = useState("idle");
2302
+ const [statusMessage, setStatusMessage] = useState("");
2303
+ const [error, setError] = useState(null);
2304
+ const [isBalancesModalOpen, setIsBalancesModalOpen] = useState(false);
2305
+ const { address, isConnected, signTypedData, switchChain, walletChainId } = useEmbeddableWallet();
2306
+ const { chainId, chain } = useChain();
2307
+ const { earnAccountAddress, isDeployed } = useEarnAccount();
2308
+ const queryClient = useQueryClient();
2309
+ const { data: balanceData, isLoading: balancesLoading } = useQuery({
2310
+ queryKey: ["earnAccountBalances", chainId, address],
2311
+ queryFn: async () => {
2312
+ if (!address) return null;
2313
+ const response = await fetch(
2314
+ `/api/compass/earn-account/balances?owner=${address}&chain=${chainId}`
2315
+ );
2316
+ if (!response.ok) {
2317
+ throw new Error("Failed to fetch balances");
2318
+ }
2319
+ return response.json();
2320
+ },
2321
+ enabled: !!address && isDeployed,
2322
+ staleTime: 30 * 1e3
2323
+ });
2324
+ const { data: eoaBalances } = useQuery({
2325
+ queryKey: ["eoaBalances", chainId, address, TRANSFER_TOKENS.join(",")],
2326
+ queryFn: async () => {
2327
+ if (!address) return {};
2328
+ const balances = {};
2329
+ for (const token of TRANSFER_TOKENS) {
2330
+ try {
2331
+ const response = await fetch(
2332
+ `/api/compass/token/balance?chain=${chainId}&token=${token}&address=${address}`
2333
+ );
2334
+ if (response.ok) {
2335
+ const data = await response.json();
2336
+ balances[token] = data.balance || "0";
2337
+ }
2338
+ } catch {
2339
+ }
2340
+ }
2341
+ return balances;
2342
+ },
2343
+ enabled: !!address && activeAction === "deposit",
2344
+ staleTime: 30 * 1e3
2345
+ });
2346
+ const earnBalances = balanceData?.balances || {};
2347
+ const totalUsdValue = parseFloat(balanceData?.totalUsdValue || "0");
2348
+ const tokenBalances = Object.entries(earnBalances).filter(([, data]) => {
2349
+ const usdVal = parseFloat(data.usdValue || "0");
2350
+ return usdVal > 0;
2351
+ }).map(([symbol, data]) => ({
2352
+ symbol,
2353
+ balance: data.balance || "0",
2354
+ usdValue: data.usdValue || "0"
2355
+ }));
2356
+ const earnBalanceAmounts = {};
2357
+ for (const [symbol, data] of Object.entries(earnBalances)) {
2358
+ earnBalanceAmounts[symbol] = data.balance;
2359
+ }
2360
+ const resetForm = useCallback(() => {
2361
+ setAmount("");
2362
+ setTransferState("idle");
2363
+ setStatusMessage("");
2364
+ setError(null);
2365
+ }, []);
2366
+ const handleOpenModal = () => {
2367
+ resetForm();
2368
+ setIsModalOpen(true);
2369
+ };
2370
+ const handleCloseModal = () => {
2371
+ setIsModalOpen(false);
2372
+ resetForm();
2373
+ };
2374
+ const handleActionChange = (action) => {
2375
+ setActiveAction(action);
2376
+ setAmount("");
2377
+ setError(null);
2378
+ };
2379
+ const getMaxBalance = () => {
2380
+ if (activeAction === "deposit") {
2381
+ return eoaBalances?.[selectedToken] || "0";
2382
+ }
2383
+ return earnBalanceAmounts[selectedToken] || "0";
2384
+ };
2385
+ const handleQuickAmount = (percentage) => {
2386
+ const max = parseFloat(getMaxBalance());
2387
+ if (isNaN(max)) return;
2388
+ setAmount(formatAmount(max * percentage));
2389
+ };
2390
+ const handleTransfer = useCallback(async () => {
2391
+ if (!address || !amount || !signTypedData) return;
2392
+ setError(null);
2393
+ try {
2394
+ const targetChainId = chain.viemChain.id;
2395
+ if (walletChainId !== void 0 && walletChainId !== targetChainId) {
2396
+ if (!switchChain) {
2397
+ throw new Error(`Please switch your wallet to ${chain.name} (chain ID ${targetChainId}) to continue. Your wallet is currently on chain ID ${walletChainId}.`);
2398
+ }
2399
+ setStatusMessage(`Switching network to ${chain.name}...`);
2400
+ try {
2401
+ await switchChain(targetChainId);
2402
+ } catch (switchError) {
2403
+ 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}.`);
2404
+ }
2405
+ } else if (switchChain && walletChainId === void 0) {
2406
+ setStatusMessage("Switching network...");
2407
+ try {
2408
+ await switchChain(targetChainId);
2409
+ } catch (switchError) {
2410
+ throw new Error(`Please switch your wallet to ${chain.name} to continue`);
2411
+ }
2412
+ }
2413
+ if (activeAction === "deposit") {
2414
+ setTransferState("checking_approval");
2415
+ setStatusMessage("Checking token approval...");
2416
+ const approveResponse = await fetch("/api/compass/transfer/approve", {
2417
+ method: "POST",
2418
+ headers: { "Content-Type": "application/json" },
2419
+ body: JSON.stringify({
2420
+ owner: address,
2421
+ chain: chainId,
2422
+ token: selectedToken
2423
+ })
2424
+ });
2425
+ if (!approveResponse.ok) {
2426
+ const errData = await approveResponse.json();
2427
+ throw new Error(errData.error || "Failed to check approval");
2428
+ }
2429
+ const approvalData = await approveResponse.json();
2430
+ if (!approvalData.approved) {
2431
+ if (approvalData.requiresTransaction) {
2432
+ throw new Error("This token requires a transaction-based approval. Please approve manually.");
2433
+ }
2434
+ setTransferState("awaiting_approval_signature");
2435
+ setStatusMessage("Please sign the approval...");
2436
+ const approvalSignature = await signTypedData({
2437
+ domain: approvalData.domain,
2438
+ types: approvalData.normalizedTypes,
2439
+ primaryType: "Permit",
2440
+ message: approvalData.message
2441
+ });
2442
+ setTransferState("approving");
2443
+ setStatusMessage("Executing approval...");
2444
+ const executeApprovalResponse = await fetch("/api/compass/transfer/execute", {
2445
+ method: "POST",
2446
+ headers: { "Content-Type": "application/json" },
2447
+ body: JSON.stringify({
2448
+ owner: address,
2449
+ chain: chainId,
2450
+ eip712: approvalData.eip712,
2451
+ signature: approvalSignature
2452
+ })
2453
+ });
2454
+ if (!executeApprovalResponse.ok) {
2455
+ const errData = await executeApprovalResponse.json();
2456
+ throw new Error(errData.error || "Approval failed");
2457
+ }
2458
+ }
2459
+ }
2460
+ setTransferState("awaiting_transfer_signature");
2461
+ setStatusMessage("Preparing transfer...");
2462
+ const prepareResponse = await fetch("/api/compass/transfer/prepare", {
2463
+ method: "POST",
2464
+ headers: { "Content-Type": "application/json" },
2465
+ body: JSON.stringify({
2466
+ owner: address,
2467
+ chain: chainId,
2468
+ token: selectedToken,
2469
+ amount,
2470
+ action: activeAction.toUpperCase()
2471
+ })
2472
+ });
2473
+ if (!prepareResponse.ok) {
2474
+ const errData = await prepareResponse.json();
2475
+ throw new Error(errData.error || "Failed to prepare transfer");
2476
+ }
2477
+ const prepareData = await prepareResponse.json();
2478
+ setStatusMessage("Please sign the transfer...");
2479
+ const transferSignature = await signTypedData({
2480
+ domain: prepareData.domain,
2481
+ types: prepareData.normalizedTypes,
2482
+ primaryType: prepareData.primaryType,
2483
+ message: prepareData.message
2484
+ });
2485
+ setTransferState("transferring");
2486
+ setStatusMessage("Executing transfer...");
2487
+ const executeResponse = await fetch("/api/compass/transfer/execute", {
2488
+ method: "POST",
2489
+ headers: { "Content-Type": "application/json" },
2490
+ body: JSON.stringify({
2491
+ owner: address,
2492
+ chain: chainId,
2493
+ eip712: prepareData.eip712,
2494
+ signature: transferSignature
2495
+ })
2496
+ });
2497
+ if (!executeResponse.ok) {
2498
+ const errData = await executeResponse.json();
2499
+ throw new Error(errData.error || "Transfer failed");
2500
+ }
2501
+ const { txHash } = await executeResponse.json();
2502
+ setTransferState("success");
2503
+ setStatusMessage("Transfer successful!");
2504
+ onTransferComplete?.(activeAction, selectedToken, amount, txHash);
2505
+ queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
2506
+ queryClient.invalidateQueries({ queryKey: ["eoaBalances"] });
2507
+ setTimeout(() => {
2508
+ resetForm();
2509
+ }, 2e3);
2510
+ } catch (err) {
2511
+ console.error("Transfer failed:", err);
2512
+ setTransferState("error");
2513
+ setError(err instanceof Error ? err.message : "Transfer failed");
2514
+ }
2515
+ }, [
2516
+ address,
2517
+ amount,
2518
+ activeAction,
2519
+ selectedToken,
2520
+ chainId,
2521
+ chain,
2522
+ walletChainId,
2523
+ signTypedData,
2524
+ switchChain,
2525
+ queryClient,
2526
+ onTransferComplete,
2527
+ resetForm
2528
+ ]);
2529
+ if (!isConnected) {
2530
+ return null;
2531
+ }
2532
+ const isProcessing = transferState !== "idle" && transferState !== "success" && transferState !== "error";
2533
+ if (!isDeployed) {
2534
+ return /* @__PURE__ */ jsxs(
2535
+ "div",
2536
+ {
2537
+ className: `flex items-center gap-2 rounded-lg border ${compact ? "px-2 py-1.5" : "px-3 py-2"}`,
2538
+ style: {
2539
+ backgroundColor: "var(--compass-color-surface)",
2540
+ borderColor: "var(--compass-color-border)"
2541
+ },
2542
+ children: [
2543
+ /* @__PURE__ */ jsx(Wallet, { size: compact ? 14 : 16, style: { color: "var(--compass-color-text-secondary)" } }),
2544
+ /* @__PURE__ */ jsx(
2545
+ "span",
2546
+ {
2547
+ className: `${compact ? "text-xs" : "text-sm"}`,
2548
+ style: { color: "var(--compass-color-text-secondary)" },
2549
+ children: "No Earn Account"
2550
+ }
2551
+ )
2552
+ ]
2553
+ }
2554
+ );
2555
+ }
2556
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2557
+ /* @__PURE__ */ jsxs(
2558
+ "button",
2559
+ {
2560
+ onClick: () => setIsBalancesModalOpen(true),
2561
+ 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"}`,
2562
+ style: {
2563
+ backgroundColor: "var(--compass-color-surface)",
2564
+ borderColor: "var(--compass-color-border)",
2565
+ cursor: "pointer"
2566
+ },
2567
+ children: [
2568
+ /* @__PURE__ */ jsx(Wallet, { size: compact ? 14 : 16, style: { color: "var(--compass-color-primary)" } }),
2569
+ balancesLoading ? /* @__PURE__ */ jsx(Loader2, { size: compact ? 12 : 14, className: "animate-spin", style: { color: "var(--compass-color-text-secondary)" } }) : /* @__PURE__ */ jsx(
2570
+ "span",
2571
+ {
2572
+ className: `font-medium ${compact ? "text-xs" : "text-sm"}`,
2573
+ style: { color: "var(--compass-color-text)" },
2574
+ children: formatUSD(totalUsdValue)
2575
+ }
2576
+ )
2577
+ ]
2578
+ }
2579
+ ),
2580
+ /* @__PURE__ */ jsx(
2581
+ "button",
2582
+ {
2583
+ onClick: handleOpenModal,
2584
+ className: `rounded-md font-medium transition-colors ${compact ? "px-2 py-1 text-xs" : "px-3 py-1.5 text-sm"}`,
2585
+ style: {
2586
+ backgroundColor: "var(--compass-color-primary)",
2587
+ color: "var(--compass-color-primary-text)"
2588
+ },
2589
+ children: "Fund"
2590
+ }
2591
+ ),
2592
+ /* @__PURE__ */ jsx(
2593
+ AccountBalancesModal,
2594
+ {
2595
+ isOpen: isBalancesModalOpen,
2596
+ onClose: () => setIsBalancesModalOpen(false),
2597
+ balances: tokenBalances,
2598
+ totalUsdValue: totalUsdValue.toString(),
2599
+ isLoading: balancesLoading,
2600
+ earnAccountAddress: earnAccountAddress ?? void 0
2601
+ }
2602
+ ),
2603
+ /* @__PURE__ */ jsx(
2604
+ ActionModal,
2605
+ {
2606
+ isOpen: isModalOpen,
2607
+ onClose: handleCloseModal,
2608
+ title: "Transfer Funds",
2609
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
2610
+ /* @__PURE__ */ jsx(
2611
+ "div",
2612
+ {
2613
+ className: "flex gap-1 p-1 rounded-lg",
2614
+ style: { backgroundColor: "var(--compass-color-background)" },
2615
+ children: ["deposit", "withdraw"].map((action) => /* @__PURE__ */ jsxs(
2616
+ "button",
2617
+ {
2618
+ onClick: () => handleActionChange(action),
2619
+ disabled: isProcessing,
2620
+ className: "flex-1 py-2 rounded-md text-sm font-medium capitalize transition-all flex items-center justify-center gap-2",
2621
+ style: {
2622
+ backgroundColor: activeAction === action ? "var(--compass-color-surface)" : "transparent",
2623
+ color: activeAction === action ? "var(--compass-color-text)" : "var(--compass-color-text-secondary)"
2624
+ },
2625
+ children: [
2626
+ action === "deposit" ? /* @__PURE__ */ jsx(ArrowDownLeft, { size: 14 }) : /* @__PURE__ */ jsx(ArrowUpRight, { size: 14 }),
2627
+ action
2628
+ ]
2629
+ },
2630
+ action
2631
+ ))
2632
+ }
2633
+ ),
2634
+ /* @__PURE__ */ jsxs("div", { children: [
2635
+ /* @__PURE__ */ jsx(
2636
+ "label",
2637
+ {
2638
+ className: "text-sm font-medium mb-1 block",
2639
+ style: { color: "var(--compass-color-text-secondary)" },
2640
+ children: "Token"
2641
+ }
2642
+ ),
2643
+ /* @__PURE__ */ jsx(
2644
+ TokenSelector,
2645
+ {
2646
+ tokens: TRANSFER_TOKENS,
2647
+ selectedToken,
2648
+ onSelect: setSelectedToken,
2649
+ balances: activeAction === "deposit" ? eoaBalances : earnBalanceAmounts,
2650
+ disabled: isProcessing
2651
+ }
2652
+ )
2653
+ ] }),
2654
+ /* @__PURE__ */ jsxs("div", { children: [
2655
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
2656
+ /* @__PURE__ */ jsx(
2657
+ "label",
2658
+ {
2659
+ className: "text-sm font-medium",
2660
+ style: { color: "var(--compass-color-text-secondary)" },
2661
+ children: "Amount"
2662
+ }
2663
+ ),
2664
+ /* @__PURE__ */ jsxs("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: [
2665
+ "Available: ",
2666
+ formatAmount(getMaxBalance()),
2667
+ " ",
2668
+ selectedToken
2669
+ ] })
2670
+ ] }),
2671
+ /* @__PURE__ */ jsxs(
2672
+ "div",
2673
+ {
2674
+ className: "flex items-center gap-2 p-3 rounded-lg border",
2675
+ style: {
2676
+ backgroundColor: "var(--compass-color-background)",
2677
+ borderColor: "var(--compass-color-border)"
2678
+ },
2679
+ children: [
2680
+ /* @__PURE__ */ jsx(
2681
+ "input",
2682
+ {
2683
+ type: "number",
2684
+ value: amount,
2685
+ onChange: (e) => {
2686
+ setAmount(e.target.value);
2687
+ setError(null);
2688
+ },
2689
+ placeholder: "0.00",
2690
+ disabled: isProcessing,
2691
+ className: "flex-1 bg-transparent outline-none text-lg font-mono",
2692
+ style: { color: "var(--compass-color-text)" }
2693
+ }
2694
+ ),
2695
+ /* @__PURE__ */ jsx(
2696
+ "span",
2697
+ {
2698
+ className: "text-sm font-medium",
2699
+ style: { color: "var(--compass-color-text-secondary)" },
2700
+ children: selectedToken
2701
+ }
2702
+ )
2703
+ ]
2704
+ }
2705
+ )
2706
+ ] }),
2707
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: [0.25, 0.5, 1].map((pct) => /* @__PURE__ */ jsx(
2708
+ "button",
2709
+ {
2710
+ onClick: () => handleQuickAmount(pct),
2711
+ disabled: isProcessing,
2712
+ className: "flex-1 py-1.5 rounded-md text-xs font-medium transition-colors",
2713
+ style: {
2714
+ backgroundColor: "var(--compass-color-secondary)",
2715
+ color: "var(--compass-color-text-secondary)"
2716
+ },
2717
+ children: pct === 1 ? "Max" : `${pct * 100}%`
2718
+ },
2719
+ pct
2720
+ )) }),
2721
+ error && /* @__PURE__ */ jsx(
2722
+ "div",
2723
+ {
2724
+ className: "p-3 rounded-lg text-sm",
2725
+ style: {
2726
+ backgroundColor: "var(--compass-color-error-muted)",
2727
+ color: "var(--compass-color-error)"
2728
+ },
2729
+ children: error
2730
+ }
2731
+ ),
2732
+ statusMessage && !error && /* @__PURE__ */ jsx(
2733
+ "div",
2734
+ {
2735
+ className: "p-3 rounded-lg text-sm text-center",
2736
+ style: {
2737
+ backgroundColor: transferState === "success" ? "var(--compass-color-success-muted)" : "var(--compass-color-primary-muted)",
2738
+ color: transferState === "success" ? "var(--compass-color-success)" : "var(--compass-color-primary)"
2739
+ },
2740
+ children: statusMessage
2741
+ }
2742
+ ),
2743
+ /* @__PURE__ */ jsxs(
2744
+ "button",
2745
+ {
2746
+ onClick: handleTransfer,
2747
+ disabled: isProcessing || !amount || parseFloat(amount) <= 0,
2748
+ className: "w-full py-3 rounded-lg font-medium transition-colors flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
2749
+ style: {
2750
+ backgroundColor: "var(--compass-color-primary)",
2751
+ color: "var(--compass-color-primary-text)"
2752
+ },
2753
+ children: [
2754
+ isProcessing && /* @__PURE__ */ jsx(Loader2, { size: 18, className: "animate-spin" }),
2755
+ isProcessing ? "Processing..." : activeAction === "deposit" ? "Deposit to Earn Account" : "Withdraw to Wallet"
2756
+ ]
2757
+ }
2758
+ ),
2759
+ /* @__PURE__ */ jsx(
2760
+ "p",
2761
+ {
2762
+ className: "text-xs text-center",
2763
+ style: { color: "var(--compass-color-text-tertiary)" },
2764
+ children: "Gas fees are sponsored by Compass"
2765
+ }
2766
+ )
2767
+ ] })
2768
+ }
2769
+ )
2770
+ ] });
2771
+ }
1890
2772
  function formatTVL(tvl) {
1891
2773
  if (!tvl) return "$0";
1892
2774
  const num = parseFloat(tvl);
@@ -2016,9 +2898,9 @@ function useVaultsData(options = {}) {
2016
2898
  const { client } = useEmbeddableApi();
2017
2899
  const { address } = useEmbeddableWallet();
2018
2900
  const { chainId } = useChain();
2019
- const { sortBy = "apy_7d", assetFilter, minApy } = options;
2901
+ const { sortBy = "apy_7d", assetFilter, minApy, minTvl } = options;
2020
2902
  const vaultsQuery = useQuery({
2021
- queryKey: ["vaults", chainId, sortBy, assetFilter, minApy],
2903
+ queryKey: ["vaults", chainId, sortBy, assetFilter, minApy, minTvl],
2022
2904
  queryFn: async () => {
2023
2905
  const assetSymbol = assetFilter && assetFilter.length === 1 ? assetFilter[0] : void 0;
2024
2906
  const response = await client.earn.earnVaults({
@@ -2048,6 +2930,12 @@ function useVaultsData(options = {}) {
2048
2930
  return apy >= minApy;
2049
2931
  });
2050
2932
  }
2933
+ if (minTvl !== void 0 && minTvl > 0) {
2934
+ vaults = vaults.filter((v) => {
2935
+ const tvl = parseFloat(v.tvlUsd || "0");
2936
+ return tvl >= minTvl;
2937
+ });
2938
+ }
2051
2939
  return vaults;
2052
2940
  },
2053
2941
  staleTime: 30 * 1e3
@@ -2101,15 +2989,6 @@ function useVaultsData(options = {}) {
2101
2989
  }
2102
2990
  };
2103
2991
  }
2104
- var TOKEN_DECIMALS2 = {
2105
- USDC: 6,
2106
- USDT: 6,
2107
- DAI: 18,
2108
- ETH: 18,
2109
- WETH: 18,
2110
- WBTC: 8,
2111
- cbBTC: 8
2112
- };
2113
2992
  function VaultsList({
2114
2993
  showApy = true,
2115
2994
  apyPeriods = ["7d", "30d", "90d"],
@@ -2119,10 +2998,11 @@ function VaultsList({
2119
2998
  showHistory = true,
2120
2999
  showSearch = true,
2121
3000
  showSort = true,
2122
- actionMode = "modal",
2123
3001
  defaultSort = "apy_7d",
2124
3002
  assetFilter,
2125
3003
  minApy,
3004
+ minTvl: initialMinTvl,
3005
+ showTvlFilter = true,
2126
3006
  onVaultSelect,
2127
3007
  onDeposit,
2128
3008
  onWithdraw
@@ -2130,11 +3010,18 @@ function VaultsList({
2130
3010
  const [searchQuery, setSearchQuery] = useState("");
2131
3011
  const [sortBy, setSortBy] = useState(defaultSort);
2132
3012
  const [selectedVault, setSelectedVault] = useState(null);
3013
+ const [minTvlFilter, setMinTvlFilter] = useState(initialMinTvl);
3014
+ const [showFilterPanel, setShowFilterPanel] = useState(false);
2133
3015
  const { vaults, isLoading, isError, refetch } = useVaultsData({
2134
3016
  sortBy,
2135
3017
  assetFilter,
2136
- minApy
3018
+ minApy,
3019
+ minTvl: minTvlFilter
2137
3020
  });
3021
+ const handleMinTvlChange = useCallback((value) => {
3022
+ const num = parseFloat(value);
3023
+ setMinTvlFilter(isNaN(num) || num <= 0 ? void 0 : num);
3024
+ }, []);
2138
3025
  const filteredVaults = useMemo(() => {
2139
3026
  if (!searchQuery) return vaults;
2140
3027
  const query = searchQuery.toLowerCase();
@@ -2157,51 +3044,121 @@ function VaultsList({
2157
3044
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
2158
3045
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
2159
3046
  /* @__PURE__ */ jsx(ChainSwitcher, {}),
2160
- /* @__PURE__ */ jsx(WalletStatus, { compact: true })
3047
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3048
+ /* @__PURE__ */ jsx(EarnAccountBalance, { compact: true }),
3049
+ /* @__PURE__ */ jsx(WalletStatus, { compact: true })
3050
+ ] })
2161
3051
  ] }),
2162
- (showSearch || showSort) && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2163
- showSearch && /* @__PURE__ */ jsxs(
3052
+ (showSearch || showSort || showTvlFilter) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3053
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3054
+ showSearch && /* @__PURE__ */ jsxs(
3055
+ "div",
3056
+ {
3057
+ className: "flex-1 flex items-center gap-2 px-3 py-2 rounded-lg border",
3058
+ style: {
3059
+ backgroundColor: "var(--compass-color-background)",
3060
+ borderColor: "var(--compass-color-border)"
3061
+ },
3062
+ children: [
3063
+ /* @__PURE__ */ jsx(Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
3064
+ /* @__PURE__ */ jsx(
3065
+ "input",
3066
+ {
3067
+ type: "text",
3068
+ placeholder: "Search vaults...",
3069
+ value: searchQuery,
3070
+ onChange: (e) => setSearchQuery(e.target.value),
3071
+ className: "flex-1 bg-transparent outline-none text-sm",
3072
+ style: { color: "var(--compass-color-text)" }
3073
+ }
3074
+ )
3075
+ ]
3076
+ }
3077
+ ),
3078
+ showSort && /* @__PURE__ */ jsxs(
3079
+ "select",
3080
+ {
3081
+ value: sortBy,
3082
+ onChange: (e) => setSortBy(e.target.value),
3083
+ className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
3084
+ style: {
3085
+ backgroundColor: "var(--compass-color-background)",
3086
+ borderColor: "var(--compass-color-border)",
3087
+ color: "var(--compass-color-text)"
3088
+ },
3089
+ children: [
3090
+ /* @__PURE__ */ jsx("option", { value: "apy_7d", children: "APY (7D)" }),
3091
+ /* @__PURE__ */ jsx("option", { value: "apy_30d", children: "APY (30D)" }),
3092
+ /* @__PURE__ */ jsx("option", { value: "apy_90d", children: "APY (90D)" }),
3093
+ /* @__PURE__ */ jsx("option", { value: "tvl", children: "TVL" })
3094
+ ]
3095
+ }
3096
+ ),
3097
+ showTvlFilter && /* @__PURE__ */ jsxs(
3098
+ "button",
3099
+ {
3100
+ onClick: () => setShowFilterPanel(!showFilterPanel),
3101
+ className: "px-3 py-2 rounded-lg border text-sm flex items-center gap-2",
3102
+ style: {
3103
+ backgroundColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary-muted)" : "var(--compass-color-background)",
3104
+ borderColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-border)",
3105
+ color: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-text)"
3106
+ },
3107
+ children: [
3108
+ /* @__PURE__ */ jsx(SlidersHorizontal, { size: 14 }),
3109
+ "Filter"
3110
+ ]
3111
+ }
3112
+ )
3113
+ ] }),
3114
+ showTvlFilter && showFilterPanel && /* @__PURE__ */ jsxs(
2164
3115
  "div",
2165
3116
  {
2166
- className: "flex-1 flex items-center gap-2 px-3 py-2 rounded-lg border",
3117
+ className: "flex items-center gap-3 p-3 rounded-lg border",
2167
3118
  style: {
2168
- backgroundColor: "var(--compass-color-background)",
3119
+ backgroundColor: "var(--compass-color-surface)",
2169
3120
  borderColor: "var(--compass-color-border)"
2170
3121
  },
2171
3122
  children: [
2172
- /* @__PURE__ */ jsx(Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
2173
3123
  /* @__PURE__ */ jsx(
2174
- "input",
3124
+ "label",
2175
3125
  {
2176
- type: "text",
2177
- placeholder: "Search vaults...",
2178
- value: searchQuery,
2179
- onChange: (e) => setSearchQuery(e.target.value),
2180
- className: "flex-1 bg-transparent outline-none text-sm",
2181
- style: { color: "var(--compass-color-text)" }
3126
+ className: "text-sm font-medium whitespace-nowrap",
3127
+ style: { color: "var(--compass-color-text-secondary)" },
3128
+ children: "Min TVL:"
3129
+ }
3130
+ ),
3131
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3132
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-tertiary)" }, children: "$" }),
3133
+ /* @__PURE__ */ jsx(
3134
+ "input",
3135
+ {
3136
+ type: "number",
3137
+ placeholder: "0",
3138
+ value: minTvlFilter || "",
3139
+ onChange: (e) => handleMinTvlChange(e.target.value),
3140
+ className: "w-24 px-2 py-1 rounded border text-sm bg-transparent",
3141
+ style: {
3142
+ borderColor: "var(--compass-color-border)",
3143
+ color: "var(--compass-color-text)"
3144
+ }
3145
+ }
3146
+ )
3147
+ ] }),
3148
+ minTvlFilter && /* @__PURE__ */ jsx(
3149
+ "button",
3150
+ {
3151
+ onClick: () => setMinTvlFilter(void 0),
3152
+ className: "text-xs px-2 py-1 rounded",
3153
+ style: {
3154
+ backgroundColor: "var(--compass-color-error-muted)",
3155
+ color: "var(--compass-color-error)"
3156
+ },
3157
+ children: "Clear"
2182
3158
  }
2183
3159
  )
2184
3160
  ]
2185
3161
  }
2186
- ),
2187
- showSort && /* @__PURE__ */ jsxs(
2188
- "select",
2189
- {
2190
- value: sortBy,
2191
- onChange: (e) => setSortBy(e.target.value),
2192
- className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
2193
- style: {
2194
- backgroundColor: "var(--compass-color-background)",
2195
- borderColor: "var(--compass-color-border)",
2196
- color: "var(--compass-color-text)"
2197
- },
2198
- children: [
2199
- /* @__PURE__ */ jsx("option", { value: "apy_7d", children: "APY (7D)" }),
2200
- /* @__PURE__ */ jsx("option", { value: "apy_30d", children: "APY (30D)" }),
2201
- /* @__PURE__ */ jsx("option", { value: "apy_90d", children: "APY (90D)" }),
2202
- /* @__PURE__ */ jsx("option", { value: "tvl", children: "TVL" })
2203
- ]
2204
- }
2205
3162
  )
2206
3163
  ] }),
2207
3164
  isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(Loader2, { size: 24, className: "animate-spin", style: { color: "var(--compass-color-primary)" } }) }) : isError ? /* @__PURE__ */ jsx(
@@ -2233,7 +3190,7 @@ function VaultsList({
2233
3190
  },
2234
3191
  vault.vaultAddress
2235
3192
  )) }),
2236
- actionMode === "modal" && selectedVault && /* @__PURE__ */ jsx(
3193
+ selectedVault && /* @__PURE__ */ jsx(
2237
3194
  ActionModal,
2238
3195
  {
2239
3196
  isOpen: !!selectedVault,
@@ -2261,8 +3218,7 @@ function VaultsList({
2261
3218
  {
2262
3219
  venueType: "VAULT",
2263
3220
  venueAddress: selectedVault.vaultAddress,
2264
- tokenSymbol: selectedVault.assetSymbol,
2265
- tokenDecimals: TOKEN_DECIMALS2[selectedVault.assetSymbol] || 18,
3221
+ venueToken: selectedVault.assetSymbol,
2266
3222
  positionBalance: selectedVault.userPosition?.balance,
2267
3223
  onSuccess: handleActionSuccess
2268
3224
  }
@@ -2362,15 +3318,6 @@ function useAaveData(options = {}) {
2362
3318
  }
2363
3319
  };
2364
3320
  }
2365
- var TOKEN_DECIMALS3 = {
2366
- USDC: 6,
2367
- USDT: 6,
2368
- DAI: 18,
2369
- ETH: 18,
2370
- WETH: 18,
2371
- WBTC: 8,
2372
- cbBTC: 8
2373
- };
2374
3321
  function formatAPY2(apy) {
2375
3322
  if (!apy) return "0.00%";
2376
3323
  const num = parseFloat(apy);
@@ -2394,7 +3341,6 @@ function AaveMarketsList({
2394
3341
  showSearch = true,
2395
3342
  showSort = false,
2396
3343
  // Only one sort option (APY), so hide by default
2397
- actionMode = "modal",
2398
3344
  defaultSort = "supply_apy",
2399
3345
  assetFilter,
2400
3346
  onMarketSelect,
@@ -2427,7 +3373,10 @@ function AaveMarketsList({
2427
3373
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
2428
3374
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
2429
3375
  /* @__PURE__ */ jsx(ChainSwitcher, {}),
2430
- /* @__PURE__ */ jsx(WalletStatus, { compact: true })
3376
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3377
+ /* @__PURE__ */ jsx(EarnAccountBalance, { compact: true }),
3378
+ /* @__PURE__ */ jsx(WalletStatus, { compact: true })
3379
+ ] })
2431
3380
  ] }),
2432
3381
  (showSearch || showSort) && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2433
3382
  showSearch && /* @__PURE__ */ jsxs(
@@ -2579,7 +3528,7 @@ function AaveMarketsList({
2579
3528
  market.marketAddress
2580
3529
  );
2581
3530
  }) }),
2582
- actionMode === "modal" && selectedMarket && /* @__PURE__ */ jsx(
3531
+ selectedMarket && /* @__PURE__ */ jsx(
2583
3532
  ActionModal,
2584
3533
  {
2585
3534
  isOpen: !!selectedMarket,
@@ -2607,8 +3556,7 @@ function AaveMarketsList({
2607
3556
  {
2608
3557
  venueType: "AAVE",
2609
3558
  venueAddress: selectedMarket.marketAddress,
2610
- tokenSymbol: selectedMarket.underlyingSymbol,
2611
- tokenDecimals: TOKEN_DECIMALS3[selectedMarket.underlyingSymbol] || 18,
3559
+ venueToken: selectedMarket.underlyingSymbol,
2612
3560
  positionBalance: selectedMarket.userPosition?.balance,
2613
3561
  onSuccess: handleActionSuccess
2614
3562
  }
@@ -2622,9 +3570,9 @@ function usePendleData(options = {}) {
2622
3570
  const { client } = useEmbeddableApi();
2623
3571
  const { address } = useEmbeddableWallet();
2624
3572
  const { chainId } = useChain();
2625
- const { sortBy = "fixed_apy", assetFilter } = options;
3573
+ const { sortBy = "fixed_apy", assetFilter, minTvl } = options;
2626
3574
  const marketsQuery = useQuery({
2627
- queryKey: ["pendleMarkets", chainId, sortBy, assetFilter],
3575
+ queryKey: ["pendleMarkets", chainId, sortBy, assetFilter, minTvl],
2628
3576
  queryFn: async () => {
2629
3577
  const underlyingSymbol = assetFilter && assetFilter.length === 1 ? assetFilter[0] : void 0;
2630
3578
  const orderBy = sortBy === "tvl" ? "tvl_usd" : "implied_apy";
@@ -2653,6 +3601,12 @@ function usePendleData(options = {}) {
2653
3601
  (m) => assetFilter.includes(m.underlyingSymbol.toUpperCase())
2654
3602
  );
2655
3603
  }
3604
+ if (minTvl !== void 0 && minTvl > 0) {
3605
+ markets = markets.filter((m) => {
3606
+ const tvl = parseFloat(m.tvlUsd || "0");
3607
+ return tvl >= minTvl;
3608
+ });
3609
+ }
2656
3610
  if (sortBy === "expiry") {
2657
3611
  markets.sort((a, b) => {
2658
3612
  return new Date(a.expiry).getTime() - new Date(b.expiry).getTime();
@@ -2711,15 +3665,6 @@ function usePendleData(options = {}) {
2711
3665
  }
2712
3666
  };
2713
3667
  }
2714
- var TOKEN_DECIMALS4 = {
2715
- USDC: 6,
2716
- USDT: 6,
2717
- DAI: 18,
2718
- ETH: 18,
2719
- WETH: 18,
2720
- WBTC: 8,
2721
- cbBTC: 8
2722
- };
2723
3668
  function formatAPY3(apy) {
2724
3669
  if (!apy) return "0.00%";
2725
3670
  return `${parseFloat(apy).toFixed(2)}%`;
@@ -2745,9 +3690,10 @@ function PendleMarketsList({
2745
3690
  showHistory = true,
2746
3691
  showSearch = true,
2747
3692
  showSort = true,
2748
- actionMode = "modal",
2749
3693
  defaultSort = "fixed_apy",
2750
3694
  assetFilter,
3695
+ minTvl: initialMinTvl,
3696
+ showTvlFilter = true,
2751
3697
  onMarketSelect,
2752
3698
  onDeposit,
2753
3699
  onWithdraw
@@ -2755,7 +3701,13 @@ function PendleMarketsList({
2755
3701
  const [searchQuery, setSearchQuery] = useState("");
2756
3702
  const [sortBy, setSortBy] = useState(defaultSort);
2757
3703
  const [selectedMarket, setSelectedMarket] = useState(null);
2758
- const { markets, isLoading, isError, refetch } = usePendleData({ sortBy, assetFilter });
3704
+ const [minTvlFilter, setMinTvlFilter] = useState(initialMinTvl);
3705
+ const [showFilterPanel, setShowFilterPanel] = useState(false);
3706
+ const { markets, isLoading, isError, refetch } = usePendleData({ sortBy, assetFilter, minTvl: minTvlFilter });
3707
+ const handleMinTvlChange = useCallback((value) => {
3708
+ const num = parseFloat(value);
3709
+ setMinTvlFilter(isNaN(num) || num <= 0 ? void 0 : num);
3710
+ }, []);
2759
3711
  const filteredMarkets = useMemo(() => {
2760
3712
  if (!searchQuery) return markets;
2761
3713
  const query = searchQuery.toLowerCase();
@@ -2778,50 +3730,120 @@ function PendleMarketsList({
2778
3730
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
2779
3731
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
2780
3732
  /* @__PURE__ */ jsx(ChainSwitcher, {}),
2781
- /* @__PURE__ */ jsx(WalletStatus, { compact: true })
3733
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3734
+ /* @__PURE__ */ jsx(EarnAccountBalance, { compact: true }),
3735
+ /* @__PURE__ */ jsx(WalletStatus, { compact: true })
3736
+ ] })
2782
3737
  ] }),
2783
- (showSearch || showSort) && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2784
- showSearch && /* @__PURE__ */ jsxs(
3738
+ (showSearch || showSort || showTvlFilter) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3739
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3740
+ showSearch && /* @__PURE__ */ jsxs(
3741
+ "div",
3742
+ {
3743
+ className: "flex-1 flex items-center gap-2 px-3 py-2 rounded-lg border",
3744
+ style: {
3745
+ backgroundColor: "var(--compass-color-background)",
3746
+ borderColor: "var(--compass-color-border)"
3747
+ },
3748
+ children: [
3749
+ /* @__PURE__ */ jsx(Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
3750
+ /* @__PURE__ */ jsx(
3751
+ "input",
3752
+ {
3753
+ type: "text",
3754
+ placeholder: "Search markets...",
3755
+ value: searchQuery,
3756
+ onChange: (e) => setSearchQuery(e.target.value),
3757
+ className: "flex-1 bg-transparent outline-none text-sm",
3758
+ style: { color: "var(--compass-color-text)" }
3759
+ }
3760
+ )
3761
+ ]
3762
+ }
3763
+ ),
3764
+ showSort && /* @__PURE__ */ jsxs(
3765
+ "select",
3766
+ {
3767
+ value: sortBy,
3768
+ onChange: (e) => setSortBy(e.target.value),
3769
+ className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
3770
+ style: {
3771
+ backgroundColor: "var(--compass-color-background)",
3772
+ borderColor: "var(--compass-color-border)",
3773
+ color: "var(--compass-color-text)"
3774
+ },
3775
+ children: [
3776
+ /* @__PURE__ */ jsx("option", { value: "fixed_apy", children: "Fixed APY" }),
3777
+ /* @__PURE__ */ jsx("option", { value: "tvl", children: "TVL" }),
3778
+ /* @__PURE__ */ jsx("option", { value: "expiry", children: "Expiry" })
3779
+ ]
3780
+ }
3781
+ ),
3782
+ showTvlFilter && /* @__PURE__ */ jsxs(
3783
+ "button",
3784
+ {
3785
+ onClick: () => setShowFilterPanel(!showFilterPanel),
3786
+ className: "px-3 py-2 rounded-lg border text-sm flex items-center gap-2",
3787
+ style: {
3788
+ backgroundColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary-muted)" : "var(--compass-color-background)",
3789
+ borderColor: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-border)",
3790
+ color: showFilterPanel || minTvlFilter ? "var(--compass-color-primary)" : "var(--compass-color-text)"
3791
+ },
3792
+ children: [
3793
+ /* @__PURE__ */ jsx(SlidersHorizontal, { size: 14 }),
3794
+ "Filter"
3795
+ ]
3796
+ }
3797
+ )
3798
+ ] }),
3799
+ showTvlFilter && showFilterPanel && /* @__PURE__ */ jsxs(
2785
3800
  "div",
2786
3801
  {
2787
- className: "flex-1 flex items-center gap-2 px-3 py-2 rounded-lg border",
3802
+ className: "flex items-center gap-3 p-3 rounded-lg border",
2788
3803
  style: {
2789
- backgroundColor: "var(--compass-color-background)",
3804
+ backgroundColor: "var(--compass-color-surface)",
2790
3805
  borderColor: "var(--compass-color-border)"
2791
3806
  },
2792
3807
  children: [
2793
- /* @__PURE__ */ jsx(Search, { size: 16, style: { color: "var(--compass-color-text-tertiary)" } }),
2794
3808
  /* @__PURE__ */ jsx(
2795
- "input",
3809
+ "label",
2796
3810
  {
2797
- type: "text",
2798
- placeholder: "Search markets...",
2799
- value: searchQuery,
2800
- onChange: (e) => setSearchQuery(e.target.value),
2801
- className: "flex-1 bg-transparent outline-none text-sm",
2802
- style: { color: "var(--compass-color-text)" }
3811
+ className: "text-sm font-medium whitespace-nowrap",
3812
+ style: { color: "var(--compass-color-text-secondary)" },
3813
+ children: "Min TVL:"
3814
+ }
3815
+ ),
3816
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3817
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--compass-color-text-tertiary)" }, children: "$" }),
3818
+ /* @__PURE__ */ jsx(
3819
+ "input",
3820
+ {
3821
+ type: "number",
3822
+ placeholder: "0",
3823
+ value: minTvlFilter || "",
3824
+ onChange: (e) => handleMinTvlChange(e.target.value),
3825
+ className: "w-24 px-2 py-1 rounded border text-sm bg-transparent",
3826
+ style: {
3827
+ borderColor: "var(--compass-color-border)",
3828
+ color: "var(--compass-color-text)"
3829
+ }
3830
+ }
3831
+ )
3832
+ ] }),
3833
+ minTvlFilter && /* @__PURE__ */ jsx(
3834
+ "button",
3835
+ {
3836
+ onClick: () => setMinTvlFilter(void 0),
3837
+ className: "text-xs px-2 py-1 rounded",
3838
+ style: {
3839
+ backgroundColor: "var(--compass-color-error-muted)",
3840
+ color: "var(--compass-color-error)"
3841
+ },
3842
+ children: "Clear"
2803
3843
  }
2804
3844
  )
2805
3845
  ]
2806
3846
  }
2807
- ),
2808
- showSort && /* @__PURE__ */ jsxs(
2809
- "select",
2810
- {
2811
- value: sortBy,
2812
- onChange: (e) => setSortBy(e.target.value),
2813
- className: "px-3 py-2 rounded-lg border text-sm cursor-pointer",
2814
- style: {
2815
- backgroundColor: "var(--compass-color-background)",
2816
- borderColor: "var(--compass-color-border)",
2817
- color: "var(--compass-color-text)"
2818
- },
2819
- children: [
2820
- /* @__PURE__ */ jsx("option", { value: "fixed_apy", children: "Fixed APY" }),
2821
- /* @__PURE__ */ jsx("option", { value: "tvl", children: "TVL" }),
2822
- /* @__PURE__ */ jsx("option", { value: "expiry", children: "Expiry" })
2823
- ]
2824
- }
2825
3847
  )
2826
3848
  ] }),
2827
3849
  isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(Loader2, { size: 24, className: "animate-spin", style: { color: "var(--compass-color-primary)" } }) }) : isError ? /* @__PURE__ */ jsx(
@@ -2956,7 +3978,7 @@ function PendleMarketsList({
2956
3978
  market.marketAddress
2957
3979
  );
2958
3980
  }) }),
2959
- actionMode === "modal" && selectedMarket && /* @__PURE__ */ jsx(
3981
+ selectedMarket && /* @__PURE__ */ jsx(
2960
3982
  ActionModal,
2961
3983
  {
2962
3984
  isOpen: !!selectedMarket,
@@ -2984,8 +4006,7 @@ function PendleMarketsList({
2984
4006
  {
2985
4007
  venueType: "PENDLE_PT",
2986
4008
  venueAddress: selectedMarket.marketAddress,
2987
- tokenSymbol: selectedMarket.underlyingSymbol,
2988
- tokenDecimals: TOKEN_DECIMALS4[selectedMarket.underlyingSymbol] || 18,
4009
+ venueToken: selectedMarket.underlyingSymbol,
2989
4010
  positionBalance: selectedMarket.userPosition?.balance,
2990
4011
  onSuccess: handleActionSuccess
2991
4012
  }
@@ -2996,43 +4017,55 @@ function PendleMarketsList({
2996
4017
  ] });
2997
4018
  }
2998
4019
  function useSwapQuote({ fromToken, toToken, amount, enabled = true }) {
2999
- const { client } = useEmbeddableApi();
3000
4020
  const { chainId } = useChain();
4021
+ const { address } = useCompassWallet();
3001
4022
  const query = useQuery({
3002
- queryKey: ["swapQuote", chainId, fromToken, toToken, amount],
4023
+ queryKey: ["swapQuote", chainId, fromToken, toToken, amount, address],
3003
4024
  queryFn: async () => {
3004
- if (!fromToken || !toToken || !amount || parseFloat(amount) <= 0) {
4025
+ if (!fromToken || !toToken || !amount || parseFloat(amount) <= 0 || !address) {
3005
4026
  return null;
3006
4027
  }
3007
4028
  try {
3008
- const estimatedRate = 1;
3009
- const outputAmount = (parseFloat(amount) * estimatedRate).toString();
4029
+ const params = new URLSearchParams({
4030
+ owner: address,
4031
+ chain: chainId,
4032
+ tokenIn: fromToken,
4033
+ tokenOut: toToken,
4034
+ amountIn: amount
4035
+ });
4036
+ const response = await fetch(`/api/compass/swap/quote?${params}`);
4037
+ if (!response.ok) {
4038
+ const error = await response.json();
4039
+ throw new Error(error.error || "Failed to get swap quote");
4040
+ }
4041
+ const data = await response.json();
4042
+ const outputAmount = data.estimatedAmountOut || "0";
4043
+ const inputAmountNum = parseFloat(amount);
4044
+ const outputAmountNum = parseFloat(outputAmount);
3010
4045
  return {
3011
4046
  inputAmount: amount,
3012
4047
  outputAmount,
3013
- rate: estimatedRate.toString(),
3014
- priceImpact: "0",
3015
- fee: "0"
4048
+ rate: inputAmountNum > 0 ? (outputAmountNum / inputAmountNum).toString() : "0"
3016
4049
  };
3017
4050
  } catch (error) {
3018
4051
  console.error("Failed to get swap quote:", error);
3019
- return null;
4052
+ throw error;
3020
4053
  }
3021
4054
  },
3022
- enabled: enabled && !!fromToken && !!toToken && !!amount && parseFloat(amount) > 0,
4055
+ enabled: enabled && !!address && !!fromToken && !!toToken && !!amount && parseFloat(amount) > 0,
3023
4056
  staleTime: 10 * 1e3,
3024
- // 10 seconds - quotes change frequently
3025
- refetchInterval: 15 * 1e3
3026
- // Refresh every 15 seconds
4057
+ refetchInterval: 15 * 1e3,
4058
+ retry: 1
3027
4059
  });
3028
4060
  return {
3029
4061
  quote: query.data,
3030
4062
  isLoading: query.isLoading,
3031
4063
  isError: query.isError,
4064
+ error: query.error,
3032
4065
  refetch: query.refetch
3033
4066
  };
3034
4067
  }
3035
- var DEFAULT_TOKENS = ["USDC", "ETH", "WETH", "WBTC", "DAI", "USDT"];
4068
+ var DEFAULT_TOKENS = ["USDC", "ETH", "WETH", "WBTC", "DAI", "USDT", "AUSD", "SBC"];
3036
4069
  function SwapWidget({
3037
4070
  layout = "full",
3038
4071
  defaultFromToken = "ETH",
@@ -3040,7 +4073,6 @@ function SwapWidget({
3040
4073
  allowedTokens = DEFAULT_TOKENS,
3041
4074
  showReverseButton = true,
3042
4075
  showSettings = false,
3043
- showPriceImpact = true,
3044
4076
  onSwapSuccess,
3045
4077
  onSwapError
3046
4078
  }) {
@@ -3048,8 +4080,8 @@ function SwapWidget({
3048
4080
  const [toToken, setToToken] = useState(defaultToToken);
3049
4081
  const [fromAmount, setFromAmount] = useState("");
3050
4082
  const [isSwapping, setIsSwapping] = useState(false);
3051
- const { address, isConnected } = useCompassWallet();
3052
- const { client } = useEmbeddableApi();
4083
+ const [swapStatus, setSwapStatus] = useState("");
4084
+ const { address, isConnected, signTypedData } = useCompassWallet();
3053
4085
  const { chainId } = useChain();
3054
4086
  const { quote, isLoading: isQuoteLoading } = useSwapQuote({
3055
4087
  fromToken,
@@ -3065,32 +4097,75 @@ function SwapWidget({
3065
4097
  const handleSwap = useCallback(async () => {
3066
4098
  if (!address || !fromAmount || !quote) return;
3067
4099
  setIsSwapping(true);
4100
+ setSwapStatus("Preparing swap...");
3068
4101
  try {
3069
- const response = await client.earn.earnSwap({
3070
- chain: chainId,
3071
- sender: address,
3072
- tokenIn: fromToken,
3073
- tokenOut: toToken,
3074
- humanReadableAmountIn: fromAmount
4102
+ const prepareResponse = await fetch("/api/compass/swap/prepare", {
4103
+ method: "POST",
4104
+ headers: { "Content-Type": "application/json" },
4105
+ body: JSON.stringify({
4106
+ owner: address,
4107
+ chain: chainId,
4108
+ tokenIn: fromToken,
4109
+ tokenOut: toToken,
4110
+ amountIn: fromAmount
4111
+ })
4112
+ });
4113
+ if (!prepareResponse.ok) {
4114
+ const error = await prepareResponse.json();
4115
+ throw new Error(error.error || "Failed to prepare swap");
4116
+ }
4117
+ const prepareData = await prepareResponse.json();
4118
+ const { eip712, normalizedTypes } = prepareData;
4119
+ if (!eip712) {
4120
+ throw new Error("No EIP-712 data returned from prepare");
4121
+ }
4122
+ setSwapStatus("Please sign the transaction...");
4123
+ const signature = await signTypedData({
4124
+ domain: eip712.domain,
4125
+ types: normalizedTypes || eip712.types,
4126
+ primaryType: "SafeTx",
4127
+ message: eip712.message
4128
+ });
4129
+ setSwapStatus("Executing swap...");
4130
+ const executeResponse = await fetch("/api/compass/swap/execute", {
4131
+ method: "POST",
4132
+ headers: { "Content-Type": "application/json" },
4133
+ body: JSON.stringify({
4134
+ owner: address,
4135
+ chain: chainId,
4136
+ eip712,
4137
+ signature
4138
+ })
3075
4139
  });
3076
- console.log("Swap prepared:", response);
3077
- onSwapSuccess?.(fromToken, toToken, fromAmount, quote.outputAmount, "pending");
4140
+ if (!executeResponse.ok) {
4141
+ const error = await executeResponse.json();
4142
+ throw new Error(error.error || "Failed to execute swap");
4143
+ }
4144
+ const executeData = await executeResponse.json();
4145
+ const txHash = executeData.txHash;
4146
+ setSwapStatus("Swap successful!");
4147
+ onSwapSuccess?.(fromToken, toToken, fromAmount, quote.outputAmount, txHash);
3078
4148
  setFromAmount("");
4149
+ setTimeout(() => setSwapStatus(""), 3e3);
3079
4150
  } catch (error) {
3080
4151
  console.error("Swap failed:", error);
4152
+ setSwapStatus("");
3081
4153
  onSwapError?.(error);
3082
4154
  } finally {
3083
4155
  setIsSwapping(false);
3084
4156
  }
3085
- }, [address, fromAmount, quote, client, chainId, fromToken, toToken, onSwapSuccess, onSwapError]);
4157
+ }, [address, fromAmount, quote, chainId, fromToken, toToken, signTypedData, onSwapSuccess, onSwapError]);
3086
4158
  const isCompact = layout === "compact";
3087
4159
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
3088
4160
  !isCompact && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
3089
4161
  /* @__PURE__ */ jsx(ChainSwitcher, {}),
3090
- /* @__PURE__ */ jsx(WalletStatus, { compact: true })
4162
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4163
+ /* @__PURE__ */ jsx(EarnAccountBalance, { compact: true }),
4164
+ /* @__PURE__ */ jsx(WalletStatus, { compact: true })
4165
+ ] })
3091
4166
  ] }),
3092
4167
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3093
- /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border", style: { backgroundColor: "var(--compass-color-surface)", borderColor: "var(--compass-color-border)" }, children: [
4168
+ /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border relative", style: { backgroundColor: "var(--compass-color-surface)", borderColor: "var(--compass-color-border)" }, children: [
3094
4169
  /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: "From" }) }),
3095
4170
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
3096
4171
  /* @__PURE__ */ jsx(
@@ -3100,7 +4175,7 @@ function SwapWidget({
3100
4175
  value: fromAmount,
3101
4176
  onChange: (e) => setFromAmount(e.target.value),
3102
4177
  placeholder: "0.00",
3103
- className: "flex-1 bg-transparent outline-none text-2xl font-mono",
4178
+ className: "flex-1 bg-transparent outline-none text-2xl font-mono min-w-0",
3104
4179
  style: { color: "var(--compass-color-text)" }
3105
4180
  }
3106
4181
  ),
@@ -3109,9 +4184,9 @@ function SwapWidget({
3109
4184
  {
3110
4185
  value: fromToken,
3111
4186
  onChange: (e) => setFromToken(e.target.value),
3112
- className: "px-3 py-2 rounded-lg border text-sm font-medium cursor-pointer",
4187
+ className: "px-3 py-2 rounded-lg border text-sm font-medium cursor-pointer flex-shrink-0",
3113
4188
  style: { backgroundColor: "var(--compass-color-background)", borderColor: "var(--compass-color-border)", color: "var(--compass-color-text)" },
3114
- children: allowedTokens.map((token) => /* @__PURE__ */ jsx("option", { value: token, children: token }, token))
4189
+ children: allowedTokens.filter((t) => t !== toToken).map((token) => /* @__PURE__ */ jsx("option", { value: token, children: token }, token))
3115
4190
  }
3116
4191
  )
3117
4192
  ] })
@@ -3131,7 +4206,7 @@ function SwapWidget({
3131
4206
  /* @__PURE__ */ jsx("div", { className: "flex-1 text-2xl font-mono", style: { color: isQuoteLoading ? "var(--compass-color-text-tertiary)" : "var(--compass-color-text)" }, children: isQuoteLoading ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
3132
4207
  /* @__PURE__ */ jsx(Loader2, { size: 16, className: "animate-spin" }),
3133
4208
  "Loading..."
3134
- ] }) : quote?.outputAmount ? parseFloat(quote.outputAmount).toFixed(6) : "0.00" }),
4209
+ ] }) : quote?.outputAmount ? parseFloat(quote.outputAmount).toFixed(8) : "0.00000000" }),
3135
4210
  /* @__PURE__ */ jsx(
3136
4211
  "select",
3137
4212
  {
@@ -3145,14 +4220,6 @@ function SwapWidget({
3145
4220
  ] })
3146
4221
  ] })
3147
4222
  ] }),
3148
- showPriceImpact && quote && parseFloat(quote.priceImpact) > 0.01 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-3 rounded-lg", style: { backgroundColor: "var(--compass-color-warning-muted)" }, children: [
3149
- /* @__PURE__ */ jsx(AlertCircle, { size: 16, style: { color: "var(--compass-color-warning)" } }),
3150
- /* @__PURE__ */ jsxs("span", { className: "text-sm", style: { color: "var(--compass-color-warning)" }, children: [
3151
- "Price impact: ",
3152
- (parseFloat(quote.priceImpact) * 100).toFixed(2),
3153
- "%"
3154
- ] })
3155
- ] }),
3156
4223
  quote && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", style: { color: "var(--compass-color-text-secondary)" }, children: [
3157
4224
  /* @__PURE__ */ jsx("span", { children: "Rate" }),
3158
4225
  /* @__PURE__ */ jsxs("span", { className: "font-mono", children: [
@@ -3164,6 +4231,20 @@ function SwapWidget({
3164
4231
  toToken
3165
4232
  ] })
3166
4233
  ] }),
4234
+ swapStatus && /* @__PURE__ */ jsxs(
4235
+ "div",
4236
+ {
4237
+ className: "flex items-center gap-2 p-3 rounded-lg text-sm",
4238
+ style: {
4239
+ backgroundColor: swapStatus.includes("successful") ? "var(--compass-color-success-muted)" : "var(--compass-color-surface)",
4240
+ color: swapStatus.includes("successful") ? "var(--compass-color-success)" : "var(--compass-color-text-secondary)"
4241
+ },
4242
+ children: [
4243
+ !swapStatus.includes("successful") && /* @__PURE__ */ jsx(Loader2, { size: 14, className: "animate-spin" }),
4244
+ swapStatus
4245
+ ]
4246
+ }
4247
+ ),
3167
4248
  !isConnected ? /* @__PURE__ */ jsxs(
3168
4249
  "div",
3169
4250
  {
@@ -3199,78 +4280,29 @@ function SwapWidget({
3199
4280
  )
3200
4281
  ] });
3201
4282
  }
3202
-
3203
- // src/components/CompassEarnWidget/presets.ts
3204
- var allTabs = [
4283
+ var tabs = [
3205
4284
  { id: "vaults", label: "Vaults", enabled: true },
3206
4285
  { id: "aave", label: "Aave", enabled: true },
3207
4286
  { id: "pendle", label: "Pendle", enabled: true },
3208
4287
  { id: "swap", label: "Swap", enabled: true }
3209
4288
  ];
3210
- function getTabsForPreset(preset) {
3211
- switch (preset) {
3212
- case "full":
3213
- return allTabs;
3214
- case "earn-only":
3215
- return allTabs.map((tab) => ({
3216
- ...tab,
3217
- enabled: tab.id !== "swap"
3218
- }));
3219
- case "swap-only":
3220
- return allTabs.map((tab) => ({
3221
- ...tab,
3222
- enabled: tab.id === "swap"
3223
- }));
3224
- case "vaults-only":
3225
- return allTabs.map((tab) => ({
3226
- ...tab,
3227
- enabled: tab.id === "vaults"
3228
- }));
3229
- default:
3230
- return allTabs;
3231
- }
3232
- }
3233
- function getDefaultTab(tabs) {
3234
- const enabledTab = tabs.find((t) => t.enabled);
3235
- return enabledTab?.id || "vaults";
3236
- }
3237
4289
  function CompassEarnWidget({
3238
- preset = "full",
3239
- enableVaults,
3240
- enableAave,
3241
- enablePendle,
3242
- enableSwap,
3243
- defaultTab,
3244
- showHeader = true,
4290
+ defaultTab = "vaults",
3245
4291
  onTabChange
3246
4292
  }) {
3247
- const tabs = useMemo(() => {
3248
- const baseTabs = getTabsForPreset(preset);
3249
- return baseTabs.map((tab) => {
3250
- let enabled = tab.enabled;
3251
- if (tab.id === "vaults" && enableVaults !== void 0) enabled = enableVaults;
3252
- if (tab.id === "aave" && enableAave !== void 0) enabled = enableAave;
3253
- if (tab.id === "pendle" && enablePendle !== void 0) enabled = enablePendle;
3254
- if (tab.id === "swap" && enableSwap !== void 0) enabled = enableSwap;
3255
- return { ...tab, enabled };
3256
- });
3257
- }, [preset, enableVaults, enableAave, enablePendle, enableSwap]);
3258
- const enabledTabs = tabs.filter((t) => t.enabled);
3259
- const initialTab = defaultTab && tabs.find((t) => t.id === defaultTab)?.enabled ? defaultTab : getDefaultTab(tabs);
3260
- const [activeTab, setActiveTab] = useState(initialTab);
4293
+ const [activeTab, setActiveTab] = useState(defaultTab);
3261
4294
  const handleTabChange = (tab) => {
3262
4295
  setActiveTab(tab);
3263
4296
  onTabChange?.(tab);
3264
4297
  };
3265
- const showTabs = enabledTabs.length > 1;
3266
4298
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
3267
- showHeader && /* @__PURE__ */ jsx("h1", { className: "font-bold text-xl", style: { color: "var(--compass-color-text)" }, children: "Compass Earn" }),
3268
- showTabs && /* @__PURE__ */ jsx(
4299
+ /* @__PURE__ */ jsx("h1", { className: "font-bold text-xl", style: { color: "var(--compass-color-text)" }, children: "Compass Earn" }),
4300
+ /* @__PURE__ */ jsx(
3269
4301
  "div",
3270
4302
  {
3271
4303
  className: "flex gap-1 p-1 rounded-lg",
3272
4304
  style: { backgroundColor: "var(--compass-color-surface)" },
3273
- children: enabledTabs.map((tab) => /* @__PURE__ */ jsx(
4305
+ children: tabs.map((tab) => /* @__PURE__ */ jsx(
3274
4306
  "button",
3275
4307
  {
3276
4308
  onClick: () => handleTabChange(tab.id),
@@ -3286,14 +4318,34 @@ function CompassEarnWidget({
3286
4318
  }
3287
4319
  ),
3288
4320
  /* @__PURE__ */ jsxs("div", { children: [
3289
- activeTab === "vaults" && tabs.find((t) => t.id === "vaults")?.enabled && /* @__PURE__ */ jsx(VaultsList, { showSearch: true, showSort: true }),
3290
- activeTab === "aave" && tabs.find((t) => t.id === "aave")?.enabled && /* @__PURE__ */ jsx(AaveMarketsList, { showSearch: true, showSort: true }),
3291
- activeTab === "pendle" && tabs.find((t) => t.id === "pendle")?.enabled && /* @__PURE__ */ jsx(PendleMarketsList, { showSearch: true, showSort: true }),
3292
- activeTab === "swap" && tabs.find((t) => t.id === "swap")?.enabled && /* @__PURE__ */ jsx(SwapWidget, { layout: "full" })
4321
+ activeTab === "vaults" && /* @__PURE__ */ jsx(VaultsList, {}),
4322
+ activeTab === "aave" && /* @__PURE__ */ jsx(AaveMarketsList, {}),
4323
+ activeTab === "pendle" && /* @__PURE__ */ jsx(PendleMarketsList, {}),
4324
+ activeTab === "swap" && /* @__PURE__ */ jsx(SwapWidget, {})
3293
4325
  ] })
3294
4326
  ] });
3295
4327
  }
4328
+ var CHAINS = {
4329
+ ethereum: {
4330
+ id: "ethereum",
4331
+ name: "Ethereum",
4332
+ viemChain: mainnet,
4333
+ icon: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png"
4334
+ },
4335
+ base: {
4336
+ id: "base",
4337
+ name: "Base",
4338
+ viemChain: base,
4339
+ icon: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/base/info/logo.png"
4340
+ },
4341
+ arbitrum: {
4342
+ id: "arbitrum",
4343
+ name: "Arbitrum",
4344
+ viemChain: arbitrum,
4345
+ icon: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/arbitrum/info/logo.png"
4346
+ }
4347
+ };
3296
4348
 
3297
- export { AaveMarketsList, ActionModal, ApiProvider, CHAINS, ChainSwitcher, CompassEarnWidget, CompassProvider, DepositWithdrawForm, EarnAccountGuard, PendleMarketsList, PnLSummary, SwapWidget, TOKEN_DECIMALS, ThemeProvider, TransactionHistory, VaultsList, WalletStatus, themePresets, useAaveData, useChain, useCompassApi, useCompassChain, useCompassWallet, useEarnAccount, useEmbeddableApi, useEmbeddableWallet, usePendleData, useSwapQuote, useTheme, useVaultsData };
4349
+ export { AaveMarketsList, AccountBalancesModal, ActionModal, ApiProvider, CHAINS, ChainSwitcher, CompassEarnWidget, CompassProvider, DepositWithdrawForm, EarnAccountBalance, EarnAccountGuard, PendleMarketsList, PnLSummary, SwapWidget, ThemeProvider, TransactionHistory, VaultsList, WalletStatus, themePresets, useAaveData, useChain, useCompassApi, useCompassChain, useCompassWallet, useEarnAccount, useEmbeddableApi, useEmbeddableWallet, usePendleData, useSwapQuote, useTheme, useVaultsData };
3298
4350
  //# sourceMappingURL=index.mjs.map
3299
4351
  //# sourceMappingURL=index.mjs.map