1use reqwest::Client;
2use serde::{Deserialize, Serialize};
3use serde_with::{serde_as, DisplayFromStr};
4use std::collections::HashMap;
5use std::error::Error;
6
7#[serde_with::skip_serializing_none]
8#[derive(Serialize, Deserialize, Debug)]
9#[serde(rename_all = "camelCase")]
10pub struct PriceResponse {
11 pub data: HashMap<String, PriceData>,
12 pub time_taken: f64,
13}
14
15#[serde_as]
16#[serde_with::skip_serializing_none]
17#[derive(Serialize, Deserialize, Debug)]
18pub struct PriceData {
19 pub id: String,
20 #[serde_as(as = "DisplayFromStr")]
21 pub price: f64,
22}
23
24pub async fn fetch_token_price(
25 mint: String,
26 client: &Client,
27) -> Result<f64, Box<dyn Error>> {
28 let url = format!("https://api.jup.ag/price/v2?ids={}", mint);
29 let res = client
30 .get(url)
31 .header("accept", "application/json")
32 .send()
33 .await?;
34 let data = res.json::<PriceResponse>().await?;
35 Ok(data.data.get(&mint).unwrap().price)
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[tokio::test]
43 pub async fn test_fetch_token_price() {
44 let res = fetch_token_price(
45 "Cn5Ne1vmR9ctMGY9z5NC71A3NYFvopjXNyxYtfVYpump".to_string(),
46 &reqwest::Client::new(),
47 )
48 .await;
49 println!("{:?}", res);
50 assert!(res.is_ok());
51 }
52}