Skip to main content

binance_sdk/staking/rest_api/apis/
sol_staking_api.rs

1/*
2 * Binance Staking REST API
3 *
4 * OpenAPI Specification for the Binance Staking REST API
5 *
6 * The version of the OpenAPI document: 1.0.0
7 *
8 *
9 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
10 * https://openapi-generator.tech
11 * Do not edit the class manually.
12 */
13
14#![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::staking::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait SolStakingApi: Send + Sync {
34    async fn claim_boost_rewards(
35        &self,
36        params: ClaimBoostRewardsParams,
37    ) -> anyhow::Result<RestApiResponse<models::ClaimBoostRewardsResponse>>;
38    async fn get_bnsol_rate_history(
39        &self,
40        params: GetBnsolRateHistoryParams,
41    ) -> anyhow::Result<RestApiResponse<models::GetBnsolRateHistoryResponse>>;
42    async fn get_bnsol_rewards_history(
43        &self,
44        params: GetBnsolRewardsHistoryParams,
45    ) -> anyhow::Result<RestApiResponse<models::GetBnsolRewardsHistoryResponse>>;
46    async fn get_boost_rewards_history(
47        &self,
48        params: GetBoostRewardsHistoryParams,
49    ) -> anyhow::Result<RestApiResponse<models::GetBoostRewardsHistoryResponse>>;
50    async fn get_sol_redemption_history(
51        &self,
52        params: GetSolRedemptionHistoryParams,
53    ) -> anyhow::Result<RestApiResponse<models::GetSolRedemptionHistoryResponse>>;
54    async fn get_sol_staking_history(
55        &self,
56        params: GetSolStakingHistoryParams,
57    ) -> anyhow::Result<RestApiResponse<models::GetSolStakingHistoryResponse>>;
58    async fn get_sol_staking_quota_details(
59        &self,
60        params: GetSolStakingQuotaDetailsParams,
61    ) -> anyhow::Result<RestApiResponse<models::GetSolStakingQuotaDetailsResponse>>;
62    async fn get_unclaimed_rewards(
63        &self,
64        params: GetUnclaimedRewardsParams,
65    ) -> anyhow::Result<RestApiResponse<Vec<models::GetUnclaimedRewardsResponseInner>>>;
66    async fn redeem_sol(
67        &self,
68        params: RedeemSolParams,
69    ) -> anyhow::Result<RestApiResponse<models::RedeemSolResponse>>;
70    async fn sol_staking_account(
71        &self,
72        params: SolStakingAccountParams,
73    ) -> anyhow::Result<RestApiResponse<models::SolStakingAccountResponse>>;
74    async fn subscribe_sol_staking(
75        &self,
76        params: SubscribeSolStakingParams,
77    ) -> anyhow::Result<RestApiResponse<models::SubscribeSolStakingResponse>>;
78}
79
80#[derive(Debug, Clone)]
81pub struct SolStakingApiClient {
82    configuration: ConfigurationRestApi,
83}
84
85impl SolStakingApiClient {
86    pub fn new(configuration: ConfigurationRestApi) -> Self {
87        Self { configuration }
88    }
89}
90
91/// Request parameters for the [`claim_boost_rewards`] operation.
92///
93/// This struct holds all of the inputs you can pass when calling
94/// [`claim_boost_rewards`](#method.claim_boost_rewards).
95#[derive(Clone, Debug, Builder, Default)]
96#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
97pub struct ClaimBoostRewardsParams {
98    ///
99    /// The `recv_window` parameter.
100    ///
101    /// This field is **optional.
102    #[builder(setter(into), default)]
103    pub recv_window: Option<i64>,
104}
105
106impl ClaimBoostRewardsParams {
107    /// Create a builder for [`claim_boost_rewards`].
108    ///
109    #[must_use]
110    pub fn builder() -> ClaimBoostRewardsParamsBuilder {
111        ClaimBoostRewardsParamsBuilder::default()
112    }
113}
114/// Request parameters for the [`get_bnsol_rate_history`] operation.
115///
116/// This struct holds all of the inputs you can pass when calling
117/// [`get_bnsol_rate_history`](#method.get_bnsol_rate_history).
118#[derive(Clone, Debug, Builder, Default)]
119#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
120pub struct GetBnsolRateHistoryParams {
121    ///
122    /// The `start_time` parameter.
123    ///
124    /// This field is **optional.
125    #[builder(setter(into), default)]
126    pub start_time: Option<i64>,
127    ///
128    /// The `end_time` parameter.
129    ///
130    /// This field is **optional.
131    #[builder(setter(into), default)]
132    pub end_time: Option<i64>,
133    /// Currently querying page. Start from 1. Default:1
134    ///
135    /// This field is **optional.
136    #[builder(setter(into), default)]
137    pub current: Option<i64>,
138    /// Default:10, Max:100
139    ///
140    /// This field is **optional.
141    #[builder(setter(into), default)]
142    pub size: Option<i64>,
143    ///
144    /// The `recv_window` parameter.
145    ///
146    /// This field is **optional.
147    #[builder(setter(into), default)]
148    pub recv_window: Option<i64>,
149}
150
151impl GetBnsolRateHistoryParams {
152    /// Create a builder for [`get_bnsol_rate_history`].
153    ///
154    #[must_use]
155    pub fn builder() -> GetBnsolRateHistoryParamsBuilder {
156        GetBnsolRateHistoryParamsBuilder::default()
157    }
158}
159/// Request parameters for the [`get_bnsol_rewards_history`] operation.
160///
161/// This struct holds all of the inputs you can pass when calling
162/// [`get_bnsol_rewards_history`](#method.get_bnsol_rewards_history).
163#[derive(Clone, Debug, Builder, Default)]
164#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
165pub struct GetBnsolRewardsHistoryParams {
166    ///
167    /// The `start_time` parameter.
168    ///
169    /// This field is **optional.
170    #[builder(setter(into), default)]
171    pub start_time: Option<i64>,
172    ///
173    /// The `end_time` parameter.
174    ///
175    /// This field is **optional.
176    #[builder(setter(into), default)]
177    pub end_time: Option<i64>,
178    /// Currently querying page. Start from 1. Default:1
179    ///
180    /// This field is **optional.
181    #[builder(setter(into), default)]
182    pub current: Option<i64>,
183    /// Default:10, Max:100
184    ///
185    /// This field is **optional.
186    #[builder(setter(into), default)]
187    pub size: Option<i64>,
188    ///
189    /// The `recv_window` parameter.
190    ///
191    /// This field is **optional.
192    #[builder(setter(into), default)]
193    pub recv_window: Option<i64>,
194}
195
196impl GetBnsolRewardsHistoryParams {
197    /// Create a builder for [`get_bnsol_rewards_history`].
198    ///
199    #[must_use]
200    pub fn builder() -> GetBnsolRewardsHistoryParamsBuilder {
201        GetBnsolRewardsHistoryParamsBuilder::default()
202    }
203}
204/// Request parameters for the [`get_boost_rewards_history`] operation.
205///
206/// This struct holds all of the inputs you can pass when calling
207/// [`get_boost_rewards_history`](#method.get_boost_rewards_history).
208#[derive(Clone, Debug, Builder)]
209#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
210pub struct GetBoostRewardsHistoryParams {
211    /// "CLAIM", "DISTRIBUTE", default "CLAIM"
212    ///
213    /// This field is **required.
214    #[builder(setter(into))]
215    pub r#type: String,
216    ///
217    /// The `start_time` parameter.
218    ///
219    /// This field is **optional.
220    #[builder(setter(into), default)]
221    pub start_time: Option<i64>,
222    ///
223    /// The `end_time` parameter.
224    ///
225    /// This field is **optional.
226    #[builder(setter(into), default)]
227    pub end_time: Option<i64>,
228    /// Currently querying page. Start from 1. Default:1
229    ///
230    /// This field is **optional.
231    #[builder(setter(into), default)]
232    pub current: Option<i64>,
233    /// Default:10, Max:100
234    ///
235    /// This field is **optional.
236    #[builder(setter(into), default)]
237    pub size: Option<i64>,
238    ///
239    /// The `recv_window` parameter.
240    ///
241    /// This field is **optional.
242    #[builder(setter(into), default)]
243    pub recv_window: Option<i64>,
244}
245
246impl GetBoostRewardsHistoryParams {
247    /// Create a builder for [`get_boost_rewards_history`].
248    ///
249    /// Required parameters:
250    ///
251    /// * `r#type` — \"CLAIM\", \"DISTRIBUTE\", default \"CLAIM\"
252    ///
253    #[must_use]
254    pub fn builder(r#type: String) -> GetBoostRewardsHistoryParamsBuilder {
255        GetBoostRewardsHistoryParamsBuilder::default().r#type(r#type)
256    }
257}
258/// Request parameters for the [`get_sol_redemption_history`] operation.
259///
260/// This struct holds all of the inputs you can pass when calling
261/// [`get_sol_redemption_history`](#method.get_sol_redemption_history).
262#[derive(Clone, Debug, Builder, Default)]
263#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
264pub struct GetSolRedemptionHistoryParams {
265    ///
266    /// The `redeem_id` parameter.
267    ///
268    /// This field is **optional.
269    #[builder(setter(into), default)]
270    pub redeem_id: Option<i64>,
271    ///
272    /// The `start_time` parameter.
273    ///
274    /// This field is **optional.
275    #[builder(setter(into), default)]
276    pub start_time: Option<i64>,
277    ///
278    /// The `end_time` parameter.
279    ///
280    /// This field is **optional.
281    #[builder(setter(into), default)]
282    pub end_time: Option<i64>,
283    /// Currently querying page. Start from 1. Default:1
284    ///
285    /// This field is **optional.
286    #[builder(setter(into), default)]
287    pub current: Option<i64>,
288    /// Default:10, Max:100
289    ///
290    /// This field is **optional.
291    #[builder(setter(into), default)]
292    pub size: Option<i64>,
293    ///
294    /// The `recv_window` parameter.
295    ///
296    /// This field is **optional.
297    #[builder(setter(into), default)]
298    pub recv_window: Option<i64>,
299}
300
301impl GetSolRedemptionHistoryParams {
302    /// Create a builder for [`get_sol_redemption_history`].
303    ///
304    #[must_use]
305    pub fn builder() -> GetSolRedemptionHistoryParamsBuilder {
306        GetSolRedemptionHistoryParamsBuilder::default()
307    }
308}
309/// Request parameters for the [`get_sol_staking_history`] operation.
310///
311/// This struct holds all of the inputs you can pass when calling
312/// [`get_sol_staking_history`](#method.get_sol_staking_history).
313#[derive(Clone, Debug, Builder, Default)]
314#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
315pub struct GetSolStakingHistoryParams {
316    ///
317    /// The `purchase_id` parameter.
318    ///
319    /// This field is **optional.
320    #[builder(setter(into), default)]
321    pub purchase_id: Option<i64>,
322    ///
323    /// The `start_time` parameter.
324    ///
325    /// This field is **optional.
326    #[builder(setter(into), default)]
327    pub start_time: Option<i64>,
328    ///
329    /// The `end_time` parameter.
330    ///
331    /// This field is **optional.
332    #[builder(setter(into), default)]
333    pub end_time: Option<i64>,
334    /// Currently querying page. Start from 1. Default:1
335    ///
336    /// This field is **optional.
337    #[builder(setter(into), default)]
338    pub current: Option<i64>,
339    /// Default:10, Max:100
340    ///
341    /// This field is **optional.
342    #[builder(setter(into), default)]
343    pub size: Option<i64>,
344    ///
345    /// The `recv_window` parameter.
346    ///
347    /// This field is **optional.
348    #[builder(setter(into), default)]
349    pub recv_window: Option<i64>,
350}
351
352impl GetSolStakingHistoryParams {
353    /// Create a builder for [`get_sol_staking_history`].
354    ///
355    #[must_use]
356    pub fn builder() -> GetSolStakingHistoryParamsBuilder {
357        GetSolStakingHistoryParamsBuilder::default()
358    }
359}
360/// Request parameters for the [`get_sol_staking_quota_details`] operation.
361///
362/// This struct holds all of the inputs you can pass when calling
363/// [`get_sol_staking_quota_details`](#method.get_sol_staking_quota_details).
364#[derive(Clone, Debug, Builder, Default)]
365#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
366pub struct GetSolStakingQuotaDetailsParams {
367    ///
368    /// The `recv_window` parameter.
369    ///
370    /// This field is **optional.
371    #[builder(setter(into), default)]
372    pub recv_window: Option<i64>,
373}
374
375impl GetSolStakingQuotaDetailsParams {
376    /// Create a builder for [`get_sol_staking_quota_details`].
377    ///
378    #[must_use]
379    pub fn builder() -> GetSolStakingQuotaDetailsParamsBuilder {
380        GetSolStakingQuotaDetailsParamsBuilder::default()
381    }
382}
383/// Request parameters for the [`get_unclaimed_rewards`] operation.
384///
385/// This struct holds all of the inputs you can pass when calling
386/// [`get_unclaimed_rewards`](#method.get_unclaimed_rewards).
387#[derive(Clone, Debug, Builder, Default)]
388#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
389pub struct GetUnclaimedRewardsParams {
390    ///
391    /// The `recv_window` parameter.
392    ///
393    /// This field is **optional.
394    #[builder(setter(into), default)]
395    pub recv_window: Option<i64>,
396}
397
398impl GetUnclaimedRewardsParams {
399    /// Create a builder for [`get_unclaimed_rewards`].
400    ///
401    #[must_use]
402    pub fn builder() -> GetUnclaimedRewardsParamsBuilder {
403        GetUnclaimedRewardsParamsBuilder::default()
404    }
405}
406/// Request parameters for the [`redeem_sol`] operation.
407///
408/// This struct holds all of the inputs you can pass when calling
409/// [`redeem_sol`](#method.redeem_sol).
410#[derive(Clone, Debug, Builder)]
411#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
412pub struct RedeemSolParams {
413    /// Amount in SOL.
414    ///
415    /// This field is **required.
416    #[builder(setter(into))]
417    pub amount: rust_decimal::Decimal,
418    ///
419    /// The `recv_window` parameter.
420    ///
421    /// This field is **optional.
422    #[builder(setter(into), default)]
423    pub recv_window: Option<i64>,
424}
425
426impl RedeemSolParams {
427    /// Create a builder for [`redeem_sol`].
428    ///
429    /// Required parameters:
430    ///
431    /// * `amount` — Amount in SOL.
432    ///
433    #[must_use]
434    pub fn builder(amount: rust_decimal::Decimal) -> RedeemSolParamsBuilder {
435        RedeemSolParamsBuilder::default().amount(amount)
436    }
437}
438/// Request parameters for the [`sol_staking_account`] operation.
439///
440/// This struct holds all of the inputs you can pass when calling
441/// [`sol_staking_account`](#method.sol_staking_account).
442#[derive(Clone, Debug, Builder, Default)]
443#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
444pub struct SolStakingAccountParams {
445    ///
446    /// The `recv_window` parameter.
447    ///
448    /// This field is **optional.
449    #[builder(setter(into), default)]
450    pub recv_window: Option<i64>,
451}
452
453impl SolStakingAccountParams {
454    /// Create a builder for [`sol_staking_account`].
455    ///
456    #[must_use]
457    pub fn builder() -> SolStakingAccountParamsBuilder {
458        SolStakingAccountParamsBuilder::default()
459    }
460}
461/// Request parameters for the [`subscribe_sol_staking`] operation.
462///
463/// This struct holds all of the inputs you can pass when calling
464/// [`subscribe_sol_staking`](#method.subscribe_sol_staking).
465#[derive(Clone, Debug, Builder)]
466#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
467pub struct SubscribeSolStakingParams {
468    /// Amount in SOL.
469    ///
470    /// This field is **required.
471    #[builder(setter(into))]
472    pub amount: rust_decimal::Decimal,
473    ///
474    /// The `recv_window` parameter.
475    ///
476    /// This field is **optional.
477    #[builder(setter(into), default)]
478    pub recv_window: Option<i64>,
479}
480
481impl SubscribeSolStakingParams {
482    /// Create a builder for [`subscribe_sol_staking`].
483    ///
484    /// Required parameters:
485    ///
486    /// * `amount` — Amount in SOL.
487    ///
488    #[must_use]
489    pub fn builder(amount: rust_decimal::Decimal) -> SubscribeSolStakingParamsBuilder {
490        SubscribeSolStakingParamsBuilder::default().amount(amount)
491    }
492}
493
494#[async_trait]
495impl SolStakingApi for SolStakingApiClient {
496    async fn claim_boost_rewards(
497        &self,
498        params: ClaimBoostRewardsParams,
499    ) -> anyhow::Result<RestApiResponse<models::ClaimBoostRewardsResponse>> {
500        let ClaimBoostRewardsParams { recv_window } = params;
501
502        let mut query_params = BTreeMap::new();
503        let body_params = BTreeMap::new();
504
505        if let Some(rw) = recv_window {
506            query_params.insert("recvWindow".to_string(), json!(rw));
507        }
508
509        send_request::<models::ClaimBoostRewardsResponse>(
510            &self.configuration,
511            "/sapi/v1/sol-staking/sol/claim",
512            reqwest::Method::POST,
513            query_params,
514            body_params,
515            if HAS_TIME_UNIT {
516                self.configuration.time_unit
517            } else {
518                None
519            },
520            true,
521        )
522        .await
523    }
524
525    async fn get_bnsol_rate_history(
526        &self,
527        params: GetBnsolRateHistoryParams,
528    ) -> anyhow::Result<RestApiResponse<models::GetBnsolRateHistoryResponse>> {
529        let GetBnsolRateHistoryParams {
530            start_time,
531            end_time,
532            current,
533            size,
534            recv_window,
535        } = params;
536
537        let mut query_params = BTreeMap::new();
538        let body_params = BTreeMap::new();
539
540        if let Some(rw) = start_time {
541            query_params.insert("startTime".to_string(), json!(rw));
542        }
543
544        if let Some(rw) = end_time {
545            query_params.insert("endTime".to_string(), json!(rw));
546        }
547
548        if let Some(rw) = current {
549            query_params.insert("current".to_string(), json!(rw));
550        }
551
552        if let Some(rw) = size {
553            query_params.insert("size".to_string(), json!(rw));
554        }
555
556        if let Some(rw) = recv_window {
557            query_params.insert("recvWindow".to_string(), json!(rw));
558        }
559
560        send_request::<models::GetBnsolRateHistoryResponse>(
561            &self.configuration,
562            "/sapi/v1/sol-staking/sol/history/rateHistory",
563            reqwest::Method::GET,
564            query_params,
565            body_params,
566            if HAS_TIME_UNIT {
567                self.configuration.time_unit
568            } else {
569                None
570            },
571            true,
572        )
573        .await
574    }
575
576    async fn get_bnsol_rewards_history(
577        &self,
578        params: GetBnsolRewardsHistoryParams,
579    ) -> anyhow::Result<RestApiResponse<models::GetBnsolRewardsHistoryResponse>> {
580        let GetBnsolRewardsHistoryParams {
581            start_time,
582            end_time,
583            current,
584            size,
585            recv_window,
586        } = params;
587
588        let mut query_params = BTreeMap::new();
589        let body_params = BTreeMap::new();
590
591        if let Some(rw) = start_time {
592            query_params.insert("startTime".to_string(), json!(rw));
593        }
594
595        if let Some(rw) = end_time {
596            query_params.insert("endTime".to_string(), json!(rw));
597        }
598
599        if let Some(rw) = current {
600            query_params.insert("current".to_string(), json!(rw));
601        }
602
603        if let Some(rw) = size {
604            query_params.insert("size".to_string(), json!(rw));
605        }
606
607        if let Some(rw) = recv_window {
608            query_params.insert("recvWindow".to_string(), json!(rw));
609        }
610
611        send_request::<models::GetBnsolRewardsHistoryResponse>(
612            &self.configuration,
613            "/sapi/v1/sol-staking/sol/history/bnsolRewardsHistory",
614            reqwest::Method::GET,
615            query_params,
616            body_params,
617            if HAS_TIME_UNIT {
618                self.configuration.time_unit
619            } else {
620                None
621            },
622            true,
623        )
624        .await
625    }
626
627    async fn get_boost_rewards_history(
628        &self,
629        params: GetBoostRewardsHistoryParams,
630    ) -> anyhow::Result<RestApiResponse<models::GetBoostRewardsHistoryResponse>> {
631        let GetBoostRewardsHistoryParams {
632            r#type,
633            start_time,
634            end_time,
635            current,
636            size,
637            recv_window,
638        } = params;
639
640        let mut query_params = BTreeMap::new();
641        let body_params = BTreeMap::new();
642
643        query_params.insert("type".to_string(), json!(r#type));
644
645        if let Some(rw) = start_time {
646            query_params.insert("startTime".to_string(), json!(rw));
647        }
648
649        if let Some(rw) = end_time {
650            query_params.insert("endTime".to_string(), json!(rw));
651        }
652
653        if let Some(rw) = current {
654            query_params.insert("current".to_string(), json!(rw));
655        }
656
657        if let Some(rw) = size {
658            query_params.insert("size".to_string(), json!(rw));
659        }
660
661        if let Some(rw) = recv_window {
662            query_params.insert("recvWindow".to_string(), json!(rw));
663        }
664
665        send_request::<models::GetBoostRewardsHistoryResponse>(
666            &self.configuration,
667            "/sapi/v1/sol-staking/sol/history/boostRewardsHistory",
668            reqwest::Method::GET,
669            query_params,
670            body_params,
671            if HAS_TIME_UNIT {
672                self.configuration.time_unit
673            } else {
674                None
675            },
676            true,
677        )
678        .await
679    }
680
681    async fn get_sol_redemption_history(
682        &self,
683        params: GetSolRedemptionHistoryParams,
684    ) -> anyhow::Result<RestApiResponse<models::GetSolRedemptionHistoryResponse>> {
685        let GetSolRedemptionHistoryParams {
686            redeem_id,
687            start_time,
688            end_time,
689            current,
690            size,
691            recv_window,
692        } = params;
693
694        let mut query_params = BTreeMap::new();
695        let body_params = BTreeMap::new();
696
697        if let Some(rw) = redeem_id {
698            query_params.insert("redeemId".to_string(), json!(rw));
699        }
700
701        if let Some(rw) = start_time {
702            query_params.insert("startTime".to_string(), json!(rw));
703        }
704
705        if let Some(rw) = end_time {
706            query_params.insert("endTime".to_string(), json!(rw));
707        }
708
709        if let Some(rw) = current {
710            query_params.insert("current".to_string(), json!(rw));
711        }
712
713        if let Some(rw) = size {
714            query_params.insert("size".to_string(), json!(rw));
715        }
716
717        if let Some(rw) = recv_window {
718            query_params.insert("recvWindow".to_string(), json!(rw));
719        }
720
721        send_request::<models::GetSolRedemptionHistoryResponse>(
722            &self.configuration,
723            "/sapi/v1/sol-staking/sol/history/redemptionHistory",
724            reqwest::Method::GET,
725            query_params,
726            body_params,
727            if HAS_TIME_UNIT {
728                self.configuration.time_unit
729            } else {
730                None
731            },
732            true,
733        )
734        .await
735    }
736
737    async fn get_sol_staking_history(
738        &self,
739        params: GetSolStakingHistoryParams,
740    ) -> anyhow::Result<RestApiResponse<models::GetSolStakingHistoryResponse>> {
741        let GetSolStakingHistoryParams {
742            purchase_id,
743            start_time,
744            end_time,
745            current,
746            size,
747            recv_window,
748        } = params;
749
750        let mut query_params = BTreeMap::new();
751        let body_params = BTreeMap::new();
752
753        if let Some(rw) = purchase_id {
754            query_params.insert("purchaseId".to_string(), json!(rw));
755        }
756
757        if let Some(rw) = start_time {
758            query_params.insert("startTime".to_string(), json!(rw));
759        }
760
761        if let Some(rw) = end_time {
762            query_params.insert("endTime".to_string(), json!(rw));
763        }
764
765        if let Some(rw) = current {
766            query_params.insert("current".to_string(), json!(rw));
767        }
768
769        if let Some(rw) = size {
770            query_params.insert("size".to_string(), json!(rw));
771        }
772
773        if let Some(rw) = recv_window {
774            query_params.insert("recvWindow".to_string(), json!(rw));
775        }
776
777        send_request::<models::GetSolStakingHistoryResponse>(
778            &self.configuration,
779            "/sapi/v1/sol-staking/sol/history/stakingHistory",
780            reqwest::Method::GET,
781            query_params,
782            body_params,
783            if HAS_TIME_UNIT {
784                self.configuration.time_unit
785            } else {
786                None
787            },
788            true,
789        )
790        .await
791    }
792
793    async fn get_sol_staking_quota_details(
794        &self,
795        params: GetSolStakingQuotaDetailsParams,
796    ) -> anyhow::Result<RestApiResponse<models::GetSolStakingQuotaDetailsResponse>> {
797        let GetSolStakingQuotaDetailsParams { recv_window } = params;
798
799        let mut query_params = BTreeMap::new();
800        let body_params = BTreeMap::new();
801
802        if let Some(rw) = recv_window {
803            query_params.insert("recvWindow".to_string(), json!(rw));
804        }
805
806        send_request::<models::GetSolStakingQuotaDetailsResponse>(
807            &self.configuration,
808            "/sapi/v1/sol-staking/sol/quota",
809            reqwest::Method::GET,
810            query_params,
811            body_params,
812            if HAS_TIME_UNIT {
813                self.configuration.time_unit
814            } else {
815                None
816            },
817            true,
818        )
819        .await
820    }
821
822    async fn get_unclaimed_rewards(
823        &self,
824        params: GetUnclaimedRewardsParams,
825    ) -> anyhow::Result<RestApiResponse<Vec<models::GetUnclaimedRewardsResponseInner>>> {
826        let GetUnclaimedRewardsParams { recv_window } = params;
827
828        let mut query_params = BTreeMap::new();
829        let body_params = BTreeMap::new();
830
831        if let Some(rw) = recv_window {
832            query_params.insert("recvWindow".to_string(), json!(rw));
833        }
834
835        send_request::<Vec<models::GetUnclaimedRewardsResponseInner>>(
836            &self.configuration,
837            "/sapi/v1/sol-staking/sol/history/unclaimedRewards",
838            reqwest::Method::GET,
839            query_params,
840            body_params,
841            if HAS_TIME_UNIT {
842                self.configuration.time_unit
843            } else {
844                None
845            },
846            true,
847        )
848        .await
849    }
850
851    async fn redeem_sol(
852        &self,
853        params: RedeemSolParams,
854    ) -> anyhow::Result<RestApiResponse<models::RedeemSolResponse>> {
855        let RedeemSolParams {
856            amount,
857            recv_window,
858        } = params;
859
860        let mut query_params = BTreeMap::new();
861        let body_params = BTreeMap::new();
862
863        query_params.insert("amount".to_string(), json!(amount));
864
865        if let Some(rw) = recv_window {
866            query_params.insert("recvWindow".to_string(), json!(rw));
867        }
868
869        send_request::<models::RedeemSolResponse>(
870            &self.configuration,
871            "/sapi/v1/sol-staking/sol/redeem",
872            reqwest::Method::POST,
873            query_params,
874            body_params,
875            if HAS_TIME_UNIT {
876                self.configuration.time_unit
877            } else {
878                None
879            },
880            true,
881        )
882        .await
883    }
884
885    async fn sol_staking_account(
886        &self,
887        params: SolStakingAccountParams,
888    ) -> anyhow::Result<RestApiResponse<models::SolStakingAccountResponse>> {
889        let SolStakingAccountParams { recv_window } = params;
890
891        let mut query_params = BTreeMap::new();
892        let body_params = BTreeMap::new();
893
894        if let Some(rw) = recv_window {
895            query_params.insert("recvWindow".to_string(), json!(rw));
896        }
897
898        send_request::<models::SolStakingAccountResponse>(
899            &self.configuration,
900            "/sapi/v1/sol-staking/account",
901            reqwest::Method::GET,
902            query_params,
903            body_params,
904            if HAS_TIME_UNIT {
905                self.configuration.time_unit
906            } else {
907                None
908            },
909            true,
910        )
911        .await
912    }
913
914    async fn subscribe_sol_staking(
915        &self,
916        params: SubscribeSolStakingParams,
917    ) -> anyhow::Result<RestApiResponse<models::SubscribeSolStakingResponse>> {
918        let SubscribeSolStakingParams {
919            amount,
920            recv_window,
921        } = params;
922
923        let mut query_params = BTreeMap::new();
924        let body_params = BTreeMap::new();
925
926        query_params.insert("amount".to_string(), json!(amount));
927
928        if let Some(rw) = recv_window {
929            query_params.insert("recvWindow".to_string(), json!(rw));
930        }
931
932        send_request::<models::SubscribeSolStakingResponse>(
933            &self.configuration,
934            "/sapi/v1/sol-staking/sol/stake",
935            reqwest::Method::POST,
936            query_params,
937            body_params,
938            if HAS_TIME_UNIT {
939                self.configuration.time_unit
940            } else {
941                None
942            },
943            true,
944        )
945        .await
946    }
947}
948
949#[cfg(all(test, feature = "staking"))]
950mod tests {
951    use super::*;
952    use crate::TOKIO_SHARED_RT;
953    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
954    use async_trait::async_trait;
955    use std::collections::HashMap;
956
957    struct DummyRestApiResponse<T> {
958        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
959        status: u16,
960        headers: HashMap<String, String>,
961        rate_limits: Option<Vec<RestApiRateLimit>>,
962    }
963
964    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
965        fn from(dummy: DummyRestApiResponse<T>) -> Self {
966            Self {
967                data_fn: dummy.inner,
968                status: dummy.status,
969                headers: dummy.headers,
970                rate_limits: dummy.rate_limits,
971            }
972        }
973    }
974
975    struct MockSolStakingApiClient {
976        force_error: bool,
977    }
978
979    #[async_trait]
980    impl SolStakingApi for MockSolStakingApiClient {
981        async fn claim_boost_rewards(
982            &self,
983            _params: ClaimBoostRewardsParams,
984        ) -> anyhow::Result<RestApiResponse<models::ClaimBoostRewardsResponse>> {
985            if self.force_error {
986                return Err(ConnectorError::ConnectorClientError {
987                    msg: "ResponseError".to_string(),
988                    code: None,
989                }
990                .into());
991            }
992
993            let resp_json: Value = serde_json::from_str(r#"{"success":true}"#).unwrap();
994            let dummy_response: models::ClaimBoostRewardsResponse =
995                serde_json::from_value(resp_json.clone())
996                    .expect("should parse into models::ClaimBoostRewardsResponse");
997
998            let dummy = DummyRestApiResponse {
999                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1000                status: 200,
1001                headers: HashMap::new(),
1002                rate_limits: None,
1003            };
1004
1005            Ok(dummy.into())
1006        }
1007
1008        async fn get_bnsol_rate_history(
1009            &self,
1010            _params: GetBnsolRateHistoryParams,
1011        ) -> anyhow::Result<RestApiResponse<models::GetBnsolRateHistoryResponse>> {
1012            if self.force_error {
1013                return Err(ConnectorError::ConnectorClientError {
1014                    msg: "ResponseError".to_string(),
1015                    code: None,
1016                }
1017                .into());
1018            }
1019
1020            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"annualPercentageRate":"0.00006408","exchangeRate":"1.001212343432","boostRewards":[{"boostAPR":"0.12000000","rewardsAsset":"SOL"},{"boostAPR":"0.00200000","rewardsAsset":"BNB"}],"time":1577233578000}],"total":"1"}"#).unwrap();
1021            let dummy_response: models::GetBnsolRateHistoryResponse =
1022                serde_json::from_value(resp_json.clone())
1023                    .expect("should parse into models::GetBnsolRateHistoryResponse");
1024
1025            let dummy = DummyRestApiResponse {
1026                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1027                status: 200,
1028                headers: HashMap::new(),
1029                rate_limits: None,
1030            };
1031
1032            Ok(dummy.into())
1033        }
1034
1035        async fn get_bnsol_rewards_history(
1036            &self,
1037            _params: GetBnsolRewardsHistoryParams,
1038        ) -> anyhow::Result<RestApiResponse<models::GetBnsolRewardsHistoryResponse>> {
1039            if self.force_error {
1040                return Err(ConnectorError::ConnectorClientError {
1041                    msg: "ResponseError".to_string(),
1042                    code: None,
1043                }
1044                .into());
1045            }
1046
1047            let resp_json: Value = serde_json::from_str(r#"{"estRewardsInSOL":"1.23230920","rows":[{"time":1575018510000,"amountInSOL":"0.23223","holding":"2.3223","holdingInSOL":"2.4231","annualPercentageRate":"0.5"}],"total":1}"#).unwrap();
1048            let dummy_response: models::GetBnsolRewardsHistoryResponse =
1049                serde_json::from_value(resp_json.clone())
1050                    .expect("should parse into models::GetBnsolRewardsHistoryResponse");
1051
1052            let dummy = DummyRestApiResponse {
1053                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1054                status: 200,
1055                headers: HashMap::new(),
1056                rate_limits: None,
1057            };
1058
1059            Ok(dummy.into())
1060        }
1061
1062        async fn get_boost_rewards_history(
1063            &self,
1064            _params: GetBoostRewardsHistoryParams,
1065        ) -> anyhow::Result<RestApiResponse<models::GetBoostRewardsHistoryResponse>> {
1066            if self.force_error {
1067                return Err(ConnectorError::ConnectorClientError {
1068                    msg: "ResponseError".to_string(),
1069                    code: None,
1070                }
1071                .into());
1072            }
1073
1074            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1729520680,"token":"SOL","amount":"1.20291028","bnsolHolding":"2.0928798","status":"SUCCESS"}],"total":1}"#).unwrap();
1075            let dummy_response: models::GetBoostRewardsHistoryResponse =
1076                serde_json::from_value(resp_json.clone())
1077                    .expect("should parse into models::GetBoostRewardsHistoryResponse");
1078
1079            let dummy = DummyRestApiResponse {
1080                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1081                status: 200,
1082                headers: HashMap::new(),
1083                rate_limits: None,
1084            };
1085
1086            Ok(dummy.into())
1087        }
1088
1089        async fn get_sol_redemption_history(
1090            &self,
1091            _params: GetSolRedemptionHistoryParams,
1092        ) -> anyhow::Result<RestApiResponse<models::GetSolRedemptionHistoryResponse>> {
1093            if self.force_error {
1094                return Err(ConnectorError::ConnectorClientError {
1095                    msg: "ResponseError".to_string(),
1096                    code: None,
1097                }
1098                .into());
1099            }
1100
1101            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"arrivalTime":1575018510000,"asset":"BNSOL","amount":"21312.23223","distributeAsset":"SOL","distributeAmount":"21338.0699","exchangeRate":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap();
1102            let dummy_response: models::GetSolRedemptionHistoryResponse =
1103                serde_json::from_value(resp_json.clone())
1104                    .expect("should parse into models::GetSolRedemptionHistoryResponse");
1105
1106            let dummy = DummyRestApiResponse {
1107                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1108                status: 200,
1109                headers: HashMap::new(),
1110                rate_limits: None,
1111            };
1112
1113            Ok(dummy.into())
1114        }
1115
1116        async fn get_sol_staking_history(
1117            &self,
1118            _params: GetSolStakingHistoryParams,
1119        ) -> anyhow::Result<RestApiResponse<models::GetSolStakingHistoryResponse>> {
1120            if self.force_error {
1121                return Err(ConnectorError::ConnectorClientError {
1122                    msg: "ResponseError".to_string(),
1123                    code: None,
1124                }
1125                .into());
1126            }
1127
1128            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"asset":"SOL","amount":"21312.23223","distributeAsset":"BNSOL","distributeAmount":"21286.42584","exchangeRate":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap();
1129            let dummy_response: models::GetSolStakingHistoryResponse =
1130                serde_json::from_value(resp_json.clone())
1131                    .expect("should parse into models::GetSolStakingHistoryResponse");
1132
1133            let dummy = DummyRestApiResponse {
1134                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1135                status: 200,
1136                headers: HashMap::new(),
1137                rate_limits: None,
1138            };
1139
1140            Ok(dummy.into())
1141        }
1142
1143        async fn get_sol_staking_quota_details(
1144            &self,
1145            _params: GetSolStakingQuotaDetailsParams,
1146        ) -> anyhow::Result<RestApiResponse<models::GetSolStakingQuotaDetailsResponse>> {
1147            if self.force_error {
1148                return Err(ConnectorError::ConnectorClientError {
1149                    msg: "ResponseError".to_string(),
1150                    code: None,
1151                }
1152                .into());
1153            }
1154
1155            let resp_json: Value = serde_json::from_str(r#"{"leftStakingPersonalQuota":"1000","leftRedemptionPersonalQuota":"1000","minStakeAmount":"0.01000000","minRedeemAmount":"0.00000001","redeemPeriod":4,"stakeable":true,"redeemable":true,"soldOut":false,"commissionFee":"0.25000000","nextEpochTime":725993969475,"calculating":false}"#).unwrap();
1156            let dummy_response: models::GetSolStakingQuotaDetailsResponse =
1157                serde_json::from_value(resp_json.clone())
1158                    .expect("should parse into models::GetSolStakingQuotaDetailsResponse");
1159
1160            let dummy = DummyRestApiResponse {
1161                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1162                status: 200,
1163                headers: HashMap::new(),
1164                rate_limits: None,
1165            };
1166
1167            Ok(dummy.into())
1168        }
1169
1170        async fn get_unclaimed_rewards(
1171            &self,
1172            _params: GetUnclaimedRewardsParams,
1173        ) -> anyhow::Result<RestApiResponse<Vec<models::GetUnclaimedRewardsResponseInner>>>
1174        {
1175            if self.force_error {
1176                return Err(ConnectorError::ConnectorClientError {
1177                    msg: "ResponseError".to_string(),
1178                    code: None,
1179                }
1180                .into());
1181            }
1182
1183            let resp_json: Value = serde_json::from_str(r#"[{"amount":"1.00000011","rewardsAsset":"SOL"},{"amount":"2.00202321","rewardsAsset":"BNB"}]"#).unwrap();
1184            let dummy_response: Vec<models::GetUnclaimedRewardsResponseInner> =
1185                serde_json::from_value(resp_json.clone())
1186                    .expect("should parse into Vec<models::GetUnclaimedRewardsResponseInner>");
1187
1188            let dummy = DummyRestApiResponse {
1189                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1190                status: 200,
1191                headers: HashMap::new(),
1192                rate_limits: None,
1193            };
1194
1195            Ok(dummy.into())
1196        }
1197
1198        async fn redeem_sol(
1199            &self,
1200            _params: RedeemSolParams,
1201        ) -> anyhow::Result<RestApiResponse<models::RedeemSolResponse>> {
1202            if self.force_error {
1203                return Err(ConnectorError::ConnectorClientError {
1204                    msg: "ResponseError".to_string(),
1205                    code: None,
1206                }
1207                .into());
1208            }
1209
1210            let resp_json: Value = serde_json::from_str(r#"{"success":true,"solAmount":"0.23092091","exchangeRate":"1.00121234","arrivalTime":1575018510000,"redeemId":1234567}"#).unwrap();
1211            let dummy_response: models::RedeemSolResponse =
1212                serde_json::from_value(resp_json.clone())
1213                    .expect("should parse into models::RedeemSolResponse");
1214
1215            let dummy = DummyRestApiResponse {
1216                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1217                status: 200,
1218                headers: HashMap::new(),
1219                rate_limits: None,
1220            };
1221
1222            Ok(dummy.into())
1223        }
1224
1225        async fn sol_staking_account(
1226            &self,
1227            _params: SolStakingAccountParams,
1228        ) -> anyhow::Result<RestApiResponse<models::SolStakingAccountResponse>> {
1229            if self.force_error {
1230                return Err(ConnectorError::ConnectorClientError {
1231                    msg: "ResponseError".to_string(),
1232                    code: None,
1233                }
1234                .into());
1235            }
1236
1237            let resp_json: Value = serde_json::from_str(r#"{"bnsolAmount":"1.10928781","holdingInSOL":"1.22330928","thirtyDaysProfitInSOL":"0.22330928"}"#).unwrap();
1238            let dummy_response: models::SolStakingAccountResponse =
1239                serde_json::from_value(resp_json.clone())
1240                    .expect("should parse into models::SolStakingAccountResponse");
1241
1242            let dummy = DummyRestApiResponse {
1243                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1244                status: 200,
1245                headers: HashMap::new(),
1246                rate_limits: None,
1247            };
1248
1249            Ok(dummy.into())
1250        }
1251
1252        async fn subscribe_sol_staking(
1253            &self,
1254            _params: SubscribeSolStakingParams,
1255        ) -> anyhow::Result<RestApiResponse<models::SubscribeSolStakingResponse>> {
1256            if self.force_error {
1257                return Err(ConnectorError::ConnectorClientError {
1258                    msg: "ResponseError".to_string(),
1259                    code: None,
1260                }
1261                .into());
1262            }
1263
1264            let resp_json: Value = serde_json::from_str(r#"{"success":true,"bnsolAmount":"0.23092091","exchangeRate":"1.001212342342","purchaseId":1234567}"#).unwrap();
1265            let dummy_response: models::SubscribeSolStakingResponse =
1266                serde_json::from_value(resp_json.clone())
1267                    .expect("should parse into models::SubscribeSolStakingResponse");
1268
1269            let dummy = DummyRestApiResponse {
1270                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1271                status: 200,
1272                headers: HashMap::new(),
1273                rate_limits: None,
1274            };
1275
1276            Ok(dummy.into())
1277        }
1278    }
1279
1280    #[test]
1281    fn claim_boost_rewards_required_params_success() {
1282        TOKIO_SHARED_RT.block_on(async {
1283            let client = MockSolStakingApiClient { force_error: false };
1284
1285            let params = ClaimBoostRewardsParams::builder().build().unwrap();
1286
1287            let resp_json: Value = serde_json::from_str(r#"{"success":true}"#).unwrap();
1288            let expected_response: models::ClaimBoostRewardsResponse =
1289                serde_json::from_value(resp_json.clone())
1290                    .expect("should parse into models::ClaimBoostRewardsResponse");
1291
1292            let resp = client
1293                .claim_boost_rewards(params)
1294                .await
1295                .expect("Expected a response");
1296            let data_future = resp.data();
1297            let actual_response = data_future.await.unwrap();
1298            assert_eq!(actual_response, expected_response);
1299        });
1300    }
1301
1302    #[test]
1303    fn claim_boost_rewards_optional_params_success() {
1304        TOKIO_SHARED_RT.block_on(async {
1305            let client = MockSolStakingApiClient { force_error: false };
1306
1307            let params = ClaimBoostRewardsParams::builder()
1308                .recv_window(5000)
1309                .build()
1310                .unwrap();
1311
1312            let resp_json: Value = serde_json::from_str(r#"{"success":true}"#).unwrap();
1313            let expected_response: models::ClaimBoostRewardsResponse =
1314                serde_json::from_value(resp_json.clone())
1315                    .expect("should parse into models::ClaimBoostRewardsResponse");
1316
1317            let resp = client
1318                .claim_boost_rewards(params)
1319                .await
1320                .expect("Expected a response");
1321            let data_future = resp.data();
1322            let actual_response = data_future.await.unwrap();
1323            assert_eq!(actual_response, expected_response);
1324        });
1325    }
1326
1327    #[test]
1328    fn claim_boost_rewards_response_error() {
1329        TOKIO_SHARED_RT.block_on(async {
1330            let client = MockSolStakingApiClient { force_error: true };
1331
1332            let params = ClaimBoostRewardsParams::builder().build().unwrap();
1333
1334            match client.claim_boost_rewards(params).await {
1335                Ok(_) => panic!("Expected an error"),
1336                Err(err) => {
1337                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1338                }
1339            }
1340        });
1341    }
1342
1343    #[test]
1344    fn get_bnsol_rate_history_required_params_success() {
1345        TOKIO_SHARED_RT.block_on(async {
1346            let client = MockSolStakingApiClient { force_error: false };
1347
1348            let params = GetBnsolRateHistoryParams::builder().build().unwrap();
1349
1350            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"annualPercentageRate":"0.00006408","exchangeRate":"1.001212343432","boostRewards":[{"boostAPR":"0.12000000","rewardsAsset":"SOL"},{"boostAPR":"0.00200000","rewardsAsset":"BNB"}],"time":1577233578000}],"total":"1"}"#).unwrap();
1351            let expected_response : models::GetBnsolRateHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetBnsolRateHistoryResponse");
1352
1353            let resp = client.get_bnsol_rate_history(params).await.expect("Expected a response");
1354            let data_future = resp.data();
1355            let actual_response = data_future.await.unwrap();
1356            assert_eq!(actual_response, expected_response);
1357        });
1358    }
1359
1360    #[test]
1361    fn get_bnsol_rate_history_optional_params_success() {
1362        TOKIO_SHARED_RT.block_on(async {
1363            let client = MockSolStakingApiClient { force_error: false };
1364
1365            let params = GetBnsolRateHistoryParams::builder().start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1366
1367            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"annualPercentageRate":"0.00006408","exchangeRate":"1.001212343432","boostRewards":[{"boostAPR":"0.12000000","rewardsAsset":"SOL"},{"boostAPR":"0.00200000","rewardsAsset":"BNB"}],"time":1577233578000}],"total":"1"}"#).unwrap();
1368            let expected_response : models::GetBnsolRateHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetBnsolRateHistoryResponse");
1369
1370            let resp = client.get_bnsol_rate_history(params).await.expect("Expected a response");
1371            let data_future = resp.data();
1372            let actual_response = data_future.await.unwrap();
1373            assert_eq!(actual_response, expected_response);
1374        });
1375    }
1376
1377    #[test]
1378    fn get_bnsol_rate_history_response_error() {
1379        TOKIO_SHARED_RT.block_on(async {
1380            let client = MockSolStakingApiClient { force_error: true };
1381
1382            let params = GetBnsolRateHistoryParams::builder().build().unwrap();
1383
1384            match client.get_bnsol_rate_history(params).await {
1385                Ok(_) => panic!("Expected an error"),
1386                Err(err) => {
1387                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1388                }
1389            }
1390        });
1391    }
1392
1393    #[test]
1394    fn get_bnsol_rewards_history_required_params_success() {
1395        TOKIO_SHARED_RT.block_on(async {
1396            let client = MockSolStakingApiClient { force_error: false };
1397
1398            let params = GetBnsolRewardsHistoryParams::builder().build().unwrap();
1399
1400            let resp_json: Value = serde_json::from_str(r#"{"estRewardsInSOL":"1.23230920","rows":[{"time":1575018510000,"amountInSOL":"0.23223","holding":"2.3223","holdingInSOL":"2.4231","annualPercentageRate":"0.5"}],"total":1}"#).unwrap();
1401            let expected_response : models::GetBnsolRewardsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetBnsolRewardsHistoryResponse");
1402
1403            let resp = client.get_bnsol_rewards_history(params).await.expect("Expected a response");
1404            let data_future = resp.data();
1405            let actual_response = data_future.await.unwrap();
1406            assert_eq!(actual_response, expected_response);
1407        });
1408    }
1409
1410    #[test]
1411    fn get_bnsol_rewards_history_optional_params_success() {
1412        TOKIO_SHARED_RT.block_on(async {
1413            let client = MockSolStakingApiClient { force_error: false };
1414
1415            let params = GetBnsolRewardsHistoryParams::builder().start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1416
1417            let resp_json: Value = serde_json::from_str(r#"{"estRewardsInSOL":"1.23230920","rows":[{"time":1575018510000,"amountInSOL":"0.23223","holding":"2.3223","holdingInSOL":"2.4231","annualPercentageRate":"0.5"}],"total":1}"#).unwrap();
1418            let expected_response : models::GetBnsolRewardsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetBnsolRewardsHistoryResponse");
1419
1420            let resp = client.get_bnsol_rewards_history(params).await.expect("Expected a response");
1421            let data_future = resp.data();
1422            let actual_response = data_future.await.unwrap();
1423            assert_eq!(actual_response, expected_response);
1424        });
1425    }
1426
1427    #[test]
1428    fn get_bnsol_rewards_history_response_error() {
1429        TOKIO_SHARED_RT.block_on(async {
1430            let client = MockSolStakingApiClient { force_error: true };
1431
1432            let params = GetBnsolRewardsHistoryParams::builder().build().unwrap();
1433
1434            match client.get_bnsol_rewards_history(params).await {
1435                Ok(_) => panic!("Expected an error"),
1436                Err(err) => {
1437                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1438                }
1439            }
1440        });
1441    }
1442
1443    #[test]
1444    fn get_boost_rewards_history_required_params_success() {
1445        TOKIO_SHARED_RT.block_on(async {
1446            let client = MockSolStakingApiClient { force_error: false };
1447
1448            let params = GetBoostRewardsHistoryParams::builder("CLAIM".to_string(),).build().unwrap();
1449
1450            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1729520680,"token":"SOL","amount":"1.20291028","bnsolHolding":"2.0928798","status":"SUCCESS"}],"total":1}"#).unwrap();
1451            let expected_response : models::GetBoostRewardsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetBoostRewardsHistoryResponse");
1452
1453            let resp = client.get_boost_rewards_history(params).await.expect("Expected a response");
1454            let data_future = resp.data();
1455            let actual_response = data_future.await.unwrap();
1456            assert_eq!(actual_response, expected_response);
1457        });
1458    }
1459
1460    #[test]
1461    fn get_boost_rewards_history_optional_params_success() {
1462        TOKIO_SHARED_RT.block_on(async {
1463            let client = MockSolStakingApiClient { force_error: false };
1464
1465            let params = GetBoostRewardsHistoryParams::builder("CLAIM".to_string(),).start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1466
1467            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1729520680,"token":"SOL","amount":"1.20291028","bnsolHolding":"2.0928798","status":"SUCCESS"}],"total":1}"#).unwrap();
1468            let expected_response : models::GetBoostRewardsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetBoostRewardsHistoryResponse");
1469
1470            let resp = client.get_boost_rewards_history(params).await.expect("Expected a response");
1471            let data_future = resp.data();
1472            let actual_response = data_future.await.unwrap();
1473            assert_eq!(actual_response, expected_response);
1474        });
1475    }
1476
1477    #[test]
1478    fn get_boost_rewards_history_response_error() {
1479        TOKIO_SHARED_RT.block_on(async {
1480            let client = MockSolStakingApiClient { force_error: true };
1481
1482            let params = GetBoostRewardsHistoryParams::builder("CLAIM".to_string())
1483                .build()
1484                .unwrap();
1485
1486            match client.get_boost_rewards_history(params).await {
1487                Ok(_) => panic!("Expected an error"),
1488                Err(err) => {
1489                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1490                }
1491            }
1492        });
1493    }
1494
1495    #[test]
1496    fn get_sol_redemption_history_required_params_success() {
1497        TOKIO_SHARED_RT.block_on(async {
1498            let client = MockSolStakingApiClient { force_error: false };
1499
1500            let params = GetSolRedemptionHistoryParams::builder().build().unwrap();
1501
1502            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"arrivalTime":1575018510000,"asset":"BNSOL","amount":"21312.23223","distributeAsset":"SOL","distributeAmount":"21338.0699","exchangeRate":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap();
1503            let expected_response : models::GetSolRedemptionHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetSolRedemptionHistoryResponse");
1504
1505            let resp = client.get_sol_redemption_history(params).await.expect("Expected a response");
1506            let data_future = resp.data();
1507            let actual_response = data_future.await.unwrap();
1508            assert_eq!(actual_response, expected_response);
1509        });
1510    }
1511
1512    #[test]
1513    fn get_sol_redemption_history_optional_params_success() {
1514        TOKIO_SHARED_RT.block_on(async {
1515            let client = MockSolStakingApiClient { force_error: false };
1516
1517            let params = GetSolRedemptionHistoryParams::builder().redeem_id(1).start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1518
1519            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"arrivalTime":1575018510000,"asset":"BNSOL","amount":"21312.23223","distributeAsset":"SOL","distributeAmount":"21338.0699","exchangeRate":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap();
1520            let expected_response : models::GetSolRedemptionHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetSolRedemptionHistoryResponse");
1521
1522            let resp = client.get_sol_redemption_history(params).await.expect("Expected a response");
1523            let data_future = resp.data();
1524            let actual_response = data_future.await.unwrap();
1525            assert_eq!(actual_response, expected_response);
1526        });
1527    }
1528
1529    #[test]
1530    fn get_sol_redemption_history_response_error() {
1531        TOKIO_SHARED_RT.block_on(async {
1532            let client = MockSolStakingApiClient { force_error: true };
1533
1534            let params = GetSolRedemptionHistoryParams::builder().build().unwrap();
1535
1536            match client.get_sol_redemption_history(params).await {
1537                Ok(_) => panic!("Expected an error"),
1538                Err(err) => {
1539                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1540                }
1541            }
1542        });
1543    }
1544
1545    #[test]
1546    fn get_sol_staking_history_required_params_success() {
1547        TOKIO_SHARED_RT.block_on(async {
1548            let client = MockSolStakingApiClient { force_error: false };
1549
1550            let params = GetSolStakingHistoryParams::builder().build().unwrap();
1551
1552            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"asset":"SOL","amount":"21312.23223","distributeAsset":"BNSOL","distributeAmount":"21286.42584","exchangeRate":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap();
1553            let expected_response : models::GetSolStakingHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetSolStakingHistoryResponse");
1554
1555            let resp = client.get_sol_staking_history(params).await.expect("Expected a response");
1556            let data_future = resp.data();
1557            let actual_response = data_future.await.unwrap();
1558            assert_eq!(actual_response, expected_response);
1559        });
1560    }
1561
1562    #[test]
1563    fn get_sol_staking_history_optional_params_success() {
1564        TOKIO_SHARED_RT.block_on(async {
1565            let client = MockSolStakingApiClient { force_error: false };
1566
1567            let params = GetSolStakingHistoryParams::builder().purchase_id(1).start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1568
1569            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"asset":"SOL","amount":"21312.23223","distributeAsset":"BNSOL","distributeAmount":"21286.42584","exchangeRate":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap();
1570            let expected_response : models::GetSolStakingHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetSolStakingHistoryResponse");
1571
1572            let resp = client.get_sol_staking_history(params).await.expect("Expected a response");
1573            let data_future = resp.data();
1574            let actual_response = data_future.await.unwrap();
1575            assert_eq!(actual_response, expected_response);
1576        });
1577    }
1578
1579    #[test]
1580    fn get_sol_staking_history_response_error() {
1581        TOKIO_SHARED_RT.block_on(async {
1582            let client = MockSolStakingApiClient { force_error: true };
1583
1584            let params = GetSolStakingHistoryParams::builder().build().unwrap();
1585
1586            match client.get_sol_staking_history(params).await {
1587                Ok(_) => panic!("Expected an error"),
1588                Err(err) => {
1589                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1590                }
1591            }
1592        });
1593    }
1594
1595    #[test]
1596    fn get_sol_staking_quota_details_required_params_success() {
1597        TOKIO_SHARED_RT.block_on(async {
1598            let client = MockSolStakingApiClient { force_error: false };
1599
1600            let params = GetSolStakingQuotaDetailsParams::builder().build().unwrap();
1601
1602            let resp_json: Value = serde_json::from_str(r#"{"leftStakingPersonalQuota":"1000","leftRedemptionPersonalQuota":"1000","minStakeAmount":"0.01000000","minRedeemAmount":"0.00000001","redeemPeriod":4,"stakeable":true,"redeemable":true,"soldOut":false,"commissionFee":"0.25000000","nextEpochTime":725993969475,"calculating":false}"#).unwrap();
1603            let expected_response : models::GetSolStakingQuotaDetailsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetSolStakingQuotaDetailsResponse");
1604
1605            let resp = client.get_sol_staking_quota_details(params).await.expect("Expected a response");
1606            let data_future = resp.data();
1607            let actual_response = data_future.await.unwrap();
1608            assert_eq!(actual_response, expected_response);
1609        });
1610    }
1611
1612    #[test]
1613    fn get_sol_staking_quota_details_optional_params_success() {
1614        TOKIO_SHARED_RT.block_on(async {
1615            let client = MockSolStakingApiClient { force_error: false };
1616
1617            let params = GetSolStakingQuotaDetailsParams::builder().recv_window(5000).build().unwrap();
1618
1619            let resp_json: Value = serde_json::from_str(r#"{"leftStakingPersonalQuota":"1000","leftRedemptionPersonalQuota":"1000","minStakeAmount":"0.01000000","minRedeemAmount":"0.00000001","redeemPeriod":4,"stakeable":true,"redeemable":true,"soldOut":false,"commissionFee":"0.25000000","nextEpochTime":725993969475,"calculating":false}"#).unwrap();
1620            let expected_response : models::GetSolStakingQuotaDetailsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetSolStakingQuotaDetailsResponse");
1621
1622            let resp = client.get_sol_staking_quota_details(params).await.expect("Expected a response");
1623            let data_future = resp.data();
1624            let actual_response = data_future.await.unwrap();
1625            assert_eq!(actual_response, expected_response);
1626        });
1627    }
1628
1629    #[test]
1630    fn get_sol_staking_quota_details_response_error() {
1631        TOKIO_SHARED_RT.block_on(async {
1632            let client = MockSolStakingApiClient { force_error: true };
1633
1634            let params = GetSolStakingQuotaDetailsParams::builder().build().unwrap();
1635
1636            match client.get_sol_staking_quota_details(params).await {
1637                Ok(_) => panic!("Expected an error"),
1638                Err(err) => {
1639                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1640                }
1641            }
1642        });
1643    }
1644
1645    #[test]
1646    fn get_unclaimed_rewards_required_params_success() {
1647        TOKIO_SHARED_RT.block_on(async {
1648            let client = MockSolStakingApiClient { force_error: false };
1649
1650            let params = GetUnclaimedRewardsParams::builder().build().unwrap();
1651
1652            let resp_json: Value = serde_json::from_str(r#"[{"amount":"1.00000011","rewardsAsset":"SOL"},{"amount":"2.00202321","rewardsAsset":"BNB"}]"#).unwrap();
1653            let expected_response : Vec<models::GetUnclaimedRewardsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetUnclaimedRewardsResponseInner>");
1654
1655            let resp = client.get_unclaimed_rewards(params).await.expect("Expected a response");
1656            let data_future = resp.data();
1657            let actual_response = data_future.await.unwrap();
1658            assert_eq!(actual_response, expected_response);
1659        });
1660    }
1661
1662    #[test]
1663    fn get_unclaimed_rewards_optional_params_success() {
1664        TOKIO_SHARED_RT.block_on(async {
1665            let client = MockSolStakingApiClient { force_error: false };
1666
1667            let params = GetUnclaimedRewardsParams::builder().recv_window(5000).build().unwrap();
1668
1669            let resp_json: Value = serde_json::from_str(r#"[{"amount":"1.00000011","rewardsAsset":"SOL"},{"amount":"2.00202321","rewardsAsset":"BNB"}]"#).unwrap();
1670            let expected_response : Vec<models::GetUnclaimedRewardsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetUnclaimedRewardsResponseInner>");
1671
1672            let resp = client.get_unclaimed_rewards(params).await.expect("Expected a response");
1673            let data_future = resp.data();
1674            let actual_response = data_future.await.unwrap();
1675            assert_eq!(actual_response, expected_response);
1676        });
1677    }
1678
1679    #[test]
1680    fn get_unclaimed_rewards_response_error() {
1681        TOKIO_SHARED_RT.block_on(async {
1682            let client = MockSolStakingApiClient { force_error: true };
1683
1684            let params = GetUnclaimedRewardsParams::builder().build().unwrap();
1685
1686            match client.get_unclaimed_rewards(params).await {
1687                Ok(_) => panic!("Expected an error"),
1688                Err(err) => {
1689                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1690                }
1691            }
1692        });
1693    }
1694
1695    #[test]
1696    fn redeem_sol_required_params_success() {
1697        TOKIO_SHARED_RT.block_on(async {
1698            let client = MockSolStakingApiClient { force_error: false };
1699
1700            let params = RedeemSolParams::builder(dec!(1.0),).build().unwrap();
1701
1702            let resp_json: Value = serde_json::from_str(r#"{"success":true,"solAmount":"0.23092091","exchangeRate":"1.00121234","arrivalTime":1575018510000,"redeemId":1234567}"#).unwrap();
1703            let expected_response : models::RedeemSolResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RedeemSolResponse");
1704
1705            let resp = client.redeem_sol(params).await.expect("Expected a response");
1706            let data_future = resp.data();
1707            let actual_response = data_future.await.unwrap();
1708            assert_eq!(actual_response, expected_response);
1709        });
1710    }
1711
1712    #[test]
1713    fn redeem_sol_optional_params_success() {
1714        TOKIO_SHARED_RT.block_on(async {
1715            let client = MockSolStakingApiClient { force_error: false };
1716
1717            let params = RedeemSolParams::builder(dec!(1.0),).recv_window(5000).build().unwrap();
1718
1719            let resp_json: Value = serde_json::from_str(r#"{"success":true,"solAmount":"0.23092091","exchangeRate":"1.00121234","arrivalTime":1575018510000,"redeemId":1234567}"#).unwrap();
1720            let expected_response : models::RedeemSolResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RedeemSolResponse");
1721
1722            let resp = client.redeem_sol(params).await.expect("Expected a response");
1723            let data_future = resp.data();
1724            let actual_response = data_future.await.unwrap();
1725            assert_eq!(actual_response, expected_response);
1726        });
1727    }
1728
1729    #[test]
1730    fn redeem_sol_response_error() {
1731        TOKIO_SHARED_RT.block_on(async {
1732            let client = MockSolStakingApiClient { force_error: true };
1733
1734            let params = RedeemSolParams::builder(dec!(1.0)).build().unwrap();
1735
1736            match client.redeem_sol(params).await {
1737                Ok(_) => panic!("Expected an error"),
1738                Err(err) => {
1739                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1740                }
1741            }
1742        });
1743    }
1744
1745    #[test]
1746    fn sol_staking_account_required_params_success() {
1747        TOKIO_SHARED_RT.block_on(async {
1748            let client = MockSolStakingApiClient { force_error: false };
1749
1750            let params = SolStakingAccountParams::builder().build().unwrap();
1751
1752            let resp_json: Value = serde_json::from_str(r#"{"bnsolAmount":"1.10928781","holdingInSOL":"1.22330928","thirtyDaysProfitInSOL":"0.22330928"}"#).unwrap();
1753            let expected_response : models::SolStakingAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::SolStakingAccountResponse");
1754
1755            let resp = client.sol_staking_account(params).await.expect("Expected a response");
1756            let data_future = resp.data();
1757            let actual_response = data_future.await.unwrap();
1758            assert_eq!(actual_response, expected_response);
1759        });
1760    }
1761
1762    #[test]
1763    fn sol_staking_account_optional_params_success() {
1764        TOKIO_SHARED_RT.block_on(async {
1765            let client = MockSolStakingApiClient { force_error: false };
1766
1767            let params = SolStakingAccountParams::builder().recv_window(5000).build().unwrap();
1768
1769            let resp_json: Value = serde_json::from_str(r#"{"bnsolAmount":"1.10928781","holdingInSOL":"1.22330928","thirtyDaysProfitInSOL":"0.22330928"}"#).unwrap();
1770            let expected_response : models::SolStakingAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::SolStakingAccountResponse");
1771
1772            let resp = client.sol_staking_account(params).await.expect("Expected a response");
1773            let data_future = resp.data();
1774            let actual_response = data_future.await.unwrap();
1775            assert_eq!(actual_response, expected_response);
1776        });
1777    }
1778
1779    #[test]
1780    fn sol_staking_account_response_error() {
1781        TOKIO_SHARED_RT.block_on(async {
1782            let client = MockSolStakingApiClient { force_error: true };
1783
1784            let params = SolStakingAccountParams::builder().build().unwrap();
1785
1786            match client.sol_staking_account(params).await {
1787                Ok(_) => panic!("Expected an error"),
1788                Err(err) => {
1789                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1790                }
1791            }
1792        });
1793    }
1794
1795    #[test]
1796    fn subscribe_sol_staking_required_params_success() {
1797        TOKIO_SHARED_RT.block_on(async {
1798            let client = MockSolStakingApiClient { force_error: false };
1799
1800            let params = SubscribeSolStakingParams::builder(dec!(1.0),).build().unwrap();
1801
1802            let resp_json: Value = serde_json::from_str(r#"{"success":true,"bnsolAmount":"0.23092091","exchangeRate":"1.001212342342","purchaseId":1234567}"#).unwrap();
1803            let expected_response : models::SubscribeSolStakingResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::SubscribeSolStakingResponse");
1804
1805            let resp = client.subscribe_sol_staking(params).await.expect("Expected a response");
1806            let data_future = resp.data();
1807            let actual_response = data_future.await.unwrap();
1808            assert_eq!(actual_response, expected_response);
1809        });
1810    }
1811
1812    #[test]
1813    fn subscribe_sol_staking_optional_params_success() {
1814        TOKIO_SHARED_RT.block_on(async {
1815            let client = MockSolStakingApiClient { force_error: false };
1816
1817            let params = SubscribeSolStakingParams::builder(dec!(1.0),).recv_window(5000).build().unwrap();
1818
1819            let resp_json: Value = serde_json::from_str(r#"{"success":true,"bnsolAmount":"0.23092091","exchangeRate":"1.001212342342","purchaseId":1234567}"#).unwrap();
1820            let expected_response : models::SubscribeSolStakingResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::SubscribeSolStakingResponse");
1821
1822            let resp = client.subscribe_sol_staking(params).await.expect("Expected a response");
1823            let data_future = resp.data();
1824            let actual_response = data_future.await.unwrap();
1825            assert_eq!(actual_response, expected_response);
1826        });
1827    }
1828
1829    #[test]
1830    fn subscribe_sol_staking_response_error() {
1831        TOKIO_SHARED_RT.block_on(async {
1832            let client = MockSolStakingApiClient { force_error: true };
1833
1834            let params = SubscribeSolStakingParams::builder(dec!(1.0))
1835                .build()
1836                .unwrap();
1837
1838            match client.subscribe_sol_staking(params).await {
1839                Ok(_) => panic!("Expected an error"),
1840                Err(err) => {
1841                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1842                }
1843            }
1844        });
1845    }
1846}