binance-api 0.1.0

Yet another async Binance API
Documentation
//! All endpoints for HTTP requests.
pub(crate) use reqwest::Method as HttpVerb;

/// Fully describes the HTTP endpoint:
///
/// - path;
/// - HTTP method (verb);
/// - weight (how much API limits will be affected by the query);
/// - additional security to access the endpoint.
pub trait Endpoint {
    /// The HTTP path for the given request.
    fn as_endpoint(&self) -> String;

    /// HTTP method (verb) used to access the endpoint. The most common are:
    ///
    /// - GET
    /// - POST
    /// - PUT
    /// - DELETE
    fn http_verb(&self) -> HttpVerb;

    /// The API weight regarding [IP limits](https://binance-docs.github.io/apidocs/spot/en/#ip-limits)
    /// for the given request.
    ///
    /// Endpoints share the 1200 per minute limit based on IP.
    ///
    /// Responses contain the header `X-MBX-USED-WEIGHT-(intervalNum)(intervalLetter)`,
    /// defining the weight used by the current IP.
    fn ip_weight(&self) -> Option<u16>;

    /// The API weight regarding [UID (account) limits](https://binance-docs.github.io/apidocs/spot/en/#order-rate-limits)
    /// for the given request.
    ///
    /// The order rate limit is counted against each account.
    ///
    /// Successful order responses contain the header `X-MBX-ORDER-COUNT-(intervalNum)(intervalLetter)`,
    /// defining the order limit used by the UID.
    ///
    /// To monitor order count usage, refer to `GET api/v3/rateLimit/order`.
    fn order_weight(&self) -> Option<u16>;

    /// Determines access to the endpoint.
    fn security_type(&self) -> SecurityType;
}

#[derive(Debug, Copy, Clone)]
/// Each endpoint has a security type that determines how you will interact with it.
///
/// - API-keys are passed into the Rest API via the `X-MBX-APIKEY` header.
/// - API-keys and secret-keys are case sensitive.
/// - API-keys can be configured to only access certain types of secure endpoints.
///   For example, one API-key could be used for [TRADE][Self::Trade] only,
///   while another API-key can access everything except for [TRADE][Self::Trade] routes.
/// - By default, API-keys can access all secure routes.
///
/// More on it: <https://binance-docs.github.io/apidocs/spot/en/#endpoint-security-type>
pub enum SecurityType {
    /// Those endpoints include:
    ///
    /// - general info about exchange;
    /// - recent market data.
    ///
    /// Endpoints can be accessed freely.
    ///
    /// Usually accessed via the `GET` (idempotent and not able to change server state).
    ///
    /// Those endpoints can be found at:
    ///
    /// - [spot](https://binance-docs.github.io/apidocs/spot/en/#market-data-endpoints);
    /// - [futures](https://binance-docs.github.io/apidocs/futures/en/#market-data-endpoints).
    None,

    /// Query of historical market data.
    ///
    /// Can be accessed with the API-key.
    ///
    /// Usually accessed via the `GET` (idempotent and not able to change server state).
    MarketData,

    /// Management of Websocket streams to receive any account updates.
    ///
    /// Those endpoints can be found at:
    ///
    /// - [spot and margin](https://binance-docs.github.io/apidocs/spot/en/#user-data-streams);
    /// - [futures](https://binance-docs.github.io/apidocs/futures/en/#user-data-streams).
    UserStream,

    /// The endpoints changing the actual trading status of an account:
    ///
    /// - placing a new order (usually `POST`);
    /// - cancelling an active order (usually `DELETE`);
    /// - requesting the order count usage (usually `GET`).
    ///
    /// Can only be accessed with the API-key and signed with the secret key.
    ///
    /// Those endpoints can be found at:
    ///
    /// - [spot](https://binance-docs.github.io/apidocs/spot/en/#spot-account-trade);
    /// - [futures](https://binance-docs.github.io/apidocs/futures/en/#account-trades-endpoints);
    /// - [margin](https://binance-docs.github.io/apidocs/spot/en/#margin-account-trade).
    Trade,

    /// Query User data.
    ///
    /// Can only be accessed with the API-key and signed with the secret key.
    ///
    /// Usually accessed via the `GET` (idempotent and not able to change server state).
    ///
    /// Those endpoints can be found at:
    ///
    /// - [spot](https://binance-docs.github.io/apidocs/spot/en/#spot-account-trade);
    /// - [futures](https://binance-docs.github.io/apidocs/futures/en/#account-trades-endpoints);
    /// - [margin](https://binance-docs.github.io/apidocs/spot/en/#margin-account-trade).
    UserData,

    /// Account action associated with transferring of funds on Margin trading.
    ///
    /// Can only be accessed with the API-key and signed with the secret key.
    ///
    /// Those endpoints can be found at:
    /// - [margin](https://binance-docs.github.io/apidocs/spot/en/#margin-account-trade).
    Margin,
}

impl SecurityType {
    /// Endpoint requires sending a valid API-Key.
    pub fn is_key_required(self) -> bool {
        match self {
            Self::None => false,
            Self::MarketData | Self::UserStream | Self::Trade | Self::UserData | Self::Margin => {
                true
            }
        }
    }

    /// Endpoint requires sending a valid API-Key and signature.
    ///
    /// - Signed endpoints require an additional parameter, `signature`,
    ///   to be sent in the query string or request body.
    /// - Endpoints use HMAC SHA256 signatures. The HMAC SHA256 signature is a keyed HMAC SHA256 operation.
    /// - Use your `secretKey` as the key and `totalParams` as the value for the HMAC operation.
    /// - The signature is **not case sensitive**.
    /// - `totalParams` is defined as the query string concatenated with the request body.
    ///
    /// ### Timing security
    ///
    /// - A signed endpoint also requires a parameter, `timestamp`,
    ///   to be sent which should be the millisecond timestamp of when
    ///   the request was created and sent.
    /// - An additional parameter, `recvWindow`, may be sent to specify the number of milliseconds
    ///   after timestamp the request is valid for. If `recvWindow` is not sent, it defaults to 5000.
    ///
    ///   The logic is as follows:
    ///
    ///   ```no-compile
    ///   if timestamp < (server_time + 1000) &&
    ///     (server_time - timestamp) <= recv_window {
    ///     // process request
    ///   }
    ///   else {
    ///     // reject request
    ///   }
    ///   ```
    ///
    /// **Serious trading is about timing.** Networks can be unstable and unreliable,
    /// which can lead to requests taking varying amounts of time to reach the servers.
    /// With `recvWindow`, you can specify that the request must be processed within
    /// a certain number of milliseconds or be rejected by the server.
    /// It is recommended to use a small `recvWindow` of `5000` or less!
    /// The max cannot go beyond `60,000`!
    pub fn is_signature_required(self) -> bool {
        match self {
            Self::None => false,
            Self::MarketData | Self::UserStream => false,
            Self::Trade | Self::UserData | Self::Margin => true,
        }
    }

    pub fn http_method_hint(self) -> Option<HttpVerb> {
        match self {
            // idempotent and not able to change server state
            Self::None | Self::MarketData | Self::UserData => Some(HttpVerb::GET),
            Self::UserStream | Self::Trade | Self::Margin => None,
        }
    }
}