From cd366c5f7d169ecbeaec456c110cfd9dd273d60b Mon Sep 17 00:00:00 2001 From: shr1ftyy Date: Tue, 14 Jan 2025 17:30:54 +0600 Subject: [PATCH 1/8] feat: added getStakeColdkey to staking precompile --- runtime/src/precompiles/solidity/staking.abi | 19 +++++++++++++++++++ runtime/src/precompiles/solidity/staking.sol | 12 ++++++++++++ runtime/src/precompiles/staking.rs | 19 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/runtime/src/precompiles/solidity/staking.abi b/runtime/src/precompiles/solidity/staking.abi index 44b1829c40..07e4a5f560 100644 --- a/runtime/src/precompiles/solidity/staking.abi +++ b/runtime/src/precompiles/solidity/staking.abi @@ -39,5 +39,24 @@ "outputs": [], "stateMutability": "payable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "coldkey", + "type": "bytes32" + } + ], + "name": "getStakeColdkey", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" } ] diff --git a/runtime/src/precompiles/solidity/staking.sol b/runtime/src/precompiles/solidity/staking.sol index ec7fb72974..d7c83007a5 100644 --- a/runtime/src/precompiles/solidity/staking.sol +++ b/runtime/src/precompiles/solidity/staking.sol @@ -42,4 +42,16 @@ interface IStaking { * - The existing stake amount must be not lower than specified amount */ function removeStake(bytes32 hotkey, uint256 amount, uint16 netuid) external; + + /** + * @dev Returns the amount of RAO staked by the coldkey associated with the hotkey. + * + * This function allows external accounts and contracts to query the amount of RAO staked by the coldkey + * associated with the coldkey, which effectively calls `get_coldkey_stake` on the subtensor pallet with + * specified coldkey as a parameter. + * + * @param coldkey The coldkey public key (32 bytes). + * @return The amount of RAO staked by the coldkey associated with the hotkey. + */ + function getStakeColdkey(bytes32 coldkey) external view returns (uint256); } diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index bf930005bd..7bb160a62c 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -59,6 +59,9 @@ impl StakingPrecompile { id if id == get_method_id("removeStake(bytes32,uint256,uint16)") => { Self::remove_stake(handle, &method_input) } + id if id == get_method_id("getStakeColdkey(bytes32)") => { + Self::get_stake_coldkey(&method_input) + } _ => Err(PrecompileFailure::Error { exit_status: ExitError::InvalidRange, }), @@ -110,6 +113,22 @@ impl StakingPrecompile { Self::dispatch(handle, call) } + fn get_stake_coldkey(data: &[u8]) -> PrecompileResult { + // TODO: rename parse_hotkey to parse_key or something? + let coldkey: AccountId32 = Self::parse_hotkey(data)?.into(); + + // get total stake of coldkey + let total_stake = pallet_subtensor::TotalColdkeyStake::::get(coldkey); + let result_u256 = U256::from(total_stake); + let mut result = [0_u8; 32]; + U256::to_big_endian(&result_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + fn parse_hotkey(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> { if data.len() < 32 { return Err(PrecompileFailure::Error { From 54f1d33e9802803a11bb273e72f8cb1715786892 Mon Sep 17 00:00:00 2001 From: shr1ftyy Date: Wed, 15 Jan 2025 09:21:52 +0600 Subject: [PATCH 2/8] chore: rename parse_hotkey to parse_ss58 --- runtime/src/precompiles/staking.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 7bb160a62c..13a3500b3d 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -69,7 +69,7 @@ impl StakingPrecompile { } fn add_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let hotkey = Self::parse_hotkey(data)?.into(); + let hotkey = Self::parse_ss58(data)?.into(); let amount: U256 = handle.context().apparent_value; // TODO: Use netuid method parameter here @@ -89,7 +89,7 @@ impl StakingPrecompile { Self::dispatch(handle, call) } fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let hotkey = Self::parse_hotkey(data)?.into(); + let hotkey = Self::parse_ss58(data)?.into(); // TODO: Use netuid method parameter here let netuid: u16 = 0; @@ -114,8 +114,8 @@ impl StakingPrecompile { } fn get_stake_coldkey(data: &[u8]) -> PrecompileResult { - // TODO: rename parse_hotkey to parse_key or something? - let coldkey: AccountId32 = Self::parse_hotkey(data)?.into(); + // TODO: rename parse_ss58 to parse_key or something? + let coldkey: AccountId32 = Self::parse_ss58(data)?.into(); // get total stake of coldkey let total_stake = pallet_subtensor::TotalColdkeyStake::::get(coldkey); @@ -129,7 +129,7 @@ impl StakingPrecompile { }) } - fn parse_hotkey(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> { + fn parse_ss58(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> { if data.len() < 32 { return Err(PrecompileFailure::Error { exit_status: ExitError::InvalidRange, From 080363bfd893fe77a5eab3180c8d69679466b3df Mon Sep 17 00:00:00 2001 From: shr1ftyy Date: Tue, 21 Jan 2025 10:30:55 +0600 Subject: [PATCH 3/8] feat: some func signature changes + hotkey stake --- runtime/src/precompiles/solidity/staking.abi | 21 +++++++++++++++++- runtime/src/precompiles/solidity/staking.sol | 16 ++++++++++++-- runtime/src/precompiles/staking.rs | 23 +++++++++++++++++--- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/runtime/src/precompiles/solidity/staking.abi b/runtime/src/precompiles/solidity/staking.abi index 795b29baaf..f06dfb651b 100644 --- a/runtime/src/precompiles/solidity/staking.abi +++ b/runtime/src/precompiles/solidity/staking.abi @@ -103,7 +103,26 @@ "type": "bytes32" } ], - "name": "getStakeColdkey", + "name": "getTotalColdkeyStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hotkey", + "type": "bytes32" + } + ], + "name": "getTotalHotkeyStake", "outputs": [ { "internalType": "uint256", diff --git a/runtime/src/precompiles/solidity/staking.sol b/runtime/src/precompiles/solidity/staking.sol index 596443c04c..67f57ff670 100644 --- a/runtime/src/precompiles/solidity/staking.sol +++ b/runtime/src/precompiles/solidity/staking.sol @@ -46,13 +46,25 @@ interface IStaking { * @dev Returns the amount of RAO staked by the coldkey. * * This function allows external accounts and contracts to query the amount of RAO staked by the coldkey - * which effectively calls `get_coldkey_stake` on the subtensor pallet with + * which effectively calls `get_total_coldkey_stake` on the subtensor pallet with * specified coldkey as a parameter. * * @param coldkey The coldkey public key (32 bytes). * @return The amount of RAO staked by the coldkey. */ - function getStakeColdkey(bytes32 coldkey) external view returns (uint256); + function getTotalColdkeyStake(bytes32 coldkey) external view returns (uint256); + + /** + * @dev Returns the total amount of stake under a hotkey (delegative or otherwise) + * + * This function allows external accounts and contracts to query the total amount of RAO staked under a hotkey + * which effectively calls `get_total_hotkey_stake` on the subtensor pallet with + * specified hotkey as a parameter. + * + * @param hotkey The hotkey public key (32 bytes). + * @return The total amount of RAO staked under the hotkey. + */ + function getTotalHotkeyStake(bytes32 hotkey) external view returns (uint256); /** * @dev Delegates staking to a proxy account. diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 193c4bbc6a..4fdf410125 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -61,8 +61,10 @@ impl StakingPrecompile { Self::remove_stake(handle, &method_input) } else if method_id == get_method_id("getStake(bytes32,bytes32,uint256)") { Self::get_stake(&method_input) - } else if method_id == get_method_id("getStakeColdkey(bytes32)") { - Self::get_stake_coldkey(&method_input) + } else if method_id == get_method_id("getTotalColdkeyStake(bytes32)") { + Self::get_total_coldkey_stake(&method_input) + } else if method_id == get_method_id("getTotalHotkeyStake(bytes32)") { + Self::get_total_hotkey_stake(&method_input) } else if method_id == get_method_id("addProxy(bytes32)") { Self::add_proxy(handle, &method_input) } else if method_id == get_method_id("removeProxy(bytes32)") { @@ -116,7 +118,7 @@ impl StakingPrecompile { Self::dispatch(handle, call) } - fn get_stake_coldkey(data: &[u8]) -> PrecompileResult { + fn get_total_coldkey_stake(data: &[u8]) -> PrecompileResult { let coldkey: AccountId32 = Self::parse_pub_key(data)?.into(); // get total stake of coldkey @@ -131,6 +133,21 @@ impl StakingPrecompile { }) } + fn get_total_hotkey_stake(data: &[u8]) -> PrecompileResult { + let hotkey: AccountId32 = Self::parse_pub_key(data)?.into(); + + // get total stake of hotkey + let total_stake = pallet_subtensor::Pallet::::get_total_stake_for_hotkey(&hotkey); + let result_u256 = U256::from(total_stake); + let mut result = [0_u8; 32]; + U256::to_big_endian(&result_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + fn add_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { let delegate = AccountId32::from(Self::parse_pub_key(data)?); let delegate = ::Lookup::unlookup(delegate); From 573a7b1e953377f51627e3b19685a450fd93a397 Mon Sep 17 00:00:00 2001 From: shr1ftyy Date: Thu, 23 Jan 2025 00:38:21 +0600 Subject: [PATCH 4/8] chore: netuid should be uint256 --- runtime/src/precompiles/solidity/staking.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/precompiles/solidity/staking.sol b/runtime/src/precompiles/solidity/staking.sol index 67f57ff670..bd26530b03 100644 --- a/runtime/src/precompiles/solidity/staking.sol +++ b/runtime/src/precompiles/solidity/staking.sol @@ -40,7 +40,7 @@ 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, uint256 netuid) external; /** * @dev Returns the amount of RAO staked by the coldkey. From 3de9c3d3ade11822f21332117a9f2a3f3e00afc0 Mon Sep 17 00:00:00 2001 From: shr1ftyy Date: Mon, 27 Jan 2025 11:32:18 +0600 Subject: [PATCH 5/8] feat: modify total stake coldkey func - gets stake for coldkey on subnet and across all subnets --- pallets/subtensor/src/staking/stake_utils.rs | 63 ++++++++++++++++++++ runtime/src/precompiles/staking.rs | 25 ++++++-- 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 524cd2069b..20693fda1a 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -379,6 +379,69 @@ impl Pallet { TotalHotkeyAlpha::::get(hotkey, netuid) } + /// Retrieves the total stake (alpha) for a given coldkey on a specific sunbet. + /// + /// This function performs the following steps: + /// 1. Retrieves the list of hotkeys associated with the coldkey on the subnet. + /// 2. Iterates through the list of hotkeys and retrieves the alpha stake for each hotkey. + /// 3. Sums the alpha stakes for all hotkeys to calculate the total stake for the coldkey. + /// 4. Returns the total alpha stake for the coldkey on the subnet. + /// + /// # Arguments + /// * `coldkey` - The account ID of the coldkey. + /// * `netuid` - The unique identifier of the subnet. + /// + /// # Returns + /// * `u64` - The total alpha value for the coldkey on the specified subnet. + /// + /// # Note + /// This function returns the cumulative stake across all hotkeys associated with this coldkey on the subnet. + /// This value represents the sum of stakes from all hotkeys associated with this coldkey. + pub fn get_stake_for_coldkey_on_subnet(coldkey: &T::AccountId, netuid: u16) -> u64 { + // Retrieve the list of hotkeys associated with the coldkey on the subnet. + let hotkeys: Vec = StakingHotkeys::::get(coldkey); + + // Calculate the total alpha stake for the coldkey on the subnet. + let total_stake: u64 = hotkeys + .iter() + .map(|hotkey| Self::get_stake_for_hotkey_on_subnet(hotkey, netuid)) + .sum(); + + // Return the total alpha stake for the coldkey on the subnet. + total_stake + } + + /// Retrieves the total stake (alpha) for a given coldkey across all subnets + /// + /// This function performs the following steps: + /// 1. Retrieves the list of subnets associated with the coldkey. + /// 2. Iterates through the list of subnets and retrieves the alpha stake for each subnet. + /// 3. Sums the alpha stakes for all subnets to calculate the total stake for the coldkey. + /// 4. Returns the total alpha stake for the coldkey across all subnets. + /// + /// # Arguments + /// * `coldkey` - The account ID of the coldkey. + /// + /// # Returns + /// * `u64` - The total alpha value for the coldkey across all subnets. + /// + /// # Note + /// This function returns the cumulative stake across all subnets for the coldkey. + /// This value represents the sum of stakes from all subnets associated with this coldkey. + /// This function is useful for calculating the total stake for a coldkey across all subnets. + pub fn get_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { + // get number of subnets + let netuids = Self::get_all_subnet_netuids(); + + // Calculate the total alpha stake for the coldkey across all subnets. + let total_stake: u64 = netuids + .iter() + .map(|netuid| Self::get_stake_for_coldkey_on_subnet(coldkey, *netuid)) + .sum(); + // Return the total alpha stake for the coldkey across all subnets. + total_stake + } + /// Increase hotkey stake on a subnet. /// /// The function updates share totals given current prices. diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 4fdf410125..6e0c423a57 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -118,14 +118,21 @@ impl StakingPrecompile { Self::dispatch(handle, call) } - fn get_total_coldkey_stake(data: &[u8]) -> PrecompileResult { + fn get_total_coldkey_stake(data: &[u8]) -> PrecompileResult { let coldkey: AccountId32 = Self::parse_pub_key(data)?.into(); // get total stake of coldkey - let total_stake = pallet_subtensor::Pallet::::get_total_stake_for_coldkey(&coldkey); - let result_u256 = U256::from(total_stake); + // TODO: is using the function that was written for this purpose in the pallet the right way to go about this? + let total_stake = pallet_subtensor::Pallet::::get_stake_for_coldkey(&coldkey); + // Convert to EVM decimals + let stake_u256 = U256::from(total_stake); + let stake_eth = + ::BalanceConverter::into_evm_balance(stake_u256) + .ok_or(ExitError::InvalidRange)?; + + // Format output let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); + U256::to_big_endian(&stake_eth, &mut result); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, @@ -138,9 +145,15 @@ impl StakingPrecompile { // get total stake of hotkey let total_stake = pallet_subtensor::Pallet::::get_total_stake_for_hotkey(&hotkey); - let result_u256 = U256::from(total_stake); + // Convert to EVM decimals + let stake_u256 = U256::from(total_stake); + let stake_eth = + ::BalanceConverter::into_evm_balance(stake_u256) + .ok_or(ExitError::InvalidRange)?; + + // Format output let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); + U256::to_big_endian(&stake_eth, &mut result); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, From 6d65d4b7aaec8d297371f742aff5f4e85416e775 Mon Sep 17 00:00:00 2001 From: shr1ftyy Date: Fri, 31 Jan 2025 19:25:53 +0600 Subject: [PATCH 6/8] fix: use correct coldkey stake helper --- pallets/subtensor/src/staking/stake_utils.rs | 63 -------------------- runtime/src/precompiles/staking.rs | 4 +- 2 files changed, 2 insertions(+), 65 deletions(-) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 20693fda1a..524cd2069b 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -379,69 +379,6 @@ impl Pallet { TotalHotkeyAlpha::::get(hotkey, netuid) } - /// Retrieves the total stake (alpha) for a given coldkey on a specific sunbet. - /// - /// This function performs the following steps: - /// 1. Retrieves the list of hotkeys associated with the coldkey on the subnet. - /// 2. Iterates through the list of hotkeys and retrieves the alpha stake for each hotkey. - /// 3. Sums the alpha stakes for all hotkeys to calculate the total stake for the coldkey. - /// 4. Returns the total alpha stake for the coldkey on the subnet. - /// - /// # Arguments - /// * `coldkey` - The account ID of the coldkey. - /// * `netuid` - The unique identifier of the subnet. - /// - /// # Returns - /// * `u64` - The total alpha value for the coldkey on the specified subnet. - /// - /// # Note - /// This function returns the cumulative stake across all hotkeys associated with this coldkey on the subnet. - /// This value represents the sum of stakes from all hotkeys associated with this coldkey. - pub fn get_stake_for_coldkey_on_subnet(coldkey: &T::AccountId, netuid: u16) -> u64 { - // Retrieve the list of hotkeys associated with the coldkey on the subnet. - let hotkeys: Vec = StakingHotkeys::::get(coldkey); - - // Calculate the total alpha stake for the coldkey on the subnet. - let total_stake: u64 = hotkeys - .iter() - .map(|hotkey| Self::get_stake_for_hotkey_on_subnet(hotkey, netuid)) - .sum(); - - // Return the total alpha stake for the coldkey on the subnet. - total_stake - } - - /// Retrieves the total stake (alpha) for a given coldkey across all subnets - /// - /// This function performs the following steps: - /// 1. Retrieves the list of subnets associated with the coldkey. - /// 2. Iterates through the list of subnets and retrieves the alpha stake for each subnet. - /// 3. Sums the alpha stakes for all subnets to calculate the total stake for the coldkey. - /// 4. Returns the total alpha stake for the coldkey across all subnets. - /// - /// # Arguments - /// * `coldkey` - The account ID of the coldkey. - /// - /// # Returns - /// * `u64` - The total alpha value for the coldkey across all subnets. - /// - /// # Note - /// This function returns the cumulative stake across all subnets for the coldkey. - /// This value represents the sum of stakes from all subnets associated with this coldkey. - /// This function is useful for calculating the total stake for a coldkey across all subnets. - pub fn get_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { - // get number of subnets - let netuids = Self::get_all_subnet_netuids(); - - // Calculate the total alpha stake for the coldkey across all subnets. - let total_stake: u64 = netuids - .iter() - .map(|netuid| Self::get_stake_for_coldkey_on_subnet(coldkey, *netuid)) - .sum(); - // Return the total alpha stake for the coldkey across all subnets. - total_stake - } - /// Increase hotkey stake on a subnet. /// /// The function updates share totals given current prices. diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 6e0c423a57..b0d186a2b4 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -122,8 +122,8 @@ impl StakingPrecompile { let coldkey: AccountId32 = Self::parse_pub_key(data)?.into(); // get total stake of coldkey - // TODO: is using the function that was written for this purpose in the pallet the right way to go about this? - let total_stake = pallet_subtensor::Pallet::::get_stake_for_coldkey(&coldkey); + let total_stake = + pallet_subtensor::Pallet::::get_total_stake_for_coldkey(&coldkey); // Convert to EVM decimals let stake_u256 = U256::from(total_stake); let stake_eth = From cd768921deb079d69a36bbc3799e890309a24ef9 Mon Sep 17 00:00:00 2001 From: shr1ftyy Date: Tue, 25 Feb 2025 22:05:41 +1030 Subject: [PATCH 7/8] chore: fmt --- runtime/src/precompiles/staking.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index f8f6310730..4cc5b5e835 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -91,7 +91,10 @@ impl StakingPrecompile { } #[precompile::public("getTotalColdkeyStake(bytes32)")] - fn get_total_coldkey_stake(_handle: &mut impl PrecompileHandle, coldkey_h256: H256) -> EvmResult { + fn get_total_coldkey_stake( + _handle: &mut impl PrecompileHandle, + coldkey_h256: H256, + ) -> EvmResult { let (coldkey, _) = parse_pubkey(coldkey_h256.as_bytes())?; // get total stake of coldkey @@ -107,7 +110,10 @@ impl StakingPrecompile { } #[precompile::public("getTotalHotkeyStake(bytes32)")] - fn get_total_hotkey_stake(_handle: &mut impl PrecompileHandle, hotkey_h256: H256) -> EvmResult { + fn get_total_hotkey_stake( + _handle: &mut impl PrecompileHandle, + hotkey_h256: H256, + ) -> EvmResult { let (hotkey, _) = parse_pubkey(hotkey_h256.as_bytes())?; // get total stake of hotkey From 0cdc9cb1d870d3fd05ca12cb25e91c7eb3b9ea23 Mon Sep 17 00:00:00 2001 From: Syeam Bin Abdullah <49330057+Shr1ftyy@users.noreply.github.com> Date: Tue, 25 Feb 2025 23:11:55 +1030 Subject: [PATCH 8/8] chore: bump spec version to 245 --- 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 a8774795b9..11ca6d6d03 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -228,7 +228,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: 244, + spec_version: 245, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,