Files
assetx/webapp/lib/api/fundmarket.ts

244 lines
5.9 KiB
TypeScript
Raw Permalink Normal View History

// 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<Product[]> {
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<StatsData[]> {
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<Product | null> {
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<DailyReturnPoint[]> {
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<HistoryPoint[]> {
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<ProductDetail | null> {
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;
}
}