bybit_rust_api/rest/asset/
asset_client.rs

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