polyte_data/api/
builders.rs

1use reqwest::Client;
2use serde::{Deserialize, Serialize};
3use url::Url;
4
5use crate::{
6    error::DataApiError,
7    request::{QueryBuilder, Request},
8};
9
10/// Builders namespace for builder-related operations
11#[derive(Clone)]
12pub struct BuildersApi {
13    pub(crate) client: Client,
14    pub(crate) base_url: Url,
15}
16
17impl BuildersApi {
18    /// Get the aggregated builder leaderboard
19    pub fn leaderboard(&self) -> GetBuilderLeaderboard {
20        let request = Request::new(
21            self.client.clone(),
22            self.base_url.clone(),
23            "/v1/builders/leaderboard".to_string(),
24        );
25
26        GetBuilderLeaderboard { request }
27    }
28
29    /// Get daily builder volume time series
30    pub fn volume(&self) -> GetBuilderVolume {
31        let request = Request::new(
32            self.client.clone(),
33            self.base_url.clone(),
34            "/v1/builders/volume".to_string(),
35        );
36
37        GetBuilderVolume { request }
38    }
39}
40
41/// Request builder for getting the builder leaderboard
42pub struct GetBuilderLeaderboard {
43    request: Request<Vec<BuilderRanking>>,
44}
45
46impl GetBuilderLeaderboard {
47    /// Set the aggregation time period (default: DAY)
48    pub fn time_period(mut self, period: TimePeriod) -> Self {
49        self.request = self.request.query("timePeriod", period);
50        self
51    }
52
53    /// Set maximum number of results (0-50, default: 25)
54    pub fn limit(mut self, limit: u32) -> Self {
55        self.request = self.request.query("limit", limit);
56        self
57    }
58
59    /// Set pagination offset (0-1000, default: 0)
60    pub fn offset(mut self, offset: u32) -> Self {
61        self.request = self.request.query("offset", offset);
62        self
63    }
64
65    /// Execute the request
66    pub async fn send(self) -> Result<Vec<BuilderRanking>, DataApiError> {
67        self.request.send().await
68    }
69}
70
71/// Time period for aggregation
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
73#[serde(rename_all = "UPPERCASE")]
74pub enum TimePeriod {
75    /// Daily aggregation (default)
76    #[default]
77    Day,
78    /// Weekly aggregation
79    Week,
80    /// Monthly aggregation
81    Month,
82    /// All time aggregation
83    All,
84}
85
86impl std::fmt::Display for TimePeriod {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        match self {
89            Self::Day => write!(f, "DAY"),
90            Self::Week => write!(f, "WEEK"),
91            Self::Month => write!(f, "MONTH"),
92            Self::All => write!(f, "ALL"),
93        }
94    }
95}
96
97/// Builder ranking entry in the leaderboard
98#[derive(Debug, Clone, Serialize, Deserialize)]
99#[serde(rename_all(deserialize = "camelCase"))]
100pub struct BuilderRanking {
101    /// Builder's ranking position
102    pub rank: String,
103    /// Builder identifier/name
104    pub builder: String,
105    /// Trading volume metric
106    pub volume: f64,
107    /// Count of active users
108    pub active_users: u64,
109    /// Verification status
110    pub verified: bool,
111    /// Logo image URL
112    pub builder_logo: Option<String>,
113}
114
115/// Request builder for getting the builder volume time series
116pub struct GetBuilderVolume {
117    request: Request<Vec<BuilderVolume>>,
118}
119
120impl GetBuilderVolume {
121    /// Set the time period filter (default: DAY)
122    pub fn time_period(mut self, period: TimePeriod) -> Self {
123        self.request = self.request.query("timePeriod", period);
124        self
125    }
126
127    /// Execute the request
128    pub async fn send(self) -> Result<Vec<BuilderVolume>, DataApiError> {
129        self.request.send().await
130    }
131}
132
133/// Builder volume entry in the time series
134#[derive(Debug, Clone, Serialize, Deserialize)]
135#[serde(rename_all(deserialize = "camelCase"))]
136pub struct BuilderVolume {
137    /// Date/time of the volume record (ISO 8601)
138    pub dt: String,
139    /// Builder identifier/name
140    pub builder: String,
141    /// Logo image URL
142    pub builder_logo: Option<String>,
143    /// Verification status
144    pub verified: bool,
145    /// Trading volume metric
146    pub volume: f64,
147    /// Count of active users
148    pub active_users: u64,
149    /// Builder's ranking position
150    pub rank: String,
151}