diff --git a/app/api/balances/route.ts b/app/api/balances/route.ts
index 85f00a57..d5cf6559 100644
--- a/app/api/balances/route.ts
+++ b/app/api/balances/route.ts
@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { SupportedNetworks } from '@/utils/networks';
import { DEFAULT_RPC_URLS } from '@/utils/rpc';
+import { supportedTokens } from '@/utils/tokens';
type TokenBalance = {
contractAddress: string;
@@ -22,7 +23,18 @@ export async function GET(req: NextRequest) {
throw new Error(`Chain ${chainId} not supported`);
}
- // Get token balances
+ // Get supported token addresses for this chain
+ const tokenAddresses = supportedTokens
+ .filter(token =>
+ token.networks.some(network => network.chain.id === Number(chainId))
+ )
+ .flatMap(token =>
+ token.networks
+ .filter(network => network.chain.id === Number(chainId))
+ .map(network => network.address)
+ );
+
+ // Get token balances for specific tokens only
const balancesResponse = await fetch(alchemyUrl, {
method: 'POST',
headers: {
@@ -33,7 +45,7 @@ export async function GET(req: NextRequest) {
id: 1,
jsonrpc: '2.0',
method: 'alchemy_getTokenBalances',
- params: [address],
+ params: [address, tokenAddresses],
}),
});
diff --git a/app/autovault/[vaultAddress]/components/VaultSettings.tsx b/app/autovault/[vaultAddress]/components/VaultSettings.tsx
new file mode 100644
index 00000000..5d6353b0
--- /dev/null
+++ b/app/autovault/[vaultAddress]/components/VaultSettings.tsx
@@ -0,0 +1,176 @@
+import { Card, CardHeader, CardBody } from '@heroui/react';
+import { Button } from '@/components/common/Button';
+import { AutovaultData } from '@/hooks/useAutovaultData';
+
+type VaultSettingsProps = {
+ vault: AutovaultData;
+ onClose: () => void;
+};
+
+export function VaultSettings({ onClose }: VaultSettingsProps) {
+ return (
+
+
+
Vault Settings
+
Configure your autovault automation and strategies
+
+
+ {/* Agent Configuration */}
+
+
+ Agent Configuration
+
+
+
+
+
+
Rebalancing Agent
+
+ Automatically rebalance funds between markets based on yield opportunities
+
+
+
+
+
+
+
Risk Management Agent
+
+ Monitor and manage risk exposure across markets
+
+
+
+
+
+
+
Yield Optimization Agent
+
+ Optimize yield by finding the best opportunities
+
+
+
+
+
+
+
+
+ {/* Rebalancing Rules */}
+
+
+ Rebalancing Rules
+
+
+
+
+
Minimum APY Difference
+
+ 2.0%
+
+
+
+
+
Maximum Position per Market
+
+ 50%
+
+
+
+
+
Rebalance Frequency
+
+ Daily
+
+
+
+
+
+
+
+ {/* Risk Parameters */}
+
+
+ Risk Parameters
+
+
+
+
+
Maximum Utilization
+
+ 80%
+
+
+
+
+
Emergency Stop Loss
+
+ Enabled
+
+
+
+
+
Minimum Liquidity
+
+ $100K
+
+
+
+
+
+
+
+ {/* Vault Management */}
+
+
+ Vault Management
+
+
+
+
+
+
Pause Vault
+
Temporarily stop all automated activities
+
+
+
+
+
+
Emergency Withdrawal
+
+ Withdraw all funds and stop vault operations
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/autovault/[vaultAddress]/content.tsx b/app/autovault/[vaultAddress]/content.tsx
new file mode 100644
index 00000000..970ab88e
--- /dev/null
+++ b/app/autovault/[vaultAddress]/content.tsx
@@ -0,0 +1,218 @@
+'use client';
+
+import { useMemo, useState } from 'react';
+import { Card, CardHeader, CardBody } from '@heroui/react';
+import { ChevronLeftIcon, GearIcon } from '@radix-ui/react-icons';
+import Link from 'next/link';
+import { useParams, useRouter } from 'next/navigation';
+import { Address } from 'viem';
+import { useAccount } from 'wagmi';
+import { Button } from '@/components/common';
+import { AddressDisplay } from '@/components/common/AddressDisplay';
+import Header from '@/components/layout/header/Header';
+import LoadingScreen from '@/components/Status/LoadingScreen';
+import { useVaultDetails } from '@/hooks/useAutovaultData';
+import { VaultSettings } from './components/VaultSettings';
+
+export default function VaultContent() {
+ const router = useRouter();
+ const { vaultAddress } = useParams<{ vaultAddress: string }>();
+ const { address } = useAccount();
+ const [showSettings, setShowSettings] = useState(false);
+
+ const { vault, isLoading, isError } = useVaultDetails(vaultAddress as Address);
+
+ const isOwner = useMemo(() => {
+ if (!vault || !address) return false;
+ return vault.owner.toLowerCase() === address.toLowerCase();
+ }, [vault, address]);
+
+ if (isLoading) {
+ return (
+
+
+
+
+ );
+ }
+
+ if (isError || !vault) {
+ return (
+
+
+
+
+
+
Vault Not Found
+
+ The requested vault could not be found or does not exist.
+
+
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ {/* Header Section */}
+
+
+
+
{vault.name}
+
{vault.description}
+
+ {isOwner && (
+
+ )}
+
+
+ {/* Vault Address */}
+
+
+ {/* Main Content Grid */}
+
+ {/* Basic Info Card */}
+
+
+ Vault Overview
+
+
+
+
+ Status
+
+ {vault.status.charAt(0).toUpperCase() + vault.status.slice(1)}
+
+
+
+ Active Agents
+
+ {vault.agents.filter((agent) => agent.status === 'active').length}
+
+
+
+ Created
+ {vault.createdAt.toLocaleDateString()}
+
+
+
+
+
+ {/* Performance Card */}
+
+
+ Performance
+
+
+
+
+
+ {vault.currentApy.toFixed(2)}%
+
+
Current APY
+
+
+
+
+
+ {/* Agents Card */}
+
+
+ Active Agents
+
+
+ {vault.agents.length === 0 ? (
+ No agents configured
+ ) : (
+
+ {vault.agents.map((agent) => (
+
+
+
{agent.name}
+
{agent.description}
+
+
+ {agent.status}
+
+
+ ))}
+
+ )}
+
+
+
+
+ {/* Settings Panel */}
+ {showSettings && (
+
+
+
+ setShowSettings(false)} />
+
+
+
+ )}
+
+ {/* TODO: Add charts and more detailed analytics */}
+ {!showSettings && (
+
+
+
+ Analytics & Charts
+
+
+
+
Performance charts and analytics coming soon...
+
+
+
+
+ )}
+
+
+ );
+}
diff --git a/app/autovault/[vaultAddress]/page.tsx b/app/autovault/[vaultAddress]/page.tsx
new file mode 100644
index 00000000..bc1ccc3a
--- /dev/null
+++ b/app/autovault/[vaultAddress]/page.tsx
@@ -0,0 +1,14 @@
+import { generateMetadata } from '@/utils/generateMetadata';
+
+import VaultContent from './content';
+
+export const metadata = generateMetadata({
+ title: 'Vault Details | Monarch',
+ description: 'Detailed information about a specific autovault',
+ images: 'themes.png',
+ pathname: '',
+});
+
+export default function VaultPage() {
+ return ;
+}
diff --git a/app/autovault/components/AutovaultContent.tsx b/app/autovault/components/AutovaultContent.tsx
new file mode 100644
index 00000000..6e7d1f6e
--- /dev/null
+++ b/app/autovault/components/AutovaultContent.tsx
@@ -0,0 +1,86 @@
+'use client';
+
+import { useState } from 'react';
+import { FaPlus } from 'react-icons/fa';
+import { useAccount } from 'wagmi';
+import { Button } from '@/components/common/Button';
+import AccountConnect from '@/components/layout/header/AccountConnect';
+import Header from '@/components/layout/header/Header';
+import { useUserVaultsV2 } from '@/hooks/useUserVaultsV2';
+import { DeploymentModal } from './deployment/DeploymentModal';
+import { VaultListV2 } from './VaultListV2';
+
+export default function AutovaultContent() {
+ const { isConnected } = useAccount();
+ const [showDeploymentModal, setShowDeploymentModal] = useState(false);
+
+ const { vaults, loading: vaultsLoading } = useUserVaultsV2();
+
+ const handleCreateVault = () => {
+ setShowDeploymentModal(true);
+ };
+
+ if (!isConnected) {
+ return (
+
+
+
+
+
Autovault
+
+
+
+
+ Automate your vault management with intelligent agents
+
+
+
+
+
+
+
+ Connect your wallet to view and manage your autovaults
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
Autovault
+
+
+
+
+
+ Automate your vault management with intelligent agents
+
+
+
+
+
+
+
+
+
+
+
+ {/* Deployment Modal */}
+
setShowDeploymentModal(false)}
+ />
+
+
+ );
+}
diff --git a/app/autovault/components/VaultListV2.tsx b/app/autovault/components/VaultListV2.tsx
new file mode 100644
index 00000000..324d7c8d
--- /dev/null
+++ b/app/autovault/components/VaultListV2.tsx
@@ -0,0 +1,113 @@
+import Image from 'next/image';
+import { formatUnits } from 'viem';
+import { Spinner } from '@/components/common/Spinner';
+import { useTokens } from '@/components/providers/TokenProvider';
+import { TokenIcon } from '@/components/TokenIcon';
+import { UserVaultV2 } from '@/data-sources/subgraph/v2-vaults';
+import { formatReadable } from '@/utils/balance';
+import { getNetworkImg } from '@/utils/networks';
+
+type VaultListV2Props = {
+ vaults: UserVaultV2[];
+ loading: boolean;
+};
+
+export function VaultListV2({ vaults, loading }: VaultListV2Props) {
+ const { findToken } = useTokens();
+
+ if (loading) {
+ return (
+
+
+
+
Loading your vaults...
+
+
+ );
+ }
+
+ if (vaults.length === 0) {
+ return (
+
+
+ 🏛️
+
+
No Vaults Found
+
+ You haven't deployed any autovaults yet. Create your first one to get started!
+
+
+ );
+ }
+
+ return (
+
+
Your Vaults
+
+
+
+
+
+ | ID |
+ Asset |
+ APY |
+ Agents |
+ Collaterals |
+
+
+
+ {vaults.map((vault) => {
+ const token = findToken(vault.asset, vault.networkId);
+ const networkImg = getNetworkImg(vault.networkId);
+
+ return (
+
+ {/* ID */}
+ |
+
+ {networkImg && }
+ {vault.newVaultV2.slice(2, 8)}
+
+ |
+
+ {/* Asset */}
+
+
+
+ {vault.balance && token ?
+ formatReadable(formatUnits(BigInt(vault.balance), token.decimals))
+ : '0'}
+
+ {token?.symbol ?? 'USDC'}
+
+
+ |
+
+ {/* APY */}
+
+ --
+ |
+
+ {/* Agents */}
+
+ --
+ |
+
+ {/* Collaterals */}
+
+ --
+ |
+
+ );
+ })}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/autovault/components/deployment/DeploymentContext.tsx b/app/autovault/components/deployment/DeploymentContext.tsx
new file mode 100644
index 00000000..b652a91c
--- /dev/null
+++ b/app/autovault/components/deployment/DeploymentContext.tsx
@@ -0,0 +1,95 @@
+import { createContext, useContext, useState, useCallback, useMemo } from 'react';
+import { Address } from 'viem';
+import { useAccount } from 'wagmi';
+import { useCreateVault } from '@/hooks/useCreateVault';
+import { useMarketNetwork } from '@/hooks/useMarketNetwork';
+import { SupportedNetworks } from '@/utils/networks';
+
+// Keeping enum for backwards compatibility but not using steps anymore
+export enum DeploymentStep {
+ TOKEN_SELECTION = 0,
+ DEPLOY = 1,
+ SUCCESS = 2,
+}
+
+export type SelectedToken = {
+ symbol: string;
+ name: string;
+ address: Address;
+ decimals: number;
+};
+
+export type SelectedTokenAndNetwork = {
+ token: SelectedToken;
+ networkId: SupportedNetworks;
+};
+
+type DeploymentContextType = {
+ selectedTokenAndNetwork: SelectedTokenAndNetwork | null;
+ needSwitchChain: boolean;
+ switchToNetwork: () => void;
+ createVault: () => Promise;
+ isDeploying: boolean;
+ setSelectedTokenAndNetwork: (selection: SelectedTokenAndNetwork) => void;
+ resetDeployment: () => void;
+};
+
+const DeploymentContext = createContext(null);
+
+export function DeploymentProvider({ children }: { children: React.ReactNode }) {
+ const [selectedTokenAndNetwork, setSelectedTokenAndNetwork] = useState(null);
+
+ const { address: account } = useAccount();
+
+ // Network switching logic
+ const { needSwitchChain, switchToNetwork } = useMarketNetwork({
+ targetChainId: selectedTokenAndNetwork?.networkId ?? 1,
+ });
+
+ // Vault creation logic
+ const { createVault: createVaultTx, isDeploying } = useCreateVault(
+ selectedTokenAndNetwork?.networkId ?? 1
+ );
+
+ const createVault = useCallback(async () => {
+ if (!selectedTokenAndNetwork || !account) return;
+
+ await createVaultTx(selectedTokenAndNetwork.token.address);
+ }, [selectedTokenAndNetwork, account, createVaultTx]);
+
+ const resetDeployment = useCallback(() => {
+ setSelectedTokenAndNetwork(null);
+ }, []);
+
+ const contextValue = useMemo(() => ({
+ selectedTokenAndNetwork,
+ needSwitchChain,
+ switchToNetwork,
+ createVault,
+ isDeploying,
+ setSelectedTokenAndNetwork,
+ resetDeployment,
+ }), [
+ selectedTokenAndNetwork,
+ needSwitchChain,
+ switchToNetwork,
+ createVault,
+ isDeploying,
+ setSelectedTokenAndNetwork,
+ resetDeployment,
+ ]);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useDeployment() {
+ const context = useContext(DeploymentContext);
+ if (!context) {
+ throw new Error('useDeployment must be used within a DeploymentProvider');
+ }
+ return context;
+}
\ No newline at end of file
diff --git a/app/autovault/components/deployment/DeploymentModal.tsx b/app/autovault/components/deployment/DeploymentModal.tsx
new file mode 100644
index 00000000..d088f7bb
--- /dev/null
+++ b/app/autovault/components/deployment/DeploymentModal.tsx
@@ -0,0 +1,98 @@
+import { Modal, ModalContent, ModalHeader } from '@heroui/react';
+import { RxCross2 } from 'react-icons/rx';
+import { Button } from '@/components/common';
+import { Spinner } from '@/components/common/Spinner';
+import { useMarkets } from '@/contexts/MarketsContext';
+import { useUserBalances } from '@/hooks/useUserBalances';
+import { getNetworkName } from '@/utils/networks';
+import { DeploymentProvider, useDeployment } from './DeploymentContext';
+import { TokenSelection } from './TokenSelection';
+
+function DeploymentModalContent({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) {
+ const { selectedTokenAndNetwork, needSwitchChain, switchToNetwork, createVault, isDeploying } = useDeployment();
+
+ // Load balances and tokens at modal level
+ const { balances, loading: balancesLoading } = useUserBalances();
+ const { whitelistedMarkets, loading: marketsLoading } = useMarkets();
+
+ return (
+
+
+
+
+
Deploy Autovault
+
Choose the token and network for your autovault
+
+
+
+
+
+
+
+
+
+
+
+ {selectedTokenAndNetwork && (
+
+ You can configure the vault to have caps, automation agents and more after you deploy the vault.
+
+ )}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export function DeploymentModal({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/autovault/components/deployment/TokenSelection.tsx b/app/autovault/components/deployment/TokenSelection.tsx
new file mode 100644
index 00000000..1f87b2e9
--- /dev/null
+++ b/app/autovault/components/deployment/TokenSelection.tsx
@@ -0,0 +1,198 @@
+import { useMemo } from 'react';
+import Image from 'next/image';
+import { Address, formatUnits } from 'viem';
+import { Spinner } from '@/components/common/Spinner';
+import { useTokens } from '@/components/providers/TokenProvider';
+import { TokenIcon } from '@/components/TokenIcon';
+import { TokenBalance } from '@/hooks/useUserBalances';
+import { formatReadable } from '@/utils/balance';
+import { getNetworkImg, SupportedNetworks } from '@/utils/networks';
+import type { Market } from '@/utils/types';
+import { useDeployment, SelectedToken } from './DeploymentContext';
+
+type TokenNetwork = {
+ symbol: string;
+ name: string;
+ address: Address;
+ decimals: number;
+ img?: string;
+ balance: bigint;
+ networkId: number;
+ marketCount: number;
+};
+
+function NetworkIcon({ networkId }: { networkId: number }) {
+ const url = getNetworkImg(networkId);
+ return (
+
+ );
+}
+
+type TokenSelectionProps = {
+ balances: TokenBalance[] | null;
+ balancesLoading: boolean;
+ whitelistedMarkets: Market[] | null;
+ marketsLoading: boolean;
+};
+
+export function TokenSelection({ balances, balancesLoading, whitelistedMarkets, marketsLoading }: TokenSelectionProps) {
+ const { selectedTokenAndNetwork, setSelectedTokenAndNetwork } = useDeployment();
+
+ const { allTokens, findToken } = useTokens()
+
+ const availableTokenNetworks = useMemo(() => {
+ if (!balances || !whitelistedMarkets) return [];
+
+ // Use whitelisted markets only
+ const marketsToUse = whitelistedMarkets;
+
+ const tokenNetworks: TokenNetwork[] = [];
+
+ balances.forEach((balance) => {
+ const token = findToken(balance.address, balance.chainId)
+
+ if (!token) return;
+
+ const network = balance.chainId as SupportedNetworks
+ const balanceValue = balance.balance ? BigInt(balance.balance) : 0n;
+
+ if (network && balanceValue > 0n) {
+ // Count markets for this token on this network
+ const marketCount = marketsToUse.filter(
+ (market) =>
+ market.loanAsset.address.toLowerCase() === balance.address.toLowerCase() &&
+ market.morphoBlue.chain.id === balance.chainId
+ ).length;
+
+ if (marketCount === 0) return;
+
+ tokenNetworks.push({
+ symbol: token.symbol,
+ name: token.symbol,
+ address: balance.address as Address,
+ decimals: token.decimals,
+ img: token.img,
+ balance: balanceValue,
+ networkId: balance.chainId,
+ marketCount,
+ });
+ }
+ });
+
+ // Sort by balance descending, then by symbol
+ return tokenNetworks.sort((a, b) => {
+ const aBalance = Number(formatUnits(a.balance, a.decimals));
+ const bBalance = Number(formatUnits(b.balance, b.decimals));
+ if (bBalance !== aBalance) return bBalance - aBalance;
+ return a.symbol.localeCompare(b.symbol);
+ });
+ }, [balances, allTokens, whitelistedMarkets]);
+
+ const handleTokenNetworkSelect = (tokenNetwork: TokenNetwork) => {
+ const selectedToken: SelectedToken = {
+ symbol: tokenNetwork.symbol,
+ name: tokenNetwork.name,
+ address: tokenNetwork.address,
+ decimals: tokenNetwork.decimals,
+ };
+
+ setSelectedTokenAndNetwork({
+ token: selectedToken,
+ networkId: tokenNetwork.networkId,
+ });
+ };
+
+ // Show loading state while fetching balances or markets
+ if (balancesLoading || marketsLoading) {
+ return (
+
+
+
+
+ {balancesLoading && marketsLoading
+ ? 'Loading token balances and markets...'
+ : balancesLoading
+ ? 'Fetching your token balances across networks'
+ : 'Loading available markets...'}
+
+
+
+ );
+ }
+
+ return (
+
+ {availableTokenNetworks.length === 0 ? (
+
+
+ 💰
+
+
No Tokens Found
+
+ Make sure you have some tokens in your wallet to create an autovault
+
+
+ ) : (
+
+ {availableTokenNetworks.map((tokenNetwork) => {
+ const isSelected =
+ selectedTokenAndNetwork?.token?.address?.toLowerCase?.() === tokenNetwork.address.toLowerCase() &&
+ selectedTokenAndNetwork?.networkId === tokenNetwork.networkId;
+
+ return (
+
handleTokenNetworkSelect(tokenNetwork)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ handleTokenNetworkSelect(tokenNetwork);
+ }
+ }}
+ role="button"
+ tabIndex={0}
+ >
+ {isSelected && (
+
+ )}
+
+
+
+
+ {formatReadable(formatUnits(tokenNetwork.balance, tokenNetwork.decimals))} {tokenNetwork.symbol}
+
+
+
+
+
+ {tokenNetwork.marketCount} market{tokenNetwork.marketCount !== 1 ? 's' : ''}
+
+
+
+
+ );
+ })}
+
+ )}
+
+ );
+}
diff --git a/app/autovault/page.tsx b/app/autovault/page.tsx
new file mode 100644
index 00000000..8e4dc7d2
--- /dev/null
+++ b/app/autovault/page.tsx
@@ -0,0 +1,14 @@
+import { generateMetadata } from '@/utils/generateMetadata';
+
+import AutovaultContent from './components/AutovaultContent';
+
+export const metadata = generateMetadata({
+ title: 'Autovault | Monarch',
+ description: 'Automated vault management with intelligent agents',
+ images: 'themes.png',
+ pathname: '',
+});
+
+export default function AutovaultPage() {
+ return ;
+}
diff --git a/app/market/[chainId]/[marketid]/components/CampaignBadge.tsx b/app/market/[chainId]/[marketid]/components/CampaignBadge.tsx
index b8c70238..c6875401 100644
--- a/app/market/[chainId]/[marketid]/components/CampaignBadge.tsx
+++ b/app/market/[chainId]/[marketid]/components/CampaignBadge.tsx
@@ -32,11 +32,10 @@ export function CampaignBadge({ marketId, loanTokenAddress, chainId }: CampaignB
@@ -47,4 +46,4 @@ export function CampaignBadge({ marketId, loanTokenAddress, chainId }: CampaignB
/>
>
);
-}
\ No newline at end of file
+}
diff --git a/app/market/[chainId]/[marketid]/components/CampaignModal.tsx b/app/market/[chainId]/[marketid]/components/CampaignModal.tsx
index 5cda3d21..1c8290e4 100644
--- a/app/market/[chainId]/[marketid]/components/CampaignModal.tsx
+++ b/app/market/[chainId]/[marketid]/components/CampaignModal.tsx
@@ -50,7 +50,7 @@ function CampaignRow({ campaign }: { campaign: SimplifiedCampaign }) {
height={20}
className="rounded-full"
/>
- {campaign.rewardToken.symbol}
+ {campaign.rewardToken.symbol}
@@ -105,11 +105,11 @@ export function CampaignModal({ isOpen, onClose, campaigns }: CampaignModalProps
{campaigns.map((campaign) => (
-
+
))}
);
-}
\ No newline at end of file
+}
diff --git a/app/market/[chainId]/[marketid]/components/PositionStats.tsx b/app/market/[chainId]/[marketid]/components/PositionStats.tsx
index 3d77e17b..75a2ac6b 100644
--- a/app/market/[chainId]/[marketid]/components/PositionStats.tsx
+++ b/app/market/[chainId]/[marketid]/components/PositionStats.tsx
@@ -31,8 +31,12 @@ function ThumbIcon({ isSelected, className }: { isSelected: boolean; className?:
}
const hasPosition = (position: MarketPosition) => {
- return position.state.borrowAssets !== "0" || position.state.collateral !== "0" || position.state.supplyAssets !== "0"
-}
+ return (
+ position.state.borrowAssets !== '0' ||
+ position.state.collateral !== '0' ||
+ position.state.supplyAssets !== '0'
+ );
+};
export function PositionStats({
market,
@@ -43,7 +47,9 @@ export function PositionStats({
isRefreshing = false,
}: PositionStatsProps) {
// Default to user view if they have a position, otherwise global
- const [viewMode, setViewMode] = useState<'global' | 'user'>((userPosition && hasPosition(userPosition)) ? 'user' : 'global');
+ const [viewMode, setViewMode] = useState<'global' | 'user'>(
+ userPosition && hasPosition(userPosition) ? 'user' : 'global',
+ );
const { showFullRewardAPY } = useMarkets();
const { activeCampaigns, hasActiveRewards } = useMarketCampaigns({
@@ -199,7 +205,8 @@ export function PositionStats({
{baseSupplyAPY.toFixed(2)}%
- {' '}(+{extraRewards.toFixed(2)}%)
+ {' '}
+ (+{extraRewards.toFixed(2)}%)
diff --git a/app/positions/components/PositionsContent.tsx b/app/positions/components/PositionsContent.tsx
index 14d87321..2b8863ae 100644
--- a/app/positions/components/PositionsContent.tsx
+++ b/app/positions/components/PositionsContent.tsx
@@ -5,13 +5,11 @@ import Link from 'next/link';
import { useParams } from 'next/navigation';
import { FaHistory, FaPlus } from 'react-icons/fa';
import { IoRefreshOutline } from 'react-icons/io5';
-import { RiRobot2Line } from 'react-icons/ri';
import { TbReport } from 'react-icons/tb';
import { toast } from 'react-toastify';
import { Address } from 'viem';
import { useAccount } from 'wagmi';
import { AddressDisplay } from '@/components/common/AddressDisplay';
-import { Badge } from '@/components/common/Badge';
import { Button } from '@/components/common/Button';
import Header from '@/components/layout/header/Header';
import EmptyScreen from '@/components/Status/EmptyScreen';
@@ -19,10 +17,7 @@ import LoadingScreen from '@/components/Status/LoadingScreen';
import { SupplyModalV2 } from '@/components/SupplyModalV2';
import { useMarkets } from '@/hooks/useMarkets';
import useUserPositionsSummaryData from '@/hooks/useUserPositionsSummaryData';
-import { useUserRebalancerInfo } from '@/hooks/useUserRebalancerInfo';
-import { isAgentAvailable } from '@/utils/networks';
import { MarketPosition } from '@/utils/types';
-import { SetupAgentModal } from './agent/SetupAgentModal';
import { OnboardingModal } from './onboarding/Modal';
import { PositionsSummaryTable } from './PositionsSummaryTable';
@@ -30,12 +25,10 @@ export default function Positions() {
const [showSupplyModal, setShowSupplyModal] = useState(false);
const [showWithdrawModal, setShowWithdrawModal] = useState(false);
const [showOnboardingModal, setShowOnboardingModal] = useState(false);
- const [showSetupAgentModal, setShowSetupAgentModal] = useState(false);
const [selectedPosition, setSelectedPosition] = useState(null);
const { account } = useParams<{ account: string }>();
const { address } = useAccount();
- const { rebalancerInfos, refetch: refetchRebalancerInfo } = useUserRebalancerInfo(account);
const isOwner = useMemo(() => {
if (!account) return false;
@@ -56,13 +49,6 @@ export default function Positions() {
const hasSuppliedMarkets = marketPositions && marketPositions.length > 0;
- const hasActivePositionForAgent = marketPositions?.some((position) => {
- return (
- isAgentAvailable(position.market.morphoBlue.chain.id) &&
- BigInt(position.state.supplyShares) > 0
- );
- });
-
const handleRefetch = () => {
void refetch(() => toast.info('Data refreshed', { icon: 🚀 }));
};
@@ -89,12 +75,6 @@ export default function Positions() {
Report
- {isOwner && hasActivePositionForAgent && (
-
- )}
{isOwner && (