use crate::rest::client::{RestClient, SecType, ServerResponse};
use crate::rest::BybitResult as Result;
use serde_json::json;
#[derive(Clone)]
pub struct CryptoLoanClient {
client: RestClient,
}
impl CryptoLoanClient {
pub fn new(client: RestClient) -> Self {
CryptoLoanClient { client }
}
pub async fn get_collateral_data(
&self,
ltv_type: Option<&str>,
) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/collateral-data";
let mut params = json!({});
if let Some(ltv_type) = ltv_type {
params["ltvType"] = json!(ltv_type);
}
let response = self.client.get(endpoint, params, SecType::Signed).await?;
Ok(response)
}
pub async fn borrow(
&self,
ltv_type: &str,
loan_currency: &str,
loan_amount: &str,
collateral_currency: &str,
max_rate: Option<&str>,
) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/borrow";
let mut body = json!({
"ltvType": ltv_type,
"loanCurrency": loan_currency,
"loanAmount": loan_amount,
"collateralCurrency": collateral_currency,
});
if let Some(max_rate) = max_rate {
body["maxRate"] = json!(max_rate);
}
let response = self.client.post(endpoint, body, SecType::Signed).await?;
Ok(response)
}
pub async fn repay(
&self,
order_id: &str,
repay_amount: Option<&str>,
) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/repay";
let mut body = json!({
"orderId": order_id,
});
if let Some(repay_amount) = repay_amount {
body["repayAmount"] = json!(repay_amount);
}
let response = self.client.post(endpoint, body, SecType::Signed).await?;
Ok(response)
}
pub async fn get_ongoing_orders(
&self,
order_id: Option<&str>,
loan_currency: Option<&str>,
collateral_currency: Option<&str>,
limit: Option<i32>,
cursor: Option<&str>,
) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/ongoing-orders";
let mut params = json!({});
if let Some(order_id) = order_id {
params["orderId"] = json!(order_id);
}
if let Some(loan_currency) = loan_currency {
params["loanCurrency"] = json!(loan_currency);
}
if let Some(collateral_currency) = collateral_currency {
params["collateralCurrency"] = json!(collateral_currency);
}
if let Some(limit) = limit {
params["limit"] = json!(limit);
}
if let Some(cursor) = cursor {
params["cursor"] = json!(cursor);
}
let response = self.client.get(endpoint, params, SecType::Signed).await?;
Ok(response)
}
pub async fn get_borrow_history(
&self,
order_id: Option<&str>,
loan_currency: Option<&str>,
collateral_currency: Option<&str>,
start_time: Option<i64>,
end_time: Option<i64>,
limit: Option<i32>,
cursor: Option<&str>,
) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/borrow-history";
let mut params = json!({});
if let Some(order_id) = order_id {
params["orderId"] = json!(order_id);
}
if let Some(loan_currency) = loan_currency {
params["loanCurrency"] = json!(loan_currency);
}
if let Some(collateral_currency) = collateral_currency {
params["collateralCurrency"] = json!(collateral_currency);
}
if let Some(start_time) = start_time {
params["startTime"] = json!(start_time);
}
if let Some(end_time) = end_time {
params["endTime"] = json!(end_time);
}
if let Some(limit) = limit {
params["limit"] = json!(limit);
}
if let Some(cursor) = cursor {
params["cursor"] = json!(cursor);
}
let response = self.client.get(endpoint, params, SecType::Signed).await?;
Ok(response)
}
pub async fn get_max_collateral_amount(
&self,
ltv_type: &str,
loan_currency: &str,
loan_amount: &str,
collateral_currency: &str,
) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/max-collateral-amount";
let params = json!({
"ltvType": ltv_type,
"loanCurrency": loan_currency,
"loanAmount": loan_amount,
"collateralCurrency": collateral_currency,
});
let response = self.client.get(endpoint, params, SecType::Signed).await?;
Ok(response)
}
pub async fn adjust_ltv(
&self,
order_id: &str,
amount: &str,
direction: i32, ) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/adjust-ltv";
let body = json!({
"orderId": order_id,
"amount": amount,
"direction": direction,
});
let response = self.client.post(endpoint, body, SecType::Signed).await?;
Ok(response)
}
pub async fn get_adjustment_history(
&self,
order_id: Option<&str>,
adjustment_id: Option<&str>,
start_time: Option<i64>,
end_time: Option<i64>,
limit: Option<i32>,
cursor: Option<&str>,
) -> Result<ServerResponse<serde_json::Value>> {
let endpoint = "v5/crypto-loan/adjustment-history";
let mut params = json!({});
if let Some(order_id) = order_id {
params["orderId"] = json!(order_id);
}
if let Some(adjustment_id) = adjustment_id {
params["adjustmentId"] = json!(adjustment_id);
}
if let Some(start_time) = start_time {
params["startTime"] = json!(start_time);
}
if let Some(end_time) = end_time {
params["endTime"] = json!(end_time);
}
if let Some(limit) = limit {
params["limit"] = json!(limit);
}
if let Some(cursor) = cursor {
params["cursor"] = json!(cursor);
}
let response = self.client.get(endpoint, params, SecType::Signed).await?;
Ok(response)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::rest::ApiKeyPair;
fn create_test_client() -> CryptoLoanClient {
let api_key_pair = ApiKeyPair::new(
"test_key".to_string(),
"test_secret".to_string(),
"".to_string(),
);
let rest_client =
RestClient::new(api_key_pair, "https://api-testnet.bybit.com".to_string());
CryptoLoanClient::new(rest_client)
}
#[test]
fn test_client_creation() {
let client = create_test_client();
assert_eq!(
std::mem::size_of_val(&client),
std::mem::size_of::<CryptoLoanClient>()
);
}
#[tokio::test]
async fn test_borrow_required_params() {
let client = create_test_client();
let result = client
.borrow("1", "USDT", "1000.0", "BTC", Some("0.05"))
.await;
assert!(result.is_err() || result.is_ok());
}
#[tokio::test]
async fn test_repay_required_params() {
let client = create_test_client();
let result = client.repay("order_123", Some("500.0")).await;
assert!(result.is_err() || result.is_ok());
}
#[tokio::test]
async fn test_adjust_ltv_required_params() {
let client = create_test_client();
let result = client
.adjust_ltv(
"order_123",
"100.0",
1, )
.await;
assert!(result.is_err() || result.is_ok());
}
}