bitski-provider 0.3.1

Bitski Web3 provider
Documentation
use crate::access_token_providers::AccessTokenProvider;
use crate::USER_AGENT;
use bitski_chain_models::networks::Network;
use ethers::prelude::*;
use reqwest::header::HeaderValue;
use reqwest::Client;
use reqwest::{header, Url};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::fmt::Debug;
use std::sync::Arc;

#[derive(Clone, Debug)]
pub struct AuthenticatedEthersProvider {
    pub network: Network,
    pub client_id: String,
    pub auth_token_provider: Arc<dyn AccessTokenProvider + Sync + Send>,
}

impl AuthenticatedEthersProvider {
    pub fn new(
        network: Network,
        client_id: &dyn ToString,
        auth_token_provider: Arc<dyn AccessTokenProvider + Sync + Send>,
    ) -> Self {
        AuthenticatedEthersProvider {
            network,
            client_id: client_id.to_string(),
            auth_token_provider,
        }
    }

    async fn send<I: Debug + Serialize + Send + Sync, T: DeserializeOwned + Send>(
        &self,
        method: &str,
        params: I,
    ) -> Result<T, HttpClientError> {
        let access_token = self
            .auth_token_provider
            .get_access_token()
            .await
            .map_err(|error| {
                HttpClientError::JsonRpcError(JsonRpcError {
                    code: 403,
                    message: format!("{error}"),
                    data: None,
                })
            })?;
        self.send_with_auth(method, params, access_token).await
    }

    async fn send_with_auth<I: Debug + Serialize + Send + Sync, T: DeserializeOwned + Send>(
        &self,
        method: &str,
        params: I,
        token: String,
    ) -> Result<T, HttpClientError> {
        let auth_header_value = format!("Bearer {}", token).parse().map_err(|error| {
            HttpClientError::JsonRpcError(JsonRpcError {
                code: 403,
                message: format!("{error}"),
                data: None,
            })
        })?;

        let mut headers = header::HeaderMap::new();
        headers.insert(header::AUTHORIZATION, auth_header_value);
        headers.insert("X-API-Key", HeaderValue::from_str(&self.client_id).unwrap());
        headers.insert(
            header::USER_AGENT,
            HeaderValue::from_str(&USER_AGENT).unwrap(),
        );

        let client = Client::builder()
            .default_headers(headers)
            .build()
            .map_err(|error| {
                HttpClientError::JsonRpcError(JsonRpcError {
                    code: 500,
                    message: format!("{error}"),
                    data: None,
                })
            })?;

        let url: Url = self
            .network
            .rpc_url
            .parse()
            .expect("Failed to parse RPC URL");

        let transport = Http::new_with_client(url, client);
        JsonRpcClient::request(&transport, method, params).await
    }
}

#[async_trait::async_trait]
impl JsonRpcClient for AuthenticatedEthersProvider {
    type Error = HttpClientError;

    async fn request<T: Debug + Serialize + Send + Sync, R: DeserializeOwned + Send>(
        &self,
        method: &str,
        params: T,
    ) -> Result<R, HttpClientError> {
        self.send(method, params).await
    }
}