diff --git a/runtime/src/precompiles/solidity/staking.abi b/runtime/src/precompiles/solidity/staking.abi index a3c51ea45..82583543d 100644 --- a/runtime/src/precompiles/solidity/staking.abi +++ b/runtime/src/precompiles/solidity/staking.abi @@ -18,28 +18,33 @@ "type": "function" }, { - inputs: [ - { - internalType: "bytes32", - name: "hotkey", - type: "bytes32", - }, - { - internalType: "bytes32", - name: "coldkey", - type: "bytes32", - }, + "inputs": [ + { + "internalType": "bytes32", + "name": "hotkey", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "coldkey", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "netuid", + "type": "uint256" + } ], - name: "getStake", - outputs: [ - { - internalType: "uint64", - name: "", - type: "uint64", - }, + "name": "getStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } ], - stateMutability: "view", - type: "function", + "stateMutability": "view", + "type": "function" }, { "inputs": [ @@ -64,4 +69,4 @@ "stateMutability": "nonpayable", "type": "function" } -] +] \ No newline at end of file diff --git a/runtime/src/precompiles/solidity/staking.sol b/runtime/src/precompiles/solidity/staking.sol index ce62b4326..7c80d53e0 100644 --- a/runtime/src/precompiles/solidity/staking.sol +++ b/runtime/src/precompiles/solidity/staking.sol @@ -14,7 +14,7 @@ interface IStaking { * 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 (uint256). Currently a noop, functionality will be enabled with RAO. + * @param netuid The subnet to stake to (uint256). * * Requirements: * - `hotkey` must be a valid hotkey registered on the network, ensuring that the stake is @@ -33,8 +33,7 @@ interface IStaking { * * @param hotkey The hotkey public key (32 bytes). * @param amount The amount to unstake in rao. - * @param netuid The subnet to stake to (uint256). Currently a noop, functionality will be enabled with RAO. - + * @param netuid The subnet to stake to (uint256). * * Requirements: * - `hotkey` must be a valid hotkey registered on the network, ensuring that the stake is @@ -42,4 +41,17 @@ interface IStaking { * - The existing stake amount must be not lower than specified amount */ function removeStake(bytes32 hotkey, uint256 amount, uint256 netuid) external; + + /** + * @dev Returns the stake amount associated with the specified `hotkey` and `coldkey`. + * + * This function retrieves the current stake amount linked to a specific hotkey and coldkey pair. + * It is a view function, meaning it does not modify the state of the contract and is free to call. + * + * @param hotkey The hotkey public key (32 bytes). + * @param coldkey The coldkey public key (32 bytes). + * @param netuid The subnet the stake is on (uint256). + * @return The current stake amount in uint256 format. + */ + function getStake(bytes32 hotkey, bytes32 coldkey, uint256 netuid) external view returns (uint256); } diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 0be8bf240..bee4b30d1 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,uint256)") => { Self::remove_stake(handle, &method_input) } + id if id == get_method_id("getStake(bytes32,bytes32,uint256)") => { + Self::get_stake(&method_input) + } _ => Err(PrecompileFailure::Error { exit_status: ExitError::InvalidRange, }), @@ -107,6 +110,45 @@ impl StakingPrecompile { Self::dispatch(handle, call) } + fn get_stake(data: &[u8]) -> PrecompileResult { + let (hotkey, coldkey) = Self::parse_hotkey_coldkey(data)?; + let netuid = Self::parse_netuid(data, 0x5E)?; + + let stake = pallet_subtensor::Pallet::::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey.into(), + &coldkey.into(), + netuid, + ); + + // Convert to EVM decimals + let stake_u256 = U256::from(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(&stake_eth, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + 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_hotkey(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> { if data.len() < 32 { return Err(PrecompileFailure::Error {