Skip to content

Commit 1c3cb36

Browse files
committed
add erg_xag oracle option
1 parent fd70a4a commit 1c3cb36

File tree

6 files changed

+163
-1
lines changed

6 files changed

+163
-1
lines changed

core/src/datapoint_source.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod erg_btc;
1010
mod erg_usd;
1111
mod erg_xau;
1212
mod predef;
13+
mod erg_xag;
1314

1415
use crate::oracle_types::Rate;
1516
use crate::pool_config::PredefinedDataPointSource;

core/src/datapoint_source/bitpanda.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::assets_exchange_rate::AssetsExchangeRate;
22
use super::assets_exchange_rate::Btc;
33
use super::assets_exchange_rate::Usd;
44
use super::erg_xau::KgAu;
5+
use super::erg_xag::KgAg;
56
use super::DataPointSourceError;
67

78
#[derive(Debug, Clone)]
@@ -48,6 +49,47 @@ pub async fn get_kgau_usd() -> Result<AssetsExchangeRate<KgAu, Usd>, DataPointSo
4849
Ok(rate)
4950
}
5051

52+
#[cfg(not(test))]
53+
pub async fn get_kgag_usd() -> Result<AssetsExchangeRate<KgAg, Usd>, DataPointSourceError> {
54+
let url = "https://api.bitpanda.com/v1/ticker";
55+
let resp = reqwest::get(url).await?;
56+
let json = json::parse(&resp.text().await?)?;
57+
if let Some(p) = json["XAG"]["USD"].as_str() {
58+
// USD price of 1 gram of silver
59+
let p_float = p
60+
.parse::<f64>()
61+
.map_err(|_| DataPointSourceError::JsonMissingField {
62+
field: "XAG.USD as f64".to_string(),
63+
json: json.dump(),
64+
})?;
65+
let usd_per_kgag = KgAg::from_gram(p_float);
66+
let rate = AssetsExchangeRate {
67+
per1: KgAg {},
68+
get: Usd {},
69+
rate: usd_per_kgag,
70+
};
71+
Ok(rate)
72+
} else {
73+
Err(DataPointSourceError::JsonMissingField {
74+
field: "XAG.USD".to_string(),
75+
json: json.dump(),
76+
})
77+
}
78+
}
79+
80+
#[cfg(test)]
81+
pub async fn get_kgag_usd() -> Result<AssetsExchangeRate<KgAg, Usd>, DataPointSourceError> {
82+
// USD price of 1 gram of silver
83+
let p_float = 0.765;
84+
let usd_per_kgag = KgAg::from_gram(p_float);
85+
let rate = AssetsExchangeRate {
86+
per1: KgAg {},
87+
get: Usd {},
88+
rate: usd_per_kgag,
89+
};
90+
Ok(rate)
91+
}
92+
5193
#[cfg(not(test))]
5294
// Get USD/BTC. Can be used as a redundant source for ERG/BTC through ERG/USD and USD/BTC
5395
pub(crate) async fn get_btc_usd() -> Result<AssetsExchangeRate<Btc, Usd>, DataPointSourceError> {
@@ -97,6 +139,13 @@ mod tests {
97139
let pair: AssetsExchangeRate<KgAu, Usd> = tokio_test::block_on(get_kgau_usd()).unwrap();
98140
assert!(pair.rate > 0.0);
99141
}
142+
143+
#[test]
144+
fn test_kgag_usd_price() {
145+
let pair: AssetsExchangeRate<KgAg, Usd> = tokio_test::block_on(get_kgag_usd()).unwrap();
146+
assert!(pair.rate > 0.0);
147+
}
148+
100149
#[test]
101150
fn test_btc_usd_price() {
102151
let pair: AssetsExchangeRate<Btc, Usd> = tokio_test::block_on(get_btc_usd()).unwrap();

core/src/datapoint_source/coingecko.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::ada_usd::Lovelace;
66
use super::assets_exchange_rate::Btc;
77
use super::assets_exchange_rate::Usd;
88
use super::erg_xau::KgAu;
9+
use super::erg_xag::KgAg;
910

1011
#[cfg(not(test))]
1112
pub async fn get_kgau_nanoerg() -> Result<AssetsExchangeRate<KgAu, NanoErg>, DataPointSourceError> {
@@ -32,7 +33,7 @@ pub async fn get_kgau_nanoerg() -> Result<AssetsExchangeRate<KgAu, NanoErg>, Dat
3233

3334
#[cfg(test)]
3435
pub async fn get_kgau_nanoerg() -> Result<AssetsExchangeRate<KgAu, NanoErg>, DataPointSourceError> {
35-
let nanoerg_per_troy_ounce = NanoErg::from_erg(1.0 / 0.0008162);
36+
let nanoerg_per_troy_ounce = NanoErg::from_erg(1.0 / 0.0482);
3637
let nanoerg_per_kg = KgAu::from_troy_ounce(nanoerg_per_troy_ounce);
3738
let rate = AssetsExchangeRate {
3839
per1: KgAu {},
@@ -42,6 +43,41 @@ pub async fn get_kgau_nanoerg() -> Result<AssetsExchangeRate<KgAu, NanoErg>, Dat
4243
Ok(rate)
4344
}
4445

46+
#[cfg(not(test))]
47+
pub async fn get_kgag_nanoerg() -> Result<AssetsExchangeRate<KgAg, NanoErg>, DataPointSourceError> {
48+
let url = "https://api.coingecko.com/api/v3/simple/price?ids=ergo&vs_currencies=XAG";
49+
let resp = reqwest::get(url).await?;
50+
let price_json = json::parse(&resp.text().await?)?;
51+
if let Some(p) = price_json["ergo"]["xag"].as_f64() {
52+
// Convert from price Erg/XAG to nanoErgs per 1 XAG
53+
let nanoerg_per_troy_ounce = NanoErg::from_erg(1.0 / p);
54+
let nanoerg_per_kg = KgAg::from_troy_ounce(nanoerg_per_troy_ounce);
55+
let rate = AssetsExchangeRate {
56+
per1: KgAg {},
57+
get: NanoErg {},
58+
rate: nanoerg_per_kg,
59+
};
60+
Ok(rate)
61+
} else {
62+
Err(DataPointSourceError::JsonMissingField {
63+
field: "ergo.xag as f64".to_string(),
64+
json: price_json.dump(),
65+
})
66+
}
67+
}
68+
69+
#[cfg(test)]
70+
pub async fn get_kgag_nanoerg() -> Result<AssetsExchangeRate<KgAg, NanoErg>, DataPointSourceError> {
71+
let nanoerg_per_troy_ounce = NanoErg::from_erg(1.0 / 0.0706);
72+
let nanoerg_per_kg = KgAg::from_troy_ounce(nanoerg_per_troy_ounce);
73+
let rate = AssetsExchangeRate {
74+
per1: KgAg {},
75+
get: NanoErg {},
76+
rate: nanoerg_per_kg,
77+
};
78+
Ok(rate)
79+
}
80+
4581
#[cfg(not(test))]
4682
pub async fn get_usd_nanoerg() -> Result<AssetsExchangeRate<Usd, NanoErg>, DataPointSourceError> {
4783
let url = "https://api.coingecko.com/api/v3/simple/price?ids=ergo&vs_currencies=USD";
@@ -154,6 +190,13 @@ mod tests {
154190
tokio_test::block_on(get_kgau_nanoerg()).unwrap();
155191
assert!(pair.rate > 0.0);
156192
}
193+
194+
#[test]
195+
fn test_erg_xag_price() {
196+
let pair: AssetsExchangeRate<KgAg, NanoErg> =
197+
tokio_test::block_on(get_kgag_nanoerg()).unwrap();
198+
assert!(pair.rate > 0.0);
199+
}
157200

158201
#[test]
159202
fn test_erg_usd_price() {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! Obtains the nanoErg per 1 XAG (troy ounce of silver) rate
2+
3+
use std::pin::Pin;
4+
5+
use futures::Future;
6+
7+
use crate::datapoint_source::assets_exchange_rate::{convert_rate, Asset, AssetsExchangeRate, NanoErg};
8+
use crate::datapoint_source::{bitpanda, coingecko, DataPointSourceError};
9+
use crate::datapoint_source::aggregator::fetch_aggregated;
10+
use crate::datapoint_source::erg_usd::nanoerg_usd_sources;
11+
12+
#[derive(Debug, Clone, Copy)]
13+
pub struct KgAg {}
14+
15+
#[derive(Debug, Clone, Copy)]
16+
pub struct Xag {}
17+
18+
impl Asset for KgAg {}
19+
20+
impl Asset for Xag {}
21+
22+
impl KgAg {
23+
pub fn from_troy_ounce(oz: f64) -> f64 {
24+
// https://en.wikipedia.org/wiki/Gold_bar
25+
// troy ounces per kg
26+
oz * 32.150746568627
27+
}
28+
29+
pub fn from_gram(g: f64) -> f64 {
30+
g * 1000.0
31+
}
32+
}
33+
34+
#[allow(clippy::type_complexity)]
35+
pub fn nanoerg_kgag_sources() -> Vec<
36+
Pin<Box<dyn Future<Output = Result<AssetsExchangeRate<KgAg, NanoErg>, DataPointSourceError>>>>,
37+
> {
38+
vec![
39+
Box::pin(coingecko::get_kgag_nanoerg()),
40+
Box::pin(combined_kgag_nanoerg()),
41+
]
42+
}
43+
44+
pub async fn combined_kgag_nanoerg(
45+
) -> Result<AssetsExchangeRate<KgAg, NanoErg>, DataPointSourceError> {
46+
let kgag_usd_rate = bitpanda::get_kgag_usd().await?;
47+
let aggregated_usd_nanoerg_rate = fetch_aggregated(nanoerg_usd_sources()).await?;
48+
Ok(convert_rate(aggregated_usd_nanoerg_rate, kgag_usd_rate))
49+
}
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use super::*;
54+
55+
#[test]
56+
fn test_kgag_nanoerg_combined() {
57+
let combined = tokio_test::block_on(combined_kgag_nanoerg()).unwrap();
58+
let coingecko = tokio_test::block_on(coingecko::get_kgag_nanoerg()).unwrap();
59+
let deviation_from_coingecko = (combined.rate - coingecko.rate).abs() / coingecko.rate;
60+
assert!(
61+
deviation_from_coingecko < 0.05,
62+
"up to 5% deviation is allowed"
63+
);
64+
}
65+
}

core/src/datapoint_source/predef.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ async fn fetch_predef_source_aggregated(
2626
PredefinedDataPointSource::NanoErgXau => {
2727
fetch_aggregated(nanoerg_kgau_sources()).await?.rate
2828
}
29+
PredefinedDataPointSource::NanoErgXag => {
30+
fetch_aggregated(nanoerg_kgau_sources()).await?.rate
31+
}
2932
PredefinedDataPointSource::NanoAdaUsd => {
3033
fetch_aggregated(usd_lovelace_sources()).await?.rate
3134
}

core/src/pool_config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub struct PoolConfig {
5656
pub enum PredefinedDataPointSource {
5757
NanoErgUsd,
5858
NanoErgXau,
59+
NanoErgXag,
5960
NanoAdaUsd,
6061
NanoErgBTC,
6162
}

0 commit comments

Comments
 (0)