use ethers::{
core::k256::ecdsa::SigningKey,
middleware::SignerMiddleware,
providers::{Http, Provider},
signers::{LocalWallet, Signer, Wallet},
types::U256,
};
use reqwest::{
header::{HeaderMap, HeaderValue, ACCEPT, AUTHORIZATION, CONTENT_TYPE},
Client,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use url::Url;
mod account;
mod bindings;
mod collection;
mod constants;
mod errors;
mod execute;
pub mod types;
use constants::{
AVALANCHE_MAINNET_CHAIN_ID, DEFAULT_AVALANCHE_C_CHAIN_RPC_URL, HYPERSPACE_API_URL,
};
use errors::HyperspaceClientError;
type HyperspaceSignerMiddleware = SignerMiddleware<Provider<Http>, Wallet<SigningKey>>;
#[derive(Debug, Clone)]
pub struct HyperspaceClient {
http_client: Client,
signer: Arc<HyperspaceSignerMiddleware>,
}
impl HyperspaceClient {
pub fn new(
api_key: impl AsRef<str>,
private_key: impl AsRef<str>,
rpc_url: Option<impl AsRef<str>>,
) -> Result<Self, HyperspaceClientError> {
if api_key.as_ref().is_empty() {
return Err(HyperspaceClientError::InvalidApiKey);
}
if private_key.as_ref().is_empty() {
return Err(HyperspaceClientError::InvalidPrivateKey);
};
let rpc_url = match rpc_url {
Some(rpc_url) => match rpc_url.as_ref().is_empty() {
true => return Err(HyperspaceClientError::InvalidRpcUrl),
false => rpc_url.as_ref().to_string(),
},
None => DEFAULT_AVALANCHE_C_CHAIN_RPC_URL.to_string(),
};
if rpc_url.is_empty() {
return Err(HyperspaceClientError::InvalidRpcUrl);
};
let mut headers = HeaderMap::new();
headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
headers.insert(AUTHORIZATION, HeaderValue::from_str(api_key.as_ref())?);
let http_client = Client::builder().default_headers(headers).build()?;
let wallet = LocalWallet::from_bytes(&hex::decode(private_key.as_ref())?)?
.with_chain_id(AVALANCHE_MAINNET_CHAIN_ID);
let provider = Provider::new(Http::new(Url::parse(&rpc_url)?));
let signer = SignerMiddleware::new(provider, wallet);
Ok(Self {
http_client,
signer: Arc::new(signer),
})
}
async fn get<Q, R>(
&self,
endpoint: impl AsRef<str>,
params: Option<Q>,
) -> Result<R, HyperspaceClientError>
where
Q: Serialize,
R: for<'de> Deserialize<'de>,
{
self.http_client
.get(format!("{HYPERSPACE_API_URL}{}", endpoint.as_ref()))
.query(¶ms)
.send()
.await?
.json::<R>()
.await
.map_err(HyperspaceClientError::Reqwest)
}
async fn post<B, R>(
&self,
endpoint: impl AsRef<str>,
body: B,
) -> Result<R, HyperspaceClientError>
where
B: Serialize,
R: for<'de> Deserialize<'de>,
{
self.http_client
.post(format!("{HYPERSPACE_API_URL}{}", endpoint.as_ref()))
.json(&body)
.send()
.await?
.json::<R>()
.await
.map_err(HyperspaceClientError::Reqwest)
}
pub fn account(&self) -> account::Account {
account::Account(self)
}
pub fn collection(&self) -> collection::Collection {
collection::Collection(self)
}
pub fn execute(&self) -> execute::Execute {
execute::Execute(self)
}
}