diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs index 5cd234b48..5776c48af 100644 --- a/pallets/subtensor/src/rpc_info/delegate_info.rs +++ b/pallets/subtensor/src/rpc_info/delegate_info.rs @@ -21,6 +21,34 @@ pub struct DelegateInfo { } impl Pallet { + fn return_per_1000_tao( + take: Compact, + total_stake: U64F64, + emissions_per_day: U64F64, + ) -> U64F64 { + // Get the take as a percentage and subtract it from 1 for remainder. + let without_take: U64F64 = U64F64::from_num(1) + .saturating_sub(U64F64::from_num(take.0).saturating_div(u16::MAX.into())); + + if total_stake > U64F64::from_num(0) { + emissions_per_day + .saturating_mul(without_take) + // Divide by 1000 TAO for return per 1k + .saturating_div(total_stake.saturating_div(U64F64::from_num(1000.0 * 1e9))) + } else { + U64F64::from_num(0) + } + } + + #[cfg(test)] + pub fn return_per_1000_tao_test( + take: Compact, + total_stake: U64F64, + emissions_per_day: U64F64, + ) -> U64F64 { + Self::return_per_1000_tao(take, total_stake, emissions_per_day) + } + fn get_delegate_by_existing_account(delegate: AccountIdOf) -> DelegateInfo { let mut nominators = Vec::<(T::AccountId, Compact)>::new(); @@ -63,14 +91,8 @@ impl Pallet { let total_stake: U64F64 = Self::get_stake_for_hotkey_on_subnet(&delegate.clone(), Self::get_root_netuid()).into(); - let return_per_1000: U64F64 = if total_stake > U64F64::from_num(0) { - emissions_per_day - .saturating_mul(u16::MAX.saturating_sub(take.0).into()) - .saturating_div(u16::MAX.into()) - .saturating_div(total_stake.saturating_div(U64F64::from_num(1000))) - } else { - U64F64::from_num(0) - }; + let return_per_1000: U64F64 = + Self::return_per_1000_tao(take, total_stake, emissions_per_day); DelegateInfo { delegate_ss58: delegate.clone(), diff --git a/pallets/subtensor/src/tests/delegate_info.rs b/pallets/subtensor/src/tests/delegate_info.rs new file mode 100644 index 000000000..78ea48482 --- /dev/null +++ b/pallets/subtensor/src/tests/delegate_info.rs @@ -0,0 +1,33 @@ +use codec::Compact; +use substrate_fixed::types::U64F64; + +use super::mock::*; + +#[test] +fn test_return_per_1000_tao() { + let take = // 18% take to the Validator + Compact::::from((U64F64::from_num(0.18 * u16::MAX as f64)).saturating_to_num::()); + + // 10_000 TAO total validator stake + let total_stake = U64F64::from_num(10_000.0 * 1e9); + // 1000 TAO emissions per day + let emissions_per_day = U64F64::from_num(1000.0 * 1e9); + + let return_per_1000 = + SubtensorModule::return_per_1000_tao_test(take, total_stake, emissions_per_day); + + // We expect 82 TAO per day with 10% of total_stake + let expected_return_per_1000 = U64F64::from_num(82.0); + + let diff_from_expected: f64 = (return_per_1000 / U64F64::from_num(1e9)) + .saturating_sub(expected_return_per_1000) + .to_num::(); + + let eps: f64 = 0.0005e9; // Precision within 0.0005 TAO + assert!( + diff_from_expected.abs() <= eps, + "Difference from expected: {} is greater than precision: {}", + diff_from_expected, + eps + ); +} diff --git a/pallets/subtensor/src/tests/mod.rs b/pallets/subtensor/src/tests/mod.rs index e0fef9d55..6865c9fa4 100644 --- a/pallets/subtensor/src/tests/mod.rs +++ b/pallets/subtensor/src/tests/mod.rs @@ -1,6 +1,7 @@ mod batch_tx; mod children; mod coinbase; +mod delegate_info; mod difficulty; mod emission; mod epoch;