use crate::{
Asset, Capability, Chain, Complete, Detail, Error, History, Protocol, Reading, Source,
Timestamp, Wallet,
};
use async_trait::async_trait;
use std::sync::Arc;
#[async_trait]
pub trait Http: Send + Sync + 'static {
async fn post(
&self,
url: &str,
body: String,
headers: &[(&str, &str)],
) -> Result<String, Error>;
async fn get(&self, url: &str, headers: &[(&str, &str)]) -> Result<String, Error>;
}
#[async_trait]
pub trait ChainProvider: Send + Sync + 'static {
async fn call(&self, chain: Chain, method: &str, params: String) -> Result<String, Error>;
}
#[async_trait]
pub trait PriceSource: Send + Sync + 'static {
async fn price_usd(&self, chain: Chain, asset: Asset) -> Result<rust_decimal::Decimal, Error>;
async fn prices_usd(
&self,
chain: Chain,
assets: &[Asset],
) -> Vec<Result<rust_decimal::Decimal, Error>> {
let mut out = Vec::with_capacity(assets.len());
for asset in assets {
out.push(self.price_usd(chain, asset.clone()).await);
}
out
}
}
pub trait Clock: Send + Sync + 'static {
fn now(&self) -> Timestamp;
}
#[derive(Clone)]
pub struct Ctx {
pub http: Arc<dyn Http>,
pub rpc: Option<Arc<dyn ChainProvider>>,
pub clock: Arc<dyn Clock>,
}
impl Ctx {
pub fn new(http: Arc<dyn Http>, clock: Arc<dyn Clock>) -> Self {
Ctx {
http,
rpc: None,
clock,
}
}
pub fn with_rpc(mut self, rpc: Arc<dyn ChainProvider>) -> Self {
self.rpc = Some(rpc);
self
}
pub fn rpc(&self) -> Result<&Arc<dyn ChainProvider>, Error> {
self.rpc.as_ref().ok_or_else(|| Error::Permanent {
message: "this read needs an on-chain provider (RPC), but none was configured".into(),
})
}
}
#[async_trait]
pub trait ProtocolAdapter: Send + Sync + 'static {
fn protocol(&self) -> Protocol;
fn source(&self) -> Source;
fn capabilities(&self) -> &'static [Capability];
fn supported_chains(&self) -> &'static [Chain];
async fn read(
&self,
owner: &Wallet,
chain: Chain,
detail: Detail,
cx: &Ctx,
) -> Result<Complete<Reading>, Error>;
async fn read_history(
&self,
owner: &Wallet,
chain: Chain,
position: Option<&str>,
since: Option<Timestamp>,
cx: &Ctx,
) -> Result<Complete<History>, Error> {
let _ = (owner, chain, position, since, cx);
Err(Error::Unsupported {
protocol: self.protocol(),
capability: Capability::History,
backend: self.source(),
})
}
}