Skip to content

Commit ff6f384

Browse files
committed
add rsn_xag oracle option
- add ergodex as datasource
1 parent 1c3cb36 commit ff6f384

File tree

8 files changed

+187
-15
lines changed

8 files changed

+187
-15
lines changed

core/src/datapoint_source.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ mod coingecko;
88
mod custom_ext_script;
99
mod erg_btc;
1010
mod erg_usd;
11+
mod erg_xag;
1112
mod erg_xau;
13+
mod ergodex;
1214
mod predef;
13-
mod erg_xag;
15+
mod rsn_xag;
1416

1517
use crate::oracle_types::Rate;
1618
use crate::pool_config::PredefinedDataPointSource;

core/src/datapoint_source/bitpanda.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use super::assets_exchange_rate::AssetsExchangeRate;
22
use super::assets_exchange_rate::Btc;
33
use super::assets_exchange_rate::Usd;
4-
use super::erg_xau::KgAu;
54
use super::erg_xag::KgAg;
5+
use super::erg_xau::KgAu;
66
use super::DataPointSourceError;
77

88
#[derive(Debug, Clone)]
@@ -139,13 +139,13 @@ mod tests {
139139
let pair: AssetsExchangeRate<KgAu, Usd> = tokio_test::block_on(get_kgau_usd()).unwrap();
140140
assert!(pair.rate > 0.0);
141141
}
142-
142+
143143
#[test]
144144
fn test_kgag_usd_price() {
145145
let pair: AssetsExchangeRate<KgAg, Usd> = tokio_test::block_on(get_kgag_usd()).unwrap();
146146
assert!(pair.rate > 0.0);
147147
}
148-
148+
149149
#[test]
150150
fn test_btc_usd_price() {
151151
let pair: AssetsExchangeRate<Btc, Usd> = tokio_test::block_on(get_btc_usd()).unwrap();

core/src/datapoint_source/coingecko.rs

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use crate::datapoint_source::assets_exchange_rate::AssetsExchangeRate;
2-
use crate::datapoint_source::assets_exchange_rate::NanoErg;
3-
use crate::datapoint_source::DataPointSourceError;
4-
51
use super::ada_usd::Lovelace;
62
use super::assets_exchange_rate::Btc;
73
use super::assets_exchange_rate::Usd;
8-
use super::erg_xau::KgAu;
94
use super::erg_xag::KgAg;
5+
use super::erg_xau::KgAu;
6+
use crate::datapoint_source::assets_exchange_rate::AssetsExchangeRate;
7+
use crate::datapoint_source::assets_exchange_rate::NanoErg;
8+
use crate::datapoint_source::rsn_xag::Rsn;
9+
use crate::datapoint_source::DataPointSourceError;
1010

1111
#[cfg(not(test))]
1212
pub async fn get_kgau_nanoerg() -> Result<AssetsExchangeRate<KgAu, NanoErg>, DataPointSourceError> {
@@ -180,6 +180,46 @@ pub async fn get_btc_nanoerg() -> Result<AssetsExchangeRate<Btc, NanoErg>, DataP
180180
Ok(rate)
181181
}
182182

183+
pub async fn get_kgag_rsn() -> Result<AssetsExchangeRate<KgAg, Rsn>, DataPointSourceError> {
184+
let url = "https://api.coingecko.com/api/v3/simple/price?ids=rosen-bridge&vs_currencies=XAG";
185+
let resp = reqwest::get(url).await?;
186+
let price_json = json::parse(&resp.text().await?)?;
187+
if let Some(p) = price_json["rosen-bridge"]["xag"].as_f64() {
188+
// Convert from price RSN/XAG
189+
let rsn_per_ag = KgAg::from_troy_ounce(1.0 / p);
190+
let rate = AssetsExchangeRate {
191+
per1: KgAg {},
192+
get: Rsn {},
193+
rate: rsn_per_ag,
194+
};
195+
Ok(rate)
196+
} else {
197+
Err(DataPointSourceError::JsonMissingField {
198+
field: "rsn.xag as f64".to_string(),
199+
json: price_json.dump(),
200+
})
201+
}
202+
}
203+
204+
pub async fn get_rsn_usd() -> Result<AssetsExchangeRate<Usd, Rsn>, DataPointSourceError> {
205+
let url = "https://api.coingecko.com/api/v3/simple/price?ids=rosen-bridge&vs_currencies=USD";
206+
let resp = reqwest::get(url).await?;
207+
let price_json = json::parse(&resp.text().await?)?;
208+
if let Some(p) = price_json["rosen-bridge"]["usd"].as_f64() {
209+
let rate = AssetsExchangeRate {
210+
per1: Usd {},
211+
get: Rsn {},
212+
rate: 1.0 / p,
213+
};
214+
Ok(rate)
215+
} else {
216+
Err(DataPointSourceError::JsonMissingField {
217+
field: "rsn.usd as f64".to_string(),
218+
json: price_json.dump(),
219+
})
220+
}
221+
}
222+
183223
#[cfg(test)]
184224
mod tests {
185225
use super::*;
@@ -190,10 +230,10 @@ mod tests {
190230
tokio_test::block_on(get_kgau_nanoerg()).unwrap();
191231
assert!(pair.rate > 0.0);
192232
}
193-
233+
194234
#[test]
195235
fn test_erg_xag_price() {
196-
let pair: AssetsExchangeRate<KgAg, NanoErg> =
236+
let pair: AssetsExchangeRate<KgAg, NanoErg> =
197237
tokio_test::block_on(get_kgag_nanoerg()).unwrap();
198238
assert!(pair.rate > 0.0);
199239
}
@@ -217,4 +257,16 @@ mod tests {
217257
tokio_test::block_on(get_btc_nanoerg()).unwrap();
218258
assert!(pair.rate > 0.0);
219259
}
260+
261+
#[test]
262+
fn test_rsn_xag_price() {
263+
let pair: AssetsExchangeRate<KgAg, Rsn> = tokio_test::block_on(get_kgag_rsn()).unwrap();
264+
assert!(pair.rate > 0.0);
265+
}
266+
267+
#[test]
268+
fn test_rsn_usd_price() {
269+
let pair: AssetsExchangeRate<Usd, Rsn> = tokio_test::block_on(get_rsn_usd()).unwrap();
270+
assert!(pair.rate > 0.0);
271+
}
220272
}

core/src/datapoint_source/erg_xag.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ use std::pin::Pin;
44

55
use futures::Future;
66

7-
use crate::datapoint_source::assets_exchange_rate::{convert_rate, Asset, AssetsExchangeRate, NanoErg};
8-
use crate::datapoint_source::{bitpanda, coingecko, DataPointSourceError};
97
use crate::datapoint_source::aggregator::fetch_aggregated;
8+
use crate::datapoint_source::assets_exchange_rate::{
9+
convert_rate, Asset, AssetsExchangeRate, NanoErg,
10+
};
1011
use crate::datapoint_source::erg_usd::nanoerg_usd_sources;
12+
use crate::datapoint_source::{bitpanda, coingecko, DataPointSourceError};
1113

1214
#[derive(Debug, Clone, Copy)]
1315
pub struct KgAg {}
@@ -25,15 +27,15 @@ impl KgAg {
2527
// troy ounces per kg
2628
oz * 32.150746568627
2729
}
28-
30+
2931
pub fn from_gram(g: f64) -> f64 {
3032
g * 1000.0
3133
}
3234
}
3335

3436
#[allow(clippy::type_complexity)]
3537
pub fn nanoerg_kgag_sources() -> Vec<
36-
Pin<Box<dyn Future<Output = Result<AssetsExchangeRate<KgAg, NanoErg>, DataPointSourceError>>>>,
38+
Pin<Box<dyn Future<Output = Result<AssetsExchangeRate<KgAg, NanoErg>, DataPointSourceError>>>>,
3739
> {
3840
vec![
3941
Box::pin(coingecko::get_kgag_nanoerg()),

core/src/datapoint_source/ergodex.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use crate::datapoint_source::assets_exchange_rate::{AssetsExchangeRate, NanoErg};
2+
use crate::datapoint_source::rsn_xag::Rsn;
3+
use crate::datapoint_source::DataPointSourceError;
4+
5+
pub async fn get_rsn_nanoerg() -> Result<AssetsExchangeRate<NanoErg, Rsn>, DataPointSourceError> {
6+
let url = "https://api.spectrum.fi/v1/amm/pool/1b694b15467c62f0cd4525e368dbdea2329c713aa200b73df4a622e950551b40/stats";
7+
let resp = reqwest::get(url).await?;
8+
let pool_json = json::parse(&resp.text().await?)?;
9+
let locked_erg = pool_json["lockedX"]["amount"].as_f64().ok_or_else(|| {
10+
DataPointSourceError::JsonMissingField {
11+
field: "lockedX.amount as f64".to_string(),
12+
json: pool_json.dump(),
13+
}
14+
})?;
15+
16+
let locked_rsn = pool_json["lockedY"]["amount"].as_f64().ok_or_else(|| {
17+
DataPointSourceError::JsonMissingField {
18+
field: "lockedY.amount as f64".to_string(),
19+
json: pool_json.dump(),
20+
}
21+
})?;
22+
let price = Rsn::from_rsn(Rsn::from_rsn(locked_rsn) / NanoErg::from_erg(locked_erg));
23+
let rate = AssetsExchangeRate {
24+
per1: NanoErg {},
25+
get: Rsn {},
26+
rate: price,
27+
};
28+
Ok(rate)
29+
}
30+
31+
#[cfg(test)]
32+
mod tests {
33+
use super::*;
34+
35+
#[test]
36+
fn test_rsn_nanoerg_price() {
37+
let pair: AssetsExchangeRate<NanoErg, Rsn> =
38+
tokio_test::block_on(get_rsn_nanoerg()).unwrap();
39+
assert!(pair.rate > 0.0);
40+
}
41+
}

core/src/datapoint_source/predef.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::datapoint_source::rsn_xag::rsn_kgag_sources;
12
use crate::oracle_types::Rate;
23

34
use super::ada_usd::usd_lovelace_sources;
@@ -35,6 +36,7 @@ async fn fetch_predef_source_aggregated(
3536
PredefinedDataPointSource::NanoErgBTC => {
3637
fetch_aggregated(nanoerg_btc_sources()).await?.rate
3738
}
39+
PredefinedDataPointSource::RsnXag => fetch_aggregated(rsn_kgag_sources()).await?.rate,
3840
};
3941
Ok((rate_float as i64).into())
4042
}

core/src/datapoint_source/rsn_xag.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use futures::Future;
2+
use std::pin::Pin;
3+
4+
use crate::datapoint_source::assets_exchange_rate::{convert_rate, Asset, AssetsExchangeRate};
5+
use crate::datapoint_source::erg_xag::KgAg;
6+
use crate::datapoint_source::{bitpanda, coingecko, ergodex, DataPointSourceError};
7+
8+
#[derive(Debug, Clone, Copy)]
9+
pub struct Rsn {}
10+
11+
impl Asset for Rsn {}
12+
13+
impl Rsn {
14+
pub fn from_rsn(rsn: f64) -> f64 {
15+
rsn * 1_000.0
16+
}
17+
}
18+
19+
#[allow(clippy::type_complexity)]
20+
pub fn rsn_kgag_sources(
21+
) -> Vec<Pin<Box<dyn Future<Output = Result<AssetsExchangeRate<KgAg, Rsn>, DataPointSourceError>>>>>
22+
{
23+
vec![
24+
Box::pin(coingecko::get_kgag_rsn()),
25+
Box::pin(get_rsn_kgag_erg()),
26+
Box::pin(get_rsn_kgag_usd()),
27+
]
28+
}
29+
30+
// Calculate RSN/KGAG through RSN/USD and KGAG/USD
31+
async fn get_rsn_kgag_usd() -> Result<AssetsExchangeRate<KgAg, Rsn>, DataPointSourceError> {
32+
Ok(convert_rate(
33+
coingecko::get_rsn_usd().await?,
34+
bitpanda::get_kgag_usd().await?,
35+
))
36+
}
37+
38+
// Calculate KGAG/RSN through KGAG/ERG and ERG/RSN
39+
async fn get_rsn_kgag_erg() -> Result<AssetsExchangeRate<KgAg, Rsn>, DataPointSourceError> {
40+
Ok(convert_rate(
41+
ergodex::get_rsn_nanoerg().await?,
42+
coingecko::get_kgag_nanoerg().await?,
43+
))
44+
}
45+
46+
#[cfg(test)]
47+
mod tests {
48+
use super::*;
49+
50+
#[test]
51+
fn test_kgag_rsn_combined() {
52+
let combined = tokio_test::block_on(get_rsn_kgag_usd()).unwrap();
53+
let coingecko = tokio_test::block_on(coingecko::get_kgag_rsn()).unwrap();
54+
let ergodex = tokio_test::block_on(get_rsn_kgag_erg()).unwrap();
55+
let deviation_from_coingecko = (combined.rate - coingecko.rate).abs() / coingecko.rate;
56+
assert!(
57+
deviation_from_coingecko < 0.05,
58+
"up to 5% deviation is allowed"
59+
);
60+
let ergodex_deviation_from_coingecko =
61+
(ergodex.rate - coingecko.rate).abs() / coingecko.rate;
62+
assert!(
63+
ergodex_deviation_from_coingecko < 0.05,
64+
"up to 5% deviation is allowed"
65+
);
66+
let deviation_from_ergodex = (ergodex.rate - combined.rate).abs() / combined.rate;
67+
assert!(
68+
deviation_from_ergodex < 0.05,
69+
"up to 5% deviation is allowed"
70+
);
71+
}
72+
}

core/src/pool_config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub enum PredefinedDataPointSource {
5959
NanoErgXag,
6060
NanoAdaUsd,
6161
NanoErgBTC,
62+
RsnXag,
6263
}
6364

6465
/// Holds the token ids of every important token used by the oracle pool.

0 commit comments

Comments
 (0)