Skip to content

Commit 3200a1f

Browse files
author
Roman
committed
Merge branch 'devnet-ready' into devnet-ready-with-nodes
2 parents e346f20 + ad43ed6 commit 3200a1f

File tree

8 files changed

+242
-27
lines changed

8 files changed

+242
-27
lines changed

pallets/subtensor/runtime-api/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ sp_api::decl_runtime_apis! {
4646
fn get_stake_info_for_coldkey( coldkey_account: AccountId32 ) -> Vec<StakeInfo<AccountId32>>;
4747
fn get_stake_info_for_coldkeys( coldkey_accounts: Vec<AccountId32> ) -> Vec<(AccountId32, Vec<StakeInfo<AccountId32>>)>;
4848
fn get_stake_info_for_hotkey_coldkey_netuid( hotkey_account: AccountId32, coldkey_account: AccountId32, netuid: u16 ) -> Option<StakeInfo<AccountId32>>;
49+
fn get_stake_fee( origin: Option<(AccountId32, u16)>, origin_coldkey_account: AccountId32, destination: Option<(AccountId32, u16)>, destination_coldkey_account: AccountId32, amount: u64 ) -> u64;
4950
}
5051

5152
pub trait SubnetRegistrationRuntimeApi {

pallets/subtensor/src/rpc_info/stake_info.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::*;
22
use frame_support::pallet_prelude::{Decode, Encode};
33
extern crate alloc;
44
use codec::Compact;
5+
use substrate_fixed::types::I96F32;
56

67
#[freeze_struct("5cfb3c84c3af3116")]
78
#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)]
@@ -112,4 +113,24 @@ impl<T: Config> Pallet<T> {
112113
is_registered,
113114
})
114115
}
116+
117+
pub fn get_stake_fee(
118+
origin: Option<(T::AccountId, u16)>,
119+
_origin_coldkey_account: T::AccountId,
120+
_destination: Option<(T::AccountId, u16)>,
121+
_destination_coldkey_account: T::AccountId,
122+
amount: u64,
123+
) -> u64 {
124+
match origin {
125+
Some((origin_hotkey_account, origin_netuid)) => Self::calculate_staking_fee(
126+
origin_netuid,
127+
&origin_hotkey_account,
128+
I96F32::saturating_from_num(amount),
129+
),
130+
None => {
131+
// Adding stake (comes from no netuid)
132+
DefaultStakingFee::<T>::get()
133+
}
134+
}
135+
}
115136
}

pallets/subtensor/src/staking/move_stake.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,10 @@ impl<T: Config> Pallet<T> {
339339

340340
// Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
341341
let fee = Self::calculate_staking_fee(
342-
origin_netuid,
343-
origin_hotkey,
342+
Some((origin_hotkey, origin_netuid)),
343+
origin_coldkey,
344+
Some((destination_hotkey, destination_netuid)),
345+
destination_coldkey,
344346
I96F32::saturating_from_num(alpha_amount),
345347
)
346348
.safe_div(2);

pallets/subtensor/src/staking/remove_stake.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ impl<T: Config> Pallet<T> {
5959

6060
// 3. Swap the alpba to tao and update counters for this subnet.
6161
let fee = Self::calculate_staking_fee(
62-
netuid,
63-
&hotkey,
62+
Some((&hotkey, netuid)),
63+
&coldkey,
64+
None,
65+
&coldkey,
6466
I96F32::saturating_from_num(alpha_unstaked),
6567
);
6668
let tao_unstaked: u64 =
@@ -133,8 +135,10 @@ impl<T: Config> Pallet<T> {
133135
let alpha_unstaked =
134136
Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
135137
let fee = Self::calculate_staking_fee(
136-
netuid,
137-
&hotkey,
138+
Some((&hotkey, netuid)),
139+
&coldkey,
140+
None,
141+
&coldkey,
138142
I96F32::saturating_from_num(alpha_unstaked),
139143
);
140144

@@ -208,8 +212,10 @@ impl<T: Config> Pallet<T> {
208212
let alpha_unstaked =
209213
Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
210214
let fee = Self::calculate_staking_fee(
211-
netuid,
212-
&hotkey,
215+
Some((&hotkey, netuid)),
216+
&coldkey,
217+
None,
218+
&coldkey,
213219
I96F32::saturating_from_num(alpha_unstaked),
214220
);
215221

@@ -315,8 +321,10 @@ impl<T: Config> Pallet<T> {
315321

316322
// 4. Swap the alpha to tao and update counters for this subnet.
317323
let fee = Self::calculate_staking_fee(
318-
netuid,
319-
&hotkey,
324+
Some((&hotkey, netuid)),
325+
&coldkey,
326+
None,
327+
&coldkey,
320328
I96F32::saturating_from_num(alpha_unstaked),
321329
);
322330
let tao_unstaked =

pallets/subtensor/src/staking/stake_utils.rs

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,24 +1073,48 @@ impl<T: Config> Pallet<T> {
10731073
}
10741074

10751075
pub(crate) fn calculate_staking_fee(
1076-
netuid: u16,
1077-
hotkey: &T::AccountId,
1076+
origin: Option<(&T::AccountId, u16)>,
1077+
_origin_coldkey: &T::AccountId,
1078+
destination: Option<(&T::AccountId, u16)>,
1079+
_destination_coldkey: &T::AccountId,
10781080
alpha_estimate: I96F32,
10791081
) -> u64 {
1080-
if (netuid == Self::get_root_netuid()) || (SubnetMechanism::<T>::get(netuid)) == 0 {
1081-
DefaultStakingFee::<T>::get()
1082-
} else {
1083-
let fee = alpha_estimate
1084-
.saturating_mul(
1085-
I96F32::saturating_from_num(AlphaDividendsPerSubnet::<T>::get(netuid, &hotkey))
1086-
.safe_div(I96F32::saturating_from_num(TotalHotkeyAlpha::<T>::get(
1087-
&hotkey, netuid,
1088-
))),
1089-
)
1090-
.saturating_mul(Self::get_alpha_price(netuid)) // fee needs to be in TAO
1091-
.saturating_to_num::<u64>();
1082+
match origin {
1083+
// If origin is defined, we are removing/moving stake
1084+
Some((origin_hotkey, origin_netuid)) => {
1085+
if let Some((_destination_hotkey, destination_netuid)) = destination {
1086+
// This is a stake move/swap/transfer
1087+
if destination_netuid == origin_netuid {
1088+
// If destination is on the same subnet, use the default fee
1089+
return DefaultStakingFee::<T>::get();
1090+
}
1091+
}
10921092

1093-
fee.max(DefaultStakingFee::<T>::get())
1093+
if origin_netuid == Self::get_root_netuid()
1094+
|| SubnetMechanism::<T>::get(origin_netuid) == 0
1095+
{
1096+
// If the origin netuid is root, or the subnet mechanism is 0, use the default fee
1097+
DefaultStakingFee::<T>::get()
1098+
} else {
1099+
// Otherwise, calculate the fee based on the alpha estimate
1100+
let fee = alpha_estimate
1101+
.saturating_mul(
1102+
I96F32::saturating_from_num(AlphaDividendsPerSubnet::<T>::get(
1103+
origin_netuid,
1104+
&origin_hotkey,
1105+
))
1106+
.safe_div(I96F32::saturating_from_num(
1107+
TotalHotkeyAlpha::<T>::get(&origin_hotkey, origin_netuid),
1108+
)),
1109+
)
1110+
.saturating_mul(Self::get_alpha_price(origin_netuid)) // fee needs to be in TAO
1111+
.saturating_to_num::<u64>();
1112+
1113+
fee.max(DefaultStakingFee::<T>::get())
1114+
}
1115+
}
1116+
// If origin is not defined, we are adding stake; use default fee
1117+
None => DefaultStakingFee::<T>::get(),
10941118
}
10951119
}
10961120
}

pallets/subtensor/src/tests/staking2.rs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,3 +623,152 @@ fn test_try_associate_hotkey() {
623623
assert_eq!(SubtensorModule::get_owned_hotkeys(&coldkey2).len(), 0);
624624
});
625625
}
626+
627+
#[test]
628+
fn test_stake_fee_api() {
629+
new_test_ext(1).execute_with(|| {
630+
let hotkey1 = U256::from(1);
631+
let coldkey1 = U256::from(2);
632+
let hotkey2 = U256::from(3);
633+
let coldkey2 = U256::from(4);
634+
635+
let netuid0 = 1;
636+
let netuid1 = 2;
637+
let root_netuid = SubtensorModule::get_root_netuid();
638+
639+
let alpha_divs = 100_000_000_000;
640+
let total_hotkey_alpha = 100_000_000_000;
641+
let tao_in = 100_000_000_000; // 100 TAO
642+
let reciprocal_price = 2; // 1 / price
643+
let stake_amount = 100_000_000_000;
644+
645+
let default_fee = DefaultStakingFee::<Test>::get();
646+
647+
// Setup alpha out
648+
SubnetAlphaOut::<Test>::insert(netuid0, 100_000_000_000);
649+
SubnetAlphaOut::<Test>::insert(netuid1, 100_000_000_000);
650+
// Set pools using price
651+
SubnetAlphaIn::<Test>::insert(netuid0, tao_in * reciprocal_price);
652+
SubnetTAO::<Test>::insert(netuid0, tao_in);
653+
SubnetAlphaIn::<Test>::insert(netuid1, tao_in * reciprocal_price);
654+
SubnetTAO::<Test>::insert(netuid1, tao_in);
655+
656+
// Setup alpha divs for hotkey1
657+
AlphaDividendsPerSubnet::<Test>::insert(netuid0, hotkey1, alpha_divs);
658+
AlphaDividendsPerSubnet::<Test>::insert(netuid1, hotkey1, alpha_divs);
659+
660+
// Setup total hotkey alpha for hotkey1
661+
TotalHotkeyAlpha::<Test>::insert(hotkey1, netuid0, total_hotkey_alpha);
662+
TotalHotkeyAlpha::<Test>::insert(hotkey1, netuid1, total_hotkey_alpha);
663+
664+
// Test stake fee for add_stake
665+
let stake_fee_0 = SubtensorModule::get_stake_fee(
666+
None,
667+
coldkey1,
668+
Some((hotkey1, netuid0)),
669+
coldkey1,
670+
stake_amount,
671+
); // Default for adding stake
672+
assert_eq!(stake_fee_0, default_fee);
673+
674+
// Test stake fee for remove on root
675+
let stake_fee_1 = SubtensorModule::get_stake_fee(
676+
Some((hotkey1, root_netuid)),
677+
coldkey1,
678+
None,
679+
coldkey1,
680+
stake_amount,
681+
); // Default for removing stake from root
682+
assert_eq!(stake_fee_1, default_fee);
683+
684+
// Test stake fee for move from root to non-root
685+
let stake_fee_2 = SubtensorModule::get_stake_fee(
686+
Some((hotkey1, root_netuid)),
687+
coldkey1,
688+
Some((hotkey1, netuid0)),
689+
coldkey1,
690+
stake_amount,
691+
); // Default for moving stake from root to non-root
692+
assert_eq!(stake_fee_2, default_fee);
693+
694+
// Test stake fee for move between hotkeys on root
695+
let stake_fee_3 = SubtensorModule::get_stake_fee(
696+
Some((hotkey1, root_netuid)),
697+
coldkey1,
698+
Some((hotkey2, root_netuid)),
699+
coldkey1,
700+
stake_amount,
701+
); // Default for moving stake between hotkeys on root
702+
assert_eq!(stake_fee_3, default_fee);
703+
704+
// Test stake fee for move between coldkeys on root
705+
let stake_fee_4 = SubtensorModule::get_stake_fee(
706+
Some((hotkey1, root_netuid)),
707+
coldkey1,
708+
Some((hotkey1, root_netuid)),
709+
coldkey2,
710+
stake_amount,
711+
); // Default for moving stake between coldkeys on root
712+
assert_eq!(stake_fee_4, default_fee);
713+
714+
// Test stake fee for *swap* from non-root to root
715+
let stake_fee_5 = SubtensorModule::get_stake_fee(
716+
Some((hotkey1, netuid0)),
717+
coldkey1,
718+
Some((hotkey1, root_netuid)),
719+
coldkey1,
720+
stake_amount,
721+
); // Charged a dynamic fee
722+
let dynamic_fee_5 = SubtensorModule::calculate_staking_fee(
723+
netuid0,
724+
&hotkey1,
725+
I96F32::from_num(stake_amount),
726+
);
727+
assert_eq!(stake_fee_5, dynamic_fee_5);
728+
729+
// Test stake fee for move between hotkeys on non-root
730+
let stake_fee_6 = SubtensorModule::get_stake_fee(
731+
Some((hotkey1, netuid0)),
732+
coldkey1,
733+
Some((hotkey2, netuid0)),
734+
coldkey1,
735+
stake_amount,
736+
); // Charged a dynamic fee
737+
let dynamic_fee_6 = SubtensorModule::calculate_staking_fee(
738+
netuid0,
739+
&hotkey1,
740+
I96F32::from_num(stake_amount),
741+
);
742+
assert_eq!(stake_fee_6, dynamic_fee_6);
743+
744+
// Test stake fee for move between coldkeys on non-root
745+
let stake_fee_7 = SubtensorModule::get_stake_fee(
746+
Some((hotkey1, netuid0)),
747+
coldkey1,
748+
Some((hotkey1, netuid0)),
749+
coldkey2,
750+
stake_amount,
751+
); // Charged a dynamic fee
752+
let dynamic_fee_7 = SubtensorModule::calculate_staking_fee(
753+
netuid0,
754+
&hotkey1,
755+
I96F32::from_num(stake_amount),
756+
);
757+
assert_eq!(stake_fee_7, dynamic_fee_7);
758+
759+
// Test stake fee for *swap* from non-root to non-root
760+
let stake_fee_8 = SubtensorModule::get_stake_fee(
761+
Some((hotkey1, netuid0)),
762+
coldkey1,
763+
Some((hotkey1, netuid1)),
764+
coldkey1,
765+
stake_amount,
766+
); // Charged a dynamic fee
767+
let dynamic_fee_8 = SubtensorModule::calculate_staking_fee(
768+
netuid0,
769+
&hotkey1,
770+
I96F32::from_num(stake_amount),
771+
);
772+
assert_eq!(stake_fee_8, dynamic_fee_8);
773+
});
774+
}

pallets/subtensor/src/tests/swap_coldkey.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,13 @@ fn test_swap_concurrent_modifications() {
540540
let additional_stake = 500_000_000_000;
541541
let initial_stake_alpha =
542542
I96F32::from(initial_stake).saturating_mul(SubtensorModule::get_alpha_price(netuid));
543-
let fee = SubtensorModule::calculate_staking_fee(netuid, &hotkey, initial_stake_alpha);
543+
let fee = SubtensorModule::calculate_staking_fee(
544+
None,
545+
&new_coldkey,
546+
Some((&hotkey, netuid)),
547+
&new_coldkey,
548+
initial_stake_alpha,
549+
);
544550

545551
// Setup initial state
546552
add_network(netuid, 1, 1);

runtime/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
205205
// `spec_version`, and `authoring_version` are the same between Wasm and native.
206206
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
207207
// the compatible custom types.
208-
spec_version: 248,
208+
spec_version: 249,
209209
impl_version: 1,
210210
apis: RUNTIME_API_VERSIONS,
211211
transaction_version: 1,
@@ -2066,6 +2066,10 @@ impl_runtime_apis! {
20662066
fn get_stake_info_for_hotkey_coldkey_netuid( hotkey_account: AccountId32, coldkey_account: AccountId32, netuid: u16 ) -> Option<StakeInfo<AccountId32>> {
20672067
SubtensorModule::get_stake_info_for_hotkey_coldkey_netuid( hotkey_account, coldkey_account, netuid )
20682068
}
2069+
2070+
fn get_stake_fee( origin: Option<(AccountId32, u16)>, origin_coldkey_account: AccountId32, destination: Option<(AccountId32, u16)>, destination_coldkey_account: AccountId32, amount: u64 ) -> u64 {
2071+
SubtensorModule::get_stake_fee( origin, origin_coldkey_account, destination, destination_coldkey_account, amount )
2072+
}
20692073
}
20702074

20712075
impl subtensor_custom_rpc_runtime_api::SubnetRegistrationRuntimeApi<Block> for Runtime {

0 commit comments

Comments
 (0)