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::crypto_loan::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait StableRateApi: Send + Sync {
34 async fn get_crypto_loans_income_history(
35 &self,
36 params: GetCryptoLoansIncomeHistoryParams,
37 ) -> anyhow::Result<RestApiResponse<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>>;
38 async fn get_loan_borrow_history(
39 &self,
40 params: GetLoanBorrowHistoryParams,
41 ) -> anyhow::Result<RestApiResponse<models::GetLoanBorrowHistoryResponse>>;
42 async fn get_loan_ltv_adjustment_history(
43 &self,
44 params: GetLoanLtvAdjustmentHistoryParams,
45 ) -> anyhow::Result<RestApiResponse<models::GetLoanLtvAdjustmentHistoryResponse>>;
46 async fn get_loan_repayment_history(
47 &self,
48 params: GetLoanRepaymentHistoryParams,
49 ) -> anyhow::Result<RestApiResponse<models::GetLoanRepaymentHistoryResponse>>;
50}
51
52#[derive(Debug, Clone)]
53pub struct StableRateApiClient {
54 configuration: ConfigurationRestApi,
55}
56
57impl StableRateApiClient {
58 pub fn new(configuration: ConfigurationRestApi) -> Self {
59 Self { configuration }
60 }
61}
62
63#[allow(non_camel_case_types)]
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub enum GetCryptoLoansIncomeHistoryTypeEnum {
66 #[serde(rename = "borrowIn")]
67 Borrowin,
68 #[serde(rename = "collateralSpent")]
69 Collateralspent,
70 #[serde(rename = "repayAmount")]
71 Repayamount,
72 #[serde(rename = "collateralReturn")]
73 Collateralreturn,
74 #[serde(rename = "addCollateral")]
75 Addcollateral,
76 #[serde(rename = "removeCollateral")]
77 Removecollateral,
78 #[serde(rename = "collateralReturnAfterLiquidation")]
79 Collateralreturnafterliquidation,
80}
81
82impl GetCryptoLoansIncomeHistoryTypeEnum {
83 #[must_use]
84 pub fn as_str(&self) -> &'static str {
85 match self {
86 Self::Borrowin => "borrowIn",
87 Self::Collateralspent => "collateralSpent",
88 Self::Repayamount => "repayAmount",
89 Self::Collateralreturn => "collateralReturn",
90 Self::Addcollateral => "addCollateral",
91 Self::Removecollateral => "removeCollateral",
92 Self::Collateralreturnafterliquidation => "collateralReturnAfterLiquidation",
93 }
94 }
95}
96
97impl std::str::FromStr for GetCryptoLoansIncomeHistoryTypeEnum {
98 type Err = Box<dyn std::error::Error + Send + Sync>;
99
100 fn from_str(s: &str) -> Result<Self, Self::Err> {
101 match s {
102 "borrowIn" => Ok(Self::Borrowin),
103 "collateralSpent" => Ok(Self::Collateralspent),
104 "repayAmount" => Ok(Self::Repayamount),
105 "collateralReturn" => Ok(Self::Collateralreturn),
106 "addCollateral" => Ok(Self::Addcollateral),
107 "removeCollateral" => Ok(Self::Removecollateral),
108 "collateralReturnAfterLiquidation" => Ok(Self::Collateralreturnafterliquidation),
109 other => Err(format!("invalid GetCryptoLoansIncomeHistoryTypeEnum: {}", other).into()),
110 }
111 }
112}
113
114#[derive(Clone, Debug, Builder, Deserialize, Default)]
119#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
120pub struct GetCryptoLoansIncomeHistoryParams {
121 #[builder(setter(into), default)]
126 #[serde(rename = "asset", default)]
127 pub asset: Option<String>,
128 #[builder(setter(into), default)]
132 #[serde(rename = "type", default)]
133 pub r#type: Option<GetCryptoLoansIncomeHistoryTypeEnum>,
134 #[builder(setter(into), default)]
139 #[serde(rename = "startTime", default)]
140 pub start_time: Option<i64>,
141 #[builder(setter(into), default)]
146 #[serde(rename = "endTime", default)]
147 pub end_time: Option<i64>,
148 #[builder(setter(into), default)]
152 #[serde(rename = "limit", default)]
153 pub limit: Option<i64>,
154 #[builder(setter(into), default)]
158 #[serde(rename = "recvWindow", default)]
159 pub recv_window: Option<i64>,
160}
161
162impl GetCryptoLoansIncomeHistoryParams {
163 #[must_use]
166 pub fn builder() -> GetCryptoLoansIncomeHistoryParamsBuilder {
167 GetCryptoLoansIncomeHistoryParamsBuilder::default()
168 }
169}
170#[derive(Clone, Debug, Builder, Deserialize, Default)]
175#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
176pub struct GetLoanBorrowHistoryParams {
177 #[builder(setter(into), default)]
181 #[serde(rename = "orderId", default)]
182 pub order_id: Option<i64>,
183 #[builder(setter(into), default)]
188 #[serde(rename = "loanCoin", default)]
189 pub loan_coin: Option<String>,
190 #[builder(setter(into), default)]
195 #[serde(rename = "collateralCoin", default)]
196 pub collateral_coin: Option<String>,
197 #[builder(setter(into), default)]
202 #[serde(rename = "startTime", default)]
203 pub start_time: Option<i64>,
204 #[builder(setter(into), default)]
209 #[serde(rename = "endTime", default)]
210 pub end_time: Option<i64>,
211 #[builder(setter(into), default)]
215 #[serde(rename = "current", default)]
216 pub current: Option<i64>,
217 #[builder(setter(into), default)]
221 #[serde(rename = "limit", default)]
222 pub limit: Option<i64>,
223 #[builder(setter(into), default)]
227 #[serde(rename = "recvWindow", default)]
228 pub recv_window: Option<i64>,
229}
230
231impl GetLoanBorrowHistoryParams {
232 #[must_use]
235 pub fn builder() -> GetLoanBorrowHistoryParamsBuilder {
236 GetLoanBorrowHistoryParamsBuilder::default()
237 }
238}
239#[derive(Clone, Debug, Builder, Deserialize, Default)]
244#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
245pub struct GetLoanLtvAdjustmentHistoryParams {
246 #[builder(setter(into), default)]
250 #[serde(rename = "orderId", default)]
251 pub order_id: Option<i64>,
252 #[builder(setter(into), default)]
257 #[serde(rename = "loanCoin", default)]
258 pub loan_coin: Option<String>,
259 #[builder(setter(into), default)]
264 #[serde(rename = "collateralCoin", default)]
265 pub collateral_coin: Option<String>,
266 #[builder(setter(into), default)]
271 #[serde(rename = "startTime", default)]
272 pub start_time: Option<i64>,
273 #[builder(setter(into), default)]
278 #[serde(rename = "endTime", default)]
279 pub end_time: Option<i64>,
280 #[builder(setter(into), default)]
284 #[serde(rename = "current", default)]
285 pub current: Option<i64>,
286 #[builder(setter(into), default)]
290 #[serde(rename = "limit", default)]
291 pub limit: Option<i64>,
292 #[builder(setter(into), default)]
296 #[serde(rename = "recvWindow", default)]
297 pub recv_window: Option<i64>,
298}
299
300impl GetLoanLtvAdjustmentHistoryParams {
301 #[must_use]
304 pub fn builder() -> GetLoanLtvAdjustmentHistoryParamsBuilder {
305 GetLoanLtvAdjustmentHistoryParamsBuilder::default()
306 }
307}
308#[derive(Clone, Debug, Builder, Deserialize, Default)]
313#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
314pub struct GetLoanRepaymentHistoryParams {
315 #[builder(setter(into), default)]
319 #[serde(rename = "orderId", default)]
320 pub order_id: Option<i64>,
321 #[builder(setter(into), default)]
326 #[serde(rename = "loanCoin", default)]
327 pub loan_coin: Option<String>,
328 #[builder(setter(into), default)]
333 #[serde(rename = "collateralCoin", default)]
334 pub collateral_coin: Option<String>,
335 #[builder(setter(into), default)]
340 #[serde(rename = "startTime", default)]
341 pub start_time: Option<i64>,
342 #[builder(setter(into), default)]
347 #[serde(rename = "endTime", default)]
348 pub end_time: Option<i64>,
349 #[builder(setter(into), default)]
353 #[serde(rename = "current", default)]
354 pub current: Option<i64>,
355 #[builder(setter(into), default)]
359 #[serde(rename = "limit", default)]
360 pub limit: Option<i64>,
361 #[builder(setter(into), default)]
365 #[serde(rename = "recvWindow", default)]
366 pub recv_window: Option<i64>,
367}
368
369impl GetLoanRepaymentHistoryParams {
370 #[must_use]
373 pub fn builder() -> GetLoanRepaymentHistoryParamsBuilder {
374 GetLoanRepaymentHistoryParamsBuilder::default()
375 }
376}
377
378#[async_trait]
379impl StableRateApi for StableRateApiClient {
380 async fn get_crypto_loans_income_history(
381 &self,
382 params: GetCryptoLoansIncomeHistoryParams,
383 ) -> anyhow::Result<RestApiResponse<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>>
384 {
385 let GetCryptoLoansIncomeHistoryParams {
386 asset,
387 r#type,
388 start_time,
389 end_time,
390 limit,
391 recv_window,
392 } = params;
393
394 let mut query_params = BTreeMap::new();
395 let body_params = BTreeMap::new();
396
397 if let Some(rw) = asset {
398 query_params.insert("asset".to_string(), json!(rw));
399 }
400
401 if let Some(rw) = r#type {
402 query_params.insert("type".to_string(), json!(rw));
403 }
404
405 if let Some(rw) = start_time {
406 query_params.insert("startTime".to_string(), json!(rw));
407 }
408
409 if let Some(rw) = end_time {
410 query_params.insert("endTime".to_string(), json!(rw));
411 }
412
413 if let Some(rw) = limit {
414 query_params.insert("limit".to_string(), json!(rw));
415 }
416
417 if let Some(rw) = recv_window {
418 query_params.insert("recvWindow".to_string(), json!(rw));
419 }
420
421 send_request::<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>(
422 &self.configuration,
423 "/sapi/v1/loan/income",
424 reqwest::Method::GET,
425 query_params,
426 body_params,
427 if HAS_TIME_UNIT {
428 self.configuration.time_unit
429 } else {
430 None
431 },
432 true,
433 )
434 .await
435 }
436
437 async fn get_loan_borrow_history(
438 &self,
439 params: GetLoanBorrowHistoryParams,
440 ) -> anyhow::Result<RestApiResponse<models::GetLoanBorrowHistoryResponse>> {
441 let GetLoanBorrowHistoryParams {
442 order_id,
443 loan_coin,
444 collateral_coin,
445 start_time,
446 end_time,
447 current,
448 limit,
449 recv_window,
450 } = params;
451
452 let mut query_params = BTreeMap::new();
453 let body_params = BTreeMap::new();
454
455 if let Some(rw) = order_id {
456 query_params.insert("orderId".to_string(), json!(rw));
457 }
458
459 if let Some(rw) = loan_coin {
460 query_params.insert("loanCoin".to_string(), json!(rw));
461 }
462
463 if let Some(rw) = collateral_coin {
464 query_params.insert("collateralCoin".to_string(), json!(rw));
465 }
466
467 if let Some(rw) = start_time {
468 query_params.insert("startTime".to_string(), json!(rw));
469 }
470
471 if let Some(rw) = end_time {
472 query_params.insert("endTime".to_string(), json!(rw));
473 }
474
475 if let Some(rw) = current {
476 query_params.insert("current".to_string(), json!(rw));
477 }
478
479 if let Some(rw) = limit {
480 query_params.insert("limit".to_string(), json!(rw));
481 }
482
483 if let Some(rw) = recv_window {
484 query_params.insert("recvWindow".to_string(), json!(rw));
485 }
486
487 send_request::<models::GetLoanBorrowHistoryResponse>(
488 &self.configuration,
489 "/sapi/v1/loan/borrow/history",
490 reqwest::Method::GET,
491 query_params,
492 body_params,
493 if HAS_TIME_UNIT {
494 self.configuration.time_unit
495 } else {
496 None
497 },
498 true,
499 )
500 .await
501 }
502
503 async fn get_loan_ltv_adjustment_history(
504 &self,
505 params: GetLoanLtvAdjustmentHistoryParams,
506 ) -> anyhow::Result<RestApiResponse<models::GetLoanLtvAdjustmentHistoryResponse>> {
507 let GetLoanLtvAdjustmentHistoryParams {
508 order_id,
509 loan_coin,
510 collateral_coin,
511 start_time,
512 end_time,
513 current,
514 limit,
515 recv_window,
516 } = params;
517
518 let mut query_params = BTreeMap::new();
519 let body_params = BTreeMap::new();
520
521 if let Some(rw) = order_id {
522 query_params.insert("orderId".to_string(), json!(rw));
523 }
524
525 if let Some(rw) = loan_coin {
526 query_params.insert("loanCoin".to_string(), json!(rw));
527 }
528
529 if let Some(rw) = collateral_coin {
530 query_params.insert("collateralCoin".to_string(), json!(rw));
531 }
532
533 if let Some(rw) = start_time {
534 query_params.insert("startTime".to_string(), json!(rw));
535 }
536
537 if let Some(rw) = end_time {
538 query_params.insert("endTime".to_string(), json!(rw));
539 }
540
541 if let Some(rw) = current {
542 query_params.insert("current".to_string(), json!(rw));
543 }
544
545 if let Some(rw) = limit {
546 query_params.insert("limit".to_string(), json!(rw));
547 }
548
549 if let Some(rw) = recv_window {
550 query_params.insert("recvWindow".to_string(), json!(rw));
551 }
552
553 send_request::<models::GetLoanLtvAdjustmentHistoryResponse>(
554 &self.configuration,
555 "/sapi/v1/loan/ltv/adjustment/history",
556 reqwest::Method::GET,
557 query_params,
558 body_params,
559 if HAS_TIME_UNIT {
560 self.configuration.time_unit
561 } else {
562 None
563 },
564 true,
565 )
566 .await
567 }
568
569 async fn get_loan_repayment_history(
570 &self,
571 params: GetLoanRepaymentHistoryParams,
572 ) -> anyhow::Result<RestApiResponse<models::GetLoanRepaymentHistoryResponse>> {
573 let GetLoanRepaymentHistoryParams {
574 order_id,
575 loan_coin,
576 collateral_coin,
577 start_time,
578 end_time,
579 current,
580 limit,
581 recv_window,
582 } = params;
583
584 let mut query_params = BTreeMap::new();
585 let body_params = BTreeMap::new();
586
587 if let Some(rw) = order_id {
588 query_params.insert("orderId".to_string(), json!(rw));
589 }
590
591 if let Some(rw) = loan_coin {
592 query_params.insert("loanCoin".to_string(), json!(rw));
593 }
594
595 if let Some(rw) = collateral_coin {
596 query_params.insert("collateralCoin".to_string(), json!(rw));
597 }
598
599 if let Some(rw) = start_time {
600 query_params.insert("startTime".to_string(), json!(rw));
601 }
602
603 if let Some(rw) = end_time {
604 query_params.insert("endTime".to_string(), json!(rw));
605 }
606
607 if let Some(rw) = current {
608 query_params.insert("current".to_string(), json!(rw));
609 }
610
611 if let Some(rw) = limit {
612 query_params.insert("limit".to_string(), json!(rw));
613 }
614
615 if let Some(rw) = recv_window {
616 query_params.insert("recvWindow".to_string(), json!(rw));
617 }
618
619 send_request::<models::GetLoanRepaymentHistoryResponse>(
620 &self.configuration,
621 "/sapi/v1/loan/repay/history",
622 reqwest::Method::GET,
623 query_params,
624 body_params,
625 if HAS_TIME_UNIT {
626 self.configuration.time_unit
627 } else {
628 None
629 },
630 true,
631 )
632 .await
633 }
634}
635
636#[cfg(all(test, feature = "crypto_loan"))]
637mod tests {
638 use super::*;
639 use crate::TOKIO_SHARED_RT;
640 use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
641 use async_trait::async_trait;
642 use std::collections::HashMap;
643
644 struct DummyRestApiResponse<T> {
645 inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
646 status: u16,
647 headers: HashMap<String, String>,
648 rate_limits: Option<Vec<RestApiRateLimit>>,
649 }
650
651 impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
652 fn from(dummy: DummyRestApiResponse<T>) -> Self {
653 Self {
654 data_fn: dummy.inner,
655 status: dummy.status,
656 headers: dummy.headers,
657 rate_limits: dummy.rate_limits,
658 }
659 }
660 }
661
662 struct MockStableRateApiClient {
663 force_error: bool,
664 }
665
666 #[async_trait]
667 impl StableRateApi for MockStableRateApiClient {
668 async fn get_crypto_loans_income_history(
669 &self,
670 _params: GetCryptoLoansIncomeHistoryParams,
671 ) -> anyhow::Result<RestApiResponse<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>>
672 {
673 if self.force_error {
674 return Err(ConnectorError::ConnectorClientError {
675 msg: "ResponseError".to_string(),
676 code: None,
677 }
678 .into());
679 }
680
681 let resp_json: Value = serde_json::from_str(r#"[{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1633771139847,"tranId":"80423589583"}]"#).unwrap_or_else(|_| serde_json::json!({}));
682 let dummy_response: Vec<models::GetCryptoLoansIncomeHistoryResponseInner> =
683 serde_json::from_value(resp_json.clone()).expect(
684 "should parse into Vec<models::GetCryptoLoansIncomeHistoryResponseInner>",
685 );
686
687 let dummy = DummyRestApiResponse {
688 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
689 status: 200,
690 headers: HashMap::new(),
691 rate_limits: None,
692 };
693
694 Ok(dummy.into())
695 }
696
697 async fn get_loan_borrow_history(
698 &self,
699 _params: GetLoanBorrowHistoryParams,
700 ) -> anyhow::Result<RestApiResponse<models::GetLoanBorrowHistoryResponse>> {
701 if self.force_error {
702 return Err(ConnectorError::ConnectorClientError {
703 msg: "ResponseError".to_string(),
704 code: None,
705 }
706 .into());
707 }
708
709 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"orderId":100000001,"loanCoin":"BUSD","initialLoanAmount":"10000","hourlyInterestRate":"0.000057","loanTerm":"7","collateralCoin":"BNB","initialCollateralAmount":"49.27565492","borrowTime":1575018510000,"status":"Repaid"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
710 let dummy_response: models::GetLoanBorrowHistoryResponse =
711 serde_json::from_value(resp_json.clone())
712 .expect("should parse into models::GetLoanBorrowHistoryResponse");
713
714 let dummy = DummyRestApiResponse {
715 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
716 status: 200,
717 headers: HashMap::new(),
718 rate_limits: None,
719 };
720
721 Ok(dummy.into())
722 }
723
724 async fn get_loan_ltv_adjustment_history(
725 &self,
726 _params: GetLoanLtvAdjustmentHistoryParams,
727 ) -> anyhow::Result<RestApiResponse<models::GetLoanLtvAdjustmentHistoryResponse>> {
728 if self.force_error {
729 return Err(ConnectorError::ConnectorClientError {
730 msg: "ResponseError".to_string(),
731 code: None,
732 }
733 .into());
734 }
735
736 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","amount":"5.235","preLTV":"0.78","afterLTV":"0.56","adjustTime":1575018510000,"orderId":756783308056935400}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
737 let dummy_response: models::GetLoanLtvAdjustmentHistoryResponse =
738 serde_json::from_value(resp_json.clone())
739 .expect("should parse into models::GetLoanLtvAdjustmentHistoryResponse");
740
741 let dummy = DummyRestApiResponse {
742 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
743 status: 200,
744 headers: HashMap::new(),
745 rate_limits: None,
746 };
747
748 Ok(dummy.into())
749 }
750
751 async fn get_loan_repayment_history(
752 &self,
753 _params: GetLoanRepaymentHistoryParams,
754 ) -> anyhow::Result<RestApiResponse<models::GetLoanRepaymentHistoryResponse>> {
755 if self.force_error {
756 return Err(ConnectorError::ConnectorClientError {
757 msg: "ResponseError".to_string(),
758 code: None,
759 }
760 .into());
761 }
762
763 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","repayAmount":"10000","collateralCoin":"BNB","collateralUsed":"0","collateralReturn":"49.27565492","repayType":"1","repayStatus":"Repaid","repayTime":1575018510000,"orderId":756783308056935400}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
764 let dummy_response: models::GetLoanRepaymentHistoryResponse =
765 serde_json::from_value(resp_json.clone())
766 .expect("should parse into models::GetLoanRepaymentHistoryResponse");
767
768 let dummy = DummyRestApiResponse {
769 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
770 status: 200,
771 headers: HashMap::new(),
772 rate_limits: None,
773 };
774
775 Ok(dummy.into())
776 }
777 }
778
779 #[test]
780 fn get_crypto_loans_income_history_required_params_success() {
781 TOKIO_SHARED_RT.block_on(async {
782 let client = MockStableRateApiClient { force_error: false };
783
784 let params = GetCryptoLoansIncomeHistoryParams::builder().build().unwrap();
785
786 let resp_json: Value = serde_json::from_str(r#"[{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1633771139847,"tranId":"80423589583"}]"#).unwrap_or_else(|_| serde_json::json!({}));
787 let expected_response : Vec<models::GetCryptoLoansIncomeHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetCryptoLoansIncomeHistoryResponseInner>");
788
789 let resp = client.get_crypto_loans_income_history(params).await.expect("Expected a response");
790 let data_future = resp.data();
791 let actual_response = data_future.await.unwrap();
792 assert_eq!(actual_response, expected_response);
793 });
794 }
795
796 #[test]
797 fn get_crypto_loans_income_history_optional_params_success() {
798 TOKIO_SHARED_RT.block_on(async {
799 let client = MockStableRateApiClient { force_error: false };
800
801 let params = GetCryptoLoansIncomeHistoryParams::builder().asset("BUSD".to_string()).r#type(GetCryptoLoansIncomeHistoryTypeEnum::Borrowin).start_time(1623319461670).end_time(1641782889000).limit(10).recv_window(5000).build().unwrap();
802
803 let resp_json: Value = serde_json::from_str(r#"[{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1633771139847,"tranId":"80423589583"}]"#).unwrap_or_else(|_| serde_json::json!({}));
804 let expected_response : Vec<models::GetCryptoLoansIncomeHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetCryptoLoansIncomeHistoryResponseInner>");
805
806 let resp = client.get_crypto_loans_income_history(params).await.expect("Expected a response");
807 let data_future = resp.data();
808 let actual_response = data_future.await.unwrap();
809 assert_eq!(actual_response, expected_response);
810 });
811 }
812
813 #[test]
814 fn get_crypto_loans_income_history_response_error() {
815 TOKIO_SHARED_RT.block_on(async {
816 let client = MockStableRateApiClient { force_error: true };
817
818 let params = GetCryptoLoansIncomeHistoryParams::builder()
819 .build()
820 .unwrap();
821
822 match client.get_crypto_loans_income_history(params).await {
823 Ok(_) => panic!("Expected an error"),
824 Err(err) => {
825 assert_eq!(err.to_string(), "Connector client error: ResponseError");
826 }
827 }
828 });
829 }
830
831 #[test]
832 fn get_loan_borrow_history_required_params_success() {
833 TOKIO_SHARED_RT.block_on(async {
834 let client = MockStableRateApiClient { force_error: false };
835
836 let params = GetLoanBorrowHistoryParams::builder().build().unwrap();
837
838 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"orderId":100000001,"loanCoin":"BUSD","initialLoanAmount":"10000","hourlyInterestRate":"0.000057","loanTerm":"7","collateralCoin":"BNB","initialCollateralAmount":"49.27565492","borrowTime":1575018510000,"status":"Repaid"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
839 let expected_response : models::GetLoanBorrowHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanBorrowHistoryResponse");
840
841 let resp = client.get_loan_borrow_history(params).await.expect("Expected a response");
842 let data_future = resp.data();
843 let actual_response = data_future.await.unwrap();
844 assert_eq!(actual_response, expected_response);
845 });
846 }
847
848 #[test]
849 fn get_loan_borrow_history_optional_params_success() {
850 TOKIO_SHARED_RT.block_on(async {
851 let client = MockStableRateApiClient { force_error: false };
852
853 let params = GetLoanBorrowHistoryParams::builder().order_id(1).loan_coin("BUSD".to_string()).collateral_coin("BNB".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();
854
855 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"orderId":100000001,"loanCoin":"BUSD","initialLoanAmount":"10000","hourlyInterestRate":"0.000057","loanTerm":"7","collateralCoin":"BNB","initialCollateralAmount":"49.27565492","borrowTime":1575018510000,"status":"Repaid"}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
856 let expected_response : models::GetLoanBorrowHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanBorrowHistoryResponse");
857
858 let resp = client.get_loan_borrow_history(params).await.expect("Expected a response");
859 let data_future = resp.data();
860 let actual_response = data_future.await.unwrap();
861 assert_eq!(actual_response, expected_response);
862 });
863 }
864
865 #[test]
866 fn get_loan_borrow_history_response_error() {
867 TOKIO_SHARED_RT.block_on(async {
868 let client = MockStableRateApiClient { force_error: true };
869
870 let params = GetLoanBorrowHistoryParams::builder().build().unwrap();
871
872 match client.get_loan_borrow_history(params).await {
873 Ok(_) => panic!("Expected an error"),
874 Err(err) => {
875 assert_eq!(err.to_string(), "Connector client error: ResponseError");
876 }
877 }
878 });
879 }
880
881 #[test]
882 fn get_loan_ltv_adjustment_history_required_params_success() {
883 TOKIO_SHARED_RT.block_on(async {
884 let client = MockStableRateApiClient { force_error: false };
885
886 let params = GetLoanLtvAdjustmentHistoryParams::builder().build().unwrap();
887
888 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","amount":"5.235","preLTV":"0.78","afterLTV":"0.56","adjustTime":1575018510000,"orderId":756783308056935400}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
889 let expected_response : models::GetLoanLtvAdjustmentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanLtvAdjustmentHistoryResponse");
890
891 let resp = client.get_loan_ltv_adjustment_history(params).await.expect("Expected a response");
892 let data_future = resp.data();
893 let actual_response = data_future.await.unwrap();
894 assert_eq!(actual_response, expected_response);
895 });
896 }
897
898 #[test]
899 fn get_loan_ltv_adjustment_history_optional_params_success() {
900 TOKIO_SHARED_RT.block_on(async {
901 let client = MockStableRateApiClient { force_error: false };
902
903 let params = GetLoanLtvAdjustmentHistoryParams::builder().order_id(1).loan_coin("BUSD".to_string()).collateral_coin("BNB".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();
904
905 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","collateralCoin":"BNB","direction":"ADDITIONAL","amount":"5.235","preLTV":"0.78","afterLTV":"0.56","adjustTime":1575018510000,"orderId":756783308056935400}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
906 let expected_response : models::GetLoanLtvAdjustmentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanLtvAdjustmentHistoryResponse");
907
908 let resp = client.get_loan_ltv_adjustment_history(params).await.expect("Expected a response");
909 let data_future = resp.data();
910 let actual_response = data_future.await.unwrap();
911 assert_eq!(actual_response, expected_response);
912 });
913 }
914
915 #[test]
916 fn get_loan_ltv_adjustment_history_response_error() {
917 TOKIO_SHARED_RT.block_on(async {
918 let client = MockStableRateApiClient { force_error: true };
919
920 let params = GetLoanLtvAdjustmentHistoryParams::builder()
921 .build()
922 .unwrap();
923
924 match client.get_loan_ltv_adjustment_history(params).await {
925 Ok(_) => panic!("Expected an error"),
926 Err(err) => {
927 assert_eq!(err.to_string(), "Connector client error: ResponseError");
928 }
929 }
930 });
931 }
932
933 #[test]
934 fn get_loan_repayment_history_required_params_success() {
935 TOKIO_SHARED_RT.block_on(async {
936 let client = MockStableRateApiClient { force_error: false };
937
938 let params = GetLoanRepaymentHistoryParams::builder().build().unwrap();
939
940 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","repayAmount":"10000","collateralCoin":"BNB","collateralUsed":"0","collateralReturn":"49.27565492","repayType":"1","repayStatus":"Repaid","repayTime":1575018510000,"orderId":756783308056935400}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
941 let expected_response : models::GetLoanRepaymentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanRepaymentHistoryResponse");
942
943 let resp = client.get_loan_repayment_history(params).await.expect("Expected a response");
944 let data_future = resp.data();
945 let actual_response = data_future.await.unwrap();
946 assert_eq!(actual_response, expected_response);
947 });
948 }
949
950 #[test]
951 fn get_loan_repayment_history_optional_params_success() {
952 TOKIO_SHARED_RT.block_on(async {
953 let client = MockStableRateApiClient { force_error: false };
954
955 let params = GetLoanRepaymentHistoryParams::builder().order_id(1).loan_coin("BUSD".to_string()).collateral_coin("BNB".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();
956
957 let resp_json: Value = serde_json::from_str(r#"{"rows":[{"loanCoin":"BUSD","repayAmount":"10000","collateralCoin":"BNB","collateralUsed":"0","collateralReturn":"49.27565492","repayType":"1","repayStatus":"Repaid","repayTime":1575018510000,"orderId":756783308056935400}],"total":1}"#).unwrap_or_else(|_| serde_json::json!({}));
958 let expected_response : models::GetLoanRepaymentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanRepaymentHistoryResponse");
959
960 let resp = client.get_loan_repayment_history(params).await.expect("Expected a response");
961 let data_future = resp.data();
962 let actual_response = data_future.await.unwrap();
963 assert_eq!(actual_response, expected_response);
964 });
965 }
966
967 #[test]
968 fn get_loan_repayment_history_response_error() {
969 TOKIO_SHARED_RT.block_on(async {
970 let client = MockStableRateApiClient { force_error: true };
971
972 let params = GetLoanRepaymentHistoryParams::builder().build().unwrap();
973
974 match client.get_loan_repayment_history(params).await {
975 Ok(_) => panic!("Expected an error"),
976 Err(err) => {
977 assert_eq!(err.to_string(), "Connector client error: ResponseError");
978 }
979 }
980 });
981 }
982}