- {/* Position History Chart with synchronized pie */}
+
- {/* Markets Table - Always visible */}
-
-
-
- Market
- {rateLabel}
- Allocation
- Risk Tiers
- Actions
-
-
-
- {sortedMarkets.map((position) => (
-
- ))}
-
-
+
+
+
+
+ Market
+ {rateLabel}
+ Allocation
+ Risk Tiers
+ Actions
+
+
+
+ {sortedMarkets.map((position) => (
+
+ ))}
+
+
+
);
diff --git a/src/features/positions/components/vault-allocation-detail.tsx b/src/features/positions/components/vault-allocation-detail.tsx
index 0cc4bd78..59278664 100644
--- a/src/features/positions/components/vault-allocation-detail.tsx
+++ b/src/features/positions/components/vault-allocation-detail.tsx
@@ -1,6 +1,7 @@
import { useMemo } from 'react';
import type { Address } from 'viem';
import { motion } from 'framer-motion';
+import { TableContainerWithHeader } from '@/components/common/table-container-with-header';
import { Button } from '@/components/ui/button';
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@/components/ui/table';
import { Spinner } from '@/components/ui/spinner';
@@ -19,6 +20,7 @@ type VaultAllocationDetailProps = {
export function VaultAllocationDetail({ vault }: VaultAllocationDetailProps) {
const { short: rateLabel } = useRateLabel();
+ const title = 'Market Allocations';
// Fetch actual allocations - useVaultAllocations pulls caps internally
const { marketAllocations, loading } = useVaultAllocations({
@@ -45,9 +47,11 @@ export function VaultAllocationDetail({ vault }: VaultAllocationDetailProps) {
transition={{ duration: 0.2 }}
className="overflow-hidden"
>
-
-
-
+
+
+
+
+
);
}
@@ -61,9 +65,9 @@ export function VaultAllocationDetail({ vault }: VaultAllocationDetailProps) {
transition={{ duration: 0.2 }}
className="overflow-hidden"
>
-
- No market allocations configured for this vault.
-
+
+ No market allocations configured for this vault.
+
);
}
@@ -76,7 +80,7 @@ export function VaultAllocationDetail({ vault }: VaultAllocationDetailProps) {
transition={{ duration: 0.2 }}
className="overflow-hidden"
>
-
+
@@ -89,10 +93,7 @@ export function VaultAllocationDetail({ vault }: VaultAllocationDetailProps) {
{marketAllocations.map((allocation) => {
- // Calculate allocated amount
const allocatedAmount = Number(formatBalance(allocation.allocation, vaultAssetDecimals));
-
- // Calculate percentage
const percentage =
totalAllocation > 0n ? (allocatedAmount / Number(formatBalance(totalAllocation, vaultAssetDecimals))) * 100 : 0;
@@ -101,7 +102,6 @@ export function VaultAllocationDetail({ vault }: VaultAllocationDetailProps) {
key={allocation.market.uniqueKey}
className="gap-1"
>
- {/* Market */}
- {/* APY/APR */}
- {/* Allocation */}
- {/* Risk Tiers */}
- {/* Actions */}
-
+
);
}
diff --git a/src/graphql/envio-queries.ts b/src/graphql/envio-queries.ts
index 5a1935b7..7a8c490c 100644
--- a/src/graphql/envio-queries.ts
+++ b/src/graphql/envio-queries.ts
@@ -411,3 +411,276 @@ export const envioLiquidationsPageQuery = `
}
}
`;
+
+const marketTxContextFields = `
+ id
+ chainId
+ timestamp
+ txHash
+ vaultTxType
+ hasVaultUserDeposit
+ hasVaultUserWithdraw
+ hasVaultRebalance
+ morphoSupplies {
+ market_id
+ assets
+ onBehalf
+ caller
+ isMonarch
+ }
+ morphoWithdraws {
+ market_id
+ assets
+ onBehalf
+ caller
+ receiver
+ isMonarch
+ }
+ morphoBorrows {
+ market_id
+ assets
+ onBehalf
+ caller
+ receiver
+ isMonarch
+ }
+ morphoRepays {
+ market_id
+ assets
+ onBehalf
+ caller
+ isMonarch
+ }
+ morphoSupplyCollaterals {
+ market_id
+ assets
+ onBehalf
+ caller
+ isMonarch
+ }
+ morphoWithdrawCollaterals {
+ market_id
+ assets
+ onBehalf
+ caller
+ receiver
+ isMonarch
+ }
+ vaultDeposits {
+ id
+ vault_id
+ onBehalf
+ sender
+ assets
+ shares
+ isMonarch
+ }
+ vaultWithdrawals {
+ id
+ vault_id
+ onBehalf
+ sender
+ receiver
+ assets
+ shares
+ isMonarch
+ }
+ vaultAllocations {
+ id
+ vault_id
+ sender
+ assets
+ change
+ isMonarch
+ }
+ vaultDeallocations {
+ id
+ vault_id
+ sender
+ assets
+ change
+ isMonarch
+ }
+ vaultForceDeallocations {
+ id
+ vault_id
+ onBehalf
+ sender
+ assets
+ penaltyAssets
+ isMonarch
+ }
+ legacyVaultDeposits {
+ id
+ vaultAddress
+ owner
+ sender
+ assets
+ shares
+ isMonarch
+ }
+ legacyVaultWithdrawals {
+ id
+ vaultAddress
+ owner
+ sender
+ receiver
+ assets
+ shares
+ isMonarch
+ }
+ legacyVaultReallocateSupplies {
+ id
+ vaultAddress
+ market_id
+ suppliedAssets
+ suppliedShares
+ caller
+ isMonarch
+ }
+ legacyVaultReallocateWithdrawals {
+ id
+ vaultAddress
+ market_id
+ withdrawnAssets
+ withdrawnShares
+ caller
+ isMonarch
+ }
+`;
+
+export const envioMarketTxContextSeedsQuery = `
+ query EnvioMarketTxContextSeedsPage($chainId: Int!, $marketId: String!, $limit: Int!, $offset: Int!) {
+ supplies: Morpho_Supply(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ withdraws: Morpho_Withdraw(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ borrows: Morpho_Borrow(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ repays: Morpho_Repay(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ supplyCollaterals: Morpho_SupplyCollateral(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ withdrawCollaterals: Morpho_WithdrawCollateral(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ legacyReallocateSupplies: MetaMorphoVault_ReallocateSupply(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ legacyReallocateWithdrawals: MetaMorphoVault_ReallocateWithdraw(
+ where: { chainId: { _eq: $chainId }, market_id: { _eq: $marketId } }
+ limit: $limit
+ offset: $offset
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+ id
+ txHash
+ timestamp
+ txContext {
+ id
+ txHash
+ timestamp
+ }
+ }
+ }
+`;
+
+export const envioMarketTxContextsByIdsQuery = `
+ query EnvioMarketTxContextsByIds($ids: [String!]!) {
+ TxContext(
+ where: { id: { _in: $ids } }
+ order_by: [{ timestamp: desc }, { txHash: desc }, { id: desc }]
+ ) {
+${marketTxContextFields}
+ }
+ }
+`;
diff --git a/src/hooks/useMarketTxContexts.ts b/src/hooks/useMarketTxContexts.ts
new file mode 100644
index 00000000..5e3b0349
--- /dev/null
+++ b/src/hooks/useMarketTxContexts.ts
@@ -0,0 +1,63 @@
+import { useEffect } from 'react';
+import { useQuery, useQueryClient } from '@tanstack/react-query';
+import { fetchMonarchMarketTxContexts, type PaginatedMarketProActivities } from '@/data-sources/monarch-api';
+import type { SupportedNetworks } from '@/utils/networks';
+
+export const useMarketTxContexts = (
+ marketId: string | undefined,
+ network: SupportedNetworks | undefined,
+ page = 1,
+ pageSize = 8,
+) => {
+ const queryClient = useQueryClient();
+
+ const queryKey = ['marketTxContexts', marketId, network, page, pageSize];
+
+ const queryFn = async (targetPage: number): Promise
=> {
+ if (!marketId || !network) {
+ return null;
+ }
+
+ const targetSkip = (targetPage - 1) * pageSize;
+ return fetchMonarchMarketTxContexts(marketId, Number(network), pageSize, targetSkip);
+ };
+
+ const { data, isLoading, isFetching, error, refetch } = useQuery({
+ queryKey,
+ queryFn: async () => queryFn(page),
+ enabled: !!marketId && !!network,
+ staleTime: 1000 * 60 * 5,
+ placeholderData: () => null,
+ retry: 1,
+ });
+
+ useEffect(() => {
+ if (!marketId || !network || !data) {
+ return;
+ }
+
+ if (page > 1) {
+ void queryClient.prefetchQuery({
+ queryKey: ['marketTxContexts', marketId, network, page - 1, pageSize],
+ queryFn: async () => queryFn(page - 1),
+ staleTime: 1000 * 60 * 5,
+ });
+ }
+
+ if (data.hasNextPage) {
+ void queryClient.prefetchQuery({
+ queryKey: ['marketTxContexts', marketId, network, page + 1, pageSize],
+ queryFn: async () => queryFn(page + 1),
+ staleTime: 1000 * 60 * 5,
+ });
+ }
+ }, [data, marketId, network, page, pageSize, queryClient]);
+
+ return {
+ data,
+ isLoading,
+ isFetching,
+ error,
+ refetch,
+ };
+};
diff --git a/src/stores/useMarketDetailPreferences.ts b/src/stores/useMarketDetailPreferences.ts
index 828d0aef..39375bf9 100644
--- a/src/stores/useMarketDetailPreferences.ts
+++ b/src/stores/useMarketDetailPreferences.ts
@@ -6,14 +6,17 @@ import {
} from '@/features/market-detail/components/borrower-table-column-visibility';
type MarketDetailTab = 'trend' | 'activities' | 'positions' | 'analysis';
+type MarketDetailActivitiesView = 'basic' | 'pro';
type MarketDetailPreferencesState = {
selectedTab: MarketDetailTab;
+ activitiesView: MarketDetailActivitiesView;
borrowerTableColumnVisibility: BorrowerTableColumnVisibility;
};
type MarketDetailPreferencesActions = {
setSelectedTab: (tab: MarketDetailTab) => void;
+ setActivitiesView: (view: MarketDetailActivitiesView) => void;
setBorrowerTableColumnVisibility: (
visibilityOrUpdater: BorrowerTableColumnVisibility | ((prev: BorrowerTableColumnVisibility) => BorrowerTableColumnVisibility),
) => void;
@@ -26,8 +29,10 @@ export const useMarketDetailPreferences = create()
persist(
(set) => ({
selectedTab: 'trend',
+ activitiesView: 'basic',
borrowerTableColumnVisibility: DEFAULT_BORROWER_TABLE_COLUMN_VISIBILITY,
setSelectedTab: (tab) => set({ selectedTab: tab }),
+ setActivitiesView: (view) => set({ activitiesView: view }),
setBorrowerTableColumnVisibility: (visibilityOrUpdater) =>
set((state) => ({
borrowerTableColumnVisibility:
@@ -37,21 +42,23 @@ export const useMarketDetailPreferences = create()
}),
{
name: 'monarch_store_marketDetailPreferences',
- version: 2,
+ version: 3,
migrate: (state, version) => {
if (!state || typeof state !== 'object') {
return {
selectedTab: 'trend',
+ activitiesView: 'basic',
borrowerTableColumnVisibility: DEFAULT_BORROWER_TABLE_COLUMN_VISIBILITY,
} as MarketDetailPreferencesState;
}
const persisted = state as Partial;
- if (version < 2) {
+ if (version < 3) {
return {
...persisted,
selectedTab: persisted.selectedTab ?? 'trend',
+ activitiesView: persisted.activitiesView ?? 'basic',
borrowerTableColumnVisibility: {
...DEFAULT_BORROWER_TABLE_COLUMN_VISIBILITY,
...(persisted.borrowerTableColumnVisibility ?? {}),
@@ -62,6 +69,7 @@ export const useMarketDetailPreferences = create()
return {
...persisted,
selectedTab: persisted.selectedTab ?? 'trend',
+ activitiesView: persisted.activitiesView ?? 'basic',
borrowerTableColumnVisibility: {
...DEFAULT_BORROWER_TABLE_COLUMN_VISIBILITY,
...(persisted.borrowerTableColumnVisibility ?? {}),
@@ -72,4 +80,4 @@ export const useMarketDetailPreferences = create()
),
);
-export type { MarketDetailTab };
+export type { MarketDetailActivitiesView, MarketDetailTab };