1#![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 EthStakingApi: Send + Sync {
34 async fn eth_staking_account(
35 &self,
36 params: EthStakingAccountParams,
37 ) -> anyhow::Result<RestApiResponse<models::EthStakingAccountResponse>>;
38 async fn get_current_eth_staking_quota(
39 &self,
40 params: GetCurrentEthStakingQuotaParams,
41 ) -> anyhow::Result<RestApiResponse<models::GetCurrentEthStakingQuotaResponse>>;
42 async fn get_eth_redemption_history(
43 &self,
44 params: GetEthRedemptionHistoryParams,
45 ) -> anyhow::Result<RestApiResponse<models::GetEthRedemptionHistoryResponse>>;
46 async fn get_eth_staking_history(
47 &self,
48 params: GetEthStakingHistoryParams,
49 ) -> anyhow::Result<RestApiResponse<models::GetEthStakingHistoryResponse>>;
50 async fn get_wbeth_rate_history(
51 &self,
52 params: GetWbethRateHistoryParams,
53 ) -> anyhow::Result<RestApiResponse<models::GetWbethRateHistoryResponse>>;
54 async fn get_wbeth_rewards_history(
55 &self,
56 params: GetWbethRewardsHistoryParams,
57 ) -> anyhow::Result<RestApiResponse<models::GetWbethRewardsHistoryResponse>>;
58 async fn get_wbeth_unwrap_history(
59 &self,
60 params: GetWbethUnwrapHistoryParams,
61 ) -> anyhow::Result<RestApiResponse<models::GetWbethUnwrapHistoryResponse>>;
62 async fn get_wbeth_wrap_history(
63 &self,
64 params: GetWbethWrapHistoryParams,
65 ) -> anyhow::Result<RestApiResponse<models::GetWbethWrapHistoryResponse>>;
66 async fn redeem_eth(
67 &self,
68 params: RedeemEthParams,
69 ) -> anyhow::Result<RestApiResponse<models::RedeemEthResponse>>;
70 async fn subscribe_eth_staking(
71 &self,
72 params: SubscribeEthStakingParams,
73 ) -> anyhow::Result<RestApiResponse<models::SubscribeEthStakingResponse>>;
74 async fn wrap_beth(
75 &self,
76 params: WrapBethParams,
77 ) -> anyhow::Result<RestApiResponse<models::WrapBethResponse>>;
78}
79
80#[derive(Debug, Clone)]
81pub struct EthStakingApiClient {
82 configuration: ConfigurationRestApi,
83}
84
85impl EthStakingApiClient {
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 RedeemEthAssetEnum {
94 #[serde(rename = "WBETH")]
95 Wbeth,
96 #[serde(rename = "BETH")]
97 Beth,
98}
99
100impl RedeemEthAssetEnum {
101 #[must_use]
102 pub fn as_str(&self) -> &'static str {
103 match self {
104 Self::Wbeth => "WBETH",
105 Self::Beth => "BETH",
106 }
107 }
108}
109
110impl std::str::FromStr for RedeemEthAssetEnum {
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 "WBETH" => Ok(Self::Wbeth),
116 "BETH" => Ok(Self::Beth),
117 other => Err(format!("invalid RedeemEthAssetEnum: {}", other).into()),
118 }
119 }
120}
121
122#[derive(Clone, Debug, Builder, Deserialize, Default)]
127#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
128pub struct EthStakingAccountParams {
129 #[builder(setter(into), default)]
133 #[serde(rename = "recvWindow", default)]
134 pub recv_window: Option<i64>,
135}
136
137impl EthStakingAccountParams {
138 #[must_use]
141 pub fn builder() -> EthStakingAccountParamsBuilder {
142 EthStakingAccountParamsBuilder::default()
143 }
144}
145#[derive(Clone, Debug, Builder, Deserialize, Default)]
150#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
151pub struct GetCurrentEthStakingQuotaParams {
152 #[builder(setter(into), default)]
156 #[serde(rename = "recvWindow", default)]
157 pub recv_window: Option<i64>,
158}
159
160impl GetCurrentEthStakingQuotaParams {
161 #[must_use]
164 pub fn builder() -> GetCurrentEthStakingQuotaParamsBuilder {
165 GetCurrentEthStakingQuotaParamsBuilder::default()
166 }
167}
168#[derive(Clone, Debug, Builder, Deserialize, Default)]
173#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
174pub struct GetEthRedemptionHistoryParams {
175 #[builder(setter(into), default)]
180 #[serde(rename = "redeemId", default)]
181 pub redeem_id: Option<i64>,
182 #[builder(setter(into), default)]
187 #[serde(rename = "startTime", default)]
188 pub start_time: Option<i64>,
189 #[builder(setter(into), default)]
194 #[serde(rename = "endTime", default)]
195 pub end_time: Option<i64>,
196 #[builder(setter(into), default)]
200 #[serde(rename = "current", default)]
201 pub current: Option<i64>,
202 #[builder(setter(into), default)]
207 #[serde(rename = "size", default)]
208 pub size: Option<i64>,
209 #[builder(setter(into), default)]
213 #[serde(rename = "recvWindow", default)]
214 pub recv_window: Option<i64>,
215}
216
217impl GetEthRedemptionHistoryParams {
218 #[must_use]
221 pub fn builder() -> GetEthRedemptionHistoryParamsBuilder {
222 GetEthRedemptionHistoryParamsBuilder::default()
223 }
224}
225#[derive(Clone, Debug, Builder, Deserialize, Default)]
230#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
231pub struct GetEthStakingHistoryParams {
232 #[builder(setter(into), default)]
237 #[serde(rename = "purchaseId", default)]
238 pub purchase_id: Option<i64>,
239 #[builder(setter(into), default)]
244 #[serde(rename = "startTime", default)]
245 pub start_time: Option<i64>,
246 #[builder(setter(into), default)]
251 #[serde(rename = "endTime", default)]
252 pub end_time: Option<i64>,
253 #[builder(setter(into), default)]
257 #[serde(rename = "current", default)]
258 pub current: Option<i64>,
259 #[builder(setter(into), default)]
264 #[serde(rename = "size", default)]
265 pub size: Option<i64>,
266 #[builder(setter(into), default)]
270 #[serde(rename = "recvWindow", default)]
271 pub recv_window: Option<i64>,
272}
273
274impl GetEthStakingHistoryParams {
275 #[must_use]
278 pub fn builder() -> GetEthStakingHistoryParamsBuilder {
279 GetEthStakingHistoryParamsBuilder::default()
280 }
281}
282#[derive(Clone, Debug, Builder, Deserialize, Default)]
287#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
288pub struct GetWbethRateHistoryParams {
289 #[builder(setter(into), default)]
294 #[serde(rename = "startTime", default)]
295 pub start_time: Option<i64>,
296 #[builder(setter(into), default)]
301 #[serde(rename = "endTime", default)]
302 pub end_time: Option<i64>,
303 #[builder(setter(into), default)]
307 #[serde(rename = "current", default)]
308 pub current: Option<i64>,
309 #[builder(setter(into), default)]
314 #[serde(rename = "size", default)]
315 pub size: Option<i64>,
316 #[builder(setter(into), default)]
320 #[serde(rename = "recvWindow", default)]
321 pub recv_window: Option<i64>,
322}
323
324impl GetWbethRateHistoryParams {
325 #[must_use]
328 pub fn builder() -> GetWbethRateHistoryParamsBuilder {
329 GetWbethRateHistoryParamsBuilder::default()
330 }
331}
332#[derive(Clone, Debug, Builder, Deserialize, Default)]
337#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
338pub struct GetWbethRewardsHistoryParams {
339 #[builder(setter(into), default)]
344 #[serde(rename = "startTime", default)]
345 pub start_time: Option<i64>,
346 #[builder(setter(into), default)]
351 #[serde(rename = "endTime", default)]
352 pub end_time: Option<i64>,
353 #[builder(setter(into), default)]
357 #[serde(rename = "current", default)]
358 pub current: Option<i64>,
359 #[builder(setter(into), default)]
364 #[serde(rename = "size", default)]
365 pub size: Option<i64>,
366 #[builder(setter(into), default)]
370 #[serde(rename = "recvWindow", default)]
371 pub recv_window: Option<i64>,
372}
373
374impl GetWbethRewardsHistoryParams {
375 #[must_use]
378 pub fn builder() -> GetWbethRewardsHistoryParamsBuilder {
379 GetWbethRewardsHistoryParamsBuilder::default()
380 }
381}
382#[derive(Clone, Debug, Builder, Deserialize, Default)]
387#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
388pub struct GetWbethUnwrapHistoryParams {
389 #[builder(setter(into), default)]
394 #[serde(rename = "startTime", default)]
395 pub start_time: Option<i64>,
396 #[builder(setter(into), default)]
401 #[serde(rename = "endTime", default)]
402 pub end_time: Option<i64>,
403 #[builder(setter(into), default)]
407 #[serde(rename = "current", default)]
408 pub current: Option<i64>,
409 #[builder(setter(into), default)]
414 #[serde(rename = "size", default)]
415 pub size: Option<i64>,
416 #[builder(setter(into), default)]
420 #[serde(rename = "recvWindow", default)]
421 pub recv_window: Option<i64>,
422}
423
424impl GetWbethUnwrapHistoryParams {
425 #[must_use]
428 pub fn builder() -> GetWbethUnwrapHistoryParamsBuilder {
429 GetWbethUnwrapHistoryParamsBuilder::default()
430 }
431}
432#[derive(Clone, Debug, Builder, Deserialize, Default)]
437#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
438pub struct GetWbethWrapHistoryParams {
439 #[builder(setter(into), default)]
444 #[serde(rename = "startTime", default)]
445 pub start_time: Option<i64>,
446 #[builder(setter(into), default)]
451 #[serde(rename = "endTime", default)]
452 pub end_time: Option<i64>,
453 #[builder(setter(into), default)]
457 #[serde(rename = "current", default)]
458 pub current: Option<i64>,
459 #[builder(setter(into), default)]
464 #[serde(rename = "size", default)]
465 pub size: Option<i64>,
466 #[builder(setter(into), default)]
470 #[serde(rename = "recvWindow", default)]
471 pub recv_window: Option<i64>,
472}
473
474impl GetWbethWrapHistoryParams {
475 #[must_use]
478 pub fn builder() -> GetWbethWrapHistoryParamsBuilder {
479 GetWbethWrapHistoryParamsBuilder::default()
480 }
481}
482#[derive(Clone, Debug, Builder, Deserialize)]
487#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
488pub struct RedeemEthParams {
489 #[builder(setter(into))]
493 #[serde(rename = "amount")]
494 pub amount: rust_decimal::Decimal,
495 #[builder(setter(into), default)]
500 #[serde(rename = "asset", default)]
501 pub asset: Option<RedeemEthAssetEnum>,
502 #[builder(setter(into), default)]
506 #[serde(rename = "recvWindow", default)]
507 pub recv_window: Option<i64>,
508}
509
510impl RedeemEthParams {
511 #[must_use]
518 pub fn builder(amount: rust_decimal::Decimal) -> RedeemEthParamsBuilder {
519 RedeemEthParamsBuilder::default().amount(amount)
520 }
521}
522#[derive(Clone, Debug, Builder, Deserialize)]
527#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
528pub struct SubscribeEthStakingParams {
529 #[builder(setter(into))]
533 #[serde(rename = "amount")]
534 pub amount: rust_decimal::Decimal,
535 #[builder(setter(into), default)]
539 #[serde(rename = "recvWindow", default)]
540 pub recv_window: Option<i64>,
541}
542
543impl SubscribeEthStakingParams {
544 #[must_use]
551 pub fn builder(amount: rust_decimal::Decimal) -> SubscribeEthStakingParamsBuilder {
552 SubscribeEthStakingParamsBuilder::default().amount(amount)
553 }
554}
555#[derive(Clone, Debug, Builder, Deserialize)]
560#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
561pub struct WrapBethParams {
562 #[builder(setter(into))]
566 #[serde(rename = "amount")]
567 pub amount: rust_decimal::Decimal,
568 #[builder(setter(into), default)]
572 #[serde(rename = "recvWindow", default)]
573 pub recv_window: Option<i64>,
574}
575
576impl WrapBethParams {
577 #[must_use]
584 pub fn builder(amount: rust_decimal::Decimal) -> WrapBethParamsBuilder {
585 WrapBethParamsBuilder::default().amount(amount)
586 }
587}
588
589#[async_trait]
590impl EthStakingApi for EthStakingApiClient {
591 async fn eth_staking_account(
592 &self,
593 params: EthStakingAccountParams,
594 ) -> anyhow::Result<RestApiResponse<models::EthStakingAccountResponse>> {
595 let EthStakingAccountParams { recv_window } = params;
596
597 let mut query_params = BTreeMap::new();
598 let body_params = BTreeMap::new();
599
600 if let Some(rw) = recv_window {
601 query_params.insert("recvWindow".to_string(), json!(rw));
602 }
603
604 send_request::<models::EthStakingAccountResponse>(
605 &self.configuration,
606 "/sapi/v2/eth-staking/account",
607 reqwest::Method::GET,
608 query_params,
609 body_params,
610 if HAS_TIME_UNIT {
611 self.configuration.time_unit
612 } else {
613 None
614 },
615 true,
616 )
617 .await
618 }
619
620 async fn get_current_eth_staking_quota(
621 &self,
622 params: GetCurrentEthStakingQuotaParams,
623 ) -> anyhow::Result<RestApiResponse<models::GetCurrentEthStakingQuotaResponse>> {
624 let GetCurrentEthStakingQuotaParams { recv_window } = params;
625
626 let mut query_params = BTreeMap::new();
627 let body_params = BTreeMap::new();
628
629 if let Some(rw) = recv_window {
630 query_params.insert("recvWindow".to_string(), json!(rw));
631 }
632
633 send_request::<models::GetCurrentEthStakingQuotaResponse>(
634 &self.configuration,
635 "/sapi/v1/eth-staking/eth/quota",
636 reqwest::Method::GET,
637 query_params,
638 body_params,
639 if HAS_TIME_UNIT {
640 self.configuration.time_unit
641 } else {
642 None
643 },
644 true,
645 )
646 .await
647 }
648
649 async fn get_eth_redemption_history(
650 &self,
651 params: GetEthRedemptionHistoryParams,
652 ) -> anyhow::Result<RestApiResponse<models::GetEthRedemptionHistoryResponse>> {
653 let GetEthRedemptionHistoryParams {
654 redeem_id,
655 start_time,
656 end_time,
657 current,
658 size,
659 recv_window,
660 } = params;
661
662 let mut query_params = BTreeMap::new();
663 let body_params = BTreeMap::new();
664
665 if let Some(rw) = redeem_id {
666 query_params.insert("redeemId".to_string(), json!(rw));
667 }
668
669 if let Some(rw) = start_time {
670 query_params.insert("startTime".to_string(), json!(rw));
671 }
672
673 if let Some(rw) = end_time {
674 query_params.insert("endTime".to_string(), json!(rw));
675 }
676
677 if let Some(rw) = current {
678 query_params.insert("current".to_string(), json!(rw));
679 }
680
681 if let Some(rw) = size {
682 query_params.insert("size".to_string(), json!(rw));
683 }
684
685 if let Some(rw) = recv_window {
686 query_params.insert("recvWindow".to_string(), json!(rw));
687 }
688
689 send_request::<models::GetEthRedemptionHistoryResponse>(
690 &self.configuration,
691 "/sapi/v1/eth-staking/eth/history/redemptionHistory",
692 reqwest::Method::GET,
693 query_params,
694 body_params,
695 if HAS_TIME_UNIT {
696 self.configuration.time_unit
697 } else {
698 None
699 },
700 true,
701 )
702 .await
703 }
704
705 async fn get_eth_staking_history(
706 &self,
707 params: GetEthStakingHistoryParams,
708 ) -> anyhow::Result<RestApiResponse<models::GetEthStakingHistoryResponse>> {
709 let GetEthStakingHistoryParams {
710 purchase_id,
711 start_time,
712 end_time,
713 current,
714 size,
715 recv_window,
716 } = params;
717
718 let mut query_params = BTreeMap::new();
719 let body_params = BTreeMap::new();
720
721 if let Some(rw) = purchase_id {
722 query_params.insert("purchaseId".to_string(), json!(rw));
723 }
724
725 if let Some(rw) = start_time {
726 query_params.insert("startTime".to_string(), json!(rw));
727 }
728
729 if let Some(rw) = end_time {
730 query_params.insert("endTime".to_string(), json!(rw));
731 }
732
733 if let Some(rw) = current {
734 query_params.insert("current".to_string(), json!(rw));
735 }
736
737 if let Some(rw) = size {
738 query_params.insert("size".to_string(), json!(rw));
739 }
740
741 if let Some(rw) = recv_window {
742 query_params.insert("recvWindow".to_string(), json!(rw));
743 }
744
745 send_request::<models::GetEthStakingHistoryResponse>(
746 &self.configuration,
747 "/sapi/v1/eth-staking/eth/history/stakingHistory",
748 reqwest::Method::GET,
749 query_params,
750 body_params,
751 if HAS_TIME_UNIT {
752 self.configuration.time_unit
753 } else {
754 None
755 },
756 true,
757 )
758 .await
759 }
760
761 async fn get_wbeth_rate_history(
762 &self,
763 params: GetWbethRateHistoryParams,
764 ) -> anyhow::Result<RestApiResponse<models::GetWbethRateHistoryResponse>> {
765 let GetWbethRateHistoryParams {
766 start_time,
767 end_time,
768 current,
769 size,
770 recv_window,
771 } = params;
772
773 let mut query_params = BTreeMap::new();
774 let body_params = BTreeMap::new();
775
776 if let Some(rw) = start_time {
777 query_params.insert("startTime".to_string(), json!(rw));
778 }
779
780 if let Some(rw) = end_time {
781 query_params.insert("endTime".to_string(), json!(rw));
782 }
783
784 if let Some(rw) = current {
785 query_params.insert("current".to_string(), json!(rw));
786 }
787
788 if let Some(rw) = size {
789 query_params.insert("size".to_string(), json!(rw));
790 }
791
792 if let Some(rw) = recv_window {
793 query_params.insert("recvWindow".to_string(), json!(rw));
794 }
795
796 send_request::<models::GetWbethRateHistoryResponse>(
797 &self.configuration,
798 "/sapi/v1/eth-staking/eth/history/rateHistory",
799 reqwest::Method::GET,
800 query_params,
801 body_params,
802 if HAS_TIME_UNIT {
803 self.configuration.time_unit
804 } else {
805 None
806 },
807 true,
808 )
809 .await
810 }
811
812 async fn get_wbeth_rewards_history(
813 &self,
814 params: GetWbethRewardsHistoryParams,
815 ) -> anyhow::Result<RestApiResponse<models::GetWbethRewardsHistoryResponse>> {
816 let GetWbethRewardsHistoryParams {
817 start_time,
818 end_time,
819 current,
820 size,
821 recv_window,
822 } = params;
823
824 let mut query_params = BTreeMap::new();
825 let body_params = BTreeMap::new();
826
827 if let Some(rw) = start_time {
828 query_params.insert("startTime".to_string(), json!(rw));
829 }
830
831 if let Some(rw) = end_time {
832 query_params.insert("endTime".to_string(), json!(rw));
833 }
834
835 if let Some(rw) = current {
836 query_params.insert("current".to_string(), json!(rw));
837 }
838
839 if let Some(rw) = size {
840 query_params.insert("size".to_string(), json!(rw));
841 }
842
843 if let Some(rw) = recv_window {
844 query_params.insert("recvWindow".to_string(), json!(rw));
845 }
846
847 send_request::<models::GetWbethRewardsHistoryResponse>(
848 &self.configuration,
849 "/sapi/v1/eth-staking/eth/history/wbethRewardsHistory",
850 reqwest::Method::GET,
851 query_params,
852 body_params,
853 if HAS_TIME_UNIT {
854 self.configuration.time_unit
855 } else {
856 None
857 },
858 true,
859 )
860 .await
861 }
862
863 async fn get_wbeth_unwrap_history(
864 &self,
865 params: GetWbethUnwrapHistoryParams,
866 ) -> anyhow::Result<RestApiResponse<models::GetWbethUnwrapHistoryResponse>> {
867 let GetWbethUnwrapHistoryParams {
868 start_time,
869 end_time,
870 current,
871 size,
872 recv_window,
873 } = params;
874
875 let mut query_params = BTreeMap::new();
876 let body_params = BTreeMap::new();
877
878 if let Some(rw) = start_time {
879 query_params.insert("startTime".to_string(), json!(rw));
880 }
881
882 if let Some(rw) = end_time {
883 query_params.insert("endTime".to_string(), json!(rw));
884 }
885
886 if let Some(rw) = current {
887 query_params.insert("current".to_string(), json!(rw));
888 }
889
890 if let Some(rw) = size {
891 query_params.insert("size".to_string(), json!(rw));
892 }
893
894 if let Some(rw) = recv_window {
895 query_params.insert("recvWindow".to_string(), json!(rw));
896 }
897
898 send_request::<models::GetWbethUnwrapHistoryResponse>(
899 &self.configuration,
900 "/sapi/v1/eth-staking/wbeth/history/unwrapHistory",
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 get_wbeth_wrap_history(
915 &self,
916 params: GetWbethWrapHistoryParams,
917 ) -> anyhow::Result<RestApiResponse<models::GetWbethWrapHistoryResponse>> {
918 let GetWbethWrapHistoryParams {
919 start_time,
920 end_time,
921 current,
922 size,
923 recv_window,
924 } = params;
925
926 let mut query_params = BTreeMap::new();
927 let body_params = BTreeMap::new();
928
929 if let Some(rw) = start_time {
930 query_params.insert("startTime".to_string(), json!(rw));
931 }
932
933 if let Some(rw) = end_time {
934 query_params.insert("endTime".to_string(), json!(rw));
935 }
936
937 if let Some(rw) = current {
938 query_params.insert("current".to_string(), json!(rw));
939 }
940
941 if let Some(rw) = size {
942 query_params.insert("size".to_string(), json!(rw));
943 }
944
945 if let Some(rw) = recv_window {
946 query_params.insert("recvWindow".to_string(), json!(rw));
947 }
948
949 send_request::<models::GetWbethWrapHistoryResponse>(
950 &self.configuration,
951 "/sapi/v1/eth-staking/wbeth/history/wrapHistory",
952 reqwest::Method::GET,
953 query_params,
954 body_params,
955 if HAS_TIME_UNIT {
956 self.configuration.time_unit
957 } else {
958 None
959 },
960 true,
961 )
962 .await
963 }
964
965 async fn redeem_eth(
966 &self,
967 params: RedeemEthParams,
968 ) -> anyhow::Result<RestApiResponse<models::RedeemEthResponse>> {
969 let RedeemEthParams {
970 amount,
971 asset,
972 recv_window,
973 } = params;
974
975 let mut query_params = BTreeMap::new();
976 let body_params = BTreeMap::new();
977
978 query_params.insert("amount".to_string(), json!(amount));
979
980 if let Some(rw) = asset {
981 query_params.insert("asset".to_string(), json!(rw));
982 }
983
984 if let Some(rw) = recv_window {
985 query_params.insert("recvWindow".to_string(), json!(rw));
986 }
987
988 send_request::<models::RedeemEthResponse>(
989 &self.configuration,
990 "/sapi/v1/eth-staking/eth/redeem",
991 reqwest::Method::POST,
992 query_params,
993 body_params,
994 if HAS_TIME_UNIT {
995 self.configuration.time_unit
996 } else {
997 None
998 },
999 true,
1000 )
1001 .await
1002 }
1003
1004 async fn subscribe_eth_staking(
1005 &self,
1006 params: SubscribeEthStakingParams,
1007 ) -> anyhow::Result<RestApiResponse<models::SubscribeEthStakingResponse>> {
1008 let SubscribeEthStakingParams {
1009 amount,
1010 recv_window,
1011 } = params;
1012
1013 let mut query_params = BTreeMap::new();
1014 let body_params = BTreeMap::new();
1015
1016 query_params.insert("amount".to_string(), json!(amount));
1017
1018 if let Some(rw) = recv_window {
1019 query_params.insert("recvWindow".to_string(), json!(rw));
1020 }
1021
1022 send_request::<models::SubscribeEthStakingResponse>(
1023 &self.configuration,
1024 "/sapi/v2/eth-staking/eth/stake",
1025 reqwest::Method::POST,
1026 query_params,
1027 body_params,
1028 if HAS_TIME_UNIT {
1029 self.configuration.time_unit
1030 } else {
1031 None
1032 },
1033 true,
1034 )
1035 .await
1036 }
1037
1038 async fn wrap_beth(
1039 &self,
1040 params: WrapBethParams,
1041 ) -> anyhow::Result<RestApiResponse<models::WrapBethResponse>> {
1042 let WrapBethParams {
1043 amount,
1044 recv_window,
1045 } = params;
1046
1047 let mut query_params = BTreeMap::new();
1048 let body_params = BTreeMap::new();
1049
1050 query_params.insert("amount".to_string(), json!(amount));
1051
1052 if let Some(rw) = recv_window {
1053 query_params.insert("recvWindow".to_string(), json!(rw));
1054 }
1055
1056 send_request::<models::WrapBethResponse>(
1057 &self.configuration,
1058 "/sapi/v1/eth-staking/wbeth/wrap",
1059 reqwest::Method::POST,
1060 query_params,
1061 body_params,
1062 if HAS_TIME_UNIT {
1063 self.configuration.time_unit
1064 } else {
1065 None
1066 },
1067 true,
1068 )
1069 .await
1070 }
1071}
1072
1073#[cfg(all(test, feature = "staking"))]
1074mod tests {
1075 use super::*;
1076 use crate::TOKIO_SHARED_RT;
1077 use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
1078 use async_trait::async_trait;
1079 use std::collections::HashMap;
1080
1081 struct DummyRestApiResponse<T> {
1082 inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
1083 status: u16,
1084 headers: HashMap<String, String>,
1085 rate_limits: Option<Vec<RestApiRateLimit>>,
1086 }
1087
1088 impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
1089 fn from(dummy: DummyRestApiResponse<T>) -> Self {
1090 Self {
1091 data_fn: dummy.inner,
1092 status: dummy.status,
1093 headers: dummy.headers,
1094 rate_limits: dummy.rate_limits,
1095 }
1096 }
1097 }
1098
1099 struct MockEthStakingApiClient {
1100 force_error: bool,
1101 }
1102
1103 #[async_trait]
1104 impl EthStakingApi for MockEthStakingApiClient {
1105 async fn eth_staking_account(
1106 &self,
1107 _params: EthStakingAccountParams,
1108 ) -> anyhow::Result<RestApiResponse<models::EthStakingAccountResponse>> {
1109 if self.force_error {
1110 return Err(ConnectorError::ConnectorClientError {
1111 msg: "ResponseError".to_string(),
1112 code: None,
1113 }
1114 .into());
1115 }
1116
1117 let resp_json: Value = serde_json::from_str(r#"{"holdingInETH":"1.22330928","holdings":{"wbethAmount":"1.10928781","bethAmount":"1.90002112"},"thirtyDaysProfitInETH":"0.22330928","profit":{"amountFromWBETH":"0.12330928","amountFromBETH":"0.1"}}"#).unwrap_or_else(|_| serde_json::json!({}));
1118 let dummy_response: models::EthStakingAccountResponse =
1119 serde_json::from_value(resp_json.clone())
1120 .expect("should parse into models::EthStakingAccountResponse");
1121
1122 let dummy = DummyRestApiResponse {
1123 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1124 status: 200,
1125 headers: HashMap::new(),
1126 rate_limits: None,
1127 };
1128
1129 Ok(dummy.into())
1130 }
1131
1132 async fn get_current_eth_staking_quota(
1133 &self,
1134 _params: GetCurrentEthStakingQuotaParams,
1135 ) -> anyhow::Result<RestApiResponse<models::GetCurrentEthStakingQuotaResponse>> {
1136 if self.force_error {
1137 return Err(ConnectorError::ConnectorClientError {
1138 msg: "ResponseError".to_string(),
1139 code: None,
1140 }
1141 .into());
1142 }
1143
1144 let resp_json: Value = serde_json::from_str(r#"{"leftStakingPersonalQuota":"1000","leftRedemptionPersonalQuota":"1000","minStakeAmount":"0.00010000","minRedeemAmount":"0.00000001","redeemPeriod":20,"stakeable":true,"redeemable":true,"commissionFee":"0.05000000","calculating":false}"#).unwrap_or_else(|_| serde_json::json!({}));
1145 let dummy_response: models::GetCurrentEthStakingQuotaResponse =
1146 serde_json::from_value(resp_json.clone())
1147 .expect("should parse into models::GetCurrentEthStakingQuotaResponse");
1148
1149 let dummy = DummyRestApiResponse {
1150 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1151 status: 200,
1152 headers: HashMap::new(),
1153 rate_limits: None,
1154 };
1155
1156 Ok(dummy.into())
1157 }
1158
1159 async fn get_eth_redemption_history(
1160 &self,
1161 _params: GetEthRedemptionHistoryParams,
1162 ) -> anyhow::Result<RestApiResponse<models::GetEthRedemptionHistoryResponse>> {
1163 if self.force_error {
1164 return Err(ConnectorError::ConnectorClientError {
1165 msg: "ResponseError".to_string(),
1166 code: None,
1167 }
1168 .into());
1169 }
1170
1171 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"arrivalTime":1575018510000,"asset":"WBETH","amount":"21312.23223","distributeAsset":"ETH","distributeAmount":"21338.0699","conversionRatio":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1172 let dummy_response: models::GetEthRedemptionHistoryResponse =
1173 serde_json::from_value(resp_json.clone())
1174 .expect("should parse into models::GetEthRedemptionHistoryResponse");
1175
1176 let dummy = DummyRestApiResponse {
1177 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1178 status: 200,
1179 headers: HashMap::new(),
1180 rate_limits: None,
1181 };
1182
1183 Ok(dummy.into())
1184 }
1185
1186 async fn get_eth_staking_history(
1187 &self,
1188 _params: GetEthStakingHistoryParams,
1189 ) -> anyhow::Result<RestApiResponse<models::GetEthStakingHistoryResponse>> {
1190 if self.force_error {
1191 return Err(ConnectorError::ConnectorClientError {
1192 msg: "ResponseError".to_string(),
1193 code: None,
1194 }
1195 .into());
1196 }
1197
1198 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"asset":"ETH","amount":"21312.23223","distributeAsset":"WBETH","distributeAmount":"21286.42584","conversionRatio":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1199 let dummy_response: models::GetEthStakingHistoryResponse =
1200 serde_json::from_value(resp_json.clone())
1201 .expect("should parse into models::GetEthStakingHistoryResponse");
1202
1203 let dummy = DummyRestApiResponse {
1204 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1205 status: 200,
1206 headers: HashMap::new(),
1207 rate_limits: None,
1208 };
1209
1210 Ok(dummy.into())
1211 }
1212
1213 async fn get_wbeth_rate_history(
1214 &self,
1215 _params: GetWbethRateHistoryParams,
1216 ) -> anyhow::Result<RestApiResponse<models::GetWbethRateHistoryResponse>> {
1217 if self.force_error {
1218 return Err(ConnectorError::ConnectorClientError {
1219 msg: "ResponseError".to_string(),
1220 code: None,
1221 }
1222 .into());
1223 }
1224
1225 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"annualPercentageRate":"0.00006408","exchangeRate":"1.00121234","time":1577233578000}],"total":"1"}"#).unwrap_or_else(|_| serde_json::json!({}));
1226 let dummy_response: models::GetWbethRateHistoryResponse =
1227 serde_json::from_value(resp_json.clone())
1228 .expect("should parse into models::GetWbethRateHistoryResponse");
1229
1230 let dummy = DummyRestApiResponse {
1231 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1232 status: 200,
1233 headers: HashMap::new(),
1234 rate_limits: None,
1235 };
1236
1237 Ok(dummy.into())
1238 }
1239
1240 async fn get_wbeth_rewards_history(
1241 &self,
1242 _params: GetWbethRewardsHistoryParams,
1243 ) -> anyhow::Result<RestApiResponse<models::GetWbethRewardsHistoryResponse>> {
1244 if self.force_error {
1245 return Err(ConnectorError::ConnectorClientError {
1246 msg: "ResponseError".to_string(),
1247 code: None,
1248 }
1249 .into());
1250 }
1251
1252 let resp_json: Value = serde_json::from_str(r#"{"estRewardsInETH":"1.23230920","rows":[{"time":1575018510000,"amountInETH":"0.23223","holding":"2.3223","holdingInETH":"2.4231","annualPercentageRate":"0.5"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1253 let dummy_response: models::GetWbethRewardsHistoryResponse =
1254 serde_json::from_value(resp_json.clone())
1255 .expect("should parse into models::GetWbethRewardsHistoryResponse");
1256
1257 let dummy = DummyRestApiResponse {
1258 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1259 status: 200,
1260 headers: HashMap::new(),
1261 rate_limits: None,
1262 };
1263
1264 Ok(dummy.into())
1265 }
1266
1267 async fn get_wbeth_unwrap_history(
1268 &self,
1269 _params: GetWbethUnwrapHistoryParams,
1270 ) -> anyhow::Result<RestApiResponse<models::GetWbethUnwrapHistoryResponse>> {
1271 if self.force_error {
1272 return Err(ConnectorError::ConnectorClientError {
1273 msg: "ResponseError".to_string(),
1274 code: None,
1275 }
1276 .into());
1277 }
1278
1279 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"fromAsset":"WBETH","fromAmount":"21312.23223","toAsset":"BETH","toAmount":"21312.23223","exchangeRate":"1.01243253","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1280 let dummy_response: models::GetWbethUnwrapHistoryResponse =
1281 serde_json::from_value(resp_json.clone())
1282 .expect("should parse into models::GetWbethUnwrapHistoryResponse");
1283
1284 let dummy = DummyRestApiResponse {
1285 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1286 status: 200,
1287 headers: HashMap::new(),
1288 rate_limits: None,
1289 };
1290
1291 Ok(dummy.into())
1292 }
1293
1294 async fn get_wbeth_wrap_history(
1295 &self,
1296 _params: GetWbethWrapHistoryParams,
1297 ) -> anyhow::Result<RestApiResponse<models::GetWbethWrapHistoryResponse>> {
1298 if self.force_error {
1299 return Err(ConnectorError::ConnectorClientError {
1300 msg: "ResponseError".to_string(),
1301 code: None,
1302 }
1303 .into());
1304 }
1305
1306 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"fromAsset":"BETH","fromAmount":"21312.23223","toAsset":"WBETH","toAmount":"21312.23223","exchangeRate":"1.01243253","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1307 let dummy_response: models::GetWbethWrapHistoryResponse =
1308 serde_json::from_value(resp_json.clone())
1309 .expect("should parse into models::GetWbethWrapHistoryResponse");
1310
1311 let dummy = DummyRestApiResponse {
1312 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1313 status: 200,
1314 headers: HashMap::new(),
1315 rate_limits: None,
1316 };
1317
1318 Ok(dummy.into())
1319 }
1320
1321 async fn redeem_eth(
1322 &self,
1323 _params: RedeemEthParams,
1324 ) -> anyhow::Result<RestApiResponse<models::RedeemEthResponse>> {
1325 if self.force_error {
1326 return Err(ConnectorError::ConnectorClientError {
1327 msg: "ResponseError".to_string(),
1328 code: None,
1329 }
1330 .into());
1331 }
1332
1333 let resp_json: Value = serde_json::from_str(r#"{"success":true,"ethAmount":"0.23092091","redeemId":1234567,"conversionRatio":"1.00121234","arrivalTime":1575018510000}"#).unwrap_or_else(|_| serde_json::json!({}));
1334 let dummy_response: models::RedeemEthResponse =
1335 serde_json::from_value(resp_json.clone())
1336 .expect("should parse into models::RedeemEthResponse");
1337
1338 let dummy = DummyRestApiResponse {
1339 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1340 status: 200,
1341 headers: HashMap::new(),
1342 rate_limits: None,
1343 };
1344
1345 Ok(dummy.into())
1346 }
1347
1348 async fn subscribe_eth_staking(
1349 &self,
1350 _params: SubscribeEthStakingParams,
1351 ) -> anyhow::Result<RestApiResponse<models::SubscribeEthStakingResponse>> {
1352 if self.force_error {
1353 return Err(ConnectorError::ConnectorClientError {
1354 msg: "ResponseError".to_string(),
1355 code: None,
1356 }
1357 .into());
1358 }
1359
1360 let resp_json: Value = serde_json::from_str(r#"{"success":true,"wbethAmount":"0.23092091","purchaseId":1234567,"conversionRatio":"1.001212342342"}"#).unwrap_or_else(|_| serde_json::json!({}));
1361 let dummy_response: models::SubscribeEthStakingResponse =
1362 serde_json::from_value(resp_json.clone())
1363 .expect("should parse into models::SubscribeEthStakingResponse");
1364
1365 let dummy = DummyRestApiResponse {
1366 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1367 status: 200,
1368 headers: HashMap::new(),
1369 rate_limits: None,
1370 };
1371
1372 Ok(dummy.into())
1373 }
1374
1375 async fn wrap_beth(
1376 &self,
1377 _params: WrapBethParams,
1378 ) -> anyhow::Result<RestApiResponse<models::WrapBethResponse>> {
1379 if self.force_error {
1380 return Err(ConnectorError::ConnectorClientError {
1381 msg: "ResponseError".to_string(),
1382 code: None,
1383 }
1384 .into());
1385 }
1386
1387 let resp_json: Value = serde_json::from_str(
1388 r#"{"success":true,"wbethAmount":"0.23092091","exchangeRate":"1.001212343432"}"#,
1389 )
1390 .unwrap_or_else(|_| serde_json::json!({}));
1391 let dummy_response: models::WrapBethResponse =
1392 serde_json::from_value(resp_json.clone())
1393 .expect("should parse into models::WrapBethResponse");
1394
1395 let dummy = DummyRestApiResponse {
1396 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1397 status: 200,
1398 headers: HashMap::new(),
1399 rate_limits: None,
1400 };
1401
1402 Ok(dummy.into())
1403 }
1404 }
1405
1406 #[test]
1407 fn eth_staking_account_required_params_success() {
1408 TOKIO_SHARED_RT.block_on(async {
1409 let client = MockEthStakingApiClient { force_error: false };
1410
1411 let params = EthStakingAccountParams::builder().build().unwrap();
1412
1413 let resp_json: Value = serde_json::from_str(r#"{"holdingInETH":"1.22330928","holdings":{"wbethAmount":"1.10928781","bethAmount":"1.90002112"},"thirtyDaysProfitInETH":"0.22330928","profit":{"amountFromWBETH":"0.12330928","amountFromBETH":"0.1"}}"#).unwrap_or_else(|_| serde_json::json!({}));
1414 let expected_response : models::EthStakingAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::EthStakingAccountResponse");
1415
1416 let resp = client.eth_staking_account(params).await.expect("Expected a response");
1417 let data_future = resp.data();
1418 let actual_response = data_future.await.unwrap();
1419 assert_eq!(actual_response, expected_response);
1420 });
1421 }
1422
1423 #[test]
1424 fn eth_staking_account_optional_params_success() {
1425 TOKIO_SHARED_RT.block_on(async {
1426 let client = MockEthStakingApiClient { force_error: false };
1427
1428 let params = EthStakingAccountParams::builder().recv_window(5000).build().unwrap();
1429
1430 let resp_json: Value = serde_json::from_str(r#"{"holdingInETH":"1.22330928","holdings":{"wbethAmount":"1.10928781","bethAmount":"1.90002112"},"thirtyDaysProfitInETH":"0.22330928","profit":{"amountFromWBETH":"0.12330928","amountFromBETH":"0.1"}}"#).unwrap_or_else(|_| serde_json::json!({}));
1431 let expected_response : models::EthStakingAccountResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::EthStakingAccountResponse");
1432
1433 let resp = client.eth_staking_account(params).await.expect("Expected a response");
1434 let data_future = resp.data();
1435 let actual_response = data_future.await.unwrap();
1436 assert_eq!(actual_response, expected_response);
1437 });
1438 }
1439
1440 #[test]
1441 fn eth_staking_account_response_error() {
1442 TOKIO_SHARED_RT.block_on(async {
1443 let client = MockEthStakingApiClient { force_error: true };
1444
1445 let params = EthStakingAccountParams::builder().build().unwrap();
1446
1447 match client.eth_staking_account(params).await {
1448 Ok(_) => panic!("Expected an error"),
1449 Err(err) => {
1450 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1451 }
1452 }
1453 });
1454 }
1455
1456 #[test]
1457 fn get_current_eth_staking_quota_required_params_success() {
1458 TOKIO_SHARED_RT.block_on(async {
1459 let client = MockEthStakingApiClient { force_error: false };
1460
1461 let params = GetCurrentEthStakingQuotaParams::builder().build().unwrap();
1462
1463 let resp_json: Value = serde_json::from_str(r#"{"leftStakingPersonalQuota":"1000","leftRedemptionPersonalQuota":"1000","minStakeAmount":"0.00010000","minRedeemAmount":"0.00000001","redeemPeriod":20,"stakeable":true,"redeemable":true,"commissionFee":"0.05000000","calculating":false}"#).unwrap_or_else(|_| serde_json::json!({}));
1464 let expected_response : models::GetCurrentEthStakingQuotaResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetCurrentEthStakingQuotaResponse");
1465
1466 let resp = client.get_current_eth_staking_quota(params).await.expect("Expected a response");
1467 let data_future = resp.data();
1468 let actual_response = data_future.await.unwrap();
1469 assert_eq!(actual_response, expected_response);
1470 });
1471 }
1472
1473 #[test]
1474 fn get_current_eth_staking_quota_optional_params_success() {
1475 TOKIO_SHARED_RT.block_on(async {
1476 let client = MockEthStakingApiClient { force_error: false };
1477
1478 let params = GetCurrentEthStakingQuotaParams::builder().recv_window(5000).build().unwrap();
1479
1480 let resp_json: Value = serde_json::from_str(r#"{"leftStakingPersonalQuota":"1000","leftRedemptionPersonalQuota":"1000","minStakeAmount":"0.00010000","minRedeemAmount":"0.00000001","redeemPeriod":20,"stakeable":true,"redeemable":true,"commissionFee":"0.05000000","calculating":false}"#).unwrap_or_else(|_| serde_json::json!({}));
1481 let expected_response : models::GetCurrentEthStakingQuotaResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetCurrentEthStakingQuotaResponse");
1482
1483 let resp = client.get_current_eth_staking_quota(params).await.expect("Expected a response");
1484 let data_future = resp.data();
1485 let actual_response = data_future.await.unwrap();
1486 assert_eq!(actual_response, expected_response);
1487 });
1488 }
1489
1490 #[test]
1491 fn get_current_eth_staking_quota_response_error() {
1492 TOKIO_SHARED_RT.block_on(async {
1493 let client = MockEthStakingApiClient { force_error: true };
1494
1495 let params = GetCurrentEthStakingQuotaParams::builder().build().unwrap();
1496
1497 match client.get_current_eth_staking_quota(params).await {
1498 Ok(_) => panic!("Expected an error"),
1499 Err(err) => {
1500 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1501 }
1502 }
1503 });
1504 }
1505
1506 #[test]
1507 fn get_eth_redemption_history_required_params_success() {
1508 TOKIO_SHARED_RT.block_on(async {
1509 let client = MockEthStakingApiClient { force_error: false };
1510
1511 let params = GetEthRedemptionHistoryParams::builder().build().unwrap();
1512
1513 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"arrivalTime":1575018510000,"asset":"WBETH","amount":"21312.23223","distributeAsset":"ETH","distributeAmount":"21338.0699","conversionRatio":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1514 let expected_response : models::GetEthRedemptionHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetEthRedemptionHistoryResponse");
1515
1516 let resp = client.get_eth_redemption_history(params).await.expect("Expected a response");
1517 let data_future = resp.data();
1518 let actual_response = data_future.await.unwrap();
1519 assert_eq!(actual_response, expected_response);
1520 });
1521 }
1522
1523 #[test]
1524 fn get_eth_redemption_history_optional_params_success() {
1525 TOKIO_SHARED_RT.block_on(async {
1526 let client = MockEthStakingApiClient { force_error: false };
1527
1528 let params = GetEthRedemptionHistoryParams::builder().redeem_id(1234567).start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1529
1530 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"arrivalTime":1575018510000,"asset":"WBETH","amount":"21312.23223","distributeAsset":"ETH","distributeAmount":"21338.0699","conversionRatio":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1531 let expected_response : models::GetEthRedemptionHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetEthRedemptionHistoryResponse");
1532
1533 let resp = client.get_eth_redemption_history(params).await.expect("Expected a response");
1534 let data_future = resp.data();
1535 let actual_response = data_future.await.unwrap();
1536 assert_eq!(actual_response, expected_response);
1537 });
1538 }
1539
1540 #[test]
1541 fn get_eth_redemption_history_response_error() {
1542 TOKIO_SHARED_RT.block_on(async {
1543 let client = MockEthStakingApiClient { force_error: true };
1544
1545 let params = GetEthRedemptionHistoryParams::builder().build().unwrap();
1546
1547 match client.get_eth_redemption_history(params).await {
1548 Ok(_) => panic!("Expected an error"),
1549 Err(err) => {
1550 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1551 }
1552 }
1553 });
1554 }
1555
1556 #[test]
1557 fn get_eth_staking_history_required_params_success() {
1558 TOKIO_SHARED_RT.block_on(async {
1559 let client = MockEthStakingApiClient { force_error: false };
1560
1561 let params = GetEthStakingHistoryParams::builder().build().unwrap();
1562
1563 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"asset":"ETH","amount":"21312.23223","distributeAsset":"WBETH","distributeAmount":"21286.42584","conversionRatio":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1564 let expected_response : models::GetEthStakingHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetEthStakingHistoryResponse");
1565
1566 let resp = client.get_eth_staking_history(params).await.expect("Expected a response");
1567 let data_future = resp.data();
1568 let actual_response = data_future.await.unwrap();
1569 assert_eq!(actual_response, expected_response);
1570 });
1571 }
1572
1573 #[test]
1574 fn get_eth_staking_history_optional_params_success() {
1575 TOKIO_SHARED_RT.block_on(async {
1576 let client = MockEthStakingApiClient { force_error: false };
1577
1578 let params = GetEthStakingHistoryParams::builder().purchase_id(1234567).start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1579
1580 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"asset":"ETH","amount":"21312.23223","distributeAsset":"WBETH","distributeAmount":"21286.42584","conversionRatio":"1.00121234","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1581 let expected_response : models::GetEthStakingHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetEthStakingHistoryResponse");
1582
1583 let resp = client.get_eth_staking_history(params).await.expect("Expected a response");
1584 let data_future = resp.data();
1585 let actual_response = data_future.await.unwrap();
1586 assert_eq!(actual_response, expected_response);
1587 });
1588 }
1589
1590 #[test]
1591 fn get_eth_staking_history_response_error() {
1592 TOKIO_SHARED_RT.block_on(async {
1593 let client = MockEthStakingApiClient { force_error: true };
1594
1595 let params = GetEthStakingHistoryParams::builder().build().unwrap();
1596
1597 match client.get_eth_staking_history(params).await {
1598 Ok(_) => panic!("Expected an error"),
1599 Err(err) => {
1600 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1601 }
1602 }
1603 });
1604 }
1605
1606 #[test]
1607 fn get_wbeth_rate_history_required_params_success() {
1608 TOKIO_SHARED_RT.block_on(async {
1609 let client = MockEthStakingApiClient { force_error: false };
1610
1611 let params = GetWbethRateHistoryParams::builder().build().unwrap();
1612
1613 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"annualPercentageRate":"0.00006408","exchangeRate":"1.00121234","time":1577233578000}],"total":"1"}"#).unwrap_or_else(|_| serde_json::json!({}));
1614 let expected_response : models::GetWbethRateHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethRateHistoryResponse");
1615
1616 let resp = client.get_wbeth_rate_history(params).await.expect("Expected a response");
1617 let data_future = resp.data();
1618 let actual_response = data_future.await.unwrap();
1619 assert_eq!(actual_response, expected_response);
1620 });
1621 }
1622
1623 #[test]
1624 fn get_wbeth_rate_history_optional_params_success() {
1625 TOKIO_SHARED_RT.block_on(async {
1626 let client = MockEthStakingApiClient { force_error: false };
1627
1628 let params = GetWbethRateHistoryParams::builder().start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1629
1630 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"annualPercentageRate":"0.00006408","exchangeRate":"1.00121234","time":1577233578000}],"total":"1"}"#).unwrap_or_else(|_| serde_json::json!({}));
1631 let expected_response : models::GetWbethRateHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethRateHistoryResponse");
1632
1633 let resp = client.get_wbeth_rate_history(params).await.expect("Expected a response");
1634 let data_future = resp.data();
1635 let actual_response = data_future.await.unwrap();
1636 assert_eq!(actual_response, expected_response);
1637 });
1638 }
1639
1640 #[test]
1641 fn get_wbeth_rate_history_response_error() {
1642 TOKIO_SHARED_RT.block_on(async {
1643 let client = MockEthStakingApiClient { force_error: true };
1644
1645 let params = GetWbethRateHistoryParams::builder().build().unwrap();
1646
1647 match client.get_wbeth_rate_history(params).await {
1648 Ok(_) => panic!("Expected an error"),
1649 Err(err) => {
1650 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1651 }
1652 }
1653 });
1654 }
1655
1656 #[test]
1657 fn get_wbeth_rewards_history_required_params_success() {
1658 TOKIO_SHARED_RT.block_on(async {
1659 let client = MockEthStakingApiClient { force_error: false };
1660
1661 let params = GetWbethRewardsHistoryParams::builder().build().unwrap();
1662
1663 let resp_json: Value = serde_json::from_str(r#"{"estRewardsInETH":"1.23230920","rows":[{"time":1575018510000,"amountInETH":"0.23223","holding":"2.3223","holdingInETH":"2.4231","annualPercentageRate":"0.5"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1664 let expected_response : models::GetWbethRewardsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethRewardsHistoryResponse");
1665
1666 let resp = client.get_wbeth_rewards_history(params).await.expect("Expected a response");
1667 let data_future = resp.data();
1668 let actual_response = data_future.await.unwrap();
1669 assert_eq!(actual_response, expected_response);
1670 });
1671 }
1672
1673 #[test]
1674 fn get_wbeth_rewards_history_optional_params_success() {
1675 TOKIO_SHARED_RT.block_on(async {
1676 let client = MockEthStakingApiClient { force_error: false };
1677
1678 let params = GetWbethRewardsHistoryParams::builder().start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1679
1680 let resp_json: Value = serde_json::from_str(r#"{"estRewardsInETH":"1.23230920","rows":[{"time":1575018510000,"amountInETH":"0.23223","holding":"2.3223","holdingInETH":"2.4231","annualPercentageRate":"0.5"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1681 let expected_response : models::GetWbethRewardsHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethRewardsHistoryResponse");
1682
1683 let resp = client.get_wbeth_rewards_history(params).await.expect("Expected a response");
1684 let data_future = resp.data();
1685 let actual_response = data_future.await.unwrap();
1686 assert_eq!(actual_response, expected_response);
1687 });
1688 }
1689
1690 #[test]
1691 fn get_wbeth_rewards_history_response_error() {
1692 TOKIO_SHARED_RT.block_on(async {
1693 let client = MockEthStakingApiClient { force_error: true };
1694
1695 let params = GetWbethRewardsHistoryParams::builder().build().unwrap();
1696
1697 match client.get_wbeth_rewards_history(params).await {
1698 Ok(_) => panic!("Expected an error"),
1699 Err(err) => {
1700 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1701 }
1702 }
1703 });
1704 }
1705
1706 #[test]
1707 fn get_wbeth_unwrap_history_required_params_success() {
1708 TOKIO_SHARED_RT.block_on(async {
1709 let client = MockEthStakingApiClient { force_error: false };
1710
1711 let params = GetWbethUnwrapHistoryParams::builder().build().unwrap();
1712
1713 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"fromAsset":"WBETH","fromAmount":"21312.23223","toAsset":"BETH","toAmount":"21312.23223","exchangeRate":"1.01243253","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1714 let expected_response : models::GetWbethUnwrapHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethUnwrapHistoryResponse");
1715
1716 let resp = client.get_wbeth_unwrap_history(params).await.expect("Expected a response");
1717 let data_future = resp.data();
1718 let actual_response = data_future.await.unwrap();
1719 assert_eq!(actual_response, expected_response);
1720 });
1721 }
1722
1723 #[test]
1724 fn get_wbeth_unwrap_history_optional_params_success() {
1725 TOKIO_SHARED_RT.block_on(async {
1726 let client = MockEthStakingApiClient { force_error: false };
1727
1728 let params = GetWbethUnwrapHistoryParams::builder().start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1729
1730 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"fromAsset":"WBETH","fromAmount":"21312.23223","toAsset":"BETH","toAmount":"21312.23223","exchangeRate":"1.01243253","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1731 let expected_response : models::GetWbethUnwrapHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethUnwrapHistoryResponse");
1732
1733 let resp = client.get_wbeth_unwrap_history(params).await.expect("Expected a response");
1734 let data_future = resp.data();
1735 let actual_response = data_future.await.unwrap();
1736 assert_eq!(actual_response, expected_response);
1737 });
1738 }
1739
1740 #[test]
1741 fn get_wbeth_unwrap_history_response_error() {
1742 TOKIO_SHARED_RT.block_on(async {
1743 let client = MockEthStakingApiClient { force_error: true };
1744
1745 let params = GetWbethUnwrapHistoryParams::builder().build().unwrap();
1746
1747 match client.get_wbeth_unwrap_history(params).await {
1748 Ok(_) => panic!("Expected an error"),
1749 Err(err) => {
1750 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1751 }
1752 }
1753 });
1754 }
1755
1756 #[test]
1757 fn get_wbeth_wrap_history_required_params_success() {
1758 TOKIO_SHARED_RT.block_on(async {
1759 let client = MockEthStakingApiClient { force_error: false };
1760
1761 let params = GetWbethWrapHistoryParams::builder().build().unwrap();
1762
1763 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"fromAsset":"BETH","fromAmount":"21312.23223","toAsset":"WBETH","toAmount":"21312.23223","exchangeRate":"1.01243253","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1764 let expected_response : models::GetWbethWrapHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethWrapHistoryResponse");
1765
1766 let resp = client.get_wbeth_wrap_history(params).await.expect("Expected a response");
1767 let data_future = resp.data();
1768 let actual_response = data_future.await.unwrap();
1769 assert_eq!(actual_response, expected_response);
1770 });
1771 }
1772
1773 #[test]
1774 fn get_wbeth_wrap_history_optional_params_success() {
1775 TOKIO_SHARED_RT.block_on(async {
1776 let client = MockEthStakingApiClient { force_error: false };
1777
1778 let params = GetWbethWrapHistoryParams::builder().start_time(1623319461670).end_time(1641782889000).current(1).size(10).recv_window(5000).build().unwrap();
1779
1780 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"time":1575018510000,"fromAsset":"BETH","fromAmount":"21312.23223","toAsset":"WBETH","toAmount":"21312.23223","exchangeRate":"1.01243253","status":"SUCCESS"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
1781 let expected_response : models::GetWbethWrapHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetWbethWrapHistoryResponse");
1782
1783 let resp = client.get_wbeth_wrap_history(params).await.expect("Expected a response");
1784 let data_future = resp.data();
1785 let actual_response = data_future.await.unwrap();
1786 assert_eq!(actual_response, expected_response);
1787 });
1788 }
1789
1790 #[test]
1791 fn get_wbeth_wrap_history_response_error() {
1792 TOKIO_SHARED_RT.block_on(async {
1793 let client = MockEthStakingApiClient { force_error: true };
1794
1795 let params = GetWbethWrapHistoryParams::builder().build().unwrap();
1796
1797 match client.get_wbeth_wrap_history(params).await {
1798 Ok(_) => panic!("Expected an error"),
1799 Err(err) => {
1800 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1801 }
1802 }
1803 });
1804 }
1805
1806 #[test]
1807 fn redeem_eth_required_params_success() {
1808 TOKIO_SHARED_RT.block_on(async {
1809 let client = MockEthStakingApiClient { force_error: false };
1810
1811 let params = RedeemEthParams::builder(dec!(1.0),).build().unwrap();
1812
1813 let resp_json: Value = serde_json::from_str(r#"{"success":true,"ethAmount":"0.23092091","redeemId":1234567,"conversionRatio":"1.00121234","arrivalTime":1575018510000}"#).unwrap_or_else(|_| serde_json::json!({}));
1814 let expected_response : models::RedeemEthResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RedeemEthResponse");
1815
1816 let resp = client.redeem_eth(params).await.expect("Expected a response");
1817 let data_future = resp.data();
1818 let actual_response = data_future.await.unwrap();
1819 assert_eq!(actual_response, expected_response);
1820 });
1821 }
1822
1823 #[test]
1824 fn redeem_eth_optional_params_success() {
1825 TOKIO_SHARED_RT.block_on(async {
1826 let client = MockEthStakingApiClient { force_error: false };
1827
1828 let params = RedeemEthParams::builder(dec!(1.0),).asset(RedeemEthAssetEnum::Wbeth).recv_window(5000).build().unwrap();
1829
1830 let resp_json: Value = serde_json::from_str(r#"{"success":true,"ethAmount":"0.23092091","redeemId":1234567,"conversionRatio":"1.00121234","arrivalTime":1575018510000}"#).unwrap_or_else(|_| serde_json::json!({}));
1831 let expected_response : models::RedeemEthResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RedeemEthResponse");
1832
1833 let resp = client.redeem_eth(params).await.expect("Expected a response");
1834 let data_future = resp.data();
1835 let actual_response = data_future.await.unwrap();
1836 assert_eq!(actual_response, expected_response);
1837 });
1838 }
1839
1840 #[test]
1841 fn redeem_eth_response_error() {
1842 TOKIO_SHARED_RT.block_on(async {
1843 let client = MockEthStakingApiClient { force_error: true };
1844
1845 let params = RedeemEthParams::builder(dec!(1.0)).build().unwrap();
1846
1847 match client.redeem_eth(params).await {
1848 Ok(_) => panic!("Expected an error"),
1849 Err(err) => {
1850 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1851 }
1852 }
1853 });
1854 }
1855
1856 #[test]
1857 fn subscribe_eth_staking_required_params_success() {
1858 TOKIO_SHARED_RT.block_on(async {
1859 let client = MockEthStakingApiClient { force_error: false };
1860
1861 let params = SubscribeEthStakingParams::builder(dec!(1.0),).build().unwrap();
1862
1863 let resp_json: Value = serde_json::from_str(r#"{"success":true,"wbethAmount":"0.23092091","purchaseId":1234567,"conversionRatio":"1.001212342342"}"#).unwrap_or_else(|_| serde_json::json!({}));
1864 let expected_response : models::SubscribeEthStakingResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::SubscribeEthStakingResponse");
1865
1866 let resp = client.subscribe_eth_staking(params).await.expect("Expected a response");
1867 let data_future = resp.data();
1868 let actual_response = data_future.await.unwrap();
1869 assert_eq!(actual_response, expected_response);
1870 });
1871 }
1872
1873 #[test]
1874 fn subscribe_eth_staking_optional_params_success() {
1875 TOKIO_SHARED_RT.block_on(async {
1876 let client = MockEthStakingApiClient { force_error: false };
1877
1878 let params = SubscribeEthStakingParams::builder(dec!(1.0),).recv_window(5000).build().unwrap();
1879
1880 let resp_json: Value = serde_json::from_str(r#"{"success":true,"wbethAmount":"0.23092091","purchaseId":1234567,"conversionRatio":"1.001212342342"}"#).unwrap_or_else(|_| serde_json::json!({}));
1881 let expected_response : models::SubscribeEthStakingResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::SubscribeEthStakingResponse");
1882
1883 let resp = client.subscribe_eth_staking(params).await.expect("Expected a response");
1884 let data_future = resp.data();
1885 let actual_response = data_future.await.unwrap();
1886 assert_eq!(actual_response, expected_response);
1887 });
1888 }
1889
1890 #[test]
1891 fn subscribe_eth_staking_response_error() {
1892 TOKIO_SHARED_RT.block_on(async {
1893 let client = MockEthStakingApiClient { force_error: true };
1894
1895 let params = SubscribeEthStakingParams::builder(dec!(1.0))
1896 .build()
1897 .unwrap();
1898
1899 match client.subscribe_eth_staking(params).await {
1900 Ok(_) => panic!("Expected an error"),
1901 Err(err) => {
1902 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1903 }
1904 }
1905 });
1906 }
1907
1908 #[test]
1909 fn wrap_beth_required_params_success() {
1910 TOKIO_SHARED_RT.block_on(async {
1911 let client = MockEthStakingApiClient { force_error: false };
1912
1913 let params = WrapBethParams::builder(dec!(1.0)).build().unwrap();
1914
1915 let resp_json: Value = serde_json::from_str(
1916 r#"{"success":true,"wbethAmount":"0.23092091","exchangeRate":"1.001212343432"}"#,
1917 )
1918 .unwrap_or_else(|_| serde_json::json!({}));
1919 let expected_response: models::WrapBethResponse =
1920 serde_json::from_value(resp_json.clone())
1921 .expect("should parse into models::WrapBethResponse");
1922
1923 let resp = client.wrap_beth(params).await.expect("Expected a response");
1924 let data_future = resp.data();
1925 let actual_response = data_future.await.unwrap();
1926 assert_eq!(actual_response, expected_response);
1927 });
1928 }
1929
1930 #[test]
1931 fn wrap_beth_optional_params_success() {
1932 TOKIO_SHARED_RT.block_on(async {
1933 let client = MockEthStakingApiClient { force_error: false };
1934
1935 let params = WrapBethParams::builder(dec!(1.0))
1936 .recv_window(5000)
1937 .build()
1938 .unwrap();
1939
1940 let resp_json: Value = serde_json::from_str(
1941 r#"{"success":true,"wbethAmount":"0.23092091","exchangeRate":"1.001212343432"}"#,
1942 )
1943 .unwrap_or_else(|_| serde_json::json!({}));
1944 let expected_response: models::WrapBethResponse =
1945 serde_json::from_value(resp_json.clone())
1946 .expect("should parse into models::WrapBethResponse");
1947
1948 let resp = client.wrap_beth(params).await.expect("Expected a response");
1949 let data_future = resp.data();
1950 let actual_response = data_future.await.unwrap();
1951 assert_eq!(actual_response, expected_response);
1952 });
1953 }
1954
1955 #[test]
1956 fn wrap_beth_response_error() {
1957 TOKIO_SHARED_RT.block_on(async {
1958 let client = MockEthStakingApiClient { force_error: true };
1959
1960 let params = WrapBethParams::builder(dec!(1.0)).build().unwrap();
1961
1962 match client.wrap_beth(params).await {
1963 Ok(_) => panic!("Expected an error"),
1964 Err(err) => {
1965 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1966 }
1967 }
1968 });
1969 }
1970}