From bc8c514aa39b307c7e8a944152d189641cba16ff Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Tue, 10 Dec 2024 21:15:23 +0800
Subject: [PATCH 001/145] add subnet precompile contract

---
 runtime/src/precompiles/mod.rs              |  98 +++++++++++-
 runtime/src/precompiles/solidity/subnet.abi |  32 ++++
 runtime/src/precompiles/solidity/subnet.sol |  10 ++
 runtime/src/precompiles/staking.rs          | 160 ++++++++++----------
 runtime/src/precompiles/subnet.rs           | 130 ++++++++++++++++
 5 files changed, 345 insertions(+), 85 deletions(-)
 create mode 100644 runtime/src/precompiles/solidity/subnet.abi
 create mode 100644 runtime/src/precompiles/solidity/subnet.sol
 create mode 100644 runtime/src/precompiles/subnet.rs

diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index 22f2a4881..ff8efa599 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -3,21 +3,35 @@ use sp_core::{hashing::keccak_256, H160};
 use sp_runtime::AccountId32;
 
 use pallet_evm::{
-    ExitError, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
+    AddressMapping, BalanceConverter, ExitError, ExitSucceed, HashedAddressMapping,
+    IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput,
     PrecompileResult, PrecompileSet,
 };
 use pallet_evm_precompile_modexp::Modexp;
 use pallet_evm_precompile_sha3fips::Sha3FIPS256;
 use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256};
 
+use frame_system::RawOrigin;
+
+use sp_core::crypto::Ss58Codec;
+use sp_core::U256;
+use sp_runtime::traits::Dispatchable;
+use sp_runtime::traits::{BlakeTwo256, UniqueSaturatedInto};
+
+use sp_std::vec;
+
+use crate::{Runtime, RuntimeCall};
+
 // Include custom precompiles
 mod balance_transfer;
 mod ed25519;
 mod staking;
+mod subnet;
 
 use balance_transfer::*;
 use ed25519::*;
 use staking::*;
+use subnet::*;
 
 pub struct FrontierPrecompiles<R>(PhantomData<R>);
 
@@ -37,7 +51,7 @@ where
     pub fn new() -> Self {
         Self(Default::default())
     }
-    pub fn used_addresses() -> [H160; 10] {
+    pub fn used_addresses() -> [H160; 11] {
         [
             hash(1),
             hash(2),
@@ -49,6 +63,7 @@ where
             hash(EDVERIFY_PRECOMPILE_INDEX),
             hash(BALANCE_TRANSFER_INDEX),
             hash(STAKING_PRECOMPILE_INDEX),
+            hash(SUBNET_PRECOMPILE_INDEX),
         ]
     }
 }
@@ -73,6 +88,7 @@ where
                 Some(BalanceTransferPrecompile::execute(handle))
             }
             a if a == hash(STAKING_PRECOMPILE_INDEX) => Some(StakingPrecompile::execute(handle)),
+            a if a == hash(SUBNET_PRECOMPILE_INDEX) => Some(SubnetPrecompile::execute(handle)),
             _ => None,
         }
     }
@@ -118,8 +134,86 @@ pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], Precompil
     if let Some(slice) = maybe_slice {
         Ok(slice)
     } else {
+        log::error!(
+            "fail to get slice from data, {:?}, from {}, to {}",
+            &data,
+            from,
+            to
+        );
         Err(PrecompileFailure::Error {
             exit_status: ExitError::InvalidRange,
         })
     }
 }
+
+fn transfer_back_to_caller(
+    account_id: &AccountId32,
+    amount: U256,
+) -> Result<(), PrecompileFailure> {
+    // this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
+    let smart_contract_account_id =
+        match AccountId32::from_ss58check("5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X") {
+            Ok(addr) => addr,
+            Err(_) => {
+                return Err(PrecompileFailure::Error {
+                    exit_status: ExitError::Other("Invalid SS58 address".into()),
+                });
+            }
+        };
+    let amount_sub =
+        <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
+            .ok_or(ExitError::OutOfFund)?;
+
+    // Create a transfer call from the smart contract to the caller
+    let transfer_call =
+        RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
+            dest: account_id.clone().into(),
+            value: amount_sub.unique_saturated_into(),
+        });
+
+    // Execute the transfer
+    let transfer_result =
+        transfer_call.dispatch(RawOrigin::Signed(smart_contract_account_id).into());
+
+    if let Err(dispatch_error) = transfer_result {
+        log::error!(
+            "Transfer back to caller failed. Error: {:?}",
+            dispatch_error
+        );
+        return Err(PrecompileFailure::Error {
+            exit_status: ExitError::Other("Transfer back to caller failed".into()),
+        });
+    }
+
+    Ok(())
+}
+
+fn dispatch(handle: &mut impl PrecompileHandle, call: RuntimeCall) -> PrecompileResult {
+    let account_id =
+        <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
+            handle.context().caller,
+        );
+
+    // Transfer the amount back to the caller before executing the staking operation
+    // let caller = handle.context().caller;
+    let amount = handle.context().apparent_value;
+
+    if !amount.is_zero() {
+        transfer_back_to_caller(&account_id, amount)?;
+    }
+
+    let result = call.dispatch(RawOrigin::Signed(account_id.clone()).into());
+    match &result {
+        Ok(post_info) => log::info!("Dispatch succeeded. Post info: {:?}", post_info),
+        Err(dispatch_error) => log::error!("Dispatch failed. Error: {:?}", dispatch_error),
+    }
+    match result {
+        Ok(_) => Ok(PrecompileOutput {
+            exit_status: ExitSucceed::Returned,
+            output: vec![],
+        }),
+        Err(_) => Err(PrecompileFailure::Error {
+            exit_status: ExitError::Other("Subtensor call failed".into()),
+        }),
+    }
+}
diff --git a/runtime/src/precompiles/solidity/subnet.abi b/runtime/src/precompiles/solidity/subnet.abi
new file mode 100644
index 000000000..a89cf91f1
--- /dev/null
+++ b/runtime/src/precompiles/solidity/subnet.abi
@@ -0,0 +1,32 @@
+[
+    {
+        "inputs": [
+            {
+                "internalType": "bytes",
+                "name": "subnetName",
+                "type": "bytes"
+            },
+            {
+                "internalType": "bytes",
+                "name": "githubRepo",
+                "type": "bytes"
+            },
+            {
+                "internalType": "bytes",
+                "name": "subnetContact",
+                "type": "bytes"
+            }
+        ],
+        "name": "registerNetwork",
+        "outputs": [],
+        "stateMutability": "payable",
+        "type": "function"
+    },
+    {
+        "inputs": [],
+        "name": "registerNetwork",
+        "outputs": [],
+        "stateMutability": "payable",
+        "type": "function"
+    }
+]
\ No newline at end of file
diff --git a/runtime/src/precompiles/solidity/subnet.sol b/runtime/src/precompiles/solidity/subnet.sol
new file mode 100644
index 000000000..e2857ad63
--- /dev/null
+++ b/runtime/src/precompiles/solidity/subnet.sol
@@ -0,0 +1,10 @@
+pragma solidity ^0.8.0;
+
+address constant ISTAKING_ADDRESS = 0x0000000000000000000000000000000000000803;
+
+interface ISubnet {
+  /// Registers a new network without specifying details.
+  function registerNetwork() external payable;
+  /// Registers a new network with specified subnet name, GitHub repository, and contact information.
+  function registerNetwork(bytes subnetName, bytes githubRepo, bytes subnetContact) external payable;
+}
\ No newline at end of file
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index e6237dfcf..fc1e7b512 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -25,18 +25,12 @@
 //   - Precompile checks the result of do_remove_stake and, in case of a failure, reverts the transaction.
 //
 
-use frame_system::RawOrigin;
-use pallet_evm::{AddressMapping, BalanceConverter, HashedAddressMapping};
-use pallet_evm::{
-    ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
-};
-use sp_core::crypto::Ss58Codec;
+use pallet_evm::BalanceConverter;
+use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
 use sp_core::U256;
-use sp_runtime::traits::Dispatchable;
-use sp_runtime::traits::{BlakeTwo256, UniqueSaturatedInto};
-use sp_runtime::AccountId32;
+use sp_runtime::traits::UniqueSaturatedInto;
 
-use crate::precompiles::{get_method_id, get_slice};
+use crate::precompiles::{dispatch, get_method_id, get_slice};
 use sp_std::vec;
 
 use crate::{Runtime, RuntimeCall};
@@ -78,7 +72,7 @@ impl StakingPrecompile {
             amount_staked: amount_sub.unique_saturated_into(),
         });
         // Dispatch the add_stake call
-        Self::dispatch(handle, call)
+        dispatch(handle, call)
     }
     fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
         let hotkey = Self::parse_hotkey(data)?.into();
@@ -98,7 +92,7 @@ impl StakingPrecompile {
             hotkey,
             amount_unstaked: amount_sub.unique_saturated_into(),
         });
-        Self::dispatch(handle, call)
+        dispatch(handle, call)
     }
 
     fn parse_hotkey(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> {
@@ -112,75 +106,75 @@ impl StakingPrecompile {
         Ok(hotkey)
     }
 
-    fn dispatch(handle: &mut impl PrecompileHandle, call: RuntimeCall) -> PrecompileResult {
-        let account_id =
-            <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
-                handle.context().caller,
-            );
-
-        // Transfer the amount back to the caller before executing the staking operation
-        // let caller = handle.context().caller;
-        let amount = handle.context().apparent_value;
-
-        if !amount.is_zero() {
-            Self::transfer_back_to_caller(&account_id, amount)?;
-        }
-
-        let result = call.dispatch(RawOrigin::Signed(account_id.clone()).into());
-        match &result {
-            Ok(post_info) => log::info!("Dispatch succeeded. Post info: {:?}", post_info),
-            Err(dispatch_error) => log::error!("Dispatch failed. Error: {:?}", dispatch_error),
-        }
-        match result {
-            Ok(_) => Ok(PrecompileOutput {
-                exit_status: ExitSucceed::Returned,
-                output: vec![],
-            }),
-            Err(_) => Err(PrecompileFailure::Error {
-                exit_status: ExitError::Other("Subtensor call failed".into()),
-            }),
-        }
-    }
-
-    fn transfer_back_to_caller(
-        account_id: &AccountId32,
-        amount: U256,
-    ) -> Result<(), PrecompileFailure> {
-        // this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
-        let smart_contract_account_id =
-            match AccountId32::from_ss58check("5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X") {
-                Ok(addr) => addr,
-                Err(_) => {
-                    return Err(PrecompileFailure::Error {
-                        exit_status: ExitError::Other("Invalid SS58 address".into()),
-                    });
-                }
-            };
-        let amount_sub =
-            <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
-                .ok_or(ExitError::OutOfFund)?;
-
-        // Create a transfer call from the smart contract to the caller
-        let transfer_call =
-            RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
-                dest: account_id.clone().into(),
-                value: amount_sub.unique_saturated_into(),
-            });
-
-        // Execute the transfer
-        let transfer_result =
-            transfer_call.dispatch(RawOrigin::Signed(smart_contract_account_id).into());
-
-        if let Err(dispatch_error) = transfer_result {
-            log::error!(
-                "Transfer back to caller failed. Error: {:?}",
-                dispatch_error
-            );
-            return Err(PrecompileFailure::Error {
-                exit_status: ExitError::Other("Transfer back to caller failed".into()),
-            });
-        }
-
-        Ok(())
-    }
+    // fn dispatch(handle: &mut impl PrecompileHandle, call: RuntimeCall) -> PrecompileResult {
+    //     let account_id =
+    //         <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
+    //             handle.context().caller,
+    //         );
+
+    //     // Transfer the amount back to the caller before executing the staking operation
+    //     // let caller = handle.context().caller;
+    //     let amount = handle.context().apparent_value;
+
+    //     if !amount.is_zero() {
+    //         Self::transfer_back_to_caller(&account_id, amount)?;
+    //     }
+
+    //     let result = call.dispatch(RawOrigin::Signed(account_id.clone()).into());
+    //     match &result {
+    //         Ok(post_info) => log::info!("Dispatch succeeded. Post info: {:?}", post_info),
+    //         Err(dispatch_error) => log::error!("Dispatch failed. Error: {:?}", dispatch_error),
+    //     }
+    //     match result {
+    //         Ok(_) => Ok(PrecompileOutput {
+    //             exit_status: ExitSucceed::Returned,
+    //             output: vec![],
+    //         }),
+    //         Err(_) => Err(PrecompileFailure::Error {
+    //             exit_status: ExitError::Other("Subtensor call failed".into()),
+    //         }),
+    //     }
+    // }
+
+    // fn transfer_back_to_caller(
+    //     account_id: &AccountId32,
+    //     amount: U256,
+    // ) -> Result<(), PrecompileFailure> {
+    //     // this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
+    //     let smart_contract_account_id =
+    //         match AccountId32::from_ss58check("5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X") {
+    //             Ok(addr) => addr,
+    //             Err(_) => {
+    //                 return Err(PrecompileFailure::Error {
+    //                     exit_status: ExitError::Other("Invalid SS58 address".into()),
+    //                 });
+    //             }
+    //         };
+    //     let amount_sub =
+    //         <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
+    //             .ok_or(ExitError::OutOfFund)?;
+
+    //     // Create a transfer call from the smart contract to the caller
+    //     let transfer_call =
+    //         RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
+    //             dest: account_id.clone().into(),
+    //             value: amount_sub.unique_saturated_into(),
+    //         });
+
+    //     // Execute the transfer
+    //     let transfer_result =
+    //         transfer_call.dispatch(RawOrigin::Signed(smart_contract_account_id).into());
+
+    //     if let Err(dispatch_error) = transfer_result {
+    //         log::error!(
+    //             "Transfer back to caller failed. Error: {:?}",
+    //             dispatch_error
+    //         );
+    //         return Err(PrecompileFailure::Error {
+    //             exit_status: ExitError::Other("Transfer back to caller failed".into()),
+    //         });
+    //     }
+
+    //     Ok(())
+    // }
 }
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
new file mode 100644
index 000000000..a74bbf53a
--- /dev/null
+++ b/runtime/src/precompiles/subnet.rs
@@ -0,0 +1,130 @@
+use crate::precompiles::{dispatch, get_method_id, get_slice};
+use crate::{Runtime, RuntimeCall};
+use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
+use sp_std::vec;
+
+pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051;
+// three bytes with max lenght 1K
+pub const MAX_PARAMETER_SIZE: usize = 3 * 1024;
+
+pub struct SubnetPrecompile;
+
+impl SubnetPrecompile {
+    pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
+        let txdata = handle.input();
+        if txdata.len() > MAX_PARAMETER_SIZE {
+            log::error!("the length of subnet call is {} ", txdata.len());
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
+        let method_id = get_slice(txdata, 0, 4)?;
+        let method_input = txdata
+            .get(4..)
+            .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts
+
+        match method_id {
+            id if id == get_method_id("registerNetwork(bytes,bytes,bytes)") => {
+                Self::register_network(handle, &method_input)
+            }
+            id if id == get_method_id("registerNetwork()") => {
+                Self::register_network(handle, &[0_u8; 0])
+            }
+            _ => Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            }),
+        }
+    }
+
+    fn register_network(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
+        let call = if data.is_empty() {
+            RuntimeCall::SubtensorModule(
+                pallet_subtensor::Call::<Runtime>::register_network_with_identity {
+                    identity: None,
+                },
+            )
+        } else {
+            let (subnet_name, github_repo, subnet_contact) =
+                Self::parse_register_network_parameters(data)?;
+
+            let identity: pallet_subtensor::SubnetIdentityOf = pallet_subtensor::SubnetIdentityOf {
+                subnet_name,
+                github_repo,
+                subnet_contact,
+            };
+
+            // Create the register_network callcle
+            RuntimeCall::SubtensorModule(
+                pallet_subtensor::Call::<Runtime>::register_network_with_identity {
+                    identity: Some(identity),
+                },
+            )
+        };
+
+        // Dispatch the register_network call
+        dispatch(handle, call)
+    }
+
+    fn parse_register_network_parameters(
+        data: &[u8],
+    ) -> Result<(vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {
+        let mut buf = [0_u8; 4];
+
+        // get all start point for three data items: name, repo and contact
+        buf.copy_from_slice(get_slice(data, 28, 32)?);
+        let subnet_name_start: usize = u32::from_be_bytes(buf) as usize;
+
+        buf.copy_from_slice(get_slice(data, 60, 64)?);
+        let github_repo_start: usize = u32::from_be_bytes(buf) as usize;
+
+        buf.copy_from_slice(get_slice(data, 92, 96)?);
+        let subnet_contact_start: usize = u32::from_be_bytes(buf) as usize;
+
+        // get name
+        buf.copy_from_slice(get_slice(
+            data,
+            subnet_name_start + 28,
+            subnet_name_start + 32,
+        )?);
+        let subnet_name_len: usize = u32::from_be_bytes(buf) as usize;
+
+        let mut name_vec = vec![0; subnet_name_len];
+        name_vec.copy_from_slice(get_slice(
+            data,
+            subnet_name_start + 32,
+            subnet_name_start + subnet_name_len + 32,
+        )?);
+
+        // get repo data
+        buf.copy_from_slice(get_slice(
+            data,
+            github_repo_start + 28,
+            github_repo_start + 32,
+        )?);
+        let github_repo_len: usize = u32::from_be_bytes(buf) as usize;
+
+        let mut repo_vec = vec![0; github_repo_len];
+        repo_vec.copy_from_slice(get_slice(
+            data,
+            github_repo_start + 32,
+            github_repo_start + github_repo_len + 32,
+        )?);
+
+        // get contact data
+        buf.copy_from_slice(get_slice(
+            data,
+            subnet_contact_start + 28,
+            subnet_contact_start + 32,
+        )?);
+        let subnet_contact_len: usize = u32::from_be_bytes(buf) as usize;
+
+        let mut contact_vec = vec![0; subnet_contact_len];
+        contact_vec.copy_from_slice(get_slice(
+            data,
+            subnet_contact_start + 32,
+            subnet_contact_start + subnet_contact_len + 32,
+        )?);
+
+        Ok((name_vec, repo_vec, contact_vec))
+    }
+}

From 157032bc03c1341adb5651ec481902584572034a Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Tue, 10 Dec 2024 23:55:11 +0800
Subject: [PATCH 002/145] remove commented code

---
 runtime/src/precompiles/staking.rs | 72 ------------------------------
 1 file changed, 72 deletions(-)

diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index fc1e7b512..e8d33c05e 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -105,76 +105,4 @@ impl StakingPrecompile {
         hotkey.copy_from_slice(get_slice(data, 0, 32)?);
         Ok(hotkey)
     }
-
-    // fn dispatch(handle: &mut impl PrecompileHandle, call: RuntimeCall) -> PrecompileResult {
-    //     let account_id =
-    //         <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
-    //             handle.context().caller,
-    //         );
-
-    //     // Transfer the amount back to the caller before executing the staking operation
-    //     // let caller = handle.context().caller;
-    //     let amount = handle.context().apparent_value;
-
-    //     if !amount.is_zero() {
-    //         Self::transfer_back_to_caller(&account_id, amount)?;
-    //     }
-
-    //     let result = call.dispatch(RawOrigin::Signed(account_id.clone()).into());
-    //     match &result {
-    //         Ok(post_info) => log::info!("Dispatch succeeded. Post info: {:?}", post_info),
-    //         Err(dispatch_error) => log::error!("Dispatch failed. Error: {:?}", dispatch_error),
-    //     }
-    //     match result {
-    //         Ok(_) => Ok(PrecompileOutput {
-    //             exit_status: ExitSucceed::Returned,
-    //             output: vec![],
-    //         }),
-    //         Err(_) => Err(PrecompileFailure::Error {
-    //             exit_status: ExitError::Other("Subtensor call failed".into()),
-    //         }),
-    //     }
-    // }
-
-    // fn transfer_back_to_caller(
-    //     account_id: &AccountId32,
-    //     amount: U256,
-    // ) -> Result<(), PrecompileFailure> {
-    //     // this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
-    //     let smart_contract_account_id =
-    //         match AccountId32::from_ss58check("5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X") {
-    //             Ok(addr) => addr,
-    //             Err(_) => {
-    //                 return Err(PrecompileFailure::Error {
-    //                     exit_status: ExitError::Other("Invalid SS58 address".into()),
-    //                 });
-    //             }
-    //         };
-    //     let amount_sub =
-    //         <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
-    //             .ok_or(ExitError::OutOfFund)?;
-
-    //     // Create a transfer call from the smart contract to the caller
-    //     let transfer_call =
-    //         RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
-    //             dest: account_id.clone().into(),
-    //             value: amount_sub.unique_saturated_into(),
-    //         });
-
-    //     // Execute the transfer
-    //     let transfer_result =
-    //         transfer_call.dispatch(RawOrigin::Signed(smart_contract_account_id).into());
-
-    //     if let Err(dispatch_error) = transfer_result {
-    //         log::error!(
-    //             "Transfer back to caller failed. Error: {:?}",
-    //             dispatch_error
-    //         );
-    //         return Err(PrecompileFailure::Error {
-    //             exit_status: ExitError::Other("Transfer back to caller failed".into()),
-    //         });
-    //     }
-
-    //     Ok(())
-    // }
 }

From 5435ccd467dd53a8200285c52550070a5ee05801 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Wed, 11 Dec 2024 00:17:09 +0800
Subject: [PATCH 003/145] refactor code

---
 runtime/src/precompiles/mod.rs     | 28 +++++++++++++++++-----------
 runtime/src/precompiles/staking.rs |  8 +++++---
 runtime/src/precompiles/subnet.rs  |  6 +++++-
 3 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index ff8efa599..7f54d2e3c 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -146,20 +146,22 @@ pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], Precompil
     }
 }
 
+/// The function return the token to smart contract
 fn transfer_back_to_caller(
+    smart_contract_address: &str,
     account_id: &AccountId32,
     amount: U256,
 ) -> Result<(), PrecompileFailure> {
     // this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
-    let smart_contract_account_id =
-        match AccountId32::from_ss58check("5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X") {
-            Ok(addr) => addr,
-            Err(_) => {
-                return Err(PrecompileFailure::Error {
-                    exit_status: ExitError::Other("Invalid SS58 address".into()),
-                });
-            }
-        };
+    let smart_contract_account_id = match AccountId32::from_ss58check(smart_contract_address) {
+        // match AccountId32::from_ss58check("5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X") {
+        Ok(addr) => addr,
+        Err(_) => {
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::Other("Invalid SS58 address".into()),
+            });
+        }
+    };
     let amount_sub =
         <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
             .ok_or(ExitError::OutOfFund)?;
@@ -188,7 +190,11 @@ fn transfer_back_to_caller(
     Ok(())
 }
 
-fn dispatch(handle: &mut impl PrecompileHandle, call: RuntimeCall) -> PrecompileResult {
+fn dispatch(
+    handle: &mut impl PrecompileHandle,
+    call: RuntimeCall,
+    smart_contract_address: &str,
+) -> PrecompileResult {
     let account_id =
         <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
             handle.context().caller,
@@ -199,7 +205,7 @@ fn dispatch(handle: &mut impl PrecompileHandle, call: RuntimeCall) -> Precompile
     let amount = handle.context().apparent_value;
 
     if !amount.is_zero() {
-        transfer_back_to_caller(&account_id, amount)?;
+        transfer_back_to_caller(smart_contract_address, &account_id, amount)?;
     }
 
     let result = call.dispatch(RawOrigin::Signed(account_id.clone()).into());
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index e8d33c05e..9454485ff 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -35,7 +35,9 @@ use sp_std::vec;
 
 use crate::{Runtime, RuntimeCall};
 pub const STAKING_PRECOMPILE_INDEX: u64 = 2049;
-
+// this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
+pub const STAKING_CONTRACT_ADDRESS: &'static str =
+    "5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X";
 pub struct StakingPrecompile;
 
 impl StakingPrecompile {
@@ -72,7 +74,7 @@ impl StakingPrecompile {
             amount_staked: amount_sub.unique_saturated_into(),
         });
         // Dispatch the add_stake call
-        dispatch(handle, call)
+        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
     }
     fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
         let hotkey = Self::parse_hotkey(data)?.into();
@@ -92,7 +94,7 @@ impl StakingPrecompile {
             hotkey,
             amount_unstaked: amount_sub.unique_saturated_into(),
         });
-        dispatch(handle, call)
+        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
     }
 
     fn parse_hotkey(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> {
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index a74bbf53a..f68e089b3 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -7,6 +7,10 @@ pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051;
 // three bytes with max lenght 1K
 pub const MAX_PARAMETER_SIZE: usize = 3 * 1024;
 
+// this is staking smart contract's(0x0000000000000000000000000000000000000803) sr25519 address
+pub const STAKING_CONTRACT_ADDRESS: &'static str =
+    "5DPSUCb5mZFfizvBDSnRoAqmxV5Bmov2CS3xV773qU6VP1w2";
+
 pub struct SubnetPrecompile;
 
 impl SubnetPrecompile {
@@ -62,7 +66,7 @@ impl SubnetPrecompile {
         };
 
         // Dispatch the register_network call
-        dispatch(handle, call)
+        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
     }
 
     fn parse_register_network_parameters(

From 71699085a6d9b554630abb4d9d19e54c607d33c1 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Wed, 11 Dec 2024 09:42:35 +0800
Subject: [PATCH 004/145] fix clippy

---
 runtime/src/precompiles/staking.rs | 3 +--
 runtime/src/precompiles/subnet.rs  | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index 9454485ff..31c692cd6 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -36,8 +36,7 @@ use sp_std::vec;
 use crate::{Runtime, RuntimeCall};
 pub const STAKING_PRECOMPILE_INDEX: u64 = 2049;
 // this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
-pub const STAKING_CONTRACT_ADDRESS: &'static str =
-    "5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X";
+pub const STAKING_CONTRACT_ADDRESS: &str = "5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X";
 pub struct StakingPrecompile;
 
 impl StakingPrecompile {
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index f68e089b3..9230a01e9 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -8,8 +8,7 @@ pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051;
 pub const MAX_PARAMETER_SIZE: usize = 3 * 1024;
 
 // this is staking smart contract's(0x0000000000000000000000000000000000000803) sr25519 address
-pub const STAKING_CONTRACT_ADDRESS: &'static str =
-    "5DPSUCb5mZFfizvBDSnRoAqmxV5Bmov2CS3xV773qU6VP1w2";
+pub const STAKING_CONTRACT_ADDRESS: &str = "5DPSUCb5mZFfizvBDSnRoAqmxV5Bmov2CS3xV773qU6VP1w2";
 
 pub struct SubnetPrecompile;
 

From cdda2f68ac3d50dc2f9c3631328f4bd8f6abbe90 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Wed, 11 Dec 2024 10:59:41 +0800
Subject: [PATCH 005/145] fix compile error

---
 runtime/src/precompiles/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index 4d8abdac2..398a80a05 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -53,7 +53,7 @@ where
     pub fn new() -> Self {
         Self(Default::default())
     }
-    pub fn used_addresses() -> [H160; 11] {
+    pub fn used_addresses() -> [H160; 12] {
         [
             hash(1),
             hash(2),

From e565825b2a0b852d614bc5496f5d43b17763552d Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Mon, 16 Dec 2024 20:30:54 +0800
Subject: [PATCH 006/145] add memory storage

---
 runtime/src/precompiles/solidity/subnet.sol | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtime/src/precompiles/solidity/subnet.sol b/runtime/src/precompiles/solidity/subnet.sol
index e2857ad63..581788b03 100644
--- a/runtime/src/precompiles/solidity/subnet.sol
+++ b/runtime/src/precompiles/solidity/subnet.sol
@@ -6,5 +6,5 @@ interface ISubnet {
   /// Registers a new network without specifying details.
   function registerNetwork() external payable;
   /// Registers a new network with specified subnet name, GitHub repository, and contact information.
-  function registerNetwork(bytes subnetName, bytes githubRepo, bytes subnetContact) external payable;
+  function registerNetwork(bytes memory subnetName, bytes memory githubRepo, bytes memory subnetContact) external payable;
 }
\ No newline at end of file

From 6a0f6f91accff4748b1ccafe258ca6f1a44536e8 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Fri, 20 Dec 2024 18:33:52 +0800
Subject: [PATCH 007/145] add subnets precompile

---
 runtime/src/precompiles/mod.rs               |  6 +-
 runtime/src/precompiles/solidity/staking.sol | 44 +++++++------
 runtime/src/precompiles/solidity/subnets.abi | 20 ++++++
 runtime/src/precompiles/solidity/subnets.sol | 14 ++++
 runtime/src/precompiles/subnets.rs           | 68 ++++++++++++++++++++
 5 files changed, 131 insertions(+), 21 deletions(-)
 create mode 100644 runtime/src/precompiles/solidity/subnets.abi
 create mode 100644 runtime/src/precompiles/solidity/subnets.sol
 create mode 100644 runtime/src/precompiles/subnets.rs

diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index e13516e95..20d013194 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -15,11 +15,13 @@ mod balance_transfer;
 mod ed25519;
 mod metagraph;
 mod staking;
+mod subnets;
 
 use balance_transfer::*;
 use ed25519::*;
 use metagraph::*;
 use staking::*;
+use subnets::*;
 
 pub struct FrontierPrecompiles<R>(PhantomData<R>);
 
@@ -39,7 +41,7 @@ where
     pub fn new() -> Self {
         Self(Default::default())
     }
-    pub fn used_addresses() -> [H160; 11] {
+    pub fn used_addresses() -> [H160; 12] {
         [
             hash(1),
             hash(2),
@@ -52,6 +54,7 @@ where
             hash(BALANCE_TRANSFER_INDEX),
             hash(STAKING_PRECOMPILE_INDEX),
             hash(METAGRAPH_PRECOMPILE_INDEX),
+            hash(SUBNETS_PRECOMPILE_INDEX),
         ]
     }
 }
@@ -79,6 +82,7 @@ where
             a if a == hash(METAGRAPH_PRECOMPILE_INDEX) => {
                 Some(MetagraphPrecompile::execute(handle))
             }
+            a if a == hash(SUBNETS_PRECOMPILE_INDEX) => Some(SubnetsPrecompile::execute(handle)),
 
             _ => None,
         }
diff --git a/runtime/src/precompiles/solidity/staking.sol b/runtime/src/precompiles/solidity/staking.sol
index ec7fb7297..057fa2dce 100644
--- a/runtime/src/precompiles/solidity/staking.sol
+++ b/runtime/src/precompiles/solidity/staking.sol
@@ -3,26 +3,26 @@ pragma solidity ^0.8.0;
 address constant ISTAKING_ADDRESS = 0x0000000000000000000000000000000000000801;
 
 interface IStaking {
-  /**
-   * @dev Adds a subtensor stake corresponding to the value sent with the transaction, associated
-   * with the `hotkey`.
-   *
-   * This function allows external accounts and contracts to stake TAO into the subtensor pallet,
-   * which effectively calls `add_stake` on the subtensor pallet with specified hotkey as a parameter
-   * and coldkey being the hashed address mapping of H160 sender address to Substrate ss58 address as
-   * implemented in Frontier HashedAddressMapping:
-   * https://github.com/polkadot-evm/frontier/blob/2e219e17a526125da003e64ef22ec037917083fa/frame/evm/src/lib.rs#L739
-   *
-   * @param hotkey The hotkey public key (32 bytes).
-   * @param netuid The subnet to stake to (uint16). Currently a noop, functionality will be enabled with RAO.
-   *
-   * Requirements:
-   * - `hotkey` must be a valid hotkey registered on the network, ensuring that the stake is
-   *   correctly attributed.
-   */
-  function addStake(bytes32 hotkey, uint16 netuid) external payable;
+    /**
+     * @dev Adds a subtensor stake corresponding to the value sent with the transaction, associated
+     * with the `hotkey`.
+     *
+     * This function allows external accounts and contracts to stake TAO into the subtensor pallet,
+     * which effectively calls `add_stake` on the subtensor pallet with specified hotkey as a parameter
+     * and coldkey being the hashed address mapping of H160 sender address to Substrate ss58 address as
+     * implemented in Frontier HashedAddressMapping:
+     * https://github.com/polkadot-evm/frontier/blob/2e219e17a526125da003e64ef22ec037917083fa/frame/evm/src/lib.rs#L739
+     *
+     * @param hotkey The hotkey public key (32 bytes).
+     * @param netuid The subnet to stake to (uint16). Currently a noop, functionality will be enabled with RAO.
+     *
+     * Requirements:
+     * - `hotkey` must be a valid hotkey registered on the network, ensuring that the stake is
+     *   correctly attributed.
+     */
+    function addStake(bytes32 hotkey, uint16 netuid) external payable;
 
-  /**
+    /**
    * @dev Removes a subtensor stake `amount` from the specified `hotkey`.
    *
    * This function allows external accounts and contracts to unstake TAO from the subtensor pallet,
@@ -41,5 +41,9 @@ interface IStaking {
    *   correctly attributed.
    * - The existing stake amount must be not lower than specified amount
    */
-  function removeStake(bytes32 hotkey, uint256 amount, uint16 netuid) external;
+    function removeStake(
+        bytes32 hotkey,
+        uint256 amount,
+        uint16 netuid
+    ) external;
 }
diff --git a/runtime/src/precompiles/solidity/subnets.abi b/runtime/src/precompiles/solidity/subnets.abi
new file mode 100644
index 000000000..09a14eb2d
--- /dev/null
+++ b/runtime/src/precompiles/solidity/subnets.abi
@@ -0,0 +1,20 @@
+[
+    {
+        "inputs": [
+            {
+                "internalType": "uint16",
+                "name": "netuid",
+                "type": "uint16"
+            },
+            {
+                "internalType": "bytes32",
+                "name": "hotkey",
+                "type": "bytes32"
+            }
+        ],
+        "name": "burnedRegister",
+        "outputs": [],
+        "stateMutability": "payable",
+        "type": "function"
+    }
+]
diff --git a/runtime/src/precompiles/solidity/subnets.sol b/runtime/src/precompiles/solidity/subnets.sol
new file mode 100644
index 000000000..5cbf72779
--- /dev/null
+++ b/runtime/src/precompiles/solidity/subnets.sol
@@ -0,0 +1,14 @@
+pragma solidity ^0.8.0;
+
+address constant ISUBNETS_ADDRESS = 0x0000000000000000000000000000000000000804;
+
+interface ISubnets {
+    /**
+     * @dev Registers a neuron by calling `do_burned_registration` internally with the origin set to the ss58 mirror of the H160 address.
+     * This allows the H160 to further call neuron-related methods and receive emissions.
+     *
+     * @param netuid The subnet to register the neuron to (uint16).
+     * @param hotkey The hotkey public key (32 bytes).
+     */
+    function burnedRegister(uint16 netuid, bytes32 hotkey) external payable;
+}
diff --git a/runtime/src/precompiles/subnets.rs b/runtime/src/precompiles/subnets.rs
new file mode 100644
index 000000000..ffc0c71a0
--- /dev/null
+++ b/runtime/src/precompiles/subnets.rs
@@ -0,0 +1,68 @@
+use pallet_evm::{
+    ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
+};
+
+use crate::precompiles::{get_method_id, get_slice};
+use sp_std::vec;
+
+use crate::{Runtime, RuntimeCall};
+pub const SUBNETS_PRECOMPILE_INDEX: u64 = 2052;
+
+// this is subnets smart contract's(0x0000000000000000000000000000000000000804) sr25519 address
+pub const SUBNETS_CONTRACT_ADDRESS: &str = "5GKZiUUgTnWSz3BgiVBMehEKkLszsG4ZXnvgWpWFUFKqrqyn";
+
+pub struct SubnetsPrecompile;
+
+impl SubnetsPrecompile {
+    pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
+        let txdata = handle.input();
+        let method_id = get_slice(txdata, 0, 4)?;
+        let method_input = txdata
+            .get(4..)
+            .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts
+
+        match method_id {
+            id if id == get_method_id("burnedRegister(uint16,bytes32)") => {
+                Self::burned_register(handle, &method_input)
+            }
+
+            _ => Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            }),
+        }
+    }
+
+    pub fn burned_register(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
+        let (netuid, hotkey) = Self::parse_netuid_hotkey_parameter(data)?;
+        let call =
+            RuntimeCall::SubtensorModule(pallet_subtensor::Call::<Runtime>::burned_register {
+                netuid,
+                hotkey: hotkey.into(),
+            });
+        Self::dispatch(handle, call)
+    }
+
+    fn parse_netuid_hotkey_parameter(data: &[u8]) -> Result<(u16, [u8; 32]), PrecompileFailure> {
+        if data.len() < 64 {
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
+        let mut netuid_vec = [0u8; 2];
+        netuid_vec.copy_from_slice(get_slice(data, 30, 32)?);
+        let netuid = u16::from_be_bytes(netuid_vec);
+
+        let mut parameter = [0u8; 32];
+        parameter.copy_from_slice(get_slice(data, 32, 64)?);
+
+        Ok((netuid, parameter))
+    }
+
+    // will remove it after merge with other PR
+    fn dispatch(_handle: &mut impl PrecompileHandle, _call: RuntimeCall) -> PrecompileResult {
+        Ok(PrecompileOutput {
+            exit_status: ExitSucceed::Returned,
+            output: vec![],
+        })
+    }
+}

From 0ff5f9a136dd681c79abfa40acb40784b81628cc Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 13 Jan 2025 20:07:17 -0500
Subject: [PATCH 008/145] wip

---
 pallets/subtensor/src/coinbase/root.rs        |  5 ++
 pallets/subtensor/src/macros/hooks.rs         |  4 +-
 .../migrate_fix_is_network_member.rs          | 58 +++++++++++++++++++
 pallets/subtensor/src/migrations/mod.rs       |  1 +
 4 files changed, 67 insertions(+), 1 deletion(-)
 create mode 100644 pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs

diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs
index fee6e672b..c4fc1a9f9 100644
--- a/pallets/subtensor/src/coinbase/root.rs
+++ b/pallets/subtensor/src/coinbase/root.rs
@@ -527,6 +527,7 @@ impl<T: Config> Pallet<T> {
 
         // --- 7. Remove incentive mechanism memory.
         let _ = Uids::<T>::clear_prefix(netuid, u32::MAX, None);
+        let keys = Keys::<T>::iter_prefix(netuid).collect::<Vec<_>>();
         let _ = Keys::<T>::clear_prefix(netuid, u32::MAX, None);
         let _ = Bonds::<T>::clear_prefix(netuid, u32::MAX, None);
 
@@ -564,6 +565,10 @@ impl<T: Config> Pallet<T> {
         ValidatorPermit::<T>::remove(netuid);
         ValidatorTrust::<T>::remove(netuid);
 
+        for key in keys {
+            IsNetworkMember::<T>::remove(key, netuid);
+        }
+
         // --- 11. Erase network parameters.
         Tempo::<T>::remove(netuid);
         Kappa::<T>::remove(netuid);
diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs
index bf255c1c7..2a43238ab 100644
--- a/pallets/subtensor/src/macros/hooks.rs
+++ b/pallets/subtensor/src/macros/hooks.rs
@@ -74,7 +74,9 @@ mod hooks {
                 // Migrate Commit-Reval 2.0
                 .saturating_add(migrations::migrate_commit_reveal_v2::migrate_commit_reveal_2::<T>())
                 // Migrate to RAO
-                .saturating_add(migrations::migrate_rao::migrate_rao::<T>());
+                .saturating_add(migrations::migrate_rao::migrate_rao::<T>())
+				// Fix the IsNetworkMember map to be consistent with other storage maps
+				.saturating_add(migrations::migrate_fix_is_network_member::migrate_fix_is_network_member::<T>());
             weight
         }
 
diff --git a/pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs b/pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs
new file mode 100644
index 000000000..0225cd8fb
--- /dev/null
+++ b/pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs
@@ -0,0 +1,58 @@
+use super::*;
+use alloc::string::String;
+use frame_support::{traits::Get, weights::Weight};
+use log;
+
+pub fn migrate_fix_is_network_member<T: Config>() -> Weight {
+    let migration_name = b"migrate_fix_is_network_member".to_vec();
+
+    // Initialize the weight with one read operation.
+    let mut weight = T::DbWeight::get().reads(1);
+
+    // Check if the migration has already run
+    if HasMigrationRun::<T>::get(&migration_name) {
+        log::info!(
+            "Migration '{:?}' has already run. Skipping.",
+            migration_name
+        );
+        return weight;
+    }
+    log::info!(
+        "Running migration '{}'",
+        String::from_utf8_lossy(&migration_name)
+    );
+
+    weight = do_fix_is_network_member::<T>(weight);
+
+    // Mark the migration as completed
+    HasMigrationRun::<T>::insert(&migration_name, true);
+    weight = weight.saturating_add(T::DbWeight::get().writes(1));
+
+    log::info!(
+        "Migration '{:?}' completed. Storage version set to 7.",
+        String::from_utf8_lossy(&migration_name)
+    );
+
+    // Return the migration weight.
+    weight
+}
+
+fn do_fix_is_network_member<T: Config>(weight: Weight) -> Weight {
+    // Clear the IsNetworkMember storage
+    let mut curr = IsNetworkMember::<T>::clear(U32::MAX, None);
+    weight = weight.saturating_add(T::DbWeight::get().reads_writes(curr.loops, curr.unique));
+    while curr.maybe_cursor.is_some() {
+        // Clear until empty
+        curr = IsNetworkMember::<T>::clear(U32::MAX, curr.maybe_cursor);
+        weight = weight.saturating_add(T::DbWeight::get().reads_writes(curr.loops, curr.unique));
+    }
+    // Repopulate the IsNetworkMember storage using the Keys map
+    let netuids = Subtensor::<T>::get_all_subnet_netuids();
+    for netuid in netuids {
+        for key in Keys::<T>::iter_prefix(netuid) {
+            IsNetworkMember::<T>::insert(key, netuid, true);
+        }
+    }
+
+    weight
+}
diff --git a/pallets/subtensor/src/migrations/mod.rs b/pallets/subtensor/src/migrations/mod.rs
index dc9011f3e..6cf358c4d 100644
--- a/pallets/subtensor/src/migrations/mod.rs
+++ b/pallets/subtensor/src/migrations/mod.rs
@@ -4,6 +4,7 @@ pub mod migrate_commit_reveal_v2;
 pub mod migrate_create_root_network;
 pub mod migrate_delete_subnet_21;
 pub mod migrate_delete_subnet_3;
+pub mod migrate_fix_is_network_member;
 pub mod migrate_fix_total_coldkey_stake;
 pub mod migrate_init_total_issuance;
 pub mod migrate_populate_owned_hotkeys;

From 53e78f94cbc256aff8d7984f675e8a5efe318fc5 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Mon, 13 Jan 2025 21:31:42 -0500
Subject: [PATCH 009/145] fix syntax

---
 pallets/subtensor/src/coinbase/root.rs        |  2 +-
 .../migrate_fix_is_network_member.rs          | 19 ++++++++++---------
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs
index c4fc1a9f9..112c88785 100644
--- a/pallets/subtensor/src/coinbase/root.rs
+++ b/pallets/subtensor/src/coinbase/root.rs
@@ -565,7 +565,7 @@ impl<T: Config> Pallet<T> {
         ValidatorPermit::<T>::remove(netuid);
         ValidatorTrust::<T>::remove(netuid);
 
-        for key in keys {
+        for (_uid, key) in keys {
             IsNetworkMember::<T>::remove(key, netuid);
         }
 
diff --git a/pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs b/pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs
index 0225cd8fb..3c89717f1 100644
--- a/pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs
+++ b/pallets/subtensor/src/migrations/migrate_fix_is_network_member.rs
@@ -38,20 +38,21 @@ pub fn migrate_fix_is_network_member<T: Config>() -> Weight {
 }
 
 fn do_fix_is_network_member<T: Config>(weight: Weight) -> Weight {
+    let mut weight = weight;
     // Clear the IsNetworkMember storage
-    let mut curr = IsNetworkMember::<T>::clear(U32::MAX, None);
-    weight = weight.saturating_add(T::DbWeight::get().reads_writes(curr.loops, curr.unique));
+    let mut curr = IsNetworkMember::<T>::clear(u32::MAX, None);
+    weight = weight
+        .saturating_add(T::DbWeight::get().reads_writes(curr.loops as u64, curr.unique as u64));
     while curr.maybe_cursor.is_some() {
         // Clear until empty
-        curr = IsNetworkMember::<T>::clear(U32::MAX, curr.maybe_cursor);
-        weight = weight.saturating_add(T::DbWeight::get().reads_writes(curr.loops, curr.unique));
+        curr = IsNetworkMember::<T>::clear(u32::MAX, curr.maybe_cursor.as_deref());
+        weight = weight
+            .saturating_add(T::DbWeight::get().reads_writes(curr.loops as u64, curr.unique as u64));
     }
     // Repopulate the IsNetworkMember storage using the Keys map
-    let netuids = Subtensor::<T>::get_all_subnet_netuids();
-    for netuid in netuids {
-        for key in Keys::<T>::iter_prefix(netuid) {
-            IsNetworkMember::<T>::insert(key, netuid, true);
-        }
+    for (netuid, _uid, key) in Keys::<T>::iter() {
+        IsNetworkMember::<T>::insert(key, netuid, true);
+        weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));
     }
 
     weight

From 164323825311e1a23918cb94fefcd1221e2061a7 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 16 Jan 2025 20:41:55 +0800
Subject: [PATCH 010/145] fix compilation

---
 runtime/src/precompiles/subnet.rs | 33 +++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index 9230a01e9..01eb331e6 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -27,10 +27,10 @@ impl SubnetPrecompile {
             .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts
 
         match method_id {
-            id if id == get_method_id("registerNetwork(bytes,bytes,bytes)") => {
+            id if id == get_method_id("registerNetwork(bytes32,bytes,bytes,bytes)") => {
                 Self::register_network(handle, &method_input)
             }
-            id if id == get_method_id("registerNetwork()") => {
+            id if id == get_method_id("registerNetwork(bytes32)") => {
                 Self::register_network(handle, &[0_u8; 0])
             }
             _ => Err(PrecompileFailure::Error {
@@ -41,13 +41,15 @@ impl SubnetPrecompile {
 
     fn register_network(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
         let call = if data.is_empty() {
+            let hotkey = Self::parse_pub_key(data)?.into();
             RuntimeCall::SubtensorModule(
                 pallet_subtensor::Call::<Runtime>::register_network_with_identity {
+                    hotkey,
                     identity: None,
                 },
             )
         } else {
-            let (subnet_name, github_repo, subnet_contact) =
+            let (pubkey, subnet_name, github_repo, subnet_contact) =
                 Self::parse_register_network_parameters(data)?;
 
             let identity: pallet_subtensor::SubnetIdentityOf = pallet_subtensor::SubnetIdentityOf {
@@ -59,6 +61,7 @@ impl SubnetPrecompile {
             // Create the register_network callcle
             RuntimeCall::SubtensorModule(
                 pallet_subtensor::Call::<Runtime>::register_network_with_identity {
+                    hotkey: pubkey.into(),
                     identity: Some(identity),
                 },
             )
@@ -68,19 +71,33 @@ impl SubnetPrecompile {
         dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
     }
 
+    fn parse_pub_key(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> {
+        if data.len() < 32 {
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
+        let mut pubkey = [0u8; 32];
+        pubkey.copy_from_slice(get_slice(data, 0, 32)?);
+        Ok(pubkey)
+    }
+
     fn parse_register_network_parameters(
         data: &[u8],
-    ) -> Result<(vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {
+    ) -> Result<([u8; 32], vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {
+        let mut pubkey = [0u8; 32];
+        pubkey.copy_from_slice(get_slice(data, 0, 32)?);
+
         let mut buf = [0_u8; 4];
 
         // get all start point for three data items: name, repo and contact
-        buf.copy_from_slice(get_slice(data, 28, 32)?);
+        buf.copy_from_slice(get_slice(data, 60, 64)?);
         let subnet_name_start: usize = u32::from_be_bytes(buf) as usize;
 
-        buf.copy_from_slice(get_slice(data, 60, 64)?);
+        buf.copy_from_slice(get_slice(data, 92, 96)?);
         let github_repo_start: usize = u32::from_be_bytes(buf) as usize;
 
-        buf.copy_from_slice(get_slice(data, 92, 96)?);
+        buf.copy_from_slice(get_slice(data, 124, 128)?);
         let subnet_contact_start: usize = u32::from_be_bytes(buf) as usize;
 
         // get name
@@ -128,6 +145,6 @@ impl SubnetPrecompile {
             subnet_contact_start + subnet_contact_len + 32,
         )?);
 
-        Ok((name_vec, repo_vec, contact_vec))
+        Ok((pubkey, name_vec, repo_vec, contact_vec))
     }
 }

From 5040e52262f9c20e496c20d391ee53c7eb94b2dc Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 16 Jan 2025 21:09:33 +0800
Subject: [PATCH 011/145] update sol

---
 runtime/src/precompiles/solidity/subnet.abi | 25 +++++++++++++++------
 runtime/src/precompiles/solidity/subnet.sol | 15 ++++++++-----
 2 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/runtime/src/precompiles/solidity/subnet.abi b/runtime/src/precompiles/solidity/subnet.abi
index a89cf91f1..a11879241 100644
--- a/runtime/src/precompiles/solidity/subnet.abi
+++ b/runtime/src/precompiles/solidity/subnet.abi
@@ -1,6 +1,24 @@
 [
     {
         "inputs": [
+            {
+                "internalType": "bytes32",
+                "name": "hotkey",
+                "type": "bytes32"
+            }
+        ],
+        "name": "registerNetwork",
+        "outputs": [],
+        "stateMutability": "payable",
+        "type": "function"
+    },
+    {
+        "inputs": [
+            {
+                "internalType": "bytes32",
+                "name": "hotkey",
+                "type": "bytes32"
+            },
             {
                 "internalType": "bytes",
                 "name": "subnetName",
@@ -21,12 +39,5 @@
         "outputs": [],
         "stateMutability": "payable",
         "type": "function"
-    },
-    {
-        "inputs": [],
-        "name": "registerNetwork",
-        "outputs": [],
-        "stateMutability": "payable",
-        "type": "function"
     }
 ]
\ No newline at end of file
diff --git a/runtime/src/precompiles/solidity/subnet.sol b/runtime/src/precompiles/solidity/subnet.sol
index 581788b03..c3d0a4a13 100644
--- a/runtime/src/precompiles/solidity/subnet.sol
+++ b/runtime/src/precompiles/solidity/subnet.sol
@@ -3,8 +3,13 @@ pragma solidity ^0.8.0;
 address constant ISTAKING_ADDRESS = 0x0000000000000000000000000000000000000803;
 
 interface ISubnet {
-  /// Registers a new network without specifying details.
-  function registerNetwork() external payable;
-  /// Registers a new network with specified subnet name, GitHub repository, and contact information.
-  function registerNetwork(bytes memory subnetName, bytes memory githubRepo, bytes memory subnetContact) external payable;
-}
\ No newline at end of file
+    /// Registers a new network without specifying details.
+    function registerNetwork(bytes32 hotkey) external payable;
+    /// Registers a new network with specified subnet name, GitHub repository, and contact information.
+    function registerNetwork(
+        bytes32 hotkey,
+        bytes memory subnetName,
+        bytes memory githubRepo,
+        bytes memory subnetContact
+    ) external payable;
+}

From 1341e7ac336119b36eea34b0a47bc7cd5544ce59 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Fri, 17 Jan 2025 22:40:33 +0800
Subject: [PATCH 012/145] rename contract

---
 runtime/src/precompiles/mod.rs                       |  8 ++++----
 runtime/src/precompiles/{subnets.rs => neuron.rs}    | 12 ++++++------
 .../precompiles/solidity/{subnets.abi => neuron.abi} |  0
 .../precompiles/solidity/{subnets.sol => neuron.sol} |  4 ++--
 4 files changed, 12 insertions(+), 12 deletions(-)
 rename runtime/src/precompiles/{subnets.rs => neuron.rs} (83%)
 rename runtime/src/precompiles/solidity/{subnets.abi => neuron.abi} (100%)
 rename runtime/src/precompiles/solidity/{subnets.sol => neuron.sol} (82%)

diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index c1524e19f..3d2c19ae9 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -26,16 +26,16 @@ use crate::{Runtime, RuntimeCall};
 mod balance_transfer;
 mod ed25519;
 mod metagraph;
+mod neuron;
 mod staking;
 mod subnet;
-mod subnets;
 
 use balance_transfer::*;
 use ed25519::*;
 use metagraph::*;
+use neuron::*;
 use staking::*;
 use subnet::*;
-use subnets::*;
 pub struct FrontierPrecompiles<R>(PhantomData<R>);
 impl<R> Default for FrontierPrecompiles<R>
 where
@@ -67,7 +67,7 @@ where
             hash(STAKING_PRECOMPILE_INDEX),
             hash(SUBNET_PRECOMPILE_INDEX),
             hash(METAGRAPH_PRECOMPILE_INDEX),
-            hash(SUBNETS_PRECOMPILE_INDEX),
+            hash(NEURON_PRECOMPILE_INDEX),
         ]
     }
 }
@@ -96,7 +96,7 @@ where
             a if a == hash(METAGRAPH_PRECOMPILE_INDEX) => {
                 Some(MetagraphPrecompile::execute(handle))
             }
-            a if a == hash(SUBNETS_PRECOMPILE_INDEX) => Some(SubnetsPrecompile::execute(handle)),
+            a if a == hash(NEURON_PRECOMPILE_INDEX) => Some(NeuronPrecompile::execute(handle)),
 
             _ => None,
         }
diff --git a/runtime/src/precompiles/subnets.rs b/runtime/src/precompiles/neuron.rs
similarity index 83%
rename from runtime/src/precompiles/subnets.rs
rename to runtime/src/precompiles/neuron.rs
index 19be425d5..341683cb3 100644
--- a/runtime/src/precompiles/subnets.rs
+++ b/runtime/src/precompiles/neuron.rs
@@ -4,14 +4,14 @@ use crate::precompiles::{dispatch, get_method_id, get_slice};
 use sp_std::vec;
 
 use crate::{Runtime, RuntimeCall};
-pub const SUBNETS_PRECOMPILE_INDEX: u64 = 2052;
+pub const NEURON_PRECOMPILE_INDEX: u64 = 2052;
 
-// this is subnets smart contract's(0x0000000000000000000000000000000000000804) sr25519 address
-pub const SUBNETS_CONTRACT_ADDRESS: &str = "5GKZiUUgTnWSz3BgiVBMehEKkLszsG4ZXnvgWpWFUFKqrqyn";
+// this is neuron smart contract's(0x0000000000000000000000000000000000000804) sr25519 address
+pub const NEURON_CONTRACT_ADDRESS: &str = "5GKZiUUgTnWSz3BgiVBMehEKkLszsG4ZXnvgWpWFUFKqrqyn";
 
-pub struct SubnetsPrecompile;
+pub struct NeuronPrecompile;
 
-impl SubnetsPrecompile {
+impl NeuronPrecompile {
     pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
         let txdata = handle.input();
         let method_id = get_slice(txdata, 0, 4)?;
@@ -37,7 +37,7 @@ impl SubnetsPrecompile {
                 netuid,
                 hotkey: hotkey.into(),
             });
-        dispatch(handle, call, SUBNETS_CONTRACT_ADDRESS)
+        dispatch(handle, call, NEURON_CONTRACT_ADDRESS)
     }
 
     fn parse_netuid_hotkey_parameter(data: &[u8]) -> Result<(u16, [u8; 32]), PrecompileFailure> {
diff --git a/runtime/src/precompiles/solidity/subnets.abi b/runtime/src/precompiles/solidity/neuron.abi
similarity index 100%
rename from runtime/src/precompiles/solidity/subnets.abi
rename to runtime/src/precompiles/solidity/neuron.abi
diff --git a/runtime/src/precompiles/solidity/subnets.sol b/runtime/src/precompiles/solidity/neuron.sol
similarity index 82%
rename from runtime/src/precompiles/solidity/subnets.sol
rename to runtime/src/precompiles/solidity/neuron.sol
index 5cbf72779..a76842339 100644
--- a/runtime/src/precompiles/solidity/subnets.sol
+++ b/runtime/src/precompiles/solidity/neuron.sol
@@ -1,8 +1,8 @@
 pragma solidity ^0.8.0;
 
-address constant ISUBNETS_ADDRESS = 0x0000000000000000000000000000000000000804;
+address constant INeuron_ADDRESS = 0x0000000000000000000000000000000000000804;
 
-interface ISubnets {
+interface INeuron {
     /**
      * @dev Registers a neuron by calling `do_burned_registration` internally with the origin set to the ss58 mirror of the H160 address.
      * This allows the H160 to further call neuron-related methods and receive emissions.

From 9637986afaffeae6579f78522eea41311da21289 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Fri, 17 Jan 2025 17:49:38 +0100
Subject: [PATCH 013/145] Fix try-runtime accounting invariants check

---
 pallets/subtensor/src/subnets/subnet.rs  |  4 ++-
 pallets/subtensor/src/utils/try_state.rs | 34 ++++++++++++++--------
 scripts/try-runtime-upgrade.sh           | 37 ++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 13 deletions(-)
 create mode 100755 scripts/try-runtime-upgrade.sh

diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs
index 7b7de6aeb..5554a477b 100644
--- a/pallets/subtensor/src/subnets/subnet.rs
+++ b/pallets/subtensor/src/subnets/subnet.rs
@@ -2,6 +2,8 @@ use super::*;
 use frame_support::IterableStorageMap;
 use sp_core::Get;
 
+pub(crate) const POOL_INITIAL_TAO: u64 = 100_000_000_000;
+
 impl<T: Config> Pallet<T> {
     /// Retrieves the unique identifier (UID) for the root network.
     ///
@@ -234,7 +236,7 @@ impl<T: Config> Pallet<T> {
         ); // Set subnet token symbol.
 
         // Put 100 TAO from lock into subnet TAO and produce numerically equal amount of Alpha
-        let mut pool_initial_tao = 100_000_000_000;
+        let mut pool_initial_tao = POOL_INITIAL_TAO;
         if pool_initial_tao > actual_tao_lock_amount {
             pool_initial_tao = actual_tao_lock_amount;
         }
diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs
index 385a21bdd..62c4aabd6 100644
--- a/pallets/subtensor/src/utils/try_state.rs
+++ b/pallets/subtensor/src/utils/try_state.rs
@@ -1,4 +1,6 @@
 use super::*;
+#[cfg(feature = "try-runtime")]
+use super::subnets::subnet::POOL_INITIAL_TAO;
 
 impl<T: Config> Pallet<T> {
     /// Checks if the accounting invariants for [`TotalStake`], [`TotalSubnetLocked`], and [`TotalIssuance`] are correct.
@@ -16,10 +18,16 @@ impl<T: Config> Pallet<T> {
         use frame_support::traits::fungible::Inspect;
 
         // Calculate the total staked amount
-        let mut total_staked: u64 = 0;
-        for (_hotkey, _coldkey, stake) in Stake::<T>::iter() {
-            total_staked = total_staked.saturating_add(stake);
-        }
+        let total_staked = SubnetTAO::<T>::iter().fold(0u64, |acc, (netuid, stake)| {
+            let acc = acc.saturating_add(stake);
+
+            if netuid == Self::get_root_netuid() {
+                // root network doesn't have initial pool TAO
+                acc
+            } else {
+                acc.saturating_sub(POOL_INITIAL_TAO)
+            }
+        });
 
         // Verify that the calculated total stake matches the stored TotalStake
         ensure!(
@@ -28,13 +36,13 @@ impl<T: Config> Pallet<T> {
         );
 
         // Get the total subnet locked amount
-        let total_subnet_locked: u64 = Self::get_total_subnet_locked();
+        let total_subnet_locked = Self::get_total_subnet_locked();
 
         // Get the total currency issuance
-        let currency_issuance: u64 = T::Currency::total_issuance();
+        let currency_issuance = T::Currency::total_issuance();
 
         // Calculate the expected total issuance
-        let expected_total_issuance: u64 = currency_issuance
+        let expected_total_issuance = currency_issuance
             .saturating_add(total_staked)
             .saturating_add(total_subnet_locked);
 
@@ -42,15 +50,17 @@ impl<T: Config> Pallet<T> {
         //
         // These values can be off slightly due to float rounding errors.
         // They are corrected every runtime upgrade.
-        const DELTA: u64 = 1000;
-        let diff = if TotalIssuance::<T>::get() > expected_total_issuance {
-            TotalIssuance::<T>::get().checked_sub(expected_total_issuance)
+        let delta = 1000;
+        let total_issuance = TotalIssuance::<T>::get();
+
+        let diff = if total_issuance > expected_total_issuance {
+            total_issuance.checked_sub(expected_total_issuance)
         } else {
-            expected_total_issuance.checked_sub(TotalIssuance::<T>::get())
+            expected_total_issuance.checked_sub(total_issuance)
         }
         .expect("LHS > RHS");
         ensure!(
-            diff <= DELTA,
+            diff <= delta,
             "TotalIssuance diff greater than allowable delta",
         );
 
diff --git a/scripts/try-runtime-upgrade.sh b/scripts/try-runtime-upgrade.sh
new file mode 100755
index 000000000..7c3e5fe77
--- /dev/null
+++ b/scripts/try-runtime-upgrade.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+# Tries runtime upgrade (via try-runtime).
+#
+# Usage:
+#   try-runtime-upgrade.sh [-p <runtime-path>] [-u <live-chain-url>]
+#
+# Dependencies:
+#   - rust toolchain
+#   - try-runtime-cli
+
+set -eou pipefail
+
+runtime_wasm_path="./target/release/wbuild/node-subtensor-runtime/node_subtensor_runtime.compact.wasm"
+live_chain_url="wss://dev.chain.opentensor.ai:443"
+
+parse_args() {
+  while getopts "p:u:" opt; do
+    case "${opt}" in
+    p) runtime_wasm_path="${OPTARG}" ;;
+    u) live_chain_url="${OPTARG}" ;;
+    *) echo "Usage: $(basename "$0") [-p <runtime-path>] [-u <live-chain-url>]" && exit 1 ;;
+    esac
+  done
+}
+
+build_runtime() {
+  cargo build -p node-subtensor-runtime --release --features "metadata-hash,try-runtime"
+}
+
+do_try_runtime() {
+  try-runtime --runtime "$runtime_wasm_path" on-runtime-upgrade live --uri "$live_chain_url"
+}
+
+parse_args "$@"
+build_runtime
+do_try_runtime

From 9df0d130664c986f844cbfff195ce8ace492188f Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Fri, 17 Jan 2025 18:11:24 +0100
Subject: [PATCH 014/145] Reformat

---
 pallets/subtensor/src/utils/try_state.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs
index 62c4aabd6..46a3ba5e4 100644
--- a/pallets/subtensor/src/utils/try_state.rs
+++ b/pallets/subtensor/src/utils/try_state.rs
@@ -1,6 +1,6 @@
-use super::*;
 #[cfg(feature = "try-runtime")]
 use super::subnets::subnet::POOL_INITIAL_TAO;
+use super::*;
 
 impl<T: Config> Pallet<T> {
     /// Checks if the accounting invariants for [`TotalStake`], [`TotalSubnetLocked`], and [`TotalIssuance`] are correct.

From 5ff711dd9a83d2760f64bff2059e9c847d565794 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Fri, 17 Jan 2025 15:12:18 -0500
Subject: [PATCH 015/145] make docker image builds trigger on key branches

---
 .github/workflows/docker.yml | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index fd00e9a31..4ace8c6fe 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -4,6 +4,11 @@ on:
   release:
     types: [published]
   workflow_dispatch:
+  push:
+    branches:
+      - devnet-ready
+      - devnet
+      - testnet
 
 permissions:
   contents: read
@@ -32,11 +37,24 @@ jobs:
           username: ${{ github.actor }}
           password: ${{ secrets.GITHUB_TOKEN }}
 
-      - name: Extract metadata (tags, labels) for Docker
-        id: meta
-        uses: docker/metadata-action@v4
-        with:
-          images: ghcr.io/${{ github.repository }}
+      - name: Determine Docker tag
+        id: tag
+        run: |
+          case "${{ github.ref_name }}" in
+            devnet-ready)
+              echo "tag=devnet-ready" >> $GITHUB_ENV
+              ;;
+            devnet)
+              echo "tag=devnet" >> $GITHUB_ENV
+              ;;
+            testnet)
+              echo "tag=testnet" >> $GITHUB_ENV
+              ;;
+            *)
+              echo "Branch not recognized for custom tagging."
+              exit 1
+              ;;
+          esac
 
       - name: Build and push Docker image
         uses: docker/build-push-action@v4
@@ -44,6 +62,5 @@ jobs:
           context: .
           push: true
           tags: |
-            ${{ steps.meta.outputs.tags }}
+            ghcr.io/${{ github.repository }}:${{ env.tag }}
             ghcr.io/${{ github.repository }}:latest
-          labels: ${{ steps.meta.outputs.labels }}

From 18a4c6de7e264427ce75ed36201fc122186bdbc8 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Fri, 17 Jan 2025 15:58:10 -0500
Subject: [PATCH 016/145] fix

---
 .github/workflows/docker.yml | 25 ++++++++++---------------
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 4ace8c6fe..fa15d8174 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -4,6 +4,12 @@ on:
   release:
     types: [published]
   workflow_dispatch:
+    inputs:
+      branch-or-tag:
+        description: "Branch or tag to use for the Docker image tag (optional)"
+        required: false
+        default: ""
+
   push:
     branches:
       - devnet-ready
@@ -40,21 +46,10 @@ jobs:
       - name: Determine Docker tag
         id: tag
         run: |
-          case "${{ github.ref_name }}" in
-            devnet-ready)
-              echo "tag=devnet-ready" >> $GITHUB_ENV
-              ;;
-            devnet)
-              echo "tag=devnet" >> $GITHUB_ENV
-              ;;
-            testnet)
-              echo "tag=testnet" >> $GITHUB_ENV
-              ;;
-            *)
-              echo "Branch not recognized for custom tagging."
-              exit 1
-              ;;
-          esac
+          # Use the provided branch-or-tag input or fallback to the current ref
+          branch_or_tag="${{ github.event.inputs.branch-or-tag || github.ref_name }}"
+          echo "Determined branch or tag: $branch_or_tag"
+          echo "tag=$branch_or_tag" >> $GITHUB_ENV
 
       - name: Build and push Docker image
         uses: docker/build-push-action@v4

From 53cdd8f2ed2bea4d45a20724eca7ff2faaacd543 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Fri, 17 Jan 2025 16:00:42 -0500
Subject: [PATCH 017/145] use specified ref

---
 .github/workflows/docker.yml | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index fa15d8174..85fd20269 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -6,7 +6,7 @@ on:
   workflow_dispatch:
     inputs:
       branch-or-tag:
-        description: "Branch or tag to use for the Docker image tag (optional)"
+        description: "Branch or tag to use for the Docker image tag and ref to checkout (optional)"
         required: false
         default: ""
 
@@ -27,8 +27,19 @@ jobs:
     runs-on: SubtensorCI
 
     steps:
+      - name: Determine Docker tag and ref
+        id: tag
+        run: |
+          # Use the provided branch-or-tag input or fallback to the current ref
+          branch_or_tag="${{ github.event.inputs.branch-or-tag || github.ref_name }}"
+          echo "Determined branch or tag: $branch_or_tag"
+          echo "tag=$branch_or_tag" >> $GITHUB_ENV
+          echo "ref=$branch_or_tag" >> $GITHUB_ENV
+
       - name: Checkout code
         uses: actions/checkout@v4
+        with:
+          ref: ${{ env.ref }}
 
       - name: Set up QEMU
         uses: docker/setup-qemu-action@v2
@@ -43,14 +54,6 @@ jobs:
           username: ${{ github.actor }}
           password: ${{ secrets.GITHUB_TOKEN }}
 
-      - name: Determine Docker tag
-        id: tag
-        run: |
-          # Use the provided branch-or-tag input or fallback to the current ref
-          branch_or_tag="${{ github.event.inputs.branch-or-tag || github.ref_name }}"
-          echo "Determined branch or tag: $branch_or_tag"
-          echo "tag=$branch_or_tag" >> $GITHUB_ENV
-
       - name: Build and push Docker image
         uses: docker/build-push-action@v4
         with:

From 92a476e478803309a883d827d6318fed62101859 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Fri, 17 Jan 2025 22:14:15 +0100
Subject: [PATCH 018/145] Change subnet initial supply fallback value

---
 pallets/subtensor/src/subnets/subnet.rs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs
index 5554a477b..050514c4c 100644
--- a/pallets/subtensor/src/subnets/subnet.rs
+++ b/pallets/subtensor/src/subnets/subnet.rs
@@ -3,6 +3,7 @@ use frame_support::IterableStorageMap;
 use sp_core::Get;
 
 pub(crate) const POOL_INITIAL_TAO: u64 = 100_000_000_000;
+pub(crate) const POOL_INITIAL_TAO_FALLBACK: u64 = 500;
 
 impl<T: Config> Pallet<T> {
     /// Retrieves the unique identifier (UID) for the root network.
@@ -240,8 +241,8 @@ impl<T: Config> Pallet<T> {
         if pool_initial_tao > actual_tao_lock_amount {
             pool_initial_tao = actual_tao_lock_amount;
         }
-        if pool_initial_tao < 1 {
-            pool_initial_tao = 1;
+        if pool_initial_tao == 0 {
+            pool_initial_tao = POOL_INITIAL_TAO_FALLBACK;
         }
         let actual_tao_lock_amount_less_pool_tao =
             actual_tao_lock_amount.saturating_sub(pool_initial_tao);

From fede19b80817315a512ec5a69b86db2198997e5c Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Fri, 17 Jan 2025 16:17:26 -0500
Subject: [PATCH 019/145] only bump latest tag if this is a github release!

---
 .github/workflows/docker.yml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 85fd20269..530c7cd8d 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -30,7 +30,6 @@ jobs:
       - name: Determine Docker tag and ref
         id: tag
         run: |
-          # Use the provided branch-or-tag input or fallback to the current ref
           branch_or_tag="${{ github.event.inputs.branch-or-tag || github.ref_name }}"
           echo "Determined branch or tag: $branch_or_tag"
           echo "tag=$branch_or_tag" >> $GITHUB_ENV
@@ -61,4 +60,3 @@ jobs:
           push: true
           tags: |
             ghcr.io/${{ github.repository }}:${{ env.tag }}
-            ghcr.io/${{ github.repository }}:latest

From 1f073d3a53e9d8e7cc2ae5d613c307b5f9439106 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Fri, 17 Jan 2025 19:51:55 -0500
Subject: [PATCH 020/145] calculate owner cut first

---
 .../subtensor/src/coinbase/run_coinbase.rs    | 75 ++++++++++++-------
 1 file changed, 48 insertions(+), 27 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index 6d835cd40..a150df654 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -124,6 +124,9 @@ impl<T: Config> Pallet<T> {
             EmissionValues::<T>::insert(*netuid, tao_in);
         }
 
+        // == We'll save the owner cuts for each subnet.
+        let mut owner_cuts: BTreeMap<u16, u64> = BTreeMap::new();
+
         // --- 4. Distribute subnet emission into subnets based on mechanism type.
         for netuid in subnets.iter() {
             // Do not emit into root network.
@@ -189,12 +192,27 @@ impl<T: Config> Pallet<T> {
                 log::debug!("Increased TotalIssuance: {:?}", *total);
             });
 
+            // Calculate the owner cut.
+            let owner_cut: u64 = I96F32::from_num(alpha_out_emission)
+                .saturating_mul(Self::get_float_subnet_owner_cut())
+                .to_num::<u64>();
+            log::debug!("Owner cut for netuid {:?}: {:?}", netuid, owner_cut);
+            // Store the owner cut for this subnet.
+            *owner_cuts.entry(*netuid).or_insert(0) = owner_cut;
+
+            let remaining_emission: u64 = alpha_out_emission.saturating_sub(owner_cut);
+            log::debug!(
+                "Remaining emission for netuid {:?}: {:?}",
+                netuid,
+                remaining_emission
+            );
+
             // Get proportion of alpha out emission as root divs.
             let root_emission_in_alpha: I96F32 =
-                Self::get_root_divs_in_alpha(*netuid, I96F32::from_num(alpha_out_emission));
+                Self::get_root_divs_in_alpha(*netuid, I96F32::from_num(remaining_emission));
             // Subtract root divs from alpha divs.
             let pending_alpha_emission: I96F32 =
-                I96F32::from_num(alpha_out_emission).saturating_sub(root_emission_in_alpha);
+                I96F32::from_num(remaining_emission).saturating_sub(root_emission_in_alpha);
             // Sell root emission through the pool.
             let root_emission_in_tao: u64 =
                 Self::swap_alpha_for_tao(*netuid, root_emission_in_alpha.to_num::<u64>());
@@ -225,12 +243,24 @@ impl<T: Config> Pallet<T> {
                 BlocksSinceLastStep::<T>::insert(netuid, 0);
                 LastMechansimStepBlock::<T>::insert(netuid, current_block);
 
-                // 5.2 Get and drain the subnet pending emission.
+                // 5.2.1 Get and drain the subnet pending emission.
                 let pending_emission: u64 = PendingEmission::<T>::get(netuid);
                 PendingEmission::<T>::insert(netuid, 0);
 
-                // Drain pending root divs and alpha emission.
-                Self::drain_pending_emission(netuid, pending_emission);
+                // 5.2.2 Get and drain the subnet pending root divs.
+                let pending_root_divs: u64 = PendingRootDivs::<T>::get(netuid);
+                PendingRootDivs::<T>::insert(netuid, 0);
+
+                // 5.2.3 Get owner cut.
+                let owner_cut: u64 = *owner_cuts.get(&netuid).unwrap_or(&0);
+
+                // 5.2.4 Drain pending root divs, alpha emission, and owner cut.
+                Self::drain_pending_emission(
+                    netuid,
+                    pending_emission,
+                    pending_root_divs,
+                    owner_cut,
+                );
             } else {
                 // Increment
                 BlocksSinceLastStep::<T>::mutate(netuid, |total| *total = total.saturating_add(1));
@@ -238,31 +268,23 @@ impl<T: Config> Pallet<T> {
         }
     }
 
-    pub fn drain_pending_emission(netuid: u16, pending_emission: u64) {
-        let alpha_out: u64 = pending_emission;
-
-        log::debug!(
-            "Draining pending emission for netuid {:?}: {:?}",
-            netuid,
-            alpha_out
-        );
-
-        // Calculate the 18% owner cut.
-        let owner_cut: u64 = I96F32::from_num(alpha_out)
-            .saturating_mul(Self::get_float_subnet_owner_cut())
-            .to_num::<u64>();
-        log::debug!("Owner cut for netuid {:?}: {:?}", netuid, owner_cut);
-
-        let remaining_emission: u64 = alpha_out.saturating_sub(owner_cut);
+    pub fn drain_pending_emission(
+        netuid: u16,
+        pending_alpha_emission: u64,
+        pending_root_divs: u64,
+        owner_cut: u64,
+    ) {
         log::debug!(
-            "Remaining emission for netuid {:?}: {:?}",
+            "Draining pending alpha emission for netuid {:?}: {:?}, with pending root divs {:?}, and owner cut {:?}",
             netuid,
-            remaining_emission
+            pending_alpha_emission,
+            pending_root_divs,
+            owner_cut
         );
 
         // Run the epoch() --> hotkey emission.
         let hotkey_emission: Vec<(T::AccountId, u64, u64)> =
-            Self::epoch(netuid, remaining_emission);
+            Self::epoch(netuid, pending_alpha_emission);
         log::debug!(
             "Hotkey emission for netuid {:?}: {:?}",
             netuid,
@@ -463,14 +485,13 @@ impl<T: Config> Pallet<T> {
 
         // For all the root-alpha divs give this proportion of the swapped tao to the root participants.
         let _ = TaoDividendsPerSubnet::<T>::clear_prefix(netuid, u32::MAX, None);
-        let total_root_divs_to_distribute = PendingRootDivs::<T>::get(netuid);
-        PendingRootDivs::<T>::insert(netuid, 0);
+
         for (hotkey_j, root_divs) in root_alpha_divs.iter() {
             let proportion: I96F32 = I96F32::from_num(*root_divs)
                 .checked_div(I96F32::from_num(total_root_alpha_divs))
                 .unwrap_or(I96F32::from_num(0));
             let root_divs_to_pay: u64 = proportion
-                .saturating_mul(I96F32::from_num(total_root_divs_to_distribute))
+                .saturating_mul(I96F32::from_num(pending_root_divs))
                 .to_num::<u64>();
             log::debug!(
                 "Proportion for hotkey {:?}: {:?}, root_divs_to_pay: {:?}",

From 23f9b87f37737fde2765899ebf7b4fdd28d496b2 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Mon, 20 Jan 2025 10:05:24 +0800
Subject: [PATCH 021/145] fix e2e test

---
 runtime/src/precompiles/subnet.rs | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index 01eb331e6..db3adfc1b 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -31,7 +31,7 @@ impl SubnetPrecompile {
                 Self::register_network(handle, &method_input)
             }
             id if id == get_method_id("registerNetwork(bytes32)") => {
-                Self::register_network(handle, &[0_u8; 0])
+                Self::register_network(handle, &method_input)
             }
             _ => Err(PrecompileFailure::Error {
                 exit_status: ExitError::InvalidRange,
@@ -40,15 +40,17 @@ impl SubnetPrecompile {
     }
 
     fn register_network(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
-        let call = if data.is_empty() {
-            let hotkey = Self::parse_pub_key(data)?.into();
+        let call = if data.len() == 32 {
+            let mut hotkey = [0u8; 32];
+            hotkey.copy_from_slice(get_slice(data, 0, 32)?);
+
             RuntimeCall::SubtensorModule(
                 pallet_subtensor::Call::<Runtime>::register_network_with_identity {
-                    hotkey,
+                    hotkey: hotkey.into(),
                     identity: None,
                 },
             )
-        } else {
+        } else if data.len() > 32 {
             let (pubkey, subnet_name, github_repo, subnet_contact) =
                 Self::parse_register_network_parameters(data)?;
 
@@ -65,23 +67,16 @@ impl SubnetPrecompile {
                     identity: Some(identity),
                 },
             )
+        } else {
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
         };
 
         // Dispatch the register_network call
         dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
     }
 
-    fn parse_pub_key(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> {
-        if data.len() < 32 {
-            return Err(PrecompileFailure::Error {
-                exit_status: ExitError::InvalidRange,
-            });
-        }
-        let mut pubkey = [0u8; 32];
-        pubkey.copy_from_slice(get_slice(data, 0, 32)?);
-        Ok(pubkey)
-    }
-
     fn parse_register_network_parameters(
         data: &[u8],
     ) -> Result<([u8; 32], vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {

From 9de1927a0a866b3c768432972e315c6744c63a18 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Mon, 20 Jan 2025 10:22:41 +0800
Subject: [PATCH 022/145] commit Cargo.lock

---
 runtime/src/precompiles/subnet.rs | 67 +++++++++++++++++--------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index db3adfc1b..f883a6996 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -40,37 +40,42 @@ impl SubnetPrecompile {
     }
 
     fn register_network(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
-        let call = if data.len() == 32 {
-            let mut hotkey = [0u8; 32];
-            hotkey.copy_from_slice(get_slice(data, 0, 32)?);
-
-            RuntimeCall::SubtensorModule(
-                pallet_subtensor::Call::<Runtime>::register_network_with_identity {
-                    hotkey: hotkey.into(),
-                    identity: None,
-                },
-            )
-        } else if data.len() > 32 {
-            let (pubkey, subnet_name, github_repo, subnet_contact) =
-                Self::parse_register_network_parameters(data)?;
-
-            let identity: pallet_subtensor::SubnetIdentityOf = pallet_subtensor::SubnetIdentityOf {
-                subnet_name,
-                github_repo,
-                subnet_contact,
-            };
-
-            // Create the register_network callcle
-            RuntimeCall::SubtensorModule(
-                pallet_subtensor::Call::<Runtime>::register_network_with_identity {
-                    hotkey: pubkey.into(),
-                    identity: Some(identity),
-                },
-            )
-        } else {
-            return Err(PrecompileFailure::Error {
-                exit_status: ExitError::InvalidRange,
-            });
+        let call = match data.len() {
+            32 => {
+                let mut hotkey = [0u8; 32];
+                hotkey.copy_from_slice(get_slice(data, 0, 32)?);
+
+                RuntimeCall::SubtensorModule(
+                    pallet_subtensor::Call::<Runtime>::register_network_with_identity {
+                        hotkey: hotkey.into(),
+                        identity: None,
+                    },
+                )
+            }
+            32.. => {
+                let (pubkey, subnet_name, github_repo, subnet_contact) =
+                    Self::parse_register_network_parameters(data)?;
+
+                let identity: pallet_subtensor::SubnetIdentityOf =
+                    pallet_subtensor::SubnetIdentityOf {
+                        subnet_name,
+                        github_repo,
+                        subnet_contact,
+                    };
+
+                // Create the register_network callcle
+                RuntimeCall::SubtensorModule(
+                    pallet_subtensor::Call::<Runtime>::register_network_with_identity {
+                        hotkey: pubkey.into(),
+                        identity: Some(identity),
+                    },
+                )
+            }
+            _ => {
+                return Err(PrecompileFailure::Error {
+                    exit_status: ExitError::InvalidRange,
+                });
+            }
         };
 
         // Dispatch the register_network call

From 3d05f7bcf325970bba94ef55cad5ebfd59f7e6e4 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Mon, 20 Jan 2025 10:23:09 +0800
Subject: [PATCH 023/145] cargo clippy

---
 runtime/src/precompiles/subnet.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index f883a6996..c1827f77a 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -52,7 +52,7 @@ impl SubnetPrecompile {
                     },
                 )
             }
-            32.. => {
+            33.. => {
                 let (pubkey, subnet_name, github_repo, subnet_contact) =
                     Self::parse_register_network_parameters(data)?;
 

From c4ea8a4a741e6ba9b2345cfc7232bf420d6098ea Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Mon, 20 Jan 2025 10:45:13 -0500
Subject: [PATCH 024/145] commit Cargo.lock changes

---
 Cargo.lock | 184 +++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 137 insertions(+), 47 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 964c583e1..90c2fb86f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1550,9 +1550,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-queue"
-version = "0.3.12"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
+checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
 dependencies = [
  "crossbeam-utils",
 ]
@@ -2187,9 +2187,9 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60"
 dependencies = [
  "crunchy",
  "fixed-hash",
- "impl-codec",
+ "impl-codec 0.6.0",
  "impl-rlp",
- "impl-serde",
+ "impl-serde 0.4.0",
  "scale-info",
  "tiny-keccak",
 ]
@@ -2220,12 +2220,12 @@ checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee"
 dependencies = [
  "ethbloom",
  "fixed-hash",
- "impl-codec",
+ "impl-codec 0.6.0",
  "impl-rlp",
- "impl-serde",
- "primitive-types",
+ "impl-serde 0.4.0",
+ "primitive-types 0.12.2",
  "scale-info",
- "uint",
+ "uint 0.9.5",
 ]
 
 [[package]]
@@ -2269,7 +2269,7 @@ dependencies = [
  "evm-runtime",
  "log",
  "parity-scale-codec",
- "primitive-types",
+ "primitive-types 0.12.2",
  "rlp",
  "scale-info",
  "serde",
@@ -2283,7 +2283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d1da6cedc5cedb4208e59467106db0d1f50db01b920920589f8e672c02fdc04f"
 dependencies = [
  "parity-scale-codec",
- "primitive-types",
+ "primitive-types 0.12.2",
  "scale-info",
  "serde",
 ]
@@ -2297,7 +2297,7 @@ dependencies = [
  "environmental",
  "evm-core",
  "evm-runtime",
- "primitive-types",
+ "primitive-types 0.12.2",
 ]
 
 [[package]]
@@ -2309,7 +2309,7 @@ dependencies = [
  "auto_impl",
  "environmental",
  "evm-core",
- "primitive-types",
+ "primitive-types 0.12.2",
  "sha3",
 ]
 
@@ -2694,7 +2694,7 @@ version = "1.0.0-dev"
 source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
 dependencies = [
  "hex",
- "impl-serde",
+ "impl-serde 0.4.0",
  "libsecp256k1",
  "log",
  "parity-scale-codec",
@@ -3876,6 +3876,26 @@ dependencies = [
  "parity-scale-codec",
 ]
 
+[[package]]
+name = "impl-codec"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941"
+dependencies = [
+ "parity-scale-codec",
+]
+
+[[package]]
+name = "impl-num-traits"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "803d15461ab0dcc56706adf266158acbc44ccf719bf7d0af30705f58b90a4b8c"
+dependencies = [
+ "integer-sqrt",
+ "num-traits",
+ "uint 0.10.0",
+]
+
 [[package]]
 name = "impl-rlp"
 version = "0.3.0"
@@ -3894,6 +3914,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "impl-serde"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a143eada6a1ec4aefa5049037a26a6d597bfd64f8c026d07b77133e02b7dd0b"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "impl-trait-for-tuples"
 version = "0.2.2"
@@ -4430,7 +4459,7 @@ dependencies = [
  "sha2 0.10.8",
  "smallvec",
  "thiserror",
- "uint",
+ "uint 0.9.5",
  "unsigned-varint 0.7.2",
  "void",
 ]
@@ -4892,7 +4921,7 @@ dependencies = [
  "tokio-util",
  "tracing",
  "trust-dns-resolver",
- "uint",
+ "uint 0.9.5",
  "unsigned-varint 0.8.0",
  "url",
  "webpki",
@@ -6635,7 +6664,7 @@ dependencies = [
  "lru 0.8.1",
  "parity-util-mem-derive",
  "parking_lot 0.12.3",
- "primitive-types",
+ "primitive-types 0.12.2",
  "smallvec",
  "winapi",
 ]
@@ -6877,7 +6906,7 @@ dependencies = [
  "libc",
  "log",
  "polkavm-assembler",
- "polkavm-common",
+ "polkavm-common 0.9.0",
  "polkavm-linux-raw",
 ]
 
@@ -6899,13 +6928,28 @@ dependencies = [
  "log",
 ]
 
+[[package]]
+name = "polkavm-common"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f0dbafef4ab6ceecb4982ac3b550df430ef4f9fdbf07c108b7d4f91a0682fce"
+
 [[package]]
 name = "polkavm-derive"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606"
 dependencies = [
- "polkavm-derive-impl-macro",
+ "polkavm-derive-impl-macro 0.9.0",
+]
+
+[[package]]
+name = "polkavm-derive"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "206caf322dfc02144510ad8360ff2051e5072f0874dcab3b410f78cdd52d0ebb"
+dependencies = [
+ "polkavm-derive-impl-macro 0.17.0",
 ]
 
 [[package]]
@@ -6914,7 +6958,19 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c"
 dependencies = [
- "polkavm-common",
+ "polkavm-common 0.9.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "polkavm-derive-impl"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42565aed4adbc4034612d0b17dea8db3681fb1bd1aed040d6edc5455a9f478a1"
+dependencies = [
+ "polkavm-common 0.17.0",
  "proc-macro2",
  "quote",
  "syn 2.0.90",
@@ -6926,7 +6982,17 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429"
 dependencies = [
- "polkavm-derive-impl",
+ "polkavm-derive-impl 0.9.0",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "polkavm-derive-impl-macro"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86d9838e95241b0bce4fe269cdd4af96464160505840ed5a8ac8536119ba19e2"
+dependencies = [
+ "polkavm-derive-impl 0.17.0",
  "syn 2.0.90",
 ]
 
@@ -6940,7 +7006,7 @@ dependencies = [
  "hashbrown 0.14.5",
  "log",
  "object 0.32.2",
- "polkavm-common",
+ "polkavm-common 0.9.0",
  "regalloc2 0.9.3",
  "rustc-demangle",
 ]
@@ -7077,11 +7143,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
 dependencies = [
  "fixed-hash",
- "impl-codec",
+ "impl-codec 0.6.0",
  "impl-rlp",
- "impl-serde",
+ "impl-serde 0.4.0",
  "scale-info",
- "uint",
+ "uint 0.9.5",
+]
+
+[[package]]
+name = "primitive-types"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5"
+dependencies = [
+ "fixed-hash",
+ "impl-codec 0.7.0",
+ "impl-num-traits",
+ "uint 0.10.0",
 ]
 
 [[package]]
@@ -9327,9 +9405,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
 
 [[package]]
 name = "serde"
-version = "1.0.216"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
 dependencies = [
  "serde_derive",
 ]
@@ -9364,9 +9442,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.216"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9858,7 +9936,7 @@ dependencies = [
  "futures",
  "hash-db",
  "hash256-std-hasher",
- "impl-serde",
+ "impl-serde 0.4.0",
  "itertools 0.11.0",
  "k256",
  "libsecp256k1",
@@ -9868,7 +9946,7 @@ dependencies = [
  "parity-scale-codec",
  "parking_lot 0.12.3",
  "paste",
- "primitive-types",
+ "primitive-types 0.12.2",
  "rand",
  "scale-info",
  "schnorrkel",
@@ -9892,7 +9970,7 @@ dependencies = [
 [[package]]
 name = "sp-crypto-ec-utils"
 version = "0.10.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
  "ark-bls12-377",
  "ark-bls12-377-ext",
@@ -9988,7 +10066,7 @@ dependencies = [
 [[package]]
 name = "sp-debug-derive"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9998,7 +10076,7 @@ dependencies = [
 [[package]]
 name = "sp-externalities"
 version = "0.25.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
  "environmental",
  "parity-scale-codec",
@@ -10051,7 +10129,7 @@ dependencies = [
  "libsecp256k1",
  "log",
  "parity-scale-codec",
- "polkavm-derive",
+ "polkavm-derive 0.9.1",
  "rustversion",
  "secp256k1",
  "sp-core",
@@ -10176,13 +10254,13 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface"
 version = "24.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive",
- "primitive-types",
+ "polkavm-derive 0.17.1",
+ "primitive-types 0.13.1",
  "sp-externalities 0.25.0",
  "sp-runtime-interface-proc-macro 17.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)",
@@ -10200,8 +10278,8 @@ dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive",
- "primitive-types",
+ "polkavm-derive 0.9.1",
+ "primitive-types 0.12.2",
  "sp-externalities 0.29.0",
  "sp-runtime-interface-proc-macro 18.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
@@ -10214,7 +10292,7 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface-proc-macro"
 version = "17.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
  "Inflector",
  "expander",
@@ -10316,14 +10394,14 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable
 [[package]]
 name = "sp-std"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 
 [[package]]
 name = "sp-storage"
 version = "19.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
- "impl-serde",
+ "impl-serde 0.5.0",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10335,7 +10413,7 @@ name = "sp-storage"
 version = "21.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde",
+ "impl-serde 0.4.0",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10357,7 +10435,7 @@ dependencies = [
 [[package]]
 name = "sp-tracing"
 version = "16.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
  "parity-scale-codec",
  "tracing",
@@ -10427,7 +10505,7 @@ name = "sp-version"
 version = "37.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde",
+ "impl-serde 0.4.0",
  "parity-scale-codec",
  "parity-wasm",
  "scale-info",
@@ -10453,7 +10531,7 @@ dependencies = [
 [[package]]
 name = "sp-wasm-interface"
 version = "20.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
 dependencies = [
  "anyhow",
  "impl-trait-for-tuples",
@@ -11627,6 +11705,18 @@ dependencies = [
  "static_assertions",
 ]
 
+[[package]]
+name = "uint"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.17"

From 8aa57171345bcabbbb88e03df344b96c24f0016d Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Mon, 20 Jan 2025 12:02:21 -0500
Subject: [PATCH 025/145] put owner cut in a pending

---
 Cargo.lock                                    | 184 +++++-------------
 .../subtensor/src/coinbase/run_coinbase.rs    |   9 +-
 pallets/subtensor/src/lib.rs                  |   3 +
 3 files changed, 57 insertions(+), 139 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 90c2fb86f..964c583e1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1550,9 +1550,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-queue"
-version = "0.3.11"
+version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
 dependencies = [
  "crossbeam-utils",
 ]
@@ -2187,9 +2187,9 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60"
 dependencies = [
  "crunchy",
  "fixed-hash",
- "impl-codec 0.6.0",
+ "impl-codec",
  "impl-rlp",
- "impl-serde 0.4.0",
+ "impl-serde",
  "scale-info",
  "tiny-keccak",
 ]
@@ -2220,12 +2220,12 @@ checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee"
 dependencies = [
  "ethbloom",
  "fixed-hash",
- "impl-codec 0.6.0",
+ "impl-codec",
  "impl-rlp",
- "impl-serde 0.4.0",
- "primitive-types 0.12.2",
+ "impl-serde",
+ "primitive-types",
  "scale-info",
- "uint 0.9.5",
+ "uint",
 ]
 
 [[package]]
@@ -2269,7 +2269,7 @@ dependencies = [
  "evm-runtime",
  "log",
  "parity-scale-codec",
- "primitive-types 0.12.2",
+ "primitive-types",
  "rlp",
  "scale-info",
  "serde",
@@ -2283,7 +2283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d1da6cedc5cedb4208e59467106db0d1f50db01b920920589f8e672c02fdc04f"
 dependencies = [
  "parity-scale-codec",
- "primitive-types 0.12.2",
+ "primitive-types",
  "scale-info",
  "serde",
 ]
@@ -2297,7 +2297,7 @@ dependencies = [
  "environmental",
  "evm-core",
  "evm-runtime",
- "primitive-types 0.12.2",
+ "primitive-types",
 ]
 
 [[package]]
@@ -2309,7 +2309,7 @@ dependencies = [
  "auto_impl",
  "environmental",
  "evm-core",
- "primitive-types 0.12.2",
+ "primitive-types",
  "sha3",
 ]
 
@@ -2694,7 +2694,7 @@ version = "1.0.0-dev"
 source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
 dependencies = [
  "hex",
- "impl-serde 0.4.0",
+ "impl-serde",
  "libsecp256k1",
  "log",
  "parity-scale-codec",
@@ -3876,26 +3876,6 @@ dependencies = [
  "parity-scale-codec",
 ]
 
-[[package]]
-name = "impl-codec"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941"
-dependencies = [
- "parity-scale-codec",
-]
-
-[[package]]
-name = "impl-num-traits"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "803d15461ab0dcc56706adf266158acbc44ccf719bf7d0af30705f58b90a4b8c"
-dependencies = [
- "integer-sqrt",
- "num-traits",
- "uint 0.10.0",
-]
-
 [[package]]
 name = "impl-rlp"
 version = "0.3.0"
@@ -3914,15 +3894,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "impl-serde"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a143eada6a1ec4aefa5049037a26a6d597bfd64f8c026d07b77133e02b7dd0b"
-dependencies = [
- "serde",
-]
-
 [[package]]
 name = "impl-trait-for-tuples"
 version = "0.2.2"
@@ -4459,7 +4430,7 @@ dependencies = [
  "sha2 0.10.8",
  "smallvec",
  "thiserror",
- "uint 0.9.5",
+ "uint",
  "unsigned-varint 0.7.2",
  "void",
 ]
@@ -4921,7 +4892,7 @@ dependencies = [
  "tokio-util",
  "tracing",
  "trust-dns-resolver",
- "uint 0.9.5",
+ "uint",
  "unsigned-varint 0.8.0",
  "url",
  "webpki",
@@ -6664,7 +6635,7 @@ dependencies = [
  "lru 0.8.1",
  "parity-util-mem-derive",
  "parking_lot 0.12.3",
- "primitive-types 0.12.2",
+ "primitive-types",
  "smallvec",
  "winapi",
 ]
@@ -6906,7 +6877,7 @@ dependencies = [
  "libc",
  "log",
  "polkavm-assembler",
- "polkavm-common 0.9.0",
+ "polkavm-common",
  "polkavm-linux-raw",
 ]
 
@@ -6928,28 +6899,13 @@ dependencies = [
  "log",
 ]
 
-[[package]]
-name = "polkavm-common"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f0dbafef4ab6ceecb4982ac3b550df430ef4f9fdbf07c108b7d4f91a0682fce"
-
 [[package]]
 name = "polkavm-derive"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606"
 dependencies = [
- "polkavm-derive-impl-macro 0.9.0",
-]
-
-[[package]]
-name = "polkavm-derive"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "206caf322dfc02144510ad8360ff2051e5072f0874dcab3b410f78cdd52d0ebb"
-dependencies = [
- "polkavm-derive-impl-macro 0.17.0",
+ "polkavm-derive-impl-macro",
 ]
 
 [[package]]
@@ -6958,19 +6914,7 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c"
 dependencies = [
- "polkavm-common 0.9.0",
- "proc-macro2",
- "quote",
- "syn 2.0.90",
-]
-
-[[package]]
-name = "polkavm-derive-impl"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42565aed4adbc4034612d0b17dea8db3681fb1bd1aed040d6edc5455a9f478a1"
-dependencies = [
- "polkavm-common 0.17.0",
+ "polkavm-common",
  "proc-macro2",
  "quote",
  "syn 2.0.90",
@@ -6982,17 +6926,7 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429"
 dependencies = [
- "polkavm-derive-impl 0.9.0",
- "syn 2.0.90",
-]
-
-[[package]]
-name = "polkavm-derive-impl-macro"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86d9838e95241b0bce4fe269cdd4af96464160505840ed5a8ac8536119ba19e2"
-dependencies = [
- "polkavm-derive-impl 0.17.0",
+ "polkavm-derive-impl",
  "syn 2.0.90",
 ]
 
@@ -7006,7 +6940,7 @@ dependencies = [
  "hashbrown 0.14.5",
  "log",
  "object 0.32.2",
- "polkavm-common 0.9.0",
+ "polkavm-common",
  "regalloc2 0.9.3",
  "rustc-demangle",
 ]
@@ -7143,23 +7077,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
 dependencies = [
  "fixed-hash",
- "impl-codec 0.6.0",
+ "impl-codec",
  "impl-rlp",
- "impl-serde 0.4.0",
+ "impl-serde",
  "scale-info",
- "uint 0.9.5",
-]
-
-[[package]]
-name = "primitive-types"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5"
-dependencies = [
- "fixed-hash",
- "impl-codec 0.7.0",
- "impl-num-traits",
- "uint 0.10.0",
+ "uint",
 ]
 
 [[package]]
@@ -9405,9 +9327,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
 
 [[package]]
 name = "serde"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
 dependencies = [
  "serde_derive",
 ]
@@ -9442,9 +9364,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9936,7 +9858,7 @@ dependencies = [
  "futures",
  "hash-db",
  "hash256-std-hasher",
- "impl-serde 0.4.0",
+ "impl-serde",
  "itertools 0.11.0",
  "k256",
  "libsecp256k1",
@@ -9946,7 +9868,7 @@ dependencies = [
  "parity-scale-codec",
  "parking_lot 0.12.3",
  "paste",
- "primitive-types 0.12.2",
+ "primitive-types",
  "rand",
  "scale-info",
  "schnorrkel",
@@ -9970,7 +9892,7 @@ dependencies = [
 [[package]]
 name = "sp-crypto-ec-utils"
 version = "0.10.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "ark-bls12-377",
  "ark-bls12-377-ext",
@@ -10066,7 +9988,7 @@ dependencies = [
 [[package]]
 name = "sp-debug-derive"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -10076,7 +9998,7 @@ dependencies = [
 [[package]]
 name = "sp-externalities"
 version = "0.25.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "environmental",
  "parity-scale-codec",
@@ -10129,7 +10051,7 @@ dependencies = [
  "libsecp256k1",
  "log",
  "parity-scale-codec",
- "polkavm-derive 0.9.1",
+ "polkavm-derive",
  "rustversion",
  "secp256k1",
  "sp-core",
@@ -10254,13 +10176,13 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface"
 version = "24.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive 0.17.1",
- "primitive-types 0.13.1",
+ "polkavm-derive",
+ "primitive-types",
  "sp-externalities 0.25.0",
  "sp-runtime-interface-proc-macro 17.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)",
@@ -10278,8 +10200,8 @@ dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive 0.9.1",
- "primitive-types 0.12.2",
+ "polkavm-derive",
+ "primitive-types",
  "sp-externalities 0.29.0",
  "sp-runtime-interface-proc-macro 18.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
@@ -10292,7 +10214,7 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface-proc-macro"
 version = "17.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "Inflector",
  "expander",
@@ -10394,14 +10316,14 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable
 [[package]]
 name = "sp-std"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 
 [[package]]
 name = "sp-storage"
 version = "19.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
- "impl-serde 0.5.0",
+ "impl-serde",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10413,7 +10335,7 @@ name = "sp-storage"
 version = "21.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde 0.4.0",
+ "impl-serde",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10435,7 +10357,7 @@ dependencies = [
 [[package]]
 name = "sp-tracing"
 version = "16.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "parity-scale-codec",
  "tracing",
@@ -10505,7 +10427,7 @@ name = "sp-version"
 version = "37.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde 0.4.0",
+ "impl-serde",
  "parity-scale-codec",
  "parity-wasm",
  "scale-info",
@@ -10531,7 +10453,7 @@ dependencies = [
 [[package]]
 name = "sp-wasm-interface"
 version = "20.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "anyhow",
  "impl-trait-for-tuples",
@@ -11705,18 +11627,6 @@ dependencies = [
  "static_assertions",
 ]
 
-[[package]]
-name = "uint"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e"
-dependencies = [
- "byteorder",
- "crunchy",
- "hex",
- "static_assertions",
-]
-
 [[package]]
 name = "unicode-bidi"
 version = "0.3.17"
diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index a150df654..11ea4887f 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -225,6 +225,10 @@ impl<T: Config> Pallet<T> {
             PendingEmission::<T>::mutate(*netuid, |total| {
                 *total = total.saturating_add(pending_alpha_emission.to_num::<u64>());
             });
+            // Accumulate the owner cut in pending.
+            PendingOwnerCut::<T>::mutate(*netuid, |total| {
+                *total = total.saturating_add(owner_cut);
+            });
         }
 
         // --- 5. Drain pending emission through the subnet based on tempo.
@@ -251,8 +255,9 @@ impl<T: Config> Pallet<T> {
                 let pending_root_divs: u64 = PendingRootDivs::<T>::get(netuid);
                 PendingRootDivs::<T>::insert(netuid, 0);
 
-                // 5.2.3 Get owner cut.
-                let owner_cut: u64 = *owner_cuts.get(&netuid).unwrap_or(&0);
+                // 5.2.3 Get owner cut and drain.
+                let owner_cut: u64 = PendingOwnerCut::<T>::get(netuid);
+                PendingOwnerCut::<T>::insert(netuid, 0);
 
                 // 5.2.4 Drain pending root divs, alpha emission, and owner cut.
                 Self::drain_pending_emission(
diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 7f75568ba..4a2150f7f 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -1097,6 +1097,9 @@ pub mod pallet {
     /// --- MAP ( netuid ) --> pending_root_emission
     pub type PendingRootDivs<T> = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
     #[pallet::storage]
+    /// --- MAP ( netuid ) --> pending_owner_cut
+    pub type PendingOwnerCut<T> = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
+    #[pallet::storage]
     /// --- MAP ( netuid ) --> blocks_since_last_step
     pub type BlocksSinceLastStep<T> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBlocksSinceLastStep<T>>;

From eef3ce637a1888286b00ef8386a7faa55d8d6edb Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Mon, 20 Jan 2025 14:49:25 -0500
Subject: [PATCH 026/145] move val prop to outside func

---
 pallets/subtensor/src/coinbase/run_coinbase.rs | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index 11ea4887f..259bf68cd 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -18,7 +18,11 @@ pub struct WeightsTlockPayload {
 }
 
 impl<T: Config> Pallet<T> {
-    pub fn get_root_divs_in_alpha(netuid: u16, alpha_out_emission: I96F32) -> I96F32 {
+    pub fn get_root_divs_in_alpha(
+        netuid: u16,
+        alpha_out_emission: I96F32,
+        validator_proportion: I96F32,
+    ) -> I96F32 {
         // Get total TAO on root.
         let total_root_tao: I96F32 = I96F32::from_num(SubnetTAO::<T>::get(0));
         // Get total ALPHA on subnet.
@@ -32,7 +36,8 @@ impl<T: Config> Pallet<T> {
         // Get root proportion of alpha_out dividends.
         let root_divs_in_alpha: I96F32 = root_proportion
             .saturating_mul(alpha_out_emission)
-            .saturating_mul(I96F32::from_num(0.41));
+            .saturating_mul(validator_proportion); // % of emission that goes to *all* validators.
+
         // Return
         root_divs_in_alpha
     }
@@ -207,9 +212,14 @@ impl<T: Config> Pallet<T> {
                 remaining_emission
             );
 
+            // Validators get 50% of remaining emission.
+            let validator_proportion: I96F32 = I96F32::from_num(0.5);
             // Get proportion of alpha out emission as root divs.
-            let root_emission_in_alpha: I96F32 =
-                Self::get_root_divs_in_alpha(*netuid, I96F32::from_num(remaining_emission));
+            let root_emission_in_alpha: I96F32 = Self::get_root_divs_in_alpha(
+                *netuid,
+                I96F32::from_num(remaining_emission),
+                validator_proportion,
+            );
             // Subtract root divs from alpha divs.
             let pending_alpha_emission: I96F32 =
                 I96F32::from_num(remaining_emission).saturating_sub(root_emission_in_alpha);

From 2bb5e208455e37ac91ec393ca3f98955d659409a Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 21 Jan 2025 14:57:13 -0500
Subject: [PATCH 027/145] Fix/charge-for-swap-before-schedule (#1141)

* charge for swap before sched

* add swap cost to the events

* pass swap cost into swap_coldkey call

* fmt

* oops, add arg

* commit Cargo.lock

* bump spec

* fix tests
---
 pallets/subtensor/src/benchmarks.rs         |  2 +-
 pallets/subtensor/src/macros/dispatches.rs  | 12 +++-
 pallets/subtensor/src/macros/events.rs      |  4 ++
 pallets/subtensor/src/swap/swap_coldkey.rs  |  5 +-
 pallets/subtensor/src/tests/swap_coldkey.rs | 67 ++++++++++++++++++---
 runtime/src/lib.rs                          |  2 +-
 6 files changed, 78 insertions(+), 14 deletions(-)

diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs
index ecb5a1303..30d1f39e1 100644
--- a/pallets/subtensor/src/benchmarks.rs
+++ b/pallets/subtensor/src/benchmarks.rs
@@ -515,7 +515,7 @@ reveal_weights {
     Identities::<T>::insert(&old_coldkey, identity);
 
     // Benchmark setup complete, now execute the extrinsic
-}: swap_coldkey(RawOrigin::Root, old_coldkey.clone(), new_coldkey.clone())
+}: swap_coldkey(RawOrigin::Root, old_coldkey.clone(), new_coldkey.clone(), swap_cost)
 
 batch_reveal_weights {
   let tempo: u16 = 0;
diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs
index 7073a1413..285c9df66 100644
--- a/pallets/subtensor/src/macros/dispatches.rs
+++ b/pallets/subtensor/src/macros/dispatches.rs
@@ -962,12 +962,13 @@ mod dispatches {
             origin: OriginFor<T>,
             old_coldkey: T::AccountId,
             new_coldkey: T::AccountId,
+            swap_cost: u64,
         ) -> DispatchResultWithPostInfo {
             // Ensure it's called with root privileges (scheduler has root privileges)
             ensure_root(origin)?;
             log::info!("swap_coldkey: {:?} -> {:?}", old_coldkey, new_coldkey);
 
-            Self::do_swap_coldkey(&old_coldkey, &new_coldkey)
+            Self::do_swap_coldkey(&old_coldkey, &new_coldkey, swap_cost)
         }
 
         /// Sets the childkey take for a given hotkey.
@@ -1327,6 +1328,13 @@ mod dispatches {
                 Error::<T>::SwapAlreadyScheduled
             );
 
+            // Calculate the swap cost and ensure sufficient balance
+            let swap_cost = Self::get_key_swap_cost();
+            ensure!(
+                Self::can_remove_balance_from_coldkey_account(&who, swap_cost),
+                Error::<T>::NotEnoughBalanceToPaySwapColdKey
+            );
+
             let current_block: BlockNumberFor<T> = <frame_system::Pallet<T>>::block_number();
             let duration: BlockNumberFor<T> = ColdkeySwapScheduleDuration::<T>::get();
             let when: BlockNumberFor<T> = current_block.saturating_add(duration);
@@ -1334,6 +1342,7 @@ mod dispatches {
             let call = Call::<T>::swap_coldkey {
                 old_coldkey: who.clone(),
                 new_coldkey: new_coldkey.clone(),
+                swap_cost,
             };
 
             let bound_call = T::Preimages::bound(LocalCallOf::<T>::from(call.clone()))
@@ -1354,6 +1363,7 @@ mod dispatches {
                 old_coldkey: who.clone(),
                 new_coldkey: new_coldkey.clone(),
                 execution_block: when,
+                swap_cost,
             });
 
             Ok(().into())
diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs
index 30566ac47..c1d25b8f4 100644
--- a/pallets/subtensor/src/macros/events.rs
+++ b/pallets/subtensor/src/macros/events.rs
@@ -155,6 +155,8 @@ mod events {
             old_coldkey: T::AccountId,
             /// the account ID of new coldkey
             new_coldkey: T::AccountId,
+            /// the swap cost
+            swap_cost: u64,
         },
         /// All balance of a hotkey has been unstaked and transferred to a new coldkey
         AllBalanceUnstakedAndTransferredToNewColdkey {
@@ -175,6 +177,8 @@ mod events {
             new_coldkey: T::AccountId,
             /// The arbitration block for the coldkey swap
             execution_block: BlockNumberFor<T>,
+            /// The swap cost
+            swap_cost: u64,
         },
         /// The arbitration period has been extended
         ArbitrationPeriodExtended {
diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs
index 2f0a6f2c6..075538421 100644
--- a/pallets/subtensor/src/swap/swap_coldkey.rs
+++ b/pallets/subtensor/src/swap/swap_coldkey.rs
@@ -33,6 +33,7 @@ impl<T: Config> Pallet<T> {
     pub fn do_swap_coldkey(
         old_coldkey: &T::AccountId,
         new_coldkey: &T::AccountId,
+        swap_cost: u64,
     ) -> DispatchResultWithPostInfo {
         // 2. Initialize the weight for this operation
         let mut weight: Weight = T::DbWeight::get().reads(2);
@@ -55,8 +56,7 @@ impl<T: Config> Pallet<T> {
             Identities::<T>::insert(new_coldkey, identity);
         }
 
-        // 6. Calculate the swap cost and ensure sufficient balance
-        let swap_cost = Self::get_key_swap_cost();
+        // 6. Ensure sufficient balance for the swap cost
         ensure!(
             Self::can_remove_balance_from_coldkey_account(old_coldkey, swap_cost),
             Error::<T>::NotEnoughBalanceToPaySwapColdKey
@@ -83,6 +83,7 @@ impl<T: Config> Pallet<T> {
         Self::deposit_event(Event::ColdkeySwapped {
             old_coldkey: old_coldkey.clone(),
             new_coldkey: new_coldkey.clone(),
+            swap_cost,
         });
 
         // 12. Return the result with the updated weight
diff --git a/pallets/subtensor/src/tests/swap_coldkey.rs b/pallets/subtensor/src/tests/swap_coldkey.rs
index 0cbcecfaf..bf4f1ad40 100644
--- a/pallets/subtensor/src/tests/swap_coldkey.rs
+++ b/pallets/subtensor/src/tests/swap_coldkey.rs
@@ -709,7 +709,8 @@ fn test_do_swap_coldkey_success() {
         assert_ok!(SubtensorModule::do_swap_coldkey(
             // <<Test as Config>::RuntimeOrigin>::signed(old_coldkey),
             &old_coldkey,
-            &new_coldkey
+            &new_coldkey,
+            swap_cost
         ));
 
         // Log state after swap
@@ -782,6 +783,7 @@ fn test_do_swap_coldkey_success() {
             Event::ColdkeySwapped {
                 old_coldkey,
                 new_coldkey,
+                swap_cost,
             }
             .into(),
         );
@@ -1195,7 +1197,11 @@ fn test_do_swap_coldkey_with_subnet_ownership() {
         OwnedHotkeys::<Test>::insert(old_coldkey, vec![hotkey]);
 
         // Perform the swap
-        assert_ok!(SubtensorModule::do_swap_coldkey(&old_coldkey, &new_coldkey));
+        assert_ok!(SubtensorModule::do_swap_coldkey(
+            &old_coldkey,
+            &new_coldkey,
+            swap_cost
+        ));
 
         // Verify subnet ownership transfer
         assert_eq!(SubnetOwner::<Test>::get(netuid), new_coldkey);
@@ -1652,8 +1658,10 @@ fn test_schedule_swap_coldkey_success() {
         let old_coldkey: U256 = U256::from(1);
         let new_coldkey: U256 = U256::from(2);
 
+        let swap_cost = SubtensorModule::get_key_swap_cost();
+
         // Add balance to the old coldkey account
-        SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 1000);
+        SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, swap_cost + 1_000);
 
         // Schedule the coldkey swap
         assert_ok!(SubtensorModule::schedule_swap_coldkey(
@@ -1673,6 +1681,7 @@ fn test_schedule_swap_coldkey_success() {
                 old_coldkey,
                 new_coldkey,
                 execution_block: expected_execution_block,
+                swap_cost,
             }
             .into(),
         );
@@ -1689,7 +1698,9 @@ fn test_schedule_swap_coldkey_duplicate() {
         let old_coldkey = U256::from(1);
         let new_coldkey = U256::from(2);
 
-        SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 2000);
+        let swap_cost = SubtensorModule::get_key_swap_cost();
+
+        SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, swap_cost + 2_000);
 
         assert_ok!(SubtensorModule::schedule_swap_coldkey(
             <<Test as Config>::RuntimeOrigin>::signed(old_coldkey),
@@ -1734,6 +1745,8 @@ fn test_schedule_swap_coldkey_execution() {
             "Initial ownership check failed"
         );
 
+        let swap_cost = SubtensorModule::get_key_swap_cost();
+
         // Schedule the swap
         assert_ok!(SubtensorModule::schedule_swap_coldkey(
             <<Test as Config>::RuntimeOrigin>::signed(old_coldkey),
@@ -1749,6 +1762,7 @@ fn test_schedule_swap_coldkey_execution() {
                 old_coldkey,
                 new_coldkey,
                 execution_block,
+                swap_cost,
             }
             .into(),
         );
@@ -1790,6 +1804,7 @@ fn test_schedule_swap_coldkey_execution() {
             Event::ColdkeySwapped {
                 old_coldkey,
                 new_coldkey,
+                swap_cost,
             }
             .into(),
         );
@@ -1807,7 +1822,8 @@ fn test_direct_swap_coldkey_call_fails() {
             SubtensorModule::swap_coldkey(
                 <<Test as Config>::RuntimeOrigin>::signed(old_coldkey),
                 old_coldkey,
-                new_coldkey
+                new_coldkey,
+                0
             ),
             BadOrigin
         );
@@ -1822,7 +1838,9 @@ fn test_schedule_swap_coldkey_with_pending_swap() {
         let new_coldkey1 = U256::from(2);
         let new_coldkey2 = U256::from(3);
 
-        SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 2000);
+        let swap_cost = SubtensorModule::get_key_swap_cost();
+
+        SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, swap_cost + 1_000);
 
         assert_ok!(SubtensorModule::schedule_swap_coldkey(
             <<Test as Config>::RuntimeOrigin>::signed(old_coldkey),
@@ -1876,7 +1894,11 @@ fn test_coldkey_swap_delegate_identity_updated() {
         assert!(Identities::<Test>::get(old_coldkey).is_some());
         assert!(Identities::<Test>::get(new_coldkey).is_none());
 
-        assert_ok!(SubtensorModule::do_swap_coldkey(&old_coldkey, &new_coldkey));
+        assert_ok!(SubtensorModule::do_swap_coldkey(
+            &old_coldkey,
+            &new_coldkey,
+            burn_cost
+        ));
 
         assert!(Identities::<Test>::get(old_coldkey).is_none());
         assert!(Identities::<Test>::get(new_coldkey).is_some());
@@ -1912,7 +1934,11 @@ fn test_coldkey_swap_no_identity_no_changes() {
         assert!(Identities::<Test>::get(old_coldkey).is_none());
 
         // Perform the coldkey swap
-        assert_ok!(SubtensorModule::do_swap_coldkey(&old_coldkey, &new_coldkey));
+        assert_ok!(SubtensorModule::do_swap_coldkey(
+            &old_coldkey,
+            &new_coldkey,
+            burn_cost
+        ));
 
         // Ensure no identities have been changed
         assert!(Identities::<Test>::get(old_coldkey).is_none());
@@ -1956,10 +1982,33 @@ fn test_coldkey_swap_no_identity_no_changes_newcoldkey_exists() {
         assert!(Identities::<Test>::get(old_coldkey).is_none());
 
         // Perform the coldkey swap
-        assert_ok!(SubtensorModule::do_swap_coldkey(&old_coldkey, &new_coldkey));
+        assert_ok!(SubtensorModule::do_swap_coldkey(
+            &old_coldkey,
+            &new_coldkey,
+            burn_cost
+        ));
 
         // Ensure no identities have been changed
         assert!(Identities::<Test>::get(old_coldkey).is_none());
         assert!(Identities::<Test>::get(new_coldkey).is_some());
     });
 }
+
+// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_cant_schedule_swap_without_enough_to_burn --exact --nocapture
+#[test]
+fn test_cant_schedule_swap_without_enough_to_burn() {
+    new_test_ext(1).execute_with(|| {
+        let old_coldkey = U256::from(3);
+        let new_coldkey = U256::from(4);
+        let hotkey = U256::from(5);
+
+        let burn_cost = SubtensorModule::get_key_swap_cost();
+        assert_noop!(
+            SubtensorModule::schedule_swap_coldkey(
+                <<Test as Config>::RuntimeOrigin>::signed(old_coldkey),
+                new_coldkey
+            ),
+            Error::<Test>::NotEnoughBalanceToPaySwapColdKey
+        );
+    });
+}
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 72221b9ff..128d2b8f3 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
     //   `spec_version`, and `authoring_version` are the same between Wasm and native.
     // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
     //   the compatible custom types.
-    spec_version: 222,
+    spec_version: 223,
     impl_version: 1,
     apis: RUNTIME_API_VERSIONS,
     transaction_version: 1,

From 09e205b1bd151dfe50d4486528b2e4a5f6f0690b Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 21 Jan 2025 15:28:51 -0500
Subject: [PATCH 028/145] Fix/per 1k estimate always zero (#1152)

* add fix for return per 1k

* extract helper and add test
---
 .../subtensor/src/rpc_info/delegate_info.rs   | 38 +++++++++++++++----
 pallets/subtensor/src/tests/delegate_info.rs  | 33 ++++++++++++++++
 pallets/subtensor/src/tests/mod.rs            |  1 +
 3 files changed, 64 insertions(+), 8 deletions(-)
 create mode 100644 pallets/subtensor/src/tests/delegate_info.rs

diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs
index 5cd234b48..5776c48af 100644
--- a/pallets/subtensor/src/rpc_info/delegate_info.rs
+++ b/pallets/subtensor/src/rpc_info/delegate_info.rs
@@ -21,6 +21,34 @@ pub struct DelegateInfo<T: Config> {
 }
 
 impl<T: Config> Pallet<T> {
+    fn return_per_1000_tao(
+        take: Compact<u16>,
+        total_stake: U64F64,
+        emissions_per_day: U64F64,
+    ) -> U64F64 {
+        // Get the take as a percentage and subtract it from 1 for remainder.
+        let without_take: U64F64 = U64F64::from_num(1)
+            .saturating_sub(U64F64::from_num(take.0).saturating_div(u16::MAX.into()));
+
+        if total_stake > U64F64::from_num(0) {
+            emissions_per_day
+                .saturating_mul(without_take)
+                // Divide by 1000 TAO for return per 1k
+                .saturating_div(total_stake.saturating_div(U64F64::from_num(1000.0 * 1e9)))
+        } else {
+            U64F64::from_num(0)
+        }
+    }
+
+    #[cfg(test)]
+    pub fn return_per_1000_tao_test(
+        take: Compact<u16>,
+        total_stake: U64F64,
+        emissions_per_day: U64F64,
+    ) -> U64F64 {
+        Self::return_per_1000_tao(take, total_stake, emissions_per_day)
+    }
+
     fn get_delegate_by_existing_account(delegate: AccountIdOf<T>) -> DelegateInfo<T> {
         let mut nominators = Vec::<(T::AccountId, Compact<u64>)>::new();
 
@@ -63,14 +91,8 @@ impl<T: Config> Pallet<T> {
         let total_stake: U64F64 =
             Self::get_stake_for_hotkey_on_subnet(&delegate.clone(), Self::get_root_netuid()).into();
 
-        let return_per_1000: U64F64 = if total_stake > U64F64::from_num(0) {
-            emissions_per_day
-                .saturating_mul(u16::MAX.saturating_sub(take.0).into())
-                .saturating_div(u16::MAX.into())
-                .saturating_div(total_stake.saturating_div(U64F64::from_num(1000)))
-        } else {
-            U64F64::from_num(0)
-        };
+        let return_per_1000: U64F64 =
+            Self::return_per_1000_tao(take, total_stake, emissions_per_day);
 
         DelegateInfo {
             delegate_ss58: delegate.clone(),
diff --git a/pallets/subtensor/src/tests/delegate_info.rs b/pallets/subtensor/src/tests/delegate_info.rs
new file mode 100644
index 000000000..78ea48482
--- /dev/null
+++ b/pallets/subtensor/src/tests/delegate_info.rs
@@ -0,0 +1,33 @@
+use codec::Compact;
+use substrate_fixed::types::U64F64;
+
+use super::mock::*;
+
+#[test]
+fn test_return_per_1000_tao() {
+    let take = // 18% take to the Validator
+        Compact::<u16>::from((U64F64::from_num(0.18 * u16::MAX as f64)).saturating_to_num::<u16>());
+
+    // 10_000 TAO total validator stake
+    let total_stake = U64F64::from_num(10_000.0 * 1e9);
+    // 1000 TAO emissions per day
+    let emissions_per_day = U64F64::from_num(1000.0 * 1e9);
+
+    let return_per_1000 =
+        SubtensorModule::return_per_1000_tao_test(take, total_stake, emissions_per_day);
+
+    // We expect 82 TAO per day with 10% of total_stake
+    let expected_return_per_1000 = U64F64::from_num(82.0);
+
+    let diff_from_expected: f64 = (return_per_1000 / U64F64::from_num(1e9))
+        .saturating_sub(expected_return_per_1000)
+        .to_num::<f64>();
+
+    let eps: f64 = 0.0005e9; // Precision within 0.0005 TAO
+    assert!(
+        diff_from_expected.abs() <= eps,
+        "Difference from expected: {} is greater than precision: {}",
+        diff_from_expected,
+        eps
+    );
+}
diff --git a/pallets/subtensor/src/tests/mod.rs b/pallets/subtensor/src/tests/mod.rs
index e0fef9d55..6865c9fa4 100644
--- a/pallets/subtensor/src/tests/mod.rs
+++ b/pallets/subtensor/src/tests/mod.rs
@@ -1,6 +1,7 @@
 mod batch_tx;
 mod children;
 mod coinbase;
+mod delegate_info;
 mod difficulty;
 mod emission;
 mod epoch;

From d392516865272997a982258e968b6dd8557d6c2c Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 21 Jan 2025 15:32:28 -0500
Subject: [PATCH 029/145] Send staking and unstaking fees to SubnetTAO

---
 pallets/subtensor/src/staking/stake_utils.rs | 63 +++++++++----
 pallets/subtensor/src/tests/staking.rs       | 97 ++++++++++++++++++++
 2 files changed, 140 insertions(+), 20 deletions(-)

diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index 524cd2069..b79b141d0 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -1,5 +1,7 @@
 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};
 
@@ -621,11 +623,19 @@ impl<T: Config> Pallet<T> {
         //     });
         // }
 
-        // Step 4. Deposit and log the unstaking event.
+        // 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);
+        });
+
+        // Step 5. Deposit and log the unstaking event.
         Self::deposit_event(Event::StakeRemoved(
             coldkey.clone(),
             hotkey.clone(),
-            tao,
+            tao_unstaked,
             alpha,
             netuid,
         ));
@@ -633,13 +643,13 @@ impl<T: Config> Pallet<T> {
             "StakeRemoved( coldkey: {:?}, hotkey:{:?}, tao: {:?}, alpha:{:?}, netuid: {:?} )",
             coldkey.clone(),
             hotkey.clone(),
-            tao,
+            tao_unstaked,
             alpha,
             netuid
         );
 
-        // Step 5: Return the amount of TAO unstaked.
-        tao
+        // Step 6: Return the amount of TAO unstaked.
+        tao_unstaked
     }
 
     /// Stakes TAO into a subnet for a given hotkey and coldkey pair.
@@ -651,24 +661,37 @@ impl<T: Config> Pallet<T> {
         netuid: u16,
         tao: u64,
     ) -> u64 {
-        // Step 1. Swap the tao to alpha.
-        let alpha: u64 = Self::swap_tao_for_alpha(netuid, tao);
-
-        // Step 2: Increase the alpha on the hotkey account.
-        Self::increase_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha);
-
-        // Step 4: Update the list of hotkeys staking for this coldkey
-        let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
-        if !staking_hotkeys.contains(hotkey) {
-            staking_hotkeys.push(hotkey.clone());
-            StakingHotkeys::<T>::insert(coldkey, staking_hotkeys.clone());
+        // 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 
+        // available
+        let fee = DefaultMinStake::<T>::get();
+        let tao_staked = tao.saturating_sub(fee);
+        let actual_fee = tao.saturating_sub(tao_staked);
+
+        // Step 2. Swap the tao to alpha.
+        let alpha: u64 = Self::swap_tao_for_alpha(netuid, tao_staked);
+        if (tao_staked > 0) && (alpha > 0) {
+            // Step 3: Increase the alpha on the hotkey account.
+            Self::increase_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha);
+
+            // Step 4: Update the list of hotkeys staking for this coldkey
+            let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
+            if !staking_hotkeys.contains(hotkey) {
+                staking_hotkeys.push(hotkey.clone());
+                StakingHotkeys::<T>::insert(coldkey, staking_hotkeys.clone());
+            }
         }
 
-        // Step 5. Deposit and log the staking event.
+        // Step 5. Increase Tao reserves by the fee amount.
+        SubnetTAO::<T>::mutate(netuid, |total| {
+            *total = total.saturating_add(actual_fee);
+        });
+
+        // Step 6. Deposit and log the staking event.
         Self::deposit_event(Event::StakeAdded(
             coldkey.clone(),
             hotkey.clone(),
-            tao,
+            tao_staked,
             alpha,
             netuid,
         ));
@@ -676,12 +699,12 @@ impl<T: Config> Pallet<T> {
             "StakeAdded( coldkey: {:?}, hotkey:{:?}, tao: {:?}, alpha:{:?}, netuid: {:?} )",
             coldkey.clone(),
             hotkey.clone(),
-            tao,
+            tao_staked,
             alpha,
             netuid
         );
 
-        // Step 6: Return the amount of alpha staked
+        // Step 7: Return the amount of alpha staked
         alpha
     }
 
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 6594887b9..882184811 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -1941,3 +1941,100 @@ fn test_staking_too_little_fails() {
         );
     });
 }
+
+// cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_fee_goes_to_subnet_tao --exact --show-output --nocapture
+#[test]
+fn test_add_stake_fee_goes_to_subnet_tao() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let hotkey = U256::from(2);
+        let coldkey = U256::from(3);
+        let existential_deposit = ExistentialDeposit::get();
+        let tao_to_stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
+
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        let subnet_tao_before = SubnetTAO::<Test>::get(netuid);
+
+        // Add stake
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, tao_to_stake);
+        assert_ok!(SubtensorModule::add_stake(
+            RuntimeOrigin::signed(coldkey),
+            hotkey,
+            netuid,
+            tao_to_stake
+        ));
+
+        // Calculate expected stake
+        let expected_alpha = tao_to_stake - existential_deposit - fee;
+        let actual_alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        let subnet_tao_after = SubnetTAO::<Test>::get(netuid);
+
+        // Total subnet stake should match the sum of delegators' stakes minus existential deposits.
+        assert_abs_diff_eq!(
+            actual_alpha,
+            expected_alpha,
+            epsilon = expected_alpha / 1000
+        );
+
+        // Subnet TAO should have increased by the full tao_to_stake amount
+        assert_abs_diff_eq!(
+            subnet_tao_before + tao_to_stake,
+            subnet_tao_after,
+            epsilon = 10
+        );
+    });
+}
+
+// cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_stake_fee_goes_to_subnet_tao --exact --show-output --nocapture
+#[test]
+fn test_remove_stake_fee_goes_to_subnet_tao() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let hotkey = U256::from(2);
+        let coldkey = U256::from(3);
+        let tao_to_stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
+
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        let subnet_tao_before = SubnetTAO::<Test>::get(netuid);
+
+        // Add stake
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, tao_to_stake);
+        assert_ok!(SubtensorModule::add_stake(
+            RuntimeOrigin::signed(coldkey),
+            hotkey,
+            netuid,
+            tao_to_stake
+        ));
+
+        // Remove all stake
+        let alpha_to_unstake = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        assert_ok!(SubtensorModule::remove_stake(
+            RuntimeOrigin::signed(coldkey),
+            hotkey,
+            netuid,
+            alpha_to_unstake
+        ));
+        let subnet_tao_after = SubnetTAO::<Test>::get(netuid);
+
+        // Subnet TAO should have increased by 2x fee as a result of staking + unstaking
+        assert_abs_diff_eq!(
+            subnet_tao_before + 2 * fee,
+            subnet_tao_after,
+            epsilon = alpha_to_unstake / 1000
+        );
+
+        // User balance should decrease by 2x fee as a result of staking + unstaking
+        let balance_after = SubtensorModule::get_coldkey_balance(&coldkey);
+        assert_abs_diff_eq!(
+            balance_after + 2 * fee,
+            tao_to_stake,
+            epsilon = tao_to_stake / 1000
+        );
+    });
+}
\ No newline at end of file

From 01203b329539c81ecd4dded6c14332bf1fb0c70f Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Tue, 21 Jan 2025 15:52:45 -0500
Subject: [PATCH 030/145] add alpha swapped tracker

---
 .../subtensor/src/coinbase/run_coinbase.rs    | 22 +++++++++++++++----
 pallets/subtensor/src/lib.rs                  |  4 ++++
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index 259bf68cd..e86c07c24 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -231,6 +231,10 @@ impl<T: Config> Pallet<T> {
             PendingRootDivs::<T>::mutate(*netuid, |total| {
                 *total = total.saturating_add(root_emission_in_tao);
             });
+            // Accumulate alpha that was swapped for the pending root divs.
+            PendingAlphaSwapped::<T>::mutate(*netuid, |total| {
+                *total = total.saturating_add(root_emission_in_alpha.to_num::<u64>());
+            });
             // Accumulate alpha emission in pending.
             PendingEmission::<T>::mutate(*netuid, |total| {
                 *total = total.saturating_add(pending_alpha_emission.to_num::<u64>());
@@ -261,10 +265,14 @@ impl<T: Config> Pallet<T> {
                 let pending_emission: u64 = PendingEmission::<T>::get(netuid);
                 PendingEmission::<T>::insert(netuid, 0);
 
-                // 5.2.2 Get and drain the subnet pending root divs.
+                // 5.2.2a Get and drain the subnet pending root divs.
                 let pending_root_divs: u64 = PendingRootDivs::<T>::get(netuid);
                 PendingRootDivs::<T>::insert(netuid, 0);
 
+                // 5.2.2b Get this amount as alpha that was swapped for pending root divs.
+                let pending_alpha_swapped: u64 = PendingAlphaSwapped::<T>::get(netuid);
+                PendingAlphaSwapped::<T>::insert(netuid, 0);
+
                 // 5.2.3 Get owner cut and drain.
                 let owner_cut: u64 = PendingOwnerCut::<T>::get(netuid);
                 PendingOwnerCut::<T>::insert(netuid, 0);
@@ -274,6 +282,7 @@ impl<T: Config> Pallet<T> {
                     netuid,
                     pending_emission,
                     pending_root_divs,
+                    pending_alpha_swapped,
                     owner_cut,
                 );
             } else {
@@ -287,19 +296,24 @@ impl<T: Config> Pallet<T> {
         netuid: u16,
         pending_alpha_emission: u64,
         pending_root_divs: u64,
+        pending_alpha_swapped: u64,
         owner_cut: u64,
     ) {
         log::debug!(
-            "Draining pending alpha emission for netuid {:?}: {:?}, with pending root divs {:?}, and owner cut {:?}",
+            "Draining pending alpha emission for netuid {:?}: {:?}, with pending root divs {:?}, pending alpha swapped {:?}, and owner cut {:?}",
             netuid,
             pending_alpha_emission,
             pending_root_divs,
+            pending_alpha_swapped,
             owner_cut
         );
 
         // Run the epoch() --> hotkey emission.
-        let hotkey_emission: Vec<(T::AccountId, u64, u64)> =
-            Self::epoch(netuid, pending_alpha_emission);
+        // Needs to run on the full emission to the subnet.
+        let hotkey_emission: Vec<(T::AccountId, u64, u64)> = Self::epoch(
+            netuid,
+            pending_alpha_emission.saturating_add(pending_alpha_swapped),
+        );
         log::debug!(
             "Hotkey emission for netuid {:?}: {:?}",
             netuid,
diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 4a2150f7f..1d2690503 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -1097,6 +1097,10 @@ pub mod pallet {
     /// --- MAP ( netuid ) --> pending_root_emission
     pub type PendingRootDivs<T> = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
     #[pallet::storage]
+    /// --- MAP ( netuid ) --> pending_alpha_swapped
+    pub type PendingAlphaSwapped<T> =
+        StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
+    #[pallet::storage]
     /// --- MAP ( netuid ) --> pending_owner_cut
     pub type PendingOwnerCut<T> = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
     #[pallet::storage]

From f0f4c6b990dccb5cf7e9bdd6dc8f3e0dbf7f9fc7 Mon Sep 17 00:00:00 2001
From: JohnReedV <87283488+JohnReedV@users.noreply.github.com>
Date: Tue, 21 Jan 2025 14:34:46 -0800
Subject: [PATCH 031/145] add transfer_stake & tests

---
 pallets/subtensor/src/macros/dispatches.rs  |  44 ++++
 pallets/subtensor/src/macros/events.rs      |   5 +
 pallets/subtensor/src/staking/move_stake.rs | 107 +++++++++
 pallets/subtensor/src/tests/move_stake.rs   | 253 ++++++++++++++++++++
 4 files changed, 409 insertions(+)

diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs
index 7073a1413..34712ccb5 100644
--- a/pallets/subtensor/src/macros/dispatches.rs
+++ b/pallets/subtensor/src/macros/dispatches.rs
@@ -1596,5 +1596,49 @@ mod dispatches {
                 alpha_amount,
             )
         }
+
+        /// Transfers a specified amount of stake from one coldkey to another, optionally across subnets,
+        /// while keeping the same hotkey.
+        ///
+        /// # Arguments
+        /// * `origin` - The origin of the transaction, which must be signed by the `origin_coldkey`.
+        /// * `destination_coldkey` - The coldkey to which the stake is transferred.
+        /// * `hotkey` - The hotkey associated with the stake.
+        /// * `origin_netuid` - The network/subnet ID to move stake from.
+        /// * `destination_netuid` - The network/subnet ID to move stake to (for cross-subnet transfer).
+        /// * `alpha_amount` - The amount of stake to transfer.
+        ///
+        /// # Weight
+        /// Uses a fixed weight of 3_000_000 (plus any DB write overhead).
+        ///
+        /// # Errors
+        /// Returns an error if:
+        /// * The origin is not signed by the correct coldkey.
+        /// * Either subnet does not exist.
+        /// * The hotkey does not exist.
+        /// * There is insufficient stake on `(origin_coldkey, hotkey, origin_netuid)`.
+        /// * The transfer amount is below the minimum stake requirement.
+        ///
+        /// # Events
+        /// May emit a `StakeTransferred` event on success.
+        #[pallet::call_index(86)]
+        #[pallet::weight((Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))]
+        pub fn transfer_stake(
+            origin: T::RuntimeOrigin,
+            destination_coldkey: T::AccountId,
+            hotkey: T::AccountId,
+            origin_netuid: u16,
+            destination_netuid: u16,
+            alpha_amount: u64,
+        ) -> DispatchResult {
+            Self::do_transfer_stake(
+                origin,
+                destination_coldkey,
+                hotkey,
+                origin_netuid,
+                destination_netuid,
+                alpha_amount,
+            )
+        }
     }
 }
diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs
index 30566ac47..782f6b792 100644
--- a/pallets/subtensor/src/macros/events.rs
+++ b/pallets/subtensor/src/macros/events.rs
@@ -248,5 +248,10 @@ mod events {
         ///
         /// - **error**: The dispatch error emitted by the failed item.
         BatchWeightItemFailed(sp_runtime::DispatchError),
+
+        /// Stake has been transferred from one coldkey to another on the same subnet.
+        /// Parameters:
+        /// (origin_coldkey, destination_coldkey, hotkey, origin_netuid, destination_netuid, amount)
+        StakeTransferred(T::AccountId, T::AccountId, T::AccountId, u16, u16, u64),
     }
 }
diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 9628c5814..49d823b86 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -110,4 +110,111 @@ impl<T: Config> Pallet<T> {
         // -- 10. Ok and return.
         Ok(())
     }
+
+    /// Transfers stake from one coldkey to another, optionally moving from one subnet to another,
+    /// while keeping the same hotkey.
+    ///
+    /// # Arguments
+    /// * `origin` - The origin of the transaction, which must be signed by the `origin_coldkey`.
+    /// * `destination_coldkey` - The account ID of the coldkey to which the stake is being transferred.
+    /// * `hotkey` - The account ID of the hotkey associated with this stake.
+    /// * `origin_netuid` - The network ID (subnet) from which the stake is being transferred.
+    /// * `destination_netuid` - The network ID (subnet) to which the stake is being transferred.
+    /// * `alpha_amount` - The amount of stake to transfer.
+    ///
+    /// # Returns
+    /// * `DispatchResult` - Indicates success or failure.
+    ///
+    /// # Errors
+    /// This function will return an error if:
+    /// * The transaction is not signed by the `origin_coldkey`.
+    /// * The subnet (`origin_netuid` or `destination_netuid`) does not exist.
+    /// * The `hotkey` does not exist.
+    /// * The `(origin_coldkey, hotkey, origin_netuid)` does not have enough stake for `alpha_amount`.
+    /// * The amount to be transferred is below the minimum stake requirement.
+    /// * There is a failure in staking or unstaking logic.
+    ///
+    /// # Events
+    /// Emits a `StakeTransferred` event upon successful completion of the transfer.
+    pub fn do_transfer_stake(
+        origin: T::RuntimeOrigin,
+        destination_coldkey: T::AccountId,
+        hotkey: T::AccountId,
+        origin_netuid: u16,
+        destination_netuid: u16,
+        alpha_amount: u64,
+    ) -> dispatch::DispatchResult {
+        // 1. Ensure the extrinsic is signed by the origin_coldkey.
+        let coldkey = ensure_signed(origin)?;
+
+        // 2. Ensure both subnets exist.
+        ensure!(
+            Self::if_subnet_exist(origin_netuid),
+            Error::<T>::SubnetNotExists
+        );
+        ensure!(
+            Self::if_subnet_exist(destination_netuid),
+            Error::<T>::SubnetNotExists
+        );
+
+        // 3. Check that the hotkey exists.
+        ensure!(
+            Self::hotkey_account_exists(&hotkey),
+            Error::<T>::HotKeyAccountNotExists
+        );
+
+        // 4. Check that the signed coldkey actually owns the given hotkey.
+        ensure!(
+            Self::coldkey_owns_hotkey(&coldkey, &hotkey),
+            Error::<T>::NonAssociatedColdKey
+        );
+
+        // 5. Get current stake.
+        let origin_alpha =
+            Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, origin_netuid);
+        ensure!(
+            alpha_amount <= origin_alpha,
+            Error::<T>::NotEnoughStakeToWithdraw
+        );
+
+        // 6. Unstake from the origin coldkey; this returns an amount of TAO.
+        let origin_tao = Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount);
+
+        // 7. Ensure the returned TAO meets a minimum stake requirement (if required).
+        ensure!(
+            origin_tao >= DefaultMinStake::<T>::get(),
+            Error::<T>::AmountTooLow
+        );
+
+        // 8. Stake the TAO into `(destination_coldkey, hotkey)` on the destination subnet.
+        //    Create the account if it does not exist.
+        Self::stake_into_subnet(
+            &hotkey,
+            &destination_coldkey,
+            destination_netuid,
+            origin_tao,
+        );
+
+        // 9. Emit an event for logging/monitoring.
+        log::info!(
+            "StakeTransferred(origin_coldkey: {:?}, destination_coldkey: {:?}, hotkey: {:?}, origin_netuid: {:?}, destination_netuid: {:?}, amount: {:?})",
+            coldkey,
+            destination_coldkey,
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            origin_tao
+        );
+        Self::deposit_event(Event::StakeTransferred(
+            coldkey,
+            destination_coldkey,
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            origin_tao,
+        ));
+
+        // 10. Return success.
+        Ok(())
+    }
 }
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index f26a82432..59afc9b62 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -773,3 +773,256 @@ fn test_moving_too_little_fails() {
         );
     });
 }
+
+#[test]
+fn test_do_transfer_success() {
+    new_test_ext(1).execute_with(|| {
+        // 1. Create a new dynamic network and IDs.
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        // 2. Define the origin coldkey, destination coldkey, and hotkey to be used.
+        let origin_coldkey = U256::from(1);
+        let destination_coldkey = U256::from(2);
+        let hotkey = U256::from(3);
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
+
+        // 3. Set up initial stake: (origin_coldkey, hotkey) on netuid.
+        SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
+        SubtensorModule::create_account_if_non_existent(&destination_coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+        let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey,
+            &origin_coldkey,
+            netuid,
+        );
+
+        // 4. Transfer the entire stake to the destination coldkey on the same subnet (netuid, netuid).
+        assert_ok!(SubtensorModule::do_transfer_stake(
+            RuntimeOrigin::signed(origin_coldkey),
+            destination_coldkey,
+            hotkey,
+            netuid,
+            netuid,
+            alpha
+        ));
+
+        // 5. Check that the stake has moved.
+        assert_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &origin_coldkey,
+                netuid
+            ),
+            0
+        );
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &destination_coldkey,
+                netuid
+            ),
+            stake_amount,
+            epsilon = stake_amount / 1000
+        );
+    });
+}
+
+#[test]
+fn test_do_transfer_nonexistent_subnet() {
+    new_test_ext(1).execute_with(|| {
+        let origin_coldkey = U256::from(1);
+        let destination_coldkey = U256::from(2);
+        let hotkey = U256::from(3);
+        let nonexistent_netuid = 9999;
+        let stake_amount = DefaultMinStake::<Test>::get() * 5;
+
+        assert_noop!(
+            SubtensorModule::do_transfer_stake(
+                RuntimeOrigin::signed(origin_coldkey),
+                destination_coldkey,
+                hotkey,
+                nonexistent_netuid,
+                nonexistent_netuid,
+                stake_amount
+            ),
+            Error::<Test>::SubnetNotExists
+        );
+    });
+}
+
+#[test]
+fn test_do_transfer_nonexistent_hotkey() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let origin_coldkey = U256::from(1);
+        let destination_coldkey = U256::from(2);
+        let nonexistent_hotkey = U256::from(999);
+
+        assert_noop!(
+            SubtensorModule::do_transfer_stake(
+                RuntimeOrigin::signed(origin_coldkey),
+                destination_coldkey,
+                nonexistent_hotkey,
+                netuid,
+                netuid,
+                100
+            ),
+            Error::<Test>::HotKeyAccountNotExists
+        );
+    });
+}
+
+#[test]
+fn test_do_transfer_insufficient_stake() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let origin_coldkey = U256::from(1);
+        let destination_coldkey = U256::from(2);
+        let hotkey = U256::from(3);
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
+
+        SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+
+        let alpha = stake_amount * 2;
+        assert_noop!(
+            SubtensorModule::do_transfer_stake(
+                RuntimeOrigin::signed(origin_coldkey),
+                destination_coldkey,
+                hotkey,
+                netuid,
+                netuid,
+                alpha
+            ),
+            Error::<Test>::NotEnoughStakeToWithdraw
+        );
+    });
+}
+
+#[test]
+fn test_do_transfer_wrong_origin() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1010);
+        let subnet_owner_hotkey = U256::from(1011);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let origin_coldkey = U256::from(1);
+        let wrong_coldkey = U256::from(9999);
+        let destination_coldkey = U256::from(2);
+        let hotkey = U256::from(3);
+        let stake_amount = 100_000;
+
+        SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
+        SubtensorModule::add_balance_to_coldkey_account(&origin_coldkey, 1_000_000_000);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+
+        assert_noop!(
+            SubtensorModule::do_transfer_stake(
+                RuntimeOrigin::signed(wrong_coldkey),
+                destination_coldkey,
+                hotkey,
+                netuid,
+                netuid,
+                stake_amount
+            ),
+            Error::<Test>::NonAssociatedColdKey
+        );
+    });
+}
+
+#[test]
+fn test_do_transfer_minimum_stake_check() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let origin_coldkey = U256::from(1);
+        let destination_coldkey = U256::from(2);
+        let hotkey = U256::from(3);
+
+        let stake_amount = DefaultMinStake::<Test>::get();
+        SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+
+        assert_err!(
+            SubtensorModule::do_transfer_stake(
+                RuntimeOrigin::signed(origin_coldkey),
+                destination_coldkey,
+                hotkey,
+                netuid,
+                netuid,
+                1
+            ),
+            Error::<Test>::AmountTooLow
+        );
+    });
+}
+
+#[test]
+fn test_do_transfer_different_subnets() {
+    new_test_ext(1).execute_with(|| {
+        // 1. Create two distinct subnets.
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        // 2. Define origin/destination coldkeys and hotkey.
+        let origin_coldkey = U256::from(1);
+        let destination_coldkey = U256::from(2);
+        let hotkey = U256::from(3);
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
+
+        // 3. Create accounts if needed.
+        SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
+        SubtensorModule::create_account_if_non_existent(&destination_coldkey, &hotkey);
+
+        // 4. Deposit free balance so transaction fees do not reduce staked funds.
+        SubtensorModule::add_balance_to_coldkey_account(&origin_coldkey, 1_000_000_000);
+
+        // 5. Stake into the origin subnet.
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, origin_netuid, stake_amount);
+
+        // 6. Transfer entire stake from origin_netuid -> destination_netuid.
+        let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey,
+            &origin_coldkey,
+            origin_netuid,
+        );
+        assert_ok!(SubtensorModule::do_transfer_stake(
+            RuntimeOrigin::signed(origin_coldkey),
+            destination_coldkey,
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            alpha
+        ));
+
+        // 7. Verify origin now has 0 in origin_netuid.
+        assert_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &origin_coldkey,
+                origin_netuid
+            ),
+            0
+        );
+
+        // 8. Verify stake ended up in destination subnet for destination coldkey.
+        let dest_stake = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey,
+            &destination_coldkey,
+            destination_netuid,
+        );
+        assert_abs_diff_eq!(dest_stake, stake_amount, epsilon = stake_amount / 1000);
+    });
+}

From a516c2b6de51cfb1fbb59bceef2da27b93ccd65b Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 21 Jan 2025 19:22:51 -0500
Subject: [PATCH 032/145] Implement fees for add_stake, remove_stake, and
 move_stake

---
 pallets/subtensor/src/lib.rs                  |  42 +++-
 pallets/subtensor/src/staking/add_stake.rs    |   3 +-
 pallets/subtensor/src/staking/helpers.rs      |   3 +-
 pallets/subtensor/src/staking/move_stake.rs   |   5 +-
 pallets/subtensor/src/staking/remove_stake.rs |  17 +-
 pallets/subtensor/src/staking/stake_utils.rs  |  14 +-
 pallets/subtensor/src/tests/mock.rs           |   3 +-
 pallets/subtensor/src/tests/move_stake.rs     |  90 +++++---
 pallets/subtensor/src/tests/senate.rs         |  30 +--
 pallets/subtensor/src/tests/staking.rs        | 197 +++++++++++++-----
 pallets/subtensor/src/tests/swap_coldkey.rs   |  51 +++--
 pallets/subtensor/src/tests/swap_hotkey.rs    |   5 +-
 pallets/subtensor/src/tests/weights.rs        |  12 +-
 13 files changed, 326 insertions(+), 146 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 7f75568ba..58aef11a8 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -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};
@@ -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},
@@ -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]
@@ -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,
         }
     }
 }
@@ -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()
diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index f63735cd3..66b337b3d 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -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(())
diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs
index 4f99d954e..1a1a2d00d 100644
--- a/pallets/subtensor/src/staking/helpers.rs
+++ b/pallets/subtensor/src/staking/helpers.rs
@@ -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);
             }
diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 9628c5814..6fbd0db07 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -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
@@ -87,6 +89,7 @@ impl<T: Config> Pallet<T> {
             &coldkey.clone(),
             destination_netuid,
             origin_tao,
+            fee,
         );
 
         // --- 9. Log the event.
@@ -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.
diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index 5578219d3..5b3ed3390 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -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.
@@ -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);
@@ -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(())
     }
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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.
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index b79b141d0..d6901eec2 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -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};
 
@@ -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);
@@ -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(
@@ -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);
 
@@ -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(
diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs
index a6f9caed7..9731113e5 100644
--- a/pallets/subtensor/src/tests/mock.rs
+++ b/pallets/subtensor/src/tests/mock.rs
@@ -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.
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index f26a82432..f46327305 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -17,11 +17,12 @@ fn test_do_move_success() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey);
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -53,7 +54,7 @@ fn test_do_move_success() {
                 &coldkey,
                 netuid
             ),
-            stake_amount,
+            stake_amount - 2 * fee,
             epsilon = stake_amount / 1000
         );
     });
@@ -73,11 +74,18 @@ fn test_do_move_different_subnets() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake and subnets
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey);
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(
+            &origin_hotkey,
+            &coldkey,
+            origin_netuid,
+            stake_amount,
+            fee,
+        );
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -109,7 +117,7 @@ fn test_do_move_different_subnets() {
                 &coldkey,
                 destination_netuid
             ),
-            stake_amount,
+            stake_amount - 2 * fee,
             epsilon = stake_amount / 1000
         );
     });
@@ -129,9 +137,16 @@ fn test_do_move_nonexistent_subnet() {
         let destination_hotkey = U256::from(3);
         let nonexistent_netuid = 99; // Assuming this subnet doesn't exist
         let stake_amount = 1_000_000;
+        let fee = 0;
 
         // Set up initial stake
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(
+            &origin_hotkey,
+            &coldkey,
+            origin_netuid,
+            stake_amount,
+            fee,
+        );
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -221,9 +236,10 @@ fn test_do_move_nonexistent_destination_hotkey() {
         let nonexistent_destination_hotkey = U256::from(99); // Assuming this hotkey doesn't exist
         let netuid = 1;
         let stake_amount = 1_000_000;
+        let fee = 0;
 
         // Set up initial stake
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
 
         // Attempt to move stake from a non-existent origin hotkey
         add_network(netuid, 0, 0);
@@ -272,9 +288,10 @@ fn test_do_move_all_stake() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -308,7 +325,7 @@ fn test_do_move_all_stake() {
                 &coldkey,
                 netuid
             ),
-            stake_amount,
+            stake_amount - 2 * fee,
             epsilon = stake_amount / 1000
         );
     });
@@ -324,9 +341,10 @@ fn test_do_move_half_stake() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -352,8 +370,8 @@ fn test_do_move_half_stake() {
                 &coldkey,
                 netuid
             ),
-            stake_amount / 2,
-            epsilon = stake_amount / 1000
+            alpha / 2,
+            epsilon = alpha / 1000
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -361,8 +379,8 @@ fn test_do_move_half_stake() {
                 &coldkey,
                 netuid
             ),
-            stake_amount / 2,
-            epsilon = stake_amount / 1000
+            alpha / 2 - fee,
+            epsilon = alpha / 1000
         );
     });
 }
@@ -380,9 +398,10 @@ fn test_do_move_partial_stake() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let total_stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, total_stake);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, total_stake, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -416,7 +435,7 @@ fn test_do_move_partial_stake() {
                 &coldkey,
                 netuid
             ),
-            total_stake,
+            total_stake - 2 * fee,
             epsilon = total_stake / 1000
         );
     });
@@ -435,11 +454,12 @@ fn test_do_move_multiple_times() {
         let hotkey1 = U256::from(2);
         let hotkey2 = U256::from(3);
         let initial_stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey1);
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey2);
-        SubtensorModule::stake_into_subnet(&hotkey1, &coldkey, netuid, initial_stake);
+        SubtensorModule::stake_into_subnet(&hotkey1, &coldkey, netuid, initial_stake, fee);
 
         // Move stake multiple times
         for _ in 0..3 {
@@ -470,7 +490,7 @@ fn test_do_move_multiple_times() {
         // Check final stake distribution
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid),
-            initial_stake,
+            initial_stake - 7 * fee,
             epsilon = initial_stake / 1000
         );
         assert_eq!(
@@ -492,9 +512,10 @@ fn test_do_move_wrong_origin() {
         let destination_hotkey = U256::from(3);
         let netuid = 1;
         let stake_amount = 1000;
+        let fee = 0;
 
         // Set up initial stake
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -549,10 +570,11 @@ fn test_do_move_same_hotkey() {
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount, fee);
         let alpha =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
 
@@ -569,8 +591,8 @@ fn test_do_move_same_hotkey() {
         // Check that stake remains unchanged
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid),
-            alpha,
-            epsilon = 5
+            alpha - fee,
+            epsilon = alpha / 1000
         );
     });
 }
@@ -588,11 +610,12 @@ fn test_do_move_event_emission() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey);
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, 0); // use 0 fee for precision
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -618,7 +641,7 @@ fn test_do_move_event_emission() {
                 netuid,
                 destination_hotkey,
                 netuid,
-                19999999, // Should be TAO equivalent
+                stake_amount - fee - 1, // Should be TAO equivalent
             )
             .into(),
         );
@@ -639,9 +662,16 @@ fn test_do_move_storage_updates() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Set up initial stake
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(
+            &origin_hotkey,
+            &coldkey,
+            origin_netuid,
+            stake_amount,
+            fee,
+        );
 
         // Move stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
@@ -676,8 +706,8 @@ fn test_do_move_storage_updates() {
                 &coldkey,
                 destination_netuid
             ),
-            alpha,
-            epsilon = 5
+            alpha - fee,
+            epsilon = alpha / 1000
         );
     });
 }
@@ -695,11 +725,12 @@ fn test_do_move_max_values() {
         let destination_hotkey = U256::from(3);
         let max_stake = u64::MAX;
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let fee = 0;
 
         // Set up initial stake with maximum value
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey);
-        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, max_stake);
+        SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, max_stake, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
             &coldkey,
@@ -744,19 +775,20 @@ fn test_moving_too_little_fails() {
         let hotkey_account_id = U256::from(533453);
         let coldkey_account_id = U256::from(55453);
         let amount = DefaultMinStake::<Test>::get();
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
         let netuid2: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
 
         // Give it some $$$ in his coldkey balance
-        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount + fee);
 
         assert_ok!(SubtensorModule::add_stake(
             RuntimeOrigin::signed(coldkey_account_id),
             hotkey_account_id,
             netuid,
-            amount
+            amount + fee
         ));
 
         // Coldkey / hotkey 0 decreases take to 5%. This should fail as the minimum take is 9%
diff --git a/pallets/subtensor/src/tests/senate.rs b/pallets/subtensor/src/tests/senate.rs
index 00a1b897f..01dfc17d7 100644
--- a/pallets/subtensor/src/tests/senate.rs
+++ b/pallets/subtensor/src/tests/senate.rs
@@ -67,6 +67,7 @@ fn test_senate_join_works() {
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
         let stake = DefaultMinStake::<Test>::get() * 100;
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -112,12 +113,12 @@ fn test_senate_join_works() {
                 &staker_coldkey,
                 netuid
             ),
-            stake,
+            stake - fee,
             epsilon = 10
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_account_id, netuid),
-            stake,
+            stake - fee,
             epsilon = 10
         );
 
@@ -140,6 +141,7 @@ fn test_senate_vote_works() {
         let hotkey_account_id = U256::from(6);
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -185,12 +187,12 @@ fn test_senate_vote_works() {
                 &staker_coldkey,
                 netuid
             ),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_account_id, netuid),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
 
@@ -313,6 +315,7 @@ fn test_senate_leave_works() {
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
         let stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -357,12 +360,12 @@ fn test_senate_leave_works() {
                 &staker_coldkey,
                 netuid
             ),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_account_id, netuid),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
 
@@ -387,6 +390,7 @@ fn test_senate_leave_vote_removal() {
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
         let coldkey_origin = <<Test as Config>::RuntimeOrigin>::signed(coldkey_account_id);
         let stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -431,12 +435,12 @@ fn test_senate_leave_vote_removal() {
                 &staker_coldkey,
                 netuid
             ),
-            stake,
+            stake - fee,
             epsilon = 10
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_account_id, netuid),
-            stake,
+            stake - fee,
             epsilon = 10
         );
 
@@ -528,6 +532,7 @@ fn test_senate_not_leave_when_stake_removed() {
         let hotkey_account_id = U256::from(6);
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -573,12 +578,12 @@ fn test_senate_not_leave_when_stake_removed() {
                 &staker_coldkey,
                 netuid
             ),
-            stake_amount,
+            stake_amount - fee,
             epsilon = stake_amount / 1000
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_account_id, netuid),
-            stake_amount,
+            stake_amount - fee,
             epsilon = stake_amount / 1000
         );
 
@@ -686,6 +691,7 @@ fn test_adjust_senate_events() {
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667);
         let root_netuid = SubtensorModule::get_root_netuid();
+        let fee = DefaultMinStake::<Test>::get();
 
         let max_senate_size: u16 = SenateMaxMembers::get() as u16;
         let stake_threshold: u64 = DefaultMinStake::<Test>::get(); // Give this much to every senator
@@ -806,7 +812,7 @@ fn test_adjust_senate_events() {
                 &coldkey_account_id,
                 root_netuid
             ),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
         assert_abs_diff_eq!(
@@ -814,7 +820,7 @@ fn test_adjust_senate_events() {
                 &replacement_hotkey_account_id,
                 root_netuid
             ),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
 
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 882184811..ef5ac5f4a 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -42,6 +42,7 @@ fn test_add_stake_ok_no_emission() {
         let hotkey_account_id = U256::from(533453);
         let coldkey_account_id = U256::from(55453);
         let amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
@@ -69,7 +70,7 @@ fn test_add_stake_ok_no_emission() {
         // Check if stake has increased
         assert_abs_diff_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
-            amount,
+            amount - fee,
             epsilon = amount / 1000,
         );
 
@@ -78,7 +79,6 @@ fn test_add_stake_ok_no_emission() {
 
         // Check if total stake has increased accordingly.
         assert_eq!(SubtensorModule::get_total_stake(), amount);
-        assert_abs_diff_eq!(SubtensorModule::get_total_stake(), amount, epsilon = 1,);
     });
 }
 
@@ -350,7 +350,8 @@ fn test_remove_stake_ok_no_emission() {
         let subnet_owner_hotkey = U256::from(2);
         let coldkey_account_id = U256::from(4343);
         let hotkey_account_id = U256::from(4968585);
-        let amount = 10000;
+        let amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);
 
@@ -379,12 +380,12 @@ fn test_remove_stake_ok_no_emission() {
         ));
 
         // we do not expect the exact amount due to slippage
-        assert!(SubtensorModule::get_coldkey_balance(&coldkey_account_id) > amount / 10 * 9,);
+        assert!(SubtensorModule::get_coldkey_balance(&coldkey_account_id) > amount / 10 * 9 - fee);
         assert_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
             0
         );
-        assert_eq!(SubtensorModule::get_total_stake(), 0);
+        assert_eq!(SubtensorModule::get_total_stake(), fee);
     });
 }
 
@@ -498,6 +499,7 @@ fn test_remove_stake_no_enough_stake() {
 #[test]
 fn test_remove_stake_total_balance_no_change() {
     // When we remove stake, the total balance of the coldkey account should not change
+    //    (except for staking fees)
     //    this is because the stake should be part of the coldkey account balance (reserved/locked)
     //    then the removed stake just becomes free balance
     new_test_ext(1).execute_with(|| {
@@ -505,7 +507,8 @@ fn test_remove_stake_total_balance_no_change() {
         let subnet_owner_hotkey = U256::from(2);
         let hotkey_account_id = U256::from(571337);
         let coldkey_account_id = U256::from(71337);
-        let amount = 10_000;
+        let amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);
 
@@ -537,18 +540,18 @@ fn test_remove_stake_total_balance_no_change() {
 
         assert_abs_diff_eq!(
             SubtensorModule::get_coldkey_balance(&coldkey_account_id),
-            amount,
-            epsilon = 1,
+            amount - fee,
+            epsilon = amount / 1000,
         );
         assert_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
             0
         );
-        assert_eq!(SubtensorModule::get_total_stake(), 0);
+        assert_eq!(SubtensorModule::get_total_stake(), fee);
 
         // Check total balance is equal to the added stake. Even after remove stake (no fee, includes reserved/locked balance)
         let total_balance = Balances::total_balance(&coldkey_account_id);
-        assert_abs_diff_eq!(total_balance, amount, epsilon = 1,);
+        assert_abs_diff_eq!(total_balance, amount - fee, epsilon = amount / 1000);
     });
 }
 
@@ -564,6 +567,7 @@ fn test_remove_stake_total_issuance_no_change() {
         let coldkey_account_id = U256::from(81337);
         let amount = DefaultMinStake::<Test>::get() * 10;
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let fee = DefaultMinStake::<Test>::get();
         register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);
 
         // Give it some $$$ in his coldkey balance
@@ -610,14 +614,18 @@ fn test_remove_stake_total_issuance_no_change() {
 
         assert_abs_diff_eq!(
             SubtensorModule::get_coldkey_balance(&coldkey_account_id),
-            amount,
-            epsilon = 1,
+            amount - fee * 2,
+            epsilon = amount / 1000,
         );
         assert_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
             0
         );
-        assert_abs_diff_eq!(SubtensorModule::get_total_stake(), 0, epsilon = 1,);
+        assert_abs_diff_eq!(
+            SubtensorModule::get_total_stake(),
+            fee * 2,
+            epsilon = fee / 1000
+        );
 
         // Check if total issuance is equal to the added stake, even after remove stake (no fee, includes reserved/locked balance)
         assert_abs_diff_eq!(
@@ -625,10 +633,13 @@ fn test_remove_stake_total_issuance_no_change() {
             total_issuance_after_stake + amount,
             epsilon = 1,
         );
+
+        // After staking + unstaking the 2 * fee amount stays in SubnetTAO and TotalStake,
+        // so the total issuance should be lower by that amount
         assert_abs_diff_eq!(
             inital_total_issuance,
-            total_issuance_after_unstake,
-            epsilon = 1,
+            total_issuance_after_unstake + 2 * fee,
+            epsilon = inital_total_issuance / 10000,
         );
     });
 }
@@ -1108,6 +1119,8 @@ fn test_clear_small_nominations() {
         let cold2 = U256::from(4);
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let amount = DefaultMinStake::<Test>::get() * 10;
+        let fee: u64 = DefaultMinStake::<Test>::get();
+        let init_balance = amount + fee + ExistentialDeposit::get();
 
         // Register hot1.
         register_ok_neuron(netuid, hot1, cold1, 0);
@@ -1120,80 +1133,84 @@ fn test_clear_small_nominations() {
         assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot2), cold2);
 
         // Add stake cold1 --> hot1 (non delegation.)
-        SubtensorModule::add_balance_to_coldkey_account(&cold1, amount);
+        SubtensorModule::add_balance_to_coldkey_account(&cold1, init_balance);
         assert_ok!(SubtensorModule::add_stake(
             RuntimeOrigin::signed(cold1),
             hot1,
             netuid,
-            amount
+            amount + fee
         ));
         assert_ok!(SubtensorModule::remove_stake(
             RuntimeOrigin::signed(cold1),
             hot1,
             netuid,
-            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold1, netuid) - 1
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold1, netuid)
+                - 100
         ));
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold1, netuid),
-            1
+            100
         );
 
         // Add stake cold2 --> hot1 (is delegation.)
-        SubtensorModule::add_balance_to_coldkey_account(&cold2, amount);
+        SubtensorModule::add_balance_to_coldkey_account(&cold2, init_balance);
         assert_ok!(SubtensorModule::add_stake(
             RuntimeOrigin::signed(cold2),
             hot1,
             netuid,
-            amount
+            amount + fee
         ));
         assert_ok!(SubtensorModule::remove_stake(
             RuntimeOrigin::signed(cold2),
             hot1,
             netuid,
-            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold2, netuid) - 1
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold2, netuid)
+                - 100
         ));
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold2, netuid),
-            1
+            100
         );
 
         // Add stake cold1 --> hot2 (non delegation.)
-        SubtensorModule::add_balance_to_coldkey_account(&cold1, amount);
+        SubtensorModule::add_balance_to_coldkey_account(&cold1, init_balance);
         assert_ok!(SubtensorModule::add_stake(
             RuntimeOrigin::signed(cold1),
             hot2,
             netuid,
-            amount
+            amount + fee
         ));
         assert_ok!(SubtensorModule::remove_stake(
             RuntimeOrigin::signed(cold1),
             hot2,
             netuid,
-            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold1, netuid) - 1
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold1, netuid)
+                - 100
         ));
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold1, netuid),
-            1
+            100
         );
         let balance1_before_cleaning = Balances::free_balance(cold1);
 
         // Add stake cold2 --> hot2 (is delegation.)
-        SubtensorModule::add_balance_to_coldkey_account(&cold2, amount);
+        SubtensorModule::add_balance_to_coldkey_account(&cold2, init_balance);
         assert_ok!(SubtensorModule::add_stake(
             RuntimeOrigin::signed(cold2),
             hot2,
             netuid,
-            amount
+            amount + fee
         ));
         assert_ok!(SubtensorModule::remove_stake(
             RuntimeOrigin::signed(cold2),
             hot2,
             netuid,
-            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold2, netuid) - 1
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold2, netuid)
+                - 100
         ));
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold2, netuid),
-            1
+            100
         );
         let balance2_before_cleaning = Balances::free_balance(cold2);
 
@@ -1203,19 +1220,19 @@ fn test_clear_small_nominations() {
         SubtensorModule::clear_small_nominations();
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold1, netuid),
-            1
+            100
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold1, netuid),
-            1
+            100
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold2, netuid),
-            1
+            100
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold2, netuid),
-            1
+            100
         );
 
         // Set min nomination to 10
@@ -1224,13 +1241,13 @@ fn test_clear_small_nominations() {
         let total_hot1_stake_before = TotalHotkeyAlpha::<Test>::get(hot1, netuid);
         let total_hot2_stake_before = TotalHotkeyAlpha::<Test>::get(hot2, netuid);
         let total_stake_before = TotalStake::<Test>::get();
-        SubtensorModule::set_nominator_min_required_stake(10);
+        SubtensorModule::set_nominator_min_required_stake(1000);
 
         // Run clear all small nominations (removes delegations under 10)
         SubtensorModule::clear_small_nominations();
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot1, &cold1, netuid),
-            1
+            100
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold1, netuid),
@@ -1242,24 +1259,26 @@ fn test_clear_small_nominations() {
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hot2, &cold2, netuid),
-            1
+            100
         );
 
         // Balances have been added back into accounts.
         let balance1_after_cleaning = Balances::free_balance(cold1);
         let balance2_after_cleaning = Balances::free_balance(cold2);
-        assert_eq!(balance1_before_cleaning + 1, balance1_after_cleaning);
-        assert_eq!(balance2_before_cleaning + 1, balance2_after_cleaning);
+        assert_eq!(balance1_before_cleaning + 100, balance1_after_cleaning);
+        assert_eq!(balance2_before_cleaning + 100, balance2_after_cleaning);
 
-        assert_eq!(
+        assert_abs_diff_eq!(
             TotalHotkeyAlpha::<Test>::get(hot2, netuid),
-            total_hot2_stake_before - 1
+            total_hot2_stake_before - 100,
+            epsilon = 1
         );
-        assert_eq!(
+        assert_abs_diff_eq!(
             TotalHotkeyAlpha::<Test>::get(hot1, netuid),
-            total_hot1_stake_before - 1
+            total_hot1_stake_before - 100,
+            epsilon = 1
         );
-        assert_eq!(TotalStake::<Test>::get(), total_stake_before - 2);
+        assert_eq!(TotalStake::<Test>::get(), total_stake_before - 200);
     });
 }
 
@@ -1590,6 +1609,7 @@ fn test_get_total_delegated_stake_after_unstaking() {
         let unstake_amount = DefaultMinStake::<Test>::get() * 5;
         let existential_deposit = ExistentialDeposit::get();
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let fee = DefaultMinStake::<Test>::get();
 
         register_ok_neuron(netuid, delegate_hotkey, delegate_coldkey, 0);
 
@@ -1607,12 +1627,12 @@ fn test_get_total_delegated_stake_after_unstaking() {
         // Check initial delegated stake
         assert_abs_diff_eq!(
             SubtensorModule::get_total_stake_for_coldkey(&delegator),
-            initial_stake - existential_deposit,
+            initial_stake - existential_deposit - fee,
             epsilon = initial_stake / 1000,
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&delegate_hotkey),
-            initial_stake - existential_deposit,
+            initial_stake - existential_deposit - fee,
             epsilon = initial_stake / 1000,
         );
 
@@ -1625,7 +1645,7 @@ fn test_get_total_delegated_stake_after_unstaking() {
         ));
 
         // Calculate the expected delegated stake
-        let expected_delegated_stake = initial_stake - unstake_amount - existential_deposit;
+        let expected_delegated_stake = initial_stake - unstake_amount - existential_deposit - fee;
 
         // Debug prints
         log::debug!("Initial stake: {}", initial_stake);
@@ -1677,6 +1697,7 @@ fn test_get_total_delegated_stake_single_delegator() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10 - 1;
         let existential_deposit = ExistentialDeposit::get();
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let fee = DefaultMinStake::<Test>::get();
 
         register_ok_neuron(netuid, delegate_hotkey, delegate_coldkey, 0);
 
@@ -1705,7 +1726,7 @@ fn test_get_total_delegated_stake_single_delegator() {
         );
 
         // Calculate expected delegated stake
-        let expected_delegated_stake = stake_amount - existential_deposit;
+        let expected_delegated_stake = stake_amount - existential_deposit - fee;
         let actual_delegated_stake = SubtensorModule::get_total_stake_for_hotkey(&delegate_hotkey);
         let actual_delegator_stake = SubtensorModule::get_total_stake_for_coldkey(&delegator);
 
@@ -1734,6 +1755,7 @@ fn test_get_alpha_share_stake_multiple_delegators() {
         let existential_deposit = 2;
         let stake1 = DefaultMinStake::<Test>::get() * 10;
         let stake2 = DefaultMinStake::<Test>::get() * 10 - 1;
+        let fee = DefaultMinStake::<Test>::get();
 
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         register_ok_neuron(netuid, hotkey1, coldkey1, 0);
@@ -1770,7 +1792,7 @@ fn test_get_alpha_share_stake_multiple_delegators() {
         );
 
         // Calculate expected total delegated stake
-        let expected_total_stake = stake1 + stake2 - existential_deposit * 2;
+        let expected_total_stake = stake1 + stake2 - existential_deposit * 2 - fee * 2;
         let actual_total_stake = SubtensorModule::get_alpha_share_pool(hotkey1, netuid)
             .get_value(&coldkey1)
             + SubtensorModule::get_alpha_share_pool(hotkey2, netuid).get_value(&coldkey2);
@@ -1792,6 +1814,7 @@ fn test_get_total_delegated_stake_exclude_owner_stake() {
         let delegator = U256::from(3);
         let owner_stake = DefaultMinStake::<Test>::get() * 10;
         let delegator_stake = DefaultMinStake::<Test>::get() * 10 - 1;
+        let fee = DefaultMinStake::<Test>::get();
 
         let netuid = add_dynamic_network(&delegate_hotkey, &delegate_coldkey);
 
@@ -1825,7 +1848,7 @@ fn test_get_total_delegated_stake_exclude_owner_stake() {
         );
 
         // Check the total delegated stake (should exclude owner's stake)
-        let expected_delegated_stake = delegator_stake;
+        let expected_delegated_stake = delegator_stake - fee;
         let actual_delegated_stake =
             SubtensorModule::get_total_stake_for_coldkey(&delegate_coldkey);
 
@@ -1969,7 +1992,8 @@ fn test_add_stake_fee_goes_to_subnet_tao() {
 
         // Calculate expected stake
         let expected_alpha = tao_to_stake - existential_deposit - fee;
-        let actual_alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        let actual_alpha =
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
         let subnet_tao_after = SubnetTAO::<Test>::get(netuid);
 
         // Total subnet stake should match the sum of delegators' stakes minus existential deposits.
@@ -2013,7 +2037,8 @@ fn test_remove_stake_fee_goes_to_subnet_tao() {
         ));
 
         // Remove all stake
-        let alpha_to_unstake = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        let alpha_to_unstake =
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
         assert_ok!(SubtensorModule::remove_stake(
             RuntimeOrigin::signed(coldkey),
             hotkey,
@@ -2037,4 +2062,68 @@ fn test_remove_stake_fee_goes_to_subnet_tao() {
             epsilon = tao_to_stake / 1000
         );
     });
-}
\ No newline at end of file
+}
+
+#[test]
+fn test_stake_below_min_validate() {
+    // Testing the signed extension validate function
+    // correctly filters the `add_stake` transaction.
+
+    new_test_ext(0).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let hotkey = U256::from(2);
+        let coldkey = U256::from(3);
+        let amount_staked = DefaultMinStake::<Test>::get() - 1;
+
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
+
+        // Add stake call
+        let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
+            hotkey,
+            netuid,
+            amount_staked,
+        });
+
+        let info: crate::DispatchInfo =
+            crate::DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
+
+        let extension = crate::SubtensorSignedExtension::<Test>::new();
+        // Submit to the signed extension validate function
+        let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
+
+        // Should fail due to insufficient stake
+        assert_err!(
+            result_no_stake,
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(1))
+        );
+
+        // Increase the stake to be equal to the minimum, but leave the balance low
+        let amount_staked = DefaultMinStake::<Test>::get();
+        let call_2 = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
+            hotkey,
+            netuid,
+            amount_staked,
+        });
+
+        // Submit to the signed extension validate function
+        let result_low_balance = extension.validate(&coldkey, &call_2.clone(), &info, 10);
+
+        // Still doesn't pass
+        assert_err!(
+            result_low_balance,
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(1))
+        );
+
+        // Increase the coldkey balance to match the minimum
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1);
+
+        // Submit to the signed extension validate function
+        let result_min_stake = extension.validate(&coldkey, &call_2.clone(), &info, 10);
+
+        // Now the call passes
+        assert_ok!(result_min_stake);
+    });
+}
diff --git a/pallets/subtensor/src/tests/swap_coldkey.rs b/pallets/subtensor/src/tests/swap_coldkey.rs
index 0cbcecfaf..ae2a1649c 100644
--- a/pallets/subtensor/src/tests/swap_coldkey.rs
+++ b/pallets/subtensor/src/tests/swap_coldkey.rs
@@ -366,6 +366,7 @@ fn test_swap_with_max_values() {
         let netuid2 = 2u16;
         let stake = 10_000;
         let max_stake = 21_000_000_000_000_000; // 21 Million TAO; max possible balance.
+        let fee = DefaultMinStake::<Test>::get();
 
         // Add a network
         add_network(netuid, 1, 0);
@@ -412,7 +413,7 @@ fn test_swap_with_max_values() {
         );
         assert_eq!(
             SubtensorModule::get_total_stake_for_coldkey(&new_coldkey),
-            max_stake
+            max_stake - fee
         );
         assert_eq!(
             SubtensorModule::get_total_stake_for_coldkey(&old_coldkey2),
@@ -420,7 +421,7 @@ fn test_swap_with_max_values() {
         );
         assert_eq!(
             SubtensorModule::get_total_stake_for_coldkey(&new_coldkey2),
-            max_stake
+            max_stake - fee
         );
     });
 }
@@ -434,6 +435,8 @@ fn test_swap_with_non_existent_new_coldkey() {
         let hotkey = U256::from(3);
         let stake = DefaultMinStake::<Test>::get() * 10;
         let netuid = 1u16;
+        let fee = DefaultMinStake::<Test>::get();
+
         add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey, old_coldkey, 1001000);
         // Give old coldkey some balance.
@@ -459,7 +462,7 @@ fn test_swap_with_non_existent_new_coldkey() {
         );
         assert_eq!(
             SubtensorModule::get_total_stake_for_coldkey(&new_coldkey),
-            stake
+            stake - fee
         );
     });
 }
@@ -525,6 +528,7 @@ fn test_swap_concurrent_modifications() {
         let netuid: u16 = 1;
         let initial_stake = 1_000_000_000_000;
         let additional_stake = 500_000_000_000;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Setup initial state
         add_network(netuid, 1, 1);
@@ -547,7 +551,7 @@ fn test_swap_concurrent_modifications() {
                 &new_coldkey,
                 netuid
             ),
-            initial_stake
+            initial_stake - fee
         );
 
         // Wait some blocks
@@ -576,15 +580,14 @@ fn test_swap_concurrent_modifications() {
         ));
 
         let eps = 500; // RAO
-        assert!(
-            (SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &hotkey,
                 &new_coldkey,
                 netuid
-            ) as i64
-                - (stake_before_swap + additional_stake) as i64)
-                .abs()
-                <= eps
+            ),
+            stake_before_swap + additional_stake - fee,
+            epsilon = eps
         );
         assert!(!Alpha::<Test>::contains_key((hotkey, old_coldkey, netuid)));
     });
@@ -801,6 +804,7 @@ fn test_swap_stake_for_coldkey() {
         let stake_amount3 = DefaultMinStake::<Test>::get() * 30;
         let total_stake = stake_amount1 + stake_amount2;
         let mut weight = Weight::zero();
+        let fee = DefaultMinStake::<Test>::get();
 
         // Setup initial state
         // Add a network
@@ -837,7 +841,7 @@ fn test_swap_stake_for_coldkey() {
                 &old_coldkey,
                 netuid
             ),
-            stake_amount1
+            stake_amount1 - fee
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -845,7 +849,7 @@ fn test_swap_stake_for_coldkey() {
                 &old_coldkey,
                 netuid
             ),
-            stake_amount2
+            stake_amount2 - fee
         );
 
         // Insert existing for same hotkey1
@@ -892,7 +896,7 @@ fn test_swap_stake_for_coldkey() {
                 &new_coldkey,
                 netuid
             ),
-            stake_amount1 + stake_amount3
+            stake_amount1 + stake_amount3 - fee * 2
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -900,7 +904,7 @@ fn test_swap_stake_for_coldkey() {
                 &new_coldkey,
                 netuid
             ),
-            stake_amount2
+            stake_amount2 - fee
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -956,6 +960,7 @@ fn test_swap_staking_hotkeys_for_coldkey() {
         let stake_amount2 = DefaultMinStake::<Test>::get() * 20;
         let total_stake = stake_amount1 + stake_amount2;
         let mut weight = Weight::zero();
+        let fee = DefaultMinStake::<Test>::get();
 
         // Setup initial state
         // Add a network
@@ -991,7 +996,7 @@ fn test_swap_staking_hotkeys_for_coldkey() {
                 &old_coldkey,
                 netuid
             ),
-            stake_amount1
+            stake_amount1 - fee
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -999,7 +1004,7 @@ fn test_swap_staking_hotkeys_for_coldkey() {
                 &old_coldkey,
                 netuid
             ),
-            stake_amount2
+            stake_amount2 - fee
         );
 
         // Perform the swap
@@ -1027,6 +1032,7 @@ fn test_swap_delegated_stake_for_coldkey() {
         let stake_amount2 = DefaultMinStake::<Test>::get() * 20;
         let mut weight = Weight::zero();
         let netuid = 1u16;
+        let fee = DefaultMinStake::<Test>::get();
 
         // Setup initial state
         add_network(netuid, 1, 0);
@@ -1081,7 +1087,7 @@ fn test_swap_delegated_stake_for_coldkey() {
                 &new_coldkey,
                 netuid
             ),
-            stake_amount1
+            stake_amount1 - fee
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -1089,7 +1095,7 @@ fn test_swap_delegated_stake_for_coldkey() {
                 &new_coldkey,
                 netuid
             ),
-            stake_amount2
+            stake_amount2 - fee
         );
         assert_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -1583,6 +1589,7 @@ fn test_coldkey_delegations() {
         let netuid = 0u16; // Stake to 0
         let netuid2 = 1u16; // Stake to 1
         let stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         add_network(netuid, 13, 0); // root
         add_network(netuid2, 13, 0);
@@ -1620,25 +1627,25 @@ fn test_coldkey_delegations() {
         // Verify stake was moved for the delegate
         assert_abs_diff_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&delegate),
-            stake * 2,
+            stake * 2 - fee * 2,
             epsilon = stake / 1000
         );
         assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&coldkey), 0);
         assert_abs_diff_eq!(
             SubtensorModule::get_total_stake_for_coldkey(&new_coldkey),
-            stake * 2,
+            stake * 2 - fee * 2,
             epsilon = stake / 1000
         );
         assert_abs_diff_eq!(
             Alpha::<Test>::get((delegate, new_coldkey, netuid)).to_num::<u64>(),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
         assert_eq!(Alpha::<Test>::get((delegate, coldkey, netuid)), 0);
 
         assert_abs_diff_eq!(
             Alpha::<Test>::get((delegate, new_coldkey, netuid2)).to_num::<u64>(),
-            stake,
+            stake - fee,
             epsilon = stake / 1000
         );
         assert_eq!(Alpha::<Test>::get((delegate, coldkey, netuid2)), 0);
diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs
index 0f11dfa98..d35dd6d56 100644
--- a/pallets/subtensor/src/tests/swap_hotkey.rs
+++ b/pallets/subtensor/src/tests/swap_hotkey.rs
@@ -66,6 +66,7 @@ fn test_swap_total_hotkey_stake() {
         let coldkey = U256::from(3);
         let amount = DefaultMinStake::<Test>::get() * 10;
         let mut weight = Weight::zero();
+        let fee = DefaultMinStake::<Test>::get();
 
         //add network
         let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey);
@@ -84,7 +85,7 @@ fn test_swap_total_hotkey_stake() {
         // Check if stake has increased
         assert_abs_diff_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&old_hotkey),
-            amount,
+            amount - fee,
             epsilon = amount / 1000,
         );
         assert_abs_diff_eq!(
@@ -109,7 +110,7 @@ fn test_swap_total_hotkey_stake() {
         );
         assert_abs_diff_eq!(
             SubtensorModule::get_total_stake_for_hotkey(&new_hotkey),
-            amount,
+            amount - fee,
             epsilon = amount / 1000,
         );
     });
diff --git a/pallets/subtensor/src/tests/weights.rs b/pallets/subtensor/src/tests/weights.rs
index b71093776..10c829870 100644
--- a/pallets/subtensor/src/tests/weights.rs
+++ b/pallets/subtensor/src/tests/weights.rs
@@ -69,6 +69,7 @@ fn test_set_rootweights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1); // Add the hotkey field
         assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!!
+        let fee = DefaultMinStake::<Test>::get();
 
         let who = coldkey; // The coldkey signs this transaction
 
@@ -112,7 +113,7 @@ fn test_set_rootweights_validate() {
             RuntimeOrigin::signed(hotkey),
             hotkey,
             netuid,
-            min_stake
+            min_stake + fee
         ));
 
         // Verify stake is equal to minimum
@@ -183,6 +184,7 @@ fn test_commit_weights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1); // Add the hotkey field
         assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!!
+        let fee = DefaultMinStake::<Test>::get();
 
         let who = hotkey; // The hotkey signs this transaction
 
@@ -226,7 +228,7 @@ fn test_commit_weights_validate() {
             RuntimeOrigin::signed(hotkey),
             hotkey,
             netuid,
-            min_stake
+            min_stake + fee
         ));
 
         // Verify stake is equal to minimum
@@ -292,6 +294,7 @@ fn test_set_weights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1);
         assert_ne!(hotkey, coldkey);
+        let fee = DefaultMinStake::<Test>::get();
 
         let who = hotkey; // The hotkey signs this transaction
 
@@ -333,7 +336,7 @@ fn test_set_weights_validate() {
             RuntimeOrigin::signed(hotkey),
             hotkey,
             netuid,
-            min_stake
+            min_stake + fee
         ));
 
         // Verify stake is equal to minimum
@@ -364,6 +367,7 @@ fn test_reveal_weights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1); // Add the hotkey field
         assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!!
+        let fee = DefaultMinStake::<Test>::get();
 
         let who = hotkey; // The hotkey signs this transaction
 
@@ -406,7 +410,7 @@ fn test_reveal_weights_validate() {
             RuntimeOrigin::signed(hotkey),
             hotkey,
             netuid,
-            min_stake
+            min_stake + fee
         ));
 
         // Verify stake is equal to minimum

From fe28b487b90eae405411969de33a5d659746306b Mon Sep 17 00:00:00 2001
From: cuteolaf <OliverLim818@gmail.com>
Date: Wed, 22 Jan 2025 06:36:14 -0800
Subject: [PATCH 033/145] fix wrong comments for some storage items

---
 pallets/subtensor/src/lib.rs | 48 ++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 7f75568ba..396b7fe71 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -886,34 +886,34 @@ pub mod pallet {
     pub type TotalStake<T> = StorageValue<_, u64, ValueQuery>;
     #[pallet::storage] // --- ITEM ( dynamic_block ) -- block when dynamic was turned on.
     pub type DynamicBlock<T> = StorageValue<_, u64, ValueQuery>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> total_volume | The total amount of TAO bought and sold since the start of the network.
+    #[pallet::storage] // --- MAP ( netuid ) --> total_volume | The total amount of TAO bought and sold since the start of the network.
     pub type SubnetVolume<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> tao_in_subnet | Returns the amount of TAO in the subnet.
+    #[pallet::storage] // --- MAP ( netuid ) --> tao_in_subnet | Returns the amount of TAO in the subnet.
     pub type SubnetTAO<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> alpha_in_emission | Returns the amount of alph in  emission into the pool per block.
+    #[pallet::storage] // --- MAP ( netuid ) --> alpha_in_emission | Returns the amount of alph in  emission into the pool per block.
     pub type SubnetAlphaInEmission<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> alpha_out_emission | Returns the amount of alpha out emission into the network per block.
+    #[pallet::storage] // --- MAP ( netuid ) --> alpha_out_emission | Returns the amount of alpha out emission into the network per block.
     pub type SubnetAlphaOutEmission<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> tao_in_emission | Returns the amount of tao emitted into this subent on the last block.
+    #[pallet::storage] // --- MAP ( netuid ) --> tao_in_emission | Returns the amount of tao emitted into this subent on the last block.
     pub type SubnetTaoInEmission<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> alpha_sell_per_block | Alpha sold per block.
+    #[pallet::storage] // --- MAP ( netuid ) --> alpha_sell_per_block | Alpha sold per block.
     pub type SubnetAlphaEmissionSell<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> total_stake_at_moment_of_subnet_registration
+    #[pallet::storage] // --- MAP ( netuid ) --> total_stake_at_moment_of_subnet_registration
     pub type TotalStakeAtDynamic<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> alpha_supply_in_pool | Returns the amount of alpha in the subnet.
+    #[pallet::storage] // --- MAP ( netuid ) --> alpha_supply_in_pool | Returns the amount of alpha in the pool.
     pub type SubnetAlphaIn<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> alpha_supply_in_subnet | Returns the amount of alpha in the subnet.
+    #[pallet::storage] // --- MAP ( netuid ) --> alpha_supply_in_subnet | Returns the amount of alpha in the subnet.
     pub type SubnetAlphaOut<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
-    #[pallet::storage] // --- DMAP ( cold ) --> Vec<hot> | Maps coldkey to hotkeys that stake to it
+    #[pallet::storage] // --- MAP ( cold ) --> Vec<hot> | Maps coldkey to hotkeys that stake to it
     pub type StakingHotkeys<T: Config> =
         StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;
     #[pallet::storage] // --- MAP ( cold ) --> Vec<hot> | Returns the vector of hotkeys controlled by this coldkey.
@@ -970,10 +970,10 @@ pub mod pallet {
         U64F64, // Shares
         ValueQuery,
     >;
-    #[pallet::storage] // --- DMAP ( netuid ) --> token_symbol | Returns the token symbol for a subnet.
+    #[pallet::storage] // --- MAP ( netuid ) --> token_symbol | Returns the token symbol for a subnet.
     pub type TokenSymbol<T: Config> =
         StorageMap<_, Identity, u16, Vec<u8>, ValueQuery, DefaultUnicodeVecU8<T>>;
-    #[pallet::storage] // --- DMAP ( netuid ) --> subnet_name | Returns the name of the subnet.
+    #[pallet::storage] // --- MAP ( netuid ) --> subnet_name | Returns the name of the subnet.
     pub type SubnetName<T: Config> =
         StorageMap<_, Identity, u16, Vec<u8>, ValueQuery, DefaultUnicodeVecU8<T>>;
 
@@ -1267,49 +1267,49 @@ pub mod pallet {
     pub type Keys<T: Config> =
         StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> (hotkey, se, ve)
+    /// --- MAP ( netuid ) --> (hotkey, se, ve)
     pub type LoadedEmission<T: Config> =
         StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> active
+    /// --- MAP ( netuid ) --> active
     pub type Active<T: Config> =
         StorageMap<_, Identity, u16, Vec<bool>, ValueQuery, EmptyBoolVec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> rank
+    /// --- MAP ( netuid ) --> rank
     pub type Rank<T: Config> = StorageMap<_, Identity, u16, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> trust
+    /// --- MAP ( netuid ) --> trust
     pub type Trust<T: Config> = StorageMap<_, Identity, u16, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> consensus
+    /// --- MAP ( netuid ) --> consensus
     pub type Consensus<T: Config> =
         StorageMap<_, Identity, u16, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> incentive
+    /// --- MAP ( netuid ) --> incentive
     pub type Incentive<T: Config> =
         StorageMap<_, Identity, u16, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> dividends
+    /// --- MAP ( netuid ) --> dividends
     pub type Dividends<T: Config> =
         StorageMap<_, Identity, u16, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> emission
+    /// --- MAP ( netuid ) --> emission
     pub type Emission<T: Config> =
         StorageMap<_, Identity, u16, Vec<u64>, ValueQuery, EmptyU64Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> last_update
+    /// --- MAP ( netuid ) --> last_update
     pub type LastUpdate<T: Config> =
         StorageMap<_, Identity, u16, Vec<u64>, ValueQuery, EmptyU64Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> validator_trust
+    /// --- MAP ( netuid ) --> validator_trust
     pub type ValidatorTrust<T: Config> =
         StorageMap<_, Identity, u16, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> pruning_scores
+    /// --- MAP ( netuid ) --> pruning_scores
     pub type PruningScores<T: Config> =
         StorageMap<_, Identity, u16, Vec<u16>, ValueQuery, EmptyU16Vec<T>>;
     #[pallet::storage]
-    /// --- DMAP ( netuid ) --> validator_permit
+    /// --- MAP ( netuid ) --> validator_permit
     pub type ValidatorPermit<T: Config> =
         StorageMap<_, Identity, u16, Vec<bool>, ValueQuery, EmptyBoolVec<T>>;
     #[pallet::storage]

From a1d7e8713e6320665dfdb3887715922cf16ed2ca Mon Sep 17 00:00:00 2001
From: Unconst <32490803+unconst@users.noreply.github.com>
Date: Wed, 22 Jan 2025 12:14:59 -0500
Subject: [PATCH 034/145] Metagraph struct (#1175)

* universal subnet struct

* oops typo

* cargo clippy

* cargo fmt

* add new field

---------

Co-authored-by: unconst <jake@bittensor.com>
Co-authored-by: camfairchild <cameron@opentensor.dev>
Co-authored-by: Cameron Fairchild <cameron@opentensor.ai>
---
 Cargo.lock                                  | 184 ++++---------
 pallets/subtensor/rpc/src/lib.rs            |  23 ++
 pallets/subtensor/runtime-api/src/lib.rs    |   2 +
 pallets/subtensor/src/rpc_info/metagraph.rs | 287 ++++++++++++++++++++
 pallets/subtensor/src/rpc_info/mod.rs       |   1 +
 runtime/src/lib.rs                          |  15 +
 6 files changed, 375 insertions(+), 137 deletions(-)
 create mode 100644 pallets/subtensor/src/rpc_info/metagraph.rs

diff --git a/Cargo.lock b/Cargo.lock
index 90c2fb86f..964c583e1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1550,9 +1550,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-queue"
-version = "0.3.11"
+version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
 dependencies = [
  "crossbeam-utils",
 ]
@@ -2187,9 +2187,9 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60"
 dependencies = [
  "crunchy",
  "fixed-hash",
- "impl-codec 0.6.0",
+ "impl-codec",
  "impl-rlp",
- "impl-serde 0.4.0",
+ "impl-serde",
  "scale-info",
  "tiny-keccak",
 ]
@@ -2220,12 +2220,12 @@ checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee"
 dependencies = [
  "ethbloom",
  "fixed-hash",
- "impl-codec 0.6.0",
+ "impl-codec",
  "impl-rlp",
- "impl-serde 0.4.0",
- "primitive-types 0.12.2",
+ "impl-serde",
+ "primitive-types",
  "scale-info",
- "uint 0.9.5",
+ "uint",
 ]
 
 [[package]]
@@ -2269,7 +2269,7 @@ dependencies = [
  "evm-runtime",
  "log",
  "parity-scale-codec",
- "primitive-types 0.12.2",
+ "primitive-types",
  "rlp",
  "scale-info",
  "serde",
@@ -2283,7 +2283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d1da6cedc5cedb4208e59467106db0d1f50db01b920920589f8e672c02fdc04f"
 dependencies = [
  "parity-scale-codec",
- "primitive-types 0.12.2",
+ "primitive-types",
  "scale-info",
  "serde",
 ]
@@ -2297,7 +2297,7 @@ dependencies = [
  "environmental",
  "evm-core",
  "evm-runtime",
- "primitive-types 0.12.2",
+ "primitive-types",
 ]
 
 [[package]]
@@ -2309,7 +2309,7 @@ dependencies = [
  "auto_impl",
  "environmental",
  "evm-core",
- "primitive-types 0.12.2",
+ "primitive-types",
  "sha3",
 ]
 
@@ -2694,7 +2694,7 @@ version = "1.0.0-dev"
 source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
 dependencies = [
  "hex",
- "impl-serde 0.4.0",
+ "impl-serde",
  "libsecp256k1",
  "log",
  "parity-scale-codec",
@@ -3876,26 +3876,6 @@ dependencies = [
  "parity-scale-codec",
 ]
 
-[[package]]
-name = "impl-codec"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941"
-dependencies = [
- "parity-scale-codec",
-]
-
-[[package]]
-name = "impl-num-traits"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "803d15461ab0dcc56706adf266158acbc44ccf719bf7d0af30705f58b90a4b8c"
-dependencies = [
- "integer-sqrt",
- "num-traits",
- "uint 0.10.0",
-]
-
 [[package]]
 name = "impl-rlp"
 version = "0.3.0"
@@ -3914,15 +3894,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "impl-serde"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a143eada6a1ec4aefa5049037a26a6d597bfd64f8c026d07b77133e02b7dd0b"
-dependencies = [
- "serde",
-]
-
 [[package]]
 name = "impl-trait-for-tuples"
 version = "0.2.2"
@@ -4459,7 +4430,7 @@ dependencies = [
  "sha2 0.10.8",
  "smallvec",
  "thiserror",
- "uint 0.9.5",
+ "uint",
  "unsigned-varint 0.7.2",
  "void",
 ]
@@ -4921,7 +4892,7 @@ dependencies = [
  "tokio-util",
  "tracing",
  "trust-dns-resolver",
- "uint 0.9.5",
+ "uint",
  "unsigned-varint 0.8.0",
  "url",
  "webpki",
@@ -6664,7 +6635,7 @@ dependencies = [
  "lru 0.8.1",
  "parity-util-mem-derive",
  "parking_lot 0.12.3",
- "primitive-types 0.12.2",
+ "primitive-types",
  "smallvec",
  "winapi",
 ]
@@ -6906,7 +6877,7 @@ dependencies = [
  "libc",
  "log",
  "polkavm-assembler",
- "polkavm-common 0.9.0",
+ "polkavm-common",
  "polkavm-linux-raw",
 ]
 
@@ -6928,28 +6899,13 @@ dependencies = [
  "log",
 ]
 
-[[package]]
-name = "polkavm-common"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f0dbafef4ab6ceecb4982ac3b550df430ef4f9fdbf07c108b7d4f91a0682fce"
-
 [[package]]
 name = "polkavm-derive"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606"
 dependencies = [
- "polkavm-derive-impl-macro 0.9.0",
-]
-
-[[package]]
-name = "polkavm-derive"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "206caf322dfc02144510ad8360ff2051e5072f0874dcab3b410f78cdd52d0ebb"
-dependencies = [
- "polkavm-derive-impl-macro 0.17.0",
+ "polkavm-derive-impl-macro",
 ]
 
 [[package]]
@@ -6958,19 +6914,7 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c"
 dependencies = [
- "polkavm-common 0.9.0",
- "proc-macro2",
- "quote",
- "syn 2.0.90",
-]
-
-[[package]]
-name = "polkavm-derive-impl"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42565aed4adbc4034612d0b17dea8db3681fb1bd1aed040d6edc5455a9f478a1"
-dependencies = [
- "polkavm-common 0.17.0",
+ "polkavm-common",
  "proc-macro2",
  "quote",
  "syn 2.0.90",
@@ -6982,17 +6926,7 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429"
 dependencies = [
- "polkavm-derive-impl 0.9.0",
- "syn 2.0.90",
-]
-
-[[package]]
-name = "polkavm-derive-impl-macro"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86d9838e95241b0bce4fe269cdd4af96464160505840ed5a8ac8536119ba19e2"
-dependencies = [
- "polkavm-derive-impl 0.17.0",
+ "polkavm-derive-impl",
  "syn 2.0.90",
 ]
 
@@ -7006,7 +6940,7 @@ dependencies = [
  "hashbrown 0.14.5",
  "log",
  "object 0.32.2",
- "polkavm-common 0.9.0",
+ "polkavm-common",
  "regalloc2 0.9.3",
  "rustc-demangle",
 ]
@@ -7143,23 +7077,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
 dependencies = [
  "fixed-hash",
- "impl-codec 0.6.0",
+ "impl-codec",
  "impl-rlp",
- "impl-serde 0.4.0",
+ "impl-serde",
  "scale-info",
- "uint 0.9.5",
-]
-
-[[package]]
-name = "primitive-types"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5"
-dependencies = [
- "fixed-hash",
- "impl-codec 0.7.0",
- "impl-num-traits",
- "uint 0.10.0",
+ "uint",
 ]
 
 [[package]]
@@ -9405,9 +9327,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
 
 [[package]]
 name = "serde"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
 dependencies = [
  "serde_derive",
 ]
@@ -9442,9 +9364,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9936,7 +9858,7 @@ dependencies = [
  "futures",
  "hash-db",
  "hash256-std-hasher",
- "impl-serde 0.4.0",
+ "impl-serde",
  "itertools 0.11.0",
  "k256",
  "libsecp256k1",
@@ -9946,7 +9868,7 @@ dependencies = [
  "parity-scale-codec",
  "parking_lot 0.12.3",
  "paste",
- "primitive-types 0.12.2",
+ "primitive-types",
  "rand",
  "scale-info",
  "schnorrkel",
@@ -9970,7 +9892,7 @@ dependencies = [
 [[package]]
 name = "sp-crypto-ec-utils"
 version = "0.10.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "ark-bls12-377",
  "ark-bls12-377-ext",
@@ -10066,7 +9988,7 @@ dependencies = [
 [[package]]
 name = "sp-debug-derive"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -10076,7 +9998,7 @@ dependencies = [
 [[package]]
 name = "sp-externalities"
 version = "0.25.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "environmental",
  "parity-scale-codec",
@@ -10129,7 +10051,7 @@ dependencies = [
  "libsecp256k1",
  "log",
  "parity-scale-codec",
- "polkavm-derive 0.9.1",
+ "polkavm-derive",
  "rustversion",
  "secp256k1",
  "sp-core",
@@ -10254,13 +10176,13 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface"
 version = "24.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive 0.17.1",
- "primitive-types 0.13.1",
+ "polkavm-derive",
+ "primitive-types",
  "sp-externalities 0.25.0",
  "sp-runtime-interface-proc-macro 17.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)",
@@ -10278,8 +10200,8 @@ dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive 0.9.1",
- "primitive-types 0.12.2",
+ "polkavm-derive",
+ "primitive-types",
  "sp-externalities 0.29.0",
  "sp-runtime-interface-proc-macro 18.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
@@ -10292,7 +10214,7 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface-proc-macro"
 version = "17.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "Inflector",
  "expander",
@@ -10394,14 +10316,14 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable
 [[package]]
 name = "sp-std"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 
 [[package]]
 name = "sp-storage"
 version = "19.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
- "impl-serde 0.5.0",
+ "impl-serde",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10413,7 +10335,7 @@ name = "sp-storage"
 version = "21.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde 0.4.0",
+ "impl-serde",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10435,7 +10357,7 @@ dependencies = [
 [[package]]
 name = "sp-tracing"
 version = "16.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "parity-scale-codec",
  "tracing",
@@ -10505,7 +10427,7 @@ name = "sp-version"
 version = "37.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde 0.4.0",
+ "impl-serde",
  "parity-scale-codec",
  "parity-wasm",
  "scale-info",
@@ -10531,7 +10453,7 @@ dependencies = [
 [[package]]
 name = "sp-wasm-interface"
 version = "20.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#44766de645c741fd03d159fca7f17cd6e99c33e3"
+source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
 dependencies = [
  "anyhow",
  "impl-trait-for-tuples",
@@ -11705,18 +11627,6 @@ dependencies = [
  "static_assertions",
 ]
 
-[[package]]
-name = "uint"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e"
-dependencies = [
- "byteorder",
- "crunchy",
- "hex",
- "static_assertions",
-]
-
 [[package]]
 name = "unicode-bidi"
 version = "0.3.17"
diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs
index 5b4c7777a..cdbcebcac 100644
--- a/pallets/subtensor/rpc/src/lib.rs
+++ b/pallets/subtensor/rpc/src/lib.rs
@@ -55,6 +55,10 @@ pub trait SubtensorCustomApi<BlockHash> {
     fn get_all_dynamic_info(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
     #[method(name = "subnetInfo_getDynamicInfo")]
     fn get_dynamic_info(&self, netuid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
+    #[method(name = "subnetInfo_getAllMetagraphs")]
+    fn get_all_metagraphs(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
+    #[method(name = "subnetInfo_getMetagraph")]
+    fn get_metagraph(&self, netuid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
     #[method(name = "subnetInfo_getSubnetState")]
     fn get_subnet_state(&self, netuid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
     #[method(name = "subnetInfo_getLockCost")]
@@ -223,6 +227,13 @@ where
         })
     }
 
+    fn get_all_metagraphs(&self, at: Option<<Block as BlockT>::Hash>) -> RpcResult<Vec<u8>> {
+        let api = self.client.runtime_api();
+        let at = at.unwrap_or_else(|| self.client.info().best_hash);
+        api.get_all_metagraphs(at)
+            .map_err(|e| Error::RuntimeError(format!("Unable to get metagraps: {:?}", e)).into())
+    }
+
     fn get_dynamic_info(
         &self,
         netuid: u16,
@@ -235,6 +246,18 @@ where
         })
     }
 
+    fn get_metagraph(
+        &self,
+        netuid: u16,
+        at: Option<<Block as BlockT>::Hash>,
+    ) -> RpcResult<Vec<u8>> {
+        let api = self.client.runtime_api();
+        let at = at.unwrap_or_else(|| self.client.info().best_hash);
+        api.get_metagraph(at, netuid).map_err(|e| {
+            Error::RuntimeError(format!("Unable to get dynamic subnets info: {:?}", e)).into()
+        })
+    }
+
     fn get_subnet_state(
         &self,
         netuid: u16,
diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs
index 85adada68..cdcd6ed39 100644
--- a/pallets/subtensor/runtime-api/src/lib.rs
+++ b/pallets/subtensor/runtime-api/src/lib.rs
@@ -25,6 +25,8 @@ sp_api::decl_runtime_apis! {
         fn get_subnets_info_v2() -> Vec<u8>;
         fn get_subnet_hyperparams(netuid: u16) -> Vec<u8>;
         fn get_all_dynamic_info() -> Vec<u8>;
+        fn get_all_metagraphs() -> Vec<u8>;
+        fn get_metagraph(netuid: u16) -> Vec<u8>;
         fn get_dynamic_info(netuid: u16) -> Vec<u8>;
         fn get_subnet_state(netuid: u16) -> Vec<u8>;
     }
diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs
new file mode 100644
index 000000000..091c7e259
--- /dev/null
+++ b/pallets/subtensor/src/rpc_info/metagraph.rs
@@ -0,0 +1,287 @@
+use super::*;
+extern crate alloc;
+use crate::epoch::math::*;
+use codec::Compact;
+use frame_support::pallet_prelude::{Decode, Encode};
+use substrate_fixed::types::I64F64;
+use subtensor_macros::freeze_struct;
+
+#[freeze_struct("eff674535ea437ae")]
+#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
+pub struct Metagraph<T: Config> {
+    // Subnet index
+    netuid: Compact<u16>,
+
+    // Name and symbol
+    name: Vec<Compact<u8>>,              // name
+    symbol: Vec<Compact<u8>>,            // token symbol
+    identity: Option<SubnetIdentity>,    // identity information.
+    network_registered_at: Compact<u64>, // block at registration
+
+    // Keys for owner.
+    owner_hotkey: T::AccountId,  // hotkey
+    owner_coldkey: T::AccountId, // coldkey.
+
+    // Tempo terms.
+    block: Compact<u64>,                  // block at call.
+    tempo: Compact<u16>,                  // epoch tempo
+    last_step: Compact<u64>,              // last epoch
+    blocks_since_last_step: Compact<u64>, // blocks since last epoch.
+
+    // Subnet emission terms
+    subnet_emission: Compact<u64>,        // subnet emission via stao
+    alpha_in: Compact<u64>,               // amount of alpha in reserve
+    alpha_out: Compact<u64>,              // amount of alpha outstanding
+    tao_in: Compact<u64>,                 // amount of tao injected per block
+    alpha_out_emission: Compact<u64>,     // amount injected in alpha reserves per block
+    alpha_in_emission: Compact<u64>,      // amount injected outstanding per block
+    tao_in_emission: Compact<u64>,        // amount of tao injected per block
+    pending_alpha_emission: Compact<u64>, // pending alpha to be distributed
+    pending_root_emission: Compact<u64>,  // panding tao for root divs to be distributed
+
+    // Hparams for epoch
+    rho: Compact<u16>,   // subnet rho param
+    kappa: Compact<u16>, // subnet kappa param
+
+    // Validator params
+    min_allowed_weights: Compact<u16>, // min allowed weights per val
+    max_weights_limit: Compact<u16>,   // max allowed weights per val
+    weights_version: Compact<u64>,     // allowed weights version
+    weights_rate_limit: Compact<u64>,  // rate limit on weights.
+    activity_cutoff: Compact<u16>,     // validator weights cut off period in blocks
+    max_validators: Compact<u16>,      // max allowed validators.
+
+    // Registration
+    num_uids: Compact<u16>,
+    max_uids: Compact<u16>,
+    burn: Compact<u64>,                     // current burn cost..
+    difficulty: Compact<u64>,               // current difficulty.
+    registration_allowed: bool,             // allows registrations.
+    pow_registration_allowed: bool,         // pow registration enabled.
+    immunity_period: Compact<u16>,          // subnet miner immunity period
+    min_difficulty: Compact<u64>,           // min pow difficulty
+    max_difficulty: Compact<u64>,           // max pow difficulty
+    min_burn: Compact<u64>,                 // min tao burn
+    max_burn: Compact<u64>,                 // max tao burn
+    adjustment_alpha: Compact<u64>,         // adjustment speed for registration params.
+    adjustment_interval: Compact<u16>,      // pow and burn adjustment interval
+    target_regs_per_interval: Compact<u16>, // target registrations per interval
+    max_regs_per_block: Compact<u16>,       // max registrations per block.
+    serving_rate_limit: Compact<u64>,       // axon serving rate limit
+
+    // CR
+    commit_reveal_weights_enabled: bool, // Is CR enabled.
+    commit_reveal_period: Compact<u64>,  // Commit reveal interval
+
+    // Bonds
+    liquid_alpha_enabled: bool,     // Bonds liquid enabled.
+    alpha_high: Compact<u16>,       // Alpha param high
+    alpha_low: Compact<u16>,        // Alpha param low
+    bonds_moving_avg: Compact<u64>, // Bonds moving avg
+
+    // Metagraph info.
+    hotkeys: Vec<T::AccountId>,               // hotkey per UID
+    coldkeys: Vec<T::AccountId>,              // coldkey per UID
+    identities: Vec<ChainIdentityOf>,         // coldkeys identities
+    axons: Vec<AxonInfo>,                     // UID axons.
+    active: Vec<bool>,                        // Avtive per UID
+    validator_permit: Vec<bool>,              // Val permit per UID
+    pruning_score: Vec<Compact<u16>>,         // Pruning per UID
+    last_update: Vec<Compact<u64>>,           // Last update per UID
+    emission: Vec<Compact<u64>>,              // Emission per UID
+    dividends: Vec<Compact<u16>>,             // Dividends per UID
+    incentives: Vec<Compact<u16>>,            // Mining incentives per UID
+    consensus: Vec<Compact<u16>>,             // Consensus per UID
+    trust: Vec<Compact<u16>>,                 // Trust per UID
+    rank: Vec<Compact<u16>>,                  // Rank per UID
+    block_at_registration: Vec<Compact<u64>>, // Reg block per UID
+    alpha_stake: Vec<Compact<u64>>,           // Alpha staked per UID
+    tao_stake: Vec<Compact<u64>>,             // TAO staked per UID
+    total_stake: Vec<Compact<u64>>,           // Total stake per UID
+
+    // Dividend break down.
+    tao_dividends_per_hotkey: Vec<(T::AccountId, Compact<u64>)>, // List of dividend payouts in tao via root.
+    alpha_dividends_per_hotkey: Vec<(T::AccountId, Compact<u64>)>, // List of dividend payout in alpha via subnet.
+}
+
+impl<T: Config> Pallet<T> {
+    pub fn get_metagraph(netuid: u16) -> Option<Metagraph<T>> {
+        if !Self::if_subnet_exist(netuid) {
+            return None;
+        }
+
+        let n: u16 = Self::get_subnetwork_n(netuid);
+        let mut hotkeys: Vec<T::AccountId> = vec![];
+        let mut coldkeys: Vec<T::AccountId> = vec![];
+        let mut block_at_registration: Vec<Compact<u64>> = vec![];
+        let mut identities: Vec<ChainIdentityOf> = vec![];
+        let mut axons: Vec<AxonInfo> = vec![];
+        for uid in 0..n {
+            let hotkey = Keys::<T>::get(netuid, uid);
+            let coldkey = Owner::<T>::get(hotkey.clone());
+            hotkeys.push(hotkey.clone());
+            coldkeys.push(coldkey.clone());
+            block_at_registration.push(BlockAtRegistration::<T>::get(netuid, uid).into());
+            identities.push(Identities::<T>::get(coldkey.clone())?);
+            axons.push(Self::get_axon_info(netuid, &hotkey));
+        }
+        let mut tao_dividends_per_hotkey: Vec<(T::AccountId, Compact<u64>)> = vec![];
+        let mut alpha_dividends_per_hotkey: Vec<(T::AccountId, Compact<u64>)> = vec![];
+        for hotkey in hotkeys.clone() {
+            let tao_divs = TaoDividendsPerSubnet::<T>::get(netuid, hotkey.clone());
+            let alpha_divs = AlphaDividendsPerSubnet::<T>::get(netuid, hotkey.clone());
+            tao_dividends_per_hotkey.push((hotkey.clone(), tao_divs.into()));
+            alpha_dividends_per_hotkey.push((hotkey.clone(), alpha_divs.into()));
+        }
+        let current_block: u64 = Pallet::<T>::get_current_block_as_u64();
+        let last_step = LastMechansimStepBlock::<T>::get(netuid);
+        let blocks_since_last_step: u64 = current_block.saturating_sub(last_step);
+        let (total_stake_fl, alpha_stake_fl, tao_stake_fl): (
+            Vec<I64F64>,
+            Vec<I64F64>,
+            Vec<I64F64>,
+        ) = Self::get_stake_weights_for_network(netuid);
+        Some(Metagraph {
+            // Subnet index
+            netuid: netuid.into(), // subnet index.
+
+            // Name and symbol
+            name: Self::get_name_for_subnet(netuid)
+                .into_iter()
+                .map(Compact)
+                .collect(), // Name
+            symbol: Self::get_symbol_for_subnet(netuid)
+                .into_iter()
+                .map(Compact)
+                .collect(), // Symbol.
+            identity: SubnetIdentities::<T>::get(netuid), // identity information.
+            network_registered_at: NetworkRegisteredAt::<T>::get(netuid).into(), // block at registration
+
+            // Keys for owner.
+            owner_hotkey: SubnetOwnerHotkey::<T>::get(netuid), // Owner hotkey
+            owner_coldkey: SubnetOwner::<T>::get(netuid),      // Owner Coldkey
+
+            // Tempo terms.
+            block: current_block.into(),           // Block at call.
+            tempo: Self::get_tempo(netuid).into(), // epoch tempo
+            last_step: LastMechansimStepBlock::<T>::get(netuid).into(), // last epoch
+            blocks_since_last_step: blocks_since_last_step.into(), // blocks since last epoch.
+
+            // Subnet emission terms
+            subnet_emission: EmissionValues::<T>::get(netuid).into(), // subnet emission via stao
+            alpha_in: SubnetAlphaIn::<T>::get(netuid).into(),         // amount of alpha in reserve
+            alpha_out: SubnetAlphaOut::<T>::get(netuid).into(),       // amount of alpha outstanding
+            tao_in: SubnetTAO::<T>::get(netuid).into(), // amount of tao injected per block
+            alpha_out_emission: SubnetAlphaOutEmission::<T>::get(netuid).into(), // amount injected in alpha reserves per block
+            alpha_in_emission: SubnetAlphaInEmission::<T>::get(netuid).into(), // amount injected outstanding per block
+            tao_in_emission: SubnetTaoInEmission::<T>::get(netuid).into(), // amount of tao injected per block
+            pending_alpha_emission: PendingEmission::<T>::get(netuid).into(), // pending alpha to be distributed
+            pending_root_emission: PendingRootDivs::<T>::get(netuid).into(), // panding tao for root divs to be distributed
+
+            // Hparams for epoch
+            rho: Self::get_rho(netuid).into(), // subnet rho param
+            kappa: Self::get_kappa(netuid).into(), // subnet kappa param
+
+            // Validator params
+            min_allowed_weights: Self::get_min_allowed_weights(netuid).into(), // min allowed weights per val
+            max_weights_limit: Self::get_max_weight_limit(netuid).into(),      // max allowed weight
+            weights_version: Self::get_weights_version_key(netuid).into(), // allowed weights version
+            weights_rate_limit: Self::get_weights_set_rate_limit(netuid).into(), // rate limit on weights.
+            activity_cutoff: Self::get_activity_cutoff(netuid).into(), // validator weights cut off period in blocks
+            max_validators: Self::get_max_allowed_validators(netuid).into(), // max allowed validators.
+
+            // Registration
+            num_uids: Self::get_subnetwork_n(netuid).into(),
+            max_uids: Self::get_max_allowed_uids(netuid).into(),
+            registration_allowed: Self::get_network_registration_allowed(netuid), // allows registrations.
+            pow_registration_allowed: Self::get_network_pow_registration_allowed(netuid), // allows pow registrations.
+            difficulty: Self::get_difficulty_as_u64(netuid).into(), // current difficulty.
+            burn: Self::get_burn_as_u64(netuid).into(),
+            immunity_period: Self::get_immunity_period(netuid).into(), // subnet miner immunity period
+            min_difficulty: Self::get_min_difficulty(netuid).into(),   // min pow difficulty
+            max_difficulty: Self::get_max_difficulty(netuid).into(),   // max pow difficulty
+            min_burn: Self::get_min_burn_as_u64(netuid).into(),        // min tao burn
+            max_burn: Self::get_max_burn_as_u64(netuid).into(),        // max tao burn
+            adjustment_alpha: Self::get_adjustment_alpha(netuid).into(), // adjustment speed for registration params.
+            adjustment_interval: Self::get_adjustment_interval(netuid).into(), // pow and burn adjustment interval
+            target_regs_per_interval: Self::get_target_registrations_per_interval(netuid).into(), // target registrations per interval
+            max_regs_per_block: Self::get_max_registrations_per_block(netuid).into(), // max registrations per block.
+            serving_rate_limit: Self::get_serving_rate_limit(netuid).into(), // axon serving rate limit
+
+            // CR
+            commit_reveal_weights_enabled: Self::get_commit_reveal_weights_enabled(netuid), // Is CR enabled.
+            commit_reveal_period: Self::get_reveal_period(netuid).into(), // Commit reveal interval
+
+            // Bonds
+            liquid_alpha_enabled: Self::get_liquid_alpha_enabled(netuid), // Bonds liquid enabled.
+            alpha_high: Self::get_alpha_values(netuid).1.into(),          // Alpha param high
+            alpha_low: Self::get_alpha_values(netuid).0.into(),           // Alpha param low
+            bonds_moving_avg: Self::get_bonds_moving_average(netuid).into(), // Bonds moving avg
+
+            // Metagraph info.
+            hotkeys,  // hotkey per UID
+            coldkeys, // coldkey per UID
+            axons,    // Axon information per UID.
+            identities,
+            active: Active::<T>::get(netuid), // Avtive per UID
+            validator_permit: ValidatorPermit::<T>::get(netuid), // Val permit per UID
+            pruning_score: PruningScores::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Pruning per UID
+            last_update: LastUpdate::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Last update per UID
+            emission: Emission::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Emission per UID
+            dividends: Dividends::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Dividends per UID
+            incentives: Incentive::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Mining incentives per UID
+            consensus: Consensus::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Consensus per UID
+            trust: Trust::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Trust per UID
+            rank: Rank::<T>::get(netuid)
+                .into_iter()
+                .map(Compact::from)
+                .collect(), // Rank per UID
+            block_at_registration,            // Reg block per UID
+            alpha_stake: alpha_stake_fl
+                .iter()
+                .map(|xi| Compact::from(fixed64_to_u64(*xi)))
+                .collect::<Vec<Compact<u64>>>(), // Alpha staked per UID
+            tao_stake: tao_stake_fl
+                .iter()
+                .map(|xi| Compact::from(fixed64_to_u64(*xi)))
+                .collect::<Vec<Compact<u64>>>(), // TAO staked per UID
+            total_stake: total_stake_fl
+                .iter()
+                .map(|xi| Compact::from(fixed64_to_u64(*xi)))
+                .collect::<Vec<Compact<u64>>>(), // Total stake per UID
+
+            // Dividend break down.
+            tao_dividends_per_hotkey,
+            alpha_dividends_per_hotkey,
+        })
+    }
+    pub fn get_all_metagraphs() -> Vec<Option<Metagraph<T>>> {
+        let netuids: Vec<u16> = Self::get_all_subnet_netuids();
+        let mut metagraphs = Vec::<Option<Metagraph<T>>>::new();
+        for netuid in netuids.clone().iter() {
+            metagraphs.push(Self::get_metagraph(*netuid));
+        }
+        metagraphs
+    }
+}
diff --git a/pallets/subtensor/src/rpc_info/mod.rs b/pallets/subtensor/src/rpc_info/mod.rs
index 4c224050e..13b2e9cbb 100644
--- a/pallets/subtensor/src/rpc_info/mod.rs
+++ b/pallets/subtensor/src/rpc_info/mod.rs
@@ -1,6 +1,7 @@
 use super::*;
 pub mod delegate_info;
 pub mod dynamic_info;
+pub mod metagraph;
 pub mod neuron_info;
 pub mod show_subnet;
 pub mod stake_info;
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 128d2b8f3..5c3688a51 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -2112,6 +2112,16 @@ impl_runtime_apis! {
             }
         }
 
+        fn get_metagraph(netuid: u16) -> Vec<u8> {
+            let _result = SubtensorModule::get_metagraph(netuid);
+            if _result.is_some() {
+                let result = _result.expect("Could not get Metagraph.");
+                result.encode()
+            } else {
+                vec![]
+            }
+        }
+
         fn get_subnet_state(netuid: u16) -> Vec<u8> {
             let _result = SubtensorModule::get_subnet_state(netuid);
             if _result.is_some() {
@@ -2122,6 +2132,11 @@ impl_runtime_apis! {
             }
         }
 
+        fn get_all_metagraphs() -> Vec<u8> {
+            let result = SubtensorModule::get_all_metagraphs();
+            result.encode()
+        }
+
         fn get_all_dynamic_info() -> Vec<u8> {
             let result = SubtensorModule::get_all_dynamic_info();
             result.encode()

From af8cd5ec44946ae4e9e6820c89c90162f27cb2cd Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Wed, 22 Jan 2025 13:24:05 -0500
Subject: [PATCH 035/145] Fix tests and transfer stake after merging
 devnet-ready

---
 pallets/subtensor/src/staking/move_stake.rs |  5 +++-
 pallets/subtensor/src/tests/move_stake.rs   | 31 +++++++++++++++------
 2 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index ee9cb49a7..701d8911d 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -181,7 +181,9 @@ impl<T: Config> Pallet<T> {
         );
 
         // 6. Unstake from the origin coldkey; this returns an amount of TAO.
-        let origin_tao = Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount);
+        let fee = DefaultMinStake::<T>::get().saturating_div(2);
+        let origin_tao =
+            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount, fee);
 
         // 7. Ensure the returned TAO meets a minimum stake requirement (if required).
         ensure!(
@@ -196,6 +198,7 @@ impl<T: Config> Pallet<T> {
             &destination_coldkey,
             destination_netuid,
             origin_tao,
+            fee,
         );
 
         // 9. Emit an event for logging/monitoring.
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 3c1f2b448..a8896eef4 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -813,6 +813,7 @@ fn test_do_transfer_success() {
         let subnet_owner_coldkey = U256::from(1001);
         let subnet_owner_hotkey = U256::from(1002);
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let fee = DefaultMinStake::<Test>::get();
 
         // 2. Define the origin coldkey, destination coldkey, and hotkey to be used.
         let origin_coldkey = U256::from(1);
@@ -823,7 +824,7 @@ fn test_do_transfer_success() {
         // 3. Set up initial stake: (origin_coldkey, hotkey) on netuid.
         SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
         SubtensorModule::create_account_if_non_existent(&destination_coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount, 0);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey,
             &origin_coldkey,
@@ -855,7 +856,7 @@ fn test_do_transfer_success() {
                 &destination_coldkey,
                 netuid
             ),
-            stake_amount,
+            stake_amount - fee,
             epsilon = stake_amount / 1000
         );
     });
@@ -922,7 +923,7 @@ fn test_do_transfer_insufficient_stake() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount, 0);
 
         let alpha = stake_amount * 2;
         assert_noop!(
@@ -950,11 +951,12 @@ fn test_do_transfer_wrong_origin() {
         let wrong_coldkey = U256::from(9999);
         let destination_coldkey = U256::from(2);
         let hotkey = U256::from(3);
-        let stake_amount = 100_000;
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
-        SubtensorModule::add_balance_to_coldkey_account(&origin_coldkey, 1_000_000_000);
-        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+        SubtensorModule::add_balance_to_coldkey_account(&origin_coldkey, stake_amount + fee);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount, fee);
 
         assert_noop!(
             SubtensorModule::do_transfer_stake(
@@ -983,7 +985,7 @@ fn test_do_transfer_minimum_stake_check() {
 
         let stake_amount = DefaultMinStake::<Test>::get();
         SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, netuid, stake_amount, 0);
 
         assert_err!(
             SubtensorModule::do_transfer_stake(
@@ -1013,6 +1015,7 @@ fn test_do_transfer_different_subnets() {
         let destination_coldkey = U256::from(2);
         let hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultMinStake::<Test>::get();
 
         // 3. Create accounts if needed.
         SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
@@ -1022,7 +1025,13 @@ fn test_do_transfer_different_subnets() {
         SubtensorModule::add_balance_to_coldkey_account(&origin_coldkey, 1_000_000_000);
 
         // 5. Stake into the origin subnet.
-        SubtensorModule::stake_into_subnet(&hotkey, &origin_coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(
+            &hotkey,
+            &origin_coldkey,
+            origin_netuid,
+            stake_amount,
+            0,
+        );
 
         // 6. Transfer entire stake from origin_netuid -> destination_netuid.
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -1055,6 +1064,10 @@ fn test_do_transfer_different_subnets() {
             &destination_coldkey,
             destination_netuid,
         );
-        assert_abs_diff_eq!(dest_stake, stake_amount, epsilon = stake_amount / 1000);
+        assert_abs_diff_eq!(
+            dest_stake,
+            stake_amount - fee,
+            epsilon = stake_amount / 1000
+        );
     });
 }

From 7d43c7e6bbc1d900a8c168967a208991da0dfc56 Mon Sep 17 00:00:00 2001
From: JohnReedV <87283488+JohnReedV@users.noreply.github.com>
Date: Wed, 22 Jan 2025 10:58:30 -0800
Subject: [PATCH 036/145] add swap_stake & tests

---
 pallets/subtensor/src/macros/dispatches.rs  |  44 ++-
 pallets/subtensor/src/macros/events.rs      |   6 +
 pallets/subtensor/src/staking/move_stake.rs |  97 ++++++
 pallets/subtensor/src/tests/move_stake.rs   | 360 ++++++++++++++++++++
 4 files changed, 504 insertions(+), 3 deletions(-)

diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs
index 34712ccb5..7a3e3b240 100644
--- a/pallets/subtensor/src/macros/dispatches.rs
+++ b/pallets/subtensor/src/macros/dispatches.rs
@@ -1608,9 +1608,6 @@ mod dispatches {
         /// * `destination_netuid` - The network/subnet ID to move stake to (for cross-subnet transfer).
         /// * `alpha_amount` - The amount of stake to transfer.
         ///
-        /// # Weight
-        /// Uses a fixed weight of 3_000_000 (plus any DB write overhead).
-        ///
         /// # Errors
         /// Returns an error if:
         /// * The origin is not signed by the correct coldkey.
@@ -1640,5 +1637,46 @@ mod dispatches {
                 alpha_amount,
             )
         }
+
+        /// 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.
+        ///
+        /// # 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(87)]
+        #[pallet::weight((
+            Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().writes(1)),
+            DispatchClass::Operational,
+            Pays::No
+        ))]
+        pub fn swap_stake(
+            origin: T::RuntimeOrigin,
+            hotkey: T::AccountId,
+            origin_netuid: u16,
+            destination_netuid: u16,
+            alpha_amount: u64,
+        ) -> DispatchResult {
+            Self::do_swap_stake(
+                origin,
+                hotkey,
+                origin_netuid,
+                destination_netuid,
+                alpha_amount,
+            )
+        }
     }
 }
diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs
index 782f6b792..9083e57f6 100644
--- a/pallets/subtensor/src/macros/events.rs
+++ b/pallets/subtensor/src/macros/events.rs
@@ -253,5 +253,11 @@ mod events {
         /// Parameters:
         /// (origin_coldkey, destination_coldkey, hotkey, origin_netuid, destination_netuid, amount)
         StakeTransferred(T::AccountId, T::AccountId, T::AccountId, u16, u16, u64),
+
+        /// Stake has been swapped from one subnet to another for the same coldkey-hotkey pair.
+        ///
+        /// Parameters:
+        /// (coldkey, hotkey, origin_netuid, destination_netuid, amount)
+        StakeSwapped(T::AccountId, T::AccountId, u16, u16, u64),
     }
 }
diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 49d823b86..60667e453 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -217,4 +217,101 @@ impl<T: Config> Pallet<T> {
         // 10. Return success.
         Ok(())
     }
+
+    /// Swaps a specified amount of stake for the same `(coldkey, hotkey)` pair from one subnet
+    /// (`origin_netuid`) to another (`destination_netuid`).
+    ///
+    /// # 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 subnet ID from which stake is removed.
+    /// * `destination_netuid` - The subnet ID to which stake is added.
+    /// * `alpha_amount` - The amount of stake to swap.
+    ///
+    /// # Returns
+    /// * `DispatchResult` - Indicates success or failure.
+    ///
+    /// # Errors
+    /// This function returns an error if:
+    /// * The origin is not signed by the correct coldkey (i.e., not associated with `hotkey`).
+    /// * Either the `origin_netuid` or the `destination_netuid` does not exist.
+    /// * The specified `hotkey` does not exist.
+    /// * The `(coldkey, hotkey, origin_netuid)` does not have enough stake (`alpha_amount`).
+    /// * The unstaked amount is below `DefaultMinStake`.
+    ///
+    /// # Events
+    /// Emits a `StakeSwapped` event upon successful completion.
+    pub fn do_swap_stake(
+        origin: T::RuntimeOrigin,
+        hotkey: T::AccountId,
+        origin_netuid: u16,
+        destination_netuid: u16,
+        alpha_amount: u64,
+    ) -> dispatch::DispatchResult {
+        // 1. Ensure the extrinsic is signed by the coldkey.
+        let coldkey = ensure_signed(origin)?;
+
+        // 2. Check that both subnets exist.
+        ensure!(
+            Self::if_subnet_exist(origin_netuid),
+            Error::<T>::SubnetNotExists
+        );
+        ensure!(
+            Self::if_subnet_exist(destination_netuid),
+            Error::<T>::SubnetNotExists
+        );
+
+        // 3. Check that the hotkey exists.
+        ensure!(
+            Self::hotkey_account_exists(&hotkey),
+            Error::<T>::HotKeyAccountNotExists
+        );
+
+        // 4. Ensure this coldkey actually owns the hotkey.
+        ensure!(
+            Self::coldkey_owns_hotkey(&coldkey, &hotkey),
+            Error::<T>::NonAssociatedColdKey
+        );
+
+        // 5. Ensure there is enough stake in the origin subnet.
+        let origin_alpha =
+            Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, origin_netuid);
+        ensure!(
+            alpha_amount <= origin_alpha,
+            Error::<T>::NotEnoughStakeToWithdraw
+        );
+
+        // 6. Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
+        let tao_unstaked =
+            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount);
+
+        // 7. Check that the unstaked amount is above the minimum stake threshold.
+        ensure!(
+            tao_unstaked >= DefaultMinStake::<T>::get(),
+            Error::<T>::AmountTooLow
+        );
+
+        // 8. Stake the unstaked amount into the destination subnet, using the same coldkey/hotkey.
+        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked);
+
+        // 9. Emit an event for logging.
+        log::info!(
+            "StakeSwapped(coldkey: {:?}, hotkey: {:?}, origin_netuid: {:?}, destination_netuid: {:?}, amount: {:?})",
+            coldkey,
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            tao_unstaked
+        );
+        Self::deposit_event(Event::StakeSwapped(
+            coldkey,
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            tao_unstaked,
+        ));
+
+        // 10. Return success.
+        Ok(())
+    }
 }
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 59afc9b62..b15f49d92 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -1026,3 +1026,363 @@ fn test_do_transfer_different_subnets() {
         assert_abs_diff_eq!(dest_stake, stake_amount, epsilon = stake_amount / 1000);
     });
 }
+
+#[test]
+fn test_do_swap_success() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(2);
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+        let alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey,
+            &coldkey,
+            origin_netuid,
+        );
+
+        assert_ok!(SubtensorModule::do_swap_stake(
+            RuntimeOrigin::signed(coldkey),
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            alpha_before,
+        ));
+
+        assert_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &coldkey,
+                origin_netuid
+            ),
+            0
+        );
+
+        let alpha_after = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey,
+            &coldkey,
+            destination_netuid,
+        );
+        assert_abs_diff_eq!(alpha_after, stake_amount, epsilon = stake_amount / 1000);
+    });
+}
+
+#[test]
+fn test_do_swap_nonexistent_subnet() {
+    new_test_ext(1).execute_with(|| {
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(2);
+        let nonexistent_netuid: u16 = 9999;
+        let stake_amount = 1_000_000;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+
+        assert_noop!(
+            SubtensorModule::do_swap_stake(
+                RuntimeOrigin::signed(coldkey),
+                hotkey,
+                nonexistent_netuid,
+                nonexistent_netuid,
+                stake_amount
+            ),
+            Error::<Test>::SubnetNotExists
+        );
+    });
+}
+
+#[test]
+fn test_do_swap_nonexistent_hotkey() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid1 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let netuid2 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let nonexistent_hotkey = U256::from(999);
+        let stake_amount = 10_000;
+
+        assert_noop!(
+            SubtensorModule::do_swap_stake(
+                RuntimeOrigin::signed(coldkey),
+                nonexistent_hotkey,
+                netuid1,
+                netuid2,
+                stake_amount
+            ),
+            Error::<Test>::HotKeyAccountNotExists
+        );
+    });
+}
+
+#[test]
+fn test_do_swap_insufficient_stake() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid1 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let netuid2 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(2);
+        let stake_amount = DefaultMinStake::<Test>::get() * 5;
+        let attempted_swap = stake_amount * 2;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, stake_amount);
+
+        assert_noop!(
+            SubtensorModule::do_swap_stake(
+                RuntimeOrigin::signed(coldkey),
+                hotkey,
+                netuid1,
+                netuid2,
+                attempted_swap
+            ),
+            Error::<Test>::NotEnoughStakeToWithdraw
+        );
+    });
+}
+
+#[test]
+fn test_do_swap_wrong_origin() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1010);
+        let subnet_owner_hotkey = U256::from(1011);
+        let netuid1 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let netuid2 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let real_coldkey = U256::from(1);
+        let wrong_coldkey = U256::from(9999);
+        let hotkey = U256::from(3);
+        let stake_amount = 100_000;
+
+        SubtensorModule::create_account_if_non_existent(&real_coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &real_coldkey, netuid1, stake_amount);
+
+        assert_noop!(
+            SubtensorModule::do_swap_stake(
+                RuntimeOrigin::signed(wrong_coldkey),
+                hotkey,
+                netuid1,
+                netuid2,
+                stake_amount
+            ),
+            Error::<Test>::NonAssociatedColdKey
+        );
+    });
+}
+
+#[test]
+fn test_do_swap_minimum_stake_check() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(3);
+        let total_stake = DefaultMinStake::<Test>::get();
+        let swap_amount = 1;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, total_stake);
+
+        assert_err!(
+            SubtensorModule::do_swap_stake(
+                RuntimeOrigin::signed(coldkey),
+                hotkey,
+                netuid,
+                netuid,
+                swap_amount
+            ),
+            Error::<Test>::AmountTooLow
+        );
+    });
+}
+
+#[test]
+fn test_do_swap_same_subnet() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1100);
+        let subnet_owner_hotkey = U256::from(1101);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(2);
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount);
+
+        let alpha_before =
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+
+        assert_ok!(SubtensorModule::do_swap_stake(
+            RuntimeOrigin::signed(coldkey),
+            hotkey,
+            netuid,
+            netuid,
+            alpha_before
+        ));
+
+        let alpha_after =
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        assert_abs_diff_eq!(alpha_after, alpha_before, epsilon = 5);
+    });
+}
+
+#[test]
+fn test_do_swap_partial_stake() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1100);
+        let subnet_owner_hotkey = U256::from(1101);
+        let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(2);
+        let total_stake = DefaultMinStake::<Test>::get() * 10;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake);
+
+        let swap_amount = total_stake / 2;
+        assert_ok!(SubtensorModule::do_swap_stake(
+            RuntimeOrigin::signed(coldkey),
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            swap_amount,
+        ));
+
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &coldkey,
+                origin_netuid
+            ),
+            total_stake - swap_amount,
+            epsilon = total_stake / 1000
+        );
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &coldkey,
+                destination_netuid
+            ),
+            swap_amount,
+            epsilon = total_stake / 1000
+        );
+    });
+}
+
+#[test]
+fn test_do_swap_storage_updates() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1300);
+        let subnet_owner_hotkey = U256::from(1301);
+        let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(2);
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+
+        let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey,
+            &coldkey,
+            origin_netuid,
+        );
+        assert_ok!(SubtensorModule::do_swap_stake(
+            RuntimeOrigin::signed(coldkey),
+            hotkey,
+            origin_netuid,
+            destination_netuid,
+            alpha
+        ));
+
+        assert_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &coldkey,
+                origin_netuid
+            ),
+            0
+        );
+
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey,
+                &coldkey,
+                destination_netuid
+            ),
+            alpha,
+            epsilon = 5
+        );
+    });
+}
+
+#[test]
+fn test_do_swap_multiple_times() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1500);
+        let subnet_owner_hotkey = U256::from(1501);
+        let netuid1 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let netuid2 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        let coldkey = U256::from(1);
+        let hotkey = U256::from(2);
+        let initial_stake = DefaultMinStake::<Test>::get() * 10;
+
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake);
+
+        for _ in 0..3 {
+            let alpha1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey, &coldkey, netuid1,
+            );
+            if alpha1 > 0 {
+                assert_ok!(SubtensorModule::do_swap_stake(
+                    RuntimeOrigin::signed(coldkey),
+                    hotkey,
+                    netuid1,
+                    netuid2,
+                    alpha1
+                ));
+            }
+            let alpha2 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey, &coldkey, netuid2,
+            );
+            if alpha2 > 0 {
+                assert_ok!(SubtensorModule::do_swap_stake(
+                    RuntimeOrigin::signed(coldkey),
+                    hotkey,
+                    netuid2,
+                    netuid1,
+                    alpha2
+                ));
+            }
+        }
+
+        let final_stake_netuid1 =
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid1);
+        let final_stake_netuid2 =
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid2);
+        assert_abs_diff_eq!(
+            final_stake_netuid1,
+            initial_stake,
+            epsilon = initial_stake / 1000
+        );
+        assert_eq!(final_stake_netuid2, 0);
+    });
+}

From 845cba99e605bde195f3fb8d4d705131d466bbb0 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Wed, 22 Jan 2025 13:58:46 -0500
Subject: [PATCH 037/145] Make commitment pallet rate limit configurable via
 sudo

---
 pallets/commitments/src/lib.rs     | 27 +++++++++++++++++++++++++--
 pallets/commitments/src/tests.rs   |  2 +-
 pallets/commitments/src/weights.rs | 12 ++++++++++++
 runtime/src/lib.rs                 |  2 +-
 4 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs
index d5d132034..7e862a593 100644
--- a/pallets/commitments/src/lib.rs
+++ b/pallets/commitments/src/lib.rs
@@ -58,7 +58,7 @@ pub mod pallet {
 
         /// The rate limit for commitments
         #[pallet::constant]
-        type RateLimit: Get<BlockNumberFor<Self>>;
+        type DefaultRateLimit: Get<BlockNumberFor<Self>>;
     }
 
     #[pallet::event]
@@ -83,6 +83,16 @@ pub mod pallet {
         CommitmentSetRateLimitExceeded,
     }
 
+    #[pallet::type_value]
+    /// Default value for commitment rate limit.
+    pub fn DefaultRateLimit<T: Config>() -> BlockNumberFor<T> {
+        T::DefaultRateLimit::get()
+    }
+
+    /// The rate limit for commitments
+    #[pallet::storage]
+    pub type RateLimit<T> = StorageValue<_, BlockNumberFor<T>, ValueQuery, DefaultRateLimit<T>>;
+
     /// Identity data by account
     #[pallet::storage]
     #[pallet::getter(fn commitment_of)]
@@ -137,7 +147,7 @@ pub mod pallet {
             let cur_block = <frame_system::Pallet<T>>::block_number();
             if let Some(last_commit) = <LastCommitment<T>>::get(netuid, &who) {
                 ensure!(
-                    cur_block >= last_commit.saturating_add(T::RateLimit::get()),
+                    cur_block >= last_commit.saturating_add(RateLimit::<T>::get()),
                     Error::<T>::CommitmentSetRateLimitExceeded
                 );
             }
@@ -173,6 +183,19 @@ pub mod pallet {
 
             Ok(())
         }
+
+        /// Sudo-set the commitment rate limit
+        #[pallet::call_index(1)]
+        #[pallet::weight((
+			T::WeightInfo::set_rate_limit(),
+			DispatchClass::Operational,
+			Pays::No
+		))]
+        pub fn set_rate_limit(origin: OriginFor<T>, rate_limit_blocks: u32) -> DispatchResult {
+            ensure_root(origin)?;
+            RateLimit::<T>::set(rate_limit_blocks.into());
+            Ok(())
+        }
     }
 }
 
diff --git a/pallets/commitments/src/tests.rs b/pallets/commitments/src/tests.rs
index 036cb5d83..15675d8ad 100644
--- a/pallets/commitments/src/tests.rs
+++ b/pallets/commitments/src/tests.rs
@@ -86,7 +86,7 @@ impl pallet_commitments::Config for Test {
     type CanCommit = ();
     type FieldDeposit = frame_support::traits::ConstU64<0>;
     type InitialDeposit = frame_support::traits::ConstU64<0>;
-    type RateLimit = frame_support::traits::ConstU64<0>;
+    type DefaultRateLimit = frame_support::traits::ConstU64<0>;
 }
 
 // // Build genesis storage according to the mock runtime.
diff --git a/pallets/commitments/src/weights.rs b/pallets/commitments/src/weights.rs
index 5e58b6873..b91017e05 100644
--- a/pallets/commitments/src/weights.rs
+++ b/pallets/commitments/src/weights.rs
@@ -30,6 +30,7 @@ use core::marker::PhantomData;
 /// Weight functions needed for `pallet_commitments`.
 pub trait WeightInfo {
 	fn set_commitment() -> Weight;
+	fn set_rate_limit() -> Weight;
 }
 
 /// Weights for `pallet_commitments` using the Substrate node and recommended hardware.
@@ -48,6 +49,11 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 			.saturating_add(T::DbWeight::get().reads(2_u64))
 			.saturating_add(T::DbWeight::get().writes(2_u64))
 	}
+	/// Sudo setting rate limit for commitments
+	fn set_rate_limit() -> Weight {
+		Weight::from_parts(10_000_000, 2000)
+			.saturating_add(RocksDbWeight::get().reads(1_u64))
+	}	
 }
 
 // For backwards compatibility and tests.
@@ -65,4 +71,10 @@ impl WeightInfo for () {
 			.saturating_add(RocksDbWeight::get().reads(2_u64))
 			.saturating_add(RocksDbWeight::get().writes(2_u64))
 	}
+
+	/// Sudo setting rate limit for commitments
+	fn set_rate_limit() -> Weight {
+		Weight::from_parts(10_000_000, 2000)
+			.saturating_add(RocksDbWeight::get().reads(1_u64))
+	}	
 }
\ No newline at end of file
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 5c3688a51..36a879e48 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -974,7 +974,7 @@ impl pallet_commitments::Config for Runtime {
     type MaxFields = MaxCommitFields;
     type InitialDeposit = CommitmentInitialDeposit;
     type FieldDeposit = CommitmentFieldDeposit;
-    type RateLimit = CommitmentRateLimit;
+    type DefaultRateLimit = CommitmentRateLimit;
 }
 
 #[cfg(not(feature = "fast-blocks"))]

From feddc59ca17e16699239a884827c874e4896291f Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Wed, 22 Jan 2025 15:11:44 -0500
Subject: [PATCH 038/145] remove root divs before alpha payout

---
 pallets/subtensor/src/coinbase/run_coinbase.rs | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index e86c07c24..ddb045556 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -472,6 +472,15 @@ impl<T: Config> Pallet<T> {
                     rem_divs_j
                 );
 
+                let possible_root_divs = *root_alpha_divs.get(hotkey_j).unwrap_or(&0);
+                let alpha_divs: I96F32 =
+                    rem_divs_j.saturating_sub(I96F32::from_num(possible_root_divs));
+                log::debug!(
+                    "Removed root divs for hotkey {:?}: {:?}",
+                    hotkey_j,
+                    possible_root_divs
+                );
+
                 // Distribute validator take.
                 Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
                     hotkey_j,
@@ -490,18 +499,20 @@ impl<T: Config> Pallet<T> {
                 Self::increase_stake_for_hotkey_on_subnet(
                     hotkey_j,
                     netuid,
-                    rem_divs_j.to_num::<u64>(),
+                    alpha_divs.to_num::<u64>(),
                 );
                 log::debug!(
                     "Distributed alpha dividends for hotkey {:?} on netuid {:?}: {:?}",
                     hotkey_j,
                     netuid,
-                    rem_divs_j.to_num::<u64>()
+                    alpha_divs.to_num::<u64>()
                 );
 
                 // Record dividends for this hotkey on this subnet.
                 AlphaDividendsPerSubnet::<T>::mutate(netuid, hotkey_j.clone(), |divs| {
-                    *divs = divs.saturating_add(*divs_j);
+                    *divs = divs
+                        .saturating_add(alpha_divs.to_num::<u64>())
+                        .saturating_add(validator_take.to_num::<u64>());
                 });
                 log::debug!(
                     "Recorded dividends for hotkey {:?} on netuid {:?}: {:?}",

From 9dc0ecec678e7aa7b80917bade2b0aa1768010bd Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Wed, 22 Jan 2025 14:46:27 -0500
Subject: [PATCH 039/145] charge fee for swap and add for tests

---
 pallets/subtensor/src/staking/move_stake.rs |  5 +++--
 pallets/subtensor/src/tests/move_stake.rs   | 16 ++++++++--------
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 38a783b25..fff688084 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -288,8 +288,9 @@ impl<T: Config> Pallet<T> {
         );
 
         // 6. Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
+        let fee = DefaultMinStake::<T>::get().saturating_div(2);
         let tao_unstaked =
-            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount);
+            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount, fee);
 
         // 7. Check that the unstaked amount is above the minimum stake threshold.
         ensure!(
@@ -298,7 +299,7 @@ impl<T: Config> Pallet<T> {
         );
 
         // 8. Stake the unstaked amount into the destination subnet, using the same coldkey/hotkey.
-        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked);
+        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked, fee);
 
         // 9. Emit an event for logging.
         log::info!(
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 150fa1201..04f79f3f9 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -1085,7 +1085,7 @@ fn test_do_swap_success() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0);
         let alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey,
             &coldkey,
@@ -1180,7 +1180,7 @@ fn test_do_swap_insufficient_stake() {
         let attempted_swap = stake_amount * 2;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, stake_amount, 0);
 
         assert_noop!(
             SubtensorModule::do_swap_stake(
@@ -1209,7 +1209,7 @@ fn test_do_swap_wrong_origin() {
         let stake_amount = 100_000;
 
         SubtensorModule::create_account_if_non_existent(&real_coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &real_coldkey, netuid1, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &real_coldkey, netuid1, stake_amount, 0);
 
         assert_noop!(
             SubtensorModule::do_swap_stake(
@@ -1237,7 +1237,7 @@ fn test_do_swap_minimum_stake_check() {
         let swap_amount = 1;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, total_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, total_stake, 0);
 
         assert_err!(
             SubtensorModule::do_swap_stake(
@@ -1264,7 +1264,7 @@ fn test_do_swap_same_subnet() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount, 0);
 
         let alpha_before =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
@@ -1296,7 +1296,7 @@ fn test_do_swap_partial_stake() {
         let total_stake = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake, 0);
 
         let swap_amount = total_stake / 2;
         assert_ok!(SubtensorModule::do_swap_stake(
@@ -1341,7 +1341,7 @@ fn test_do_swap_storage_updates() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0);
 
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey,
@@ -1390,7 +1390,7 @@ fn test_do_swap_multiple_times() {
         let initial_stake = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake, 0);
 
         for _ in 0..3 {
             let alpha1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(

From 6afea18909604a1b8956de7a1b54f2b17e266520 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Wed, 22 Jan 2025 15:55:35 -0500
Subject: [PATCH 040/145] calc root prop using parent key

---
 .../subtensor/src/coinbase/run_coinbase.rs    | 46 +++++++++----------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index ddb045556..7e73ea8eb 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -356,29 +356,6 @@ impl<T: Config> Pallet<T> {
 
         // Calculate the validator take and root alpha divs using the alpha divs.
         for (hotkey, dividend_tuples) in dividends_to_distribute.iter() {
-            // Get the local alpha and root alpha.
-            let hotkey_tao: I96F32 = I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(
-                hotkey,
-                Self::get_root_netuid(),
-            ));
-            let hotkey_tao_as_alpha: I96F32 = hotkey_tao.saturating_mul(Self::get_tao_weight());
-            let hotkey_alpha =
-                I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid));
-            log::debug!("Hotkey tao for hotkey {:?} on root netuid: {:?}, hotkey tao as alpha: {:?}, hotkey alpha: {:?}", hotkey, hotkey_tao, hotkey_tao_as_alpha, hotkey_alpha);
-
-            // Compute alpha and root proportions.
-            let alpha_prop: I96F32 = hotkey_alpha
-                .checked_div(hotkey_alpha.saturating_add(hotkey_tao_as_alpha))
-                .unwrap_or(I96F32::from_num(0.0));
-            let root_prop: I96F32 = hotkey_tao_as_alpha
-                .checked_div(hotkey_alpha.saturating_add(hotkey_tao_as_alpha))
-                .unwrap_or(I96F32::from_num(0.0));
-            log::debug!(
-                "Alpha proportion: {:?}, root proportion: {:?}",
-                alpha_prop,
-                root_prop
-            );
-
             // Calculate the dividends to hotkeys based on the local vs root proportion.
             for (hotkey_j, divs_j) in dividend_tuples.iter() {
                 log::debug!(
@@ -388,6 +365,29 @@ impl<T: Config> Pallet<T> {
                     *divs_j
                 );
 
+                // Get the local alpha and root alpha.
+                let hotkey_tao: I96F32 = I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(
+                    hotkey_j,
+                    Self::get_root_netuid(),
+                ));
+                let hotkey_tao_as_alpha: I96F32 = hotkey_tao.saturating_mul(Self::get_tao_weight());
+                let hotkey_alpha =
+                    I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey_j, netuid));
+                log::debug!("Hotkey tao for hotkey {:?} on root netuid: {:?}, hotkey tao as alpha: {:?}, hotkey alpha: {:?}", hotkey_j, hotkey_tao, hotkey_tao_as_alpha, hotkey_alpha);
+
+                // Compute alpha and root proportions.
+                let alpha_prop: I96F32 = hotkey_alpha
+                    .checked_div(hotkey_alpha.saturating_add(hotkey_tao_as_alpha))
+                    .unwrap_or(I96F32::from_num(0.0));
+                let root_prop: I96F32 = hotkey_tao_as_alpha
+                    .checked_div(hotkey_alpha.saturating_add(hotkey_tao_as_alpha))
+                    .unwrap_or(I96F32::from_num(0.0));
+                log::debug!(
+                    "Alpha proportion: {:?}, root proportion: {:?}",
+                    alpha_prop,
+                    root_prop
+                );
+
                 // Remove the hotkey take straight off the top.
                 let take_prop: I96F32 = I96F32::from_num(Self::get_hotkey_take(hotkey_j))
                     .checked_div(I96F32::from_num(u16::MAX))

From 51bb6a3c2f5aa7d6ffc4ea2c2fa937c039dd6c8e Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Wed, 22 Jan 2025 15:59:18 -0500
Subject: [PATCH 041/145] Separate defaults for tx fee from min stake. Make min
 stake work like ED for stakes.

---
 pallets/subtensor/src/lib.rs                  | 20 ++++--
 pallets/subtensor/src/staking/add_stake.rs    | 10 ++-
 pallets/subtensor/src/staking/move_stake.rs   | 15 +++--
 pallets/subtensor/src/staking/remove_stake.rs |  6 +-
 pallets/subtensor/src/tests/epoch.rs          |  4 +-
 pallets/subtensor/src/tests/move_stake.rs     | 67 +++++++++++--------
 pallets/subtensor/src/tests/senate.rs         | 20 +++---
 pallets/subtensor/src/tests/staking.rs        | 26 +++----
 pallets/subtensor/src/tests/swap_coldkey.rs   | 14 ++--
 pallets/subtensor/src/tests/swap_hotkey.rs    |  2 +-
 pallets/subtensor/src/tests/weights.rs        |  8 +--
 11 files changed, 108 insertions(+), 84 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 6ecb69c87..1a3f0e27b 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -702,11 +702,17 @@ pub mod pallet {
     #[pallet::type_value]
     /// Default minimum stake.
     /// 500k rao matches $0.25 at $500/TAO
-    /// Also used as staking fee
     pub fn DefaultMinStake<T: Config>() -> u64 {
         500_000
     }
 
+    #[pallet::type_value]
+    /// Default staking fee.
+    /// 500k rao matches $0.25 at $500/TAO
+    pub fn DefaultStakingFee<T: Config>() -> u64 {
+        500_000
+    }
+
     #[pallet::type_value]
     /// Default unicode vector for tau symbol.
     pub fn DefaultUnicodeVecU8<T: Config>() -> Vec<u8> {
@@ -1545,6 +1551,7 @@ pub enum CallType {
 pub enum CustomTransactionError {
     ColdkeyInSwapSchedule,
     StakeAmountTooLow,
+    BalanceTooLow,
 }
 
 impl From<CustomTransactionError> for u8 {
@@ -1552,6 +1559,7 @@ impl From<CustomTransactionError> for u8 {
         match variant {
             CustomTransactionError::ColdkeyInSwapSchedule => 0,
             CustomTransactionError::StakeAmountTooLow => 1,
+            CustomTransactionError::BalanceTooLow => 2,
         }
     }
 }
@@ -1704,7 +1712,7 @@ where
             Some(Call::add_stake {
                 hotkey: _,
                 netuid: _,
-                amount_staked,
+                amount,
             }) => {
                 // Check that amount parameter is at least the min stake
                 // also check the coldkey balance
@@ -1713,12 +1721,14 @@ where
                 >>::reducible_balance(
                     who, Preservation::Expendable, Fortitude::Polite
                 );
+                let min_amount =
+                    DefaultMinStake::<T>::get().saturating_add(DefaultStakingFee::<T>::get());
 
-                if (*amount_staked < DefaultMinStake::<T>::get())
-                    || (coldkey_balance < DefaultMinStake::<T>::get())
-                {
+                if *amount < min_amount {
                     InvalidTransaction::Custom(CustomTransactionError::StakeAmountTooLow.into())
                         .into()
+                } else if coldkey_balance < min_amount {
+                    InvalidTransaction::Custom(CustomTransactionError::BalanceTooLow.into()).into()
                 } else {
                     Ok(ValidTransaction {
                         priority: Self::get_priority_vanilla(),
diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index 66b337b3d..763899d6d 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -62,11 +62,9 @@ impl<T: Config> Pallet<T> {
             Error::<T>::HotKeyAccountNotExists
         );
 
-        // Ensure stake_to_be_added is at least DefaultMinStake
-        ensure!(
-            stake_to_be_added >= DefaultMinStake::<T>::get(),
-            Error::<T>::AmountTooLow
-        );
+        // Ensure stake_to_be_added is at least DefaultMinStake plus fee
+        let min_amount = DefaultMinStake::<T>::get().saturating_add(DefaultStakingFee::<T>::get());
+        ensure!(stake_to_be_added >= min_amount, Error::<T>::AmountTooLow);
 
         // 5. Ensure the remove operation from the coldkey is a success.
         let tao_staked: u64 =
@@ -74,7 +72,7 @@ impl<T: Config> Pallet<T> {
 
         // 6. Swap the stake into alpha on the subnet and increase counters.
         // Emit the staking event.
-        let fee = DefaultMinStake::<T>::get();
+        let fee = DefaultStakingFee::<T>::get();
         Self::stake_into_subnet(&hotkey, &coldkey, netuid, tao_staked, fee);
 
         // Ok and return.
diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 38a783b25..9c4ffabff 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -68,7 +68,7 @@ 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 fee = DefaultStakingFee::<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(),
@@ -79,7 +79,7 @@ impl<T: Config> Pallet<T> {
 
         // Ensure origin_tao is at least DefaultMinStake
         ensure!(
-            origin_tao >= DefaultMinStake::<T>::get(),
+            origin_tao.saturating_sub(fee) >= DefaultMinStake::<T>::get(),
             Error::<T>::AmountTooLow
         );
 
@@ -181,13 +181,13 @@ impl<T: Config> Pallet<T> {
         );
 
         // 6. Unstake from the origin coldkey; this returns an amount of TAO.
-        let fee = DefaultMinStake::<T>::get().saturating_div(2);
+        let fee = DefaultStakingFee::<T>::get().saturating_div(2);
         let origin_tao =
             Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount, fee);
 
         // 7. Ensure the returned TAO meets a minimum stake requirement (if required).
         ensure!(
-            origin_tao >= DefaultMinStake::<T>::get(),
+            origin_tao.saturating_sub(fee) >= DefaultMinStake::<T>::get(),
             Error::<T>::AmountTooLow
         );
 
@@ -288,17 +288,18 @@ impl<T: Config> Pallet<T> {
         );
 
         // 6. Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
+        let fee = DefaultStakingFee::<T>::get().saturating_div(2);
         let tao_unstaked =
-            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount);
+            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount, fee);
 
         // 7. Check that the unstaked amount is above the minimum stake threshold.
         ensure!(
-            tao_unstaked >= DefaultMinStake::<T>::get(),
+            tao_unstaked.saturating_sub(fee) >= DefaultMinStake::<T>::get(),
             Error::<T>::AmountTooLow
         );
 
         // 8. Stake the unstaked amount into the destination subnet, using the same coldkey/hotkey.
-        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked);
+        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked, fee);
 
         // 9. Emit an event for logging.
         log::info!(
diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index 5b3ed3390..fd6fe8191 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -66,7 +66,7 @@ impl<T: Config> Pallet<T> {
         );
 
         // 6. Swap the alpba to tao and update counters for this subnet.
-        let fee = DefaultMinStake::<T>::get();
+        let fee = DefaultStakingFee::<T>::get();
         let tao_unstaked: u64 =
             Self::unstake_from_subnet(&hotkey, &coldkey, netuid, alpha_unstaked, fee);
 
@@ -117,7 +117,7 @@ impl<T: Config> Pallet<T> {
         origin: T::RuntimeOrigin,
         hotkey: T::AccountId,
     ) -> dispatch::DispatchResult {
-        let fee = DefaultMinStake::<T>::get();
+        let fee = DefaultStakingFee::<T>::get();
 
         // 1. We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
         let coldkey = ensure_signed(origin)?;
@@ -185,7 +185,7 @@ impl<T: Config> Pallet<T> {
         origin: T::RuntimeOrigin,
         hotkey: T::AccountId,
     ) -> dispatch::DispatchResult {
-        let fee = DefaultMinStake::<T>::get();
+        let fee = DefaultStakingFee::<T>::get();
 
         // 1. We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
         let coldkey = ensure_signed(origin)?;
diff --git a/pallets/subtensor/src/tests/epoch.rs b/pallets/subtensor/src/tests/epoch.rs
index 43ac6b98c..1d3bf8fc8 100644
--- a/pallets/subtensor/src/tests/epoch.rs
+++ b/pallets/subtensor/src/tests/epoch.rs
@@ -1505,7 +1505,7 @@ fn test_set_alpha_disabled() {
             signer.clone(),
             hotkey,
             netuid,
-            DefaultMinStake::<Test>::get()
+            DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get()
         ));
         // Only owner can set alpha values
         assert_ok!(SubtensorModule::register_network(signer.clone(), hotkey));
@@ -2600,7 +2600,7 @@ fn test_get_set_alpha() {
             signer.clone(),
             hotkey,
             netuid,
-            DefaultMinStake::<Test>::get()
+            DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get()
         ));
 
         assert_ok!(SubtensorModule::do_set_alpha_values(
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 150fa1201..4061f07e7 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -17,7 +17,7 @@ fn test_do_move_success() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
@@ -74,7 +74,7 @@ fn test_do_move_different_subnets() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake and subnets
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
@@ -288,7 +288,7 @@ fn test_do_move_all_stake() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
@@ -341,7 +341,7 @@ fn test_do_move_half_stake() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
@@ -398,7 +398,7 @@ fn test_do_move_partial_stake() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let total_stake = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, total_stake, fee);
@@ -454,7 +454,7 @@ fn test_do_move_multiple_times() {
         let hotkey1 = U256::from(2);
         let hotkey2 = U256::from(3);
         let initial_stake = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey1);
@@ -570,7 +570,7 @@ fn test_do_move_same_hotkey() {
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
@@ -610,7 +610,7 @@ fn test_do_move_event_emission() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
@@ -662,7 +662,7 @@ fn test_do_move_storage_updates() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Set up initial stake
         SubtensorModule::stake_into_subnet(
@@ -775,7 +775,7 @@ fn test_moving_too_little_fails() {
         let hotkey_account_id = U256::from(533453);
         let coldkey_account_id = U256::from(55453);
         let amount = DefaultMinStake::<Test>::get();
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
@@ -813,7 +813,7 @@ fn test_do_transfer_success() {
         let subnet_owner_coldkey = U256::from(1001);
         let subnet_owner_hotkey = U256::from(1002);
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // 2. Define the origin coldkey, destination coldkey, and hotkey to be used.
         let origin_coldkey = U256::from(1);
@@ -952,7 +952,7 @@ fn test_do_transfer_wrong_origin() {
         let destination_coldkey = U256::from(2);
         let hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
         SubtensorModule::add_balance_to_coldkey_account(&origin_coldkey, stake_amount + fee);
@@ -1015,7 +1015,7 @@ fn test_do_transfer_different_subnets() {
         let destination_coldkey = U256::from(2);
         let hotkey = U256::from(3);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // 3. Create accounts if needed.
         SubtensorModule::create_account_if_non_existent(&origin_coldkey, &hotkey);
@@ -1083,9 +1083,10 @@ fn test_do_swap_success() {
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultStakingFee::<Test>::get();
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0);
         let alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey,
             &coldkey,
@@ -1114,7 +1115,11 @@ fn test_do_swap_success() {
             &coldkey,
             destination_netuid,
         );
-        assert_abs_diff_eq!(alpha_after, stake_amount, epsilon = stake_amount / 1000);
+        assert_abs_diff_eq!(
+            alpha_after,
+            stake_amount - fee,
+            epsilon = stake_amount / 1000
+        );
     });
 }
 
@@ -1180,7 +1185,7 @@ fn test_do_swap_insufficient_stake() {
         let attempted_swap = stake_amount * 2;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, stake_amount, 0);
 
         assert_noop!(
             SubtensorModule::do_swap_stake(
@@ -1209,7 +1214,7 @@ fn test_do_swap_wrong_origin() {
         let stake_amount = 100_000;
 
         SubtensorModule::create_account_if_non_existent(&real_coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &real_coldkey, netuid1, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &real_coldkey, netuid1, stake_amount, 0);
 
         assert_noop!(
             SubtensorModule::do_swap_stake(
@@ -1237,7 +1242,7 @@ fn test_do_swap_minimum_stake_check() {
         let swap_amount = 1;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, total_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, total_stake, 0);
 
         assert_err!(
             SubtensorModule::do_swap_stake(
@@ -1262,9 +1267,10 @@ fn test_do_swap_same_subnet() {
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultStakingFee::<Test>::get();
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount, 0);
 
         let alpha_before =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
@@ -1279,7 +1285,11 @@ fn test_do_swap_same_subnet() {
 
         let alpha_after =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
-        assert_abs_diff_eq!(alpha_after, alpha_before, epsilon = 5);
+        assert_abs_diff_eq!(
+            alpha_after,
+            alpha_before - fee,
+            epsilon = alpha_after / 1000
+        );
     });
 }
 
@@ -1294,9 +1304,10 @@ fn test_do_swap_partial_stake() {
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let total_stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultStakingFee::<Test>::get();
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake, 0);
 
         let swap_amount = total_stake / 2;
         assert_ok!(SubtensorModule::do_swap_stake(
@@ -1322,7 +1333,7 @@ fn test_do_swap_partial_stake() {
                 &coldkey,
                 destination_netuid
             ),
-            swap_amount,
+            swap_amount - fee,
             epsilon = total_stake / 1000
         );
     });
@@ -1339,9 +1350,10 @@ fn test_do_swap_storage_updates() {
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultStakingFee::<Test>::get();
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0);
 
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey,
@@ -1371,8 +1383,8 @@ fn test_do_swap_storage_updates() {
                 &coldkey,
                 destination_netuid
             ),
-            alpha,
-            epsilon = 5
+            alpha - fee,
+            epsilon = alpha / 1000
         );
     });
 }
@@ -1388,9 +1400,10 @@ fn test_do_swap_multiple_times() {
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let initial_stake = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultStakingFee::<Test>::get();
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake, 0);
 
         for _ in 0..3 {
             let alpha1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -1425,7 +1438,7 @@ fn test_do_swap_multiple_times() {
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid2);
         assert_abs_diff_eq!(
             final_stake_netuid1,
-            initial_stake,
+            initial_stake - 6 * fee,
             epsilon = initial_stake / 1000
         );
         assert_eq!(final_stake_netuid2, 0);
diff --git a/pallets/subtensor/src/tests/senate.rs b/pallets/subtensor/src/tests/senate.rs
index 01dfc17d7..17f478b9c 100644
--- a/pallets/subtensor/src/tests/senate.rs
+++ b/pallets/subtensor/src/tests/senate.rs
@@ -67,7 +67,7 @@ fn test_senate_join_works() {
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
         let stake = DefaultMinStake::<Test>::get() * 100;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -141,7 +141,7 @@ fn test_senate_vote_works() {
         let hotkey_account_id = U256::from(6);
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -315,7 +315,7 @@ fn test_senate_leave_works() {
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
         let stake = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -390,7 +390,7 @@ fn test_senate_leave_vote_removal() {
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
         let coldkey_origin = <<Test as Config>::RuntimeOrigin>::signed(coldkey_account_id);
         let stake = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -532,7 +532,7 @@ fn test_senate_not_leave_when_stake_removed() {
         let hotkey_account_id = U256::from(6);
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         SubtensorModule::set_burn(netuid, burn_cost);
@@ -691,10 +691,11 @@ fn test_adjust_senate_events() {
         let burn_cost = 1000;
         let coldkey_account_id = U256::from(667);
         let root_netuid = SubtensorModule::get_root_netuid();
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let max_senate_size: u16 = SenateMaxMembers::get() as u16;
-        let stake_threshold: u64 = DefaultMinStake::<Test>::get(); // Give this much to every senator
+        let stake_threshold: u64 =
+            DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get(); // Give this much to every senator
 
         // We will be registering MaxMembers hotkeys and two more to try a replace
         let balance_to_add = DefaultMinStake::<Test>::get() * 10
@@ -761,13 +762,14 @@ fn test_adjust_senate_events() {
                 coldkey_account_id
             );
             // Add/delegate enough stake to join the senate
+            // +1 to be above hotkey_account_id
             assert_ok!(SubtensorModule::add_stake(
                 <<Test as Config>::RuntimeOrigin>::signed(coldkey_account_id),
                 new_hotkey_account_id,
                 netuid,
                 stake_threshold + 1 + i as u64 // Increasing with i to make them ordered
-            )); // +1 to be above hotkey_account_id
-                // Join senate
+            ));
+            // Join senate
             assert_ok!(SubtensorModule::root_register(
                 <<Test as Config>::RuntimeOrigin>::signed(coldkey_account_id),
                 new_hotkey_account_id
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index ef5ac5f4a..f57fb4ebe 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -42,7 +42,7 @@ fn test_add_stake_ok_no_emission() {
         let hotkey_account_id = U256::from(533453);
         let coldkey_account_id = U256::from(55453);
         let amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
@@ -351,7 +351,7 @@ fn test_remove_stake_ok_no_emission() {
         let coldkey_account_id = U256::from(4343);
         let hotkey_account_id = U256::from(4968585);
         let amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);
 
@@ -508,7 +508,7 @@ fn test_remove_stake_total_balance_no_change() {
         let hotkey_account_id = U256::from(571337);
         let coldkey_account_id = U256::from(71337);
         let amount = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);
 
@@ -567,7 +567,7 @@ fn test_remove_stake_total_issuance_no_change() {
         let coldkey_account_id = U256::from(81337);
         let amount = DefaultMinStake::<Test>::get() * 10;
         let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
         register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);
 
         // Give it some $$$ in his coldkey balance
@@ -1609,7 +1609,7 @@ fn test_get_total_delegated_stake_after_unstaking() {
         let unstake_amount = DefaultMinStake::<Test>::get() * 5;
         let existential_deposit = ExistentialDeposit::get();
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         register_ok_neuron(netuid, delegate_hotkey, delegate_coldkey, 0);
 
@@ -1697,7 +1697,7 @@ fn test_get_total_delegated_stake_single_delegator() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10 - 1;
         let existential_deposit = ExistentialDeposit::get();
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         register_ok_neuron(netuid, delegate_hotkey, delegate_coldkey, 0);
 
@@ -1755,7 +1755,7 @@ fn test_get_alpha_share_stake_multiple_delegators() {
         let existential_deposit = 2;
         let stake1 = DefaultMinStake::<Test>::get() * 10;
         let stake2 = DefaultMinStake::<Test>::get() * 10 - 1;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         register_ok_neuron(netuid, hotkey1, coldkey1, 0);
@@ -1814,7 +1814,7 @@ fn test_get_total_delegated_stake_exclude_owner_stake() {
         let delegator = U256::from(3);
         let owner_stake = DefaultMinStake::<Test>::get() * 10;
         let delegator_stake = DefaultMinStake::<Test>::get() * 10 - 1;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let netuid = add_dynamic_network(&delegate_hotkey, &delegate_coldkey);
 
@@ -1975,7 +1975,7 @@ fn test_add_stake_fee_goes_to_subnet_tao() {
         let coldkey = U256::from(3);
         let existential_deposit = ExistentialDeposit::get();
         let tao_to_stake = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
@@ -2021,7 +2021,7 @@ fn test_remove_stake_fee_goes_to_subnet_tao() {
         let hotkey = U256::from(2);
         let coldkey = U256::from(3);
         let tao_to_stake = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
@@ -2074,7 +2074,7 @@ fn test_stake_below_min_validate() {
         let subnet_owner_hotkey = U256::from(1002);
         let hotkey = U256::from(2);
         let coldkey = U256::from(3);
-        let amount_staked = DefaultMinStake::<Test>::get() - 1;
+        let amount_staked = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get() - 1;
 
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
@@ -2101,7 +2101,7 @@ fn test_stake_below_min_validate() {
         );
 
         // Increase the stake to be equal to the minimum, but leave the balance low
-        let amount_staked = DefaultMinStake::<Test>::get();
+        let amount_staked = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get();
         let call_2 = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
             hotkey,
             netuid,
@@ -2114,7 +2114,7 @@ fn test_stake_below_min_validate() {
         // Still doesn't pass
         assert_err!(
             result_low_balance,
-            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(1))
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(2))
         );
 
         // Increase the coldkey balance to match the minimum
diff --git a/pallets/subtensor/src/tests/swap_coldkey.rs b/pallets/subtensor/src/tests/swap_coldkey.rs
index 45b3ba6e6..f21af56cf 100644
--- a/pallets/subtensor/src/tests/swap_coldkey.rs
+++ b/pallets/subtensor/src/tests/swap_coldkey.rs
@@ -366,7 +366,7 @@ fn test_swap_with_max_values() {
         let netuid2 = 2u16;
         let stake = 10_000;
         let max_stake = 21_000_000_000_000_000; // 21 Million TAO; max possible balance.
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Add a network
         add_network(netuid, 1, 0);
@@ -435,7 +435,7 @@ fn test_swap_with_non_existent_new_coldkey() {
         let hotkey = U256::from(3);
         let stake = DefaultMinStake::<Test>::get() * 10;
         let netuid = 1u16;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey, old_coldkey, 1001000);
@@ -528,7 +528,7 @@ fn test_swap_concurrent_modifications() {
         let netuid: u16 = 1;
         let initial_stake = 1_000_000_000_000;
         let additional_stake = 500_000_000_000;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Setup initial state
         add_network(netuid, 1, 1);
@@ -806,7 +806,7 @@ fn test_swap_stake_for_coldkey() {
         let stake_amount3 = DefaultMinStake::<Test>::get() * 30;
         let total_stake = stake_amount1 + stake_amount2;
         let mut weight = Weight::zero();
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Setup initial state
         // Add a network
@@ -962,7 +962,7 @@ fn test_swap_staking_hotkeys_for_coldkey() {
         let stake_amount2 = DefaultMinStake::<Test>::get() * 20;
         let total_stake = stake_amount1 + stake_amount2;
         let mut weight = Weight::zero();
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Setup initial state
         // Add a network
@@ -1034,7 +1034,7 @@ fn test_swap_delegated_stake_for_coldkey() {
         let stake_amount2 = DefaultMinStake::<Test>::get() * 20;
         let mut weight = Weight::zero();
         let netuid = 1u16;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         // Setup initial state
         add_network(netuid, 1, 0);
@@ -1595,7 +1595,7 @@ fn test_coldkey_delegations() {
         let netuid = 0u16; // Stake to 0
         let netuid2 = 1u16; // Stake to 1
         let stake = DefaultMinStake::<Test>::get() * 10;
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         add_network(netuid, 13, 0); // root
         add_network(netuid2, 13, 0);
diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs
index d35dd6d56..b11901e73 100644
--- a/pallets/subtensor/src/tests/swap_hotkey.rs
+++ b/pallets/subtensor/src/tests/swap_hotkey.rs
@@ -66,7 +66,7 @@ fn test_swap_total_hotkey_stake() {
         let coldkey = U256::from(3);
         let amount = DefaultMinStake::<Test>::get() * 10;
         let mut weight = Weight::zero();
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         //add network
         let netuid: u16 = add_dynamic_network(&old_hotkey, &coldkey);
diff --git a/pallets/subtensor/src/tests/weights.rs b/pallets/subtensor/src/tests/weights.rs
index 10c829870..9a89ec76e 100644
--- a/pallets/subtensor/src/tests/weights.rs
+++ b/pallets/subtensor/src/tests/weights.rs
@@ -69,7 +69,7 @@ fn test_set_rootweights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1); // Add the hotkey field
         assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!!
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let who = coldkey; // The coldkey signs this transaction
 
@@ -184,7 +184,7 @@ fn test_commit_weights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1); // Add the hotkey field
         assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!!
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let who = hotkey; // The hotkey signs this transaction
 
@@ -294,7 +294,7 @@ fn test_set_weights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1);
         assert_ne!(hotkey, coldkey);
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let who = hotkey; // The hotkey signs this transaction
 
@@ -367,7 +367,7 @@ fn test_reveal_weights_validate() {
         let coldkey = U256::from(0);
         let hotkey: U256 = U256::from(1); // Add the hotkey field
         assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!!
-        let fee = DefaultMinStake::<Test>::get();
+        let fee = DefaultStakingFee::<Test>::get();
 
         let who = hotkey; // The hotkey signs this transaction
 

From 1a34d3318c7fb341bbb44477338c74c4883f0684 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 23 Jan 2025 09:49:36 +0800
Subject: [PATCH 042/145] refactor helper

---
 runtime/src/precompiles/mod.rs    | 11 +++++++++++
 runtime/src/precompiles/subnet.rs |  9 +++------
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index 3d2c19ae9..3c62d4b8c 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -232,3 +232,14 @@ fn dispatch(
         }),
     }
 }
+
+pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, Vec<u8>), PrecompileFailure> {
+    let mut pubkey = [0u8; 32];
+    pubkey.copy_from_slice(data.get_slice(0, 32)?);
+
+    Ok((
+        pubkey.into(),
+        data.get(4..)
+            .map_or_else(vec::Vec::new, |slice| slice.to_vec()),
+    ))
+}
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index c1827f77a..9c9fd859f 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -1,4 +1,4 @@
-use crate::precompiles::{dispatch, get_method_id, get_slice};
+use crate::precompiles::{dispatch, get_method_id, get_pubkey, get_slice};
 use crate::{Runtime, RuntimeCall};
 use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
 use sp_std::vec;
@@ -42,8 +42,7 @@ impl SubnetPrecompile {
     fn register_network(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
         let call = match data.len() {
             32 => {
-                let mut hotkey = [0u8; 32];
-                hotkey.copy_from_slice(get_slice(data, 0, 32)?);
+                let (hotkey, _) = get_pubkey(data);
 
                 RuntimeCall::SubtensorModule(
                     pallet_subtensor::Call::<Runtime>::register_network_with_identity {
@@ -85,11 +84,9 @@ impl SubnetPrecompile {
     fn parse_register_network_parameters(
         data: &[u8],
     ) -> Result<([u8; 32], vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {
-        let mut pubkey = [0u8; 32];
-        pubkey.copy_from_slice(get_slice(data, 0, 32)?);
+        let (pubkey, _) = get_pubkey(data)?;
 
         let mut buf = [0_u8; 4];
-
         // get all start point for three data items: name, repo and contact
         buf.copy_from_slice(get_slice(data, 60, 64)?);
         let subnet_name_start: usize = u32::from_be_bytes(buf) as usize;

From 130d09fb7d6fba6d89e38b73c788bdf8ffaa8b62 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Thu, 23 Jan 2025 10:01:32 -0500
Subject: [PATCH 043/145] refactor loops to be less confusing

---
 .../subtensor/src/coinbase/run_coinbase.rs    | 222 ++++++++++--------
 1 file changed, 123 insertions(+), 99 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index 7e73ea8eb..a8af8322c 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -308,7 +308,7 @@ impl<T: Config> Pallet<T> {
             owner_cut
         );
 
-        // Run the epoch() --> hotkey emission.
+        // === 1. Run the epoch() --> hotkey emission.
         // Needs to run on the full emission to the subnet.
         let hotkey_emission: Vec<(T::AccountId, u64, u64)> = Self::epoch(
             netuid,
@@ -320,15 +320,16 @@ impl<T: Config> Pallet<T> {
             hotkey_emission
         );
 
-        // Pay out the hotkey alpha dividends.
-        // First clear the netuid from HotkeyDividends
-        let mut total_root_alpha_divs: u64 = 0;
-        let mut root_alpha_divs: BTreeMap<T::AccountId, u64> = BTreeMap::new();
+        // === 2. Calculate the dividend distributions using the current stake.
+        // Clear maps
         let _ = AlphaDividendsPerSubnet::<T>::clear_prefix(netuid, u32::MAX, None);
+        let _ = TaoDividendsPerSubnet::<T>::clear_prefix(netuid, u32::MAX, None);
 
+        // Initialize maps for parent-child OR miner dividend distributions.
         let mut dividends_to_distribute: Vec<(T::AccountId, Vec<(T::AccountId, u64)>)> = Vec::new();
         let mut mining_incentive_to_distribute: Vec<(T::AccountId, u64)> = Vec::new();
 
+        // 2.1 --- Get dividend distribution from parent-child and miner distributions.
         for (hotkey, incentive, dividends) in hotkey_emission {
             log::debug!(
                 "Processing hotkey {:?} with incentive {:?} and dividends {:?}",
@@ -354,18 +355,23 @@ impl<T: Config> Pallet<T> {
             dividends_to_distribute.push((hotkey.clone(), dividend_tuples));
         }
 
-        // Calculate the validator take and root alpha divs using the alpha divs.
+        // Initialize maps for dividend calculations.
+        let mut root_divs: BTreeMap<T::AccountId, u64> = BTreeMap::new();
+        let mut alpha_divs: BTreeMap<T::AccountId, u64> = BTreeMap::new();
+        let mut validator_takes: BTreeMap<T::AccountId, u64> = BTreeMap::new();
+
+        // 2.2 --- Calculate the validator_take, alpha_divs, and root_divs using above dividend tuples.
         for (hotkey, dividend_tuples) in dividends_to_distribute.iter() {
-            // Calculate the dividends to hotkeys based on the local vs root proportion.
+            // Calculate the proportion of root vs alpha divs for each hotkey using their stake.
             for (hotkey_j, divs_j) in dividend_tuples.iter() {
                 log::debug!(
-                    "Processing dividend for hotkey {:?} to hotkey {:?}: {:?}",
+                    "Processing dividend for child-hotkey {:?} to parent-hotkey {:?}: {:?}",
                     hotkey,
                     hotkey_j,
                     *divs_j
                 );
 
-                // Get the local alpha and root alpha.
+                // 2.1 --- Get the local alpha and root alpha.
                 let hotkey_tao: I96F32 = I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(
                     hotkey_j,
                     Self::get_root_netuid(),
@@ -375,7 +381,7 @@ impl<T: Config> Pallet<T> {
                     I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey_j, netuid));
                 log::debug!("Hotkey tao for hotkey {:?} on root netuid: {:?}, hotkey tao as alpha: {:?}, hotkey alpha: {:?}", hotkey_j, hotkey_tao, hotkey_tao_as_alpha, hotkey_alpha);
 
-                // Compute alpha and root proportions.
+                // 2.2 --- Compute alpha and root proportions.
                 let alpha_prop: I96F32 = hotkey_alpha
                     .checked_div(hotkey_alpha.saturating_add(hotkey_tao_as_alpha))
                     .unwrap_or(I96F32::from_num(0.0));
@@ -388,7 +394,7 @@ impl<T: Config> Pallet<T> {
                     root_prop
                 );
 
-                // Remove the hotkey take straight off the top.
+                // 2.3.1 --- Remove the hotkey take from both alpha and root divs.
                 let take_prop: I96F32 = I96F32::from_num(Self::get_hotkey_take(hotkey_j))
                     .checked_div(I96F32::from_num(u16::MAX))
                     .unwrap_or(I96F32::from_num(0.0));
@@ -401,30 +407,57 @@ impl<T: Config> Pallet<T> {
                     rem_divs_j
                 );
 
-                // Compute root dividends
-                let root_divs: I96F32 = rem_divs_j.saturating_mul(root_prop);
+                // 2.3.2 --- Store the validator take.
+                validator_takes
+                    .entry(hotkey_j.clone())
+                    .and_modify(|e| *e = e.saturating_add(validator_take.to_num::<u64>()))
+                    .or_insert(validator_take.to_num::<u64>());
+                log::debug!(
+                    "Stored validator take for hotkey {:?}: {:?}",
+                    hotkey_j,
+                    validator_take.to_num::<u64>()
+                );
+
+                // 2.4.1 --- Compute root dividends
+                let root_divs_j: I96F32 = rem_divs_j.saturating_mul(root_prop);
+                // 2.4.2 --- Compute alpha dividends
+                let alpha_divs_j: I96F32 = rem_divs_j.saturating_sub(root_divs_j);
                 log::debug!(
                     "Alpha dividends: {:?}, root dividends: {:?}",
-                    rem_divs_j,
-                    root_divs
+                    alpha_divs_j,
+                    root_divs_j
                 );
 
-                // Store the root-alpha divs under hotkey_j
-                root_alpha_divs
+                // 2.4.3 --- Store the root divs under hotkey_j
+                root_divs
                     .entry(hotkey_j.clone())
-                    .and_modify(|e| *e = e.saturating_add(root_divs.to_num::<u64>()))
-                    .or_insert(root_divs.to_num::<u64>());
-                total_root_alpha_divs =
-                    total_root_alpha_divs.saturating_add(root_divs.to_num::<u64>());
+                    .and_modify(|e| *e = e.saturating_add(root_divs_j.to_num::<u64>()))
+                    .or_insert(root_divs_j.to_num::<u64>());
                 log::debug!(
                     "Stored root alpha dividends for hotkey {:?}: {:?}",
                     hotkey_j,
-                    root_divs.to_num::<u64>()
+                    root_divs_j.to_num::<u64>()
+                );
+
+                // 2.4.4 --- Store the alpha dividends
+                alpha_divs
+                    .entry(hotkey_j.clone())
+                    .and_modify(|e| *e = e.saturating_add(alpha_divs_j.to_num::<u64>()))
+                    .or_insert(alpha_divs_j.to_num::<u64>());
+                log::debug!(
+                    "Stored alpha dividends for hotkey {:?}: {:?}",
+                    hotkey_j,
+                    alpha_divs_j.to_num::<u64>()
                 );
             }
         }
 
-        // Check for existence of owner cold/hot pair and distribute emission directly to them.
+        let total_root_divs: u64 = root_divs.values().sum();
+
+        // === 3. Distribute the dividends to the hotkeys.
+
+        // 3.1 --- Distribute owner cut.
+        // Check for existence of subnet owner cold/hot pair and distribute emission directly to them.
         if let Ok(owner_coldkey) = SubnetOwner::<T>::try_get(netuid) {
             if let Ok(owner_hotkey) = SubnetOwnerHotkey::<T>::try_get(netuid) {
                 // Increase stake for both coldkey and hotkey on the subnet
@@ -438,98 +471,82 @@ impl<T: Config> Pallet<T> {
             }
         }
 
-        // Distribute mining incentive.
-        for (hotkey, incentive) in mining_incentive_to_distribute {
+        // 3.2 --- Distribute mining incentive.
+        for (miner_j, incentive) in mining_incentive_to_distribute {
             // Distribute mining incentive immediately.
             Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
-                &hotkey.clone(),
-                &Owner::<T>::get(hotkey.clone()),
+                &miner_j.clone(),
+                &Owner::<T>::get(miner_j.clone()),
                 netuid,
                 incentive,
             );
             log::debug!(
                 "Distributed mining incentive for hotkey {:?} on netuid {:?}: {:?}",
-                hotkey,
+                miner_j,
                 netuid,
                 incentive
             );
         }
 
-        // Distribute validator take and alpha-dividends.
-        for (_hotkey, dividend_tuples) in dividends_to_distribute.iter() {
-            // Pay out dividends to hotkeys based on the local vs root proportion.
-            for (hotkey_j, divs_j) in dividend_tuples.iter() {
-                // Remove the hotkey take straight off the top.
-                let take_prop: I96F32 = I96F32::from_num(Self::get_hotkey_take(hotkey_j))
-                    .checked_div(I96F32::from_num(u16::MAX))
-                    .unwrap_or(I96F32::from_num(0.0));
-                let validator_take: I96F32 = take_prop.saturating_mul(I96F32::from_num(*divs_j));
-                let rem_divs_j: I96F32 = I96F32::from_num(*divs_j).saturating_sub(validator_take);
-                log::debug!(
-                    "Validator take for hotkey {:?}: {:?}, remaining dividends: {:?}",
-                    hotkey_j,
-                    validator_take,
-                    rem_divs_j
-                );
-
-                let possible_root_divs = *root_alpha_divs.get(hotkey_j).unwrap_or(&0);
-                let alpha_divs: I96F32 =
-                    rem_divs_j.saturating_sub(I96F32::from_num(possible_root_divs));
-                log::debug!(
-                    "Removed root divs for hotkey {:?}: {:?}",
-                    hotkey_j,
-                    possible_root_divs
-                );
+        // 3.3 --- Distribute validator take
+        for (validator_j, validator_take) in validator_takes {
+            // 3.3.1 --- Distribute validator take to the validator.
+            Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
+                &validator_j.clone(),
+                &Owner::<T>::get(validator_j.clone()),
+                netuid,
+                validator_take,
+            );
+            log::debug!(
+                "Distributed validator take for hotkey {:?} on netuid {:?}: {:?}",
+                validator_j,
+                netuid,
+                validator_take
+            );
 
-                // Distribute validator take.
-                Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
-                    hotkey_j,
-                    &Owner::<T>::get(hotkey_j.clone()),
-                    netuid,
-                    validator_take.to_num::<u64>(),
-                );
-                log::debug!(
-                    "Distributed validator take for hotkey {:?} on netuid {:?}: {:?}",
-                    hotkey_j,
-                    netuid,
-                    validator_take.to_num::<u64>()
-                );
+            // 3.3.2 --- Record dividends for this validator on this subnet.
+            AlphaDividendsPerSubnet::<T>::mutate(netuid, validator_j.clone(), |divs| {
+                *divs = divs.saturating_add(validator_take);
+            });
+            log::debug!(
+                "Recorded dividends for validator {:?} on netuid {:?}: {:?}",
+                validator_j,
+                netuid,
+                validator_take
+            );
+        }
 
-                // Distribute the alpha divs to the hotkey.
-                Self::increase_stake_for_hotkey_on_subnet(
-                    hotkey_j,
-                    netuid,
-                    alpha_divs.to_num::<u64>(),
-                );
-                log::debug!(
-                    "Distributed alpha dividends for hotkey {:?} on netuid {:?}: {:?}",
-                    hotkey_j,
-                    netuid,
-                    alpha_divs.to_num::<u64>()
-                );
+        // 3.4 --- Distribute alpha divs
+        for (hotkey_j, alpha_divs_j) in alpha_divs {
+            // 3.4.1 --- Distribute alpha divs to the hotkey.
+            Self::increase_stake_for_hotkey_on_subnet(&hotkey_j.clone(), netuid, alpha_divs_j);
+            log::debug!(
+                "Distributed alpha dividends for hotkey {:?} on netuid {:?}: {:?}",
+                hotkey_j,
+                netuid,
+                alpha_divs_j
+            );
 
-                // Record dividends for this hotkey on this subnet.
-                AlphaDividendsPerSubnet::<T>::mutate(netuid, hotkey_j.clone(), |divs| {
-                    *divs = divs
-                        .saturating_add(alpha_divs.to_num::<u64>())
-                        .saturating_add(validator_take.to_num::<u64>());
-                });
-                log::debug!(
-                    "Recorded dividends for hotkey {:?} on netuid {:?}: {:?}",
-                    hotkey_j,
-                    netuid,
-                    *divs_j
-                );
-            }
+            // 3.4.2 --- Record dividends for this hotkey on this subnet.
+            AlphaDividendsPerSubnet::<T>::mutate(netuid, hotkey_j.clone(), |divs| {
+                *divs = divs.saturating_add(alpha_divs_j);
+            });
+            log::debug!(
+                "Recorded dividends for hotkey {:?} on netuid {:?}: {:?}",
+                hotkey_j,
+                netuid,
+                alpha_divs_j
+            );
         }
 
+        // 3.5 --- Distribute root divs
         // For all the root-alpha divs give this proportion of the swapped tao to the root participants.
-        let _ = TaoDividendsPerSubnet::<T>::clear_prefix(netuid, u32::MAX, None);
-
-        for (hotkey_j, root_divs) in root_alpha_divs.iter() {
-            let proportion: I96F32 = I96F32::from_num(*root_divs)
-                .checked_div(I96F32::from_num(total_root_alpha_divs))
+        for (hotkey_j, root_divs_j) in root_divs.iter() {
+            // 3.5.1 --- Calculate the proportion of root divs to pay out to this hotkey.
+            let proportion: I96F32 = I96F32::from_num(*root_divs_j)
+                .checked_div(I96F32::from_num(total_root_divs))
                 .unwrap_or(I96F32::from_num(0));
+            // 3.5.2 --- Get the proportion of root divs from the pending root divs.
             let root_divs_to_pay: u64 = proportion
                 .saturating_mul(I96F32::from_num(pending_root_divs))
                 .to_num::<u64>();
@@ -540,22 +557,29 @@ impl<T: Config> Pallet<T> {
                 root_divs_to_pay
             );
 
-            // Pay the tao to the hotkey on netuid 0
+            // 3.5.3 --- Distribute the root divs to the hotkey on the root subnet.
             Self::increase_stake_for_hotkey_on_subnet(
                 hotkey_j,
                 Self::get_root_netuid(),
                 root_divs_to_pay,
             );
             log::debug!(
-                "Paid tao to hotkey {:?} on root netuid: {:?}",
+                "Paid tao to hotkey {:?} on root netuid from netuid {:?}: {:?}",
                 hotkey_j,
+                netuid,
                 root_divs_to_pay
             );
 
-            // Record dividends for this hotkey on this subnet.
+            // 3.5.4 --- Record dividends for this hotkey on this subnet.
             TaoDividendsPerSubnet::<T>::mutate(netuid, hotkey_j.clone(), |divs| {
                 *divs = divs.saturating_add(root_divs_to_pay);
             });
+            log::debug!(
+                "Recorded dividends for hotkey {:?} on netuid {:?}: {:?}",
+                hotkey_j,
+                netuid,
+                root_divs_to_pay
+            );
         }
     }
 

From e797da95521577ddc610f508f31abd4f76a7ce55 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Thu, 23 Jan 2025 16:12:08 +0100
Subject: [PATCH 044/145] Fix gas estimation issues

---
 Cargo.lock                                  | 45 +++++++++++
 Cargo.toml                                  |  3 +-
 node/src/chain_spec/localnet.rs             | 13 ++-
 runtime/Cargo.toml                          |  2 +
 runtime/src/precompiles/balance_transfer.rs | 88 +++++++++++----------
 runtime/src/precompiles/staking.rs          | 42 +++++-----
 6 files changed, 130 insertions(+), 63 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 964c583e1..e86ef3d69 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1067,6 +1067,12 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "case"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c"
+
 [[package]]
 name = "cc"
 version = "1.1.24"
@@ -5658,6 +5664,7 @@ dependencies = [
  "pallet-transaction-payment-rpc-runtime-api",
  "pallet-utility",
  "parity-scale-codec",
+ "precompile-utils",
  "rand_chacha",
  "scale-info",
  "serde_json",
@@ -7010,6 +7017,44 @@ dependencies = [
  "zerocopy",
 ]
 
+[[package]]
+name = "precompile-utils"
+version = "0.1.0"
+source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
+dependencies = [
+ "environmental",
+ "evm",
+ "fp-evm",
+ "frame-support",
+ "frame-system",
+ "hex",
+ "impl-trait-for-tuples",
+ "log",
+ "num_enum",
+ "pallet-evm",
+ "parity-scale-codec",
+ "precompile-utils-macro",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-weights",
+ "staging-xcm",
+]
+
+[[package]]
+name = "precompile-utils-macro"
+version = "0.1.0"
+source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
+dependencies = [
+ "case",
+ "num_enum",
+ "prettyplease 0.2.22",
+ "proc-macro2",
+ "quote",
+ "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "predicates"
 version = "2.1.5"
diff --git a/Cargo.toml b/Cargo.toml
index 3d5adb18a..0e723d6ae 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -180,9 +180,10 @@ fc-consensus = { git = "https://github.com/opentensor/frontier", rev = "635bdac8
 fp-consensus = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
 fp-dynamic-fee = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
 fc-api = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
-fc-rpc = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
+fc-rpc = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false, features = ["rpc-binary-search-estimate"]}
 fc-rpc-core = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
 fc-mapping-sync = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
+precompile-utils = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
 
 # Frontier FRAME
 pallet-base-fee = { git = "https://github.com/opentensor/frontier", rev = "635bdac882", default-features = false }
diff --git a/node/src/chain_spec/localnet.rs b/node/src/chain_spec/localnet.rs
index 7f5b3611c..4aa84f8ca 100644
--- a/node/src/chain_spec/localnet.rs
+++ b/node/src/chain_spec/localnet.rs
@@ -76,6 +76,17 @@ fn localnet_genesis(
         (
             get_account_id_from_seed::<sr25519::Public>("Ferdie"),
             2000000000000u128,
+        ),
+		// ETH
+        (
+            // Alith - 0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac
+            AccountId::from_str("5Fghzk1AJt88PeFEzuRfXzbPchiBbsVGTTXcdx599VdZzkTA").unwrap(),
+            2000000000000u128,
+        ),
+        (
+            // Baltathar - 0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0
+            AccountId::from_str("5GeqNhKWj1KG78VHzbmo3ZjZgUTrCuWeamdgiA114XHGdaEr").unwrap(),
+            2000000000000u128,
         ),
     ];
 
@@ -120,7 +131,7 @@ fn localnet_genesis(
         "senateMembers": {
             "members": senate_members,
         },
-        "evmChainId": {
+		"evmChainId": {
             "chainId": 42,
         },
     })
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index cdb8fd52f..0d44e0907 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -98,6 +98,7 @@ pallet-commitments = { default-features = false, path = "../pallets/commitments"
 fp-evm = { workspace = true }
 fp-rpc = { workspace = true }
 fp-self-contained = { workspace = true }
+precompile-utils = { workspace = true }
 
 # Frontier FRAME
 pallet-base-fee = { workspace = true }
@@ -191,6 +192,7 @@ std = [
 	"fp-evm/std",
 	"fp-rpc/std",
 	"fp-self-contained/std",
+	"precompile-utils/std",
 	# Frontier FRAME
 	"pallet-base-fee/std",
 	"pallet-dynamic-fee/std",
diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs
index 99d911b02..7c534212d 100644
--- a/runtime/src/precompiles/balance_transfer.rs
+++ b/runtime/src/precompiles/balance_transfer.rs
@@ -3,16 +3,24 @@ use pallet_evm::{
     BalanceConverter, ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle,
     PrecompileOutput, PrecompileResult,
 };
+use precompile_utils::prelude::RuntimeHelper;
 use sp_core::U256;
 use sp_runtime::traits::{Dispatchable, UniqueSaturatedInto};
 use sp_std::vec;
 
-use crate::{Runtime, RuntimeCall};
-
 use crate::precompiles::{bytes_to_account_id, get_method_id, get_slice};
+use crate::{Runtime, RuntimeCall};
 
 pub const BALANCE_TRANSFER_INDEX: u64 = 2048;
 
+// This is a hardcoded hashed address mapping of 0x0000000000000000000000000000000000000800 to an
+// ss58 public key i.e., the contract sends funds it received to the destination address from the
+// method parameter.
+const CONTRACT_ADDRESS_SS58: [u8; 32] = [
+    0x07, 0xec, 0x71, 0x2a, 0x5d, 0x38, 0x43, 0x4d, 0xdd, 0x03, 0x3f, 0x8f, 0x02, 0x4e, 0xcd, 0xfc,
+    0x4b, 0xb5, 0x95, 0x1c, 0x13, 0xc3, 0x08, 0x5c, 0x39, 0x9c, 0x8a, 0x5f, 0x62, 0x93, 0x70, 0x5d,
+];
+
 pub struct BalanceTransferPrecompile;
 
 impl BalanceTransferPrecompile {
@@ -20,54 +28,50 @@ impl BalanceTransferPrecompile {
         let txdata = handle.input();
 
         // Match method ID: keccak256("transfer(bytes32)")
-        let method: &[u8] = get_slice(txdata, 0, 4)?;
-        if get_method_id("transfer(bytes32)") == method {
-            // Forward all received value to the destination address
-            let amount: U256 = handle.context().apparent_value;
+        let method = get_slice(txdata, 0, 4)?;
+        if get_method_id("transfer(bytes32)") != method {
+            return Ok(PrecompileOutput {
+                exit_status: ExitSucceed::Returned,
+                output: vec![],
+            });
+        }
 
-            // Use BalanceConverter to convert EVM amount to Substrate balance
-            let amount_sub =
-                <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
-                    .ok_or(ExitError::OutOfFund)?;
+        // Forward all received value to the destination address
+        let amount: U256 = handle.context().apparent_value;
 
-            if amount_sub.is_zero() {
-                return Ok(PrecompileOutput {
-                    exit_status: ExitSucceed::Returned,
-                    output: vec![],
-                });
-            }
+        // Use BalanceConverter to convert EVM amount to Substrate balance
+        let amount_sub =
+            <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
+                .ok_or(ExitError::OutOfFund)?;
 
-            // This is a hardcoded hashed address mapping of
-            // 0x0000000000000000000000000000000000000800 to an ss58 public key
-            // i.e., the contract sends funds it received to the destination address
-            // from the method parameter.
-            const ADDRESS_BYTES_SRC: [u8; 32] = [
-                0x07, 0xec, 0x71, 0x2a, 0x5d, 0x38, 0x43, 0x4d, 0xdd, 0x03, 0x3f, 0x8f, 0x02, 0x4e,
-                0xcd, 0xfc, 0x4b, 0xb5, 0x95, 0x1c, 0x13, 0xc3, 0x08, 0x5c, 0x39, 0x9c, 0x8a, 0x5f,
-                0x62, 0x93, 0x70, 0x5d,
-            ];
-            let address_bytes_dst: &[u8] = get_slice(txdata, 4, 36)?;
-            let account_id_src = bytes_to_account_id(&ADDRESS_BYTES_SRC)?;
-            let account_id_dst = bytes_to_account_id(address_bytes_dst)?;
+        if amount_sub.is_zero() {
+            return Ok(PrecompileOutput {
+                exit_status: ExitSucceed::Returned,
+                output: vec![],
+            });
+        }
 
-            let call =
-                RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
-                    dest: account_id_dst.into(),
-                    value: amount_sub.unique_saturated_into(),
-                });
+        let address_bytes_dst = get_slice(txdata, 4, 36)?;
+        let account_id_src = bytes_to_account_id(&CONTRACT_ADDRESS_SS58)?;
+        let account_id_dst = bytes_to_account_id(address_bytes_dst)?;
 
-            // Dispatch the call
-            let result = call.dispatch(RawOrigin::Signed(account_id_src).into());
-            if result.is_err() {
-                return Err(PrecompileFailure::Error {
-                    exit_status: ExitError::OutOfFund,
-                });
-            }
-        }
+        let call = RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
+            dest: account_id_dst.into(),
+            value: amount_sub.unique_saturated_into(),
+        });
 
-        Ok(PrecompileOutput {
+        // Dispatch the call
+        RuntimeHelper::<Runtime>::try_dispatch(
+            handle,
+            RawOrigin::Signed(account_id_src).into(),
+            call,
+        )
+        .map(|_| PrecompileOutput {
             exit_status: ExitSucceed::Returned,
             output: vec![],
         })
+        .map_err(|_| PrecompileFailure::Error {
+            exit_status: ExitError::OutOfFund,
+        })
     }
 }
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index 86d257a19..e670e3b3b 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -25,24 +25,24 @@
 //   - Precompile checks the result of do_remove_stake and, in case of a failure, reverts the transaction.
 //
 
+use frame_support::dispatch::{GetDispatchInfo, Pays};
 use frame_system::RawOrigin;
-use pallet_evm::{AddressMapping, BalanceConverter, HashedAddressMapping};
 use pallet_evm::{
-    ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
+    AddressMapping, BalanceConverter, ExitError, ExitSucceed, GasWeightMapping,
+    HashedAddressMapping, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
 };
+use precompile_utils::prelude::RuntimeHelper;
 use sp_core::crypto::Ss58Codec;
 use sp_core::U256;
-use sp_runtime::traits::Dispatchable;
-use sp_runtime::traits::{BlakeTwo256, StaticLookup, UniqueSaturatedInto};
+use sp_runtime::traits::{BlakeTwo256, Dispatchable, StaticLookup, UniqueSaturatedInto};
 use sp_runtime::AccountId32;
+use sp_std::vec;
 
 use crate::{
     precompiles::{get_method_id, get_slice},
-    ProxyType,
+    ProxyType, Runtime, RuntimeCall,
 };
-use sp_std::vec;
 
-use crate::{Runtime, RuntimeCall};
 pub const STAKING_PRECOMPILE_INDEX: u64 = 2049;
 
 pub struct StakingPrecompile;
@@ -209,24 +209,28 @@ impl StakingPrecompile {
             );
 
         // Transfer the amount back to the caller before executing the staking operation
-        // let caller = handle.context().caller;
         let amount = handle.context().apparent_value;
 
         if !amount.is_zero() {
             Self::transfer_back_to_caller(&account_id, amount)?;
         }
 
-        let result = call.dispatch(RawOrigin::Signed(account_id.clone()).into());
-        match &result {
-            Ok(post_info) => log::info!("Dispatch succeeded. Post info: {:?}", post_info),
-            Err(dispatch_error) => log::error!("Dispatch failed. Error: {:?}", dispatch_error),
-        }
-        match result {
-            Ok(_) => Ok(PrecompileOutput {
-                exit_status: ExitSucceed::Returned,
-                output: vec![],
-            }),
-            Err(_) => {
+        match RuntimeHelper::<Runtime>::try_dispatch(
+            handle,
+            RawOrigin::Signed(account_id.clone()).into(),
+            call,
+        ) {
+            Ok(post_info) => {
+                log::info!("Dispatch succeeded. Post info: {:?}", post_info);
+
+                Ok(PrecompileOutput {
+                    exit_status: ExitSucceed::Returned,
+                    output: vec![],
+                })
+            }
+
+            Err(dispatch_error) => {
+                log::error!("Dispatch failed. Error: {:?}", dispatch_error);
                 log::warn!("Returning error PrecompileFailure::Error");
                 Err(PrecompileFailure::Error {
                     exit_status: ExitError::Other("Subtensor call failed".into()),

From 900cccfbaee7aa854efc17ef2e00c4991fadecde Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Thu, 23 Jan 2025 10:16:29 -0500
Subject: [PATCH 045/145] pay vali take in root-divs

---
 .../subtensor/src/coinbase/run_coinbase.rs    | 141 +++++++++++++-----
 1 file changed, 101 insertions(+), 40 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index a8af8322c..9596c2bc3 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -356,11 +356,11 @@ impl<T: Config> Pallet<T> {
         }
 
         // Initialize maps for dividend calculations.
-        let mut root_divs: BTreeMap<T::AccountId, u64> = BTreeMap::new();
+        let mut root_alpha_divs: BTreeMap<T::AccountId, u64> = BTreeMap::new();
         let mut alpha_divs: BTreeMap<T::AccountId, u64> = BTreeMap::new();
-        let mut validator_takes: BTreeMap<T::AccountId, u64> = BTreeMap::new();
-
-        // 2.2 --- Calculate the validator_take, alpha_divs, and root_divs using above dividend tuples.
+        let mut validator_alpha_takes: BTreeMap<T::AccountId, u64> = BTreeMap::new();
+        let mut validator_root_alpha_takes: BTreeMap<T::AccountId, u64> = BTreeMap::new();
+        // 2.2 --- Calculate the validator_take, alpha_divs, and root_alpha_divs using above dividend tuples.
         for (hotkey, dividend_tuples) in dividends_to_distribute.iter() {
             // Calculate the proportion of root vs alpha divs for each hotkey using their stake.
             for (hotkey_j, divs_j) in dividend_tuples.iter() {
@@ -394,52 +394,67 @@ impl<T: Config> Pallet<T> {
                     root_prop
                 );
 
-                // 2.3.1 --- Remove the hotkey take from both alpha and root divs.
+                let divs_j: I96F32 = I96F32::from_num(*divs_j);
+                // 2.3.1 --- Compute root dividends
+                let root_alpha_divs_j: I96F32 = divs_j.saturating_mul(root_prop);
+                // 2.3.2 --- Compute alpha dividends
+                let alpha_divs_j: I96F32 = divs_j.saturating_sub(root_alpha_divs_j);
+                log::debug!(
+                    "Alpha dividends: {:?}, Root alpha-dividends: {:?}",
+                    alpha_divs_j,
+                    root_alpha_divs_j
+                );
+
+                // 2.4.1 --- Remove the hotkey take from both alpha and root divs.
                 let take_prop: I96F32 = I96F32::from_num(Self::get_hotkey_take(hotkey_j))
                     .checked_div(I96F32::from_num(u16::MAX))
                     .unwrap_or(I96F32::from_num(0.0));
-                let validator_take: I96F32 = take_prop.saturating_mul(I96F32::from_num(*divs_j));
-                let rem_divs_j: I96F32 = I96F32::from_num(*divs_j).saturating_sub(validator_take);
+
+                let validator_alpha_take: I96F32 = take_prop.saturating_mul(alpha_divs_j);
+                let validator_root_alpha_take: I96F32 = take_prop.saturating_mul(root_alpha_divs_j);
+
+                let rem_alpha_divs_j: I96F32 = alpha_divs_j.saturating_sub(validator_alpha_take);
+                let rem_root_alpha_divs_j: I96F32 =
+                    root_alpha_divs_j.saturating_sub(validator_root_alpha_take);
                 log::debug!(
-                    "Validator take for hotkey {:?}: {:?}, remaining dividends: {:?}",
+                    "Validator take for hotkey {:?}: alpha take: {:?}, remaining alpha: {:?}, root-alpha take: {:?}, remaining root-alpha: {:?}",
                     hotkey_j,
-                    validator_take,
-                    rem_divs_j
+                    validator_alpha_take,
+                    rem_alpha_divs_j,
+                    validator_root_alpha_take,
+                    rem_root_alpha_divs_j
                 );
 
-                // 2.3.2 --- Store the validator take.
-                validator_takes
+                // 2.4.2 --- Store the validator takes.
+                validator_alpha_takes
+                    .entry(hotkey_j.clone())
+                    .and_modify(|e| *e = e.saturating_add(validator_alpha_take.to_num::<u64>()))
+                    .or_insert(validator_alpha_take.to_num::<u64>());
+                validator_root_alpha_takes
                     .entry(hotkey_j.clone())
-                    .and_modify(|e| *e = e.saturating_add(validator_take.to_num::<u64>()))
-                    .or_insert(validator_take.to_num::<u64>());
+                    .and_modify(|e| {
+                        *e = e.saturating_add(validator_root_alpha_take.to_num::<u64>())
+                    })
+                    .or_insert(validator_root_alpha_take.to_num::<u64>());
                 log::debug!(
-                    "Stored validator take for hotkey {:?}: {:?}",
+                    "Stored validator take for hotkey {:?}: alpha take: {:?}, root-alpha take: {:?}",
                     hotkey_j,
-                    validator_take.to_num::<u64>()
+                    validator_alpha_take.to_num::<u64>(),
+                    validator_root_alpha_take.to_num::<u64>()
                 );
 
-                // 2.4.1 --- Compute root dividends
-                let root_divs_j: I96F32 = rem_divs_j.saturating_mul(root_prop);
-                // 2.4.2 --- Compute alpha dividends
-                let alpha_divs_j: I96F32 = rem_divs_j.saturating_sub(root_divs_j);
-                log::debug!(
-                    "Alpha dividends: {:?}, root dividends: {:?}",
-                    alpha_divs_j,
-                    root_divs_j
-                );
-
-                // 2.4.3 --- Store the root divs under hotkey_j
-                root_divs
+                // 2.5.1 --- Store the root divs under hotkey_j
+                root_alpha_divs
                     .entry(hotkey_j.clone())
-                    .and_modify(|e| *e = e.saturating_add(root_divs_j.to_num::<u64>()))
-                    .or_insert(root_divs_j.to_num::<u64>());
+                    .and_modify(|e| *e = e.saturating_add(root_alpha_divs_j.to_num::<u64>()))
+                    .or_insert(root_alpha_divs_j.to_num::<u64>());
                 log::debug!(
                     "Stored root alpha dividends for hotkey {:?}: {:?}",
                     hotkey_j,
-                    root_divs_j.to_num::<u64>()
+                    root_alpha_divs_j.to_num::<u64>()
                 );
 
-                // 2.4.4 --- Store the alpha dividends
+                // 2.5.2 --- Store the alpha dividends
                 alpha_divs
                     .entry(hotkey_j.clone())
                     .and_modify(|e| *e = e.saturating_add(alpha_divs_j.to_num::<u64>()))
@@ -452,7 +467,10 @@ impl<T: Config> Pallet<T> {
             }
         }
 
-        let total_root_divs: u64 = root_divs.values().sum();
+        let total_root_alpha_divs: u64 = root_alpha_divs
+            .values()
+            .sum()
+            .saturating_add(validator_root_alpha_takes.values().sum());
 
         // === 3. Distribute the dividends to the hotkeys.
 
@@ -488,9 +506,9 @@ impl<T: Config> Pallet<T> {
             );
         }
 
-        // 3.3 --- Distribute validator take
-        for (validator_j, validator_take) in validator_takes {
-            // 3.3.1 --- Distribute validator take to the validator.
+        // 3.3.1 --- Distribute validator alpha takes
+        for (validator_j, validator_take) in validator_alpha_takes {
+            // 3.3.1a --- Distribute validator take to the validator.
             Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
                 &validator_j.clone(),
                 &Owner::<T>::get(validator_j.clone()),
@@ -504,7 +522,7 @@ impl<T: Config> Pallet<T> {
                 validator_take
             );
 
-            // 3.3.2 --- Record dividends for this validator on this subnet.
+            // 3.3.1b --- Record dividends for this validator on this subnet.
             AlphaDividendsPerSubnet::<T>::mutate(netuid, validator_j.clone(), |divs| {
                 *divs = divs.saturating_add(validator_take);
             });
@@ -516,6 +534,49 @@ impl<T: Config> Pallet<T> {
             );
         }
 
+        // 3.3.2 --- Distribute validator root-alpha takes
+        for (validator_j, validator_take) in validator_root_alpha_takes {
+            // 3.3.2a --- Calculate the proportion of root divs to pay out to this validator's take.
+            let proportion: I96F32 = I96F32::from_num(validator_take)
+                .checked_div(I96F32::from_num(total_root_alpha_divs))
+                .unwrap_or(I96F32::from_num(0));
+            // 3.3.2b --- Get the proportion of root divs from the pending root divs.
+            let take_as_root_divs: u64 = proportion
+                .saturating_mul(I96F32::from_num(pending_root_divs))
+                .to_num::<u64>();
+            log::debug!(
+                "Root div proportion for validator take {:?}: {:?}, take_as_root_divs: {:?}",
+                validator_take,
+                proportion,
+                take_as_root_divs
+            );
+
+            // 3.3.2c --- Distribute validator take to the validator.
+            Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
+                &validator_j.clone(),
+                &Owner::<T>::get(validator_j.clone()),
+                Self::get_root_netuid(),
+                take_as_root_divs,
+            );
+            log::debug!(
+                "Distributed validator take for hotkey {:?} on root netuid {:?}: {:?}",
+                validator_j,
+                Self::get_root_netuid(),
+                take_as_root_divs
+            );
+
+            // 3.3.2d --- Record dividends for this validator on this subnet.
+            TaoDividendsPerSubnet::<T>::mutate(netuid, validator_j.clone(), |divs| {
+                *divs = divs.saturating_add(take_as_root_divs);
+            });
+            log::debug!(
+                "Recorded dividends for validator {:?} on netuid {:?}: {:?}",
+                validator_j,
+                netuid,
+                take_as_root_divs
+            );
+        }
+
         // 3.4 --- Distribute alpha divs
         for (hotkey_j, alpha_divs_j) in alpha_divs {
             // 3.4.1 --- Distribute alpha divs to the hotkey.
@@ -541,10 +602,10 @@ impl<T: Config> Pallet<T> {
 
         // 3.5 --- Distribute root divs
         // For all the root-alpha divs give this proportion of the swapped tao to the root participants.
-        for (hotkey_j, root_divs_j) in root_divs.iter() {
+        for (hotkey_j, root_alpha_divs_j) in root_alpha_divs.iter() {
             // 3.5.1 --- Calculate the proportion of root divs to pay out to this hotkey.
-            let proportion: I96F32 = I96F32::from_num(*root_divs_j)
-                .checked_div(I96F32::from_num(total_root_divs))
+            let proportion: I96F32 = I96F32::from_num(*root_alpha_divs_j)
+                .checked_div(I96F32::from_num(total_root_alpha_divs))
                 .unwrap_or(I96F32::from_num(0));
             // 3.5.2 --- Get the proportion of root divs from the pending root divs.
             let root_divs_to_pay: u64 = proportion

From fe34f5aa7bc8517eab83f5715717566b0a035498 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Thu, 23 Jan 2025 10:17:43 -0500
Subject: [PATCH 046/145] specify sum-type

---
 pallets/subtensor/src/coinbase/run_coinbase.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index 9596c2bc3..d340271bb 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -469,8 +469,8 @@ impl<T: Config> Pallet<T> {
 
         let total_root_alpha_divs: u64 = root_alpha_divs
             .values()
-            .sum()
-            .saturating_add(validator_root_alpha_takes.values().sum());
+            .sum::<u64>()
+            .saturating_add(validator_root_alpha_takes.values().sum::<u64>());
 
         // === 3. Distribute the dividends to the hotkeys.
 

From d66e2ed8197bf37120943ab023379b1b7df93d5f Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Thu, 23 Jan 2025 16:18:19 +0100
Subject: [PATCH 047/145] Reformat

---
 node/src/chain_spec/localnet.rs             | 4 ++--
 runtime/src/precompiles/balance_transfer.rs | 2 +-
 runtime/src/precompiles/staking.rs          | 5 ++---
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/node/src/chain_spec/localnet.rs b/node/src/chain_spec/localnet.rs
index 4aa84f8ca..3f0743199 100644
--- a/node/src/chain_spec/localnet.rs
+++ b/node/src/chain_spec/localnet.rs
@@ -77,7 +77,7 @@ fn localnet_genesis(
             get_account_id_from_seed::<sr25519::Public>("Ferdie"),
             2000000000000u128,
         ),
-		// ETH
+        // ETH
         (
             // Alith - 0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac
             AccountId::from_str("5Fghzk1AJt88PeFEzuRfXzbPchiBbsVGTTXcdx599VdZzkTA").unwrap(),
@@ -131,7 +131,7 @@ fn localnet_genesis(
         "senateMembers": {
             "members": senate_members,
         },
-		"evmChainId": {
+        "evmChainId": {
             "chainId": 42,
         },
     })
diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs
index 7c534212d..03c4be8a6 100644
--- a/runtime/src/precompiles/balance_transfer.rs
+++ b/runtime/src/precompiles/balance_transfer.rs
@@ -5,7 +5,7 @@ use pallet_evm::{
 };
 use precompile_utils::prelude::RuntimeHelper;
 use sp_core::U256;
-use sp_runtime::traits::{Dispatchable, UniqueSaturatedInto};
+use sp_runtime::traits::UniqueSaturatedInto;
 use sp_std::vec;
 
 use crate::precompiles::{bytes_to_account_id, get_method_id, get_slice};
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index e670e3b3b..f8534927b 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -25,11 +25,10 @@
 //   - Precompile checks the result of do_remove_stake and, in case of a failure, reverts the transaction.
 //
 
-use frame_support::dispatch::{GetDispatchInfo, Pays};
 use frame_system::RawOrigin;
 use pallet_evm::{
-    AddressMapping, BalanceConverter, ExitError, ExitSucceed, GasWeightMapping,
-    HashedAddressMapping, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
+    AddressMapping, BalanceConverter, ExitError, ExitSucceed, HashedAddressMapping,
+    PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
 };
 use precompile_utils::prelude::RuntimeHelper;
 use sp_core::crypto::Ss58Codec;

From 541518e091b2fe4150293a740f54f437fc47006a Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 23 Jan 2025 23:28:03 +0800
Subject: [PATCH 048/145] fix compilation error

---
 runtime/src/precompiles/mod.rs    | 4 ++--
 runtime/src/precompiles/subnet.rs | 5 +++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index 3c62d4b8c..de4f4fc1f 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -233,9 +233,9 @@ fn dispatch(
     }
 }
 
-pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, Vec<u8>), PrecompileFailure> {
+pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec<u8>), PrecompileFailure> {
     let mut pubkey = [0u8; 32];
-    pubkey.copy_from_slice(data.get_slice(0, 32)?);
+    pubkey.copy_from_slice(get_slice(data, 0, 32)?);
 
     Ok((
         pubkey.into(),
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index 9c9fd859f..7537ea8ae 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -1,6 +1,7 @@
 use crate::precompiles::{dispatch, get_method_id, get_pubkey, get_slice};
 use crate::{Runtime, RuntimeCall};
 use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
+use sp_runtime::AccountId32;
 use sp_std::vec;
 
 pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051;
@@ -42,7 +43,7 @@ impl SubnetPrecompile {
     fn register_network(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
         let call = match data.len() {
             32 => {
-                let (hotkey, _) = get_pubkey(data);
+                let (hotkey, _) = get_pubkey(data)?;
 
                 RuntimeCall::SubtensorModule(
                     pallet_subtensor::Call::<Runtime>::register_network_with_identity {
@@ -83,7 +84,7 @@ impl SubnetPrecompile {
 
     fn parse_register_network_parameters(
         data: &[u8],
-    ) -> Result<([u8; 32], vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {
+    ) -> Result<(AccountId32, vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {
         let (pubkey, _) = get_pubkey(data)?;
 
         let mut buf = [0_u8; 4];

From d148c2b3a357ad5229edbed46da06517624fe68c Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 23 Jan 2025 23:44:21 +0800
Subject: [PATCH 049/145] refactor get pubkey method

---
 runtime/src/precompiles/neuron.rs           | 12 +++----
 runtime/src/precompiles/solidity/subnet.sol |  2 +-
 runtime/src/precompiles/staking.rs          | 38 ++++-----------------
 runtime/src/precompiles/subnet.rs           |  6 ++--
 4 files changed, 17 insertions(+), 41 deletions(-)

diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs
index 341683cb3..efa0b5fec 100644
--- a/runtime/src/precompiles/neuron.rs
+++ b/runtime/src/precompiles/neuron.rs
@@ -1,6 +1,7 @@
 use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
 
-use crate::precompiles::{dispatch, get_method_id, get_slice};
+use crate::precompiles::{dispatch, get_method_id, get_pubkey, get_slice};
+use sp_runtime::AccountId32;
 use sp_std::vec;
 
 use crate::{Runtime, RuntimeCall};
@@ -35,12 +36,12 @@ impl NeuronPrecompile {
         let call =
             RuntimeCall::SubtensorModule(pallet_subtensor::Call::<Runtime>::burned_register {
                 netuid,
-                hotkey: hotkey.into(),
+                hotkey,
             });
         dispatch(handle, call, NEURON_CONTRACT_ADDRESS)
     }
 
-    fn parse_netuid_hotkey_parameter(data: &[u8]) -> Result<(u16, [u8; 32]), PrecompileFailure> {
+    fn parse_netuid_hotkey_parameter(data: &[u8]) -> Result<(u16, AccountId32), PrecompileFailure> {
         if data.len() < 64 {
             return Err(PrecompileFailure::Error {
                 exit_status: ExitError::InvalidRange,
@@ -50,9 +51,8 @@ impl NeuronPrecompile {
         netuid_vec.copy_from_slice(get_slice(data, 30, 32)?);
         let netuid = u16::from_be_bytes(netuid_vec);
 
-        let mut parameter = [0u8; 32];
-        parameter.copy_from_slice(get_slice(data, 32, 64)?);
+        let (hotkey, _) = get_pubkey(get_slice(data, 32, 64)?)?;
 
-        Ok((netuid, parameter))
+        Ok((netuid, hotkey))
     }
 }
diff --git a/runtime/src/precompiles/solidity/subnet.sol b/runtime/src/precompiles/solidity/subnet.sol
index c3d0a4a13..c6639891a 100644
--- a/runtime/src/precompiles/solidity/subnet.sol
+++ b/runtime/src/precompiles/solidity/subnet.sol
@@ -1,6 +1,6 @@
 pragma solidity ^0.8.0;
 
-address constant ISTAKING_ADDRESS = 0x0000000000000000000000000000000000000803;
+address constant ISUBNET_ADDRESS = 0x0000000000000000000000000000000000000803;
 
 interface ISubnet {
     /// Registers a new network without specifying details.
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index a29031352..f549ee1c3 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -31,10 +31,9 @@ use pallet_evm::{
 };
 use sp_core::U256;
 use sp_runtime::traits::{StaticLookup, UniqueSaturatedInto};
-use sp_runtime::AccountId32;
 
 use crate::{
-    precompiles::{dispatch, get_method_id, get_slice},
+    precompiles::{dispatch, get_method_id, get_pubkey, get_slice},
     ProxyType,
 };
 use sp_std::vec;
@@ -71,7 +70,7 @@ impl StakingPrecompile {
     }
 
     fn add_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
-        let hotkey = Self::parse_pub_key(data)?.into();
+        let (hotkey, _) = get_pubkey(data)?;
         let amount: U256 = handle.context().apparent_value;
         let netuid = Self::parse_netuid(data, 0x3E)?;
 
@@ -90,7 +89,7 @@ impl StakingPrecompile {
     }
 
     fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
-        let hotkey = Self::parse_pub_key(data)?.into();
+        let (hotkey, _) = get_pubkey(data)?;
         let netuid = Self::parse_netuid(data, 0x5E)?;
 
         // We have to treat this as uint256 (because of Solidity ABI encoding rules, it pads uint64),
@@ -113,7 +112,7 @@ impl StakingPrecompile {
     }
 
     fn add_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
-        let delegate = AccountId32::from(Self::parse_pub_key(data)?);
+        let (delegate, _) = get_pubkey(data)?;
         let delegate = <Runtime as frame_system::Config>::Lookup::unlookup(delegate);
         let call = RuntimeCall::Proxy(pallet_proxy::Call::<Runtime>::add_proxy {
             delegate,
@@ -125,7 +124,7 @@ impl StakingPrecompile {
     }
 
     fn remove_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
-        let delegate = AccountId32::from(Self::parse_pub_key(data)?);
+        let (delegate, _) = get_pubkey(data)?;
         let delegate = <Runtime as frame_system::Config>::Lookup::unlookup(delegate);
         let call = RuntimeCall::Proxy(pallet_proxy::Call::<Runtime>::remove_proxy {
             delegate,
@@ -137,7 +136,8 @@ impl StakingPrecompile {
     }
 
     fn get_stake(data: &[u8]) -> PrecompileResult {
-        let (hotkey, coldkey) = Self::parse_hotkey_coldkey(data)?;
+        let (hotkey, left_data) = get_pubkey(data)?;
+        let (coldkey, _) = get_pubkey(&left_data)?;
         let netuid = Self::parse_netuid(data, 0x5E)?;
 
         let stake = pallet_subtensor::Pallet::<Runtime>::get_stake_for_hotkey_and_coldkey_on_subnet(
@@ -162,30 +162,6 @@ impl StakingPrecompile {
         })
     }
 
-    fn parse_hotkey_coldkey(data: &[u8]) -> Result<([u8; 32], [u8; 32]), PrecompileFailure> {
-        if data.len() < 64 {
-            return Err(PrecompileFailure::Error {
-                exit_status: ExitError::InvalidRange,
-            });
-        }
-        let mut hotkey = [0u8; 32];
-        hotkey.copy_from_slice(get_slice(data, 0, 32)?);
-        let mut coldkey = [0u8; 32];
-        coldkey.copy_from_slice(get_slice(data, 32, 64)?);
-        Ok((hotkey, coldkey))
-    }
-
-    fn parse_pub_key(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> {
-        if data.len() < 32 {
-            return Err(PrecompileFailure::Error {
-                exit_status: ExitError::InvalidRange,
-            });
-        }
-        let mut pubkey = [0u8; 32];
-        pubkey.copy_from_slice(get_slice(data, 0, 32)?);
-        Ok(pubkey)
-    }
-
     fn parse_netuid(data: &[u8], offset: usize) -> Result<u16, PrecompileFailure> {
         if data.len() < offset + 2 {
             return Err(PrecompileFailure::Error {
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index 7537ea8ae..3dba5a262 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -47,13 +47,13 @@ impl SubnetPrecompile {
 
                 RuntimeCall::SubtensorModule(
                     pallet_subtensor::Call::<Runtime>::register_network_with_identity {
-                        hotkey: hotkey.into(),
+                        hotkey,
                         identity: None,
                     },
                 )
             }
             33.. => {
-                let (pubkey, subnet_name, github_repo, subnet_contact) =
+                let (hotkey, subnet_name, github_repo, subnet_contact) =
                     Self::parse_register_network_parameters(data)?;
 
                 let identity: pallet_subtensor::SubnetIdentityOf =
@@ -66,7 +66,7 @@ impl SubnetPrecompile {
                 // Create the register_network callcle
                 RuntimeCall::SubtensorModule(
                     pallet_subtensor::Call::<Runtime>::register_network_with_identity {
-                        hotkey: pubkey.into(),
+                        hotkey,
                         identity: Some(identity),
                     },
                 )

From 96a1d08dd15581752480661122e25b1207ba8979 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 23 Jan 2025 23:55:31 +0800
Subject: [PATCH 050/145] cargo clippy

---
 runtime/src/precompiles/staking.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index f549ee1c3..f6e358758 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -141,8 +141,8 @@ impl StakingPrecompile {
         let netuid = Self::parse_netuid(data, 0x5E)?;
 
         let stake = pallet_subtensor::Pallet::<Runtime>::get_stake_for_hotkey_and_coldkey_on_subnet(
-            &hotkey.into(),
-            &coldkey.into(),
+            &hotkey,
+            &coldkey,
             netuid,
         );
 

From 241d6204893936fad235cb2d247f5972bad2f1da Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 23 Jan 2025 23:55:57 +0800
Subject: [PATCH 051/145] cargo fmt

---
 runtime/src/precompiles/staking.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index f6e358758..f9a0968f4 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -141,9 +141,7 @@ impl StakingPrecompile {
         let netuid = Self::parse_netuid(data, 0x5E)?;
 
         let stake = pallet_subtensor::Pallet::<Runtime>::get_stake_for_hotkey_and_coldkey_on_subnet(
-            &hotkey,
-            &coldkey,
-            netuid,
+            &hotkey, &coldkey, netuid,
         );
 
         // Convert to EVM decimals

From 65aad3c04ad64a7ca6eeeb517a81e863c731b534 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Thu, 23 Jan 2025 11:05:20 -0500
Subject: [PATCH 052/145] add fee for swap stake

---
 pallets/subtensor/src/staking/move_stake.rs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 38a783b25..fff688084 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -288,8 +288,9 @@ impl<T: Config> Pallet<T> {
         );
 
         // 6. Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
+        let fee = DefaultMinStake::<T>::get().saturating_div(2);
         let tao_unstaked =
-            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount);
+            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount, fee);
 
         // 7. Check that the unstaked amount is above the minimum stake threshold.
         ensure!(
@@ -298,7 +299,7 @@ impl<T: Config> Pallet<T> {
         );
 
         // 8. Stake the unstaked amount into the destination subnet, using the same coldkey/hotkey.
-        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked);
+        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked, fee);
 
         // 9. Emit an event for logging.
         log::info!(

From 438b67837047f5fe2ecadc100e54497c59b58523 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Thu, 23 Jan 2025 11:06:25 -0500
Subject: [PATCH 053/145] add 0-fee to tests

---
 pallets/subtensor/src/tests/move_stake.rs | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 150fa1201..04f79f3f9 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -1085,7 +1085,7 @@ fn test_do_swap_success() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0);
         let alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey,
             &coldkey,
@@ -1180,7 +1180,7 @@ fn test_do_swap_insufficient_stake() {
         let attempted_swap = stake_amount * 2;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, stake_amount, 0);
 
         assert_noop!(
             SubtensorModule::do_swap_stake(
@@ -1209,7 +1209,7 @@ fn test_do_swap_wrong_origin() {
         let stake_amount = 100_000;
 
         SubtensorModule::create_account_if_non_existent(&real_coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &real_coldkey, netuid1, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &real_coldkey, netuid1, stake_amount, 0);
 
         assert_noop!(
             SubtensorModule::do_swap_stake(
@@ -1237,7 +1237,7 @@ fn test_do_swap_minimum_stake_check() {
         let swap_amount = 1;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, total_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, total_stake, 0);
 
         assert_err!(
             SubtensorModule::do_swap_stake(
@@ -1264,7 +1264,7 @@ fn test_do_swap_same_subnet() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, stake_amount, 0);
 
         let alpha_before =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
@@ -1296,7 +1296,7 @@ fn test_do_swap_partial_stake() {
         let total_stake = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake, 0);
 
         let swap_amount = total_stake / 2;
         assert_ok!(SubtensorModule::do_swap_stake(
@@ -1341,7 +1341,7 @@ fn test_do_swap_storage_updates() {
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0);
 
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey,
@@ -1390,7 +1390,7 @@ fn test_do_swap_multiple_times() {
         let initial_stake = DefaultMinStake::<Test>::get() * 10;
 
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake);
+        SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake, 0);
 
         for _ in 0..3 {
             let alpha1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(

From b42641f93ac9e8eed72067569153caf0648fa91a Mon Sep 17 00:00:00 2001
From: andreea-popescu-reef
 <160024917+andreea-popescu-reef@users.noreply.github.com>
Date: Fri, 24 Jan 2025 00:22:55 +0800
Subject: [PATCH 054/145] Add bonds_penalty hyperparam (#1160)

* add bonds_penalty hyperparam

* fix safe math

* add bonds_penalty admin-utils
---
 hyperparameters.md                       |   8 +-
 pallets/admin-utils/src/benchmarking.rs  |   8 +
 pallets/admin-utils/src/lib.rs           |  25 +++
 pallets/admin-utils/src/tests/mock.rs    |   2 +
 pallets/admin-utils/src/tests/mod.rs     |  33 ++++
 pallets/admin-utils/src/weights.rs       |  27 +++
 pallets/subtensor/src/epoch/math.rs      |  84 ++++++++
 pallets/subtensor/src/epoch/run_epoch.rs |  53 +++--
 pallets/subtensor/src/lib.rs             |   9 +
 pallets/subtensor/src/macros/config.rs   |   3 +
 pallets/subtensor/src/macros/events.rs   |   2 +
 pallets/subtensor/src/tests/epoch.rs     | 221 +++++++++++----------
 pallets/subtensor/src/tests/math.rs      | 234 +++++++++++++++++++++++
 pallets/subtensor/src/tests/mock.rs      |   2 +
 pallets/subtensor/src/utils/misc.rs      |   8 +
 runtime/src/lib.rs                       |   2 +
 16 files changed, 604 insertions(+), 117 deletions(-)

diff --git a/hyperparameters.md b/hyperparameters.md
index 96f955437..c8d2ce110 100644
--- a/hyperparameters.md
+++ b/hyperparameters.md
@@ -7,7 +7,7 @@ TxRateLimit: u64 = 1; // [1 @ 64,888]
 ### netuid 1 (text_prompting)
 ```rust
 Rho: u16 = 10;
-Kappa: u16 = 32_767; // 0.5 = 65535/2 
+Kappa: u16 = 32_767; // 0.5 = 65535/2
 MaxAllowedUids: u16 = 1024;
 Issuance: u64 = 0;
 MinAllowedWeights: u16 = 8;
@@ -32,10 +32,11 @@ ActivityCutoff: u16 = 5000;
 MaxRegistrationsPerBlock: u16 = 1;
 PruningScore : u16 = u16::MAX;
 BondsMovingAverage: u64 = 900_000;
+BondsPenalty: u16 = 0;
 WeightsVersionKey: u64 = 1020;
 MinDifficulty: u64 = 10_000_000;
 MaxDifficulty: u64 = u64::MAX / 4;
-ServingRateLimit: u64 = 10; 
+ServingRateLimit: u64 = 10;
 Burn: u64 = 1_000_000_000; // 1 tao
 MinBurn: u64 = 1_000_000_000; // 1 tao
 MaxBurn: u64 = 100_000_000_000; // 100 tao
@@ -45,7 +46,7 @@ WeightsSetRateLimit: u64 = 100;
 ### netuid 3 (causallmnext)
 ```rust
 Rho: u16 = 10;
-Kappa: u16 = 32_767; // 0.5 = 65535/2 
+Kappa: u16 = 32_767; // 0.5 = 65535/2
 MaxAllowedUids: u16 = 4096;
 Issuance: u64 = 0;
 MinAllowedWeights: u16 = 50;
@@ -70,6 +71,7 @@ ActivityCutoff: u16 = 5000; // [5000 @ 7,163]
 MaxRegistrationsPerBlock: u16 = 1;
 PruningScore : u16 = u16::MAX;
 BondsMovingAverage: u64 = 900_000;
+BondsPenalty: u16 = 0;
 WeightsVersionKey: u64 = 400;
 MinDifficulty: u64 = 10_000_000;
 MaxDifficulty: u64 = u64::MAX / 4;
diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs
index abbcd0f16..af9b68051 100644
--- a/pallets/admin-utils/src/benchmarking.rs
+++ b/pallets/admin-utils/src/benchmarking.rs
@@ -100,6 +100,14 @@ mod benchmarks {
 		_(RawOrigin::Root, 1u16/*netuid*/, 100u64/*bonds_moving_average*/)/*sudo_set_bonds_moving_average*/;
     }
 
+    #[benchmark]
+    fn sudo_set_bonds_penalty() {
+        pallet_subtensor::Pallet::<T>::init_new_network(1u16 /*netuid*/, 1u16 /*tempo*/);
+
+        #[extrinsic_call]
+        _(RawOrigin::Root, 1u16/*netuid*/, 100u16/*bonds_penalty*/)/*sudo_set_bonds_penalty*/;
+    }
+
     #[benchmark]
     fn sudo_set_max_allowed_validators() {
         pallet_subtensor::Pallet::<T>::init_new_network(1u16 /*netuid*/, 1u16 /*tempo*/);
diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs
index f6b132148..7de39aa38 100644
--- a/pallets/admin-utils/src/lib.rs
+++ b/pallets/admin-utils/src/lib.rs
@@ -685,6 +685,31 @@ pub mod pallet {
             Ok(())
         }
 
+        /// The extrinsic sets the bonds penalty for a subnet.
+        /// It is only callable by the root account or subnet owner.
+        /// The extrinsic will call the Subtensor pallet to set the bonds penalty.
+        #[pallet::call_index(60)]
+        #[pallet::weight(<T as Config>::WeightInfo::sudo_set_bonds_penalty())]
+        pub fn sudo_set_bonds_penalty(
+            origin: OriginFor<T>,
+            netuid: u16,
+            bonds_penalty: u16,
+        ) -> DispatchResult {
+            pallet_subtensor::Pallet::<T>::ensure_subnet_owner_or_root(origin, netuid)?;
+
+            ensure!(
+                pallet_subtensor::Pallet::<T>::if_subnet_exist(netuid),
+                Error::<T>::SubnetDoesNotExist
+            );
+            pallet_subtensor::Pallet::<T>::set_bonds_penalty(netuid, bonds_penalty);
+            log::debug!(
+                "BondsPenalty( netuid: {:?} bonds_penalty: {:?} ) ",
+                netuid,
+                bonds_penalty
+            );
+            Ok(())
+        }
+
         /// The extrinsic sets the maximum registrations per block for a subnet.
         /// It is only callable by the root account.
         /// The extrinsic will call the Subtensor pallet to set the maximum registrations per block.
diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs
index b2dbb66c0..5517196f1 100644
--- a/pallets/admin-utils/src/tests/mock.rs
+++ b/pallets/admin-utils/src/tests/mock.rs
@@ -86,6 +86,7 @@ parameter_types! {
     pub const InitialImmunityPeriod: u16 = 2;
     pub const InitialMaxAllowedUids: u16 = 2;
     pub const InitialBondsMovingAverage: u64 = 900_000;
+    pub const InitialBondsPenalty: u16 = 0;
     pub const InitialStakePruningMin: u16 = 0;
     pub const InitialFoundationDistribution: u64 = 0;
     pub const InitialDefaultDelegateTake: u16 = 11_796; // 18% honest number.
@@ -163,6 +164,7 @@ impl pallet_subtensor::Config for Test {
     type InitialMaxRegistrationsPerBlock = InitialMaxRegistrationsPerBlock;
     type InitialPruningScore = InitialPruningScore;
     type InitialBondsMovingAverage = InitialBondsMovingAverage;
+    type InitialBondsPenalty = InitialBondsPenalty;
     type InitialMaxAllowedValidators = InitialMaxAllowedValidators;
     type InitialDefaultDelegateTake = InitialDefaultDelegateTake;
     type InitialMinDelegateTake = InitialMinDelegateTake;
diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs
index 01fb985d9..a3b771444 100644
--- a/pallets/admin-utils/src/tests/mod.rs
+++ b/pallets/admin-utils/src/tests/mod.rs
@@ -741,6 +741,39 @@ fn test_sudo_set_bonds_moving_average() {
     });
 }
 
+#[test]
+fn test_sudo_set_bonds_penalty() {
+    new_test_ext().execute_with(|| {
+        let netuid: u16 = 1;
+        let to_be_set: u16 = 10;
+        add_network(netuid, 10);
+        let init_value: u16 = SubtensorModule::get_bonds_penalty(netuid);
+        assert_eq!(
+            AdminUtils::sudo_set_bonds_penalty(
+                <<Test as Config>::RuntimeOrigin>::signed(U256::from(1)),
+                netuid,
+                to_be_set
+            ),
+            Err(DispatchError::BadOrigin)
+        );
+        assert_eq!(
+            AdminUtils::sudo_set_bonds_penalty(
+                <<Test as Config>::RuntimeOrigin>::root(),
+                netuid + 1,
+                to_be_set
+            ),
+            Err(Error::<Test>::SubnetDoesNotExist.into())
+        );
+        assert_eq!(SubtensorModule::get_bonds_penalty(netuid), init_value);
+        assert_ok!(AdminUtils::sudo_set_bonds_penalty(
+            <<Test as Config>::RuntimeOrigin>::root(),
+            netuid,
+            to_be_set
+        ));
+        assert_eq!(SubtensorModule::get_bonds_penalty(netuid), to_be_set);
+    });
+}
+
 #[test]
 fn test_sudo_set_rao_recycled() {
     new_test_ext().execute_with(|| {
diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs
index cb7017023..6ef952354 100644
--- a/pallets/admin-utils/src/weights.rs
+++ b/pallets/admin-utils/src/weights.rs
@@ -42,6 +42,7 @@ pub trait WeightInfo {
 	fn sudo_set_weights_set_rate_limit() -> Weight;
 	fn sudo_set_weights_version_key() -> Weight;
 	fn sudo_set_bonds_moving_average() -> Weight;
+	fn sudo_set_bonds_penalty() -> Weight;
 	fn sudo_set_max_allowed_validators() -> Weight;
 	fn sudo_set_difficulty() -> Weight;
 	fn sudo_set_adjustment_interval() -> Weight;
@@ -182,6 +183,19 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
 	}
 	/// Storage: SubtensorModule NetworksAdded (r:1 w:0)
 	/// Proof Skipped: SubtensorModule NetworksAdded (max_values: None, max_size: None, mode: Measured)
+	/// Storage: SubtensorModule BondsPenalty (r:0 w:1)
+	/// Proof Skipped: SubtensorModule BondsPenalty (max_values: None, max_size: None, mode: Measured)
+	fn sudo_set_bonds_penalty() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `1111`
+		//  Estimated: `4697`
+		// Minimum execution time: 46_099_000 picoseconds.
+		Weight::from_parts(47_510_000, 4697)
+			.saturating_add(T::DbWeight::get().reads(1_u64))
+			.saturating_add(T::DbWeight::get().writes(1_u64))
+	}
+	/// Storage: SubtensorModule NetworksAdded (r:1 w:0)
+	/// Proof Skipped: SubtensorModule NetworksAdded (max_values: None, max_size: None, mode: Measured)
 	/// Storage: SubtensorModule MaxAllowedUids (r:1 w:0)
 	/// Proof Skipped: SubtensorModule MaxAllowedUids (max_values: None, max_size: None, mode: Measured)
 	/// Storage: SubtensorModule MaxAllowedValidators (r:0 w:1)
@@ -559,6 +573,19 @@ impl WeightInfo for () {
 	}
 	/// Storage: SubtensorModule NetworksAdded (r:1 w:0)
 	/// Proof Skipped: SubtensorModule NetworksAdded (max_values: None, max_size: None, mode: Measured)
+	/// Storage: SubtensorModule BondsPenalty (r:0 w:1)
+	/// Proof Skipped: SubtensorModule BondsPenalty (max_values: None, max_size: None, mode: Measured)
+	fn sudo_set_bonds_penalty() -> Weight {
+		// Proof Size summary in bytes:
+		//  Measured:  `1111`
+		//  Estimated: `4697`
+		// Minimum execution time: 46_099_000 picoseconds.
+		Weight::from_parts(47_510_000, 4697)
+			.saturating_add(RocksDbWeight::get().reads(1_u64))
+			.saturating_add(RocksDbWeight::get().writes(1_u64))
+	}
+	/// Storage: SubtensorModule NetworksAdded (r:1 w:0)
+	/// Proof Skipped: SubtensorModule NetworksAdded (max_values: None, max_size: None, mode: Measured)
 	/// Storage: SubtensorModule MaxAllowedUids (r:1 w:0)
 	/// Proof Skipped: SubtensorModule MaxAllowedUids (max_values: None, max_size: None, mode: Measured)
 	/// Storage: SubtensorModule MaxAllowedValidators (r:0 w:1)
diff --git a/pallets/subtensor/src/epoch/math.rs b/pallets/subtensor/src/epoch/math.rs
index 57d0f6b6f..616a9b78b 100644
--- a/pallets/subtensor/src/epoch/math.rs
+++ b/pallets/subtensor/src/epoch/math.rs
@@ -1022,6 +1022,90 @@ pub fn weighted_median_col_sparse(
     median
 }
 
+// Element-wise interpolation of two matrices: Result = A + ratio * (B - A).
+// ratio has intended range [0, 1]
+// ratio=0: Result = A
+// ratio=1: Result = B
+#[allow(dead_code)]
+pub fn interpolate(mat1: &[Vec<I32F32>], mat2: &[Vec<I32F32>], ratio: I32F32) -> Vec<Vec<I32F32>> {
+    if ratio == I32F32::from_num(0) {
+        return mat1.to_owned();
+    }
+    if ratio == I32F32::from_num(1) {
+        return mat2.to_owned();
+    }
+    assert!(mat1.len() == mat2.len());
+    if mat1.is_empty() {
+        return vec![vec![]; 1];
+    }
+    if mat1.first().unwrap_or(&vec![]).is_empty() {
+        return vec![vec![]; 1];
+    }
+    let mut result: Vec<Vec<I32F32>> =
+        vec![vec![I32F32::from_num(0); mat1.first().unwrap_or(&vec![]).len()]; mat1.len()];
+    for (i, (row1, row2)) in mat1.iter().zip(mat2.iter()).enumerate() {
+        assert!(row1.len() == row2.len());
+        for (j, (&v1, &v2)) in row1.iter().zip(row2.iter()).enumerate() {
+            if let Some(res) = result.get_mut(i).unwrap_or(&mut vec![]).get_mut(j) {
+                *res = v1.saturating_add(ratio.saturating_mul(v2.saturating_sub(v1)));
+            }
+        }
+    }
+    result
+}
+
+// Element-wise interpolation of two sparse matrices: Result = A + ratio * (B - A).
+// ratio has intended range [0, 1]
+// ratio=0: Result = A
+// ratio=1: Result = B
+#[allow(dead_code)]
+pub fn interpolate_sparse(
+    mat1: &[Vec<(u16, I32F32)>],
+    mat2: &[Vec<(u16, I32F32)>],
+    columns: u16,
+    ratio: I32F32,
+) -> Vec<Vec<(u16, I32F32)>> {
+    if ratio == I32F32::from_num(0) {
+        return mat1.to_owned();
+    }
+    if ratio == I32F32::from_num(1) {
+        return mat2.to_owned();
+    }
+    assert!(mat1.len() == mat2.len());
+    let rows = mat1.len();
+    let zero: I32F32 = I32F32::from_num(0);
+    let mut result: Vec<Vec<(u16, I32F32)>> = vec![vec![]; rows];
+    for i in 0..rows {
+        let mut row1: Vec<I32F32> = vec![zero; columns as usize];
+        if let Some(row) = mat1.get(i) {
+            for (j, value) in row {
+                if let Some(entry) = row1.get_mut(*j as usize) {
+                    *entry = *value;
+                }
+            }
+        }
+        let mut row2: Vec<I32F32> = vec![zero; columns as usize];
+        if let Some(row) = mat2.get(i) {
+            for (j, value) in row {
+                if let Some(entry) = row2.get_mut(*j as usize) {
+                    *entry = *value;
+                }
+            }
+        }
+        for j in 0..columns as usize {
+            let v1 = row1.get(j).unwrap_or(&zero);
+            let v2 = row2.get(j).unwrap_or(&zero);
+            let interp = v1.saturating_add(ratio.saturating_mul(v2.saturating_sub(*v1)));
+            if zero < interp {
+                if let Some(res) = result.get_mut(i) {
+                    res.push((j as u16, interp));
+                }
+            }
+        }
+    }
+    result
+}
+
 // Element-wise product of two matrices.
 #[allow(dead_code)]
 pub fn hadamard(mat1: &[Vec<I32F32>], mat2: &[Vec<I32F32>]) -> Vec<Vec<I32F32>> {
diff --git a/pallets/subtensor/src/epoch/run_epoch.rs b/pallets/subtensor/src/epoch/run_epoch.rs
index be06ed59f..e6edd2585 100644
--- a/pallets/subtensor/src/epoch/run_epoch.rs
+++ b/pallets/subtensor/src/epoch/run_epoch.rs
@@ -137,18 +137,22 @@ impl<T: Config> Pallet<T> {
         // Compute preranks: r_j = SUM(i) w_ij * s_i
         let preranks: Vec<I32F32> = matmul(&weights, &active_stake);
 
-        // Clip weights at majority consensus
-        let kappa: I32F32 = Self::get_float_kappa(netuid); // consensus majority ratio, e.g. 51%.
+        // Consensus majority ratio, e.g. 51%.
+        let kappa: I32F32 = Self::get_float_kappa(netuid);
+        // Calculate consensus as stake-weighted median of weights.
         let consensus: Vec<I32F32> = weighted_median_col(&active_stake, &weights, kappa);
-        inplace_col_clip(&mut weights, &consensus);
-        let validator_trust: Vec<I32F32> = row_sum(&weights);
+        // Clip weights at majority consensus.
+        let mut clipped_weights: Vec<Vec<I32F32>> = weights.clone();
+        inplace_col_clip(&mut clipped_weights, &consensus);
+        // Calculate validator trust as sum of clipped weights set by validator.
+        let validator_trust: Vec<I32F32> = row_sum(&clipped_weights);
 
         // ====================================
         // == Ranks, Server Trust, Incentive ==
         // ====================================
 
         // Compute ranks: r_j = SUM(i) w_ij * s_i
-        let mut ranks: Vec<I32F32> = matmul(&weights, &active_stake);
+        let mut ranks: Vec<I32F32> = matmul(&clipped_weights, &active_stake);
 
         // Compute server trust: ratio of rank after vs. rank before.
         let trust: Vec<I32F32> = vecdiv(&ranks, &preranks);
@@ -161,6 +165,14 @@ impl<T: Config> Pallet<T> {
         // == Bonds and Dividends ==
         // =========================
 
+        // Get validator bonds penalty in [0, 1].
+        let bonds_penalty: I32F32 = Self::get_float_bonds_penalty(netuid);
+        // Calculate weights for bonds, apply bonds penalty to weights.
+        // bonds_penalty = 0: weights_for_bonds = weights.clone()
+        // bonds_penalty = 1: weights_for_bonds = clipped_weights.clone()
+        let weights_for_bonds: Vec<Vec<I32F32>> =
+            interpolate(&weights, &clipped_weights, bonds_penalty);
+
         // Access network bonds.
         let mut bonds: Vec<Vec<I32F32>> = Self::get_bonds(netuid);
         inplace_mask_matrix(&outdated, &mut bonds); // mask outdated bonds
@@ -168,7 +180,7 @@ impl<T: Config> Pallet<T> {
         log::trace!("B:\n{:?}\n", &bonds);
 
         // Compute bonds delta column normalized.
-        let mut bonds_delta: Vec<Vec<I32F32>> = row_hadamard(&weights, &active_stake); // ΔB = W◦S
+        let mut bonds_delta: Vec<Vec<I32F32>> = row_hadamard(&weights_for_bonds, &active_stake); // ΔB = W◦S
         inplace_col_normalize(&mut bonds_delta); // sum_i b_ij = 1
         log::trace!("ΔB:\n{:?}\n", &bonds_delta);
         // Compute the Exponential Moving Average (EMA) of bonds.
@@ -474,15 +486,18 @@ impl<T: Config> Pallet<T> {
         let preranks: Vec<I32F32> = matmul_sparse(&weights, &active_stake, n);
         log::trace!("Ranks (before): {:?}", &preranks);
 
-        // Clip weights at majority consensus
-        let kappa: I32F32 = Self::get_float_kappa(netuid); // consensus majority ratio, e.g. 51%.
+        // Consensus majority ratio, e.g. 51%.
+        let kappa: I32F32 = Self::get_float_kappa(netuid);
+        // Calculate consensus as stake-weighted median of weights.
         let consensus: Vec<I32F32> = weighted_median_col_sparse(&active_stake, &weights, n, kappa);
         log::trace!("Consensus: {:?}", &consensus);
 
-        weights = col_clip_sparse(&weights, &consensus);
-        log::trace!("Weights: {:?}", &weights);
+        // Clip weights at majority consensus.
+        let clipped_weights: Vec<Vec<(u16, I32F32)>> = col_clip_sparse(&weights, &consensus);
+        log::trace!("Clipped Weights: {:?}", &clipped_weights);
 
-        let validator_trust: Vec<I32F32> = row_sum_sparse(&weights);
+        // Calculate validator trust as sum of clipped weights set by validator.
+        let validator_trust: Vec<I32F32> = row_sum_sparse(&clipped_weights);
         log::trace!("Validator Trust: {:?}", &validator_trust);
 
         // =============================
@@ -490,7 +505,7 @@ impl<T: Config> Pallet<T> {
         // =============================
 
         // Compute ranks: r_j = SUM(i) w_ij * s_i.
-        let mut ranks: Vec<I32F32> = matmul_sparse(&weights, &active_stake, n);
+        let mut ranks: Vec<I32F32> = matmul_sparse(&clipped_weights, &active_stake, n);
         log::trace!("Ranks (after): {:?}", &ranks);
 
         // Compute server trust: ratio of rank after vs. rank before.
@@ -505,6 +520,14 @@ impl<T: Config> Pallet<T> {
         // == Bonds and Dividends ==
         // =========================
 
+        // Get validator bonds penalty in [0, 1].
+        let bonds_penalty: I32F32 = Self::get_float_bonds_penalty(netuid);
+        // Calculate weights for bonds, apply bonds penalty to weights.
+        // bonds_penalty = 0: weights_for_bonds = weights.clone()
+        // bonds_penalty = 1: weights_for_bonds = clipped_weights.clone()
+        let weights_for_bonds: Vec<Vec<(u16, I32F32)>> =
+            interpolate_sparse(&weights, &clipped_weights, n, bonds_penalty);
+
         // Access network bonds.
         let mut bonds: Vec<Vec<(u16, I32F32)>> = Self::get_bonds_sparse(netuid);
         log::trace!("B: {:?}", &bonds);
@@ -523,7 +546,8 @@ impl<T: Config> Pallet<T> {
         log::trace!("B (mask+norm): {:?}", &bonds);
 
         // Compute bonds delta column normalized.
-        let mut bonds_delta: Vec<Vec<(u16, I32F32)>> = row_hadamard_sparse(&weights, &active_stake); // ΔB = W◦S (outdated W masked)
+        let mut bonds_delta: Vec<Vec<(u16, I32F32)>> =
+            row_hadamard_sparse(&weights_for_bonds, &active_stake); // ΔB = W◦S (outdated W masked)
         log::trace!("ΔB: {:?}", &bonds_delta);
 
         // Normalize bonds delta.
@@ -713,6 +737,9 @@ impl<T: Config> Pallet<T> {
     pub fn get_float_kappa(netuid: u16) -> I32F32 {
         I32F32::from_num(Self::get_kappa(netuid)).saturating_div(I32F32::from_num(u16::MAX))
     }
+    pub fn get_float_bonds_penalty(netuid: u16) -> I32F32 {
+        I32F32::from_num(Self::get_bonds_penalty(netuid)).saturating_div(I32F32::from_num(u16::MAX))
+    }
 
     pub fn get_block_at_registration(netuid: u16) -> Vec<u64> {
         let n = Self::get_subnetwork_n(netuid);
diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 6ecb69c87..9c4c5d0d4 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -572,6 +572,11 @@ pub mod pallet {
     pub fn DefaultBondsMovingAverage<T: Config>() -> u64 {
         T::InitialBondsMovingAverage::get()
     }
+    /// Default bonds penalty.
+    #[pallet::type_value]
+    pub fn DefaultBondsPenalty<T: Config>() -> u16 {
+        T::InitialBondsPenalty::get()
+    }
     #[pallet::type_value]
     /// Default validator prune length.
     pub fn DefaultValidatorPruneLen<T: Config>() -> u64 {
@@ -1184,6 +1189,10 @@ pub mod pallet {
     /// --- MAP ( netuid ) --> bonds_moving_average
     pub type BondsMovingAverage<T> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBondsMovingAverage<T>>;
+    #[pallet::storage]
+    /// --- MAP ( netuid ) --> bonds_penalty
+    pub type BondsPenalty<T> =
+        StorageMap<_, Identity, u16, u16, ValueQuery, DefaultBondsPenalty<T>>;
     /// --- MAP ( netuid ) --> weights_set_rate_limit
     #[pallet::storage]
     pub type WeightsSetRateLimit<T> =
diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs
index 6595c8a43..49bb44dc1 100644
--- a/pallets/subtensor/src/macros/config.rs
+++ b/pallets/subtensor/src/macros/config.rs
@@ -93,6 +93,9 @@ mod config {
         /// Initial bonds moving average.
         #[pallet::constant]
         type InitialBondsMovingAverage: Get<u64>;
+        /// Initial bonds penalty.
+        #[pallet::constant]
+        type InitialBondsPenalty: Get<u16>;
         /// Initial target registrations per interval.
         #[pallet::constant]
         type InitialTargetRegistrationsPerInterval: Get<u16>;
diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs
index 9c83b77c7..6dd6ddad2 100644
--- a/pallets/subtensor/src/macros/events.rs
+++ b/pallets/subtensor/src/macros/events.rs
@@ -57,6 +57,8 @@ mod events {
         ImmunityPeriodSet(u16, u16),
         /// bonds moving average is set for a subnet.
         BondsMovingAverageSet(u16, u64),
+        /// bonds penalty is set for a subnet.
+        BondsPenaltySet(u16, u16),
         /// setting the max number of allowed validators on a subnet.
         MaxAllowedValidatorsSet(u16, u16),
         /// the axon server information is added to the network.
diff --git a/pallets/subtensor/src/tests/epoch.rs b/pallets/subtensor/src/tests/epoch.rs
index 43ac6b98c..7973a44e1 100644
--- a/pallets/subtensor/src/tests/epoch.rs
+++ b/pallets/subtensor/src/tests/epoch.rs
@@ -154,10 +154,14 @@ fn init_run_epochs(
     random_weights: bool,
     random_seed: u64,
     sparse: bool,
+    bonds_penalty: u16,
 ) {
     // === Create the network
     add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead
 
+    // === Set bonds penalty
+    SubtensorModule::set_bonds_penalty(netuid, bonds_penalty);
+
     // === Register uids
     SubtensorModule::set_max_allowed_uids(netuid, n);
     for key in 0..n {
@@ -403,21 +407,25 @@ fn init_run_epochs(
 //     let epochs: u16 = 1;
 //     let interleave = 2;
 //     log::info!("test_consensus_guarantees ({network_n:?}, {validators_n:?} validators)");
-//     for (major_stake, major_weight, minor_weight, weight_stddev) in vec![
-//         (0.51, 1., 1., 0.001),
-//         (0.51, 0.03, 0., 0.001),
-//         (0.51, 0.51, 0.49, 0.001),
-//         (0.51, 0.51, 1., 0.001),
-//         (0.51, 0.61, 0.8, 0.1),
-//         (0.6, 0.67, 0.65, 0.2),
-//         (0.6, 0.74, 0.77, 0.4),
-//         (0.6, 0.76, 0.8, 0.4),
-//         (0.6, 0.76, 1., 0.4),
-//         (0.6, 0.92, 1., 0.4),
-//         (0.6, 0.94, 1., 0.4),
-//         (0.65, 0.78, 0.85, 0.6),
-//         (0.7, 0.81, 0.85, 0.8),
-//         (0.7, 0.83, 0.85, 1.),
+//     for (major_stake, major_weight, minor_weight, weight_stddev, bonds_penalty) in vec![
+// 		   (0.51, 1., 1., 0.001, u16::MAX),
+// 		   (0.51, 0.03, 0., 0.001, u16::MAX),
+// 		   (0.51, 0.51, 0.49, 0.001, u16::MAX),
+// 		   (0.51, 0.51, 1., 0.001, u16::MAX),
+// 		   (0.51, 0.61, 0.8, 0.1, u16::MAX),
+// 		   (0.6, 0.67, 0.65, 0.2, u16::MAX),
+// 		   (0.6, 0.74, 0.77, 0.4, u16::MAX),
+// 		   (0.6, 0.76, 0.8, 0.4, u16::MAX),
+// 		   (0.6, 0.73, 1., 0.4, u16::MAX), // bonds_penalty = 100%
+// 		   (0.6, 0.74, 1., 0.4, 55800), // bonds_penalty = 85%
+// 		   (0.6, 0.76, 1., 0.4, 43690), // bonds_penalty = 66%
+// 		   (0.6, 0.78, 1., 0.4, 21845), // bonds_penalty = 33%
+// 		   (0.6, 0.79, 1., 0.4, 0), // bonds_penalty = 0%
+// 		   (0.6, 0.92, 1., 0.4, u16::MAX),
+// 		   (0.6, 0.94, 1., 0.4, u16::MAX),
+// 		   (0.65, 0.78, 0.85, 0.6, u16::MAX),
+// 		   (0.7, 0.81, 0.85, 0.8, u16::MAX),
+// 		   (0.7, 0.83, 0.85, 1., u16::MAX),
 //     ] {
 //         let (
 //             validators,
@@ -455,6 +463,7 @@ fn init_run_epochs(
 //                 false,
 //                 0,
 //                 false,
+//                 bonds_penalty
 //             );
 
 //             let mut major_emission: I64F64 = I64F64::from_num(0);
@@ -698,6 +707,7 @@ fn test_512_graph() {
                     false,
                     0,
                     false,
+                    u16::MAX,
                 );
                 let bonds = SubtensorModule::get_bonds(netuid);
                 for uid in validators {
@@ -744,96 +754,99 @@ fn test_512_graph_random_weights() {
     let epochs: u16 = 1;
     log::info!("test_{network_n:?}_graph_random_weights ({validators_n:?} validators)");
     for interleave in 0..3 {
+        // server-self weight off/on
         for server_self in [false, true] {
-            // server-self weight off/on
-            let (validators, servers) = distribute_nodes(
-                validators_n as usize,
-                network_n as usize,
-                interleave as usize,
-            );
-            let server: usize = servers[0] as usize;
-            let validator: usize = validators[0] as usize;
-            #[allow(clippy::type_complexity)]
-            let (mut rank, mut incentive, mut dividend, mut emission, mut bondv, mut bonds): (
-                Vec<u16>,
-                Vec<u16>,
-                Vec<u16>,
-                Vec<u64>,
-                Vec<I32F32>,
-                Vec<I32F32>,
-            ) = (vec![], vec![], vec![], vec![], vec![], vec![]);
-
-            // Dense epoch
-            new_test_ext(1).execute_with(|| {
-                init_run_epochs(
-                    netuid,
-                    network_n,
-                    &validators,
-                    &servers,
-                    epochs,
-                    1,
-                    server_self,
-                    &[],
-                    false,
-                    &[],
-                    false,
-                    true,
-                    interleave as u64,
-                    false,
+            for bonds_penalty in [0, u16::MAX / 2, u16::MAX] {
+                let (validators, servers) = distribute_nodes(
+                    validators_n as usize,
+                    network_n as usize,
+                    interleave as usize,
                 );
+                let server: usize = servers[0] as usize;
+                let validator: usize = validators[0] as usize;
+                let (mut rank, mut incentive, mut dividend, mut emission, mut bondv, mut bonds): (
+                    Vec<u16>,
+                    Vec<u16>,
+                    Vec<u16>,
+                    Vec<u64>,
+                    Vec<I32F32>,
+                    Vec<I32F32>,
+                ) = (vec![], vec![], vec![], vec![], vec![], vec![]);
+
+                // Dense epoch
+                new_test_ext(1).execute_with(|| {
+                    init_run_epochs(
+                        netuid,
+                        network_n,
+                        &validators,
+                        &servers,
+                        epochs,
+                        1,
+                        server_self,
+                        &[],
+                        false,
+                        &[],
+                        false,
+                        true,
+                        interleave as u64,
+                        false,
+                        bonds_penalty,
+                    );
 
-                let bond = SubtensorModule::get_bonds(netuid);
-                for uid in 0..network_n {
-                    rank.push(SubtensorModule::get_rank_for_uid(netuid, uid));
-                    incentive.push(SubtensorModule::get_incentive_for_uid(netuid, uid));
-                    dividend.push(SubtensorModule::get_dividends_for_uid(netuid, uid));
-                    emission.push(SubtensorModule::get_emission_for_uid(netuid, uid));
-                    bondv.push(bond[uid as usize][validator]);
-                    bonds.push(bond[uid as usize][server]);
-                }
-            });
+                    let bond = SubtensorModule::get_bonds(netuid);
+                    for uid in 0..network_n {
+                        rank.push(SubtensorModule::get_rank_for_uid(netuid, uid));
+                        incentive.push(SubtensorModule::get_incentive_for_uid(netuid, uid));
+                        dividend.push(SubtensorModule::get_dividends_for_uid(netuid, uid));
+                        emission.push(SubtensorModule::get_emission_for_uid(netuid, uid));
+                        bondv.push(bond[uid as usize][validator]);
+                        bonds.push(bond[uid as usize][server]);
+                    }
+                });
 
-            // Sparse epoch (same random seed as dense)
-            new_test_ext(1).execute_with(|| {
-                init_run_epochs(
-                    netuid,
-                    network_n,
-                    &validators,
-                    &servers,
-                    epochs,
-                    1,
-                    server_self,
-                    &[],
-                    false,
-                    &[],
-                    false,
-                    true,
-                    interleave as u64,
-                    true,
-                );
-                // Assert that dense and sparse epoch results are equal
-                let bond = SubtensorModule::get_bonds(netuid);
-                for uid in 0..network_n {
-                    assert_eq!(
-                        SubtensorModule::get_rank_for_uid(netuid, uid),
-                        rank[uid as usize]
-                    );
-                    assert_eq!(
-                        SubtensorModule::get_incentive_for_uid(netuid, uid),
-                        incentive[uid as usize]
-                    );
-                    assert_eq!(
-                        SubtensorModule::get_dividends_for_uid(netuid, uid),
-                        dividend[uid as usize]
-                    );
-                    assert_eq!(
-                        SubtensorModule::get_emission_for_uid(netuid, uid),
-                        emission[uid as usize]
+                // Sparse epoch (same random seed as dense)
+                new_test_ext(1).execute_with(|| {
+                    init_run_epochs(
+                        netuid,
+                        network_n,
+                        &validators,
+                        &servers,
+                        epochs,
+                        1,
+                        server_self,
+                        &[],
+                        false,
+                        &[],
+                        false,
+                        true,
+                        interleave as u64,
+                        true,
+                        bonds_penalty,
                     );
-                    assert_eq!(bond[uid as usize][validator], bondv[uid as usize]);
-                    assert_eq!(bond[uid as usize][server], bonds[uid as usize]);
-                }
-            });
+                    // Assert that dense and sparse epoch results are equal
+                    let bond = SubtensorModule::get_bonds(netuid);
+                    for uid in 0..network_n {
+                        assert_eq!(
+                            SubtensorModule::get_rank_for_uid(netuid, uid),
+                            rank[uid as usize]
+                        );
+                        assert_eq!(
+                            SubtensorModule::get_incentive_for_uid(netuid, uid),
+                            incentive[uid as usize]
+                        );
+                        assert_eq!(
+                            SubtensorModule::get_dividends_for_uid(netuid, uid),
+                            dividend[uid as usize]
+                        );
+                        assert_eq!(
+                            SubtensorModule::get_emission_for_uid(netuid, uid),
+                            emission[uid as usize]
+                        );
+                        assert_eq!(bond[uid as usize][validator], bondv[uid as usize]);
+                        assert_eq!(bond[uid as usize][server], bonds[uid as usize]);
+                    }
+                });
+            }
         }
     }
 }
@@ -873,6 +886,7 @@ fn test_512_graph_random_weights() {
 //                     false,
 //                     0,
 //                     true,
+//                     u16::MAX,
 //                 );
 //                 let (total_stake, _, _) = SubtensorModule::get_stake_weights_for_network(netuid);
 //                 assert_eq!(total_stake.iter().map(|s| s.to_num::<u64>()).sum::<u64>(), 21_000_000_000_000_000);
@@ -940,6 +954,7 @@ fn test_512_graph_random_weights() {
 //             false,
 //             0,
 //             true,
+//             u16::MAX,
 //         );
 //         let bonds = SubtensorModule::get_bonds(netuid);
 //         for uid in validators {
@@ -995,6 +1010,8 @@ fn test_bonds() {
 		SubtensorModule::set_weights_set_rate_limit( netuid, 0 );
         SubtensorModule::set_min_allowed_weights( netuid, 1 );
         SubtensorModule::set_max_weight_limit( netuid, u16::MAX );
+		SubtensorModule::set_bonds_penalty(netuid, u16::MAX);
+
 
 		// === Register [validator1, validator2, validator3, validator4, server1, server2, server3, server4]
 		for key in 0..n as u64 {
@@ -1752,6 +1769,7 @@ fn test_outdated_weights() {
         SubtensorModule::set_target_registrations_per_interval(netuid, n);
         SubtensorModule::set_min_allowed_weights(netuid, 0);
         SubtensorModule::set_max_weight_limit(netuid, u16::MAX);
+        SubtensorModule::set_bonds_penalty(netuid, u16::MAX);
         assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 0);
 
         // === Register [validator1, validator2, server1, server2]
@@ -2817,6 +2835,7 @@ fn test_blocks_since_last_step() {
 //     let epochs: u16 = 1;
 //     let interleave = 0;
 //     let weight_stddev: I32F32 = fixed(0.4);
+//     let bonds_penalty: u16 = u16::MAX;
 //     println!("[");
 //     for _major_stake in vec![0.51, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.99] {
 //         let major_stake: I32F32 = I32F32::from_num(_major_stake);
@@ -2846,7 +2865,7 @@ fn test_blocks_since_last_step() {
 //                 );
 //
 //                 new_test_ext(1).execute_with(|| {
-// 					init_run_epochs(netuid, network_n, &validators, &servers, epochs, 1, true, &stake, true, &weights, true, false, 0, true);
+// 					init_run_epochs(netuid, network_n, &validators, &servers, epochs, 1, true, &stake, true, &weights, true, false, 0, true, bonds_penalty);
 //
 // 					let mut major_emission: I64F64 = I64F64::from_num(0);
 // 					let mut minor_emission: I64F64 = I64F64::from_num(0);
diff --git a/pallets/subtensor/src/tests/math.rs b/pallets/subtensor/src/tests/math.rs
index c5aaca84c..84fcc4aac 100644
--- a/pallets/subtensor/src/tests/math.rs
+++ b/pallets/subtensor/src/tests/math.rs
@@ -1716,6 +1716,240 @@ fn test_math_weighted_median_col_sparse() {
     );
 }
 
+#[test]
+fn test_math_interpolate() {
+    let mat1: Vec<Vec<I32F32>> = vec![vec![]];
+    let mat2: Vec<Vec<I32F32>> = vec![vec![]];
+    let target: Vec<Vec<I32F32>> = vec![vec![]];
+    let ratio = I32F32::from_num(0);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let mat1: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(0)]];
+    let mat2: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(1)]];
+    let target: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(0)]];
+    let ratio = I32F32::from_num(0);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(1)]];
+    let ratio = I32F32::from_num(1);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let mat1: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat2: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let target: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat1 = vec_to_mat_fixed(&mat1, 4, false);
+    let mat2 = vec_to_mat_fixed(&mat2, 4, false);
+    let ratio = I32F32::from_num(0);
+    let target = vec_to_mat_fixed(&target, 4, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let ratio = I32F32::from_num(1);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let mat1: Vec<f32> = vec![1., 10., 100., 1000., 10000., 100000.];
+    let mat2: Vec<f32> = vec![10., 100., 1000., 10000., 100000., 1000000.];
+    let target: Vec<f32> = vec![1., 10., 100., 1000., 10000., 100000.];
+    let mat1 = vec_to_mat_fixed(&mat1, 3, false);
+    let mat2 = vec_to_mat_fixed(&mat2, 3, false);
+    let ratio = I32F32::from_num(0);
+    let target = vec_to_mat_fixed(&target, 3, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![9.1, 91., 910., 9100., 91000., 910000.];
+    let ratio = I32F32::from_num(0.9);
+    let target = vec_to_mat_fixed(&target, 3, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0.0001));
+
+    let mat1: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat2: Vec<f32> = vec![1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.];
+    let target: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat1 = vec_to_mat_fixed(&mat1, 4, false);
+    let mat2 = vec_to_mat_fixed(&mat2, 4, false);
+    let ratio = I32F32::from_num(0);
+    let target = vec_to_mat_fixed(&target, 4, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+    ];
+    let ratio = I32F32::from_num(0.000000001);
+    let target = vec_to_mat_fixed(&target, 4, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5];
+    let ratio = I32F32::from_num(0.5);
+    let target = vec_to_mat_fixed(&target, 4, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+    ];
+    let ratio = I32F32::from_num(0.9999998808);
+    let target = vec_to_mat_fixed(&target, 4, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.];
+    let ratio = I32F32::from_num(1);
+    let target = vec_to_mat_fixed(&target, 4, false);
+    let result = interpolate(&mat1, &mat2, ratio);
+    assert_mat_compare(&result, &target, I32F32::from_num(0));
+}
+
+#[test]
+fn test_math_interpolate_sparse() {
+    let mat1: Vec<Vec<(u16, I32F32)>> = vec![vec![]];
+    let mat2: Vec<Vec<(u16, I32F32)>> = vec![vec![]];
+    let target: Vec<Vec<(u16, I32F32)>> = vec![vec![]];
+    let ratio = I32F32::from_num(0);
+    let result = interpolate_sparse(&mat1, &mat2, 0, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let mat1: Vec<f32> = vec![0.];
+    let mat2: Vec<f32> = vec![1.];
+    let target: Vec<f32> = vec![0.];
+    let mat1 = vec_to_sparse_mat_fixed(&mat1, 1, false);
+    let mat2 = vec_to_sparse_mat_fixed(&mat2, 1, false);
+    let ratio = I32F32::from_num(0);
+    let target = vec_to_sparse_mat_fixed(&target, 1, false);
+    let result = interpolate_sparse(&mat1, &mat2, 1, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![0.5];
+    let ratio = I32F32::from_num(0.5);
+    let target = vec_to_sparse_mat_fixed(&target, 1, false);
+    let result = interpolate_sparse(&mat1, &mat2, 1, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![1.];
+    let ratio = I32F32::from_num(1);
+    let target = vec_to_sparse_mat_fixed(&target, 1, false);
+    let result = interpolate_sparse(&mat1, &mat2, 1, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let mat1: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat2: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let target: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false);
+    let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false);
+    let ratio = I32F32::from_num(0);
+    let target = vec_to_sparse_mat_fixed(&target, 4, false);
+    let result = interpolate_sparse(&mat1, &mat2, 3, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let ratio = I32F32::from_num(1);
+    let result = interpolate_sparse(&mat1, &mat2, 3, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let mat1: Vec<f32> = vec![1., 0., 100., 1000., 10000., 100000.];
+    let mat2: Vec<f32> = vec![10., 100., 1000., 10000., 100000., 0.];
+    let target: Vec<f32> = vec![1., 0., 100., 1000., 10000., 100000.];
+    let mat1 = vec_to_sparse_mat_fixed(&mat1, 3, false);
+    let mat2 = vec_to_sparse_mat_fixed(&mat2, 3, false);
+    let ratio = I32F32::from_num(0);
+    let target = vec_to_sparse_mat_fixed(&target, 3, false);
+    let result = interpolate_sparse(&mat1, &mat2, 2, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![9.1, 90., 910., 9100., 91000., 10000.];
+    let ratio = I32F32::from_num(0.9);
+    let target = vec_to_sparse_mat_fixed(&target, 3, false);
+    let result = interpolate_sparse(&mat1, &mat2, 2, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0.0001));
+
+    let mat1: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat2: Vec<f32> = vec![1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.];
+    let target: Vec<f32> = vec![0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.];
+    let mat1 = vec_to_sparse_mat_fixed(&mat1, 4, false);
+    let mat2 = vec_to_sparse_mat_fixed(&mat2, 4, false);
+    let ratio = I32F32::from_num(0);
+    let target = vec_to_sparse_mat_fixed(&target, 4, false);
+    let result = interpolate_sparse(&mat1, &mat2, 3, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+        0.000000001,
+    ];
+    let ratio = I32F32::from_num(0.000000001);
+    let target = vec_to_sparse_mat_fixed(&target, 4, false);
+    let result = interpolate_sparse(&mat1, &mat2, 3, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5];
+    let ratio = I32F32::from_num(0.5);
+    let target = vec_to_sparse_mat_fixed(&target, 4, false);
+    let result = interpolate_sparse(&mat1, &mat2, 3, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+        0.999_999_9,
+    ];
+    let ratio = I32F32::from_num(0.9999998808);
+    let target = vec_to_sparse_mat_fixed(&target, 4, false);
+    let result = interpolate_sparse(&mat1, &mat2, 3, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+
+    let target: Vec<f32> = vec![1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.];
+    let ratio = I32F32::from_num(1);
+    let target = vec_to_sparse_mat_fixed(&target, 4, false);
+    let result = interpolate_sparse(&mat1, &mat2, 3, ratio);
+    assert_sparse_mat_compare(&result, &target, I32F32::from_num(0));
+}
+
 #[test]
 fn test_math_hadamard() {
     let mat2: Vec<f32> = vec![1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.];
diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs
index 9731113e5..9d5f939f6 100644
--- a/pallets/subtensor/src/tests/mock.rs
+++ b/pallets/subtensor/src/tests/mock.rs
@@ -138,6 +138,7 @@ parameter_types! {
     pub const InitialImmunityPeriod: u16 = 2;
     pub const InitialMaxAllowedUids: u16 = 2;
     pub const InitialBondsMovingAverage: u64 = 900_000;
+    pub const InitialBondsPenalty:u16 = 0;
     pub const InitialStakePruningMin: u16 = 0;
     pub const InitialFoundationDistribution: u64 = 0;
     pub const InitialDefaultDelegateTake: u16 = 11_796; // 18%, same as in production
@@ -373,6 +374,7 @@ impl crate::Config for Test {
     type InitialMaxRegistrationsPerBlock = InitialMaxRegistrationsPerBlock;
     type InitialPruningScore = InitialPruningScore;
     type InitialBondsMovingAverage = InitialBondsMovingAverage;
+    type InitialBondsPenalty = InitialBondsPenalty;
     type InitialMaxAllowedValidators = InitialMaxAllowedValidators;
     type InitialDefaultDelegateTake = InitialDefaultDelegateTake;
     type InitialMinDelegateTake = InitialMinDelegateTake;
diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs
index 25f547c5d..f1e0c7eb4 100644
--- a/pallets/subtensor/src/utils/misc.rs
+++ b/pallets/subtensor/src/utils/misc.rs
@@ -566,6 +566,14 @@ impl<T: Config> Pallet<T> {
         Self::deposit_event(Event::BondsMovingAverageSet(netuid, bonds_moving_average));
     }
 
+    pub fn get_bonds_penalty(netuid: u16) -> u16 {
+        BondsPenalty::<T>::get(netuid)
+    }
+    pub fn set_bonds_penalty(netuid: u16, bonds_penalty: u16) {
+        BondsPenalty::<T>::insert(netuid, bonds_penalty);
+        Self::deposit_event(Event::BondsPenaltySet(netuid, bonds_penalty));
+    }
+
     pub fn get_max_registrations_per_block(netuid: u16) -> u16 {
         MaxRegistrationsPerBlock::<T>::get(netuid)
     }
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 36a879e48..e0ea63987 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -1011,6 +1011,7 @@ parameter_types! {
     pub const SubtensorInitialMaxRegistrationsPerBlock: u16 = 1;
     pub const SubtensorInitialPruningScore : u16 = u16::MAX;
     pub const SubtensorInitialBondsMovingAverage: u64 = 900_000;
+    pub const SubtensorInitialBondsPenalty: u16 = 0;
     pub const SubtensorInitialDefaultTake: u16 = 11_796; // 18% honest number.
     pub const SubtensorInitialMinDelegateTake: u16 = 0; // Allow 0% delegate take
     pub const SubtensorInitialDefaultChildKeyTake: u16 = 0; // Allow 0% childkey take
@@ -1058,6 +1059,7 @@ impl pallet_subtensor::Config for Runtime {
     type InitialKappa = SubtensorInitialKappa;
     type InitialMaxAllowedUids = SubtensorInitialMaxAllowedUids;
     type InitialBondsMovingAverage = SubtensorInitialBondsMovingAverage;
+    type InitialBondsPenalty = SubtensorInitialBondsPenalty;
     type InitialIssuance = SubtensorInitialIssuance;
     type InitialMinAllowedWeights = SubtensorInitialMinAllowedWeights;
     type InitialEmissionValue = SubtensorInitialEmissionValue;

From a0819b4d5bb2806a771ba98c0f1a2274b0183cbb Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Fri, 24 Jan 2025 00:43:02 +0800
Subject: [PATCH 055/145] remove byte_to_account_id

---
 runtime/src/precompiles/balance_transfer.rs |  6 +++---
 runtime/src/precompiles/mod.rs              | 12 ------------
 2 files changed, 3 insertions(+), 15 deletions(-)

diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs
index 99d911b02..895e91a62 100644
--- a/runtime/src/precompiles/balance_transfer.rs
+++ b/runtime/src/precompiles/balance_transfer.rs
@@ -9,7 +9,7 @@ use sp_std::vec;
 
 use crate::{Runtime, RuntimeCall};
 
-use crate::precompiles::{bytes_to_account_id, get_method_id, get_slice};
+use crate::precompiles::{get_method_id, get_pubkey, get_slice};
 
 pub const BALANCE_TRANSFER_INDEX: u64 = 2048;
 
@@ -47,8 +47,8 @@ impl BalanceTransferPrecompile {
                 0x62, 0x93, 0x70, 0x5d,
             ];
             let address_bytes_dst: &[u8] = get_slice(txdata, 4, 36)?;
-            let account_id_src = bytes_to_account_id(&ADDRESS_BYTES_SRC)?;
-            let account_id_dst = bytes_to_account_id(address_bytes_dst)?;
+            let (account_id_src, _) = get_pubkey(&ADDRESS_BYTES_SRC)?;
+            let (account_id_dst, _) = get_pubkey(address_bytes_dst)?;
 
             let call =
                 RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index de4f4fc1f..567e7836a 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -124,18 +124,6 @@ pub fn get_method_id(method_signature: &str) -> [u8; 4] {
     [hash[0], hash[1], hash[2], hash[3]]
 }
 
-/// Convert bytes to AccountId32 with PrecompileFailure as Error
-/// which consumes all gas
-///
-pub fn bytes_to_account_id(account_id_bytes: &[u8]) -> Result<AccountId32, PrecompileFailure> {
-    AccountId32::try_from(account_id_bytes).map_err(|_| {
-        log::info!("Error parsing account id bytes {:?}", account_id_bytes);
-        PrecompileFailure::Error {
-            exit_status: ExitError::InvalidRange,
-        }
-    })
-}
-
 /// Takes a slice from bytes with PrecompileFailure as Error
 ///
 pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], PrecompileFailure> {

From 2633e8854606ebad2143179482d2e92d35c3eaf0 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Thu, 23 Jan 2025 11:54:43 -0500
Subject: [PATCH 056/145] fix tests to incl fee (#1186)

---
 pallets/subtensor/src/tests/move_stake.rs | 41 +++++++++++++++++++----
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 04f79f3f9..96d54ed77 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -1080,6 +1080,8 @@ fn test_do_swap_success() {
         let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
+        let fee = DefaultMinStake::<Test>::get();
+
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
@@ -1114,7 +1116,11 @@ fn test_do_swap_success() {
             &coldkey,
             destination_netuid,
         );
-        assert_abs_diff_eq!(alpha_after, stake_amount, epsilon = stake_amount / 1000);
+        assert_abs_diff_eq!(
+            alpha_after,
+            stake_amount - fee,
+            epsilon = stake_amount / 1000
+        );
     });
 }
 
@@ -1259,6 +1265,8 @@ fn test_do_swap_same_subnet() {
         let subnet_owner_hotkey = U256::from(1101);
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
+        let fee = DefaultMinStake::<Test>::get();
+
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
@@ -1268,6 +1276,7 @@ fn test_do_swap_same_subnet() {
 
         let alpha_before =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        let fee_as_alpha = SubtensorModule::swap_tao_for_alpha(netuid, fee);
 
         assert_ok!(SubtensorModule::do_swap_stake(
             RuntimeOrigin::signed(coldkey),
@@ -1279,7 +1288,8 @@ fn test_do_swap_same_subnet() {
 
         let alpha_after =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
-        assert_abs_diff_eq!(alpha_after, alpha_before, epsilon = 5);
+        assert_abs_diff_eq!(alpha_after, alpha_before - fee_as_alpha, epsilon = 15);
+        // Some slippage due to fee on same subnet.
     });
 }
 
@@ -1291,6 +1301,8 @@ fn test_do_swap_partial_stake() {
         let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
+        let fee = DefaultMinStake::<Test>::get();
+
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let total_stake = DefaultMinStake::<Test>::get() * 10;
@@ -1298,6 +1310,7 @@ fn test_do_swap_partial_stake() {
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
         SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake, 0);
 
+        let fee_as_alpha2 = SubtensorModule::swap_tao_for_alpha(destination_netuid, fee);
         let swap_amount = total_stake / 2;
         assert_ok!(SubtensorModule::do_swap_stake(
             RuntimeOrigin::signed(coldkey),
@@ -1322,7 +1335,7 @@ fn test_do_swap_partial_stake() {
                 &coldkey,
                 destination_netuid
             ),
-            swap_amount,
+            swap_amount - fee_as_alpha2,
             epsilon = total_stake / 1000
         );
     });
@@ -1336,6 +1349,8 @@ fn test_do_swap_storage_updates() {
         let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
+        let fee = DefaultMinStake::<Test>::get();
+
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
@@ -1365,13 +1380,15 @@ fn test_do_swap_storage_updates() {
             0
         );
 
+        let fee_as_alpha = SubtensorModule::swap_tao_for_alpha(destination_netuid, fee);
+
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &hotkey,
                 &coldkey,
                 destination_netuid
             ),
-            alpha,
+            alpha - fee_as_alpha,
             epsilon = 5
         );
     });
@@ -1385,6 +1402,8 @@ fn test_do_swap_multiple_times() {
         let netuid1 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let netuid2 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
+        let fee = DefaultMinStake::<Test>::get();
+
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let initial_stake = DefaultMinStake::<Test>::get() * 10;
@@ -1392,6 +1411,7 @@ fn test_do_swap_multiple_times() {
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
         SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid1, initial_stake, 0);
 
+        let mut total_alpha1_fee = 0;
         for _ in 0..3 {
             let alpha1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &hotkey, &coldkey, netuid1,
@@ -1404,6 +1424,9 @@ fn test_do_swap_multiple_times() {
                     netuid2,
                     alpha1
                 ));
+
+                let fee_as_alpha = SubtensorModule::swap_tao_for_alpha(netuid1, fee);
+                total_alpha1_fee += fee_as_alpha;
             }
             let alpha2 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &hotkey, &coldkey, netuid2,
@@ -1416,17 +1439,21 @@ fn test_do_swap_multiple_times() {
                     netuid1,
                     alpha2
                 ));
+
+                let fee_as_alpha = SubtensorModule::swap_tao_for_alpha(netuid1, fee);
+                total_alpha1_fee += fee_as_alpha;
             }
         }
 
-        let final_stake_netuid1 =
+        let final_stake_netuid1: u64 =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid1);
         let final_stake_netuid2 =
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid2);
+        let expected_stake = initial_stake - total_alpha1_fee;
         assert_abs_diff_eq!(
             final_stake_netuid1,
-            initial_stake,
-            epsilon = initial_stake / 1000
+            expected_stake,
+            epsilon = expected_stake / 1000
         );
         assert_eq!(final_stake_netuid2, 0);
     });

From 05b5c6b56389b58290280427d60925824554580a Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Thu, 23 Jan 2025 19:38:54 +0100
Subject: [PATCH 057/145] Disable TotalStake check in try-runtime

---
 pallets/subtensor/src/utils/try_state.rs | 34 +++++++++++++-----------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs
index 46a3ba5e4..c42e75dfe 100644
--- a/pallets/subtensor/src/utils/try_state.rs
+++ b/pallets/subtensor/src/utils/try_state.rs
@@ -17,23 +17,25 @@ impl<T: Config> Pallet<T> {
     pub fn check_accounting_invariants() -> Result<(), sp_runtime::TryRuntimeError> {
         use frame_support::traits::fungible::Inspect;
 
-        // Calculate the total staked amount
-        let total_staked = SubnetTAO::<T>::iter().fold(0u64, |acc, (netuid, stake)| {
-            let acc = acc.saturating_add(stake);
+		// Disabled: https://github.com/opentensor/subtensor/pull/1166
+		//
+        // // Calculate the total staked amount
+        // let total_staked = SubnetTAO::<T>::iter().fold(0u64, |acc, (netuid, stake)| {
+        //     let acc = acc.saturating_add(stake);
 
-            if netuid == Self::get_root_netuid() {
-                // root network doesn't have initial pool TAO
-                acc
-            } else {
-                acc.saturating_sub(POOL_INITIAL_TAO)
-            }
-        });
+        //     if netuid == Self::get_root_netuid() {
+        //         // root network doesn't have initial pool TAO
+        //         acc
+        //     } else {
+        //         acc.saturating_sub(POOL_INITIAL_TAO)
+        //     }
+        // });
 
-        // Verify that the calculated total stake matches the stored TotalStake
-        ensure!(
-            total_staked == TotalStake::<T>::get(),
-            "TotalStake does not match total staked",
-        );
+        // // Verify that the calculated total stake matches the stored TotalStake
+        // ensure!(
+        //     total_staked == TotalStake::<T>::get(),
+        //     "TotalStake does not match total staked",
+        // );
 
         // Get the total subnet locked amount
         let total_subnet_locked = Self::get_total_subnet_locked();
@@ -43,7 +45,7 @@ impl<T: Config> Pallet<T> {
 
         // Calculate the expected total issuance
         let expected_total_issuance = currency_issuance
-            .saturating_add(total_staked)
+            .saturating_add(TotalStake::<T>::get())
             .saturating_add(total_subnet_locked);
 
         // Verify the diff between calculated TI and actual TI is less than delta

From 4163b91aae39940215fb75e2aded504b498466c3 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Thu, 23 Jan 2025 19:43:57 +0100
Subject: [PATCH 058/145] Reformat

---
 pallets/subtensor/src/utils/try_state.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs
index c42e75dfe..c2292eeee 100644
--- a/pallets/subtensor/src/utils/try_state.rs
+++ b/pallets/subtensor/src/utils/try_state.rs
@@ -1,5 +1,3 @@
-#[cfg(feature = "try-runtime")]
-use super::subnets::subnet::POOL_INITIAL_TAO;
 use super::*;
 
 impl<T: Config> Pallet<T> {
@@ -17,8 +15,8 @@ impl<T: Config> Pallet<T> {
     pub fn check_accounting_invariants() -> Result<(), sp_runtime::TryRuntimeError> {
         use frame_support::traits::fungible::Inspect;
 
-		// Disabled: https://github.com/opentensor/subtensor/pull/1166
-		//
+        // Disabled: https://github.com/opentensor/subtensor/pull/1166
+        //
         // // Calculate the total staked amount
         // let total_staked = SubnetTAO::<T>::iter().fold(0u64, |acc, (netuid, stake)| {
         //     let acc = acc.saturating_add(stake);

From a58b7707ff83d6579552c85ef668da8881f8f1e9 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Thu, 23 Jan 2025 18:11:25 -0500
Subject: [PATCH 059/145] add test for just CHK div distr

---
 pallets/subtensor/src/tests/children.rs | 223 ++++++++++++++++++++++++
 1 file changed, 223 insertions(+)

diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs
index eb299d88e..70f9684a6 100644
--- a/pallets/subtensor/src/tests/children.rs
+++ b/pallets/subtensor/src/tests/children.rs
@@ -3413,6 +3413,229 @@ fn test_parent_child_chain_emission() {
     });
 }
 
+// 45: Test dividend distribution with children
+// This test verifies the correct distribution of emissions in a chain of parent-child relationships:
+// - Sets up a network with three neurons A, B, and C in a chain (A -> B -> C)
+// - Establishes parent-child relationships with different stake proportions
+// - Adds a childkey take for both B and C
+// - Distributes emission across each hotkey using a the helper
+// - Checks the emission distribution among A, B, and C
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::children::test_dividend_distribution_with_children --exact --show-output
+#[test]
+fn test_dividend_distribution_with_children() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+        // Set owner cut to 0
+        SubtensorModule::set_subnet_owner_cut(0_u16);
+
+        // Define hotkeys and coldkeys
+        let hotkey_a: U256 = U256::from(1);
+        let hotkey_b: U256 = U256::from(2);
+        let hotkey_c: U256 = U256::from(3);
+        let coldkey_a: U256 = U256::from(100);
+        let coldkey_b: U256 = U256::from(101);
+        let coldkey_c: U256 = U256::from(102);
+
+        // Register neurons with decreasing stakes
+        register_ok_neuron(netuid, hotkey_a, coldkey_a, 0);
+        register_ok_neuron(netuid, hotkey_b, coldkey_b, 0);
+        register_ok_neuron(netuid, hotkey_c, coldkey_c, 0);
+
+        // Add initial stakes
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000);
+
+        // Swap to alpha
+        let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
+        let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
+            netuid,
+            total_tao.saturating_to_num::<u64>(),
+        ));
+
+        // Set the stakes directly
+        // This avoids needing to swap tao to alpha, impacting the initial stake distribution.
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_b,
+            &coldkey_b,
+            netuid,
+            (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_c,
+            &coldkey_c,
+            netuid,
+            (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::<u64>(),
+        );
+
+        // Get old stakes
+        let stake_a: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_a);
+        let stake_b: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_b);
+        let stake_c: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_c);
+
+        // Assert initial stake is correct
+        let rel_stake_a = I96F32::from_num(stake_a) / total_tao;
+        let rel_stake_b = I96F32::from_num(stake_b) / total_tao;
+        let rel_stake_c = I96F32::from_num(stake_c) / total_tao;
+
+        log::info!("rel_stake_a: {:?}", rel_stake_a); // 0.6666 -> 2/3
+        log::info!("rel_stake_b: {:?}", rel_stake_b); // 0.2222 -> 2/9
+        log::info!("rel_stake_c: {:?}", rel_stake_c); // 0.1111 -> 1/9
+        assert_eq!(rel_stake_a, I96F32::from_num(300_000) / total_tao);
+        assert_eq!(rel_stake_b, I96F32::from_num(100_000) / total_tao);
+        assert_eq!(rel_stake_c, I96F32::from_num(50_000) / total_tao);
+
+        // Set parent-child relationships
+        // A -> B (50% of A's stake)
+        mock_set_children(&coldkey_a, &hotkey_a, netuid, &[(u64::MAX / 2, hotkey_b)]);
+
+        // B -> C (50% of B's stake)
+        mock_set_children(&coldkey_b, &hotkey_b, netuid, &[(u64::MAX / 2, hotkey_c)]);
+
+        // Set CHK take rate to 1/9
+        let chk_take: I96F32 = I96F32::from_num(1_f64 / 9_f64);
+        let chk_take_u16: u16 = (chk_take * I96F32::from_num(u16::MAX)).saturating_to_num::<u16>();
+        ChildkeyTake::<Test>::insert(hotkey_b, netuid, chk_take_u16);
+        ChildkeyTake::<Test>::insert(hotkey_c, netuid, chk_take_u16);
+
+        // Set the weight of root TAO to be 0%, so only alpha is effective.
+        SubtensorModule::set_tao_weight(0);
+
+        let hardcoded_emission: I96F32 = I96F32::from_num(1_000_000); // 1 million (adjust as needed)
+
+        let hotkey_emission: Vec<(U256, u64, u64)> =
+            SubtensorModule::epoch(netuid, hardcoded_emission.saturating_to_num::<u64>());
+        log::info!("hotkey_emission: {:?}", hotkey_emission);
+        let total_emission: I96F32 = hotkey_emission
+            .iter()
+            .map(|(_, _, emission)| I96F32::from_num(*emission))
+            .sum();
+
+        // Verify emissions match expected from CHK arrangements
+        let em_eps: I96F32 = I96F32::from_num(1e-4); // 4 decimal places
+                                                     // A's pending emission:
+        assert!(
+            ((I96F32::from_num(hotkey_emission[0].2) / total_emission) -
+            I96F32::from_num(2_f64 / 3_f64 * 1_f64 / 2_f64)).abs() // 2/3 * 1/2 = 1/3; 50% -> B
+			<= em_eps,
+            "A should have pending emission of 1/3 of total emission"
+        );
+        // B's pending emission:
+        assert!(
+            ((I96F32::from_num(hotkey_emission[1].2) / total_emission) -
+            (I96F32::from_num(2_f64 / 9_f64 * 1_f64 / 2_f64 + 2_f64 / 3_f64 * 1_f64 / 2_f64))).abs() // 2/9 * 1/2 + 2/3 * 1/2; 50% -> C + 50% from A
+            <= em_eps,
+            "B should have pending emission of 4/9 of total emission"
+        );
+        // C's pending emission:
+        assert!(
+            ((I96F32::from_num(hotkey_emission[2].2) / total_emission) -
+            (I96F32::from_num(1_f64 / 9_f64 + 1_f64 / 2_f64 * 2_f64 / 9_f64))).abs() // 1/9 + 2/9 * 1/2; 50% from B
+            <= em_eps,
+            "C should have pending emission of 1/9 of total emission"
+        );
+
+        let dividends_a = SubtensorModule::get_dividends_distribution(
+            &hotkey_a,
+            netuid,
+            hardcoded_emission.saturating_to_num::<u64>(),
+        );
+        let dividends_b = SubtensorModule::get_dividends_distribution(
+            &hotkey_b,
+            netuid,
+            hardcoded_emission.saturating_to_num::<u64>(),
+        );
+        let dividends_c = SubtensorModule::get_dividends_distribution(
+            &hotkey_c,
+            netuid,
+            hardcoded_emission.saturating_to_num::<u64>(),
+        );
+        log::info!("dividends_a: {:?}", dividends_a);
+        log::info!("dividends_b: {:?}", dividends_b);
+        log::info!("dividends_c: {:?}", dividends_c);
+
+        // We expect A to get all of its own emission, as it has no parents.
+        assert_eq!(dividends_a.len(), 1);
+        assert_eq!(dividends_a[0].0, hotkey_a);
+        assert_eq!(
+            dividends_a[0].1,
+            hardcoded_emission.saturating_to_num::<u64>()
+        );
+        assert_abs_diff_eq!(
+            dividends_a
+                .iter()
+                .map(|(_, emission)| *emission)
+                .sum::<u64>(),
+            hardcoded_emission.saturating_to_num::<u64>(),
+            epsilon = (hardcoded_emission / 1000).saturating_to_num::<u64>()
+        );
+
+        // We expect B to get a portion of its own emission, and some comission from A, where A gets the rest.
+        // B re-delegates 0.5 of its stake to C; And A re-delegates 0.5 of its stake to B.
+        let total_stake_b = rel_stake_b * 1 / 2 + rel_stake_a * 1 / 2;
+        let expected_b_b: u64 = ((rel_stake_b * 1 / 2) / total_stake_b * hardcoded_emission
+            + (rel_stake_a * 1 / 2) / total_stake_b * hardcoded_emission * chk_take)
+            .saturating_to_num::<u64>();
+        assert_eq!(dividends_b.len(), 2); // A and B
+        assert_eq!(dividends_b[1].0, hotkey_b);
+        assert_abs_diff_eq!(
+            dividends_b[1].1,
+            expected_b_b,
+            epsilon = (hardcoded_emission / 1000).saturating_to_num::<u64>()
+        );
+        let expected_b_a: u64 = hardcoded_emission.saturating_to_num::<u64>() - expected_b_b;
+        assert_eq!(dividends_b[0].0, hotkey_a);
+        assert_abs_diff_eq!(
+            dividends_b[0].1,
+            expected_b_a,
+            epsilon = (hardcoded_emission / 1000).saturating_to_num::<u64>()
+        );
+        assert_abs_diff_eq!(
+            dividends_b
+                .iter()
+                .map(|(_, emission)| *emission)
+                .sum::<u64>(),
+            hardcoded_emission.saturating_to_num::<u64>(),
+            epsilon = (hardcoded_emission / 1000).saturating_to_num::<u64>()
+        );
+
+        // We expect C to get a portion of its own emission, and some comission from B, where B gets the rest.
+        let total_stake_c = rel_stake_c + rel_stake_b * 1 / 2;
+        let expected_c_c: u64 = (rel_stake_c / total_stake_c * hardcoded_emission
+            + (rel_stake_b * 1 / 2) / total_stake_c * hardcoded_emission * chk_take)
+            .saturating_to_num::<u64>();
+        assert_eq!(dividends_c.len(), 2); // B and C
+        assert_eq!(dividends_c[1].0, hotkey_c);
+        assert_abs_diff_eq!(
+            dividends_c[1].1,
+            expected_c_c,
+            epsilon = (hardcoded_emission / 1000).saturating_to_num::<u64>()
+        );
+        let expected_c_b: u64 = hardcoded_emission.saturating_to_num::<u64>() - expected_c_c;
+        assert_eq!(dividends_c[0].0, hotkey_b);
+        assert_abs_diff_eq!(
+            dividends_c[0].1,
+            expected_c_b,
+            epsilon = (hardcoded_emission / 1000).saturating_to_num::<u64>()
+        );
+        assert_abs_diff_eq!(
+            dividends_c
+                .iter()
+                .map(|(_, emission)| *emission)
+                .sum::<u64>(),
+            hardcoded_emission.saturating_to_num::<u64>(),
+            epsilon = (hardcoded_emission / 1000).saturating_to_num::<u64>()
+        );
+    });
+}
+
 // 46: Test emission distribution when adding/removing parent-child relationships mid-epoch
 // This test verifies the correct distribution of emissions when parent-child relationships change:
 // - Sets up a network with three neurons: parent, child1, and child2

From d83388caba07b5d9aadf0d5d7c19a5839bf2dd89 Mon Sep 17 00:00:00 2001
From: camfairchild <cameron@opentensor.dev>
Date: Thu, 23 Jan 2025 18:15:57 -0500
Subject: [PATCH 060/145] separate out test for epoch with CHK

---
 pallets/subtensor/src/tests/children.rs | 167 +++++++++++++++++++-----
 1 file changed, 133 insertions(+), 34 deletions(-)

diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs
index 70f9684a6..62e8ceecc 100644
--- a/pallets/subtensor/src/tests/children.rs
+++ b/pallets/subtensor/src/tests/children.rs
@@ -3312,38 +3312,6 @@ fn test_parent_child_chain_emission() {
 
         let hardcoded_emission: I96F32 = I96F32::from_num(1_000_000); // 1 million (adjust as needed)
 
-        let hotkey_emission: Vec<(U256, u64, u64)> =
-            SubtensorModule::epoch(netuid, hardcoded_emission.saturating_to_num::<u64>());
-        log::info!("hotkey_emission: {:?}", hotkey_emission);
-        let total_emission: I96F32 = hotkey_emission
-            .iter()
-            .map(|(_, _, emission)| I96F32::from_num(*emission))
-            .sum();
-
-        // Verify emissions match expected from CHK arrangements
-        let em_eps: I96F32 = I96F32::from_num(1e-4); // 4 decimal places
-                                                     // A's pending emission:
-        assert!(
-            ((I96F32::from_num(hotkey_emission[0].2) / total_emission) -
-            I96F32::from_num(2_f64 / 3_f64 * 1_f64 / 2_f64)).abs() // 2/3 * 1/2 = 1/3; 50% -> B
-			<= em_eps,
-            "A should have pending emission of 1/3 of total emission"
-        );
-        // B's pending emission:
-        assert!(
-            ((I96F32::from_num(hotkey_emission[1].2) / total_emission) -
-            (I96F32::from_num(2_f64 / 9_f64 * 1_f64 / 2_f64 + 2_f64 / 3_f64 * 1_f64 / 2_f64))).abs() // 2/9 * 1/2 + 2/3 * 1/2; 50% -> C + 50% from A
-            <= em_eps,
-            "B should have pending emission of 4/9 of total emission"
-        );
-        // C's pending emission:
-        assert!(
-            ((I96F32::from_num(hotkey_emission[2].2) / total_emission) -
-            (I96F32::from_num(1_f64 / 9_f64 + 1_f64 / 2_f64 * 2_f64 / 9_f64))).abs() // 1/9 + 2/9 * 1/2; 50% from B
-            <= em_eps,
-            "C should have pending emission of 1/9 of total emission"
-        );
-
         // Run epoch with a hardcoded emission value
         SubtensorModule::run_coinbase(hardcoded_emission);
 
@@ -3413,7 +3381,138 @@ fn test_parent_child_chain_emission() {
     });
 }
 
-// 45: Test dividend distribution with children
+// 45: Test *epoch* with a chain of parent-child relationships (e.g., A -> B -> C)
+// This test verifies the correct distribution of emissions in a chain of parent-child relationships:
+// - Sets up a network with three neurons A, B, and C in a chain (A -> B -> C)
+// - Establishes parent-child relationships with different stake proportions
+// - Sets weights for all neurons
+// - Runs an epoch with a hardcoded emission value
+// - Checks the emission distribution among A, B, and C
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::children::test_parent_child_chain_epoch --exact --show-output
+#[test]
+fn test_parent_child_chain_epoch() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+        // Set owner cut to 0
+        SubtensorModule::set_subnet_owner_cut(0_u16);
+
+        // Define hotkeys and coldkeys
+        let hotkey_a: U256 = U256::from(1);
+        let hotkey_b: U256 = U256::from(2);
+        let hotkey_c: U256 = U256::from(3);
+        let coldkey_a: U256 = U256::from(100);
+        let coldkey_b: U256 = U256::from(101);
+        let coldkey_c: U256 = U256::from(102);
+
+        // Register neurons with decreasing stakes
+        register_ok_neuron(netuid, hotkey_a, coldkey_a, 0);
+        register_ok_neuron(netuid, hotkey_b, coldkey_b, 0);
+        register_ok_neuron(netuid, hotkey_c, coldkey_c, 0);
+
+        // Add initial stakes
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000);
+
+        // Swap to alpha
+        let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
+        let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
+            netuid,
+            total_tao.saturating_to_num::<u64>(),
+        ));
+
+        // Set the stakes directly
+        // This avoids needing to swap tao to alpha, impacting the initial stake distribution.
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_b,
+            &coldkey_b,
+            netuid,
+            (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_c,
+            &coldkey_c,
+            netuid,
+            (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::<u64>(),
+        );
+
+        // Get old stakes
+        let stake_a: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_a);
+        let stake_b: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_b);
+        let stake_c: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_c);
+
+        // Assert initial stake is correct
+        let rel_stake_a = I96F32::from_num(stake_a) / total_tao;
+        let rel_stake_b = I96F32::from_num(stake_b) / total_tao;
+        let rel_stake_c = I96F32::from_num(stake_c) / total_tao;
+
+        log::info!("rel_stake_a: {:?}", rel_stake_a); // 0.6666 -> 2/3
+        log::info!("rel_stake_b: {:?}", rel_stake_b); // 0.2222 -> 2/9
+        log::info!("rel_stake_c: {:?}", rel_stake_c); // 0.1111 -> 1/9
+        assert_eq!(rel_stake_a, I96F32::from_num(300_000) / total_tao);
+        assert_eq!(rel_stake_b, I96F32::from_num(100_000) / total_tao);
+        assert_eq!(rel_stake_c, I96F32::from_num(50_000) / total_tao);
+
+        // Set parent-child relationships
+        // A -> B (50% of A's stake)
+        mock_set_children(&coldkey_a, &hotkey_a, netuid, &[(u64::MAX / 2, hotkey_b)]);
+
+        // B -> C (50% of B's stake)
+        mock_set_children(&coldkey_b, &hotkey_b, netuid, &[(u64::MAX / 2, hotkey_c)]);
+
+        // Set CHK take rate to 1/9
+        let chk_take: I96F32 = I96F32::from_num(1_f64 / 9_f64);
+        let chk_take_u16: u16 = (chk_take * I96F32::from_num(u16::MAX)).saturating_to_num::<u16>();
+        ChildkeyTake::<Test>::insert(hotkey_b, netuid, chk_take_u16);
+        ChildkeyTake::<Test>::insert(hotkey_c, netuid, chk_take_u16);
+
+        // Set the weight of root TAO to be 0%, so only alpha is effective.
+        SubtensorModule::set_tao_weight(0);
+
+        let hardcoded_emission: I96F32 = I96F32::from_num(1_000_000); // 1 million (adjust as needed)
+
+        let hotkey_emission: Vec<(U256, u64, u64)> =
+            SubtensorModule::epoch(netuid, hardcoded_emission.saturating_to_num::<u64>());
+        log::info!("hotkey_emission: {:?}", hotkey_emission);
+        let total_emission: I96F32 = hotkey_emission
+            .iter()
+            .map(|(_, _, emission)| I96F32::from_num(*emission))
+            .sum();
+
+        // Verify emissions match expected from CHK arrangements
+        let em_eps: I96F32 = I96F32::from_num(1e-4); // 4 decimal places
+                                                     // A's pending emission:
+        assert!(
+            ((I96F32::from_num(hotkey_emission[0].2) / total_emission) -
+            I96F32::from_num(2_f64 / 3_f64 * 1_f64 / 2_f64)).abs() // 2/3 * 1/2 = 1/3; 50% -> B
+			<= em_eps,
+            "A should have pending emission of 1/3 of total emission"
+        );
+        // B's pending emission:
+        assert!(
+            ((I96F32::from_num(hotkey_emission[1].2) / total_emission) -
+            (I96F32::from_num(2_f64 / 9_f64 * 1_f64 / 2_f64 + 2_f64 / 3_f64 * 1_f64 / 2_f64))).abs() // 2/9 * 1/2 + 2/3 * 1/2; 50% -> C + 50% from A
+            <= em_eps,
+            "B should have pending emission of 4/9 of total emission"
+        );
+        // C's pending emission:
+        assert!(
+            ((I96F32::from_num(hotkey_emission[2].2) / total_emission) -
+            (I96F32::from_num(1_f64 / 9_f64 + 1_f64 / 2_f64 * 2_f64 / 9_f64))).abs() // 1/9 + 2/9 * 1/2; 50% from B
+            <= em_eps,
+            "C should have pending emission of 1/9 of total emission"
+        );
+    });
+}
+
+// 46: Test dividend distribution with children
 // This test verifies the correct distribution of emissions in a chain of parent-child relationships:
 // - Sets up a network with three neurons A, B, and C in a chain (A -> B -> C)
 // - Establishes parent-child relationships with different stake proportions
@@ -3636,7 +3735,7 @@ fn test_dividend_distribution_with_children() {
     });
 }
 
-// 46: Test emission distribution when adding/removing parent-child relationships mid-epoch
+// 47: Test emission distribution when adding/removing parent-child relationships mid-epoch
 // This test verifies the correct distribution of emissions when parent-child relationships change:
 // - Sets up a network with three neurons: parent, child1, and child2
 // - Establishes initial parent-child relationship between parent and child1

From 77a9aab3b1d1172a195fd46dc9bf764e844ef24f Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Thu, 23 Jan 2025 18:48:22 -0500
Subject: [PATCH 061/145] Fix tx validation for staking extrinsics

---
 pallets/subtensor/src/lib.rs                  | 184 +++++++++++---
 pallets/subtensor/src/macros/dispatches.rs    |   4 +-
 pallets/subtensor/src/macros/errors.rs        |   4 +-
 pallets/subtensor/src/staking/add_stake.rs    |  24 +-
 pallets/subtensor/src/staking/move_stake.rs   | 240 ++++++------------
 pallets/subtensor/src/staking/remove_stake.rs |  27 +-
 pallets/subtensor/src/staking/stake_utils.rs  | 122 +++++++++
 pallets/subtensor/src/tests/move_stake.rs     |   7 +-
 pallets/subtensor/src/tests/registration.rs   |  12 +-
 pallets/subtensor/src/tests/staking.rs        |  37 +--
 pallets/subtensor/src/tests/weights.rs        |  12 +-
 runtime/src/precompiles/staking.rs            |   2 +-
 runtime/tests/pallet_proxy.rs                 |   4 +-
 13 files changed, 410 insertions(+), 269 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 1a3f0e27b..ec23c64bf 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -12,10 +12,7 @@ use frame_support::{
     dispatch::{self, DispatchInfo, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo},
     ensure,
     pallet_macros::import_section,
-    traits::{
-        tokens::{fungible, Fortitude, Preservation},
-        IsSubType,
-    },
+    traits::{tokens::fungible, IsSubType},
 };
 
 use codec::{Decode, Encode};
@@ -1552,6 +1549,11 @@ pub enum CustomTransactionError {
     ColdkeyInSwapSchedule,
     StakeAmountTooLow,
     BalanceTooLow,
+    SubnetDoesntExist,
+    HotkeyAccountDoesntExist,
+    NotEnoughStakeToWithdraw,
+    RateLimitExceeded,
+    BadRequest,
 }
 
 impl From<CustomTransactionError> for u8 {
@@ -1560,6 +1562,11 @@ impl From<CustomTransactionError> for u8 {
             CustomTransactionError::ColdkeyInSwapSchedule => 0,
             CustomTransactionError::StakeAmountTooLow => 1,
             CustomTransactionError::BalanceTooLow => 2,
+            CustomTransactionError::SubnetDoesntExist => 3,
+            CustomTransactionError::HotkeyAccountDoesntExist => 4,
+            CustomTransactionError::NotEnoughStakeToWithdraw => 5,
+            CustomTransactionError::RateLimitExceeded => 6,
+            CustomTransactionError::BadRequest => 255,
         }
     }
 }
@@ -1602,6 +1609,41 @@ where
     pub fn check_weights_min_stake(who: &T::AccountId, netuid: u16) -> bool {
         Pallet::<T>::check_weights_min_stake(who, netuid)
     }
+
+    pub fn result_to_validity(result: Result<(), Error<T>>) -> TransactionValidity {
+        if let Err(err) = result {
+            match err {
+                Error::<T>::AmountTooLow => Err(InvalidTransaction::Custom(
+                    CustomTransactionError::StakeAmountTooLow.into(),
+                )
+                .into()),
+                Error::<T>::SubnetNotExists => Err(InvalidTransaction::Custom(
+                    CustomTransactionError::SubnetDoesntExist.into(),
+                )
+                .into()),
+                Error::<T>::NotEnoughBalanceToStake => Err(InvalidTransaction::Custom(
+                    CustomTransactionError::BalanceTooLow.into(),
+                )
+                .into()),
+                Error::<T>::HotKeyAccountNotExists => Err(InvalidTransaction::Custom(
+                    CustomTransactionError::HotkeyAccountDoesntExist.into(),
+                )
+                .into()),
+                Error::<T>::NotEnoughStakeToWithdraw => Err(InvalidTransaction::Custom(
+                    CustomTransactionError::NotEnoughStakeToWithdraw.into(),
+                )
+                .into()),
+                _ => Err(
+                    InvalidTransaction::Custom(CustomTransactionError::BadRequest.into()).into(),
+                ),
+            }
+        } else {
+            Ok(ValidTransaction {
+                priority: Self::get_priority_vanilla(),
+                ..Default::default()
+            })
+        }
+    }
 }
 
 impl<T: Config + Send + Sync + TypeInfo> sp_std::fmt::Debug for SubtensorSignedExtension<T> {
@@ -1646,7 +1688,10 @@ where
                         ..Default::default()
                     })
                 } else {
-                    Err(InvalidTransaction::Custom(1).into())
+                    Err(InvalidTransaction::Custom(
+                        CustomTransactionError::StakeAmountTooLow.into(),
+                    )
+                    .into())
                 }
             }
             Some(Call::reveal_weights { netuid, .. }) => {
@@ -1658,7 +1703,10 @@ where
                         ..Default::default()
                     })
                 } else {
-                    Err(InvalidTransaction::Custom(2).into())
+                    Err(InvalidTransaction::Custom(
+                        CustomTransactionError::StakeAmountTooLow.into(),
+                    )
+                    .into())
                 }
             }
             Some(Call::batch_reveal_weights { netuid, .. }) => {
@@ -1670,7 +1718,10 @@ where
                         ..Default::default()
                     })
                 } else {
-                    Err(InvalidTransaction::Custom(6).into())
+                    Err(InvalidTransaction::Custom(
+                        CustomTransactionError::StakeAmountTooLow.into(),
+                    )
+                    .into())
                 }
             }
             Some(Call::set_weights { netuid, .. }) => {
@@ -1682,7 +1733,10 @@ where
                         ..Default::default()
                     })
                 } else {
-                    Err(InvalidTransaction::Custom(3).into())
+                    Err(InvalidTransaction::Custom(
+                        CustomTransactionError::StakeAmountTooLow.into(),
+                    )
+                    .into())
                 }
             }
             Some(Call::set_tao_weights { netuid, hotkey, .. }) => {
@@ -1694,7 +1748,10 @@ where
                         ..Default::default()
                     })
                 } else {
-                    Err(InvalidTransaction::Custom(4).into())
+                    Err(InvalidTransaction::Custom(
+                        CustomTransactionError::StakeAmountTooLow.into(),
+                    )
+                    .into())
                 }
             }
             Some(Call::commit_crv3_weights { netuid, .. }) => {
@@ -1706,40 +1763,88 @@ where
                         ..Default::default()
                     })
                 } else {
-                    Err(InvalidTransaction::Custom(7).into())
+                    Err(InvalidTransaction::Custom(
+                        CustomTransactionError::StakeAmountTooLow.into(),
+                    )
+                    .into())
                 }
             }
             Some(Call::add_stake {
-                hotkey: _,
-                netuid: _,
+                hotkey,
+                netuid,
                 amount,
             }) => {
-                // 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
-                );
-                let min_amount =
-                    DefaultMinStake::<T>::get().saturating_add(DefaultStakingFee::<T>::get());
-
-                if *amount < min_amount {
-                    InvalidTransaction::Custom(CustomTransactionError::StakeAmountTooLow.into())
-                        .into()
-                } else if coldkey_balance < min_amount {
-                    InvalidTransaction::Custom(CustomTransactionError::BalanceTooLow.into()).into()
-                } else {
-                    Ok(ValidTransaction {
-                        priority: Self::get_priority_vanilla(),
-                        ..Default::default()
-                    })
-                }
+                // Fully validate the user input
+                Self::result_to_validity(Pallet::<T>::validate_add_stake(
+                    who, hotkey, *netuid, *amount,
+                ))
+            }
+            Some(Call::remove_stake {
+                hotkey,
+                netuid,
+                amount_unstaked,
+            }) => {
+                // Fully validate the user input
+                Self::result_to_validity(Pallet::<T>::validate_remove_stake(
+                    who,
+                    hotkey,
+                    *netuid,
+                    *amount_unstaked,
+                ))
+            }
+            Some(Call::move_stake {
+                origin_hotkey,
+                destination_hotkey,
+                origin_netuid,
+                destination_netuid,
+                alpha_amount,
+            }) => {
+                // Fully validate the user input
+                Self::result_to_validity(Pallet::<T>::validate_stake_transition(
+                    who,
+                    who,
+                    origin_hotkey,
+                    destination_hotkey,
+                    *origin_netuid,
+                    *destination_netuid,
+                    *alpha_amount,
+                ))
+            }
+            Some(Call::transfer_stake {
+                destination_coldkey,
+                hotkey,
+                origin_netuid,
+                destination_netuid,
+                alpha_amount,
+            }) => {
+                // Fully validate the user input
+                Self::result_to_validity(Pallet::<T>::validate_stake_transition(
+                    who,
+                    destination_coldkey,
+                    hotkey,
+                    hotkey,
+                    *origin_netuid,
+                    *destination_netuid,
+                    *alpha_amount,
+                ))
+            }
+            Some(Call::swap_stake {
+                hotkey,
+                origin_netuid,
+                destination_netuid,
+                alpha_amount,
+            }) => {
+                // Fully validate the user input
+                Self::result_to_validity(Pallet::<T>::validate_stake_transition(
+                    who,
+                    who,
+                    hotkey,
+                    hotkey,
+                    *origin_netuid,
+                    *destination_netuid,
+                    *alpha_amount,
+                ))
             }
-            Some(Call::remove_stake { .. }) => Ok(ValidTransaction {
-                priority: Self::get_priority_vanilla(),
-                ..Default::default()
-            }),
             Some(Call::register { netuid, .. } | Call::burned_register { netuid, .. }) => {
                 let registrations_this_interval =
                     Pallet::<T>::get_registrations_this_interval(*netuid);
@@ -1748,7 +1853,10 @@ where
                 if registrations_this_interval >= (max_registrations_per_interval.saturating_mul(3))
                 {
                     // If the registration limit for the interval is exceeded, reject the transaction
-                    return Err(InvalidTransaction::Custom(5).into());
+                    return Err(InvalidTransaction::Custom(
+                        CustomTransactionError::RateLimitExceeded.into(),
+                    )
+                    .into());
                 }
                 Ok(ValidTransaction {
                     priority: Self::get_priority_vanilla(),
diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs
index d9eafffa7..2f4e2f563 100644
--- a/pallets/subtensor/src/macros/dispatches.rs
+++ b/pallets/subtensor/src/macros/dispatches.rs
@@ -584,9 +584,9 @@ mod dispatches {
             origin: OriginFor<T>,
             hotkey: T::AccountId,
             netuid: u16,
-            amount_staked: u64,
+            amount: u64,
         ) -> DispatchResult {
-            Self::do_add_stake(origin, hotkey, netuid, amount_staked)
+            Self::do_add_stake(origin, hotkey, netuid, amount)
         }
 
         /// Remove stake from the staking account. The call must be made
diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs
index 649336674..dd5e97b78 100644
--- a/pallets/subtensor/src/macros/errors.rs
+++ b/pallets/subtensor/src/macros/errors.rs
@@ -25,8 +25,8 @@ mod errors {
         /// Request to stake, unstake or subscribe is made by a coldkey that is not associated with
         /// the hotkey account.
         NonAssociatedColdKey,
-        /// Stake amount to withdraw is zero.
-        StakeToWithdrawIsZero,
+        /// DEPRECATED: Stake amount to withdraw is zero.
+        // StakeToWithdrawIsZero,
         /// The caller does not have enought stake to perform this action.
         NotEnoughStake,
         /// The caller is requesting removing more stake than there exists in the staking account.
diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index 763899d6d..326eca1dc 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -47,30 +47,14 @@ impl<T: Config> Pallet<T> {
             stake_to_be_added
         );
 
-        // 2. Ensure that the subnet exists.
-        ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
+        // 2. Validate user input
+        Self::validate_add_stake(&coldkey, &hotkey, netuid, stake_to_be_added)?;
 
-        // 3. Ensure the callers coldkey has enough stake to perform the transaction.
-        ensure!(
-            Self::can_remove_balance_from_coldkey_account(&coldkey, stake_to_be_added),
-            Error::<T>::NotEnoughBalanceToStake
-        );
-
-        // 4. Ensure that the hotkey account exists this is only possible through registration.
-        ensure!(
-            Self::hotkey_account_exists(&hotkey),
-            Error::<T>::HotKeyAccountNotExists
-        );
-
-        // Ensure stake_to_be_added is at least DefaultMinStake plus fee
-        let min_amount = DefaultMinStake::<T>::get().saturating_add(DefaultStakingFee::<T>::get());
-        ensure!(stake_to_be_added >= min_amount, Error::<T>::AmountTooLow);
-
-        // 5. Ensure the remove operation from the coldkey is a success.
+        // 3. Ensure the remove operation from the coldkey is a success.
         let tao_staked: u64 =
             Self::remove_balance_from_coldkey_account(&coldkey, stake_to_be_added)?;
 
-        // 6. Swap the stake into alpha on the subnet and increase counters.
+        // 4. Swap the stake into alpha on the subnet and increase counters.
         // Emit the staking event.
         let fee = DefaultStakingFee::<T>::get();
         Self::stake_into_subnet(&hotkey, &coldkey, netuid, tao_staked, fee);
diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 9c4ffabff..4644b3213 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -31,68 +31,21 @@ impl<T: Config> Pallet<T> {
         destination_netuid: u16,
         alpha_amount: u64,
     ) -> dispatch::DispatchResult {
-        // --- 1. Check that the origin is signed by the origin_hotkey.
+        // Check that the origin is signed by the origin_hotkey.
         let coldkey = ensure_signed(origin)?;
 
-        // --- 2. Check that the subnet exists.
-        ensure!(
-            Self::if_subnet_exist(origin_netuid),
-            Error::<T>::SubnetNotExists
-        );
-        ensure!(
-            Self::if_subnet_exist(destination_netuid),
-            Error::<T>::SubnetNotExists
-        );
-
-        // --- 3. Check that the origin_hotkey exists.
-        ensure!(
-            Self::hotkey_account_exists(&origin_hotkey),
-            Error::<T>::HotKeyAccountNotExists
-        );
-
-        // --- 4. Check that the destination_hotkey exists.
-        ensure!(
-            Self::hotkey_account_exists(&destination_hotkey),
-            Error::<T>::HotKeyAccountNotExists
-        );
-
-        // --- 6. Get the current alpha stake for the origin hotkey-coldkey pair in the origin subnet
-        let origin_alpha = Self::get_stake_for_hotkey_and_coldkey_on_subnet(
-            &origin_hotkey,
+        // Validate input and move stake
+        let tao_moved = Self::transition_stake_internal(
             &coldkey,
+            &coldkey,
+            &origin_hotkey,
+            &destination_hotkey,
             origin_netuid,
-        );
-        ensure!(
-            alpha_amount <= origin_alpha,
-            Error::<T>::NotEnoughStakeToWithdraw
-        );
-
-        // --- 7. Unstake the amount of alpha from the origin subnet, converting it to TAO
-        let fee = DefaultStakingFee::<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
-        ensure!(
-            origin_tao.saturating_sub(fee) >= DefaultMinStake::<T>::get(),
-            Error::<T>::AmountTooLow
-        );
-
-        // --- 8. Stake the resulting TAO into the destination subnet for the destination hotkey
-        Self::stake_into_subnet(
-            &destination_hotkey.clone(),
-            &coldkey.clone(),
             destination_netuid,
-            origin_tao,
-            fee,
-        );
+            alpha_amount,
+        )?;
 
-        // --- 9. Log the event.
+        // Log the event.
         log::info!(
             "StakeMoved( coldkey:{:?}, origin_hotkey:{:?}, origin_netuid:{:?}, destination_hotkey:{:?}, destination_netuid:{:?} )",
             coldkey.clone(),
@@ -107,10 +60,10 @@ impl<T: Config> Pallet<T> {
             origin_netuid,
             destination_hotkey,
             destination_netuid,
-            origin_tao.saturating_sub(fee),
+            tao_moved,
         ));
 
-        // -- 10. Ok and return.
+        // Ok and return.
         Ok(())
     }
 
@@ -147,59 +100,19 @@ impl<T: Config> Pallet<T> {
         destination_netuid: u16,
         alpha_amount: u64,
     ) -> dispatch::DispatchResult {
-        // 1. Ensure the extrinsic is signed by the origin_coldkey.
+        // Ensure the extrinsic is signed by the origin_coldkey.
         let coldkey = ensure_signed(origin)?;
 
-        // 2. Ensure both subnets exist.
-        ensure!(
-            Self::if_subnet_exist(origin_netuid),
-            Error::<T>::SubnetNotExists
-        );
-        ensure!(
-            Self::if_subnet_exist(destination_netuid),
-            Error::<T>::SubnetNotExists
-        );
-
-        // 3. Check that the hotkey exists.
-        ensure!(
-            Self::hotkey_account_exists(&hotkey),
-            Error::<T>::HotKeyAccountNotExists
-        );
-
-        // 4. Check that the signed coldkey actually owns the given hotkey.
-        ensure!(
-            Self::coldkey_owns_hotkey(&coldkey, &hotkey),
-            Error::<T>::NonAssociatedColdKey
-        );
-
-        // 5. Get current stake.
-        let origin_alpha =
-            Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, origin_netuid);
-        ensure!(
-            alpha_amount <= origin_alpha,
-            Error::<T>::NotEnoughStakeToWithdraw
-        );
-
-        // 6. Unstake from the origin coldkey; this returns an amount of TAO.
-        let fee = DefaultStakingFee::<T>::get().saturating_div(2);
-        let origin_tao =
-            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount, fee);
-
-        // 7. Ensure the returned TAO meets a minimum stake requirement (if required).
-        ensure!(
-            origin_tao.saturating_sub(fee) >= DefaultMinStake::<T>::get(),
-            Error::<T>::AmountTooLow
-        );
-
-        // 8. Stake the TAO into `(destination_coldkey, hotkey)` on the destination subnet.
-        //    Create the account if it does not exist.
-        Self::stake_into_subnet(
-            &hotkey,
+        // Validate input and move stake
+        let tao_moved = Self::transition_stake_internal(
+            &coldkey,
             &destination_coldkey,
+            &hotkey,
+            &hotkey,
+            origin_netuid,
             destination_netuid,
-            origin_tao,
-            fee,
-        );
+            alpha_amount,
+        )?;
 
         // 9. Emit an event for logging/monitoring.
         log::info!(
@@ -209,7 +122,7 @@ impl<T: Config> Pallet<T> {
             hotkey,
             origin_netuid,
             destination_netuid,
-            origin_tao
+            tao_moved
         );
         Self::deposit_event(Event::StakeTransferred(
             coldkey,
@@ -217,7 +130,7 @@ impl<T: Config> Pallet<T> {
             hotkey,
             origin_netuid,
             destination_netuid,
-            origin_tao,
+            tao_moved,
         ));
 
         // 10. Return success.
@@ -254,71 +167,84 @@ impl<T: Config> Pallet<T> {
         destination_netuid: u16,
         alpha_amount: u64,
     ) -> dispatch::DispatchResult {
-        // 1. Ensure the extrinsic is signed by the coldkey.
+        // Ensure the extrinsic is signed by the coldkey.
         let coldkey = ensure_signed(origin)?;
 
-        // 2. Check that both subnets exist.
-        ensure!(
-            Self::if_subnet_exist(origin_netuid),
-            Error::<T>::SubnetNotExists
-        );
-        ensure!(
-            Self::if_subnet_exist(destination_netuid),
-            Error::<T>::SubnetNotExists
-        );
-
-        // 3. Check that the hotkey exists.
-        ensure!(
-            Self::hotkey_account_exists(&hotkey),
-            Error::<T>::HotKeyAccountNotExists
-        );
-
-        // 4. Ensure this coldkey actually owns the hotkey.
-        ensure!(
-            Self::coldkey_owns_hotkey(&coldkey, &hotkey),
-            Error::<T>::NonAssociatedColdKey
-        );
-
-        // 5. Ensure there is enough stake in the origin subnet.
-        let origin_alpha =
-            Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, origin_netuid);
-        ensure!(
-            alpha_amount <= origin_alpha,
-            Error::<T>::NotEnoughStakeToWithdraw
-        );
-
-        // 6. Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
-        let fee = DefaultStakingFee::<T>::get().saturating_div(2);
-        let tao_unstaked =
-            Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount, fee);
-
-        // 7. Check that the unstaked amount is above the minimum stake threshold.
-        ensure!(
-            tao_unstaked.saturating_sub(fee) >= DefaultMinStake::<T>::get(),
-            Error::<T>::AmountTooLow
-        );
-
-        // 8. Stake the unstaked amount into the destination subnet, using the same coldkey/hotkey.
-        Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked, fee);
+        // Validate input and move stake
+        let tao_moved = Self::transition_stake_internal(
+            &coldkey,
+            &coldkey,
+            &hotkey,
+            &hotkey,
+            origin_netuid,
+            destination_netuid,
+            alpha_amount,
+        )?;
 
-        // 9. Emit an event for logging.
+        // Emit an event for logging.
         log::info!(
             "StakeSwapped(coldkey: {:?}, hotkey: {:?}, origin_netuid: {:?}, destination_netuid: {:?}, amount: {:?})",
             coldkey,
             hotkey,
             origin_netuid,
             destination_netuid,
-            tao_unstaked
+            tao_moved
         );
         Self::deposit_event(Event::StakeSwapped(
             coldkey,
             hotkey,
             origin_netuid,
             destination_netuid,
-            tao_unstaked,
+            tao_moved,
         ));
 
-        // 10. Return success.
+        // 6. Return success.
         Ok(())
     }
+
+    fn transition_stake_internal(
+        origin_coldkey: &T::AccountId,
+        destination_coldkey: &T::AccountId,
+        origin_hotkey: &T::AccountId,
+        destination_hotkey: &T::AccountId,
+        origin_netuid: u16,
+        destination_netuid: u16,
+        alpha_amount: u64,
+    ) -> Result<u64, Error<T>> {
+        // Validate user input
+        Self::validate_stake_transition(
+            origin_coldkey,
+            destination_coldkey,
+            origin_hotkey,
+            destination_hotkey,
+            origin_netuid,
+            destination_netuid,
+            alpha_amount,
+        )?;
+
+        // Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
+        let fee = DefaultStakingFee::<T>::get().saturating_div(2);
+        let tao_unstaked = Self::unstake_from_subnet(
+            origin_hotkey,
+            origin_coldkey,
+            origin_netuid,
+            alpha_amount,
+            fee,
+        );
+
+        // Stake the unstaked amount into the destination.
+        // Because of the fee, the tao_unstaked may be too low if initial stake is low. In that case,
+        // do not restake.
+        if tao_unstaked >= DefaultMinStake::<T>::get().saturating_add(fee) {
+            Self::stake_into_subnet(
+                destination_hotkey,
+                destination_coldkey,
+                destination_netuid,
+                tao_unstaked,
+                fee,
+            );
+        }
+
+        Ok(tao_unstaked.saturating_sub(fee))
+    }
 }
diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index fd6fe8191..bab8c9a29 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -47,36 +47,21 @@ impl<T: Config> Pallet<T> {
             alpha_unstaked
         );
 
-        // 2. Ensure that the stake amount to be removed is above zero.
-        ensure!(alpha_unstaked > 0, Error::<T>::StakeToWithdrawIsZero);
+        // 2. Validate the user input
+        Self::validate_remove_stake(&coldkey, &hotkey, netuid, alpha_unstaked)?;
 
-        // 3. Ensure that the subnet exists.
-        ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
-
-        // 4. Ensure that the hotkey account exists this is only possible through registration.
-        ensure!(
-            Self::hotkey_account_exists(&hotkey),
-            Error::<T>::HotKeyAccountNotExists
-        );
-
-        // 5. Ensure that the hotkey has enough stake to withdraw.
-        ensure!(
-            Self::has_enough_stake_on_subnet(&hotkey, &coldkey, netuid, alpha_unstaked),
-            Error::<T>::NotEnoughStakeToWithdraw
-        );
-
-        // 6. Swap the alpba to tao and update counters for this subnet.
+        // 3. Swap the alpba to tao and update counters for this subnet.
         let fee = DefaultStakingFee::<T>::get();
         let tao_unstaked: u64 =
             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.
+        // 4. 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);
 
-        // 8. If the stake is below the minimum, we clear the nomination from storage.
+        // 5. If the stake is below the minimum, we clear the nomination from storage.
         Self::clear_small_nomination_if_required(&hotkey, &coldkey, netuid);
 
-        // 9. Check if stake lowered below MinStake and remove Pending children if it did
+        // 6. Check if stake lowered below MinStake and remove Pending children if it did
         if Self::get_total_stake_for_hotkey(&hotkey) < StakeThreshold::<T>::get() {
             Self::get_all_subnet_netuids().iter().for_each(|netuid| {
                 PendingChildKeys::<T>::remove(netuid, &hotkey);
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index d6901eec2..f34a5ace0 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -719,6 +719,128 @@ impl<T: Config> Pallet<T> {
         let ops = HotkeyAlphaSharePoolDataOperations::new(hotkey, netuid);
         SharePool::<AlphaShareKey<T>, HotkeyAlphaSharePoolDataOperations<T>>::new(ops)
     }
+
+    /// Validate add_stake user input
+    ///
+    pub fn validate_add_stake(
+        coldkey: &T::AccountId,
+        hotkey: &T::AccountId,
+        netuid: u16,
+        stake_to_be_added: u64,
+    ) -> Result<(), Error<T>> {
+        // Ensure that the subnet exists.
+        ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
+
+        // Get the minimum balance (and amount) that satisfies the transaction
+        let min_amount = DefaultMinStake::<T>::get().saturating_add(DefaultStakingFee::<T>::get());
+
+        // Ensure that the stake_to_be_added is at least the min_amount
+        ensure!(stake_to_be_added >= min_amount, Error::<T>::AmountTooLow);
+
+        // Ensure the callers coldkey has enough stake to perform the transaction.
+        ensure!(
+            Self::can_remove_balance_from_coldkey_account(coldkey, stake_to_be_added),
+            Error::<T>::NotEnoughBalanceToStake
+        );
+
+        // Ensure that the hotkey account exists this is only possible through registration.
+        ensure!(
+            Self::hotkey_account_exists(hotkey),
+            Error::<T>::HotKeyAccountNotExists
+        );
+
+        Ok(())
+    }
+
+    /// Validate remove_stake user input
+    ///
+    pub fn validate_remove_stake(
+        coldkey: &T::AccountId,
+        hotkey: &T::AccountId,
+        netuid: u16,
+        alpha_unstaked: u64,
+    ) -> Result<(), Error<T>> {
+        // Ensure that the subnet exists.
+        ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
+
+        // Ensure that the stake amount to be removed is above the minimum in tao equivalent.
+        let tao_equivalent = Self::sim_swap_alpha_for_tao(netuid, alpha_unstaked);
+        ensure!(
+            tao_equivalent > DefaultMinStake::<T>::get(),
+            Error::<T>::AmountTooLow
+        );
+
+        // Ensure that the hotkey account exists this is only possible through registration.
+        ensure!(
+            Self::hotkey_account_exists(hotkey),
+            Error::<T>::HotKeyAccountNotExists
+        );
+
+        // Ensure that the hotkey has enough stake to withdraw.
+        ensure!(
+            Self::has_enough_stake_on_subnet(hotkey, coldkey, netuid, alpha_unstaked),
+            Error::<T>::NotEnoughStakeToWithdraw
+        );
+
+        Ok(())
+    }
+
+    /// Validate stake transition user input
+    /// That works for move_stake, transfer_stake, and swap_stake
+    ///
+    pub fn validate_stake_transition(
+        origin_coldkey: &T::AccountId,
+        _destination_coldkey: &T::AccountId,
+        origin_hotkey: &T::AccountId,
+        _destination_hotkey: &T::AccountId,
+        origin_netuid: u16,
+        destination_netuid: u16,
+        alpha_amount: u64,
+    ) -> Result<(), Error<T>> {
+        // Ensure that both subnets exist.
+        ensure!(
+            Self::if_subnet_exist(origin_netuid),
+            Error::<T>::SubnetNotExists
+        );
+        if origin_netuid != destination_netuid {
+            ensure!(
+                Self::if_subnet_exist(destination_netuid),
+                Error::<T>::SubnetNotExists
+            );
+        }
+
+        // Ensure that the origin hotkey account exists
+        ensure!(
+            Self::hotkey_account_exists(origin_hotkey),
+            Error::<T>::HotKeyAccountNotExists
+        );
+
+        // Ensure origin coldkey owns the origin hotkey.
+        ensure!(
+            Self::coldkey_owns_hotkey(origin_coldkey, origin_hotkey),
+            Error::<T>::NonAssociatedColdKey
+        );
+
+        // Ensure there is enough stake in the origin subnet.
+        let origin_alpha = Self::get_stake_for_hotkey_and_coldkey_on_subnet(
+            origin_hotkey,
+            origin_coldkey,
+            origin_netuid,
+        );
+        ensure!(
+            alpha_amount <= origin_alpha,
+            Error::<T>::NotEnoughStakeToWithdraw
+        );
+
+        // Ensure that the stake amount to be removed is above the minimum in tao equivalent.
+        let tao_equivalent = Self::sim_swap_alpha_for_tao(origin_netuid, alpha_amount);
+        ensure!(
+            tao_equivalent > DefaultMinStake::<T>::get(),
+            Error::<T>::AmountTooLow
+        );
+
+        Ok(())
+    }
 }
 
 ///////////////////////////////////////////
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 4061f07e7..6af41b388 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -511,7 +511,7 @@ fn test_do_move_wrong_origin() {
         let origin_hotkey = U256::from(2);
         let destination_hotkey = U256::from(3);
         let netuid = 1;
-        let stake_amount = 1000;
+        let stake_amount = DefaultMinStake::<Test>::get() * 10;
         let fee = 0;
 
         // Set up initial stake
@@ -535,7 +535,7 @@ fn test_do_move_wrong_origin() {
                 netuid,
                 alpha,
             ),
-            Error::<Test>::NotEnoughStakeToWithdraw
+            Error::<Test>::NonAssociatedColdKey
         );
 
         // Check that no stake was moved
@@ -770,7 +770,7 @@ fn test_do_move_max_values() {
 
 // Verify moving too low amount is impossible
 #[test]
-fn test_moving_too_little_fails() {
+fn test_moving_too_little_unstakes() {
     new_test_ext(1).execute_with(|| {
         let hotkey_account_id = U256::from(533453);
         let coldkey_account_id = U256::from(55453);
@@ -791,7 +791,6 @@ fn test_moving_too_little_fails() {
             amount + fee
         ));
 
-        // Coldkey / hotkey 0 decreases take to 5%. This should fail as the minimum take is 9%
         assert_err!(
             SubtensorModule::move_stake(
                 RuntimeOrigin::signed(coldkey_account_id),
diff --git a/pallets/subtensor/src/tests/registration.rs b/pallets/subtensor/src/tests/registration.rs
index 07a456c83..e4d1b1045 100644
--- a/pallets/subtensor/src/tests/registration.rs
+++ b/pallets/subtensor/src/tests/registration.rs
@@ -3,7 +3,7 @@
 use frame_support::traits::Currency;
 
 use super::mock::*;
-use crate::{AxonInfoOf, Error, SubtensorSignedExtension};
+use crate::{AxonInfoOf, CustomTransactionError, Error, SubtensorSignedExtension};
 use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays};
 use frame_support::sp_runtime::{transaction_validity::InvalidTransaction, DispatchError};
 use frame_support::{assert_err, assert_noop, assert_ok};
@@ -274,7 +274,10 @@ fn test_registration_rate_limit_exceeded() {
         let result = extension.validate(&who, &call.into(), &info, 10);
 
         // Expectation: The transaction should be rejected
-        assert_err!(result, InvalidTransaction::Custom(5));
+        assert_err!(
+            result,
+            InvalidTransaction::Custom(CustomTransactionError::RateLimitExceeded.into())
+        );
 
         let current_registrants = SubtensorModule::get_registrations_this_interval(netuid);
         assert!(current_registrants <= max_registrants);
@@ -356,7 +359,10 @@ fn test_burned_registration_rate_limit_exceeded() {
             extension.validate(&who, &call_burned_register.into(), &info, 10);
 
         // Expectation: The transaction should be rejected
-        assert_err!(burned_register_result, InvalidTransaction::Custom(5));
+        assert_err!(
+            burned_register_result,
+            InvalidTransaction::Custom(CustomTransactionError::RateLimitExceeded.into())
+        );
 
         let current_registrants = SubtensorModule::get_registrations_this_interval(netuid);
         assert!(current_registrants <= max_registrants);
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index f57fb4ebe..8087e85df 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -19,12 +19,12 @@ use sp_core::{Get, H256, U256};
 fn test_add_stake_dispatch_info_ok() {
     new_test_ext(1).execute_with(|| {
         let hotkey = U256::from(0);
-        let amount_staked = 5000;
+        let amount = 5000;
         let netuid = 1;
         let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
             hotkey,
             netuid,
-            amount_staked,
+            amount,
         });
         assert_eq!(
             call.get_dispatch_info(),
@@ -158,8 +158,9 @@ fn test_add_stake_not_registered_key_pair() {
         let coldkey_account_id = U256::from(435445);
         let hotkey_account_id = U256::from(54544);
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
-        let amount = 1337;
-        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 1800);
+        let amount = DefaultMinStake::<Test>::get() * 10;
+        let fee = DefaultStakingFee::<Test>::get();
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount + fee);
         assert_err!(
             SubtensorModule::add_stake(
                 RuntimeOrigin::signed(coldkey_account_id),
@@ -390,7 +391,7 @@ fn test_remove_stake_ok_no_emission() {
 }
 
 #[test]
-fn test_remove_stake_amount_zero() {
+fn test_remove_stake_amount_too_low() {
     new_test_ext(1).execute_with(|| {
         let subnet_owner_coldkey = U256::from(1);
         let subnet_owner_hotkey = U256::from(2);
@@ -424,7 +425,7 @@ fn test_remove_stake_amount_zero() {
                 netuid,
                 0
             ),
-            Error::<Test>::StakeToWithdrawIsZero
+            Error::<Test>::AmountTooLow
         );
     });
 }
@@ -454,7 +455,7 @@ fn test_remove_stake_ok_hotkey_does_not_belong_to_coldkey() {
         let coldkey_id = U256::from(544);
         let hotkey_id = U256::from(54544);
         let other_cold_key = U256::from(99498);
-        let amount = 1000;
+        let amount = DefaultMinStake::<Test>::get() * 10;
         let netuid: u16 = add_dynamic_network(&hotkey_id, &coldkey_id);
 
         // Give the neuron some stake to remove
@@ -479,7 +480,7 @@ fn test_remove_stake_no_enough_stake() {
     new_test_ext(1).execute_with(|| {
         let coldkey_id = U256::from(544);
         let hotkey_id = U256::from(54544);
-        let amount = 10000;
+        let amount = DefaultMinStake::<Test>::get() * 10;
         let netuid = add_dynamic_network(&hotkey_id, &coldkey_id);
 
         assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0);
@@ -2074,17 +2075,17 @@ fn test_stake_below_min_validate() {
         let subnet_owner_hotkey = U256::from(1002);
         let hotkey = U256::from(2);
         let coldkey = U256::from(3);
-        let amount_staked = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get() - 1;
+        let amount = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get() - 1;
 
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount);
 
         // Add stake call
         let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
             hotkey,
             netuid,
-            amount_staked,
+            amount,
         });
 
         let info: crate::DispatchInfo =
@@ -2097,24 +2098,28 @@ fn test_stake_below_min_validate() {
         // Should fail due to insufficient stake
         assert_err!(
             result_no_stake,
-            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(1))
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::StakeAmountTooLow.into()
+            ))
         );
 
         // Increase the stake to be equal to the minimum, but leave the balance low
-        let amount_staked = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get();
+        let amount = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get();
         let call_2 = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
             hotkey,
             netuid,
-            amount_staked,
+            amount,
         });
 
         // Submit to the signed extension validate function
         let result_low_balance = extension.validate(&coldkey, &call_2.clone(), &info, 10);
 
-        // Still doesn't pass
+        // Still doesn't pass, but with a different reason (balance too low)
         assert_err!(
             result_low_balance,
-            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(2))
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::BalanceTooLow.into()
+            ))
         );
 
         // Increase the coldkey balance to match the minimum
diff --git a/pallets/subtensor/src/tests/weights.rs b/pallets/subtensor/src/tests/weights.rs
index 9a89ec76e..3b6919064 100644
--- a/pallets/subtensor/src/tests/weights.rs
+++ b/pallets/subtensor/src/tests/weights.rs
@@ -105,7 +105,9 @@ fn test_set_rootweights_validate() {
         assert_err!(
             // Should get an invalid transaction error
             result_no_stake,
-            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(4))
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::StakeAmountTooLow.into()
+            ))
         );
 
         // Increase the stake to be equal to the minimum
@@ -328,7 +330,9 @@ fn test_set_weights_validate() {
         // Should fail due to insufficient stake
         assert_err!(
             result_no_stake,
-            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(3))
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::StakeAmountTooLow.into()
+            ))
         );
 
         // Increase the stake to be equal to the minimum
@@ -402,7 +406,9 @@ fn test_reveal_weights_validate() {
         assert_err!(
             // Should get an invalid transaction error
             result_no_stake,
-            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(2))
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::StakeAmountTooLow.into()
+            ))
         );
 
         // Increase the stake to be equal to the minimum
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index 86d257a19..743000dec 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -85,7 +85,7 @@ impl StakingPrecompile {
         let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::<Runtime>::add_stake {
             hotkey,
             netuid,
-            amount_staked: amount_sub.unique_saturated_into(),
+            amount: amount_sub.unique_saturated_into(),
         });
         // Dispatch the add_stake call
         Self::dispatch(handle, call)
diff --git a/runtime/tests/pallet_proxy.rs b/runtime/tests/pallet_proxy.rs
index 2cfbd908b..1aad63283 100644
--- a/runtime/tests/pallet_proxy.rs
+++ b/runtime/tests/pallet_proxy.rs
@@ -103,11 +103,11 @@ fn call_senate() -> RuntimeCall {
 // staking call
 fn call_add_stake() -> RuntimeCall {
     let netuid = 1;
-    let amount_staked = 100;
+    let amount = 100;
     RuntimeCall::SubtensorModule(pallet_subtensor::Call::add_stake {
         hotkey: AccountId::from(DELEGATE),
         netuid,
-        amount_staked,
+        amount,
     })
 }
 

From f0534f1cb9fb96c601771ba31bc12b3850aa09dd Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Thu, 23 Jan 2025 18:57:30 -0500
Subject: [PATCH 062/145] Fix merge conflicts

---
 pallets/subtensor/src/tests/move_stake.rs | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 11939a1a6..c7f88f985 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -1079,8 +1079,6 @@ fn test_do_swap_success() {
         let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
-        let fee = DefaultMinStake::<Test>::get();
-
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
@@ -1265,8 +1263,6 @@ fn test_do_swap_same_subnet() {
         let subnet_owner_hotkey = U256::from(1101);
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
-        let fee = DefaultMinStake::<Test>::get();
-
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
@@ -1291,8 +1287,8 @@ fn test_do_swap_same_subnet() {
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
         assert_abs_diff_eq!(
             alpha_after,
-            alpha_before - fee,
-            epsilon = alpha_after / 1000
+            alpha_before - fee_as_alpha,
+            epsilon = alpha_after / 10000
         );
     });
 }
@@ -1305,8 +1301,6 @@ fn test_do_swap_partial_stake() {
         let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
-        let fee = DefaultMinStake::<Test>::get();
-
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let total_stake = DefaultMinStake::<Test>::get() * 10;
@@ -1354,8 +1348,6 @@ fn test_do_swap_storage_updates() {
         let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
-        let fee = DefaultMinStake::<Test>::get();
-
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let stake_amount = DefaultMinStake::<Test>::get() * 10;
@@ -1408,8 +1400,6 @@ fn test_do_swap_multiple_times() {
         let netuid1 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         let netuid2 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
 
-        let fee = DefaultMinStake::<Test>::get();
-
         let coldkey = U256::from(1);
         let hotkey = U256::from(2);
         let initial_stake = DefaultMinStake::<Test>::get() * 10;
@@ -1459,8 +1449,8 @@ fn test_do_swap_multiple_times() {
         let expected_stake = initial_stake - total_alpha1_fee;
         assert_abs_diff_eq!(
             final_stake_netuid1,
-            initial_stake - 6 * fee,
-            epsilon = initial_stake / 1000
+            expected_stake,
+            epsilon = initial_stake / 10000
         );
         assert_eq!(final_stake_netuid2, 0);
     });

From ab4d6e1bccb519c270850b19b35b442113ee8b1f Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Thu, 23 Jan 2025 19:09:03 -0500
Subject: [PATCH 063/145] Rename amount back to amount_staked in add_stake
 parameters

---
 pallets/subtensor/src/lib.rs               |  4 ++--
 pallets/subtensor/src/macros/dispatches.rs |  4 ++--
 pallets/subtensor/src/tests/staking.rs     | 14 +++++++-------
 runtime/src/precompiles/staking.rs         |  2 +-
 runtime/tests/pallet_proxy.rs              |  4 ++--
 5 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 2a7c32054..45012625c 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -1781,11 +1781,11 @@ where
             Some(Call::add_stake {
                 hotkey,
                 netuid,
-                amount,
+                amount_staked,
             }) => {
                 // Fully validate the user input
                 Self::result_to_validity(Pallet::<T>::validate_add_stake(
-                    who, hotkey, *netuid, *amount,
+                    who, hotkey, *netuid, *amount_staked,
                 ))
             }
             Some(Call::remove_stake {
diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs
index 2f4e2f563..d9eafffa7 100644
--- a/pallets/subtensor/src/macros/dispatches.rs
+++ b/pallets/subtensor/src/macros/dispatches.rs
@@ -584,9 +584,9 @@ mod dispatches {
             origin: OriginFor<T>,
             hotkey: T::AccountId,
             netuid: u16,
-            amount: u64,
+            amount_staked: u64,
         ) -> DispatchResult {
-            Self::do_add_stake(origin, hotkey, netuid, amount)
+            Self::do_add_stake(origin, hotkey, netuid, amount_staked)
         }
 
         /// Remove stake from the staking account. The call must be made
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 8087e85df..f73f9b447 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -19,12 +19,12 @@ use sp_core::{Get, H256, U256};
 fn test_add_stake_dispatch_info_ok() {
     new_test_ext(1).execute_with(|| {
         let hotkey = U256::from(0);
-        let amount = 5000;
+        let amount_staked = 5000;
         let netuid = 1;
         let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
             hotkey,
             netuid,
-            amount,
+            amount_staked,
         });
         assert_eq!(
             call.get_dispatch_info(),
@@ -2075,17 +2075,17 @@ fn test_stake_below_min_validate() {
         let subnet_owner_hotkey = U256::from(1002);
         let hotkey = U256::from(2);
         let coldkey = U256::from(3);
-        let amount = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get() - 1;
+        let amount_staked = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get() - 1;
 
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
-        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
 
         // Add stake call
         let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
             hotkey,
             netuid,
-            amount,
+            amount_staked,
         });
 
         let info: crate::DispatchInfo =
@@ -2104,11 +2104,11 @@ fn test_stake_below_min_validate() {
         );
 
         // Increase the stake to be equal to the minimum, but leave the balance low
-        let amount = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get();
+        let amount_staked = DefaultMinStake::<Test>::get() + DefaultStakingFee::<Test>::get();
         let call_2 = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
             hotkey,
             netuid,
-            amount,
+            amount_staked,
         });
 
         // Submit to the signed extension validate function
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index 169802dc4..f8534927b 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -84,7 +84,7 @@ impl StakingPrecompile {
         let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::<Runtime>::add_stake {
             hotkey,
             netuid,
-            amount: amount_sub.unique_saturated_into(),
+            amount_staked: amount_sub.unique_saturated_into(),
         });
         // Dispatch the add_stake call
         Self::dispatch(handle, call)
diff --git a/runtime/tests/pallet_proxy.rs b/runtime/tests/pallet_proxy.rs
index 1aad63283..2cfbd908b 100644
--- a/runtime/tests/pallet_proxy.rs
+++ b/runtime/tests/pallet_proxy.rs
@@ -103,11 +103,11 @@ fn call_senate() -> RuntimeCall {
 // staking call
 fn call_add_stake() -> RuntimeCall {
     let netuid = 1;
-    let amount = 100;
+    let amount_staked = 100;
     RuntimeCall::SubtensorModule(pallet_subtensor::Call::add_stake {
         hotkey: AccountId::from(DELEGATE),
         netuid,
-        amount,
+        amount_staked,
     })
 }
 

From beb6f6b144ddebc39f06ce72c98cd2a43dc427cd Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Fri, 24 Jan 2025 09:11:09 -0500
Subject: [PATCH 064/145] Format and bump spec

---
 pallets/subtensor/src/lib.rs | 5 ++++-
 runtime/src/lib.rs           | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 45012625c..cbe394037 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -1785,7 +1785,10 @@ where
             }) => {
                 // Fully validate the user input
                 Self::result_to_validity(Pallet::<T>::validate_add_stake(
-                    who, hotkey, *netuid, *amount_staked,
+                    who,
+                    hotkey,
+                    *netuid,
+                    *amount_staked,
                 ))
             }
             Some(Call::remove_stake {
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index e0ea63987..f8491dd57 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
     //   `spec_version`, and `authoring_version` are the same between Wasm and native.
     // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
     //   the compatible custom types.
-    spec_version: 223,
+    spec_version: 224,
     impl_version: 1,
     apis: RUNTIME_API_VERSIONS,
     transaction_version: 1,

From d91dc3c8e0f7af7916543244195187db1429a9cc Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Fri, 24 Jan 2025 10:09:06 -0500
Subject: [PATCH 065/145] Fix/run set pending children on epoch (#1171)

* add back running set-pending-children

* add test

* move to step block

* commit Cargo.lock

* use mock sched children at end of loop instead

* set reg diff before try reg again

* oops, add netuid

* fix tests using add network tempo 0 -> 1

* chore: fmt

* only wait blocks after schedule all children for tests

* fix test: wip

* charge fee for swap and add for tests

* wip

* chore: clippy

* chore: fmt

* use get_dynamic_tao_emission for testing emission

* spec bump
---
 pallets/subtensor/src/coinbase/block_step.rs |  14 ++
 pallets/subtensor/src/tests/children.rs      | 191 +++++++++++++++----
 pallets/subtensor/src/tests/epoch.rs         |   2 +-
 pallets/subtensor/src/tests/mock.rs          |  22 ++-
 pallets/subtensor/src/tests/move_stake.rs    |   4 +-
 pallets/subtensor/src/tests/registration.rs  |   4 +-
 pallets/subtensor/src/tests/senate.rs        |   2 +-
 pallets/subtensor/src/tests/staking.rs       |  18 +-
 pallets/subtensor/src/tests/swap_hotkey.rs   |  26 +--
 pallets/subtensor/src/tests/weights.rs       |  16 +-
 runtime/src/lib.rs                           |   2 +-
 11 files changed, 225 insertions(+), 76 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs
index c3abf8dab..23218ed50 100644
--- a/pallets/subtensor/src/coinbase/block_step.rs
+++ b/pallets/subtensor/src/coinbase/block_step.rs
@@ -14,10 +14,24 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
         log::debug!("Block emission: {:?}", block_emission);
         // --- 3. Run emission through network.
         Self::run_coinbase(block_emission);
+
+        // --- 4. Set pending children on the epoch; but only after the coinbase has been run.
+        Self::try_set_pending_children(block_number);
+
         // Return ok.
         Ok(())
     }
 
+    fn try_set_pending_children(block_number: u64) {
+        let subnets: Vec<u16> = Self::get_all_subnet_netuids();
+        for &netuid in subnets.iter() {
+            if Self::should_run_epoch(netuid, block_number) {
+                // Set pending children on the epoch.
+                Self::do_set_pending_children(netuid);
+            }
+        }
+    }
+
     /// Adjusts the network difficulties/burns of every active network. Resetting state parameters.
     ///
     pub fn adjust_registration_terms_for_networks() {
diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs
index eb299d88e..30fe8287b 100644
--- a/pallets/subtensor/src/tests/children.rs
+++ b/pallets/subtensor/src/tests/children.rs
@@ -331,7 +331,7 @@ fn test_add_singular_child() {
             ),
             Err(Error::<Test>::SubNetworkDoesNotExist.into())
         );
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         step_rate_limit(&TransactionType::SetChildren, netuid);
         assert_eq!(
             SubtensorModule::do_schedule_children(
@@ -376,7 +376,7 @@ fn test_get_stake_for_hotkey_on_subnet() {
         let child = U256::from(2);
         let coldkey1 = U256::from(3);
         let coldkey2 = U256::from(4);
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, parent, coldkey1, 0);
         register_ok_neuron(netuid, child, coldkey2, 0);
         // Set parent-child relationship with 100% stake allocation
@@ -1664,7 +1664,7 @@ fn test_get_parents_chain() {
 
         // Set up parent-child relationships
         for i in 0..num_keys - 1 {
-            mock_set_children(
+            mock_schedule_children(
                 &coldkey,
                 &hotkeys[i],
                 netuid,
@@ -1677,6 +1677,8 @@ fn test_get_parents_chain() {
                 proportion
             );
         }
+        // Wait for children to be set
+        wait_and_set_pending_children(netuid);
 
         // Test get_parents for each hotkey
         for i in 1..num_keys {
@@ -1715,7 +1717,9 @@ fn test_get_parents_chain() {
         // Test multiple parents
         let last_hotkey = hotkeys[num_keys - 1];
         let new_parent = U256::from(num_keys as u64 + 2);
-        register_ok_neuron(netuid, new_parent, coldkey, 0);
+        // Set reg diff back down (adjusted from last block steps)
+        SubtensorModule::set_difficulty(netuid, 1);
+        register_ok_neuron(netuid, new_parent, coldkey, 99 * 2);
         log::info!(
             "Registered new parent neuron: new_parent={}, coldkey={}, netuid={}",
             new_parent,
@@ -1772,7 +1776,7 @@ fn test_get_stake_for_hotkey_on_subnet_basic() {
         let hotkey = U256::from(1);
         let coldkey = U256::from(2);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey, coldkey, 0);
         SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey, &coldkey, netuid, 1000,
@@ -1798,7 +1802,7 @@ fn test_get_stake_for_hotkey_on_subnet_multiple_coldkeys() {
         let coldkey1 = U256::from(2);
         let coldkey2 = U256::from(3);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey, coldkey1, 0);
 
         SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
@@ -1831,7 +1835,7 @@ fn test_get_stake_for_hotkey_on_subnet_single_parent_child() {
         let child = U256::from(2);
         let coldkey = U256::from(3);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, parent, coldkey, 0);
         register_ok_neuron(netuid, child, coldkey, 0);
 
@@ -1869,7 +1873,7 @@ fn test_get_stake_for_hotkey_on_subnet_multiple_parents_single_child() {
         let child = U256::from(3);
         let coldkey = U256::from(4);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, parent1, coldkey, 0);
         register_ok_neuron(netuid, parent2, coldkey, 0);
         register_ok_neuron(netuid, child, coldkey, 0);
@@ -1922,7 +1926,7 @@ fn test_get_stake_for_hotkey_on_subnet_single_parent_multiple_children() {
         let child2 = U256::from(3);
         let coldkey = U256::from(4);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, parent, coldkey, 0);
         register_ok_neuron(netuid, child1, coldkey, 0);
         register_ok_neuron(netuid, child2, coldkey, 0);
@@ -1985,7 +1989,7 @@ fn test_get_stake_for_hotkey_on_subnet_edge_cases() {
         let child2 = U256::from(3);
         let coldkey = U256::from(4);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, parent, coldkey, 0);
         register_ok_neuron(netuid, child1, coldkey, 0);
         register_ok_neuron(netuid, child2, coldkey, 0);
@@ -2057,7 +2061,7 @@ fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() {
         let coldkey_child2 = U256::from(7);
         let coldkey_grandchild = U256::from(8);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         SubtensorModule::set_max_registrations_per_block(netuid, 1000);
         SubtensorModule::set_target_registrations_per_interval(netuid, 1000);
         register_ok_neuron(netuid, parent, coldkey_parent, 0);
@@ -2247,8 +2251,8 @@ fn test_get_stake_for_hotkey_on_subnet_multiple_networks() {
         let hotkey = U256::from(1);
         let coldkey = U256::from(2);
 
-        add_network(netuid1, 0, 0);
-        add_network(netuid2, 0, 0);
+        add_network(netuid1, 1, 0);
+        add_network(netuid2, 1, 0);
         register_ok_neuron(netuid1, hotkey, coldkey, 0);
         register_ok_neuron(netuid2, hotkey, coldkey, 0);
 
@@ -2439,6 +2443,73 @@ fn test_do_set_child_cooldown_period() {
     });
 }
 
+// Test that pending childkeys get set during the epoch after the cooldown period.
+//
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::children::test_do_set_pending_children_runs_in_epoch --exact --show-output --nocapture
+#[cfg(test)]
+#[test]
+fn test_do_set_pending_children_runs_in_epoch() {
+    new_test_ext(1).execute_with(|| {
+        let coldkey = U256::from(1);
+        let parent = U256::from(2);
+        let child = U256::from(3);
+        let netuid: u16 = 1;
+        let proportion: u64 = 1000;
+
+        // Add network and register hotkey
+        add_network(netuid, 13, 0);
+        register_ok_neuron(netuid, parent, coldkey, 0);
+
+        // Set minimum stake for setting children
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &parent,
+            &coldkey,
+            netuid,
+            StakeThreshold::<Test>::get(),
+        );
+
+        // Schedule parent-child relationship
+        assert_ok!(SubtensorModule::do_schedule_children(
+            RuntimeOrigin::signed(coldkey),
+            parent,
+            netuid,
+            vec![(proportion, child)],
+        ));
+
+        // Ensure the childkeys are not yet applied
+        let children_before = SubtensorModule::get_children(&parent, netuid);
+        close(
+            children_before.len() as u64,
+            0,
+            0,
+            "Children vector should be empty before cooldown",
+        );
+
+        wait_set_pending_children_cooldown(netuid);
+
+        // Verify child assignment
+        let children_after = SubtensorModule::get_children(&parent, netuid);
+        close(
+            children_after.len() as u64,
+            1,
+            0,
+            "Children vector should have one entry after cooldown",
+        );
+        close(
+            children_after[0].0,
+            proportion,
+            0,
+            "Child proportion should match",
+        );
+        close(
+            children_after[0].1.try_into().unwrap(),
+            child.try_into().unwrap(),
+            0,
+            "Child key should match",
+        );
+    });
+}
+
 // Test that revoking childkeys does not require minimum stake
 // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::children::test_revoke_child_no_min_stake_check --exact --show-output --nocapture
 #[test]
@@ -3033,14 +3104,17 @@ fn test_childkey_take_drain_validator_take() {
 // - Runs an epoch
 // - Checks the emission distribution among parents, child, and weight setter
 // - Verifies that all parties received emissions and the total stake increased correctly
-// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_childkey_multiple_parents_emission -- --nocapture
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::children::test_childkey_multiple_parents_emission --exact --nocapture
 #[test]
 fn test_childkey_multiple_parents_emission() {
     new_test_ext(1).execute_with(|| {
         let subnet_owner_coldkey = U256::from(1001);
-        let subnet_owner_hotkey = U256::from(1002);
+        let subnet_owner_hotkey: U256 = U256::from(1002);
         let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
         Tempo::<Test>::insert(netuid, 10); // run epoch every 10 blocks
+                                           // Set subnet owner cut to 0
+        SubtensorModule::set_subnet_owner_cut(0);
+        SubtensorModule::set_tao_weight(0); // No TAO weight
 
         // Set registration parameters and emission tempo
         SubtensorModule::set_max_registrations_per_block(netuid, 1000);
@@ -3064,9 +3138,9 @@ fn test_childkey_multiple_parents_emission() {
             (true, coldkey_weight_setter, weight_setter, 100_000_000),
         ];
 
-        let initial_actual_stakes: Vec<u64> = initial_stakes
+        initial_stakes
             .iter()
-            .map(|(register, coldkey, hotkey, stake)| {
+            .for_each(|(register, coldkey, hotkey, stake)| {
                 SubtensorModule::add_balance_to_coldkey_account(coldkey, *stake);
                 if *register {
                     // Register a neuron
@@ -3081,20 +3155,28 @@ fn test_childkey_multiple_parents_emission() {
                     netuid,
                     *stake
                 ));
-
-                // Return actual stake
-                SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid)
-            })
-            .collect();
+            });
 
         SubtensorModule::set_weights_set_rate_limit(netuid, 0);
         step_block(2);
 
         // Set parent-child relationships
-        mock_set_children(&coldkey_parent1, &parent1, netuid, &[(u64::MAX, child)]);
-        mock_set_children(&coldkey_parent2, &parent2, netuid, &[(u64::MAX / 2, child)]);
+        mock_schedule_children(&coldkey_parent1, &parent1, netuid, &[(u64::MAX, child)]);
+        mock_schedule_children(&coldkey_parent2, &parent2, netuid, &[(u64::MAX / 2, child)]);
+        wait_and_set_pending_children(netuid);
         ChildkeyTake::<Test>::insert(child, netuid, u16::MAX / 5);
 
+        // Set pending emission to 0
+        PendingEmission::<Test>::insert(netuid, 0);
+
+        let initial_actual_stakes: Vec<u64> = initial_stakes
+            .iter()
+            .map(|(_register, coldkey, hotkey, _stake)| {
+                // Return actual stake
+                SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid)
+            })
+            .collect();
+
         // Set weights (subnet owner is uid 0, ignore him)
         let uids: Vec<u16> = vec![1, 2];
         let values: Vec<u16> = vec![65354, 65354];
@@ -3107,7 +3189,7 @@ fn test_childkey_multiple_parents_emission() {
             values,
             version_key
         ));
-
+        log::info!("Running an epoch");
         // Wait until epoch
         let start_block = SubtensorModule::get_current_block_as_u64();
         loop {
@@ -3118,8 +3200,19 @@ fn test_childkey_multiple_parents_emission() {
             }
             step_block(1);
         }
-        let total_emission = SubtensorModule::get_block_emission().unwrap_or(0)
-            * (SubtensorModule::get_current_block_as_u64() - start_block + 1);
+        // We substract one because we are running it *after* the epoch, so we don't expect it to effect the emission.
+        let blocks_passed = SubtensorModule::get_current_block_as_u64() - start_block - 1;
+        log::info!("blocks_passed: {:?}", blocks_passed);
+        let alpha_block_emission: u64 = SubtensorModule::get_block_emission_for_issuance(
+            SubtensorModule::get_alpha_issuance(netuid),
+        )
+        .unwrap_or(0);
+        let (_, _, per_block_emission) = SubtensorModule::get_dynamic_tao_emission(
+            netuid,
+            SubtensorModule::get_block_emission().unwrap_or(0),
+            alpha_block_emission,
+        );
+        let total_emission = per_block_emission * blocks_passed;
 
         // Check emission distribution
         let stakes: Vec<(U256, U256, &str)> = vec![
@@ -3200,6 +3293,19 @@ fn test_childkey_multiple_parents_emission() {
             "Child should have received some emission"
         );
 
+        let mut total_stake_on_subnet = 0;
+        let hks = [parent1, parent2, child, weight_setter];
+        for (hk, net, alpha) in TotalHotkeyAlpha::<Test>::iter() {
+            if hks.contains(&hk) && net == netuid {
+                total_stake_on_subnet += alpha;
+            } else {
+                log::info!("hk: {:?}, net: {:?}, alpha: {:?}", hk, net, alpha);
+            }
+        }
+
+        log::info!("total_stake_on_subnet: {:?}", total_stake_on_subnet);
+        log::info!("total_stake: {:?}", TotalStake::<Test>::get());
+        log::info!("total_emission: {:?}", total_emission);
         // Check that the total stake has increased by the emission amount
         // Allow 1% slippage
         let total_stake = parent1_stake + parent2_stake + child_stake + weight_setter_stake;
@@ -3207,7 +3313,7 @@ fn test_childkey_multiple_parents_emission() {
         assert_abs_diff_eq!(
             total_stake,
             initial_total_stake + total_emission,
-            epsilon = total_emission / 100
+            epsilon = total_emission / 100,
         );
     });
 }
@@ -3280,7 +3386,7 @@ fn test_parent_child_chain_emission() {
         let stake_b: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_b);
         let stake_c: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_c);
 
-        let total_stake: I96F32 = I96F32::from_num(stake_a + stake_b + stake_c);
+        let _total_stake: I96F32 = I96F32::from_num(stake_a + stake_b + stake_c);
 
         // Assert initial stake is correct
         let rel_stake_a = I96F32::from_num(stake_a) / total_tao;
@@ -3296,10 +3402,18 @@ fn test_parent_child_chain_emission() {
 
         // Set parent-child relationships
         // A -> B (50% of A's stake)
-        mock_set_children(&coldkey_a, &hotkey_a, netuid, &[(u64::MAX / 2, hotkey_b)]);
+        mock_schedule_children(&coldkey_a, &hotkey_a, netuid, &[(u64::MAX / 2, hotkey_b)]);
 
         // B -> C (50% of B's stake)
-        mock_set_children(&coldkey_b, &hotkey_b, netuid, &[(u64::MAX / 2, hotkey_c)]);
+        mock_schedule_children(&coldkey_b, &hotkey_b, netuid, &[(u64::MAX / 2, hotkey_c)]);
+        wait_and_set_pending_children(netuid); // Don't want to run blocks before both children are scheduled
+
+        // Get old stakes after children are scheduled
+        let stake_a_old: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_a);
+        let stake_b_old: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_b);
+        let stake_c_old: u64 = SubtensorModule::get_total_stake_for_hotkey(&hotkey_c);
+
+        let total_stake_old: I96F32 = I96F32::from_num(stake_a_old + stake_b_old + stake_c_old);
 
         // Set CHK take rate to 1/9
         let chk_take: I96F32 = I96F32::from_num(1_f64 / 9_f64);
@@ -3344,6 +3458,9 @@ fn test_parent_child_chain_emission() {
             "C should have pending emission of 1/9 of total emission"
         );
 
+        // Set pending emission to 0
+        PendingEmission::<Test>::insert(netuid, 0);
+
         // Run epoch with a hardcoded emission value
         SubtensorModule::run_coinbase(hardcoded_emission);
 
@@ -3356,10 +3473,10 @@ fn test_parent_child_chain_emission() {
         log::info!("Stake for hotkey B: {:?}", stake_b_new);
         log::info!("Stake for hotkey C: {:?}", stake_c_new);
 
-        let stake_inc_a: u64 = stake_a_new - stake_a;
-        let stake_inc_b: u64 = stake_b_new - stake_b;
-        let stake_inc_c: u64 = stake_c_new - stake_c;
-        let total_stake_inc: I96F32 = total_stake_new - total_stake;
+        let stake_inc_a: u64 = stake_a_new - stake_a_old;
+        let stake_inc_b: u64 = stake_b_new - stake_b_old;
+        let stake_inc_c: u64 = stake_c_new - stake_c_old;
+        let total_stake_inc: I96F32 = total_stake_new - total_stake_old;
         log::info!("Stake increase for hotkey A: {:?}", stake_inc_a);
         log::info!("Stake increase for hotkey B: {:?}", stake_inc_b);
         log::info!("Stake increase for hotkey C: {:?}", stake_inc_c);
@@ -3406,9 +3523,9 @@ fn test_parent_child_chain_emission() {
 
         let eps: I96F32 = I96F32::from_num(10_000);
         assert!(
-            (total_stake_new - (total_stake + hardcoded_emission)).abs() <= eps,
+            (total_stake_new - (total_stake_old + hardcoded_emission)).abs() <= eps,
             "Total stake should have increased by the hardcoded emission amount {:?}",
-            total_stake_new - (total_stake + hardcoded_emission)
+            total_stake_new - (total_stake_old + hardcoded_emission)
         );
     });
 }
diff --git a/pallets/subtensor/src/tests/epoch.rs b/pallets/subtensor/src/tests/epoch.rs
index 7973a44e1..d80c9e074 100644
--- a/pallets/subtensor/src/tests/epoch.rs
+++ b/pallets/subtensor/src/tests/epoch.rs
@@ -493,7 +493,7 @@ fn init_run_epochs(
 //     new_test_ext(1).execute_with(|| {
 //         log::info!("test_overflow:");
 //         let netuid: u16 = 1;
-//         add_network(netuid, 0, 0);
+//         add_network(netuid, 1,  0);
 //         SubtensorModule::set_max_allowed_uids(netuid, 3);
 //         SubtensorModule::increase_stake_on_coldkey_hotkey_account(
 //             &U256::from(0),
diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs
index 9d5f939f6..b0d7c461a 100644
--- a/pallets/subtensor/src/tests/mock.rs
+++ b/pallets/subtensor/src/tests/mock.rs
@@ -601,6 +601,7 @@ pub(crate) fn step_epochs(count: u16, netuid: u16) {
             SubtensorModule::get_tempo(netuid),
             SubtensorModule::get_current_block_as_u64(),
         );
+        log::info!("Blocks to next epoch: {:?}", blocks_to_next_epoch);
         step_block(blocks_to_next_epoch as u16);
 
         assert!(SubtensorModule::should_run_epoch(
@@ -686,16 +687,28 @@ pub fn setup_neuron_with_stake(netuid: u16, hotkey: U256, coldkey: U256, stake:
     increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake, netuid);
 }
 
+#[allow(dead_code)]
+pub fn wait_set_pending_children_cooldown(netuid: u16) {
+    let cooldown = DefaultPendingCooldown::<Test>::get();
+    step_block(cooldown as u16); // Wait for cooldown to pass
+    step_epochs(1, netuid); // Run next epoch
+}
+
 #[allow(dead_code)]
 pub fn wait_and_set_pending_children(netuid: u16) {
     let original_block = System::block_number();
-    System::set_block_number(System::block_number() + 7300);
+    wait_set_pending_children_cooldown(netuid);
     SubtensorModule::do_set_pending_children(netuid);
     System::set_block_number(original_block);
 }
 
 #[allow(dead_code)]
-pub fn mock_set_children(coldkey: &U256, parent: &U256, netuid: u16, child_vec: &[(u64, U256)]) {
+pub fn mock_schedule_children(
+    coldkey: &U256,
+    parent: &U256,
+    netuid: u16,
+    child_vec: &[(u64, U256)],
+) {
     // Set minimum stake for setting children
     StakeThreshold::<Test>::put(0);
 
@@ -706,6 +719,11 @@ pub fn mock_set_children(coldkey: &U256, parent: &U256, netuid: u16, child_vec:
         netuid,
         child_vec.to_vec()
     ));
+}
+
+#[allow(dead_code)]
+pub fn mock_set_children(coldkey: &U256, parent: &U256, netuid: u16, child_vec: &[(u64, U256)]) {
+    mock_schedule_children(coldkey, parent, netuid, child_vec);
     wait_and_set_pending_children(netuid);
 }
 
diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 96d54ed77..b212de94e 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -242,7 +242,7 @@ fn test_do_move_nonexistent_destination_hotkey() {
         SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, stake_amount, fee);
 
         // Attempt to move stake from a non-existent origin hotkey
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         assert_noop!(
             SubtensorModule::do_move_stake(
                 RuntimeOrigin::signed(coldkey),
@@ -523,7 +523,7 @@ fn test_do_move_wrong_origin() {
         );
 
         // Attempt to move stake with wrong origin
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey);
         assert_err!(
diff --git a/pallets/subtensor/src/tests/registration.rs b/pallets/subtensor/src/tests/registration.rs
index 07a456c83..3088f4085 100644
--- a/pallets/subtensor/src/tests/registration.rs
+++ b/pallets/subtensor/src/tests/registration.rs
@@ -1211,7 +1211,7 @@ fn test_registration_get_uid_to_prune_all_in_immunity_period() {
     new_test_ext(1).execute_with(|| {
         System::set_block_number(0);
         let netuid: u16 = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         log::info!("add network");
         register_ok_neuron(netuid, U256::from(0), U256::from(0), 39420842);
         register_ok_neuron(netuid, U256::from(1), U256::from(1), 12412392);
@@ -1235,7 +1235,7 @@ fn test_registration_get_uid_to_prune_none_in_immunity_period() {
     new_test_ext(1).execute_with(|| {
         System::set_block_number(0);
         let netuid: u16 = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         log::info!("add network");
         register_ok_neuron(netuid, U256::from(0), U256::from(0), 39420842);
         register_ok_neuron(netuid, U256::from(1), U256::from(1), 12412392);
diff --git a/pallets/subtensor/src/tests/senate.rs b/pallets/subtensor/src/tests/senate.rs
index 01dfc17d7..dd198deb7 100644
--- a/pallets/subtensor/src/tests/senate.rs
+++ b/pallets/subtensor/src/tests/senate.rs
@@ -473,7 +473,7 @@ fn test_senate_leave_vote_removal() {
         // Add two networks.
         let root_netuid: u16 = 0;
         let other_netuid: u16 = 5;
-        add_network(other_netuid, 0, 0);
+        add_network(other_netuid, 1, 0);
         SubtensorModule::set_burn(other_netuid, 0);
         SubtensorModule::set_max_registrations_per_block(other_netuid, 1000);
         SubtensorModule::set_target_registrations_per_interval(other_netuid, 1000);
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index ef5ac5f4a..6de68a193 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -1295,7 +1295,7 @@ fn test_delegate_take_can_be_decreased() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Coldkey / hotkey 0 become delegates with 9% take
@@ -1330,7 +1330,7 @@ fn test_can_set_min_take_ok() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Coldkey / hotkey 0 become delegates
@@ -1362,7 +1362,7 @@ fn test_delegate_take_can_not_be_increased_with_decrease_take() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Set min take
@@ -1397,7 +1397,7 @@ fn test_delegate_take_can_be_increased() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Coldkey / hotkey 0 become delegates with 9% take
@@ -1432,7 +1432,7 @@ fn test_delegate_take_can_not_be_decreased_with_increase_take() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Coldkey / hotkey 0 become delegates with 9% take
@@ -1471,7 +1471,7 @@ fn test_delegate_take_can_be_increased_to_limit() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Coldkey / hotkey 0 become delegates with 9% take
@@ -1509,7 +1509,7 @@ fn test_delegate_take_can_not_be_increased_beyond_limit() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Coldkey / hotkey 0 become delegates with 9% take
@@ -1551,7 +1551,7 @@ fn test_rate_limits_enforced_on_increase_take() {
 
         // Register the neuron to a new network
         let netuid = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey0, coldkey0, 124124);
 
         // Coldkey / hotkey 0 become delegates with 9% take
@@ -1678,7 +1678,7 @@ fn test_get_total_delegated_stake_no_delegations() {
         let coldkey = U256::from(2);
         let netuid = 1u16;
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, delegate, coldkey, 0);
 
         // Check that there's no delegated stake
diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs
index d35dd6d56..328600cd8 100644
--- a/pallets/subtensor/src/tests/swap_hotkey.rs
+++ b/pallets/subtensor/src/tests/swap_hotkey.rs
@@ -222,7 +222,7 @@ fn test_swap_subnet_membership() {
         let netuid = 0u16;
         let mut weight = Weight::zero();
 
-        add_network(netuid, 0, 1);
+        add_network(netuid, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid, true);
         assert_ok!(SubtensorModule::perform_hotkey_swap(
             &old_hotkey,
@@ -247,7 +247,7 @@ fn test_swap_uids_and_keys() {
         let uid = 5u16;
         let mut weight = Weight::zero();
 
-        add_network(netuid, 0, 1);
+        add_network(netuid, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid, true);
         Uids::<Test>::insert(netuid, old_hotkey, uid);
         Keys::<Test>::insert(netuid, uid, old_hotkey);
@@ -276,7 +276,7 @@ fn test_swap_prometheus() {
         let prometheus_info = PrometheusInfo::default();
         let mut weight = Weight::zero();
 
-        add_network(netuid, 0, 1);
+        add_network(netuid, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid, true);
         Prometheus::<Test>::insert(netuid, old_hotkey, prometheus_info.clone());
 
@@ -306,7 +306,7 @@ fn test_swap_axons() {
         let axon_info = AxonInfo::default();
         let mut weight = Weight::zero();
 
-        add_network(netuid, 0, 1);
+        add_network(netuid, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid, true);
         Axons::<Test>::insert(netuid, old_hotkey, axon_info.clone());
 
@@ -333,7 +333,7 @@ fn test_swap_certificates() {
         let certificate = NeuronCertificate::try_from(vec![1, 2, 3]).unwrap();
         let mut weight = Weight::zero();
 
-        add_network(netuid, 0, 1);
+        add_network(netuid, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid, true);
         NeuronCertificates::<Test>::insert(netuid, old_hotkey, certificate.clone());
 
@@ -366,7 +366,7 @@ fn test_swap_weight_commits() {
         weight_commits.push_back((H256::from_low_u64_be(100), 200, 1, 1));
         let mut weight = Weight::zero();
 
-        add_network(netuid, 0, 1);
+        add_network(netuid, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid, true);
         WeightCommits::<Test>::insert(netuid, old_hotkey, weight_commits.clone());
 
@@ -397,7 +397,7 @@ fn test_swap_loaded_emission() {
         let validator_emission = 1000u64;
         let mut weight = Weight::zero();
 
-        add_network(netuid, 0, 1);
+        add_network(netuid, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid, true);
         LoadedEmission::<Test>::insert(
             netuid,
@@ -537,8 +537,8 @@ fn test_swap_hotkey_with_multiple_subnets() {
         let netuid2 = 1;
         let mut weight = Weight::zero();
 
-        add_network(netuid1, 0, 1);
-        add_network(netuid2, 0, 1);
+        add_network(netuid1, 1, 1);
+        add_network(netuid2, 1, 1);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid1, true);
         IsNetworkMember::<Test>::insert(old_hotkey, netuid2, true);
 
@@ -639,8 +639,8 @@ fn test_swap_hotkey_with_multiple_coldkeys_and_subnets() {
         let mut weight = Weight::zero();
 
         // Set up initial state
-        add_network(netuid1, 0, 1);
-        add_network(netuid2, 0, 1);
+        add_network(netuid1, 1, 1);
+        add_network(netuid2, 1, 1);
         register_ok_neuron(netuid1, old_hotkey, coldkey1, 1234);
         register_ok_neuron(netuid2, old_hotkey, coldkey1, 1234);
 
@@ -1258,7 +1258,7 @@ fn test_swap_parent_hotkey_childkey_maps() {
         let coldkey = U256::from(2);
         let child = U256::from(3);
         let parent_new = U256::from(4);
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         SubtensorModule::create_account_if_non_existent(&coldkey, &parent_old);
 
         // Set child and verify state maps
@@ -1301,7 +1301,7 @@ fn test_swap_child_hotkey_childkey_maps() {
         let coldkey = U256::from(2);
         let child_old = U256::from(3);
         let child_new = U256::from(4);
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         SubtensorModule::create_account_if_non_existent(&coldkey, &child_old);
         SubtensorModule::create_account_if_non_existent(&coldkey, &parent);
 
diff --git a/pallets/subtensor/src/tests/weights.rs b/pallets/subtensor/src/tests/weights.rs
index 10c829870..ee45252a3 100644
--- a/pallets/subtensor/src/tests/weights.rs
+++ b/pallets/subtensor/src/tests/weights.rs
@@ -82,7 +82,7 @@ fn test_set_rootweights_validate() {
         });
 
         // Create netuid
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         // Register the hotkey
         SubtensorModule::append_neuron(netuid, &hotkey, 0);
         crate::Owner::<Test>::insert(hotkey, coldkey);
@@ -197,7 +197,7 @@ fn test_commit_weights_validate() {
         });
 
         // Create netuid
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         // Register the hotkey
         SubtensorModule::append_neuron(netuid, &hotkey, 0);
         crate::Owner::<Test>::insert(hotkey, coldkey);
@@ -306,7 +306,7 @@ fn test_set_weights_validate() {
         });
 
         // Create netuid
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         // Register the hotkey
         SubtensorModule::append_neuron(netuid, &hotkey, 0);
         crate::Owner::<Test>::insert(hotkey, coldkey);
@@ -380,7 +380,7 @@ fn test_reveal_weights_validate() {
         });
 
         // Create netuid
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         // Register the hotkey
         SubtensorModule::append_neuron(netuid, &hotkey, 0);
         crate::Owner::<Test>::insert(hotkey, coldkey);
@@ -521,7 +521,7 @@ fn test_set_stake_threshold_failed() {
         let hotkey = U256::from(0);
         let coldkey = U256::from(0);
 
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, hotkey, coldkey, 2143124);
         SubtensorModule::set_stake_threshold(20_000_000_000_000);
         SubtensorModule::add_balance_to_coldkey_account(&hotkey, u64::MAX);
@@ -583,8 +583,8 @@ fn test_weights_version_key() {
         let netuid0: u16 = 1;
         let netuid1: u16 = 2;
 
-        add_network(netuid0, 0, 0);
-        add_network(netuid1, 0, 0);
+        add_network(netuid0, 1, 0);
+        add_network(netuid1, 1, 0);
         register_ok_neuron(netuid0, hotkey, coldkey, 2143124);
         register_ok_neuron(netuid1, hotkey, coldkey, 3124124);
 
@@ -1421,7 +1421,7 @@ fn test_check_len_uids_within_allowed_not_within_network_pool() {
 fn test_set_weights_commit_reveal_enabled_error() {
     new_test_ext(0).execute_with(|| {
         let netuid: u16 = 1;
-        add_network(netuid, 0, 0);
+        add_network(netuid, 1, 0);
         register_ok_neuron(netuid, U256::from(1), U256::from(2), 10);
 
         let uids = vec![0];
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index e0ea63987..f8491dd57 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
     //   `spec_version`, and `authoring_version` are the same between Wasm and native.
     // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
     //   the compatible custom types.
-    spec_version: 223,
+    spec_version: 224,
     impl_version: 1,
     apis: RUNTIME_API_VERSIONS,
     transaction_version: 1,

From 013fa47082bc95b013d4934a17672bcca94f9491 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Fri, 24 Jan 2025 15:31:46 -0500
Subject: [PATCH 066/145] change pool liq init

---
 .../subtensor/src/migrations/migrate_rao.rs   | 19 ++++++++++++++-----
 pallets/subtensor/src/subnets/subnet.rs       | 18 +++++++++---------
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/pallets/subtensor/src/migrations/migrate_rao.rs b/pallets/subtensor/src/migrations/migrate_rao.rs
index d575c07f5..f3990cc1c 100644
--- a/pallets/subtensor/src/migrations/migrate_rao.rs
+++ b/pallets/subtensor/src/migrations/migrate_rao.rs
@@ -71,17 +71,26 @@ pub fn migrate_rao<T: Config>() -> Weight {
         }
         let owner: T::AccountId = SubnetOwner::<T>::get(netuid);
         let lock: u64 = SubnetLocked::<T>::get(netuid);
-        let initial_liquidity: u64 = 100_000_000_000; // 100 TAO.
-        let remaining_lock: u64 = lock.saturating_sub(initial_liquidity);
+
+        // Put initial TAO from lock into subnet TAO and produce numerically equal amount of Alpha
+        // The initial TAO is the locked amount, with a minimum of 1 TAO and a cap of 100 TAO.
+        let pool_initial_tao = 100_000_000_000.min(lock.max(1));
+
+        let remaining_lock = lock.saturating_sub(pool_initial_tao);
+        // Refund the owner for the remaining lock.
         Pallet::<T>::add_balance_to_coldkey_account(&owner, remaining_lock);
-        SubnetTAO::<T>::insert(netuid, initial_liquidity); // Set TAO to the lock.
-        SubnetAlphaIn::<T>::insert(netuid, initial_liquidity); // Set AlphaIn to the initial alpha distribution.
+        SubnetTAO::<T>::insert(netuid, pool_initial_tao); // Set TAO to the lock.
+
+        SubnetAlphaIn::<T>::insert(
+            netuid,
+            pool_initial_tao.saturating_mul(netuids.len() as u64),
+        ); // Set AlphaIn to the initial alpha distribution.
+
         SubnetAlphaOut::<T>::insert(netuid, 0); // Set zero subnet alpha out.
         SubnetMechanism::<T>::insert(netuid, 1); // Convert to dynamic immediately with initialization.
         Tempo::<T>::insert(netuid, DefaultTempo::<T>::get());
         // Set the token symbol for this subnet using Self instead of Pallet::<T>
         TokenSymbol::<T>::insert(netuid, Pallet::<T>::get_symbol_for_subnet(*netuid));
-        SubnetTAO::<T>::insert(netuid, initial_liquidity); // Set TAO to the lock.
         TotalStakeAtDynamic::<T>::insert(netuid, 0);
 
         if let Ok(owner_coldkey) = SubnetOwner::<T>::try_get(netuid) {
diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs
index 7b7de6aeb..b2568808e 100644
--- a/pallets/subtensor/src/subnets/subnet.rs
+++ b/pallets/subtensor/src/subnets/subnet.rs
@@ -233,18 +233,18 @@ impl<T: Config> Pallet<T> {
             Self::get_symbol_for_subnet(netuid_to_register),
         ); // Set subnet token symbol.
 
-        // Put 100 TAO from lock into subnet TAO and produce numerically equal amount of Alpha
-        let mut pool_initial_tao = 100_000_000_000;
-        if pool_initial_tao > actual_tao_lock_amount {
-            pool_initial_tao = actual_tao_lock_amount;
-        }
-        if pool_initial_tao < 1 {
-            pool_initial_tao = 1;
-        }
+        // Put initial TAO from lock into subnet TAO and produce numerically equal amount of Alpha
+        // The initial TAO is the locked amount, with a minimum of 1 TAO and a cap of 100 TAO.
+        let pool_initial_tao = 100_000_000_000.min(actual_tao_lock_amount.max(1));
+
         let actual_tao_lock_amount_less_pool_tao =
             actual_tao_lock_amount.saturating_sub(pool_initial_tao);
         SubnetTAO::<T>::insert(netuid_to_register, pool_initial_tao);
-        SubnetAlphaIn::<T>::insert(netuid_to_register, pool_initial_tao);
+        SubnetAlphaIn::<T>::insert(
+            netuid_to_register,
+            pool_initial_tao.saturating_mul(Self::get_all_subnet_netuids().len() as u64),
+        ); // Set AlphaIn to the initial alpha distribution.
+
         SubnetOwner::<T>::insert(netuid_to_register, coldkey.clone());
         SubnetOwnerHotkey::<T>::insert(netuid_to_register, hotkey.clone());
         TotalStakeAtDynamic::<T>::insert(netuid_to_register, TotalStake::<T>::get());

From 7ee3e8998d8a412bf7020da0a2fa74b2054290c5 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Fri, 24 Jan 2025 15:33:17 -0500
Subject: [PATCH 067/145] TAO -> RAO

---
 pallets/subtensor/src/migrations/migrate_rao.rs | 2 +-
 pallets/subtensor/src/subnets/subnet.rs         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/migrations/migrate_rao.rs b/pallets/subtensor/src/migrations/migrate_rao.rs
index f3990cc1c..2b325aadc 100644
--- a/pallets/subtensor/src/migrations/migrate_rao.rs
+++ b/pallets/subtensor/src/migrations/migrate_rao.rs
@@ -73,7 +73,7 @@ pub fn migrate_rao<T: Config>() -> Weight {
         let lock: u64 = SubnetLocked::<T>::get(netuid);
 
         // Put initial TAO from lock into subnet TAO and produce numerically equal amount of Alpha
-        // The initial TAO is the locked amount, with a minimum of 1 TAO and a cap of 100 TAO.
+        // The initial TAO is the locked amount, with a minimum of 1 RAO and a cap of 100 TAO.
         let pool_initial_tao = 100_000_000_000.min(lock.max(1));
 
         let remaining_lock = lock.saturating_sub(pool_initial_tao);
diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs
index b2568808e..942f6fe8b 100644
--- a/pallets/subtensor/src/subnets/subnet.rs
+++ b/pallets/subtensor/src/subnets/subnet.rs
@@ -234,7 +234,7 @@ impl<T: Config> Pallet<T> {
         ); // Set subnet token symbol.
 
         // Put initial TAO from lock into subnet TAO and produce numerically equal amount of Alpha
-        // The initial TAO is the locked amount, with a minimum of 1 TAO and a cap of 100 TAO.
+        // The initial TAO is the locked amount, with a minimum of 1 RAO and a cap of 100 TAO.
         let pool_initial_tao = 100_000_000_000.min(actual_tao_lock_amount.max(1));
 
         let actual_tao_lock_amount_less_pool_tao =

From 4dca324b89831d273d8da4167368a90a1b2b5822 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Fri, 24 Jan 2025 16:07:27 -0500
Subject: [PATCH 068/145] fix migration test for new expectation

---
 pallets/subtensor/src/tests/migration.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs
index 56cbe6cdc..793908336 100644
--- a/pallets/subtensor/src/tests/migration.rs
+++ b/pallets/subtensor/src/tests/migration.rs
@@ -598,9 +598,9 @@ fn test_migrate_rao() {
 
         // Verify root subnet (netuid 0) state after migration
         assert_eq!(SubnetTAO::<Test>::get(netuid_0), 4 * stake_amount); // Root has everything
-        assert_eq!(SubnetTAO::<Test>::get(netuid_1), 100_000_000_000); // Initial Rao amount.
+        assert_eq!(SubnetTAO::<Test>::get(netuid_1), lock_amount); // Initial Rao amount.
         assert_eq!(SubnetAlphaIn::<Test>::get(netuid_0), 1); // No Alpha in pool on root.
-        assert_eq!(SubnetAlphaIn::<Test>::get(netuid_1), 100_000_000_000); // Initial Rao amount.
+        assert_eq!(SubnetAlphaIn::<Test>::get(netuid_1), 2 * lock_amount); // Initial Rao amount == num_subnets * lock_amount
         assert_eq!(SubnetAlphaOut::<Test>::get(netuid_0), 4 * stake_amount); // All stake is outstanding.
         assert_eq!(SubnetAlphaOut::<Test>::get(netuid_1), 0); // No stake outstanding.
 

From 672a379fd57851415e53881c458a19929525df09 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Fri, 24 Jan 2025 17:44:31 -0500
Subject: [PATCH 069/145] add_stake_limit in progress

---
 pallets/subtensor/src/epoch/math.rs           |  50 ++++++-
 pallets/subtensor/src/macros/dispatches.rs    |  99 ++++++++++++++
 pallets/subtensor/src/staking/add_stake.rs    | 111 ++++++++++++++++
 pallets/subtensor/src/staking/remove_stake.rs |  21 +++
 pallets/subtensor/src/tests/staking.rs        | 125 ++++++++++++++++++
 5 files changed, 405 insertions(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/epoch/math.rs b/pallets/subtensor/src/epoch/math.rs
index 616a9b78b..7f7ff7d9c 100644
--- a/pallets/subtensor/src/epoch/math.rs
+++ b/pallets/subtensor/src/epoch/math.rs
@@ -8,7 +8,7 @@ use sp_std::cmp::Ordering;
 
 use sp_std::vec;
 use substrate_fixed::transcendental::{exp, ln};
-use substrate_fixed::types::{I32F32, I64F64};
+use substrate_fixed::types::{I32F32, I64F64, U96F32};
 
 // TODO: figure out what cfg gate this needs to not be a warning in rustc
 #[allow(unused)]
@@ -1411,3 +1411,51 @@ pub fn safe_ln(value: I32F32) -> I32F32 {
 pub fn safe_exp(value: I32F32) -> I32F32 {
     exp(value).unwrap_or(I32F32::from_num(0.0))
 }
+
+fn abs_diff(a: U96F32, b: U96F32) -> U96F32 {
+    if a < b {
+        b.saturating_sub(a)
+    } else {
+        a.saturating_sub(b)
+    }
+}
+
+/// Safe sqrt with good precision
+pub fn checked_sqrt(value: U96F32, epsilon: U96F32) -> Option<U96F32> {
+    let zero: U96F32 = U96F32::from_num(0);
+    let two: U96F32 = U96F32::from_num(2);
+
+    // print!("sqrt({:?}) = ...", value);
+
+    if value < zero {
+        return None;
+    }
+
+    let mut high: U96F32 = value;
+    let mut low: U96F32 = zero;
+    let mut middle: U96F32 = (high + low) / two;
+
+    let mut iteration = 0;
+    let max_iterations = 128;
+
+    // Iterative approximation using bisection
+    while abs_diff(value.checked_div(middle).unwrap_or(zero), middle) > epsilon {
+        // println!("abs diff = {:?}", abs_diff(value.checked_div(middle).unwrap_or(zero), middle));
+
+        if value.checked_div(middle).unwrap_or(zero) < middle {
+            high = middle;
+        } else {
+            low = middle;
+        }
+
+        middle = (high + low) / two;
+
+        iteration += 1;
+        if iteration > max_iterations {
+            break;
+        }
+    }
+
+    // println!("iterations = {:?}, result = {:?}", iteration, middle);
+    Some(middle)
+}
diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs
index d9eafffa7..2a1165b1f 100644
--- a/pallets/subtensor/src/macros/dispatches.rs
+++ b/pallets/subtensor/src/macros/dispatches.rs
@@ -1688,5 +1688,104 @@ mod dispatches {
                 alpha_amount,
             )
         }
+
+        /// --- Adds stake to a hotkey on a subnet with a price limit.
+        /// This extrinsic allows to specify the limit price for alpha token
+        /// at which or better (lower) the staking should execute.
+        ///
+        /// In case if slippage occurs and the price shall move beyond the limit
+        /// price, the staking order may execute only partially or not execute
+        /// at all.
+        ///
+        /// # Args:
+        ///  * 'origin': (<T as frame_system::Config>Origin):
+        /// 	- The signature of the caller's coldkey.
+        ///
+        ///  * 'hotkey' (T::AccountId):
+        /// 	- The associated hotkey account.
+        ///
+        ///  * 'amount_staked' (u64):
+        /// 	- 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.
+        ///
+        /// # Event:
+        ///  * StakeAdded;
+        /// 	- On the successfully adding stake to a global account.
+        ///
+        /// # Raises:
+        ///  * 'NotEnoughBalanceToStake':
+        /// 	- Not enough balance on the coldkey to add onto the global account.
+        ///
+        ///  * 'NonAssociatedColdKey':
+        /// 	- The calling coldkey is not associated with this hotkey.
+        ///
+        ///  * 'BalanceWithdrawalError':
+        ///  	- Errors stemming from transaction pallet.
+        ///
+        #[pallet::call_index(88)]
+        #[pallet::weight((Weight::from_parts(124_000_000, 0)
+		.saturating_add(T::DbWeight::get().reads(10))
+		.saturating_add(T::DbWeight::get().writes(7)), DispatchClass::Normal, Pays::No))]
+        pub fn add_stake_limit(
+            origin: OriginFor<T>,
+            hotkey: T::AccountId,
+            netuid: u16,
+            amount_staked: u64,
+            limit_price: u64,
+        ) -> DispatchResult {
+            Self::do_add_stake_limit(origin, hotkey, netuid, amount_staked, limit_price)
+        }
+
+        /// --- Removes stake from a hotkey on a subnet with a price limit.
+        /// This extrinsic allows to specify the limit price for alpha token
+        /// at which or better (higher) the staking should execute.
+        ///
+        /// In case if slippage occurs and the price shall move beyond the limit
+        /// price, the staking order may execute only partially or not execute
+        /// at all.
+        ///
+        /// # Args:
+        /// * 'origin': (<T as frame_system::Config>Origin):
+        /// 	- The signature of the caller's coldkey.
+        ///
+        /// * 'hotkey' (T::AccountId):
+        /// 	- The associated hotkey account.
+        ///
+        /// * 'amount_unstaked' (u64):
+        /// 	- 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.
+        ///
+        /// # Event:
+        /// * StakeRemoved;
+        /// 	- On the successfully removing stake from the hotkey account.
+        ///
+        /// # Raises:
+        /// * 'NotRegistered':
+        /// 	- Thrown if the account we are attempting to unstake from is non existent.
+        ///
+        /// * 'NonAssociatedColdKey':
+        /// 	- Thrown if the coldkey does not own the hotkey we are unstaking from.
+        ///
+        /// * 'NotEnoughStakeToWithdraw':
+        /// 	- Thrown if there is not enough stake on the hotkey to withdwraw this amount.
+        ///
+        #[pallet::call_index(89)]
+        #[pallet::weight((Weight::from_parts(111_000_000, 0)
+		.saturating_add(Weight::from_parts(0, 43991))
+		.saturating_add(T::DbWeight::get().reads(10))
+		.saturating_add(T::DbWeight::get().writes(7)), DispatchClass::Normal, Pays::No))]
+        pub fn remove_stake_limit(
+            origin: OriginFor<T>,
+            hotkey: T::AccountId,
+            netuid: u16,
+            amount_unstaked: u64,
+            limit_price: u64,
+        ) -> DispatchResult {
+            Self::do_remove_stake_limit(origin, hotkey, netuid, amount_unstaked, limit_price)
+        }
     }
 }
diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index 66b337b3d..ca2670f12 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -1,5 +1,7 @@
 use super::*;
+use crate::epoch::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.
@@ -80,4 +82,113 @@ impl<T: Config> Pallet<T> {
         // Ok and return.
         Ok(())
     }
+
+    /// ---- The implementation for the extrinsic add_stake_limit: Adds stake to a hotkey
+    /// account on a subnet with price limit.
+    ///
+    /// # Args:
+    /// * 'origin': (<T as frame_system::Config>RuntimeOrigin):
+    ///     -  The signature of the caller's coldkey.
+    ///
+    /// * 'hotkey' (T::AccountId):
+    ///     -  The associated hotkey account.
+    ///
+    /// * 'stake_to_be_added' (u64):
+    ///     -  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.
+    ///
+    /// # Event:
+    /// * StakeAdded;
+    ///     -  On the successfully adding stake to a global account.
+    ///
+    /// # Raises:
+    /// * 'NotEnoughBalanceToStake':
+    ///     -  Not enough balance on the coldkey to add onto the global account.
+    ///
+    /// * 'NonAssociatedColdKey':
+    ///     -  The calling coldkey is not associated with this hotkey.
+    ///
+    /// * 'BalanceWithdrawalError':
+    ///     -  Errors stemming from transaction pallet.
+    ///
+    /// * 'TxRateLimitExceeded':
+    ///     -  Thrown if key has hit transaction rate limit
+    ///
+    pub fn do_add_stake_limit(
+        origin: T::RuntimeOrigin,
+        hotkey: T::AccountId,
+        netuid: u16,
+        stake_to_be_added: u64,
+        limit_price: u64,
+    ) -> dispatch::DispatchResult {
+        // TODO: Do all checks
+
+        // Calcaulate the maximum amount that can be executed with price limit
+        let max_amount = Self::get_max_amount_add(netuid, limit_price);
+        let mut possible_stake = stake_to_be_added;
+        if possible_stake > max_amount {
+            possible_stake = max_amount;
+        }
+
+        // Perform staking
+        // TODO
+
+        // Ok and return.
+        Ok(())
+    }
+
+    // Returns the maximum amount of RAO that can be executed with price limit
+    pub fn get_max_amount_add(netuid: u16, limit_price: u64) -> u64 {
+        // Corner case: root and stao
+        // There's no slippage for root or stable subnets, so if limit price is 1e9 rao or
+        // higher, then max_amount equals u64::MAX, otherwise it is 0.
+        if (netuid == Self::get_root_netuid()) || (SubnetMechanism::<T>::get(netuid)) == 0 {
+            if limit_price >= 1_000_000_000 {
+                return u64::MAX;
+            } else {
+                return 0;
+            }
+        }
+
+        // Corner case: SubnetAlphaIn is zero. Staking can't happen, so max amount is zero.
+        let alpha_in = SubnetAlphaIn::<T>::get(netuid);
+        if alpha_in == 0 {
+            return 0;
+        }
+        let alpha_in_float: U96F32 = U96F32::from_num(alpha_in);
+
+        // 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::from_num(tao_reserve);
+
+        // Corner case: limit_price < current_price (price cannot decrease with staking)
+        let limit_price_float: U96F32 = U96F32::from_num(limit_price).checked_div(
+            U96F32::from_num(1_000_000_000)
+        ).unwrap_or(U96F32::from_num(0));
+        if limit_price_float < Self::get_alpha_price(netuid) {
+            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::from_num(0.0);
+        let sqrt: U96F32 = checked_sqrt(
+            limit_price_float
+                .saturating_mul(
+                    tao_reserve_float
+                )
+                .saturating_mul(
+                    alpha_in_float
+                ),
+            U96F32::from_num(0.1)
+        ).unwrap_or(zero);
+
+        U96F32::from_num(sqrt).saturating_sub(U96F32::from_num(tao_reserve_float)).to_num::<u64>()
+    }
 }
diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index 5b3ed3390..656939a6c 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -235,4 +235,25 @@ impl<T: Config> Pallet<T> {
         // 5. Done and ok.
         Ok(())
     }
+
+    pub fn do_remove_stake_limit(
+        origin: T::RuntimeOrigin,
+        hotkey: T::AccountId,
+        netuid: u16,
+        stake_to_be_added: u64,
+        limit_price: u64,
+    ) -> dispatch::DispatchResult {
+        // TODO: Do all checks
+
+        // Calcaulate the maximum amount that can be executed with price limit
+        let _max_amount = Self::get_max_amount_remove(netuid, limit_price);
+
+        // Ok and return.
+        Ok(())
+    }
+
+    // Returns the maximum amount of RAO that can be executed with price limit
+    pub fn get_max_amount_remove(_netuid: u16, _limit_price: u64) -> u64 {
+        0
+    }
 }
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index ef5ac5f4a..2c97a2c19 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -1,8 +1,10 @@
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::arithmetic_side_effects)]
 
+use coinbase::block_step;
 use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency};
 use frame_system::RawOrigin;
+use sp_runtime::print;
 
 use super::mock::*;
 use crate::*;
@@ -10,6 +12,7 @@ use approx::assert_abs_diff_eq;
 use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays};
 use frame_support::sp_runtime::DispatchError;
 use sp_core::{Get, H256, U256};
+use substrate_fixed::types::{U96F32, U32F32};
 
 /***********************************************************
     staking::add_stake() tests
@@ -2127,3 +2130,125 @@ fn test_stake_below_min_validate() {
         assert_ok!(result_min_stake);
     });
 }
+
+
+#[test]
+fn test_stake_overflow() {
+    new_test_ext(0).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let amount = 100_000_000_000_000;
+
+        let tao_reserve: U96F32 = U96F32::from_num(100_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+
+        println!("Price = {:?}", SubtensorModule::get_alpha_price(netuid));
+        println!("SubnetAlphaIn = {:?}", SubnetAlphaIn::<Test>::get(netuid));
+        println!("SubnetTAO = {:?}", SubnetTAO::<Test>::get(netuid));
+        
+        // Give it some $$$ in his coldkey balance
+        SubtensorModule::add_balance_to_coldkey_account(&subnet_owner_coldkey, amount);
+
+        // Transfer to hotkey account, and check if the result is ok
+        assert_ok!(SubtensorModule::add_stake(
+            RuntimeOrigin::signed(subnet_owner_coldkey),
+            subnet_owner_hotkey,
+            netuid,
+            amount
+        ));
+
+        println!("Price = {:?}", SubtensorModule::get_alpha_price(netuid));
+        println!("SubnetAlphaIn = {:?}", SubnetAlphaIn::<Test>::get(netuid));
+        println!("SubnetTAO = {:?}", SubnetTAO::<Test>::get(netuid));
+
+        // Let it live for a few epochs
+        Tempo::<Test>::insert(netuid, 10);
+        step_epochs(100, netuid);
+
+        println!("Price after = {:?}", SubtensorModule::get_alpha_price(netuid));
+
+    });
+}
+
+#[test]
+fn test_max_amount_add_root() {
+    new_test_ext(0).execute_with(|| {
+        // 0 price on root => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_add(0, 0), 0);
+
+        // 0.999999... price on root => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_add(0, 999_999_999), 0);
+
+        // 1.0 price on root => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_add(0, 1_000_000_000), u64::MAX);
+
+        // 1.000...001 price on root => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_add(0, 1_000_000_001), u64::MAX);
+
+        // 2.0 price on root => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_add(0, 2_000_000_000), u64::MAX);
+    });
+}
+
+#[test]
+fn test_max_amount_add_stable() {
+    new_test_ext(0).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+
+        // 0 price => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 0), 0);
+
+        // 0.999999... price => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 999_999_999), 0);
+
+        // 1.0 price => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_000_000_000), u64::MAX);
+
+        // 1.000...001 price => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_000_000_001), u64::MAX);
+
+        // 2.0 price => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 2_000_000_000), u64::MAX);
+    });
+}
+
+#[test]
+fn test_max_amount_add_dynamic() {
+    new_test_ext(0).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        // Forse-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // 0 price => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 0), 0);
+
+        // 1.499999... price => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_499_999_999), 0);
+
+        // 1.5 price => max is 0 because of non-zero slippage
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_500_000_000), 0);
+
+        // 4x price => max is 1x TAO
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 6_000_000_000), 150_000_000_000);
+
+        // 1.50000....1 price => max is 46 rao
+        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_500_000_001), 46);
+
+        // Max price doesn't panic and returns something meaningful
+        assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX) < 21_000_000_000_000_000);
+        assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX - 1) < 21_000_000_000_000_000);
+        assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX / 2) < 21_000_000_000_000_000);
+    });
+}

From e955fcc2b5c871942e3f8282d6ecc7fa667dbc44 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Fri, 24 Jan 2025 17:52:58 -0500
Subject: [PATCH 070/145] Implemented add_stake_limit

---
 pallets/subtensor/src/staking/add_stake.rs    | 49 +++++++-----
 pallets/subtensor/src/staking/remove_stake.rs |  6 +-
 pallets/subtensor/src/tests/staking.rs        | 74 ++++++++++++-------
 3 files changed, 84 insertions(+), 45 deletions(-)

diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index 04e98575d..2f0d4875f 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -105,17 +105,33 @@ impl<T: Config> Pallet<T> {
         stake_to_be_added: u64,
         limit_price: u64,
     ) -> dispatch::DispatchResult {
-        // TODO: Do all checks
+        // 1. We check that the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
+        let coldkey = ensure_signed(origin)?;
+        log::debug!(
+            "do_add_stake( origin:{:?} hotkey:{:?}, netuid:{:?}, stake_to_be_added:{:?} )",
+            coldkey,
+            hotkey,
+            netuid,
+            stake_to_be_added
+        );
 
-        // Calcaulate the maximum amount that can be executed with price limit
+        // 2. Validate user input
+        Self::validate_add_stake(&coldkey, &hotkey, netuid, stake_to_be_added)?;
+
+        // 3. Calcaulate the maximum amount that can be executed with price limit
         let max_amount = Self::get_max_amount_add(netuid, limit_price);
         let mut possible_stake = stake_to_be_added;
         if possible_stake > max_amount {
             possible_stake = max_amount;
         }
 
-        // Perform staking
-        // TODO
+        // 4. Ensure the remove operation from the coldkey is a success.
+        let tao_staked: u64 = Self::remove_balance_from_coldkey_account(&coldkey, possible_stake)?;
+
+        // 5. Swap the stake into alpha on the subnet and increase counters.
+        // Emit the staking event.
+        let fee = DefaultStakingFee::<T>::get();
+        Self::stake_into_subnet(&hotkey, &coldkey, netuid, tao_staked, fee);
 
         // Ok and return.
         Ok(())
@@ -149,9 +165,9 @@ impl<T: Config> Pallet<T> {
         let tao_reserve_float: U96F32 = U96F32::from_num(tao_reserve);
 
         // Corner case: limit_price < current_price (price cannot decrease with staking)
-        let limit_price_float: U96F32 = U96F32::from_num(limit_price).checked_div(
-            U96F32::from_num(1_000_000_000)
-        ).unwrap_or(U96F32::from_num(0));
+        let limit_price_float: U96F32 = U96F32::from_num(limit_price)
+            .checked_div(U96F32::from_num(1_000_000_000))
+            .unwrap_or(U96F32::from_num(0));
         if limit_price_float < Self::get_alpha_price(netuid) {
             return 0;
         }
@@ -162,15 +178,14 @@ impl<T: Config> Pallet<T> {
         let zero: U96F32 = U96F32::from_num(0.0);
         let sqrt: U96F32 = checked_sqrt(
             limit_price_float
-                .saturating_mul(
-                    tao_reserve_float
-                )
-                .saturating_mul(
-                    alpha_in_float
-                ),
-            U96F32::from_num(0.1)
-        ).unwrap_or(zero);
-
-        U96F32::from_num(sqrt).saturating_sub(U96F32::from_num(tao_reserve_float)).to_num::<u64>()
+                .saturating_mul(tao_reserve_float)
+                .saturating_mul(alpha_in_float),
+            U96F32::from_num(0.1),
+        )
+        .unwrap_or(zero);
+
+        U96F32::from_num(sqrt)
+            .saturating_sub(U96F32::from_num(tao_reserve_float))
+            .to_num::<u64>()
     }
 }
diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index de05d73aa..59ff7e5b3 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -222,10 +222,10 @@ impl<T: Config> Pallet<T> {
     }
 
     pub fn do_remove_stake_limit(
-        origin: T::RuntimeOrigin,
-        hotkey: T::AccountId,
+        _origin: T::RuntimeOrigin,
+        _hotkey: T::AccountId,
         netuid: u16,
-        stake_to_be_added: u64,
+        _stake_to_be_added: u64,
         limit_price: u64,
     ) -> dispatch::DispatchResult {
         // TODO: Do all checks
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 2d5439743..233eaae78 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -1,10 +1,8 @@
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::arithmetic_side_effects)]
 
-use coinbase::block_step;
 use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency};
 use frame_system::RawOrigin;
-use sp_runtime::print;
 
 use super::mock::*;
 use crate::*;
@@ -12,7 +10,7 @@ use approx::assert_abs_diff_eq;
 use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays};
 use frame_support::sp_runtime::DispatchError;
 use sp_core::{Get, H256, U256};
-use substrate_fixed::types::{U96F32, U32F32};
+use substrate_fixed::types::U96F32;
 
 /***********************************************************
     staking::add_stake() tests
@@ -2136,7 +2134,6 @@ fn test_stake_below_min_validate() {
     });
 }
 
-
 #[test]
 fn test_stake_overflow() {
     new_test_ext(0).execute_with(|| {
@@ -2150,10 +2147,10 @@ fn test_stake_overflow() {
         SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
         SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
 
-        println!("Price = {:?}", SubtensorModule::get_alpha_price(netuid));
-        println!("SubnetAlphaIn = {:?}", SubnetAlphaIn::<Test>::get(netuid));
-        println!("SubnetTAO = {:?}", SubnetTAO::<Test>::get(netuid));
-        
+        // println!("Price = {:?}", SubtensorModule::get_alpha_price(netuid));
+        // println!("SubnetAlphaIn = {:?}", SubnetAlphaIn::<Test>::get(netuid));
+        // println!("SubnetTAO = {:?}", SubnetTAO::<Test>::get(netuid));
+
         // Give it some $$$ in his coldkey balance
         SubtensorModule::add_balance_to_coldkey_account(&subnet_owner_coldkey, amount);
 
@@ -2165,16 +2162,13 @@ fn test_stake_overflow() {
             amount
         ));
 
-        println!("Price = {:?}", SubtensorModule::get_alpha_price(netuid));
-        println!("SubnetAlphaIn = {:?}", SubnetAlphaIn::<Test>::get(netuid));
-        println!("SubnetTAO = {:?}", SubnetTAO::<Test>::get(netuid));
+        // println!("Price = {:?}", SubtensorModule::get_alpha_price(netuid));
+        // println!("SubnetAlphaIn = {:?}", SubnetAlphaIn::<Test>::get(netuid));
+        // println!("SubnetTAO = {:?}", SubnetTAO::<Test>::get(netuid));
 
-        // Let it live for a few epochs
+        // Let it live for a few epochs to make sure there are no panics
         Tempo::<Test>::insert(netuid, 10);
         step_epochs(100, netuid);
-
-        println!("Price after = {:?}", SubtensorModule::get_alpha_price(netuid));
-
     });
 }
 
@@ -2188,13 +2182,22 @@ fn test_max_amount_add_root() {
         assert_eq!(SubtensorModule::get_max_amount_add(0, 999_999_999), 0);
 
         // 1.0 price on root => max is u64::MAX
-        assert_eq!(SubtensorModule::get_max_amount_add(0, 1_000_000_000), u64::MAX);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(0, 1_000_000_000),
+            u64::MAX
+        );
 
         // 1.000...001 price on root => max is u64::MAX
-        assert_eq!(SubtensorModule::get_max_amount_add(0, 1_000_000_001), u64::MAX);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(0, 1_000_000_001),
+            u64::MAX
+        );
 
         // 2.0 price on root => max is u64::MAX
-        assert_eq!(SubtensorModule::get_max_amount_add(0, 2_000_000_000), u64::MAX);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(0, 2_000_000_000),
+            u64::MAX
+        );
     });
 }
 
@@ -2211,13 +2214,22 @@ fn test_max_amount_add_stable() {
         assert_eq!(SubtensorModule::get_max_amount_add(netuid, 999_999_999), 0);
 
         // 1.0 price => max is u64::MAX
-        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_000_000_000), u64::MAX);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(netuid, 1_000_000_000),
+            u64::MAX
+        );
 
         // 1.000...001 price => max is u64::MAX
-        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_000_000_001), u64::MAX);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(netuid, 1_000_000_001),
+            u64::MAX
+        );
 
         // 2.0 price => max is u64::MAX
-        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 2_000_000_000), u64::MAX);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(netuid, 2_000_000_000),
+            u64::MAX
+        );
     });
 }
 
@@ -2240,16 +2252,28 @@ fn test_max_amount_add_dynamic() {
         assert_eq!(SubtensorModule::get_max_amount_add(netuid, 0), 0);
 
         // 1.499999... price => max is 0
-        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_499_999_999), 0);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(netuid, 1_499_999_999),
+            0
+        );
 
         // 1.5 price => max is 0 because of non-zero slippage
-        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_500_000_000), 0);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(netuid, 1_500_000_000),
+            0
+        );
 
         // 4x price => max is 1x TAO
-        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 6_000_000_000), 150_000_000_000);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(netuid, 6_000_000_000),
+            150_000_000_000
+        );
 
         // 1.50000....1 price => max is 46 rao
-        assert_eq!(SubtensorModule::get_max_amount_add(netuid, 1_500_000_001), 46);
+        assert_eq!(
+            SubtensorModule::get_max_amount_add(netuid, 1_500_000_001),
+            46
+        );
 
         // Max price doesn't panic and returns something meaningful
         assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX) < 21_000_000_000_000_000);

From 877007945de1245f63d881e0bef059c5b5b65f95 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Fri, 24 Jan 2025 19:42:24 -0500
Subject: [PATCH 071/145] adjust move stake tests to convert stake to alpha

---
 pallets/subtensor/src/tests/move_stake.rs | 48 +++++++++++++++++------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index aa057ed4a..5dcab3d95 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -3,6 +3,7 @@ use crate::*;
 use approx::assert_abs_diff_eq;
 use frame_support::{assert_err, assert_noop, assert_ok};
 use sp_core::{Get, U256};
+use substrate_fixed::types::I96F32;
 
 // 1. test_do_move_success
 // Description: Test a successful move of stake between two hotkeys in the same subnet
@@ -111,14 +112,19 @@ fn test_do_move_different_subnets() {
             ),
             0
         );
+        let alpha_fee: I96F32 =
+            I96F32::from_num(fee) / SubtensorModule::get_alpha_price(destination_netuid);
+        let expected_value = I96F32::from_num(alpha)
+            * SubtensorModule::get_alpha_price(origin_netuid)
+            / SubtensorModule::get_alpha_price(destination_netuid);
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &destination_hotkey,
                 &coldkey,
                 destination_netuid
             ),
-            stake_amount - 2 * fee,
-            epsilon = stake_amount / 1000
+            (expected_value - alpha_fee).to_num::<u64>(),
+            epsilon = (expected_value / 1000).to_num::<u64>()
         );
     });
 }
@@ -700,13 +706,17 @@ fn test_do_move_storage_updates() {
             ),
             0
         );
+        let alpha_fee =
+            I96F32::from_num(fee) / SubtensorModule::get_alpha_price(destination_netuid);
+        let alpha2 = I96F32::from_num(alpha) * SubtensorModule::get_alpha_price(origin_netuid)
+            / SubtensorModule::get_alpha_price(destination_netuid);
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &destination_hotkey,
                 &coldkey,
                 destination_netuid
             ),
-            alpha - fee,
+            (alpha2 - alpha_fee).to_num::<u64>(),
             epsilon = alpha / 1000
         );
     });
@@ -1063,10 +1073,12 @@ fn test_do_transfer_different_subnets() {
             &destination_coldkey,
             destination_netuid,
         );
+        let expected_value = I96F32::from_num(stake_amount - fee)
+            / SubtensorModule::get_alpha_price(destination_netuid);
         assert_abs_diff_eq!(
             dest_stake,
-            stake_amount - fee,
-            epsilon = stake_amount / 1000
+            expected_value.to_num::<u64>(),
+            epsilon = (expected_value / 1000).to_num::<u64>()
         );
     });
 }
@@ -1114,10 +1126,15 @@ fn test_do_swap_success() {
             &coldkey,
             destination_netuid,
         );
+        let alpha_fee =
+            I96F32::from_num(fee) / SubtensorModule::get_alpha_price(destination_netuid);
+        let expected_value = I96F32::from_num(alpha_before)
+            * SubtensorModule::get_alpha_price(origin_netuid)
+            / SubtensorModule::get_alpha_price(destination_netuid);
         assert_abs_diff_eq!(
             alpha_after,
-            stake_amount - fee,
-            epsilon = stake_amount / 1000
+            (expected_value - alpha_fee).to_num::<u64>(),
+            epsilon = (expected_value / 1000).to_num::<u64>()
         );
     });
 }
@@ -1309,7 +1326,6 @@ fn test_do_swap_partial_stake() {
         SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
         SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, total_stake, 0);
 
-        let fee_as_alpha2 = SubtensorModule::swap_tao_for_alpha(destination_netuid, fee);
         let swap_amount = total_stake / 2;
         assert_ok!(SubtensorModule::do_swap_stake(
             RuntimeOrigin::signed(coldkey),
@@ -1328,14 +1344,20 @@ fn test_do_swap_partial_stake() {
             total_stake - swap_amount,
             epsilon = total_stake / 1000
         );
+
+        let alpha_fee =
+            I96F32::from_num(fee) / SubtensorModule::get_alpha_price(destination_netuid);
+        let expected_value = I96F32::from_num(swap_amount)
+            * SubtensorModule::get_alpha_price(origin_netuid)
+            / SubtensorModule::get_alpha_price(destination_netuid);
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &hotkey,
                 &coldkey,
                 destination_netuid
             ),
-            swap_amount - fee_as_alpha2,
-            epsilon = total_stake / 1000
+            (expected_value - alpha_fee).to_num::<u64>(),
+            epsilon = (expected_value / 1000).to_num::<u64>()
         );
     });
 }
@@ -1378,15 +1400,15 @@ fn test_do_swap_storage_updates() {
             0
         );
 
-        let fee_as_alpha = SubtensorModule::swap_tao_for_alpha(destination_netuid, fee);
-
+        let alpha_fee =
+            SubtensorModule::get_alpha_price(destination_netuid) * I96F32::from_num(fee);
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &hotkey,
                 &coldkey,
                 destination_netuid
             ),
-            alpha - fee_as_alpha,
+            alpha - alpha_fee.to_num::<u64>(),
             epsilon = 5
         );
     });

From cc44b645c9bea233a47bcc009aaf463e20fa2b6f Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Fri, 24 Jan 2025 23:41:54 -0500
Subject: [PATCH 072/145] remove epoch run

---
 pallets/subtensor/src/tests/children.rs | 43 +++++++------------------
 1 file changed, 11 insertions(+), 32 deletions(-)

diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs
index 769e47ddc..d6e0b510a 100644
--- a/pallets/subtensor/src/tests/children.rs
+++ b/pallets/subtensor/src/tests/children.rs
@@ -3426,38 +3426,6 @@ fn test_parent_child_chain_emission() {
 
         let hardcoded_emission: I96F32 = I96F32::from_num(1_000_000); // 1 million (adjust as needed)
 
-        let hotkey_emission: Vec<(U256, u64, u64)> =
-            SubtensorModule::epoch(netuid, hardcoded_emission.saturating_to_num::<u64>());
-        log::info!("hotkey_emission: {:?}", hotkey_emission);
-        let total_emission: I96F32 = hotkey_emission
-            .iter()
-            .map(|(_, _, emission)| I96F32::from_num(*emission))
-            .sum();
-
-        // Verify emissions match expected from CHK arrangements
-        let em_eps: I96F32 = I96F32::from_num(1e-4); // 4 decimal places
-                                                     // A's pending emission:
-        assert!(
-            ((I96F32::from_num(hotkey_emission[0].2) / total_emission) -
-            I96F32::from_num(2_f64 / 3_f64 * 1_f64 / 2_f64)).abs() // 2/3 * 1/2 = 1/3; 50% -> B
-			<= em_eps,
-            "A should have pending emission of 1/3 of total emission"
-        );
-        // B's pending emission:
-        assert!(
-            ((I96F32::from_num(hotkey_emission[1].2) / total_emission) -
-            (I96F32::from_num(2_f64 / 9_f64 * 1_f64 / 2_f64 + 2_f64 / 3_f64 * 1_f64 / 2_f64))).abs() // 2/9 * 1/2 + 2/3 * 1/2; 50% -> C + 50% from A
-            <= em_eps,
-            "B should have pending emission of 4/9 of total emission"
-        );
-        // C's pending emission:
-        assert!(
-            ((I96F32::from_num(hotkey_emission[2].2) / total_emission) -
-            (I96F32::from_num(1_f64 / 9_f64 + 1_f64 / 2_f64 * 2_f64 / 9_f64))).abs() // 1/9 + 2/9 * 1/2; 50% from B
-            <= em_eps,
-            "C should have pending emission of 1/9 of total emission"
-        );
-
         // Set pending emission to 0
         PendingEmission::<Test>::insert(netuid, 0);
 
@@ -3521,6 +3489,17 @@ fn test_parent_child_chain_emission() {
             rel_stake_inc_c
         );
 
+		let hotkeys = [hotkey_a, hotkey_b, hotkey_c];
+		let mut total_stake_now = 0;
+		for (hotkey, netuid,stake) in TotalHotkeyAlpha::<Test>::iter() {
+			if hotkeys.contains(&hotkey) {
+				total_stake_now += stake;
+			} else {
+				log::info!("hotkey: {:?}, netuid: {:?}, stake: {:?}", hotkey, netuid, stake);
+			}
+		}
+		log::info!("total_stake_now: {:?}, total_stake_new: {:?}", total_stake_now, total_stake_new);
+
         let eps: I96F32 = I96F32::from_num(10_000);
         assert!(
             (total_stake_new - (total_stake_old + hardcoded_emission)).abs() <= eps,

From f5df32af4ddcd1242a49af5170830cddb940d385 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Fri, 24 Jan 2025 23:45:42 -0500
Subject: [PATCH 073/145] fix price math in test

---
 pallets/subtensor/src/tests/move_stake.rs | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 5dcab3d95..f299832ed 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -1401,15 +1401,18 @@ fn test_do_swap_storage_updates() {
         );
 
         let alpha_fee =
-            SubtensorModule::get_alpha_price(destination_netuid) * I96F32::from_num(fee);
+            I96F32::from_num(fee) / SubtensorModule::get_alpha_price(destination_netuid);
+        let expected_value = I96F32::from_num(alpha)
+            * SubtensorModule::get_alpha_price(origin_netuid)
+            / SubtensorModule::get_alpha_price(destination_netuid);
         assert_abs_diff_eq!(
             SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
                 &hotkey,
                 &coldkey,
                 destination_netuid
             ),
-            alpha - alpha_fee.to_num::<u64>(),
-            epsilon = 5
+            (expected_value - alpha_fee).to_num::<u64>(),
+            epsilon = (expected_value / 1000).to_num::<u64>()
         );
     });
 }

From a4046a095c11bdea65c43a1ee4eee64e28705627 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sat, 25 Jan 2025 00:46:20 -0500
Subject: [PATCH 074/145] use rem divs

---
 pallets/subtensor/src/coinbase/run_coinbase.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index d340271bb..2e9fe44b4 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -457,12 +457,12 @@ impl<T: Config> Pallet<T> {
                 // 2.5.2 --- Store the alpha dividends
                 alpha_divs
                     .entry(hotkey_j.clone())
-                    .and_modify(|e| *e = e.saturating_add(alpha_divs_j.to_num::<u64>()))
-                    .or_insert(alpha_divs_j.to_num::<u64>());
+                    .and_modify(|e| *e = e.saturating_add(rem_alpha_divs_j.to_num::<u64>()))
+                    .or_insert(rem_alpha_divs_j.to_num::<u64>());
                 log::debug!(
                     "Stored alpha dividends for hotkey {:?}: {:?}",
                     hotkey_j,
-                    alpha_divs_j.to_num::<u64>()
+                    rem_alpha_divs_j.to_num::<u64>()
                 );
             }
         }

From 7f67188f6b85301731988363d20d10485a0bd26f Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:15:25 -0500
Subject: [PATCH 075/145] test total issuance after coinbase

---
 pallets/subtensor/src/tests/coinbase.rs | 92 +++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs
index 257ea075f..82a68ed23 100644
--- a/pallets/subtensor/src/tests/coinbase.rs
+++ b/pallets/subtensor/src/tests/coinbase.rs
@@ -2,6 +2,7 @@
 use super::mock::*;
 
 use crate::*;
+use approx::assert_abs_diff_eq;
 use frame_support::assert_ok;
 use sp_core::U256;
 use substrate_fixed::types::I64F64;
@@ -72,3 +73,94 @@ fn test_dynamic_function_price_equal_emission() {
         close(alpha_out, 2 * alpha_block_emission - expected_alpha_in, 10);
     });
 }
+
+// Verifies that the total issuance after the coinbase is only increased by the coinbase emission.
+// Includes TAO weight.
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_total_issuance_after_coinbase --exact --show-output --nocapture
+#[test]
+fn test_total_issuance_after_coinbase() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+        // Set TAO weight to 18%
+        SubtensorModule::set_tao_weight(I96F32::from_num(0.18).saturating_to_num::<u64>());
+        // Set owner cut to ~11.11%
+        SubtensorModule::set_subnet_owner_cut(u16::MAX / 9);
+        let total_coinbase_emission: I96F32 = I96F32::from_num(1_123_456_789);
+        let epsilon: u64 = 100;
+
+        // Define hotkeys and coldkeys
+        let hotkey_a: U256 = U256::from(1);
+        let hotkey_b: U256 = U256::from(2);
+        let hotkey_c: U256 = U256::from(3);
+        let coldkey_a: U256 = U256::from(100);
+        let coldkey_b: U256 = U256::from(101);
+        let coldkey_c: U256 = U256::from(102);
+
+        // Register neurons with decreasing stakes
+        register_ok_neuron(netuid, hotkey_a, coldkey_a, 0);
+        register_ok_neuron(netuid, hotkey_b, coldkey_b, 0);
+        register_ok_neuron(netuid, hotkey_c, coldkey_c, 0);
+
+        // Add initial stakes
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000);
+
+        // Swap to alpha
+        let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
+        let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
+            netuid,
+            total_tao.saturating_to_num::<u64>(),
+        ));
+
+        // Set the stakes directly
+        // This avoids needing to swap tao to alpha, impacting the initial stake distribution.
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_b,
+            &coldkey_b,
+            netuid,
+            (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_c,
+            &coldkey_c,
+            netuid,
+            (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::<u64>(),
+        );
+
+        // Stake some to root
+        let stake_to_root: u64 = 10_000_000;
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, stake_to_root);
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            stake_to_root,
+        );
+
+        let alpha_price = SubtensorModule::get_alpha_price(netuid);
+        log::info!("alpha_price: {:?}", alpha_price);
+
+        // Get the total issuance
+        let mut total_issuance_before = TotalIssuance::<Test>::get();
+        log::info!("total_issuance_before: {:?}", total_issuance_before);
+
+        // Run the coinbase
+        SubtensorModule::run_coinbase(total_coinbase_emission);
+
+        // Compare
+        let total_issuance_after = TotalIssuance::<Test>::get();
+        assert_abs_diff_eq!(
+            total_issuance_after,
+            total_issuance_before + total_coinbase_emission.saturating_to_num::<u64>(),
+            epsilon = epsilon
+        );
+    });
+}

From 045b317a14a12582df2c42f7a3d23d2c4cf74e7f Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:16:09 -0500
Subject: [PATCH 076/145] test total stake inc after coinbase

---
 pallets/subtensor/src/tests/coinbase.rs | 225 ++++++++++++++++++++++++
 1 file changed, 225 insertions(+)

diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs
index 82a68ed23..f62f23e86 100644
--- a/pallets/subtensor/src/tests/coinbase.rs
+++ b/pallets/subtensor/src/tests/coinbase.rs
@@ -74,6 +74,231 @@ fn test_dynamic_function_price_equal_emission() {
     });
 }
 
+// Verifies that the total stake after the coinbase is only increased by the coinbase emission.
+// Avoids TAO weight.
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_total_stake_after_coinbase_no_tao_weight --exact --show-output --nocapture
+#[test]
+fn test_total_stake_after_coinbase_no_tao_weight() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+        // Set TAO weight to 0
+        SubtensorModule::set_tao_weight(0);
+        // Set owner cut to ~11.11%
+        SubtensorModule::set_subnet_owner_cut(u16::MAX / 9);
+        let total_coinbase_emission: I96F32 = I96F32::from_num(1_123_456_789);
+        let epsilon: u64 = 100;
+
+        // Define hotkeys and coldkeys
+        let hotkey_a: U256 = U256::from(1);
+        let hotkey_b: U256 = U256::from(2);
+        let hotkey_c: U256 = U256::from(3);
+        let coldkey_a: U256 = U256::from(100);
+        let coldkey_b: U256 = U256::from(101);
+        let coldkey_c: U256 = U256::from(102);
+
+        // Register neurons with decreasing stakes
+        register_ok_neuron(netuid, hotkey_a, coldkey_a, 0);
+        register_ok_neuron(netuid, hotkey_b, coldkey_b, 0);
+        register_ok_neuron(netuid, hotkey_c, coldkey_c, 0);
+
+        // Add initial stakes
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000);
+
+        // Swap to alpha
+        let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
+        let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
+            netuid,
+            total_tao.saturating_to_num::<u64>(),
+        ));
+
+        // Set the stakes directly
+        // This avoids needing to swap tao to alpha, impacting the initial stake distribution.
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_b,
+            &coldkey_b,
+            netuid,
+            (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_c,
+            &coldkey_c,
+            netuid,
+            (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::<u64>(),
+        );
+
+        // Get the total stake on the network
+        let mut total_stake_before = 0;
+        for (hotkey, netuid_i, alpha) in TotalHotkeyAlpha::<Test>::iter() {
+            if netuid_i == netuid {
+                total_stake_before += alpha;
+            } else {
+                assert!(
+                    alpha == 0,
+                    "Alpha should be 0 for non-subnet hotkeys, but is {:?} on netuid {:?}",
+                    alpha,
+                    netuid_i
+                );
+            }
+        }
+
+        log::info!("total_stake_before: {:?}", total_stake_before);
+
+        // Run the coinbase
+        SubtensorModule::run_coinbase(total_coinbase_emission);
+
+        // Get the total stake on the network
+        let mut total_stake_after = 0;
+        for (hotkey, netuid_i, alpha) in TotalHotkeyAlpha::<Test>::iter() {
+            if netuid_i == netuid {
+                total_stake_after += alpha;
+            } else {
+                assert!(
+                    alpha == 0,
+                    "Alpha should be 0 for non-subnet hotkeys, but is {:?} on netuid {:?}",
+                    alpha,
+                    netuid_i
+                );
+            }
+        }
+        assert_abs_diff_eq!(
+            total_stake_after,
+            total_stake_before + total_coinbase_emission.saturating_to_num::<u64>(),
+            epsilon = epsilon
+        );
+    });
+}
+
+// Verifies that the total stake after the coinbase is only increased by the coinbase emission.
+// Includes TAO weight.
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_total_stake_after_coinbase --exact --show-output --nocapture
+#[test]
+fn test_total_stake_after_coinbase() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+        // Set TAO weight to 18%
+        SubtensorModule::set_tao_weight(I96F32::from_num(0.18).saturating_to_num::<u64>());
+        // Set owner cut to ~11.11%
+        SubtensorModule::set_subnet_owner_cut(u16::MAX / 9);
+        let total_coinbase_emission: I96F32 = I96F32::from_num(1_123_456_789);
+        let epsilon: u64 = 100;
+
+        // Define hotkeys and coldkeys
+        let hotkey_a: U256 = U256::from(1);
+        let hotkey_b: U256 = U256::from(2);
+        let hotkey_c: U256 = U256::from(3);
+        let coldkey_a: U256 = U256::from(100);
+        let coldkey_b: U256 = U256::from(101);
+        let coldkey_c: U256 = U256::from(102);
+
+        // Register neurons with decreasing stakes
+        register_ok_neuron(netuid, hotkey_a, coldkey_a, 0);
+        register_ok_neuron(netuid, hotkey_b, coldkey_b, 0);
+        register_ok_neuron(netuid, hotkey_c, coldkey_c, 0);
+
+        // Add initial stakes
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000);
+
+        // Swap to alpha
+        let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
+        let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
+            netuid,
+            total_tao.saturating_to_num::<u64>(),
+        ));
+
+        // Set the stakes directly
+        // This avoids needing to swap tao to alpha, impacting the initial stake distribution.
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_b,
+            &coldkey_b,
+            netuid,
+            (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_c,
+            &coldkey_c,
+            netuid,
+            (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::<u64>(),
+        );
+
+        // Stake some to root
+        let stake_to_root: u64 = 10_000_000;
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, stake_to_root);
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            stake_to_root,
+        );
+
+        let alpha_price = SubtensorModule::get_alpha_price(netuid);
+        log::info!("alpha_price: {:?}", alpha_price);
+
+        // Get the total stake on the network
+        let mut total_stake_before = 0;
+        for (hotkey, netuid_i, alpha) in TotalHotkeyAlpha::<Test>::iter() {
+            if netuid_i == netuid {
+                total_stake_before += alpha;
+            } else if netuid == SubtensorModule::get_root_netuid() {
+                let as_alpha: I96F32 = I96F32::from_num(alpha) / alpha_price;
+                total_stake_before += as_alpha.saturating_to_num::<u64>();
+            } else {
+                assert!(
+                    alpha == 0,
+                    "Alpha should be 0 for non-subnet hotkeys, but is {:?} on netuid {:?}",
+                    alpha,
+                    netuid_i
+                );
+            }
+        }
+
+        log::info!("total_stake_before: {:?}", total_stake_before);
+
+        // Run the coinbase
+        SubtensorModule::run_coinbase(total_coinbase_emission);
+
+        // Get the total stake on the network
+        let mut total_stake_after = 0;
+        for (hotkey, netuid_i, alpha) in TotalHotkeyAlpha::<Test>::iter() {
+            if netuid_i == netuid {
+                total_stake_after += alpha;
+            } else if netuid == SubtensorModule::get_root_netuid() {
+                let as_alpha: I96F32 = I96F32::from_num(alpha) / alpha_price;
+                total_stake_after += as_alpha.saturating_to_num::<u64>();
+            } else {
+                assert!(
+                    alpha == 0,
+                    "Alpha should be 0 for non-subnet hotkeys, but is {:?} on netuid {:?}",
+                    alpha,
+                    netuid_i
+                );
+            }
+        }
+        assert_abs_diff_eq!(
+            total_stake_after,
+            total_stake_before + total_coinbase_emission.saturating_to_num::<u64>(),
+            epsilon = epsilon
+        );
+    });
+}
+
 // Verifies that the total issuance after the coinbase is only increased by the coinbase emission.
 // Includes TAO weight.
 // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_total_issuance_after_coinbase --exact --show-output --nocapture

From 2cb732c7345fde50ce7039a7271285135010a4e1 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:18:28 -0500
Subject: [PATCH 077/145] use alpha emission for test

---
 pallets/subtensor/src/tests/children.rs | 35 ++++++++++++++++---------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs
index d6e0b510a..a179fc5aa 100644
--- a/pallets/subtensor/src/tests/children.rs
+++ b/pallets/subtensor/src/tests/children.rs
@@ -3425,6 +3425,8 @@ fn test_parent_child_chain_emission() {
         SubtensorModule::set_tao_weight(0);
 
         let hardcoded_emission: I96F32 = I96F32::from_num(1_000_000); // 1 million (adjust as needed)
+        let emission_as_alpha =
+            I96F32::from_num(hardcoded_emission) / SubtensorModule::get_alpha_price(netuid);
 
         // Set pending emission to 0
         PendingEmission::<Test>::insert(netuid, 0);
@@ -3489,22 +3491,31 @@ fn test_parent_child_chain_emission() {
             rel_stake_inc_c
         );
 
-		let hotkeys = [hotkey_a, hotkey_b, hotkey_c];
-		let mut total_stake_now = 0;
-		for (hotkey, netuid,stake) in TotalHotkeyAlpha::<Test>::iter() {
-			if hotkeys.contains(&hotkey) {
-				total_stake_now += stake;
-			} else {
-				log::info!("hotkey: {:?}, netuid: {:?}, stake: {:?}", hotkey, netuid, stake);
-			}
-		}
-		log::info!("total_stake_now: {:?}, total_stake_new: {:?}", total_stake_now, total_stake_new);
+        let hotkeys = [hotkey_a, hotkey_b, hotkey_c];
+        let mut total_stake_now = 0;
+        for (hotkey, netuid, stake) in TotalHotkeyAlpha::<Test>::iter() {
+            if hotkeys.contains(&hotkey) {
+                total_stake_now += stake;
+            } else {
+                log::info!(
+                    "hotkey: {:?}, netuid: {:?}, stake: {:?}",
+                    hotkey,
+                    netuid,
+                    stake
+                );
+            }
+        }
+        log::info!(
+            "total_stake_now: {:?}, total_stake_new: {:?}",
+            total_stake_now,
+            total_stake_new
+        );
 
         let eps: I96F32 = I96F32::from_num(10_000);
         assert!(
-            (total_stake_new - (total_stake_old + hardcoded_emission)).abs() <= eps,
+            (total_stake_new - (total_stake_old + emission_as_alpha)).abs() <= eps,
             "Total stake should have increased by the hardcoded emission amount {:?}",
-            total_stake_new - (total_stake_old + hardcoded_emission)
+            total_stake_new - (total_stake_old + emission_as_alpha)
         );
     });
 }

From d65b2164258d46e9e016eff6fde1dcd8cffb888a Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:25:13 -0500
Subject: [PATCH 078/145] dont register owner twice

---
 pallets/subtensor/src/migrations/migrate_rao.rs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/migrations/migrate_rao.rs b/pallets/subtensor/src/migrations/migrate_rao.rs
index 2b325aadc..13ff02c11 100644
--- a/pallets/subtensor/src/migrations/migrate_rao.rs
+++ b/pallets/subtensor/src/migrations/migrate_rao.rs
@@ -98,8 +98,12 @@ pub fn migrate_rao<T: Config>() -> Weight {
             SubnetOwnerHotkey::<T>::insert(netuid, owner_coldkey.clone());
             // Associate the coldkey to coldkey.
             Pallet::<T>::create_account_if_non_existent(&owner_coldkey, &owner_coldkey);
-            // Register the owner_coldkey as neuron to the network.
-            let _neuron_uid: u16 = Pallet::<T>::register_neuron(*netuid, &owner_coldkey);
+
+            // Only register the owner coldkey if it's not already a hotkey on the subnet.
+            if !Uids::<T>::contains_key(*netuid, &owner_coldkey) {
+                // Register the owner_coldkey as neuron to the network.
+                let _neuron_uid: u16 = Pallet::<T>::register_neuron(*netuid, &owner_coldkey);
+            }
             // Register the neuron immediately.
             if !Identities::<T>::contains_key(owner_coldkey.clone()) {
                 // Set the identitiy for the Owner coldkey if non existent.

From 6cc836be8f391e5851b4c181df740e56e97b84de Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:28:14 -0500
Subject: [PATCH 079/145] change alpha out em to match alpha block em

---
 pallets/subtensor/src/coinbase/block_emission.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/block_emission.rs b/pallets/subtensor/src/coinbase/block_emission.rs
index ab570c19e..a19651f8c 100644
--- a/pallets/subtensor/src/coinbase/block_emission.rs
+++ b/pallets/subtensor/src/coinbase/block_emission.rs
@@ -65,9 +65,7 @@ impl<T: Config> Pallet<T> {
         }
 
         // Set Alpha in emission.
-        let alpha_out_emission = I96F32::from_num(2)
-            .saturating_mul(float_alpha_block_emission)
-            .saturating_sub(alpha_in_emission);
+        let alpha_out_emission = float_alpha_block_emission;
 
         // Log results.
         log::debug!("{:?} - tao_in_emission: {:?}", netuid, tao_in_emission);

From 4197a037605fe6af9a35b78a656c11107262ef6e Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:34:37 -0500
Subject: [PATCH 080/145] make sure to ensure burn reg before writing

---
 pallets/subtensor/src/subnets/registration.rs | 26 +++++++++----------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/pallets/subtensor/src/subnets/registration.rs b/pallets/subtensor/src/subnets/registration.rs
index 342c5c408..9913578e8 100644
--- a/pallets/subtensor/src/subnets/registration.rs
+++ b/pallets/subtensor/src/subnets/registration.rs
@@ -119,29 +119,29 @@ impl<T: Config> Pallet<T> {
             Error::<T>::NotEnoughBalanceToStake
         );
 
-        // --- 8. Ensure the remove operation from the coldkey is a success.
-        let actual_burn_amount =
-            Self::remove_balance_from_coldkey_account(&coldkey, registration_cost)?;
-
-        // Tokens are swapped and then burned.
-        let burned_alpha: u64 = Self::swap_tao_for_alpha(netuid, actual_burn_amount);
-        SubnetAlphaOut::<T>::mutate(netuid, |total| *total = total.saturating_sub(burned_alpha));
-
-        // --- 9. If the network account does not exist we will create it here.
-        Self::create_account_if_non_existent(&coldkey, &hotkey);
-
-        // --- 10. Ensure that the pairing is correct.
+        // --- 8. Ensure that the pairing is correct.
         ensure!(
             Self::coldkey_owns_hotkey(&coldkey, &hotkey),
             Error::<T>::NonAssociatedColdKey
         );
 
-        // Possibly there is no neuron slots at all.
+        // --- 9. Possibly there are no neuron slots at all.
         ensure!(
             Self::get_max_allowed_uids(netuid) != 0,
             Error::<T>::NoNeuronIdAvailable
         );
 
+        // --- 10. Ensure the remove operation from the coldkey is a success.
+        let actual_burn_amount =
+            Self::remove_balance_from_coldkey_account(&coldkey, registration_cost)?;
+
+        // Tokens are swapped and then burned.
+        let burned_alpha: u64 = Self::swap_tao_for_alpha(netuid, actual_burn_amount);
+        SubnetAlphaOut::<T>::mutate(netuid, |total| *total = total.saturating_sub(burned_alpha));
+
+        // --- 11. If the network account does not exist we will create it here.
+        Self::create_account_if_non_existent(&coldkey, &hotkey);
+
         // Actually perform the registration.
         let neuron_uid: u16 = Self::register_neuron(netuid, &hotkey);
 

From c46628d583dd4dd50f4b9bf8a11c382ce19401a6 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:44:52 -0500
Subject: [PATCH 081/145] fixes #1125; add pending CHK to hk swap

---
 pallets/subtensor/src/swap/swap_hotkey.rs | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs
index eb1babe82..725e3c36f 100644
--- a/pallets/subtensor/src/swap/swap_hotkey.rs
+++ b/pallets/subtensor/src/swap/swap_hotkey.rs
@@ -403,8 +403,15 @@ impl<T: Config> Pallet<T> {
             }
         }
 
-        // 14. Swap Stake Delta for all coldkeys.
-        // DEPRECATED
+        // 14. Swap PendingChildKeys.
+        // PendingChildKeys( netuid, parent ) --> Vec<(proportion,child), cool_down_block>
+        for netuid in Self::get_all_subnet_netuids() {
+            if PendingChildKeys::<T>::contains_key(netuid, old_hotkey) {
+                let (children, cool_down_block) = PendingChildKeys::<T>::get(netuid, old_hotkey);
+                PendingChildKeys::<T>::remove(netuid, old_hotkey);
+                PendingChildKeys::<T>::insert(netuid, new_hotkey, (children, cool_down_block));
+            }
+        }
 
         // Return successful after swapping all the relevant terms.
         Ok(())

From 45480ee1ca422141870b54e95db0bd602e9cf858 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 19:49:09 -0500
Subject: [PATCH 082/145] add tests for #1125

---
 pallets/subtensor/src/tests/swap_hotkey.rs | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs
index a67e6696c..528ad4576 100644
--- a/pallets/subtensor/src/tests/swap_hotkey.rs
+++ b/pallets/subtensor/src/tests/swap_hotkey.rs
@@ -1257,12 +1257,16 @@ fn test_swap_parent_hotkey_childkey_maps() {
         let parent_old = U256::from(1);
         let coldkey = U256::from(2);
         let child = U256::from(3);
+        let child_other = U256::from(4);
         let parent_new = U256::from(4);
         add_network(netuid, 1, 0);
         SubtensorModule::create_account_if_non_existent(&coldkey, &parent_old);
 
         // Set child and verify state maps
         mock_set_children(&coldkey, &parent_old, netuid, &[(u64::MAX, child)]);
+        // Schedule some pending child keys.
+        mock_schedule_children(&coldkey, &parent_old, netuid, &[(u64::MAX, child_other)]);
+
         assert_eq!(
             ParentKeys::<Test>::get(child, netuid),
             vec![(u64::MAX, parent_old)]
@@ -1271,6 +1275,8 @@ fn test_swap_parent_hotkey_childkey_maps() {
             ChildKeys::<Test>::get(parent_old, netuid),
             vec![(u64::MAX, child)]
         );
+        let existing_pending_child_keys = PendingChildKeys::<Test>::get(netuid, parent_old);
+        assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_other)]);
 
         // Swap
         let mut weight = Weight::zero();
@@ -1290,6 +1296,10 @@ fn test_swap_parent_hotkey_childkey_maps() {
             ChildKeys::<Test>::get(parent_new, netuid),
             vec![(u64::MAX, child)]
         );
+        assert_eq!(
+            PendingChildKeys::<Test>::get(netuid, parent_new),
+            existing_pending_child_keys // Entry under new hotkey.
+        );
     })
 }
 
@@ -1307,6 +1317,8 @@ fn test_swap_child_hotkey_childkey_maps() {
 
         // Set child and verify state maps
         mock_set_children(&coldkey, &parent, netuid, &[(u64::MAX, child_old)]);
+        // Schedule some pending child keys.
+        mock_schedule_children(&coldkey, &parent, netuid, &[(u64::MAX, child_old)]);
 
         assert_eq!(
             ParentKeys::<Test>::get(child_old, netuid),
@@ -1316,6 +1328,8 @@ fn test_swap_child_hotkey_childkey_maps() {
             ChildKeys::<Test>::get(parent, netuid),
             vec![(u64::MAX, child_old)]
         );
+        let existing_pending_child_keys = PendingChildKeys::<Test>::get(netuid, parent);
+        assert_eq!(existing_pending_child_keys.0, vec![(u64::MAX, child_old)]);
 
         // Swap
         let mut weight = Weight::zero();
@@ -1335,5 +1349,9 @@ fn test_swap_child_hotkey_childkey_maps() {
             ChildKeys::<Test>::get(parent, netuid),
             vec![(u64::MAX, child_new)]
         );
+        assert_eq!(
+            PendingChildKeys::<Test>::get(netuid, parent),
+            (vec![(u64::MAX, child_new)], existing_pending_child_keys.1) // Same cooldown block.
+        );
     })
 }

From 7e13ad50e482457ffaa07f1a8db5b5e95c7ee232 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Sun, 26 Jan 2025 20:02:06 -0500
Subject: [PATCH 083/145] also swap if in another hotkey's pending CHK

---
 pallets/subtensor/src/swap/swap_hotkey.rs | 24 +++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs
index 725e3c36f..f8bd979df 100644
--- a/pallets/subtensor/src/swap/swap_hotkey.rs
+++ b/pallets/subtensor/src/swap/swap_hotkey.rs
@@ -364,6 +364,7 @@ impl<T: Config> Pallet<T> {
             ChildKeys::<T>::remove(old_hotkey, netuid);
             // Insert the same child entries for the new hotkey
             ChildKeys::<T>::insert(new_hotkey, netuid, my_children.clone());
+            weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
             for (_, child_key_i) in my_children {
                 // For each child, update their parent list
                 let mut child_parents: Vec<(u64, T::AccountId)> =
@@ -376,6 +377,7 @@ impl<T: Config> Pallet<T> {
                 }
                 // Update the child's parent list
                 ParentKeys::<T>::insert(child_key_i, netuid, child_parents);
+                weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
             }
         }
 
@@ -388,6 +390,7 @@ impl<T: Config> Pallet<T> {
             ParentKeys::<T>::remove(old_hotkey, netuid);
             // Insert the same parent entries for the new hotkey
             ParentKeys::<T>::insert(new_hotkey, netuid, parents.clone());
+            weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
             for (_, parent_key_i) in parents {
                 // For each parent, update their children list
                 let mut parent_children: Vec<(u64, T::AccountId)> =
@@ -400,16 +403,37 @@ impl<T: Config> Pallet<T> {
                 }
                 // Update the parent's children list
                 ChildKeys::<T>::insert(parent_key_i, netuid, parent_children);
+                weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
             }
         }
 
         // 14. Swap PendingChildKeys.
         // PendingChildKeys( netuid, parent ) --> Vec<(proportion,child), cool_down_block>
         for netuid in Self::get_all_subnet_netuids() {
+            weight.saturating_accrue(T::DbWeight::get().reads(1));
             if PendingChildKeys::<T>::contains_key(netuid, old_hotkey) {
                 let (children, cool_down_block) = PendingChildKeys::<T>::get(netuid, old_hotkey);
                 PendingChildKeys::<T>::remove(netuid, old_hotkey);
                 PendingChildKeys::<T>::insert(netuid, new_hotkey, (children, cool_down_block));
+                weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
+            }
+
+            // Also check for others with our hotkey as a child
+            for (hotkey, (children, cool_down_block)) in PendingChildKeys::<T>::iter_prefix(netuid)
+            {
+                weight.saturating_accrue(T::DbWeight::get().reads(1));
+
+                if let Some(potential_idx) =
+                    children.iter().position(|(_, child)| *child == *old_hotkey)
+                {
+                    let mut new_children = children.clone();
+                    let entry_to_remove = new_children.remove(potential_idx);
+                    new_children.push((entry_to_remove.0, new_hotkey.clone())); // Keep the proportion.
+
+                    PendingChildKeys::<T>::remove(netuid, hotkey.clone());
+                    PendingChildKeys::<T>::insert(netuid, hotkey, (new_children, cool_down_block));
+                    weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));
+                }
             }
         }
 

From 2ba69b19c5ce54e095ff2e511780b4c4137bf5db Mon Sep 17 00:00:00 2001
From: andreea-popescu-reef
 <160024917+andreea-popescu-reef@users.noreply.github.com>
Date: Mon, 27 Jan 2025 20:38:23 +0800
Subject: [PATCH 084/145] reset neuron data on registration (#755)

---
 pallets/subtensor/src/subnets/uids.rs | 23 ++++++++++
 pallets/subtensor/src/tests/uids.rs   | 66 ++++++++++++++++++++++++---
 2 files changed, 82 insertions(+), 7 deletions(-)

diff --git a/pallets/subtensor/src/subnets/uids.rs b/pallets/subtensor/src/subnets/uids.rs
index afdbc0371..6b1fa5c6b 100644
--- a/pallets/subtensor/src/subnets/uids.rs
+++ b/pallets/subtensor/src/subnets/uids.rs
@@ -8,6 +8,23 @@ impl<T: Config> Pallet<T> {
         SubnetworkN::<T>::get(netuid)
     }
 
+    /// Sets value for the element at the given position if it exists.
+    pub fn set_element_at<N>(vec: &mut [N], position: usize, value: N) {
+        if let Some(element) = vec.get_mut(position) {
+            *element = value;
+        }
+    }
+
+    /// Resets the trust, emission, consensus, incentive, dividends of the neuron to default
+    pub fn clear_neuron(netuid: u16, neuron_uid: u16) {
+        let neuron_index: usize = neuron_uid.into();
+        Emission::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
+        Trust::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
+        Consensus::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
+        Incentive::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
+        Dividends::<T>::mutate(netuid, |v| Self::set_element_at(v, neuron_index, 0));
+    }
+
     /// Replace the neuron under this uid.
     pub fn replace_neuron(
         netuid: u16,
@@ -40,6 +57,12 @@ impl<T: Config> Pallet<T> {
 
         // 4. Clear neuron certificates
         NeuronCertificates::<T>::remove(netuid, old_hotkey.clone());
+
+        // 5. Reset new neuron's values.
+        Self::clear_neuron(netuid, uid_to_replace);
+
+        // 5a. reset axon info for the new uid.
+        Axons::<T>::remove(netuid, old_hotkey);
     }
 
     /// Appends the uid to the network.
diff --git a/pallets/subtensor/src/tests/uids.rs b/pallets/subtensor/src/tests/uids.rs
index 9fdeca041..b45a156a9 100644
--- a/pallets/subtensor/src/tests/uids.rs
+++ b/pallets/subtensor/src/tests/uids.rs
@@ -50,17 +50,47 @@ fn test_replace_neuron() {
         // Get UID
         let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id);
         assert_ok!(neuron_uid);
+        let neuron_uid = neuron_uid.unwrap();
+
+        // set non-default values
+        Trust::<Test>::mutate(netuid, |v| {
+            SubtensorModule::set_element_at(v, neuron_uid as usize, 5u16)
+        });
+        Emission::<Test>::mutate(netuid, |v| {
+            SubtensorModule::set_element_at(v, neuron_uid as usize, 5u64)
+        });
+        Consensus::<Test>::mutate(netuid, |v| {
+            SubtensorModule::set_element_at(v, neuron_uid as usize, 5u16)
+        });
+        Incentive::<Test>::mutate(netuid, |v| {
+            SubtensorModule::set_element_at(v, neuron_uid as usize, 5u16)
+        });
+        Dividends::<Test>::mutate(netuid, |v| {
+            SubtensorModule::set_element_at(v, neuron_uid as usize, 5u16)
+        });
+
+        // serve axon mock address
+        let ip: u128 = 1676056785;
+        let port: u16 = 9999;
+        let ip_type: u8 = 4;
+        assert!(SubtensorModule::serve_axon(
+            <<Test as Config>::RuntimeOrigin>::signed(hotkey_account_id),
+            netuid,
+            0,
+            ip,
+            port,
+            ip_type,
+            0,
+            0,
+            0
+        )
+        .is_ok());
 
         // Set a neuron certificate for it
         NeuronCertificates::<Test>::insert(netuid, hotkey_account_id, certificate);
 
         // Replace the neuron.
-        SubtensorModule::replace_neuron(
-            netuid,
-            neuron_uid.unwrap(),
-            &new_hotkey_account_id,
-            block_number,
-        );
+        SubtensorModule::replace_neuron(netuid, neuron_uid, &new_hotkey_account_id, block_number);
 
         // Check old hotkey is not registered on any network.
         assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_err());
@@ -68,7 +98,7 @@ fn test_replace_neuron() {
             &hotkey_account_id
         ));
 
-        let curr_hotkey = SubtensorModule::get_hotkey_for_net_and_uid(netuid, neuron_uid.unwrap());
+        let curr_hotkey = SubtensorModule::get_hotkey_for_net_and_uid(netuid, neuron_uid);
         assert_ok!(curr_hotkey);
         assert_ne!(curr_hotkey.unwrap(), hotkey_account_id);
 
@@ -84,6 +114,28 @@ fn test_replace_neuron() {
         // Check neuron certificate was reset
         let certificate = NeuronCertificates::<Test>::get(netuid, hotkey_account_id);
         assert_eq!(certificate, None);
+
+        // Check trust, emission, consensus, incentive, dividends have been reset to 0.
+        assert_eq!(SubtensorModule::get_trust_for_uid(netuid, neuron_uid), 0);
+        assert_eq!(SubtensorModule::get_emission_for_uid(netuid, neuron_uid), 0);
+        assert_eq!(
+            SubtensorModule::get_consensus_for_uid(netuid, neuron_uid),
+            0
+        );
+        assert_eq!(
+            SubtensorModule::get_incentive_for_uid(netuid, neuron_uid),
+            0
+        );
+        assert_eq!(
+            SubtensorModule::get_dividends_for_uid(netuid, neuron_uid),
+            0
+        );
+
+        // Check axon info is reset.
+        let axon_info = SubtensorModule::get_axon_info(netuid, &curr_hotkey.unwrap());
+        assert_eq!(axon_info.ip, 0);
+        assert_eq!(axon_info.port, 0);
+        assert_eq!(axon_info.ip_type, 0);
     });
 }
 

From 4dd50d701c99bdd2928d92620ff911d1060e4137 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 11:18:02 -0500
Subject: [PATCH 085/145] move create before other ensures

---
 pallets/subtensor/src/subnets/registration.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pallets/subtensor/src/subnets/registration.rs b/pallets/subtensor/src/subnets/registration.rs
index 9913578e8..bce9ea25c 100644
--- a/pallets/subtensor/src/subnets/registration.rs
+++ b/pallets/subtensor/src/subnets/registration.rs
@@ -119,6 +119,9 @@ impl<T: Config> Pallet<T> {
             Error::<T>::NotEnoughBalanceToStake
         );
 
+        // If the network account does not exist we will create it here.
+        Self::create_account_if_non_existent(&coldkey, &hotkey);
+
         // --- 8. Ensure that the pairing is correct.
         ensure!(
             Self::coldkey_owns_hotkey(&coldkey, &hotkey),
@@ -139,9 +142,6 @@ impl<T: Config> Pallet<T> {
         let burned_alpha: u64 = Self::swap_tao_for_alpha(netuid, actual_burn_amount);
         SubnetAlphaOut::<T>::mutate(netuid, |total| *total = total.saturating_sub(burned_alpha));
 
-        // --- 11. If the network account does not exist we will create it here.
-        Self::create_account_if_non_existent(&coldkey, &hotkey);
-
         // Actually perform the registration.
         let neuron_uid: u16 = Self::register_neuron(netuid, &hotkey);
 

From a7e2ad121cb923befd57f8eb2c7f6f56e117067e Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 11:34:18 -0500
Subject: [PATCH 086/145] add test for no write

---
 pallets/subtensor/src/tests/registration.rs | 43 +++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/pallets/subtensor/src/tests/registration.rs b/pallets/subtensor/src/tests/registration.rs
index 36be6f2fc..fa7c06f9e 100644
--- a/pallets/subtensor/src/tests/registration.rs
+++ b/pallets/subtensor/src/tests/registration.rs
@@ -490,6 +490,49 @@ fn test_burn_registration_without_neuron_slot() {
     });
 }
 
+#[test]
+fn test_burn_registration_doesnt_write_on_failure() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        let tempo: u16 = 13;
+        let hotkey_account_id = U256::from(1);
+        let burn_cost = 1000;
+        let initial_balance = burn_cost * 10;
+        let coldkey_account_id = U256::from(987);
+
+        // Add network and set burn cost
+        add_network(netuid, tempo, 0);
+        SubtensorModule::set_burn(netuid, burn_cost);
+        // Give coldkey balance to pay for registration
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance);
+        // Set max allowed uids to 0 so registration will fail, but only on last check.
+        SubtensorModule::set_max_allowed_uids(netuid, 0);
+
+        // We expect this to fail at the last ensure check.
+        assert_err!(
+            SubtensorModule::burned_register(
+                <<Test as Config>::RuntimeOrigin>::signed(coldkey_account_id),
+                netuid,
+                hotkey_account_id
+            ),
+            Error::<Test>::NoNeuronIdAvailable
+        );
+
+        // Make sure the coldkey balance is unchanged.
+        assert_eq!(
+            SubtensorModule::get_coldkey_balance(&coldkey_account_id),
+            initial_balance
+        );
+        // Make sure the neuron is not registered.
+        assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0);
+        // Make sure the hotkey is not registered.
+        assert_eq!(
+            SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_err(),
+            true
+        );
+    });
+}
+
 #[test]
 fn test_burn_adjustment() {
     new_test_ext(1).execute_with(|| {

From b0a6a78d4a1f5049d088bdc4511ca6f0638f62d7 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 11:49:17 -0500
Subject: [PATCH 087/145] Ban saturating_div

---
 pallets/collective/src/lib.rs                 |  3 +-
 .../subtensor/src/coinbase/block_emission.rs  |  3 +-
 pallets/subtensor/src/coinbase/block_step.rs  |  9 +-
 pallets/subtensor/src/coinbase/root.rs        |  3 +-
 .../subtensor/src/coinbase/run_coinbase.rs    |  7 +-
 pallets/subtensor/src/epoch/math.rs           | 90 +++++++++++++------
 pallets/subtensor/src/epoch/run_epoch.rs      | 21 +++--
 .../subtensor/src/rpc_info/delegate_info.rs   |  9 +-
 pallets/subtensor/src/staking/move_stake.rs   |  3 +-
 pallets/subtensor/src/staking/stake_utils.rs  |  7 +-
 pallets/subtensor/src/subnets/weights.rs      |  4 +-
 pallets/subtensor/src/tests/children.rs       |  2 +-
 pallets/subtensor/src/tests/epoch.rs          | 12 +--
 pallets/subtensor/src/utils/misc.rs           |  8 +-
 runtime/src/lib.rs                            |  4 +-
 15 files changed, 114 insertions(+), 71 deletions(-)

diff --git a/pallets/collective/src/lib.rs b/pallets/collective/src/lib.rs
index 823e92663..707f49ded 100644
--- a/pallets/collective/src/lib.rs
+++ b/pallets/collective/src/lib.rs
@@ -549,7 +549,8 @@ pub mod pallet {
             );
 
             let threshold = T::GetVotingMembers::get_count()
-                .saturating_div(2)
+                .checked_div(2)
+                .unwrap_or(0)
                 .saturating_add(1);
 
             let members = Self::members();
diff --git a/pallets/subtensor/src/coinbase/block_emission.rs b/pallets/subtensor/src/coinbase/block_emission.rs
index ab570c19e..dbc93cf93 100644
--- a/pallets/subtensor/src/coinbase/block_emission.rs
+++ b/pallets/subtensor/src/coinbase/block_emission.rs
@@ -1,4 +1,5 @@
 use super::*;
+use crate::epoch::math::*;
 use frame_support::traits::Get;
 use substrate_fixed::{transcendental::log2, types::I96F32};
 
@@ -139,7 +140,7 @@ impl<T: Config> Pallet<T> {
         for _ in 0..floored_residual_int {
             multiplier = multiplier.saturating_mul(I96F32::from_num(2.0));
         }
-        let block_emission_percentage: I96F32 = I96F32::from_num(1.0).saturating_div(multiplier);
+        let block_emission_percentage: I96F32 = I96F32::from_num(1.0).safe_div(multiplier);
         // Calculate the actual emission based on the emission rate
         let block_emission: I96F32 = block_emission_percentage
             .saturating_mul(I96F32::from_num(DefaultBlockEmission::<T>::get()));
diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs
index 23218ed50..ce793def9 100644
--- a/pallets/subtensor/src/coinbase/block_step.rs
+++ b/pallets/subtensor/src/coinbase/block_step.rs
@@ -1,4 +1,5 @@
 use super::*;
+use crate::epoch::math::*;
 use frame_support::storage::IterableStorageMap;
 use substrate_fixed::types::{I110F18, I96F32};
 
@@ -202,11 +203,11 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
             .saturating_mul(I110F18::from_num(
                 registrations_this_interval.saturating_add(target_registrations_per_interval),
             ))
-            .saturating_div(I110F18::from_num(
+            .safe_div(I110F18::from_num(
                 target_registrations_per_interval.saturating_add(target_registrations_per_interval),
             ));
         let alpha: I110F18 = I110F18::from_num(Self::get_adjustment_alpha(netuid))
-            .saturating_div(I110F18::from_num(u64::MAX));
+            .safe_div(I110F18::from_num(u64::MAX));
         let next_value: I110F18 = alpha
             .saturating_mul(I110F18::from_num(current_difficulty))
             .saturating_add(
@@ -236,11 +237,11 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
             .saturating_mul(I110F18::from_num(
                 registrations_this_interval.saturating_add(target_registrations_per_interval),
             ))
-            .saturating_div(I110F18::from_num(
+            .safe_div(I110F18::from_num(
                 target_registrations_per_interval.saturating_add(target_registrations_per_interval),
             ));
         let alpha: I110F18 = I110F18::from_num(Self::get_adjustment_alpha(netuid))
-            .saturating_div(I110F18::from_num(u64::MAX));
+            .safe_div(I110F18::from_num(u64::MAX));
         let next_value: I110F18 = alpha
             .saturating_mul(I110F18::from_num(current_burn))
             .saturating_add(
diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs
index 112c88785..165526ac2 100644
--- a/pallets/subtensor/src/coinbase/root.rs
+++ b/pallets/subtensor/src/coinbase/root.rs
@@ -16,6 +16,7 @@
 // DEALINGS IN THE SOFTWARE.
 
 use super::*;
+use crate::epoch::math::*;
 use frame_support::dispatch::Pays;
 use frame_support::storage::IterableStorageDoubleMap;
 use frame_support::weights::Weight;
@@ -624,7 +625,7 @@ impl<T: Config> Pallet<T> {
 
         let mut lock_cost = last_lock.saturating_mul(mult).saturating_sub(
             last_lock
-                .saturating_div(lock_reduction_interval)
+                .safe_div(lock_reduction_interval)
                 .saturating_mul(current_block.saturating_sub(last_lock_block)),
         );
 
diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index e86c07c24..e15dc15d3 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -1,4 +1,5 @@
 use super::*;
+use crate::epoch::math::*;
 use alloc::collections::BTreeMap;
 use substrate_fixed::types::I96F32;
 use tle::stream_ciphers::AESGCMStreamCipherProvider;
@@ -557,7 +558,7 @@ impl<T: Config> Pallet<T> {
         for (proportion, _) in childkeys {
             remaining_proportion = remaining_proportion.saturating_sub(
                 I96F32::from_num(proportion) // Normalize
-                    .saturating_div(I96F32::from_num(u64::MAX)),
+                    .safe_div(I96F32::from_num(u64::MAX)),
             );
         }
 
@@ -608,7 +609,7 @@ impl<T: Config> Pallet<T> {
         let validating_emission: I96F32 = I96F32::from_num(dividends);
         let childkey_take_proportion: I96F32 =
             I96F32::from_num(Self::get_childkey_take(hotkey, netuid))
-                .saturating_div(I96F32::from_num(u16::MAX));
+                .safe_div(I96F32::from_num(u16::MAX));
         log::debug!(
             "Childkey take proportion: {:?} for hotkey {:?}",
             childkey_take_proportion,
@@ -656,7 +657,7 @@ impl<T: Config> Pallet<T> {
         for (proportion, parent) in Self::get_parents(hotkey, netuid) {
             // Convert the parent's stake proportion to a fractional value
             let parent_proportion: I96F32 =
-                I96F32::from_num(proportion).saturating_div(I96F32::from_num(u64::MAX));
+                I96F32::from_num(proportion).safe_div(I96F32::from_num(u64::MAX));
 
             // Get the parent's root and subnet-specific (alpha) stakes
             let parent_root: I96F32 = I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(
diff --git a/pallets/subtensor/src/epoch/math.rs b/pallets/subtensor/src/epoch/math.rs
index 616a9b78b..926375446 100644
--- a/pallets/subtensor/src/epoch/math.rs
+++ b/pallets/subtensor/src/epoch/math.rs
@@ -8,7 +8,7 @@ use sp_std::cmp::Ordering;
 
 use sp_std::vec;
 use substrate_fixed::transcendental::{exp, ln};
-use substrate_fixed::types::{I32F32, I64F64};
+use substrate_fixed::types::{I110F18, I32F32, I64F64, I96F32, U64F64};
 
 // TODO: figure out what cfg gate this needs to not be a warning in rustc
 #[allow(unused)]
@@ -51,7 +51,7 @@ pub fn u16_to_fixed(x: u16) -> I32F32 {
 
 #[allow(dead_code)]
 pub fn u16_proportion_to_fixed(x: u16) -> I32F32 {
-    I32F32::from_num(x).saturating_div(I32F32::from_num(u16::MAX))
+    I32F32::from_num(x).safe_div(I32F32::from_num(u16::MAX))
 }
 
 #[allow(dead_code)]
@@ -107,7 +107,7 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
                 return vec
                     .iter()
                     .map(|e: &I32F32| {
-                        e.saturating_mul(u16_max.saturating_div(*val))
+                        e.saturating_mul(u16_max.safe_div(*val))
                             .round()
                             .to_num::<u16>()
                     })
@@ -116,7 +116,7 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
             vec.iter()
                 .map(|e: &I32F32| {
                     e.saturating_mul(u16_max)
-                        .saturating_div(*val)
+                        .safe_div(*val)
                         .round()
                         .to_num::<u16>()
                 })
@@ -125,11 +125,7 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
         None => {
             let sum: I32F32 = vec.iter().sum();
             vec.iter()
-                .map(|e: &I32F32| {
-                    e.saturating_mul(u16_max)
-                        .saturating_div(sum)
-                        .to_num::<u16>()
-                })
+                .map(|e: &I32F32| e.saturating_mul(u16_max).safe_div(sum).to_num::<u16>())
                 .collect()
         }
     }
@@ -145,8 +141,7 @@ pub fn vec_u16_max_upscale_to_u16(vec: &[u16]) -> Vec<u16> {
 #[allow(dead_code)]
 // Checks if u16 vector, when normalized, has a max value not greater than a u16 ratio max_limit.
 pub fn check_vec_max_limited(vec: &[u16], max_limit: u16) -> bool {
-    let max_limit_fixed: I32F32 =
-        I32F32::from_num(max_limit).saturating_div(I32F32::from_num(u16::MAX));
+    let max_limit_fixed: I32F32 = I32F32::from_num(max_limit).safe_div(I32F32::from_num(u16::MAX));
     let mut vec_fixed: Vec<I32F32> = vec.iter().map(|e: &u16| I32F32::from_num(*e)).collect();
     inplace_normalize(&mut vec_fixed);
     let max_value: Option<&I32F32> = vec_fixed.iter().max();
@@ -219,7 +214,7 @@ pub fn sigmoid_safe(input: I32F32, rho: I32F32, kappa: I32F32) -> I32F32 {
     let exp_input: I32F32 = neg_rho.saturating_mul(offset); // -rho*(input-kappa)
     let exp_output: I32F32 = exp_safe(exp_input); // exp(-rho*(input-kappa))
     let denominator: I32F32 = exp_output.saturating_add(one); // 1 + exp(-rho*(input-kappa))
-    let sigmoid_output: I32F32 = one.saturating_div(denominator); // 1 / (1 + exp(-rho*(input-kappa)))
+    let sigmoid_output: I32F32 = one.safe_div(denominator); // 1 / (1 + exp(-rho*(input-kappa)))
     sigmoid_output
 }
 
@@ -244,7 +239,7 @@ pub fn is_topk(vector: &[I32F32], k: usize) -> Vec<bool> {
 pub fn normalize(x: &[I32F32]) -> Vec<I32F32> {
     let x_sum: I32F32 = sum(x);
     if x_sum != I32F32::from_num(0.0_f32) {
-        x.iter().map(|xi| xi.saturating_div(x_sum)).collect()
+        x.iter().map(|xi| xi.safe_div(x_sum)).collect()
     } else {
         x.to_vec()
     }
@@ -258,7 +253,7 @@ pub fn inplace_normalize(x: &mut [I32F32]) {
         return;
     }
     x.iter_mut()
-        .for_each(|value| *value = value.saturating_div(x_sum));
+        .for_each(|value| *value = value.safe_div(x_sum));
 }
 
 // Normalizes (sum to 1 except 0) the input vector directly in-place, using the sum arg.
@@ -268,7 +263,7 @@ pub fn inplace_normalize_using_sum(x: &mut [I32F32], x_sum: I32F32) {
         return;
     }
     x.iter_mut()
-        .for_each(|value| *value = value.saturating_div(x_sum));
+        .for_each(|value| *value = value.safe_div(x_sum));
 }
 
 // Normalizes (sum to 1 except 0) the I64F64 input vector directly in-place.
@@ -279,7 +274,7 @@ pub fn inplace_normalize_64(x: &mut [I64F64]) {
         return;
     }
     x.iter_mut()
-        .for_each(|value| *value = value.saturating_div(x_sum));
+        .for_each(|value| *value = value.safe_div(x_sum));
 }
 
 /// Normalizes (sum to 1 except 0) each row (dim=0) of a I64F64 matrix in-place.
@@ -289,7 +284,7 @@ pub fn inplace_row_normalize_64(x: &mut [Vec<I64F64>]) {
         let row_sum: I64F64 = row.iter().sum();
         if row_sum > I64F64::from_num(0.0_f64) {
             row.iter_mut()
-                .for_each(|x_ij: &mut I64F64| *x_ij = x_ij.saturating_div(row_sum));
+                .for_each(|x_ij: &mut I64F64| *x_ij = x_ij.safe_div(row_sum));
         }
     }
 }
@@ -302,7 +297,7 @@ pub fn vecdiv(x: &[I32F32], y: &[I32F32]) -> Vec<I32F32> {
         .zip(y)
         .map(|(x_i, y_i)| {
             if *y_i != 0 {
-                x_i.saturating_div(*y_i)
+                x_i.safe_div(*y_i)
             } else {
                 I32F32::from_num(0)
             }
@@ -317,7 +312,7 @@ pub fn inplace_row_normalize(x: &mut [Vec<I32F32>]) {
         let row_sum: I32F32 = row.iter().sum();
         if row_sum > I32F32::from_num(0.0_f32) {
             row.iter_mut()
-                .for_each(|x_ij: &mut I32F32| *x_ij = x_ij.saturating_div(row_sum));
+                .for_each(|x_ij: &mut I32F32| *x_ij = x_ij.safe_div(row_sum));
         }
     }
 }
@@ -330,7 +325,7 @@ pub fn inplace_row_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>]) {
         if row_sum > I32F32::from_num(0.0) {
             sparse_row
                 .iter_mut()
-                .for_each(|(_j, value)| *value = value.saturating_div(row_sum));
+                .for_each(|(_j, value)| *value = value.safe_div(row_sum));
         }
     }
 }
@@ -400,7 +395,7 @@ pub fn inplace_col_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>], co
             if col_sum[*j as usize] == I32F32::from_num(0.0_f32) {
                 continue;
             }
-            *value = value.saturating_div(col_sum[*j as usize]);
+            *value = value.safe_div(col_sum[*j as usize]);
         }
     }
 }
@@ -428,7 +423,7 @@ pub fn inplace_col_normalize(x: &mut [Vec<I32F32>]) {
             .zip(&col_sums)
             .filter(|(_, col_sum)| **col_sum != I32F32::from_num(0_f32))
             .for_each(|(m_val, col_sum)| {
-                *m_val = m_val.saturating_div(*col_sum);
+                *m_val = m_val.safe_div(*col_sum);
             });
     });
 }
@@ -449,7 +444,7 @@ pub fn inplace_col_max_upscale_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>],
             if col_max[*j as usize] == I32F32::from_num(0.0_f32) {
                 continue;
             }
-            *value = value.saturating_div(col_max[*j as usize]);
+            *value = value.safe_div(col_max[*j as usize]);
         }
     }
 }
@@ -477,7 +472,7 @@ pub fn inplace_col_max_upscale(x: &mut [Vec<I32F32>]) {
             .zip(&col_maxes)
             .filter(|(_, col_max)| **col_max != I32F32::from_num(0))
             .for_each(|(m_val, col_max)| {
-                *m_val = m_val.saturating_div(*col_max);
+                *m_val = m_val.safe_div(*col_max);
             });
     });
 }
@@ -898,7 +893,7 @@ pub fn weighted_median(
         return score[partition_idx[0]];
     }
     assert!(stake.len() == score.len());
-    let mid_idx: usize = n.saturating_div(2);
+    let mid_idx: usize = n.safe_div(2);
     let pivot: I32F32 = score[partition_idx[mid_idx]];
     let mut lo_stake: I32F32 = I32F32::from_num(0);
     let mut hi_stake: I32F32 = I32F32::from_num(0);
@@ -1411,3 +1406,48 @@ pub fn safe_ln(value: I32F32) -> I32F32 {
 pub fn safe_exp(value: I32F32) -> I32F32 {
     exp(value).unwrap_or(I32F32::from_num(0.0))
 }
+
+/// Safe division trait
+pub trait SafeDiv {
+    /// Safe division that returns supplied default value for division by zero
+    fn safe_div_or(self, rhs: Self, def: Self) -> Self;
+    /// Safe division that returns default value for division by zero
+    fn safe_div(self, rhs: Self) -> Self;
+}
+
+/// Implementation of safe division trait for primitive types
+macro_rules! impl_safe_div_for_primitive {
+    ($($t:ty),*) => {
+        $(
+            impl SafeDiv for $t {
+                fn safe_div_or(self, rhs: Self, def: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or(def)
+                }
+
+                fn safe_div(self, rhs: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or_default()
+                }
+            }
+        )*
+    };
+}
+impl_safe_div_for_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, usize);
+
+/// Implementation of safe division trait for substrate fixed types
+macro_rules! impl_safe_div_for_fixed {
+    ($($t:ty),*) => {
+        $(
+            impl SafeDiv for $t {
+                fn safe_div_or(self, rhs: Self, def: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or(def)
+                }
+
+                fn safe_div(self, rhs: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or_default()
+                }
+            }
+        )*
+    };
+}
+
+impl_safe_div_for_fixed!(I96F32, I32F32, I64F64, I110F18, U64F64);
diff --git a/pallets/subtensor/src/epoch/run_epoch.rs b/pallets/subtensor/src/epoch/run_epoch.rs
index e6edd2585..9b3023818 100644
--- a/pallets/subtensor/src/epoch/run_epoch.rs
+++ b/pallets/subtensor/src/epoch/run_epoch.rs
@@ -735,10 +735,10 @@ impl<T: Config> Pallet<T> {
         I32F32::from_num(Self::get_rho(netuid))
     }
     pub fn get_float_kappa(netuid: u16) -> I32F32 {
-        I32F32::from_num(Self::get_kappa(netuid)).saturating_div(I32F32::from_num(u16::MAX))
+        I32F32::from_num(Self::get_kappa(netuid)).safe_div(I32F32::from_num(u16::MAX))
     }
     pub fn get_float_bonds_penalty(netuid: u16) -> I32F32 {
-        I32F32::from_num(Self::get_bonds_penalty(netuid)).saturating_div(I32F32::from_num(u16::MAX))
+        I32F32::from_num(Self::get_bonds_penalty(netuid)).safe_div(I32F32::from_num(u16::MAX))
     }
 
     pub fn get_block_at_registration(netuid: u16) -> Vec<u64> {
@@ -864,19 +864,18 @@ impl<T: Config> Pallet<T> {
         // Calculate the slope 'a' of the logistic function.
         // a = (ln((1 / alpha_high - 1)) - ln((1 / alpha_low - 1))) / (consensus_low - consensus_high)
         let a = (safe_ln(
-            (I32F32::from_num(1.0).saturating_div(alpha_high))
-                .saturating_sub(I32F32::from_num(1.0)),
+            (I32F32::from_num(1.0).safe_div(alpha_high)).saturating_sub(I32F32::from_num(1.0)),
         )
         .saturating_sub(safe_ln(
-            (I32F32::from_num(1.0).saturating_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)),
+            (I32F32::from_num(1.0).safe_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)),
         )))
-        .saturating_div(consensus_low.saturating_sub(consensus_high));
+        .safe_div(consensus_low.saturating_sub(consensus_high));
         log::trace!("a: {:?}", a);
 
         // Calculate the intercept 'b' of the logistic function.
         // b = ln((1 / alpha_low - 1)) + a * consensus_low
         let b = safe_ln(
-            (I32F32::from_num(1.0).saturating_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)),
+            (I32F32::from_num(1.0).safe_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)),
         )
         .saturating_add(a.saturating_mul(consensus_low));
         log::trace!("b: {:?}", b);
@@ -905,7 +904,7 @@ impl<T: Config> Pallet<T> {
 
                 // Compute the alpha value using the logistic function formula.
                 // alpha = 1 / (1 + exp_val)
-                I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val))
+                I32F32::from_num(1.0).safe_div(I32F32::from_num(1.0).saturating_add(exp_val))
             })
             .collect();
 
@@ -1020,7 +1019,7 @@ impl<T: Config> Pallet<T> {
     ) -> Vec<Vec<(u16, I32F32)>> {
         // Retrieve the bonds moving average for the given network ID and scale it down.
         let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid))
-            .saturating_div(I64F64::from_num(1_000_000));
+            .safe_div(I64F64::from_num(1_000_000));
 
         // Calculate the alpha value for the EMA calculation.
         // Alpha is derived by subtracting the scaled bonds moving average from 1.
@@ -1053,7 +1052,7 @@ impl<T: Config> Pallet<T> {
     ) -> Vec<Vec<I32F32>> {
         // Retrieve the bonds moving average for the given network ID and scale it down.
         let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid))
-            .saturating_div(I64F64::from_num(1_000_000));
+            .safe_div(I64F64::from_num(1_000_000));
 
         // Calculate the alpha value for the EMA calculation.
         // Alpha is derived by subtracting the scaled bonds moving average from 1.
@@ -1221,7 +1220,7 @@ impl<T: Config> Pallet<T> {
         );
 
         let max_u16: u32 = u16::MAX as u32; // 65535
-        let min_alpha_high: u16 = (max_u16.saturating_mul(4).saturating_div(5)) as u16; // 52428
+        let min_alpha_high: u16 = (max_u16.saturating_mul(4).safe_div(5)) as u16; // 52428
 
         // --- 4. Ensure alpha high is greater than the minimum
         ensure!(alpha_high >= min_alpha_high, Error::<T>::AlphaHighTooLow);
diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs
index 5776c48af..ec8d48110 100644
--- a/pallets/subtensor/src/rpc_info/delegate_info.rs
+++ b/pallets/subtensor/src/rpc_info/delegate_info.rs
@@ -1,4 +1,5 @@
 use super::*;
+use crate::epoch::math::*;
 use frame_support::pallet_prelude::{Decode, Encode};
 use frame_support::storage::IterableStorageMap;
 use frame_support::IterableStorageDoubleMap;
@@ -27,14 +28,14 @@ impl<T: Config> Pallet<T> {
         emissions_per_day: U64F64,
     ) -> U64F64 {
         // Get the take as a percentage and subtract it from 1 for remainder.
-        let without_take: U64F64 = U64F64::from_num(1)
-            .saturating_sub(U64F64::from_num(take.0).saturating_div(u16::MAX.into()));
+        let without_take: U64F64 =
+            U64F64::from_num(1).saturating_sub(U64F64::from_num(take.0).safe_div(u16::MAX.into()));
 
         if total_stake > U64F64::from_num(0) {
             emissions_per_day
                 .saturating_mul(without_take)
                 // Divide by 1000 TAO for return per 1k
-                .saturating_div(total_stake.saturating_div(U64F64::from_num(1000.0 * 1e9)))
+                .safe_div(total_stake.safe_div(U64F64::from_num(1000.0 * 1e9)))
         } else {
             U64F64::from_num(0)
         }
@@ -78,7 +79,7 @@ impl<T: Config> Pallet<T> {
                 let emission: U64F64 = Self::get_emission_for_uid(*netuid, uid).into();
                 let tempo: U64F64 = Self::get_tempo(*netuid).into();
                 if tempo > U64F64::from_num(0) {
-                    let epochs_per_day: U64F64 = U64F64::from_num(7200).saturating_div(tempo);
+                    let epochs_per_day: U64F64 = U64F64::from_num(7200).safe_div(tempo);
                     emissions_per_day =
                         emissions_per_day.saturating_add(emission.saturating_mul(epochs_per_day));
                 }
diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 4644b3213..88dd1463f 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -1,4 +1,5 @@
 use super::*;
+use crate::epoch::math::*;
 use sp_core::Get;
 
 impl<T: Config> Pallet<T> {
@@ -223,7 +224,7 @@ impl<T: Config> Pallet<T> {
         )?;
 
         // Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
-        let fee = DefaultStakingFee::<T>::get().saturating_div(2);
+        let fee = DefaultStakingFee::<T>::get().safe_div(2);
         let tao_unstaked = Self::unstake_from_subnet(
             origin_hotkey,
             origin_coldkey,
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index f34a5ace0..bb30b5c34 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -1,4 +1,5 @@
 use super::*;
+use crate::epoch::math::*;
 use share_pool::{SharePool, SharePoolDataOperations};
 use sp_std::ops::Neg;
 use substrate_fixed::types::{I64F64, I96F32, U64F64};
@@ -70,7 +71,7 @@ impl<T: Config> Pallet<T> {
 
         // Step 3: Normalize the weight by dividing by u64::MAX
         // This ensures the result is always between 0 and 1
-        weight_fixed.saturating_div(I96F32::from_num(u64::MAX))
+        weight_fixed.safe_div(I96F32::from_num(u64::MAX))
     }
 
     /// Sets the global global weight in storage.
@@ -234,7 +235,7 @@ impl<T: Config> Pallet<T> {
         for (proportion, _) in children {
             // Convert the proportion to a normalized value between 0 and 1.
             let normalized_proportion: I96F32 =
-                I96F32::from_num(proportion).saturating_div(I96F32::from_num(u64::MAX));
+                I96F32::from_num(proportion).safe_div(I96F32::from_num(u64::MAX));
             log::trace!(
                 "Normalized proportion for child: {:?}",
                 normalized_proportion
@@ -264,7 +265,7 @@ impl<T: Config> Pallet<T> {
 
             // Convert the proportion to a normalized value between 0 and 1.
             let normalized_proportion: I96F32 =
-                I96F32::from_num(proportion).saturating_div(I96F32::from_num(u64::MAX));
+                I96F32::from_num(proportion).safe_div(I96F32::from_num(u64::MAX));
             log::trace!(
                 "Normalized proportion from parent: {:?}",
                 normalized_proportion
diff --git a/pallets/subtensor/src/subnets/weights.rs b/pallets/subtensor/src/subnets/weights.rs
index fca0e5999..13fa0dafc 100644
--- a/pallets/subtensor/src/subnets/weights.rs
+++ b/pallets/subtensor/src/subnets/weights.rs
@@ -1001,9 +1001,7 @@ impl<T: Config> Pallet<T> {
             return weights;
         }
         weights.iter_mut().for_each(|x| {
-            *x = (*x as u64)
-                .saturating_mul(u16::MAX as u64)
-                .saturating_div(sum) as u16;
+            *x = (*x as u64).saturating_mul(u16::MAX as u64).safe_div(sum) as u16;
         });
         weights
     }
diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs
index 30fe8287b..7a3780c0b 100644
--- a/pallets/subtensor/src/tests/children.rs
+++ b/pallets/subtensor/src/tests/children.rs
@@ -3702,7 +3702,7 @@ fn test_dynamic_parent_child_relationships() {
         let expected_parent_stake = ((I96F32::from_num(stake_parent_0)
             + total_emission * rel_stake_parent_0)
             * I96F32::from_num(5))
-        .saturating_div(I96F32::from_num(12));
+            / I96F32::from_num(12);
         assert!(
             (I96F32::from_num(stake_parent_2) - expected_parent_stake).abs()
                 / expected_parent_stake
diff --git a/pallets/subtensor/src/tests/epoch.rs b/pallets/subtensor/src/tests/epoch.rs
index ae0c8f669..a353ee5b9 100644
--- a/pallets/subtensor/src/tests/epoch.rs
+++ b/pallets/subtensor/src/tests/epoch.rs
@@ -2285,22 +2285,19 @@ fn test_compute_alpha_values() {
     // exp_val = exp(0.0 - 1.0 * 0.1) = exp(-0.1)
     // alpha[0] = 1 / (1 + exp(-0.1)) ~ 0.9048374180359595
     let exp_val_0 = I32F32::from_num(0.9048374180359595);
-    let expected_alpha_0 =
-        I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val_0));
+    let expected_alpha_0 = I32F32::from_num(1.0) / I32F32::from_num(1.0).saturating_add(exp_val_0);
 
     // For consensus[1] = 0.5:
     // exp_val = exp(0.0 - 1.0 * 0.5) = exp(-0.5)
     // alpha[1] = 1 / (1 + exp(-0.5)) ~ 0.6065306597126334
     let exp_val_1 = I32F32::from_num(0.6065306597126334);
-    let expected_alpha_1 =
-        I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val_1));
+    let expected_alpha_1 = I32F32::from_num(1.0) / I32F32::from_num(1.0).saturating_add(exp_val_1);
 
     // For consensus[2] = 0.9:
     // exp_val = exp(0.0 - 1.0 * 0.9) = exp(-0.9)
     // alpha[2] = 1 / (1 + exp(-0.9)) ~ 0.4065696597405991
     let exp_val_2 = I32F32::from_num(0.4065696597405991);
-    let expected_alpha_2 =
-        I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val_2));
+    let expected_alpha_2 = I32F32::from_num(1.0) / I32F32::from_num(1.0).saturating_add(exp_val_2);
 
     // Define an epsilon for approximate equality checks.
     let epsilon = I32F32::from_num(1e-6);
@@ -2338,8 +2335,7 @@ fn test_compute_alpha_values_256_miners() {
         let exp_val = safe_exp(exponent);
 
         // Use saturating addition and division
-        let expected_alpha =
-            I32F32::from_num(1.0).saturating_div(I32F32::from_num(1.0).saturating_add(exp_val));
+        let expected_alpha = I32F32::from_num(1.0) / I32F32::from_num(1.0).saturating_add(exp_val);
 
         // Assert that the computed alpha values match the expected values within the epsilon.
         assert_approx_eq(alpha[i], expected_alpha, epsilon);
diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs
index f1e0c7eb4..e211a2485 100644
--- a/pallets/subtensor/src/utils/misc.rs
+++ b/pallets/subtensor/src/utils/misc.rs
@@ -1,5 +1,6 @@
 use super::*;
 use crate::{
+    epoch::math::*,
     system::{ensure_root, ensure_signed_or_root, pallet_prelude::BlockNumberFor},
     Error,
 };
@@ -592,7 +593,7 @@ impl<T: Config> Pallet<T> {
         SubnetOwnerCut::<T>::get()
     }
     pub fn get_float_subnet_owner_cut() -> I96F32 {
-        I96F32::from_num(SubnetOwnerCut::<T>::get()).saturating_div(I96F32::from_num(u16::MAX))
+        I96F32::from_num(SubnetOwnerCut::<T>::get()).safe_div(I96F32::from_num(u16::MAX))
     }
     pub fn set_subnet_owner_cut(subnet_owner_cut: u16) {
         SubnetOwnerCut::<T>::set(subnet_owner_cut);
@@ -664,9 +665,8 @@ impl<T: Config> Pallet<T> {
 
     pub fn get_alpha_values_32(netuid: u16) -> (I32F32, I32F32) {
         let (alpha_low, alpha_high): (u16, u16) = AlphaValues::<T>::get(netuid);
-        let converted_low = I32F32::from_num(alpha_low).saturating_div(I32F32::from_num(u16::MAX));
-        let converted_high =
-            I32F32::from_num(alpha_high).saturating_div(I32F32::from_num(u16::MAX));
+        let converted_low = I32F32::from_num(alpha_low).safe_div(I32F32::from_num(u16::MAX));
+        let converted_high = I32F32::from_num(alpha_high).safe_div(I32F32::from_num(u16::MAX));
 
         (converted_low, converted_high)
     }
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index f8491dd57..372c9a981 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -1179,7 +1179,9 @@ const BLOCK_GAS_LIMIT: u64 = 75_000_000;
 /// `WeightPerGas` is an approximate ratio of the amount of Weight per Gas.
 ///
 fn weight_per_gas() -> Weight {
-    (NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT).saturating_div(BLOCK_GAS_LIMIT)
+    (NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT)
+        .checked_div(BLOCK_GAS_LIMIT)
+        .unwrap_or_default()
 }
 
 parameter_types! {

From 445fae0a21592b22a03500f3cb6f62bd01b11351 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 12:23:58 -0500
Subject: [PATCH 088/145] chore: clippy

---
 pallets/subtensor/src/tests/registration.rs | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/pallets/subtensor/src/tests/registration.rs b/pallets/subtensor/src/tests/registration.rs
index fa7c06f9e..768d923d0 100644
--- a/pallets/subtensor/src/tests/registration.rs
+++ b/pallets/subtensor/src/tests/registration.rs
@@ -526,10 +526,7 @@ fn test_burn_registration_doesnt_write_on_failure() {
         // Make sure the neuron is not registered.
         assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0);
         // Make sure the hotkey is not registered.
-        assert_eq!(
-            SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_err(),
-            true
-        );
+        assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_err());
     });
 }
 

From 88ab78c5e02622e0d84dbb7005a176501d71c1d8 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 12:26:43 -0500
Subject: [PATCH 089/145] use option for identity instead

---
 pallets/subtensor/src/rpc_info/metagraph.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs
index 091c7e259..1e77e5fe6 100644
--- a/pallets/subtensor/src/rpc_info/metagraph.rs
+++ b/pallets/subtensor/src/rpc_info/metagraph.rs
@@ -6,7 +6,7 @@ use frame_support::pallet_prelude::{Decode, Encode};
 use substrate_fixed::types::I64F64;
 use subtensor_macros::freeze_struct;
 
-#[freeze_struct("eff674535ea437ae")]
+#[freeze_struct("bce2310daa502e48")]
 #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
 pub struct Metagraph<T: Config> {
     // Subnet index
@@ -82,7 +82,7 @@ pub struct Metagraph<T: Config> {
     // Metagraph info.
     hotkeys: Vec<T::AccountId>,               // hotkey per UID
     coldkeys: Vec<T::AccountId>,              // coldkey per UID
-    identities: Vec<ChainIdentityOf>,         // coldkeys identities
+    identities: Vec<Option<ChainIdentityOf>>, // coldkeys identities
     axons: Vec<AxonInfo>,                     // UID axons.
     active: Vec<bool>,                        // Avtive per UID
     validator_permit: Vec<bool>,              // Val permit per UID
@@ -114,7 +114,7 @@ impl<T: Config> Pallet<T> {
         let mut hotkeys: Vec<T::AccountId> = vec![];
         let mut coldkeys: Vec<T::AccountId> = vec![];
         let mut block_at_registration: Vec<Compact<u64>> = vec![];
-        let mut identities: Vec<ChainIdentityOf> = vec![];
+        let mut identities: Vec<Option<ChainIdentityOf>> = vec![];
         let mut axons: Vec<AxonInfo> = vec![];
         for uid in 0..n {
             let hotkey = Keys::<T>::get(netuid, uid);
@@ -122,7 +122,7 @@ impl<T: Config> Pallet<T> {
             hotkeys.push(hotkey.clone());
             coldkeys.push(coldkey.clone());
             block_at_registration.push(BlockAtRegistration::<T>::get(netuid, uid).into());
-            identities.push(Identities::<T>::get(coldkey.clone())?);
+            identities.push(Identities::<T>::get(coldkey.clone()));
             axons.push(Self::get_axon_info(netuid, &hotkey));
         }
         let mut tao_dividends_per_hotkey: Vec<(T::AccountId, Compact<u64>)> = vec![];

From 5122fa7ec5c76b700df72e639e0106631bd516de Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 12:43:19 -0500
Subject: [PATCH 090/145] wait rate limit in tests

---
 pallets/subtensor/src/tests/swap_hotkey.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/pallets/subtensor/src/tests/swap_hotkey.rs b/pallets/subtensor/src/tests/swap_hotkey.rs
index 528ad4576..8cf04d285 100644
--- a/pallets/subtensor/src/tests/swap_hotkey.rs
+++ b/pallets/subtensor/src/tests/swap_hotkey.rs
@@ -1264,6 +1264,8 @@ fn test_swap_parent_hotkey_childkey_maps() {
 
         // Set child and verify state maps
         mock_set_children(&coldkey, &parent_old, netuid, &[(u64::MAX, child)]);
+        // Wait rate limit
+        step_rate_limit(&TransactionType::SetChildren, netuid);
         // Schedule some pending child keys.
         mock_schedule_children(&coldkey, &parent_old, netuid, &[(u64::MAX, child_other)]);
 
@@ -1317,6 +1319,8 @@ fn test_swap_child_hotkey_childkey_maps() {
 
         // Set child and verify state maps
         mock_set_children(&coldkey, &parent, netuid, &[(u64::MAX, child_old)]);
+        // Wait rate limit
+        step_rate_limit(&TransactionType::SetChildren, netuid);
         // Schedule some pending child keys.
         mock_schedule_children(&coldkey, &parent, netuid, &[(u64::MAX, child_old)]);
 

From f81608d55a24323f5d1d2b4ecdde3dffd40db9c1 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 13:13:25 -0500
Subject: [PATCH 091/145] use rem root alpha

---
 pallets/subtensor/src/coinbase/run_coinbase.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index 2e9fe44b4..d1e17f5e5 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -446,12 +446,12 @@ impl<T: Config> Pallet<T> {
                 // 2.5.1 --- Store the root divs under hotkey_j
                 root_alpha_divs
                     .entry(hotkey_j.clone())
-                    .and_modify(|e| *e = e.saturating_add(root_alpha_divs_j.to_num::<u64>()))
-                    .or_insert(root_alpha_divs_j.to_num::<u64>());
+                    .and_modify(|e| *e = e.saturating_add(rem_root_alpha_divs_j.to_num::<u64>()))
+                    .or_insert(rem_root_alpha_divs_j.to_num::<u64>());
                 log::debug!(
                     "Stored root alpha dividends for hotkey {:?}: {:?}",
                     hotkey_j,
-                    root_alpha_divs_j.to_num::<u64>()
+                    rem_root_alpha_divs_j.to_num::<u64>()
                 );
 
                 // 2.5.2 --- Store the alpha dividends

From 13bd30b1cec464d57cdca7f5fcf359ff1a48676e Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 13:45:12 -0500
Subject: [PATCH 092/145] fix test involving alpha out emission

---
 pallets/subtensor/src/tests/coinbase.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs
index f62f23e86..08f1eb3b3 100644
--- a/pallets/subtensor/src/tests/coinbase.rs
+++ b/pallets/subtensor/src/tests/coinbase.rs
@@ -39,7 +39,7 @@ fn test_dynamic_function_various_values() {
                     assert!(alpha_in_emission <= alpha_emission, "alpha_in_emission is greater than alpha_emission");
                     assert!(alpha_out_emission <= 2 * alpha_emission, "alpha_out_emission is greater than 2 * alpha_emission");
                     assert!((alpha_in_emission + alpha_out_emission) <= 2 * alpha_emission, "Sum of alpha_in_emission and alpha_out_emission is less than or equal to. 2 * alpha_emission");
-                    close( alpha_in_emission + alpha_out_emission, 2 * alpha_emission, 10 );
+                    close( alpha_in_emission + alpha_out_emission, alpha_in_emission + alpha_emission, 10 );
                     if alpha_in_emission > 0 || tao_in_emission > 0 {
                         assert!((tao_in_emission as f64 / alpha_in_emission as f64 - price).abs() < 1e-1, "Ratio of tao_in_emission to alpha_in_emission is not equal to price");
                     }

From f7e9566ced61f0abe4e0ae428285556b8cb7b436 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Mon, 27 Jan 2025 13:49:51 -0500
Subject: [PATCH 093/145] fix alpha out expectation

---
 pallets/subtensor/src/tests/coinbase.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs
index 08f1eb3b3..ff4908172 100644
--- a/pallets/subtensor/src/tests/coinbase.rs
+++ b/pallets/subtensor/src/tests/coinbase.rs
@@ -70,7 +70,7 @@ fn test_dynamic_function_price_equal_emission() {
         let expected_alpha_in: u64 =
             (alpha_block_emission * tao_subnet_emission) / tao_block_emission;
         close(alpha_in, expected_alpha_in, 10);
-        close(alpha_out, 2 * alpha_block_emission - expected_alpha_in, 10);
+        close(alpha_out, alpha_block_emission, 10);
     });
 }
 

From 33c6af0cee87653ceb54fbd26f421a4c387eb652 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 14:28:10 -0500
Subject: [PATCH 094/145] Ban to_num, organize safe math into a crate

---
 Cargo.lock                                    | 11 +++
 pallets/subtensor/Cargo.toml                  |  1 +
 .../subtensor/src/coinbase/block_emission.rs  | 12 ++--
 pallets/subtensor/src/coinbase/block_step.rs  |  6 +-
 pallets/subtensor/src/coinbase/root.rs        |  2 +-
 .../subtensor/src/coinbase/run_coinbase.rs    | 45 ++++++------
 pallets/subtensor/src/epoch/math.rs           | 66 ++++-------------
 pallets/subtensor/src/epoch/run_epoch.rs      | 13 ++--
 .../subtensor/src/rpc_info/delegate_info.rs   |  6 +-
 pallets/subtensor/src/staking/helpers.rs      |  4 +-
 pallets/subtensor/src/staking/move_stake.rs   |  2 +-
 pallets/subtensor/src/staking/stake_utils.rs  | 26 +++----
 pallets/subtensor/src/subnets/weights.rs      |  1 +
 pallets/subtensor/src/tests/children.rs       |  2 +-
 pallets/subtensor/src/tests/delegate_info.rs  |  2 +-
 pallets/subtensor/src/tests/math.rs           | 20 +++---
 pallets/subtensor/src/utils/misc.rs           |  2 +-
 primitives/safe-math/Cargo.toml               | 19 +++++
 primitives/safe-math/src/lib.rs               | 71 +++++++++++++++++++
 primitives/share-pool/Cargo.toml              |  1 +
 primitives/share-pool/src/lib.rs              |  2 +-
 21 files changed, 193 insertions(+), 121 deletions(-)
 create mode 100644 primitives/safe-math/Cargo.toml
 create mode 100644 primitives/safe-math/src/lib.rs

diff --git a/Cargo.lock b/Cargo.lock
index e86ef3d69..1d5fad7da 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6456,6 +6456,7 @@ dependencies = [
  "parity-util-mem",
  "rand",
  "rand_chacha",
+ "safe-math",
  "scale-info",
  "serde",
  "serde-tuple-vec-map",
@@ -8032,6 +8033,15 @@ version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
+[[package]]
+name = "safe-math"
+version = "0.1.0"
+dependencies = [
+ "num-traits",
+ "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
+ "substrate-fixed",
+]
+
 [[package]]
 name = "safe-mix"
 version = "1.0.1"
@@ -9568,6 +9578,7 @@ dependencies = [
 name = "share-pool"
 version = "0.1.0"
 dependencies = [
+ "safe-math",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
  "substrate-fixed",
 ]
diff --git a/pallets/subtensor/Cargo.toml b/pallets/subtensor/Cargo.toml
index fe1bb7e2d..e8085615d 100644
--- a/pallets/subtensor/Cargo.toml
+++ b/pallets/subtensor/Cargo.toml
@@ -41,6 +41,7 @@ pallet-utility = { workspace = true }
 ndarray = { workspace = true }
 hex = { workspace = true }
 share-pool = { default-features = false, path = "../../primitives/share-pool" }
+safe-math = { default-features = false, path = "../../primitives/safe-math" }
 approx = { workspace = true }
 
 pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../collective" }
diff --git a/pallets/subtensor/src/coinbase/block_emission.rs b/pallets/subtensor/src/coinbase/block_emission.rs
index dbc93cf93..9ea99120d 100644
--- a/pallets/subtensor/src/coinbase/block_emission.rs
+++ b/pallets/subtensor/src/coinbase/block_emission.rs
@@ -1,6 +1,6 @@
 use super::*;
-use crate::epoch::math::*;
 use frame_support::traits::Get;
+use safe_math::*;
 use substrate_fixed::{transcendental::log2, types::I96F32};
 
 impl<T: Config> Pallet<T> {
@@ -81,9 +81,9 @@ impl<T: Config> Pallet<T> {
 
         // Return result.
         (
-            tao_in_emission.to_num::<u64>(),
-            alpha_in_emission.to_num::<u64>(),
-            alpha_out_emission.to_num::<u64>(),
+            tao_in_emission.saturating_to_num::<u64>(),
+            alpha_in_emission.saturating_to_num::<u64>(),
+            alpha_out_emission.saturating_to_num::<u64>(),
         )
     }
 
@@ -134,7 +134,7 @@ impl<T: Config> Pallet<T> {
         let floored_residual: I96F32 = residual.floor();
         // Calculate the final emission rate using the floored residual.
         // Convert floored_residual to an integer
-        let floored_residual_int: u64 = floored_residual.to_num::<u64>();
+        let floored_residual_int: u64 = floored_residual.saturating_to_num::<u64>();
         // Multiply 2.0 by itself floored_residual times to calculate the power of 2.
         let mut multiplier: I96F32 = I96F32::from_num(1.0);
         for _ in 0..floored_residual_int {
@@ -145,7 +145,7 @@ impl<T: Config> Pallet<T> {
         let block_emission: I96F32 = block_emission_percentage
             .saturating_mul(I96F32::from_num(DefaultBlockEmission::<T>::get()));
         // Convert to u64
-        let block_emission_u64: u64 = block_emission.to_num::<u64>();
+        let block_emission_u64: u64 = block_emission.saturating_to_num::<u64>();
         if BlockEmission::<T>::get() != block_emission_u64 {
             BlockEmission::<T>::put(block_emission_u64);
         }
diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs
index ce793def9..b8b27ae73 100644
--- a/pallets/subtensor/src/coinbase/block_step.rs
+++ b/pallets/subtensor/src/coinbase/block_step.rs
@@ -1,6 +1,6 @@
 use super::*;
-use crate::epoch::math::*;
 use frame_support::storage::IterableStorageMap;
+use safe_math::*;
 use substrate_fixed::types::{I110F18, I96F32};
 
 impl<T: Config + pallet_drand::Config> Pallet<T> {
@@ -220,7 +220,7 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
         } else if next_value <= I110F18::from_num(Self::get_min_difficulty(netuid)) {
             return Self::get_min_difficulty(netuid);
         } else {
-            return next_value.to_num::<u64>();
+            return next_value.saturating_to_num::<u64>();
         }
     }
 
@@ -254,7 +254,7 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
         } else if next_value <= I110F18::from_num(Self::get_min_burn_as_u64(netuid)) {
             return Self::get_min_burn_as_u64(netuid);
         } else {
-            return next_value.to_num::<u64>();
+            return next_value.saturating_to_num::<u64>();
         }
     }
 }
diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs
index 165526ac2..9e510fa0a 100644
--- a/pallets/subtensor/src/coinbase/root.rs
+++ b/pallets/subtensor/src/coinbase/root.rs
@@ -16,10 +16,10 @@
 // DEALINGS IN THE SOFTWARE.
 
 use super::*;
-use crate::epoch::math::*;
 use frame_support::dispatch::Pays;
 use frame_support::storage::IterableStorageDoubleMap;
 use frame_support::weights::Weight;
+use safe_math::*;
 use sp_core::Get;
 use sp_std::vec;
 use substrate_fixed::types::I64F64;
diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index e15dc15d3..cc15d7cbe 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -1,6 +1,6 @@
 use super::*;
-use crate::epoch::math::*;
 use alloc::collections::BTreeMap;
+use safe_math::*;
 use substrate_fixed::types::I96F32;
 use tle::stream_ciphers::AESGCMStreamCipherProvider;
 use tle::tlock::tld;
@@ -118,7 +118,7 @@ impl<T: Config> Pallet<T> {
             let tao_in: u64 = mech_emission
                 .checked_mul(subnet_proportion)
                 .unwrap_or(I96F32::from_num(0))
-                .to_num::<u64>();
+                .saturating_to_num::<u64>();
             log::debug!(
                 "Subnet TAO emission (E_s) for netuid {:?}: {:?}",
                 netuid,
@@ -201,7 +201,7 @@ impl<T: Config> Pallet<T> {
             // Calculate the owner cut.
             let owner_cut: u64 = I96F32::from_num(alpha_out_emission)
                 .saturating_mul(Self::get_float_subnet_owner_cut())
-                .to_num::<u64>();
+                .saturating_to_num::<u64>();
             log::debug!("Owner cut for netuid {:?}: {:?}", netuid, owner_cut);
             // Store the owner cut for this subnet.
             *owner_cuts.entry(*netuid).or_insert(0) = owner_cut;
@@ -225,20 +225,25 @@ impl<T: Config> Pallet<T> {
             let pending_alpha_emission: I96F32 =
                 I96F32::from_num(remaining_emission).saturating_sub(root_emission_in_alpha);
             // Sell root emission through the pool.
-            let root_emission_in_tao: u64 =
-                Self::swap_alpha_for_tao(*netuid, root_emission_in_alpha.to_num::<u64>());
-            SubnetAlphaEmissionSell::<T>::insert(*netuid, root_emission_in_alpha.to_num::<u64>());
+            let root_emission_in_tao: u64 = Self::swap_alpha_for_tao(
+                *netuid,
+                root_emission_in_alpha.saturating_to_num::<u64>(),
+            );
+            SubnetAlphaEmissionSell::<T>::insert(
+                *netuid,
+                root_emission_in_alpha.saturating_to_num::<u64>(),
+            );
             // Accumulate root divs for subnet.
             PendingRootDivs::<T>::mutate(*netuid, |total| {
                 *total = total.saturating_add(root_emission_in_tao);
             });
             // Accumulate alpha that was swapped for the pending root divs.
             PendingAlphaSwapped::<T>::mutate(*netuid, |total| {
-                *total = total.saturating_add(root_emission_in_alpha.to_num::<u64>());
+                *total = total.saturating_add(root_emission_in_alpha.saturating_to_num::<u64>());
             });
             // Accumulate alpha emission in pending.
             PendingEmission::<T>::mutate(*netuid, |total| {
-                *total = total.saturating_add(pending_alpha_emission.to_num::<u64>());
+                *total = total.saturating_add(pending_alpha_emission.saturating_to_num::<u64>());
             });
             // Accumulate the owner cut in pending.
             PendingOwnerCut::<T>::mutate(*netuid, |total| {
@@ -413,14 +418,14 @@ impl<T: Config> Pallet<T> {
                 // Store the root-alpha divs under hotkey_j
                 root_alpha_divs
                     .entry(hotkey_j.clone())
-                    .and_modify(|e| *e = e.saturating_add(root_divs.to_num::<u64>()))
-                    .or_insert(root_divs.to_num::<u64>());
+                    .and_modify(|e| *e = e.saturating_add(root_divs.saturating_to_num::<u64>()))
+                    .or_insert(root_divs.saturating_to_num::<u64>());
                 total_root_alpha_divs =
-                    total_root_alpha_divs.saturating_add(root_divs.to_num::<u64>());
+                    total_root_alpha_divs.saturating_add(root_divs.saturating_to_num::<u64>());
                 log::debug!(
                     "Stored root alpha dividends for hotkey {:?}: {:?}",
                     hotkey_j,
-                    root_divs.to_num::<u64>()
+                    root_divs.saturating_to_num::<u64>()
                 );
             }
         }
@@ -478,26 +483,26 @@ impl<T: Config> Pallet<T> {
                     hotkey_j,
                     &Owner::<T>::get(hotkey_j.clone()),
                     netuid,
-                    validator_take.to_num::<u64>(),
+                    validator_take.saturating_to_num::<u64>(),
                 );
                 log::debug!(
                     "Distributed validator take for hotkey {:?} on netuid {:?}: {:?}",
                     hotkey_j,
                     netuid,
-                    validator_take.to_num::<u64>()
+                    validator_take.saturating_to_num::<u64>()
                 );
 
                 // Distribute the alpha divs to the hotkey.
                 Self::increase_stake_for_hotkey_on_subnet(
                     hotkey_j,
                     netuid,
-                    rem_divs_j.to_num::<u64>(),
+                    rem_divs_j.saturating_to_num::<u64>(),
                 );
                 log::debug!(
                     "Distributed alpha dividends for hotkey {:?} on netuid {:?}: {:?}",
                     hotkey_j,
                     netuid,
-                    rem_divs_j.to_num::<u64>()
+                    rem_divs_j.saturating_to_num::<u64>()
                 );
 
                 // Record dividends for this hotkey on this subnet.
@@ -522,7 +527,7 @@ impl<T: Config> Pallet<T> {
                 .unwrap_or(I96F32::from_num(0));
             let root_divs_to_pay: u64 = proportion
                 .saturating_mul(I96F32::from_num(pending_root_divs))
-                .to_num::<u64>();
+                .saturating_to_num::<u64>();
             log::debug!(
                 "Proportion for hotkey {:?}: {:?}, root_divs_to_pay: {:?}",
                 hotkey_j,
@@ -581,7 +586,7 @@ impl<T: Config> Pallet<T> {
         let combined_contribution: I96F32 = alpha_contribution.saturating_add(root_contribution);
 
         // Return the combined contribution as a u64
-        combined_contribution.to_num::<u64>()
+        combined_contribution.saturating_to_num::<u64>()
     }
 
     /// Returns a list of tuples for each parent associated with this hotkey including self
@@ -695,7 +700,7 @@ impl<T: Config> Pallet<T> {
                 .checked_div(total_contribution)
                 .unwrap_or(I96F32::from_num(0));
             let parent_emission: u64 =
-                (remaining_emission.saturating_mul(emission_factor)).to_num::<u64>();
+                (remaining_emission.saturating_mul(emission_factor)).saturating_to_num::<u64>();
 
             // Add the parent's emission to the distribution list
             dividend_tuples.push((parent, parent_emission));
@@ -707,7 +712,7 @@ impl<T: Config> Pallet<T> {
         // This includes the take left from the parents and the self contribution.
         let child_emission = remaining_emission
             .saturating_add(child_emission_take)
-            .to_num::<u64>()
+            .saturating_to_num::<u64>()
             .saturating_sub(to_parents);
 
         // Add the hotkey's own emission to the distribution list
diff --git a/pallets/subtensor/src/epoch/math.rs b/pallets/subtensor/src/epoch/math.rs
index 926375446..e57d63b3a 100644
--- a/pallets/subtensor/src/epoch/math.rs
+++ b/pallets/subtensor/src/epoch/math.rs
@@ -3,12 +3,13 @@
 use crate::alloc::borrow::ToOwned;
 #[allow(unused)]
 use num_traits::float::Float;
+use safe_math::*;
 use sp_runtime::traits::{CheckedAdd, Saturating};
 use sp_std::cmp::Ordering;
 
 use sp_std::vec;
 use substrate_fixed::transcendental::{exp, ln};
-use substrate_fixed::types::{I110F18, I32F32, I64F64, I96F32, U64F64};
+use substrate_fixed::types::{I32F32, I64F64};
 
 // TODO: figure out what cfg gate this needs to not be a warning in rustc
 #[allow(unused)]
@@ -21,17 +22,17 @@ pub fn fixed(val: f32) -> I32F32 {
 
 #[allow(dead_code)]
 pub fn fixed_to_u16(x: I32F32) -> u16 {
-    x.to_num::<u16>()
+    x.saturating_to_num::<u16>()
 }
 
 #[allow(dead_code)]
 pub fn fixed_to_u64(x: I32F32) -> u64 {
-    x.to_num::<u64>()
+    x.saturating_to_num::<u64>()
 }
 
 #[allow(dead_code)]
 pub fn fixed64_to_u64(x: I64F64) -> u64 {
-    x.to_num::<u64>()
+    x.saturating_to_num::<u64>()
 }
 
 #[allow(dead_code)]
@@ -100,7 +101,7 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
             if *val == I32F32::from_num(0) {
                 return vec
                     .iter()
-                    .map(|e: &I32F32| e.saturating_mul(u16_max).to_num::<u16>())
+                    .map(|e: &I32F32| e.saturating_mul(u16_max).saturating_to_num::<u16>())
                     .collect();
             }
             if *val > threshold {
@@ -109,7 +110,7 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
                     .map(|e: &I32F32| {
                         e.saturating_mul(u16_max.safe_div(*val))
                             .round()
-                            .to_num::<u16>()
+                            .saturating_to_num::<u16>()
                     })
                     .collect();
             }
@@ -118,14 +119,18 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
                     e.saturating_mul(u16_max)
                         .safe_div(*val)
                         .round()
-                        .to_num::<u16>()
+                        .saturating_to_num::<u16>()
                 })
                 .collect()
         }
         None => {
             let sum: I32F32 = vec.iter().sum();
             vec.iter()
-                .map(|e: &I32F32| e.saturating_mul(u16_max).safe_div(sum).to_num::<u16>())
+                .map(|e: &I32F32| {
+                    e.saturating_mul(u16_max)
+                        .safe_div(sum)
+                        .saturating_to_num::<u16>()
+                })
                 .collect()
         }
     }
@@ -1406,48 +1411,3 @@ pub fn safe_ln(value: I32F32) -> I32F32 {
 pub fn safe_exp(value: I32F32) -> I32F32 {
     exp(value).unwrap_or(I32F32::from_num(0.0))
 }
-
-/// Safe division trait
-pub trait SafeDiv {
-    /// Safe division that returns supplied default value for division by zero
-    fn safe_div_or(self, rhs: Self, def: Self) -> Self;
-    /// Safe division that returns default value for division by zero
-    fn safe_div(self, rhs: Self) -> Self;
-}
-
-/// Implementation of safe division trait for primitive types
-macro_rules! impl_safe_div_for_primitive {
-    ($($t:ty),*) => {
-        $(
-            impl SafeDiv for $t {
-                fn safe_div_or(self, rhs: Self, def: Self) -> Self {
-                    self.checked_div(rhs).unwrap_or(def)
-                }
-
-                fn safe_div(self, rhs: Self) -> Self {
-                    self.checked_div(rhs).unwrap_or_default()
-                }
-            }
-        )*
-    };
-}
-impl_safe_div_for_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, usize);
-
-/// Implementation of safe division trait for substrate fixed types
-macro_rules! impl_safe_div_for_fixed {
-    ($($t:ty),*) => {
-        $(
-            impl SafeDiv for $t {
-                fn safe_div_or(self, rhs: Self, def: Self) -> Self {
-                    self.checked_div(rhs).unwrap_or(def)
-                }
-
-                fn safe_div(self, rhs: Self) -> Self {
-                    self.checked_div(rhs).unwrap_or_default()
-                }
-            }
-        )*
-    };
-}
-
-impl_safe_div_for_fixed!(I96F32, I32F32, I64F64, I110F18, U64F64);
diff --git a/pallets/subtensor/src/epoch/run_epoch.rs b/pallets/subtensor/src/epoch/run_epoch.rs
index 9b3023818..4e9f36e4e 100644
--- a/pallets/subtensor/src/epoch/run_epoch.rs
+++ b/pallets/subtensor/src/epoch/run_epoch.rs
@@ -1,6 +1,7 @@
 use super::*;
 use crate::epoch::math::*;
 use frame_support::IterableStorageDoubleMap;
+use safe_math::*;
 use sp_std::vec;
 use substrate_fixed::types::{I32F32, I64F64, I96F32};
 
@@ -238,7 +239,7 @@ impl<T: Config> Pallet<T> {
             .collect();
         let server_emission: Vec<u64> = server_emission
             .iter()
-            .map(|e: &I96F32| e.to_num::<u64>())
+            .map(|e: &I96F32| e.saturating_to_num::<u64>())
             .collect();
 
         let validator_emission: Vec<I96F32> = normalized_validator_emission
@@ -247,7 +248,7 @@ impl<T: Config> Pallet<T> {
             .collect();
         let validator_emission: Vec<u64> = validator_emission
             .iter()
-            .map(|e: &I96F32| e.to_num::<u64>())
+            .map(|e: &I96F32| e.saturating_to_num::<u64>())
             .collect();
 
         // Used only to track combined emission in the storage.
@@ -257,7 +258,7 @@ impl<T: Config> Pallet<T> {
             .collect();
         let combined_emission: Vec<u64> = combined_emission
             .iter()
-            .map(|e: &I96F32| e.to_num::<u64>())
+            .map(|e: &I96F32| e.saturating_to_num::<u64>())
             .collect();
 
         log::trace!("nSE: {:?}", &normalized_server_emission);
@@ -609,7 +610,7 @@ impl<T: Config> Pallet<T> {
             .collect();
         let server_emission: Vec<u64> = server_emission
             .iter()
-            .map(|e: &I96F32| e.to_num::<u64>())
+            .map(|e: &I96F32| e.saturating_to_num::<u64>())
             .collect();
 
         let validator_emission: Vec<I96F32> = normalized_validator_emission
@@ -618,7 +619,7 @@ impl<T: Config> Pallet<T> {
             .collect();
         let validator_emission: Vec<u64> = validator_emission
             .iter()
-            .map(|e: &I96F32| e.to_num::<u64>())
+            .map(|e: &I96F32| e.saturating_to_num::<u64>())
             .collect();
 
         // Only used to track emission in storage.
@@ -628,7 +629,7 @@ impl<T: Config> Pallet<T> {
             .collect();
         let combined_emission: Vec<u64> = combined_emission
             .iter()
-            .map(|e: &I96F32| e.to_num::<u64>())
+            .map(|e: &I96F32| e.saturating_to_num::<u64>())
             .collect();
 
         log::trace!(
diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs
index ec8d48110..0f79ab2eb 100644
--- a/pallets/subtensor/src/rpc_info/delegate_info.rs
+++ b/pallets/subtensor/src/rpc_info/delegate_info.rs
@@ -1,8 +1,8 @@
 use super::*;
-use crate::epoch::math::*;
 use frame_support::pallet_prelude::{Decode, Encode};
 use frame_support::storage::IterableStorageMap;
 use frame_support::IterableStorageDoubleMap;
+use safe_math::*;
 use substrate_fixed::types::U64F64;
 extern crate alloc;
 use codec::Compact;
@@ -102,8 +102,8 @@ impl<T: Config> Pallet<T> {
             owner_ss58: owner.clone(),
             registrations: registrations.iter().map(|x| x.into()).collect(),
             validator_permits,
-            return_per_1000: U64F64::to_num::<u64>(return_per_1000).into(),
-            total_daily_return: U64F64::to_num::<u64>(emissions_per_day).into(),
+            return_per_1000: return_per_1000.saturating_to_num::<u64>().into(),
+            total_daily_return: emissions_per_day.saturating_to_num::<u64>().into(),
         }
     }
 
diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs
index 1a1a2d00d..5bb10e0bb 100644
--- a/pallets/subtensor/src/staking/helpers.rs
+++ b/pallets/subtensor/src/staking/helpers.rs
@@ -49,7 +49,7 @@ impl<T: Config> Pallet<T> {
                 let alpha: I96F32 =
                     I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, *netuid));
                 let tao_price: I96F32 = Self::get_alpha_price(*netuid);
-                alpha.saturating_mul(tao_price).to_num::<u64>()
+                alpha.saturating_mul(tao_price).saturating_to_num::<u64>()
             })
             .sum()
     }
@@ -67,7 +67,7 @@ impl<T: Config> Pallet<T> {
                     total_stake = total_stake.saturating_add(
                         I96F32::from_num(alpha)
                             .saturating_mul(tao_price)
-                            .to_num::<u64>(),
+                            .saturating_to_num::<u64>(),
                     );
                 }
                 total_stake
diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs
index 88dd1463f..75f933135 100644
--- a/pallets/subtensor/src/staking/move_stake.rs
+++ b/pallets/subtensor/src/staking/move_stake.rs
@@ -1,5 +1,5 @@
 use super::*;
-use crate::epoch::math::*;
+use safe_math::*;
 use sp_core::Get;
 
 impl<T: Config> Pallet<T> {
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index bb30b5c34..482b7c163 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -1,5 +1,5 @@
 use super::*;
-use crate::epoch::math::*;
+use safe_math::*;
 use share_pool::{SharePool, SharePoolDataOperations};
 use sp_std::ops::Neg;
 use substrate_fixed::types::{I64F64, I96F32, U64F64};
@@ -208,7 +208,7 @@ impl<T: Config> Pallet<T> {
             initial_alpha
         );
         if netuid == 0 {
-            return initial_alpha.to_num::<u64>();
+            return initial_alpha.saturating_to_num::<u64>();
         }
 
         // Initialize variables to track alpha allocated to children and inherited from parents.
@@ -299,7 +299,7 @@ impl<T: Config> Pallet<T> {
         );
 
         // Step 6: Return the final inherited alpha value.
-        finalized_alpha.to_num::<u64>()
+        finalized_alpha.saturating_to_num::<u64>()
     }
 
     /// Checks if a specific hotkey-coldkey pair has enough stake on a subnet to fulfill a given decrement.
@@ -476,7 +476,7 @@ impl<T: Config> Pallet<T> {
             I96F32::from_num(tao)
         };
         // Return simulated amount.
-        alpha.to_num::<u64>()
+        alpha.saturating_to_num::<u64>()
     }
 
     /// Swaps a subnet's Alpba token for TAO.
@@ -502,7 +502,7 @@ impl<T: Config> Pallet<T> {
             // Step 3.b.1: Stable mechanism, just return the value 1:1
             I96F32::from_num(alpha)
         };
-        tao.to_num::<u64>()
+        tao.saturating_to_num::<u64>()
     }
 
     /// Swaps TAO for the alpha token on the subnet.
@@ -530,11 +530,11 @@ impl<T: Config> Pallet<T> {
         };
         // Step 4. Decrease Alpha reserves.
         SubnetAlphaIn::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(alpha.to_num::<u64>());
+            *total = total.saturating_sub(alpha.saturating_to_num::<u64>());
         });
         // Step 5: Increase Alpha outstanding.
         SubnetAlphaOut::<T>::mutate(netuid, |total| {
-            *total = total.saturating_add(alpha.to_num::<u64>());
+            *total = total.saturating_add(alpha.saturating_to_num::<u64>());
         });
         // Step 6: Increase Tao reserves.
         SubnetTAO::<T>::mutate(netuid, |total| {
@@ -549,7 +549,7 @@ impl<T: Config> Pallet<T> {
             *total = total.saturating_sub(tao);
         });
         // Step 9. Return the alpha received.
-        alpha.to_num::<u64>()
+        alpha.saturating_to_num::<u64>()
     }
 
     /// Swaps a subnet's Alpba token for TAO.
@@ -585,18 +585,18 @@ impl<T: Config> Pallet<T> {
         });
         // Step 6: Decrease tao reserves.
         SubnetTAO::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(tao.to_num::<u64>());
+            *total = total.saturating_sub(tao.saturating_to_num::<u64>());
         });
         // Step 7: Reduce total TAO reserves.
         TotalStake::<T>::mutate(|total| {
-            *total = total.saturating_sub(tao.to_num::<u64>());
+            *total = total.saturating_sub(tao.saturating_to_num::<u64>());
         });
         // Step 8. Decrease Alpha reserves.
         SubnetVolume::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(tao.to_num::<u64>());
+            *total = total.saturating_sub(tao.saturating_to_num::<u64>());
         });
         // Step 9. Return the tao received.
-        tao.to_num::<u64>()
+        tao.saturating_to_num::<u64>()
     }
 
     /// Unstakes alpha from a subnet for a given hotkey and coldkey pair.
@@ -891,7 +891,7 @@ impl<T: Config> SharePoolDataOperations<AlphaShareKey<T>>
             crate::TotalHotkeyAlpha::<T>::insert(
                 &(self.hotkey),
                 self.netuid,
-                value.to_num::<u64>(),
+                value.saturating_to_num::<u64>(),
             );
         } else {
             crate::TotalHotkeyAlpha::<T>::remove(&(self.hotkey), self.netuid);
diff --git a/pallets/subtensor/src/subnets/weights.rs b/pallets/subtensor/src/subnets/weights.rs
index 13fa0dafc..ad868c52d 100644
--- a/pallets/subtensor/src/subnets/weights.rs
+++ b/pallets/subtensor/src/subnets/weights.rs
@@ -1,6 +1,7 @@
 use super::*;
 use crate::epoch::math::*;
 use codec::Compact;
+use safe_math::*;
 use sp_core::{ConstU32, H256};
 use sp_runtime::{
     traits::{BlakeTwo256, Hash},
diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs
index 7a3780c0b..f10e75603 100644
--- a/pallets/subtensor/src/tests/children.rs
+++ b/pallets/subtensor/src/tests/children.rs
@@ -3357,7 +3357,7 @@ fn test_parent_child_chain_emission() {
         let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
         let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
             netuid,
-            total_tao.saturating_to_num::<u64>(),
+            total_tao.to_num::<u64>(),
         ));
 
         // Set the stakes directly
diff --git a/pallets/subtensor/src/tests/delegate_info.rs b/pallets/subtensor/src/tests/delegate_info.rs
index 78ea48482..0dcb69d78 100644
--- a/pallets/subtensor/src/tests/delegate_info.rs
+++ b/pallets/subtensor/src/tests/delegate_info.rs
@@ -6,7 +6,7 @@ use super::mock::*;
 #[test]
 fn test_return_per_1000_tao() {
     let take = // 18% take to the Validator
-        Compact::<u16>::from((U64F64::from_num(0.18 * u16::MAX as f64)).saturating_to_num::<u16>());
+        Compact::<u16>::from((U64F64::from_num(0.18 * u16::MAX as f64)).to_num::<u16>());
 
     // 10_000 TAO total validator stake
     let total_stake = U64F64::from_num(10_000.0 * 1e9);
diff --git a/pallets/subtensor/src/tests/math.rs b/pallets/subtensor/src/tests/math.rs
index 84fcc4aac..7409ed8eb 100644
--- a/pallets/subtensor/src/tests/math.rs
+++ b/pallets/subtensor/src/tests/math.rs
@@ -2264,16 +2264,17 @@ fn test_math_fixed_to_u64() {
 }
 
 #[test]
-#[should_panic(expected = "-1 overflows")]
-fn test_math_fixed_to_u64_panics() {
+fn test_math_fixed_to_u64_saturates() {
     let bad_input = I32F32::from_num(-1);
-    fixed_to_u64(bad_input);
+    let expected = 0;
+    assert_eq!(fixed_to_u64(bad_input), expected);
 }
 
 #[test]
 fn test_math_fixed64_to_u64() {
     let expected = u64::MIN;
-    assert_eq!(fixed64_to_u64(I64F64::from_num(expected)), expected);
+    let input = I64F64::from_num(expected);
+    assert_eq!(fixed64_to_u64(input), expected);
 
     let input = i64::MAX / 2;
     let expected = u64::try_from(input).unwrap();
@@ -2285,10 +2286,10 @@ fn test_math_fixed64_to_u64() {
 }
 
 #[test]
-#[should_panic(expected = "-1 overflows")]
-fn test_math_fixed64_to_u64_panics() {
+fn test_math_fixed64_to_u64_saturates() {
     let bad_input = I64F64::from_num(-1);
-    fixed64_to_u64(bad_input);
+    let expected = 0;
+    assert_eq!(fixed64_to_u64(bad_input), expected);
 }
 
 /* @TODO: find the _true_ max, and half, input values */
@@ -2340,14 +2341,15 @@ fn test_fixed_proportion_to_u16() {
 }
 
 #[test]
-#[should_panic(expected = "overflow")]
-fn test_fixed_proportion_to_u16_panics() {
+fn test_fixed_proportion_to_u16_saturates() {
     let expected = u16::MAX;
     let input = I32F32::from_num(expected);
     log::trace!("Testing with input: {:?}", input); // Debug output
     let result = fixed_proportion_to_u16(input);
     log::trace!("Testing with result: {:?}", result); // Debug output
+    assert_eq!(result, expected);
 }
+
 #[test]
 fn test_vec_fixed64_to_fixed32() {
     let input = vec![I64F64::from_num(i32::MIN)];
diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs
index e211a2485..4749d6594 100644
--- a/pallets/subtensor/src/utils/misc.rs
+++ b/pallets/subtensor/src/utils/misc.rs
@@ -1,9 +1,9 @@
 use super::*;
 use crate::{
-    epoch::math::*,
     system::{ensure_root, ensure_signed_or_root, pallet_prelude::BlockNumberFor},
     Error,
 };
+use safe_math::*;
 use sp_core::Get;
 use sp_core::U256;
 use sp_runtime::Saturating;
diff --git a/primitives/safe-math/Cargo.toml b/primitives/safe-math/Cargo.toml
new file mode 100644
index 000000000..f50ac6b90
--- /dev/null
+++ b/primitives/safe-math/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "safe-math"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+substrate-fixed = { workspace = true }
+sp-std = { workspace = true }
+num-traits = { version = "0.2.19", default-features = false, features = ["libm"] }
+
+[lints]
+workspace = true
+
+[features]
+default = ["std"]
+std = [
+	"substrate-fixed/std",
+	"sp-std/std",
+]
diff --git a/primitives/safe-math/src/lib.rs b/primitives/safe-math/src/lib.rs
new file mode 100644
index 000000000..83c27b07c
--- /dev/null
+++ b/primitives/safe-math/src/lib.rs
@@ -0,0 +1,71 @@
+#![cfg_attr(not(feature = "std"), no_std)]
+#![allow(clippy::result_unit_err)]
+
+use substrate_fixed::types::{I110F18, I32F32, I64F64, I96F32, U64F64};
+
+/// Safe division trait
+pub trait SafeDiv {
+    /// Safe division that returns supplied default value for division by zero
+    fn safe_div_or(self, rhs: Self, def: Self) -> Self;
+    /// Safe division that returns default value for division by zero
+    fn safe_div(self, rhs: Self) -> Self;
+}
+
+/// Implementation of safe division trait for primitive types
+macro_rules! impl_safe_div_for_primitive {
+    ($($t:ty),*) => {
+        $(
+            impl SafeDiv for $t {
+                fn safe_div_or(self, rhs: Self, def: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or(def)
+                }
+
+                fn safe_div(self, rhs: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or_default()
+                }
+            }
+        )*
+    };
+}
+impl_safe_div_for_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, usize);
+
+/// Implementation of safe division trait for substrate fixed types
+macro_rules! impl_safe_div_for_fixed {
+    ($($t:ty),*) => {
+        $(
+            impl SafeDiv for $t {
+                fn safe_div_or(self, rhs: Self, def: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or(def)
+                }
+
+                fn safe_div(self, rhs: Self) -> Self {
+                    self.checked_div(rhs).unwrap_or_default()
+                }
+            }
+        )*
+    };
+}
+impl_safe_div_for_fixed!(I96F32, I32F32, I64F64, I110F18, U64F64);
+
+// /// Trait for safe conversion to primitive type P
+// pub trait SafeToNum<T> {
+//     /// Safe conversion to primitive type P
+//     fn safe_to_num<P>(self) -> P
+//     where
+//         P: num_traits::Bounded + substrate_fixed::prelude::ToFixed + substrate_fixed::prelude::FromFixed;
+// }
+
+// impl<T> SafeToNum<T> for T
+// where
+//     T: substrate_fixed::traits::Fixed,
+// {
+//     fn safe_to_num<P>(self) -> P
+//     where
+//         P: num_traits::Bounded + substrate_fixed::prelude::ToFixed + substrate_fixed::prelude::FromFixed
+//     {
+//         match self.try_into() {
+//             Ok(value) => value,
+//             Err(_) => P::max_value(),
+//         }
+//     }
+// }
diff --git a/primitives/share-pool/Cargo.toml b/primitives/share-pool/Cargo.toml
index 219123269..370f32cbb 100644
--- a/primitives/share-pool/Cargo.toml
+++ b/primitives/share-pool/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 substrate-fixed = { workspace = true }
 sp-std = { workspace = true }
+safe-math = { default-features = false, path = "../safe-math" }
 
 [lints]
 workspace = true
diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs
index 2f4d25ef9..8af506945 100644
--- a/primitives/share-pool/src/lib.rs
+++ b/primitives/share-pool/src/lib.rs
@@ -54,7 +54,7 @@ where
             .checked_div(denominator)
             .unwrap_or(U64F64::from_num(0))
             .saturating_mul(current_share)
-            .to_num::<u64>()
+            .saturating_to_num::<u64>()
     }
 
     pub fn try_get_value(&self, key: &K) -> Result<u64, ()> {

From 46f02950142f469bba8c69fbf40bf53a7133cb95 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 14:46:39 -0500
Subject: [PATCH 095/145] Avoid using from_num

---
 .../subtensor/src/coinbase/block_emission.rs  |  40 ++--
 pallets/subtensor/src/coinbase/block_step.rs  |  39 ++--
 pallets/subtensor/src/coinbase/root.rs        |   4 +-
 .../subtensor/src/coinbase/run_coinbase.rs    | 131 +++++++------
 pallets/subtensor/src/epoch/math.rs           | 175 ++++++++++--------
 pallets/subtensor/src/epoch/run_epoch.rs      |  79 ++++----
 pallets/subtensor/src/lib.rs                  |   2 +-
 pallets/subtensor/src/macros/genesis.rs       |   4 +-
 .../subtensor/src/migrations/migrate_rao.rs   |   4 +-
 .../subtensor/src/rpc_info/delegate_info.rs   |  16 +-
 pallets/subtensor/src/staking/helpers.rs      |   7 +-
 pallets/subtensor/src/staking/stake_utils.rs  | 103 ++++++-----
 pallets/subtensor/src/tests/math.rs           |  10 +-
 pallets/subtensor/src/utils/misc.rs           |   9 +-
 primitives/share-pool/src/lib.rs              |  64 ++++---
 15 files changed, 377 insertions(+), 310 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/block_emission.rs b/pallets/subtensor/src/coinbase/block_emission.rs
index 9ea99120d..af9f8dd51 100644
--- a/pallets/subtensor/src/coinbase/block_emission.rs
+++ b/pallets/subtensor/src/coinbase/block_emission.rs
@@ -31,15 +31,15 @@ impl<T: Config> Pallet<T> {
         alpha_block_emission: u64,
     ) -> (u64, u64, u64) {
         // Init terms.
-        let mut tao_in_emission: I96F32 = I96F32::from_num(tao_emission);
-        let float_alpha_block_emission: I96F32 = I96F32::from_num(alpha_block_emission);
+        let mut tao_in_emission: I96F32 = I96F32::saturating_from_num(tao_emission);
+        let float_alpha_block_emission: I96F32 = I96F32::saturating_from_num(alpha_block_emission);
 
         // Get alpha price for subnet.
         let alpha_price: I96F32 = Self::get_alpha_price(netuid);
         log::debug!("{:?} - alpha_price: {:?}", netuid, alpha_price);
 
         // Get initial alpha_in
-        let mut alpha_in_emission: I96F32 = I96F32::from_num(tao_emission)
+        let mut alpha_in_emission: I96F32 = I96F32::saturating_from_num(tao_emission)
             .checked_div(alpha_price)
             .unwrap_or(float_alpha_block_emission);
 
@@ -60,13 +60,15 @@ impl<T: Config> Pallet<T> {
         }
 
         // Avoid rounding errors.
-        if tao_in_emission < I96F32::from_num(1) || alpha_in_emission < I96F32::from_num(1) {
-            alpha_in_emission = I96F32::from_num(0);
-            tao_in_emission = I96F32::from_num(0);
+        if tao_in_emission < I96F32::saturating_from_num(1)
+            || alpha_in_emission < I96F32::saturating_from_num(1)
+        {
+            alpha_in_emission = I96F32::saturating_from_num(0);
+            tao_in_emission = I96F32::saturating_from_num(0);
         }
 
         // Set Alpha in emission.
-        let alpha_out_emission = I96F32::from_num(2)
+        let alpha_out_emission = I96F32::saturating_from_num(2)
             .saturating_mul(float_alpha_block_emission)
             .saturating_sub(alpha_in_emission);
 
@@ -106,23 +108,22 @@ impl<T: Config> Pallet<T> {
     /// Returns the block emission for an issuance value.
     pub fn get_block_emission_for_issuance(issuance: u64) -> Result<u64, &'static str> {
         // Convert issuance to a float for calculations below.
-        let total_issuance: I96F32 = I96F32::from_num(issuance);
+        let total_issuance: I96F32 = I96F32::saturating_from_num(issuance);
         // Check to prevent division by zero when the total supply is reached
         // and creating an issuance greater than the total supply.
-        if total_issuance >= I96F32::from_num(TotalSupply::<T>::get()) {
+        if total_issuance >= I96F32::saturating_from_num(TotalSupply::<T>::get()) {
             return Ok(0);
         }
         // Calculate the logarithmic residual of the issuance against half the total supply.
         let residual: I96F32 = log2(
-            I96F32::from_num(1.0)
+            I96F32::saturating_from_num(1.0)
                 .checked_div(
-                    I96F32::from_num(1.0)
+                    I96F32::saturating_from_num(1.0)
                         .checked_sub(
                             total_issuance
-                                .checked_div(
-                                    I96F32::from_num(2.0)
-                                        .saturating_mul(I96F32::from_num(10_500_000_000_000_000.0)),
-                                )
+                                .checked_div(I96F32::saturating_from_num(2.0).saturating_mul(
+                                    I96F32::saturating_from_num(10_500_000_000_000_000.0),
+                                ))
                                 .ok_or("Logarithm calculation failed")?,
                         )
                         .ok_or("Logarithm calculation failed")?,
@@ -136,14 +137,15 @@ impl<T: Config> Pallet<T> {
         // Convert floored_residual to an integer
         let floored_residual_int: u64 = floored_residual.saturating_to_num::<u64>();
         // Multiply 2.0 by itself floored_residual times to calculate the power of 2.
-        let mut multiplier: I96F32 = I96F32::from_num(1.0);
+        let mut multiplier: I96F32 = I96F32::saturating_from_num(1.0);
         for _ in 0..floored_residual_int {
-            multiplier = multiplier.saturating_mul(I96F32::from_num(2.0));
+            multiplier = multiplier.saturating_mul(I96F32::saturating_from_num(2.0));
         }
-        let block_emission_percentage: I96F32 = I96F32::from_num(1.0).safe_div(multiplier);
+        let block_emission_percentage: I96F32 =
+            I96F32::saturating_from_num(1.0).safe_div(multiplier);
         // Calculate the actual emission based on the emission rate
         let block_emission: I96F32 = block_emission_percentage
-            .saturating_mul(I96F32::from_num(DefaultBlockEmission::<T>::get()));
+            .saturating_mul(I96F32::saturating_from_num(DefaultBlockEmission::<T>::get()));
         // Convert to u64
         let block_emission_u64: u64 = block_emission.saturating_to_num::<u64>();
         if BlockEmission::<T>::get() != block_emission_u64 {
diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs
index b8b27ae73..bcfd1a37b 100644
--- a/pallets/subtensor/src/coinbase/block_step.rs
+++ b/pallets/subtensor/src/coinbase/block_step.rs
@@ -11,7 +11,8 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
         // --- 1. Adjust difficulties.
         Self::adjust_registration_terms_for_networks();
         // --- 2. Get the current coinbase emission.
-        let block_emission: I96F32 = I96F32::from_num(Self::get_block_emission().unwrap_or(0));
+        let block_emission: I96F32 =
+            I96F32::saturating_from_num(Self::get_block_emission().unwrap_or(0));
         log::debug!("Block emission: {:?}", block_emission);
         // --- 3. Run emission through network.
         Self::run_coinbase(block_emission);
@@ -199,25 +200,25 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
         registrations_this_interval: u16,
         target_registrations_per_interval: u16,
     ) -> u64 {
-        let updated_difficulty: I110F18 = I110F18::from_num(current_difficulty)
-            .saturating_mul(I110F18::from_num(
+        let updated_difficulty: I110F18 = I110F18::saturating_from_num(current_difficulty)
+            .saturating_mul(I110F18::saturating_from_num(
                 registrations_this_interval.saturating_add(target_registrations_per_interval),
             ))
-            .safe_div(I110F18::from_num(
+            .safe_div(I110F18::saturating_from_num(
                 target_registrations_per_interval.saturating_add(target_registrations_per_interval),
             ));
-        let alpha: I110F18 = I110F18::from_num(Self::get_adjustment_alpha(netuid))
-            .safe_div(I110F18::from_num(u64::MAX));
+        let alpha: I110F18 = I110F18::saturating_from_num(Self::get_adjustment_alpha(netuid))
+            .safe_div(I110F18::saturating_from_num(u64::MAX));
         let next_value: I110F18 = alpha
-            .saturating_mul(I110F18::from_num(current_difficulty))
+            .saturating_mul(I110F18::saturating_from_num(current_difficulty))
             .saturating_add(
-                I110F18::from_num(1.0)
+                I110F18::saturating_from_num(1.0)
                     .saturating_sub(alpha)
                     .saturating_mul(updated_difficulty),
             );
-        if next_value >= I110F18::from_num(Self::get_max_difficulty(netuid)) {
+        if next_value >= I110F18::saturating_from_num(Self::get_max_difficulty(netuid)) {
             Self::get_max_difficulty(netuid)
-        } else if next_value <= I110F18::from_num(Self::get_min_difficulty(netuid)) {
+        } else if next_value <= I110F18::saturating_from_num(Self::get_min_difficulty(netuid)) {
             return Self::get_min_difficulty(netuid);
         } else {
             return next_value.saturating_to_num::<u64>();
@@ -233,25 +234,25 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
         registrations_this_interval: u16,
         target_registrations_per_interval: u16,
     ) -> u64 {
-        let updated_burn: I110F18 = I110F18::from_num(current_burn)
-            .saturating_mul(I110F18::from_num(
+        let updated_burn: I110F18 = I110F18::saturating_from_num(current_burn)
+            .saturating_mul(I110F18::saturating_from_num(
                 registrations_this_interval.saturating_add(target_registrations_per_interval),
             ))
-            .safe_div(I110F18::from_num(
+            .safe_div(I110F18::saturating_from_num(
                 target_registrations_per_interval.saturating_add(target_registrations_per_interval),
             ));
-        let alpha: I110F18 = I110F18::from_num(Self::get_adjustment_alpha(netuid))
-            .safe_div(I110F18::from_num(u64::MAX));
+        let alpha: I110F18 = I110F18::saturating_from_num(Self::get_adjustment_alpha(netuid))
+            .safe_div(I110F18::saturating_from_num(u64::MAX));
         let next_value: I110F18 = alpha
-            .saturating_mul(I110F18::from_num(current_burn))
+            .saturating_mul(I110F18::saturating_from_num(current_burn))
             .saturating_add(
-                I110F18::from_num(1.0)
+                I110F18::saturating_from_num(1.0)
                     .saturating_sub(alpha)
                     .saturating_mul(updated_burn),
             );
-        if next_value >= I110F18::from_num(Self::get_max_burn_as_u64(netuid)) {
+        if next_value >= I110F18::saturating_from_num(Self::get_max_burn_as_u64(netuid)) {
             Self::get_max_burn_as_u64(netuid)
-        } else if next_value <= I110F18::from_num(Self::get_min_burn_as_u64(netuid)) {
+        } else if next_value <= I110F18::saturating_from_num(Self::get_min_burn_as_u64(netuid)) {
             return Self::get_min_burn_as_u64(netuid);
         } else {
             return next_value.saturating_to_num::<u64>();
diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs
index 9e510fa0a..3f83f934f 100644
--- a/pallets/subtensor/src/coinbase/root.rs
+++ b/pallets/subtensor/src/coinbase/root.rs
@@ -113,7 +113,7 @@ impl<T: Config> Pallet<T> {
 
         // --- 2. Initialize a 2D vector with zeros to store the weights. The dimensions are determined
         // by `n` (number of validators) and `k` (total number of subnets).
-        let mut weights: Vec<Vec<I64F64>> = vec![vec![I64F64::from_num(0.0); k]; n];
+        let mut weights: Vec<Vec<I64F64>> = vec![vec![I64F64::saturating_from_num(0.0); k]; n];
         log::debug!("weights:\n{:?}\n", weights);
 
         let subnet_list = Self::get_all_subnet_netuids();
@@ -135,7 +135,7 @@ impl<T: Config> Pallet<T> {
                         .zip(&subnet_list)
                         .find(|(_, subnet)| *subnet == netuid)
                     {
-                        *w = I64F64::from_num(*weight_ij);
+                        *w = I64F64::saturating_from_num(*weight_ij);
                     }
                 }
             }
diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index cc15d7cbe..b9d959a2e 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -25,15 +25,16 @@ impl<T: Config> Pallet<T> {
         validator_proportion: I96F32,
     ) -> I96F32 {
         // Get total TAO on root.
-        let total_root_tao: I96F32 = I96F32::from_num(SubnetTAO::<T>::get(0));
+        let total_root_tao: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(0));
         // Get total ALPHA on subnet.
-        let total_alpha_issuance: I96F32 = I96F32::from_num(Self::get_alpha_issuance(netuid));
+        let total_alpha_issuance: I96F32 =
+            I96F32::saturating_from_num(Self::get_alpha_issuance(netuid));
         // Get tao_weight
         let tao_weight: I96F32 = total_root_tao.saturating_mul(Self::get_tao_weight());
         // Get root proportional dividends.
         let root_proportion: I96F32 = tao_weight
             .checked_div(tao_weight.saturating_add(total_alpha_issuance))
-            .unwrap_or(I96F32::from_num(0.0));
+            .unwrap_or(I96F32::saturating_from_num(0.0));
         // Get root proportion of alpha_out dividends.
         let root_divs_in_alpha: I96F32 = root_proportion
             .saturating_mul(alpha_out_emission)
@@ -54,17 +55,22 @@ impl<T: Config> Pallet<T> {
 
         // --- 2. Sum all the SubnetTAO associated with the same mechanism.
         // Mechanisms get emission based on the proportion of TAO across all their subnets
-        let mut total_active_tao: I96F32 = I96F32::from_num(0);
+        let mut total_active_tao: I96F32 = I96F32::saturating_from_num(0);
         let mut mechanism_tao: BTreeMap<u16, I96F32> = BTreeMap::new();
         for netuid in subnets.iter() {
             if *netuid == 0 {
                 continue;
             } // Skip root network
             let mechid = SubnetMechanism::<T>::get(*netuid);
-            let subnet_tao = I96F32::from_num(SubnetTAO::<T>::get(*netuid));
-            let new_subnet_tao = subnet_tao
-                .saturating_add(*mechanism_tao.entry(mechid).or_insert(I96F32::from_num(0)));
-            *mechanism_tao.entry(mechid).or_insert(I96F32::from_num(0)) = new_subnet_tao;
+            let subnet_tao = I96F32::saturating_from_num(SubnetTAO::<T>::get(*netuid));
+            let new_subnet_tao = subnet_tao.saturating_add(
+                *mechanism_tao
+                    .entry(mechid)
+                    .or_insert(I96F32::saturating_from_num(0)),
+            );
+            *mechanism_tao
+                .entry(mechid)
+                .or_insert(I96F32::saturating_from_num(0)) = new_subnet_tao;
             total_active_tao = total_active_tao.saturating_add(subnet_tao);
         }
         log::debug!("Mechanism TAO sums: {:?}", mechanism_tao);
@@ -80,10 +86,12 @@ impl<T: Config> Pallet<T> {
             let mechid: u16 = SubnetMechanism::<T>::get(*netuid);
             log::debug!("Netuid: {:?}, Mechanism ID: {:?}", netuid, mechid);
             // 3.2: Get subnet TAO (T_s)
-            let subnet_tao: I96F32 = I96F32::from_num(SubnetTAO::<T>::get(*netuid));
+            let subnet_tao: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(*netuid));
             log::debug!("Subnet TAO (T_s) for netuid {:?}: {:?}", netuid, subnet_tao);
             // 3.3: Get the denominator as the sum of all TAO associated with a specific mechanism (T_m)
-            let mech_tao: I96F32 = *mechanism_tao.get(&mechid).unwrap_or(&I96F32::from_num(0));
+            let mech_tao: I96F32 = *mechanism_tao
+                .get(&mechid)
+                .unwrap_or(&I96F32::saturating_from_num(0));
             log::debug!(
                 "Mechanism TAO (T_m) for mechanism ID {:?}: {:?}",
                 mechid,
@@ -92,7 +100,7 @@ impl<T: Config> Pallet<T> {
             // 3.4: Compute the mechanism emission proportion: P_m = T_m / T_total
             let mech_proportion: I96F32 = mech_tao
                 .checked_div(total_active_tao)
-                .unwrap_or(I96F32::from_num(0));
+                .unwrap_or(I96F32::saturating_from_num(0));
             log::debug!(
                 "Mechanism proportion (P_m) for mechanism ID {:?}: {:?}",
                 mechid,
@@ -108,7 +116,7 @@ impl<T: Config> Pallet<T> {
             // 3.6: Calculate subnet's proportion of mechanism TAO: P_s = T_s / T_m
             let subnet_proportion: I96F32 = subnet_tao
                 .checked_div(mech_tao)
-                .unwrap_or(I96F32::from_num(0));
+                .unwrap_or(I96F32::saturating_from_num(0));
             log::debug!(
                 "Subnet proportion (P_s) for netuid {:?}: {:?}",
                 netuid,
@@ -117,7 +125,7 @@ impl<T: Config> Pallet<T> {
             // 3.7: Calculate subnet's TAO emission: E_s = P_s * E_m
             let tao_in: u64 = mech_emission
                 .checked_mul(subnet_proportion)
-                .unwrap_or(I96F32::from_num(0))
+                .unwrap_or(I96F32::saturating_from_num(0))
                 .saturating_to_num::<u64>();
             log::debug!(
                 "Subnet TAO emission (E_s) for netuid {:?}: {:?}",
@@ -199,7 +207,7 @@ impl<T: Config> Pallet<T> {
             });
 
             // Calculate the owner cut.
-            let owner_cut: u64 = I96F32::from_num(alpha_out_emission)
+            let owner_cut: u64 = I96F32::saturating_from_num(alpha_out_emission)
                 .saturating_mul(Self::get_float_subnet_owner_cut())
                 .saturating_to_num::<u64>();
             log::debug!("Owner cut for netuid {:?}: {:?}", netuid, owner_cut);
@@ -214,16 +222,16 @@ impl<T: Config> Pallet<T> {
             );
 
             // Validators get 50% of remaining emission.
-            let validator_proportion: I96F32 = I96F32::from_num(0.5);
+            let validator_proportion: I96F32 = I96F32::saturating_from_num(0.5);
             // Get proportion of alpha out emission as root divs.
             let root_emission_in_alpha: I96F32 = Self::get_root_divs_in_alpha(
                 *netuid,
-                I96F32::from_num(remaining_emission),
+                I96F32::saturating_from_num(remaining_emission),
                 validator_proportion,
             );
             // Subtract root divs from alpha divs.
-            let pending_alpha_emission: I96F32 =
-                I96F32::from_num(remaining_emission).saturating_sub(root_emission_in_alpha);
+            let pending_alpha_emission: I96F32 = I96F32::saturating_from_num(remaining_emission)
+                .saturating_sub(root_emission_in_alpha);
             // Sell root emission through the pool.
             let root_emission_in_tao: u64 = Self::swap_alpha_for_tao(
                 *netuid,
@@ -363,22 +371,21 @@ impl<T: Config> Pallet<T> {
         // Calculate the validator take and root alpha divs using the alpha divs.
         for (hotkey, dividend_tuples) in dividends_to_distribute.iter() {
             // Get the local alpha and root alpha.
-            let hotkey_tao: I96F32 = I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(
-                hotkey,
-                Self::get_root_netuid(),
-            ));
+            let hotkey_tao: I96F32 = I96F32::saturating_from_num(
+                Self::get_stake_for_hotkey_on_subnet(hotkey, Self::get_root_netuid()),
+            );
             let hotkey_tao_as_alpha: I96F32 = hotkey_tao.saturating_mul(Self::get_tao_weight());
             let hotkey_alpha =
-                I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid));
+                I96F32::saturating_from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid));
             log::debug!("Hotkey tao for hotkey {:?} on root netuid: {:?}, hotkey tao as alpha: {:?}, hotkey alpha: {:?}", hotkey, hotkey_tao, hotkey_tao_as_alpha, hotkey_alpha);
 
             // Compute alpha and root proportions.
             let alpha_prop: I96F32 = hotkey_alpha
                 .checked_div(hotkey_alpha.saturating_add(hotkey_tao_as_alpha))
-                .unwrap_or(I96F32::from_num(0.0));
+                .unwrap_or(I96F32::saturating_from_num(0.0));
             let root_prop: I96F32 = hotkey_tao_as_alpha
                 .checked_div(hotkey_alpha.saturating_add(hotkey_tao_as_alpha))
-                .unwrap_or(I96F32::from_num(0.0));
+                .unwrap_or(I96F32::saturating_from_num(0.0));
             log::debug!(
                 "Alpha proportion: {:?}, root proportion: {:?}",
                 alpha_prop,
@@ -395,11 +402,14 @@ impl<T: Config> Pallet<T> {
                 );
 
                 // Remove the hotkey take straight off the top.
-                let take_prop: I96F32 = I96F32::from_num(Self::get_hotkey_take(hotkey_j))
-                    .checked_div(I96F32::from_num(u16::MAX))
-                    .unwrap_or(I96F32::from_num(0.0));
-                let validator_take: I96F32 = take_prop.saturating_mul(I96F32::from_num(*divs_j));
-                let rem_divs_j: I96F32 = I96F32::from_num(*divs_j).saturating_sub(validator_take);
+                let take_prop: I96F32 =
+                    I96F32::saturating_from_num(Self::get_hotkey_take(hotkey_j))
+                        .checked_div(I96F32::saturating_from_num(u16::MAX))
+                        .unwrap_or(I96F32::saturating_from_num(0.0));
+                let validator_take: I96F32 =
+                    take_prop.saturating_mul(I96F32::saturating_from_num(*divs_j));
+                let rem_divs_j: I96F32 =
+                    I96F32::saturating_from_num(*divs_j).saturating_sub(validator_take);
                 log::debug!(
                     "Validator take for hotkey {:?}: {:?}, remaining dividends: {:?}",
                     hotkey_j,
@@ -466,11 +476,14 @@ impl<T: Config> Pallet<T> {
             // Pay out dividends to hotkeys based on the local vs root proportion.
             for (hotkey_j, divs_j) in dividend_tuples.iter() {
                 // Remove the hotkey take straight off the top.
-                let take_prop: I96F32 = I96F32::from_num(Self::get_hotkey_take(hotkey_j))
-                    .checked_div(I96F32::from_num(u16::MAX))
-                    .unwrap_or(I96F32::from_num(0.0));
-                let validator_take: I96F32 = take_prop.saturating_mul(I96F32::from_num(*divs_j));
-                let rem_divs_j: I96F32 = I96F32::from_num(*divs_j).saturating_sub(validator_take);
+                let take_prop: I96F32 =
+                    I96F32::saturating_from_num(Self::get_hotkey_take(hotkey_j))
+                        .checked_div(I96F32::saturating_from_num(u16::MAX))
+                        .unwrap_or(I96F32::saturating_from_num(0.0));
+                let validator_take: I96F32 =
+                    take_prop.saturating_mul(I96F32::saturating_from_num(*divs_j));
+                let rem_divs_j: I96F32 =
+                    I96F32::saturating_from_num(*divs_j).saturating_sub(validator_take);
                 log::debug!(
                     "Validator take for hotkey {:?}: {:?}, remaining dividends: {:?}",
                     hotkey_j,
@@ -522,11 +535,11 @@ impl<T: Config> Pallet<T> {
         let _ = TaoDividendsPerSubnet::<T>::clear_prefix(netuid, u32::MAX, None);
 
         for (hotkey_j, root_divs) in root_alpha_divs.iter() {
-            let proportion: I96F32 = I96F32::from_num(*root_divs)
-                .checked_div(I96F32::from_num(total_root_alpha_divs))
-                .unwrap_or(I96F32::from_num(0));
+            let proportion: I96F32 = I96F32::saturating_from_num(*root_divs)
+                .checked_div(I96F32::saturating_from_num(total_root_alpha_divs))
+                .unwrap_or(I96F32::saturating_from_num(0));
             let root_divs_to_pay: u64 = proportion
-                .saturating_mul(I96F32::from_num(pending_root_divs))
+                .saturating_mul(I96F32::saturating_from_num(pending_root_divs))
                 .saturating_to_num::<u64>();
             log::debug!(
                 "Proportion for hotkey {:?}: {:?}, root_divs_to_pay: {:?}",
@@ -559,11 +572,11 @@ impl<T: Config> Pallet<T> {
     pub fn get_self_contribution(hotkey: &T::AccountId, netuid: u16) -> u64 {
         // Get all childkeys for this hotkey.
         let childkeys = Self::get_children(hotkey, netuid);
-        let mut remaining_proportion: I96F32 = I96F32::from_num(1.0);
+        let mut remaining_proportion: I96F32 = I96F32::saturating_from_num(1.0);
         for (proportion, _) in childkeys {
             remaining_proportion = remaining_proportion.saturating_sub(
-                I96F32::from_num(proportion) // Normalize
-                    .safe_div(I96F32::from_num(u64::MAX)),
+                I96F32::saturating_from_num(proportion) // Normalize
+                    .safe_div(I96F32::saturating_from_num(u64::MAX)),
             );
         }
 
@@ -571,12 +584,12 @@ impl<T: Config> Pallet<T> {
         let tao_weight: I96F32 = Self::get_tao_weight();
 
         // Get the hotkey's stake including weight
-        let root_stake: I96F32 = I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(
+        let root_stake: I96F32 = I96F32::saturating_from_num(Self::get_stake_for_hotkey_on_subnet(
             hotkey,
             Self::get_root_netuid(),
         ));
         let alpha_stake: I96F32 =
-            I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid));
+            I96F32::saturating_from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid));
 
         // Calculate the
         let alpha_contribution: I96F32 = alpha_stake.saturating_mul(remaining_proportion);
@@ -611,10 +624,10 @@ impl<T: Config> Pallet<T> {
         let mut dividend_tuples: Vec<(T::AccountId, u64)> = vec![];
 
         // Calculate the hotkey's share of the validator emission based on its childkey take
-        let validating_emission: I96F32 = I96F32::from_num(dividends);
+        let validating_emission: I96F32 = I96F32::saturating_from_num(dividends);
         let childkey_take_proportion: I96F32 =
-            I96F32::from_num(Self::get_childkey_take(hotkey, netuid))
-                .safe_div(I96F32::from_num(u16::MAX));
+            I96F32::saturating_from_num(Self::get_childkey_take(hotkey, netuid))
+                .safe_div(I96F32::saturating_from_num(u16::MAX));
         log::debug!(
             "Childkey take proportion: {:?} for hotkey {:?}",
             childkey_take_proportion,
@@ -623,8 +636,8 @@ impl<T: Config> Pallet<T> {
         // NOTE: Only the validation emission should be split amongst parents.
 
         // Reserve childkey take
-        let child_emission_take: I96F32 =
-            childkey_take_proportion.saturating_mul(I96F32::from_num(validating_emission));
+        let child_emission_take: I96F32 = childkey_take_proportion
+            .saturating_mul(I96F32::saturating_from_num(validating_emission));
         let remaining_emission: I96F32 = validating_emission.saturating_sub(child_emission_take);
         log::debug!(
             "Child emission take: {:?} for hotkey {:?}",
@@ -641,7 +654,7 @@ impl<T: Config> Pallet<T> {
         let mut to_parents: u64 = 0;
 
         // Initialize variables to calculate total stakes from parents
-        let mut total_contribution: I96F32 = I96F32::from_num(0);
+        let mut total_contribution: I96F32 = I96F32::saturating_from_num(0);
         let mut parent_contributions: Vec<(T::AccountId, I96F32)> = Vec::new();
 
         // Get the weights for root and alpha stakes in emission distribution
@@ -656,21 +669,21 @@ impl<T: Config> Pallet<T> {
             self_contribution
         );
         // Add self contribution to total contribution but not to the parent contributions.
-        total_contribution = total_contribution.saturating_add(I96F32::from_num(self_contribution));
+        total_contribution =
+            total_contribution.saturating_add(I96F32::saturating_from_num(self_contribution));
 
         // Calculate total root and alpha (subnet-specific) stakes from all parents
         for (proportion, parent) in Self::get_parents(hotkey, netuid) {
             // Convert the parent's stake proportion to a fractional value
-            let parent_proportion: I96F32 =
-                I96F32::from_num(proportion).safe_div(I96F32::from_num(u64::MAX));
+            let parent_proportion: I96F32 = I96F32::saturating_from_num(proportion)
+                .safe_div(I96F32::saturating_from_num(u64::MAX));
 
             // Get the parent's root and subnet-specific (alpha) stakes
-            let parent_root: I96F32 = I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(
-                &parent,
-                Self::get_root_netuid(),
-            ));
+            let parent_root: I96F32 = I96F32::saturating_from_num(
+                Self::get_stake_for_hotkey_on_subnet(&parent, Self::get_root_netuid()),
+            );
             let parent_alpha: I96F32 =
-                I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(&parent, netuid));
+                I96F32::saturating_from_num(Self::get_stake_for_hotkey_on_subnet(&parent, netuid));
 
             // Calculate the parent's contribution to the hotkey's stakes
             let parent_alpha_contribution: I96F32 = parent_alpha.saturating_mul(parent_proportion);
@@ -698,7 +711,7 @@ impl<T: Config> Pallet<T> {
             // Sum up the total emission for this parent
             let emission_factor: I96F32 = contribution
                 .checked_div(total_contribution)
-                .unwrap_or(I96F32::from_num(0));
+                .unwrap_or(I96F32::saturating_from_num(0));
             let parent_emission: u64 =
                 (remaining_emission.saturating_mul(emission_factor)).saturating_to_num::<u64>();
 
diff --git a/pallets/subtensor/src/epoch/math.rs b/pallets/subtensor/src/epoch/math.rs
index e57d63b3a..9818b06a4 100644
--- a/pallets/subtensor/src/epoch/math.rs
+++ b/pallets/subtensor/src/epoch/math.rs
@@ -17,7 +17,7 @@ use sp_std::vec::Vec;
 
 #[allow(dead_code)]
 pub fn fixed(val: f32) -> I32F32 {
-    I32F32::from_num(val)
+    I32F32::saturating_from_num(val)
 }
 
 #[allow(dead_code)]
@@ -37,27 +37,27 @@ pub fn fixed64_to_u64(x: I64F64) -> u64 {
 
 #[allow(dead_code)]
 pub fn fixed64_to_fixed32(x: I64F64) -> I32F32 {
-    I32F32::from_num(x)
+    I32F32::saturating_from_num(x)
 }
 
 #[allow(dead_code)]
 pub fn fixed32_to_fixed64(x: I32F32) -> I64F64 {
-    I64F64::from_num(x)
+    I64F64::saturating_from_num(x)
 }
 
 #[allow(dead_code)]
 pub fn u16_to_fixed(x: u16) -> I32F32 {
-    I32F32::from_num(x)
+    I32F32::saturating_from_num(x)
 }
 
 #[allow(dead_code)]
 pub fn u16_proportion_to_fixed(x: u16) -> I32F32 {
-    I32F32::from_num(x).safe_div(I32F32::from_num(u16::MAX))
+    I32F32::saturating_from_num(x).safe_div(I32F32::saturating_from_num(u16::MAX))
 }
 
 #[allow(dead_code)]
 pub fn fixed_proportion_to_u16(x: I32F32) -> u16 {
-    fixed_to_u16(x.saturating_mul(I32F32::from_num(u16::MAX)))
+    fixed_to_u16(x.saturating_mul(I32F32::saturating_from_num(u16::MAX)))
 }
 
 #[allow(dead_code)]
@@ -93,12 +93,12 @@ pub fn vec_fixed_proportions_to_u16(vec: Vec<I32F32>) -> Vec<u16> {
 #[allow(dead_code)]
 // Max-upscale vector and convert to u16 so max_value = u16::MAX. Assumes non-negative normalized input.
 pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
-    let u16_max: I32F32 = I32F32::from_num(u16::MAX);
-    let threshold: I32F32 = I32F32::from_num(32768);
+    let u16_max: I32F32 = I32F32::saturating_from_num(u16::MAX);
+    let threshold: I32F32 = I32F32::saturating_from_num(32768);
     let max_value: Option<&I32F32> = vec.iter().max();
     match max_value {
         Some(val) => {
-            if *val == I32F32::from_num(0) {
+            if *val == I32F32::saturating_from_num(0) {
                 return vec
                     .iter()
                     .map(|e: &I32F32| e.saturating_mul(u16_max).saturating_to_num::<u16>())
@@ -139,15 +139,22 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec<u16> {
 #[allow(dead_code)]
 // Max-upscale u16 vector and convert to u16 so max_value = u16::MAX. Assumes u16 vector input.
 pub fn vec_u16_max_upscale_to_u16(vec: &[u16]) -> Vec<u16> {
-    let vec_fixed: Vec<I32F32> = vec.iter().map(|e: &u16| I32F32::from_num(*e)).collect();
+    let vec_fixed: Vec<I32F32> = vec
+        .iter()
+        .map(|e: &u16| I32F32::saturating_from_num(*e))
+        .collect();
     vec_max_upscale_to_u16(&vec_fixed)
 }
 
 #[allow(dead_code)]
 // Checks if u16 vector, when normalized, has a max value not greater than a u16 ratio max_limit.
 pub fn check_vec_max_limited(vec: &[u16], max_limit: u16) -> bool {
-    let max_limit_fixed: I32F32 = I32F32::from_num(max_limit).safe_div(I32F32::from_num(u16::MAX));
-    let mut vec_fixed: Vec<I32F32> = vec.iter().map(|e: &u16| I32F32::from_num(*e)).collect();
+    let max_limit_fixed: I32F32 =
+        I32F32::saturating_from_num(max_limit).safe_div(I32F32::saturating_from_num(u16::MAX));
+    let mut vec_fixed: Vec<I32F32> = vec
+        .iter()
+        .map(|e: &u16| I32F32::saturating_from_num(*e))
+        .collect();
     inplace_normalize(&mut vec_fixed);
     let max_value: Option<&I32F32> = vec_fixed.iter().max();
     max_value.is_none_or(|v| *v <= max_limit_fixed)
@@ -180,14 +187,14 @@ where
 #[allow(dead_code)]
 pub fn is_zero(vector: &[I32F32]) -> bool {
     let vector_sum: I32F32 = sum(vector);
-    vector_sum == I32F32::from_num(0)
+    vector_sum == I32F32::saturating_from_num(0)
 }
 
 // Exp safe function with I32F32 output of I32F32 input.
 #[allow(dead_code)]
 pub fn exp_safe(input: I32F32) -> I32F32 {
-    let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903
-    let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903
+    let min_input: I32F32 = I32F32::saturating_from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903
+    let max_input: I32F32 = I32F32::saturating_from_num(20); // <= exp(20) = 485 165 195,4097903
     let mut safe_input: I32F32 = input;
     if input < min_input {
         safe_input = min_input;
@@ -201,7 +208,7 @@ pub fn exp_safe(input: I32F32) -> I32F32 {
         }
         Err(_err) => {
             if safe_input <= 0 {
-                output = I32F32::from_num(0);
+                output = I32F32::saturating_from_num(0);
             } else {
                 output = I32F32::max_value();
             }
@@ -213,7 +220,7 @@ pub fn exp_safe(input: I32F32) -> I32F32 {
 // Sigmoid safe function with I32F32 output of I32F32 input with offset kappa and (recommended) scaling 0 < rho <= 40.
 #[allow(dead_code)]
 pub fn sigmoid_safe(input: I32F32, rho: I32F32, kappa: I32F32) -> I32F32 {
-    let one: I32F32 = I32F32::from_num(1);
+    let one: I32F32 = I32F32::saturating_from_num(1);
     let offset: I32F32 = input.saturating_sub(kappa); // (input - kappa)
     let neg_rho: I32F32 = rho.saturating_mul(one.saturating_neg()); // -rho
     let exp_input: I32F32 = neg_rho.saturating_mul(offset); // -rho*(input-kappa)
@@ -243,7 +250,7 @@ pub fn is_topk(vector: &[I32F32], k: usize) -> Vec<bool> {
 #[allow(dead_code)]
 pub fn normalize(x: &[I32F32]) -> Vec<I32F32> {
     let x_sum: I32F32 = sum(x);
-    if x_sum != I32F32::from_num(0.0_f32) {
+    if x_sum != I32F32::saturating_from_num(0.0_f32) {
         x.iter().map(|xi| xi.safe_div(x_sum)).collect()
     } else {
         x.to_vec()
@@ -254,7 +261,7 @@ pub fn normalize(x: &[I32F32]) -> Vec<I32F32> {
 #[allow(dead_code)]
 pub fn inplace_normalize(x: &mut [I32F32]) {
     let x_sum: I32F32 = x.iter().sum();
-    if x_sum == I32F32::from_num(0.0_f32) {
+    if x_sum == I32F32::saturating_from_num(0.0_f32) {
         return;
     }
     x.iter_mut()
@@ -264,7 +271,7 @@ pub fn inplace_normalize(x: &mut [I32F32]) {
 // Normalizes (sum to 1 except 0) the input vector directly in-place, using the sum arg.
 #[allow(dead_code)]
 pub fn inplace_normalize_using_sum(x: &mut [I32F32], x_sum: I32F32) {
-    if x_sum == I32F32::from_num(0.0_f32) {
+    if x_sum == I32F32::saturating_from_num(0.0_f32) {
         return;
     }
     x.iter_mut()
@@ -275,7 +282,7 @@ pub fn inplace_normalize_using_sum(x: &mut [I32F32], x_sum: I32F32) {
 #[allow(dead_code)]
 pub fn inplace_normalize_64(x: &mut [I64F64]) {
     let x_sum: I64F64 = x.iter().sum();
-    if x_sum == I64F64::from_num(0) {
+    if x_sum == I64F64::saturating_from_num(0) {
         return;
     }
     x.iter_mut()
@@ -287,7 +294,7 @@ pub fn inplace_normalize_64(x: &mut [I64F64]) {
 pub fn inplace_row_normalize_64(x: &mut [Vec<I64F64>]) {
     for row in x {
         let row_sum: I64F64 = row.iter().sum();
-        if row_sum > I64F64::from_num(0.0_f64) {
+        if row_sum > I64F64::saturating_from_num(0.0_f64) {
             row.iter_mut()
                 .for_each(|x_ij: &mut I64F64| *x_ij = x_ij.safe_div(row_sum));
         }
@@ -304,7 +311,7 @@ pub fn vecdiv(x: &[I32F32], y: &[I32F32]) -> Vec<I32F32> {
             if *y_i != 0 {
                 x_i.safe_div(*y_i)
             } else {
-                I32F32::from_num(0)
+                I32F32::saturating_from_num(0)
             }
         })
         .collect()
@@ -315,7 +322,7 @@ pub fn vecdiv(x: &[I32F32], y: &[I32F32]) -> Vec<I32F32> {
 pub fn inplace_row_normalize(x: &mut [Vec<I32F32>]) {
     for row in x {
         let row_sum: I32F32 = row.iter().sum();
-        if row_sum > I32F32::from_num(0.0_f32) {
+        if row_sum > I32F32::saturating_from_num(0.0_f32) {
             row.iter_mut()
                 .for_each(|x_ij: &mut I32F32| *x_ij = x_ij.safe_div(row_sum));
         }
@@ -327,7 +334,7 @@ pub fn inplace_row_normalize(x: &mut [Vec<I32F32>]) {
 pub fn inplace_row_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>]) {
     for sparse_row in sparse_matrix.iter_mut() {
         let row_sum: I32F32 = sparse_row.iter().map(|(_j, value)| *value).sum();
-        if row_sum > I32F32::from_num(0.0) {
+        if row_sum > I32F32::saturating_from_num(0.0) {
             sparse_row
                 .iter_mut()
                 .for_each(|(_j, value)| *value = value.safe_div(row_sum));
@@ -365,19 +372,21 @@ pub fn col_sum(x: &[Vec<I32F32>]) -> Vec<I32F32> {
     if cols == 0 {
         return vec![];
     }
-    x.iter()
-        .fold(vec![I32F32::from_num(0); cols], |acc, next_row| {
+    x.iter().fold(
+        vec![I32F32::saturating_from_num(0); cols],
+        |acc, next_row| {
             acc.into_iter()
                 .zip(next_row)
                 .map(|(acc_elem, next_elem)| acc_elem.saturating_add(*next_elem))
                 .collect()
-        })
+        },
+    )
 }
 
 // Sum across each column (dim=1) of a sparse matrix.
 #[allow(dead_code, clippy::indexing_slicing)]
 pub fn col_sum_sparse(sparse_matrix: &[Vec<(u16, I32F32)>], columns: u16) -> Vec<I32F32> {
-    let mut result: Vec<I32F32> = vec![I32F32::from_num(0); columns as usize];
+    let mut result: Vec<I32F32> = vec![I32F32::saturating_from_num(0); columns as usize];
     for sparse_row in sparse_matrix {
         for (j, value) in sparse_row {
             result[*j as usize] = result[*j as usize].saturating_add(*value);
@@ -389,7 +398,7 @@ pub fn col_sum_sparse(sparse_matrix: &[Vec<(u16, I32F32)>], columns: u16) -> Vec
 // Normalizes (sum to 1 except 0) each column (dim=1) of a sparse matrix in-place.
 #[allow(dead_code, clippy::indexing_slicing)]
 pub fn inplace_col_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>], columns: u16) {
-    let mut col_sum: Vec<I32F32> = vec![I32F32::from_num(0.0); columns as usize]; // assume square matrix, rows=cols
+    let mut col_sum: Vec<I32F32> = vec![I32F32::saturating_from_num(0.0); columns as usize]; // assume square matrix, rows=cols
     for sparse_row in sparse_matrix.iter() {
         for (j, value) in sparse_row.iter() {
             col_sum[*j as usize] = col_sum[*j as usize].saturating_add(*value);
@@ -397,7 +406,7 @@ pub fn inplace_col_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>], co
     }
     for sparse_row in sparse_matrix {
         for (j, value) in sparse_row {
-            if col_sum[*j as usize] == I32F32::from_num(0.0_f32) {
+            if col_sum[*j as usize] == I32F32::saturating_from_num(0.0_f32) {
                 continue;
             }
             *value = value.safe_div(col_sum[*j as usize]);
@@ -417,7 +426,7 @@ pub fn inplace_col_normalize(x: &mut [Vec<I32F32>]) {
     let cols = first_row.len();
     let col_sums = x
         .iter_mut()
-        .fold(vec![I32F32::from_num(0.0); cols], |acc, row| {
+        .fold(vec![I32F32::saturating_from_num(0.0); cols], |acc, row| {
             row.iter_mut()
                 .zip(acc)
                 .map(|(&mut m_val, acc_val)| acc_val.saturating_add(m_val))
@@ -426,7 +435,7 @@ pub fn inplace_col_normalize(x: &mut [Vec<I32F32>]) {
     x.iter_mut().for_each(|row| {
         row.iter_mut()
             .zip(&col_sums)
-            .filter(|(_, col_sum)| **col_sum != I32F32::from_num(0_f32))
+            .filter(|(_, col_sum)| **col_sum != I32F32::saturating_from_num(0_f32))
             .for_each(|(m_val, col_sum)| {
                 *m_val = m_val.safe_div(*col_sum);
             });
@@ -436,7 +445,7 @@ pub fn inplace_col_normalize(x: &mut [Vec<I32F32>]) {
 // Max-upscale each column (dim=1) of a sparse matrix in-place.
 #[allow(dead_code, clippy::indexing_slicing)]
 pub fn inplace_col_max_upscale_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>], columns: u16) {
-    let mut col_max: Vec<I32F32> = vec![I32F32::from_num(0.0); columns as usize]; // assume square matrix, rows=cols
+    let mut col_max: Vec<I32F32> = vec![I32F32::saturating_from_num(0.0); columns as usize]; // assume square matrix, rows=cols
     for sparse_row in sparse_matrix.iter() {
         for (j, value) in sparse_row.iter() {
             if col_max[*j as usize] < *value {
@@ -446,7 +455,7 @@ pub fn inplace_col_max_upscale_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>],
     }
     for sparse_row in sparse_matrix {
         for (j, value) in sparse_row {
-            if col_max[*j as usize] == I32F32::from_num(0.0_f32) {
+            if col_max[*j as usize] == I32F32::saturating_from_num(0.0_f32) {
                 continue;
             }
             *value = value.safe_div(col_max[*j as usize]);
@@ -464,18 +473,19 @@ pub fn inplace_col_max_upscale(x: &mut [Vec<I32F32>]) {
         return;
     }
     let cols = first_row.len();
-    let col_maxes = x
-        .iter_mut()
-        .fold(vec![I32F32::from_num(0_f32); cols], |acc, row| {
+    let col_maxes = x.iter_mut().fold(
+        vec![I32F32::saturating_from_num(0_f32); cols],
+        |acc, row| {
             row.iter_mut()
                 .zip(acc)
                 .map(|(m_val, acc_val)| acc_val.max(*m_val))
                 .collect()
-        });
+        },
+    );
     x.iter_mut().for_each(|row| {
         row.iter_mut()
             .zip(&col_maxes)
-            .filter(|(_, col_max)| **col_max != I32F32::from_num(0))
+            .filter(|(_, col_max)| **col_max != I32F32::saturating_from_num(0))
             .for_each(|(m_val, col_max)| {
                 *m_val = m_val.safe_div(*col_max);
             });
@@ -489,7 +499,7 @@ pub fn inplace_mask_vector(mask: &[bool], vector: &mut [I32F32]) {
         return;
     }
     assert_eq!(mask.len(), vector.len());
-    let zero: I32F32 = I32F32::from_num(0.0);
+    let zero: I32F32 = I32F32::saturating_from_num(0.0);
     mask.iter()
         .zip(vector)
         .filter(|(m, _)| **m)
@@ -508,7 +518,7 @@ pub fn inplace_mask_matrix(mask: &[Vec<bool>], matrix: &mut Vec<Vec<I32F32>>) {
         return;
     }
     assert_eq!(mask.len(), matrix.len());
-    let zero: I32F32 = I32F32::from_num(0.0);
+    let zero: I32F32 = I32F32::saturating_from_num(0.0);
     mask.iter().zip(matrix).for_each(|(mask_row, matrix_row)| {
         mask_row
             .iter()
@@ -528,7 +538,7 @@ pub fn inplace_mask_rows(mask: &[bool], matrix: &mut [Vec<I32F32>]) {
     };
     let cols = first_row.len();
     assert_eq!(mask.len(), matrix.len());
-    let zero: I32F32 = I32F32::from_num(0);
+    let zero: I32F32 = I32F32::saturating_from_num(0);
     matrix
         .iter_mut()
         .zip(mask)
@@ -549,7 +559,7 @@ pub fn inplace_mask_diag(matrix: &mut [Vec<I32F32>]) {
         return;
     }
     assert_eq!(matrix.len(), first_row.len());
-    let zero: I32F32 = I32F32::from_num(0.0);
+    let zero: I32F32 = I32F32::saturating_from_num(0.0);
     matrix.iter_mut().enumerate().for_each(|(idx, row)| {
         let Some(elem) = row.get_mut(idx) else {
             // Should not happen since matrix is square
@@ -664,7 +674,7 @@ pub fn matmul(matrix: &[Vec<I32F32>], vector: &[I32F32]) -> Vec<I32F32> {
     }
     assert!(matrix.len() == vector.len());
     matrix.iter().zip(vector).fold(
-        vec![I32F32::from_num(0_f32); cols],
+        vec![I32F32::saturating_from_num(0_f32); cols],
         |acc, (row, vec_val)| {
             row.iter()
                 .zip(acc)
@@ -690,10 +700,9 @@ pub fn matmul_64(matrix: &[Vec<I64F64>], vector: &[I64F64]) -> Vec<I64F64> {
         return vec![];
     }
     assert!(matrix.len() == vector.len());
-    matrix
-        .iter()
-        .zip(vector)
-        .fold(vec![I64F64::from_num(0.0); cols], |acc, (row, vec_val)| {
+    matrix.iter().zip(vector).fold(
+        vec![I64F64::saturating_from_num(0.0); cols],
+        |acc, (row, vec_val)| {
             row.iter()
                 .zip(acc)
                 .map(|(m_val, acc_val)| {
@@ -703,7 +712,8 @@ pub fn matmul_64(matrix: &[Vec<I64F64>], vector: &[I64F64]) -> Vec<I64F64> {
                     acc_val.saturating_add(vec_val.saturating_mul(*m_val))
                 })
                 .collect()
-        })
+        },
+    )
 }
 
 // Column-wise matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij.
@@ -721,7 +731,7 @@ pub fn matmul_transpose(matrix: &[Vec<I32F32>], vector: &[I32F32]) -> Vec<I32F32
         .map(|row| {
             row.iter()
                 .zip(vector)
-                .fold(I32F32::from_num(0.0), |acc, (velem, melem)| {
+                .fold(I32F32::saturating_from_num(0.0), |acc, (velem, melem)| {
                     // Compute dividends: d_j = SUM(i) b_ji * inc_i
                     // result_j = SUM(i) vector_i * matrix_ji
                     // result_i = SUM(j) vector_j * matrix_ij
@@ -738,7 +748,7 @@ pub fn matmul_sparse(
     vector: &[I32F32],
     columns: u16,
 ) -> Vec<I32F32> {
-    let mut result: Vec<I32F32> = vec![I32F32::from_num(0.0); columns as usize];
+    let mut result: Vec<I32F32> = vec![I32F32::saturating_from_num(0.0); columns as usize];
     for (i, sparse_row) in sparse_matrix.iter().enumerate() {
         for (j, value) in sparse_row.iter() {
             // Compute ranks: r_j = SUM(i) w_ij * s_i
@@ -757,7 +767,7 @@ pub fn matmul_transpose_sparse(
     sparse_matrix: &[Vec<(u16, I32F32)>],
     vector: &[I32F32],
 ) -> Vec<I32F32> {
-    let mut result: Vec<I32F32> = vec![I32F32::from_num(0.0); sparse_matrix.len()];
+    let mut result: Vec<I32F32> = vec![I32F32::saturating_from_num(0.0); sparse_matrix.len()];
     for (i, sparse_row) in sparse_matrix.iter().enumerate() {
         for (j, value) in sparse_row.iter() {
             // Compute dividends: d_j = SUM(i) b_ji * inc_i
@@ -892,7 +902,7 @@ pub fn weighted_median(
 ) -> I32F32 {
     let n = partition_idx.len();
     if n == 0 {
-        return I32F32::from_num(0);
+        return I32F32::saturating_from_num(0);
     }
     if n == 1 {
         return score[partition_idx[0]];
@@ -900,8 +910,8 @@ pub fn weighted_median(
     assert!(stake.len() == score.len());
     let mid_idx: usize = n.safe_div(2);
     let pivot: I32F32 = score[partition_idx[mid_idx]];
-    let mut lo_stake: I32F32 = I32F32::from_num(0);
-    let mut hi_stake: I32F32 = I32F32::from_num(0);
+    let mut lo_stake: I32F32 = I32F32::saturating_from_num(0);
+    let mut hi_stake: I32F32 = I32F32::saturating_from_num(0);
     let mut lower: Vec<usize> = vec![];
     let mut upper: Vec<usize> = vec![];
     for &idx in partition_idx {
@@ -951,7 +961,7 @@ pub fn weighted_median_col(
 ) -> Vec<I32F32> {
     let rows = stake.len();
     let columns = score[0].len();
-    let zero: I32F32 = I32F32::from_num(0);
+    let zero: I32F32 = I32F32::saturating_from_num(0);
     let mut median: Vec<I32F32> = vec![zero; columns];
 
     #[allow(clippy::needless_range_loop)]
@@ -991,7 +1001,7 @@ pub fn weighted_median_col_sparse(
     majority: I32F32,
 ) -> Vec<I32F32> {
     let rows = stake.len();
-    let zero: I32F32 = I32F32::from_num(0);
+    let zero: I32F32 = I32F32::saturating_from_num(0);
     let mut use_stake: Vec<I32F32> = stake.iter().copied().filter(|&s| s > zero).collect();
     inplace_normalize(&mut use_stake);
     let stake_sum: I32F32 = use_stake.iter().sum();
@@ -1028,10 +1038,10 @@ pub fn weighted_median_col_sparse(
 // ratio=1: Result = B
 #[allow(dead_code)]
 pub fn interpolate(mat1: &[Vec<I32F32>], mat2: &[Vec<I32F32>], ratio: I32F32) -> Vec<Vec<I32F32>> {
-    if ratio == I32F32::from_num(0) {
+    if ratio == I32F32::saturating_from_num(0) {
         return mat1.to_owned();
     }
-    if ratio == I32F32::from_num(1) {
+    if ratio == I32F32::saturating_from_num(1) {
         return mat2.to_owned();
     }
     assert!(mat1.len() == mat2.len());
@@ -1042,7 +1052,10 @@ pub fn interpolate(mat1: &[Vec<I32F32>], mat2: &[Vec<I32F32>], ratio: I32F32) ->
         return vec![vec![]; 1];
     }
     let mut result: Vec<Vec<I32F32>> =
-        vec![vec![I32F32::from_num(0); mat1.first().unwrap_or(&vec![]).len()]; mat1.len()];
+        vec![
+            vec![I32F32::saturating_from_num(0); mat1.first().unwrap_or(&vec![]).len()];
+            mat1.len()
+        ];
     for (i, (row1, row2)) in mat1.iter().zip(mat2.iter()).enumerate() {
         assert!(row1.len() == row2.len());
         for (j, (&v1, &v2)) in row1.iter().zip(row2.iter()).enumerate() {
@@ -1065,15 +1078,15 @@ pub fn interpolate_sparse(
     columns: u16,
     ratio: I32F32,
 ) -> Vec<Vec<(u16, I32F32)>> {
-    if ratio == I32F32::from_num(0) {
+    if ratio == I32F32::saturating_from_num(0) {
         return mat1.to_owned();
     }
-    if ratio == I32F32::from_num(1) {
+    if ratio == I32F32::saturating_from_num(1) {
         return mat2.to_owned();
     }
     assert!(mat1.len() == mat2.len());
     let rows = mat1.len();
-    let zero: I32F32 = I32F32::from_num(0);
+    let zero: I32F32 = I32F32::saturating_from_num(0);
     let mut result: Vec<Vec<(u16, I32F32)>> = vec![vec![]; rows];
     for i in 0..rows {
         let mut row1: Vec<I32F32> = vec![zero; columns as usize];
@@ -1137,7 +1150,7 @@ pub fn hadamard_sparse(
 ) -> Vec<Vec<(u16, I32F32)>> {
     assert!(mat1.len() == mat2.len());
     let rows = mat1.len();
-    let zero: I32F32 = I32F32::from_num(0);
+    let zero: I32F32 = I32F32::saturating_from_num(0);
     let mut result: Vec<Vec<(u16, I32F32)>> = vec![vec![]; rows];
     for i in 0..rows {
         let mut row1: Vec<I32F32> = vec![zero; columns as usize];
@@ -1169,7 +1182,7 @@ pub fn mat_ema(new: &[Vec<I32F32>], old: &[Vec<I32F32>], alpha: I32F32) -> Vec<V
     if first_row.is_empty() {
         return vec![vec![]; 1];
     }
-    let one_minus_alpha: I32F32 = I32F32::from_num(1.0).saturating_sub(alpha);
+    let one_minus_alpha: I32F32 = I32F32::saturating_from_num(1.0).saturating_sub(alpha);
     new.iter()
         .zip(old)
         .map(|(new_row, old_row)| {
@@ -1197,8 +1210,8 @@ pub fn mat_ema_sparse(
 ) -> Vec<Vec<(u16, I32F32)>> {
     assert!(new.len() == old.len());
     let n = new.len(); // assume square matrix, rows=cols
-    let zero: I32F32 = I32F32::from_num(0.0);
-    let one_minus_alpha: I32F32 = I32F32::from_num(1.0).saturating_sub(alpha);
+    let zero: I32F32 = I32F32::saturating_from_num(0.0);
+    let one_minus_alpha: I32F32 = I32F32::saturating_from_num(1.0).saturating_sub(alpha);
     let mut result: Vec<Vec<(u16, I32F32)>> = vec![vec![]; n];
     for i in 0..new.len() {
         let mut row: Vec<I32F32> = vec![zero; n];
@@ -1241,7 +1254,7 @@ pub fn mat_ema_alpha_vec_sparse(
     // Ensure the new and old matrices have the same number of rows.
     assert!(new.len() == old.len());
     let n = new.len(); // Assume square matrix, rows=cols
-    let zero: I32F32 = I32F32::from_num(0.0);
+    let zero: I32F32 = I32F32::saturating_from_num(0.0);
     let mut result: Vec<Vec<(u16, I32F32)>> = vec![vec![]; n];
 
     // Iterate over each row of the matrices.
@@ -1273,7 +1286,8 @@ pub fn mat_ema_alpha_vec_sparse(
             // Retrieve the alpha value for the current column.
             let alpha_val: I32F32 = alpha.get(*j as usize).copied().unwrap_or(zero);
             // Calculate the complement of the alpha value using saturating subtraction.
-            let one_minus_alpha: I32F32 = I32F32::from_num(1.0).saturating_sub(alpha_val);
+            let one_minus_alpha: I32F32 =
+                I32F32::saturating_from_num(1.0).saturating_sub(alpha_val);
             // Compute the EMA component for the old value and add it to the row using saturating operations.
             if let Some(row_val) = row.get_mut(*j as usize) {
                 *row_val = row_val.saturating_add(one_minus_alpha.saturating_mul(*value));
@@ -1323,7 +1337,10 @@ pub fn mat_ema_alpha_vec(
 
     // Initialize the result matrix with zeros, having the same dimensions as the new matrix.
     let mut result: Vec<Vec<I32F32>> =
-        vec![vec![I32F32::from_num(0.0); new.first().map_or(0, |row| row.len())]; new.len()];
+        vec![
+            vec![I32F32::saturating_from_num(0.0); new.first().map_or(0, |row| row.len())];
+            new.len()
+        ];
 
     // Iterate over each row of the matrices.
     for (i, (new_row, old_row)) in new.iter().zip(old).enumerate() {
@@ -1333,7 +1350,7 @@ pub fn mat_ema_alpha_vec(
         // Iterate over each column of the current row.
         for (j, &alpha_val) in alpha.iter().enumerate().take(new_row.len()) {
             // Calculate the complement of the alpha value using saturating subtraction.
-            let one_minus_alpha = I32F32::from_num(1.0).saturating_sub(alpha_val);
+            let one_minus_alpha = I32F32::saturating_from_num(1.0).saturating_sub(alpha_val);
 
             // Compute the EMA for the current element using saturating operations.
             if let (Some(new_val), Some(old_val), Some(result_val)) = (
@@ -1365,7 +1382,7 @@ pub fn quantile(data: &[I32F32], quantile: f64) -> I32F32 {
 
     // If the data is empty, return 0 as the quantile value.
     if len == 0 {
-        return I32F32::from_num(0);
+        return I32F32::saturating_from_num(0);
     }
 
     // Calculate the position in the sorted array corresponding to the quantile.
@@ -1382,20 +1399,20 @@ pub fn quantile(data: &[I32F32], quantile: f64) -> I32F32 {
         sorted_data
             .get(low)
             .copied()
-            .unwrap_or_else(|| I32F32::from_num(0))
+            .unwrap_or_else(|| I32F32::saturating_from_num(0))
     } else {
         // Otherwise, perform linear interpolation between the low and high values.
         let low_value = sorted_data
             .get(low)
             .copied()
-            .unwrap_or_else(|| I32F32::from_num(0));
+            .unwrap_or_else(|| I32F32::saturating_from_num(0));
         let high_value = sorted_data
             .get(high)
             .copied()
-            .unwrap_or_else(|| I32F32::from_num(0));
+            .unwrap_or_else(|| I32F32::saturating_from_num(0));
 
         // Calculate the weight for interpolation.
-        let weight = I32F32::from_num(pos - low as f64);
+        let weight = I32F32::saturating_from_num(pos - low as f64);
 
         // Return the interpolated value using saturating operations.
         low_value.saturating_add((high_value.saturating_sub(low_value)).saturating_mul(weight))
@@ -1404,10 +1421,10 @@ pub fn quantile(data: &[I32F32], quantile: f64) -> I32F32 {
 
 /// Safe ln function, returns 0 if value is 0.
 pub fn safe_ln(value: I32F32) -> I32F32 {
-    ln(value).unwrap_or(I32F32::from_num(0.0))
+    ln(value).unwrap_or(I32F32::saturating_from_num(0.0))
 }
 
 /// Safe exp function, returns 0 if value is 0.
 pub fn safe_exp(value: I32F32) -> I32F32 {
-    exp(value).unwrap_or(I32F32::from_num(0.0))
+    exp(value).unwrap_or(I32F32::saturating_from_num(0.0))
 }
diff --git a/pallets/subtensor/src/epoch/run_epoch.rs b/pallets/subtensor/src/epoch/run_epoch.rs
index 4e9f36e4e..9a7e4f6ab 100644
--- a/pallets/subtensor/src/epoch/run_epoch.rs
+++ b/pallets/subtensor/src/epoch/run_epoch.rs
@@ -231,11 +231,11 @@ impl<T: Config> Pallet<T> {
         }
 
         // Compute rao based emission scores. range: I96F32(0, rao_emission)
-        let float_rao_emission: I96F32 = I96F32::from_num(rao_emission);
+        let float_rao_emission: I96F32 = I96F32::saturating_from_num(rao_emission);
 
         let server_emission: Vec<I96F32> = normalized_server_emission
             .iter()
-            .map(|se: &I32F32| I96F32::from_num(*se).saturating_mul(float_rao_emission))
+            .map(|se: &I32F32| I96F32::saturating_from_num(*se).saturating_mul(float_rao_emission))
             .collect();
         let server_emission: Vec<u64> = server_emission
             .iter()
@@ -244,7 +244,7 @@ impl<T: Config> Pallet<T> {
 
         let validator_emission: Vec<I96F32> = normalized_validator_emission
             .iter()
-            .map(|ve: &I32F32| I96F32::from_num(*ve).saturating_mul(float_rao_emission))
+            .map(|ve: &I32F32| I96F32::saturating_from_num(*ve).saturating_mul(float_rao_emission))
             .collect();
         let validator_emission: Vec<u64> = validator_emission
             .iter()
@@ -254,7 +254,7 @@ impl<T: Config> Pallet<T> {
         // Used only to track combined emission in the storage.
         let combined_emission: Vec<I96F32> = normalized_combined_emission
             .iter()
-            .map(|ce: &I32F32| I96F32::from_num(*ce).saturating_mul(float_rao_emission))
+            .map(|ce: &I32F32| I96F32::saturating_from_num(*ce).saturating_mul(float_rao_emission))
             .collect();
         let combined_emission: Vec<u64> = combined_emission
             .iter()
@@ -602,11 +602,11 @@ impl<T: Config> Pallet<T> {
         }
 
         // Compute rao based emission scores. range: I96F32(0, rao_emission)
-        let float_rao_emission: I96F32 = I96F32::from_num(rao_emission);
+        let float_rao_emission: I96F32 = I96F32::saturating_from_num(rao_emission);
 
         let server_emission: Vec<I96F32> = normalized_server_emission
             .iter()
-            .map(|se: &I32F32| I96F32::from_num(*se).saturating_mul(float_rao_emission))
+            .map(|se: &I32F32| I96F32::saturating_from_num(*se).saturating_mul(float_rao_emission))
             .collect();
         let server_emission: Vec<u64> = server_emission
             .iter()
@@ -615,7 +615,7 @@ impl<T: Config> Pallet<T> {
 
         let validator_emission: Vec<I96F32> = normalized_validator_emission
             .iter()
-            .map(|ve: &I32F32| I96F32::from_num(*ve).saturating_mul(float_rao_emission))
+            .map(|ve: &I32F32| I96F32::saturating_from_num(*ve).saturating_mul(float_rao_emission))
             .collect();
         let validator_emission: Vec<u64> = validator_emission
             .iter()
@@ -625,7 +625,7 @@ impl<T: Config> Pallet<T> {
         // Only used to track emission in storage.
         let combined_emission: Vec<I96F32> = normalized_combined_emission
             .iter()
-            .map(|ce: &I32F32| I96F32::from_num(*ce).saturating_mul(float_rao_emission))
+            .map(|ce: &I32F32| I96F32::saturating_from_num(*ce).saturating_mul(float_rao_emission))
             .collect();
         let combined_emission: Vec<u64> = combined_emission
             .iter()
@@ -733,13 +733,15 @@ impl<T: Config> Pallet<T> {
     }
 
     pub fn get_float_rho(netuid: u16) -> I32F32 {
-        I32F32::from_num(Self::get_rho(netuid))
+        I32F32::saturating_from_num(Self::get_rho(netuid))
     }
     pub fn get_float_kappa(netuid: u16) -> I32F32 {
-        I32F32::from_num(Self::get_kappa(netuid)).safe_div(I32F32::from_num(u16::MAX))
+        I32F32::saturating_from_num(Self::get_kappa(netuid))
+            .safe_div(I32F32::saturating_from_num(u16::MAX))
     }
     pub fn get_float_bonds_penalty(netuid: u16) -> I32F32 {
-        I32F32::from_num(Self::get_bonds_penalty(netuid)).safe_div(I32F32::from_num(u16::MAX))
+        I32F32::saturating_from_num(Self::get_bonds_penalty(netuid))
+            .safe_div(I32F32::saturating_from_num(u16::MAX))
     }
 
     pub fn get_block_at_registration(netuid: u16) -> Vec<u64> {
@@ -768,7 +770,7 @@ impl<T: Config> Pallet<T> {
                 weights
                     .get_mut(uid_i as usize)
                     .expect("uid_i is filtered to be less than n; qed")
-                    .push((*uid_j, I32F32::from_num(*weight_ij)));
+                    .push((*uid_j, I32F32::saturating_from_num(*weight_ij)));
             }
         }
         weights
@@ -777,7 +779,7 @@ impl<T: Config> Pallet<T> {
     /// Output unnormalized weights in [n, n] matrix, input weights are assumed to be row max-upscaled in u16.
     pub fn get_weights(netuid: u16) -> Vec<Vec<I32F32>> {
         let n: usize = Self::get_subnetwork_n(netuid) as usize;
-        let mut weights: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(0.0); n]; n];
+        let mut weights: Vec<Vec<I32F32>> = vec![vec![I32F32::saturating_from_num(0.0); n]; n];
         for (uid_i, weights_vec) in
             <Weights<T> as IterableStorageDoubleMap<u16, u16, Vec<(u16, u16)>>>::iter_prefix(netuid)
                 .filter(|(uid_i, _)| *uid_i < n as u16)
@@ -791,7 +793,7 @@ impl<T: Config> Pallet<T> {
                     .expect("uid_i is filtered to be less than n; qed")
                     .get_mut(uid_j as usize)
                     .expect("uid_j is filtered to be less than n; qed") =
-                    I32F32::from_num(weight_ij);
+                    I32F32::saturating_from_num(weight_ij);
             }
         }
         weights
@@ -809,7 +811,7 @@ impl<T: Config> Pallet<T> {
                 bonds
                     .get_mut(uid_i as usize)
                     .expect("uid_i is filtered to be less than n; qed")
-                    .push((uid_j, I32F32::from_num(bonds_ij)));
+                    .push((uid_j, I32F32::saturating_from_num(bonds_ij)));
             }
         }
         bonds
@@ -818,7 +820,7 @@ impl<T: Config> Pallet<T> {
     /// Output unnormalized bonds in [n, n] matrix, input bonds are assumed to be column max-upscaled in u16.
     pub fn get_bonds(netuid: u16) -> Vec<Vec<I32F32>> {
         let n: usize = Self::get_subnetwork_n(netuid) as usize;
-        let mut bonds: Vec<Vec<I32F32>> = vec![vec![I32F32::from_num(0.0); n]; n];
+        let mut bonds: Vec<Vec<I32F32>> = vec![vec![I32F32::saturating_from_num(0.0); n]; n];
         for (uid_i, bonds_vec) in
             <Bonds<T> as IterableStorageDoubleMap<u16, u16, Vec<(u16, u16)>>>::iter_prefix(netuid)
                 .filter(|(uid_i, _)| *uid_i < n as u16)
@@ -829,7 +831,7 @@ impl<T: Config> Pallet<T> {
                     .expect("uid_i has been filtered to be less than n; qed")
                     .get_mut(uid_j as usize)
                     .expect("uid_j has been filtered to be less than n; qed") =
-                    I32F32::from_num(bonds_ij);
+                    I32F32::saturating_from_num(bonds_ij);
             }
         }
         bonds
@@ -859,16 +861,21 @@ impl<T: Config> Pallet<T> {
         // extra caution to ensure we never divide by zero
         if consensus_high <= consensus_low || alpha_low == 0 || alpha_high == 0 {
             // Return 0 for both 'a' and 'b' when consensus values are equal
-            return (I32F32::from_num(0.0), I32F32::from_num(0.0));
+            return (
+                I32F32::saturating_from_num(0.0),
+                I32F32::saturating_from_num(0.0),
+            );
         }
 
         // Calculate the slope 'a' of the logistic function.
         // a = (ln((1 / alpha_high - 1)) - ln((1 / alpha_low - 1))) / (consensus_low - consensus_high)
         let a = (safe_ln(
-            (I32F32::from_num(1.0).safe_div(alpha_high)).saturating_sub(I32F32::from_num(1.0)),
+            (I32F32::saturating_from_num(1.0).safe_div(alpha_high))
+                .saturating_sub(I32F32::saturating_from_num(1.0)),
         )
         .saturating_sub(safe_ln(
-            (I32F32::from_num(1.0).safe_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)),
+            (I32F32::saturating_from_num(1.0).safe_div(alpha_low))
+                .saturating_sub(I32F32::saturating_from_num(1.0)),
         )))
         .safe_div(consensus_low.saturating_sub(consensus_high));
         log::trace!("a: {:?}", a);
@@ -876,7 +883,8 @@ impl<T: Config> Pallet<T> {
         // Calculate the intercept 'b' of the logistic function.
         // b = ln((1 / alpha_low - 1)) + a * consensus_low
         let b = safe_ln(
-            (I32F32::from_num(1.0).safe_div(alpha_low)).saturating_sub(I32F32::from_num(1.0)),
+            (I32F32::saturating_from_num(1.0).safe_div(alpha_low))
+                .saturating_sub(I32F32::saturating_from_num(1.0)),
         )
         .saturating_add(a.saturating_mul(consensus_low));
         log::trace!("b: {:?}", b);
@@ -905,7 +913,8 @@ impl<T: Config> Pallet<T> {
 
                 // Compute the alpha value using the logistic function formula.
                 // alpha = 1 / (1 + exp_val)
-                I32F32::from_num(1.0).safe_div(I32F32::from_num(1.0).saturating_add(exp_val))
+                I32F32::saturating_from_num(1.0)
+                    .safe_div(I32F32::saturating_from_num(1.0).saturating_add(exp_val))
             })
             .collect();
 
@@ -1019,13 +1028,14 @@ impl<T: Config> Pallet<T> {
         netuid: u16,
     ) -> Vec<Vec<(u16, I32F32)>> {
         // Retrieve the bonds moving average for the given network ID and scale it down.
-        let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid))
-            .safe_div(I64F64::from_num(1_000_000));
+        let bonds_moving_average: I64F64 =
+            I64F64::saturating_from_num(Self::get_bonds_moving_average(netuid))
+                .safe_div(I64F64::saturating_from_num(1_000_000));
 
         // Calculate the alpha value for the EMA calculation.
         // Alpha is derived by subtracting the scaled bonds moving average from 1.
-        let alpha: I32F32 =
-            I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average));
+        let alpha: I32F32 = I32F32::saturating_from_num(1)
+            .saturating_sub(I32F32::saturating_from_num(bonds_moving_average));
 
         // Compute the Exponential Moving Average (EMA) of bonds using the calculated alpha value.
         let ema_bonds = mat_ema_sparse(bonds_delta, bonds, alpha);
@@ -1052,13 +1062,14 @@ impl<T: Config> Pallet<T> {
         netuid: u16,
     ) -> Vec<Vec<I32F32>> {
         // Retrieve the bonds moving average for the given network ID and scale it down.
-        let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid))
-            .safe_div(I64F64::from_num(1_000_000));
+        let bonds_moving_average: I64F64 =
+            I64F64::saturating_from_num(Self::get_bonds_moving_average(netuid))
+                .safe_div(I64F64::saturating_from_num(1_000_000));
 
         // Calculate the alpha value for the EMA calculation.
         // Alpha is derived by subtracting the scaled bonds moving average from 1.
-        let alpha: I32F32 =
-            I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average));
+        let alpha: I32F32 = I32F32::saturating_from_num(1)
+            .saturating_sub(I32F32::saturating_from_num(bonds_moving_average));
 
         // Compute the Exponential Moving Average (EMA) of bonds using the calculated alpha value.
         let ema_bonds = mat_ema(bonds_delta, bonds, alpha);
@@ -1090,7 +1101,9 @@ impl<T: Config> Pallet<T> {
         // This way we avoid the quantil function panic.
         if LiquidAlphaOn::<T>::get(netuid)
             && !consensus.is_empty()
-            && consensus.iter().any(|&c| c != I32F32::from_num(0))
+            && consensus
+                .iter()
+                .any(|&c| c != I32F32::saturating_from_num(0))
         {
             // Calculate the 75th percentile (high) and 25th percentile (low) of the consensus values.
             let consensus_high = quantile(&consensus, 0.75);
@@ -1158,7 +1171,9 @@ impl<T: Config> Pallet<T> {
         // Check if Liquid Alpha is enabled, consensus is not empty, and contains non-zero values.
         if LiquidAlphaOn::<T>::get(netuid)
             && !consensus.is_empty()
-            && consensus.iter().any(|&c| c != I32F32::from_num(0))
+            && consensus
+                .iter()
+                .any(|&c| c != I32F32::saturating_from_num(0))
         {
             // Calculate the 75th percentile (high) and 25th percentile (low) of the consensus values.
             let consensus_high = quantile(&consensus, 0.75);
diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index cbe394037..3fd67e0d8 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -730,7 +730,7 @@ pub mod pallet {
     #[pallet::type_value]
     /// Default value for Share Pool variables
     pub fn DefaultSharePoolZero<T: Config>() -> U64F64 {
-        U64F64::from_num(0)
+        U64F64::saturating_from_num(0)
     }
 
     #[pallet::storage]
diff --git a/pallets/subtensor/src/macros/genesis.rs b/pallets/subtensor/src/macros/genesis.rs
index 96c4db62e..f1288c5a6 100644
--- a/pallets/subtensor/src/macros/genesis.rs
+++ b/pallets/subtensor/src/macros/genesis.rs
@@ -66,13 +66,13 @@ mod genesis {
                 Alpha::<T>::insert(
                     // Lock the initial funds making this key the owner.
                     (hotkey.clone(), hotkey.clone(), netuid),
-                    U64F64::from_num(1_000_000_000),
+                    U64F64::saturating_from_num(1_000_000_000),
                 );
                 TotalHotkeyAlpha::<T>::insert(hotkey.clone(), netuid, 1_000_000_000);
                 TotalHotkeyShares::<T>::insert(
                     hotkey.clone(),
                     netuid,
-                    U64F64::from_num(1_000_000_000),
+                    U64F64::saturating_from_num(1_000_000_000),
                 );
                 // TotalColdkeyAlpha::<T>::insert(hotkey.clone(), netuid, 1_000_000_000);
                 SubnetAlphaOut::<T>::insert(netuid, 1_000_000_000);
diff --git a/pallets/subtensor/src/migrations/migrate_rao.rs b/pallets/subtensor/src/migrations/migrate_rao.rs
index 2b325aadc..ef4a9fecb 100644
--- a/pallets/subtensor/src/migrations/migrate_rao.rs
+++ b/pallets/subtensor/src/migrations/migrate_rao.rs
@@ -45,10 +45,10 @@ pub fn migrate_rao<T: Config>() -> Weight {
         });
         // Set all the stake on root 0 subnet.
         Alpha::<T>::mutate((hotkey.clone(), coldkey.clone(), 0), |total| {
-            *total = total.saturating_add(U64F64::from_num(stake))
+            *total = total.saturating_add(U64F64::saturating_from_num(stake))
         });
         TotalHotkeyShares::<T>::mutate(hotkey.clone(), 0, |total| {
-            *total = total.saturating_add(U64F64::from_num(stake))
+            *total = total.saturating_add(U64F64::saturating_from_num(stake))
         });
         // Set the total stake on the hotkey
         TotalHotkeyAlpha::<T>::mutate(hotkey.clone(), 0, |total| {
diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs
index 0f79ab2eb..f8d641823 100644
--- a/pallets/subtensor/src/rpc_info/delegate_info.rs
+++ b/pallets/subtensor/src/rpc_info/delegate_info.rs
@@ -28,16 +28,16 @@ impl<T: Config> Pallet<T> {
         emissions_per_day: U64F64,
     ) -> U64F64 {
         // Get the take as a percentage and subtract it from 1 for remainder.
-        let without_take: U64F64 =
-            U64F64::from_num(1).saturating_sub(U64F64::from_num(take.0).safe_div(u16::MAX.into()));
+        let without_take: U64F64 = U64F64::saturating_from_num(1)
+            .saturating_sub(U64F64::saturating_from_num(take.0).safe_div(u16::MAX.into()));
 
-        if total_stake > U64F64::from_num(0) {
+        if total_stake > U64F64::saturating_from_num(0) {
             emissions_per_day
                 .saturating_mul(without_take)
                 // Divide by 1000 TAO for return per 1k
-                .safe_div(total_stake.safe_div(U64F64::from_num(1000.0 * 1e9)))
+                .safe_div(total_stake.safe_div(U64F64::saturating_from_num(1000.0 * 1e9)))
         } else {
-            U64F64::from_num(0)
+            U64F64::saturating_from_num(0)
         }
     }
 
@@ -67,7 +67,7 @@ impl<T: Config> Pallet<T> {
 
         let registrations = Self::get_registered_networks_for_hotkey(&delegate.clone());
         let mut validator_permits = Vec::<Compact<u16>>::new();
-        let mut emissions_per_day: U64F64 = U64F64::from_num(0);
+        let mut emissions_per_day: U64F64 = U64F64::saturating_from_num(0);
 
         for netuid in registrations.iter() {
             if let Ok(uid) = Self::get_uid_for_net_and_hotkey(*netuid, &delegate.clone()) {
@@ -78,8 +78,8 @@ impl<T: Config> Pallet<T> {
 
                 let emission: U64F64 = Self::get_emission_for_uid(*netuid, uid).into();
                 let tempo: U64F64 = Self::get_tempo(*netuid).into();
-                if tempo > U64F64::from_num(0) {
-                    let epochs_per_day: U64F64 = U64F64::from_num(7200).safe_div(tempo);
+                if tempo > U64F64::saturating_from_num(0) {
+                    let epochs_per_day: U64F64 = U64F64::saturating_from_num(7200).safe_div(tempo);
                     emissions_per_day =
                         emissions_per_day.saturating_add(emission.saturating_mul(epochs_per_day));
                 }
diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs
index 5bb10e0bb..0cbe3bccf 100644
--- a/pallets/subtensor/src/staking/helpers.rs
+++ b/pallets/subtensor/src/staking/helpers.rs
@@ -46,8 +46,9 @@ impl<T: Config> Pallet<T> {
         Self::get_all_subnet_netuids()
             .iter()
             .map(|netuid| {
-                let alpha: I96F32 =
-                    I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, *netuid));
+                let alpha: I96F32 = I96F32::saturating_from_num(
+                    Self::get_stake_for_hotkey_on_subnet(hotkey, *netuid),
+                );
                 let tao_price: I96F32 = Self::get_alpha_price(*netuid);
                 alpha.saturating_mul(tao_price).saturating_to_num::<u64>()
             })
@@ -65,7 +66,7 @@ impl<T: Config> Pallet<T> {
                 for (netuid, alpha) in Alpha::<T>::iter_prefix((hotkey, coldkey)) {
                     let tao_price: I96F32 = Self::get_alpha_price(netuid);
                     total_stake = total_stake.saturating_add(
-                        I96F32::from_num(alpha)
+                        I96F32::saturating_from_num(alpha)
                             .saturating_mul(tao_price)
                             .saturating_to_num::<u64>(),
                     );
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index 482b7c163..1bd6aa1af 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -32,17 +32,17 @@ impl<T: Config> Pallet<T> {
     /// * `I96F32` - The price of alpha for the specified subnet.
     pub fn get_alpha_price(netuid: u16) -> I96F32 {
         if netuid == Self::get_root_netuid() {
-            return I96F32::from_num(1.0); // Root.
+            return I96F32::saturating_from_num(1.0); // Root.
         }
         if SubnetMechanism::<T>::get(netuid) == 0 {
-            return I96F32::from_num(1.0); // Stable
+            return I96F32::saturating_from_num(1.0); // Stable
         }
         if SubnetAlphaIn::<T>::get(netuid) == 0 {
-            I96F32::from_num(0)
+            I96F32::saturating_from_num(0)
         } else {
-            I96F32::from_num(SubnetTAO::<T>::get(netuid))
-                .checked_div(I96F32::from_num(SubnetAlphaIn::<T>::get(netuid)))
-                .unwrap_or(I96F32::from_num(0))
+            I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid))
+                .checked_div(I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid)))
+                .unwrap_or(I96F32::saturating_from_num(0))
         }
     }
 
@@ -67,11 +67,11 @@ impl<T: Config> Pallet<T> {
         let stored_weight = TaoWeight::<T>::get();
 
         // Step 2: Convert the u64 weight to I96F32
-        let weight_fixed = I96F32::from_num(stored_weight);
+        let weight_fixed = I96F32::saturating_from_num(stored_weight);
 
         // Step 3: Normalize the weight by dividing by u64::MAX
         // This ensures the result is always between 0 and 1
-        weight_fixed.safe_div(I96F32::from_num(u64::MAX))
+        weight_fixed.safe_div(I96F32::saturating_from_num(u64::MAX))
     }
 
     /// Sets the global global weight in storage.
@@ -102,16 +102,17 @@ impl<T: Config> Pallet<T> {
         netuid: u16,
     ) -> (I64F64, I64F64, I64F64) {
         // Retrieve the global tao weight.
-        let tao_weight = I64F64::from_num(Self::get_tao_weight());
+        let tao_weight = I64F64::saturating_from_num(Self::get_tao_weight());
         log::debug!("tao_weight: {:?}", tao_weight);
 
         // Step 1: Get stake of hotkey (neuron)
         let alpha_stake =
-            I64F64::from_num(Self::get_inherited_for_hotkey_on_subnet(hotkey, netuid));
+            I64F64::saturating_from_num(Self::get_inherited_for_hotkey_on_subnet(hotkey, netuid));
         log::trace!("alpha_stake: {:?}", alpha_stake);
 
         // Step 2: Get the global tao stake for the hotkey
-        let tao_stake = I64F64::from_num(Self::get_inherited_for_hotkey_on_subnet(hotkey, 0));
+        let tao_stake =
+            I64F64::saturating_from_num(Self::get_inherited_for_hotkey_on_subnet(hotkey, 0));
         log::trace!("tao_stake: {:?}", tao_stake);
 
         // Step 3: Combine alpha and tao stakes
@@ -125,7 +126,7 @@ impl<T: Config> Pallet<T> {
     ///
     pub fn get_stake_weights_for_network(netuid: u16) -> (Vec<I64F64>, Vec<I64F64>, Vec<I64F64>) {
         // Retrieve the global tao weight.
-        let tao_weight: I64F64 = I64F64::from_num(Self::get_tao_weight());
+        let tao_weight: I64F64 = I64F64::saturating_from_num(Self::get_tao_weight());
         log::debug!("tao_weight: {:?}", tao_weight);
 
         // Step 1: Get subnetwork size
@@ -136,9 +137,11 @@ impl<T: Config> Pallet<T> {
             .map(|uid| {
                 if Keys::<T>::contains_key(netuid, uid) {
                     let hotkey: T::AccountId = Keys::<T>::get(netuid, uid);
-                    I64F64::from_num(Self::get_inherited_for_hotkey_on_subnet(&hotkey, netuid))
+                    I64F64::saturating_from_num(Self::get_inherited_for_hotkey_on_subnet(
+                        &hotkey, netuid,
+                    ))
                 } else {
-                    I64F64::from_num(0)
+                    I64F64::saturating_from_num(0)
                 }
             })
             .collect();
@@ -150,9 +153,11 @@ impl<T: Config> Pallet<T> {
             .map(|uid| {
                 if Keys::<T>::contains_key(netuid, uid) {
                     let hotkey: T::AccountId = Keys::<T>::get(netuid, uid);
-                    I64F64::from_num(Self::get_inherited_for_hotkey_on_subnet(&hotkey, 0))
+                    I64F64::saturating_from_num(Self::get_inherited_for_hotkey_on_subnet(
+                        &hotkey, 0,
+                    ))
                 } else {
-                    I64F64::from_num(0)
+                    I64F64::saturating_from_num(0)
                 }
             })
             .collect();
@@ -200,7 +205,7 @@ impl<T: Config> Pallet<T> {
     pub fn get_inherited_for_hotkey_on_subnet(hotkey: &T::AccountId, netuid: u16) -> u64 {
         // Step 1: Retrieve the initial total stake (alpha) for the hotkey on the specified subnet.
         let initial_alpha: I96F32 =
-            I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid));
+            I96F32::saturating_from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid));
         log::trace!(
             "Initial alpha for hotkey {:?} on subnet {}: {:?}",
             hotkey,
@@ -212,8 +217,8 @@ impl<T: Config> Pallet<T> {
         }
 
         // Initialize variables to track alpha allocated to children and inherited from parents.
-        let mut alpha_to_children: I96F32 = I96F32::from_num(0);
-        let mut alpha_from_parents: I96F32 = I96F32::from_num(0);
+        let mut alpha_to_children: I96F32 = I96F32::saturating_from_num(0);
+        let mut alpha_from_parents: I96F32 = I96F32::saturating_from_num(0);
 
         // Step 2: Retrieve the lists of parents and children for the hotkey on the subnet.
         let parents: Vec<(u64, T::AccountId)> = Self::get_parents(hotkey, netuid);
@@ -234,8 +239,8 @@ impl<T: Config> Pallet<T> {
         // Step 3: Calculate the total alpha allocated to children.
         for (proportion, _) in children {
             // Convert the proportion to a normalized value between 0 and 1.
-            let normalized_proportion: I96F32 =
-                I96F32::from_num(proportion).safe_div(I96F32::from_num(u64::MAX));
+            let normalized_proportion: I96F32 = I96F32::saturating_from_num(proportion)
+                .safe_div(I96F32::saturating_from_num(u64::MAX));
             log::trace!(
                 "Normalized proportion for child: {:?}",
                 normalized_proportion
@@ -243,7 +248,7 @@ impl<T: Config> Pallet<T> {
 
             // Calculate the amount of alpha to be allocated to this child.
             let alpha_proportion_to_child: I96F32 =
-                I96F32::from_num(initial_alpha).saturating_mul(normalized_proportion);
+                I96F32::saturating_from_num(initial_alpha).saturating_mul(normalized_proportion);
             log::trace!("Alpha proportion to child: {:?}", alpha_proportion_to_child);
 
             // Add this child's allocation to the total alpha allocated to children.
@@ -255,7 +260,7 @@ impl<T: Config> Pallet<T> {
         for (proportion, parent) in parents {
             // Retrieve the parent's total stake on this subnet.
             let parent_alpha: I96F32 =
-                I96F32::from_num(Self::get_stake_for_hotkey_on_subnet(&parent, netuid));
+                I96F32::saturating_from_num(Self::get_stake_for_hotkey_on_subnet(&parent, netuid));
             log::trace!(
                 "Parent alpha for parent {:?} on subnet {}: {:?}",
                 parent,
@@ -264,8 +269,8 @@ impl<T: Config> Pallet<T> {
             );
 
             // Convert the proportion to a normalized value between 0 and 1.
-            let normalized_proportion: I96F32 =
-                I96F32::from_num(proportion).safe_div(I96F32::from_num(u64::MAX));
+            let normalized_proportion: I96F32 = I96F32::saturating_from_num(proportion)
+                .safe_div(I96F32::saturating_from_num(u64::MAX));
             log::trace!(
                 "Normalized proportion from parent: {:?}",
                 normalized_proportion
@@ -273,7 +278,7 @@ impl<T: Config> Pallet<T> {
 
             // Calculate the amount of alpha to be inherited from this parent.
             let alpha_proportion_from_parent: I96F32 =
-                I96F32::from_num(parent_alpha).saturating_mul(normalized_proportion);
+                I96F32::saturating_from_num(parent_alpha).saturating_mul(normalized_proportion);
             log::trace!(
                 "Alpha proportion from parent: {:?}",
                 alpha_proportion_from_parent
@@ -461,19 +466,20 @@ impl<T: Config> Pallet<T> {
         // Step 2: Initialized vars.
         let alpha: I96F32 = if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 = I96F32::from_num(SubnetAlphaIn::<T>::get(netuid));
+            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
+            let alpha_reserves: I96F32 =
+                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
             let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // alpha_stake_recieved = current_alpha - (k / (current_tao + new_tao))
             alpha_reserves.saturating_sub(
-                k.checked_div(tao_reserves.saturating_add(I96F32::from_num(tao)))
-                    .unwrap_or(I96F32::from_num(0)),
+                k.checked_div(tao_reserves.saturating_add(I96F32::saturating_from_num(tao)))
+                    .unwrap_or(I96F32::saturating_from_num(0)),
             )
         } else {
             // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::from_num(tao)
+            I96F32::saturating_from_num(tao)
         };
         // Return simulated amount.
         alpha.saturating_to_num::<u64>()
@@ -488,19 +494,20 @@ impl<T: Config> Pallet<T> {
         // Step 2: Swap alpha and attain tao
         let tao: I96F32 = if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 = I96F32::from_num(SubnetAlphaIn::<T>::get(netuid));
+            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
+            let alpha_reserves: I96F32 =
+                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
             let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // tao_recieved = tao_reserves - (k / (alpha_reserves + new_tao))
             tao_reserves.saturating_sub(
-                k.checked_div(alpha_reserves.saturating_add(I96F32::from_num(alpha)))
-                    .unwrap_or(I96F32::from_num(0)),
+                k.checked_div(alpha_reserves.saturating_add(I96F32::saturating_from_num(alpha)))
+                    .unwrap_or(I96F32::saturating_from_num(0)),
             )
         } else {
             // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::from_num(alpha)
+            I96F32::saturating_from_num(alpha)
         };
         tao.saturating_to_num::<u64>()
     }
@@ -514,19 +521,20 @@ impl<T: Config> Pallet<T> {
         // Step 2: Initialized vars.
         let alpha: I96F32 = if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 = I96F32::from_num(SubnetAlphaIn::<T>::get(netuid));
+            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
+            let alpha_reserves: I96F32 =
+                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
             let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // alpha_stake_recieved = current_alpha - (k / (current_tao + new_tao))
             alpha_reserves.saturating_sub(
-                k.checked_div(tao_reserves.saturating_add(I96F32::from_num(tao)))
-                    .unwrap_or(I96F32::from_num(0)),
+                k.checked_div(tao_reserves.saturating_add(I96F32::saturating_from_num(tao)))
+                    .unwrap_or(I96F32::saturating_from_num(0)),
             )
         } else {
             // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::from_num(tao)
+            I96F32::saturating_from_num(tao)
         };
         // Step 4. Decrease Alpha reserves.
         SubnetAlphaIn::<T>::mutate(netuid, |total| {
@@ -561,19 +569,20 @@ impl<T: Config> Pallet<T> {
         // Step 2: Swap alpha and attain tao
         let tao: I96F32 = if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 = I96F32::from_num(SubnetAlphaIn::<T>::get(netuid));
+            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
+            let alpha_reserves: I96F32 =
+                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
             let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // tao_recieved = tao_reserves - (k / (alpha_reserves + new_tao))
             tao_reserves.saturating_sub(
-                k.checked_div(alpha_reserves.saturating_add(I96F32::from_num(alpha)))
-                    .unwrap_or(I96F32::from_num(0)),
+                k.checked_div(alpha_reserves.saturating_add(I96F32::saturating_from_num(alpha)))
+                    .unwrap_or(I96F32::saturating_from_num(0)),
             )
         } else {
             // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::from_num(alpha)
+            I96F32::saturating_from_num(alpha)
         };
         // Step 4: Increase Alpha reserves.
         SubnetAlphaIn::<T>::mutate(netuid, |total| {
@@ -871,7 +880,7 @@ impl<T: Config> SharePoolDataOperations<AlphaShareKey<T>>
     for HotkeyAlphaSharePoolDataOperations<T>
 {
     fn get_shared_value(&self) -> U64F64 {
-        U64F64::from_num(crate::TotalHotkeyAlpha::<T>::get(&self.hotkey, self.netuid))
+        U64F64::saturating_from_num(crate::TotalHotkeyAlpha::<T>::get(&self.hotkey, self.netuid))
     }
 
     fn get_share(&self, key: &AlphaShareKey<T>) -> U64F64 {
diff --git a/pallets/subtensor/src/tests/math.rs b/pallets/subtensor/src/tests/math.rs
index 7409ed8eb..59d826ab3 100644
--- a/pallets/subtensor/src/tests/math.rs
+++ b/pallets/subtensor/src/tests/math.rs
@@ -2305,10 +2305,9 @@ fn test_math_fixed64_to_fixed32() {
 }
 
 #[test]
-#[should_panic(expected = "overflow")]
-fn test_math_fixed64_to_fixed32_panics() {
+fn test_math_fixed64_to_fixed32_saturates() {
     let bad_input = I64F64::from_num(u32::MAX);
-    fixed64_to_fixed32(bad_input);
+    assert_eq!(fixed64_to_fixed32(bad_input), I32F32::max_value());
 }
 
 #[test]
@@ -2362,10 +2361,9 @@ fn test_vec_fixed64_to_fixed32() {
 }
 
 #[test]
-#[should_panic(expected = "overflow")]
-fn test_vec_fixed64_to_fixed32_panics() {
+fn test_vec_fixed64_to_fixed32_saturates() {
     let bad_input = vec![I64F64::from_num(i64::MAX)];
-    vec_fixed64_to_fixed32(bad_input);
+    assert_eq!(vec_fixed64_to_fixed32(bad_input), [I32F32::max_value()]);
 }
 
 #[test]
diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs
index 4749d6594..b27921f27 100644
--- a/pallets/subtensor/src/utils/misc.rs
+++ b/pallets/subtensor/src/utils/misc.rs
@@ -593,7 +593,8 @@ impl<T: Config> Pallet<T> {
         SubnetOwnerCut::<T>::get()
     }
     pub fn get_float_subnet_owner_cut() -> I96F32 {
-        I96F32::from_num(SubnetOwnerCut::<T>::get()).safe_div(I96F32::from_num(u16::MAX))
+        I96F32::saturating_from_num(SubnetOwnerCut::<T>::get())
+            .safe_div(I96F32::saturating_from_num(u16::MAX))
     }
     pub fn set_subnet_owner_cut(subnet_owner_cut: u16) {
         SubnetOwnerCut::<T>::set(subnet_owner_cut);
@@ -665,8 +666,10 @@ impl<T: Config> Pallet<T> {
 
     pub fn get_alpha_values_32(netuid: u16) -> (I32F32, I32F32) {
         let (alpha_low, alpha_high): (u16, u16) = AlphaValues::<T>::get(netuid);
-        let converted_low = I32F32::from_num(alpha_low).safe_div(I32F32::from_num(u16::MAX));
-        let converted_high = I32F32::from_num(alpha_high).safe_div(I32F32::from_num(u16::MAX));
+        let converted_low =
+            I32F32::saturating_from_num(alpha_low).safe_div(I32F32::saturating_from_num(u16::MAX));
+        let converted_high =
+            I32F32::saturating_from_num(alpha_high).safe_div(I32F32::saturating_from_num(u16::MAX));
 
         (converted_low, converted_high)
     }
diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs
index 8af506945..f3e00fca9 100644
--- a/primitives/share-pool/src/lib.rs
+++ b/primitives/share-pool/src/lib.rs
@@ -52,7 +52,7 @@ where
 
         shared_value
             .checked_div(denominator)
-            .unwrap_or(U64F64::from_num(0))
+            .unwrap_or(U64F64::saturating_from_num(0))
             .saturating_mul(current_share)
             .saturating_to_num::<u64>()
     }
@@ -69,9 +69,9 @@ where
     pub fn update_value_for_all(&mut self, update: i64) {
         let shared_value: U64F64 = self.state_ops.get_shared_value();
         self.state_ops.set_shared_value(if update >= 0 {
-            shared_value.saturating_add(U64F64::from_num(update))
+            shared_value.saturating_add(U64F64::saturating_from_num(update))
         } else {
-            shared_value.saturating_sub(U64F64::from_num(update.neg()))
+            shared_value.saturating_sub(U64F64::saturating_from_num(update.neg()))
         });
     }
 
@@ -92,31 +92,33 @@ where
             self.state_ops.set_share(key, new_shared_value);
         } else {
             // There are already keys in the pool, set or update this key
-            let value_per_share: I64F64 = I64F64::from_num(
+            let value_per_share: I64F64 = I64F64::saturating_from_num(
                 shared_value
                     .checked_div(denominator) // denominator is never 0 here
-                    .unwrap_or(U64F64::from_num(0)),
+                    .unwrap_or(U64F64::saturating_from_num(0)),
             );
 
-            let shares_per_update: I64F64 = I64F64::from_num(update)
+            let shares_per_update: I64F64 = I64F64::saturating_from_num(update)
                 .checked_div(value_per_share)
-                .unwrap_or(I64F64::from_num(0));
+                .unwrap_or(I64F64::saturating_from_num(0));
 
             if shares_per_update >= 0 {
                 self.state_ops.set_denominator(
-                    denominator.saturating_add(U64F64::from_num(shares_per_update)),
+                    denominator.saturating_add(U64F64::saturating_from_num(shares_per_update)),
                 );
                 self.state_ops.set_share(
                     key,
-                    current_share.saturating_add(U64F64::from_num(shares_per_update)),
+                    current_share.saturating_add(U64F64::saturating_from_num(shares_per_update)),
                 );
             } else {
                 self.state_ops.set_denominator(
-                    denominator.saturating_sub(U64F64::from_num(shares_per_update.neg())),
+                    denominator
+                        .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())),
                 );
                 self.state_ops.set_share(
                     key,
-                    current_share.saturating_sub(U64F64::from_num(shares_per_update.neg())),
+                    current_share
+                        .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())),
                 );
             }
         }
@@ -137,9 +139,9 @@ mod tests {
     impl MockSharePoolDataOperations {
         fn new() -> Self {
             MockSharePoolDataOperations {
-                shared_value: U64F64::from_num(0),
+                shared_value: U64F64::saturating_from_num(0),
                 share: BTreeMap::new(),
-                denominator: U64F64::from_num(0),
+                denominator: U64F64::saturating_from_num(0),
             }
         }
     }
@@ -150,7 +152,10 @@ mod tests {
         }
 
         fn get_share(&self, key: &u16) -> U64F64 {
-            *self.share.get(key).unwrap_or(&U64F64::from_num(0))
+            *self
+                .share
+                .get(key)
+                .unwrap_or(&U64F64::saturating_from_num(0))
         }
 
         fn try_get_share(&self, key: &u16) -> Result<U64F64, ()> {
@@ -180,10 +185,10 @@ mod tests {
     #[test]
     fn test_get_value() {
         let mut mock_ops = MockSharePoolDataOperations::new();
-        mock_ops.set_denominator(U64F64::from_num(10));
-        mock_ops.set_share(&1_u16, U64F64::from_num(3));
-        mock_ops.set_share(&2_u16, U64F64::from_num(7));
-        mock_ops.set_shared_value(U64F64::from_num(100));
+        mock_ops.set_denominator(U64F64::saturating_from_num(10));
+        mock_ops.set_share(&1_u16, U64F64::saturating_from_num(3));
+        mock_ops.set_share(&2_u16, U64F64::saturating_from_num(7));
+        mock_ops.set_shared_value(U64F64::saturating_from_num(100));
         let share_pool = SharePool::new(mock_ops);
         let result1 = share_pool.get_value(&1);
         let result2 = share_pool.get_value(&2);
@@ -194,7 +199,7 @@ mod tests {
     #[test]
     fn test_division_by_zero() {
         let mut mock_ops = MockSharePoolDataOperations::new();
-        mock_ops.set_denominator(U64F64::from_num(0)); // Zero denominator
+        mock_ops.set_denominator(U64F64::saturating_from_num(0)); // Zero denominator
         let pool = SharePool::<u16, MockSharePoolDataOperations>::new(mock_ops);
 
         let value = pool.get_value(&1);
@@ -204,10 +209,10 @@ mod tests {
     #[test]
     fn test_max_shared_value() {
         let mut mock_ops = MockSharePoolDataOperations::new();
-        mock_ops.set_shared_value(U64F64::from_num(u64::MAX));
-        mock_ops.set_share(&1, U64F64::from_num(3)); // Use a neutral value for share
-        mock_ops.set_share(&2, U64F64::from_num(7)); // Use a neutral value for share
-        mock_ops.set_denominator(U64F64::from_num(10)); // Neutral value to see max effect
+        mock_ops.set_shared_value(U64F64::saturating_from_num(u64::MAX));
+        mock_ops.set_share(&1, U64F64::saturating_from_num(3)); // Use a neutral value for share
+        mock_ops.set_share(&2, U64F64::saturating_from_num(7)); // Use a neutral value for share
+        mock_ops.set_denominator(U64F64::saturating_from_num(10)); // Neutral value to see max effect
         let pool = SharePool::<u16, MockSharePoolDataOperations>::new(mock_ops);
 
         let max_value = pool.get_value(&1) + pool.get_value(&2);
@@ -217,10 +222,10 @@ mod tests {
     #[test]
     fn test_max_share_value() {
         let mut mock_ops = MockSharePoolDataOperations::new();
-        mock_ops.set_shared_value(U64F64::from_num(1_000_000_000)); // Use a neutral value for shared value
-        mock_ops.set_share(&1, U64F64::from_num(u64::MAX / 2));
-        mock_ops.set_share(&2, U64F64::from_num(u64::MAX / 2));
-        mock_ops.set_denominator(U64F64::from_num(u64::MAX));
+        mock_ops.set_shared_value(U64F64::saturating_from_num(1_000_000_000)); // Use a neutral value for shared value
+        mock_ops.set_share(&1, U64F64::saturating_from_num(u64::MAX / 2));
+        mock_ops.set_share(&2, U64F64::saturating_from_num(u64::MAX / 2));
+        mock_ops.set_denominator(U64F64::saturating_from_num(u64::MAX));
         let pool = SharePool::<u16, MockSharePoolDataOperations>::new(mock_ops);
 
         let value1 = pool.get_value(&1) as i128;
@@ -268,6 +273,9 @@ mod tests {
         let mut pool = SharePool::<u16, MockSharePoolDataOperations>::new(mock_ops);
 
         pool.update_value_for_all(1000);
-        assert_eq!(pool.state_ops.shared_value, U64F64::from_num(1000));
+        assert_eq!(
+            pool.state_ops.shared_value,
+            U64F64::saturating_from_num(1000)
+        );
     }
 }

From 72f35e0a478a0e4a3c448545358475f63a2426d3 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 15:45:39 -0500
Subject: [PATCH 096/145] Fix zepter

---
 primitives/safe-math/Cargo.toml  | 1 +
 primitives/share-pool/Cargo.toml | 1 +
 2 files changed, 2 insertions(+)

diff --git a/primitives/safe-math/Cargo.toml b/primitives/safe-math/Cargo.toml
index f50ac6b90..f67d53c5d 100644
--- a/primitives/safe-math/Cargo.toml
+++ b/primitives/safe-math/Cargo.toml
@@ -16,4 +16,5 @@ default = ["std"]
 std = [
 	"substrate-fixed/std",
 	"sp-std/std",
+	"num-traits/std",
 ]
diff --git a/primitives/share-pool/Cargo.toml b/primitives/share-pool/Cargo.toml
index 370f32cbb..e0696ee30 100644
--- a/primitives/share-pool/Cargo.toml
+++ b/primitives/share-pool/Cargo.toml
@@ -16,4 +16,5 @@ default = ["std"]
 std = [
 	"substrate-fixed/std",
 	"sp-std/std",
+	"safe-math/std",
 ]

From ffa8a6e2a057e6bb6272fb31a1eff607703b2bfa Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 15:50:38 -0500
Subject: [PATCH 097/145] Fix zepter

---
 pallets/subtensor/Cargo.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pallets/subtensor/Cargo.toml b/pallets/subtensor/Cargo.toml
index e8085615d..f22f855fc 100644
--- a/pallets/subtensor/Cargo.toml
+++ b/pallets/subtensor/Cargo.toml
@@ -105,6 +105,7 @@ std = [
 	"ark-serialize/std",
 	"w3f-bls/std",
 	"rand_chacha/std",
+	"safe-math/std",
 	"sha2/std",
 	"share-pool/std"
 ]

From 95d2d533b5beb6b0322f95a4a96c2db6e8182fd9 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 18:30:09 -0500
Subject: [PATCH 098/145] Invalidate staking and unstaking transactions if
 liquidity is inadequate

---
 pallets/subtensor/src/lib.rs                 |  15 +-
 pallets/subtensor/src/macros/errors.rs       |   2 +
 pallets/subtensor/src/staking/stake_utils.rs | 235 ++++++++++---------
 3 files changed, 136 insertions(+), 116 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 3fd67e0d8..c26a2a422 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -82,7 +82,7 @@ pub mod pallet {
     use sp_std::collections::vec_deque::VecDeque;
     use sp_std::vec;
     use sp_std::vec::Vec;
-    use substrate_fixed::types::U64F64;
+    use substrate_fixed::types::{I96F32, U64F64};
     use subtensor_macros::freeze_struct;
 
     #[cfg(not(feature = "std"))]
@@ -733,6 +733,13 @@ pub mod pallet {
         U64F64::saturating_from_num(0)
     }
 
+    #[pallet::type_value]
+    /// Default value for minimum liquidity in pool
+    pub fn DefaultMinimumPoolLiquidity<T: Config>() -> I96F32 {
+        // I96F32::saturating_from_num(1_000_000)
+        I96F32::saturating_from_num(0)
+    }
+
     #[pallet::storage]
     pub type ColdkeySwapScheduleDuration<T: Config> =
         StorageValue<_, BlockNumberFor<T>, ValueQuery, DefaultColdkeySwapScheduleDuration<T>>;
@@ -1562,6 +1569,7 @@ pub enum CustomTransactionError {
     HotkeyAccountDoesntExist,
     NotEnoughStakeToWithdraw,
     RateLimitExceeded,
+    InsufficientLiquidity,
     BadRequest,
 }
 
@@ -1575,6 +1583,7 @@ impl From<CustomTransactionError> for u8 {
             CustomTransactionError::HotkeyAccountDoesntExist => 4,
             CustomTransactionError::NotEnoughStakeToWithdraw => 5,
             CustomTransactionError::RateLimitExceeded => 6,
+            CustomTransactionError::InsufficientLiquidity => 7,
             CustomTransactionError::BadRequest => 255,
         }
     }
@@ -1642,6 +1651,10 @@ where
                     CustomTransactionError::NotEnoughStakeToWithdraw.into(),
                 )
                 .into()),
+                Error::<T>::InsufficientLiquidity => Err(InvalidTransaction::Custom(
+                    CustomTransactionError::InsufficientLiquidity.into(),
+                )
+                .into()),
                 _ => Err(
                     InvalidTransaction::Custom(CustomTransactionError::BadRequest.into()).into(),
                 ),
diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs
index dd5e97b78..f1eea3b9c 100644
--- a/pallets/subtensor/src/macros/errors.rs
+++ b/pallets/subtensor/src/macros/errors.rs
@@ -185,5 +185,7 @@ mod errors {
         CommittingWeightsTooFast,
         /// Stake amount is too low.
         AmountTooLow,
+        /// Not enough liquidity.
+        InsufficientLiquidity,
     }
 }
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index 1bd6aa1af..284d484da 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -457,155 +457,148 @@ impl<T: Config> Pallet<T> {
         }
     }
 
-    /// Swaps TAO for the alpha token on the subnet.
+    /// Calculates Some(Alpha) returned from pool by staking operation
+    /// if liquidity allows that. If not, returns None.
     ///
-    /// Updates TaoIn, AlphaIn, and AlphaOut
-    pub fn sim_swap_tao_for_alpha(netuid: u16, tao: u64) -> u64 {
+    /// If new alpha_reserve is about to drop below DefaultMinimumPoolLiquidity,
+    /// then don't do it.
+    ///
+    pub fn sim_swap_tao_for_alpha(netuid: u16, tao: u64) -> Option<u64> {
         // Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
         let mechanism_id: u16 = SubnetMechanism::<T>::get(netuid);
         // Step 2: Initialized vars.
-        let alpha: I96F32 = if mechanism_id == 1 {
+        if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
             let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
             let alpha_reserves: I96F32 =
                 I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
             let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
+
+            // Calculate new alpha reserve
+            let new_alpha_reserves: I96F32 = k
+                .checked_div(tao_reserves.saturating_add(I96F32::saturating_from_num(tao)))
+                .unwrap_or(I96F32::saturating_from_num(0));
+
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // alpha_stake_recieved = current_alpha - (k / (current_tao + new_tao))
-            alpha_reserves.saturating_sub(
-                k.checked_div(tao_reserves.saturating_add(I96F32::saturating_from_num(tao)))
-                    .unwrap_or(I96F32::saturating_from_num(0)),
-            )
+            if new_alpha_reserves >= DefaultMinimumPoolLiquidity::<T>::get() {
+                Some(
+                    alpha_reserves
+                        .saturating_sub(new_alpha_reserves)
+                        .saturating_to_num::<u64>(),
+                )
+            } else {
+                None
+            }
         } else {
             // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::saturating_from_num(tao)
-        };
-        // Return simulated amount.
-        alpha.saturating_to_num::<u64>()
+            Some(tao)
+        }
     }
 
-    /// Swaps a subnet's Alpba token for TAO.
+    /// Calculates Some(Tao) returned from pool by unstaking operation
+    /// if liquidity allows that. If not, returns None.
     ///
-    /// Updates TaoIn, AlphaIn, and AlphaOut
-    pub fn sim_swap_alpha_for_tao(netuid: u16, alpha: u64) -> u64 {
+    /// If new tao_reserve is about to drop below DefaultMinimumPoolLiquidity,
+    /// then don't do it.
+    ///
+    pub fn sim_swap_alpha_for_tao(netuid: u16, alpha: u64) -> Option<u64> {
         // Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
         let mechanism_id: u16 = SubnetMechanism::<T>::get(netuid);
         // Step 2: Swap alpha and attain tao
-        let tao: I96F32 = if mechanism_id == 1 {
+        if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
             let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
             let alpha_reserves: I96F32 =
                 I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
             let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
+
+            // Calculate new tao reserve
+            let new_tao_reserves: I96F32 = k
+                .checked_div(alpha_reserves.saturating_add(I96F32::saturating_from_num(alpha)))
+                .unwrap_or(I96F32::saturating_from_num(0));
+
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // tao_recieved = tao_reserves - (k / (alpha_reserves + new_tao))
-            tao_reserves.saturating_sub(
-                k.checked_div(alpha_reserves.saturating_add(I96F32::saturating_from_num(alpha)))
-                    .unwrap_or(I96F32::saturating_from_num(0)),
-            )
+            if new_tao_reserves >= DefaultMinimumPoolLiquidity::<T>::get() {
+                Some(
+                    tao_reserves
+                        .saturating_sub(new_tao_reserves)
+                        .saturating_to_num::<u64>(),
+                )
+            } else {
+                None
+            }
         } else {
             // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::saturating_from_num(alpha)
-        };
-        tao.saturating_to_num::<u64>()
+            Some(alpha)
+        }
     }
 
     /// Swaps TAO for the alpha token on the subnet.
     ///
     /// Updates TaoIn, AlphaIn, and AlphaOut
     pub fn swap_tao_for_alpha(netuid: u16, tao: u64) -> u64 {
-        // Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
-        let mechanism_id: u16 = SubnetMechanism::<T>::get(netuid);
-        // Step 2: Initialized vars.
-        let alpha: I96F32 = if mechanism_id == 1 {
-            // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 =
-                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
-            // Step 3.a.2: Compute constant product k = alpha * tao
-            let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
-            // Step 3.a.3: Calculate alpha staked using the constant product formula
-            // alpha_stake_recieved = current_alpha - (k / (current_tao + new_tao))
-            alpha_reserves.saturating_sub(
-                k.checked_div(tao_reserves.saturating_add(I96F32::saturating_from_num(tao)))
-                    .unwrap_or(I96F32::saturating_from_num(0)),
-            )
+        if let Some(alpha) = Self::sim_swap_tao_for_alpha(netuid, tao) {
+            // Step 4. Decrease Alpha reserves.
+            SubnetAlphaIn::<T>::mutate(netuid, |total| {
+                *total = total.saturating_sub(alpha);
+            });
+            // Step 5: Increase Alpha outstanding.
+            SubnetAlphaOut::<T>::mutate(netuid, |total| {
+                *total = total.saturating_add(alpha);
+            });
+            // Step 6: Increase Tao reserves.
+            SubnetTAO::<T>::mutate(netuid, |total| {
+                *total = total.saturating_add(tao);
+            });
+            // Step 7: Increase Total Tao reserves.
+            TotalStake::<T>::mutate(|total| {
+                *total = total.saturating_add(tao);
+            });
+            // Step 8. Decrease Alpha reserves.
+            SubnetVolume::<T>::mutate(netuid, |total| {
+                *total = total.saturating_sub(tao);
+            });
+            // Step 9. Return the alpha received.
+            alpha
         } else {
-            // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::saturating_from_num(tao)
-        };
-        // Step 4. Decrease Alpha reserves.
-        SubnetAlphaIn::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(alpha.saturating_to_num::<u64>());
-        });
-        // Step 5: Increase Alpha outstanding.
-        SubnetAlphaOut::<T>::mutate(netuid, |total| {
-            *total = total.saturating_add(alpha.saturating_to_num::<u64>());
-        });
-        // Step 6: Increase Tao reserves.
-        SubnetTAO::<T>::mutate(netuid, |total| {
-            *total = total.saturating_add(tao);
-        });
-        // Step 7: Increase Total Tao reserves.
-        TotalStake::<T>::mutate(|total| {
-            *total = total.saturating_add(tao);
-        });
-        // Step 8. Decrease Alpha reserves.
-        SubnetVolume::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(tao);
-        });
-        // Step 9. Return the alpha received.
-        alpha.saturating_to_num::<u64>()
+            0
+        }
     }
 
     /// Swaps a subnet's Alpba token for TAO.
     ///
     /// Updates TaoIn, AlphaIn, and AlphaOut
     pub fn swap_alpha_for_tao(netuid: u16, alpha: u64) -> u64 {
-        // Step 1: Get the mechanism type for the subnet (0 for Stable, 1 for Dynamic)
-        let mechanism_id: u16 = SubnetMechanism::<T>::get(netuid);
-        // Step 2: Swap alpha and attain tao
-        let tao: I96F32 = if mechanism_id == 1 {
-            // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 =
-                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
-            // Step 3.a.2: Compute constant product k = alpha * tao
-            let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
-            // Step 3.a.3: Calculate alpha staked using the constant product formula
-            // tao_recieved = tao_reserves - (k / (alpha_reserves + new_tao))
-            tao_reserves.saturating_sub(
-                k.checked_div(alpha_reserves.saturating_add(I96F32::saturating_from_num(alpha)))
-                    .unwrap_or(I96F32::saturating_from_num(0)),
-            )
+        if let Some(tao) = Self::sim_swap_tao_for_alpha(netuid, alpha) {
+            // Step 4: Increase Alpha reserves.
+            SubnetAlphaIn::<T>::mutate(netuid, |total| {
+                *total = total.saturating_add(alpha);
+            });
+            // Step 5: Decrease Alpha outstanding.
+            SubnetAlphaOut::<T>::mutate(netuid, |total| {
+                *total = total.saturating_sub(alpha);
+            });
+            // Step 6: Decrease tao reserves.
+            SubnetTAO::<T>::mutate(netuid, |total| {
+                *total = total.saturating_sub(tao);
+            });
+            // Step 7: Reduce total TAO reserves.
+            TotalStake::<T>::mutate(|total| {
+                *total = total.saturating_sub(tao);
+            });
+            // Step 8. Decrease Alpha reserves.
+            SubnetVolume::<T>::mutate(netuid, |total| {
+                *total = total.saturating_sub(tao);
+            });
+            // Step 9. Return the tao received.
+            tao
         } else {
-            // Step 3.b.1: Stable mechanism, just return the value 1:1
-            I96F32::saturating_from_num(alpha)
-        };
-        // Step 4: Increase Alpha reserves.
-        SubnetAlphaIn::<T>::mutate(netuid, |total| {
-            *total = total.saturating_add(alpha);
-        });
-        // Step 5: Decrease Alpha outstanding.
-        SubnetAlphaOut::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(alpha);
-        });
-        // Step 6: Decrease tao reserves.
-        SubnetTAO::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(tao.saturating_to_num::<u64>());
-        });
-        // Step 7: Reduce total TAO reserves.
-        TotalStake::<T>::mutate(|total| {
-            *total = total.saturating_sub(tao.saturating_to_num::<u64>());
-        });
-        // Step 8. Decrease Alpha reserves.
-        SubnetVolume::<T>::mutate(netuid, |total| {
-            *total = total.saturating_sub(tao.saturating_to_num::<u64>());
-        });
-        // Step 9. Return the tao received.
-        tao.saturating_to_num::<u64>()
+            0
+        }
     }
 
     /// Unstakes alpha from a subnet for a given hotkey and coldkey pair.
@@ -759,6 +752,12 @@ impl<T: Config> Pallet<T> {
             Error::<T>::HotKeyAccountNotExists
         );
 
+        // Ensure that we have adequate liquidity
+        ensure!(
+            Self::sim_swap_tao_for_alpha(netuid, stake_to_be_added).is_some(),
+            Error::<T>::InsufficientLiquidity
+        );
+
         Ok(())
     }
 
@@ -774,11 +773,14 @@ impl<T: Config> Pallet<T> {
         ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
 
         // Ensure that the stake amount to be removed is above the minimum in tao equivalent.
-        let tao_equivalent = Self::sim_swap_alpha_for_tao(netuid, alpha_unstaked);
-        ensure!(
-            tao_equivalent > DefaultMinStake::<T>::get(),
-            Error::<T>::AmountTooLow
-        );
+        if let Some(tao_equivalent) = Self::sim_swap_alpha_for_tao(netuid, alpha_unstaked) {
+            ensure!(
+                tao_equivalent > DefaultMinStake::<T>::get(),
+                Error::<T>::AmountTooLow
+            );
+        } else {
+            return Err(Error::<T>::InsufficientLiquidity);
+        };
 
         // Ensure that the hotkey account exists this is only possible through registration.
         ensure!(
@@ -843,11 +845,14 @@ impl<T: Config> Pallet<T> {
         );
 
         // Ensure that the stake amount to be removed is above the minimum in tao equivalent.
-        let tao_equivalent = Self::sim_swap_alpha_for_tao(origin_netuid, alpha_amount);
-        ensure!(
-            tao_equivalent > DefaultMinStake::<T>::get(),
-            Error::<T>::AmountTooLow
-        );
+        if let Some(tao_equivalent) = Self::sim_swap_alpha_for_tao(origin_netuid, alpha_amount) {
+            ensure!(
+                tao_equivalent > DefaultMinStake::<T>::get(),
+                Error::<T>::AmountTooLow
+            );
+        } else {
+            return Err(Error::<T>::InsufficientLiquidity);
+        }
 
         Ok(())
     }

From bbc542d82411425b4036ca03892acc926e104a9b Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 18:41:16 -0500
Subject: [PATCH 099/145] Fix swap_alpha_for_tao

---
 pallets/subtensor/src/staking/stake_utils.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index 284d484da..d68f2eb1c 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -573,7 +573,7 @@ impl<T: Config> Pallet<T> {
     ///
     /// Updates TaoIn, AlphaIn, and AlphaOut
     pub fn swap_alpha_for_tao(netuid: u16, alpha: u64) -> u64 {
-        if let Some(tao) = Self::sim_swap_tao_for_alpha(netuid, alpha) {
+        if let Some(tao) = Self::sim_swap_alpha_for_tao(netuid, alpha) {
             // Step 4: Increase Alpha reserves.
             SubnetAlphaIn::<T>::mutate(netuid, |total| {
                 *total = total.saturating_add(alpha);

From 680b5bcfef06ee2dee520e40175de46961b7ba98 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Mon, 27 Jan 2025 18:43:02 -0500
Subject: [PATCH 100/145] Set DefaultMinimumPoolLiquidity

---
 pallets/subtensor/src/lib.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index c26a2a422..7f9cd7120 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -736,8 +736,7 @@ pub mod pallet {
     #[pallet::type_value]
     /// Default value for minimum liquidity in pool
     pub fn DefaultMinimumPoolLiquidity<T: Config>() -> I96F32 {
-        // I96F32::saturating_from_num(1_000_000)
-        I96F32::saturating_from_num(0)
+        I96F32::saturating_from_num(1_000_000)
     }
 
     #[pallet::storage]

From 0401f08ae93fbf0d85cf8daf796b07b554a2eb4d Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 09:58:08 -0500
Subject: [PATCH 101/145] Fix test_do_move_max_values

---
 pallets/subtensor/src/tests/move_stake.rs | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index f299832ed..4d48cfa6a 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -724,7 +724,7 @@ fn test_do_move_storage_updates() {
 
 // 18. test_do_move_max_values
 // Description: Test moving the maximum possible stake values to check for overflows
-// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test move -- test_do_move_max_values --exact --nocapture
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::move_stake::test_do_move_max_values --exact --show-output
 #[test]
 fn test_do_move_max_values() {
     new_test_ext(1).execute_with(|| {
@@ -740,6 +740,11 @@ fn test_do_move_max_values() {
         // Set up initial stake with maximum value
         SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey);
         SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey);
+
+        // Add lots of liquidity to bypass low liquidity check
+        SubnetTAO::<Test>::insert(netuid, u64::MAX/1000);
+        SubnetAlphaIn::<Test>::insert(netuid, u64::MAX/1000);
+
         SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, max_stake, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
             &origin_hotkey,
@@ -773,7 +778,7 @@ fn test_do_move_max_values() {
                 netuid
             ),
             alpha,
-            epsilon = 5
+            epsilon = alpha / 1_000_000
         );
     });
 }

From dd251428f0a44f63d84e78a97ade1b30953bfe27 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 11:52:46 -0500
Subject: [PATCH 102/145] Add tests

---
 pallets/subtensor/src/tests/move_stake.rs |   4 +-
 pallets/subtensor/src/tests/staking.rs    | 177 ++++++++++++++++++++++
 2 files changed, 179 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs
index 4d48cfa6a..7a60d4736 100644
--- a/pallets/subtensor/src/tests/move_stake.rs
+++ b/pallets/subtensor/src/tests/move_stake.rs
@@ -742,8 +742,8 @@ fn test_do_move_max_values() {
         SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey);
 
         // Add lots of liquidity to bypass low liquidity check
-        SubnetTAO::<Test>::insert(netuid, u64::MAX/1000);
-        SubnetAlphaIn::<Test>::insert(netuid, u64::MAX/1000);
+        SubnetTAO::<Test>::insert(netuid, u64::MAX / 1000);
+        SubnetAlphaIn::<Test>::insert(netuid, u64::MAX / 1000);
 
         SubtensorModule::stake_into_subnet(&origin_hotkey, &coldkey, netuid, max_stake, fee);
         let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 54413fdc0..a570175c9 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -556,6 +556,78 @@ fn test_remove_stake_total_balance_no_change() {
     });
 }
 
+#[test]
+fn test_add_stake_insufficient_liquidity() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let hotkey = U256::from(2);
+        let coldkey = U256::from(3);
+        let amount_staked = DefaultMinStake::<Test>::get() * 10 + DefaultStakingFee::<Test>::get();
+
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
+
+        // Set the liquidity at lowest possible value so that all staking requests fail
+        SubnetTAO::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+        SubnetAlphaIn::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+
+        // Check the error
+        assert_noop!(
+            SubtensorModule::add_stake(
+                RuntimeOrigin::signed(coldkey),
+                hotkey,
+                netuid,
+                amount_staked
+            ),
+            Error::<Test>::InsufficientLiquidity
+        );
+    });
+}
+
+#[test]
+fn test_remove_stake_insufficient_liquidity() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let hotkey = U256::from(2);
+        let coldkey = U256::from(3);
+        let amount_staked = DefaultMinStake::<Test>::get() * 10 + DefaultStakingFee::<Test>::get();
+
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
+
+        // Simulate stake for hotkey
+        SubnetTAO::<Test>::insert(netuid, u64::MAX / 1000);
+        SubnetAlphaIn::<Test>::insert(netuid, u64::MAX / 1000);
+        let alpha = SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, amount_staked, 0);
+
+        // Set the liquidity at lowest possible value so that all staking requests fail
+        SubnetTAO::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+        SubnetAlphaIn::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+
+        // Check the error
+        assert_noop!(
+            SubtensorModule::remove_stake(RuntimeOrigin::signed(coldkey), hotkey, netuid, alpha),
+            Error::<Test>::InsufficientLiquidity
+        );
+    });
+}
+
 #[test]
 fn test_remove_stake_total_issuance_no_change() {
     // When we remove stake, the total issuance of the balances pallet should not change
@@ -2132,3 +2204,108 @@ fn test_stake_below_min_validate() {
         assert_ok!(result_min_stake);
     });
 }
+
+#[test]
+fn test_stake_low_liquidity_validate() {
+    // Testing the signed extension validate function
+    // correctly filters the `add_stake` transaction.
+
+    new_test_ext(0).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let hotkey = U256::from(2);
+        let coldkey = U256::from(3);
+        let amount_staked = DefaultMinStake::<Test>::get() * 10 + DefaultStakingFee::<Test>::get();
+
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
+
+        // Set the liquidity at lowest possible value so that all staking requests fail
+        SubnetTAO::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+        SubnetAlphaIn::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+
+        // Add stake call
+        let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
+            hotkey,
+            netuid,
+            amount_staked,
+        });
+
+        let info: crate::DispatchInfo =
+            crate::DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
+
+        let extension = crate::SubtensorSignedExtension::<Test>::new();
+        // Submit to the signed extension validate function
+        let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
+
+        // Should fail due to insufficient stake
+        assert_err!(
+            result_no_stake,
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::InsufficientLiquidity.into()
+            ))
+        );
+    });
+}
+
+#[test]
+fn test_unstake_low_liquidity_validate() {
+    // Testing the signed extension validate function
+    // correctly filters the `add_stake` transaction.
+
+    new_test_ext(0).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let hotkey = U256::from(2);
+        let coldkey = U256::from(3);
+        let amount_staked = DefaultMinStake::<Test>::get() * 10 + DefaultStakingFee::<Test>::get();
+
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
+
+        // Simulate stake for hotkey
+        SubnetTAO::<Test>::insert(netuid, u64::MAX / 1000);
+        SubnetAlphaIn::<Test>::insert(netuid, u64::MAX / 1000);
+        let alpha = SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, amount_staked, 0);
+
+        // Set the liquidity at lowest possible value so that all staking requests fail
+        SubnetTAO::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+        SubnetAlphaIn::<Test>::insert(
+            netuid,
+            DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
+        );
+
+        // Remove stake call
+        let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake {
+            hotkey,
+            netuid,
+            amount_unstaked: alpha,
+        });
+
+        let info: crate::DispatchInfo =
+            crate::DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
+
+        let extension = crate::SubtensorSignedExtension::<Test>::new();
+        // Submit to the signed extension validate function
+        let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
+
+        // Should fail due to insufficient stake
+        assert_err!(
+            result_no_stake,
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::InsufficientLiquidity.into()
+            ))
+        );
+    });
+}

From 693221ce5c0d596d8cc20417d01b5f7e667a04c9 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 12:11:14 -0500
Subject: [PATCH 103/145] Fix unsafe math

---
 pallets/subtensor/src/staking/add_stake.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index 2f0d4875f..1dc75664f 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -185,7 +185,7 @@ impl<T: Config> Pallet<T> {
         .unwrap_or(zero);
 
         U96F32::from_num(sqrt)
-            .saturating_sub(U96F32::from_num(tao_reserve_float))
-            .to_num::<u64>()
+            .saturating_sub(U96F32::saturating_from_num(tao_reserve_float))
+            .saturating_to_num::<u64>()
     }
 }

From 624dd07e6a9e57c2267b816ee1cc47b81e312c27 Mon Sep 17 00:00:00 2001
From: gztensor <166415444+gztensor@users.noreply.github.com>
Date: Tue, 28 Jan 2025 09:15:20 -0800
Subject: [PATCH 104/145] Update pallets/subtensor/src/staking/stake_utils.rs

Co-authored-by: Cameron Fairchild <cameron@opentensor.ai>
---
 pallets/subtensor/src/staking/stake_utils.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index d68f2eb1c..1e6d2d0a1 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -560,7 +560,7 @@ impl<T: Config> Pallet<T> {
             });
             // Step 8. Decrease Alpha reserves.
             SubnetVolume::<T>::mutate(netuid, |total| {
-                *total = total.saturating_sub(tao);
+                *total = total.saturating_add(tao);
             });
             // Step 9. Return the alpha received.
             alpha

From 7fc9b4179ff671e5d554bcb0553e99cd7bd9d726 Mon Sep 17 00:00:00 2001
From: gztensor <166415444+gztensor@users.noreply.github.com>
Date: Tue, 28 Jan 2025 09:15:38 -0800
Subject: [PATCH 105/145] Update pallets/subtensor/src/staking/stake_utils.rs

Co-authored-by: Cameron Fairchild <cameron@opentensor.ai>
---
 pallets/subtensor/src/staking/stake_utils.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index 1e6d2d0a1..805b61e50 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -592,7 +592,7 @@ impl<T: Config> Pallet<T> {
             });
             // Step 8. Decrease Alpha reserves.
             SubnetVolume::<T>::mutate(netuid, |total| {
-                *total = total.saturating_sub(tao);
+                *total = total.saturating_add(tao);
             });
             // Step 9. Return the tao received.
             tao

From 7eaacf9b3d89350f29d30a54336d0ced3c9e30de Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:39:32 -0500
Subject: [PATCH 106/145] make min burn only callable by root

---
 pallets/admin-utils/src/lib.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs
index 7de39aa38..90e0c1292 100644
--- a/pallets/admin-utils/src/lib.rs
+++ b/pallets/admin-utils/src/lib.rs
@@ -554,7 +554,7 @@ pub mod pallet {
         }
 
         /// The extrinsic sets the minimum burn for a subnet.
-        /// It is only callable by the root account or subnet owner.
+        /// It is only callable by the root account.
         /// The extrinsic will call the Subtensor pallet to set the minimum burn.
         #[pallet::call_index(22)]
         #[pallet::weight(<T as Config>::WeightInfo::sudo_set_min_burn())]
@@ -563,7 +563,7 @@ pub mod pallet {
             netuid: u16,
             min_burn: u64,
         ) -> DispatchResult {
-            pallet_subtensor::Pallet::<T>::ensure_subnet_owner_or_root(origin, netuid)?;
+            ensure_root(origin)?;
 
             ensure!(
                 pallet_subtensor::Pallet::<T>::if_subnet_exist(netuid),

From 4cf3a6851e87435acc1e12778ea093093973764e Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:39:48 -0500
Subject: [PATCH 107/145] add tests for reg disable -> tao-in == 0

---
 pallets/subtensor/src/tests/coinbase.rs | 186 ++++++++++++++++++++++++
 1 file changed, 186 insertions(+)

diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs
index ff4908172..fb7a927be 100644
--- a/pallets/subtensor/src/tests/coinbase.rs
+++ b/pallets/subtensor/src/tests/coinbase.rs
@@ -389,3 +389,189 @@ fn test_total_issuance_after_coinbase() {
         );
     });
 }
+
+// Verifies that the total issuance after the coinbase is not changed when registration is disabled.
+// Includes TAO weight.
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_registration_disabled_total_issuance_same --exact --show-output --nocapture
+#[test]
+fn test_registration_disabled_total_issuance_same() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+        // Set TAO weight to 18%
+        SubtensorModule::set_tao_weight(I96F32::from_num(0.18).saturating_to_num::<u64>());
+        // Set owner cut to ~11.11%
+        SubtensorModule::set_subnet_owner_cut(u16::MAX / 9);
+        let total_coinbase_emission: I96F32 = I96F32::from_num(1_123_456_789);
+        let epsilon: u64 = 100;
+
+        // Define hotkeys and coldkeys
+        let hotkey_a: U256 = U256::from(1);
+        let hotkey_b: U256 = U256::from(2);
+        let hotkey_c: U256 = U256::from(3);
+        let coldkey_a: U256 = U256::from(100);
+        let coldkey_b: U256 = U256::from(101);
+        let coldkey_c: U256 = U256::from(102);
+
+        // Register neurons with decreasing stakes
+        register_ok_neuron(netuid, hotkey_a, coldkey_a, 0);
+        register_ok_neuron(netuid, hotkey_b, coldkey_b, 0);
+        register_ok_neuron(netuid, hotkey_c, coldkey_c, 0);
+
+        // Add initial stakes
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000);
+
+        // Swap to alpha
+        let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
+        let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
+            netuid,
+            total_tao.saturating_to_num::<u64>(),
+        ));
+
+        // Set the stakes directly
+        // This avoids needing to swap tao to alpha, impacting the initial stake distribution.
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_b,
+            &coldkey_b,
+            netuid,
+            (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_c,
+            &coldkey_c,
+            netuid,
+            (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::<u64>(),
+        );
+
+        // Stake some to root
+        let stake_to_root: u64 = 10_000_000;
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, stake_to_root);
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            stake_to_root,
+        );
+
+        let alpha_price = SubtensorModule::get_alpha_price(netuid);
+        log::info!("alpha_price: {:?}", alpha_price);
+
+        // Get the total issuance
+        let mut total_issuance_before = TotalIssuance::<Test>::get();
+        log::info!("total_issuance_before: {:?}", total_issuance_before);
+
+        // Disable registration on the network
+        SubtensorModule::set_network_registration_allowed(netuid, false);
+        SubtensorModule::set_network_pow_registration_allowed(netuid, false);
+
+        // Run the coinbase
+        SubtensorModule::run_coinbase(total_coinbase_emission);
+
+        // Should be the same
+        let total_issuance_after = TotalIssuance::<Test>::get();
+        assert_abs_diff_eq!(
+            total_issuance_after,
+            total_issuance_before,
+            epsilon = epsilon
+        );
+    });
+}
+
+// Verifies that the TAO-in after the coinbase is not changed when registration is disabled.
+// Includes TAO weight.
+// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_registration_disabled_tao_in_same --exact --show-output --nocapture
+#[test]
+fn test_registration_disabled_tao_in_same() {
+    new_test_ext(1).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+        // Set TAO weight to 18%
+        SubtensorModule::set_tao_weight(I96F32::from_num(0.18).saturating_to_num::<u64>());
+        // Set owner cut to ~11.11%
+        SubtensorModule::set_subnet_owner_cut(u16::MAX / 9);
+        let total_coinbase_emission: I96F32 = I96F32::from_num(1_123_456_789);
+        let epsilon: u64 = 100;
+
+        // Define hotkeys and coldkeys
+        let hotkey_a: U256 = U256::from(1);
+        let hotkey_b: U256 = U256::from(2);
+        let hotkey_c: U256 = U256::from(3);
+        let coldkey_a: U256 = U256::from(100);
+        let coldkey_b: U256 = U256::from(101);
+        let coldkey_c: U256 = U256::from(102);
+
+        // Register neurons with decreasing stakes
+        register_ok_neuron(netuid, hotkey_a, coldkey_a, 0);
+        register_ok_neuron(netuid, hotkey_b, coldkey_b, 0);
+        register_ok_neuron(netuid, hotkey_c, coldkey_c, 0);
+
+        // Add initial stakes
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000);
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000);
+
+        // Swap to alpha
+        let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000);
+        let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha(
+            netuid,
+            total_tao.saturating_to_num::<u64>(),
+        ));
+
+        // Set the stakes directly
+        // This avoids needing to swap tao to alpha, impacting the initial stake distribution.
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_b,
+            &coldkey_b,
+            netuid,
+            (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::<u64>(),
+        );
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_c,
+            &coldkey_c,
+            netuid,
+            (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::<u64>(),
+        );
+
+        // Stake some to root
+        let stake_to_root: u64 = 10_000_000;
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, stake_to_root);
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_a,
+            &coldkey_a,
+            netuid,
+            stake_to_root,
+        );
+
+        let alpha_price = SubtensorModule::get_alpha_price(netuid);
+        log::info!("alpha_price: {:?}", alpha_price);
+
+        // Get the total issuance
+        let mut tao_in_before = SubnetTAO::<Test>::get(netuid);
+        log::info!("tao_in_before: {:?}", tao_in_before);
+
+        // Disable registration on the network
+        SubtensorModule::set_network_registration_allowed(netuid, false);
+        SubtensorModule::set_network_pow_registration_allowed(netuid, false);
+
+        // Run the coinbase
+        SubtensorModule::run_coinbase(total_coinbase_emission);
+
+        // Should be the same
+        let tao_in_after = SubnetTAO::<Test>::get(netuid);
+        assert_abs_diff_eq!(tao_in_after, tao_in_before, epsilon = epsilon);
+    });
+}

From 17308f5d17d3706e71d2b269bdc2ddfef3d09172 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:40:02 -0500
Subject: [PATCH 108/145] disable TAO into subnet if reg are disabled

---
 .../subtensor/src/coinbase/run_coinbase.rs    | 34 +++++++++++--------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs
index 7516857b4..b57a08503 100644
--- a/pallets/subtensor/src/coinbase/run_coinbase.rs
+++ b/pallets/subtensor/src/coinbase/run_coinbase.rs
@@ -122,20 +122,26 @@ impl<T: Config> Pallet<T> {
                 netuid,
                 subnet_proportion
             );
-            // 3.7: Calculate subnet's TAO emission: E_s = P_s * E_m
-            let tao_in: u64 = mech_emission
-                .checked_mul(subnet_proportion)
-                .unwrap_or(I96F32::saturating_from_num(0))
-                .saturating_to_num::<u64>();
-            log::debug!(
-                "Subnet TAO emission (E_s) for netuid {:?}: {:?}",
-                netuid,
-                tao_in
-            );
-            // 3.8: Store the subnet TAO emission.
-            *tao_in_map.entry(*netuid).or_insert(0) = tao_in;
-            // 3.9: Store the block emission for this subnet for chain storage.
-            EmissionValues::<T>::insert(*netuid, tao_in);
+
+            // Only emit TAO if the subnetwork allows registration.
+            if Self::get_network_registration_allowed(*netuid)
+                || Self::get_network_pow_registration_allowed(*netuid)
+            {
+                // 3.7: Calculate subnet's TAO emission: E_s = P_s * E_m
+                let tao_in: u64 = mech_emission
+                    .checked_mul(subnet_proportion)
+                    .unwrap_or(I96F32::saturating_from_num(0))
+                    .saturating_to_num::<u64>();
+                log::debug!(
+                    "Subnet TAO emission (E_s) for netuid {:?}: {:?}",
+                    netuid,
+                    tao_in
+                );
+                // 3.8: Store the subnet TAO emission.
+                *tao_in_map.entry(*netuid).or_insert(0) = tao_in;
+                // 3.9: Store the block emission for this subnet for chain storage.
+                EmissionValues::<T>::insert(*netuid, tao_in);
+            }
         }
 
         // == We'll save the owner cuts for each subnet.

From e0e2b84c04dc72aa1d8999c54d1d7c0097979f9b Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:49:20 -0500
Subject: [PATCH 109/145] add stake info by hk, ck, netuid

---
 pallets/subtensor/runtime-api/src/lib.rs     |  1 +
 pallets/subtensor/src/rpc_info/stake_info.rs | 38 ++++++++++++++++++++
 runtime/src/lib.rs                           |  5 +++
 3 files changed, 44 insertions(+)

diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs
index cdcd6ed39..31f351aeb 100644
--- a/pallets/subtensor/runtime-api/src/lib.rs
+++ b/pallets/subtensor/runtime-api/src/lib.rs
@@ -34,6 +34,7 @@ sp_api::decl_runtime_apis! {
     pub trait StakeInfoRuntimeApi {
         fn get_stake_info_for_coldkey( coldkey_account_vec: Vec<u8> ) -> Vec<u8>;
         fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec<Vec<u8>> ) -> Vec<u8>;
+        fn get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8>;
     }
 
     pub trait SubnetRegistrationRuntimeApi {
diff --git a/pallets/subtensor/src/rpc_info/stake_info.rs b/pallets/subtensor/src/rpc_info/stake_info.rs
index 97afd5aa2..0422bc33b 100644
--- a/pallets/subtensor/src/rpc_info/stake_info.rs
+++ b/pallets/subtensor/src/rpc_info/stake_info.rs
@@ -99,4 +99,42 @@ impl<T: Config> Pallet<T> {
             first.1.clone()
         }
     }
+
+    pub fn get_stake_info_for_hotkey_coldkey_netuid(
+        hotkey_account_vec: Vec<u8>,
+        coldkey_account_vec: Vec<u8>,
+        netuid: u16,
+    ) -> Option<StakeInfo<T>> {
+        if coldkey_account_vec.len() != 32 {
+            return None; // Invalid coldkey
+        }
+
+        let Ok(coldkey) = T::AccountId::decode(&mut coldkey_account_vec.as_bytes_ref()) else {
+            return None;
+        };
+
+        if hotkey_account_vec.len() != 32 {
+            return None; // Invalid hotkey
+        }
+
+        let Ok(hotkey) = T::AccountId::decode(&mut hotkey_account_vec.as_bytes_ref()) else {
+            return None;
+        };
+
+        let alpha: u64 =
+            Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        let emission: u64 = AlphaDividendsPerSubnet::<T>::get(netuid, &hotkey);
+        let is_registered: bool = Self::is_hotkey_registered_on_network(netuid, &hotkey);
+
+        Some(StakeInfo {
+            hotkey: hotkey.clone(),
+            coldkey: coldkey.clone(),
+            netuid: (netuid).into(),
+            stake: alpha.into(),
+            locked: 0.into(),
+            emission: emission.into(),
+            drain: 0.into(),
+            is_registered,
+        })
+    }
 }
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 372c9a981..93357f227 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -2157,6 +2157,11 @@ impl_runtime_apis! {
             let result = SubtensorModule::get_stake_info_for_coldkeys( coldkey_account_vecs );
             result.encode()
         }
+
+        fn get_stake_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8> {
+            let result = SubtensorModule::get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec, coldkey_account_vec, netuid );
+            result.encode()
+        }
     }
 
     impl subtensor_custom_rpc_runtime_api::SubnetRegistrationRuntimeApi<Block> for Runtime {

From 067ddd3b328cc15f005ba8f4d0d55e287bdfc3f1 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:50:09 -0500
Subject: [PATCH 110/145] Revert "add stake info by hk, ck, netuid"

This reverts commit e0e2b84c04dc72aa1d8999c54d1d7c0097979f9b.
---
 pallets/subtensor/runtime-api/src/lib.rs     |  1 -
 pallets/subtensor/src/rpc_info/stake_info.rs | 38 --------------------
 runtime/src/lib.rs                           |  5 ---
 3 files changed, 44 deletions(-)

diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs
index 31f351aeb..cdcd6ed39 100644
--- a/pallets/subtensor/runtime-api/src/lib.rs
+++ b/pallets/subtensor/runtime-api/src/lib.rs
@@ -34,7 +34,6 @@ sp_api::decl_runtime_apis! {
     pub trait StakeInfoRuntimeApi {
         fn get_stake_info_for_coldkey( coldkey_account_vec: Vec<u8> ) -> Vec<u8>;
         fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec<Vec<u8>> ) -> Vec<u8>;
-        fn get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8>;
     }
 
     pub trait SubnetRegistrationRuntimeApi {
diff --git a/pallets/subtensor/src/rpc_info/stake_info.rs b/pallets/subtensor/src/rpc_info/stake_info.rs
index 0422bc33b..97afd5aa2 100644
--- a/pallets/subtensor/src/rpc_info/stake_info.rs
+++ b/pallets/subtensor/src/rpc_info/stake_info.rs
@@ -99,42 +99,4 @@ impl<T: Config> Pallet<T> {
             first.1.clone()
         }
     }
-
-    pub fn get_stake_info_for_hotkey_coldkey_netuid(
-        hotkey_account_vec: Vec<u8>,
-        coldkey_account_vec: Vec<u8>,
-        netuid: u16,
-    ) -> Option<StakeInfo<T>> {
-        if coldkey_account_vec.len() != 32 {
-            return None; // Invalid coldkey
-        }
-
-        let Ok(coldkey) = T::AccountId::decode(&mut coldkey_account_vec.as_bytes_ref()) else {
-            return None;
-        };
-
-        if hotkey_account_vec.len() != 32 {
-            return None; // Invalid hotkey
-        }
-
-        let Ok(hotkey) = T::AccountId::decode(&mut hotkey_account_vec.as_bytes_ref()) else {
-            return None;
-        };
-
-        let alpha: u64 =
-            Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
-        let emission: u64 = AlphaDividendsPerSubnet::<T>::get(netuid, &hotkey);
-        let is_registered: bool = Self::is_hotkey_registered_on_network(netuid, &hotkey);
-
-        Some(StakeInfo {
-            hotkey: hotkey.clone(),
-            coldkey: coldkey.clone(),
-            netuid: (netuid).into(),
-            stake: alpha.into(),
-            locked: 0.into(),
-            emission: emission.into(),
-            drain: 0.into(),
-            is_registered,
-        })
-    }
 }
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 93357f227..372c9a981 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -2157,11 +2157,6 @@ impl_runtime_apis! {
             let result = SubtensorModule::get_stake_info_for_coldkeys( coldkey_account_vecs );
             result.encode()
         }
-
-        fn get_stake_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8> {
-            let result = SubtensorModule::get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec, coldkey_account_vec, netuid );
-            result.encode()
-        }
     }
 
     impl subtensor_custom_rpc_runtime_api::SubnetRegistrationRuntimeApi<Block> for Runtime {

From 19d35a6f0baa8e3824e29979ef9ce5a81ce74eb8 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:51:13 -0500
Subject: [PATCH 111/145] Add stakeinfo by hk, ck, netuid

---
 pallets/subtensor/runtime-api/src/lib.rs     |  1 +
 pallets/subtensor/src/rpc_info/stake_info.rs | 38 ++++++++++++++++++++
 runtime/src/lib.rs                           |  5 +++
 3 files changed, 44 insertions(+)

diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs
index cdcd6ed39..31f351aeb 100644
--- a/pallets/subtensor/runtime-api/src/lib.rs
+++ b/pallets/subtensor/runtime-api/src/lib.rs
@@ -34,6 +34,7 @@ sp_api::decl_runtime_apis! {
     pub trait StakeInfoRuntimeApi {
         fn get_stake_info_for_coldkey( coldkey_account_vec: Vec<u8> ) -> Vec<u8>;
         fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec<Vec<u8>> ) -> Vec<u8>;
+        fn get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8>;
     }
 
     pub trait SubnetRegistrationRuntimeApi {
diff --git a/pallets/subtensor/src/rpc_info/stake_info.rs b/pallets/subtensor/src/rpc_info/stake_info.rs
index 97afd5aa2..0422bc33b 100644
--- a/pallets/subtensor/src/rpc_info/stake_info.rs
+++ b/pallets/subtensor/src/rpc_info/stake_info.rs
@@ -99,4 +99,42 @@ impl<T: Config> Pallet<T> {
             first.1.clone()
         }
     }
+
+    pub fn get_stake_info_for_hotkey_coldkey_netuid(
+        hotkey_account_vec: Vec<u8>,
+        coldkey_account_vec: Vec<u8>,
+        netuid: u16,
+    ) -> Option<StakeInfo<T>> {
+        if coldkey_account_vec.len() != 32 {
+            return None; // Invalid coldkey
+        }
+
+        let Ok(coldkey) = T::AccountId::decode(&mut coldkey_account_vec.as_bytes_ref()) else {
+            return None;
+        };
+
+        if hotkey_account_vec.len() != 32 {
+            return None; // Invalid hotkey
+        }
+
+        let Ok(hotkey) = T::AccountId::decode(&mut hotkey_account_vec.as_bytes_ref()) else {
+            return None;
+        };
+
+        let alpha: u64 =
+            Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid);
+        let emission: u64 = AlphaDividendsPerSubnet::<T>::get(netuid, &hotkey);
+        let is_registered: bool = Self::is_hotkey_registered_on_network(netuid, &hotkey);
+
+        Some(StakeInfo {
+            hotkey: hotkey.clone(),
+            coldkey: coldkey.clone(),
+            netuid: (netuid).into(),
+            stake: alpha.into(),
+            locked: 0.into(),
+            emission: emission.into(),
+            drain: 0.into(),
+            is_registered,
+        })
+    }
 }
diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 372c9a981..93357f227 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -2157,6 +2157,11 @@ impl_runtime_apis! {
             let result = SubtensorModule::get_stake_info_for_coldkeys( coldkey_account_vecs );
             result.encode()
         }
+
+        fn get_stake_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8> {
+            let result = SubtensorModule::get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec, coldkey_account_vec, netuid );
+            result.encode()
+        }
     }
 
     impl subtensor_custom_rpc_runtime_api::SubnetRegistrationRuntimeApi<Block> for Runtime {

From fce08351e36232b994bbdc570498398cbe875209 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:54:07 -0500
Subject: [PATCH 112/145] typo

---
 runtime/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 93357f227..a2cb120e1 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -2158,7 +2158,7 @@ impl_runtime_apis! {
             result.encode()
         }
 
-        fn get_stake_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8> {
+        fn get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec: Vec<u8>, coldkey_account_vec: Vec<u8>, netuid: u16 ) -> Vec<u8> {
             let result = SubtensorModule::get_stake_info_for_hotkey_coldkey_netuid( hotkey_account_vec, coldkey_account_vec, netuid );
             result.encode()
         }

From 5a1f1f23c99c9898745b52c426aed31d90b51b94 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Tue, 28 Jan 2025 19:11:27 +0100
Subject: [PATCH 113/145] Replace frontier's RuntimeHelper with manual
 dispatcher

---
 Cargo.lock                                  | 45 -----------
 runtime/Cargo.toml                          | 16 ++--
 runtime/src/precompiles/balance_transfer.rs | 32 +++-----
 runtime/src/precompiles/mod.rs              | 82 ++++++++++++++++++++-
 runtime/src/precompiles/staking.rs          | 26 +------
 5 files changed, 97 insertions(+), 104 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index e86ef3d69..964c583e1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1067,12 +1067,6 @@ dependencies = [
  "thiserror",
 ]
 
-[[package]]
-name = "case"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c"
-
 [[package]]
 name = "cc"
 version = "1.1.24"
@@ -5664,7 +5658,6 @@ dependencies = [
  "pallet-transaction-payment-rpc-runtime-api",
  "pallet-utility",
  "parity-scale-codec",
- "precompile-utils",
  "rand_chacha",
  "scale-info",
  "serde_json",
@@ -7017,44 +7010,6 @@ dependencies = [
  "zerocopy",
 ]
 
-[[package]]
-name = "precompile-utils"
-version = "0.1.0"
-source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
-dependencies = [
- "environmental",
- "evm",
- "fp-evm",
- "frame-support",
- "frame-system",
- "hex",
- "impl-trait-for-tuples",
- "log",
- "num_enum",
- "pallet-evm",
- "parity-scale-codec",
- "precompile-utils-macro",
- "sp-core",
- "sp-io",
- "sp-runtime",
- "sp-weights",
- "staging-xcm",
-]
-
-[[package]]
-name = "precompile-utils-macro"
-version = "0.1.0"
-source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
-dependencies = [
- "case",
- "num_enum",
- "prettyplease 0.2.22",
- "proc-macro2",
- "quote",
- "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "predicates"
 version = "2.1.5"
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index 0d44e0907..171ef3c47 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -20,7 +20,9 @@ name = "spec_version"
 path = "src/spec_version.rs"
 
 [dependencies]
-ed25519-dalek = { workspace = true, default-features = false, features = ["alloc"] }
+ed25519-dalek = { workspace = true, default-features = false, features = [
+	"alloc",
+] }
 subtensor-macros.workspace = true
 subtensor-custom-rpc-runtime-api = { path = "../pallets/subtensor/runtime-api", default-features = false }
 smallvec = { workspace = true }
@@ -98,7 +100,6 @@ pallet-commitments = { default-features = false, path = "../pallets/commitments"
 fp-evm = { workspace = true }
 fp-rpc = { workspace = true }
 fp-self-contained = { workspace = true }
-precompile-utils = { workspace = true }
 
 # Frontier FRAME
 pallet-base-fee = { workspace = true }
@@ -133,9 +134,7 @@ substrate-wasm-builder = { workspace = true, optional = true }
 [features]
 default = ["std"]
 pow-faucet = ["pallet-subtensor/pow-faucet"]
-fast-blocks = [
-	"pallet-subtensor/fast-blocks"
-]
+fast-blocks = ["pallet-subtensor/fast-blocks"]
 std = [
 	"frame-try-runtime?/std",
 	"frame-system-benchmarking?/std",
@@ -192,7 +191,6 @@ std = [
 	"fp-evm/std",
 	"fp-rpc/std",
 	"fp-self-contained/std",
-	"precompile-utils/std",
 	# Frontier FRAME
 	"pallet-base-fee/std",
 	"pallet-dynamic-fee/std",
@@ -211,7 +209,7 @@ std = [
 	"hex/std",
 	"rand_chacha/std",
 	"sha2/std",
-	"w3f-bls/std"
+	"w3f-bls/std",
 ]
 runtime-benchmarks = [
 	"frame-benchmarking/runtime-benchmarks",
@@ -240,7 +238,7 @@ runtime-benchmarks = [
 	"pallet-ethereum/runtime-benchmarks",
 	"pallet-evm/runtime-benchmarks",
 	"pallet-hotfix-sufficients/runtime-benchmarks",
-	"pallet-drand/runtime-benchmarks"
+	"pallet-drand/runtime-benchmarks",
 ]
 try-runtime = [
 	"frame-try-runtime/try-runtime",
@@ -276,6 +274,6 @@ try-runtime = [
 	"pallet-ethereum/try-runtime",
 	"pallet-evm/try-runtime",
 	"pallet-evm-chain-id/try-runtime",
-	"pallet-drand/try-runtime"
+	"pallet-drand/try-runtime",
 ]
 metadata-hash = ["substrate-wasm-builder/metadata-hash"]
diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs
index 03c4be8a6..177ced50e 100644
--- a/runtime/src/precompiles/balance_transfer.rs
+++ b/runtime/src/precompiles/balance_transfer.rs
@@ -1,15 +1,14 @@
 use frame_system::RawOrigin;
 use pallet_evm::{
-    BalanceConverter, ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle,
-    PrecompileOutput, PrecompileResult,
+    BalanceConverter, ExitError, ExitSucceed, PrecompileHandle, PrecompileOutput, PrecompileResult,
 };
-use precompile_utils::prelude::RuntimeHelper;
-use sp_core::U256;
 use sp_runtime::traits::UniqueSaturatedInto;
 use sp_std::vec;
 
-use crate::precompiles::{bytes_to_account_id, get_method_id, get_slice};
-use crate::{Runtime, RuntimeCall};
+use crate::precompiles::{
+    bytes_to_account_id, get_method_id, get_slice, try_dispatch_runtime_call,
+};
+use crate::Runtime;
 
 pub const BALANCE_TRANSFER_INDEX: u64 = 2048;
 
@@ -37,7 +36,7 @@ impl BalanceTransferPrecompile {
         }
 
         // Forward all received value to the destination address
-        let amount: U256 = handle.context().apparent_value;
+        let amount = handle.context().apparent_value;
 
         // Use BalanceConverter to convert EVM amount to Substrate balance
         let amount_sub =
@@ -55,23 +54,12 @@ impl BalanceTransferPrecompile {
         let account_id_src = bytes_to_account_id(&CONTRACT_ADDRESS_SS58)?;
         let account_id_dst = bytes_to_account_id(address_bytes_dst)?;
 
-        let call = RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
+        let call = pallet_balances::Call::<Runtime>::transfer_allow_death {
             dest: account_id_dst.into(),
             value: amount_sub.unique_saturated_into(),
-        });
+        };
+        let origin = RawOrigin::Signed(account_id_src);
 
-        // Dispatch the call
-        RuntimeHelper::<Runtime>::try_dispatch(
-            handle,
-            RawOrigin::Signed(account_id_src).into(),
-            call,
-        )
-        .map(|_| PrecompileOutput {
-            exit_status: ExitSucceed::Returned,
-            output: vec![],
-        })
-        .map_err(|_| PrecompileFailure::Error {
-            exit_status: ExitError::OutOfFund,
-        })
+        try_dispatch_runtime_call(handle, call, origin)
     }
 }
diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index e13516e95..e0cb85f3b 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -1,14 +1,21 @@
+extern crate alloc;
+
+use alloc::format;
 use core::marker::PhantomData;
-use sp_core::{hashing::keccak_256, H160};
-use sp_runtime::AccountId32;
 
+use frame_support::dispatch::{GetDispatchInfo, Pays};
+use frame_system::RawOrigin;
 use pallet_evm::{
-    ExitError, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
-    PrecompileResult, PrecompileSet,
+    ExitError, ExitSucceed, GasWeightMapping, IsPrecompileResult, Precompile, PrecompileFailure,
+    PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet,
 };
 use pallet_evm_precompile_modexp::Modexp;
 use pallet_evm_precompile_sha3fips::Sha3FIPS256;
 use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256};
+use sp_core::{hashing::keccak_256, H160};
+use sp_runtime::{traits::Dispatchable, AccountId32};
+
+use crate::{Runtime, RuntimeCall};
 
 // Include custom precompiles
 mod balance_transfer;
@@ -130,3 +137,70 @@ pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], Precompil
         })
     }
 }
+
+/// Dispatches a runtime call, but also checks and records the gas costs.
+fn try_dispatch_runtime_call(
+    handle: &mut impl PrecompileHandle,
+    call: impl Into<RuntimeCall>,
+    origin: RawOrigin<AccountId32>,
+) -> PrecompileResult {
+    let call = Into::<RuntimeCall>::into(call);
+    let info = call.get_dispatch_info();
+
+    let target_gas = handle.gas_limit();
+    if let Some(gas) = target_gas {
+        let valid_weight =
+            <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(gas, false).ref_time();
+        if info.weight.ref_time() > valid_weight {
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::OutOfGas,
+            });
+        }
+    }
+
+    handle.record_external_cost(
+        Some(info.weight.ref_time()),
+        Some(info.weight.proof_size()),
+        None,
+    )?;
+
+    match call.dispatch(origin.into()) {
+        Ok(post_info) => {
+            if post_info.pays_fee(&info) == Pays::Yes {
+                let actual_weight = post_info.actual_weight.unwrap_or(info.weight);
+                let cost =
+                    <Runtime as pallet_evm::Config>::GasWeightMapping::weight_to_gas(actual_weight);
+                handle.record_cost(cost)?;
+
+                handle.refund_external_cost(
+                    Some(
+                        info.weight
+                            .ref_time()
+                            .saturating_sub(actual_weight.ref_time()),
+                    ),
+                    Some(
+                        info.weight
+                            .proof_size()
+                            .saturating_sub(actual_weight.proof_size()),
+                    ),
+                );
+            }
+
+            log::info!("Dispatch succeeded. Post info: {:?}", post_info);
+
+            Ok(PrecompileOutput {
+                exit_status: ExitSucceed::Returned,
+                output: Default::default(),
+            })
+        }
+        Err(e) => {
+            log::error!("Dispatch failed. Error: {:?}", e);
+            log::warn!("Returning error PrecompileFailure::Error");
+            Err(PrecompileFailure::Error {
+                exit_status: ExitError::Other(
+                    format!("dispatch execution failed: {}", <&'static str>::from(e)).into(),
+                ),
+            })
+        }
+    }
+}
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index f8534927b..57e706026 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -30,7 +30,6 @@ use pallet_evm::{
     AddressMapping, BalanceConverter, ExitError, ExitSucceed, HashedAddressMapping,
     PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
 };
-use precompile_utils::prelude::RuntimeHelper;
 use sp_core::crypto::Ss58Codec;
 use sp_core::U256;
 use sp_runtime::traits::{BlakeTwo256, Dispatchable, StaticLookup, UniqueSaturatedInto};
@@ -38,7 +37,7 @@ use sp_runtime::AccountId32;
 use sp_std::vec;
 
 use crate::{
-    precompiles::{get_method_id, get_slice},
+    precompiles::{get_method_id, get_slice, try_dispatch_runtime_call},
     ProxyType, Runtime, RuntimeCall,
 };
 
@@ -214,28 +213,7 @@ impl StakingPrecompile {
             Self::transfer_back_to_caller(&account_id, amount)?;
         }
 
-        match RuntimeHelper::<Runtime>::try_dispatch(
-            handle,
-            RawOrigin::Signed(account_id.clone()).into(),
-            call,
-        ) {
-            Ok(post_info) => {
-                log::info!("Dispatch succeeded. Post info: {:?}", post_info);
-
-                Ok(PrecompileOutput {
-                    exit_status: ExitSucceed::Returned,
-                    output: vec![],
-                })
-            }
-
-            Err(dispatch_error) => {
-                log::error!("Dispatch failed. Error: {:?}", dispatch_error);
-                log::warn!("Returning error PrecompileFailure::Error");
-                Err(PrecompileFailure::Error {
-                    exit_status: ExitError::Other("Subtensor call failed".into()),
-                })
-            }
-        }
+        try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id.clone()))
     }
 
     fn transfer_back_to_caller(

From 2bf58540b3de575bf5dc5e4bd3d9b3c877103c60 Mon Sep 17 00:00:00 2001
From: Cameron Fairchild <cameron@opentensor.ai>
Date: Tue, 28 Jan 2025 13:58:33 -0500
Subject: [PATCH 114/145] add subnet volume to runtimeAPIs

---
 pallets/subtensor/src/rpc_info/dynamic_info.rs | 4 +++-
 pallets/subtensor/src/rpc_info/metagraph.rs    | 6 +++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/rpc_info/dynamic_info.rs b/pallets/subtensor/src/rpc_info/dynamic_info.rs
index a8ffd8549..bbee27c55 100644
--- a/pallets/subtensor/src/rpc_info/dynamic_info.rs
+++ b/pallets/subtensor/src/rpc_info/dynamic_info.rs
@@ -4,7 +4,7 @@ use codec::Compact;
 use frame_support::pallet_prelude::{Decode, Encode};
 use subtensor_macros::freeze_struct;
 
-#[freeze_struct("44fd17b240416875")]
+#[freeze_struct("1be5a1e26a82082f")]
 #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
 pub struct DynamicInfo<T: Config> {
     netuid: Compact<u16>,
@@ -24,6 +24,7 @@ pub struct DynamicInfo<T: Config> {
     tao_in_emission: Compact<u64>,
     pending_alpha_emission: Compact<u64>,
     pending_root_emission: Compact<u64>,
+    subnet_volume: Compact<u64>,
     network_registered_at: Compact<u64>,
     subnet_identity: Option<SubnetIdentity>,
 }
@@ -60,6 +61,7 @@ impl<T: Config> Pallet<T> {
             tao_in_emission: SubnetTaoInEmission::<T>::get(netuid).into(),
             pending_alpha_emission: PendingEmission::<T>::get(netuid).into(),
             pending_root_emission: PendingRootDivs::<T>::get(netuid).into(),
+            subnet_volume: SubnetVolume::<T>::get(netuid).into(),
             network_registered_at: NetworkRegisteredAt::<T>::get(netuid).into(),
             subnet_identity: SubnetIdentities::<T>::get(netuid),
         })
diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs
index 1e77e5fe6..ee3864932 100644
--- a/pallets/subtensor/src/rpc_info/metagraph.rs
+++ b/pallets/subtensor/src/rpc_info/metagraph.rs
@@ -6,7 +6,7 @@ use frame_support::pallet_prelude::{Decode, Encode};
 use substrate_fixed::types::I64F64;
 use subtensor_macros::freeze_struct;
 
-#[freeze_struct("bce2310daa502e48")]
+#[freeze_struct("fa24d156067e5eb9")]
 #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
 pub struct Metagraph<T: Config> {
     // Subnet index
@@ -38,6 +38,7 @@ pub struct Metagraph<T: Config> {
     tao_in_emission: Compact<u64>,        // amount of tao injected per block
     pending_alpha_emission: Compact<u64>, // pending alpha to be distributed
     pending_root_emission: Compact<u64>,  // panding tao for root divs to be distributed
+    subnet_volume: Compact<u64>,          // volume of the subnet in TAO
 
     // Hparams for epoch
     rho: Compact<u16>,   // subnet rho param
@@ -141,6 +142,8 @@ impl<T: Config> Pallet<T> {
             Vec<I64F64>,
             Vec<I64F64>,
         ) = Self::get_stake_weights_for_network(netuid);
+
+        let subnet_volume = SubnetVolume::<T>::get(netuid);
         Some(Metagraph {
             // Subnet index
             netuid: netuid.into(), // subnet index.
@@ -177,6 +180,7 @@ impl<T: Config> Pallet<T> {
             tao_in_emission: SubnetTaoInEmission::<T>::get(netuid).into(), // amount of tao injected per block
             pending_alpha_emission: PendingEmission::<T>::get(netuid).into(), // pending alpha to be distributed
             pending_root_emission: PendingRootDivs::<T>::get(netuid).into(), // panding tao for root divs to be distributed
+            subnet_volume: subnet_volume.into(),
 
             // Hparams for epoch
             rho: Self::get_rho(netuid).into(), // subnet rho param

From d66f77f1ceabe392459881d8db37a3e03441404e Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 14:58:45 -0500
Subject: [PATCH 115/145] Move checked_sqrt to save math and add tests

---
 pallets/subtensor/src/epoch/math.rs        |  48 -------
 pallets/subtensor/src/staking/add_stake.rs |  16 +--
 primitives/safe-math/src/lib.rs            | 153 +++++++++++++++++----
 3 files changed, 136 insertions(+), 81 deletions(-)

diff --git a/pallets/subtensor/src/epoch/math.rs b/pallets/subtensor/src/epoch/math.rs
index c0c9616c6..faa7ce21e 100644
--- a/pallets/subtensor/src/epoch/math.rs
+++ b/pallets/subtensor/src/epoch/math.rs
@@ -1428,51 +1428,3 @@ pub fn safe_ln(value: I32F32) -> I32F32 {
 pub fn safe_exp(value: I32F32) -> I32F32 {
     exp(value).unwrap_or(I32F32::saturating_from_num(0.0))
 }
-
-fn abs_diff(a: U96F32, b: U96F32) -> U96F32 {
-    if a < b {
-        b.saturating_sub(a)
-    } else {
-        a.saturating_sub(b)
-    }
-}
-
-/// Safe sqrt with good precision
-pub fn checked_sqrt(value: U96F32, epsilon: U96F32) -> Option<U96F32> {
-    let zero: U96F32 = U96F32::from_num(0);
-    let two: U96F32 = U96F32::from_num(2);
-
-    // print!("sqrt({:?}) = ...", value);
-
-    if value < zero {
-        return None;
-    }
-
-    let mut high: U96F32 = value;
-    let mut low: U96F32 = zero;
-    let mut middle: U96F32 = (high + low) / two;
-
-    let mut iteration = 0;
-    let max_iterations = 128;
-
-    // Iterative approximation using bisection
-    while abs_diff(value.checked_div(middle).unwrap_or(zero), middle) > epsilon {
-        // println!("abs diff = {:?}", abs_diff(value.checked_div(middle).unwrap_or(zero), middle));
-
-        if value.checked_div(middle).unwrap_or(zero) < middle {
-            high = middle;
-        } else {
-            low = middle;
-        }
-
-        middle = (high + low) / two;
-
-        iteration += 1;
-        if iteration > max_iterations {
-            break;
-        }
-    }
-
-    // println!("iterations = {:?}, result = {:?}", iteration, middle);
-    Some(middle)
-}
diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index 1dc75664f..793488824 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -155,19 +155,19 @@ impl<T: Config> Pallet<T> {
         if alpha_in == 0 {
             return 0;
         }
-        let alpha_in_float: U96F32 = U96F32::from_num(alpha_in);
+        let alpha_in_float: U96F32 = U96F32::saturating_from_num(alpha_in);
 
         // 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::from_num(tao_reserve);
+        let tao_reserve_float: U96F32 = U96F32::saturating_from_num(tao_reserve);
 
         // Corner case: limit_price < current_price (price cannot decrease with staking)
-        let limit_price_float: U96F32 = U96F32::from_num(limit_price)
-            .checked_div(U96F32::from_num(1_000_000_000))
-            .unwrap_or(U96F32::from_num(0));
+        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) {
             return 0;
         }
@@ -175,16 +175,16 @@ impl<T: Config> Pallet<T> {
         // 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::from_num(0.0);
+        let zero: U96F32 = U96F32::saturating_from_num(0.0);
         let sqrt: U96F32 = checked_sqrt(
             limit_price_float
                 .saturating_mul(tao_reserve_float)
                 .saturating_mul(alpha_in_float),
-            U96F32::from_num(0.1),
+            U96F32::saturating_from_num(0.1),
         )
         .unwrap_or(zero);
 
-        U96F32::from_num(sqrt)
+        U96F32::saturating_from_num(sqrt)
             .saturating_sub(U96F32::saturating_from_num(tao_reserve_float))
             .saturating_to_num::<u64>()
     }
diff --git a/primitives/safe-math/src/lib.rs b/primitives/safe-math/src/lib.rs
index 83c27b07c..e642793f8 100644
--- a/primitives/safe-math/src/lib.rs
+++ b/primitives/safe-math/src/lib.rs
@@ -1,7 +1,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![allow(clippy::result_unit_err)]
 
-use substrate_fixed::types::{I110F18, I32F32, I64F64, I96F32, U64F64};
+use substrate_fixed::types::{I110F18, I32F32, I64F64, I96F32, U64F64, U110F18};
 
 /// Safe division trait
 pub trait SafeDiv {
@@ -45,27 +45,130 @@ macro_rules! impl_safe_div_for_fixed {
         )*
     };
 }
-impl_safe_div_for_fixed!(I96F32, I32F32, I64F64, I110F18, U64F64);
-
-// /// Trait for safe conversion to primitive type P
-// pub trait SafeToNum<T> {
-//     /// Safe conversion to primitive type P
-//     fn safe_to_num<P>(self) -> P
-//     where
-//         P: num_traits::Bounded + substrate_fixed::prelude::ToFixed + substrate_fixed::prelude::FromFixed;
-// }
-
-// impl<T> SafeToNum<T> for T
-// where
-//     T: substrate_fixed::traits::Fixed,
-// {
-//     fn safe_to_num<P>(self) -> P
-//     where
-//         P: num_traits::Bounded + substrate_fixed::prelude::ToFixed + substrate_fixed::prelude::FromFixed
-//     {
-//         match self.try_into() {
-//             Ok(value) => value,
-//             Err(_) => P::max_value(),
-//         }
-//     }
-// }
+impl_safe_div_for_fixed!(I96F32, I32F32, I64F64, I110F18, U64F64, U110F18);
+
+fn abs_diff(a: U110F18, b: U110F18) -> U110F18 {
+    if a < b {
+        b.saturating_sub(a)
+    } else {
+        a.saturating_sub(b)
+    }
+}
+
+/// Safe sqrt with good precision
+pub fn checked_sqrt(value: U110F18, epsilon: U110F18) -> Option<U110F18> {
+    let zero: U110F18 = U110F18::from_num(0);
+    let two: U110F18 = U110F18::from_num(2);
+
+    if value < zero {
+        return None;
+    }
+
+    let mut high: U110F18 = value;
+    let mut low: U110F18 = zero;
+    let mut middle: U110F18 = (high + low) / two;
+
+    let mut iteration = 0;
+    let max_iterations = 128;
+    let mut check_val: U110F18 = value.safe_div(middle);
+
+    // Iterative approximation using bisection
+    while abs_diff(check_val, middle) > epsilon {
+        if check_val < middle {
+            high = middle;
+        } else {
+            low = middle;
+        }
+
+        middle = (high + low) / two;
+        check_val = value.safe_div(middle);
+
+        iteration += 1;
+        if iteration > max_iterations {
+            break;
+        }
+    }
+
+    Some(middle)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use substrate_fixed::types::U110F18; // Assuming U110F18 is properly imported
+
+    // Helper function for absolute difference
+    fn abs_diff(a: U110F18, b: U110F18) -> U110F18 {
+        if a > b {
+            a - b
+        } else {
+            b - a
+        }
+    }
+
+    #[test]
+    fn test_checked_sqrt_positive_values() {
+        let value: U110F18 = U110F18::from_num(4.0);
+        let epsilon: U110F18 = U110F18::from_num(0.0001);
+
+        let result: Option<U110F18> = checked_sqrt(value, epsilon);
+        assert!(result.is_some());
+        let sqrt_result: U110F18 = result.unwrap();
+        let precise_sqrt: U110F18 = U110F18::from_num(4.0_f64.sqrt());
+        assert!(abs_diff(sqrt_result, precise_sqrt) <= epsilon);
+    }
+
+    #[test]
+    fn test_checked_sqrt_large_value() {
+        let value: U110F18 = U110F18::from_num(1_000_000_000_000_000_000.0);
+        let epsilon: U110F18 = U110F18::from_num(0.0001);
+
+        let result: Option<U110F18> = checked_sqrt(value, epsilon);
+        assert!(result.is_some());
+        let sqrt_result: U110F18 = result.unwrap();
+        let precise_sqrt: U110F18 = U110F18::from_num(1_000_000_000_000_000_000.0_f64.sqrt());
+        assert!(abs_diff(sqrt_result, precise_sqrt) <= epsilon);
+    }
+
+    #[test]
+    fn test_checked_sqrt_21m_tao_value() {
+        let value: U110F18 = U110F18::from_num(441_000_000_000_000_000_000_000_000_000_000.0);
+        let epsilon: U110F18 = U110F18::from_num(1000);
+
+        let result: Option<U110F18> = checked_sqrt(value, epsilon);
+        assert!(result.is_some());
+        let sqrt_result: U110F18 = result.unwrap();
+        let precise_sqrt: U110F18 = U110F18::from_num(441_000_000_000_000_000_000_000_000_000_000.0_f64.sqrt());
+        assert!(abs_diff(sqrt_result, precise_sqrt) <= epsilon);
+    }
+
+    #[test]
+    fn test_checked_sqrt_zero() {
+        let value: U110F18 = U110F18::from_num(0.0);
+        let epsilon: U110F18 = U110F18::from_num(0.0001);
+
+        let result: Option<U110F18> = checked_sqrt(value, epsilon);
+        assert!(result.is_some());
+        assert_eq!(result.unwrap(), U110F18::from_num(0.0));
+    }
+
+    #[test]
+    fn test_checked_sqrt_precision() {
+        let value: U110F18 = U110F18::from_num(2.0);
+        let epsilon: U110F18 = U110F18::from_num(0.0001);
+
+        let result: Option<U110F18> = checked_sqrt(value, epsilon);
+        assert!(result.is_some());
+        let sqrt_result: U110F18 = result.unwrap();
+        let precise_sqrt: U110F18 = U110F18::from_num(2.0_f64.sqrt());
+        assert!(abs_diff(sqrt_result, precise_sqrt) <= epsilon);
+    }
+
+    #[test]
+    fn test_checked_sqrt_max_iterations() {
+        let value: U110F18 = U110F18::from_num(2.0);
+        let epsilon: U110F18 = U110F18::from_num(1e-30); // Very high precision
+        let result: Option<U110F18> = checked_sqrt(value, epsilon);
+        assert!(result.is_some()); // Check that it doesn't break, but may not be highly accurate
+    }
+}

From fd77135eb34faa5b8f113066f5b21aa8118c6338 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 15:38:32 -0500
Subject: [PATCH 116/145] Change type for pool k to I110F18

---
 pallets/subtensor/src/staking/stake_utils.rs | 29 +++++++--------
 pallets/subtensor/src/tests/staking.rs       | 39 ++++++++++++++++++++
 2 files changed, 53 insertions(+), 15 deletions(-)

diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index 805b61e50..e247f7f4f 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -2,7 +2,7 @@ use super::*;
 use safe_math::*;
 use share_pool::{SharePool, SharePoolDataOperations};
 use sp_std::ops::Neg;
-use substrate_fixed::types::{I64F64, I96F32, U64F64};
+use substrate_fixed::types::{I110F18, I64F64, I96F32, U64F64};
 
 impl<T: Config> Pallet<T> {
     /// Retrieves the total alpha issuance for a given subnet.
@@ -469,16 +469,15 @@ impl<T: Config> Pallet<T> {
         // Step 2: Initialized vars.
         if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 =
-                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
+            let tao_reserves: I110F18 = I110F18::saturating_from_num(SubnetTAO::<T>::get(netuid));
+            let alpha_reserves: I110F18 =
+                I110F18::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
-            let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
+            let k: I110F18 = alpha_reserves.saturating_mul(tao_reserves);
 
             // Calculate new alpha reserve
-            let new_alpha_reserves: I96F32 = k
-                .checked_div(tao_reserves.saturating_add(I96F32::saturating_from_num(tao)))
-                .unwrap_or(I96F32::saturating_from_num(0));
+            let new_alpha_reserves: I110F18 =
+                k.safe_div(tao_reserves.saturating_add(I110F18::saturating_from_num(tao)));
 
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // alpha_stake_recieved = current_alpha - (k / (current_tao + new_tao))
@@ -509,16 +508,16 @@ impl<T: Config> Pallet<T> {
         // Step 2: Swap alpha and attain tao
         if mechanism_id == 1 {
             // Step 3.a.1: Dynamic mechanism calculations
-            let tao_reserves: I96F32 = I96F32::saturating_from_num(SubnetTAO::<T>::get(netuid));
-            let alpha_reserves: I96F32 =
-                I96F32::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
+            let tao_reserves: I110F18 = I110F18::saturating_from_num(SubnetTAO::<T>::get(netuid));
+            let alpha_reserves: I110F18 =
+                I110F18::saturating_from_num(SubnetAlphaIn::<T>::get(netuid));
             // Step 3.a.2: Compute constant product k = alpha * tao
-            let k: I96F32 = alpha_reserves.saturating_mul(tao_reserves);
+            let k: I110F18 = alpha_reserves.saturating_mul(tao_reserves);
 
             // Calculate new tao reserve
-            let new_tao_reserves: I96F32 = k
-                .checked_div(alpha_reserves.saturating_add(I96F32::saturating_from_num(alpha)))
-                .unwrap_or(I96F32::saturating_from_num(0));
+            let new_tao_reserves: I110F18 = k
+                .checked_div(alpha_reserves.saturating_add(I110F18::saturating_from_num(alpha)))
+                .unwrap_or(I110F18::saturating_from_num(0));
 
             // Step 3.a.3: Calculate alpha staked using the constant product formula
             // tao_recieved = tao_reserves - (k / (alpha_reserves + new_tao))
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index a570175c9..b678968df 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -2309,3 +2309,42 @@ fn test_unstake_low_liquidity_validate() {
         );
     });
 }
+
+#[test]
+fn test_stake_oveflow() {
+    new_test_ext(1).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let coldkey_account_id = U256::from(435445);
+        let hotkey_account_id = U256::from(54544);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+        let amount = 21_000_000_000_000_000; // Max TAO supply
+        let fee = DefaultStakingFee::<Test>::get();
+        register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);
+
+        // Give it some $$$ in his coldkey balance
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount);
+
+        // Setup liquidity with 21M TAO values
+        SubnetTAO::<Test>::insert(netuid, amount);
+        SubnetAlphaIn::<Test>::insert(netuid, amount);
+
+        // Stake and check if the result is ok
+        assert_ok!(SubtensorModule::add_stake(
+            RuntimeOrigin::signed(coldkey_account_id),
+            hotkey_account_id,
+            netuid,
+            amount
+        ));
+
+        // Check if stake has increased properly (staking 1:1 to SubnetTAO results in SubnetTAO/2 alpha)
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_account_id, netuid),
+            (amount - fee) / 2,
+            epsilon = amount / 1_000_000,
+        );
+
+        // Check if total stake has increased accordingly.
+        assert_abs_diff_eq!(SubtensorModule::get_total_stake(), amount, epsilon = 10,);
+    });
+}

From af3fcf77cd2ed291eb7c1742f5f496a5b97a4e33 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 16:09:29 -0500
Subject: [PATCH 117/145] Raise minimum pool liquidity to 1 TAO

---
 pallets/subtensor/src/lib.rs            | 2 +-
 pallets/subtensor/src/tests/staking2.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 7f9cd7120..65bd1cd71 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -736,7 +736,7 @@ pub mod pallet {
     #[pallet::type_value]
     /// Default value for minimum liquidity in pool
     pub fn DefaultMinimumPoolLiquidity<T: Config>() -> I96F32 {
-        I96F32::saturating_from_num(1_000_000)
+        I96F32::saturating_from_num(1_000_000_000)
     }
 
     #[pallet::storage]
diff --git a/pallets/subtensor/src/tests/staking2.rs b/pallets/subtensor/src/tests/staking2.rs
index bb71c8594..2abff8faf 100644
--- a/pallets/subtensor/src/tests/staking2.rs
+++ b/pallets/subtensor/src/tests/staking2.rs
@@ -15,7 +15,7 @@ fn test_stake_base_case() {
 
         // Initialize subnet with some existing TAO and Alpha
         let initial_subnet_tao = 10_000_000_000; // 10 TAO
-        let initial_subnet_alpha = 5_000_000; // 5 Alpha
+        let initial_subnet_alpha = 5_000_000_000; // 5 Alpha
         SubnetTAO::<Test>::insert(netuid, initial_subnet_tao);
         SubnetAlphaIn::<Test>::insert(netuid, initial_subnet_alpha);
         SubnetAlphaOut::<Test>::insert(netuid, initial_subnet_alpha);

From baf4a95721c9a00499245605ebd6b536f4407426 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 16:48:41 -0500
Subject: [PATCH 118/145] Format

---
 pallets/subtensor/src/staking/add_stake.rs | 2 +-
 pallets/subtensor/src/tests/staking.rs     | 2 +-
 primitives/safe-math/src/lib.rs            | 8 ++++++--
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index 291d26a30..d6c49686a 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -180,7 +180,7 @@ impl<T: Config> Pallet<T> {
             limit_price_float
                 .saturating_mul(tao_reserve_float)
                 .saturating_mul(alpha_in_float),
-                U96F32::saturating_from_num(0.1),
+            U96F32::saturating_from_num(0.1),
         )
         .unwrap_or(zero);
 
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 0506fc82d..c5fe0578f 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -2458,4 +2458,4 @@ fn test_max_amount_add_dynamic() {
         assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX - 1) < 21_000_000_000_000_000);
         assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX / 2) < 21_000_000_000_000_000);
     });
-}
\ No newline at end of file
+}
diff --git a/primitives/safe-math/src/lib.rs b/primitives/safe-math/src/lib.rs
index 450b7a203..af27b738b 100644
--- a/primitives/safe-math/src/lib.rs
+++ b/primitives/safe-math/src/lib.rs
@@ -1,7 +1,10 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![allow(clippy::result_unit_err)]
 
-use substrate_fixed::{traits::Fixed, types::{I110F18, I32F32, I64F64, I96F32, U110F18, U64F64, U96F32}};
+use substrate_fixed::{
+    traits::Fixed,
+    types::{I110F18, I32F32, I64F64, I96F32, U110F18, U64F64, U96F32},
+};
 
 /// Safe division trait
 pub trait SafeDiv {
@@ -138,7 +141,8 @@ mod tests {
         let result: Option<U110F18> = checked_sqrt(value, epsilon);
         assert!(result.is_some());
         let sqrt_result: U110F18 = result.unwrap();
-        let precise_sqrt: U110F18 = U110F18::from_num(441_000_000_000_000_000_000_000_000_000_000.0_f64.sqrt());
+        let precise_sqrt: U110F18 =
+            U110F18::from_num(441_000_000_000_000_000_000_000_000_000_000.0_f64.sqrt());
         assert!(abs_diff(sqrt_result, precise_sqrt) <= epsilon);
     }
 

From bffbcd78727868a04eb50efd400450b0260412d1 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 18:26:02 -0500
Subject: [PATCH 119/145] Implement remove_stake_limit

---
 pallets/subtensor/src/staking/add_stake.rs    |  19 +-
 pallets/subtensor/src/staking/remove_stake.rs | 104 ++++++-
 pallets/subtensor/src/tests/staking.rs        | 265 +++++++++++++++++-
 primitives/safe-math/src/lib.rs               |   8 +-
 4 files changed, 363 insertions(+), 33 deletions(-)

diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index d6c49686a..fd4ec630a 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -79,7 +79,7 @@ impl<T: Config> Pallet<T> {
     ///     -  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.
     ///
     /// # Event:
     /// * StakeAdded;
@@ -176,16 +176,13 @@ impl<T: Config> Pallet<T> {
         // 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 sqrt: U96F32 = checked_sqrt(
-            limit_price_float
-                .saturating_mul(tao_reserve_float)
-                .saturating_mul(alpha_in_float),
-            U96F32::saturating_from_num(0.1),
-        )
-        .unwrap_or(zero);
-
-        U96F32::saturating_from_num(sqrt)
-            .saturating_sub(U96F32::saturating_from_num(tao_reserve_float))
+        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>()
     }
 }
diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index 59ff7e5b3..564a62f78 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -1,5 +1,7 @@
 use super::*;
+use safe_math::*;
 use sp_core::Get;
+use substrate_fixed::types::U96F32;
 
 impl<T: Config> Pallet<T> {
     /// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey.
@@ -222,23 +224,107 @@ impl<T: Config> Pallet<T> {
     }
 
     pub fn do_remove_stake_limit(
-        _origin: T::RuntimeOrigin,
-        _hotkey: T::AccountId,
+        origin: T::RuntimeOrigin,
+        hotkey: T::AccountId,
         netuid: u16,
-        _stake_to_be_added: u64,
+        alpha_unstaked: u64,
         limit_price: u64,
     ) -> dispatch::DispatchResult {
-        // TODO: Do all checks
+        // 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_remove_stake( origin:{:?} hotkey:{:?}, netuid: {:?}, alpha_unstaked:{:?} )",
+            coldkey,
+            hotkey,
+            netuid,
+            alpha_unstaked
+        );
+
+        // 2. Validate the user input
+        Self::validate_remove_stake(&coldkey, &hotkey, netuid, alpha_unstaked)?;
+
+        // 3. Calcaulate the maximum amount that can be executed with price limit
+        let max_amount = Self::get_max_amount_remove(netuid, limit_price);
+        let mut possible_alpha = alpha_unstaked;
+        if possible_alpha > max_amount {
+            possible_alpha = max_amount;
+        }
+
+        // 4. Swap the alpba to tao and update counters for this subnet.
+        let fee = DefaultStakingFee::<T>::get();
+        let tao_unstaked: u64 =
+            Self::unstake_from_subnet(&hotkey, &coldkey, netuid, possible_alpha, fee);
+
+        // 5. 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);
 
-        // Calcaulate the maximum amount that can be executed with price limit
-        let _max_amount = Self::get_max_amount_remove(netuid, limit_price);
+        // 6. If the stake is below the minimum, we clear the nomination from storage.
+        Self::clear_small_nomination_if_required(&hotkey, &coldkey, netuid);
 
-        // Ok and return.
+        // 7. Check if stake lowered below MinStake and remove Pending children if it did
+        if Self::get_total_stake_for_hotkey(&hotkey) < StakeThreshold::<T>::get() {
+            Self::get_all_subnet_netuids().iter().for_each(|netuid| {
+                PendingChildKeys::<T>::remove(netuid, &hotkey);
+            })
+        }
+
+        // Done and ok.
         Ok(())
     }
 
     // Returns the maximum amount of RAO that can be executed with price limit
-    pub fn get_max_amount_remove(_netuid: u16, _limit_price: u64) -> u64 {
-        0
+    pub fn get_max_amount_remove(netuid: u16, limit_price: u64) -> u64 {
+        // Corner case: root and stao
+        // There's no slippage for root or stable subnets, so if limit price is 1e9 rao or
+        // higher, then max_amount equals u64::MAX, otherwise it is 0.
+        if (netuid == Self::get_root_netuid()) || (SubnetMechanism::<T>::get(netuid)) == 0 {
+            if limit_price <= 1_000_000_000 {
+                return u64::MAX;
+            } else {
+                return 0;
+            }
+        }
+
+        // Corner case: SubnetAlphaIn is zero. Staking can't happen, so max amount is zero.
+        let alpha_in = SubnetAlphaIn::<T>::get(netuid);
+        if alpha_in == 0 {
+            return 0;
+        }
+        let alpha_in_float: U96F32 = U96F32::saturating_from_num(alpha_in);
+
+        // 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);
+
+        // Corner case: limit_price == 0 (because there's division by limit price)
+        // => can sell all
+        if limit_price == 0 {
+            return u64::MAX;
+        }
+
+        // Corner case: limit_price > current_price (price cannot increase with unstaking)
+        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) {
+            return 0;
+        }
+
+        // Main case: return SQRT(SubnetTAO * SubnetAlphaIn / limit_price) - SubnetAlphaIn
+        // This is the positive solution of quare equation for finding Alpha amount 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(tao_reserve_float, epsilon)
+            .unwrap_or(zero)
+            .saturating_mul(
+                checked_sqrt(alpha_in_float.safe_div(limit_price_float), epsilon).unwrap_or(zero),
+            );
+
+        sqrt.saturating_sub(U96F32::saturating_from_num(alpha_in_float))
+            .saturating_to_num::<u64>()
     }
 }
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index c5fe0578f..0c5f8d526 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -145,7 +145,7 @@ fn test_add_stake_err_signature() {
         let netuid = 1;
 
         assert_err!(
-            SubtensorModule::add_stake(RawOrigin::None.into(), hotkey_account_id, netuid, amount,),
+            SubtensorModule::add_stake(RawOrigin::None.into(), hotkey_account_id, netuid, amount),
             DispatchError::BadOrigin
         );
     });
@@ -2241,7 +2241,7 @@ fn test_stake_overflow() {
         );
 
         // Check if total stake has increased accordingly.
-        assert_abs_diff_eq!(SubtensorModule::get_total_stake(), amount, epsilon = 10,);
+        assert_abs_diff_eq!(SubtensorModule::get_total_stake(), amount, epsilon = 10);
     });
 }
 
@@ -2411,6 +2411,7 @@ fn test_max_amount_add_stable() {
     });
 }
 
+// cargo test --package pallet-subtensor --lib -- tests::staking::test_max_amount_add_dynamic --exact --show-output
 #[test]
 fn test_max_amount_add_dynamic() {
     new_test_ext(0).execute_with(|| {
@@ -2442,16 +2443,15 @@ fn test_max_amount_add_dynamic() {
         );
 
         // 4x price => max is 1x TAO
-        assert_eq!(
+        assert_abs_diff_eq!(
             SubtensorModule::get_max_amount_add(netuid, 6_000_000_000),
-            150_000_000_000
+            150_000_000_000,
+            epsilon = 10_000,
         );
 
-        // 1.50000....1 price => max is 46 rao
-        assert_eq!(
-            SubtensorModule::get_max_amount_add(netuid, 1_500_000_001),
-            46
-        );
+        // Precision test:
+        // 1.50000..100 price => max > 0
+        assert!(SubtensorModule::get_max_amount_add(netuid, 1_500_000_100) > 0);
 
         // Max price doesn't panic and returns something meaningful
         assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX) < 21_000_000_000_000_000);
@@ -2459,3 +2459,250 @@ fn test_max_amount_add_dynamic() {
         assert!(SubtensorModule::get_max_amount_add(netuid, u64::MAX / 2) < 21_000_000_000_000_000);
     });
 }
+
+#[test]
+fn test_max_amount_remove_root() {
+    new_test_ext(0).execute_with(|| {
+        // 0 price on root => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_remove(0, 0), 0);
+
+        // 0.999999... price on root => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_remove(0, 999_999_999), 0);
+
+        // 1.0 price on root => max is u64::MAX
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(0, 1_000_000_000),
+            u64::MAX
+        );
+
+        // 1.000...001 price on root => max is u64::MAX
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(0, 1_000_000_001),
+            u64::MAX
+        );
+
+        // 2.0 price on root => max is u64::MAX
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(0, 2_000_000_000),
+            u64::MAX
+        );
+    });
+}
+
+#[test]
+fn test_max_amount_remove_stable() {
+    new_test_ext(0).execute_with(|| {
+        let netuid: u16 = 1;
+        add_network(netuid, 1, 0);
+
+        // 0 price => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_remove(netuid, 0), 0);
+
+        // 0.999999... price => max is 0
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(netuid, 999_999_999),
+            0
+        );
+
+        // 1.0 price => max is u64::MAX
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(netuid, 1_000_000_000),
+            u64::MAX
+        );
+
+        // 1.000...001 price => max is u64::MAX
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(netuid, 1_000_000_001),
+            u64::MAX
+        );
+
+        // 2.0 price => max is u64::MAX
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(netuid, 2_000_000_000),
+            u64::MAX
+        );
+    });
+}
+
+// cargo test --package pallet-subtensor --lib -- tests::staking::test_max_amount_remove_dynamic --exact --show-output
+#[test]
+fn test_max_amount_remove_dynamic() {
+    new_test_ext(0).execute_with(|| {
+        let subnet_owner_coldkey = U256::from(1001);
+        let subnet_owner_hotkey = U256::from(1002);
+        let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
+
+        // Forse-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // 0 price => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_remove(netuid, 0), u64::MAX);
+
+        // Low price values don't blow things up
+        assert!(SubtensorModule::get_max_amount_remove(netuid, 1) > 0);
+        assert!(SubtensorModule::get_max_amount_remove(netuid, 2) > 0);
+        assert!(SubtensorModule::get_max_amount_remove(netuid, 3) > 0);
+
+        // 1.5000...1 price => max is 0
+        assert_eq!(
+            SubtensorModule::get_max_amount_remove(netuid, 1_500_000_001),
+            0
+        );
+
+        // 1.5 price => max is 0 because of non-zero slippage
+        assert_abs_diff_eq!(
+            SubtensorModule::get_max_amount_remove(netuid, 1_500_000_000),
+            0,
+            epsilon = 10_000
+        );
+
+        // 1/4 price => max is 2x Alpha
+        assert_abs_diff_eq!(
+            SubtensorModule::get_max_amount_remove(netuid, 375_000_000),
+            100_000_000_000,
+            epsilon = 10_000,
+        );
+
+        // Precision test:
+        // 1.499999.. price => max > 0
+        assert!(SubtensorModule::get_max_amount_remove(netuid, 1_499_999_999) > 0);
+
+        // Max price doesn't panic and returns something meaningful
+        assert!(SubtensorModule::get_max_amount_remove(netuid, u64::MAX) < 21_000_000_000_000_000);
+        assert!(
+            SubtensorModule::get_max_amount_remove(netuid, u64::MAX - 1) < 21_000_000_000_000_000
+        );
+        assert!(
+            SubtensorModule::get_max_amount_remove(netuid, u64::MAX / 2) < 21_000_000_000_000_000
+        );
+    });
+}
+
+#[test]
+fn test_add_stake_limit_ok() {
+    new_test_ext(1).execute_with(|| {
+        let hotkey_account_id = U256::from(533453);
+        let coldkey_account_id = U256::from(55453);
+        let amount = 300_000_000_000;
+        let fee = DefaultStakingFee::<Test>::get();
+
+        // add network
+        let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
+
+        // Forse-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // Give it some $$$ in his coldkey balance
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount);
+
+        // Setup limit price so that it doesn't peak above 4x of current price
+        // The amount that can be executed at this price is 150 TAO only
+        // Alpha produced will be equal to 50 = 100 - 150*100/300
+        let limit_price = 6_000_000_000;
+        let expected_executed_stake = 50_000_000_000;
+
+        // Add stake with slippage safety and check if the result is ok
+        assert_ok!(SubtensorModule::add_stake_limit(
+            RuntimeOrigin::signed(coldkey_account_id),
+            hotkey_account_id,
+            netuid,
+            amount,
+            limit_price
+        ));
+
+        // Check if stake has increased only by 50 Alpha
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey_account_id,
+                &coldkey_account_id,
+                netuid
+            ),
+            expected_executed_stake - fee,
+            epsilon = expected_executed_stake / 1000,
+        );
+
+        // Check that 150 TAO balance still remains free on coldkey
+        assert_abs_diff_eq!(
+            SubtensorModule::get_coldkey_balance(&coldkey_account_id),
+            150_000_000_000,
+            epsilon = 10_000
+        );
+
+        // Check that price has updated to ~6
+        let exp_price = U96F32::from_num(6.0);
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert!(exp_price.saturating_sub(current_price) < 0.0001);
+        assert!(current_price.saturating_sub(exp_price) < 0.0001);
+    });
+}
+
+#[test]
+fn test_remove_stake_limit_ok() {
+    new_test_ext(1).execute_with(|| {
+        let hotkey_account_id = U256::from(533453);
+        let coldkey_account_id = U256::from(55453);
+        let stake_amount = 300_000_000_000;
+        let unstake_amount = 150_000_000_000;
+        let fee = DefaultStakingFee::<Test>::get();
+
+        // add network
+        let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
+
+        // Give the neuron some stake to remove
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_account_id,
+            &coldkey_account_id,
+            netuid,
+            stake_amount,
+        );
+        let alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_account_id,
+            &coldkey_account_id,
+            netuid,
+        );
+
+        // Forse-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // Setup limit price so that it doesn't drop by more than 10% from current price
+        let limit_price = 1_350_000_000;
+
+        // Alpha unstaked = sqrt(150 * 100 / 1.35) - 100 ~ 5.409
+        let expected_alpha_reduction = 5_409_000_000;
+
+        // Remove stake with slippage safety
+        assert_ok!(SubtensorModule::remove_stake_limit(
+            RuntimeOrigin::signed(coldkey_account_id),
+            hotkey_account_id,
+            netuid,
+            unstake_amount,
+            limit_price
+        ));
+
+        // Check if stake has decreased only by
+        assert_abs_diff_eq!(
+            SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
+                &hotkey_account_id,
+                &coldkey_account_id,
+                netuid
+            ),
+            alpha_before - expected_alpha_reduction - fee,
+            epsilon = expected_alpha_reduction / 1_000,
+        );
+    });
+}
diff --git a/primitives/safe-math/src/lib.rs b/primitives/safe-math/src/lib.rs
index af27b738b..da68e819c 100644
--- a/primitives/safe-math/src/lib.rs
+++ b/primitives/safe-math/src/lib.rs
@@ -69,9 +69,9 @@ pub fn checked_sqrt<T: SafeDiv + Fixed>(value: T, epsilon: T) -> Option<T> {
 
     let mut high: T = value;
     let mut low: T = zero;
-    let mut middle: T = (high + low) / two;
+    let mut middle: T = high.saturating_add(low).safe_div(two);
 
-    let mut iteration = 0;
+    let mut iteration: i32 = 0;
     let max_iterations = 128;
     let mut check_val: T = value.safe_div(middle);
 
@@ -83,10 +83,10 @@ pub fn checked_sqrt<T: SafeDiv + Fixed>(value: T, epsilon: T) -> Option<T> {
             low = middle;
         }
 
-        middle = (high + low) / two;
+        middle = high.saturating_add(low).safe_div(two);
         check_val = value.safe_div(middle);
 
-        iteration += 1;
+        iteration = iteration.saturating_add(1);
         if iteration > max_iterations {
             break;
         }

From 0a99ee9167ab0eedb2b87f10a3c7e562858e849d Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 18:47:33 -0500
Subject: [PATCH 120/145] Fix clippy

---
 primitives/safe-math/src/lib.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/primitives/safe-math/src/lib.rs b/primitives/safe-math/src/lib.rs
index da68e819c..e73aeb003 100644
--- a/primitives/safe-math/src/lib.rs
+++ b/primitives/safe-math/src/lib.rs
@@ -1,5 +1,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 #![allow(clippy::result_unit_err)]
+#![cfg_attr(test, allow(clippy::arithmetic_side_effects))]
+#![cfg_attr(test, allow(clippy::unwrap_used))]
 
 use substrate_fixed::{
     traits::Fixed,

From 1bc4d6eeb05dabb53fc1d0c5843057a4a43052ca Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Tue, 28 Jan 2025 19:00:27 -0500
Subject: [PATCH 121/145] Fix tests

---
 pallets/subtensor/src/tests/staking.rs | 41 ++++++++++++++------------
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 0c5f8d526..51887a17d 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -2463,29 +2463,32 @@ fn test_max_amount_add_dynamic() {
 #[test]
 fn test_max_amount_remove_root() {
     new_test_ext(0).execute_with(|| {
-        // 0 price on root => max is 0
-        assert_eq!(SubtensorModule::get_max_amount_remove(0, 0), 0);
-
-        // 0.999999... price on root => max is 0
-        assert_eq!(SubtensorModule::get_max_amount_remove(0, 999_999_999), 0);
+        // 0 price on root => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_remove(0, 0), u64::MAX);
 
-        // 1.0 price on root => max is u64::MAX
+        // 0.5 price on root => max is u64::MAX
         assert_eq!(
-            SubtensorModule::get_max_amount_remove(0, 1_000_000_000),
+            SubtensorModule::get_max_amount_remove(0, 500_000_000),
             u64::MAX
         );
 
-        // 1.000...001 price on root => max is u64::MAX
+        // 0.999999... price on root => max is u64::MAX
         assert_eq!(
-            SubtensorModule::get_max_amount_remove(0, 1_000_000_001),
+            SubtensorModule::get_max_amount_remove(0, 999_999_999),
             u64::MAX
         );
 
-        // 2.0 price on root => max is u64::MAX
+        // 1.0 price on root => max is u64::MAX
         assert_eq!(
-            SubtensorModule::get_max_amount_remove(0, 2_000_000_000),
+            SubtensorModule::get_max_amount_remove(0, 1_000_000_000),
             u64::MAX
         );
+
+        // 1.000...001 price on root => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_remove(0, 1_000_000_001), 0);
+
+        // 2.0 price on root => max is 0
+        assert_eq!(SubtensorModule::get_max_amount_remove(0, 2_000_000_000), 0);
     });
 }
 
@@ -2495,13 +2498,13 @@ fn test_max_amount_remove_stable() {
         let netuid: u16 = 1;
         add_network(netuid, 1, 0);
 
-        // 0 price => max is 0
-        assert_eq!(SubtensorModule::get_max_amount_remove(netuid, 0), 0);
+        // 0 price => max is u64::MAX
+        assert_eq!(SubtensorModule::get_max_amount_remove(netuid, 0), u64::MAX);
 
-        // 0.999999... price => max is 0
+        // 0.999999... price => max is u64::MAX
         assert_eq!(
             SubtensorModule::get_max_amount_remove(netuid, 999_999_999),
-            0
+            u64::MAX
         );
 
         // 1.0 price => max is u64::MAX
@@ -2510,16 +2513,16 @@ fn test_max_amount_remove_stable() {
             u64::MAX
         );
 
-        // 1.000...001 price => max is u64::MAX
+        // 1.000...001 price => max is 0
         assert_eq!(
             SubtensorModule::get_max_amount_remove(netuid, 1_000_000_001),
-            u64::MAX
+            0
         );
 
-        // 2.0 price => max is u64::MAX
+        // 2.0 price => max is 0
         assert_eq!(
             SubtensorModule::get_max_amount_remove(netuid, 2_000_000_000),
-            u64::MAX
+            0
         );
     });
 }

From 06ba8e57fccdc9b4e152711e355026d317349ee4 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Wed, 29 Jan 2025 14:50:06 +0100
Subject: [PATCH 122/145] Add an option to run try-runtime script with a
 snapshot

---
 scripts/try-runtime-upgrade.sh | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/scripts/try-runtime-upgrade.sh b/scripts/try-runtime-upgrade.sh
index 7c3e5fe77..80495bcb1 100755
--- a/scripts/try-runtime-upgrade.sh
+++ b/scripts/try-runtime-upgrade.sh
@@ -3,7 +3,7 @@
 # Tries runtime upgrade (via try-runtime).
 #
 # Usage:
-#   try-runtime-upgrade.sh [-p <runtime-path>] [-u <live-chain-url>]
+#   try-runtime-upgrade.sh [-p <runtime-path>] [-u <live-chain-url>] [-s <snapshot-path>]
 #
 # Dependencies:
 #   - rust toolchain
@@ -13,15 +13,28 @@ set -eou pipefail
 
 runtime_wasm_path="./target/release/wbuild/node-subtensor-runtime/node_subtensor_runtime.compact.wasm"
 live_chain_url="wss://dev.chain.opentensor.ai:443"
+snapshot_path=""
 
 parse_args() {
-  while getopts "p:u:" opt; do
+  u_provided=false
+
+  while getopts "r:u:s:" opt; do
     case "${opt}" in
-    p) runtime_wasm_path="${OPTARG}" ;;
-    u) live_chain_url="${OPTARG}" ;;
-    *) echo "Usage: $(basename "$0") [-p <runtime-path>] [-u <live-chain-url>]" && exit 1 ;;
+    r) runtime_wasm_path="${OPTARG}" ;;
+    u)
+      live_chain_url="${OPTARG}"
+      u_provided=true
+      ;;
+    s) snapshot_path="${OPTARG}" ;;
+    *) echo "Usage: $(basename "$0") [-r <runtime-path>] [-u <live-chain-url>] [-s <snapshot-path>]" && exit 1 ;;
     esac
   done
+
+  # Prevent specifying URI if snapshot is specified
+  if [ -n "$snapshot_path" ] && [ "$u_provided" = true ]; then
+    echo "Error: Either live URI or snapshot path should be specified, but not both."
+    exit 1
+  fi
 }
 
 build_runtime() {
@@ -29,7 +42,15 @@ build_runtime() {
 }
 
 do_try_runtime() {
-  try-runtime --runtime "$runtime_wasm_path" on-runtime-upgrade live --uri "$live_chain_url"
+  if [ -n "$snapshot_path" ]; then
+    chain_state="snap --path $snapshot_path"
+  else
+    chain_state="live --uri $live_chain_url"
+  fi
+
+  eval "try-runtime --runtime $runtime_wasm_path on-runtime-upgrade \
+    --no-weight-warnings --disable-spec-version-check --disable-idempotency-checks \
+    $chain_state"
 }
 
 parse_args "$@"

From 3678d4c2aee36a0984f552bb89694ef95e094428 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Wed, 29 Jan 2025 15:08:05 +0100
Subject: [PATCH 123/145] Update spec version

---
 runtime/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 372c9a981..2a2d2fac4 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
     //   `spec_version`, and `authoring_version` are the same between Wasm and native.
     // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
     //   the compatible custom types.
-    spec_version: 224,
+    spec_version: 225,
     impl_version: 1,
     apis: RUNTIME_API_VERSIONS,
     transaction_version: 1,

From 79ed9e3d09cf725fa6cd24c9c53bce03e786e5fc Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Wed, 29 Jan 2025 11:33:05 -0500
Subject: [PATCH 124/145] Add allow_partial parameter for add_stake_limit and
 remove_stake_limit

---
 pallets/subtensor/src/lib.rs                  |  10 ++
 pallets/subtensor/src/macros/dispatches.rs    |  28 ++++-
 pallets/subtensor/src/macros/errors.rs        |   2 +
 pallets/subtensor/src/staking/add_stake.rs    |  29 ++++-
 pallets/subtensor/src/staking/remove_stake.rs |  63 +++++++++-
 pallets/subtensor/src/staking/stake_utils.rs  |  16 +++
 pallets/subtensor/src/tests/staking.rs        | 112 +++++++++++++++++-
 7 files changed, 246 insertions(+), 14 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 7f9cd7120..d346b9241 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -1569,6 +1569,7 @@ pub enum CustomTransactionError {
     NotEnoughStakeToWithdraw,
     RateLimitExceeded,
     InsufficientLiquidity,
+    SlippageTooHigh,
     BadRequest,
 }
 
@@ -1583,6 +1584,7 @@ impl From<CustomTransactionError> for u8 {
             CustomTransactionError::NotEnoughStakeToWithdraw => 5,
             CustomTransactionError::RateLimitExceeded => 6,
             CustomTransactionError::InsufficientLiquidity => 7,
+            CustomTransactionError::SlippageTooHigh => 8,
             CustomTransactionError::BadRequest => 255,
         }
     }
@@ -1654,6 +1656,10 @@ where
                     CustomTransactionError::InsufficientLiquidity.into(),
                 )
                 .into()),
+                Error::<T>::SlippageTooHigh => Err(InvalidTransaction::Custom(
+                    CustomTransactionError::SlippageTooHigh.into(),
+                )
+                .into()),
                 _ => Err(
                     InvalidTransaction::Custom(CustomTransactionError::BadRequest.into()).into(),
                 ),
@@ -1801,6 +1807,8 @@ where
                     hotkey,
                     *netuid,
                     *amount_staked,
+                    *amount_staked,
+                    false,
                 ))
             }
             Some(Call::remove_stake {
@@ -1814,6 +1822,8 @@ where
                     hotkey,
                     *netuid,
                     *amount_unstaked,
+                    *amount_unstaked,
+                    false,
                 ))
             }
             Some(Call::move_stake {
diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs
index 2a1165b1f..6b8592db8 100644
--- a/pallets/subtensor/src/macros/dispatches.rs
+++ b/pallets/subtensor/src/macros/dispatches.rs
@@ -1710,6 +1710,10 @@ mod dispatches {
         ///  * 'limit_price' (u64):
         /// 	- 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
+        ///       fill or kill type or order.
+        ///
         /// # Event:
         ///  * StakeAdded;
         /// 	- On the successfully adding stake to a global account.
@@ -1734,8 +1738,16 @@ mod dispatches {
             netuid: u16,
             amount_staked: u64,
             limit_price: u64,
+            allow_partial: bool,
         ) -> DispatchResult {
-            Self::do_add_stake_limit(origin, hotkey, netuid, amount_staked, limit_price)
+            Self::do_add_stake_limit(
+                origin,
+                hotkey,
+                netuid,
+                amount_staked,
+                limit_price,
+                allow_partial,
+            )
         }
 
         /// --- Removes stake from a hotkey on a subnet with a price limit.
@@ -1759,6 +1771,10 @@ mod dispatches {
         ///  * 'limit_price' (u64):
         /// 	- 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
+        ///       fill or kill type or order.
+        ///
         /// # Event:
         /// * StakeRemoved;
         /// 	- On the successfully removing stake from the hotkey account.
@@ -1784,8 +1800,16 @@ mod dispatches {
             netuid: u16,
             amount_unstaked: u64,
             limit_price: u64,
+            allow_partial: bool,
         ) -> DispatchResult {
-            Self::do_remove_stake_limit(origin, hotkey, netuid, amount_unstaked, limit_price)
+            Self::do_remove_stake_limit(
+                origin,
+                hotkey,
+                netuid,
+                amount_unstaked,
+                limit_price,
+                allow_partial,
+            )
         }
     }
 }
diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs
index f1eea3b9c..926aead58 100644
--- a/pallets/subtensor/src/macros/errors.rs
+++ b/pallets/subtensor/src/macros/errors.rs
@@ -187,5 +187,7 @@ mod errors {
         AmountTooLow,
         /// Not enough liquidity.
         InsufficientLiquidity,
+        /// Slippage is too high for the transaction.
+        SlippageTooHigh,
     }
 }
diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs
index fd4ec630a..ded1ae18a 100644
--- a/pallets/subtensor/src/staking/add_stake.rs
+++ b/pallets/subtensor/src/staking/add_stake.rs
@@ -50,7 +50,14 @@ impl<T: Config> Pallet<T> {
         );
 
         // 2. Validate user input
-        Self::validate_add_stake(&coldkey, &hotkey, netuid, stake_to_be_added)?;
+        Self::validate_add_stake(
+            &coldkey,
+            &hotkey,
+            netuid,
+            stake_to_be_added,
+            stake_to_be_added,
+            false,
+        )?;
 
         // 3. Ensure the remove operation from the coldkey is a success.
         let tao_staked: u64 =
@@ -81,6 +88,10 @@ impl<T: Config> Pallet<T> {
     ///  * 'limit_price' (u64):
     ///     - 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
+    ///       fill or kill type or order.
+    ///
     /// # Event:
     /// * StakeAdded;
     ///     -  On the successfully adding stake to a global account.
@@ -104,6 +115,7 @@ impl<T: Config> Pallet<T> {
         netuid: u16,
         stake_to_be_added: u64,
         limit_price: u64,
+        allow_partial: bool,
     ) -> dispatch::DispatchResult {
         // 1. We check that the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
         let coldkey = ensure_signed(origin)?;
@@ -115,16 +127,23 @@ impl<T: Config> Pallet<T> {
             stake_to_be_added
         );
 
-        // 2. Validate user input
-        Self::validate_add_stake(&coldkey, &hotkey, netuid, stake_to_be_added)?;
-
-        // 3. Calcaulate the maximum amount that can be executed with price limit
+        // 2. Calcaulate the maximum amount that can be executed with price limit
         let max_amount = Self::get_max_amount_add(netuid, limit_price);
         let mut possible_stake = stake_to_be_added;
         if possible_stake > max_amount {
             possible_stake = max_amount;
         }
 
+        // 3. Validate user input
+        Self::validate_add_stake(
+            &coldkey,
+            &hotkey,
+            netuid,
+            stake_to_be_added,
+            max_amount,
+            allow_partial,
+        )?;
+
         // 4. Ensure the remove operation from the coldkey is a success.
         let tao_staked: u64 = Self::remove_balance_from_coldkey_account(&coldkey, possible_stake)?;
 
diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index 564a62f78..743188057 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -50,7 +50,14 @@ impl<T: Config> Pallet<T> {
         );
 
         // 2. Validate the user input
-        Self::validate_remove_stake(&coldkey, &hotkey, netuid, alpha_unstaked)?;
+        Self::validate_remove_stake(
+            &coldkey,
+            &hotkey,
+            netuid,
+            alpha_unstaked,
+            alpha_unstaked,
+            false,
+        )?;
 
         // 3. Swap the alpba to tao and update counters for this subnet.
         let fee = DefaultStakingFee::<T>::get();
@@ -223,12 +230,51 @@ impl<T: Config> Pallet<T> {
         Ok(())
     }
 
+    /// ---- The implementation for the extrinsic remove_stake_limit: Removes stake from
+    /// a hotkey on a subnet with a price limit.
+    ///
+    /// In case if slippage occurs and the price shall move beyond the limit
+    /// price, the staking order may execute only partially or not execute
+    /// at all.
+    ///
+    /// # Args:
+    /// * 'origin': (<T as frame_system::Config>Origin):
+    ///     - The signature of the caller's coldkey.
+    ///
+    /// * 'hotkey' (T::AccountId):
+    ///     - The associated hotkey account.
+    ///
+    /// * 'amount_unstaked' (u64):
+    ///     - 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.
+    ///
+    ///  * 'allow_partial' (bool):
+    ///     - Allows partial execution of the amount. If set to false, this becomes
+    ///       fill or kill type or order.
+    ///
+    /// # Event:
+    /// * StakeRemoved;
+    ///     - On the successfully removing stake from the hotkey account.
+    ///
+    /// # Raises:
+    /// * 'NotRegistered':
+    ///     - Thrown if the account we are attempting to unstake from is non existent.
+    ///
+    /// * 'NonAssociatedColdKey':
+    ///     - Thrown if the coldkey does not own the hotkey we are unstaking from.
+    ///
+    /// * 'NotEnoughStakeToWithdraw':
+    ///     - Thrown if there is not enough stake on the hotkey to withdwraw this amount.
+    ///
     pub fn do_remove_stake_limit(
         origin: T::RuntimeOrigin,
         hotkey: T::AccountId,
         netuid: u16,
         alpha_unstaked: u64,
         limit_price: u64,
+        allow_partial: bool,
     ) -> dispatch::DispatchResult {
         // 1. We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information.
         let coldkey = ensure_signed(origin)?;
@@ -240,16 +286,23 @@ impl<T: Config> Pallet<T> {
             alpha_unstaked
         );
 
-        // 2. Validate the user input
-        Self::validate_remove_stake(&coldkey, &hotkey, netuid, alpha_unstaked)?;
-
-        // 3. Calcaulate the maximum amount that can be executed with price limit
+        // 2. Calcaulate the maximum amount that can be executed with price limit
         let max_amount = Self::get_max_amount_remove(netuid, limit_price);
         let mut possible_alpha = alpha_unstaked;
         if possible_alpha > max_amount {
             possible_alpha = max_amount;
         }
 
+        // 3. Validate the user input
+        Self::validate_remove_stake(
+            &coldkey,
+            &hotkey,
+            netuid,
+            alpha_unstaked,
+            max_amount,
+            allow_partial,
+        )?;
+
         // 4. Swap the alpba to tao and update counters for this subnet.
         let fee = DefaultStakingFee::<T>::get();
         let tao_unstaked: u64 =
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index e247f7f4f..4c446947f 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -729,6 +729,8 @@ impl<T: Config> Pallet<T> {
         hotkey: &T::AccountId,
         netuid: u16,
         stake_to_be_added: u64,
+        max_amount: u64,
+        allow_partial: bool,
     ) -> Result<(), Error<T>> {
         // Ensure that the subnet exists.
         ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
@@ -739,6 +741,12 @@ impl<T: Config> Pallet<T> {
         // Ensure that the stake_to_be_added is at least the min_amount
         ensure!(stake_to_be_added >= min_amount, Error::<T>::AmountTooLow);
 
+        // Ensure that if partial execution is not allowed, the amount will not cause
+        // slippage over desired
+        if !allow_partial {
+            ensure!(stake_to_be_added <= max_amount, Error::<T>::SlippageTooHigh);
+        }
+
         // Ensure the callers coldkey has enough stake to perform the transaction.
         ensure!(
             Self::can_remove_balance_from_coldkey_account(coldkey, stake_to_be_added),
@@ -767,6 +775,8 @@ impl<T: Config> Pallet<T> {
         hotkey: &T::AccountId,
         netuid: u16,
         alpha_unstaked: u64,
+        max_amount: u64,
+        allow_partial: bool,
     ) -> Result<(), Error<T>> {
         // Ensure that the subnet exists.
         ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
@@ -781,6 +791,12 @@ impl<T: Config> Pallet<T> {
             return Err(Error::<T>::InsufficientLiquidity);
         };
 
+        // Ensure that if partial execution is not allowed, the amount will not cause
+        // slippage over desired
+        if !allow_partial {
+            ensure!(alpha_unstaked <= max_amount, Error::<T>::SlippageTooHigh);
+        }
+
         // Ensure that the hotkey account exists this is only possible through registration.
         ensure!(
             Self::hotkey_account_exists(hotkey),
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 51887a17d..a96c91b2b 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -2620,7 +2620,8 @@ fn test_add_stake_limit_ok() {
             hotkey_account_id,
             netuid,
             amount,
-            limit_price
+            limit_price,
+            true
         ));
 
         // Check if stake has increased only by 50 Alpha
@@ -2649,6 +2650,57 @@ fn test_add_stake_limit_ok() {
     });
 }
 
+#[test]
+fn test_add_stake_limit_fill_or_kill() {
+    new_test_ext(1).execute_with(|| {
+        let hotkey_account_id = U256::from(533453);
+        let coldkey_account_id = U256::from(55453);
+        let amount = 300_000_000_000;
+
+        // add network
+        let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
+
+        // Forse-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // Give it some $$$ in his coldkey balance
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount);
+
+        // Setup limit price so that it doesn't peak above 4x of current price
+        // The amount that can be executed at this price is 150 TAO only
+        // Alpha produced will be equal to 50 = 100 - 150*100/300
+        let limit_price = 6_000_000_000;
+
+        // Add stake with slippage safety and check if it fails
+        assert_noop!(
+            SubtensorModule::add_stake_limit(
+                RuntimeOrigin::signed(coldkey_account_id),
+                hotkey_account_id,
+                netuid,
+                amount,
+                limit_price,
+                false
+            ),
+            Error::<Test>::SlippageTooHigh
+        );
+
+        // Lower the amount and it should succeed now
+        assert_ok!(SubtensorModule::add_stake_limit(
+            RuntimeOrigin::signed(coldkey_account_id),
+            hotkey_account_id,
+            netuid,
+            amount / 100,
+            limit_price,
+            false
+        ));
+    });
+}
+
 #[test]
 fn test_remove_stake_limit_ok() {
     new_test_ext(1).execute_with(|| {
@@ -2694,7 +2746,8 @@ fn test_remove_stake_limit_ok() {
             hotkey_account_id,
             netuid,
             unstake_amount,
-            limit_price
+            limit_price,
+            true
         ));
 
         // Check if stake has decreased only by
@@ -2709,3 +2762,58 @@ fn test_remove_stake_limit_ok() {
         );
     });
 }
+
+#[test]
+fn test_remove_stake_limit_fill_or_kill() {
+    new_test_ext(1).execute_with(|| {
+        let hotkey_account_id = U256::from(533453);
+        let coldkey_account_id = U256::from(55453);
+        let stake_amount = 300_000_000_000;
+        let unstake_amount = 150_000_000_000;
+
+        // add network
+        let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
+
+        // Give the neuron some stake to remove
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey_account_id,
+            &coldkey_account_id,
+            netuid,
+            stake_amount,
+        );
+
+        // Forse-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // Setup limit price so that it doesn't drop by more than 10% from current price
+        let limit_price = 1_350_000_000;
+
+        // Remove stake with slippage safety - fails
+        assert_noop!(
+            SubtensorModule::remove_stake_limit(
+                RuntimeOrigin::signed(coldkey_account_id),
+                hotkey_account_id,
+                netuid,
+                unstake_amount,
+                limit_price,
+                false
+            ),
+            Error::<Test>::SlippageTooHigh
+        );
+
+        // Lower the amount: Should succeed
+        assert_ok!(SubtensorModule::remove_stake_limit(
+            RuntimeOrigin::signed(coldkey_account_id),
+            hotkey_account_id,
+            netuid,
+            unstake_amount / 100,
+            limit_price,
+            false
+        ),);
+    });
+}

From 55203dedca0912df3d45e0cdf5aaf8951c7df4d8 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Wed, 29 Jan 2025 11:47:39 -0500
Subject: [PATCH 125/145] Bump spec version to 225

---
 runtime/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs
index 372c9a981..2a2d2fac4 100644
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
     //   `spec_version`, and `authoring_version` are the same between Wasm and native.
     // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
     //   the compatible custom types.
-    spec_version: 224,
+    spec_version: 225,
     impl_version: 1,
     apis: RUNTIME_API_VERSIONS,
     transaction_version: 1,

From 0a2635f31f48ee7a4791597d05f8d44a73e4e913 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Wed, 29 Jan 2025 12:28:27 -0500
Subject: [PATCH 126/145] Update pallets/subtensor/src/tests/staking.rs

Co-authored-by: Cameron Fairchild <cameron@opentensor.ai>
---
 pallets/subtensor/src/tests/staking.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index a96c91b2b..6a61008a3 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -2660,7 +2660,7 @@ fn test_add_stake_limit_fill_or_kill() {
         // add network
         let netuid: u16 = add_dynamic_network(&hotkey_account_id, &coldkey_account_id);
 
-        // Forse-set alpha in and tao reserve to make price equal 1.5
+        // Force-set alpha in and tao reserve to make price equal 1.5
         let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
         let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
         SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());

From c3822c70c23418555680879bbb8e7101d09e52fa Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Wed, 29 Jan 2025 12:28:34 -0500
Subject: [PATCH 127/145] Update pallets/subtensor/src/staking/remove_stake.rs

Co-authored-by: Cameron Fairchild <cameron@opentensor.ai>
---
 pallets/subtensor/src/staking/remove_stake.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs
index 743188057..92d0c2e83 100644
--- a/pallets/subtensor/src/staking/remove_stake.rs
+++ b/pallets/subtensor/src/staking/remove_stake.rs
@@ -303,7 +303,7 @@ impl<T: Config> Pallet<T> {
             allow_partial,
         )?;
 
-        // 4. Swap the alpba to tao and update counters for this subnet.
+        // 4. Swap the alpha to tao and update counters for this subnet.
         let fee = DefaultStakingFee::<T>::get();
         let tao_unstaked: u64 =
             Self::unstake_from_subnet(&hotkey, &coldkey, netuid, possible_alpha, fee);

From f644f267244b4da4b5d8b4ba007f8e99bf881bde Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 30 Jan 2025 10:54:47 +0800
Subject: [PATCH 128/145] refactor code

---
 runtime/src/precompiles/balance_transfer.rs |   9 +-
 runtime/src/precompiles/mod.rs              | 107 ++++----------------
 runtime/src/precompiles/neuron.rs           |  20 ++--
 runtime/src/precompiles/staking.rs          |  27 +++--
 runtime/src/precompiles/subnet.rs           |  15 ++-
 5 files changed, 67 insertions(+), 111 deletions(-)

diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs
index 25dfcfc9f..6154cf8a5 100644
--- a/runtime/src/precompiles/balance_transfer.rs
+++ b/runtime/src/precompiles/balance_transfer.rs
@@ -1,11 +1,12 @@
-use frame_system::RawOrigin;
 use pallet_evm::{
     BalanceConverter, ExitError, ExitSucceed, PrecompileHandle, PrecompileOutput, PrecompileResult,
 };
 use sp_runtime::traits::UniqueSaturatedInto;
 use sp_std::vec;
 
-use crate::precompiles::{get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call};
+use crate::precompiles::{
+    contract_to_origin, get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call,
+};
 use crate::Runtime;
 
 pub const BALANCE_TRANSFER_INDEX: u64 = 2048;
@@ -47,15 +48,13 @@ impl BalanceTransferPrecompile {
         }
 
         let address_bytes_dst = get_slice(txdata, 4, 36)?;
-        let (account_id_src, _) = get_pubkey(&CONTRACT_ADDRESS_SS58)?;
         let (account_id_dst, _) = get_pubkey(address_bytes_dst)?;
 
         let call = pallet_balances::Call::<Runtime>::transfer_allow_death {
             dest: account_id_dst.into(),
             value: amount_sub.unique_saturated_into(),
         };
-        let origin = RawOrigin::Signed(account_id_src);
 
-        try_dispatch_runtime_call(handle, call, origin)
+        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
     }
 }
diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs
index e4009d39d..d820f50ec 100644
--- a/runtime/src/precompiles/mod.rs
+++ b/runtime/src/precompiles/mod.rs
@@ -6,9 +6,8 @@ use core::marker::PhantomData;
 use frame_support::dispatch::{GetDispatchInfo, Pays};
 
 use pallet_evm::{
-    AddressMapping, BalanceConverter, ExitError, ExitSucceed, GasWeightMapping,
-    HashedAddressMapping, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
-    PrecompileOutput, PrecompileResult, PrecompileSet,
+    ExitError, ExitSucceed, GasWeightMapping, IsPrecompileResult, Precompile, PrecompileFailure,
+    PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet,
 };
 use pallet_evm_precompile_modexp::Modexp;
 use pallet_evm_precompile_sha3fips::Sha3FIPS256;
@@ -20,10 +19,6 @@ use crate::{Runtime, RuntimeCall};
 
 use frame_system::RawOrigin;
 
-use sp_core::crypto::Ss58Codec;
-use sp_core::U256;
-use sp_runtime::traits::{BlakeTwo256, UniqueSaturatedInto};
-
 use sp_std::vec;
 
 // Include custom precompiles
@@ -147,84 +142,6 @@ pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], Precompil
     }
 }
 
-/// The function return the token to smart contract
-fn transfer_back_to_caller(
-    smart_contract_address: &str,
-    account_id: &AccountId32,
-    amount: U256,
-) -> Result<(), PrecompileFailure> {
-    // this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
-    let smart_contract_account_id = match AccountId32::from_ss58check(smart_contract_address) {
-        // match AccountId32::from_ss58check("5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X") {
-        Ok(addr) => addr,
-        Err(_) => {
-            return Err(PrecompileFailure::Error {
-                exit_status: ExitError::Other("Invalid SS58 address".into()),
-            });
-        }
-    };
-    let amount_sub =
-        <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
-            .ok_or(ExitError::OutOfFund)?;
-
-    // Create a transfer call from the smart contract to the caller
-    let transfer_call =
-        RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
-            dest: account_id.clone().into(),
-            value: amount_sub.unique_saturated_into(),
-        });
-
-    // Execute the transfer
-    let transfer_result =
-        transfer_call.dispatch(RawOrigin::Signed(smart_contract_account_id).into());
-
-    if let Err(dispatch_error) = transfer_result {
-        log::error!(
-            "Transfer back to caller failed. Error: {:?}",
-            dispatch_error
-        );
-        return Err(PrecompileFailure::Error {
-            exit_status: ExitError::Other("Transfer back to caller failed".into()),
-        });
-    }
-
-    Ok(())
-}
-
-fn dispatch(
-    handle: &mut impl PrecompileHandle,
-    call: RuntimeCall,
-    smart_contract_address: &str,
-) -> PrecompileResult {
-    let account_id =
-        <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
-            handle.context().caller,
-        );
-
-    // Transfer the amount back to the caller before executing the staking operation
-    // let caller = handle.context().caller;
-    let amount = handle.context().apparent_value;
-
-    if !amount.is_zero() {
-        transfer_back_to_caller(smart_contract_address, &account_id, amount)?;
-    }
-
-    let result = call.dispatch(RawOrigin::Signed(account_id.clone()).into());
-    match &result {
-        Ok(post_info) => log::info!("Dispatch succeeded. Post info: {:?}", post_info),
-        Err(dispatch_error) => log::error!("Dispatch failed. Error: {:?}", dispatch_error),
-    }
-    match result {
-        Ok(_) => Ok(PrecompileOutput {
-            exit_status: ExitSucceed::Returned,
-            output: vec![],
-        }),
-        Err(_) => Err(PrecompileFailure::Error {
-            exit_status: ExitError::Other("Subtensor call failed".into()),
-        }),
-    }
-}
-
 pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec<u8>), PrecompileFailure> {
     let mut pubkey = [0u8; 32];
     pubkey.copy_from_slice(get_slice(data, 0, 32)?);
@@ -235,6 +152,26 @@ pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec<u8>), Precompile
             .map_or_else(vec::Vec::new, |slice| slice.to_vec()),
     ))
 }
+
+fn parse_netuid(data: &[u8], offset: usize) -> Result<u16, PrecompileFailure> {
+    if data.len() < offset + 2 {
+        return Err(PrecompileFailure::Error {
+            exit_status: ExitError::InvalidRange,
+        });
+    }
+
+    let mut netuid_bytes = [0u8; 2];
+    netuid_bytes.copy_from_slice(get_slice(data, offset, offset + 2)?);
+    let netuid: u16 = netuid_bytes[1] as u16 | ((netuid_bytes[0] as u16) << 8u16);
+
+    Ok(netuid)
+}
+
+fn contract_to_origin(contract: &[u8; 32]) -> Result<RawOrigin<AccountId32>, PrecompileFailure> {
+    let (account_id, _) = get_pubkey(contract)?;
+    Ok(RawOrigin::Signed(account_id))
+}
+
 /// Dispatches a runtime call, but also checks and records the gas costs.
 fn try_dispatch_runtime_call(
     handle: &mut impl PrecompileHandle,
diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs
index efa0b5fec..97167c900 100644
--- a/runtime/src/precompiles/neuron.rs
+++ b/runtime/src/precompiles/neuron.rs
@@ -1,15 +1,21 @@
 use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
 
-use crate::precompiles::{dispatch, get_method_id, get_pubkey, get_slice};
+use crate::precompiles::{
+    contract_to_origin, get_method_id, get_pubkey, get_slice, parse_netuid,
+    try_dispatch_runtime_call,
+};
 use sp_runtime::AccountId32;
 use sp_std::vec;
 
 use crate::{Runtime, RuntimeCall};
 pub const NEURON_PRECOMPILE_INDEX: u64 = 2052;
 
-// this is neuron smart contract's(0x0000000000000000000000000000000000000804) sr25519 address
-pub const NEURON_CONTRACT_ADDRESS: &str = "5GKZiUUgTnWSz3BgiVBMehEKkLszsG4ZXnvgWpWFUFKqrqyn";
-
+// ss58 public key i.e., the contract sends funds it received to the destination address from the
+// method parameter.
+const CONTRACT_ADDRESS_SS58: [u8; 32] = [
+    0xbc, 0x46, 0x35, 0x79, 0xbc, 0x99, 0xf9, 0xee, 0x7c, 0x59, 0xed, 0xee, 0x20, 0x61, 0xa3, 0x09,
+    0xd2, 0x1e, 0x68, 0xd5, 0x39, 0xb6, 0x40, 0xec, 0x66, 0x46, 0x90, 0x30, 0xab, 0x74, 0xc1, 0xdb,
+];
 pub struct NeuronPrecompile;
 
 impl NeuronPrecompile {
@@ -38,7 +44,7 @@ impl NeuronPrecompile {
                 netuid,
                 hotkey,
             });
-        dispatch(handle, call, NEURON_CONTRACT_ADDRESS)
+        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
     }
 
     fn parse_netuid_hotkey_parameter(data: &[u8]) -> Result<(u16, AccountId32), PrecompileFailure> {
@@ -47,9 +53,7 @@ impl NeuronPrecompile {
                 exit_status: ExitError::InvalidRange,
             });
         }
-        let mut netuid_vec = [0u8; 2];
-        netuid_vec.copy_from_slice(get_slice(data, 30, 32)?);
-        let netuid = u16::from_be_bytes(netuid_vec);
+        let netuid = parse_netuid(data, 30)?;
 
         let (hotkey, _) = get_pubkey(get_slice(data, 32, 64)?)?;
 
diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index d588799fc..3c3ee7ad9 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -25,7 +25,10 @@
 //   - Precompile checks the result of do_remove_stake and, in case of a failure, reverts the transaction.
 //
 
-use crate::precompiles::{dispatch, get_method_id, get_pubkey, get_slice};
+use crate::precompiles::{
+    contract_to_origin, get_method_id, get_pubkey, get_slice, parse_netuid,
+    try_dispatch_runtime_call,
+};
 use crate::{ProxyType, Runtime, RuntimeCall};
 use pallet_evm::{
     BalanceConverter, ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle,
@@ -36,8 +39,14 @@ use sp_runtime::traits::{StaticLookup, UniqueSaturatedInto};
 use sp_std::vec;
 
 pub const STAKING_PRECOMPILE_INDEX: u64 = 2049;
-// this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address
-pub const STAKING_CONTRACT_ADDRESS: &str = "5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X";
+
+// ss58 public key i.e., the contract sends funds it received to the destination address from the
+// method parameter.
+const CONTRACT_ADDRESS_SS58: [u8; 32] = [
+    0x26, 0xf4, 0x10, 0x1e, 0x52, 0xb7, 0x57, 0x34, 0x33, 0x24, 0x5b, 0xc3, 0x0a, 0xe1, 0x8b, 0x63,
+    0x99, 0x53, 0xd8, 0x41, 0x79, 0x33, 0x03, 0x61, 0x4d, 0xfa, 0xcf, 0xf0, 0x37, 0xf7, 0x12, 0x94,
+];
+
 pub struct StakingPrecompile;
 
 impl StakingPrecompile {
@@ -74,14 +83,16 @@ impl StakingPrecompile {
             <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
                 .ok_or(ExitError::OutOfFund)?;
 
+        // let (account_id_src, _) = get_pubkey(&CONTRACT_ADDRESS_SS58)?;
         // Create the add_stake call
         let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::<Runtime>::add_stake {
             hotkey,
             netuid,
             amount_staked: amount_sub.unique_saturated_into(),
         });
+        // let origin = RawOrigin::Signed(account_id_src);
         // Dispatch the add_stake call
-        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
+        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
     }
 
     fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
@@ -104,7 +115,7 @@ impl StakingPrecompile {
             netuid,
             amount_unstaked: amount_sub.unique_saturated_into(),
         });
-        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
+        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
     }
 
     fn add_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
@@ -116,7 +127,7 @@ impl StakingPrecompile {
             delay: 0,
         });
 
-        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
+        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
     }
 
     fn remove_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
@@ -128,13 +139,13 @@ impl StakingPrecompile {
             delay: 0,
         });
 
-        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
+        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
     }
 
     fn get_stake(data: &[u8]) -> PrecompileResult {
         let (hotkey, left_data) = get_pubkey(data)?;
         let (coldkey, _) = get_pubkey(&left_data)?;
-        let netuid = Self::parse_netuid(data, 0x5E)?;
+        let netuid = parse_netuid(data, 0x5E)?;
 
         let stake = pallet_subtensor::Pallet::<Runtime>::get_stake_for_hotkey_and_coldkey_on_subnet(
             &hotkey, &coldkey, netuid,
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index 3dba5a262..edef73ff0 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -1,4 +1,6 @@
-use crate::precompiles::{dispatch, get_method_id, get_pubkey, get_slice};
+use crate::precompiles::{
+    contract_to_origin, get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call,
+};
 use crate::{Runtime, RuntimeCall};
 use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
 use sp_runtime::AccountId32;
@@ -8,9 +10,12 @@ pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051;
 // three bytes with max lenght 1K
 pub const MAX_PARAMETER_SIZE: usize = 3 * 1024;
 
-// this is staking smart contract's(0x0000000000000000000000000000000000000803) sr25519 address
-pub const STAKING_CONTRACT_ADDRESS: &str = "5DPSUCb5mZFfizvBDSnRoAqmxV5Bmov2CS3xV773qU6VP1w2";
-
+// ss58 public key i.e., the contract sends funds it received to the destination address from the
+// method parameter.
+const CONTRACT_ADDRESS_SS58: [u8; 32] = [
+    0x3a, 0x86, 0x18, 0xfb, 0xbb, 0x1b, 0xbc, 0x47, 0x86, 0x64, 0xff, 0x53, 0x46, 0x18, 0x0c, 0x35,
+    0xd0, 0x9f, 0xac, 0x26, 0xf2, 0x02, 0x70, 0x85, 0xb3, 0x1c, 0x56, 0xc1, 0x06, 0x3c, 0x1c, 0xd3,
+];
 pub struct SubnetPrecompile;
 
 impl SubnetPrecompile {
@@ -79,7 +84,7 @@ impl SubnetPrecompile {
         };
 
         // Dispatch the register_network call
-        dispatch(handle, call, STAKING_CONTRACT_ADDRESS)
+        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
     }
 
     fn parse_register_network_parameters(

From 40bc8d9c7fb018f949c1636bf818264437394cf6 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 02:09:40 -0500
Subject: [PATCH 129/145] fix cargo audit working in CI :tada:

---
 .github/workflows/cargo-audit.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml
index 1934dcaeb..d7904712d 100644
--- a/.github/workflows/cargo-audit.yml
+++ b/.github/workflows/cargo-audit.yml
@@ -5,6 +5,7 @@ on:
       - labeled
       - unlabeled
       - synchronize
+      - opened
 concurrency:
   group: cargo-audit-${{ github.ref }}
   cancel-in-progress: true
@@ -24,7 +25,7 @@ jobs:
           sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler
 
       - name: Install cargo-audit
-        run: cargo install --version 0.20.1 --force cargo-audit
+        run: cargo install --force cargo-audit
 
       - name: Display cargo-audit --version
         run: cargo audit --version

From df596e6cb9c6e3a75d4efde4b66482e2ed5b138f Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 02:11:43 -0500
Subject: [PATCH 130/145] bump CI


From 6f825cc3e5a3454d0b9ed2d34c928d93c9145429 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 02:26:54 -0500
Subject: [PATCH 131/145] upgrade futures-util

---
 Cargo.lock | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 9a828e53f..5709f7c3c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3131,9 +3131,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -3141,9 +3141,9 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
 
 [[package]]
 name = "futures-executor"
@@ -3170,9 +3170,9 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
 
 [[package]]
 name = "futures-lite"
@@ -3186,9 +3186,9 @@ dependencies = [
 
 [[package]]
 name = "futures-macro"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3207,15 +3207,15 @@ dependencies = [
 
 [[package]]
 name = "futures-sink"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
 
 [[package]]
 name = "futures-task"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
 
 [[package]]
 name = "futures-timer"
@@ -3225,9 +3225,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
 
 [[package]]
 name = "futures-util"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
 dependencies = [
  "futures-channel",
  "futures-core",

From e876609cb546f8bb01104c4c514dbb02eb8e96a6 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 02:35:20 -0500
Subject: [PATCH 132/145] ignore some unmaintained advisories

---
 .github/workflows/cargo-audit.yml | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml
index d7904712d..e91c4a20f 100644
--- a/.github/workflows/cargo-audit.yml
+++ b/.github/workflows/cargo-audit.yml
@@ -31,4 +31,11 @@ jobs:
         run: cargo audit --version
 
       - name: cargo audit
-        run: cargo audit --ignore RUSTSEC-2024-0336 # rustls issue; wait for upstream to resolve this
+        run: |
+          cargo audit --ignore RUSTSEC-2024-0336 \
+                      --ignore RUSTSEC-2021-0127 \
+                      --ignore RUSTSEC-2024-0370 \
+                      --ignore RUSTSEC-2022-0080 \
+                      --ignore RUSTSEC-2022-0061 \
+                      --ignore RUSTSEC-2020-0168 \
+                      --ignore RUSTSEC-2024-0384

From 1690ce20295c2b7e44ae857b0247eeca64f9e351 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 02:36:03 -0500
Subject: [PATCH 133/145] add another unmaintained

---
 .github/workflows/cargo-audit.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml
index e91c4a20f..69521c475 100644
--- a/.github/workflows/cargo-audit.yml
+++ b/.github/workflows/cargo-audit.yml
@@ -38,4 +38,5 @@ jobs:
                       --ignore RUSTSEC-2022-0080 \
                       --ignore RUSTSEC-2022-0061 \
                       --ignore RUSTSEC-2020-0168 \
-                      --ignore RUSTSEC-2024-0384
+                      --ignore RUSTSEC-2024-0384 \
+                      --ignore RUSTSEC-2024-0388

From 4e7cd7fe00342e25c64c7da62bd604053f56d43b Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 02:37:06 -0500
Subject: [PATCH 134/145] cargo update url

---
 Cargo.lock | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 243 insertions(+), 7 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 5709f7c3c..010e99494 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3782,6 +3782,124 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
 [[package]]
 name = "ident_case"
 version = "1.0.1"
@@ -3811,12 +3929,23 @@ dependencies = [
 
 [[package]]
 name = "idna"
-version = "0.5.0"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
 dependencies = [
- "unicode-bidi",
- "unicode-normalization",
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
 ]
 
 [[package]]
@@ -4847,6 +4976,12 @@ dependencies = [
  "keystream",
 ]
 
+[[package]]
+name = "litemap"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
+
 [[package]]
 name = "litep2p"
 version = "0.6.2"
@@ -11176,6 +11311,16 @@ dependencies = [
  "crunchy",
 ]
 
+[[package]]
+name = "tinystr"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
 [[package]]
 name = "tinyvec"
 version = "1.8.0"
@@ -11723,12 +11868,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
 
 [[package]]
 name = "url"
-version = "2.5.2"
+version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
 dependencies = [
  "form_urlencoded",
- "idna 0.5.0",
+ "idna 1.0.3",
  "percent-encoding",
 ]
 
@@ -11738,6 +11883,18 @@ version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
 
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
 [[package]]
 name = "utf8parse"
 version = "0.2.2"
@@ -12514,6 +12671,18 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
 [[package]]
 name = "wyz"
 version = "0.5.1"
@@ -12619,6 +12788,30 @@ dependencies = [
  "time",
 ]
 
+[[package]]
+name = "yoke"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "synstructure 0.13.1",
+]
+
 [[package]]
 name = "zerocopy"
 version = "0.7.35"
@@ -12640,6 +12833,27 @@ dependencies = [
  "syn 2.0.90",
 ]
 
+[[package]]
+name = "zerofrom"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "synstructure 0.13.1",
+]
+
 [[package]]
 name = "zeroize"
 version = "1.8.1"
@@ -12660,6 +12874,28 @@ dependencies = [
  "syn 2.0.90",
 ]
 
+[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
 [[package]]
 name = "zstd"
 version = "0.11.2+zstd.1.5.2"

From c6d0b443977afc28644fd8b2ebe4a39fd0061cae Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 02:40:05 -0500
Subject: [PATCH 135/145] fix more advisories

---
 Cargo.lock | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 010e99494..6156794ba 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4171,15 +4171,6 @@ dependencies = [
  "either",
 ]
 
-[[package]]
-name = "itertools"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
-dependencies = [
- "either",
-]
-
 [[package]]
 name = "itoa"
 version = "1.0.11"
@@ -7400,7 +7391,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4"
 dependencies = [
  "bytes",
  "heck 0.5.0",
- "itertools 0.12.1",
+ "itertools 0.11.0",
  "log",
  "multimap",
  "once_cell",
@@ -7433,7 +7424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
 dependencies = [
  "anyhow",
- "itertools 0.12.1",
+ "itertools 0.11.0",
  "proc-macro2",
  "quote",
  "syn 2.0.90",

From 4166c5eb4abe322fd649e1ecac54cd7081841ed7 Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 03:25:20 -0500
Subject: [PATCH 136/145] fix more advisories

---
 .github/workflows/cargo-audit.yml |    3 +-
 Cargo.lock                        | 1626 ++++++++++++++++-------------
 2 files changed, 905 insertions(+), 724 deletions(-)

diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml
index 69521c475..14e2d9449 100644
--- a/.github/workflows/cargo-audit.yml
+++ b/.github/workflows/cargo-audit.yml
@@ -39,4 +39,5 @@ jobs:
                       --ignore RUSTSEC-2022-0061 \
                       --ignore RUSTSEC-2020-0168 \
                       --ignore RUSTSEC-2024-0384 \
-                      --ignore RUSTSEC-2024-0388
+                      --ignore RUSTSEC-2024-0388 \
+                      --ignore RUSTSEC-2024-0421
diff --git a/Cargo.lock b/Cargo.lock
index 6156794ba..42522da32 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -23,11 +23,11 @@ dependencies = [
 
 [[package]]
 name = "addr2line"
-version = "0.24.1"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
- "gimli 0.31.0",
+ "gimli 0.31.1",
 ]
 
 [[package]]
@@ -77,7 +77,7 @@ version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "once_cell",
  "version_check",
 ]
@@ -89,7 +89,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
 dependencies = [
  "cfg-if",
- "getrandom",
+ "getrandom 0.2.15",
  "once_cell",
  "version_check",
  "zerocopy",
@@ -106,9 +106,9 @@ dependencies = [
 
 [[package]]
 name = "allocator-api2"
-version = "0.2.18"
+version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
 name = "android-tzdata"
@@ -127,9 +127,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.15"
+version = "0.6.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -142,43 +142,44 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.8"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.4"
+version = "3.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
 dependencies = [
  "anstyle",
- "windows-sys 0.52.0",
+ "once_cell",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.89"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
+checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
 
 [[package]]
 name = "approx"
@@ -200,7 +201,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -567,7 +568,7 @@ dependencies = [
  "nom",
  "num-traits",
  "rusticata-macros",
- "thiserror",
+ "thiserror 1.0.69",
  "time",
 ]
 
@@ -583,7 +584,7 @@ dependencies = [
  "nom",
  "num-traits",
  "rusticata-macros",
- "thiserror",
+ "thiserror 1.0.69",
  "time",
 ]
 
@@ -607,7 +608,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
  "synstructure 0.13.1",
 ]
 
@@ -630,7 +631,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -652,9 +653,9 @@ dependencies = [
 
 [[package]]
 name = "async-io"
-version = "2.3.4"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
+checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
 dependencies = [
  "async-lock",
  "cfg-if",
@@ -663,7 +664,7 @@ dependencies = [
  "futures-lite",
  "parking",
  "polling",
- "rustix 0.38.37",
+ "rustix 0.38.44",
  "slab",
  "tracing",
  "windows-sys 0.59.0",
@@ -675,20 +676,20 @@ version = "3.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
 dependencies = [
- "event-listener 5.3.1",
+ "event-listener 5.4.0",
  "event-listener-strategy",
  "pin-project-lite",
 ]
 
 [[package]]
 name = "async-trait"
-version = "0.1.83"
+version = "0.1.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
+checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -732,13 +733,13 @@ dependencies = [
 
 [[package]]
 name = "auto_impl"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
+checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -753,11 +754,11 @@ version = "0.3.74"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
 dependencies = [
- "addr2line 0.24.1",
+ "addr2line 0.24.2",
  "cfg-if",
  "libc",
  "miniz_oxide",
- "object 0.36.4",
+ "object 0.36.7",
  "rustc-demangle",
  "windows-targets 0.52.6",
 ]
@@ -819,13 +820,13 @@ dependencies = [
  "lazy_static",
  "lazycell",
  "peeking_take_while",
- "prettyplease 0.2.22",
+ "prettyplease 0.2.29",
  "proc-macro2",
  "quote",
  "regex",
  "rustc-hash 1.1.0",
  "shlex",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -852,9 +853,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
 
 [[package]]
 name = "bitvec"
@@ -913,9 +914,9 @@ dependencies = [
 
 [[package]]
 name = "blake3"
-version = "1.5.4"
+version = "1.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7"
+checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e"
 dependencies = [
  "arrayref",
  "arrayvec",
@@ -944,9 +945,9 @@ dependencies = [
 
 [[package]]
 name = "bounded-collections"
-version = "0.2.0"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d32385ecb91a31bddaf908e8dcf4a15aef1bcd3913cc03ebfad02ff6d568abc1"
+checksum = "3d077619e9c237a5d1875166f5e8033e8f6bff0c96f8caf81e1c2d7738c431bf"
 dependencies = [
  "log",
  "parity-scale-codec",
@@ -980,9 +981,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.16.0"
+version = "3.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "byte-slice-cast"
@@ -998,9 +999,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
 
 [[package]]
 name = "bytemuck"
-version = "1.18.0"
+version = "1.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
+checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
 
 [[package]]
 name = "byteorder"
@@ -1010,9 +1011,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.7.2"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
 
 [[package]]
 name = "bzip2-sys"
@@ -1046,9 +1047,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
+checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
 dependencies = [
  "serde",
 ]
@@ -1061,17 +1062,17 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
 dependencies = [
  "camino",
  "cargo-platform",
- "semver 1.0.23",
+ "semver 1.0.25",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
 name = "cc"
-version = "1.1.24"
+version = "1.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
+checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
 dependencies = [
  "jobserver",
  "libc",
@@ -1144,9 +1145,9 @@ dependencies = [
 
 [[package]]
 name = "chrono"
-version = "0.4.38"
+version = "0.4.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -1216,9 +1217,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.19"
+version = "4.5.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615"
+checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -1226,9 +1227,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.19"
+version = "4.5.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b"
+checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
 dependencies = [
  "anstream",
  "anstyle",
@@ -1239,21 +1240,21 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.18"
+version = "4.5.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
 dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "clap_lex"
-version = "0.7.2"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
 
 [[package]]
 name = "codespan-reporting"
@@ -1262,14 +1263,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
 dependencies = [
  "termcolor",
- "unicode-width",
+ "unicode-width 0.1.14",
 ]
 
 [[package]]
 name = "colorchoice"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 
 [[package]]
 name = "combine"
@@ -1283,13 +1284,13 @@ dependencies = [
 
 [[package]]
 name = "comfy-table"
-version = "7.1.1"
+version = "7.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7"
+checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9"
 dependencies = [
  "strum 0.26.3",
  "strum_macros 0.26.4",
- "unicode-width",
+ "unicode-width 0.2.0",
 ]
 
 [[package]]
@@ -1309,15 +1310,15 @@ dependencies = [
 
 [[package]]
 name = "console"
-version = "0.15.8"
+version = "0.15.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
+checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b"
 dependencies = [
  "encode_unicode",
- "lazy_static",
  "libc",
- "unicode-width",
- "windows-sys 0.52.0",
+ "once_cell",
+ "unicode-width 0.2.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1341,7 +1342,7 @@ version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "once_cell",
  "tiny-keccak",
 ]
@@ -1400,9 +1401,9 @@ dependencies = [
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.14"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
 dependencies = [
  "libc",
 ]
@@ -1531,9 +1532,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.5"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
 dependencies = [
  "crossbeam-epoch",
  "crossbeam-utils",
@@ -1559,15 +1560,15 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.20"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 
 [[package]]
 name = "crunchy"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
 
 [[package]]
 name = "crypto-bigint"
@@ -1645,51 +1646,66 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "cxx"
-version = "1.0.128"
+version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54ccead7d199d584d139148b04b4a368d1ec7556a1d9ea2548febb1b9d49f9a4"
+checksum = "0fc894913dccfed0f84106062c284fa021c3ba70cb1d78797d6f5165d4492e45"
 dependencies = [
  "cc",
+ "cxxbridge-cmd",
  "cxxbridge-flags",
  "cxxbridge-macro",
+ "foldhash",
  "link-cplusplus",
 ]
 
 [[package]]
 name = "cxx-build"
-version = "1.0.128"
+version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c77953e99f01508f89f55c494bfa867171ef3a6c8cea03d26975368f2121a5c1"
+checksum = "503b2bfb6b3e8ce7f95d865a67419451832083d3186958290cee6c53e39dfcfe"
 dependencies = [
  "cc",
  "codespan-reporting",
- "once_cell",
  "proc-macro2",
  "quote",
  "scratch",
- "syn 2.0.90",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "cxxbridge-cmd"
+version = "1.0.137"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0d2cb64a95b4b5a381971482235c4db2e0208302a962acdbe314db03cbbe2fb"
+dependencies = [
+ "clap",
+ "codespan-reporting",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "cxxbridge-flags"
-version = "1.0.128"
+version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65777e06cc48f0cb0152024c77d6cf9e4bdb4408e7b48bea993d42fa0f5b02b6"
+checksum = "5f797b0206463c9c2a68ed605ab28892cca784f1ef066050f4942e3de26ad885"
 
 [[package]]
 name = "cxxbridge-macro"
-version = "1.0.128"
+version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98532a60dedaebc4848cb2cba5023337cc9ea3af16a5b062633fabfd9f18fb60"
+checksum = "e79010a2093848e65a3e0f7062d3f02fb2ef27f866416dfe436fccfa73d3bb59"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "rustversion",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -1713,7 +1729,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -1724,7 +1740,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -1742,15 +1758,15 @@ dependencies = [
 
 [[package]]
 name = "data-encoding"
-version = "2.6.0"
+version = "2.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
+checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f"
 
 [[package]]
 name = "data-encoding-macro"
-version = "0.1.15"
+version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639"
+checksum = "5b16d9d0d88a5273d830dac8b78ceb217ffc9b1d5404e5597a3542515329405b"
 dependencies = [
  "data-encoding",
  "data-encoding-macro-internal",
@@ -1758,12 +1774,12 @@ dependencies = [
 
 [[package]]
 name = "data-encoding-macro-internal"
-version = "0.1.13"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f"
+checksum = "1145d32e826a7748b69ee8fc62d3e6355ff7f1051df53141e7048162fc90481b"
 dependencies = [
  "data-encoding",
- "syn 1.0.109",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -1833,7 +1849,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -1846,7 +1862,27 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustc_version 0.4.1",
- "syn 2.0.90",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "derive_more"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -1935,23 +1971,23 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "docify"
-version = "0.2.8"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a2f138ad521dc4a2ced1a4576148a6a610b4c5923933b062a263130a6802ce"
+checksum = "a772b62b1837c8f060432ddcc10b17aae1453ef17617a99bc07789252d2a5896"
 dependencies = [
  "docify_macros",
 ]
 
 [[package]]
 name = "docify_macros"
-version = "0.2.8"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad"
+checksum = "60e6be249b0a462a14784a99b19bf35a667bb5e09de611738bb7362fa4c95ff7"
 dependencies = [
  "common-path",
  "derive-syn-parse",
@@ -1959,7 +1995,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "regex",
- "syn 2.0.90",
+ "syn 2.0.96",
  "termcolor",
  "toml 0.8.19",
  "walkdir",
@@ -1985,9 +2021,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
 
 [[package]]
 name = "dyn-clonable"
-version = "0.9.0"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4"
+checksum = "a36efbb9bfd58e1723780aa04b61aba95ace6a05d9ffabfdb0b43672552f0805"
 dependencies = [
  "dyn-clonable-impl",
  "dyn-clone",
@@ -1995,13 +2031,13 @@ dependencies = [
 
 [[package]]
 name = "dyn-clonable-impl"
-version = "0.9.0"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5"
+checksum = "7e8671d54058979a37a26f3511fbf8d198ba1aa35ffb202c42587d918d77213a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -2096,9 +2132,9 @@ dependencies = [
 
 [[package]]
 name = "encode_unicode"
-version = "0.3.6"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
 
 [[package]]
 name = "enum-as-inner"
@@ -2121,27 +2157,27 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "enumflags2"
-version = "0.7.10"
+version = "0.7.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d"
+checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147"
 dependencies = [
  "enumflags2_derive",
 ]
 
 [[package]]
 name = "enumflags2_derive"
-version = "0.7.10"
+version = "0.7.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
+checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -2171,12 +2207,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
-version = "0.3.9"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -2187,9 +2223,9 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60"
 dependencies = [
  "crunchy",
  "fixed-hash",
- "impl-codec",
+ "impl-codec 0.6.0",
  "impl-rlp",
- "impl-serde",
+ "impl-serde 0.4.0",
  "scale-info",
  "tiny-keccak",
 ]
@@ -2220,12 +2256,12 @@ checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee"
 dependencies = [
  "ethbloom",
  "fixed-hash",
- "impl-codec",
+ "impl-codec 0.6.0",
  "impl-rlp",
- "impl-serde",
- "primitive-types",
+ "impl-serde 0.4.0",
+ "primitive-types 0.12.2",
  "scale-info",
- "uint",
+ "uint 0.9.5",
 ]
 
 [[package]]
@@ -2236,9 +2272,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
 
 [[package]]
 name = "event-listener"
-version = "5.3.1"
+version = "5.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
+checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae"
 dependencies = [
  "concurrent-queue",
  "parking",
@@ -2247,11 +2283,11 @@ dependencies = [
 
 [[package]]
 name = "event-listener-strategy"
-version = "0.5.2"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
+checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
 dependencies = [
- "event-listener 5.3.1",
+ "event-listener 5.4.0",
  "pin-project-lite",
 ]
 
@@ -2269,7 +2305,7 @@ dependencies = [
  "evm-runtime",
  "log",
  "parity-scale-codec",
- "primitive-types",
+ "primitive-types 0.12.2",
  "rlp",
  "scale-info",
  "serde",
@@ -2283,7 +2319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d1da6cedc5cedb4208e59467106db0d1f50db01b920920589f8e672c02fdc04f"
 dependencies = [
  "parity-scale-codec",
- "primitive-types",
+ "primitive-types 0.12.2",
  "scale-info",
  "serde",
 ]
@@ -2297,7 +2333,7 @@ dependencies = [
  "environmental",
  "evm-core",
  "evm-runtime",
- "primitive-types",
+ "primitive-types 0.12.2",
 ]
 
 [[package]]
@@ -2309,7 +2345,7 @@ dependencies = [
  "auto_impl",
  "environmental",
  "evm-core",
- "primitive-types",
+ "primitive-types 0.12.2",
  "sha3",
 ]
 
@@ -2331,10 +2367,10 @@ dependencies = [
  "blake2 0.10.6",
  "file-guard",
  "fs-err",
- "prettyplease 0.2.22",
+ "prettyplease 0.2.29",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -2351,9 +2387,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
 
 [[package]]
 name = "fastrand"
-version = "2.1.1"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "fc-api"
@@ -2380,7 +2416,7 @@ dependencies = [
  "sp-block-builder",
  "sp-consensus",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -2486,7 +2522,7 @@ dependencies = [
  "sp-storage 21.0.0",
  "sp-timestamp",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
 ]
 
@@ -2529,7 +2565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e182f7dbc2ef73d9ef67351c5fbbea084729c48362d3ce9dd44c28e32e277fe5"
 dependencies = [
  "libc",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -2642,9 +2678,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "foldhash"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
 
 [[package]]
 name = "foreign-types"
@@ -2685,7 +2721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9"
 dependencies = [
  "nonempty",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -2694,7 +2730,7 @@ version = "1.0.0-dev"
 source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e"
 dependencies = [
  "hex",
- "impl-serde",
+ "impl-serde 0.4.0",
  "libsecp256k1",
  "log",
  "parity-scale-codec",
@@ -2868,7 +2904,7 @@ dependencies = [
  "sp-storage 21.0.0",
  "sp-trie",
  "sp-wasm-interface 21.0.1",
- "thiserror",
+ "thiserror 1.0.69",
  "thousands",
 ]
 
@@ -2975,7 +3011,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -2988,7 +3024,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -3000,7 +3036,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -3011,7 +3047,7 @@ checksum = "68672b9ec6fe72d259d3879dc212c5e42e977588cdac830c76f54d9f492aeb58"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -3021,7 +3057,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -3106,9 +3142,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
 
 [[package]]
 name = "futures"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -3147,9 +3183,9 @@ checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -3176,9 +3212,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
 
 [[package]]
 name = "futures-lite"
-version = "2.3.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
+checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532"
 dependencies = [
  "futures-core",
  "pin-project-lite",
@@ -3192,7 +3228,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -3288,7 +3324,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.13.3+wasi-0.2.2",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -3334,15 +3382,15 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.31.0"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
 [[package]]
 name = "glob"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
 
 [[package]]
 name = "governor"
@@ -3387,7 +3435,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http 0.2.12",
- "indexmap 2.6.0",
+ "indexmap 2.7.1",
  "slab",
  "tokio",
  "tokio-util",
@@ -3396,17 +3444,17 @@ dependencies = [
 
 [[package]]
 name = "h2"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
+checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
 dependencies = [
  "atomic-waker",
  "bytes",
  "fnv",
  "futures-core",
  "futures-sink",
- "http 1.1.0",
- "indexmap 2.6.0",
+ "http 1.2.0",
+ "indexmap 2.7.1",
  "slab",
  "tokio",
  "tokio-util",
@@ -3430,7 +3478,7 @@ dependencies = [
  "pest_derive",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -3478,9 +3526,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.15.0"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
 dependencies = [
  "allocator-api2",
  "equivalent",
@@ -3498,11 +3546,11 @@ dependencies = [
 
 [[package]]
 name = "hashlink"
-version = "0.9.1"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
+checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
 dependencies = [
- "hashbrown 0.14.5",
+ "hashbrown 0.15.2",
 ]
 
 [[package]]
@@ -3591,11 +3639,11 @@ dependencies = [
 
 [[package]]
 name = "home"
-version = "0.5.9"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -3622,9 +3670,9 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
 dependencies = [
  "bytes",
  "fnv",
@@ -3649,7 +3697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
 dependencies = [
  "bytes",
- "http 1.1.0",
+ "http 1.2.0",
 ]
 
 [[package]]
@@ -3660,16 +3708,16 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
 dependencies = [
  "bytes",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "pin-project-lite",
 ]
 
 [[package]]
 name = "httparse"
-version = "1.9.5"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
+checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a"
 
 [[package]]
 name = "httpdate"
@@ -3685,9 +3733,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "hyper"
-version = "0.14.30"
+version = "0.14.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9"
+checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -3700,7 +3748,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2 0.5.7",
+ "socket2 0.5.8",
  "tokio",
  "tower-service",
  "tracing",
@@ -3709,15 +3757,15 @@ dependencies = [
 
 [[package]]
 name = "hyper"
-version = "1.5.0"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
+checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
 dependencies = [
  "bytes",
  "futures-channel",
  "futures-util",
- "h2 0.4.6",
- "http 1.1.0",
+ "h2 0.4.7",
+ "http 1.2.0",
  "http-body 1.0.1",
  "httparse",
  "httpdate",
@@ -3735,7 +3783,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
 dependencies = [
  "futures-util",
  "http 0.2.12",
- "hyper 0.14.30",
+ "hyper 0.14.32",
  "log",
  "rustls 0.21.12",
  "rustls-native-certs",
@@ -3751,9 +3799,9 @@ checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
 dependencies = [
  "bytes",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
- "hyper 1.5.0",
+ "hyper 1.6.0",
  "pin-project-lite",
  "tokio",
  "tower-service",
@@ -3897,7 +3945,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -3960,9 +4008,9 @@ dependencies = [
 
 [[package]]
 name = "if-watch"
-version = "3.2.0"
+version = "3.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e"
+checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38"
 dependencies = [
  "async-io",
  "core-foundation",
@@ -3971,6 +4019,10 @@ dependencies = [
  "if-addrs",
  "ipnet",
  "log",
+ "netlink-packet-core",
+ "netlink-packet-route",
+ "netlink-proto",
+ "netlink-sys",
  "rtnetlink",
  "system-configuration",
  "tokio",
@@ -3988,7 +4040,7 @@ dependencies = [
  "bytes",
  "futures",
  "http 0.2.12",
- "hyper 0.14.30",
+ "hyper 0.14.32",
  "log",
  "rand",
  "tokio",
@@ -4005,6 +4057,26 @@ dependencies = [
  "parity-scale-codec",
 ]
 
+[[package]]
+name = "impl-codec"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941"
+dependencies = [
+ "parity-scale-codec",
+]
+
+[[package]]
+name = "impl-num-traits"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "803d15461ab0dcc56706adf266158acbc44ccf719bf7d0af30705f58b90a4b8c"
+dependencies = [
+ "integer-sqrt",
+ "num-traits",
+ "uint 0.10.0",
+]
+
 [[package]]
 name = "impl-rlp"
 version = "0.3.0"
@@ -4023,15 +4095,24 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "impl-serde"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a143eada6a1ec4aefa5049037a26a6d597bfd64f8c026d07b77133e02b7dd0b"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "impl-trait-for-tuples"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb"
+checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -4066,12 +4147,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.6.0"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
 dependencies = [
  "equivalent",
- "hashbrown 0.15.0",
+ "hashbrown 0.15.2",
 ]
 
 [[package]]
@@ -4124,7 +4205,7 @@ version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
 dependencies = [
- "socket2 0.5.7",
+ "socket2 0.5.8",
  "widestring",
  "windows-sys 0.48.0",
  "winreg",
@@ -4132,19 +4213,19 @@ dependencies = [
 
 [[package]]
 name = "ipnet"
-version = "2.10.0"
+version = "2.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
+checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
 
 [[package]]
 name = "is-terminal"
-version = "0.4.13"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
+checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37"
 dependencies = [
  "hermit-abi 0.4.0",
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -4171,11 +4252,20 @@ dependencies = [
  "either",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
-version = "1.0.11"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "jobserver"
@@ -4188,18 +4278,19 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.70"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
 dependencies = [
+ "once_cell",
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "jsonrpsee"
-version = "0.24.7"
+version = "0.24.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843"
+checksum = "834af00800e962dee8f7bfc0f60601de215e73e78e5497d733a2919da837d3c8"
 dependencies = [
  "jsonrpsee-core",
  "jsonrpsee-proc-macros",
@@ -4211,51 +4302,51 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-core"
-version = "0.24.7"
+version = "0.24.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280"
+checksum = "76637f6294b04e747d68e69336ef839a3493ca62b35bf488ead525f7da75c5bb"
 dependencies = [
  "async-trait",
  "bytes",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "http-body-util",
  "jsonrpsee-types",
  "parking_lot 0.12.3",
  "rand",
- "rustc-hash 2.0.0",
+ "rustc-hash 2.1.0",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tracing",
 ]
 
 [[package]]
 name = "jsonrpsee-proc-macros"
-version = "0.24.7"
+version = "0.24.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d"
+checksum = "6fcae0c6c159e11541080f1f829873d8f374f81eda0abc67695a13fc8dc1a580"
 dependencies = [
  "heck 0.5.0",
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "jsonrpsee-server"
-version = "0.24.7"
+version = "0.24.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c"
+checksum = "66b7a3df90a1a60c3ed68e7ca63916b53e9afa928e33531e87f61a9c8e9ae87b"
 dependencies = [
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "http-body-util",
- "hyper 1.5.0",
+ "hyper 1.6.0",
  "hyper-util",
  "jsonrpsee-core",
  "jsonrpsee-types",
@@ -4264,7 +4355,7 @@ dependencies = [
  "serde",
  "serde_json",
  "soketto",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tokio-stream",
  "tokio-util",
@@ -4274,14 +4365,14 @@ dependencies = [
 
 [[package]]
 name = "jsonrpsee-types"
-version = "0.24.7"
+version = "0.24.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1"
+checksum = "ddb81adb1a5ae9182df379e374a79e24e992334e7346af4d065ae5b2acb8d4c6"
 dependencies = [
- "http 1.1.0",
+ "http 1.2.0",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -4360,15 +4451,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.159"
+version = "0.2.169"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 
 [[package]]
 name = "libloading"
-version = "0.8.5"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
 dependencies = [
  "cfg-if",
  "windows-targets 0.52.6",
@@ -4376,9 +4467,9 @@ dependencies = [
 
 [[package]]
 name = "libm"
-version = "0.2.8"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
+checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
 
 [[package]]
 name = "libp2p"
@@ -4390,7 +4481,7 @@ dependencies = [
  "either",
  "futures",
  "futures-timer",
- "getrandom",
+ "getrandom 0.2.15",
  "instant",
  "libp2p-allow-block-list",
  "libp2p-connection-limits",
@@ -4414,7 +4505,7 @@ dependencies = [
  "multiaddr 0.18.2",
  "pin-project",
  "rw-stream-sink",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -4455,7 +4546,7 @@ dependencies = [
  "libp2p-identity",
  "log",
  "multiaddr 0.18.2",
- "multihash 0.19.2",
+ "multihash 0.19.3",
  "multistream-select",
  "once_cell",
  "parking_lot 0.12.3",
@@ -4464,7 +4555,7 @@ dependencies = [
  "rand",
  "rw-stream-sink",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.69",
  "unsigned-varint 0.7.2",
  "void",
 ]
@@ -4504,24 +4595,24 @@ dependencies = [
  "quick-protobuf",
  "quick-protobuf-codec",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.69",
  "void",
 ]
 
 [[package]]
 name = "libp2p-identity"
-version = "0.2.9"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8"
+checksum = "257b5621d159b32282eac446bed6670c39c7dc68a200a992d8f056afa0066f6d"
 dependencies = [
  "bs58 0.5.1",
  "ed25519-dalek",
  "hkdf",
- "multihash 0.19.2",
+ "multihash 0.19.3",
  "quick-protobuf",
  "rand",
  "sha2 0.10.8",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
  "zeroize",
 ]
@@ -4549,8 +4640,8 @@ dependencies = [
  "rand",
  "sha2 0.10.8",
  "smallvec",
- "thiserror",
- "uint",
+ "thiserror 1.0.69",
+ "uint 0.9.5",
  "unsigned-varint 0.7.2",
  "void",
 ]
@@ -4570,7 +4661,7 @@ dependencies = [
  "log",
  "rand",
  "smallvec",
- "socket2 0.5.7",
+ "socket2 0.5.8",
  "tokio",
  "trust-dns-proto 0.22.0",
  "void",
@@ -4606,14 +4697,14 @@ dependencies = [
  "libp2p-identity",
  "log",
  "multiaddr 0.18.2",
- "multihash 0.19.2",
+ "multihash 0.19.3",
  "once_cell",
  "quick-protobuf",
  "rand",
  "sha2 0.10.8",
  "snow",
  "static_assertions",
- "thiserror",
+ "thiserror 1.0.69",
  "x25519-dalek",
  "zeroize",
 ]
@@ -4655,8 +4746,8 @@ dependencies = [
  "rand",
  "ring 0.16.20",
  "rustls 0.21.12",
- "socket2 0.5.7",
- "thiserror",
+ "socket2 0.5.8",
+ "thiserror 1.0.69",
  "tokio",
 ]
 
@@ -4711,7 +4802,7 @@ dependencies = [
  "proc-macro-warning 0.4.2",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -4727,7 +4818,7 @@ dependencies = [
  "libp2p-core",
  "libp2p-identity",
  "log",
- "socket2 0.5.7",
+ "socket2 0.5.8",
  "tokio",
 ]
 
@@ -4745,7 +4836,7 @@ dependencies = [
  "ring 0.16.20",
  "rustls 0.21.12",
  "rustls-webpki",
- "thiserror",
+ "thiserror 1.0.69",
  "x509-parser 0.15.1",
  "yasna",
 ]
@@ -4796,7 +4887,7 @@ dependencies = [
  "pin-project-lite",
  "rw-stream-sink",
  "soketto",
- "thiserror",
+ "thiserror 1.0.69",
  "url",
  "webpki-roots",
 ]
@@ -4810,7 +4901,7 @@ dependencies = [
  "futures",
  "libp2p-core",
  "log",
- "thiserror",
+ "thiserror 1.0.69",
  "yamux",
 ]
 
@@ -4820,9 +4911,9 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "libc",
- "redox_syscall 0.5.7",
+ "redox_syscall 0.5.8",
 ]
 
 [[package]]
@@ -4901,9 +4992,9 @@ dependencies = [
 
 [[package]]
 name = "libz-sys"
-version = "1.1.20"
+version = "1.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472"
+checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa"
 dependencies = [
  "cc",
  "pkg-config",
@@ -4927,18 +5018,18 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
 
 [[package]]
 name = "linked_hash_set"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588"
+checksum = "bae85b5be22d9843c80e5fc80e9b64c8a3b1f98f867c709956eca3efff4e92e2"
 dependencies = [
  "linked-hash-map",
 ]
 
 [[package]]
 name = "linregress"
-version = "0.5.3"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4de04dcecc58d366391f9920245b85ffa684558a5ef6e7736e754347c3aea9c2"
+checksum = "a9eda9dcf4f2a99787827661f312ac3219292549c2ee992bf9a6248ffb066bf7"
 dependencies = [
  "nalgebra",
 ]
@@ -4951,9 +5042,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.14"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
 
 [[package]]
 name = "lioness"
@@ -4987,7 +5078,7 @@ dependencies = [
  "futures",
  "futures-timer",
  "hex-literal",
- "indexmap 2.6.0",
+ "indexmap 2.7.1",
  "libc",
  "mockall 0.12.1",
  "multiaddr 0.17.1",
@@ -5008,17 +5099,17 @@ dependencies = [
  "simple-dns",
  "smallvec",
  "snow",
- "socket2 0.5.7",
+ "socket2 0.5.8",
  "static_assertions",
  "str0m",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tokio-stream",
  "tokio-tungstenite",
  "tokio-util",
  "tracing",
  "trust-dns-resolver",
- "uint",
+ "uint 0.9.5",
  "unsigned-varint 0.8.0",
  "url",
  "webpki",
@@ -5040,9 +5131,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
 
 [[package]]
 name = "lru"
@@ -5059,7 +5150,7 @@ version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
 dependencies = [
- "hashbrown 0.15.0",
+ "hashbrown 0.15.2",
 ]
 
 [[package]]
@@ -5073,9 +5164,9 @@ dependencies = [
 
 [[package]]
 name = "lz4"
-version = "1.28.0"
+version = "1.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725"
+checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4"
 dependencies = [
  "lz4-sys",
 ]
@@ -5108,7 +5199,7 @@ dependencies = [
  "macro_magic_core",
  "macro_magic_macros",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -5122,7 +5213,7 @@ dependencies = [
  "macro_magic_core_macros",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -5133,7 +5224,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -5144,7 +5235,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869"
 dependencies = [
  "macro_magic_core",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -5190,7 +5281,7 @@ version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
 dependencies = [
- "rustix 0.38.37",
+ "rustix 0.38.44",
 ]
 
 [[package]]
@@ -5263,22 +5354,21 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.0"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
 dependencies = [
  "adler2",
 ]
 
 [[package]]
 name = "mio"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
- "hermit-abi 0.3.9",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
  "windows-sys 0.52.0",
 ]
 
@@ -5303,7 +5393,7 @@ dependencies = [
  "rand_chacha",
  "rand_distr",
  "subtle 2.6.1",
- "thiserror",
+ "thiserror 1.0.69",
  "zeroize",
 ]
 
@@ -5333,7 +5423,7 @@ dependencies = [
  "fragile",
  "lazy_static",
  "mockall_derive 0.12.1",
- "predicates 3.1.2",
+ "predicates 3.1.3",
  "predicates-tree",
 ]
 
@@ -5358,7 +5448,7 @@ dependencies = [
  "cfg-if",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -5391,7 +5481,7 @@ dependencies = [
  "data-encoding",
  "libp2p-identity",
  "multibase",
- "multihash 0.19.2",
+ "multihash 0.19.3",
  "percent-encoding",
  "serde",
  "static_assertions",
@@ -5446,9 +5536,9 @@ dependencies = [
 
 [[package]]
 name = "multihash"
-version = "0.19.2"
+version = "0.19.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2"
+checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d"
 dependencies = [
  "core2",
  "unsigned-varint 0.8.0",
@@ -5474,6 +5564,12 @@ version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
 
+[[package]]
+name = "multimap"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
+
 [[package]]
 name = "multistream-select"
 version = "0.13.0"
@@ -5490,13 +5586,12 @@ dependencies = [
 
 [[package]]
 name = "nalgebra"
-version = "0.32.6"
+version = "0.33.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4"
+checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
 dependencies = [
  "approx",
  "matrixmultiply",
- "nalgebra-macros",
  "num-complex",
  "num-rational",
  "num-traits",
@@ -5504,17 +5599,6 @@ dependencies = [
  "typenum 1.17.0",
 ]
 
-[[package]]
-name = "nalgebra-macros"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.90",
-]
-
 [[package]]
 name = "names"
 version = "0.14.0"
@@ -5526,9 +5610,9 @@ dependencies = [
 
 [[package]]
 name = "native-tls"
-version = "0.2.12"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c"
 dependencies = [
  "libc",
  "log",
@@ -5556,21 +5640,20 @@ dependencies = [
 
 [[package]]
 name = "netlink-packet-core"
-version = "0.4.2"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297"
+checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4"
 dependencies = [
  "anyhow",
  "byteorder",
- "libc",
  "netlink-packet-utils",
 ]
 
 [[package]]
 name = "netlink-packet-route"
-version = "0.12.0"
+version = "0.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab"
+checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66"
 dependencies = [
  "anyhow",
  "bitflags 1.3.2",
@@ -5589,29 +5672,28 @@ dependencies = [
  "anyhow",
  "byteorder",
  "paste",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
 name = "netlink-proto"
-version = "0.10.0"
+version = "0.11.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6"
+checksum = "72452e012c2f8d612410d89eea01e2d9b56205274abb35d53f60200b2ec41d60"
 dependencies = [
  "bytes",
  "futures",
  "log",
  "netlink-packet-core",
  "netlink-sys",
- "thiserror",
- "tokio",
+ "thiserror 2.0.11",
 ]
 
 [[package]]
 name = "netlink-sys"
-version = "0.8.6"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307"
+checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23"
 dependencies = [
  "bytes",
  "futures",
@@ -5628,15 +5710,15 @@ checksum = "a4a43439bf756eed340bdf8feba761e2d50c7d47175d87545cd5cbe4a137c4d1"
 dependencies = [
  "cc",
  "libc",
- "thiserror",
+ "thiserror 1.0.69",
  "winapi",
 ]
 
 [[package]]
 name = "nix"
-version = "0.24.3"
+version = "0.26.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
+checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
 dependencies = [
  "bitflags 1.3.2",
  "cfg-if",
@@ -5728,7 +5810,7 @@ dependencies = [
  "substrate-prometheus-endpoint",
  "subtensor-custom-rpc",
  "subtensor-custom-rpc-runtime-api",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -5750,7 +5832,7 @@ dependencies = [
  "frame-system-benchmarking",
  "frame-system-rpc-runtime-api",
  "frame-try-runtime",
- "getrandom",
+ "getrandom 0.2.15",
  "hex",
  "log",
  "pallet-admin-utils",
@@ -5973,7 +6055,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -5999,9 +6081,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.4"
+version = "0.36.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
 dependencies = [
  "memchr",
 ]
@@ -6026,12 +6108,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.20.1"
+version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
-dependencies = [
- "portable-atomic",
-]
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "opaque-debug"
@@ -6047,11 +6126,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
 
 [[package]]
 name = "openssl"
-version = "0.10.68"
+version = "0.10.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
+checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "cfg-if",
  "foreign-types",
  "libc",
@@ -6068,20 +6147,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "openssl-probe"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
 
 [[package]]
 name = "openssl-src"
-version = "300.4.0+3.4.0"
+version = "300.4.1+3.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6"
+checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c"
 dependencies = [
  "cc",
 ]
@@ -6762,7 +6841,7 @@ dependencies = [
  "lru 0.8.1",
  "parity-util-mem-derive",
  "parking_lot 0.12.3",
- "primitive-types",
+ "primitive-types 0.12.2",
  "smallvec",
  "winapi",
 ]
@@ -6833,7 +6912,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.5.7",
+ "redox_syscall 0.5.8",
  "smallvec",
  "windows-targets 0.52.6",
 ]
@@ -6894,20 +6973,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.13"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9"
+checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
 dependencies = [
  "memchr",
- "thiserror",
+ "thiserror 2.0.11",
  "ucd-trie",
 ]
 
 [[package]]
 name = "pest_derive"
-version = "2.7.13"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0"
+checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
 dependencies = [
  "pest",
  "pest_generator",
@@ -6915,22 +6994,22 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.13"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e"
+checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
 dependencies = [
  "pest",
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "pest_meta"
-version = "2.7.13"
+version = "2.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f"
+checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
 dependencies = [
  "once_cell",
  "pest",
@@ -6944,34 +7023,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
 dependencies = [
  "fixedbitset",
- "indexmap 2.6.0",
+ "indexmap 2.7.1",
 ]
 
 [[package]]
 name = "pin-project"
-version = "1.1.5"
+version = "1.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
+checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.1.5"
+version = "1.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
+checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.14"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
 
 [[package]]
 name = "pin-utils"
@@ -7004,7 +7083,7 @@ dependencies = [
  "libc",
  "log",
  "polkavm-assembler",
- "polkavm-common",
+ "polkavm-common 0.9.0",
  "polkavm-linux-raw",
 ]
 
@@ -7026,13 +7105,28 @@ dependencies = [
  "log",
 ]
 
+[[package]]
+name = "polkavm-common"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31ff33982a807d8567645d4784b9b5d7ab87bcb494f534a57cadd9012688e102"
+
 [[package]]
 name = "polkavm-derive"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606"
 dependencies = [
- "polkavm-derive-impl-macro",
+ "polkavm-derive-impl-macro 0.9.0",
+]
+
+[[package]]
+name = "polkavm-derive"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2eb703f3b6404c13228402e98a5eae063fd16b8f58afe334073ec105ee4117e"
+dependencies = [
+ "polkavm-derive-impl-macro 0.18.0",
 ]
 
 [[package]]
@@ -7041,10 +7135,22 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c"
 dependencies = [
- "polkavm-common",
+ "polkavm-common 0.9.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "polkavm-derive-impl"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f2116a92e6e96220a398930f4c8a6cda1264206f3e2034fc9982bfd93f261f7"
+dependencies = [
+ "polkavm-common 0.18.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7053,8 +7159,18 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429"
 dependencies = [
- "polkavm-derive-impl",
- "syn 2.0.90",
+ "polkavm-derive-impl 0.9.0",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "polkavm-derive-impl-macro"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c16669ddc7433e34c1007d31080b80901e3e8e523cb9d4b441c3910cf9294b"
+dependencies = [
+ "polkavm-derive-impl 0.18.1",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7067,7 +7183,7 @@ dependencies = [
  "hashbrown 0.14.5",
  "log",
  "object 0.32.2",
- "polkavm-common",
+ "polkavm-common 0.9.0",
  "regalloc2 0.9.3",
  "rustc-demangle",
 ]
@@ -7080,15 +7196,15 @@ checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120"
 
 [[package]]
 name = "polling"
-version = "3.7.3"
+version = "3.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
+checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
 dependencies = [
  "cfg-if",
  "concurrent-queue",
  "hermit-abi 0.4.0",
  "pin-project-lite",
- "rustix 0.38.37",
+ "rustix 0.38.44",
  "tracing",
  "windows-sys 0.59.0",
 ]
@@ -7118,9 +7234,9 @@ dependencies = [
 
 [[package]]
 name = "portable-atomic"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
 
 [[package]]
 name = "powerfmt"
@@ -7153,9 +7269,9 @@ dependencies = [
 
 [[package]]
 name = "predicates"
-version = "3.1.2"
+version = "3.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
+checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573"
 dependencies = [
  "anstyle",
  "predicates-core",
@@ -7163,15 +7279,15 @@ dependencies = [
 
 [[package]]
 name = "predicates-core"
-version = "1.0.8"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931"
+checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa"
 
 [[package]]
 name = "predicates-tree"
-version = "1.0.11"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13"
+checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c"
 dependencies = [
  "predicates-core",
  "termtree",
@@ -7189,12 +7305,12 @@ dependencies = [
 
 [[package]]
 name = "prettyplease"
-version = "0.2.22"
+version = "0.2.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
+checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
 dependencies = [
  "proc-macro2",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7204,11 +7320,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
 dependencies = [
  "fixed-hash",
- "impl-codec",
+ "impl-codec 0.6.0",
  "impl-rlp",
- "impl-serde",
+ "impl-serde 0.4.0",
  "scale-info",
- "uint",
+ "uint 0.9.5",
+]
+
+[[package]]
+name = "primitive-types"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5"
+dependencies = [
+ "fixed-hash",
+ "impl-codec 0.7.0",
+ "impl-num-traits",
+ "uint 0.10.0",
 ]
 
 [[package]]
@@ -7217,7 +7345,7 @@ version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
 dependencies = [
- "thiserror",
+ "thiserror 1.0.69",
  "toml 0.5.11",
 ]
 
@@ -7262,7 +7390,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7273,14 +7401,14 @@ checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.92"
+version = "1.0.93"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
 dependencies = [
  "unicode-ident",
 ]
@@ -7301,7 +7429,7 @@ dependencies = [
  "quote",
  "regex",
  "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7315,7 +7443,7 @@ dependencies = [
  "lazy_static",
  "memchr",
  "parking_lot 0.12.3",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -7338,7 +7466,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7372,7 +7500,7 @@ dependencies = [
  "itertools 0.10.5",
  "lazy_static",
  "log",
- "multimap",
+ "multimap 0.8.3",
  "petgraph",
  "prettyplease 0.1.25",
  "prost 0.11.9",
@@ -7391,16 +7519,16 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4"
 dependencies = [
  "bytes",
  "heck 0.5.0",
- "itertools 0.11.0",
+ "itertools 0.12.1",
  "log",
- "multimap",
+ "multimap 0.10.0",
  "once_cell",
  "petgraph",
- "prettyplease 0.2.22",
+ "prettyplease 0.2.29",
  "prost 0.12.6",
  "prost-types 0.12.6",
  "regex",
- "syn 2.0.90",
+ "syn 2.0.96",
  "tempfile",
 ]
 
@@ -7424,10 +7552,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
 dependencies = [
  "anyhow",
- "itertools 0.11.0",
+ "itertools 0.12.1",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7450,24 +7578,24 @@ dependencies = [
 
 [[package]]
 name = "psm"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205"
+checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "quanta"
-version = "0.12.3"
+version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
+checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e"
 dependencies = [
  "crossbeam-utils",
  "libc",
  "once_cell",
  "raw-cpuid",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
  "web-sys",
  "winapi",
 ]
@@ -7496,7 +7624,7 @@ dependencies = [
  "asynchronous-codec",
  "bytes",
  "quick-protobuf",
- "thiserror",
+ "thiserror 1.0.69",
  "unsigned-varint 0.7.2",
 ]
 
@@ -7512,7 +7640,7 @@ dependencies = [
  "quinn-udp 0.3.2",
  "rustc-hash 1.1.0",
  "rustls 0.20.9",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tracing",
  "webpki",
@@ -7531,7 +7659,7 @@ dependencies = [
  "quinn-udp 0.4.1",
  "rustc-hash 1.1.0",
  "rustls 0.21.12",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tracing",
 ]
@@ -7548,7 +7676,7 @@ dependencies = [
  "rustc-hash 1.1.0",
  "rustls 0.20.9",
  "slab",
- "thiserror",
+ "thiserror 1.0.69",
  "tinyvec",
  "tracing",
  "webpki",
@@ -7566,7 +7694,7 @@ dependencies = [
  "rustc-hash 1.1.0",
  "rustls 0.21.12",
  "slab",
- "thiserror",
+ "thiserror 1.0.69",
  "tinyvec",
  "tracing",
 ]
@@ -7592,16 +7720,16 @@ checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7"
 dependencies = [
  "bytes",
  "libc",
- "socket2 0.5.7",
+ "socket2 0.5.8",
  "tracing",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.37"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
 dependencies = [
  "proc-macro2",
 ]
@@ -7639,7 +7767,7 @@ version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
 ]
 
 [[package]]
@@ -7663,11 +7791,11 @@ dependencies = [
 
 [[package]]
 name = "raw-cpuid"
-version = "11.2.0"
+version = "11.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0"
+checksum = "c6928fa44c097620b706542d428957635951bade7143269085389d42c8a4927e"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
 ]
 
 [[package]]
@@ -7719,11 +7847,11 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
 ]
 
 [[package]]
@@ -7732,9 +7860,9 @@ version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "libredox",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -7754,7 +7882,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -7784,13 +7912,13 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.11.0"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata 0.4.8",
+ "regex-automata 0.4.9",
  "regex-syntax 0.8.5",
 ]
 
@@ -7805,9 +7933,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.8"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -7869,7 +7997,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
 dependencies = [
  "cc",
  "cfg-if",
- "getrandom",
+ "getrandom 0.2.15",
  "libc",
  "spin 0.9.8",
  "untrusted 0.9.0",
@@ -7936,16 +8064,19 @@ dependencies = [
 
 [[package]]
 name = "rtnetlink"
-version = "0.10.1"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0"
+checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0"
 dependencies = [
  "futures",
  "log",
+ "netlink-packet-core",
  "netlink-packet-route",
+ "netlink-packet-utils",
  "netlink-proto",
+ "netlink-sys",
  "nix",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
 ]
 
@@ -7973,9 +8104,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
 [[package]]
 name = "rustc-hash"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
+checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
 
 [[package]]
 name = "rustc-hex"
@@ -7998,7 +8129,7 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
 dependencies = [
- "semver 1.0.23",
+ "semver 1.0.25",
 ]
 
 [[package]]
@@ -8026,15 +8157,15 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.37"
+version = "0.38.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "errno",
  "libc",
- "linux-raw-sys 0.4.14",
- "windows-sys 0.52.0",
+ "linux-raw-sys 0.4.15",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -8093,9 +8224,9 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.17"
+version = "1.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
 
 [[package]]
 name = "rw-stream-sink"
@@ -8110,9 +8241,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.18"
+version = "1.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
 
 [[package]]
 name = "safe-math"
@@ -8134,9 +8265,9 @@ dependencies = [
 
 [[package]]
 name = "safe_arch"
-version = "0.7.2"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a"
+checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
 dependencies = [
  "bytemuck",
 ]
@@ -8158,7 +8289,7 @@ dependencies = [
  "log",
  "sp-core",
  "sp-wasm-interface 21.0.1",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8233,7 +8364,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -8273,7 +8404,7 @@ dependencies = [
  "sp-panic-handler",
  "sp-runtime",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
 ]
 
@@ -8351,7 +8482,7 @@ dependencies = [
  "sp-runtime",
  "sp-state-machine",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8380,7 +8511,7 @@ dependencies = [
  "sp-keystore",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8416,7 +8547,7 @@ dependencies = [
  "sp-keystore",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8473,7 +8604,7 @@ dependencies = [
  "sp-keystore",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8493,7 +8624,7 @@ dependencies = [
  "sp-blockchain",
  "sp-core",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8528,7 +8659,7 @@ dependencies = [
  "sp-runtime",
  "sp-timestamp",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8586,7 +8717,7 @@ dependencies = [
  "sc-allocator",
  "sp-maybe-compressed-blob",
  "sp-wasm-interface 21.0.1",
- "thiserror",
+ "thiserror 1.0.69",
  "wasm-instrument",
 ]
 
@@ -8647,7 +8778,7 @@ dependencies = [
  "sp-application-crypto",
  "sp-core",
  "sp-keystore",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8676,7 +8807,7 @@ dependencies = [
  "sp-keystore",
  "sp-mixnet",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8721,7 +8852,7 @@ dependencies = [
  "sp-core",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tokio-stream",
  "unsigned-varint 0.7.2",
@@ -8785,7 +8916,7 @@ dependencies = [
  "sp-blockchain",
  "sp-core",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8820,7 +8951,7 @@ dependencies = [
  "sp-core",
  "sp-runtime",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tokio-stream",
 ]
@@ -8855,9 +8986,9 @@ dependencies = [
  "litep2p",
  "log",
  "multiaddr 0.18.2",
- "multihash 0.19.2",
+ "multihash 0.19.3",
  "rand",
- "thiserror",
+ "thiserror 1.0.69",
  "zeroize",
 ]
 
@@ -8871,7 +9002,7 @@ dependencies = [
  "fnv",
  "futures",
  "futures-timer",
- "hyper 0.14.30",
+ "hyper 0.14.32",
  "hyper-rustls",
  "log",
  "num_cpus",
@@ -8953,7 +9084,7 @@ dependencies = [
  "sp-rpc",
  "sp-runtime",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -8965,9 +9096,9 @@ dependencies = [
  "forwarded-header-value",
  "futures",
  "governor",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body-util",
- "hyper 1.5.0",
+ "hyper 1.6.0",
  "ip_network",
  "jsonrpsee",
  "log",
@@ -9007,7 +9138,7 @@ dependencies = [
  "sp-rpc",
  "sp-runtime",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tokio-stream",
 ]
@@ -9070,7 +9201,7 @@ dependencies = [
  "static_init",
  "substrate-prometheus-endpoint",
  "tempfile",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tracing",
  "tracing-futures",
@@ -9092,7 +9223,7 @@ name = "sc-sysinfo"
 version = "38.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "derive_more",
+ "derive_more 0.99.18",
  "futures",
  "libc",
  "log",
@@ -9124,7 +9255,7 @@ dependencies = [
  "sc-utils",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 1.0.69",
  "wasm-timer",
 ]
 
@@ -9151,10 +9282,10 @@ dependencies = [
  "sp-rpc",
  "sp-runtime",
  "sp-tracing 17.0.1",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
  "tracing-log",
- "tracing-subscriber 0.3.18",
+ "tracing-subscriber 0.3.19",
 ]
 
 [[package]]
@@ -9165,7 +9296,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -9192,7 +9323,7 @@ dependencies = [
  "sp-tracing 17.0.1",
  "sp-transaction-pool",
  "substrate-prometheus-endpoint",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -9208,7 +9339,7 @@ dependencies = [
  "sp-blockchain",
  "sp-core",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -9242,7 +9373,7 @@ version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27"
 dependencies = [
- "derive_more",
+ "derive_more 0.99.18",
  "parity-scale-codec",
  "scale-bits",
  "scale-type-resolver",
@@ -9251,13 +9382,13 @@ dependencies = [
 
 [[package]]
 name = "scale-info"
-version = "2.11.3"
+version = "2.11.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024"
+checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b"
 dependencies = [
  "bitvec",
  "cfg-if",
- "derive_more",
+ "derive_more 1.0.0",
  "parity-scale-codec",
  "scale-info-derive",
  "serde",
@@ -9265,14 +9396,14 @@ dependencies = [
 
 [[package]]
 name = "scale-info-derive"
-version = "2.11.3"
+version = "2.11.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62"
+checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf"
 dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -9283,18 +9414,18 @@ checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb"
 
 [[package]]
 name = "schannel"
-version = "0.1.24"
+version = "0.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
 dependencies = [
  "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "schnellru"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367"
+checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649"
 dependencies = [
  "ahash 0.8.11",
  "cfg-if",
@@ -9354,7 +9485,7 @@ dependencies = [
  "log",
  "rand",
  "slab",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -9405,7 +9536,7 @@ version = "2.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "core-foundation",
  "core-foundation-sys",
  "libc",
@@ -9414,9 +9545,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "2.12.0"
+version = "2.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
+checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -9442,9 +9573,9 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.23"
+version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
 dependencies = [
  "serde",
 ]
@@ -9463,9 +9594,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
 
 [[package]]
 name = "serde"
-version = "1.0.216"
+version = "1.0.217"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
 dependencies = [
  "serde_derive",
 ]
@@ -9500,20 +9631,20 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.216"
+version = "1.0.217"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.128"
+version = "1.0.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
 dependencies = [
  "itoa",
  "memchr",
@@ -9567,7 +9698,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -9691,9 +9822,9 @@ dependencies = [
 
 [[package]]
 name = "simba"
-version = "0.8.1"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae"
+checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa"
 dependencies = [
  "approx",
  "num-complex",
@@ -9708,7 +9839,7 @@ version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cae9a3fcdadafb6d97f4c0e007e4247b114ee0f119f650c3cbf3a8b3a1479694"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
 ]
 
 [[package]]
@@ -9779,9 +9910,9 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -9789,14 +9920,14 @@ dependencies = [
 
 [[package]]
 name = "soketto"
-version = "0.8.0"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53"
+checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721"
 dependencies = [
  "base64 0.22.1",
  "bytes",
  "futures",
- "http 1.1.0",
+ "http 1.2.0",
  "httparse",
  "log",
  "rand",
@@ -9822,7 +9953,7 @@ dependencies = [
  "sp-state-machine",
  "sp-trie",
  "sp-version",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -9836,7 +9967,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -9899,7 +10030,7 @@ dependencies = [
  "sp-database",
  "sp-runtime",
  "sp-state-machine",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
 ]
 
@@ -9915,7 +10046,7 @@ dependencies = [
  "sp-inherents",
  "sp-runtime",
  "sp-state-machine",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -9995,7 +10126,7 @@ dependencies = [
  "futures",
  "hash-db",
  "hash256-std-hasher",
- "impl-serde",
+ "impl-serde 0.4.0",
  "itertools 0.11.0",
  "k256",
  "libsecp256k1",
@@ -10005,7 +10136,7 @@ dependencies = [
  "parity-scale-codec",
  "parking_lot 0.12.3",
  "paste",
- "primitive-types",
+ "primitive-types 0.12.2",
  "rand",
  "scale-info",
  "schnorrkel",
@@ -10020,7 +10151,7 @@ dependencies = [
  "sp-storage 21.0.0",
  "ss58-registry",
  "substrate-bip39",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
  "w3f-bls",
  "zeroize",
@@ -10029,7 +10160,7 @@ dependencies = [
 [[package]]
 name = "sp-crypto-ec-utils"
 version = "0.10.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
  "ark-bls12-377",
  "ark-bls12-377-ext",
@@ -10100,7 +10231,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable
 dependencies = [
  "quote",
  "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -10119,23 +10250,23 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "sp-debug-derive"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "sp-externalities"
 version = "0.25.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
  "environmental",
  "parity-scale-codec",
@@ -10174,7 +10305,7 @@ dependencies = [
  "parity-scale-codec",
  "scale-info",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -10188,7 +10319,7 @@ dependencies = [
  "libsecp256k1",
  "log",
  "parity-scale-codec",
- "polkavm-derive",
+ "polkavm-derive 0.9.1",
  "rustversion",
  "secp256k1",
  "sp-core",
@@ -10229,7 +10360,7 @@ name = "sp-maybe-compressed-blob"
 version = "11.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "thiserror",
+ "thiserror 1.0.69",
  "zstd 0.12.4",
 ]
 
@@ -10313,13 +10444,13 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface"
 version = "24.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive",
- "primitive-types",
+ "polkavm-derive 0.18.0",
+ "primitive-types 0.13.1",
  "sp-externalities 0.25.0",
  "sp-runtime-interface-proc-macro 17.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)",
@@ -10337,8 +10468,8 @@ dependencies = [
  "bytes",
  "impl-trait-for-tuples",
  "parity-scale-codec",
- "polkavm-derive",
- "primitive-types",
+ "polkavm-derive 0.9.1",
+ "primitive-types 0.12.2",
  "sp-externalities 0.29.0",
  "sp-runtime-interface-proc-macro 18.0.0",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
@@ -10351,14 +10482,14 @@ dependencies = [
 [[package]]
 name = "sp-runtime-interface-proc-macro"
 version = "17.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
  "Inflector",
  "expander",
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -10371,7 +10502,7 @@ dependencies = [
  "proc-macro-crate 3.2.0",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -10416,7 +10547,7 @@ dependencies = [
  "sp-externalities 0.29.0",
  "sp-panic-handler",
  "sp-trie",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
  "trie-db",
 ]
@@ -10441,7 +10572,7 @@ dependencies = [
  "sp-externalities 0.29.0",
  "sp-runtime",
  "sp-runtime-interface 28.0.0",
- "thiserror",
+ "thiserror 1.0.69",
  "x25519-dalek",
 ]
 
@@ -10453,14 +10584,14 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable
 [[package]]
 name = "sp-std"
 version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 
 [[package]]
 name = "sp-storage"
 version = "19.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
- "impl-serde",
+ "impl-serde 0.5.0",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10472,7 +10603,7 @@ name = "sp-storage"
 version = "21.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde",
+ "impl-serde 0.4.0",
  "parity-scale-codec",
  "ref-cast",
  "serde",
@@ -10488,18 +10619,18 @@ dependencies = [
  "parity-scale-codec",
  "sp-inherents",
  "sp-runtime",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
 name = "sp-tracing"
 version = "16.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
  "parity-scale-codec",
  "tracing",
  "tracing-core",
- "tracing-subscriber 0.3.18",
+ "tracing-subscriber 0.3.19",
 ]
 
 [[package]]
@@ -10510,7 +10641,7 @@ dependencies = [
  "parity-scale-codec",
  "tracing",
  "tracing-core",
- "tracing-subscriber 0.3.18",
+ "tracing-subscriber 0.3.19",
 ]
 
 [[package]]
@@ -10553,7 +10684,7 @@ dependencies = [
  "schnellru",
  "sp-core",
  "sp-externalities 0.29.0",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
  "trie-db",
  "trie-root",
@@ -10564,7 +10695,7 @@ name = "sp-version"
 version = "37.0.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
- "impl-serde",
+ "impl-serde 0.4.0",
  "parity-scale-codec",
  "parity-wasm",
  "scale-info",
@@ -10573,7 +10704,7 @@ dependencies = [
  "sp-runtime",
  "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)",
  "sp-version-proc-macro",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
@@ -10584,13 +10715,13 @@ dependencies = [
  "parity-scale-codec",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "sp-wasm-interface"
 version = "20.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk#8614dc0e055d06de4a3774ac1da0a422b33f34e2"
+source = "git+https://github.com/paritytech/polkadot-sdk#80e30ec3cdccae8e9099bd67840ff8737b043496"
 dependencies = [
  "anyhow",
  "impl-trait-for-tuples",
@@ -10658,21 +10789,11 @@ dependencies = [
  "der",
 ]
 
-[[package]]
-name = "sqlformat"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790"
-dependencies = [
- "nom",
- "unicode_categories",
-]
-
 [[package]]
 name = "sqlx"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e"
+checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f"
 dependencies = [
  "sqlx-core",
  "sqlx-macros",
@@ -10681,37 +10802,31 @@ dependencies = [
 
 [[package]]
 name = "sqlx-core"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e"
+checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0"
 dependencies = [
- "atoi",
- "byteorder",
  "bytes",
  "crc",
  "crossbeam-queue",
  "either",
- "event-listener 5.3.1",
- "futures-channel",
+ "event-listener 5.4.0",
  "futures-core",
  "futures-intrusive",
  "futures-io",
  "futures-util",
- "hashbrown 0.14.5",
- "hashlink 0.9.1",
- "hex",
- "indexmap 2.6.0",
+ "hashbrown 0.15.2",
+ "hashlink 0.10.0",
+ "indexmap 2.7.1",
  "log",
  "memchr",
  "native-tls",
  "once_cell",
- "paste",
  "percent-encoding",
  "serde",
  "sha2 0.10.8",
  "smallvec",
- "sqlformat",
- "thiserror",
+ "thiserror 2.0.11",
  "tokio",
  "tokio-stream",
  "tracing",
@@ -10720,22 +10835,22 @@ dependencies = [
 
 [[package]]
 name = "sqlx-macros"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657"
+checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310"
 dependencies = [
  "proc-macro2",
  "quote",
  "sqlx-core",
  "sqlx-macros-core",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "sqlx-macros-core"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5"
+checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad"
 dependencies = [
  "dotenvy",
  "either",
@@ -10749,7 +10864,7 @@ dependencies = [
  "sha2 0.10.8",
  "sqlx-core",
  "sqlx-sqlite",
- "syn 2.0.90",
+ "syn 2.0.96",
  "tempfile",
  "tokio",
  "url",
@@ -10757,9 +10872,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-sqlite"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680"
+checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540"
 dependencies = [
  "atoi",
  "flume",
@@ -10780,9 +10895,9 @@ dependencies = [
 
 [[package]]
 name = "ss58-registry"
-version = "1.50.0"
+version = "1.51.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43fce22ed1df64d04b262351c8f9d5c6da4f76f79f25ad15529792f893fad25d"
+checksum = "19409f13998e55816d1c728395af0b52ec066206341d939e22e7766df9b494b8"
 dependencies = [
  "Inflector",
  "num-format",
@@ -10841,9 +10956,9 @@ dependencies = [
 
 [[package]]
 name = "static_init_macro"
-version = "1.0.2"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf"
+checksum = "1389c88ddd739ec6d3f8f83343764a0e944cd23cfbf126a9796a714b0b6edd6f"
 dependencies = [
  "cfg_aliases",
  "memchr",
@@ -10868,7 +10983,7 @@ dependencies = [
  "sctp-proto",
  "serde",
  "sha-1",
- "thiserror",
+ "thiserror 1.0.69",
  "tracing",
 ]
 
@@ -10916,7 +11031,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -10973,11 +11088,11 @@ version = "0.17.0"
 source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409#87971b3e92721bdf10bf40b410eaae779d494ca0"
 dependencies = [
  "http-body-util",
- "hyper 1.5.0",
+ "hyper 1.6.0",
  "hyper-util",
  "log",
  "prometheus",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
 ]
 
@@ -11020,7 +11135,7 @@ dependencies = [
  "quote",
  "rayon",
  "subtensor-linting",
- "syn 2.0.90",
+ "syn 2.0.96",
  "walkdir",
 ]
 
@@ -11056,7 +11171,7 @@ dependencies = [
  "proc-macro2",
  "procedural-fork",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -11066,7 +11181,7 @@ dependencies = [
  "ahash 0.8.11",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -11075,7 +11190,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "clap",
- "semver 1.0.23",
+ "semver 1.0.25",
  "toml_edit",
 ]
 
@@ -11104,9 +11219,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.90"
+version = "2.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
+checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -11133,25 +11248,25 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "system-configuration"
-version = "0.5.1"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.8.0",
  "core-foundation",
  "system-configuration-sys",
 ]
 
 [[package]]
 name = "system-configuration-sys"
-version = "0.5.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -11171,14 +11286,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
 
 [[package]]
 name = "tempfile"
-version = "3.13.0"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "getrandom 0.3.1",
  "once_cell",
- "rustix 0.38.37",
+ "rustix 0.38.44",
  "windows-sys 0.59.0",
 ]
 
@@ -11193,38 +11309,58 @@ dependencies = [
 
 [[package]]
 name = "terminal_size"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
+checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
 dependencies = [
- "rustix 0.38.37",
+ "rustix 0.38.44",
  "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "termtree"
-version = "0.4.1"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
+checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
 
 [[package]]
 name = "thiserror"
-version = "1.0.64"
+version = "2.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
+checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
 dependencies = [
- "thiserror-impl",
+ "thiserror-impl 2.0.11",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.64"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -11264,9 +11400,9 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.36"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
 dependencies = [
  "deranged",
  "itoa",
@@ -11285,9 +11421,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.18"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
 dependencies = [
  "num-conv",
  "time-core",
@@ -11314,9 +11450,9 @@ dependencies = [
 
 [[package]]
 name = "tinyvec"
-version = "1.8.0"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
 dependencies = [
  "tinyvec_macros",
 ]
@@ -11357,9 +11493,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.40.0"
+version = "1.43.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
+checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
 dependencies = [
  "backtrace",
  "bytes",
@@ -11368,20 +11504,20 @@ dependencies = [
  "parking_lot 0.12.3",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2 0.5.7",
+ "socket2 0.5.8",
  "tokio-macros",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
+checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -11396,9 +11532,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-stream"
-version = "0.1.16"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1"
+checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
 dependencies = [
  "futures-core",
  "pin-project-lite",
@@ -11423,9 +11559,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-util"
-version = "0.7.12"
+version = "0.7.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
 dependencies = [
  "bytes",
  "futures-core",
@@ -11471,7 +11607,7 @@ version = "0.22.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
 dependencies = [
- "indexmap 2.6.0",
+ "indexmap 2.7.1",
  "serde",
  "serde_spanned",
  "toml_datetime",
@@ -11499,9 +11635,9 @@ version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "bytes",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "http-body-util",
  "pin-project-lite",
@@ -11523,9 +11659,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
 
 [[package]]
 name = "tracing"
-version = "0.1.40"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
 dependencies = [
  "log",
  "pin-project-lite",
@@ -11535,20 +11671,20 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.27"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "tracing-core"
-version = "0.1.32"
+version = "0.1.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
 dependencies = [
  "once_cell",
  "valuable",
@@ -11586,9 +11722,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.18"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
 dependencies = [
  "matchers",
  "nu-ansi-term",
@@ -11644,7 +11780,7 @@ dependencies = [
  "rand",
  "smallvec",
  "socket2 0.4.10",
- "thiserror",
+ "thiserror 1.0.69",
  "tinyvec",
  "tokio",
  "tracing",
@@ -11669,7 +11805,7 @@ dependencies = [
  "once_cell",
  "rand",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.69",
  "tinyvec",
  "tokio",
  "tracing",
@@ -11691,7 +11827,7 @@ dependencies = [
  "rand",
  "resolv-conf",
  "smallvec",
- "thiserror",
+ "thiserror 1.0.69",
  "tokio",
  "tracing",
  "trust-dns-proto 0.23.2",
@@ -11724,7 +11860,7 @@ dependencies = [
  "rand",
  "rustls 0.21.12",
  "sha1",
- "thiserror",
+ "thiserror 1.0.69",
  "url",
  "utf-8",
 ]
@@ -11774,17 +11910,29 @@ dependencies = [
  "static_assertions",
 ]
 
+[[package]]
+name = "uint"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
+
 [[package]]
 name = "unicode-bidi"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.13"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
 
 [[package]]
 name = "unicode-normalization"
@@ -11802,16 +11950,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
 [[package]]
-name = "unicode-xid"
-version = "0.2.6"
+name = "unicode-width"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
 
 [[package]]
-name = "unicode_categories"
-version = "0.1.1"
+name = "unicode-xid"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
 
 [[package]]
 name = "universal-hash"
@@ -11894,9 +12042,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
 name = "valuable"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
 
 [[package]]
 name = "vcpkg"
@@ -11936,7 +12084,7 @@ dependencies = [
  "rand_core",
  "sha2 0.10.8",
  "sha3",
- "thiserror",
+ "thiserror 1.0.69",
  "zeroize",
 ]
 
@@ -11965,49 +12113,59 @@ version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
+[[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.93"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.93"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.43"
+version = "0.4.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
 dependencies = [
  "cfg-if",
  "js-sys",
+ "once_cell",
  "wasm-bindgen",
  "web-sys",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.93"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -12015,22 +12173,25 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.93"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.93"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "wasm-instrument"
@@ -12052,7 +12213,7 @@ dependencies = [
  "strum 0.24.1",
  "strum_macros 0.24.3",
  "tempfile",
- "thiserror",
+ "thiserror 1.0.69",
  "wasm-opt-cxx-sys",
  "wasm-opt-sys",
 ]
@@ -12179,7 +12340,7 @@ dependencies = [
  "log",
  "object 0.30.4",
  "target-lexicon",
- "thiserror",
+ "thiserror 1.0.69",
  "wasmparser",
  "wasmtime-cranelift-shared",
  "wasmtime-environ",
@@ -12214,7 +12375,7 @@ dependencies = [
  "object 0.30.4",
  "serde",
  "target-lexicon",
- "thiserror",
+ "thiserror 1.0.69",
  "wasmparser",
  "wasmtime-types",
 ]
@@ -12297,15 +12458,15 @@ checksum = "a4f6fffd2a1011887d57f07654dd112791e872e3ff4a2e626aee8059ee17f06f"
 dependencies = [
  "cranelift-entity",
  "serde",
- "thiserror",
+ "thiserror 1.0.69",
  "wasmparser",
 ]
 
 [[package]]
 name = "web-sys"
-version = "0.3.70"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -12336,14 +12497,14 @@ dependencies = [
  "either",
  "home",
  "once_cell",
- "rustix 0.38.37",
+ "rustix 0.38.44",
 ]
 
 [[package]]
 name = "wide"
-version = "0.7.28"
+version = "0.7.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690"
+checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22"
 dependencies = [
  "bytemuck",
  "safe_arch",
@@ -12388,28 +12549,38 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows"
-version = "0.51.1"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9"
+checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538"
 dependencies = [
- "windows-core 0.51.1",
- "windows-targets 0.48.5",
+ "windows-core 0.53.0",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
 name = "windows-core"
-version = "0.51.1"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
 name = "windows-core"
-version = "0.52.0"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd"
+dependencies = [
+ "windows-result",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
 dependencies = [
  "windows-targets 0.52.6",
 ]
@@ -12645,9 +12816,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.6.20"
+version = "0.6.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310"
 dependencies = [
  "memchr",
 ]
@@ -12662,6 +12833,15 @@ dependencies = [
  "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags 2.8.0",
+]
+
 [[package]]
 name = "write16"
 version = "1.0.0"
@@ -12708,7 +12888,7 @@ dependencies = [
  "nom",
  "oid-registry 0.6.1",
  "rusticata-macros",
- "thiserror",
+ "thiserror 1.0.69",
  "time",
 ]
 
@@ -12725,7 +12905,7 @@ dependencies = [
  "nom",
  "oid-registry 0.7.1",
  "rusticata-macros",
- "thiserror",
+ "thiserror 1.0.69",
  "time",
 ]
 
@@ -12737,14 +12917,14 @@ dependencies = [
  "Inflector",
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
 name = "xml-rs"
-version = "0.8.22"
+version = "0.8.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26"
+checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
 
 [[package]]
 name = "xmltree"
@@ -12799,7 +12979,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
  "synstructure 0.13.1",
 ]
 
@@ -12821,7 +13001,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -12841,7 +13021,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
  "synstructure 0.13.1",
 ]
 
@@ -12862,7 +13042,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]
@@ -12884,7 +13064,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.90",
+ "syn 2.0.96",
 ]
 
 [[package]]

From f25cabc641df8f379ac3a2d6d0030f42477f9df0 Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Thu, 30 Jan 2025 18:22:38 +0800
Subject: [PATCH 137/145] add len check

---
 runtime/src/precompiles/subnet.rs | 59 +++++++++++++++++++++++++++++--
 1 file changed, 57 insertions(+), 2 deletions(-)

diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index edef73ff0..36f861d48 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -7,8 +7,10 @@ use sp_runtime::AccountId32;
 use sp_std::vec;
 
 pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051;
+// bytes with max lenght 1K
+pub const MAX_SINGLE_PARAMETER_SIZE: usize = 1024;
 // three bytes with max lenght 1K
-pub const MAX_PARAMETER_SIZE: usize = 3 * 1024;
+pub const MAX_PARAMETER_SIZE: usize = 3 * MAX_SINGLE_PARAMETER_SIZE;
 
 // ss58 public key i.e., the contract sends funds it received to the destination address from the
 // method parameter.
@@ -90,18 +92,46 @@ impl SubnetPrecompile {
     fn parse_register_network_parameters(
         data: &[u8],
     ) -> Result<(AccountId32, vec::Vec<u8>, vec::Vec<u8>, vec::Vec<u8>), PrecompileFailure> {
-        let (pubkey, _) = get_pubkey(data)?;
+        let (pubkey, dynamic_params) = get_pubkey(data)?;
+        let dynamic_data_len = dynamic_params.len();
 
         let mut buf = [0_u8; 4];
         // get all start point for three data items: name, repo and contact
         buf.copy_from_slice(get_slice(data, 60, 64)?);
         let subnet_name_start: usize = u32::from_be_bytes(buf) as usize;
+        if subnet_name_start > dynamic_data_len {
+            log::error!(
+                "the start position of subnet name as {} is too big ",
+                subnet_name_start
+            );
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
 
         buf.copy_from_slice(get_slice(data, 92, 96)?);
         let github_repo_start: usize = u32::from_be_bytes(buf) as usize;
+        if github_repo_start > dynamic_data_len {
+            log::error!(
+                "the start position of github repo as {} is too big ",
+                github_repo_start
+            );
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
 
         buf.copy_from_slice(get_slice(data, 124, 128)?);
         let subnet_contact_start: usize = u32::from_be_bytes(buf) as usize;
+        if subnet_contact_start > dynamic_data_len {
+            log::error!(
+                "the start position of subnet contact as {} is too big ",
+                subnet_contact_start
+            );
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
 
         // get name
         buf.copy_from_slice(get_slice(
@@ -111,6 +141,13 @@ impl SubnetPrecompile {
         )?);
         let subnet_name_len: usize = u32::from_be_bytes(buf) as usize;
 
+        if subnet_name_len > MAX_SINGLE_PARAMETER_SIZE {
+            log::error!("the length of subnet nae as {} is too big", subnet_name_len);
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
+
         let mut name_vec = vec![0; subnet_name_len];
         name_vec.copy_from_slice(get_slice(
             data,
@@ -125,6 +162,15 @@ impl SubnetPrecompile {
             github_repo_start + 32,
         )?);
         let github_repo_len: usize = u32::from_be_bytes(buf) as usize;
+        if github_repo_len > MAX_SINGLE_PARAMETER_SIZE {
+            log::error!(
+                "the length of github repo as {} is too big",
+                github_repo_len
+            );
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
 
         let mut repo_vec = vec![0; github_repo_len];
         repo_vec.copy_from_slice(get_slice(
@@ -140,6 +186,15 @@ impl SubnetPrecompile {
             subnet_contact_start + 32,
         )?);
         let subnet_contact_len: usize = u32::from_be_bytes(buf) as usize;
+        if subnet_contact_len > MAX_SINGLE_PARAMETER_SIZE {
+            log::error!(
+                "the length of subnet contact as {} is too big",
+                subnet_contact_len
+            );
+            return Err(PrecompileFailure::Error {
+                exit_status: ExitError::InvalidRange,
+            });
+        }
 
         let mut contact_vec = vec![0; subnet_contact_len];
         contact_vec.copy_from_slice(get_slice(

From f8d5d4d7e2dfe8745e6445432c3877e976db059e Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Thu, 30 Jan 2025 14:28:17 +0100
Subject: [PATCH 138/145] Fix rao migration did not update TotalIssuance

---
 .../migrations/migrate_init_total_issuance.rs | 77 ++++++++++---------
 .../subtensor/src/migrations/migrate_rao.rs   | 16 ++--
 scripts/try-runtime-upgrade.sh                |  2 +-
 3 files changed, 52 insertions(+), 43 deletions(-)

diff --git a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
index a488771c5..4501ccf6d 100644
--- a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
+++ b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
@@ -1,6 +1,6 @@
 use super::*;
-use frame_support::pallet_prelude::OptionQuery;
-use frame_support::{pallet_prelude::Identity, storage_alias};
+use frame_support::pallet_prelude::{Identity, OptionQuery, Weight};
+use frame_support::storage_alias;
 use sp_std::vec::Vec;
 
 // TODO: Implement comprehensive tests for this migration
@@ -14,6 +14,43 @@ pub mod deprecated_loaded_emission_format {
         StorageMap<Pallet<T>, Identity, u16, Vec<(AccountIdOf<T>, u64)>, OptionQuery>;
 }
 
+pub(crate) fn migrate_init_total_issuance<T: Config>() -> Weight {
+    // Calculate the total locked tokens across all subnets
+    let subnets_len = crate::SubnetLocked::<T>::iter().count() as u64;
+    let total_subnet_locked: u64 =
+        crate::SubnetLocked::<T>::iter().fold(0, |acc, (_, v)| acc.saturating_add(v));
+
+    // Retrieve the total balance of all accounts
+    let total_account_balances = <<T as crate::Config>::Currency as fungible::Inspect<
+        <T as frame_system::Config>::AccountId,
+    >>::total_issuance();
+
+    // Get the total stake from the system
+    let total_stake = crate::TotalStake::<T>::get();
+
+    // Retrieve the previous total issuance for logging purposes
+    let prev_total_issuance = crate::TotalIssuance::<T>::get();
+
+    // Calculate the new total issuance
+    let new_total_issuance = total_account_balances
+        .saturating_add(total_stake)
+        .saturating_add(total_subnet_locked);
+
+    // Update the total issuance in storage
+    crate::TotalIssuance::<T>::put(new_total_issuance);
+
+    // Log the change in total issuance
+    log::info!(
+        "Subtensor Pallet Total Issuance Updated: previous: {:?}, new: {:?}",
+        prev_total_issuance,
+        new_total_issuance
+    );
+
+    // Return the weight of the operation
+    // We performed subnets_len + 5 reads and 1 write
+    <T as frame_system::Config>::DbWeight::get().reads_writes(subnets_len.saturating_add(5), 1)
+}
+
 pub mod initialise_total_issuance {
     use frame_support::pallet_prelude::Weight;
     use frame_support::traits::{fungible, OnRuntimeUpgrade};
@@ -33,41 +70,7 @@ pub mod initialise_total_issuance {
         ///
         /// Returns the weight of the migration operation.
         fn on_runtime_upgrade() -> Weight {
-            // Calculate the total locked tokens across all subnets
-            let subnets_len = crate::SubnetLocked::<T>::iter().count() as u64;
-            let total_subnet_locked: u64 =
-                crate::SubnetLocked::<T>::iter().fold(0, |acc, (_, v)| acc.saturating_add(v));
-
-            // Retrieve the total balance of all accounts
-            let total_account_balances = <<T as crate::Config>::Currency as fungible::Inspect<
-                <T as frame_system::Config>::AccountId,
-            >>::total_issuance();
-
-            // Get the total stake from the system
-            let total_stake = crate::TotalStake::<T>::get();
-
-            // Retrieve the previous total issuance for logging purposes
-            let prev_total_issuance = crate::TotalIssuance::<T>::get();
-
-            // Calculate the new total issuance
-            let new_total_issuance = total_account_balances
-                .saturating_add(total_stake)
-                .saturating_add(total_subnet_locked);
-
-            // Update the total issuance in storage
-            crate::TotalIssuance::<T>::put(new_total_issuance);
-
-            // Log the change in total issuance
-            log::info!(
-                "Subtensor Pallet Total Issuance Updated: previous: {:?}, new: {:?}",
-                prev_total_issuance,
-                new_total_issuance
-            );
-
-            // Return the weight of the operation
-            // We performed subnets_len + 5 reads and 1 write
-            <T as frame_system::Config>::DbWeight::get()
-                .reads_writes(subnets_len.saturating_add(5), 1)
+            super::migrate_init_total_issuance::<T>()
         }
 
         /// Performs post-upgrade checks to ensure the migration was successful.
diff --git a/pallets/subtensor/src/migrations/migrate_rao.rs b/pallets/subtensor/src/migrations/migrate_rao.rs
index 3c034b7da..136bd4c59 100644
--- a/pallets/subtensor/src/migrations/migrate_rao.rs
+++ b/pallets/subtensor/src/migrations/migrate_rao.rs
@@ -1,11 +1,13 @@
-use super::*;
 use alloc::string::String;
+
 use frame_support::IterableStorageMap;
 use frame_support::{traits::Get, weights::Weight};
-use log;
 use sp_runtime::format;
 use substrate_fixed::types::U64F64;
 
+use super::*;
+use crate::subnets::subnet::POOL_INITIAL_TAO;
+
 pub fn migrate_rao<T: Config>() -> Weight {
     let migration_name = b"migrate_rao".to_vec();
 
@@ -69,12 +71,12 @@ pub fn migrate_rao<T: Config>() -> Weight {
             TokenSymbol::<T>::insert(netuid, Pallet::<T>::get_symbol_for_subnet(0));
             continue;
         }
-        let owner: T::AccountId = SubnetOwner::<T>::get(netuid);
-        let lock: u64 = SubnetLocked::<T>::get(netuid);
+        let owner = SubnetOwner::<T>::get(netuid);
+        let lock = SubnetLocked::<T>::get(netuid);
 
         // Put initial TAO from lock into subnet TAO and produce numerically equal amount of Alpha
         // The initial TAO is the locked amount, with a minimum of 1 RAO and a cap of 100 TAO.
-        let pool_initial_tao = 100_000_000_000.min(lock.max(1));
+        let pool_initial_tao = POOL_INITIAL_TAO.min(lock.max(1));
 
         let remaining_lock = lock.saturating_sub(pool_initial_tao);
         // Refund the owner for the remaining lock.
@@ -127,6 +129,10 @@ pub fn migrate_rao<T: Config>() -> Weight {
         // TargetStakesPerInterval::<T>::put(10); (DEPRECATED)
     }
 
+    // update `TotalIssuance`, because currency issuance (`T::Currency`) has changed due to lock
+    // refunds above
+    weight = weight.saturating_add(migrate_init_total_issuance::migrate_init_total_issuance::<T>());
+
     // Mark the migration as completed
     HasMigrationRun::<T>::insert(&migration_name, true);
     weight = weight.saturating_add(T::DbWeight::get().writes(1));
diff --git a/scripts/try-runtime-upgrade.sh b/scripts/try-runtime-upgrade.sh
index 80495bcb1..bf8ac8393 100755
--- a/scripts/try-runtime-upgrade.sh
+++ b/scripts/try-runtime-upgrade.sh
@@ -49,7 +49,7 @@ do_try_runtime() {
   fi
 
   eval "try-runtime --runtime $runtime_wasm_path on-runtime-upgrade \
-    --no-weight-warnings --disable-spec-version-check --disable-idempotency-checks \
+    --no-weight-warnings --disable-spec-version-check --disable-idempotency-checks --checks=all \
     $chain_state"
 }
 

From a7fffd8dec7f59281003b159fd6fa66a207444b3 Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Thu, 30 Jan 2025 15:55:00 +0100
Subject: [PATCH 139/145] Refactor TryState

---
 pallets/subtensor/src/macros/hooks.rs         |  7 +-
 .../migrations/migrate_init_total_issuance.rs |  7 +-
 pallets/subtensor/src/utils/mod.rs            |  1 +
 pallets/subtensor/src/utils/try_state.rs      | 71 ++++++++++---------
 scripts/try-runtime-upgrade.sh                |  2 +-
 5 files changed, 48 insertions(+), 40 deletions(-)

diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs
index 2a43238ab..cefc2e24b 100644
--- a/pallets/subtensor/src/macros/hooks.rs
+++ b/pallets/subtensor/src/macros/hooks.rs
@@ -4,6 +4,9 @@ use frame_support::pallet_macros::pallet_section;
 /// This can later be imported into the pallet using [`import_section`].
 #[pallet_section]
 mod hooks {
+	#[cfg(feature = "try-runtime")]
+	use crate::utils::try_state::TryState;
+
     // ================
     // ==== Hooks =====
     // ================
@@ -82,7 +85,9 @@ mod hooks {
 
         #[cfg(feature = "try-runtime")]
         fn try_state(_n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
-            Self::check_accounting_invariants()?;
+            TryState::<T>::check_total_issuance()?;
+			// Disabled: https://github.com/opentensor/subtensor/pull/1166
+            // TryState::<T>::check_total_stake()?;
             Ok(())
         }
     }
diff --git a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
index 4501ccf6d..e1423a625 100644
--- a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
+++ b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
@@ -53,9 +53,10 @@ pub(crate) fn migrate_init_total_issuance<T: Config>() -> Weight {
 
 pub mod initialise_total_issuance {
     use frame_support::pallet_prelude::Weight;
-    use frame_support::traits::{fungible, OnRuntimeUpgrade};
-    use sp_core::Get;
+    use frame_support::traits::OnRuntimeUpgrade;
 
+    #[cfg(feature = "try-runtime")]
+    use crate::utils::try_state::TryState;
     use crate::*;
 
     pub struct Migration<T: Config>(PhantomData<T>);
@@ -79,7 +80,7 @@ pub mod initialise_total_issuance {
         #[cfg(feature = "try-runtime")]
         fn post_upgrade(_state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
             // Verify that all accounting invariants are satisfied after the migration
-            crate::Pallet::<T>::check_accounting_invariants()?;
+            TryState::<T>::check_total_issuance()?;
             Ok(())
         }
     }
diff --git a/pallets/subtensor/src/utils/mod.rs b/pallets/subtensor/src/utils/mod.rs
index a42c91119..909ad8959 100644
--- a/pallets/subtensor/src/utils/mod.rs
+++ b/pallets/subtensor/src/utils/mod.rs
@@ -2,4 +2,5 @@ use super::*;
 pub mod identity;
 pub mod misc;
 pub mod rate_limiting;
+#[cfg(feature = "try-runtime")]
 pub mod try_state;
diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs
index c2292eeee..9899131c3 100644
--- a/pallets/subtensor/src/utils/try_state.rs
+++ b/pallets/subtensor/src/utils/try_state.rs
@@ -1,42 +1,17 @@
-use super::*;
-
-impl<T: Config> Pallet<T> {
-    /// Checks if the accounting invariants for [`TotalStake`], [`TotalSubnetLocked`], and [`TotalIssuance`] are correct.
-    ///
-    /// This function verifies that:
-    /// 1. The sum of all stakes matches the [`TotalStake`].
-    /// 2. The [`TotalSubnetLocked`] is correctly calculated.
-    /// 3. The [`TotalIssuance`] equals the sum of currency issuance, total stake, and total subnet locked.
-    ///
-    /// # Returns
-    ///
-    /// Returns `Ok(())` if all invariants are correct, otherwise returns an error.
-    #[cfg(feature = "try-runtime")]
-    pub fn check_accounting_invariants() -> Result<(), sp_runtime::TryRuntimeError> {
+use core::marker::PhantomData;
         use frame_support::traits::fungible::Inspect;
 
-        // Disabled: https://github.com/opentensor/subtensor/pull/1166
-        //
-        // // Calculate the total staked amount
-        // let total_staked = SubnetTAO::<T>::iter().fold(0u64, |acc, (netuid, stake)| {
-        //     let acc = acc.saturating_add(stake);
-
-        //     if netuid == Self::get_root_netuid() {
-        //         // root network doesn't have initial pool TAO
-        //         acc
-        //     } else {
-        //         acc.saturating_sub(POOL_INITIAL_TAO)
-        //     }
-        // });
+use crate::subnets::subnet::POOL_INITIAL_TAO;
+use super::*;
 
-        // // Verify that the calculated total stake matches the stored TotalStake
-        // ensure!(
-        //     total_staked == TotalStake::<T>::get(),
-        //     "TotalStake does not match total staked",
-        // );
+pub(crate) struct TryState<T: Config>(PhantomData<T>);
 
+impl<T: Config> TryState<T> {
+	/// Checks [`TotalIssuance`] equals the sum of currency issuance, total stake, and total subnet
+	/// locked.
+    pub(crate) fn check_total_issuance() -> Result<(), sp_runtime::TryRuntimeError> {
         // Get the total subnet locked amount
-        let total_subnet_locked = Self::get_total_subnet_locked();
+        let total_subnet_locked = Pallet::<T>::get_total_subnet_locked();
 
         // Get the total currency issuance
         let currency_issuance = T::Currency::total_issuance();
@@ -59,11 +34,37 @@ impl<T: Config> Pallet<T> {
             expected_total_issuance.checked_sub(total_issuance)
         }
         .expect("LHS > RHS");
+
         ensure!(
             diff <= delta,
             "TotalIssuance diff greater than allowable delta",
         );
 
-        Ok(())
+		Ok(())
     }
+
+	/// Checks the sum of all stakes matches the [`TotalStake`].
+    pub(crate) fn check_total_stake() -> Result<(), sp_runtime::TryRuntimeError> {
+        // Calculate the total staked amount
+        let total_staked = SubnetTAO::<T>::iter().fold(0u64, |acc, (netuid, stake)| {
+            let acc = acc.saturating_add(stake);
+
+            if netuid == Pallet::<T>::get_root_netuid() {
+                // root network doesn't have initial pool TAO
+                acc
+            } else {
+                acc.saturating_sub(POOL_INITIAL_TAO)
+            }
+        });
+
+		log::warn!("total_staked: {}, TotalStake: {}", total_staked, TotalStake::<T>::get());
+
+        // Verify that the calculated total stake matches the stored TotalStake
+        ensure!(
+            total_staked == TotalStake::<T>::get(),
+            "TotalStake does not match total staked",
+        );
+
+		Ok(())
+	}
 }
diff --git a/scripts/try-runtime-upgrade.sh b/scripts/try-runtime-upgrade.sh
index bf8ac8393..11ce78147 100755
--- a/scripts/try-runtime-upgrade.sh
+++ b/scripts/try-runtime-upgrade.sh
@@ -49,7 +49,7 @@ do_try_runtime() {
   fi
 
   eval "try-runtime --runtime $runtime_wasm_path on-runtime-upgrade \
-    --no-weight-warnings --disable-spec-version-check --disable-idempotency-checks --checks=all \
+    --disable-spec-version-check --disable-idempotency-checks --checks=all \
     $chain_state"
 }
 

From d39a6ea31d13eb4a64875ccd61ff3fa5a3fa948f Mon Sep 17 00:00:00 2001
From: Aliaksandr Tsurko <ales@opentensor.dev>
Date: Thu, 30 Jan 2025 15:56:44 +0100
Subject: [PATCH 140/145] Reformat

---
 pallets/subtensor/src/macros/hooks.rs         |  9 ++----
 .../migrations/migrate_init_total_issuance.rs |  4 +--
 pallets/subtensor/src/utils/try_state.rs      | 32 ++++++++++---------
 scripts/try-runtime-upgrade.sh                |  2 +-
 4 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs
index cefc2e24b..4310d3b1e 100644
--- a/pallets/subtensor/src/macros/hooks.rs
+++ b/pallets/subtensor/src/macros/hooks.rs
@@ -4,9 +4,6 @@ use frame_support::pallet_macros::pallet_section;
 /// This can later be imported into the pallet using [`import_section`].
 #[pallet_section]
 mod hooks {
-	#[cfg(feature = "try-runtime")]
-	use crate::utils::try_state::TryState;
-
     // ================
     // ==== Hooks =====
     // ================
@@ -85,9 +82,9 @@ mod hooks {
 
         #[cfg(feature = "try-runtime")]
         fn try_state(_n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
-            TryState::<T>::check_total_issuance()?;
-			// Disabled: https://github.com/opentensor/subtensor/pull/1166
-            // TryState::<T>::check_total_stake()?;
+            Self::check_total_issuance()?;
+            // Disabled: https://github.com/opentensor/subtensor/pull/1166
+            // Self::check_total_stake()?;
             Ok(())
         }
     }
diff --git a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
index e1423a625..ba9d85bad 100644
--- a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
+++ b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
@@ -55,8 +55,6 @@ pub mod initialise_total_issuance {
     use frame_support::pallet_prelude::Weight;
     use frame_support::traits::OnRuntimeUpgrade;
 
-    #[cfg(feature = "try-runtime")]
-    use crate::utils::try_state::TryState;
     use crate::*;
 
     pub struct Migration<T: Config>(PhantomData<T>);
@@ -80,7 +78,7 @@ pub mod initialise_total_issuance {
         #[cfg(feature = "try-runtime")]
         fn post_upgrade(_state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
             // Verify that all accounting invariants are satisfied after the migration
-            TryState::<T>::check_total_issuance()?;
+            crate::Pallet::<T>::check_total_issuance()?;
             Ok(())
         }
     }
diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs
index 9899131c3..db7e4352e 100644
--- a/pallets/subtensor/src/utils/try_state.rs
+++ b/pallets/subtensor/src/utils/try_state.rs
@@ -1,17 +1,14 @@
-use core::marker::PhantomData;
-        use frame_support::traits::fungible::Inspect;
+use frame_support::traits::fungible::Inspect;
 
-use crate::subnets::subnet::POOL_INITIAL_TAO;
 use super::*;
+use crate::subnets::subnet::POOL_INITIAL_TAO;
 
-pub(crate) struct TryState<T: Config>(PhantomData<T>);
-
-impl<T: Config> TryState<T> {
-	/// Checks [`TotalIssuance`] equals the sum of currency issuance, total stake, and total subnet
-	/// locked.
+impl<T: Config> Pallet<T> {
+    /// Checks [`TotalIssuance`] equals the sum of currency issuance, total stake, and total subnet
+    /// locked.
     pub(crate) fn check_total_issuance() -> Result<(), sp_runtime::TryRuntimeError> {
         // Get the total subnet locked amount
-        let total_subnet_locked = Pallet::<T>::get_total_subnet_locked();
+        let total_subnet_locked = Self::get_total_subnet_locked();
 
         // Get the total currency issuance
         let currency_issuance = T::Currency::total_issuance();
@@ -40,16 +37,17 @@ impl<T: Config> TryState<T> {
             "TotalIssuance diff greater than allowable delta",
         );
 
-		Ok(())
+        Ok(())
     }
 
-	/// Checks the sum of all stakes matches the [`TotalStake`].
+    /// Checks the sum of all stakes matches the [`TotalStake`].
+    #[allow(dead_code)]
     pub(crate) fn check_total_stake() -> Result<(), sp_runtime::TryRuntimeError> {
         // Calculate the total staked amount
         let total_staked = SubnetTAO::<T>::iter().fold(0u64, |acc, (netuid, stake)| {
             let acc = acc.saturating_add(stake);
 
-            if netuid == Pallet::<T>::get_root_netuid() {
+            if netuid == Self::get_root_netuid() {
                 // root network doesn't have initial pool TAO
                 acc
             } else {
@@ -57,7 +55,11 @@ impl<T: Config> TryState<T> {
             }
         });
 
-		log::warn!("total_staked: {}, TotalStake: {}", total_staked, TotalStake::<T>::get());
+        log::warn!(
+            "total_staked: {}, TotalStake: {}",
+            total_staked,
+            TotalStake::<T>::get()
+        );
 
         // Verify that the calculated total stake matches the stored TotalStake
         ensure!(
@@ -65,6 +67,6 @@ impl<T: Config> TryState<T> {
             "TotalStake does not match total staked",
         );
 
-		Ok(())
-	}
+        Ok(())
+    }
 }
diff --git a/scripts/try-runtime-upgrade.sh b/scripts/try-runtime-upgrade.sh
index 11ce78147..bf8ac8393 100755
--- a/scripts/try-runtime-upgrade.sh
+++ b/scripts/try-runtime-upgrade.sh
@@ -49,7 +49,7 @@ do_try_runtime() {
   fi
 
   eval "try-runtime --runtime $runtime_wasm_path on-runtime-upgrade \
-    --disable-spec-version-check --disable-idempotency-checks --checks=all \
+    --no-weight-warnings --disable-spec-version-check --disable-idempotency-checks --checks=all \
     $chain_state"
 }
 

From 998867ead0e6618fbccbd8bb3d69b0671c2fc02e Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Fri, 31 Jan 2025 00:11:02 +0800
Subject: [PATCH 141/145] fix wrong origin

---
 runtime/src/precompiles/staking.rs | 81 ++++++++++++++++++++++--------
 runtime/src/precompiles/subnet.rs  | 20 +++++---
 2 files changed, 73 insertions(+), 28 deletions(-)

diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index 3c3ee7ad9..eefde3a37 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -26,16 +26,17 @@
 //
 
 use crate::precompiles::{
-    contract_to_origin, get_method_id, get_pubkey, get_slice, parse_netuid,
-    try_dispatch_runtime_call,
+    get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call,
 };
 use crate::{ProxyType, Runtime, RuntimeCall};
+use frame_system::RawOrigin;
 use pallet_evm::{
-    BalanceConverter, ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle,
-    PrecompileOutput, PrecompileResult,
+    AddressMapping, BalanceConverter, ExitError, ExitSucceed, HashedAddressMapping,
+    PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
 };
 use sp_core::U256;
-use sp_runtime::traits::{StaticLookup, UniqueSaturatedInto};
+use sp_runtime::traits::{BlakeTwo256, Dispatchable, StaticLookup, UniqueSaturatedInto};
+use sp_runtime::AccountId32;
 use sp_std::vec;
 
 pub const STAKING_PRECOMPILE_INDEX: u64 = 2049;
@@ -75,27 +76,37 @@ impl StakingPrecompile {
     }
 
     fn add_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
+        let account_id =
+            <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
+                handle.context().caller,
+            );
+
         let (hotkey, _) = get_pubkey(data)?;
         let amount: U256 = handle.context().apparent_value;
         let netuid = Self::parse_netuid(data, 0x3E)?;
 
+        if !amount.is_zero() {
+            Self::transfer_back_to_caller(&account_id, amount)?;
+        }
+
         let amount_sub =
             <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
                 .ok_or(ExitError::OutOfFund)?;
 
-        // let (account_id_src, _) = get_pubkey(&CONTRACT_ADDRESS_SS58)?;
-        // Create the add_stake call
         let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::<Runtime>::add_stake {
             hotkey,
             netuid,
             amount_staked: amount_sub.unique_saturated_into(),
         });
-        // let origin = RawOrigin::Signed(account_id_src);
-        // Dispatch the add_stake call
-        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
+
+        try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id))
     }
 
     fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
+        let account_id =
+            <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
+                handle.context().caller,
+            );
         let (hotkey, _) = get_pubkey(data)?;
         let netuid = Self::parse_netuid(data, 0x5E)?;
 
@@ -115,10 +126,14 @@ impl StakingPrecompile {
             netuid,
             amount_unstaked: amount_sub.unique_saturated_into(),
         });
-        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
+        try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id))
     }
 
     fn add_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
+        let account_id =
+            <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
+                handle.context().caller,
+            );
         let (delegate, _) = get_pubkey(data)?;
         let delegate = <Runtime as frame_system::Config>::Lookup::unlookup(delegate);
         let call = RuntimeCall::Proxy(pallet_proxy::Call::<Runtime>::add_proxy {
@@ -127,10 +142,14 @@ impl StakingPrecompile {
             delay: 0,
         });
 
-        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
+        try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id))
     }
 
     fn remove_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult {
+        let account_id =
+            <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
+                handle.context().caller,
+            );
         let (delegate, _) = get_pubkey(data)?;
         let delegate = <Runtime as frame_system::Config>::Lookup::unlookup(delegate);
         let call = RuntimeCall::Proxy(pallet_proxy::Call::<Runtime>::remove_proxy {
@@ -139,7 +158,7 @@ impl StakingPrecompile {
             delay: 0,
         });
 
-        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
+        try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id))
     }
 
     fn get_stake(data: &[u8]) -> PrecompileResult {
@@ -167,17 +186,37 @@ impl StakingPrecompile {
         })
     }
 
-    fn parse_netuid(data: &[u8], offset: usize) -> Result<u16, PrecompileFailure> {
-        if data.len() < offset + 2 {
+    fn transfer_back_to_caller(
+        account_id: &AccountId32,
+        amount: U256,
+    ) -> Result<(), PrecompileFailure> {
+        let smart_contract_account_id: AccountId32 = CONTRACT_ADDRESS_SS58.into();
+
+        let amount_sub =
+            <Runtime as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount)
+                .ok_or(ExitError::OutOfFund)?;
+
+        // Create a transfer call from the smart contract to the caller
+        let transfer_call =
+            RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
+                dest: account_id.clone().into(),
+                value: amount_sub.unique_saturated_into(),
+            });
+
+        // Execute the transfer
+        let transfer_result =
+            transfer_call.dispatch(RawOrigin::Signed(smart_contract_account_id).into());
+
+        if let Err(dispatch_error) = transfer_result {
+            log::error!(
+                "Transfer back to caller failed. Error: {:?}",
+                dispatch_error
+            );
             return Err(PrecompileFailure::Error {
-                exit_status: ExitError::InvalidRange,
+                exit_status: ExitError::Other("Transfer back to caller failed".into()),
             });
         }
 
-        let mut netuid_bytes = [0u8; 2];
-        netuid_bytes.copy_from_slice(get_slice(data, offset, offset + 2)?);
-        let netuid: u16 = netuid_bytes[1] as u16 | ((netuid_bytes[0] as u16) << 8u16);
-
-        Ok(netuid)
+        Ok(())
     }
 }
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index 36f861d48..2701c67d3 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -1,11 +1,13 @@
-use crate::precompiles::{
-    contract_to_origin, get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call,
-};
+use crate::precompiles::{get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call};
 use crate::{Runtime, RuntimeCall};
-use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult};
+use frame_system::RawOrigin;
+use pallet_evm::{
+    AddressMapping, ExitError, HashedAddressMapping, PrecompileFailure, PrecompileHandle,
+    PrecompileResult,
+};
+use sp_runtime::traits::BlakeTwo256;
 use sp_runtime::AccountId32;
 use sp_std::vec;
-
 pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051;
 // bytes with max lenght 1K
 pub const MAX_SINGLE_PARAMETER_SIZE: usize = 1024;
@@ -51,7 +53,6 @@ impl SubnetPrecompile {
         let call = match data.len() {
             32 => {
                 let (hotkey, _) = get_pubkey(data)?;
-
                 RuntimeCall::SubtensorModule(
                     pallet_subtensor::Call::<Runtime>::register_network_with_identity {
                         hotkey,
@@ -85,8 +86,13 @@ impl SubnetPrecompile {
             }
         };
 
+        let account_id =
+            <HashedAddressMapping<BlakeTwo256> as AddressMapping<AccountId32>>::into_account_id(
+                handle.context().caller,
+            );
+
         // Dispatch the register_network call
-        try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)
+        try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id))
     }
 
     fn parse_register_network_parameters(

From cdfffaf05a816a9cfd84af2b15e76fe32388ad5d Mon Sep 17 00:00:00 2001
From: open-junius <zhou@opentensor.dev>
Date: Fri, 31 Jan 2025 00:22:16 +0800
Subject: [PATCH 142/145] fix clippy

---
 runtime/src/precompiles/staking.rs | 4 ++--
 runtime/src/precompiles/subnet.rs  | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs
index eefde3a37..8cc1c879a 100644
--- a/runtime/src/precompiles/staking.rs
+++ b/runtime/src/precompiles/staking.rs
@@ -83,7 +83,7 @@ impl StakingPrecompile {
 
         let (hotkey, _) = get_pubkey(data)?;
         let amount: U256 = handle.context().apparent_value;
-        let netuid = Self::parse_netuid(data, 0x3E)?;
+        let netuid = parse_netuid(data, 0x3E)?;
 
         if !amount.is_zero() {
             Self::transfer_back_to_caller(&account_id, amount)?;
@@ -108,7 +108,7 @@ impl StakingPrecompile {
                 handle.context().caller,
             );
         let (hotkey, _) = get_pubkey(data)?;
-        let netuid = Self::parse_netuid(data, 0x5E)?;
+        let netuid = parse_netuid(data, 0x5E)?;
 
         // We have to treat this as uint256 (because of Solidity ABI encoding rules, it pads uint64),
         // but this will never exceed 8 bytes, se we will ignore higher bytes and will only use lower
diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs
index 2701c67d3..9944572c5 100644
--- a/runtime/src/precompiles/subnet.rs
+++ b/runtime/src/precompiles/subnet.rs
@@ -16,6 +16,7 @@ pub const MAX_PARAMETER_SIZE: usize = 3 * MAX_SINGLE_PARAMETER_SIZE;
 
 // ss58 public key i.e., the contract sends funds it received to the destination address from the
 // method parameter.
+#[allow(dead_code)]
 const CONTRACT_ADDRESS_SS58: [u8; 32] = [
     0x3a, 0x86, 0x18, 0xfb, 0xbb, 0x1b, 0xbc, 0x47, 0x86, 0x64, 0xff, 0x53, 0x46, 0x18, 0x0c, 0x35,
     0xd0, 0x9f, 0xac, 0x26, 0xf2, 0x02, 0x70, 0x85, 0xb3, 0x1c, 0x56, 0xc1, 0x06, 0x3c, 0x1c, 0xd3,

From abec477dab48c06d13fbafaffca1afe6c3ed2c0d Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Thu, 30 Jan 2025 14:09:02 -0500
Subject: [PATCH 143/145] Validate slippage-safe staking extrinsics

---
 pallets/subtensor/src/lib.rs           |  42 ++++++++-
 pallets/subtensor/src/tests/staking.rs | 116 +++++++++++++++++++++++++
 2 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index d346b9241..d694d3d43 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -1783,7 +1783,7 @@ where
             }
             Some(Call::commit_crv3_weights { netuid, .. }) => {
                 if Self::check_weights_min_stake(who, *netuid) {
-                    let priority: u64 = Self::get_priority_set_weights(who, *netuid);
+                    let priority: u64 = Pallet::<T>::get_priority_set_weights(who, *netuid);
                     Ok(ValidTransaction {
                         priority,
                         longevity: 1,
@@ -1811,6 +1811,26 @@ where
                     false,
                 ))
             }
+            Some(Call::add_stake_limit {
+                hotkey,
+                netuid,
+                amount_staked,
+                limit_price,
+                allow_partial,
+            }) => {
+                // Calcaulate the maximum amount that can be executed with price limit
+                let max_amount = Pallet::<T>::get_max_amount_add(*netuid, *limit_price);
+
+                // Fully validate the user input
+                Self::result_to_validity(Pallet::<T>::validate_add_stake(
+                    who,
+                    hotkey,
+                    *netuid,
+                    *amount_staked,
+                    max_amount,
+                    *allow_partial,
+                ))
+            }
             Some(Call::remove_stake {
                 hotkey,
                 netuid,
@@ -1826,6 +1846,26 @@ where
                     false,
                 ))
             }
+            Some(Call::remove_stake_limit {
+                hotkey,
+                netuid,
+                amount_unstaked,
+                limit_price,
+                allow_partial,
+            }) => {
+                // Calcaulate the maximum amount that can be executed with price limit
+                let max_amount = Pallet::<T>::get_max_amount_remove(*netuid, *limit_price);
+
+                // Fully validate the user input
+                Self::result_to_validity(Pallet::<T>::validate_remove_stake(
+                    who,
+                    hotkey,
+                    *netuid,
+                    *amount_unstaked,
+                    max_amount,
+                    *allow_partial,
+                ))
+            }
             Some(Call::move_stake {
                 origin_hotkey,
                 destination_hotkey,
diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs
index 6a61008a3..3d2172692 100644
--- a/pallets/subtensor/src/tests/staking.rs
+++ b/pallets/subtensor/src/tests/staking.rs
@@ -2206,6 +2206,122 @@ fn test_stake_below_min_validate() {
     });
 }
 
+// cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_limit_validate --exact --show-output
+#[test]
+fn test_add_stake_limit_validate() {
+    // Testing the signed extension validate function
+    // correctly filters the `add_stake` transaction.
+
+    new_test_ext(0).execute_with(|| {
+        let hotkey = U256::from(533453);
+        let coldkey = U256::from(55453);
+        let amount = 300_000_000_000;
+
+        // add network
+        let netuid: u16 = add_dynamic_network(&hotkey, &coldkey);
+
+        // Force-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // Give it some $$$ in his coldkey balance
+        SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount);
+
+        // Setup limit price so that it doesn't peak above 4x of current price
+        // The amount that can be executed at this price is 150 TAO only
+        // Alpha produced will be equal to 50 = 100 - 150*100/300
+        let limit_price = 6_000_000_000;
+
+        // Add stake limit call
+        let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake_limit {
+            hotkey,
+            netuid,
+            amount_staked: amount,
+            limit_price,
+            allow_partial: false,
+        });
+
+        let info: crate::DispatchInfo =
+            crate::DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
+
+        let extension = crate::SubtensorSignedExtension::<Test>::new();
+        // Submit to the signed extension validate function
+        let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
+
+        // Should fail due to slippage
+        assert_err!(
+            result_no_stake,
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::SlippageTooHigh.into()
+            ))
+        );
+    });
+}
+
+// cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_stake_limit_validate --exact --show-output
+#[test]
+fn test_remove_stake_limit_validate() {
+    // Testing the signed extension validate function
+    // correctly filters the `add_stake` transaction.
+
+    new_test_ext(0).execute_with(|| {
+        let hotkey = U256::from(533453);
+        let coldkey = U256::from(55453);
+        let stake_amount = 300_000_000_000;
+        let unstake_amount = 150_000_000_000;
+
+        // add network
+        let netuid: u16 = add_dynamic_network(&hotkey, &coldkey);
+
+        // Give the neuron some stake to remove
+        SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
+            &hotkey,
+            &coldkey,
+            netuid,
+            stake_amount,
+        );
+
+        // Forse-set alpha in and tao reserve to make price equal 1.5
+        let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
+        let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
+        SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
+        SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
+        let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
+        assert_eq!(current_price, U96F32::from_num(1.5));
+
+        // Setup limit price so that it doesn't drop by more than 10% from current price
+        let limit_price = 1_350_000_000;
+
+        // Remove stake limit call
+        let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake_limit {
+            hotkey,
+            netuid,
+            amount_unstaked: unstake_amount,
+            limit_price,
+            allow_partial: false,
+        });
+
+        let info: crate::DispatchInfo =
+            crate::DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
+
+        let extension = crate::SubtensorSignedExtension::<Test>::new();
+        // Submit to the signed extension validate function
+        let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
+
+        // Should fail due to slippage
+        assert_err!(
+            result_no_stake,
+            crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
+                CustomTransactionError::SlippageTooHigh.into()
+            ))
+        );
+    });
+}
+
 #[test]
 fn test_stake_overflow() {
     new_test_ext(1).execute_with(|| {

From 5bc7f9ca0b99150e98d8937aac0094d1465a5e3c Mon Sep 17 00:00:00 2001
From: Sam Johnson <sam@durosoft.com>
Date: Thu, 30 Jan 2025 15:57:25 -0500
Subject: [PATCH 144/145] fix some CI actions not triggering on newly opened
 pull request

---
 .github/workflows/check-devnet.yml   | 2 +-
 .github/workflows/check-finney.yml   | 2 +-
 .github/workflows/check-testnet.yml  | 2 +-
 .github/workflows/label-triggers.yml | 3 +++
 4 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/check-devnet.yml b/.github/workflows/check-devnet.yml
index c7f39082e..13ebf89cc 100644
--- a/.github/workflows/check-devnet.yml
+++ b/.github/workflows/check-devnet.yml
@@ -3,7 +3,7 @@ name: Devnet Deploy Check
 on:
   pull_request:
     branches: [devnet, devnet-ready]
-    types: [labeled, unlabeled, synchronize]
+    types: [labeled, unlabeled, synchronize, opened]
 
 env:
   CARGO_TERM_COLOR: always
diff --git a/.github/workflows/check-finney.yml b/.github/workflows/check-finney.yml
index 292bae7ee..98f90fc8e 100644
--- a/.github/workflows/check-finney.yml
+++ b/.github/workflows/check-finney.yml
@@ -3,7 +3,7 @@ name: Finney Deploy Check
 on:
   pull_request:
     branches: [finney, main]
-    types: [labeled, unlabeled, synchronize]
+    types: [labeled, unlabeled, synchronize, opened]
 
 env:
   CARGO_TERM_COLOR: always
diff --git a/.github/workflows/check-testnet.yml b/.github/workflows/check-testnet.yml
index 03c7e8f8a..7c8532ec5 100644
--- a/.github/workflows/check-testnet.yml
+++ b/.github/workflows/check-testnet.yml
@@ -3,7 +3,7 @@ name: Testnet Deploy Check
 on:
   pull_request:
     branches: [testnet, testnet-ready]
-    types: [labeled, unlabeled, synchronize]
+    types: [labeled, unlabeled, synchronize, opened]
 
 env:
   CARGO_TERM_COLOR: always
diff --git a/.github/workflows/label-triggers.yml b/.github/workflows/label-triggers.yml
index d32396e07..f3c330f85 100644
--- a/.github/workflows/label-triggers.yml
+++ b/.github/workflows/label-triggers.yml
@@ -3,6 +3,9 @@ on:
   pull_request:
     types:
       - labeled
+      - unlabeled
+      - synchronize
+      - opened
 
 permissions:
   issues: write

From 645689dd4413e6dc9382960c87a19d9c9de67ce0 Mon Sep 17 00:00:00 2001
From: Greg Zaitsev <gregz@opentensor.dev>
Date: Thu, 30 Jan 2025 17:09:40 -0500
Subject: [PATCH 145/145] Double-size SubnetVolume to u128

---
 pallets/subtensor/src/lib.rs                   | 7 ++++++-
 pallets/subtensor/src/rpc_info/dynamic_info.rs | 4 ++--
 pallets/subtensor/src/rpc_info/metagraph.rs    | 4 ++--
 pallets/subtensor/src/staking/stake_utils.rs   | 8 ++++----
 4 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs
index 56646f857..f789d8191 100644
--- a/pallets/subtensor/src/lib.rs
+++ b/pallets/subtensor/src/lib.rs
@@ -234,6 +234,11 @@ pub mod pallet {
     }
     #[pallet::type_value]
     /// Default value for zero.
+    pub fn DefaultZeroU128<T: Config>() -> u128 {
+        0
+    }
+    #[pallet::type_value]
+    /// Default value for zero.
     pub fn DefaultZeroU16<T: Config>() -> u16 {
         0
     }
@@ -907,7 +912,7 @@ pub mod pallet {
     pub type DynamicBlock<T> = StorageValue<_, u64, ValueQuery>;
     #[pallet::storage] // --- MAP ( netuid ) --> total_volume | The total amount of TAO bought and sold since the start of the network.
     pub type SubnetVolume<T: Config> =
-        StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
+        StorageMap<_, Identity, u16, u128, ValueQuery, DefaultZeroU128<T>>;
     #[pallet::storage] // --- MAP ( netuid ) --> tao_in_subnet | Returns the amount of TAO in the subnet.
     pub type SubnetTAO<T: Config> =
         StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64<T>>;
diff --git a/pallets/subtensor/src/rpc_info/dynamic_info.rs b/pallets/subtensor/src/rpc_info/dynamic_info.rs
index bbee27c55..27d10dc2d 100644
--- a/pallets/subtensor/src/rpc_info/dynamic_info.rs
+++ b/pallets/subtensor/src/rpc_info/dynamic_info.rs
@@ -4,7 +4,7 @@ use codec::Compact;
 use frame_support::pallet_prelude::{Decode, Encode};
 use subtensor_macros::freeze_struct;
 
-#[freeze_struct("1be5a1e26a82082f")]
+#[freeze_struct("a5cdc80d655398e9")]
 #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
 pub struct DynamicInfo<T: Config> {
     netuid: Compact<u16>,
@@ -24,7 +24,7 @@ pub struct DynamicInfo<T: Config> {
     tao_in_emission: Compact<u64>,
     pending_alpha_emission: Compact<u64>,
     pending_root_emission: Compact<u64>,
-    subnet_volume: Compact<u64>,
+    subnet_volume: Compact<u128>,
     network_registered_at: Compact<u64>,
     subnet_identity: Option<SubnetIdentity>,
 }
diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs
index ee3864932..267af1d05 100644
--- a/pallets/subtensor/src/rpc_info/metagraph.rs
+++ b/pallets/subtensor/src/rpc_info/metagraph.rs
@@ -6,7 +6,7 @@ use frame_support::pallet_prelude::{Decode, Encode};
 use substrate_fixed::types::I64F64;
 use subtensor_macros::freeze_struct;
 
-#[freeze_struct("fa24d156067e5eb9")]
+#[freeze_struct("7c5fe907490c5d5e")]
 #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
 pub struct Metagraph<T: Config> {
     // Subnet index
@@ -38,7 +38,7 @@ pub struct Metagraph<T: Config> {
     tao_in_emission: Compact<u64>,        // amount of tao injected per block
     pending_alpha_emission: Compact<u64>, // pending alpha to be distributed
     pending_root_emission: Compact<u64>,  // panding tao for root divs to be distributed
-    subnet_volume: Compact<u64>,          // volume of the subnet in TAO
+    subnet_volume: Compact<u128>,         // volume of the subnet in TAO
 
     // Hparams for epoch
     rho: Compact<u16>,   // subnet rho param
diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs
index 4c446947f..147490dd8 100644
--- a/pallets/subtensor/src/staking/stake_utils.rs
+++ b/pallets/subtensor/src/staking/stake_utils.rs
@@ -557,9 +557,9 @@ impl<T: Config> Pallet<T> {
             TotalStake::<T>::mutate(|total| {
                 *total = total.saturating_add(tao);
             });
-            // Step 8. Decrease Alpha reserves.
+            // Step 8. Increase total subnet TAO volume.
             SubnetVolume::<T>::mutate(netuid, |total| {
-                *total = total.saturating_add(tao);
+                *total = total.saturating_add(tao.into());
             });
             // Step 9. Return the alpha received.
             alpha
@@ -589,9 +589,9 @@ impl<T: Config> Pallet<T> {
             TotalStake::<T>::mutate(|total| {
                 *total = total.saturating_sub(tao);
             });
-            // Step 8. Decrease Alpha reserves.
+            // Step 8. Increase total subnet TAO volume.
             SubnetVolume::<T>::mutate(netuid, |total| {
-                *total = total.saturating_add(tao);
+                *total = total.saturating_add(tao.into());
             });
             // Step 9. Return the tao received.
             tao