binance-core 0.2.3

Core functionality including API request signing, HTTP client setup, and shared logic for Binance Spot and Futures.
Documentation
use base64::Engine;
use binance_common::error::BinanceError;
use ed25519_dalek::{Signer, SigningKey, pkcs8::DecodePrivateKey};
use reqwest::Method;

pub struct Ed25519Dalek {
    api_key: String,
    signing_key: SigningKey,
}

impl Ed25519Dalek {
    pub fn new(api_key: String, signing_key: &str) -> Result<Ed25519Dalek, BinanceError> {
        Ok(Ed25519Dalek {
            api_key,
            signing_key: SigningKey::from_pkcs8_pem(signing_key).map_err(|_| {
                BinanceError::Unknown("Invalid private key pem for ed25519!".to_string())
            })?,
        })
    }
}

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

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

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

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

    fn sign(
        &self,
        host: &str,
        path: &str,
        params: &str,
    ) -> Result<String, binance_common::error::BinanceError> {
        let params = self.add_timestamp(params);
        let signature = self.signing_key.sign(params.as_bytes());
        let endpoint = format!(
            "{}&signature={}",
            params,
            base64::engine::general_purpose::STANDARD.encode(signature.to_bytes())
        );

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