Skip to content

Commit 4563e78

Browse files
author
Samuel Dare
committed
feat: get total delegated stake
1 parent 83819ff commit 4563e78

File tree

2 files changed

+246
-16
lines changed

2 files changed

+246
-16
lines changed

pallets/subtensor/src/delegate_info.rs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,19 @@ impl<T: Config> Pallet<T> {
4040
let mut emissions_per_day: U64F64 = U64F64::from_num(0);
4141

4242
for netuid in registrations.iter() {
43-
let _uid = Self::get_uid_for_net_and_hotkey(*netuid, &delegate.clone());
44-
if _uid.is_err() {
45-
continue; // this should never happen
46-
} else {
47-
let uid = _uid.expect("Delegate's UID should be ok");
43+
if let Ok(uid) = Self::get_uid_for_net_and_hotkey(*netuid, &delegate.clone()) {
4844
let validator_permit = Self::get_validator_permit_for_uid(*netuid, uid);
4945
if validator_permit {
5046
validator_permits.push((*netuid).into());
5147
}
5248

5349
let emission: U64F64 = Self::get_emission_for_uid(*netuid, uid).into();
5450
let tempo: U64F64 = Self::get_tempo(*netuid).into();
55-
let epochs_per_day: U64F64 = U64F64::from_num(7200).saturating_div(tempo);
56-
emissions_per_day =
57-
emissions_per_day.saturating_add(emission.saturating_mul(epochs_per_day));
51+
if tempo > U64F64::from_num(0) {
52+
let epochs_per_day: U64F64 = U64F64::from_num(7200).saturating_div(tempo);
53+
emissions_per_day =
54+
emissions_per_day.saturating_add(emission.saturating_mul(epochs_per_day));
55+
}
5856
}
5957
}
6058

@@ -63,15 +61,15 @@ impl<T: Config> Pallet<T> {
6361

6462
let total_stake: U64F64 = Self::get_total_stake_for_hotkey(&delegate.clone()).into();
6563

66-
let mut return_per_1000: U64F64 = U64F64::from_num(0);
67-
68-
if total_stake > U64F64::from_num(0) {
69-
return_per_1000 = emissions_per_day
64+
let return_per_1000: U64F64 = if total_stake > U64F64::from_num(0) {
65+
emissions_per_day
7066
.saturating_mul(U64F64::from_num(0.82))
71-
.saturating_div(total_stake.saturating_div(U64F64::from_num(1000)));
72-
}
67+
.saturating_div(total_stake.saturating_div(U64F64::from_num(1000)))
68+
} else {
69+
U64F64::from_num(0)
70+
};
7371

74-
return DelegateInfo {
72+
DelegateInfo {
7573
delegate_ss58: delegate.clone(),
7674
take,
7775
nominators,
@@ -80,7 +78,7 @@ impl<T: Config> Pallet<T> {
8078
validator_permits,
8179
return_per_1000: U64F64::to_num::<u64>(return_per_1000).into(),
8280
total_daily_return: U64F64::to_num::<u64>(emissions_per_day).into(),
83-
};
81+
}
8482
}
8583

8684
pub fn get_delegate(delegate_account_vec: Vec<u8>) -> Option<DelegateInfo<T>> {
@@ -132,4 +130,40 @@ impl<T: Config> Pallet<T> {
132130

133131
delegates
134132
}
133+
134+
/// Returns the total delegated stake for a given delegate, excluding the stake from the delegate's owner.
135+
///
136+
/// # Arguments
137+
///
138+
/// * `delegate` - A reference to the account ID of the delegate.
139+
///
140+
/// # Returns
141+
///
142+
/// * `u64` - The total amount of stake delegated to the delegate, excluding the owner's stake.
143+
///
144+
///
145+
/// # Notes
146+
///
147+
/// This function retrieves the delegate's information and calculates the total stake from all nominators,
148+
/// excluding the stake from the delegate's owner.
149+
pub fn get_total_delegated_stake(delegate: &T::AccountId) -> u64 {
150+
if !<Delegates<T>>::contains_key(delegate) {
151+
return 0;
152+
}
153+
154+
// Retrieve the delegate's information
155+
let delegate_info: DelegateInfo<T> =
156+
Self::get_delegate_by_existing_account(delegate.clone());
157+
158+
// Retrieve the owner's account ID for the given delegate
159+
let owner: T::AccountId = Self::get_owning_coldkey_for_hotkey(delegate);
160+
161+
// Calculate the total stake from all nominators, excluding the owner's stake
162+
delegate_info
163+
.nominators
164+
.iter()
165+
.filter(|(nominator, _)| nominator != &owner) // Exclude the owner's stake
166+
.map(|(_, stake)| stake.0 as u64) // Map the stake to u64
167+
.sum() // Sum the stakes
168+
}
135169
}

pallets/subtensor/tests/staking.rs

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use frame_support::sp_runtime::DispatchError;
1313
use mock::*;
1414
use pallet_balances::Call as BalancesCall;
1515
use pallet_subtensor::*;
16+
use serde::de;
1617
use sp_core::{H256, U256};
1718
use sp_runtime::traits::SignedExtension;
1819

@@ -4195,3 +4196,198 @@ fn test_comprehensive_coldkey_swap_scenarios() {
41954196
assert_eq!(SubtensorModule::get_coldkey_balance(&regular_user), 0);
41964197
});
41974198
}
4199+
4200+
#[test]
4201+
fn test_get_total_delegated_stake_after_unstaking() {
4202+
new_test_ext(1).execute_with(|| {
4203+
let delegate = U256::from(1);
4204+
let coldkey = U256::from(2);
4205+
let delegator = U256::from(3);
4206+
let initial_stake = 2000;
4207+
let unstake_amount = 500;
4208+
let netuid = 1u16;
4209+
let existential_deposit = 1; // Account for the existential deposit
4210+
4211+
add_network(netuid, 0, 0);
4212+
4213+
register_ok_neuron(netuid, delegate, coldkey, 0);
4214+
4215+
// Make the delegate a delegate
4216+
assert_ok!(SubtensorModule::become_delegate(
4217+
RuntimeOrigin::signed(coldkey),
4218+
delegate
4219+
));
4220+
4221+
// Add balance to delegator
4222+
SubtensorModule::add_balance_to_coldkey_account(&delegator, initial_stake);
4223+
4224+
// Delegate stake
4225+
assert_ok!(SubtensorModule::add_stake(
4226+
RuntimeOrigin::signed(delegator),
4227+
delegate,
4228+
initial_stake
4229+
));
4230+
4231+
// Unstake part of the delegation
4232+
assert_ok!(SubtensorModule::remove_stake(
4233+
RuntimeOrigin::signed(delegator),
4234+
delegate,
4235+
unstake_amount
4236+
));
4237+
4238+
// Calculate the expected delegated stake
4239+
let expected_delegated_stake = initial_stake - unstake_amount - existential_deposit;
4240+
4241+
// Check the total delegated stake after unstaking
4242+
assert_eq!(
4243+
SubtensorModule::get_total_delegated_stake(&delegate),
4244+
expected_delegated_stake
4245+
);
4246+
});
4247+
}
4248+
4249+
#[test]
4250+
fn test_get_total_delegated_stake_no_delegations() {
4251+
new_test_ext(1).execute_with(|| {
4252+
let delegate = U256::from(1);
4253+
let coldkey = U256::from(2);
4254+
let netuid = 1u16;
4255+
4256+
add_network(netuid, 0, 0);
4257+
register_ok_neuron(netuid, delegate, coldkey, 0);
4258+
4259+
// Make the delegate a delegate
4260+
assert_ok!(SubtensorModule::become_delegate(
4261+
RuntimeOrigin::signed(coldkey),
4262+
delegate
4263+
));
4264+
4265+
// Check that there's no delegated stake
4266+
assert_eq!(SubtensorModule::get_total_delegated_stake(&delegate), 0);
4267+
});
4268+
}
4269+
4270+
#[test]
4271+
fn test_get_total_delegated_stake_single_delegator() {
4272+
new_test_ext(1).execute_with(|| {
4273+
let delegate = U256::from(1);
4274+
let coldkey = U256::from(2);
4275+
let delegator = U256::from(3);
4276+
let stake_amount = 1000;
4277+
let netuid = 1u16;
4278+
4279+
add_network(netuid, 0, 0);
4280+
register_ok_neuron(netuid, delegate, coldkey, 0);
4281+
4282+
// Make the delegate a delegate
4283+
assert_ok!(SubtensorModule::become_delegate(
4284+
RuntimeOrigin::signed(coldkey),
4285+
delegate
4286+
));
4287+
4288+
// Add balance to delegator
4289+
SubtensorModule::add_balance_to_coldkey_account(&delegator, stake_amount);
4290+
4291+
// Delegate stake
4292+
assert_ok!(SubtensorModule::add_stake(
4293+
RuntimeOrigin::signed(delegator),
4294+
delegate,
4295+
stake_amount
4296+
));
4297+
4298+
// Check the total delegated stake
4299+
assert_eq!(
4300+
SubtensorModule::get_total_delegated_stake(&delegate),
4301+
stake_amount - 1 // Subtract 1 for existential deposit
4302+
);
4303+
});
4304+
}
4305+
4306+
#[test]
4307+
fn test_get_total_delegated_stake_multiple_delegators() {
4308+
new_test_ext(1).execute_with(|| {
4309+
let delegate = U256::from(1);
4310+
let coldkey = U256::from(2);
4311+
let delegator1 = U256::from(3);
4312+
let delegator2 = U256::from(4);
4313+
let stake_amount1 = 1000;
4314+
let stake_amount2 = 2000;
4315+
let netuid = 1u16;
4316+
4317+
add_network(netuid, 0, 0);
4318+
register_ok_neuron(netuid, delegate, coldkey, 0);
4319+
4320+
// Make the delegate a delegate
4321+
assert_ok!(SubtensorModule::become_delegate(
4322+
RuntimeOrigin::signed(coldkey),
4323+
delegate
4324+
));
4325+
4326+
// Add balance to delegators
4327+
SubtensorModule::add_balance_to_coldkey_account(&delegator1, stake_amount1);
4328+
SubtensorModule::add_balance_to_coldkey_account(&delegator2, stake_amount2);
4329+
4330+
// Delegate stakes
4331+
assert_ok!(SubtensorModule::add_stake(
4332+
RuntimeOrigin::signed(delegator1),
4333+
delegate,
4334+
stake_amount1
4335+
));
4336+
assert_ok!(SubtensorModule::add_stake(
4337+
RuntimeOrigin::signed(delegator2),
4338+
delegate,
4339+
stake_amount2
4340+
));
4341+
4342+
// Check the total delegated stake
4343+
assert_eq!(
4344+
SubtensorModule::get_total_delegated_stake(&delegate),
4345+
stake_amount1 + stake_amount2 - 2 // Subtract 2 for existential deposits
4346+
);
4347+
});
4348+
}
4349+
4350+
#[test]
4351+
fn test_get_total_delegated_stake_exclude_owner_stake() {
4352+
new_test_ext(1).execute_with(|| {
4353+
let delegate = U256::from(1);
4354+
let coldkey = U256::from(2);
4355+
let delegator = U256::from(3);
4356+
let owner_stake = 5000;
4357+
let delegator_stake = 1000;
4358+
let netuid = 1u16;
4359+
4360+
add_network(netuid, 0, 0);
4361+
register_ok_neuron(netuid, delegate, coldkey, 0);
4362+
4363+
// Make the delegate a delegate
4364+
assert_ok!(SubtensorModule::become_delegate(
4365+
RuntimeOrigin::signed(coldkey),
4366+
delegate
4367+
));
4368+
4369+
// Add balance to owner and delegator
4370+
SubtensorModule::add_balance_to_coldkey_account(&coldkey, owner_stake);
4371+
SubtensorModule::add_balance_to_coldkey_account(&delegator, delegator_stake);
4372+
4373+
// Owner adds stake
4374+
assert_ok!(SubtensorModule::add_stake(
4375+
RuntimeOrigin::signed(coldkey),
4376+
delegate,
4377+
owner_stake
4378+
));
4379+
4380+
// Delegator adds stake
4381+
assert_ok!(SubtensorModule::add_stake(
4382+
RuntimeOrigin::signed(delegator),
4383+
delegate,
4384+
delegator_stake
4385+
));
4386+
4387+
// Check the total delegated stake (should exclude owner's stake)
4388+
assert_eq!(
4389+
SubtensorModule::get_total_delegated_stake(&delegate),
4390+
delegator_stake - 1 // Subtract 1 for existential deposit
4391+
);
4392+
});
4393+
}

0 commit comments

Comments
 (0)