@@ -2,57 +2,46 @@ import { PublicKey } from '@solana/web3.js'
22import { useQuery } from '@tanstack/react-query'
33import queryClient from './queryClient'
44
5- const URL = 'https://lite-api.jup.ag/price/v2 '
5+ const PRICE_URL = 'https://lite-api.jup.ag/price/v3 '
66
7- /* example query
7+ /* example query - Price API V3
88# Unit price of 1 JUP & 1 SOL based on the Derived Price in USDC
9- https://api.jup.ag/price/v2 ?ids=JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN,So11111111111111111111111111111111111111112
9+ https://lite- api.jup.ag/price/v3 ?ids=JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN,So11111111111111111111111111111111111111112
1010
1111{
12- "data": {
13- "So11111111111111111111111111111111111111112": {
14- "id": "So11111111111111111111111111111111111111112",
15- "type": "derivedPrice",
16- "price": "133.890945000"
17- },
18- "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN": {
19- "id": "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN",
20- "type": "derivedPrice",
21- "price": "0.751467"
22- }
23- },
24- "timeTaken": 0.00395219
12+ "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN": {
13+ "usdPrice": 0.4056018512541055,
14+ "blockId": 348004026,
15+ "decimals": 6,
16+ "priceChange24h": 0.5292887924920519
17+ },
18+ "So11111111111111111111111111111111111111112": {
19+ "usdPrice": 147.4789340738336,
20+ "blockId": 348004023,
21+ "decimals": 9,
22+ "priceChange24h": 1.2907622140620008
23+ }
2524}
2625*/
27- /* example intentionally broken query
28- curl -X 'GET' 'https://api.jup.ag/price/v2?ids=So11111111111111111111111111111111111111112&showExtraInfo=true'
29- {
30- "data": {
31- "So11111111111111111111111111111111111111112": {
32- "id": "So11111111111111111111111111111111111111112",
33- "type": "derivedPrice",
34- "price": "134.170633378"
35- },
36- "8agCopCHWdpj7mHk3JUWrzt8pHAxMiPX5hLVDJh9TXWv": null
37- },
38- "timeTaken": 0.003186833
26+
27+ // Price API V3 Response
28+ type PriceV3Response = {
29+ usdPrice : number
30+ blockId : number
31+ decimals : number
32+ priceChange24h ?: number
3933}
40- */
4134
35+ // Internal Price format (for backwards compatibility)
4236type Price = {
4337 id : string // pubkey,
4438 // price is in USD
4539 price : number
46- // removed in v2 API
47- // mintSymbol: string
48- // vsToken: string // pubkey,
49- // vsTokenSymbol: string
50- }
51- type Response = {
52- data : Record < string , Price > //uses whatever you input (so, pubkey OR symbol). no entry if data not found
53- timeTaken : number
5440}
5541
42+ // V3 API returns direct object mapping, not wrapped in "data"
43+ type Response = Record < string , PriceV3Response | null >
44+
5645function * chunks < T > ( arr : T [ ] , n : number ) : Generator < T [ ] , void > {
5746 for ( let i = 0 ; i < arr . length ; i += n ) {
5847 yield arr . slice ( i , i + n )
@@ -69,12 +58,20 @@ export const jupiterPriceQueryKeys = {
6958}
7059
7160const jupQueryFn = async ( mint : PublicKey ) => {
72- const x = await fetch ( `${ URL } ?ids=${ mint ?. toString ( ) } ` )
61+ const x = await fetch ( `${ PRICE_URL } ?ids=${ mint ?. toString ( ) } ` )
7362 const response = ( await x . json ( ) ) as Response
74- const result = response . data [ mint . toString ( ) ]
75- return result !== undefined
76- ? ( { found : true , result } as const )
77- : ( { found : false , result : undefined } as const )
63+ const priceData = response [ mint . toString ( ) ]
64+
65+ // Convert V3 response to internal format
66+ if ( priceData && priceData . usdPrice !== undefined ) {
67+ const result : Price = {
68+ id : mint . toString ( ) ,
69+ price : priceData . usdPrice ,
70+ }
71+ return { found : true , result } as const
72+ }
73+
74+ return { found : false , result : undefined } as const
7875}
7976
8077export const useJupiterPriceByMintQuery = ( mint : PublicKey | undefined ) => {
@@ -111,19 +108,32 @@ export const useJupiterPricesByMintsQuery = (mints: PublicKey[]) => {
111108 enabled,
112109 queryKey : jupiterPriceQueryKeys . byMints ( dedupedMints ) ,
113110 queryFn : async ( ) => {
114- const batches = [ ...chunks ( dedupedMints , 100 ) ]
111+ const batches = [ ...chunks ( dedupedMints , 50 ) ] // V3 limits to 50 ids per request
115112 const responses = await Promise . all (
116113 batches . map ( async ( batch ) => {
117- const x = await fetch ( `${ URL } ?ids=${ batch . join ( ',' ) } ` )
114+ const x = await fetch ( `${ PRICE_URL } ?ids=${ batch . join ( ',' ) } ` )
118115 const response = ( await x . json ( ) ) as Response
119116 return response
120117 } ) ,
121118 )
122- const data = responses . reduce (
123- ( acc , next ) => ( { ...acc , ...next . data } ) ,
124- { } as Response [ 'data' ] ,
119+
120+ // Merge all batch responses
121+ const mergedResponse = responses . reduce (
122+ ( acc , next ) => ( { ...acc , ...next } ) ,
123+ { } as Response ,
125124 )
126125
126+ // Convert V3 response to internal Price format
127+ const data : Record < string , Price > = { }
128+ Object . entries ( mergedResponse ) . forEach ( ( [ mintAddress , priceData ] ) => {
129+ if ( priceData && priceData . usdPrice !== undefined ) {
130+ data [ mintAddress ] = {
131+ id : mintAddress ,
132+ price : priceData . usdPrice ,
133+ }
134+ }
135+ } )
136+
127137 //override chai price if its broken
128138 const chaiMint = '3jsFX1tx2Z8ewmamiwSU851GzyzM2DJMq7KWW5DM8Py3'
129139 const chaiData = data [ chaiMint ]
@@ -155,9 +165,35 @@ export const getJupiterPricesByMintStrings = async (mints: string[]) => {
155165 const deduped = new Set ( mints )
156166 const dedupedMints = Array . from ( deduped )
157167 try {
158- const x = await fetch ( `${ URL } ?ids=${ dedupedMints . join ( ',' ) } ` )
159- const response = ( await x . json ( ) ) as Response
160- const data = response . data
168+ // V3 limits to 50 ids per request
169+ const batches : string [ ] [ ] = [ ]
170+ for ( let i = 0 ; i < dedupedMints . length ; i += 50 ) {
171+ batches . push ( dedupedMints . slice ( i , i + 50 ) )
172+ }
173+
174+ const responses = await Promise . all (
175+ batches . map ( async ( batch ) => {
176+ const x = await fetch ( `${ PRICE_URL } ?ids=${ batch . join ( ',' ) } ` )
177+ return ( await x . json ( ) ) as Response
178+ } ) ,
179+ )
180+
181+ // Merge all batch responses
182+ const mergedResponse = responses . reduce (
183+ ( acc , next ) => ( { ...acc , ...next } ) ,
184+ { } as Response ,
185+ )
186+
187+ // Convert V3 response to internal Price format
188+ const data : Record < string , Price > = { }
189+ Object . entries ( mergedResponse ) . forEach ( ( [ mintAddress , priceData ] ) => {
190+ if ( priceData && priceData . usdPrice !== undefined ) {
191+ data [ mintAddress ] = {
192+ id : mintAddress ,
193+ price : priceData . usdPrice ,
194+ }
195+ }
196+ } )
161197
162198 //override chai price if its broken
163199 const chaiMint = '3jsFX1tx2Z8ewmamiwSU851GzyzM2DJMq7KWW5DM8Py3'
@@ -175,3 +211,4 @@ export const getJupiterPricesByMintStrings = async (mints: string[]) => {
175211 throw error
176212 }
177213}
214+
0 commit comments