tmp
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
use anyhow::{Error, Result};
|
||||
use anyhow::{anyhow, ensure, Context, Error, Result};
|
||||
use lnvps_db::async_trait;
|
||||
use log::info;
|
||||
use rocket::serde::Deserialize;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -9,7 +10,7 @@ use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Copy, JsonSchema)]
|
||||
pub enum Currency {
|
||||
EUR,
|
||||
BTC,
|
||||
@ -39,12 +40,12 @@ impl FromStr for Currency {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Ticker(Currency, Currency);
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Ticker(pub Currency, pub Currency);
|
||||
|
||||
impl Ticker {
|
||||
pub fn btc_rate(cur: &str) -> Result<Self> {
|
||||
let to_cur: Currency = cur.parse().map_err(|_| Error::msg(""))?;
|
||||
let to_cur: Currency = cur.parse().map_err(|_| anyhow!("Invalid currency"))?;
|
||||
Ok(Ticker(Currency::BTC, to_cur))
|
||||
}
|
||||
}
|
||||
@ -58,11 +59,43 @@ impl Display for Ticker {
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct TickerRate(pub Ticker, pub f32);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct CurrencyAmount(pub Currency, pub f32);
|
||||
|
||||
impl TickerRate {
|
||||
pub fn can_convert(&self, currency: Currency) -> bool {
|
||||
currency == self.0 .0 || currency == self.0 .1
|
||||
}
|
||||
|
||||
/// Convert from the source currency into the target currency
|
||||
pub fn convert(&self, source: CurrencyAmount) -> Result<CurrencyAmount> {
|
||||
ensure!(
|
||||
self.can_convert(source.0),
|
||||
"Cant convert, currency doesnt match"
|
||||
);
|
||||
if source.0 == self.0 .0 {
|
||||
Ok(CurrencyAmount(self.0 .1, source.1 * self.1))
|
||||
} else {
|
||||
Ok(CurrencyAmount(self.0 .0, source.1 / self.1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ExchangeRateService: Send + Sync {
|
||||
async fn fetch_rates(&self) -> Result<Vec<TickerRate>>;
|
||||
async fn set_rate(&self, ticker: Ticker, amount: f32);
|
||||
async fn get_rate(&self, ticker: Ticker) -> Option<f32>;
|
||||
async fn list_rates(&self) -> Result<Vec<TickerRate>>;
|
||||
}
|
||||
|
||||
/// Get alternative prices based on a source price
|
||||
pub fn alt_prices(rates: &Vec<TickerRate>, source: CurrencyAmount) -> Vec<CurrencyAmount> {
|
||||
// TODO: return all alt prices by cross-converting all currencies
|
||||
rates
|
||||
.iter()
|
||||
.filter_map(|r| r.convert(source).ok())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
@ -100,6 +133,11 @@ impl ExchangeRateService for DefaultRateCache {
|
||||
let cache = self.cache.read().await;
|
||||
cache.get(&ticker).cloned()
|
||||
}
|
||||
|
||||
async fn list_rates(&self) -> Result<Vec<TickerRate>> {
|
||||
let cache = self.cache.read().await;
|
||||
Ok(cache.iter().map(|(k, v)| TickerRate(*k, *v)).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -109,3 +147,27 @@ struct MempoolRates {
|
||||
#[serde(rename = "EUR")]
|
||||
pub eur: Option<f32>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const RATE: f32 = 95_000.0;
|
||||
#[test]
|
||||
fn convert() {
|
||||
let ticker = Ticker::btc_rate("EUR").unwrap();
|
||||
let f = TickerRate(ticker, RATE);
|
||||
|
||||
assert_eq!(
|
||||
f.convert(CurrencyAmount(Currency::EUR, 5.0)).unwrap(),
|
||||
CurrencyAmount(Currency::BTC, 5.0 / RATE)
|
||||
);
|
||||
assert_eq!(
|
||||
f.convert(CurrencyAmount(Currency::BTC, 0.001)).unwrap(),
|
||||
CurrencyAmount(Currency::EUR, RATE * 0.001)
|
||||
);
|
||||
assert!(!f.can_convert(Currency::USD));
|
||||
assert!(f.can_convert(Currency::EUR));
|
||||
assert!(f.can_convert(Currency::BTC));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user