1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
use crate::api::{Client, Config, Datamaxi, Result};
pub use crate::models::{CandleOptions, PoolsOptions, TradeOptions};
use crate::models::{CandleResponse, PoolsResponse, TradeResponse};
use std::collections::HashMap;

/// Provides methods for retrieving DEX candle data and related information.
#[derive(Clone)]
pub struct Dex {
    pub client: Client,
}

impl Dex {
    /// Retrieves candle data for a specified chain, exchange, and pool. Additional parameters can be
    /// provided to filter and sort the results. The response will contain an array of candle data
    /// objects, each representing a single candle with open, high, low, close, and volume values.
    pub fn candle<C, E, P>(
        &self,
        chain: C,
        exchange: E,
        pool: P,
        options: CandleOptions,
    ) -> Result<CandleResponse>
    where
        C: Into<String>,
        E: Into<String>,
        P: Into<String>,
    {
        let mut parameters = HashMap::new();

        // required
        parameters.insert("chain".to_string(), chain.into());
        parameters.insert("exchange".to_string(), exchange.into());
        parameters.insert("pool".to_string(), pool.into());

        // optional
        parameters.extend(
            [
                options
                    .market
                    .map(|market| ("market".to_string(), market.to_string())),
                options
                    .interval
                    .map(|interval| ("interval".to_string(), interval.to_string())),
                options
                    .page
                    .map(|page| ("page".to_string(), page.to_string())),
                options
                    .limit
                    .map(|limit| ("limit".to_string(), limit.to_string())),
                options
                    .from
                    .map(|from| ("from".to_string(), from.to_string())),
                options.to.map(|to| ("to".to_string(), to.to_string())),
                options
                    .sort
                    .map(|sort| ("sort".to_string(), sort.to_string())),
            ]
            .into_iter()
            .flatten(),
        );

        self.client.get("/dex/candle", Some(parameters))
    }

    /// Retrieves trade data for a specified chain, exchange, and pool. Additional parameters can be
    /// provided to filter and sort the results. The response will contain an array of trade data
    /// objects, each representing a single trade with price, amount, and timestamp values.
    pub fn trade<C, E, P>(
        &self,
        chain: C,
        exchange: E,
        pool: P,
        options: TradeOptions,
    ) -> Result<TradeResponse>
    where
        C: Into<String>,
        E: Into<String>,
        P: Into<String>,
    {
        let mut parameters = HashMap::new();

        // required
        parameters.insert("chain".to_string(), chain.into());
        parameters.insert("exchange".to_string(), exchange.into());
        parameters.insert("pool".to_string(), pool.into());

        // optional
        parameters.extend(
            [
                options
                    .page
                    .map(|page| ("page".to_string(), page.to_string())),
                options
                    .limit
                    .map(|limit| ("limit".to_string(), limit.to_string())),
                options
                    .from
                    .map(|from| ("from".to_string(), from.to_string())),
                options.to.map(|to| ("to".to_string(), to.to_string())),
                options
                    .sort
                    .map(|sort| ("sort".to_string(), sort.to_string())),
            ]
            .into_iter()
            .flatten(),
        );

        self.client.get("/dex/trade", Some(parameters))
    }

    /// Retrieves information about available pools, including details about the chain, exchange,
    /// base and quote symbols, and pool address. Optional parameters can be provided to filter the
    /// results by chain and exchange.
    pub fn pools(&self, options: PoolsOptions) -> Result<Vec<PoolsResponse>> {
        let mut parameters = HashMap::new();

        // optional
        parameters.extend(
            [
                options
                    .exchange
                    .map(|exchange| ("exchange".to_string(), exchange.to_string())),
                options
                    .chain
                    .map(|chain| ("chain".to_string(), chain.to_string())),
            ]
            .into_iter()
            .flatten(),
        );

        self.client.get("/dex/pools", Some(parameters))
    }

    /// Retrieves a list of available chains for candle data.
    pub fn chains(&self) -> Result<Vec<String>> {
        self.client.get("/dex/chains", None)
    }

    /// Retrieves a list of available exchanges for candle data.
    pub fn exchanges(&self) -> Result<Vec<String>> {
        self.client.get("/dex/exchanges", None)
    }

    /// Retrieves a list of available intervals for candle data.
    pub fn intervals(&self) -> Result<Vec<String>> {
        self.client.get("/dex/intervals", None)
    }
}

/// Implements the `Datamaxi` trait for `Dex`, providing methods
/// to create new instances of `Dex` with or without a custom base URL.
impl Datamaxi for Dex {
    /// Creates a new `Dex` instance with the default base URL.
    ///
    /// # Parameters
    /// - `api_key`: A `String` representing the API key used to authenticate requests.
    ///
    /// # Returns
    /// A new `Dex` instance configured with the default base URL and the provided `api_key`.
    ///
    /// # Example
    /// ```rust
    /// use crate::datamaxi::api::Datamaxi;
    /// let dex = datamaxi::dex::Dex::new("my_api_key".to_string());
    /// ```
    fn new(api_key: String) -> Dex {
        let config = Config {
            base_url: None, // Default base URL will be used
            api_key,        // Provided API key
        };
        Dex {
            client: Client::new(config), // Create a new client with the provided config
        }
    }

    /// Creates a new `Dex` instance with a custom base URL.
    ///
    /// # Parameters
    /// - `api_key`: A `String` representing the API key used to authenticate requests.
    /// - `base_url`: A `String` representing the custom base URL for API requests.
    ///
    /// # Returns
    /// A new `Dex` instance configured with the provided `base_url` and `api_key`.
    ///
    /// # Example
    /// ```rust
    /// use crate::datamaxi::api::Datamaxi;
    /// let dex = datamaxi::dex::Dex::new_with_base_url("my_api_key".to_string(), "https://custom-api.example.com".to_string());
    /// ```
    fn new_with_base_url(api_key: String, base_url: String) -> Dex {
        let config = Config {
            base_url: Some(base_url), // Use the provided custom base URL
            api_key,                  // Provided API key
        };
        Dex {
            client: Client::new(config), // Create a new client with the provided config
        }
    }
}