sui_graphql_rpc/data/
apys.rs1use itertools::Itertools;
5use sui_types::sui_system_state::PoolTokenExchangeRate;
6
7pub(crate) fn calculate_apy(
15 stake_subsidy_start_epoch: u64,
16 rates: &[(u64, PoolTokenExchangeRate)],
17) -> f64 {
18 let exchange_rates = rates
20 .iter()
21 .filter_map(|(epoch, rate)| {
22 if epoch >= &stake_subsidy_start_epoch {
23 Some(rate)
24 } else {
25 None
26 }
27 })
28 .collect::<Vec<_>>();
29 let exchange_rates_size = exchange_rates.len();
30
31 if exchange_rates_size >= 2 {
33 let er_e = exchange_rates.iter().dropping(1);
35 let er_e_1 = exchange_rates.iter().dropping_back(1);
37 let apys = er_e
38 .zip(er_e_1)
39 .map(apy_rate)
40 .filter(|apy| *apy > 0.0 && *apy < 0.1)
41 .take(30)
42 .collect::<Vec<_>>();
43
44 let apy_counts = apys.len() as f64;
45 apys.iter().sum::<f64>() / apy_counts
46 } else {
47 0.0
48 }
49}
50
51pub(crate) fn apy_rate(
53 (rate_e, rate_e_1): (&&PoolTokenExchangeRate, &&PoolTokenExchangeRate),
54) -> f64 {
55 (rate_e.rate() / rate_e_1.rate()).powf(365.0) - 1.0
56}
57
58#[cfg(test)]
59mod tests {
60 use std::collections::BTreeMap;
61
62 use sui_json_rpc::governance_api::ValidatorExchangeRates;
63 use sui_types::base_types::{ObjectID, SuiAddress};
64
65 use super::*;
66
67 #[test]
68 fn test_apys_calculation_filter_outliers() {
69 let file =
71 std::fs::File::open("src/unit_tests_data/validator_exchange_rates.json").unwrap();
72 let rates: BTreeMap<String, Vec<(u64, PoolTokenExchangeRate)>> =
73 serde_json::from_reader(file).unwrap();
74
75 let mut validator_exchange_rates = BTreeMap::new();
76 rates.into_iter().for_each(|(validator, rates)| {
77 let address = SuiAddress::random_for_testing_only();
78 validator_exchange_rates.insert(
79 address,
80 (
81 validator,
82 ValidatorExchangeRates {
83 address,
84 pool_id: ObjectID::random(),
85 active: true,
86 rates,
87 },
88 ),
89 );
90 });
91
92 for (address, (validator, rates)) in &validator_exchange_rates {
93 let apy = calculate_apy(20, &rates.rates);
94 println!("{} {}: {}", validator, address, apy);
95 assert!(apy < 0.07)
96 }
97 }
98}