Skip to content

Commit

Permalink
Implement fees for add_stake, remove_stake, and move_stake
Browse files Browse the repository at this point in the history
  • Loading branch information
gztensor committed Jan 22, 2025
1 parent d392516 commit a516c2b
Show file tree
Hide file tree
Showing 13 changed files with 326 additions and 146 deletions.
42 changes: 35 additions & 7 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use frame_support::{
dispatch::{self, DispatchInfo, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo},
ensure,
pallet_macros::import_section,
traits::{tokens::fungible, IsSubType},
traits::{
tokens::{fungible, Fortitude, Preservation},
IsSubType,
},
};

use codec::{Decode, Encode};
Expand All @@ -21,6 +24,7 @@ use frame_support::sp_runtime::transaction_validity::ValidTransaction;
use pallet_balances::Call as BalancesCall;
// use pallet_scheduler as Scheduler;
use scale_info::TypeInfo;
use sp_core::Get;
use sp_runtime::{
traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension},
transaction_validity::{TransactionValidity, TransactionValidityError},
Expand Down Expand Up @@ -697,9 +701,10 @@ pub mod pallet {

#[pallet::type_value]
/// Default minimum stake.
/// 2M rao matches $1 at $500/TAO
/// 500k rao matches $0.25 at $500/TAO
/// Also used as staking fee
pub fn DefaultMinStake<T: Config>() -> u64 {
2_000_000
500_000
}

#[pallet::type_value]
Expand Down Expand Up @@ -1532,12 +1537,14 @@ pub enum CallType {
#[derive(Debug, PartialEq)]
pub enum CustomTransactionError {
ColdkeyInSwapSchedule,
StakeAmountTooLow,
}

impl From<CustomTransactionError> for u8 {
fn from(variant: CustomTransactionError) -> u8 {
match variant {
CustomTransactionError::ColdkeyInSwapSchedule => 0,
CustomTransactionError::StakeAmountTooLow => 1,
}
}
}
Expand Down Expand Up @@ -1687,10 +1694,31 @@ where
Err(InvalidTransaction::Custom(7).into())
}
}
Some(Call::add_stake { .. }) => Ok(ValidTransaction {
priority: Self::get_priority_vanilla(),
..Default::default()
}),
Some(Call::add_stake {
hotkey: _,
netuid: _,
amount_staked,
}) => {
// Check that amount parameter is at least the min stake
// also check the coldkey balance
let coldkey_balance = <<T as Config>::Currency as fungible::Inspect<
<T as frame_system::Config>::AccountId,
>>::reducible_balance(
who, Preservation::Expendable, Fortitude::Polite
);

if (*amount_staked < DefaultMinStake::<T>::get())
|| (coldkey_balance < DefaultMinStake::<T>::get())
{
InvalidTransaction::Custom(CustomTransactionError::StakeAmountTooLow.into())
.into()
} else {
Ok(ValidTransaction {
priority: Self::get_priority_vanilla(),
..Default::default()
})
}
}
Some(Call::remove_stake { .. }) => Ok(ValidTransaction {
priority: Self::get_priority_vanilla(),
..Default::default()
Expand Down
3 changes: 2 additions & 1 deletion pallets/subtensor/src/staking/add_stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ impl<T: Config> Pallet<T> {

// 6. Swap the stake into alpha on the subnet and increase counters.
// Emit the staking event.
Self::stake_into_subnet(&hotkey, &coldkey, netuid, tao_staked);
let fee = DefaultMinStake::<T>::get();
Self::stake_into_subnet(&hotkey, &coldkey, netuid, tao_staked, fee);

// Ok and return.
Ok(())
Expand Down
3 changes: 2 additions & 1 deletion pallets/subtensor/src/staking/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ impl<T: Config> Pallet<T> {
// Log the clearing of a small nomination
// Remove the stake from the nominator account. (this is a more forceful unstake operation which )
// Actually deletes the staking account.
let cleared_stake = Self::unstake_from_subnet(hotkey, coldkey, netuid, stake);
// Do not apply any fees
let cleared_stake = Self::unstake_from_subnet(hotkey, coldkey, netuid, stake, 0);
// Add the stake to the coldkey account.
Self::add_balance_to_coldkey_account(coldkey, cleared_stake);
}
Expand Down
5 changes: 4 additions & 1 deletion pallets/subtensor/src/staking/move_stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@ impl<T: Config> Pallet<T> {
);

// --- 7. Unstake the amount of alpha from the origin subnet, converting it to TAO
let fee = DefaultMinStake::<T>::get().saturating_div(2); // fee is half of min stake because it is applied twice
let origin_tao = Self::unstake_from_subnet(
&origin_hotkey.clone(),
&coldkey.clone(),
origin_netuid,
alpha_amount,
fee,
);

// Ensure origin_tao is at least DefaultMinStake
Expand All @@ -87,6 +89,7 @@ impl<T: Config> Pallet<T> {
&coldkey.clone(),
destination_netuid,
origin_tao,
fee,
);

// --- 9. Log the event.
Expand All @@ -104,7 +107,7 @@ impl<T: Config> Pallet<T> {
origin_netuid,
destination_hotkey,
destination_netuid,
origin_tao,
origin_tao.saturating_sub(fee),
));

// -- 10. Ok and return.
Expand Down
17 changes: 10 additions & 7 deletions pallets/subtensor/src/staking/remove_stake.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use sp_core::Get;

impl<T: Config> Pallet<T> {
/// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey.
Expand Down Expand Up @@ -65,8 +66,9 @@ impl<T: Config> Pallet<T> {
);

// 6. Swap the alpba to tao and update counters for this subnet.
let fee = DefaultMinStake::<T>::get();
let tao_unstaked: u64 =
Self::unstake_from_subnet(&hotkey, &coldkey, netuid, alpha_unstaked);
Self::unstake_from_subnet(&hotkey, &coldkey, netuid, alpha_unstaked, fee);

// 7. We add the balance to the coldkey. If the above fails we will not credit this coldkey.
Self::add_balance_to_coldkey_account(&coldkey, tao_unstaked);
Expand All @@ -81,10 +83,6 @@ impl<T: Config> Pallet<T> {
})
}

// TODO: Regression
// Emit the unstaking event.
// Self::deposit_event(Event::StakeRemoved(hotkey, stake_to_be_removed));

// Done and ok.
Ok(())
}
Expand Down Expand Up @@ -119,6 +117,8 @@ impl<T: Config> Pallet<T> {
origin: T::RuntimeOrigin,
hotkey: T::AccountId,
) -> dispatch::DispatchResult {
let fee = DefaultMinStake::<T>::get();

// 1. We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
let coldkey = ensure_signed(origin)?;
log::info!("do_unstake_all( origin:{:?} hotkey:{:?} )", coldkey, hotkey);
Expand All @@ -141,7 +141,7 @@ impl<T: Config> Pallet<T> {
if alpha_unstaked > 0 {
// Swap the alpha to tao and update counters for this subnet.
let tao_unstaked: u64 =
Self::unstake_from_subnet(&hotkey, &coldkey, *netuid, alpha_unstaked);
Self::unstake_from_subnet(&hotkey, &coldkey, *netuid, alpha_unstaked, fee);

// Add the balance to the coldkey. If the above fails we will not credit this coldkey.
Self::add_balance_to_coldkey_account(&coldkey, tao_unstaked);
Expand Down Expand Up @@ -185,6 +185,8 @@ impl<T: Config> Pallet<T> {
origin: T::RuntimeOrigin,
hotkey: T::AccountId,
) -> dispatch::DispatchResult {
let fee = DefaultMinStake::<T>::get();

// 1. We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
let coldkey = ensure_signed(origin)?;
log::info!("do_unstake_all( origin:{:?} hotkey:{:?} )", coldkey, hotkey);
Expand All @@ -210,7 +212,7 @@ impl<T: Config> Pallet<T> {
if alpha_unstaked > 0 {
// Swap the alpha to tao and update counters for this subnet.
let tao_unstaked: u64 =
Self::unstake_from_subnet(&hotkey, &coldkey, *netuid, alpha_unstaked);
Self::unstake_from_subnet(&hotkey, &coldkey, *netuid, alpha_unstaked, fee);

// Increment total
total_tao_unstaked = total_tao_unstaked.saturating_add(tao_unstaked);
Expand All @@ -227,6 +229,7 @@ impl<T: Config> Pallet<T> {
&coldkey,
Self::get_root_netuid(),
total_tao_unstaked,
0, // no fee for restaking
);

// 5. Done and ok.
Expand Down
14 changes: 9 additions & 5 deletions pallets/subtensor/src/staking/stake_utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use super::*;
use crate::DefaultMinStake;
use share_pool::{SharePool, SharePoolDataOperations};
use sp_core::Get;
use sp_std::ops::Neg;
use substrate_fixed::types::{I64F64, I96F32, U64F64};

Expand Down Expand Up @@ -608,6 +606,7 @@ impl<T: Config> Pallet<T> {
coldkey: &T::AccountId,
netuid: u16,
alpha: u64,
fee: u64,
) -> u64 {
// Step 1: Swap the alpha for TAO.
let tao: u64 = Self::swap_alpha_for_tao(netuid, alpha);
Expand All @@ -624,12 +623,14 @@ impl<T: Config> Pallet<T> {
// }

// Step 4. Reduce tao amount by staking fee and credit this fee to SubnetTAO
let fee = DefaultMinStake::<T>::get();
let tao_unstaked = tao.saturating_sub(fee);
let actual_fee = tao.saturating_sub(tao_unstaked);
SubnetTAO::<T>::mutate(netuid, |total| {
*total = total.saturating_add(actual_fee);
});
TotalStake::<T>::mutate(|total| {
*total = total.saturating_add(actual_fee);
});

// Step 5. Deposit and log the unstaking event.
Self::deposit_event(Event::StakeRemoved(
Expand Down Expand Up @@ -660,11 +661,11 @@ impl<T: Config> Pallet<T> {
coldkey: &T::AccountId,
netuid: u16,
tao: u64,
fee: u64,
) -> u64 {
// Step 1. Reduce tao amount by staking fee and credit this fee to SubnetTAO
// At this point tao was already withdrawn from the user balance and is considered
// At this point tao was already withdrawn from the user balance and is considered
// available
let fee = DefaultMinStake::<T>::get();
let tao_staked = tao.saturating_sub(fee);
let actual_fee = tao.saturating_sub(tao_staked);

Expand All @@ -686,6 +687,9 @@ impl<T: Config> Pallet<T> {
SubnetTAO::<T>::mutate(netuid, |total| {
*total = total.saturating_add(actual_fee);
});
TotalStake::<T>::mutate(|total| {
*total = total.saturating_add(actual_fee);
});

// Step 6. Deposit and log the staking event.
Self::deposit_event(Event::StakeAdded(
Expand Down
3 changes: 2 additions & 1 deletion pallets/subtensor/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,8 @@ pub fn increase_stake_on_coldkey_hotkey_account(
tao_staked: u64,
netuid: u16,
) {
SubtensorModule::stake_into_subnet(hotkey, coldkey, netuid, tao_staked);
let fee = 0;
SubtensorModule::stake_into_subnet(hotkey, coldkey, netuid, tao_staked, fee);
}

/// Increases the stake on the hotkey account under its owning coldkey.
Expand Down
Loading

0 comments on commit a516c2b

Please sign in to comment.