binance_sdk/simple_earn/rest_api/apis/
yield_arena_api.rs1#![allow(unused_imports)]
15use async_trait::async_trait;
16use derive_builder::Builder;
17use reqwest;
18use rust_decimal::prelude::*;
19use serde::{Deserialize, Serialize};
20use serde_json::{Value, json};
21use std::collections::BTreeMap;
22
23use crate::common::{
24 config::ConfigurationRestApi,
25 models::{ParamBuildError, RestApiResponse},
26 utils::send_request,
27};
28use crate::simple_earn::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait YieldArenaApi: Send + Sync {
34 async fn get_yield_arena_activities(
35 &self,
36 params: GetYieldArenaActivitiesParams,
37 ) -> anyhow::Result<RestApiResponse<models::GetYieldArenaActivitiesResponse>>;
38}
39
40#[derive(Debug, Clone)]
41pub struct YieldArenaApiClient {
42 configuration: ConfigurationRestApi,
43}
44
45impl YieldArenaApiClient {
46 pub fn new(configuration: ConfigurationRestApi) -> Self {
47 Self { configuration }
48 }
49}
50
51#[derive(Clone, Debug, Builder, Deserialize, Default)]
56#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
57pub struct GetYieldArenaActivitiesParams {
58 #[builder(setter(into), default)]
63 #[serde(rename = "lang", default)]
64 pub lang: Option<String>,
65 #[builder(setter(into), default)]
70 #[serde(rename = "recvWindow", default)]
71 pub recv_window: Option<i64>,
72}
73
74impl GetYieldArenaActivitiesParams {
75 #[must_use]
78 pub fn builder() -> GetYieldArenaActivitiesParamsBuilder {
79 GetYieldArenaActivitiesParamsBuilder::default()
80 }
81}
82
83#[async_trait]
84impl YieldArenaApi for YieldArenaApiClient {
85 async fn get_yield_arena_activities(
86 &self,
87 params: GetYieldArenaActivitiesParams,
88 ) -> anyhow::Result<RestApiResponse<models::GetYieldArenaActivitiesResponse>> {
89 let GetYieldArenaActivitiesParams { lang, recv_window } = params;
90
91 let mut query_params = BTreeMap::new();
92 let mut body_params = BTreeMap::new();
93
94 if let Some(rw) = recv_window {
95 query_params.insert("recvWindow".to_string(), json!(rw));
96 }
97
98 if let Some(rw) = lang {
99 body_params.insert("lang".to_string(), json!(rw));
100 }
101
102 send_request::<models::GetYieldArenaActivitiesResponse>(
103 &self.configuration,
104 "/sapi/v1/earn/arena/activities",
105 reqwest::Method::GET,
106 query_params,
107 body_params,
108 if HAS_TIME_UNIT {
109 self.configuration.time_unit
110 } else {
111 None
112 },
113 true,
114 )
115 .await
116 }
117}
118
119#[cfg(all(test, feature = "simple_earn"))]
120mod tests {
121 use super::*;
122 use crate::TOKIO_SHARED_RT;
123 use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
124 use async_trait::async_trait;
125 use std::collections::HashMap;
126
127 struct DummyRestApiResponse<T> {
128 inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
129 status: u16,
130 headers: HashMap<String, String>,
131 rate_limits: Option<Vec<RestApiRateLimit>>,
132 }
133
134 impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
135 fn from(dummy: DummyRestApiResponse<T>) -> Self {
136 Self {
137 data_fn: dummy.inner,
138 status: dummy.status,
139 headers: dummy.headers,
140 rate_limits: dummy.rate_limits,
141 }
142 }
143 }
144
145 struct MockYieldArenaApiClient {
146 force_error: bool,
147 }
148
149 #[async_trait]
150 impl YieldArenaApi for MockYieldArenaApiClient {
151 async fn get_yield_arena_activities(
152 &self,
153 _params: GetYieldArenaActivitiesParams,
154 ) -> anyhow::Result<RestApiResponse<models::GetYieldArenaActivitiesResponse>> {
155 if self.force_error {
156 return Err(ConnectorError::ConnectorClientError {
157 msg: "ResponseError".to_string(),
158 code: None,
159 }
160 .into());
161 }
162
163 let resp_json: Value = serde_json::from_str(r#"{"activities":[{"activityId":10001,"activityType":"AIRDROP","title":"Hold FDUSD & Earn BNB Airdrop","description":"Subscribe to FDUSD Flexible and earn bonus BNB airdrop.","rewardPoolInUsd":"50000","rewardToken":["BNB"],"redirectUrl":"https://www.binance.com/en/earn/arena/airdrop-123","startTime":1713052800000,"endTime":1713657600000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
164 let dummy_response: models::GetYieldArenaActivitiesResponse =
165 serde_json::from_value(resp_json.clone())
166 .expect("should parse into models::GetYieldArenaActivitiesResponse");
167
168 let dummy = DummyRestApiResponse {
169 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
170 status: 200,
171 headers: HashMap::new(),
172 rate_limits: None,
173 };
174
175 Ok(dummy.into())
176 }
177 }
178
179 #[test]
180 fn get_yield_arena_activities_required_params_success() {
181 TOKIO_SHARED_RT.block_on(async {
182 let client = MockYieldArenaApiClient { force_error: false };
183
184 let params = GetYieldArenaActivitiesParams::builder().build().unwrap();
185
186 let resp_json: Value = serde_json::from_str(r#"{"activities":[{"activityId":10001,"activityType":"AIRDROP","title":"Hold FDUSD & Earn BNB Airdrop","description":"Subscribe to FDUSD Flexible and earn bonus BNB airdrop.","rewardPoolInUsd":"50000","rewardToken":["BNB"],"redirectUrl":"https://www.binance.com/en/earn/arena/airdrop-123","startTime":1713052800000,"endTime":1713657600000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
187 let expected_response : models::GetYieldArenaActivitiesResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetYieldArenaActivitiesResponse");
188
189 let resp = client.get_yield_arena_activities(params).await.expect("Expected a response");
190 let data_future = resp.data();
191 let actual_response = data_future.await.unwrap();
192 assert_eq!(actual_response, expected_response);
193 });
194 }
195
196 #[test]
197 fn get_yield_arena_activities_optional_params_success() {
198 TOKIO_SHARED_RT.block_on(async {
199 let client = MockYieldArenaApiClient { force_error: false };
200
201 let params = GetYieldArenaActivitiesParams::builder().lang("en".to_string()).recv_window(5000).build().unwrap();
202
203 let resp_json: Value = serde_json::from_str(r#"{"activities":[{"activityId":10001,"activityType":"AIRDROP","title":"Hold FDUSD & Earn BNB Airdrop","description":"Subscribe to FDUSD Flexible and earn bonus BNB airdrop.","rewardPoolInUsd":"50000","rewardToken":["BNB"],"redirectUrl":"https://www.binance.com/en/earn/arena/airdrop-123","startTime":1713052800000,"endTime":1713657600000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
204 let expected_response : models::GetYieldArenaActivitiesResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetYieldArenaActivitiesResponse");
205
206 let resp = client.get_yield_arena_activities(params).await.expect("Expected a response");
207 let data_future = resp.data();
208 let actual_response = data_future.await.unwrap();
209 assert_eq!(actual_response, expected_response);
210 });
211 }
212
213 #[test]
214 fn get_yield_arena_activities_response_error() {
215 TOKIO_SHARED_RT.block_on(async {
216 let client = MockYieldArenaApiClient { force_error: true };
217
218 let params = GetYieldArenaActivitiesParams::builder().build().unwrap();
219
220 match client.get_yield_arena_activities(params).await {
221 Ok(_) => panic!("Expected an error"),
222 Err(err) => {
223 assert_eq!(err.to_string(), "Connector client error: ResponseError");
224 }
225 }
226 });
227 }
228}