Ver Fonte

fix: 使用 Jupiter Price API v3 替代已弃用的 price.jup.ag

- jupiter: 新增 getTokenPricesFromJupiter,请求 api.jup.ag/price/v3
- lp-copy / lp-copy/calculate / lp-index/lp-add: ByReal 价格失败时回退到 Jupiter v3
- .env.example: 增加 JUPITER_PRICE_API_URL 可选说明

Co-authored-by: Cursor <cursoragent@cursor.com>
lushdog@outlook.com há 1 mês atrás
pai
commit
abb76a03a9

+ 2 - 0
.env.example

@@ -9,6 +9,8 @@ SOL_ENDPOINT=https://lb.drpc.live/solana/YOUR_API_KEY
 SOL_SECRET_KEY=your_base58_encoded_secret_key
 
 JUPITER_API_KEY=your_jupiter_api_key_here
+# 可选:Jupiter 价格 API(默认 https://api.jup.ag/price/v3,勿使用已弃用的 price.jup.ag)
+# JUPITER_PRICE_API_URL=https://api.jup.ag/price/v3
 
 # Basic Auth 配置
 # 生成 htpasswd 文件:

+ 14 - 0
src/app/api/lp-copy/calculate/route.ts

@@ -4,6 +4,7 @@ import BN from 'bn.js'
 import { Decimal } from 'decimal.js'
 import { chain } from '@/lib/config'
 import { TickMath } from '@/lib/byreal-clmm-sdk/src/instructions/utils/tickMath'
+import { getTokenPricesFromJupiter } from '@/lib/jupiter'
 
 export async function POST(request: NextRequest): Promise<NextResponse> {
 	const body = await request.json()
@@ -122,6 +123,19 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
 			console.warn('Failed to fetch prices from API:', error)
 		}
 
+		// ByReal 未返回价格时,尝试 Jupiter Price API v3(避免已弃用的 price.jup.ag)
+		if (!priceFromApi) {
+			const jupiterPrices = await getTokenPricesFromJupiter(
+				tokenAAddress,
+				tokenBAddress
+			)
+			if (jupiterPrices) {
+				tokenAPriceUsd = jupiterPrices.tokenAPriceUsd
+				tokenBPriceUsd = jupiterPrices.tokenBPriceUsd
+				priceFromApi = true
+			}
+		}
+
 		// 如果 API 获取失败,使用稳定币逻辑
 		if (!priceFromApi) {
 			if (isTokenBStable) {

+ 22 - 1
src/app/api/lp-copy/route.ts

@@ -10,7 +10,11 @@ import { Decimal } from 'decimal.js'
 import bs58 from 'bs58'
 import { chain } from '@/lib/config'
 import { TickMath } from '@/lib/byreal-clmm-sdk/src/instructions/utils/tickMath'
-import { ensureSufficientBalances, getTokenBalance } from '@/lib/jupiter'
+import {
+	ensureSufficientBalances,
+	getTokenBalance,
+	getTokenPricesFromJupiter,
+} from '@/lib/jupiter'
 
 async function copyLPPosition(
 	request: NextRequest,
@@ -134,6 +138,23 @@ async function copyLPPosition(
 			console.warn('Failed to fetch prices from API:', error)
 		}
 
+		// ByReal 未返回价格时,尝试 Jupiter Price API v3(避免已弃用的 price.jup.ag)
+		if (!priceFromApi) {
+			const jupiterPrices = await getTokenPricesFromJupiter(
+				tokenAAddress,
+				tokenBAddress
+			)
+			if (jupiterPrices) {
+				tokenAPriceUsd = jupiterPrices.tokenAPriceUsd
+				tokenBPriceUsd = jupiterPrices.tokenBPriceUsd
+				priceFromApi = true
+				console.log('Using prices from Jupiter Price API v3:', {
+					tokenAPriceUsd,
+					tokenBPriceUsd,
+				})
+			}
+		}
+
 		// 如果 API 获取失败,使用稳定币逻辑
 		if (!priceFromApi) {
 			if (isTokenBStable) {

+ 18 - 0
src/app/api/lp-index/lp-add/route.ts

@@ -4,6 +4,7 @@ import BN from 'bn.js'
 import { Decimal } from 'decimal.js'
 import bs58 from 'bs58'
 import { chain } from '@/lib/config'
+import { getTokenPricesFromJupiter } from '@/lib/jupiter'
 
 export async function POST(request: NextRequest) {
 	try {
@@ -92,6 +93,23 @@ export async function POST(request: NextRequest) {
 			console.warn('Failed to fetch prices from API:', error)
 		}
 
+		// ByReal 未返回价格时,尝试 Jupiter Price API v3(避免已弃用的 price.jup.ag)
+		if (!priceFromApi && tokenAAddress && tokenBAddress) {
+			const jupiterPrices = await getTokenPricesFromJupiter(
+				tokenAAddress,
+				tokenBAddress
+			)
+			if (jupiterPrices) {
+				tokenAPriceUsd = jupiterPrices.tokenAPriceUsd
+				tokenBPriceUsd = jupiterPrices.tokenBPriceUsd
+				priceFromApi = true
+				console.log('Using prices from Jupiter Price API v3:', {
+					tokenAPriceUsd,
+					tokenBPriceUsd,
+				})
+			}
+		}
+
 		// 如果 API 获取失败,使用稳定币逻辑或默认逻辑
 		if (!priceFromApi) {
 			if (isTokenBStable) {

+ 37 - 0
src/lib/jupiter.ts

@@ -91,6 +91,43 @@ function getJupiterHeaders(): Record<string, string> {
 	return headers
 }
 
+/** Jupiter Price API v3 返回的单个代币价格(price.jup.ag 已弃用,请用 api.jup.ag/price/v3) */
+const JUPITER_PRICE_API_URL =
+	process.env.JUPITER_PRICE_API_URL || 'https://api.jup.ag/price/v3'
+
+/**
+ * 从 Jupiter Price API v3 获取代币 USD 价格(备用,避免使用已弃用的 price.jup.ag)
+ * @returns 成功时返回 { tokenAPriceUsd, tokenBPriceUsd },失败返回 null
+ */
+export async function getTokenPricesFromJupiter(
+	mintA: string,
+	mintB: string
+): Promise<{ tokenAPriceUsd: number; tokenBPriceUsd: number } | null> {
+	try {
+		const ids = [mintA, mintB].filter((m, i, arr) => arr.indexOf(m) === i).join(',')
+		const data = await ky
+			.get(`${JUPITER_PRICE_API_URL}?ids=${ids}`, {
+				headers: getJupiterHeaders(),
+				timeout: 10000,
+			})
+			.json<Record<string, { price?: number; usdPrice?: number }>>()
+		const priceOf = (mint: string): number | undefined => {
+			const row = data[mint]
+			if (!row) return undefined
+			return row.usdPrice ?? row.price
+		}
+		const pa = priceOf(mintA)
+		const pb = priceOf(mintB)
+		if (pa != null && pa > 0 && pb != null && pb > 0) {
+			return { tokenAPriceUsd: pa, tokenBPriceUsd: pb }
+		}
+		return null
+	} catch (error) {
+		console.warn('Jupiter price v3 fetch failed:', error)
+		return null
+	}
+}
+
 /**
  * 从 Jupiter API 获取 quote
  * @param restrictIntermediate - 为 false 时允许更多中间代币路由(用于 NO_ROUTES_FOUND 时重试)