1pub mod pro;
2
3use crate::{
4 action::{ActionBuilder, ActionGroup, FunctionAction},
5 AgentState,
6};
7use pro::CoinGeckoProClient;
8use serde::Deserialize;
9use std::sync::Arc;
10
11#[derive(Debug, Deserialize)]
13pub struct CoinContractMarketChartRangeParams {
14 id: String,
15 contract_address: String,
16 vs_currency: String,
17 days: String,
18}
19
20#[derive(Debug, Deserialize)]
21pub struct CoinMarketChartParams {
22 id: String,
23 vs_currency: String,
24 days: String,
25 interval: Option<String>,
26}
27
28#[derive(Debug, Deserialize)]
30pub struct NetworkStatusParams {} #[derive(Debug, Deserialize)]
33pub struct GlobalDataParams {}
34
35#[derive(Debug, Deserialize)]
36pub struct GlobalDefiDataParams {}
37
38#[derive(Debug, Deserialize)]
39pub struct ExchangesParams {
40 per_page: Option<u32>,
41 page: Option<u32>,
42}
43
44#[derive(Debug, Deserialize)]
45pub struct ExchangeParams {
46 id: String,
47}
48
49#[derive(Debug, Deserialize)]
50pub struct ExchangeTickersParams {
51 id: String,
52 coin_ids: Option<Vec<String>>,
53 include_exchange_logo: Option<bool>,
54 page: Option<u32>,
55 depth: Option<bool>,
56 order: Option<String>,
57}
58
59#[derive(Debug, Deserialize)]
60pub struct ExchangeVolumeChartParams {
61 id: String,
62 days: u32,
63}
64
65#[derive(Debug, Deserialize)]
66pub struct CoinsListParams {
67 include_platform: Option<bool>,
68}
69
70#[derive(Debug, Deserialize)]
71pub struct CoinTickersParams {
72 id: String,
73 exchange_ids: Option<Vec<String>>,
74 include_exchange_logo: Option<bool>,
75 page: Option<u32>,
76 order: Option<String>,
77 depth: Option<bool>,
78}
79
80#[derive(Debug, Deserialize)]
81pub struct CoinHistoryParams {
82 id: String,
83 date: String,
84 localization: Option<bool>,
85}
86
87#[derive(Debug, Deserialize)]
88pub struct CoinOhlcParams {
89 id: String,
90 vs_currency: String,
91 days: String,
92}
93
94#[derive(Debug, Deserialize)]
95pub struct CoinContractParams {
96 id: String,
97 contract_address: String,
98}
99
100#[derive(Debug, Deserialize)]
101pub struct CoinContractMarketChartParams {
102 id: String,
103 contract_address: String,
104 vs_currency: String,
105 days: String,
106}
107
108#[derive(Debug, Deserialize)]
110pub struct AssetPlatformsParams {} #[derive(Debug, Deserialize)]
113pub struct CoinsCategoriesListParams {}
114
115#[derive(Debug, Deserialize)]
116pub struct CoinsCategoriesParams {
117 order: Option<String>,
118}
119
120#[derive(Debug, Deserialize)]
121pub struct IndexesParams {}
122
123#[derive(Debug, Deserialize)]
124pub struct IndexesListParams {}
125
126#[derive(Debug, Deserialize)]
127pub struct DerivativesParams {}
128
129#[derive(Debug, Deserialize)]
130pub struct DerivativesExchangesParams {
131 order: Option<String>,
132 per_page: Option<u32>,
133 page: Option<u32>,
134}
135
136#[derive(Debug, Deserialize)]
137pub struct DerivativesExchangeParams {
138 id: String,
139 include_tickers: Option<String>,
140}
141
142#[derive(Debug, Deserialize)]
143pub struct ExchangeRatesParams {}
144
145#[derive(Debug, Deserialize)]
146pub struct SearchParams {
147 query: String,
148}
149
150#[derive(Debug, Deserialize)]
151pub struct TrendingParams {}
152
153#[derive(Debug, Deserialize)]
154pub struct CompaniesPublicTreasuryParams {
155 coin_id: String,
156}
157
158pub struct CoinGeckoActionGroup<S: Send + Sync + Clone + 'static> {
160 actions: Vec<Arc<FunctionAction<S>>>,
161}
162
163impl<S: Send + Sync + Clone + 'static> ActionGroup<S> for CoinGeckoActionGroup<S> {
164 fn actions(&self) -> &[Arc<FunctionAction<S>>] {
165 &self.actions
166 }
167}
168
169impl<S: Send + Sync + Clone + 'static> CoinGeckoActionGroup<S> {
170 pub fn new() -> Self {
171 let mut actions = Vec::new();
172
173 {
175 async fn get_coin_contract_market_chart_range<S: Send + Sync + Clone + 'static>(
176 params: CoinContractMarketChartRangeParams,
177 _send_state: serde_json::Value,
178 _state: AgentState<S>,
179 ) -> Result<String, String> {
180 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
181 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
182 })?;
183
184 let client = CoinGeckoProClient::new(api_key);
185
186 let to = chrono::Utc::now().timestamp() as u64;
187 let from = calculate_from_timestamp(to, ¶ms.days)?;
188
189 client
190 .get_coin_contract_market_chart_range(
191 params.id,
192 params.contract_address,
193 params.vs_currency,
194 from,
195 to,
196 )
197 .await
198 }
199
200 let action = ActionBuilder::<_, _, _, _>::new(
201 "get_coin_contract_market_chart_range",
202 get_coin_contract_market_chart_range,
203 None,
204 )
205 .description("Get historical market data for a token contract address")
206 .parameter("id", "The coin id (e.g. ethereum)", "string", true)
207 .parameter(
208 "contract_address",
209 "Token's contract address",
210 "string",
211 true,
212 )
213 .parameter(
214 "vs_currency",
215 "The target currency (e.g. usd)",
216 "string",
217 true,
218 )
219 .parameter(
220 "days",
221 "Number of days of data to return (1, 7, 14, 30, 90, 180, 365, max)",
222 "string",
223 true,
224 )
225 .build();
226
227 actions.push(Arc::new(action));
228 }
229
230 {
232 async fn get_coin_market_chart<S: Send + Sync + Clone + 'static>(
233 params: CoinMarketChartParams,
234 _send_state: serde_json::Value,
235 _state: AgentState<S>,
236 ) -> Result<String, String> {
237 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
238 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
239 })?;
240
241 let client = CoinGeckoProClient::new(api_key);
242 client
243 .get_coin_market_chart(
244 params.id,
245 params.vs_currency,
246 params.days,
247 params.interval,
248 )
249 .await
250 }
251
252 let action = ActionBuilder::<_, _, _, _>::new(
253 "get_coin_market_chart",
254 get_coin_market_chart,
255 None,
256 )
257 .description("Get historical market data include price, market cap, and 24h volume")
258 .parameter("id", "The coin id (e.g. bitcoin)", "string", true)
259 .parameter(
260 "vs_currency",
261 "The target currency (e.g. usd)",
262 "string",
263 true,
264 )
265 .parameter("days", "Data up to number of days ago", "string", true)
266 .parameter("interval", "Data interval (e.g. daily)", "string", false)
267 .build();
268
269 actions.push(Arc::new(action));
270 }
271
272 {
274 async fn get_network_status<S: Send + Sync + Clone + 'static>(
275 _params: NetworkStatusParams,
276 _send_state: serde_json::Value,
277 _state: AgentState<S>,
278 ) -> Result<String, String> {
279 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
280 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
281 })?;
282
283 let client = CoinGeckoProClient::new(api_key);
284 client.get_network_status().await
285 }
286
287 let action =
288 ActionBuilder::<_, _, _, _>::new("get_network_status", get_network_status, None)
289 .description("Check API server status")
290 .build();
291
292 actions.push(Arc::new(action));
293 }
294
295 {
297 async fn get_global_data<S: Send + Sync + Clone + 'static>(
298 _params: GlobalDataParams,
299 _send_state: serde_json::Value,
300 _state: AgentState<S>,
301 ) -> Result<String, String> {
302 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
303 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
304 })?;
305
306 let client = CoinGeckoProClient::new(api_key);
307 client.get_global_data().await
308 }
309
310 let action = ActionBuilder::<_, _, _, _>::new("get_global_data", get_global_data, None)
311 .description("Get cryptocurrency global data")
312 .build();
313
314 actions.push(Arc::new(action));
315 }
316
317 {
319 async fn get_global_defi_data<S: Send + Sync + Clone + 'static>(
320 _params: GlobalDefiDataParams,
321 _send_state: serde_json::Value,
322 _state: AgentState<S>,
323 ) -> Result<String, String> {
324 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
325 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
326 })?;
327
328 let client = CoinGeckoProClient::new(api_key);
329 client.get_global_defi_data().await
330 }
331
332 let action = ActionBuilder::<_, _, _, _>::new(
333 "get_global_defi_data",
334 get_global_defi_data,
335 None,
336 )
337 .description("Get cryptocurrency global decentralized finance (defi) data")
338 .build();
339
340 actions.push(Arc::new(action));
341 }
342
343 {
345 async fn get_exchanges<S: Send + Sync + Clone + 'static>(
346 params: ExchangesParams,
347 _send_state: serde_json::Value,
348 _state: AgentState<S>,
349 ) -> Result<String, String> {
350 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
351 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
352 })?;
353
354 let client = CoinGeckoProClient::new(api_key);
355 client.get_exchanges(params.per_page, params.page).await
356 }
357
358 let action = ActionBuilder::<_, _, _, _>::new("get_exchanges", get_exchanges, None)
359 .description("List all exchanges")
360 .parameter("per_page", "Total results per page", "integer", false)
361 .parameter("page", "Page number", "integer", false)
362 .build();
363
364 actions.push(Arc::new(action));
365 }
366
367 {
369 async fn get_exchange<S: Send + Sync + Clone + 'static>(
370 params: ExchangeParams,
371 _send_state: serde_json::Value,
372 _state: AgentState<S>,
373 ) -> Result<String, String> {
374 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
375 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
376 })?;
377
378 let client = CoinGeckoProClient::new(api_key);
379 client.get_exchange(params.id).await
380 }
381
382 let action = ActionBuilder::<_, _, _, _>::new("get_exchange", get_exchange, None)
383 .description("Get exchange volume in BTC and top 100 tickers only")
384 .parameter("id", "Exchange id", "string", true)
385 .build();
386
387 actions.push(Arc::new(action));
388 }
389
390 {
392 async fn get_exchange_tickers<S: Send + Sync + Clone + 'static>(
393 params: ExchangeTickersParams,
394 _send_state: serde_json::Value,
395 _state: AgentState<S>,
396 ) -> Result<String, String> {
397 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
398 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
399 })?;
400
401 let client = CoinGeckoProClient::new(api_key);
402 client
403 .get_exchange_tickers(
404 params.id,
405 params.coin_ids,
406 params.include_exchange_logo,
407 params.page,
408 params.depth,
409 params.order,
410 )
411 .await
412 }
413
414 let action = ActionBuilder::<_, _, _, _>::new(
415 "get_exchange_tickers",
416 get_exchange_tickers,
417 None,
418 )
419 .description("Get exchange tickers (paginated)")
420 .parameter("id", "Exchange id", "string", true)
421 .parameter("coin_ids", "Filter tickers by coin ids", "array", false)
422 .parameter(
423 "include_exchange_logo",
424 "Include exchange logo",
425 "boolean",
426 false,
427 )
428 .parameter("page", "Page number", "integer", false)
429 .parameter("depth", "Include 2% orderbook depth", "boolean", false)
430 .parameter("order", "Sort by order", "string", false)
431 .build();
432
433 actions.push(Arc::new(action));
434 }
435
436 {
438 async fn get_exchange_volume_chart<S: Send + Sync + Clone + 'static>(
439 params: ExchangeVolumeChartParams,
440 _send_state: serde_json::Value,
441 _state: AgentState<S>,
442 ) -> Result<String, String> {
443 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
444 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
445 })?;
446
447 let client = CoinGeckoProClient::new(api_key);
448 client
449 .get_exchange_volume_chart(params.id, params.days)
450 .await
451 }
452
453 let action = ActionBuilder::<_, _, _, _>::new(
454 "get_exchange_volume_chart",
455 get_exchange_volume_chart,
456 None,
457 )
458 .description("Get volume chart data for a given exchange")
459 .parameter("id", "Exchange id", "string", true)
460 .parameter("days", "Data up to number of days ago", "integer", true)
461 .build();
462
463 actions.push(Arc::new(action));
464 }
465
466 {
468 async fn get_coins_list<S: Send + Sync + Clone + 'static>(
469 params: CoinsListParams,
470 _send_state: serde_json::Value,
471 _state: AgentState<S>,
472 ) -> Result<String, String> {
473 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
474 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
475 })?;
476
477 let client = CoinGeckoProClient::new(api_key);
478 client.get_coins_list(params.include_platform).await
479 }
480
481 let action = ActionBuilder::<_, _, _, _>::new("get_coins_list", get_coins_list, None)
482 .description("List all supported coins with id and name")
483 .parameter(
484 "include_platform",
485 "Include platform contract addresses",
486 "boolean",
487 false,
488 )
489 .build();
490
491 actions.push(Arc::new(action));
492 }
493
494 {
496 async fn get_coin_tickers<S: Send + Sync + Clone + 'static>(
497 params: CoinTickersParams,
498 _send_state: serde_json::Value,
499 _state: AgentState<S>,
500 ) -> Result<String, String> {
501 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
502 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
503 })?;
504
505 let client = CoinGeckoProClient::new(api_key);
506 client
507 .get_coin_tickers(
508 params.id,
509 params.exchange_ids,
510 params.include_exchange_logo,
511 params.page,
512 params.order,
513 params.depth,
514 )
515 .await
516 }
517
518 let action =
519 ActionBuilder::<_, _, _, _>::new("get_coin_tickers", get_coin_tickers, None)
520 .description("Get coin tickers (paginated to 100 items)")
521 .parameter("id", "The coin id", "string", true)
522 .parameter(
523 "exchange_ids",
524 "Filter results by exchange ids",
525 "array",
526 false,
527 )
528 .parameter(
529 "include_exchange_logo",
530 "Include exchange logo",
531 "boolean",
532 false,
533 )
534 .parameter("page", "Page through results", "integer", false)
535 .parameter("order", "Sort results by order", "string", false)
536 .parameter("depth", "Include 2% orderbook depth", "boolean", false)
537 .build();
538
539 actions.push(Arc::new(action));
540 }
541
542 {
544 async fn get_coin_history<S: Send + Sync + Clone + 'static>(
545 params: CoinHistoryParams,
546 _send_state: serde_json::Value,
547 _state: AgentState<S>,
548 ) -> Result<String, String> {
549 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
550 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
551 })?;
552
553 let client = CoinGeckoProClient::new(api_key);
554 client
555 .get_coin_history(params.id, params.date, params.localization)
556 .await
557 }
558
559 let action = ActionBuilder::<_, _, _, _>::new(
560 "get_coin_history",
561 get_coin_history,
562 None,
563 )
564 .description(
565 "Get historical data (name, price, market, stats) at a given date for a coin",
566 )
567 .parameter("id", "The coin id", "string", true)
568 .parameter(
569 "date",
570 "The date of data snapshot in dd-mm-yyyy",
571 "string",
572 true,
573 )
574 .parameter(
575 "localization",
576 "Set to false to exclude localized languages",
577 "boolean",
578 false,
579 )
580 .build();
581
582 actions.push(Arc::new(action));
583 }
584
585 {
587 async fn get_coin_ohlc<S: Send + Sync + Clone + 'static>(
588 params: CoinOhlcParams,
589 _send_state: serde_json::Value,
590 _state: AgentState<S>,
591 ) -> Result<String, String> {
592 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
593 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
594 })?;
595
596 let client = CoinGeckoProClient::new(api_key);
597 client
598 .get_coin_ohlc(params.id, params.vs_currency, params.days)
599 .await
600 }
601
602 let action = ActionBuilder::<_, _, _, _>::new("get_coin_ohlc", get_coin_ohlc, None)
603 .description("Get coin's OHLC (Open, High, Low, Close) data")
604 .parameter("id", "The coin id", "string", true)
605 .parameter(
606 "vs_currency",
607 "The target currency of market data (usd, eur, jpy, etc.)",
608 "string",
609 true,
610 )
611 .parameter("days", "Data up to number of days ago", "string", true)
612 .build();
613
614 actions.push(Arc::new(action));
615 }
616
617 {
619 async fn get_coin_contract<S: Send + Sync + Clone + 'static>(
620 params: CoinContractParams,
621 _send_state: serde_json::Value,
622 _state: AgentState<S>,
623 ) -> Result<String, String> {
624 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
625 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
626 })?;
627
628 let client = CoinGeckoProClient::new(api_key);
629 client
630 .get_coin_contract(params.id, params.contract_address)
631 .await
632 }
633
634 let action =
635 ActionBuilder::<_, _, _, _>::new("get_coin_contract", get_coin_contract, None)
636 .description("Get coin info from contract address")
637 .parameter("id", "Asset platform (e.g. ethereum)", "string", true)
638 .parameter(
639 "contract_address",
640 "Token's contract address",
641 "string",
642 true,
643 )
644 .build();
645
646 actions.push(Arc::new(action));
647 }
648
649 {
651 async fn get_coin_contract_market_chart<S: Send + Sync + Clone + 'static>(
652 params: CoinContractMarketChartParams,
653 _send_state: serde_json::Value,
654 _state: AgentState<S>,
655 ) -> Result<String, String> {
656 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
657 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
658 })?;
659
660 let client = CoinGeckoProClient::new(api_key);
661 client
662 .get_coin_contract_market_chart(
663 params.id,
664 params.contract_address,
665 params.vs_currency,
666 params.days,
667 )
668 .await
669 }
670
671 let action = ActionBuilder::<_, _, _, _>::new(
672 "get_coin_contract_market_chart",
673 get_coin_contract_market_chart,
674 None,
675 )
676 .description("Get historical market data for a contract address")
677 .parameter("id", "The platform id (e.g. ethereum)", "string", true)
678 .parameter(
679 "contract_address",
680 "Token's contract address",
681 "string",
682 true,
683 )
684 .parameter(
685 "vs_currency",
686 "The target currency (e.g. usd)",
687 "string",
688 true,
689 )
690 .parameter("days", "Data up to number of days ago", "string", true)
691 .build();
692
693 actions.push(Arc::new(action));
694 }
695
696 {
698 async fn get_asset_platforms<S: Send + Sync + Clone + 'static>(
699 _params: AssetPlatformsParams,
700 _send_state: serde_json::Value,
701 _state: AgentState<S>,
702 ) -> Result<String, String> {
703 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
704 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
705 })?;
706
707 let client = CoinGeckoProClient::new(api_key);
708 client.get_asset_platforms().await
709 }
710
711 let action =
712 ActionBuilder::<_, _, _, _>::new("get_asset_platforms", get_asset_platforms, None)
713 .description("List all asset platforms (blockchain networks)")
714 .build();
715
716 actions.push(Arc::new(action));
717 }
718
719 {
721 async fn get_coins_categories_list<S: Send + Sync + Clone + 'static>(
722 _params: CoinsCategoriesListParams,
723 _send_state: serde_json::Value,
724 _state: AgentState<S>,
725 ) -> Result<String, String> {
726 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
727 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
728 })?;
729
730 let client = CoinGeckoProClient::new(api_key);
731 client.get_coins_categories_list().await
732 }
733
734 let action = ActionBuilder::<_, _, _, _>::new(
735 "get_coins_categories_list",
736 get_coins_categories_list,
737 None,
738 )
739 .description("List all categories")
740 .build();
741
742 actions.push(Arc::new(action));
743 }
744
745 {
747 async fn get_coins_categories<S: Send + Sync + Clone + 'static>(
748 params: CoinsCategoriesParams,
749 _send_state: serde_json::Value,
750 _state: AgentState<S>,
751 ) -> Result<String, String> {
752 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
753 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
754 })?;
755
756 let client = CoinGeckoProClient::new(api_key);
757 client.get_coins_categories(params.order).await
758 }
759
760 let action = ActionBuilder::<_, _, _, _>::new(
761 "get_coins_categories",
762 get_coins_categories,
763 None,
764 )
765 .description("List all categories with market data")
766 .parameter("order", "Sort by market_cap or name", "string", false)
767 .build();
768
769 actions.push(Arc::new(action));
770 }
771
772 {
774 async fn get_indexes<S: Send + Sync + Clone + 'static>(
775 _params: IndexesParams,
776 _send_state: serde_json::Value,
777 _state: AgentState<S>,
778 ) -> Result<String, String> {
779 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
780 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
781 })?;
782
783 let client = CoinGeckoProClient::new(api_key);
784 client.get_indexes().await
785 }
786
787 let action = ActionBuilder::<_, _, _, _>::new("get_indexes", get_indexes, None)
788 .description("List all market indexes")
789 .build();
790
791 actions.push(Arc::new(action));
792 }
793
794 {
796 async fn get_indexes_list<S: Send + Sync + Clone + 'static>(
797 _params: IndexesListParams,
798 _send_state: serde_json::Value,
799 _state: AgentState<S>,
800 ) -> Result<String, String> {
801 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
802 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
803 })?;
804
805 let client = CoinGeckoProClient::new(api_key);
806 client.get_indexes_list().await
807 }
808
809 let action =
810 ActionBuilder::<_, _, _, _>::new("get_indexes_list", get_indexes_list, None)
811 .description("List market indexes id and name")
812 .build();
813
814 actions.push(Arc::new(action));
815 }
816
817 {
819 async fn get_derivatives<S: Send + Sync + Clone + 'static>(
820 _params: DerivativesParams,
821 _send_state: serde_json::Value,
822 _state: AgentState<S>,
823 ) -> Result<String, String> {
824 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
825 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
826 })?;
827
828 let client = CoinGeckoProClient::new(api_key);
829 client.get_derivatives().await
830 }
831
832 let action = ActionBuilder::<_, _, _, _>::new("get_derivatives", get_derivatives, None)
833 .description("List all derivative tickers")
834 .build();
835
836 actions.push(Arc::new(action));
837 }
838
839 {
841 async fn get_derivatives_exchanges<S: Send + Sync + Clone + 'static>(
842 params: DerivativesExchangesParams,
843 _send_state: serde_json::Value,
844 _state: AgentState<S>,
845 ) -> Result<String, String> {
846 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
847 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
848 })?;
849
850 let client = CoinGeckoProClient::new(api_key);
851 client
852 .get_derivatives_exchanges(params.order, params.per_page, params.page)
853 .await
854 }
855
856 let action = ActionBuilder::<_, _, _, _>::new(
857 "get_derivatives_exchanges",
858 get_derivatives_exchanges,
859 None,
860 )
861 .description("List all derivative exchanges")
862 .parameter("order", "Order results by specified field", "string", false)
863 .parameter("per_page", "Total results per page", "integer", false)
864 .parameter("page", "Page through results", "integer", false)
865 .build();
866
867 actions.push(Arc::new(action));
868 }
869
870 {
872 async fn get_derivatives_exchange<S: Send + Sync + Clone + 'static>(
873 params: DerivativesExchangeParams,
874 _send_state: serde_json::Value,
875 _state: AgentState<S>,
876 ) -> Result<String, String> {
877 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
878 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
879 })?;
880
881 let client = CoinGeckoProClient::new(api_key);
882 client
883 .get_derivatives_exchange(params.id, params.include_tickers)
884 .await
885 }
886
887 let action = ActionBuilder::<_, _, _, _>::new(
888 "get_derivatives_exchange",
889 get_derivatives_exchange,
890 None,
891 )
892 .description("Show derivative exchange data")
893 .parameter("id", "The exchange id", "string", true)
894 .parameter(
895 "include_tickers",
896 "Include tickers data (all/unexpired)",
897 "string",
898 false,
899 )
900 .build();
901
902 actions.push(Arc::new(action));
903 }
904
905 {
907 async fn get_exchange_rates<S: Send + Sync + Clone + 'static>(
908 _params: ExchangeRatesParams,
909 _send_state: serde_json::Value,
910 _state: AgentState<S>,
911 ) -> Result<String, String> {
912 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
913 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
914 })?;
915
916 let client = CoinGeckoProClient::new(api_key);
917 client.get_exchange_rates().await
918 }
919
920 let action =
921 ActionBuilder::<_, _, _, _>::new("get_exchange_rates", get_exchange_rates, None)
922 .description("Get BTC-to-Currency exchange rates")
923 .build();
924
925 actions.push(Arc::new(action));
926 }
927
928 {
930 async fn search<S: Send + Sync + Clone + 'static>(
931 params: SearchParams,
932 _send_state: serde_json::Value,
933 _state: AgentState<S>,
934 ) -> Result<String, String> {
935 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
936 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
937 })?;
938
939 let client = CoinGeckoProClient::new(api_key);
940 client.search(params.query).await
941 }
942
943 let action = ActionBuilder::<_, _, _, _>::new("search", search, None)
944 .description("Search for coins, categories and markets")
945 .parameter("query", "Search string", "string", true)
946 .build();
947
948 actions.push(Arc::new(action));
949 }
950
951 {
953 async fn get_trending<S: Send + Sync + Clone + 'static>(
954 _params: TrendingParams,
955 _send_state: serde_json::Value,
956 _state: AgentState<S>,
957 ) -> Result<String, String> {
958 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
959 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
960 })?;
961
962 let client = CoinGeckoProClient::new(api_key);
963 client.get_trending().await
964 }
965
966 let action = ActionBuilder::<_, _, _, _>::new("get_trending", get_trending, None)
967 .description("Get trending search coins (Top-7) on CoinGecko")
968 .build();
969
970 actions.push(Arc::new(action));
971 }
972
973 {
975 async fn get_companies_public_treasury<S: Send + Sync + Clone + 'static>(
976 params: CompaniesPublicTreasuryParams,
977 _send_state: serde_json::Value,
978 _state: AgentState<S>,
979 ) -> Result<String, String> {
980 let api_key = std::env::var("COINGECKO_PRO_API_KEY").map_err(|_| {
981 "COINGECKO_PRO_API_KEY environment variable not set".to_string()
982 })?;
983
984 let client = CoinGeckoProClient::new(api_key);
985 client.get_companies_public_treasury(params.coin_id).await
986 }
987
988 let action = ActionBuilder::<_, _, _, _>::new(
989 "get_companies_public_treasury",
990 get_companies_public_treasury,
991 None,
992 )
993 .description("Get public companies bitcoin or ethereum holdings")
994 .parameter(
995 "coin_id",
996 "The coin id (bitcoin or ethereum)",
997 "string",
998 true,
999 )
1000 .build();
1001
1002 actions.push(Arc::new(action));
1003 }
1004
1005 Self { actions }
1006 }
1007
1008 pub fn actions(&self) -> &[Arc<FunctionAction<S>>] {
1009 &self.actions
1010 }
1011}
1012
1013fn calculate_from_timestamp(to: u64, days: &str) -> Result<u64, String> {
1015 let duration = match days {
1016 "1" => chrono::Duration::days(1),
1017 "7" => chrono::Duration::days(7),
1018 "14" => chrono::Duration::days(14),
1019 "30" => chrono::Duration::days(30),
1020 "90" => chrono::Duration::days(90),
1021 "180" => chrono::Duration::days(180),
1022 "365" => chrono::Duration::days(365),
1023 "max" => chrono::Duration::days(365 * 8), _ => {
1025 return Err(
1026 "Invalid days parameter. Use: 1, 7, 14, 30, 90, 180, 365, or max".to_string(),
1027 )
1028 }
1029 };
1030
1031 let from = to
1032 .checked_sub(duration.num_seconds() as u64)
1033 .ok_or("Error calculating from timestamp")?;
1034
1035 Ok(from)
1036}