Skip to content

Commit ddc3d68

Browse files
committed
Fix staking fee calculation
1 parent 69e3a43 commit ddc3d68

File tree

5 files changed

+88
-28
lines changed

5 files changed

+88
-28
lines changed

pallets/subtensor/src/staking/add_stake.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::*;
2+
use safe_math::SafeDiv;
23
use sp_core::Get;
4+
use substrate_fixed::types::I96F32;
35

46
impl<T: Config> Pallet<T> {
57
/// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account.
@@ -58,13 +60,20 @@ impl<T: Config> Pallet<T> {
5860
)?;
5961

6062
// 3. Ensure the remove operation from the coldkey is a success.
61-
let tao_staked: u64 =
62-
Self::remove_balance_from_coldkey_account(&coldkey, stake_to_be_added)?;
63+
let tao_staked: I96F32 =
64+
Self::remove_balance_from_coldkey_account(&coldkey, stake_to_be_added)?.into();
65+
let alpha_estimate = tao_staked.saturating_mul(Self::get_alpha_price(netuid));
6366

6467
// 4. Swap the stake into alpha on the subnet and increase counters.
6568
// Emit the staking event.
66-
let fee = DefaultStakingFee::<T>::get();
67-
Self::stake_into_subnet(&hotkey, &coldkey, netuid, tao_staked, fee);
69+
70+
Self::stake_into_subnet(
71+
&hotkey,
72+
&coldkey,
73+
netuid,
74+
tao_staked.saturating_to_num::<u64>(),
75+
Self::calculate_staking_fee(netuid, &hotkey, alpha_estimate),
76+
);
6877

6978
// Ok and return.
7079
Ok(())
@@ -148,12 +157,19 @@ impl<T: Config> Pallet<T> {
148157
}
149158

150159
// 5. Ensure the remove operation from the coldkey is a success.
151-
let tao_staked: u64 = Self::remove_balance_from_coldkey_account(&coldkey, possible_stake)?;
160+
let tao_staked: I96F32 =
161+
Self::remove_balance_from_coldkey_account(&coldkey, possible_stake)?.into();
162+
let alpha_estimate = tao_staked.saturating_mul(Self::get_alpha_price(netuid));
152163

153164
// 6. Swap the stake into alpha on the subnet and increase counters.
154165
// Emit the staking event.
155-
let fee = DefaultStakingFee::<T>::get();
156-
Self::stake_into_subnet(&hotkey, &coldkey, netuid, tao_staked, fee);
166+
Self::stake_into_subnet(
167+
&hotkey,
168+
&coldkey,
169+
netuid,
170+
tao_staked.saturating_to_num::<u64>(),
171+
Self::calculate_staking_fee(netuid, &hotkey, alpha_estimate),
172+
);
157173

158174
// Ok and return.
159175
Ok(())

pallets/subtensor/src/staking/move_stake.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22
use safe_math::*;
33
use sp_core::Get;
4-
use substrate_fixed::types::U64F64;
4+
use substrate_fixed::types::{I96F32, U64F64};
55

66
impl<T: Config> Pallet<T> {
77
/// Moves stake from one hotkey to another across subnets.
@@ -331,7 +331,13 @@ impl<T: Config> Pallet<T> {
331331
)?;
332332

333333
// Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
334-
let fee = DefaultStakingFee::<T>::get().safe_div(2);
334+
let fee = Self::calculate_staking_fee(
335+
origin_netuid,
336+
origin_hotkey,
337+
I96F32::saturating_from_num(alpha_amount),
338+
)
339+
.safe_div(2);
340+
335341
let tao_unstaked = Self::unstake_from_subnet(
336342
origin_hotkey,
337343
origin_coldkey,

pallets/subtensor/src/staking/remove_stake.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::*;
22
use sp_core::Get;
3+
use substrate_fixed::types::I96F32;
34

45
impl<T: Config> Pallet<T> {
56
/// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey.
@@ -58,7 +59,11 @@ impl<T: Config> Pallet<T> {
5859
)?;
5960

6061
// 3. Swap the alpba to tao and update counters for this subnet.
61-
let fee = DefaultStakingFee::<T>::get();
62+
let fee = Self::calculate_staking_fee(
63+
netuid,
64+
&hotkey,
65+
I96F32::saturating_from_num(alpha_unstaked),
66+
);
6267
let tao_unstaked: u64 =
6368
Self::unstake_from_subnet(&hotkey, &coldkey, netuid, alpha_unstaked, fee);
6469

@@ -109,8 +114,6 @@ impl<T: Config> Pallet<T> {
109114
origin: T::RuntimeOrigin,
110115
hotkey: T::AccountId,
111116
) -> dispatch::DispatchResult {
112-
let fee = DefaultStakingFee::<T>::get();
113-
114117
// 1. We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
115118
let coldkey = ensure_signed(origin)?;
116119
log::info!("do_unstake_all( origin:{:?} hotkey:{:?} )", coldkey, hotkey);
@@ -126,20 +129,26 @@ impl<T: Config> Pallet<T> {
126129
log::debug!("All subnet netuids: {:?}", netuids);
127130

128131
// 4. Iterate through all subnets and remove stake.
129-
for netuid in netuids.iter() {
132+
for netuid in netuids.into_iter() {
130133
// Ensure that the hotkey has enough stake to withdraw.
131134
let alpha_unstaked =
132-
Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, *netuid);
135+
Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
136+
let fee = Self::calculate_staking_fee(
137+
netuid,
138+
&hotkey,
139+
I96F32::saturating_from_num(alpha_unstaked),
140+
);
141+
133142
if alpha_unstaked > 0 {
134143
// Swap the alpha to tao and update counters for this subnet.
135144
let tao_unstaked: u64 =
136-
Self::unstake_from_subnet(&hotkey, &coldkey, *netuid, alpha_unstaked, fee);
145+
Self::unstake_from_subnet(&hotkey, &coldkey, netuid, alpha_unstaked, fee);
137146

138147
// Add the balance to the coldkey. If the above fails we will not credit this coldkey.
139148
Self::add_balance_to_coldkey_account(&coldkey, tao_unstaked);
140149

141150
// If the stake is below the minimum, we clear the nomination from storage.
142-
Self::clear_small_nomination_if_required(&hotkey, &coldkey, *netuid);
151+
Self::clear_small_nomination_if_required(&hotkey, &coldkey, netuid);
143152
}
144153
}
145154

@@ -177,8 +186,6 @@ impl<T: Config> Pallet<T> {
177186
origin: T::RuntimeOrigin,
178187
hotkey: T::AccountId,
179188
) -> dispatch::DispatchResult {
180-
let fee = DefaultStakingFee::<T>::get();
181-
182189
// 1. We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
183190
let coldkey = ensure_signed(origin)?;
184191
log::info!("do_unstake_all( origin:{:?} hotkey:{:?} )", coldkey, hotkey);
@@ -195,22 +202,28 @@ impl<T: Config> Pallet<T> {
195202

196203
// 4. Iterate through all subnets and remove stake.
197204
let mut total_tao_unstaked: u64 = 0;
198-
for netuid in netuids.iter() {
205+
for netuid in netuids.into_iter() {
199206
// If not Root network.
200-
if *netuid != Self::get_root_netuid() {
207+
if netuid != Self::get_root_netuid() {
201208
// Ensure that the hotkey has enough stake to withdraw.
202209
let alpha_unstaked =
203-
Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, *netuid);
210+
Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
211+
let fee = Self::calculate_staking_fee(
212+
netuid,
213+
&hotkey,
214+
I96F32::saturating_from_num(alpha_unstaked),
215+
);
216+
204217
if alpha_unstaked > 0 {
205218
// Swap the alpha to tao and update counters for this subnet.
206-
let tao_unstaked: u64 =
207-
Self::unstake_from_subnet(&hotkey, &coldkey, *netuid, alpha_unstaked, fee);
219+
let tao_unstaked =
220+
Self::unstake_from_subnet(&hotkey, &coldkey, netuid, alpha_unstaked, fee);
208221

209222
// Increment total
210223
total_tao_unstaked = total_tao_unstaked.saturating_add(tao_unstaked);
211224

212225
// If the stake is below the minimum, we clear the nomination from storage.
213-
Self::clear_small_nomination_if_required(&hotkey, &coldkey, *netuid);
226+
Self::clear_small_nomination_if_required(&hotkey, &coldkey, netuid);
214227
}
215228
}
216229
}
@@ -302,8 +315,12 @@ impl<T: Config> Pallet<T> {
302315
)?;
303316

304317
// 4. Swap the alpha to tao and update counters for this subnet.
305-
let fee = DefaultStakingFee::<T>::get();
306-
let tao_unstaked: u64 =
318+
let fee = Self::calculate_staking_fee(
319+
netuid,
320+
&hotkey,
321+
I96F32::saturating_from_num(alpha_unstaked),
322+
);
323+
let tao_unstaked =
307324
Self::unstake_from_subnet(&hotkey, &coldkey, netuid, possible_alpha, fee);
308325

309326
// 5. We add the balance to the coldkey. If the above fails we will not credit this coldkey.

pallets/subtensor/src/staking/stake_utils.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ impl<T: Config> Pallet<T> {
806806
/// Stakes TAO into a subnet for a given hotkey and coldkey pair.
807807
///
808808
/// We update the pools associated with a subnet as well as update hotkey alpha shares.
809-
pub fn stake_into_subnet(
809+
pub(crate) fn stake_into_subnet(
810810
hotkey: &T::AccountId,
811811
coldkey: &T::AccountId,
812812
netuid: u16,
@@ -1066,6 +1066,24 @@ impl<T: Config> Pallet<T> {
10661066

10671067
Ok(())
10681068
}
1069+
1070+
pub(crate) fn calculate_staking_fee(
1071+
netuid: u16,
1072+
hotkey: &T::AccountId,
1073+
alpha_estimate: I96F32,
1074+
) -> u64 {
1075+
let fee = alpha_estimate
1076+
.saturating_mul(
1077+
I96F32::saturating_from_num(AlphaDividendsPerSubnet::<T>::get(netuid, &hotkey))
1078+
.safe_div(I96F32::saturating_from_num(TotalHotkeyAlpha::<T>::get(
1079+
&hotkey, netuid,
1080+
))),
1081+
)
1082+
.saturating_mul(I96F32::saturating_from_num(Tempo::<T>::get(netuid)))
1083+
.saturating_to_num::<u64>();
1084+
1085+
fee.max(DefaultStakingFee::<T>::get())
1086+
}
10691087
}
10701088

10711089
///////////////////////////////////////////

pallets/subtensor/src/tests/swap_coldkey.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use frame_support::traits::schedule::DispatchTime;
1414
use frame_support::traits::schedule::v3::Named as ScheduleNamed;
1515
use sp_core::{Get, H256, U256};
1616
use sp_runtime::DispatchError;
17+
use substrate_fixed::types::I96F32;
1718

1819
// // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_total_hotkey_coldkey_stakes_this_interval --exact --nocapture
1920
// #[test]
@@ -537,7 +538,9 @@ fn test_swap_concurrent_modifications() {
537538
let netuid: u16 = 1;
538539
let initial_stake = 1_000_000_000_000;
539540
let additional_stake = 500_000_000_000;
540-
let fee = DefaultStakingFee::<Test>::get();
541+
let initial_stake_alpha =
542+
I96F32::from(initial_stake).saturating_mul(SubtensorModule::get_alpha_price(netuid));
543+
let fee = SubtensorModule::calculate_staking_fee(netuid, &hotkey, initial_stake_alpha);
541544

542545
// Setup initial state
543546
add_network(netuid, 1, 1);

0 commit comments

Comments
 (0)