Procházet zdrojové kódy

fix: add DexScreener fallback for token price fetching

zhangchunrui před 1 měsícem
rodič
revize
b96b19ed7a
1 změnil soubory, kde provedl 58 přidání a 4 odebrání
  1. 58 4
      src/solana/jupiter.ts

+ 58 - 4
src/solana/jupiter.ts

@@ -105,16 +105,70 @@ export class JupiterSwapper {
 	}
 
 	async getTokenPrices(tokenAddresses: string[]): Promise<Record<string, { price?: number; symbol?: string }>> {
+		const result: Record<string, { price?: number; symbol?: string }> = {}
+
+		// 1. 先尝试 Jupiter Price API
 		try {
 			const ids = tokenAddresses.join(',')
 			const response = await fetch(`https://api.jup.ag/price/v2?ids=${ids}`, {
 				headers: this.getHeaders(),
 			})
-			const data = (await response.json()) as { data?: Record<string, { price?: number; symbol?: string }> }
-			return data.data || {}
+			if (response.ok) {
+				const data = (await response.json()) as { data?: Record<string, { price?: number; symbol?: string }> }
+				if (data.data) {
+					Object.assign(result, data.data)
+				}
+			}
 		} catch (error) {
-			console.error('Error fetching token prices:', error)
-			return {}
+			console.error('[Jupiter] Error fetching prices:', error)
+		}
+
+		// 2. 对 Jupiter 没有返回价格的代币,尝试 DexScreener
+		const missingMints = tokenAddresses.filter((mint) => !result[mint]?.price)
+		if (missingMints.length > 0) {
+			try {
+				for (const mint of missingMints) {
+					const dsPrice = await this.getDexScreenerPrice(mint)
+					if (dsPrice) {
+						result[mint] = dsPrice
+					}
+				}
+			} catch (error) {
+				console.error('[DexScreener] Error fetching prices:', error)
+			}
+		}
+
+		return result
+	}
+
+	private async getDexScreenerPrice(mint: string): Promise<{ price?: number; symbol?: string } | null> {
+		try {
+			const response = await fetch(`https://api.dexscreener.com/latest/dex/tokens/${mint}`)
+			if (!response.ok) return null
+
+			const data = (await response.json()) as {
+				pairs?: Array<{
+					priceUsd?: string
+					baseToken?: { symbol?: string }
+					liquidity?: { usd?: number }
+				}>
+			}
+
+			if (data.pairs && data.pairs.length > 0) {
+				// 选择流动性最高的交易对
+				const sortedPairs = data.pairs.sort((a, b) => (b.liquidity?.usd || 0) - (a.liquidity?.usd || 0))
+				const bestPair = sortedPairs[0]
+				const price = parseFloat(bestPair.priceUsd || '0')
+				if (price > 0) {
+					return {
+						price,
+						symbol: bestPair.baseToken?.symbol,
+					}
+				}
+			}
+			return null
+		} catch {
+			return null
 		}
 	}