// Price fetcher utility for getting current market prices export class PriceFetcher { private static cache = new Map() private static readonly CACHE_DURATION = 30000 // 30 seconds static async getCurrentPrice(symbol: string): Promise { const cacheKey = symbol.toUpperCase() const cached = this.cache.get(cacheKey) // Return cached price if recent if (cached && Date.now() - cached.timestamp < this.CACHE_DURATION) { return cached.price } try { // Try multiple price sources let price = await this.fetchFromCoinGecko(symbol) if (!price) { price = await this.fetchFromCoinCap(symbol) } if (!price) { price = await this.fetchFromBinance(symbol) } if (price) { this.cache.set(cacheKey, { price, timestamp: Date.now() }) return price } return 0 } catch (error) { console.error('Error fetching price:', error) return cached?.price || 0 } } private static async fetchFromCoinGecko(symbol: string): Promise { try { const coinId = this.getCoinGeckoId(symbol) if (!coinId) return null const response = await fetch( `https://api.coingecko.com/api/v3/simple/price?ids=${coinId}&vs_currencies=usd`, { cache: 'no-cache' } ) if (!response.ok) return null const data = await response.json() return data[coinId]?.usd || null } catch (error) { console.error('CoinGecko fetch error:', error) return null } } private static async fetchFromCoinCap(symbol: string): Promise { try { const asset = this.getCoinCapAsset(symbol) if (!asset) return null const response = await fetch( `https://api.coincap.io/v2/assets/${asset}`, { cache: 'no-cache' } ) if (!response.ok) return null const data = await response.json() return parseFloat(data.data?.priceUsd) || null } catch (error) { console.error('CoinCap fetch error:', error) return null } } private static async fetchFromBinance(symbol: string): Promise { try { const binanceSymbol = this.getBinanceSymbol(symbol) if (!binanceSymbol) return null const response = await fetch( `https://api.binance.com/api/v3/ticker/price?symbol=${binanceSymbol}`, { cache: 'no-cache' } ) if (!response.ok) return null const data = await response.json() return parseFloat(data.price) || null } catch (error) { console.error('Binance fetch error:', error) return null } } private static getCoinGeckoId(symbol: string): string | null { const mapping: Record = { 'BTCUSD': 'bitcoin', 'ETHUSD': 'ethereum', 'SOLUSD': 'solana', 'SUIUSD': 'sui', 'ADAUSD': 'cardano', 'DOTUSD': 'polkadot', 'AVAXUSD': 'avalanche-2', 'LINKUSD': 'chainlink', 'MATICUSD': 'matic-network', 'UNIUSD': 'uniswap' } return mapping[symbol.toUpperCase()] || null } private static getCoinCapAsset(symbol: string): string | null { const mapping: Record = { 'BTCUSD': 'bitcoin', 'ETHUSD': 'ethereum', 'SOLUSD': 'solana', 'SUIUSD': 'sui', 'ADAUSD': 'cardano', 'DOTUSD': 'polkadot', 'AVAXUSD': 'avalanche', 'LINKUSD': 'chainlink', 'MATICUSD': 'polygon', 'UNIUSD': 'uniswap' } return mapping[symbol.toUpperCase()] || null } private static getBinanceSymbol(symbol: string): string | null { const mapping: Record = { 'BTCUSD': 'BTCUSDT', 'ETHUSD': 'ETHUSDT', 'SOLUSD': 'SOLUSDT', 'SUIUSD': 'SUIUSDT', 'ADAUSD': 'ADAUSDT', 'DOTUSD': 'DOTUSDT', 'AVAXUSD': 'AVAXUSDT', 'LINKUSD': 'LINKUSDT', 'MATICUSD': 'MATICUSDT', 'UNIUSD': 'UNIUSDT' } return mapping[symbol.toUpperCase()] || null } static clearCache(): void { this.cache.clear() } } export default PriceFetcher