binance-core 0.2.3

Core functionality including API request signing, HTTP client setup, and shared logic for Binance Spot and Futures.
Documentation
use binance_common::error::BinanceError;
use hmac::{Hmac, Mac};
use reqwest::Method;
use sha2::Sha256;

use crate::signer::signature::Signature;

pub struct HmacSha256<'a> {
    pub api_key: &'a str,
    secret_key: &'a str,
}

impl<'a> HmacSha256<'a> {
    pub fn new(api_key: &'a str, secret_key: &'a str) -> HmacSha256<'a> {
        HmacSha256 {
            api_key,
            secret_key,
        }
    }
}

impl<'a> Signature<'a> for HmacSha256<'a> {
    fn build_blocking_request(
        &self,
        client: &reqwest::blocking::Client,
        host: &str,
        path: &str,
        params: &str,
        method: Method,
    ) -> Result<reqwest::blocking::RequestBuilder, BinanceError> {
        let url = self.sign(host, path, params)?;

        match method {
            Method::DELETE => Ok(client.delete(url).header("X-MBX-APIKEY", self.api_key)),
            Method::GET => Ok(client.get(url).header("X-MBX-APIKEY", self.api_key)),
            Method::POST => Ok(client.post(url).header("X-MBX-APIKEY", self.api_key)),
            _ => Err(BinanceError::Unknown(
                "Invalid method to send the reuqest!".to_string(),
            )),
        }
    }

    fn build_request(
        &self,
        client: &reqwest::Client,
        host: &str,
        path: &str,
        params: &str,
        method: Method,
    ) -> Result<reqwest::RequestBuilder, BinanceError> {
        let url = self.sign(host, path, params)?;

        match method {
            Method::DELETE => Ok(client.delete(url).header("X-MBX-APIKEY", self.api_key)),
            Method::GET => Ok(client.get(url).header("X-MBX-APIKEY", self.api_key)),
            Method::POST => Ok(client.post(url).header("X-MBX-APIKEY", self.api_key)),
            _ => Err(BinanceError::Unknown(
                "Invalid method to send the reuqest!".to_string(),
            )),
        }
    }

    fn sign(&self, host: &str, path: &str, params: &str) -> Result<String, BinanceError> {
        let mut hasher = Hmac::<Sha256>::new_from_slice(self.secret_key.as_bytes())?;
        let params = self.add_timestamp(params);

        hasher.update(params.as_bytes());

        let signature = hex::encode(hasher.finalize().into_bytes());
        let endpoint = format!("{}&signature={}", params, signature);

        Ok(format!("{}{}{}", host, path, endpoint))
    }
}