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 check_collateral_repay_rate_stable_rate(
35 &self,
36 params: CheckCollateralRepayRateStableRateParams,
37 ) -> anyhow::Result<RestApiResponse<models::CheckCollateralRepayRateStableRateResponse>>;
38 async fn get_crypto_loans_income_history(
39 &self,
40 params: GetCryptoLoansIncomeHistoryParams,
41 ) -> anyhow::Result<RestApiResponse<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>>;
42 async fn get_loan_borrow_history(
43 &self,
44 params: GetLoanBorrowHistoryParams,
45 ) -> anyhow::Result<RestApiResponse<models::GetLoanBorrowHistoryResponse>>;
46 async fn get_loan_ltv_adjustment_history(
47 &self,
48 params: GetLoanLtvAdjustmentHistoryParams,
49 ) -> anyhow::Result<RestApiResponse<models::GetLoanLtvAdjustmentHistoryResponse>>;
50 async fn get_loan_repayment_history(
51 &self,
52 params: GetLoanRepaymentHistoryParams,
53 ) -> anyhow::Result<RestApiResponse<models::GetLoanRepaymentHistoryResponse>>;
54}
55
56#[derive(Debug, Clone)]
57pub struct StableRateApiClient {
58 configuration: ConfigurationRestApi,
59}
60
61impl StableRateApiClient {
62 pub fn new(configuration: ConfigurationRestApi) -> Self {
63 Self { configuration }
64 }
65}
66
67#[derive(Clone, Debug, Builder)]
72#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
73pub struct CheckCollateralRepayRateStableRateParams {
74 #[builder(setter(into))]
79 pub loan_coin: String,
80 #[builder(setter(into))]
85 pub collateral_coin: String,
86 #[builder(setter(into))]
90 pub repay_amount: rust_decimal::Decimal,
91 #[builder(setter(into), default)]
96 pub recv_window: Option<i64>,
97}
98
99impl CheckCollateralRepayRateStableRateParams {
100 #[must_use]
109 pub fn builder(
110 loan_coin: String,
111 collateral_coin: String,
112 repay_amount: rust_decimal::Decimal,
113 ) -> CheckCollateralRepayRateStableRateParamsBuilder {
114 CheckCollateralRepayRateStableRateParamsBuilder::default()
115 .loan_coin(loan_coin)
116 .collateral_coin(collateral_coin)
117 .repay_amount(repay_amount)
118 }
119}
120#[derive(Clone, Debug, Builder, Default)]
125#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
126pub struct GetCryptoLoansIncomeHistoryParams {
127 #[builder(setter(into), default)]
132 pub asset: Option<String>,
133 #[builder(setter(into), default)]
137 pub r#type: Option<String>,
138 #[builder(setter(into), default)]
143 pub start_time: Option<i64>,
144 #[builder(setter(into), default)]
149 pub end_time: Option<i64>,
150 #[builder(setter(into), default)]
154 pub limit: Option<i64>,
155 #[builder(setter(into), default)]
160 pub recv_window: Option<i64>,
161}
162
163impl GetCryptoLoansIncomeHistoryParams {
164 #[must_use]
167 pub fn builder() -> GetCryptoLoansIncomeHistoryParamsBuilder {
168 GetCryptoLoansIncomeHistoryParamsBuilder::default()
169 }
170}
171#[derive(Clone, Debug, Builder, Default)]
176#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
177pub struct GetLoanBorrowHistoryParams {
178 #[builder(setter(into), default)]
182 pub order_id: Option<i64>,
183 #[builder(setter(into), default)]
188 pub loan_coin: Option<String>,
189 #[builder(setter(into), default)]
194 pub collateral_coin: Option<String>,
195 #[builder(setter(into), default)]
200 pub start_time: Option<i64>,
201 #[builder(setter(into), default)]
206 pub end_time: Option<i64>,
207 #[builder(setter(into), default)]
211 pub current: Option<i64>,
212 #[builder(setter(into), default)]
216 pub limit: Option<i64>,
217 #[builder(setter(into), default)]
222 pub recv_window: Option<i64>,
223}
224
225impl GetLoanBorrowHistoryParams {
226 #[must_use]
229 pub fn builder() -> GetLoanBorrowHistoryParamsBuilder {
230 GetLoanBorrowHistoryParamsBuilder::default()
231 }
232}
233#[derive(Clone, Debug, Builder, Default)]
238#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
239pub struct GetLoanLtvAdjustmentHistoryParams {
240 #[builder(setter(into), default)]
244 pub order_id: Option<i64>,
245 #[builder(setter(into), default)]
250 pub loan_coin: Option<String>,
251 #[builder(setter(into), default)]
256 pub collateral_coin: Option<String>,
257 #[builder(setter(into), default)]
262 pub start_time: Option<i64>,
263 #[builder(setter(into), default)]
268 pub end_time: Option<i64>,
269 #[builder(setter(into), default)]
273 pub current: Option<i64>,
274 #[builder(setter(into), default)]
278 pub limit: Option<i64>,
279 #[builder(setter(into), default)]
284 pub recv_window: Option<i64>,
285}
286
287impl GetLoanLtvAdjustmentHistoryParams {
288 #[must_use]
291 pub fn builder() -> GetLoanLtvAdjustmentHistoryParamsBuilder {
292 GetLoanLtvAdjustmentHistoryParamsBuilder::default()
293 }
294}
295#[derive(Clone, Debug, Builder, Default)]
300#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
301pub struct GetLoanRepaymentHistoryParams {
302 #[builder(setter(into), default)]
306 pub order_id: Option<i64>,
307 #[builder(setter(into), default)]
312 pub loan_coin: Option<String>,
313 #[builder(setter(into), default)]
318 pub collateral_coin: Option<String>,
319 #[builder(setter(into), default)]
324 pub start_time: Option<i64>,
325 #[builder(setter(into), default)]
330 pub end_time: Option<i64>,
331 #[builder(setter(into), default)]
335 pub current: Option<i64>,
336 #[builder(setter(into), default)]
340 pub limit: Option<i64>,
341 #[builder(setter(into), default)]
346 pub recv_window: Option<i64>,
347}
348
349impl GetLoanRepaymentHistoryParams {
350 #[must_use]
353 pub fn builder() -> GetLoanRepaymentHistoryParamsBuilder {
354 GetLoanRepaymentHistoryParamsBuilder::default()
355 }
356}
357
358#[async_trait]
359impl StableRateApi for StableRateApiClient {
360 async fn check_collateral_repay_rate_stable_rate(
361 &self,
362 params: CheckCollateralRepayRateStableRateParams,
363 ) -> anyhow::Result<RestApiResponse<models::CheckCollateralRepayRateStableRateResponse>> {
364 let CheckCollateralRepayRateStableRateParams {
365 loan_coin,
366 collateral_coin,
367 repay_amount,
368 recv_window,
369 } = params;
370
371 let mut query_params = BTreeMap::new();
372 let body_params = BTreeMap::new();
373
374 query_params.insert("loanCoin".to_string(), json!(loan_coin));
375
376 query_params.insert("collateralCoin".to_string(), json!(collateral_coin));
377
378 query_params.insert("repayAmount".to_string(), json!(repay_amount));
379
380 if let Some(rw) = recv_window {
381 query_params.insert("recvWindow".to_string(), json!(rw));
382 }
383
384 send_request::<models::CheckCollateralRepayRateStableRateResponse>(
385 &self.configuration,
386 "/sapi/v1/loan/repay/collateral/rate",
387 reqwest::Method::GET,
388 query_params,
389 body_params,
390 if HAS_TIME_UNIT {
391 self.configuration.time_unit
392 } else {
393 None
394 },
395 true,
396 )
397 .await
398 }
399
400 async fn get_crypto_loans_income_history(
401 &self,
402 params: GetCryptoLoansIncomeHistoryParams,
403 ) -> anyhow::Result<RestApiResponse<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>>
404 {
405 let GetCryptoLoansIncomeHistoryParams {
406 asset,
407 r#type,
408 start_time,
409 end_time,
410 limit,
411 recv_window,
412 } = params;
413
414 let mut query_params = BTreeMap::new();
415 let body_params = BTreeMap::new();
416
417 if let Some(rw) = asset {
418 query_params.insert("asset".to_string(), json!(rw));
419 }
420
421 if let Some(rw) = r#type {
422 query_params.insert("type".to_string(), json!(rw));
423 }
424
425 if let Some(rw) = start_time {
426 query_params.insert("startTime".to_string(), json!(rw));
427 }
428
429 if let Some(rw) = end_time {
430 query_params.insert("endTime".to_string(), json!(rw));
431 }
432
433 if let Some(rw) = limit {
434 query_params.insert("limit".to_string(), json!(rw));
435 }
436
437 if let Some(rw) = recv_window {
438 query_params.insert("recvWindow".to_string(), json!(rw));
439 }
440
441 send_request::<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>(
442 &self.configuration,
443 "/sapi/v1/loan/income",
444 reqwest::Method::GET,
445 query_params,
446 body_params,
447 if HAS_TIME_UNIT {
448 self.configuration.time_unit
449 } else {
450 None
451 },
452 true,
453 )
454 .await
455 }
456
457 async fn get_loan_borrow_history(
458 &self,
459 params: GetLoanBorrowHistoryParams,
460 ) -> anyhow::Result<RestApiResponse<models::GetLoanBorrowHistoryResponse>> {
461 let GetLoanBorrowHistoryParams {
462 order_id,
463 loan_coin,
464 collateral_coin,
465 start_time,
466 end_time,
467 current,
468 limit,
469 recv_window,
470 } = params;
471
472 let mut query_params = BTreeMap::new();
473 let body_params = BTreeMap::new();
474
475 if let Some(rw) = order_id {
476 query_params.insert("orderId".to_string(), json!(rw));
477 }
478
479 if let Some(rw) = loan_coin {
480 query_params.insert("loanCoin".to_string(), json!(rw));
481 }
482
483 if let Some(rw) = collateral_coin {
484 query_params.insert("collateralCoin".to_string(), json!(rw));
485 }
486
487 if let Some(rw) = start_time {
488 query_params.insert("startTime".to_string(), json!(rw));
489 }
490
491 if let Some(rw) = end_time {
492 query_params.insert("endTime".to_string(), json!(rw));
493 }
494
495 if let Some(rw) = current {
496 query_params.insert("current".to_string(), json!(rw));
497 }
498
499 if let Some(rw) = limit {
500 query_params.insert("limit".to_string(), json!(rw));
501 }
502
503 if let Some(rw) = recv_window {
504 query_params.insert("recvWindow".to_string(), json!(rw));
505 }
506
507 send_request::<models::GetLoanBorrowHistoryResponse>(
508 &self.configuration,
509 "/sapi/v1/loan/borrow/history",
510 reqwest::Method::GET,
511 query_params,
512 body_params,
513 if HAS_TIME_UNIT {
514 self.configuration.time_unit
515 } else {
516 None
517 },
518 true,
519 )
520 .await
521 }
522
523 async fn get_loan_ltv_adjustment_history(
524 &self,
525 params: GetLoanLtvAdjustmentHistoryParams,
526 ) -> anyhow::Result<RestApiResponse<models::GetLoanLtvAdjustmentHistoryResponse>> {
527 let GetLoanLtvAdjustmentHistoryParams {
528 order_id,
529 loan_coin,
530 collateral_coin,
531 start_time,
532 end_time,
533 current,
534 limit,
535 recv_window,
536 } = params;
537
538 let mut query_params = BTreeMap::new();
539 let body_params = BTreeMap::new();
540
541 if let Some(rw) = order_id {
542 query_params.insert("orderId".to_string(), json!(rw));
543 }
544
545 if let Some(rw) = loan_coin {
546 query_params.insert("loanCoin".to_string(), json!(rw));
547 }
548
549 if let Some(rw) = collateral_coin {
550 query_params.insert("collateralCoin".to_string(), json!(rw));
551 }
552
553 if let Some(rw) = start_time {
554 query_params.insert("startTime".to_string(), json!(rw));
555 }
556
557 if let Some(rw) = end_time {
558 query_params.insert("endTime".to_string(), json!(rw));
559 }
560
561 if let Some(rw) = current {
562 query_params.insert("current".to_string(), json!(rw));
563 }
564
565 if let Some(rw) = limit {
566 query_params.insert("limit".to_string(), json!(rw));
567 }
568
569 if let Some(rw) = recv_window {
570 query_params.insert("recvWindow".to_string(), json!(rw));
571 }
572
573 send_request::<models::GetLoanLtvAdjustmentHistoryResponse>(
574 &self.configuration,
575 "/sapi/v1/loan/ltv/adjustment/history",
576 reqwest::Method::GET,
577 query_params,
578 body_params,
579 if HAS_TIME_UNIT {
580 self.configuration.time_unit
581 } else {
582 None
583 },
584 true,
585 )
586 .await
587 }
588
589 async fn get_loan_repayment_history(
590 &self,
591 params: GetLoanRepaymentHistoryParams,
592 ) -> anyhow::Result<RestApiResponse<models::GetLoanRepaymentHistoryResponse>> {
593 let GetLoanRepaymentHistoryParams {
594 order_id,
595 loan_coin,
596 collateral_coin,
597 start_time,
598 end_time,
599 current,
600 limit,
601 recv_window,
602 } = params;
603
604 let mut query_params = BTreeMap::new();
605 let body_params = BTreeMap::new();
606
607 if let Some(rw) = order_id {
608 query_params.insert("orderId".to_string(), json!(rw));
609 }
610
611 if let Some(rw) = loan_coin {
612 query_params.insert("loanCoin".to_string(), json!(rw));
613 }
614
615 if let Some(rw) = collateral_coin {
616 query_params.insert("collateralCoin".to_string(), json!(rw));
617 }
618
619 if let Some(rw) = start_time {
620 query_params.insert("startTime".to_string(), json!(rw));
621 }
622
623 if let Some(rw) = end_time {
624 query_params.insert("endTime".to_string(), json!(rw));
625 }
626
627 if let Some(rw) = current {
628 query_params.insert("current".to_string(), json!(rw));
629 }
630
631 if let Some(rw) = limit {
632 query_params.insert("limit".to_string(), json!(rw));
633 }
634
635 if let Some(rw) = recv_window {
636 query_params.insert("recvWindow".to_string(), json!(rw));
637 }
638
639 send_request::<models::GetLoanRepaymentHistoryResponse>(
640 &self.configuration,
641 "/sapi/v1/loan/repay/history",
642 reqwest::Method::GET,
643 query_params,
644 body_params,
645 if HAS_TIME_UNIT {
646 self.configuration.time_unit
647 } else {
648 None
649 },
650 true,
651 )
652 .await
653 }
654}
655
656#[cfg(all(test, feature = "crypto_loan"))]
657mod tests {
658 use super::*;
659 use crate::TOKIO_SHARED_RT;
660 use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
661 use async_trait::async_trait;
662 use std::collections::HashMap;
663
664 struct DummyRestApiResponse<T> {
665 inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
666 status: u16,
667 headers: HashMap<String, String>,
668 rate_limits: Option<Vec<RestApiRateLimit>>,
669 }
670
671 impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
672 fn from(dummy: DummyRestApiResponse<T>) -> Self {
673 Self {
674 data_fn: dummy.inner,
675 status: dummy.status,
676 headers: dummy.headers,
677 rate_limits: dummy.rate_limits,
678 }
679 }
680 }
681
682 struct MockStableRateApiClient {
683 force_error: bool,
684 }
685
686 #[async_trait]
687 impl StableRateApi for MockStableRateApiClient {
688 async fn check_collateral_repay_rate_stable_rate(
689 &self,
690 _params: CheckCollateralRepayRateStableRateParams,
691 ) -> anyhow::Result<RestApiResponse<models::CheckCollateralRepayRateStableRateResponse>>
692 {
693 if self.force_error {
694 return Err(ConnectorError::ConnectorClientError {
695 msg: "ResponseError".to_string(),
696 code: None,
697 }
698 .into());
699 }
700
701 let resp_json: Value = serde_json::from_str(r#"{"loanlCoin":"BUSD","collateralCoin":"BNB","repayAmount":"1000","rate":"300.36781234"}"#).unwrap();
702 let dummy_response: models::CheckCollateralRepayRateStableRateResponse =
703 serde_json::from_value(resp_json.clone())
704 .expect("should parse into models::CheckCollateralRepayRateStableRateResponse");
705
706 let dummy = DummyRestApiResponse {
707 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
708 status: 200,
709 headers: HashMap::new(),
710 rate_limits: None,
711 };
712
713 Ok(dummy.into())
714 }
715
716 async fn get_crypto_loans_income_history(
717 &self,
718 _params: GetCryptoLoansIncomeHistoryParams,
719 ) -> anyhow::Result<RestApiResponse<Vec<models::GetCryptoLoansIncomeHistoryResponseInner>>>
720 {
721 if self.force_error {
722 return Err(ConnectorError::ConnectorClientError {
723 msg: "ResponseError".to_string(),
724 code: None,
725 }
726 .into());
727 }
728
729 let resp_json: Value = serde_json::from_str(r#"[{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1633771139847,"tranId":"80423589583"},{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1634638371496,"tranId":"81685123491"}]"#).unwrap();
730 let dummy_response: Vec<models::GetCryptoLoansIncomeHistoryResponseInner> =
731 serde_json::from_value(resp_json.clone()).expect(
732 "should parse into Vec<models::GetCryptoLoansIncomeHistoryResponseInner>",
733 );
734
735 let dummy = DummyRestApiResponse {
736 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
737 status: 200,
738 headers: HashMap::new(),
739 rate_limits: None,
740 };
741
742 Ok(dummy.into())
743 }
744
745 async fn get_loan_borrow_history(
746 &self,
747 _params: GetLoanBorrowHistoryParams,
748 ) -> anyhow::Result<RestApiResponse<models::GetLoanBorrowHistoryResponse>> {
749 if self.force_error {
750 return Err(ConnectorError::ConnectorClientError {
751 msg: "ResponseError".to_string(),
752 code: None,
753 }
754 .into());
755 }
756
757 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();
758 let dummy_response: models::GetLoanBorrowHistoryResponse =
759 serde_json::from_value(resp_json.clone())
760 .expect("should parse into models::GetLoanBorrowHistoryResponse");
761
762 let dummy = DummyRestApiResponse {
763 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
764 status: 200,
765 headers: HashMap::new(),
766 rate_limits: None,
767 };
768
769 Ok(dummy.into())
770 }
771
772 async fn get_loan_ltv_adjustment_history(
773 &self,
774 _params: GetLoanLtvAdjustmentHistoryParams,
775 ) -> anyhow::Result<RestApiResponse<models::GetLoanLtvAdjustmentHistoryResponse>> {
776 if self.force_error {
777 return Err(ConnectorError::ConnectorClientError {
778 msg: "ResponseError".to_string(),
779 code: None,
780 }
781 .into());
782 }
783
784 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();
785 let dummy_response: models::GetLoanLtvAdjustmentHistoryResponse =
786 serde_json::from_value(resp_json.clone())
787 .expect("should parse into models::GetLoanLtvAdjustmentHistoryResponse");
788
789 let dummy = DummyRestApiResponse {
790 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
791 status: 200,
792 headers: HashMap::new(),
793 rate_limits: None,
794 };
795
796 Ok(dummy.into())
797 }
798
799 async fn get_loan_repayment_history(
800 &self,
801 _params: GetLoanRepaymentHistoryParams,
802 ) -> anyhow::Result<RestApiResponse<models::GetLoanRepaymentHistoryResponse>> {
803 if self.force_error {
804 return Err(ConnectorError::ConnectorClientError {
805 msg: "ResponseError".to_string(),
806 code: None,
807 }
808 .into());
809 }
810
811 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();
812 let dummy_response: models::GetLoanRepaymentHistoryResponse =
813 serde_json::from_value(resp_json.clone())
814 .expect("should parse into models::GetLoanRepaymentHistoryResponse");
815
816 let dummy = DummyRestApiResponse {
817 inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
818 status: 200,
819 headers: HashMap::new(),
820 rate_limits: None,
821 };
822
823 Ok(dummy.into())
824 }
825 }
826
827 #[test]
828 fn check_collateral_repay_rate_stable_rate_required_params_success() {
829 TOKIO_SHARED_RT.block_on(async {
830 let client = MockStableRateApiClient { force_error: false };
831
832 let params = CheckCollateralRepayRateStableRateParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),dec!(1.0),).build().unwrap();
833
834 let resp_json: Value = serde_json::from_str(r#"{"loanlCoin":"BUSD","collateralCoin":"BNB","repayAmount":"1000","rate":"300.36781234"}"#).unwrap();
835 let expected_response : models::CheckCollateralRepayRateStableRateResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CheckCollateralRepayRateStableRateResponse");
836
837 let resp = client.check_collateral_repay_rate_stable_rate(params).await.expect("Expected a response");
838 let data_future = resp.data();
839 let actual_response = data_future.await.unwrap();
840 assert_eq!(actual_response, expected_response);
841 });
842 }
843
844 #[test]
845 fn check_collateral_repay_rate_stable_rate_optional_params_success() {
846 TOKIO_SHARED_RT.block_on(async {
847 let client = MockStableRateApiClient { force_error: false };
848
849 let params = CheckCollateralRepayRateStableRateParams::builder("loan_coin_example".to_string(),"collateral_coin_example".to_string(),dec!(1.0),).recv_window(5000).build().unwrap();
850
851 let resp_json: Value = serde_json::from_str(r#"{"loanlCoin":"BUSD","collateralCoin":"BNB","repayAmount":"1000","rate":"300.36781234"}"#).unwrap();
852 let expected_response : models::CheckCollateralRepayRateStableRateResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::CheckCollateralRepayRateStableRateResponse");
853
854 let resp = client.check_collateral_repay_rate_stable_rate(params).await.expect("Expected a response");
855 let data_future = resp.data();
856 let actual_response = data_future.await.unwrap();
857 assert_eq!(actual_response, expected_response);
858 });
859 }
860
861 #[test]
862 fn check_collateral_repay_rate_stable_rate_response_error() {
863 TOKIO_SHARED_RT.block_on(async {
864 let client = MockStableRateApiClient { force_error: true };
865
866 let params = CheckCollateralRepayRateStableRateParams::builder(
867 "loan_coin_example".to_string(),
868 "collateral_coin_example".to_string(),
869 dec!(1.0),
870 )
871 .build()
872 .unwrap();
873
874 match client.check_collateral_repay_rate_stable_rate(params).await {
875 Ok(_) => panic!("Expected an error"),
876 Err(err) => {
877 assert_eq!(err.to_string(), "Connector client error: ResponseError");
878 }
879 }
880 });
881 }
882
883 #[test]
884 fn get_crypto_loans_income_history_required_params_success() {
885 TOKIO_SHARED_RT.block_on(async {
886 let client = MockStableRateApiClient { force_error: false };
887
888 let params = GetCryptoLoansIncomeHistoryParams::builder().build().unwrap();
889
890 let resp_json: Value = serde_json::from_str(r#"[{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1633771139847,"tranId":"80423589583"},{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1634638371496,"tranId":"81685123491"}]"#).unwrap();
891 let expected_response : Vec<models::GetCryptoLoansIncomeHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetCryptoLoansIncomeHistoryResponseInner>");
892
893 let resp = client.get_crypto_loans_income_history(params).await.expect("Expected a response");
894 let data_future = resp.data();
895 let actual_response = data_future.await.unwrap();
896 assert_eq!(actual_response, expected_response);
897 });
898 }
899
900 #[test]
901 fn get_crypto_loans_income_history_optional_params_success() {
902 TOKIO_SHARED_RT.block_on(async {
903 let client = MockStableRateApiClient { force_error: false };
904
905 let params = GetCryptoLoansIncomeHistoryParams::builder().asset("asset_example".to_string()).r#type("0".to_string()).start_time(1623319461670).end_time(1641782889000).limit(10).recv_window(5000).build().unwrap();
906
907 let resp_json: Value = serde_json::from_str(r#"[{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1633771139847,"tranId":"80423589583"},{"asset":"BUSD","type":"borrowIn","amount":"100","timestamp":1634638371496,"tranId":"81685123491"}]"#).unwrap();
908 let expected_response : Vec<models::GetCryptoLoansIncomeHistoryResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetCryptoLoansIncomeHistoryResponseInner>");
909
910 let resp = client.get_crypto_loans_income_history(params).await.expect("Expected a response");
911 let data_future = resp.data();
912 let actual_response = data_future.await.unwrap();
913 assert_eq!(actual_response, expected_response);
914 });
915 }
916
917 #[test]
918 fn get_crypto_loans_income_history_response_error() {
919 TOKIO_SHARED_RT.block_on(async {
920 let client = MockStableRateApiClient { force_error: true };
921
922 let params = GetCryptoLoansIncomeHistoryParams::builder()
923 .build()
924 .unwrap();
925
926 match client.get_crypto_loans_income_history(params).await {
927 Ok(_) => panic!("Expected an error"),
928 Err(err) => {
929 assert_eq!(err.to_string(), "Connector client error: ResponseError");
930 }
931 }
932 });
933 }
934
935 #[test]
936 fn get_loan_borrow_history_required_params_success() {
937 TOKIO_SHARED_RT.block_on(async {
938 let client = MockStableRateApiClient { force_error: false };
939
940 let params = GetLoanBorrowHistoryParams::builder().build().unwrap();
941
942 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();
943 let expected_response : models::GetLoanBorrowHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanBorrowHistoryResponse");
944
945 let resp = client.get_loan_borrow_history(params).await.expect("Expected a response");
946 let data_future = resp.data();
947 let actual_response = data_future.await.unwrap();
948 assert_eq!(actual_response, expected_response);
949 });
950 }
951
952 #[test]
953 fn get_loan_borrow_history_optional_params_success() {
954 TOKIO_SHARED_RT.block_on(async {
955 let client = MockStableRateApiClient { force_error: false };
956
957 let params = GetLoanBorrowHistoryParams::builder().order_id(1).loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();
958
959 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();
960 let expected_response : models::GetLoanBorrowHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanBorrowHistoryResponse");
961
962 let resp = client.get_loan_borrow_history(params).await.expect("Expected a response");
963 let data_future = resp.data();
964 let actual_response = data_future.await.unwrap();
965 assert_eq!(actual_response, expected_response);
966 });
967 }
968
969 #[test]
970 fn get_loan_borrow_history_response_error() {
971 TOKIO_SHARED_RT.block_on(async {
972 let client = MockStableRateApiClient { force_error: true };
973
974 let params = GetLoanBorrowHistoryParams::builder().build().unwrap();
975
976 match client.get_loan_borrow_history(params).await {
977 Ok(_) => panic!("Expected an error"),
978 Err(err) => {
979 assert_eq!(err.to_string(), "Connector client error: ResponseError");
980 }
981 }
982 });
983 }
984
985 #[test]
986 fn get_loan_ltv_adjustment_history_required_params_success() {
987 TOKIO_SHARED_RT.block_on(async {
988 let client = MockStableRateApiClient { force_error: false };
989
990 let params = GetLoanLtvAdjustmentHistoryParams::builder().build().unwrap();
991
992 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();
993 let expected_response : models::GetLoanLtvAdjustmentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanLtvAdjustmentHistoryResponse");
994
995 let resp = client.get_loan_ltv_adjustment_history(params).await.expect("Expected a response");
996 let data_future = resp.data();
997 let actual_response = data_future.await.unwrap();
998 assert_eq!(actual_response, expected_response);
999 });
1000 }
1001
1002 #[test]
1003 fn get_loan_ltv_adjustment_history_optional_params_success() {
1004 TOKIO_SHARED_RT.block_on(async {
1005 let client = MockStableRateApiClient { force_error: false };
1006
1007 let params = GetLoanLtvAdjustmentHistoryParams::builder().order_id(1).loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();
1008
1009 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();
1010 let expected_response : models::GetLoanLtvAdjustmentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanLtvAdjustmentHistoryResponse");
1011
1012 let resp = client.get_loan_ltv_adjustment_history(params).await.expect("Expected a response");
1013 let data_future = resp.data();
1014 let actual_response = data_future.await.unwrap();
1015 assert_eq!(actual_response, expected_response);
1016 });
1017 }
1018
1019 #[test]
1020 fn get_loan_ltv_adjustment_history_response_error() {
1021 TOKIO_SHARED_RT.block_on(async {
1022 let client = MockStableRateApiClient { force_error: true };
1023
1024 let params = GetLoanLtvAdjustmentHistoryParams::builder()
1025 .build()
1026 .unwrap();
1027
1028 match client.get_loan_ltv_adjustment_history(params).await {
1029 Ok(_) => panic!("Expected an error"),
1030 Err(err) => {
1031 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1032 }
1033 }
1034 });
1035 }
1036
1037 #[test]
1038 fn get_loan_repayment_history_required_params_success() {
1039 TOKIO_SHARED_RT.block_on(async {
1040 let client = MockStableRateApiClient { force_error: false };
1041
1042 let params = GetLoanRepaymentHistoryParams::builder().build().unwrap();
1043
1044 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();
1045 let expected_response : models::GetLoanRepaymentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanRepaymentHistoryResponse");
1046
1047 let resp = client.get_loan_repayment_history(params).await.expect("Expected a response");
1048 let data_future = resp.data();
1049 let actual_response = data_future.await.unwrap();
1050 assert_eq!(actual_response, expected_response);
1051 });
1052 }
1053
1054 #[test]
1055 fn get_loan_repayment_history_optional_params_success() {
1056 TOKIO_SHARED_RT.block_on(async {
1057 let client = MockStableRateApiClient { force_error: false };
1058
1059 let params = GetLoanRepaymentHistoryParams::builder().order_id(1).loan_coin("loan_coin_example".to_string()).collateral_coin("collateral_coin_example".to_string()).start_time(1623319461670).end_time(1641782889000).current(1).limit(10).recv_window(5000).build().unwrap();
1060
1061 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();
1062 let expected_response : models::GetLoanRepaymentHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetLoanRepaymentHistoryResponse");
1063
1064 let resp = client.get_loan_repayment_history(params).await.expect("Expected a response");
1065 let data_future = resp.data();
1066 let actual_response = data_future.await.unwrap();
1067 assert_eq!(actual_response, expected_response);
1068 });
1069 }
1070
1071 #[test]
1072 fn get_loan_repayment_history_response_error() {
1073 TOKIO_SHARED_RT.block_on(async {
1074 let client = MockStableRateApiClient { force_error: true };
1075
1076 let params = GetLoanRepaymentHistoryParams::builder().build().unwrap();
1077
1078 match client.get_loan_repayment_history(params).await {
1079 Ok(_) => panic!("Expected an error"),
1080 Err(err) => {
1081 assert_eq!(err.to_string(), "Connector client error: ResponseError");
1082 }
1083 }
1084 });
1085 }
1086}