solagent_plugin_birdeye/
lib.rs

1use anyhow::Result;
2use solagent_core::SolanaAgentKit;
3
4mod primitive;
5pub use primitive::*;
6
7/// Get overview of a token.
8///
9/// # Parameters
10///
11/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
12///
13/// - `address`: Address of a token
14///
15/// # Returns
16///
17/// A `Result` TokenOverviewResponse
18pub async fn get_token_overview(agent: &SolanaAgentKit, address: &str) -> Result<TokenOverviewResponse> {
19    let api_key = agent
20        .config
21        .birdeye_api_key
22        .as_ref()
23        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
24
25    let client = reqwest::Client::new();
26    let url = format!("{}/defi/token_overview", BIRDEYE_URL);
27
28    let resp = client
29        .get(url)
30        .query(&[("address", address)])
31        .header("X-API-KEY", api_key)
32        .header("accept", "application/json")
33        .header("x-chain", "solana")
34        .send()
35        .await?
36        .json::<TokenOverviewResponse>()
37        .await?;
38
39    Ok(resp)
40}
41
42/// Get market data of single token
43///
44/// # Parameters
45///
46/// * `agent` - An instance of SolanaAgentKit
47///
48/// - `address`: Address of a token
49///
50/// # Returns
51///
52/// A `Result` TokenMarketDataResponse
53pub async fn get_market_data(agent: &SolanaAgentKit, address: &str) -> Result<TokenMarketDataResponse> {
54    let api_key = agent
55        .config
56        .birdeye_api_key
57        .as_ref()
58        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
59
60    let client = reqwest::Client::new();
61    let url = format!("{}/defi/v3/token/market-data", BIRDEYE_URL);
62
63    let resp = client
64        .get(url)
65        .query(&[("address", address)])
66        .header("X-API-KEY", api_key)
67        .header("accept", "application/json")
68        .header("x-chain", "solana")
69        .send()
70        .await?
71        .json::<TokenMarketDataResponse>()
72        .await?;
73
74    Ok(resp)
75}
76
77/// Get Wallet Portfolio
78///
79/// # Parameters
80///
81/// * `agent` - An instance of SolanaAgentKit
82///
83/// - `address`: Address of a wallet
84///
85/// # Returns
86///
87/// A `WalletPortfolioResponse`
88pub async fn get_wallet_portfolio(agent: &SolanaAgentKit, wallet_address: &str) -> Result<WalletPortfolioResponse> {
89    let api_key = agent
90        .config
91        .birdeye_api_key
92        .as_ref()
93        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
94
95    let client = reqwest::Client::new();
96    let url = format!("{}/v1/wallet/token_list", BIRDEYE_URL);
97
98    let response = client
99        .get(&url)
100        .query(&[("wallet", wallet_address)])
101        .header("accept", "application/json")
102        .header("X-API-KEY", api_key)
103        .header("x-chain", "solana")
104        .send()
105        .await?
106        .json::<WalletPortfolioResponse>()
107        .await?;
108
109    Ok(response)
110}
111
112/// Get top holder list of the given token
113///
114/// # Parameters
115///
116/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
117///
118/// - `params`: Query Params
119///
120/// # Returns
121///
122/// A `Result` TokenHolderResponse
123pub async fn get_token_holders(
124    agent: &SolanaAgentKit,
125    query_params: TokenHolderQueryParams,
126) -> Result<TokenHolderResponse> {
127    let api_key = agent
128        .config
129        .birdeye_api_key
130        .as_ref()
131        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
132
133    let client = reqwest::Client::new();
134    let url = format!("{}/defi/v3/token/holder", BIRDEYE_URL);
135
136    let address = query_params.address;
137    let offset = query_params.offset.unwrap_or(0);
138    let limit = query_params.limit.unwrap_or(100);
139
140    let resp = client
141        .get(url)
142        .query(&[("address", address), ("offset", offset.to_string()), ("limit", limit.to_string())])
143        .header("X-API-KEY", api_key)
144        .header("accept", "application/json")
145        .header("x-chain", "solana")
146        .send()
147        .await?
148        .json::<TokenHolderResponse>()
149        .await?;
150
151    Ok(resp)
152}
153
154/// Get metadata of single token
155///
156/// # Parameters
157///
158/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
159///
160/// - `address`: Address of a token
161///
162/// # Returns
163///
164/// A `Result` TokenMetadataResponse
165pub async fn get_token_metadata(agent: &SolanaAgentKit, address: &str) -> Result<TokenMetadataResponse> {
166    let api_key = agent
167        .config
168        .birdeye_api_key
169        .as_ref()
170        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
171
172    let client = reqwest::Client::new();
173    let url = format!("{}/defi/v3/token/meta-data/single", BIRDEYE_URL);
174
175    let resp = client
176        .get(url)
177        .query(&[("address", address)])
178        .header("X-API-KEY", api_key)
179        .header("accept", "application/json")
180        .header("x-chain", "solana")
181        .send()
182        .await?
183        .json::<TokenMetadataResponse>()
184        .await?;
185
186    Ok(resp)
187}
188
189/// Get price update of a token.
190///
191/// # Parameters
192///
193/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
194///
195/// - `address`: Address of a token
196///
197/// # Returns
198///
199/// A `Result` TokenPriceResponse
200pub async fn get_token_price(agent: &SolanaAgentKit, address: &str) -> Result<TokenPriceResponse> {
201    let api_key = agent
202        .config
203        .birdeye_api_key
204        .as_ref()
205        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
206
207    let client = reqwest::Client::new();
208    let url = format!("{}/defi/price", BIRDEYE_URL);
209
210    let resp = client
211        .get(url)
212        .query(&[("address", address)])
213        .header("X-API-KEY", api_key)
214        .header("accept", "application/json")
215        .header("x-chain", "solana")
216        .send()
217        .await?
218        .json::<TokenPriceResponse>()
219        .await?;
220
221    Ok(resp)
222}
223
224/// Get price and volume updates of a token
225///
226/// # Parameters
227///
228/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
229///
230/// - `query_params`: TokenPriceVolumeQueryParams
231///
232/// # Returns
233///
234/// A `Result` TokenPriceVolumeResponse
235pub async fn get_token_price_volume(
236    agent: &SolanaAgentKit,
237    query_params: TokenPriceVolumeQueryParams,
238) -> Result<TokenPriceVolumeResponse> {
239    let api_key = agent
240        .config
241        .birdeye_api_key
242        .as_ref()
243        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
244
245    let client = reqwest::Client::new();
246    let url = format!("{}/defi/price_volume/single", BIRDEYE_URL);
247
248    let address = query_params.address;
249    let vh = query_params.vh;
250
251    let resp = client
252        .get(url)
253        .query(&[("address", address), ("type", vh)])
254        .header("X-API-KEY", api_key)
255        .header("accept", "application/json")
256        .header("x-chain", "solana")
257        .send()
258        .await?
259        .json::<TokenPriceVolumeResponse>()
260        .await?;
261
262    Ok(resp)
263}
264
265/// Retrieve a dynamic and up-to-date list of trending tokens based on specified sorting criteria.
266///
267/// # Parameters
268///
269/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
270///
271/// - `query_params`: TokenTrendingQueryParams
272///
273/// # Returns
274///
275/// A `Result` TokenTrendingResponse
276pub async fn get_token_trending(
277    agent: &SolanaAgentKit,
278    query_params: TokenTrendingQueryParams,
279) -> Result<TokenTrendingResponse> {
280    let api_key = agent
281        .config
282        .birdeye_api_key
283        .as_ref()
284        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
285
286    let client = reqwest::Client::new();
287    let url = format!("{}/defi/token_trending", BIRDEYE_URL);
288
289    let sort_by = query_params.sort_by;
290    let sort_type = query_params.sort_type;
291    let offset = query_params.offset.unwrap_or(0);
292    let limit = query_params.limit.unwrap_or(20);
293
294    let resp = client
295        .get(url)
296        .query(&[
297            ("sort_by", sort_by),
298            ("sort_type", sort_type),
299            ("offset", offset.to_string()),
300            ("limit", limit.to_string()),
301        ])
302        .header("X-API-KEY", api_key)
303        .header("accept", "application/json")
304        .header("x-chain", "solana")
305        .send()
306        .await?
307        .json::<TokenTrendingResponse>()
308        .await?;
309
310    Ok(resp)
311}
312
313/// Get mint/burn transaction list of the given token. Only support solana currently
314///
315/// # Parameters
316///
317/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
318///
319/// - `query_params`: TokenMintOrBurnQueryParams
320///
321/// # Returns
322///
323/// A `Result` TokenMintOrBurnResponse
324pub async fn get_token_mintburn_tx(
325    agent: &SolanaAgentKit,
326    query_params: TokenMintOrBurnQueryParams,
327) -> Result<TokenMintOrBurnResponse> {
328    let api_key = agent
329        .config
330        .birdeye_api_key
331        .as_ref()
332        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
333
334    let client = reqwest::Client::new();
335    let url = format!("{}/defi/v3/token/mint-burn-txs", BIRDEYE_URL);
336
337    let address = query_params.address;
338    let tx_type = query_params.tx_type;
339    let offset = query_params.offset.unwrap_or(0);
340    let limit = query_params.limit.unwrap_or(20);
341
342    let resp = client
343        .get(url)
344        .query(&[
345            ("address", address),
346            ("type", tx_type),
347            ("sort_by", "block_time".to_string()),
348            ("sort_type", "desc".to_string()),
349            ("offset", offset.to_string()),
350            ("limit", limit.to_string()),
351        ])
352        .header("X-API-KEY", api_key)
353        .header("accept", "application/json")
354        .header("x-chain", "solana")
355        .send()
356        .await?
357        .json::<TokenMintOrBurnResponse>()
358        .await?;
359
360    Ok(resp)
361}
362
363/// Search for token and market data by matching a pattern or a specific token, market address.
364///
365/// # Parameters
366///
367/// * `agent` - An instance of SolanaAgentKit (with .config.birdeye_api_key)
368///
369/// - `query_params`: TokenOrMarketQueryParams
370///
371/// # Returns
372///
373/// A `Result` TokenOrMarketResponse
374pub async fn search_token_or_market_data(
375    agent: &SolanaAgentKit,
376    query_params: TokenOrMarketQueryParams,
377) -> Result<TokenOrMarketResponse> {
378    let api_key = agent
379        .config
380        .birdeye_api_key
381        .as_ref()
382        .ok_or_else(|| anyhow::anyhow!("Missing Birdeye API key in agent.config.birdeye_api_key"))?;
383
384    let client = reqwest::Client::new();
385    let url = format!("{}/defi/v3/search", BIRDEYE_URL);
386
387    let keyword = query_params.keyword;
388    let target = query_params.target;
389    let offset = query_params.offset.unwrap_or(0);
390    let limit = query_params.limit.unwrap_or(20);
391
392    let resp = client
393        .get(url)
394        .query(&[
395            ("chain", "solana".to_string()),
396            ("keyworkd", keyword),
397            ("target", target),
398            ("sort_by", "volume_24h_usd".to_string()),
399            ("sort_type", "desc".to_string()),
400            ("offset", offset.to_string()),
401            ("limit", limit.to_string()),
402        ])
403        .header("X-API-KEY", api_key)
404        .header("accept", "application/json")
405        .send()
406        .await?
407        .json::<TokenOrMarketResponse>()
408        .await?;
409
410    Ok(resp)
411}