Skip to main content

binance_sdk/mining/rest_api/apis/
api.rs

1/*
2 * Mining REST API
3 *
4 * Query mining status, earnings, and account data via the Binance Pool API.
5 *
6 * The version of the OpenAPI document: 1.0.0
7 *
8 *
9 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
10 * https://openapi-generator.tech
11 * Do not edit the class manually.
12 */
13
14#![allow(unused_imports)]
15use async_trait::async_trait;
16use derive_builder::Builder;
17use reqwest;
18use rust_decimal::prelude::*;
19use serde::{Deserialize, Serialize};
20use serde_json::{Value, json};
21use std::collections::BTreeMap;
22
23use crate::common::{
24    config::ConfigurationRestApi,
25    models::{ParamBuildError, RestApiResponse},
26    utils::send_request,
27};
28use crate::mining::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait Api: Send + Sync {
34    async fn account_list(
35        &self,
36        params: AccountListParams,
37    ) -> anyhow::Result<RestApiResponse<models::AccountListResponse>>;
38    async fn acquiring_algorithm(
39        &self,
40    ) -> anyhow::Result<RestApiResponse<models::AcquiringAlgorithmResponse>>;
41    async fn acquiring_coinname(
42        &self,
43    ) -> anyhow::Result<RestApiResponse<models::AcquiringCoinnameResponse>>;
44    async fn cancel_hashrate_resale_configuration(
45        &self,
46        params: CancelHashrateResaleConfigurationParams,
47    ) -> anyhow::Result<RestApiResponse<models::CancelHashrateResaleConfigurationResponse>>;
48    async fn earnings_list(
49        &self,
50        params: EarningsListParams,
51    ) -> anyhow::Result<RestApiResponse<models::EarningsListResponse>>;
52    async fn extra_bonus_list(
53        &self,
54        params: ExtraBonusListParams,
55    ) -> anyhow::Result<RestApiResponse<models::ExtraBonusListResponse>>;
56    async fn hashrate_resale_detail(
57        &self,
58        params: HashrateResaleDetailParams,
59    ) -> anyhow::Result<RestApiResponse<models::HashrateResaleDetailResponse>>;
60    async fn hashrate_resale_list(
61        &self,
62        params: HashrateResaleListParams,
63    ) -> anyhow::Result<RestApiResponse<models::HashrateResaleListResponse>>;
64    async fn hashrate_resale_request(
65        &self,
66        params: HashrateResaleRequestParams,
67    ) -> anyhow::Result<RestApiResponse<models::HashrateResaleRequestResponse>>;
68    async fn mining_account_earning(
69        &self,
70        params: MiningAccountEarningParams,
71    ) -> anyhow::Result<RestApiResponse<models::MiningAccountEarningResponse>>;
72    async fn request_for_detail_miner_list(
73        &self,
74        params: RequestForDetailMinerListParams,
75    ) -> anyhow::Result<RestApiResponse<models::RequestForDetailMinerListResponse>>;
76    async fn request_for_miner_list(
77        &self,
78        params: RequestForMinerListParams,
79    ) -> anyhow::Result<RestApiResponse<models::RequestForMinerListResponse>>;
80    async fn statistic_list(
81        &self,
82        params: StatisticListParams,
83    ) -> anyhow::Result<RestApiResponse<models::StatisticListResponse>>;
84}
85
86#[derive(Debug, Clone)]
87pub struct ApiClient {
88    configuration: ConfigurationRestApi,
89}
90
91impl ApiClient {
92    pub fn new(configuration: ConfigurationRestApi) -> Self {
93        Self { configuration }
94    }
95}
96
97/// Request parameters for the [`account_list`] operation.
98///
99/// This struct holds all of the inputs you can pass when calling
100/// [`account_list`](#method.account_list).
101#[derive(Clone, Debug, Builder, Deserialize)]
102#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
103pub struct AccountListParams {
104    /// Algorithm name.
105    ///
106    /// This field is **required.
107    #[builder(setter(into))]
108    #[serde(rename = "algo")]
109    pub algo: String,
110    /// Mining account
111    ///
112    /// This field is **required.
113    #[builder(setter(into))]
114    #[serde(rename = "userName")]
115    pub user_name: String,
116    /// Request validity window in milliseconds.
117    ///
118    /// This field is **optional.
119    #[builder(setter(into), default)]
120    #[serde(rename = "recvWindow", default)]
121    pub recv_window: Option<i64>,
122}
123
124impl AccountListParams {
125    /// Create a builder for [`account_list`].
126    ///
127    /// Required parameters:
128    ///
129    /// * `algo` — Algorithm name.
130    /// * `user_name` — Mining account
131    ///
132    #[must_use]
133    pub fn builder(algo: String, user_name: String) -> AccountListParamsBuilder {
134        AccountListParamsBuilder::default()
135            .algo(algo)
136            .user_name(user_name)
137    }
138}
139/// Request parameters for the [`cancel_hashrate_resale_configuration`] operation.
140///
141/// This struct holds all of the inputs you can pass when calling
142/// [`cancel_hashrate_resale_configuration`](#method.cancel_hashrate_resale_configuration).
143#[derive(Clone, Debug, Builder, Deserialize)]
144#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
145pub struct CancelHashrateResaleConfigurationParams {
146    /// Mining ID
147    ///
148    /// This field is **required.
149    #[builder(setter(into))]
150    #[serde(rename = "configId")]
151    pub config_id: i64,
152    /// Mining Account
153    ///
154    /// This field is **required.
155    #[builder(setter(into))]
156    #[serde(rename = "userName")]
157    pub user_name: String,
158    /// Request validity window in milliseconds.
159    ///
160    /// This field is **optional.
161    #[builder(setter(into), default)]
162    #[serde(rename = "recvWindow", default)]
163    pub recv_window: Option<i64>,
164}
165
166impl CancelHashrateResaleConfigurationParams {
167    /// Create a builder for [`cancel_hashrate_resale_configuration`].
168    ///
169    /// Required parameters:
170    ///
171    /// * `config_id` — Mining ID
172    /// * `user_name` — Mining Account
173    ///
174    #[must_use]
175    pub fn builder(
176        config_id: i64,
177        user_name: String,
178    ) -> CancelHashrateResaleConfigurationParamsBuilder {
179        CancelHashrateResaleConfigurationParamsBuilder::default()
180            .config_id(config_id)
181            .user_name(user_name)
182    }
183}
184/// Request parameters for the [`earnings_list`] operation.
185///
186/// This struct holds all of the inputs you can pass when calling
187/// [`earnings_list`](#method.earnings_list).
188#[derive(Clone, Debug, Builder, Deserialize)]
189#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
190pub struct EarningsListParams {
191    /// Algorithm name.
192    ///
193    /// This field is **required.
194    #[builder(setter(into))]
195    #[serde(rename = "algo")]
196    pub algo: String,
197    /// Mining account.
198    ///
199    /// This field is **required.
200    #[builder(setter(into))]
201    #[serde(rename = "userName")]
202    pub user_name: String,
203    /// Coin name
204    ///
205    /// This field is **optional.
206    #[builder(setter(into), default)]
207    #[serde(rename = "coin", default)]
208    pub coin: Option<String>,
209    /// Search start time in milliseconds.
210    ///
211    /// This field is **optional.
212    #[builder(setter(into), default)]
213    #[serde(rename = "startDate", default)]
214    pub start_date: Option<i64>,
215    /// Search end time in milliseconds.
216    ///
217    /// This field is **optional.
218    #[builder(setter(into), default)]
219    #[serde(rename = "endDate", default)]
220    pub end_date: Option<i64>,
221    /// Page number, starting from 1.
222    ///
223    /// This field is **optional.
224    #[builder(setter(into), default)]
225    #[serde(rename = "pageIndex", default)]
226    pub page_index: Option<i64>,
227    /// Number of rows per page.
228    ///
229    /// This field is **optional.
230    #[builder(setter(into), default)]
231    #[serde(rename = "pageSize", default)]
232    pub page_size: Option<i64>,
233    /// Request validity window in milliseconds.
234    ///
235    /// This field is **optional.
236    #[builder(setter(into), default)]
237    #[serde(rename = "recvWindow", default)]
238    pub recv_window: Option<i64>,
239}
240
241impl EarningsListParams {
242    /// Create a builder for [`earnings_list`].
243    ///
244    /// Required parameters:
245    ///
246    /// * `algo` — Algorithm name.
247    /// * `user_name` — Mining account.
248    ///
249    #[must_use]
250    pub fn builder(algo: String, user_name: String) -> EarningsListParamsBuilder {
251        EarningsListParamsBuilder::default()
252            .algo(algo)
253            .user_name(user_name)
254    }
255}
256/// Request parameters for the [`extra_bonus_list`] operation.
257///
258/// This struct holds all of the inputs you can pass when calling
259/// [`extra_bonus_list`](#method.extra_bonus_list).
260#[derive(Clone, Debug, Builder, Deserialize)]
261#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
262pub struct ExtraBonusListParams {
263    /// Transfer algorithm
264    ///
265    /// This field is **required.
266    #[builder(setter(into))]
267    #[serde(rename = "algo")]
268    pub algo: String,
269    /// Mining account
270    ///
271    /// This field is **required.
272    #[builder(setter(into))]
273    #[serde(rename = "userName")]
274    pub user_name: String,
275    /// Coin name
276    ///
277    /// This field is **optional.
278    #[builder(setter(into), default)]
279    #[serde(rename = "coin", default)]
280    pub coin: Option<String>,
281    /// Search start time in milliseconds.
282    ///
283    /// This field is **optional.
284    #[builder(setter(into), default)]
285    #[serde(rename = "startDate", default)]
286    pub start_date: Option<i64>,
287    /// Search end time in milliseconds.
288    ///
289    /// This field is **optional.
290    #[builder(setter(into), default)]
291    #[serde(rename = "endDate", default)]
292    pub end_date: Option<i64>,
293    /// Page number, starting from 1.
294    ///
295    /// This field is **optional.
296    #[builder(setter(into), default)]
297    #[serde(rename = "pageIndex", default)]
298    pub page_index: Option<i64>,
299    /// Number of rows per page.
300    ///
301    /// This field is **optional.
302    #[builder(setter(into), default)]
303    #[serde(rename = "pageSize", default)]
304    pub page_size: Option<i64>,
305    /// Request validity window in milliseconds.
306    ///
307    /// This field is **optional.
308    #[builder(setter(into), default)]
309    #[serde(rename = "recvWindow", default)]
310    pub recv_window: Option<i64>,
311}
312
313impl ExtraBonusListParams {
314    /// Create a builder for [`extra_bonus_list`].
315    ///
316    /// Required parameters:
317    ///
318    /// * `algo` — Transfer algorithm
319    /// * `user_name` — Mining account
320    ///
321    #[must_use]
322    pub fn builder(algo: String, user_name: String) -> ExtraBonusListParamsBuilder {
323        ExtraBonusListParamsBuilder::default()
324            .algo(algo)
325            .user_name(user_name)
326    }
327}
328/// Request parameters for the [`hashrate_resale_detail`] operation.
329///
330/// This struct holds all of the inputs you can pass when calling
331/// [`hashrate_resale_detail`](#method.hashrate_resale_detail).
332#[derive(Clone, Debug, Builder, Deserialize)]
333#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
334pub struct HashrateResaleDetailParams {
335    /// Configuration ID.
336    ///
337    /// This field is **required.
338    #[builder(setter(into))]
339    #[serde(rename = "configId")]
340    pub config_id: i64,
341    /// Page number, starting from 1.
342    ///
343    /// This field is **optional.
344    #[builder(setter(into), default)]
345    #[serde(rename = "pageIndex", default)]
346    pub page_index: Option<i64>,
347    /// Number of rows per page.
348    ///
349    /// This field is **optional.
350    #[builder(setter(into), default)]
351    #[serde(rename = "pageSize", default)]
352    pub page_size: Option<i64>,
353    /// Request validity window in milliseconds.
354    ///
355    /// This field is **optional.
356    #[builder(setter(into), default)]
357    #[serde(rename = "recvWindow", default)]
358    pub recv_window: Option<i64>,
359}
360
361impl HashrateResaleDetailParams {
362    /// Create a builder for [`hashrate_resale_detail`].
363    ///
364    /// Required parameters:
365    ///
366    /// * `config_id` — Configuration ID.
367    ///
368    #[must_use]
369    pub fn builder(config_id: i64) -> HashrateResaleDetailParamsBuilder {
370        HashrateResaleDetailParamsBuilder::default().config_id(config_id)
371    }
372}
373/// Request parameters for the [`hashrate_resale_list`] operation.
374///
375/// This struct holds all of the inputs you can pass when calling
376/// [`hashrate_resale_list`](#method.hashrate_resale_list).
377#[derive(Clone, Debug, Builder, Deserialize, Default)]
378#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
379pub struct HashrateResaleListParams {
380    /// Page number, starting from 1.
381    ///
382    /// This field is **optional.
383    #[builder(setter(into), default)]
384    #[serde(rename = "pageIndex", default)]
385    pub page_index: Option<i64>,
386    /// Number of rows per page.
387    ///
388    /// This field is **optional.
389    #[builder(setter(into), default)]
390    #[serde(rename = "pageSize", default)]
391    pub page_size: Option<i64>,
392    /// Request validity window in milliseconds.
393    ///
394    /// This field is **optional.
395    #[builder(setter(into), default)]
396    #[serde(rename = "recvWindow", default)]
397    pub recv_window: Option<i64>,
398}
399
400impl HashrateResaleListParams {
401    /// Create a builder for [`hashrate_resale_list`].
402    ///
403    #[must_use]
404    pub fn builder() -> HashrateResaleListParamsBuilder {
405        HashrateResaleListParamsBuilder::default()
406    }
407}
408/// Request parameters for the [`hashrate_resale_request`] operation.
409///
410/// This struct holds all of the inputs you can pass when calling
411/// [`hashrate_resale_request`](#method.hashrate_resale_request).
412#[derive(Clone, Debug, Builder, Deserialize)]
413#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
414pub struct HashrateResaleRequestParams {
415    /// Mining Account
416    ///
417    /// This field is **required.
418    #[builder(setter(into))]
419    #[serde(rename = "userName")]
420    pub user_name: String,
421    /// Transfer algorithm
422    ///
423    /// This field is **required.
424    #[builder(setter(into))]
425    #[serde(rename = "algo")]
426    pub algo: String,
427    /// Resale End Time (Millisecond timestamp)
428    ///
429    /// This field is **required.
430    #[builder(setter(into))]
431    #[serde(rename = "endDate")]
432    pub end_date: i64,
433    /// Resale Start Time(Millisecond timestamp)
434    ///
435    /// This field is **required.
436    #[builder(setter(into))]
437    #[serde(rename = "startDate")]
438    pub start_date: i64,
439    /// Mining Account
440    ///
441    /// This field is **required.
442    #[builder(setter(into))]
443    #[serde(rename = "toPoolUser")]
444    pub to_pool_user: String,
445    /// Resale hashrate h/s must be transferred (BTC is greater than 500000000000 ETH is greater than
446    /// 500000)
447    ///
448    /// This field is **required.
449    #[builder(setter(into))]
450    #[serde(rename = "hashRate")]
451    pub hash_rate: i64,
452    /// Request validity window in milliseconds.
453    ///
454    /// This field is **optional.
455    #[builder(setter(into), default)]
456    #[serde(rename = "recvWindow", default)]
457    pub recv_window: Option<i64>,
458}
459
460impl HashrateResaleRequestParams {
461    /// Create a builder for [`hashrate_resale_request`].
462    ///
463    /// Required parameters:
464    ///
465    /// * `user_name` — Mining Account
466    /// * `algo` — Transfer algorithm
467    /// * `end_date` — Resale End Time (Millisecond timestamp)
468    /// * `start_date` — Resale Start Time(Millisecond timestamp)
469    /// * `to_pool_user` — Mining Account
470    /// * `hash_rate` — Resale hashrate h/s must be transferred (BTC is greater than 500000000000 ETH is greater than 500000)
471    ///
472    #[must_use]
473    pub fn builder(
474        user_name: String,
475        algo: String,
476        end_date: i64,
477        start_date: i64,
478        to_pool_user: String,
479        hash_rate: i64,
480    ) -> HashrateResaleRequestParamsBuilder {
481        HashrateResaleRequestParamsBuilder::default()
482            .user_name(user_name)
483            .algo(algo)
484            .end_date(end_date)
485            .start_date(start_date)
486            .to_pool_user(to_pool_user)
487            .hash_rate(hash_rate)
488    }
489}
490/// Request parameters for the [`mining_account_earning`] operation.
491///
492/// This struct holds all of the inputs you can pass when calling
493/// [`mining_account_earning`](#method.mining_account_earning).
494#[derive(Clone, Debug, Builder, Deserialize)]
495#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
496pub struct MiningAccountEarningParams {
497    /// Algorithm
498    ///
499    /// This field is **required.
500    #[builder(setter(into))]
501    #[serde(rename = "algo")]
502    pub algo: String,
503    /// Millisecond timestamp
504    ///
505    /// This field is **optional.
506    #[builder(setter(into), default)]
507    #[serde(rename = "startDate", default)]
508    pub start_date: Option<i64>,
509    /// Millisecond timestamp
510    ///
511    /// This field is **optional.
512    #[builder(setter(into), default)]
513    #[serde(rename = "endDate", default)]
514    pub end_date: Option<i64>,
515    /// Page number, starting from 1.
516    ///
517    /// This field is **optional.
518    #[builder(setter(into), default)]
519    #[serde(rename = "pageIndex", default)]
520    pub page_index: Option<i64>,
521    /// Number of rows per page.
522    ///
523    /// This field is **optional.
524    #[builder(setter(into), default)]
525    #[serde(rename = "pageSize", default)]
526    pub page_size: Option<i64>,
527    /// Request validity window in milliseconds.
528    ///
529    /// This field is **optional.
530    #[builder(setter(into), default)]
531    #[serde(rename = "recvWindow", default)]
532    pub recv_window: Option<i64>,
533}
534
535impl MiningAccountEarningParams {
536    /// Create a builder for [`mining_account_earning`].
537    ///
538    /// Required parameters:
539    ///
540    /// * `algo` — Algorithm
541    ///
542    #[must_use]
543    pub fn builder(algo: String) -> MiningAccountEarningParamsBuilder {
544        MiningAccountEarningParamsBuilder::default().algo(algo)
545    }
546}
547/// Request parameters for the [`request_for_detail_miner_list`] operation.
548///
549/// This struct holds all of the inputs you can pass when calling
550/// [`request_for_detail_miner_list`](#method.request_for_detail_miner_list).
551#[derive(Clone, Debug, Builder, Deserialize)]
552#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
553pub struct RequestForDetailMinerListParams {
554    /// Algorithm
555    ///
556    /// This field is **required.
557    #[builder(setter(into))]
558    #[serde(rename = "algo")]
559    pub algo: String,
560    /// Mining account
561    ///
562    /// This field is **required.
563    #[builder(setter(into))]
564    #[serde(rename = "userName")]
565    pub user_name: String,
566    /// Miner name.
567    ///
568    /// This field is **required.
569    #[builder(setter(into))]
570    #[serde(rename = "workerName")]
571    pub worker_name: String,
572    /// Request validity window in milliseconds.
573    ///
574    /// This field is **optional.
575    #[builder(setter(into), default)]
576    #[serde(rename = "recvWindow", default)]
577    pub recv_window: Option<i64>,
578}
579
580impl RequestForDetailMinerListParams {
581    /// Create a builder for [`request_for_detail_miner_list`].
582    ///
583    /// Required parameters:
584    ///
585    /// * `algo` — Algorithm
586    /// * `user_name` — Mining account
587    /// * `worker_name` — Miner name.
588    ///
589    #[must_use]
590    pub fn builder(
591        algo: String,
592        user_name: String,
593        worker_name: String,
594    ) -> RequestForDetailMinerListParamsBuilder {
595        RequestForDetailMinerListParamsBuilder::default()
596            .algo(algo)
597            .user_name(user_name)
598            .worker_name(worker_name)
599    }
600}
601/// Request parameters for the [`request_for_miner_list`] operation.
602///
603/// This struct holds all of the inputs you can pass when calling
604/// [`request_for_miner_list`](#method.request_for_miner_list).
605#[derive(Clone, Debug, Builder, Deserialize)]
606#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
607pub struct RequestForMinerListParams {
608    /// Algorithm
609    ///
610    /// This field is **required.
611    #[builder(setter(into))]
612    #[serde(rename = "algo")]
613    pub algo: String,
614    /// Mining account
615    ///
616    /// This field is **required.
617    #[builder(setter(into))]
618    #[serde(rename = "userName")]
619    pub user_name: String,
620    /// Page number, starting from 1.
621    ///
622    /// This field is **optional.
623    #[builder(setter(into), default)]
624    #[serde(rename = "pageIndex", default)]
625    pub page_index: Option<i64>,
626    /// Sort order. 0 for ascending, 1 for descending.
627    ///
628    /// This field is **optional.
629    #[builder(setter(into), default)]
630    #[serde(rename = "sort", default)]
631    pub sort: Option<i64>,
632    /// Sort by: 1 miner name, 2 real-time hashrate, 3 daily average hashrate, 4 real-time rejection
633    /// rate, 5 last submission time
634    ///
635    /// This field is **optional.
636    #[builder(setter(into), default)]
637    #[serde(rename = "sortColumn", default)]
638    pub sort_column: Option<i64>,
639    /// Miner status. 0 all, 1 valid, 2 invalid, 3 failure.
640    ///
641    /// This field is **optional.
642    #[builder(setter(into), default)]
643    #[serde(rename = "workerStatus", default)]
644    pub worker_status: Option<i64>,
645    /// Request validity window in milliseconds.
646    ///
647    /// This field is **optional.
648    #[builder(setter(into), default)]
649    #[serde(rename = "recvWindow", default)]
650    pub recv_window: Option<i64>,
651}
652
653impl RequestForMinerListParams {
654    /// Create a builder for [`request_for_miner_list`].
655    ///
656    /// Required parameters:
657    ///
658    /// * `algo` — Algorithm
659    /// * `user_name` — Mining account
660    ///
661    #[must_use]
662    pub fn builder(algo: String, user_name: String) -> RequestForMinerListParamsBuilder {
663        RequestForMinerListParamsBuilder::default()
664            .algo(algo)
665            .user_name(user_name)
666    }
667}
668/// Request parameters for the [`statistic_list`] operation.
669///
670/// This struct holds all of the inputs you can pass when calling
671/// [`statistic_list`](#method.statistic_list).
672#[derive(Clone, Debug, Builder, Deserialize)]
673#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
674pub struct StatisticListParams {
675    /// Algorithm
676    ///
677    /// This field is **required.
678    #[builder(setter(into))]
679    #[serde(rename = "algo")]
680    pub algo: String,
681    /// Mining account
682    ///
683    /// This field is **required.
684    #[builder(setter(into))]
685    #[serde(rename = "userName")]
686    pub user_name: String,
687    /// Request validity window in milliseconds.
688    ///
689    /// This field is **optional.
690    #[builder(setter(into), default)]
691    #[serde(rename = "recvWindow", default)]
692    pub recv_window: Option<i64>,
693}
694
695impl StatisticListParams {
696    /// Create a builder for [`statistic_list`].
697    ///
698    /// Required parameters:
699    ///
700    /// * `algo` — Algorithm
701    /// * `user_name` — Mining account
702    ///
703    #[must_use]
704    pub fn builder(algo: String, user_name: String) -> StatisticListParamsBuilder {
705        StatisticListParamsBuilder::default()
706            .algo(algo)
707            .user_name(user_name)
708    }
709}
710
711#[async_trait]
712impl Api for ApiClient {
713    async fn account_list(
714        &self,
715        params: AccountListParams,
716    ) -> anyhow::Result<RestApiResponse<models::AccountListResponse>> {
717        let AccountListParams {
718            algo,
719            user_name,
720            recv_window,
721        } = params;
722
723        let mut query_params = BTreeMap::new();
724        let body_params = BTreeMap::new();
725
726        query_params.insert("algo".to_string(), json!(algo));
727
728        query_params.insert("userName".to_string(), json!(user_name));
729
730        if let Some(rw) = recv_window {
731            query_params.insert("recvWindow".to_string(), json!(rw));
732        }
733
734        send_request::<models::AccountListResponse>(
735            &self.configuration,
736            "/sapi/v1/mining/statistics/user/list",
737            reqwest::Method::GET,
738            query_params,
739            body_params,
740            if HAS_TIME_UNIT {
741                self.configuration.time_unit
742            } else {
743                None
744            },
745            true,
746        )
747        .await
748    }
749
750    async fn acquiring_algorithm(
751        &self,
752    ) -> anyhow::Result<RestApiResponse<models::AcquiringAlgorithmResponse>> {
753        let query_params = BTreeMap::new();
754        let body_params = BTreeMap::new();
755
756        send_request::<models::AcquiringAlgorithmResponse>(
757            &self.configuration,
758            "/sapi/v1/mining/pub/algoList",
759            reqwest::Method::GET,
760            query_params,
761            body_params,
762            if HAS_TIME_UNIT {
763                self.configuration.time_unit
764            } else {
765                None
766            },
767            false,
768        )
769        .await
770    }
771
772    async fn acquiring_coinname(
773        &self,
774    ) -> anyhow::Result<RestApiResponse<models::AcquiringCoinnameResponse>> {
775        let query_params = BTreeMap::new();
776        let body_params = BTreeMap::new();
777
778        send_request::<models::AcquiringCoinnameResponse>(
779            &self.configuration,
780            "/sapi/v1/mining/pub/coinList",
781            reqwest::Method::GET,
782            query_params,
783            body_params,
784            if HAS_TIME_UNIT {
785                self.configuration.time_unit
786            } else {
787                None
788            },
789            false,
790        )
791        .await
792    }
793
794    async fn cancel_hashrate_resale_configuration(
795        &self,
796        params: CancelHashrateResaleConfigurationParams,
797    ) -> anyhow::Result<RestApiResponse<models::CancelHashrateResaleConfigurationResponse>> {
798        let CancelHashrateResaleConfigurationParams {
799            config_id,
800            user_name,
801            recv_window,
802        } = params;
803
804        let mut query_params = BTreeMap::new();
805        let body_params = BTreeMap::new();
806
807        query_params.insert("configId".to_string(), json!(config_id));
808
809        query_params.insert("userName".to_string(), json!(user_name));
810
811        if let Some(rw) = recv_window {
812            query_params.insert("recvWindow".to_string(), json!(rw));
813        }
814
815        send_request::<models::CancelHashrateResaleConfigurationResponse>(
816            &self.configuration,
817            "/sapi/v1/mining/hash-transfer/config/cancel",
818            reqwest::Method::POST,
819            query_params,
820            body_params,
821            if HAS_TIME_UNIT {
822                self.configuration.time_unit
823            } else {
824                None
825            },
826            true,
827        )
828        .await
829    }
830
831    async fn earnings_list(
832        &self,
833        params: EarningsListParams,
834    ) -> anyhow::Result<RestApiResponse<models::EarningsListResponse>> {
835        let EarningsListParams {
836            algo,
837            user_name,
838            coin,
839            start_date,
840            end_date,
841            page_index,
842            page_size,
843            recv_window,
844        } = params;
845
846        let mut query_params = BTreeMap::new();
847        let body_params = BTreeMap::new();
848
849        query_params.insert("algo".to_string(), json!(algo));
850
851        query_params.insert("userName".to_string(), json!(user_name));
852
853        if let Some(rw) = coin {
854            query_params.insert("coin".to_string(), json!(rw));
855        }
856
857        if let Some(rw) = start_date {
858            query_params.insert("startDate".to_string(), json!(rw));
859        }
860
861        if let Some(rw) = end_date {
862            query_params.insert("endDate".to_string(), json!(rw));
863        }
864
865        if let Some(rw) = page_index {
866            query_params.insert("pageIndex".to_string(), json!(rw));
867        }
868
869        if let Some(rw) = page_size {
870            query_params.insert("pageSize".to_string(), json!(rw));
871        }
872
873        if let Some(rw) = recv_window {
874            query_params.insert("recvWindow".to_string(), json!(rw));
875        }
876
877        send_request::<models::EarningsListResponse>(
878            &self.configuration,
879            "/sapi/v1/mining/payment/list",
880            reqwest::Method::GET,
881            query_params,
882            body_params,
883            if HAS_TIME_UNIT {
884                self.configuration.time_unit
885            } else {
886                None
887            },
888            true,
889        )
890        .await
891    }
892
893    async fn extra_bonus_list(
894        &self,
895        params: ExtraBonusListParams,
896    ) -> anyhow::Result<RestApiResponse<models::ExtraBonusListResponse>> {
897        let ExtraBonusListParams {
898            algo,
899            user_name,
900            coin,
901            start_date,
902            end_date,
903            page_index,
904            page_size,
905            recv_window,
906        } = params;
907
908        let mut query_params = BTreeMap::new();
909        let body_params = BTreeMap::new();
910
911        query_params.insert("algo".to_string(), json!(algo));
912
913        query_params.insert("userName".to_string(), json!(user_name));
914
915        if let Some(rw) = coin {
916            query_params.insert("coin".to_string(), json!(rw));
917        }
918
919        if let Some(rw) = start_date {
920            query_params.insert("startDate".to_string(), json!(rw));
921        }
922
923        if let Some(rw) = end_date {
924            query_params.insert("endDate".to_string(), json!(rw));
925        }
926
927        if let Some(rw) = page_index {
928            query_params.insert("pageIndex".to_string(), json!(rw));
929        }
930
931        if let Some(rw) = page_size {
932            query_params.insert("pageSize".to_string(), json!(rw));
933        }
934
935        if let Some(rw) = recv_window {
936            query_params.insert("recvWindow".to_string(), json!(rw));
937        }
938
939        send_request::<models::ExtraBonusListResponse>(
940            &self.configuration,
941            "/sapi/v1/mining/payment/other",
942            reqwest::Method::GET,
943            query_params,
944            body_params,
945            if HAS_TIME_UNIT {
946                self.configuration.time_unit
947            } else {
948                None
949            },
950            true,
951        )
952        .await
953    }
954
955    async fn hashrate_resale_detail(
956        &self,
957        params: HashrateResaleDetailParams,
958    ) -> anyhow::Result<RestApiResponse<models::HashrateResaleDetailResponse>> {
959        let HashrateResaleDetailParams {
960            config_id,
961            page_index,
962            page_size,
963            recv_window,
964        } = params;
965
966        let mut query_params = BTreeMap::new();
967        let body_params = BTreeMap::new();
968
969        query_params.insert("configId".to_string(), json!(config_id));
970
971        if let Some(rw) = page_index {
972            query_params.insert("pageIndex".to_string(), json!(rw));
973        }
974
975        if let Some(rw) = page_size {
976            query_params.insert("pageSize".to_string(), json!(rw));
977        }
978
979        if let Some(rw) = recv_window {
980            query_params.insert("recvWindow".to_string(), json!(rw));
981        }
982
983        send_request::<models::HashrateResaleDetailResponse>(
984            &self.configuration,
985            "/sapi/v1/mining/hash-transfer/profit/details",
986            reqwest::Method::GET,
987            query_params,
988            body_params,
989            if HAS_TIME_UNIT {
990                self.configuration.time_unit
991            } else {
992                None
993            },
994            true,
995        )
996        .await
997    }
998
999    async fn hashrate_resale_list(
1000        &self,
1001        params: HashrateResaleListParams,
1002    ) -> anyhow::Result<RestApiResponse<models::HashrateResaleListResponse>> {
1003        let HashrateResaleListParams {
1004            page_index,
1005            page_size,
1006            recv_window,
1007        } = params;
1008
1009        let mut query_params = BTreeMap::new();
1010        let body_params = BTreeMap::new();
1011
1012        if let Some(rw) = page_index {
1013            query_params.insert("pageIndex".to_string(), json!(rw));
1014        }
1015
1016        if let Some(rw) = page_size {
1017            query_params.insert("pageSize".to_string(), json!(rw));
1018        }
1019
1020        if let Some(rw) = recv_window {
1021            query_params.insert("recvWindow".to_string(), json!(rw));
1022        }
1023
1024        send_request::<models::HashrateResaleListResponse>(
1025            &self.configuration,
1026            "/sapi/v1/mining/hash-transfer/config/details/list",
1027            reqwest::Method::GET,
1028            query_params,
1029            body_params,
1030            if HAS_TIME_UNIT {
1031                self.configuration.time_unit
1032            } else {
1033                None
1034            },
1035            true,
1036        )
1037        .await
1038    }
1039
1040    async fn hashrate_resale_request(
1041        &self,
1042        params: HashrateResaleRequestParams,
1043    ) -> anyhow::Result<RestApiResponse<models::HashrateResaleRequestResponse>> {
1044        let HashrateResaleRequestParams {
1045            user_name,
1046            algo,
1047            end_date,
1048            start_date,
1049            to_pool_user,
1050            hash_rate,
1051            recv_window,
1052        } = params;
1053
1054        let mut query_params = BTreeMap::new();
1055        let body_params = BTreeMap::new();
1056
1057        query_params.insert("userName".to_string(), json!(user_name));
1058
1059        query_params.insert("algo".to_string(), json!(algo));
1060
1061        query_params.insert("endDate".to_string(), json!(end_date));
1062
1063        query_params.insert("startDate".to_string(), json!(start_date));
1064
1065        query_params.insert("toPoolUser".to_string(), json!(to_pool_user));
1066
1067        query_params.insert("hashRate".to_string(), json!(hash_rate));
1068
1069        if let Some(rw) = recv_window {
1070            query_params.insert("recvWindow".to_string(), json!(rw));
1071        }
1072
1073        send_request::<models::HashrateResaleRequestResponse>(
1074            &self.configuration,
1075            "/sapi/v1/mining/hash-transfer/config",
1076            reqwest::Method::POST,
1077            query_params,
1078            body_params,
1079            if HAS_TIME_UNIT {
1080                self.configuration.time_unit
1081            } else {
1082                None
1083            },
1084            true,
1085        )
1086        .await
1087    }
1088
1089    async fn mining_account_earning(
1090        &self,
1091        params: MiningAccountEarningParams,
1092    ) -> anyhow::Result<RestApiResponse<models::MiningAccountEarningResponse>> {
1093        let MiningAccountEarningParams {
1094            algo,
1095            start_date,
1096            end_date,
1097            page_index,
1098            page_size,
1099            recv_window,
1100        } = params;
1101
1102        let mut query_params = BTreeMap::new();
1103        let body_params = BTreeMap::new();
1104
1105        query_params.insert("algo".to_string(), json!(algo));
1106
1107        if let Some(rw) = start_date {
1108            query_params.insert("startDate".to_string(), json!(rw));
1109        }
1110
1111        if let Some(rw) = end_date {
1112            query_params.insert("endDate".to_string(), json!(rw));
1113        }
1114
1115        if let Some(rw) = page_index {
1116            query_params.insert("pageIndex".to_string(), json!(rw));
1117        }
1118
1119        if let Some(rw) = page_size {
1120            query_params.insert("pageSize".to_string(), json!(rw));
1121        }
1122
1123        if let Some(rw) = recv_window {
1124            query_params.insert("recvWindow".to_string(), json!(rw));
1125        }
1126
1127        send_request::<models::MiningAccountEarningResponse>(
1128            &self.configuration,
1129            "/sapi/v1/mining/payment/uid",
1130            reqwest::Method::GET,
1131            query_params,
1132            body_params,
1133            if HAS_TIME_UNIT {
1134                self.configuration.time_unit
1135            } else {
1136                None
1137            },
1138            true,
1139        )
1140        .await
1141    }
1142
1143    async fn request_for_detail_miner_list(
1144        &self,
1145        params: RequestForDetailMinerListParams,
1146    ) -> anyhow::Result<RestApiResponse<models::RequestForDetailMinerListResponse>> {
1147        let RequestForDetailMinerListParams {
1148            algo,
1149            user_name,
1150            worker_name,
1151            recv_window,
1152        } = params;
1153
1154        let mut query_params = BTreeMap::new();
1155        let body_params = BTreeMap::new();
1156
1157        query_params.insert("algo".to_string(), json!(algo));
1158
1159        query_params.insert("userName".to_string(), json!(user_name));
1160
1161        query_params.insert("workerName".to_string(), json!(worker_name));
1162
1163        if let Some(rw) = recv_window {
1164            query_params.insert("recvWindow".to_string(), json!(rw));
1165        }
1166
1167        send_request::<models::RequestForDetailMinerListResponse>(
1168            &self.configuration,
1169            "/sapi/v1/mining/worker/detail",
1170            reqwest::Method::GET,
1171            query_params,
1172            body_params,
1173            if HAS_TIME_UNIT {
1174                self.configuration.time_unit
1175            } else {
1176                None
1177            },
1178            true,
1179        )
1180        .await
1181    }
1182
1183    async fn request_for_miner_list(
1184        &self,
1185        params: RequestForMinerListParams,
1186    ) -> anyhow::Result<RestApiResponse<models::RequestForMinerListResponse>> {
1187        let RequestForMinerListParams {
1188            algo,
1189            user_name,
1190            page_index,
1191            sort,
1192            sort_column,
1193            worker_status,
1194            recv_window,
1195        } = params;
1196
1197        let mut query_params = BTreeMap::new();
1198        let body_params = BTreeMap::new();
1199
1200        query_params.insert("algo".to_string(), json!(algo));
1201
1202        query_params.insert("userName".to_string(), json!(user_name));
1203
1204        if let Some(rw) = page_index {
1205            query_params.insert("pageIndex".to_string(), json!(rw));
1206        }
1207
1208        if let Some(rw) = sort {
1209            query_params.insert("sort".to_string(), json!(rw));
1210        }
1211
1212        if let Some(rw) = sort_column {
1213            query_params.insert("sortColumn".to_string(), json!(rw));
1214        }
1215
1216        if let Some(rw) = worker_status {
1217            query_params.insert("workerStatus".to_string(), json!(rw));
1218        }
1219
1220        if let Some(rw) = recv_window {
1221            query_params.insert("recvWindow".to_string(), json!(rw));
1222        }
1223
1224        send_request::<models::RequestForMinerListResponse>(
1225            &self.configuration,
1226            "/sapi/v1/mining/worker/list",
1227            reqwest::Method::GET,
1228            query_params,
1229            body_params,
1230            if HAS_TIME_UNIT {
1231                self.configuration.time_unit
1232            } else {
1233                None
1234            },
1235            true,
1236        )
1237        .await
1238    }
1239
1240    async fn statistic_list(
1241        &self,
1242        params: StatisticListParams,
1243    ) -> anyhow::Result<RestApiResponse<models::StatisticListResponse>> {
1244        let StatisticListParams {
1245            algo,
1246            user_name,
1247            recv_window,
1248        } = params;
1249
1250        let mut query_params = BTreeMap::new();
1251        let body_params = BTreeMap::new();
1252
1253        query_params.insert("algo".to_string(), json!(algo));
1254
1255        query_params.insert("userName".to_string(), json!(user_name));
1256
1257        if let Some(rw) = recv_window {
1258            query_params.insert("recvWindow".to_string(), json!(rw));
1259        }
1260
1261        send_request::<models::StatisticListResponse>(
1262            &self.configuration,
1263            "/sapi/v1/mining/statistics/user/status",
1264            reqwest::Method::GET,
1265            query_params,
1266            body_params,
1267            if HAS_TIME_UNIT {
1268                self.configuration.time_unit
1269            } else {
1270                None
1271            },
1272            true,
1273        )
1274        .await
1275    }
1276}
1277
1278#[cfg(all(test, feature = "mining"))]
1279mod tests {
1280    use super::*;
1281    use crate::TOKIO_SHARED_RT;
1282    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
1283    use async_trait::async_trait;
1284    use std::collections::HashMap;
1285
1286    struct DummyRestApiResponse<T> {
1287        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
1288        status: u16,
1289        headers: HashMap<String, String>,
1290        rate_limits: Option<Vec<RestApiRateLimit>>,
1291    }
1292
1293    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
1294        fn from(dummy: DummyRestApiResponse<T>) -> Self {
1295            Self {
1296                data_fn: dummy.inner,
1297                status: dummy.status,
1298                headers: dummy.headers,
1299                rate_limits: dummy.rate_limits,
1300            }
1301        }
1302    }
1303
1304    struct MockApiClient {
1305        force_error: bool,
1306    }
1307
1308    #[async_trait]
1309    impl Api for MockApiClient {
1310        async fn account_list(
1311            &self,
1312            _params: AccountListParams,
1313        ) -> anyhow::Result<RestApiResponse<models::AccountListResponse>> {
1314            if self.force_error {
1315                return Err(ConnectorError::ConnectorClientError {
1316                    msg: "ResponseError".to_string(),
1317                    code: None,
1318                }
1319                .into());
1320            }
1321
1322            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"type":"H_hashrate","userName":"test","list":[{"time":1585267200000,"hashrate":"0.00000000","reject":"0.00000000"}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1323            let dummy_response: models::AccountListResponse =
1324                serde_json::from_value(resp_json.clone())
1325                    .expect("should parse into models::AccountListResponse");
1326
1327            let dummy = DummyRestApiResponse {
1328                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1329                status: 200,
1330                headers: HashMap::new(),
1331                rate_limits: None,
1332            };
1333
1334            Ok(dummy.into())
1335        }
1336
1337        async fn acquiring_algorithm(
1338            &self,
1339        ) -> anyhow::Result<RestApiResponse<models::AcquiringAlgorithmResponse>> {
1340            if self.force_error {
1341                return Err(ConnectorError::ConnectorClientError {
1342                    msg: "ResponseError".to_string(),
1343                    code: None,
1344                }
1345                .into());
1346            }
1347
1348            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"algoName":"SHA256-BTC","algoId":1,"poolIndex":100,"unit":"h/s"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1349            let dummy_response: models::AcquiringAlgorithmResponse =
1350                serde_json::from_value(resp_json.clone())
1351                    .expect("should parse into models::AcquiringAlgorithmResponse");
1352
1353            let dummy = DummyRestApiResponse {
1354                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1355                status: 200,
1356                headers: HashMap::new(),
1357                rate_limits: None,
1358            };
1359
1360            Ok(dummy.into())
1361        }
1362
1363        async fn acquiring_coinname(
1364            &self,
1365        ) -> anyhow::Result<RestApiResponse<models::AcquiringCoinnameResponse>> {
1366            if self.force_error {
1367                return Err(ConnectorError::ConnectorClientError {
1368                    msg: "ResponseError".to_string(),
1369                    code: None,
1370                }
1371                .into());
1372            }
1373
1374            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"coinName":"BTC","coinId":1,"poolIndex":0,"algoId":1,"algoName":"SHA256-BTC"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1375            let dummy_response: models::AcquiringCoinnameResponse =
1376                serde_json::from_value(resp_json.clone())
1377                    .expect("should parse into models::AcquiringCoinnameResponse");
1378
1379            let dummy = DummyRestApiResponse {
1380                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1381                status: 200,
1382                headers: HashMap::new(),
1383                rate_limits: None,
1384            };
1385
1386            Ok(dummy.into())
1387        }
1388
1389        async fn cancel_hashrate_resale_configuration(
1390            &self,
1391            _params: CancelHashrateResaleConfigurationParams,
1392        ) -> anyhow::Result<RestApiResponse<models::CancelHashrateResaleConfigurationResponse>>
1393        {
1394            if self.force_error {
1395                return Err(ConnectorError::ConnectorClientError {
1396                    msg: "ResponseError".to_string(),
1397                    code: None,
1398                }
1399                .into());
1400            }
1401
1402            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":true}"#)
1403                .unwrap_or_else(|_| serde_json::json!({}));
1404            let dummy_response: models::CancelHashrateResaleConfigurationResponse =
1405                serde_json::from_value(resp_json.clone())
1406                    .expect("should parse into models::CancelHashrateResaleConfigurationResponse");
1407
1408            let dummy = DummyRestApiResponse {
1409                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1410                status: 200,
1411                headers: HashMap::new(),
1412                rate_limits: None,
1413            };
1414
1415            Ok(dummy.into())
1416        }
1417
1418        async fn earnings_list(
1419            &self,
1420            _params: EarningsListParams,
1421        ) -> anyhow::Result<RestApiResponse<models::EarningsListResponse>> {
1422            if self.force_error {
1423                return Err(ConnectorError::ConnectorClientError {
1424                    msg: "ResponseError".to_string(),
1425                    code: None,
1426                }
1427                .into());
1428            }
1429
1430            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"accountProfits":[{"time":1586188800000,"type":31,"hashTransfer":200000000000,"transferAmount":0.02180958,"dayHashRate":129129903378244,"profitAmount":8.6083060304,"coinName":"BTC","status":2}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1431            let dummy_response: models::EarningsListResponse =
1432                serde_json::from_value(resp_json.clone())
1433                    .expect("should parse into models::EarningsListResponse");
1434
1435            let dummy = DummyRestApiResponse {
1436                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1437                status: 200,
1438                headers: HashMap::new(),
1439                rate_limits: None,
1440            };
1441
1442            Ok(dummy.into())
1443        }
1444
1445        async fn extra_bonus_list(
1446            &self,
1447            _params: ExtraBonusListParams,
1448        ) -> anyhow::Result<RestApiResponse<models::ExtraBonusListResponse>> {
1449            if self.force_error {
1450                return Err(ConnectorError::ConnectorClientError {
1451                    msg: "ResponseError".to_string(),
1452                    code: None,
1453                }
1454                .into());
1455            }
1456
1457            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"otherProfits":[{"time":1607443200000,"coinName":"BTC","type":4,"profitAmount":0.0011859,"status":2}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1458            let dummy_response: models::ExtraBonusListResponse =
1459                serde_json::from_value(resp_json.clone())
1460                    .expect("should parse into models::ExtraBonusListResponse");
1461
1462            let dummy = DummyRestApiResponse {
1463                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1464                status: 200,
1465                headers: HashMap::new(),
1466                rate_limits: None,
1467            };
1468
1469            Ok(dummy.into())
1470        }
1471
1472        async fn hashrate_resale_detail(
1473            &self,
1474            _params: HashrateResaleDetailParams,
1475        ) -> anyhow::Result<RestApiResponse<models::HashrateResaleDetailResponse>> {
1476            if self.force_error {
1477                return Err(ConnectorError::ConnectorClientError {
1478                    msg: "ResponseError".to_string(),
1479                    code: None,
1480                }
1481                .into());
1482            }
1483
1484            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"profitTransferDetails":[{"poolUsername":"test4001","toPoolUsername":"pop","algoName":"sha256","hashRate":200000000000,"day":20201213,"amount":0.2256872,"coinName":"BTC"}],"totalNum":8,"pageSize":200}}"#).unwrap_or_else(|_| serde_json::json!({}));
1485            let dummy_response: models::HashrateResaleDetailResponse =
1486                serde_json::from_value(resp_json.clone())
1487                    .expect("should parse into models::HashrateResaleDetailResponse");
1488
1489            let dummy = DummyRestApiResponse {
1490                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1491                status: 200,
1492                headers: HashMap::new(),
1493                rate_limits: None,
1494            };
1495
1496            Ok(dummy.into())
1497        }
1498
1499        async fn hashrate_resale_list(
1500            &self,
1501            _params: HashrateResaleListParams,
1502        ) -> anyhow::Result<RestApiResponse<models::HashrateResaleListResponse>> {
1503            if self.force_error {
1504                return Err(ConnectorError::ConnectorClientError {
1505                    msg: "ResponseError".to_string(),
1506                    code: None,
1507                }
1508                .into());
1509            }
1510
1511            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"configDetails":[{"configId":168,"poolUsername":"123","toPoolUsername":"user1","algoName":"Ethash","hashRate":5000000,"startDay":20201210,"endDay":20210405,"status":1,"type":0}],"totalNum":21,"pageSize":200}}"#).unwrap_or_else(|_| serde_json::json!({}));
1512            let dummy_response: models::HashrateResaleListResponse =
1513                serde_json::from_value(resp_json.clone())
1514                    .expect("should parse into models::HashrateResaleListResponse");
1515
1516            let dummy = DummyRestApiResponse {
1517                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1518                status: 200,
1519                headers: HashMap::new(),
1520                rate_limits: None,
1521            };
1522
1523            Ok(dummy.into())
1524        }
1525
1526        async fn hashrate_resale_request(
1527            &self,
1528            _params: HashrateResaleRequestParams,
1529        ) -> anyhow::Result<RestApiResponse<models::HashrateResaleRequestResponse>> {
1530            if self.force_error {
1531                return Err(ConnectorError::ConnectorClientError {
1532                    msg: "ResponseError".to_string(),
1533                    code: None,
1534                }
1535                .into());
1536            }
1537
1538            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":171}"#)
1539                .unwrap_or_else(|_| serde_json::json!({}));
1540            let dummy_response: models::HashrateResaleRequestResponse =
1541                serde_json::from_value(resp_json.clone())
1542                    .expect("should parse into models::HashrateResaleRequestResponse");
1543
1544            let dummy = DummyRestApiResponse {
1545                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1546                status: 200,
1547                headers: HashMap::new(),
1548                rate_limits: None,
1549            };
1550
1551            Ok(dummy.into())
1552        }
1553
1554        async fn mining_account_earning(
1555            &self,
1556            _params: MiningAccountEarningParams,
1557        ) -> anyhow::Result<RestApiResponse<models::MiningAccountEarningResponse>> {
1558            if self.force_error {
1559                return Err(ConnectorError::ConnectorClientError {
1560                    msg: "ResponseError".to_string(),
1561                    code: None,
1562                }
1563                .into());
1564            }
1565
1566            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"accountProfits":[{"time":1607443200000,"coinName":"BTC","type":2,"puid":59985472,"subName":"vdvaghani","amount":0.09186957}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1567            let dummy_response: models::MiningAccountEarningResponse =
1568                serde_json::from_value(resp_json.clone())
1569                    .expect("should parse into models::MiningAccountEarningResponse");
1570
1571            let dummy = DummyRestApiResponse {
1572                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1573                status: 200,
1574                headers: HashMap::new(),
1575                rate_limits: None,
1576            };
1577
1578            Ok(dummy.into())
1579        }
1580
1581        async fn request_for_detail_miner_list(
1582            &self,
1583            _params: RequestForDetailMinerListParams,
1584        ) -> anyhow::Result<RestApiResponse<models::RequestForDetailMinerListResponse>> {
1585            if self.force_error {
1586                return Err(ConnectorError::ConnectorClientError {
1587                    msg: "ResponseError".to_string(),
1588                    code: None,
1589                }
1590                .into());
1591            }
1592
1593            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"workerName":"bhdc1.16A10404B","type":"H_hashrate","hashrateDatas":[{"time":1587902400000,"hashrate":"0","reject":0}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1594            let dummy_response: models::RequestForDetailMinerListResponse =
1595                serde_json::from_value(resp_json.clone())
1596                    .expect("should parse into models::RequestForDetailMinerListResponse");
1597
1598            let dummy = DummyRestApiResponse {
1599                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1600                status: 200,
1601                headers: HashMap::new(),
1602                rate_limits: None,
1603            };
1604
1605            Ok(dummy.into())
1606        }
1607
1608        async fn request_for_miner_list(
1609            &self,
1610            _params: RequestForMinerListParams,
1611        ) -> anyhow::Result<RestApiResponse<models::RequestForMinerListResponse>> {
1612            if self.force_error {
1613                return Err(ConnectorError::ConnectorClientError {
1614                    msg: "ResponseError".to_string(),
1615                    code: None,
1616                }
1617                .into());
1618            }
1619
1620            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"workerDatas":[{"workerId":"1420554439452400131","workerName":"2X73","status":3,"hashRate":0,"dayHashRate":1.269778129801366E13,"rejectRate":0,"lastShareTime":1587712919000}],"totalNum":18530,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1621            let dummy_response: models::RequestForMinerListResponse =
1622                serde_json::from_value(resp_json.clone())
1623                    .expect("should parse into models::RequestForMinerListResponse");
1624
1625            let dummy = DummyRestApiResponse {
1626                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1627                status: 200,
1628                headers: HashMap::new(),
1629                rate_limits: None,
1630            };
1631
1632            Ok(dummy.into())
1633        }
1634
1635        async fn statistic_list(
1636            &self,
1637            _params: StatisticListParams,
1638        ) -> anyhow::Result<RestApiResponse<models::StatisticListResponse>> {
1639            if self.force_error {
1640                return Err(ConnectorError::ConnectorClientError {
1641                    msg: "ResponseError".to_string(),
1642                    code: None,
1643                }
1644                .into());
1645            }
1646
1647            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"fifteenMinHashRate":"457835490067496409.00000000","dayHashRate":"214289268068874127.65000000","validNum":0,"invalidNum":17562,"profitToday":{"BTC":"0.00314332","BSV":"56.17055953","BCH":"106.61586001"},"profitYesterday":{"BTC":"0.00314332","BSV":"56.17055953","BCH":"106.61586001"},"userName":"test","unit":"h/s","algo":"sha256"}}"#).unwrap_or_else(|_| serde_json::json!({}));
1648            let dummy_response: models::StatisticListResponse =
1649                serde_json::from_value(resp_json.clone())
1650                    .expect("should parse into models::StatisticListResponse");
1651
1652            let dummy = DummyRestApiResponse {
1653                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
1654                status: 200,
1655                headers: HashMap::new(),
1656                rate_limits: None,
1657            };
1658
1659            Ok(dummy.into())
1660        }
1661    }
1662
1663    #[test]
1664    fn account_list_required_params_success() {
1665        TOKIO_SHARED_RT.block_on(async {
1666            let client = MockApiClient { force_error: false };
1667
1668            let params = AccountListParams::builder("sha256".to_string(),"test".to_string(),).build().unwrap();
1669
1670            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"type":"H_hashrate","userName":"test","list":[{"time":1585267200000,"hashrate":"0.00000000","reject":"0.00000000"}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1671            let expected_response : models::AccountListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountListResponse");
1672
1673            let resp = client.account_list(params).await.expect("Expected a response");
1674            let data_future = resp.data();
1675            let actual_response = data_future.await.unwrap();
1676            assert_eq!(actual_response, expected_response);
1677        });
1678    }
1679
1680    #[test]
1681    fn account_list_optional_params_success() {
1682        TOKIO_SHARED_RT.block_on(async {
1683            let client = MockApiClient { force_error: false };
1684
1685            let params = AccountListParams::builder("sha256".to_string(),"test".to_string(),).recv_window(5000).build().unwrap();
1686
1687            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"type":"H_hashrate","userName":"test","list":[{"time":1585267200000,"hashrate":"0.00000000","reject":"0.00000000"}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1688            let expected_response : models::AccountListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountListResponse");
1689
1690            let resp = client.account_list(params).await.expect("Expected a response");
1691            let data_future = resp.data();
1692            let actual_response = data_future.await.unwrap();
1693            assert_eq!(actual_response, expected_response);
1694        });
1695    }
1696
1697    #[test]
1698    fn account_list_response_error() {
1699        TOKIO_SHARED_RT.block_on(async {
1700            let client = MockApiClient { force_error: true };
1701
1702            let params = AccountListParams::builder("sha256".to_string(), "test".to_string())
1703                .build()
1704                .unwrap();
1705
1706            match client.account_list(params).await {
1707                Ok(_) => panic!("Expected an error"),
1708                Err(err) => {
1709                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1710                }
1711            }
1712        });
1713    }
1714
1715    #[test]
1716    fn acquiring_algorithm_required_params_success() {
1717        TOKIO_SHARED_RT.block_on(async {
1718            let client = MockApiClient { force_error: false };
1719
1720
1721            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"algoName":"SHA256-BTC","algoId":1,"poolIndex":100,"unit":"h/s"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1722            let expected_response : models::AcquiringAlgorithmResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AcquiringAlgorithmResponse");
1723
1724            let resp = client.acquiring_algorithm().await.expect("Expected a response");
1725            let data_future = resp.data();
1726            let actual_response = data_future.await.unwrap();
1727            assert_eq!(actual_response, expected_response);
1728        });
1729    }
1730
1731    #[test]
1732    fn acquiring_algorithm_optional_params_success() {
1733        TOKIO_SHARED_RT.block_on(async {
1734            let client = MockApiClient { force_error: false };
1735
1736
1737            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"algoName":"SHA256-BTC","algoId":1,"poolIndex":100,"unit":"h/s"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1738            let expected_response : models::AcquiringAlgorithmResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AcquiringAlgorithmResponse");
1739
1740            let resp = client.acquiring_algorithm().await.expect("Expected a response");
1741            let data_future = resp.data();
1742            let actual_response = data_future.await.unwrap();
1743            assert_eq!(actual_response, expected_response);
1744        });
1745    }
1746
1747    #[test]
1748    fn acquiring_algorithm_response_error() {
1749        TOKIO_SHARED_RT.block_on(async {
1750            let client = MockApiClient { force_error: true };
1751
1752            match client.acquiring_algorithm().await {
1753                Ok(_) => panic!("Expected an error"),
1754                Err(err) => {
1755                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1756                }
1757            }
1758        });
1759    }
1760
1761    #[test]
1762    fn acquiring_coinname_required_params_success() {
1763        TOKIO_SHARED_RT.block_on(async {
1764            let client = MockApiClient { force_error: false };
1765
1766
1767            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"coinName":"BTC","coinId":1,"poolIndex":0,"algoId":1,"algoName":"SHA256-BTC"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1768            let expected_response : models::AcquiringCoinnameResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AcquiringCoinnameResponse");
1769
1770            let resp = client.acquiring_coinname().await.expect("Expected a response");
1771            let data_future = resp.data();
1772            let actual_response = data_future.await.unwrap();
1773            assert_eq!(actual_response, expected_response);
1774        });
1775    }
1776
1777    #[test]
1778    fn acquiring_coinname_optional_params_success() {
1779        TOKIO_SHARED_RT.block_on(async {
1780            let client = MockApiClient { force_error: false };
1781
1782
1783            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"coinName":"BTC","coinId":1,"poolIndex":0,"algoId":1,"algoName":"SHA256-BTC"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
1784            let expected_response : models::AcquiringCoinnameResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AcquiringCoinnameResponse");
1785
1786            let resp = client.acquiring_coinname().await.expect("Expected a response");
1787            let data_future = resp.data();
1788            let actual_response = data_future.await.unwrap();
1789            assert_eq!(actual_response, expected_response);
1790        });
1791    }
1792
1793    #[test]
1794    fn acquiring_coinname_response_error() {
1795        TOKIO_SHARED_RT.block_on(async {
1796            let client = MockApiClient { force_error: true };
1797
1798            match client.acquiring_coinname().await {
1799                Ok(_) => panic!("Expected an error"),
1800                Err(err) => {
1801                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1802                }
1803            }
1804        });
1805    }
1806
1807    #[test]
1808    fn cancel_hashrate_resale_configuration_required_params_success() {
1809        TOKIO_SHARED_RT.block_on(async {
1810            let client = MockApiClient { force_error: false };
1811
1812            let params = CancelHashrateResaleConfigurationParams::builder(168, "test".to_string())
1813                .build()
1814                .unwrap();
1815
1816            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":true}"#)
1817                .unwrap_or_else(|_| serde_json::json!({}));
1818            let expected_response: models::CancelHashrateResaleConfigurationResponse =
1819                serde_json::from_value(resp_json.clone())
1820                    .expect("should parse into models::CancelHashrateResaleConfigurationResponse");
1821
1822            let resp = client
1823                .cancel_hashrate_resale_configuration(params)
1824                .await
1825                .expect("Expected a response");
1826            let data_future = resp.data();
1827            let actual_response = data_future.await.unwrap();
1828            assert_eq!(actual_response, expected_response);
1829        });
1830    }
1831
1832    #[test]
1833    fn cancel_hashrate_resale_configuration_optional_params_success() {
1834        TOKIO_SHARED_RT.block_on(async {
1835            let client = MockApiClient { force_error: false };
1836
1837            let params = CancelHashrateResaleConfigurationParams::builder(168, "test".to_string())
1838                .recv_window(5000)
1839                .build()
1840                .unwrap();
1841
1842            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":true}"#)
1843                .unwrap_or_else(|_| serde_json::json!({}));
1844            let expected_response: models::CancelHashrateResaleConfigurationResponse =
1845                serde_json::from_value(resp_json.clone())
1846                    .expect("should parse into models::CancelHashrateResaleConfigurationResponse");
1847
1848            let resp = client
1849                .cancel_hashrate_resale_configuration(params)
1850                .await
1851                .expect("Expected a response");
1852            let data_future = resp.data();
1853            let actual_response = data_future.await.unwrap();
1854            assert_eq!(actual_response, expected_response);
1855        });
1856    }
1857
1858    #[test]
1859    fn cancel_hashrate_resale_configuration_response_error() {
1860        TOKIO_SHARED_RT.block_on(async {
1861            let client = MockApiClient { force_error: true };
1862
1863            let params = CancelHashrateResaleConfigurationParams::builder(168, "test".to_string())
1864                .build()
1865                .unwrap();
1866
1867            match client.cancel_hashrate_resale_configuration(params).await {
1868                Ok(_) => panic!("Expected an error"),
1869                Err(err) => {
1870                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1871                }
1872            }
1873        });
1874    }
1875
1876    #[test]
1877    fn earnings_list_required_params_success() {
1878        TOKIO_SHARED_RT.block_on(async {
1879            let client = MockApiClient { force_error: false };
1880
1881            let params = EarningsListParams::builder("sha256".to_string(),"test".to_string(),).build().unwrap();
1882
1883            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"accountProfits":[{"time":1586188800000,"type":31,"hashTransfer":200000000000,"transferAmount":0.02180958,"dayHashRate":129129903378244,"profitAmount":8.6083060304,"coinName":"BTC","status":2}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1884            let expected_response : models::EarningsListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::EarningsListResponse");
1885
1886            let resp = client.earnings_list(params).await.expect("Expected a response");
1887            let data_future = resp.data();
1888            let actual_response = data_future.await.unwrap();
1889            assert_eq!(actual_response, expected_response);
1890        });
1891    }
1892
1893    #[test]
1894    fn earnings_list_optional_params_success() {
1895        TOKIO_SHARED_RT.block_on(async {
1896            let client = MockApiClient { force_error: false };
1897
1898            let params = EarningsListParams::builder("sha256".to_string(),"test".to_string(),).coin("BTC".to_string()).start_date(1770736694138).end_date(1770736694138).page_index(1).page_size(10).recv_window(5000).build().unwrap();
1899
1900            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"accountProfits":[{"time":1586188800000,"type":31,"hashTransfer":200000000000,"transferAmount":0.02180958,"dayHashRate":129129903378244,"profitAmount":8.6083060304,"coinName":"BTC","status":2}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1901            let expected_response : models::EarningsListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::EarningsListResponse");
1902
1903            let resp = client.earnings_list(params).await.expect("Expected a response");
1904            let data_future = resp.data();
1905            let actual_response = data_future.await.unwrap();
1906            assert_eq!(actual_response, expected_response);
1907        });
1908    }
1909
1910    #[test]
1911    fn earnings_list_response_error() {
1912        TOKIO_SHARED_RT.block_on(async {
1913            let client = MockApiClient { force_error: true };
1914
1915            let params = EarningsListParams::builder("sha256".to_string(), "test".to_string())
1916                .build()
1917                .unwrap();
1918
1919            match client.earnings_list(params).await {
1920                Ok(_) => panic!("Expected an error"),
1921                Err(err) => {
1922                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1923                }
1924            }
1925        });
1926    }
1927
1928    #[test]
1929    fn extra_bonus_list_required_params_success() {
1930        TOKIO_SHARED_RT.block_on(async {
1931            let client = MockApiClient { force_error: false };
1932
1933            let params = ExtraBonusListParams::builder("sha256".to_string(),"test".to_string(),).build().unwrap();
1934
1935            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"otherProfits":[{"time":1607443200000,"coinName":"BTC","type":4,"profitAmount":0.0011859,"status":2}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1936            let expected_response : models::ExtraBonusListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::ExtraBonusListResponse");
1937
1938            let resp = client.extra_bonus_list(params).await.expect("Expected a response");
1939            let data_future = resp.data();
1940            let actual_response = data_future.await.unwrap();
1941            assert_eq!(actual_response, expected_response);
1942        });
1943    }
1944
1945    #[test]
1946    fn extra_bonus_list_optional_params_success() {
1947        TOKIO_SHARED_RT.block_on(async {
1948            let client = MockApiClient { force_error: false };
1949
1950            let params = ExtraBonusListParams::builder("sha256".to_string(),"test".to_string(),).coin("BTC".to_string()).start_date(1770736694138).end_date(1770736694138).page_index(1).page_size(10).recv_window(5000).build().unwrap();
1951
1952            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"otherProfits":[{"time":1607443200000,"coinName":"BTC","type":4,"profitAmount":0.0011859,"status":2}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
1953            let expected_response : models::ExtraBonusListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::ExtraBonusListResponse");
1954
1955            let resp = client.extra_bonus_list(params).await.expect("Expected a response");
1956            let data_future = resp.data();
1957            let actual_response = data_future.await.unwrap();
1958            assert_eq!(actual_response, expected_response);
1959        });
1960    }
1961
1962    #[test]
1963    fn extra_bonus_list_response_error() {
1964        TOKIO_SHARED_RT.block_on(async {
1965            let client = MockApiClient { force_error: true };
1966
1967            let params = ExtraBonusListParams::builder("sha256".to_string(), "test".to_string())
1968                .build()
1969                .unwrap();
1970
1971            match client.extra_bonus_list(params).await {
1972                Ok(_) => panic!("Expected an error"),
1973                Err(err) => {
1974                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1975                }
1976            }
1977        });
1978    }
1979
1980    #[test]
1981    fn hashrate_resale_detail_required_params_success() {
1982        TOKIO_SHARED_RT.block_on(async {
1983            let client = MockApiClient { force_error: false };
1984
1985            let params = HashrateResaleDetailParams::builder(168,).build().unwrap();
1986
1987            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"profitTransferDetails":[{"poolUsername":"test4001","toPoolUsername":"pop","algoName":"sha256","hashRate":200000000000,"day":20201213,"amount":0.2256872,"coinName":"BTC"}],"totalNum":8,"pageSize":200}}"#).unwrap_or_else(|_| serde_json::json!({}));
1988            let expected_response : models::HashrateResaleDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::HashrateResaleDetailResponse");
1989
1990            let resp = client.hashrate_resale_detail(params).await.expect("Expected a response");
1991            let data_future = resp.data();
1992            let actual_response = data_future.await.unwrap();
1993            assert_eq!(actual_response, expected_response);
1994        });
1995    }
1996
1997    #[test]
1998    fn hashrate_resale_detail_optional_params_success() {
1999        TOKIO_SHARED_RT.block_on(async {
2000            let client = MockApiClient { force_error: false };
2001
2002            let params = HashrateResaleDetailParams::builder(168,).page_index(1).page_size(10).recv_window(5000).build().unwrap();
2003
2004            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"profitTransferDetails":[{"poolUsername":"test4001","toPoolUsername":"pop","algoName":"sha256","hashRate":200000000000,"day":20201213,"amount":0.2256872,"coinName":"BTC"}],"totalNum":8,"pageSize":200}}"#).unwrap_or_else(|_| serde_json::json!({}));
2005            let expected_response : models::HashrateResaleDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::HashrateResaleDetailResponse");
2006
2007            let resp = client.hashrate_resale_detail(params).await.expect("Expected a response");
2008            let data_future = resp.data();
2009            let actual_response = data_future.await.unwrap();
2010            assert_eq!(actual_response, expected_response);
2011        });
2012    }
2013
2014    #[test]
2015    fn hashrate_resale_detail_response_error() {
2016        TOKIO_SHARED_RT.block_on(async {
2017            let client = MockApiClient { force_error: true };
2018
2019            let params = HashrateResaleDetailParams::builder(168).build().unwrap();
2020
2021            match client.hashrate_resale_detail(params).await {
2022                Ok(_) => panic!("Expected an error"),
2023                Err(err) => {
2024                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2025                }
2026            }
2027        });
2028    }
2029
2030    #[test]
2031    fn hashrate_resale_list_required_params_success() {
2032        TOKIO_SHARED_RT.block_on(async {
2033            let client = MockApiClient { force_error: false };
2034
2035            let params = HashrateResaleListParams::builder().build().unwrap();
2036
2037            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"configDetails":[{"configId":168,"poolUsername":"123","toPoolUsername":"user1","algoName":"Ethash","hashRate":5000000,"startDay":20201210,"endDay":20210405,"status":1,"type":0}],"totalNum":21,"pageSize":200}}"#).unwrap_or_else(|_| serde_json::json!({}));
2038            let expected_response : models::HashrateResaleListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::HashrateResaleListResponse");
2039
2040            let resp = client.hashrate_resale_list(params).await.expect("Expected a response");
2041            let data_future = resp.data();
2042            let actual_response = data_future.await.unwrap();
2043            assert_eq!(actual_response, expected_response);
2044        });
2045    }
2046
2047    #[test]
2048    fn hashrate_resale_list_optional_params_success() {
2049        TOKIO_SHARED_RT.block_on(async {
2050            let client = MockApiClient { force_error: false };
2051
2052            let params = HashrateResaleListParams::builder().page_index(1).page_size(10).recv_window(5000).build().unwrap();
2053
2054            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"configDetails":[{"configId":168,"poolUsername":"123","toPoolUsername":"user1","algoName":"Ethash","hashRate":5000000,"startDay":20201210,"endDay":20210405,"status":1,"type":0}],"totalNum":21,"pageSize":200}}"#).unwrap_or_else(|_| serde_json::json!({}));
2055            let expected_response : models::HashrateResaleListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::HashrateResaleListResponse");
2056
2057            let resp = client.hashrate_resale_list(params).await.expect("Expected a response");
2058            let data_future = resp.data();
2059            let actual_response = data_future.await.unwrap();
2060            assert_eq!(actual_response, expected_response);
2061        });
2062    }
2063
2064    #[test]
2065    fn hashrate_resale_list_response_error() {
2066        TOKIO_SHARED_RT.block_on(async {
2067            let client = MockApiClient { force_error: true };
2068
2069            let params = HashrateResaleListParams::builder().build().unwrap();
2070
2071            match client.hashrate_resale_list(params).await {
2072                Ok(_) => panic!("Expected an error"),
2073                Err(err) => {
2074                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2075                }
2076            }
2077        });
2078    }
2079
2080    #[test]
2081    fn hashrate_resale_request_required_params_success() {
2082        TOKIO_SHARED_RT.block_on(async {
2083            let client = MockApiClient { force_error: false };
2084
2085            let params = HashrateResaleRequestParams::builder(
2086                "test".to_string(),
2087                "sha256".to_string(),
2088                1770736694138,
2089                1770736694138,
2090                "S19pro".to_string(),
2091                100000000,
2092            )
2093            .build()
2094            .unwrap();
2095
2096            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":171}"#)
2097                .unwrap_or_else(|_| serde_json::json!({}));
2098            let expected_response: models::HashrateResaleRequestResponse =
2099                serde_json::from_value(resp_json.clone())
2100                    .expect("should parse into models::HashrateResaleRequestResponse");
2101
2102            let resp = client
2103                .hashrate_resale_request(params)
2104                .await
2105                .expect("Expected a response");
2106            let data_future = resp.data();
2107            let actual_response = data_future.await.unwrap();
2108            assert_eq!(actual_response, expected_response);
2109        });
2110    }
2111
2112    #[test]
2113    fn hashrate_resale_request_optional_params_success() {
2114        TOKIO_SHARED_RT.block_on(async {
2115            let client = MockApiClient { force_error: false };
2116
2117            let params = HashrateResaleRequestParams::builder(
2118                "test".to_string(),
2119                "sha256".to_string(),
2120                1770736694138,
2121                1770736694138,
2122                "S19pro".to_string(),
2123                100000000,
2124            )
2125            .recv_window(5000)
2126            .build()
2127            .unwrap();
2128
2129            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":171}"#)
2130                .unwrap_or_else(|_| serde_json::json!({}));
2131            let expected_response: models::HashrateResaleRequestResponse =
2132                serde_json::from_value(resp_json.clone())
2133                    .expect("should parse into models::HashrateResaleRequestResponse");
2134
2135            let resp = client
2136                .hashrate_resale_request(params)
2137                .await
2138                .expect("Expected a response");
2139            let data_future = resp.data();
2140            let actual_response = data_future.await.unwrap();
2141            assert_eq!(actual_response, expected_response);
2142        });
2143    }
2144
2145    #[test]
2146    fn hashrate_resale_request_response_error() {
2147        TOKIO_SHARED_RT.block_on(async {
2148            let client = MockApiClient { force_error: true };
2149
2150            let params = HashrateResaleRequestParams::builder(
2151                "test".to_string(),
2152                "sha256".to_string(),
2153                1770736694138,
2154                1770736694138,
2155                "S19pro".to_string(),
2156                100000000,
2157            )
2158            .build()
2159            .unwrap();
2160
2161            match client.hashrate_resale_request(params).await {
2162                Ok(_) => panic!("Expected an error"),
2163                Err(err) => {
2164                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2165                }
2166            }
2167        });
2168    }
2169
2170    #[test]
2171    fn mining_account_earning_required_params_success() {
2172        TOKIO_SHARED_RT.block_on(async {
2173            let client = MockApiClient { force_error: false };
2174
2175            let params = MiningAccountEarningParams::builder("sha256".to_string(),).build().unwrap();
2176
2177            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"accountProfits":[{"time":1607443200000,"coinName":"BTC","type":2,"puid":59985472,"subName":"vdvaghani","amount":0.09186957}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
2178            let expected_response : models::MiningAccountEarningResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::MiningAccountEarningResponse");
2179
2180            let resp = client.mining_account_earning(params).await.expect("Expected a response");
2181            let data_future = resp.data();
2182            let actual_response = data_future.await.unwrap();
2183            assert_eq!(actual_response, expected_response);
2184        });
2185    }
2186
2187    #[test]
2188    fn mining_account_earning_optional_params_success() {
2189        TOKIO_SHARED_RT.block_on(async {
2190            let client = MockApiClient { force_error: false };
2191
2192            let params = MiningAccountEarningParams::builder("sha256".to_string(),).start_date(1770736694138).end_date(1770736694138).page_index(1).page_size(10).recv_window(5000).build().unwrap();
2193
2194            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"accountProfits":[{"time":1607443200000,"coinName":"BTC","type":2,"puid":59985472,"subName":"vdvaghani","amount":0.09186957}],"totalNum":3,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
2195            let expected_response : models::MiningAccountEarningResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::MiningAccountEarningResponse");
2196
2197            let resp = client.mining_account_earning(params).await.expect("Expected a response");
2198            let data_future = resp.data();
2199            let actual_response = data_future.await.unwrap();
2200            assert_eq!(actual_response, expected_response);
2201        });
2202    }
2203
2204    #[test]
2205    fn mining_account_earning_response_error() {
2206        TOKIO_SHARED_RT.block_on(async {
2207            let client = MockApiClient { force_error: true };
2208
2209            let params = MiningAccountEarningParams::builder("sha256".to_string())
2210                .build()
2211                .unwrap();
2212
2213            match client.mining_account_earning(params).await {
2214                Ok(_) => panic!("Expected an error"),
2215                Err(err) => {
2216                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2217                }
2218            }
2219        });
2220    }
2221
2222    #[test]
2223    fn request_for_detail_miner_list_required_params_success() {
2224        TOKIO_SHARED_RT.block_on(async {
2225            let client = MockApiClient { force_error: false };
2226
2227            let params = RequestForDetailMinerListParams::builder("sha256".to_string(),"test".to_string(),"bhdc1.16A10404B".to_string(),).build().unwrap();
2228
2229            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"workerName":"bhdc1.16A10404B","type":"H_hashrate","hashrateDatas":[{"time":1587902400000,"hashrate":"0","reject":0}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2230            let expected_response : models::RequestForDetailMinerListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RequestForDetailMinerListResponse");
2231
2232            let resp = client.request_for_detail_miner_list(params).await.expect("Expected a response");
2233            let data_future = resp.data();
2234            let actual_response = data_future.await.unwrap();
2235            assert_eq!(actual_response, expected_response);
2236        });
2237    }
2238
2239    #[test]
2240    fn request_for_detail_miner_list_optional_params_success() {
2241        TOKIO_SHARED_RT.block_on(async {
2242            let client = MockApiClient { force_error: false };
2243
2244            let params = RequestForDetailMinerListParams::builder("sha256".to_string(),"test".to_string(),"bhdc1.16A10404B".to_string(),).recv_window(5000).build().unwrap();
2245
2246            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":[{"workerName":"bhdc1.16A10404B","type":"H_hashrate","hashrateDatas":[{"time":1587902400000,"hashrate":"0","reject":0}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2247            let expected_response : models::RequestForDetailMinerListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RequestForDetailMinerListResponse");
2248
2249            let resp = client.request_for_detail_miner_list(params).await.expect("Expected a response");
2250            let data_future = resp.data();
2251            let actual_response = data_future.await.unwrap();
2252            assert_eq!(actual_response, expected_response);
2253        });
2254    }
2255
2256    #[test]
2257    fn request_for_detail_miner_list_response_error() {
2258        TOKIO_SHARED_RT.block_on(async {
2259            let client = MockApiClient { force_error: true };
2260
2261            let params = RequestForDetailMinerListParams::builder(
2262                "sha256".to_string(),
2263                "test".to_string(),
2264                "bhdc1.16A10404B".to_string(),
2265            )
2266            .build()
2267            .unwrap();
2268
2269            match client.request_for_detail_miner_list(params).await {
2270                Ok(_) => panic!("Expected an error"),
2271                Err(err) => {
2272                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2273                }
2274            }
2275        });
2276    }
2277
2278    #[test]
2279    fn request_for_miner_list_required_params_success() {
2280        TOKIO_SHARED_RT.block_on(async {
2281            let client = MockApiClient { force_error: false };
2282
2283            let params = RequestForMinerListParams::builder("sha256".to_string(),"test".to_string(),).build().unwrap();
2284
2285            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"workerDatas":[{"workerId":"1420554439452400131","workerName":"2X73","status":3,"hashRate":0,"dayHashRate":1.269778129801366E13,"rejectRate":0,"lastShareTime":1587712919000}],"totalNum":18530,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
2286            let expected_response : models::RequestForMinerListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RequestForMinerListResponse");
2287
2288            let resp = client.request_for_miner_list(params).await.expect("Expected a response");
2289            let data_future = resp.data();
2290            let actual_response = data_future.await.unwrap();
2291            assert_eq!(actual_response, expected_response);
2292        });
2293    }
2294
2295    #[test]
2296    fn request_for_miner_list_optional_params_success() {
2297        TOKIO_SHARED_RT.block_on(async {
2298            let client = MockApiClient { force_error: false };
2299
2300            let params = RequestForMinerListParams::builder("sha256".to_string(),"test".to_string(),).page_index(1).sort(0).sort_column(1).worker_status(0).recv_window(5000).build().unwrap();
2301
2302            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"workerDatas":[{"workerId":"1420554439452400131","workerName":"2X73","status":3,"hashRate":0,"dayHashRate":1.269778129801366E13,"rejectRate":0,"lastShareTime":1587712919000}],"totalNum":18530,"pageSize":20}}"#).unwrap_or_else(|_| serde_json::json!({}));
2303            let expected_response : models::RequestForMinerListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::RequestForMinerListResponse");
2304
2305            let resp = client.request_for_miner_list(params).await.expect("Expected a response");
2306            let data_future = resp.data();
2307            let actual_response = data_future.await.unwrap();
2308            assert_eq!(actual_response, expected_response);
2309        });
2310    }
2311
2312    #[test]
2313    fn request_for_miner_list_response_error() {
2314        TOKIO_SHARED_RT.block_on(async {
2315            let client = MockApiClient { force_error: true };
2316
2317            let params =
2318                RequestForMinerListParams::builder("sha256".to_string(), "test".to_string())
2319                    .build()
2320                    .unwrap();
2321
2322            match client.request_for_miner_list(params).await {
2323                Ok(_) => panic!("Expected an error"),
2324                Err(err) => {
2325                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2326                }
2327            }
2328        });
2329    }
2330
2331    #[test]
2332    fn statistic_list_required_params_success() {
2333        TOKIO_SHARED_RT.block_on(async {
2334            let client = MockApiClient { force_error: false };
2335
2336            let params = StatisticListParams::builder("sha256".to_string(),"test".to_string(),).build().unwrap();
2337
2338            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"fifteenMinHashRate":"457835490067496409.00000000","dayHashRate":"214289268068874127.65000000","validNum":0,"invalidNum":17562,"profitToday":{"BTC":"0.00314332","BSV":"56.17055953","BCH":"106.61586001"},"profitYesterday":{"BTC":"0.00314332","BSV":"56.17055953","BCH":"106.61586001"},"userName":"test","unit":"h/s","algo":"sha256"}}"#).unwrap_or_else(|_| serde_json::json!({}));
2339            let expected_response : models::StatisticListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::StatisticListResponse");
2340
2341            let resp = client.statistic_list(params).await.expect("Expected a response");
2342            let data_future = resp.data();
2343            let actual_response = data_future.await.unwrap();
2344            assert_eq!(actual_response, expected_response);
2345        });
2346    }
2347
2348    #[test]
2349    fn statistic_list_optional_params_success() {
2350        TOKIO_SHARED_RT.block_on(async {
2351            let client = MockApiClient { force_error: false };
2352
2353            let params = StatisticListParams::builder("sha256".to_string(),"test".to_string(),).recv_window(5000).build().unwrap();
2354
2355            let resp_json: Value = serde_json::from_str(r#"{"code":0,"msg":"","data":{"fifteenMinHashRate":"457835490067496409.00000000","dayHashRate":"214289268068874127.65000000","validNum":0,"invalidNum":17562,"profitToday":{"BTC":"0.00314332","BSV":"56.17055953","BCH":"106.61586001"},"profitYesterday":{"BTC":"0.00314332","BSV":"56.17055953","BCH":"106.61586001"},"userName":"test","unit":"h/s","algo":"sha256"}}"#).unwrap_or_else(|_| serde_json::json!({}));
2356            let expected_response : models::StatisticListResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::StatisticListResponse");
2357
2358            let resp = client.statistic_list(params).await.expect("Expected a response");
2359            let data_future = resp.data();
2360            let actual_response = data_future.await.unwrap();
2361            assert_eq!(actual_response, expected_response);
2362        });
2363    }
2364
2365    #[test]
2366    fn statistic_list_response_error() {
2367        TOKIO_SHARED_RT.block_on(async {
2368            let client = MockApiClient { force_error: true };
2369
2370            let params = StatisticListParams::builder("sha256".to_string(), "test".to_string())
2371                .build()
2372                .unwrap();
2373
2374            match client.statistic_list(params).await {
2375                Ok(_) => panic!("Expected an error"),
2376                Err(err) => {
2377                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2378                }
2379            }
2380        });
2381    }
2382}