Skip to content

Commit 7df774b

Browse files
committed
Merge branch 'devnet-ready' into fix/remove-dynamic-fee
2 parents 8cd99e7 + 9958450 commit 7df774b

File tree

13 files changed

+1122
-119
lines changed

13 files changed

+1122
-119
lines changed

pallets/subtensor/src/lib.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,6 +1887,8 @@ where
18871887
*origin_netuid,
18881888
*destination_netuid,
18891889
*alpha_amount,
1890+
*alpha_amount,
1891+
None,
18901892
))
18911893
}
18921894
Some(Call::transfer_stake {
@@ -1905,6 +1907,8 @@ where
19051907
*origin_netuid,
19061908
*destination_netuid,
19071909
*alpha_amount,
1910+
*alpha_amount,
1911+
None,
19081912
))
19091913
}
19101914
Some(Call::swap_stake {
@@ -1922,6 +1926,36 @@ where
19221926
*origin_netuid,
19231927
*destination_netuid,
19241928
*alpha_amount,
1929+
*alpha_amount,
1930+
None,
1931+
))
1932+
}
1933+
Some(Call::swap_stake_limit {
1934+
hotkey,
1935+
origin_netuid,
1936+
destination_netuid,
1937+
alpha_amount,
1938+
limit_price,
1939+
allow_partial,
1940+
}) => {
1941+
// Get the max amount possible to exchange
1942+
let max_amount = Pallet::<T>::get_max_amount_move(
1943+
*origin_netuid,
1944+
*destination_netuid,
1945+
*limit_price,
1946+
);
1947+
1948+
// Fully validate the user input
1949+
Self::result_to_validity(Pallet::<T>::validate_stake_transition(
1950+
who,
1951+
who,
1952+
hotkey,
1953+
hotkey,
1954+
*origin_netuid,
1955+
*destination_netuid,
1956+
*alpha_amount,
1957+
max_amount,
1958+
Some(*allow_partial),
19251959
))
19261960
}
19271961
Some(Call::register { netuid, .. } | Call::burned_register { netuid, .. }) => {

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,10 +1769,10 @@ mod dispatches {
17691769
/// - The amount of stake to be added to the hotkey staking account.
17701770
///
17711771
/// * 'limit_price' (u64):
1772-
/// - The limit price expressed in units of RAO per one Alpha.
1772+
/// - The limit price expressed in units of RAO per one Alpha.
17731773
///
17741774
/// * 'allow_partial' (bool):
1775-
/// - Allows partial execution of the amount. If set to false, this becomes
1775+
/// - Allows partial execution of the amount. If set to false, this becomes
17761776
/// fill or kill type or order.
17771777
///
17781778
/// # Event:
@@ -1811,5 +1811,52 @@ mod dispatches {
18111811
allow_partial,
18121812
)
18131813
}
1814+
1815+
/// Swaps a specified amount of stake from one subnet to another, while keeping the same coldkey and hotkey.
1816+
///
1817+
/// # Arguments
1818+
/// * `origin` - The origin of the transaction, which must be signed by the coldkey that owns the `hotkey`.
1819+
/// * `hotkey` - The hotkey whose stake is being swapped.
1820+
/// * `origin_netuid` - The network/subnet ID from which stake is removed.
1821+
/// * `destination_netuid` - The network/subnet ID to which stake is added.
1822+
/// * `alpha_amount` - The amount of stake to swap.
1823+
/// * `limit_price` - The limit price expressed in units of RAO per one Alpha.
1824+
/// * `allow_partial` - Allows partial execution of the amount. If set to false, this becomes fill or kill type or order.
1825+
///
1826+
/// # Errors
1827+
/// Returns an error if:
1828+
/// * The transaction is not signed by the correct coldkey (i.e., `coldkey_owns_hotkey` fails).
1829+
/// * Either `origin_netuid` or `destination_netuid` does not exist.
1830+
/// * The hotkey does not exist.
1831+
/// * There is insufficient stake on `(coldkey, hotkey, origin_netuid)`.
1832+
/// * The swap amount is below the minimum stake requirement.
1833+
///
1834+
/// # Events
1835+
/// May emit a `StakeSwapped` event on success.
1836+
#[pallet::call_index(90)]
1837+
#[pallet::weight((
1838+
Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().writes(1)),
1839+
DispatchClass::Operational,
1840+
Pays::No
1841+
))]
1842+
pub fn swap_stake_limit(
1843+
origin: T::RuntimeOrigin,
1844+
hotkey: T::AccountId,
1845+
origin_netuid: u16,
1846+
destination_netuid: u16,
1847+
alpha_amount: u64,
1848+
limit_price: u64,
1849+
allow_partial: bool,
1850+
) -> DispatchResult {
1851+
Self::do_swap_stake_limit(
1852+
origin,
1853+
hotkey,
1854+
origin_netuid,
1855+
destination_netuid,
1856+
alpha_amount,
1857+
limit_price,
1858+
allow_partial,
1859+
)
1860+
}
18141861
}
18151862
}

pallets/subtensor/src/macros/hooks.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ mod hooks {
7676
// Migrate to RAO
7777
.saturating_add(migrations::migrate_rao::migrate_rao::<T>())
7878
// Fix the IsNetworkMember map to be consistent with other storage maps
79-
.saturating_add(migrations::migrate_fix_is_network_member::migrate_fix_is_network_member::<T>());
79+
.saturating_add(migrations::migrate_fix_is_network_member::migrate_fix_is_network_member::<T>())
80+
.saturating_add(migrations::migrate_subnet_volume::migrate_subnet_volume::<T>());
8081
weight
8182
}
8283

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use super::*;
2+
use alloc::string::String;
3+
use frame_support::{traits::Get, weights::Weight};
4+
5+
pub fn migrate_subnet_volume<T: Config>() -> Weight {
6+
let migration_name = b"migrate_subnet_volume".to_vec();
7+
8+
// Initialize the weight with one read operation.
9+
let weight = T::DbWeight::get().reads(1);
10+
11+
// Check if the migration has already run
12+
if HasMigrationRun::<T>::get(&migration_name) {
13+
log::info!(
14+
"Migration '{:?}' has already run. Skipping.",
15+
migration_name
16+
);
17+
return weight;
18+
}
19+
log::info!(
20+
"Running migration '{}'",
21+
String::from_utf8_lossy(&migration_name)
22+
);
23+
24+
let mut migrated = 0u64;
25+
26+
SubnetVolume::<T>::translate::<u64, _>(|_key, old_value| {
27+
migrated = migrated.saturating_add(1);
28+
Some(old_value as u128) // Convert and store as u128
29+
});
30+
31+
log::info!("Migrated {} entries in SubnetVolume", migrated);
32+
weight.saturating_add(T::DbWeight::get().reads_writes(migrated, migrated))
33+
}

pallets/subtensor/src/migrations/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub mod migrate_populate_owned_hotkeys;
1111
pub mod migrate_populate_staking_hotkeys;
1212
pub mod migrate_rao;
1313
pub mod migrate_stake_threshold;
14+
pub mod migrate_subnet_volume;
1415
pub mod migrate_to_v1_separate_emission;
1516
pub mod migrate_to_v2_fixed_total_stake;
1617
pub mod migrate_total_issuance;

pallets/subtensor/src/staking/add_stake.rs

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

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

179177
// Corner case: SubnetTAO is zero. Staking can't happen, so max amount is zero.
180178
let tao_reserve = SubnetTAO::<T>::get(netuid);
181179
if tao_reserve == 0 {
182180
return 0;
183181
}
184-
let tao_reserve_float: U96F32 = U96F32::saturating_from_num(tao_reserve);
182+
let tao_reserve_u128 = tao_reserve as u128;
185183

186184
// Corner case: limit_price < current_price (price cannot decrease with staking)
187-
let limit_price_float: U96F32 = U96F32::saturating_from_num(limit_price)
188-
.checked_div(U96F32::saturating_from_num(1_000_000_000))
189-
.unwrap_or(U96F32::saturating_from_num(0));
190-
if limit_price_float < Self::get_alpha_price(netuid) {
185+
let tao = 1_000_000_000_u128;
186+
let limit_price_u128 = limit_price as u128;
187+
if (limit_price_u128
188+
< Self::get_alpha_price(netuid)
189+
.saturating_to_num::<u128>()
190+
.saturating_mul(tao))
191+
|| (limit_price == 0u64)
192+
{
191193
return 0;
192194
}
193195

194-
// Main case: return SQRT(limit_price * SubnetTAO * SubnetAlphaIn) - SubnetTAO
195-
// This is the positive solution of quare equation for finding additional TAO from
196-
// limit_price.
197-
let zero: U96F32 = U96F32::saturating_from_num(0.0);
198-
let epsilon: U96F32 = U96F32::saturating_from_num(0.1);
199-
let sqrt: U96F32 =
200-
checked_sqrt(limit_price_float.saturating_mul(tao_reserve_float), epsilon)
201-
.unwrap_or(zero)
202-
.saturating_mul(checked_sqrt(alpha_in_float, epsilon).unwrap_or(zero));
203-
204-
sqrt.saturating_sub(U96F32::saturating_from_num(tao_reserve_float))
205-
.saturating_to_num::<u64>()
196+
// Main case: return limit_price * SubnetAlphaIn - SubnetTAO
197+
// Non overflowing calculation: limit_price * alpha_in <= u64::MAX * u64::MAX <= u128::MAX
198+
// May overflow result, then it will be capped at u64::MAX, which is OK because that matches balance u64 size.
199+
let result = limit_price_u128
200+
.saturating_mul(alpha_in_u128)
201+
.checked_div(tao)
202+
.unwrap_or(0)
203+
.saturating_sub(tao_reserve_u128);
204+
if result < u64::MAX as u128 {
205+
result as u64
206+
} else {
207+
u64::MAX
208+
}
206209
}
207210
}

0 commit comments

Comments
 (0)