mexc_rs/futures/
auth.rs

1use chrono::{DateTime, Utc};
2use hmac::digest::InvalidLength;
3use hmac::{Hmac, Mac};
4use sha2::Sha256;
5
6#[derive(Debug)]
7pub struct SignRequestParams<'a, T>
8where
9    T: serde::Serialize,
10{
11    pub time: DateTime<Utc>,
12    pub api_key: &'a str,
13    pub secret_key: &'a str,
14    pub params_kind: SignRequestParamsKind,
15    pub params: &'a T,
16}
17
18#[derive(Debug)]
19pub enum SignRequestParamsKind {
20    Query,
21    Body,
22}
23
24#[derive(Debug)]
25pub struct SignRequestOutput {
26    pub signature: String,
27}
28
29#[derive(Debug, thiserror::Error)]
30pub enum SignRequestError {
31    #[error("Serde url encoded error: {0}")]
32    SerdeUrlEncoded(#[from] serde_urlencoded::ser::Error),
33
34    #[error("Serde json error: {0}")]
35    SerdeJson(#[from] serde_json::Error),
36
37    #[error("Secret key has invalid length for hmac sha 265")]
38    SecretKeyInvalidLength(#[from] InvalidLength),
39}
40
41pub fn sign_request<T>(
42    params: SignRequestParams<'_, T>,
43) -> Result<SignRequestOutput, SignRequestError>
44where
45    T: serde::Serialize,
46{
47    let data_string = match params.params_kind {
48        SignRequestParamsKind::Query => serde_urlencoded::to_string(params.params)?,
49        SignRequestParamsKind::Body => serde_json::to_string(params.params)?,
50    };
51    let mut mac = Hmac::<Sha256>::new_from_slice(params.secret_key.as_bytes())?;
52
53    let string_to_sign = format!(
54        "{}{}{}",
55        params.api_key,
56        params.time.timestamp_millis(),
57        data_string
58    );
59
60    mac.update(string_to_sign.as_bytes());
61    let mac_result = mac.finalize();
62    let mac_bytes = mac_result.into_bytes();
63    let signature = hex::encode(mac_bytes);
64
65    Ok(SignRequestOutput { signature })
66}