Skip to content

Commit 79ecb52

Browse files
committed
Fixed fees for add_stake, dividend-based fees for remove_stake and swap_stake
1 parent 8456061 commit 79ecb52

File tree

3 files changed

+55
-53
lines changed

3 files changed

+55
-53
lines changed

pallets/subtensor/src/staking/add_stake.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,16 @@ impl<T: Config> Pallet<T> {
6060
// 3. Ensure the remove operation from the coldkey is a success.
6161
let tao_staked: I96F32 =
6262
Self::remove_balance_from_coldkey_account(&coldkey, stake_to_be_added)?.into();
63-
let alpha_estimate = tao_staked.saturating_mul(Self::get_alpha_price(netuid));
6463

6564
// 4. Swap the stake into alpha on the subnet and increase counters.
6665
// Emit the staking event.
67-
66+
let fee = DefaultStakingFee::<T>::get();
6867
Self::stake_into_subnet(
6968
&hotkey,
7069
&coldkey,
7170
netuid,
7271
tao_staked.saturating_to_num::<u64>(),
73-
Self::calculate_staking_fee(netuid, &hotkey, alpha_estimate),
72+
fee,
7473
);
7574

7675
// Ok and return.
@@ -157,16 +156,16 @@ impl<T: Config> Pallet<T> {
157156
// 5. Ensure the remove operation from the coldkey is a success.
158157
let tao_staked: I96F32 =
159158
Self::remove_balance_from_coldkey_account(&coldkey, possible_stake)?.into();
160-
let alpha_estimate = tao_staked.saturating_mul(Self::get_alpha_price(netuid));
161159

162160
// 6. Swap the stake into alpha on the subnet and increase counters.
163161
// Emit the staking event.
162+
let fee = DefaultStakingFee::<T>::get();
164163
Self::stake_into_subnet(
165164
&hotkey,
166165
&coldkey,
167166
netuid,
168167
tao_staked.saturating_to_num::<u64>(),
169-
Self::calculate_staking_fee(netuid, &hotkey, alpha_estimate),
168+
fee,
170169
);
171170

172171
// Ok and return.

pallets/subtensor/src/staking/stake_utils.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,17 +1072,21 @@ impl<T: Config> Pallet<T> {
10721072
hotkey: &T::AccountId,
10731073
alpha_estimate: I96F32,
10741074
) -> 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>();
1075+
if (netuid == Self::get_root_netuid()) || (SubnetMechanism::<T>::get(netuid)) == 0 {
1076+
DefaultStakingFee::<T>::get()
1077+
} else {
1078+
let fee = alpha_estimate
1079+
.saturating_mul(
1080+
I96F32::saturating_from_num(AlphaDividendsPerSubnet::<T>::get(netuid, &hotkey))
1081+
.safe_div(I96F32::saturating_from_num(TotalHotkeyAlpha::<T>::get(
1082+
&hotkey, netuid,
1083+
))),
1084+
)
1085+
.saturating_mul(Self::get_alpha_price(netuid)) // fee needs to be in TAO
1086+
.saturating_to_num::<u64>();
10841087

1085-
fee.max(DefaultStakingFee::<T>::get())
1088+
fee.max(DefaultStakingFee::<T>::get())
1089+
}
10861090
}
10871091
}
10881092

pallets/subtensor/src/tests/staking.rs

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,72 +2219,71 @@ fn test_remove_stake_fee_goes_to_subnet_tao() {
22192219
});
22202220
}
22212221

2222-
// cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_fee_equals_dividends --exact --show-output --nocapture
2222+
// cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_stake_fee_realistic_values --exact --show-output --nocapture
22232223
#[test]
2224-
fn test_add_stake_fee_equals_dividends() {
2224+
fn test_remove_stake_fee_realistic_values() {
22252225
new_test_ext(1).execute_with(|| {
22262226
let subnet_owner_coldkey = U256::from(1001);
22272227
let subnet_owner_hotkey = U256::from(1002);
22282228
let hotkey = U256::from(2);
22292229
let coldkey = U256::from(3);
2230-
let tao_to_stake = DefaultMinStake::<Test>::get() * 10_000;
2230+
let alpha_to_unstake = 111_180_000_000;
2231+
let alpha_divs = 2_816_190;
22312232

22322233
let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
22332234
SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
22342235

2236+
// Mock a realistic scenario:
2237+
// Subnet 1 has 3896 TAO and 128_011 Alpha in reserves, which
2238+
// makes its price ~0.03.
2239+
// A hotkey has 111 Alpha stake and is unstaking all Alpha.
2240+
// Alpha dividends of this hotkey are ~0.0028
2241+
// This makes fee be equal ~0.0028 Alpha ~= 84000 rao
2242+
let tao_reserve: U96F32 = U96F32::from_num(3_896_056_559_708_u64);
2243+
let alpha_in: U96F32 = U96F32::from_num(128_011_331_299_964_u64);
2244+
SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
2245+
SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
2246+
AlphaDividendsPerSubnet::<Test>::insert(netuid, hotkey, alpha_divs);
2247+
let current_price = SubtensorModule::get_alpha_price(netuid).to_num::<f64>();
2248+
22352249
// Add stake first time to init TotalHotkeyAlpha
2236-
SubtensorModule::add_balance_to_coldkey_account(
2250+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
2251+
&hotkey,
22372252
&coldkey,
2238-
2 * (tao_to_stake + ExistentialDeposit::get()),
2239-
);
2240-
assert_ok!(SubtensorModule::add_stake(
2241-
RuntimeOrigin::signed(coldkey),
2242-
hotkey,
2243-
netuid,
2244-
tao_to_stake
2245-
));
2246-
2247-
// Mock 0.001 per alpha dividends
2248-
AlphaDividendsPerSubnet::<Test>::insert(
22492253
netuid,
2250-
hotkey,
2251-
TotalHotkeyAlpha::<Test>::get(hotkey, netuid) / 1000,
2254+
alpha_to_unstake,
22522255
);
22532256

2254-
// Mock price to be 1 and a lot of liquidity
2255-
let tao_reserve: U96F32 = U96F32::from_num(100_000_000_000_000_u64);
2256-
let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_000_u64);
2257-
SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
2258-
SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
2257+
// Estimate fees
2258+
let expected_fee: f64 = current_price * alpha_divs as f64;
22592259

2260-
// Add stake again to measure fee
2261-
let alpha_before =
2262-
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
2263-
assert_ok!(SubtensorModule::add_stake(
2260+
// Remove stake to measure fee
2261+
let balance_before = SubtensorModule::get_coldkey_balance(&coldkey);
2262+
let expected_tao_no_fee =
2263+
SubtensorModule::sim_swap_alpha_for_tao(netuid, alpha_to_unstake).unwrap();
2264+
2265+
assert_ok!(SubtensorModule::remove_stake(
22642266
RuntimeOrigin::signed(coldkey),
22652267
hotkey,
22662268
netuid,
2267-
tao_to_stake
2269+
alpha_to_unstake
22682270
));
22692271

22702272
// Calculate expected fee
2271-
let expected_alpha_no_fee = tao_to_stake;
2272-
let alpha_after =
2273-
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
2274-
2275-
let actual_fee = expected_alpha_no_fee - (alpha_after - alpha_before);
2276-
let expected_fee =
2277-
(expected_alpha_no_fee as f64 * 0.001 * Tempo::<Test>::get(netuid) as f64) as u64;
2273+
let balance_after = SubtensorModule::get_coldkey_balance(&coldkey);
2274+
let actual_fee = expected_tao_no_fee as f64 - (balance_after - balance_before) as f64;
2275+
log::info!("Actual fee: {:?}", actual_fee);
22782276

2279-
assert_abs_diff_eq!(actual_fee, expected_fee, epsilon = expected_fee / 1000);
2277+
assert_abs_diff_eq!(
2278+
actual_fee as u64,
2279+
expected_fee as u64,
2280+
epsilon = expected_fee as u64 / 1000
2281+
);
22802282
});
22812283
}
22822284

22832285
#[test]
22842286
fn test_stake_below_min_validate() {
2285-
// Testing the signed extension validate function
2286-
// correctly filters the `add_stake` transaction.
2287-
22882287
new_test_ext(0).execute_with(|| {
22892288
let subnet_owner_coldkey = U256::from(1001);
22902289
let subnet_owner_hotkey = U256::from(1002);

0 commit comments

Comments
 (0)