Skip to main content

binance_sdk/staking/rest_api/apis/
sol_staking_api.rs

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