bybit_rust_api/rest/asset/
asset_client.rs

1use crate::rest::client::{RestClient, SecType, ServerResponse};
2use crate::rest::BybitResult as Result;
3use serde_json::json;
4
5#[derive(Clone)]
6pub struct AssetClient {
7    client: RestClient,
8}
9
10impl AssetClient {
11    pub fn new(client: RestClient) -> Self {
12        AssetClient { client }
13    }
14
15    /// Get coin exchange records
16    ///
17    /// API: GET /v5/asset/exchange/order-record
18    /// https://bybit-exchange.github.io/docs/v5/asset/exchange-order-record
19    pub async fn get_exchange_order_record(
20        &self,
21        from_coin: Option<&str>,
22        to_coin: Option<&str>,
23        limit: Option<i32>,
24        cursor: Option<&str>,
25    ) -> Result<ServerResponse<serde_json::Value>> {
26        let endpoint = "v5/asset/exchange/order-record";
27        let mut params = json!({});
28
29        if let Some(from_coin) = from_coin {
30            params["fromCoin"] = json!(from_coin);
31        }
32        if let Some(to_coin) = to_coin {
33            params["toCoin"] = json!(to_coin);
34        }
35        if let Some(limit) = limit {
36            params["limit"] = json!(limit);
37        }
38        if let Some(cursor) = cursor {
39            params["cursor"] = json!(cursor);
40        }
41
42        let response = self.client.get(endpoint, params, SecType::Signed).await?;
43        Ok(response)
44    }
45
46    /// Get delivery record
47    ///
48    /// API: GET /v5/asset/delivery-record
49    /// https://bybit-exchange.github.io/docs/v5/asset/delivery
50    pub async fn get_delivery_record(
51        &self,
52        category: &str,
53        symbol: Option<&str>,
54        exp_date: Option<&str>,
55        limit: Option<i32>,
56        cursor: Option<&str>,
57    ) -> Result<ServerResponse<serde_json::Value>> {
58        let endpoint = "v5/asset/delivery-record";
59        let mut params = json!({
60            "category": category,
61        });
62
63        if let Some(symbol) = symbol {
64            params["symbol"] = json!(symbol);
65        }
66        if let Some(exp_date) = exp_date {
67            params["expDate"] = json!(exp_date);
68        }
69        if let Some(limit) = limit {
70            params["limit"] = json!(limit);
71        }
72        if let Some(cursor) = cursor {
73            params["cursor"] = json!(cursor);
74        }
75
76        let response = self.client.get(endpoint, params, SecType::Signed).await?;
77        Ok(response)
78    }
79
80    /// Get USDC settlement records
81    ///
82    /// API: GET /v5/asset/settlement-record
83    /// https://bybit-exchange.github.io/docs/v5/asset/settlement
84    pub async fn get_settlement_record(
85        &self,
86        category: &str,
87        symbol: Option<&str>,
88        limit: Option<i32>,
89        cursor: Option<&str>,
90    ) -> Result<ServerResponse<serde_json::Value>> {
91        let endpoint = "v5/asset/settlement-record";
92        let mut params = json!({
93            "category": category,
94        });
95
96        if let Some(symbol) = symbol {
97            params["symbol"] = json!(symbol);
98        }
99        if let Some(limit) = limit {
100            params["limit"] = json!(limit);
101        }
102        if let Some(cursor) = cursor {
103            params["cursor"] = json!(cursor);
104        }
105
106        let response = self.client.get(endpoint, params, SecType::Signed).await?;
107        Ok(response)
108    }
109
110    /// Get coins
111    ///
112    /// API: GET /v5/asset/coin/query-info
113    /// https://bybit-exchange.github.io/docs/v5/asset/coin-info
114    pub async fn get_coin_info(
115        &self,
116        coin: Option<&str>,
117    ) -> Result<ServerResponse<serde_json::Value>> {
118        let endpoint = "v5/asset/coin/query-info";
119        let mut params = json!({});
120
121        if let Some(coin) = coin {
122            params["coin"] = json!(coin);
123        }
124
125        let response = self.client.get(endpoint, params, SecType::Signed).await?;
126        Ok(response)
127    }
128
129    /// Get asset info
130    ///
131    /// API: GET /v5/asset/transfer/query-asset-info
132    /// https://bybit-exchange.github.io/docs/v5/asset/asset-info
133    pub async fn get_asset_info(
134        &self,
135        account_type: &str,
136        coin: Option<&str>,
137    ) -> Result<ServerResponse<serde_json::Value>> {
138        let endpoint = "v5/asset/transfer/query-asset-info";
139        let mut params = json!({
140            "accountType": account_type,
141        });
142
143        if let Some(coin) = coin {
144            params["coin"] = json!(coin);
145        }
146
147        let response = self.client.get(endpoint, params, SecType::Signed).await?;
148        Ok(response)
149    }
150
151    /// Get sub member list
152    ///
153    /// API: GET /v5/asset/transfer/query-sub-member-list
154    /// https://bybit-exchange.github.io/docs/v5/asset/sub-member-list
155    pub async fn get_sub_member_list(&self) -> Result<ServerResponse<serde_json::Value>> {
156        let endpoint = "v5/asset/transfer/query-sub-member-list";
157        let response = self
158            .client
159            .get(endpoint, json!({}), SecType::Signed)
160            .await?;
161        Ok(response)
162    }
163
164    /// Get deposit records
165    ///
166    /// API: GET /v5/asset/deposit/query-record
167    /// https://bybit-exchange.github.io/docs/v5/asset/deposit-record
168    pub async fn get_deposit_records(
169        &self,
170        coin: Option<&str>,
171        start_time: Option<i64>,
172        end_time: Option<i64>,
173        limit: Option<i32>,
174        cursor: Option<&str>,
175    ) -> Result<ServerResponse<serde_json::Value>> {
176        let endpoint = "v5/asset/deposit/query-record";
177        let mut params = json!({});
178
179        if let Some(coin) = coin {
180            params["coin"] = json!(coin);
181        }
182        if let Some(start_time) = start_time {
183            params["startTime"] = json!(start_time);
184        }
185        if let Some(end_time) = end_time {
186            params["endTime"] = json!(end_time);
187        }
188        if let Some(limit) = limit {
189            params["limit"] = json!(limit);
190        }
191        if let Some(cursor) = cursor {
192            params["cursor"] = json!(cursor);
193        }
194
195        let response = self.client.get(endpoint, params, SecType::Signed).await?;
196        Ok(response)
197    }
198
199    /// Get sub deposit records
200    ///
201    /// API: GET /v5/asset/deposit/query-sub-member-record
202    /// https://bybit-exchange.github.io/docs/v5/asset/sub-deposit-record
203    pub async fn get_sub_deposit_records(
204        &self,
205        sub_member_id: &str,
206        coin: Option<&str>,
207        start_time: Option<i64>,
208        end_time: Option<i64>,
209        limit: Option<i32>,
210        cursor: Option<&str>,
211    ) -> Result<ServerResponse<serde_json::Value>> {
212        let endpoint = "v5/asset/deposit/query-sub-member-record";
213        let mut params = json!({
214            "subMemberId": sub_member_id,
215        });
216
217        if let Some(coin) = coin {
218            params["coin"] = json!(coin);
219        }
220        if let Some(start_time) = start_time {
221            params["startTime"] = json!(start_time);
222        }
223        if let Some(end_time) = end_time {
224            params["endTime"] = json!(end_time);
225        }
226        if let Some(limit) = limit {
227            params["limit"] = json!(limit);
228        }
229        if let Some(cursor) = cursor {
230            params["cursor"] = json!(cursor);
231        }
232
233        let response = self.client.get(endpoint, params, SecType::Signed).await?;
234        Ok(response)
235    }
236
237    /// Get internal deposit records
238    ///
239    /// API: GET /v5/asset/deposit/query-internal-record
240    /// https://bybit-exchange.github.io/docs/v5/asset/internal-deposit-record
241    pub async fn get_internal_deposit_records(
242        &self,
243        start_time: Option<i64>,
244        end_time: Option<i64>,
245        coin: Option<&str>,
246        cursor: Option<&str>,
247        limit: Option<i32>,
248    ) -> Result<ServerResponse<serde_json::Value>> {
249        let endpoint = "v5/asset/deposit/query-internal-record";
250        let mut params = json!({});
251
252        if let Some(start_time) = start_time {
253            params["startTime"] = json!(start_time);
254        }
255        if let Some(end_time) = end_time {
256            params["endTime"] = json!(end_time);
257        }
258        if let Some(coin) = coin {
259            params["coin"] = json!(coin);
260        }
261        if let Some(cursor) = cursor {
262            params["cursor"] = json!(cursor);
263        }
264        if let Some(limit) = limit {
265            params["limit"] = json!(limit);
266        }
267
268        let response = self.client.get(endpoint, params, SecType::Signed).await?;
269        Ok(response)
270    }
271
272    /// Get master deposit address
273    ///
274    /// API: GET /v5/asset/deposit/query-address
275    /// https://bybit-exchange.github.io/docs/v5/asset/master-deposit-addr
276    pub async fn get_master_deposit_address(
277        &self,
278        coin: &str,
279        chain_type: Option<&str>,
280    ) -> Result<ServerResponse<serde_json::Value>> {
281        let endpoint = "v5/asset/deposit/query-address";
282        let mut params = json!({
283            "coin": coin,
284        });
285
286        if let Some(chain_type) = chain_type {
287            params["chainType"] = json!(chain_type);
288        }
289
290        let response = self.client.get(endpoint, params, SecType::Signed).await?;
291        Ok(response)
292    }
293
294    /// Get sub deposit address
295    ///
296    /// API: GET /v5/asset/deposit/query-sub-member-address
297    /// https://bybit-exchange.github.io/docs/v5/asset/sub-deposit-addr
298    pub async fn get_sub_deposit_address(
299        &self,
300        coin: &str,
301        chain_type: &str,
302        sub_member_id: &str,
303    ) -> Result<ServerResponse<serde_json::Value>> {
304        let endpoint = "v5/asset/deposit/query-sub-member-address";
305        let params = json!({
306            "coin": coin,
307            "chainType": chain_type,
308            "subMemberId": sub_member_id,
309        });
310
311        let response = self.client.get(endpoint, params, SecType::Signed).await?;
312        Ok(response)
313    }
314
315    /// Get allowed deposit coin info
316    ///
317    /// API: GET /v5/asset/deposit/query-allowed-list
318    /// https://bybit-exchange.github.io/docs/v5/asset/deposit-coin-spec
319    pub async fn get_allowed_deposit_list(
320        &self,
321        coin: Option<&str>,
322        chain: Option<&str>,
323        limit: Option<i32>,
324        cursor: Option<&str>,
325    ) -> Result<ServerResponse<serde_json::Value>> {
326        let endpoint = "v5/asset/deposit/query-allowed-list";
327        let mut params = json!({});
328
329        if let Some(coin) = coin {
330            params["coin"] = json!(coin);
331        }
332        if let Some(chain) = chain {
333            params["chain"] = json!(chain);
334        }
335        if let Some(limit) = limit {
336            params["limit"] = json!(limit);
337        }
338        if let Some(cursor) = cursor {
339            params["cursor"] = json!(cursor);
340        }
341
342        let response = self.client.get(endpoint, params, SecType::Signed).await?;
343        Ok(response)
344    }
345
346    /// Get withdrawal records
347    ///
348    /// API: GET /v5/asset/withdraw/query-record
349    /// https://bybit-exchange.github.io/docs/v5/asset/withdraw-record
350    pub async fn get_withdrawal_records(
351        &self,
352        withdraw_id: Option<&str>,
353        coin: Option<&str>,
354        withdraw_type: Option<i32>,
355        start_time: Option<i64>,
356        end_time: Option<i64>,
357        limit: Option<i32>,
358        cursor: Option<&str>,
359    ) -> Result<ServerResponse<serde_json::Value>> {
360        let endpoint = "v5/asset/withdraw/query-record";
361        let mut params = json!({});
362
363        if let Some(withdraw_id) = withdraw_id {
364            params["withdrawID"] = json!(withdraw_id);
365        }
366        if let Some(coin) = coin {
367            params["coin"] = json!(coin);
368        }
369        if let Some(withdraw_type) = withdraw_type {
370            params["withdrawType"] = json!(withdraw_type);
371        }
372        if let Some(start_time) = start_time {
373            params["startTime"] = json!(start_time);
374        }
375        if let Some(end_time) = end_time {
376            params["endTime"] = json!(end_time);
377        }
378        if let Some(limit) = limit {
379            params["limit"] = json!(limit);
380        }
381        if let Some(cursor) = cursor {
382            params["cursor"] = json!(cursor);
383        }
384
385        let response = self.client.get(endpoint, params, SecType::Signed).await?;
386        Ok(response)
387    }
388
389    /// Get withdrawable amount
390    ///
391    /// API: GET /v5/asset/withdraw/withdrawable-amount
392    /// https://bybit-exchange.github.io/docs/v5/asset/withdrawable-amount
393    pub async fn get_withdrawable_amount(
394        &self,
395        coin: &str,
396    ) -> Result<ServerResponse<serde_json::Value>> {
397        let endpoint = "v5/asset/withdraw/withdrawable-amount";
398        let params = json!({
399            "coin": coin,
400        });
401
402        let response = self.client.get(endpoint, params, SecType::Signed).await?;
403        Ok(response)
404    }
405
406    /// Withdraw
407    ///
408    /// API: POST /v5/asset/withdraw/create
409    /// https://bybit-exchange.github.io/docs/v5/asset/withdraw
410    pub async fn withdraw(
411        &self,
412        coin: &str,
413        chain: &str,
414        address: &str,
415        tag: Option<&str>,
416        amount: &str,
417        timestamp: i64,
418        for_ce_chain: Option<i32>,
419        account_type: Option<&str>,
420    ) -> Result<ServerResponse<serde_json::Value>> {
421        let endpoint = "v5/asset/withdraw/create";
422        let mut body = json!({
423            "coin": coin,
424            "chain": chain,
425            "address": address,
426            "amount": amount,
427            "timestamp": timestamp,
428        });
429
430        if let Some(tag) = tag {
431            body["tag"] = json!(tag);
432        }
433        if let Some(for_ce_chain) = for_ce_chain {
434            body["forceChain"] = json!(for_ce_chain);
435        }
436        if let Some(account_type) = account_type {
437            body["accountType"] = json!(account_type);
438        }
439
440        let response = self.client.post(endpoint, body, SecType::Signed).await?;
441        Ok(response)
442    }
443
444    /// Cancel withdrawal
445    ///
446    /// API: POST /v5/asset/withdraw/cancel
447    /// https://bybit-exchange.github.io/docs/v5/asset/cancel-withdraw
448    pub async fn cancel_withdrawal(&self, id: &str) -> Result<ServerResponse<serde_json::Value>> {
449        let endpoint = "v5/asset/withdraw/cancel";
450        let body = json!({
451            "id": id,
452        });
453
454        let response = self.client.post(endpoint, body, SecType::Signed).await?;
455        Ok(response)
456    }
457
458    /// Create internal transfer
459    ///
460    /// API: POST /v5/asset/transfer/inter-transfer
461    /// https://bybit-exchange.github.io/docs/v5/asset/create-inter-transfer
462    pub async fn create_internal_transfer(
463        &self,
464        transfer_id: &str,
465        coin: &str,
466        amount: &str,
467        from_account_type: &str,
468        to_account_type: &str,
469    ) -> Result<ServerResponse<serde_json::Value>> {
470        let endpoint = "v5/asset/transfer/inter-transfer";
471        let body = json!({
472            "transferId": transfer_id,
473            "coin": coin,
474            "amount": amount,
475            "fromAccountType": from_account_type,
476            "toAccountType": to_account_type,
477        });
478
479        let response = self.client.post(endpoint, body, SecType::Signed).await?;
480        Ok(response)
481    }
482
483    /// Get internal transfer records
484    ///
485    /// API: GET /v5/asset/transfer/query-inter-transfer-list
486    /// https://bybit-exchange.github.io/docs/v5/asset/inter-transfer-list
487    pub async fn get_internal_transfer_records(
488        &self,
489        transfer_id: Option<&str>,
490        coin: Option<&str>,
491        status: Option<&str>,
492        start_time: Option<i64>,
493        end_time: Option<i64>,
494        limit: Option<i32>,
495        cursor: Option<&str>,
496    ) -> Result<ServerResponse<serde_json::Value>> {
497        let endpoint = "v5/asset/transfer/query-inter-transfer-list";
498        let mut params = json!({});
499
500        if let Some(transfer_id) = transfer_id {
501            params["transferId"] = json!(transfer_id);
502        }
503        if let Some(coin) = coin {
504            params["coin"] = json!(coin);
505        }
506        if let Some(status) = status {
507            params["status"] = json!(status);
508        }
509        if let Some(start_time) = start_time {
510            params["startTime"] = json!(start_time);
511        }
512        if let Some(end_time) = end_time {
513            params["endTime"] = json!(end_time);
514        }
515        if let Some(limit) = limit {
516            params["limit"] = json!(limit);
517        }
518        if let Some(cursor) = cursor {
519            params["cursor"] = json!(cursor);
520        }
521
522        let response = self.client.get(endpoint, params, SecType::Signed).await?;
523        Ok(response)
524    }
525
526    /// Create universal transfer
527    ///
528    /// API: POST /v5/asset/transfer/universal-transfer
529    /// https://bybit-exchange.github.io/docs/v5/asset/create-universal-transfer
530    pub async fn create_universal_transfer(
531        &self,
532        transfer_id: &str,
533        coin: &str,
534        amount: &str,
535        from_member_id: &str,
536        to_member_id: &str,
537        from_account_type: &str,
538        to_account_type: &str,
539    ) -> Result<ServerResponse<serde_json::Value>> {
540        let endpoint = "v5/asset/transfer/universal-transfer";
541        let body = json!({
542            "transferId": transfer_id,
543            "coin": coin,
544            "amount": amount,
545            "fromMemberId": from_member_id,
546            "toMemberId": to_member_id,
547            "fromAccountType": from_account_type,
548            "toAccountType": to_account_type,
549        });
550
551        let response = self.client.post(endpoint, body, SecType::Signed).await?;
552        Ok(response)
553    }
554
555    /// Get universal transfer records
556    ///
557    /// API: GET /v5/asset/transfer/query-universal-transfer-list
558    /// https://bybit-exchange.github.io/docs/v5/asset/universal-transfer-list
559    pub async fn get_universal_transfer_records(
560        &self,
561        transfer_id: Option<&str>,
562        coin: Option<&str>,
563        status: Option<&str>,
564        start_time: Option<i64>,
565        end_time: Option<i64>,
566        limit: Option<i32>,
567        cursor: Option<&str>,
568    ) -> Result<ServerResponse<serde_json::Value>> {
569        let endpoint = "v5/asset/transfer/query-universal-transfer-list";
570        let mut params = json!({});
571
572        if let Some(transfer_id) = transfer_id {
573            params["transferId"] = json!(transfer_id);
574        }
575        if let Some(coin) = coin {
576            params["coin"] = json!(coin);
577        }
578        if let Some(status) = status {
579            params["status"] = json!(status);
580        }
581        if let Some(start_time) = start_time {
582            params["startTime"] = json!(start_time);
583        }
584        if let Some(end_time) = end_time {
585            params["endTime"] = json!(end_time);
586        }
587        if let Some(limit) = limit {
588            params["limit"] = json!(limit);
589        }
590        if let Some(cursor) = cursor {
591            params["cursor"] = json!(cursor);
592        }
593
594        let response = self.client.get(endpoint, params, SecType::Signed).await?;
595        Ok(response)
596    }
597
598    /// Get allowed transfer coin list
599    ///
600    /// API: GET /v5/asset/transfer/query-transfer-coin-list
601    /// https://bybit-exchange.github.io/docs/v5/asset/transferable-coin
602    pub async fn get_allowed_transfer_coin_list(
603        &self,
604        from_account_type: &str,
605        to_account_type: &str,
606    ) -> Result<ServerResponse<serde_json::Value>> {
607        let endpoint = "v5/asset/transfer/query-transfer-coin-list";
608        let params = json!({
609            "fromAccountType": from_account_type,
610            "toAccountType": to_account_type,
611        });
612
613        let response = self.client.get(endpoint, params, SecType::Signed).await?;
614        Ok(response)
615    }
616
617    /// Request quote for convert
618    ///
619    /// API: POST /v5/asset/exchange/quote-apply
620    /// https://bybit-exchange.github.io/docs/v5/asset/request-quote
621    pub async fn request_convert_quote(
622        &self,
623        from_coin: &str,
624        to_coin: &str,
625        from_coin_type: Option<&str>,
626        to_coin_type: Option<&str>,
627        request_coin: &str,
628        request_amount: &str,
629        account_type: &str,
630        request_id: Option<&str>,
631    ) -> Result<ServerResponse<serde_json::Value>> {
632        let endpoint = "v5/asset/exchange/quote-apply";
633        let mut body = json!({
634            "fromCoin": from_coin,
635            "toCoin": to_coin,
636            "requestCoin": request_coin,
637            "requestAmount": request_amount,
638            "accountType": account_type,
639        });
640
641        if let Some(from_coin_type) = from_coin_type {
642            body["fromCoinType"] = json!(from_coin_type);
643        }
644        if let Some(to_coin_type) = to_coin_type {
645            body["toCoinType"] = json!(to_coin_type);
646        }
647        if let Some(request_id) = request_id {
648            body["requestId"] = json!(request_id);
649        }
650
651        let response = self.client.post(endpoint, body, SecType::Signed).await?;
652        Ok(response)
653    }
654
655    /// Confirm quote for convert
656    ///
657    /// API: POST /v5/asset/exchange/convert-execute
658    /// https://bybit-exchange.github.io/docs/v5/asset/confirm-quote
659    pub async fn confirm_convert_quote(
660        &self,
661        quote_tx_id: &str,
662    ) -> Result<ServerResponse<serde_json::Value>> {
663        let endpoint = "v5/asset/exchange/convert-execute";
664        let body = json!({
665            "quoteTxId": quote_tx_id,
666        });
667
668        let response = self.client.post(endpoint, body, SecType::Signed).await?;
669        Ok(response)
670    }
671
672    /// Get convert status
673    ///
674    /// API: GET /v5/asset/exchange/convert-result-query
675    /// https://bybit-exchange.github.io/docs/v5/asset/convert-status
676    pub async fn get_convert_result(
677        &self,
678        quote_tx_id: Option<&str>,
679        account_type: Option<&str>,
680    ) -> Result<ServerResponse<serde_json::Value>> {
681        let endpoint = "v5/asset/exchange/convert-result-query";
682        let mut params = json!({});
683
684        if let Some(quote_tx_id) = quote_tx_id {
685            params["quoteTxId"] = json!(quote_tx_id);
686        }
687        if let Some(account_type) = account_type {
688            params["accountType"] = json!(account_type);
689        }
690
691        let response = self.client.get(endpoint, params, SecType::Signed).await?;
692        Ok(response)
693    }
694
695    /// Get convert history
696    ///
697    /// API: GET /v5/asset/exchange/query-convert-history
698    /// https://bybit-exchange.github.io/docs/v5/asset/convert-history
699    pub async fn get_convert_history(
700        &self,
701        account_type: Option<&str>,
702        index: Option<i32>,
703        limit: Option<i32>,
704    ) -> Result<ServerResponse<serde_json::Value>> {
705        let endpoint = "v5/asset/exchange/query-convert-history";
706        let mut params = json!({});
707
708        if let Some(account_type) = account_type {
709            params["accountType"] = json!(account_type);
710        }
711        if let Some(index) = index {
712            params["index"] = json!(index);
713        }
714        if let Some(limit) = limit {
715            params["limit"] = json!(limit);
716        }
717
718        let response = self.client.get(endpoint, params, SecType::Signed).await?;
719        Ok(response)
720    }
721
722    /// Get convert coin list
723    ///
724    /// API: GET /v5/asset/exchange/query-coin-list
725    /// https://bybit-exchange.github.io/docs/v5/asset/convert-coin-list
726    pub async fn get_convert_coin_list(
727        &self,
728        coin: Option<&str>,
729        side: Option<i32>,
730        account_type: &str,
731    ) -> Result<ServerResponse<serde_json::Value>> {
732        let endpoint = "v5/asset/exchange/query-coin-list";
733        let mut params = json!({
734            "accountType": account_type,
735        });
736
737        if let Some(coin) = coin {
738            params["coin"] = json!(coin);
739        }
740        if let Some(side) = side {
741            params["side"] = json!(side);
742        }
743
744        let response = self.client.get(endpoint, params, SecType::Signed).await?;
745        Ok(response)
746    }
747
748    /// Get coin greeks
749    ///
750    /// API: GET /v5/asset/coin-greeks
751    /// https://bybit-exchange.github.io/docs/v5/asset/coin-greeks
752    pub async fn get_coin_greeks(
753        &self,
754        base_coin: Option<&str>,
755    ) -> Result<ServerResponse<serde_json::Value>> {
756        let endpoint = "v5/asset/coin-greeks";
757        let mut params = json!({});
758
759        if let Some(base_coin) = base_coin {
760            params["baseCoin"] = json!(base_coin);
761        }
762
763        let response = self.client.get(endpoint, params, SecType::Signed).await?;
764        Ok(response)
765    }
766
767    /// Query account coin balance
768    ///
769    /// API: GET /v5/asset/transfer/query-account-coin-balance
770    /// https://bybit-exchange.github.io/docs/v5/asset/account-coin-balance
771    pub async fn query_account_coin_balance(
772        &self,
773        member_id: Option<&str>,
774        to_member_id: Option<&str>,
775        account_type: &str,
776        to_account_type: Option<&str>,
777        coin: &str,
778        with_bonus: Option<i32>,
779        with_transfer_safe_amount: Option<i32>,
780        with_ltv_transfer_safe_amount: Option<i32>,
781    ) -> Result<ServerResponse<serde_json::Value>> {
782        let endpoint = "v5/asset/transfer/query-account-coin-balance";
783        let mut params = json!({
784            "accountType": account_type,
785            "coin": coin,
786        });
787
788        if let Some(member_id) = member_id {
789            params["memberId"] = json!(member_id);
790        }
791        if let Some(to_member_id) = to_member_id {
792            params["toMemberId"] = json!(to_member_id);
793        }
794        if let Some(to_account_type) = to_account_type {
795            params["toAccountType"] = json!(to_account_type);
796        }
797        if let Some(with_bonus) = with_bonus {
798            params["withBonus"] = json!(with_bonus);
799        }
800        if let Some(with_transfer_safe_amount) = with_transfer_safe_amount {
801            params["withTransferSafeAmount"] = json!(with_transfer_safe_amount);
802        }
803        if let Some(with_ltv_transfer_safe_amount) = with_ltv_transfer_safe_amount {
804            params["withLtvTransferSafeAmount"] = json!(with_ltv_transfer_safe_amount);
805        }
806
807        let response = self.client.get(endpoint, params, SecType::Signed).await?;
808        Ok(response)
809    }
810
811    /// Query account coins balance
812    ///
813    /// API: GET /v5/asset/transfer/query-account-coins-balance
814    /// https://bybit-exchange.github.io/docs/v5/asset/account-coins-balance
815    pub async fn query_account_coins_balance(
816        &self,
817        member_id: Option<&str>,
818        account_type: &str,
819        coin: Option<&str>,
820        with_bonus: Option<i32>,
821    ) -> Result<ServerResponse<serde_json::Value>> {
822        let endpoint = "v5/asset/transfer/query-account-coins-balance";
823        let mut params = json!({
824            "accountType": account_type,
825        });
826
827        if let Some(member_id) = member_id {
828            params["memberId"] = json!(member_id);
829        }
830        if let Some(coin) = coin {
831            params["coin"] = json!(coin);
832        }
833        if let Some(with_bonus) = with_bonus {
834            params["withBonus"] = json!(with_bonus);
835        }
836
837        let response = self.client.get(endpoint, params, SecType::Signed).await?;
838        Ok(response)
839    }
840
841    /// Set deposit account
842    ///
843    /// API: POST /v5/asset/transfer/save-transfer-sub-member
844    /// https://bybit-exchange.github.io/docs/v5/asset/set-deposit-account
845    pub async fn save_transfer_sub_member(
846        &self,
847        coin: Vec<String>,
848        member_ids: Vec<String>,
849    ) -> Result<ServerResponse<serde_json::Value>> {
850        let endpoint = "v5/asset/transfer/save-transfer-sub-member";
851        let body = json!({
852            "coin": coin,
853            "memberIds": member_ids,
854        });
855
856        let response = self.client.post(endpoint, body, SecType::Signed).await?;
857        Ok(response)
858    }
859}
860
861#[cfg(test)]
862mod tests {
863    use super::*;
864    use crate::rest::ApiKeyPair;
865
866    fn create_test_client() -> AssetClient {
867        let api_key_pair = ApiKeyPair::new(
868            "test".to_string(),
869            "test_key".to_string(),
870            "test_secret".to_string(),
871        );
872        let rest_client =
873            RestClient::new(api_key_pair, "https://api-testnet.bybit.com".to_string());
874        AssetClient::new(rest_client)
875    }
876
877    #[test]
878    fn test_asset_client_creation() {
879        let _client = create_test_client();
880    }
881
882    #[tokio::test]
883    async fn test_exchange_order_record_params() {
884        let from_coin = Some("BTC");
885        let to_coin = Some("USDT");
886        let limit = Some(50);
887        let cursor: Option<&str> = None;
888
889        assert_eq!(from_coin, Some("BTC"));
890        assert_eq!(to_coin, Some("USDT"));
891        assert_eq!(limit, Some(50));
892        assert!(cursor.is_none());
893    }
894
895    #[tokio::test]
896    async fn test_withdrawal_params() {
897        let coin = "BTC";
898        let chain = "BTC";
899        let address = "bc1qtest123456789";
900        let tag: Option<&str> = None;
901        let amount = "0.001";
902        let timestamp = 1234567890i64;
903        let for_ce_chain: Option<i32> = None;
904        let account_type = Some("UNIFIED");
905
906        assert_eq!(coin, "BTC");
907        assert_eq!(chain, "BTC");
908        assert_eq!(address, "bc1qtest123456789");
909        assert!(tag.is_none());
910        assert_eq!(amount, "0.001");
911        assert_eq!(timestamp, 1234567890);
912        assert!(for_ce_chain.is_none());
913        assert_eq!(account_type, Some("UNIFIED"));
914    }
915
916    #[tokio::test]
917    async fn test_internal_transfer_params() {
918        let transfer_id = "transfer123";
919        let coin = "USDT";
920        let amount = "100";
921        let from_account_type = "UNIFIED";
922        let to_account_type = "CONTRACT";
923
924        assert_eq!(transfer_id, "transfer123");
925        assert_eq!(coin, "USDT");
926        assert_eq!(amount, "100");
927        assert_eq!(from_account_type, "UNIFIED");
928        assert_eq!(to_account_type, "CONTRACT");
929    }
930
931    #[tokio::test]
932    async fn test_universal_transfer_params() {
933        let transfer_id = "transfer456";
934        let coin = "BTC";
935        let amount = "0.5";
936        let from_member_id = "member1";
937        let to_member_id = "member2";
938        let from_account_type = "UNIFIED";
939        let to_account_type = "SPOT";
940
941        assert_eq!(transfer_id, "transfer456");
942        assert_eq!(coin, "BTC");
943        assert_eq!(amount, "0.5");
944        assert_eq!(from_member_id, "member1");
945        assert_eq!(to_member_id, "member2");
946        assert_eq!(from_account_type, "UNIFIED");
947        assert_eq!(to_account_type, "SPOT");
948    }
949
950    #[tokio::test]
951    async fn test_convert_quote_params() {
952        let from_coin = "BTC";
953        let to_coin = "USDT";
954        let from_coin_type: Option<&str> = None;
955        let to_coin_type: Option<&str> = None;
956        let request_coin = "BTC";
957        let request_amount = "0.1";
958        let account_type = "UNIFIED";
959        let request_id = Some("req123");
960
961        assert_eq!(from_coin, "BTC");
962        assert_eq!(to_coin, "USDT");
963        assert!(from_coin_type.is_none());
964        assert!(to_coin_type.is_none());
965        assert_eq!(request_coin, "BTC");
966        assert_eq!(request_amount, "0.1");
967        assert_eq!(account_type, "UNIFIED");
968        assert_eq!(request_id, Some("req123"));
969    }
970
971    #[tokio::test]
972    async fn test_deposit_records_params() {
973        let coin = Some("ETH");
974        let start_time = Some(1234567890i64);
975        let end_time = Some(1234567999i64);
976        let limit = Some(100);
977        let cursor: Option<&str> = None;
978
979        assert_eq!(coin, Some("ETH"));
980        assert_eq!(start_time, Some(1234567890));
981        assert_eq!(end_time, Some(1234567999));
982        assert_eq!(limit, Some(100));
983        assert!(cursor.is_none());
984    }
985
986    #[tokio::test]
987    async fn test_query_account_coin_balance_params() {
988        let member_id = Some("member123");
989        let to_member_id: Option<&str> = None;
990        let account_type = "UNIFIED";
991        let to_account_type: Option<&str> = None;
992        let coin = "USDT";
993        let with_bonus = Some(1);
994        let with_transfer_safe_amount = Some(1);
995        let with_ltv_transfer_safe_amount = Some(0);
996
997        assert_eq!(member_id, Some("member123"));
998        assert!(to_member_id.is_none());
999        assert_eq!(account_type, "UNIFIED");
1000        assert!(to_account_type.is_none());
1001        assert_eq!(coin, "USDT");
1002        assert_eq!(with_bonus, Some(1));
1003        assert_eq!(with_transfer_safe_amount, Some(1));
1004        assert_eq!(with_ltv_transfer_safe_amount, Some(0));
1005    }
1006
1007    #[tokio::test]
1008    async fn test_save_transfer_sub_member_params() {
1009        let coin = vec!["BTC".to_string(), "ETH".to_string()];
1010        let member_ids = vec!["member1".to_string(), "member2".to_string()];
1011
1012        assert_eq!(coin.len(), 2);
1013        assert_eq!(coin[0], "BTC");
1014        assert_eq!(coin[1], "ETH");
1015        assert_eq!(member_ids.len(), 2);
1016        assert_eq!(member_ids[0], "member1");
1017        assert_eq!(member_ids[1], "member2");
1018    }
1019}