polyte_data/api/
builders.rs

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