@@ -656,11 +656,52 @@ where
656656 Ok(storage.read::<token::Amount>(&key)?.unwrap_or_default())
657657}
658658
659+ /// Compute an estimation of the most recent staking rewards rate.
660+ pub fn estimate_staking_reward_rate<S, Token, Parameters>(
661+ storage: &S,
662+ ) -> Result<Dec>
663+ where
664+ S: StorageRead,
665+ Parameters: parameters::Read<S>,
666+ Token: trans_token::Read<S> + trans_token::Write<S>,
667+ {
668+ // Get needed data in desired form
669+ let total_native_tokens =
670+ Token::get_effective_total_native_supply(storage)?;
671+ let last_staked_ratio = read_last_staked_ratio(storage)?
672+ .expect("Last staked ratio should exist in PoS storage");
673+ let last_inflation_amount = read_last_pos_inflation_amount(storage)?
674+ .expect("Last inflation amount should exist in PoS storage");
675+ let epochs_per_year: u64 = Parameters::epochs_per_year(storage)?;
676+
677+ let total_native_tokens =
678+ Dec::try_from(total_native_tokens).into_storage_result()?;
679+ let last_inflation_amount =
680+ Dec::try_from(last_inflation_amount).into_storage_result()?;
681+
682+ // Estimate annual inflation rate
683+ let est_inflation_rate = checked!(
684+ last_inflation_amount * epochs_per_year / total_native_tokens
685+ )?;
686+
687+ // Estimate annual staking rewards rate
688+ let est_staking_reward_rate =
689+ checked!(est_inflation_rate / last_staked_ratio)?;
690+
691+ Ok(est_staking_reward_rate)
692+ }
693+
659694#[cfg(test)]
660695mod tests {
661696 use std::str::FromStr;
662697
698+ use namada_parameters::storage::get_epochs_per_year_key;
699+ use namada_state::testing::TestState;
700+ use namada_trans_token::storage_key::minted_balance_key;
701+ use storage::write_pos_params;
702+
663703 use super::*;
704+ use crate::OwnedPosParams;
664705
665706 #[test]
666707 fn test_inflation_calc_up() {
@@ -842,10 +883,19 @@ mod tests {
842883
843884 #[test]
844885 fn test_pos_inflation_playground() {
886+ let mut storage = TestState::default();
887+ let gov_params =
888+ namada_governance::parameters::GovernanceParameters::default();
889+ gov_params.init_storage(&mut storage).unwrap();
890+ write_pos_params(&mut storage, &OwnedPosParams::default()).unwrap();
891+
845892 let epochs_per_year = 365_u64;
893+ let epy_key = get_epochs_per_year_key();
894+ storage.write(&epy_key, epochs_per_year).unwrap();
846895
847896 let init_locked_ratio = Dec::from_str("0.1").unwrap();
848897 let mut last_locked_ratio = init_locked_ratio;
898+
849899 let total_native_tokens = 1_000_000_000_u64;
850900 let locked_amount = u64::try_from(
851901 (init_locked_ratio * total_native_tokens).to_uint().unwrap(),
@@ -856,6 +906,13 @@ mod tests {
856906 let mut total_native_tokens =
857907 token::Amount::native_whole(total_native_tokens);
858908
909+ update_state_for_pos_playground(
910+ &mut storage,
911+ last_locked_ratio,
912+ last_inflation_amount,
913+ total_native_tokens,
914+ );
915+
859916 let max_reward_rate = Dec::from_str("0.1").unwrap();
860917 let target_ratio = Dec::from_str("0.66666666").unwrap();
861918 let p_gain_nom = Dec::from_str("0.25").unwrap();
@@ -882,17 +939,42 @@ mod tests {
882939 let locked_ratio = Dec::try_from(locked_amount).unwrap()
883940 / Dec::try_from(total_native_tokens).unwrap();
884941
885- let rate = Dec::try_from(inflation).unwrap()
942+ let inflation_rate = Dec::try_from(inflation).unwrap()
886943 * Dec::from(epochs_per_year)
887944 / Dec::try_from(total_native_tokens).unwrap();
945+ let staking_rate = inflation_rate / locked_ratio;
946+
888947 println!(
889948 "Round {round}: Locked ratio: {locked_ratio}, inflation rate: \
890- {rate}",
949+ {inflation_rate}, staking rate: {staking_rate }",
891950 );
892951
893952 last_inflation_amount = inflation;
894953 total_native_tokens += inflation;
895954 last_locked_ratio = locked_ratio;
955+ update_state_for_pos_playground(
956+ &mut storage,
957+ last_locked_ratio,
958+ last_inflation_amount,
959+ total_native_tokens,
960+ );
961+
962+ let query_staking_rate = estimate_staking_reward_rate::<
963+ _,
964+ namada_trans_token::Store<_>,
965+ namada_parameters::Store<_>,
966+ >(&storage)
967+ .unwrap();
968+ // println!(" ----> Query staking rate: {query_staking_rate}");
969+ if !staking_rate.is_zero() && !query_staking_rate.is_zero() {
970+ let ratio = staking_rate / query_staking_rate;
971+ let residual = ratio.abs_diff(Dec::one()).unwrap();
972+ assert!(residual < Dec::from_str("0.001").unwrap());
973+ // println!(
974+ // " ----> Ratio: {}\n",
975+ // staking_rate / query_staking_rate
976+ // );
977+ }
896978
897979 // if rate.abs_diff(&controller.max_reward_rate)
898980 // < Dec::from_str("0.01").unwrap()
@@ -930,4 +1012,22 @@ mod tests {
9301012 // );
9311013 }
9321014 }
1015+
1016+ fn update_state_for_pos_playground<S>(
1017+ storage: &mut S,
1018+ last_staked_ratio: Dec,
1019+ last_inflation_amount: token::Amount,
1020+ total_native_amount: token::Amount,
1021+ ) where
1022+ S: StorageRead + StorageWrite,
1023+ {
1024+ write_last_staked_ratio(storage, last_staked_ratio).unwrap();
1025+ write_last_pos_inflation_amount(storage, last_inflation_amount)
1026+ .unwrap();
1027+ let total_native_tokens_key =
1028+ minted_balance_key(&storage.get_native_token().unwrap());
1029+ storage
1030+ .write(&total_native_tokens_key, total_native_amount)
1031+ .unwrap();
1032+ }
9331033}
0 commit comments