diff --git a/app/admin/stats-v2/page.tsx b/app/admin/stats-v2/page.tsx index fc1dab82..36c9d089 100644 --- a/app/admin/stats-v2/page.tsx +++ b/app/admin/stats-v2/page.tsx @@ -3,8 +3,8 @@ /** * Stats V2 Dashboard (Experimental) * - * This page uses a new cross-chain indexer API that provides Monarch transaction - * data across all chains with a single API call. + * This page uses the shared Monarch API to provide cross-chain Monarch + * transaction data across all chains with a single GraphQL endpoint. * * NOTE: This API is experimental and may be reverted due to cost concerns. * The old stats page at /admin/stats should be kept as a fallback. diff --git a/app/api/admin/monarch-indexer/route.ts b/app/api/admin/monarch-indexer/route.ts deleted file mode 100644 index 0882b2fe..00000000 --- a/app/api/admin/monarch-indexer/route.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { type NextRequest, NextResponse } from 'next/server'; -import { cookies } from 'next/headers'; -import { reportApiRouteError } from '@/utils/sentry-server'; - -/** - * Proxy API route for Monarch Indexer - * - * Validates auth via httpOnly cookie, then proxies to the actual indexer. - * The real endpoint URL is never exposed to the client. - * - * Environment variables (server-side only): - * - MONARCH_INDEXER_ENDPOINT: The actual GraphQL endpoint URL - * - ADMIN_V2_PASSWORD_HASH: Expected password hash (for cookie validation) - */ - -const INDEXER_ENDPOINT = process.env.MONARCH_INDEXER_ENDPOINT; -const EXPECTED_HASH = process.env.ADMIN_V2_PASSWORD_HASH; -const COOKIE_NAME = 'monarch_admin_session'; - -export async function POST(request: NextRequest) { - // Validate auth cookie - const cookieStore = await cookies(); - const session = cookieStore.get(COOKIE_NAME); - - if (!EXPECTED_HASH || !session?.value || session.value !== EXPECTED_HASH) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - - if (!INDEXER_ENDPOINT) { - return NextResponse.json({ error: 'Indexer endpoint not configured' }, { status: 500 }); - } - - try { - const body = await request.json(); - - const response = await fetch(INDEXER_ENDPOINT, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), - }); - - if (!response.ok) { - return NextResponse.json({ error: `Indexer request failed: ${response.status}` }, { status: response.status }); - } - - const data = await response.json(); - return NextResponse.json(data); - } catch (error) { - reportApiRouteError(error, { - route: '/api/admin/monarch-indexer', - method: 'POST', - status: 500, - }); - console.error('Monarch indexer proxy error:', error); - return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); - } -} diff --git a/docs/TECHNICAL_OVERVIEW.md b/docs/TECHNICAL_OVERVIEW.md index 52c38ad0..1e58cdb5 100644 --- a/docs/TECHNICAL_OVERVIEW.md +++ b/docs/TECHNICAL_OVERVIEW.md @@ -174,6 +174,11 @@ Autovault metadata: Monarch GraphQL (https://api.monarchlend.xyz/graphql) ↓ (if indexer lag / API failure) Narrow on-chain RPC fallback +Market detail participants/activity + admin stats transactions: + Monarch GraphQL (https://api.monarchlend.xyz/graphql) + ↓ (for market-detail fallback only) + Morpho API / Subgraph + Market metrics: Monarch metrics API via `/api/monarch/metrics` ``` @@ -195,11 +200,13 @@ Market metrics: Monarch metrics API via `/api/monarch/metrics` | Vaults list | Morpho API | 5 min | `useAllMorphoVaultsQuery` | | User autovault metadata | Monarch GraphQL + on-chain enrichment | 60s | `useUserVaultsV2Query` | | Vault detail/settings metadata | Monarch GraphQL + narrow RPC fallback | 30s | `useVaultV2Data` | +| Market detail participants/activity | Monarch GraphQL + Morpho API/Subgraph fallback | 2-5 min stale | `useMarketSuppliers` / `useMarketBorrowers` / `useMarketSupplies` / `useMarketBorrows` | | Vault allocations | On-chain multicall | 30s | `useAllocationsQuery` | | Token balances | On-chain multicall | 5 min | `useUserBalancesQuery` | | Oracle metadata | Scanner Gist | 30 min | `useOracleMetadata` / `useAllOracleMetadata` | | Merkl rewards | Merkl API | On demand | `useMerklCampaignsQuery` | -| Market liquidations | Morpho API/Subgraph | 5 min stale | `useMarketLiquidations` | +| Market liquidations | Monarch GraphQL + Morpho API/Subgraph fallback | 5 min stale | `useMarketLiquidations` | +| Admin stats transactions | Monarch GraphQL | 2 min stale | `useMonarchTransactions` | ### Data Flow Patterns @@ -306,7 +313,7 @@ Fallback Strategy: **Monarch GraphQL** (`/src/data-sources/monarch-api/fetchers.ts`): - Endpoint: `NEXT_PUBLIC_MONARCH_API_NEW` - Browser fetch with `NEXT_PUBLIC_MONARCH_API_KEY` -- Used as the primary read path for autovault V2 metadata +- Used as the primary read path for autovault V2 metadata, market-detail reads, and admin transaction reads **Subgraph** (`/src/data-sources/subgraph/fetchers.ts`): - Configurable URL per network @@ -351,7 +358,7 @@ Fallback Strategy: | Service | Endpoint | Purpose | |---------|----------|---------| | Morpho API | `https://blue-api.morpho.org/graphql` | Markets, vaults, positions | -| Monarch GraphQL | `https://api.monarchlend.xyz/graphql` | Autovault metadata, adapters, caps | +| Monarch GraphQL | `https://api.monarchlend.xyz/graphql` | Autovault metadata, market detail/activity, admin transactions | | Monarch Metrics | `/api/monarch/metrics` → external Monarch metrics API | Market metrics and admin stats | | The Graph | Per-chain subgraph URLs | Fallback data, suppliers, borrowers | | Merkl API | `https://api.merkl.xyz` | Reward campaigns | diff --git a/src/data-sources/envio/fetchers.ts b/src/data-sources/envio/fetchers.ts deleted file mode 100644 index ccbfb67c..00000000 --- a/src/data-sources/envio/fetchers.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { monarchGraphqlFetcher } from '@/data-sources/monarch-api/fetchers'; - -/** - * Envio-backed Monarch GraphQL currently shares the Monarch API endpoint. - * Keep a dedicated fetcher alias so market-detail hooks can depend on an - * Envio chokepoint without coupling to vault-specific naming. - */ -export const envioGraphqlFetcher = monarchGraphqlFetcher; diff --git a/src/data-sources/monarch-api/index.ts b/src/data-sources/monarch-api/index.ts index 14b6f5b7..63e09573 100644 --- a/src/data-sources/monarch-api/index.ts +++ b/src/data-sources/monarch-api/index.ts @@ -1,4 +1,17 @@ export { monarchGraphqlFetcher } from './fetchers'; +export { + fetchMonarchMarketBorrowers, + fetchMonarchMarketBorrows, + fetchMonarchMarketLiquidations, + fetchMonarchMarketSuppliers, + fetchMonarchMarketSupplies, +} from './market-detail'; +export { + fetchMonarchTransactions, + type MonarchSupplyTransaction, + type MonarchWithdrawTransaction, + type TimeRange, +} from './transactions'; export { fetchMonarchVaultDetails, fetchUserVaultV2DetailsAllNetworks, diff --git a/src/data-sources/envio/market-detail.ts b/src/data-sources/monarch-api/market-detail.ts similarity index 69% rename from src/data-sources/envio/market-detail.ts rename to src/data-sources/monarch-api/market-detail.ts index c5962f09..5bdc42c5 100644 --- a/src/data-sources/envio/market-detail.ts +++ b/src/data-sources/monarch-api/market-detail.ts @@ -1,4 +1,3 @@ -import { envioGraphqlFetcher } from './fetchers'; import { envioBorrowersPageQuery, envioBorrowRepayPageQuery, @@ -18,8 +17,9 @@ import type { PaginatedMarketLiquidations, PaginatedMarketSuppliers, } from '@/utils/types'; +import { monarchGraphqlFetcher } from './fetchers'; -const ENVIO_SCAN_BATCH_SIZE = 1000; +const MONARCH_SCAN_BATCH_SIZE = 1000; const PARTICIPANT_CACHE_TTL_MS = 2 * 60 * 1000; type CacheEntry = { @@ -29,12 +29,12 @@ type CacheEntry = { type BorrowSharePriceState = Pick; -type EnvioSupplierRow = { +type MonarchSupplierRow = { user: string; supplyShares: string; }; -type EnvioBorrowerRow = { +type MonarchBorrowerRow = { user: string; borrowShares: string; collateral: string; @@ -46,36 +46,36 @@ type CachedBorrowerPosition = { collateral: string; }; -type EnvioGraphqlResponse = { +type MonarchGraphqlResponse = { data?: T; }; -type EnvioSuppliersPageResponse = EnvioGraphqlResponse<{ - Position: EnvioSupplierRow[]; +type MonarchSuppliersPageResponse = MonarchGraphqlResponse<{ + Position: MonarchSupplierRow[]; }>; -type EnvioBorrowersPageResponse = EnvioGraphqlResponse<{ - Position: EnvioBorrowerRow[]; +type MonarchBorrowersPageResponse = MonarchGraphqlResponse<{ + Position: MonarchBorrowerRow[]; }>; -type EnvioActivityEventRow = { +type MonarchActivityEventRow = { txHash: string; timestamp: string; assets: string; onBehalf: string; }; -type EnvioSupplyWithdrawPageResponse = EnvioGraphqlResponse<{ - supplies: EnvioActivityEventRow[]; - withdraws: EnvioActivityEventRow[]; +type MonarchSupplyWithdrawPageResponse = MonarchGraphqlResponse<{ + supplies: MonarchActivityEventRow[]; + withdraws: MonarchActivityEventRow[]; }>; -type EnvioBorrowRepayPageResponse = EnvioGraphqlResponse<{ - borrows: EnvioActivityEventRow[]; - repays: EnvioActivityEventRow[]; +type MonarchBorrowRepayPageResponse = MonarchGraphqlResponse<{ + borrows: MonarchActivityEventRow[]; + repays: MonarchActivityEventRow[]; }>; -type EnvioLiquidationRow = { +type MonarchLiquidationRow = { txHash: string; timestamp: string; caller: string; @@ -85,8 +85,8 @@ type EnvioLiquidationRow = { badDebtAssets: string; }; -type EnvioLiquidationsPageResponse = EnvioGraphqlResponse<{ - Morpho_Liquidate: EnvioLiquidationRow[]; +type MonarchLiquidationsPageResponse = MonarchGraphqlResponse<{ + Morpho_Liquidate: MonarchLiquidationRow[]; }>; const suppliersCache = new Map>(); @@ -139,10 +139,10 @@ const scanAllPages = async ({ fetchPage }: { fetchPage: (offset: number, limi let offset = 0; while (true) { - const pageItems = await fetchPage(offset, ENVIO_SCAN_BATCH_SIZE); + const pageItems = await fetchPage(offset, MONARCH_SCAN_BATCH_SIZE); items.push(...pageItems); - if (pageItems.length < ENVIO_SCAN_BATCH_SIZE) { + if (pageItems.length < MONARCH_SCAN_BATCH_SIZE) { return items; } @@ -174,7 +174,7 @@ const sortActivityTransactions = (left: MarketActivityTransaction, right: Market return right.hash.localeCompare(left.hash); }; -const mapEnvioActivityRows = (rows: EnvioActivityEventRow[], type: MarketActivityTransaction['type']): MarketActivityTransaction[] => { +const mapMonarchActivityRows = (rows: MonarchActivityEventRow[], type: MarketActivityTransaction['type']): MarketActivityTransaction[] => { return rows.map((event) => ({ type, hash: event.txHash, @@ -196,7 +196,7 @@ const mapCachedBorrowers = (positions: CachedBorrowerPosition[], marketState: Bo })); }; -const fetchEnvioSuppliersAll = async (marketId: string, chainId: number, minShares: string): Promise => { +const fetchMonarchSuppliersAll = async (marketId: string, chainId: number, minShares: string): Promise => { const cacheKey = toCacheKey(['suppliers', chainId, marketId.toLowerCase(), minShares]); return getCachedOrLoad({ @@ -206,7 +206,7 @@ const fetchEnvioSuppliersAll = async (marketId: string, chainId: number, minShar loader: async () => { return scanAllPages({ fetchPage: async (offset, limit) => { - const response = await envioGraphqlFetcher(envioSuppliersPageQuery, { + const response = await monarchGraphqlFetcher(envioSuppliersPageQuery, { chainId, marketId, minShares, @@ -224,7 +224,7 @@ const fetchEnvioSuppliersAll = async (marketId: string, chainId: number, minShar }); }; -const fetchEnvioBorrowersAll = async (marketId: string, chainId: number, minShares: string): Promise => { +const fetchMonarchBorrowersAll = async (marketId: string, chainId: number, minShares: string): Promise => { const cacheKey = toCacheKey(['borrowers', chainId, marketId.toLowerCase(), minShares]); return getCachedOrLoad({ @@ -234,7 +234,7 @@ const fetchEnvioBorrowersAll = async (marketId: string, chainId: number, minShar loader: async () => { return scanAllPages({ fetchPage: async (offset, limit) => { - const response = await envioGraphqlFetcher(envioBorrowersPageQuery, { + const response = await monarchGraphqlFetcher(envioBorrowersPageQuery, { chainId, marketId, minShares, @@ -253,13 +253,13 @@ const fetchEnvioBorrowersAll = async (marketId: string, chainId: number, minShar }); }; -const fetchEnvioSupplyWithdrawWindow = async ( +const fetchMonarchSupplyWithdrawWindow = async ( marketId: string, chainId: number, minAssets: string, limit: number, ): Promise => { - const response = await envioGraphqlFetcher(envioSupplyWithdrawPageQuery, { + const response = await monarchGraphqlFetcher(envioSupplyWithdrawPageQuery, { chainId, marketId, minAssets, @@ -267,19 +267,19 @@ const fetchEnvioSupplyWithdrawWindow = async ( offset: 0, }); - const supplies = mapEnvioActivityRows(response.data?.supplies ?? [], 'MarketSupply'); - const withdraws = mapEnvioActivityRows(response.data?.withdraws ?? [], 'MarketWithdraw'); + const supplies = mapMonarchActivityRows(response.data?.supplies ?? [], 'MarketSupply'); + const withdraws = mapMonarchActivityRows(response.data?.withdraws ?? [], 'MarketWithdraw'); return [...supplies, ...withdraws].sort(sortActivityTransactions); }; -const fetchEnvioBorrowRepayWindow = async ( +const fetchMonarchBorrowRepayWindow = async ( marketId: string, chainId: number, minAssets: string, limit: number, ): Promise => { - const response = await envioGraphqlFetcher(envioBorrowRepayPageQuery, { + const response = await monarchGraphqlFetcher(envioBorrowRepayPageQuery, { chainId, marketId, minAssets, @@ -287,19 +287,19 @@ const fetchEnvioBorrowRepayWindow = async ( offset: 0, }); - const borrows = mapEnvioActivityRows(response.data?.borrows ?? [], 'MarketBorrow'); - const repays = mapEnvioActivityRows(response.data?.repays ?? [], 'MarketRepay'); + const borrows = mapMonarchActivityRows(response.data?.borrows ?? [], 'MarketBorrow'); + const repays = mapMonarchActivityRows(response.data?.repays ?? [], 'MarketRepay'); return [...borrows, ...repays].sort(sortActivityTransactions); }; -const fetchEnvioLiquidationsWindow = async ( +const fetchMonarchLiquidationsWindow = async ( marketId: string, chainId: number, offset: number, limit: number, ): Promise => { - const response = await envioGraphqlFetcher(envioLiquidationsPageQuery, { + const response = await monarchGraphqlFetcher(envioLiquidationsPageQuery, { chainId, marketId, limit, @@ -317,17 +317,17 @@ const fetchEnvioLiquidationsWindow = async ( })); }; -export const fetchEnvioMarketSuppliers = async ( +export const fetchMonarchMarketSuppliers = async ( marketId: string, chainId: number, minShares = '0', first = 8, skip = 0, ): Promise => { - return paginateItems(await fetchEnvioSuppliersAll(marketId, chainId, minShares), first, skip); + return paginateItems(await fetchMonarchSuppliersAll(marketId, chainId, minShares), first, skip); }; -export const fetchEnvioMarketBorrowers = async ( +export const fetchMonarchMarketBorrowers = async ( marketId: string, chainId: number, marketState: BorrowSharePriceState, @@ -335,34 +335,34 @@ export const fetchEnvioMarketBorrowers = async ( first = 10, skip = 0, ): Promise => { - return paginateItems(mapCachedBorrowers(await fetchEnvioBorrowersAll(marketId, chainId, minShares), marketState), first, skip); + return paginateItems(mapCachedBorrowers(await fetchMonarchBorrowersAll(marketId, chainId, minShares), marketState), first, skip); }; -export const fetchEnvioMarketSupplies = async ( +export const fetchMonarchMarketSupplies = async ( marketId: string, chainId: number, minAssets = '0', first = 8, skip = 0, ): Promise => { - return paginateWindowedItems(await fetchEnvioSupplyWithdrawWindow(marketId, chainId, minAssets, skip + first + 1), first, skip); + return paginateWindowedItems(await fetchMonarchSupplyWithdrawWindow(marketId, chainId, minAssets, skip + first + 1), first, skip); }; -export const fetchEnvioMarketBorrows = async ( +export const fetchMonarchMarketBorrows = async ( marketId: string, chainId: number, minAssets = '0', first = 8, skip = 0, ): Promise => { - return paginateWindowedItems(await fetchEnvioBorrowRepayWindow(marketId, chainId, minAssets, skip + first + 1), first, skip); + return paginateWindowedItems(await fetchMonarchBorrowRepayWindow(marketId, chainId, minAssets, skip + first + 1), first, skip); }; -export const fetchEnvioMarketLiquidations = async ( +export const fetchMonarchMarketLiquidations = async ( marketId: string, chainId: number, first = 8, skip = 0, ): Promise => { - return paginateWindowedItems(await fetchEnvioLiquidationsWindow(marketId, chainId, skip, first + 1), first, 0); + return paginateWindowedItems(await fetchMonarchLiquidationsWindow(marketId, chainId, skip, first + 1), first, 0); }; diff --git a/src/data-sources/monarch-indexer/transactions.ts b/src/data-sources/monarch-api/transactions.ts similarity index 81% rename from src/data-sources/monarch-indexer/transactions.ts rename to src/data-sources/monarch-api/transactions.ts index 0d69fef0..ed3b7f53 100644 --- a/src/data-sources/monarch-indexer/transactions.ts +++ b/src/data-sources/monarch-api/transactions.ts @@ -1,13 +1,14 @@ /** - * Monarch Indexer Transactions + * Monarch API Transactions + * + * Fetches Monarch supply and withdraw transactions across all chains through the + * shared Monarch GraphQL endpoint. * - * Fetches Monarch supply/withdraw transactions across all chains. - * Auth is handled via httpOnly cookie. * Uses separate pagination for supplies and withdraws to ensure complete data. * Freezes endTimestamp at fetch start to ensure consistent pagination. */ -import { monarchIndexerFetcher } from './fetchers'; +import { monarchGraphqlFetcher } from './fetchers'; export type MonarchSupplyTransaction = { txHash: string; @@ -51,7 +52,7 @@ type FrozenTimeRange = { const MAX_PAGES = 50; -async function fetchSuppliesPage(timeRange: FrozenTimeRange, limit: number, offset: number): Promise { +const fetchSuppliesPage = async (timeRange: FrozenTimeRange, limit: number, offset: number): Promise => { const query = ` query MonarchSupplies($startTimestamp: numeric!, $endTimestamp: numeric!, $limit: Int!, $offset: Int!) { Morpho_Supply( @@ -68,11 +69,11 @@ async function fetchSuppliesPage(timeRange: FrozenTimeRange, limit: number, offs offset, }; - const response = await monarchIndexerFetcher(query, variables); + const response = await monarchGraphqlFetcher(query, variables); return response.data.Morpho_Supply ?? []; -} +}; -async function fetchWithdrawsPage(timeRange: FrozenTimeRange, limit: number, offset: number): Promise { +const fetchWithdrawsPage = async (timeRange: FrozenTimeRange, limit: number, offset: number): Promise => { const query = ` query MonarchWithdraws($startTimestamp: numeric!, $endTimestamp: numeric!, $limit: Int!, $offset: Int!) { Morpho_Withdraw( @@ -89,30 +90,27 @@ async function fetchWithdrawsPage(timeRange: FrozenTimeRange, limit: number, off offset, }; - const response = await monarchIndexerFetcher(query, variables); + const response = await monarchGraphqlFetcher(query, variables); return response.data.Morpho_Withdraw ?? []; -} +}; /** * Fetches all supply and withdraw transactions with independent pagination. * Each collection is fetched completely before returning. * Freezes endTimestamp at start to ensure consistent results during pagination. */ -export async function fetchMonarchTransactions( +export const fetchMonarchTransactions = async ( timeRange: TimeRange, limit = 1000, ): Promise<{ supplies: MonarchSupplyTransaction[]; withdraws: MonarchWithdrawTransaction[]; -}> { - // Freeze the end timestamp at function start to ensure consistent pagination - // This prevents skipped/duplicate data if new transactions arrive during fetching +}> => { const frozenTimeRange: FrozenTimeRange = { startTimestamp: timeRange.startTimestamp, endTimestamp: timeRange.endTimestamp ?? Math.floor(Date.now() / 1000), }; - // Fetch supplies with independent pagination const allSupplies: MonarchSupplyTransaction[] = []; let suppliesOffset = 0; for (let page = 0; page < MAX_PAGES; page++) { @@ -122,7 +120,6 @@ export async function fetchMonarchTransactions( suppliesOffset += limit; } - // Fetch withdraws with independent pagination const allWithdraws: MonarchWithdrawTransaction[] = []; let withdrawsOffset = 0; for (let page = 0; page < MAX_PAGES; page++) { @@ -133,4 +130,4 @@ export async function fetchMonarchTransactions( } return { supplies: allSupplies, withdraws: allWithdraws }; -} +}; diff --git a/src/data-sources/monarch-indexer/fetchers.ts b/src/data-sources/monarch-indexer/fetchers.ts deleted file mode 100644 index 6f82e72e..00000000 --- a/src/data-sources/monarch-indexer/fetchers.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Monarch Indexer GraphQL Fetcher - * - * Calls our internal API route which proxies to the actual indexer. - * Auth is handled via httpOnly cookie (set during login). - * - * NOTE: This API is experimental and may be reverted due to cost concerns. - * The old stats page at /admin/stats should be kept as a fallback. - */ - -type GraphQLVariables = Record; - -/** - * Fetches data from the monarch indexer via our API proxy. - * Requires valid session cookie (set via /api/admin/auth). - */ -export async function monarchIndexerFetcher(query: string, variables?: GraphQLVariables): Promise { - const response = await fetch('/api/admin/monarch-indexer', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'same-origin', // Include cookies - body: JSON.stringify({ - query, - variables, - }), - }); - - if (!response.ok) { - if (response.status === 401) { - throw new Error('Unauthorized - please log in again'); - } - throw new Error(`Monarch Indexer request failed: ${response.status} ${response.statusText}`); - } - - const result = await response.json(); - - if (result.errors) { - throw new Error(`Monarch Indexer GraphQL error: ${JSON.stringify(result.errors)}`); - } - - return result as T; -} diff --git a/src/data-sources/monarch-indexer/index.ts b/src/data-sources/monarch-indexer/index.ts deleted file mode 100644 index 64ab5bc2..00000000 --- a/src/data-sources/monarch-indexer/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Monarch Indexer Data Source - * - * A new cross-chain indexer API for fetching Monarch transactions - * across all chains with a single API call. - * - * NOTE: This API is experimental and may be reverted due to cost concerns. - * The old stats page at /admin/stats should be kept as a fallback. - */ - -export { monarchIndexerFetcher } from './fetchers'; -export { - fetchMonarchTransactions, - type MonarchSupplyTransaction, - type MonarchWithdrawTransaction, - type TimeRange, -} from './transactions'; diff --git a/src/features/admin-v2/components/password-gate.tsx b/src/features/admin-v2/components/password-gate.tsx index beaff65c..b9ef7bbd 100644 --- a/src/features/admin-v2/components/password-gate.tsx +++ b/src/features/admin-v2/components/password-gate.tsx @@ -47,7 +47,9 @@ export function PasswordGate({ children }: PasswordGateProps) {

Stats V2 (Experimental)

-

This page uses an experimental API that may be reverted due to cost concerns.

+

+ This page uses the experimental shared Monarch API and may be reverted if costs become too high. +

diff --git a/src/features/admin-v2/index.ts b/src/features/admin-v2/index.ts index ac650176..65833c52 100644 --- a/src/features/admin-v2/index.ts +++ b/src/features/admin-v2/index.ts @@ -1,7 +1,7 @@ /** * Admin V2 Feature * - * Experimental cross-chain stats dashboard that uses the monarch indexer API. + * Experimental cross-chain stats dashboard that uses the shared Monarch API. * * NOTE: This feature is experimental and may be removed if the API costs * prove too high. The original /admin/stats page should remain as a fallback. diff --git a/src/hooks/queries/market-detail-fallback.ts b/src/hooks/queries/market-detail-fallback.ts index 57f6ed51..cea87f5e 100644 --- a/src/hooks/queries/market-detail-fallback.ts +++ b/src/hooks/queries/market-detail-fallback.ts @@ -1,6 +1,6 @@ import type { SupportedNetworks } from '@/utils/networks'; -export type MarketDetailProvider = 'envio' | 'morpho-api' | 'subgraph'; +export type MarketDetailProvider = 'monarch-api' | 'morpho-api' | 'subgraph'; type ProviderAttempt = { provider: MarketDetailProvider; diff --git a/src/hooks/useMarketBorrowers.ts b/src/hooks/useMarketBorrowers.ts index 8d34571c..c0942a0d 100644 --- a/src/hooks/useMarketBorrowers.ts +++ b/src/hooks/useMarketBorrowers.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { supportsMorphoApi } from '@/config/dataSources'; -import { fetchEnvioMarketBorrowers } from '@/data-sources/envio/market-detail'; +import { fetchMonarchMarketBorrowers } from '@/data-sources/monarch-api'; import { fetchMorphoMarketBorrowers } from '@/data-sources/morpho-api/market-borrowers'; import { fetchSubgraphMarketBorrowers } from '@/data-sources/subgraph/market-borrowers'; import { runMarketDetailFallback } from '@/hooks/queries/market-detail-fallback'; @@ -28,8 +28,8 @@ const buildMarketBorrowersKey = ({ /** * Hook to fetch current borrowers (positions) for a specific market, - * using Envio as the primary source with existing sources as fallback. - * Preserves exact total counts via the shared Envio scan/cache layer. + * using Monarch API as the primary source with existing sources as fallback. + * Preserves exact total counts via the shared Monarch scan/cache layer. * Returns borrowers sorted by borrow shares (descending). * * @param marketId The ID of the market (e.g., 0x...). @@ -75,8 +75,8 @@ export const useMarketBorrowers = ( network, attempts: [ { - provider: 'envio', - fetch: () => fetchEnvioMarketBorrowers(marketId, Number(network), marketState, effectiveMinShares, pageSize, targetSkip), + provider: 'monarch-api', + fetch: () => fetchMonarchMarketBorrowers(marketId, Number(network), marketState, effectiveMinShares, pageSize, targetSkip), }, ...(supportsMorphoApi(network) ? [ diff --git a/src/hooks/useMarketBorrows.ts b/src/hooks/useMarketBorrows.ts index 3c47af8e..a055c62d 100644 --- a/src/hooks/useMarketBorrows.ts +++ b/src/hooks/useMarketBorrows.ts @@ -1,7 +1,7 @@ import { useEffect, useCallback } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { supportsMorphoApi } from '@/config/dataSources'; -import { fetchEnvioMarketBorrows } from '@/data-sources/envio/market-detail'; +import { fetchMonarchMarketBorrows } from '@/data-sources/monarch-api'; import { fetchMorphoMarketBorrows } from '@/data-sources/morpho-api/market-borrows'; import { fetchSubgraphMarketBorrows } from '@/data-sources/subgraph/market-borrows'; import { runMarketDetailFallback } from '@/hooks/queries/market-detail-fallback'; @@ -10,8 +10,8 @@ import type { PaginatedMarketActivityTransactions } from '@/utils/types'; /** * Hook to fetch borrow and repay activities for a specific market's loan asset, - * using Envio as the primary source with existing sources as fallback. - * Envio only loads the current page window instead of scanning the full event history. + * using Monarch API as the primary source with existing sources as fallback. + * Monarch API only loads the current page window instead of scanning the full event history. * @param marketId The ID or unique key of the market. * @param loanAssetId The address of the loan asset for the market. * @param network The blockchain network. @@ -46,8 +46,8 @@ export const useMarketBorrows = ( network, attempts: [ { - provider: 'envio', - fetch: () => fetchEnvioMarketBorrows(marketId, Number(network), minAssets, pageSize, targetSkip), + provider: 'monarch-api', + fetch: () => fetchMonarchMarketBorrows(marketId, Number(network), minAssets, pageSize, targetSkip), }, ...(supportsMorphoApi(network) ? [ diff --git a/src/hooks/useMarketLiquidations.ts b/src/hooks/useMarketLiquidations.ts index 1c101517..c1db4ccf 100644 --- a/src/hooks/useMarketLiquidations.ts +++ b/src/hooks/useMarketLiquidations.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { supportsMorphoApi } from '@/config/dataSources'; -import { fetchEnvioMarketLiquidations } from '@/data-sources/envio/market-detail'; +import { fetchMonarchMarketLiquidations } from '@/data-sources/monarch-api'; import { fetchMorphoMarketLiquidations } from '@/data-sources/morpho-api/market-liquidations'; import { fetchSubgraphMarketLiquidations } from '@/data-sources/subgraph/market-liquidations'; import { runMarketDetailFallback } from '@/hooks/queries/market-detail-fallback'; @@ -9,7 +9,7 @@ import type { SupportedNetworks } from '@/utils/networks'; import type { PaginatedMarketLiquidations } from '@/utils/types'; /** - * Hook to fetch liquidations for a specific market, using Envio as the primary source + * Hook to fetch liquidations for a specific market, using Monarch API as the primary source * with existing sources as fallback. * @param marketId The ID or unique key of the market. * @param network The blockchain network. @@ -35,8 +35,8 @@ export const useMarketLiquidations = (marketId: string | undefined, network: Sup network, attempts: [ { - provider: 'envio', - fetch: () => fetchEnvioMarketLiquidations(marketId, Number(network), pageSize, targetSkip), + provider: 'monarch-api', + fetch: () => fetchMonarchMarketLiquidations(marketId, Number(network), pageSize, targetSkip), }, ...(supportsMorphoApi(network) ? [ diff --git a/src/hooks/useMarketSuppliers.ts b/src/hooks/useMarketSuppliers.ts index a854bbd5..3e4469e4 100644 --- a/src/hooks/useMarketSuppliers.ts +++ b/src/hooks/useMarketSuppliers.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { supportsMorphoApi } from '@/config/dataSources'; -import { fetchEnvioMarketSuppliers } from '@/data-sources/envio/market-detail'; +import { fetchMonarchMarketSuppliers } from '@/data-sources/monarch-api'; import { fetchMorphoMarketSuppliers } from '@/data-sources/morpho-api/market-suppliers'; import { fetchSubgraphMarketSuppliers } from '@/data-sources/subgraph/market-suppliers'; import { runMarketDetailFallback } from '@/hooks/queries/market-detail-fallback'; @@ -10,8 +10,8 @@ import type { PaginatedMarketSuppliers } from '@/utils/types'; /** * Hook to fetch current suppliers (positions) for a specific market, - * using Envio as the primary source with existing sources as fallback. - * Preserves exact total counts via the shared Envio scan/cache layer. + * using Monarch API as the primary source with existing sources as fallback. + * Preserves exact total counts via the shared Monarch scan/cache layer. * Returns suppliers sorted by supply shares (descending). * * @param marketId The ID of the market (e.g., 0x...). @@ -49,8 +49,8 @@ export const useMarketSuppliers = ( network, attempts: [ { - provider: 'envio', - fetch: () => fetchEnvioMarketSuppliers(marketId, Number(network), effectiveMinShares, pageSize, targetSkip), + provider: 'monarch-api', + fetch: () => fetchMonarchMarketSuppliers(marketId, Number(network), effectiveMinShares, pageSize, targetSkip), }, ...(supportsMorphoApi(network) ? [ diff --git a/src/hooks/useMarketSupplies.ts b/src/hooks/useMarketSupplies.ts index 6048096e..7760b60a 100644 --- a/src/hooks/useMarketSupplies.ts +++ b/src/hooks/useMarketSupplies.ts @@ -1,7 +1,7 @@ import { useEffect, useCallback } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { supportsMorphoApi } from '@/config/dataSources'; -import { fetchEnvioMarketSupplies } from '@/data-sources/envio/market-detail'; +import { fetchMonarchMarketSupplies } from '@/data-sources/monarch-api'; import { fetchMorphoMarketSupplies } from '@/data-sources/morpho-api/market-supplies'; import { fetchSubgraphMarketSupplies } from '@/data-sources/subgraph/market-supplies'; import { runMarketDetailFallback } from '@/hooks/queries/market-detail-fallback'; @@ -10,8 +10,8 @@ import type { PaginatedMarketActivityTransactions } from '@/utils/types'; /** * Hook to fetch supply and withdraw activities for a specific market's loan asset, - * using Envio as the primary source with existing sources as fallback. - * Envio only loads the current page window instead of scanning the full event history. + * using Monarch API as the primary source with existing sources as fallback. + * Monarch API only loads the current page window instead of scanning the full event history. * @param marketId The ID of the market (e.g., 0x...). * @param loanAssetId The address of the loan asset for the market. * @param network The blockchain network. @@ -46,8 +46,8 @@ export const useMarketSupplies = ( network, attempts: [ { - provider: 'envio', - fetch: () => fetchEnvioMarketSupplies(marketId, Number(network), minAssets, pageSize, targetSkip), + provider: 'monarch-api', + fetch: () => fetchMonarchMarketSupplies(marketId, Number(network), minAssets, pageSize, targetSkip), }, ...(supportsMorphoApi(network) ? [ diff --git a/src/hooks/useMonarchTransactions.ts b/src/hooks/useMonarchTransactions.ts index 54869d58..26c4563e 100644 --- a/src/hooks/useMonarchTransactions.ts +++ b/src/hooks/useMonarchTransactions.ts @@ -6,7 +6,7 @@ import { type MonarchSupplyTransaction, type MonarchWithdrawTransaction, type TimeRange, -} from '@/data-sources/monarch-indexer'; +} from '@/data-sources/monarch-api'; import { useProcessedMarkets } from '@/hooks/useProcessedMarkets'; import { useTokenPrices } from '@/hooks/useTokenPrices'; import type { Market } from '@/utils/types'; @@ -85,7 +85,7 @@ export const useMonarchTransactions = (timeframe: TimeFrame): UseMonarchTransact }; }, [timeframe]); - // Fetch transactions (auth via httpOnly cookie) + // Fetch transactions from the shared Monarch API GraphQL endpoint const { data: rawTransactions, isLoading: txLoading, diff --git a/src/stores/useAdminAuth.ts b/src/stores/useAdminAuth.ts index 8f70fad3..53ddbe62 100644 --- a/src/stores/useAdminAuth.ts +++ b/src/stores/useAdminAuth.ts @@ -8,7 +8,7 @@ import { create } from 'zustand'; * 2. Password is sent to /api/admin/auth for server-side validation * 3. Server validates against ADMIN_V2_PASSWORD_HASH env var * 4. If valid, server sets httpOnly cookie (not accessible via JS) - * 5. Subsequent API requests include cookie automatically + * 5. Cookie-backed session gates access to the dashboard UI * * No sensitive data is stored client-side. * Set ADMIN_V2_PASSWORD_HASH in your .env file.