import { CRYPTO_ASSETS } from "@/lib/assets"; export interface CryptoRateResult { usdPrices: Record; updatedAt: string; } const COINGECKO_BASE_URL = "https://api.coingecko.com/api/v3"; function buildCoinGeckoHeaders(): HeadersInit { const headers: Record = { accept: "application/json" }; const proApiKey = process.env.COINGECKO_PRO_API_KEY?.trim(); const demoApiKey = process.env.COINGECKO_DEMO_API_KEY?.trim(); const genericApiKey = process.env.COINGECKO_API_KEY?.trim(); const genericApiKeyType = process.env.COINGECKO_API_KEY_TYPE?.trim().toLowerCase() ?? "demo"; if (proApiKey) { headers["x-cg-pro-api-key"] = proApiKey; return headers; } if (demoApiKey) { headers["x-cg-demo-api-key"] = demoApiKey; return headers; } if (genericApiKey) { if (genericApiKeyType === "pro") { headers["x-cg-pro-api-key"] = genericApiKey; } else { headers["x-cg-demo-api-key"] = genericApiKey; } } return headers; } export async function fetchCryptoData(): Promise { const ids = CRYPTO_ASSETS.map((asset) => asset.providerId).filter( (id): id is string => Boolean(id) ); const url = `${COINGECKO_BASE_URL}/simple/price?ids=${encodeURIComponent( ids.join(",") )}&vs_currencies=usd&include_last_updated_at=true`; const response = await fetch(url, { next: { revalidate: 60 }, headers: buildCoinGeckoHeaders() }); if (!response.ok) { throw new Error(`Unable to load crypto rates (${response.status})`); } const payload = (await response.json()) as Record< string, { usd?: number; last_updated_at?: number; } >; const usdPrices: Record = {}; let mostRecentUpdate = 0; for (const asset of CRYPTO_ASSETS) { if (!asset.providerId) { continue; } const entry = payload[asset.providerId]; if (!entry?.usd || entry.usd <= 0) { continue; } usdPrices[asset.code] = entry.usd; if (entry.last_updated_at && entry.last_updated_at > mostRecentUpdate) { mostRecentUpdate = entry.last_updated_at; } } return { usdPrices, updatedAt: mostRecentUpdate > 0 ? new Date(mostRecentUpdate * 1000).toISOString() : new Date().toISOString() }; }