ferrox_actions/
dexscreener.rs

1pub mod client;
2
3use crate::{
4    action::{ActionBuilder, ActionGroup, FunctionAction},
5    AgentState,
6};
7use client::DexScreenerClient;
8use serde::Deserialize;
9use std::sync::Arc;
10
11// Parameter structs for each action
12#[derive(Debug, Deserialize)]
13pub struct TokenProfilesParams {} // Empty struct for no params endpoint
14
15#[derive(Debug, Deserialize)]
16pub struct TokenOrdersParams {
17    chain_id: String,
18    token_address: String,
19}
20
21#[derive(Debug, Deserialize)]
22pub struct TokenBoostsParams {} // Empty struct for no params endpoint
23
24#[derive(Debug, Deserialize)]
25pub struct TokenBoostsTopParams {} // Empty struct for no params endpoint
26
27#[derive(Debug, Deserialize)]
28pub struct TokenPairsParams {
29    chain_id: String,
30    token_address: String,
31}
32
33#[derive(Debug, Deserialize)]
34pub struct TokensParams {
35    chain_id: String,
36    token_addresses: String, // Comma-separated list of addresses
37}
38
39#[derive(Debug, Deserialize)]
40pub struct SearchPairsParams {
41    query: String,
42}
43
44#[derive(Debug, Deserialize)]
45pub struct PairsParams {
46    chain_id: String,
47    pair_id: String,
48}
49
50// Action group that contains all DexScreener actions
51pub struct DexScreenerActionGroup<S: Send + Sync + Clone + 'static> {
52    actions: Vec<Arc<FunctionAction<S>>>,
53}
54
55impl<S: Send + Sync + Clone + 'static> ActionGroup<S> for DexScreenerActionGroup<S> {
56    fn actions(&self) -> &[Arc<FunctionAction<S>>] {
57        &self.actions
58    }
59}
60
61impl<S: Send + Sync + Clone + 'static> DexScreenerActionGroup<S> {
62    pub fn new() -> Self {
63        let mut actions = Vec::new();
64
65        // Add get latest token profiles action
66        {
67            async fn get_token_profiles<S: Send + Sync + Clone + 'static>(
68                _params: TokenProfilesParams,
69                _send_state: serde_json::Value,
70                _state: AgentState<S>,
71            ) -> Result<String, String> {
72                let client = DexScreenerClient::new();
73                client.get_token_profiles().await
74            }
75
76            let action =
77                ActionBuilder::<_, _, _, _>::new("get_token_profiles", get_token_profiles, None)
78                    .description("Get the latest token profiles")
79                    .build();
80
81            actions.push(Arc::new(action));
82        }
83
84        // Add check token orders action
85        {
86            async fn get_token_orders<S: Send + Sync + Clone + 'static>(
87                params: TokenOrdersParams,
88                _send_state: serde_json::Value,
89                _state: AgentState<S>,
90            ) -> Result<String, String> {
91                let client = DexScreenerClient::new();
92                client
93                    .get_token_orders(params.chain_id, params.token_address)
94                    .await
95            }
96
97            let action =
98                ActionBuilder::<_, _, _, _>::new("get_token_orders", get_token_orders, None)
99                    .description("Check orders paid for of token")
100                    .parameter("chain_id", "The chain ID (e.g. solana)", "string", true)
101                    .parameter("token_address", "Token's address", "string", true)
102                    .build();
103
104            actions.push(Arc::new(action));
105        }
106
107        // Add get latest token boosts action
108        {
109            async fn get_token_boosts<S: Send + Sync + Clone + 'static>(
110                _params: TokenBoostsParams,
111                _send_state: serde_json::Value,
112                _state: AgentState<S>,
113            ) -> Result<String, String> {
114                let client = DexScreenerClient::new();
115                client.get_token_boosts().await
116            }
117
118            let action =
119                ActionBuilder::<_, _, _, _>::new("get_token_boosts", get_token_boosts, None)
120                    .description("Get the latest boosted tokens")
121                    .build();
122
123            actions.push(Arc::new(action));
124        }
125
126        // Add get top token boosts action
127        {
128            async fn get_token_boosts_top<S: Send + Sync + Clone + 'static>(
129                _params: TokenBoostsTopParams,
130                _send_state: serde_json::Value,
131                _state: AgentState<S>,
132            ) -> Result<String, String> {
133                let client = DexScreenerClient::new();
134                client.get_token_boosts_top().await
135            }
136
137            let action = ActionBuilder::<_, _, _, _>::new(
138                "get_token_boosts_top",
139                get_token_boosts_top,
140                None,
141            )
142            .description("Get the tokens with most active boosts")
143            .build();
144
145            actions.push(Arc::new(action));
146        }
147
148        // Add get token pairs action
149        {
150            async fn get_token_pairs<S: Send + Sync + Clone + 'static>(
151                params: TokenPairsParams,
152                _send_state: serde_json::Value,
153                _state: AgentState<S>,
154            ) -> Result<String, String> {
155                let client = DexScreenerClient::new();
156                client
157                    .get_token_pairs(params.chain_id, params.token_address)
158                    .await
159            }
160
161            let action = ActionBuilder::<_, _, _, _>::new("get_token_pairs", get_token_pairs, None)
162                .description("Get the pools of a given token address")
163                .parameter("chain_id", "The chain ID (e.g. solana)", "string", true)
164                .parameter("token_address", "Token's address", "string", true)
165                .build();
166
167            actions.push(Arc::new(action));
168        }
169
170        // Add get tokens action
171        {
172            async fn get_tokens<S: Send + Sync + Clone + 'static>(
173                params: TokensParams,
174                _send_state: serde_json::Value,
175                _state: AgentState<S>,
176            ) -> Result<String, String> {
177                let client = DexScreenerClient::new();
178                client
179                    .get_tokens(params.chain_id, params.token_addresses)
180                    .await
181            }
182
183            let action = ActionBuilder::<_, _, _, _>::new("get_tokens", get_tokens, None)
184                .description("Get one or multiple pairs by token address")
185                .parameter("chain_id", "The chain ID (e.g. solana)", "string", true)
186                .parameter(
187                    "token_addresses",
188                    "Comma-separated list of token addresses (up to 30)",
189                    "string",
190                    true,
191                )
192                .build();
193
194            actions.push(Arc::new(action));
195        }
196
197        // Add search pairs action
198        {
199            async fn search_pairs<S: Send + Sync + Clone + 'static>(
200                params: SearchPairsParams,
201                _send_state: serde_json::Value,
202                _state: AgentState<S>,
203            ) -> Result<String, String> {
204                let client = DexScreenerClient::new();
205                client.search_pairs(params.query).await
206            }
207
208            let action = ActionBuilder::<_, _, _, _>::new("search_pairs", search_pairs, None)
209                .description("Search for pairs or tokens matching query")
210                .parameter("query", "Search query", "string", true)
211                .build();
212
213            actions.push(Arc::new(action));
214        }
215
216        // Add get pairs action
217        {
218            async fn get_pairs<S: Send + Sync + Clone + 'static>(
219                params: PairsParams,
220                _send_state: serde_json::Value,
221                _state: AgentState<S>,
222            ) -> Result<String, String> {
223                let client = DexScreenerClient::new();
224                client.get_pairs(params.chain_id, params.pair_id).await
225            }
226
227            let action = ActionBuilder::<_, _, _, _>::new("get_pairs", get_pairs, None)
228                .description("Get one or multiple pairs by chain and pair address")
229                .parameter("chain_id", "The chain ID (e.g. solana)", "string", true)
230                .parameter("pair_id", "Pair ID", "string", true)
231                .build();
232
233            actions.push(Arc::new(action));
234        }
235
236        Self { actions }
237    }
238}