// Fund Market API Client const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080/api'; export interface StatsData { label: string; value: string; change: string; isPositive: boolean; } export interface Product { id: number; name: string; tokenSymbol: string; decimals: number; contractAddress: string; chainId: number; token_role: string; category: string; categoryColor: "blue" | "green" | "orange" | "purple" | "red"; iconUrl: string; yieldAPY: string; poolCap: string; risk: string; riskLevel: 1 | 2 | 3; circulatingSupply: string; poolCapacityPercent: number; } // Fetch all products // tokenList=true: include stablecoins (for token dropdowns) // tokenList=false (default): exclude stablecoins (Fund Market page) export async function fetchProducts(tokenList: boolean = false): Promise { try { const url = tokenList === true ? `${API_BASE_URL}/fundmarket/products?token_list=1` : `${API_BASE_URL}/fundmarket/products`; const response = await fetch(url, { cache: 'no-store', }); if (!response.ok) { throw new Error('Failed to fetch products'); } const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to fetch products'); } return data.data ?? []; } catch (error: unknown) { console.error('Error fetching products:', error); return []; } } // Fetch market stats export async function fetchStats(): Promise { try { const response = await fetch(`${API_BASE_URL}/fundmarket/stats`, { cache: 'no-store', }); if (!response.ok) { throw new Error('Failed to fetch stats'); } const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to fetch stats'); } return data.data; } catch (error: unknown) { console.error('Error fetching stats:', error); return []; } } // Product Detail Interfaces export interface ProductDetail { // Basic Info id: number; assetCode: string; name: string; subtitle: string; description: string; tokenSymbol: string; decimals: number; // Investment Parameters underlyingAssets: string; poolCapUsd: number; riskLevel: number; riskLabel: string; targetApy: number; // Contract Info contractAddress: string; chainId: number; // Display Info category: string; categoryColor: string; iconUrl: string; // Performance Data currentApy: number; tvlUsd: number; volume24hUsd: number; volumeChangeVsAvg: number; circulatingSupply: number; poolCapacityPercent: number; currentPrice: number; // Custody Info custody?: { custodianName: string; custodyType: string; custodyLocation: string; auditorName: string; lastAuditDate: string; auditReportUrl?: string; additionalInfo?: any; }; // Audit Reports auditReports: Array<{ reportType: string; reportTitle: string; reportDate: string; auditorName: string; summary: string; reportUrl: string; }>; // Product Links productLinks: Array<{ linkText: string; linkUrl: string; description: string; displayArea: string; // 'protocol' | 'verification' | 'both' displayOrder: number; }>; } // Fetch single product by ID (simple format) export async function fetchProductById(id: number): Promise { try { const response = await fetch(`${API_BASE_URL}/fundmarket/products/${id}`, { cache: 'no-store', }); if (!response.ok) { throw new Error('Failed to fetch product'); } const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to fetch product'); } return data.data; } catch (error: unknown) { console.error('Error fetching product:', error); return null; } } // Daily return point export interface DailyReturnPoint { date: string; // "YYYY-MM-DD" ytPrice: number; dailyReturn: number; // % hasData: boolean; } export async function fetchDailyReturns(id: number, year: number, month: number): Promise { try { const response = await fetch( `${API_BASE_URL}/fundmarket/products/${id}/daily-returns?year=${year}&month=${month}`, { cache: 'no-store' } ); if (!response.ok) throw new Error('Failed to fetch daily returns'); const data = await response.json(); if (!data.success) throw new Error(data.error || 'Failed to fetch daily returns'); return data.data ?? []; } catch (error: unknown) { console.error('Error fetching daily returns:', error); return []; } } // History point for APY/Price chart export interface HistoryPoint { time: string; // "MM/DD HH:mm" apy: number; // APY % price: number; // YT token price in USDC } // Fetch hourly APY/price history for chart export async function fetchProductHistory(id: number): Promise { try { const response = await fetch(`${API_BASE_URL}/fundmarket/products/${id}/history`, { cache: 'no-store', }); if (!response.ok) throw new Error('Failed to fetch history'); const data = await response.json(); if (!data.success) throw new Error(data.error || 'Failed to fetch history'); return data.data ?? []; } catch (error: unknown) { console.error('Error fetching product history:', error); return []; } } // Fetch product detail by ID (detailed format) export async function fetchProductDetail(id: number): Promise { try { const response = await fetch(`${API_BASE_URL}/fundmarket/products/${id}`, { cache: 'no-store', }); if (!response.ok) { throw new Error('Failed to fetch product detail'); } const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to fetch product detail'); } return data.data; } catch (error: unknown) { console.error('Error fetching product detail:', error); return null; } }