Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,8 @@ where
*origin_netuid,
*destination_netuid,
*alpha_amount,
*alpha_amount,
None,
))
}
Some(Call::transfer_stake {
Expand All @@ -1905,6 +1907,8 @@ where
*origin_netuid,
*destination_netuid,
*alpha_amount,
*alpha_amount,
None,
))
}
Some(Call::swap_stake {
Expand All @@ -1922,6 +1926,36 @@ where
*origin_netuid,
*destination_netuid,
*alpha_amount,
*alpha_amount,
None,
))
}
Some(Call::swap_stake_limit {
hotkey,
origin_netuid,
destination_netuid,
alpha_amount,
limit_price,
allow_partial,
}) => {
// Get the max amount possible to exchange
let max_amount = Pallet::<T>::get_max_amount_move(
*origin_netuid,
*destination_netuid,
*limit_price,
);

// Fully validate the user input
Self::result_to_validity(Pallet::<T>::validate_stake_transition(
who,
who,
hotkey,
hotkey,
*origin_netuid,
*destination_netuid,
*alpha_amount,
max_amount,
Some(*allow_partial),
))
}
Some(Call::register { netuid, .. } | Call::burned_register { netuid, .. }) => {
Expand Down
51 changes: 49 additions & 2 deletions pallets/subtensor/src/macros/dispatches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1769,10 +1769,10 @@ mod dispatches {
/// - The amount of stake to be added to the hotkey staking account.
///
/// * 'limit_price' (u64):
/// - The limit price expressed in units of RAO per one Alpha.
/// - The limit price expressed in units of RAO per one Alpha.
///
/// * 'allow_partial' (bool):
/// - Allows partial execution of the amount. If set to false, this becomes
/// - Allows partial execution of the amount. If set to false, this becomes
/// fill or kill type or order.
///
/// # Event:
Expand Down Expand Up @@ -1811,5 +1811,52 @@ mod dispatches {
allow_partial,
)
}

/// Swaps a specified amount of stake from one subnet to another, while keeping the same coldkey and hotkey.
///
/// # Arguments
/// * `origin` - The origin of the transaction, which must be signed by the coldkey that owns the `hotkey`.
/// * `hotkey` - The hotkey whose stake is being swapped.
/// * `origin_netuid` - The network/subnet ID from which stake is removed.
/// * `destination_netuid` - The network/subnet ID to which stake is added.
/// * `alpha_amount` - The amount of stake to swap.
/// * `limit_price` - The limit price expressed in units of RAO per one Alpha.
/// * `allow_partial` - Allows partial execution of the amount. If set to false, this becomes fill or kill type or order.
///
/// # Errors
/// Returns an error if:
/// * The transaction is not signed by the correct coldkey (i.e., `coldkey_owns_hotkey` fails).
/// * Either `origin_netuid` or `destination_netuid` does not exist.
/// * The hotkey does not exist.
/// * There is insufficient stake on `(coldkey, hotkey, origin_netuid)`.
/// * The swap amount is below the minimum stake requirement.
///
/// # Events
/// May emit a `StakeSwapped` event on success.
#[pallet::call_index(90)]
#[pallet::weight((
Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().writes(1)),
DispatchClass::Operational,
Pays::No
))]
pub fn swap_stake_limit(
origin: T::RuntimeOrigin,
hotkey: T::AccountId,
origin_netuid: u16,
destination_netuid: u16,
alpha_amount: u64,
limit_price: u64,
allow_partial: bool,
) -> DispatchResult {
Self::do_swap_stake_limit(
origin,
hotkey,
origin_netuid,
destination_netuid,
alpha_amount,
limit_price,
allow_partial,
)
}
}
}
43 changes: 23 additions & 20 deletions pallets/subtensor/src/staking/add_stake.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use super::*;
use safe_math::*;
use sp_core::Get;
use substrate_fixed::types::U96F32;

impl<T: Config> Pallet<T> {
/// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account.
Expand Down Expand Up @@ -174,34 +172,39 @@ impl<T: Config> Pallet<T> {
if alpha_in == 0 {
return 0;
}
let alpha_in_float: U96F32 = U96F32::saturating_from_num(alpha_in);
let alpha_in_u128 = alpha_in as u128;

// Corner case: SubnetTAO is zero. Staking can't happen, so max amount is zero.
let tao_reserve = SubnetTAO::<T>::get(netuid);
if tao_reserve == 0 {
return 0;
}
let tao_reserve_float: U96F32 = U96F32::saturating_from_num(tao_reserve);
let tao_reserve_u128 = tao_reserve as u128;

// Corner case: limit_price < current_price (price cannot decrease with staking)
let limit_price_float: U96F32 = U96F32::saturating_from_num(limit_price)
.checked_div(U96F32::saturating_from_num(1_000_000_000))
.unwrap_or(U96F32::saturating_from_num(0));
if limit_price_float < Self::get_alpha_price(netuid) {
let tao = 1_000_000_000_u128;
let limit_price_u128 = limit_price as u128;
if (limit_price_u128
< Self::get_alpha_price(netuid)
.saturating_to_num::<u128>()
.saturating_mul(tao))
|| (limit_price == 0u64)
{
return 0;
}

// Main case: return SQRT(limit_price * SubnetTAO * SubnetAlphaIn) - SubnetTAO
// This is the positive solution of quare equation for finding additional TAO from
// limit_price.
let zero: U96F32 = U96F32::saturating_from_num(0.0);
let epsilon: U96F32 = U96F32::saturating_from_num(0.1);
let sqrt: U96F32 =
checked_sqrt(limit_price_float.saturating_mul(tao_reserve_float), epsilon)
.unwrap_or(zero)
.saturating_mul(checked_sqrt(alpha_in_float, epsilon).unwrap_or(zero));

sqrt.saturating_sub(U96F32::saturating_from_num(tao_reserve_float))
.saturating_to_num::<u64>()
// Main case: return limit_price * SubnetAlphaIn - SubnetTAO
// Non overflowing calculation: limit_price * alpha_in <= u64::MAX * u64::MAX <= u128::MAX
// May overflow result, then it will be capped at u64::MAX, which is OK because that matches balance u64 size.
let result = limit_price_u128
.saturating_mul(alpha_in_u128)
.checked_div(tao)
.unwrap_or(0)
.saturating_sub(tao_reserve_u128);
if result < u64::MAX as u128 {
result as u64
} else {
u64::MAX
}
}
}
Loading
Loading