1use crate::{
2 action::{ActionBuilder, ActionGroup, FunctionAction},
3 AgentState,
4};
5use serde::{Deserialize, Serialize};
6use std::sync::Arc;
7
8#[derive(Debug, Deserialize, Serialize)]
9pub struct GmgnKlineResponse {
10 pub code: i32,
11 pub msg: String,
12 pub data: Vec<KlineData>,
13}
14
15#[derive(Debug, Deserialize, Serialize)]
16pub struct KlineData {
17 pub open: String,
18 pub high: String,
19 pub low: String,
20 pub close: String,
21 pub volume: String,
22 pub time: String,
23}
24
25pub async fn fetch_k_line_data_from_gmgn(
26 token_address: String,
27 time_from: i64,
28 time_to: i64,
29) -> Result<GmgnKlineResponse, String> {
30 let client = reqwest::Client::new();
31
32 let url = format!(
33 "https://www.gmgn.cc/defi/quotation/v1/tokens/kline/sol/{}?resolution=1h&from={}&to={}",
34 token_address, time_from, time_to
35 );
36 println!("Fetching kline data from GMGN: {}", url);
37
38 match client.get(&url).send().await {
39 Ok(response) => match response.json::<GmgnKlineResponse>().await {
40 Ok(kline_data) => Ok(kline_data),
41 Err(e) => {
42 println!("Failed to parse GMGN response: {}", e);
43 Err("Error parsing kline data".to_string())
44 }
45 },
46 Err(e) => {
47 println!("Failed to fetch from GMGN: {}", e);
48 Err("Failed to fetch kline data".to_string())
49 }
50 }
51}
52
53#[derive(Debug, Deserialize)]
54pub struct KlineDataParams {
55 token_address: String,
56 time_from: i64,
57 time_to: i64,
58}
59
60pub struct GmgnActionGroup<S: Send + Sync + Clone + 'static> {
61 actions: Vec<Arc<FunctionAction<S>>>,
62}
63
64impl<S: Send + Sync + Clone + 'static> ActionGroup<S> for GmgnActionGroup<S> {
65 fn actions(&self) -> &[Arc<FunctionAction<S>>] {
66 &self.actions
67 }
68}
69
70impl<S: Send + Sync + Clone + 'static> GmgnActionGroup<S> {
71 pub fn new() -> Self {
72 let mut actions = Vec::new();
73 {
75 async fn get_kline_data<S: Send + Sync + Clone + 'static>(
76 params: KlineDataParams,
77 _send_state: serde_json::Value,
78 _state: AgentState<S>,
79 ) -> Result<String, String> {
80 let kline_data = fetch_k_line_data_from_gmgn(
81 params.token_address,
82 params.time_from,
83 params.time_to,
84 )
85 .await?;
86
87 serde_json::to_string(&kline_data)
88 .map_err(|e| format!("Failed to serialize GMGN response: {}", e))
89 }
90
91 let action = ActionBuilder::<_, _, _, _>::new(
92 "get_gmgn_kline_data",
93 get_kline_data,
94 None,
95 )
96 .description(
97 "Get OHLCV kline data for a Solana token from GMGN (alternative to Birdeye). Use this if the birdeye response is empty or errored",
98 )
99 .parameter("token_address", "Solana token address", "string", true)
100 .parameter("time_from", "Start timestamp (Unix)", "integer", true)
101 .parameter("time_to", "End timestamp (Unix)", "integer", true)
102 .build();
103
104 actions.push(Arc::new(action));
105 }
106
107 Self { actions }
108 }
109}