diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index e13516e95..8f726a251 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -3,23 +3,37 @@ 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 metagraph; mod staking; +mod subnet; use balance_transfer::*; use ed25519::*; use metagraph::*; use staking::*; +use subnet::*; pub struct FrontierPrecompiles(PhantomData); @@ -39,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), @@ -51,6 +65,7 @@ where hash(EDVERIFY_PRECOMPILE_INDEX), hash(BALANCE_TRANSFER_INDEX), hash(STAKING_PRECOMPILE_INDEX), + hash(SUBNET_PRECOMPILE_INDEX), hash(METAGRAPH_PRECOMPILE_INDEX), ] } @@ -76,6 +91,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)), a if a == hash(METAGRAPH_PRECOMPILE_INDEX) => { Some(MetagraphPrecompile::execute(handle)) } @@ -125,8 +141,91 @@ 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, }) } } + +/// The function return the token to smart contract +fn transfer_back_to_caller( + smart_contract_address: &str, + account_id: &AccountId32, + amount: U256, +) -> Result<(), PrecompileFailure> { + 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 = + ::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::::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 = + as AddressMapping>::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()), + }), + } +} diff --git a/runtime/src/precompiles/solidity/subnet.abi b/runtime/src/precompiles/solidity/subnet.abi new file mode 100644 index 000000000..d930d0b88 --- /dev/null +++ b/runtime/src/precompiles/solidity/subnet.abi @@ -0,0 +1,858 @@ +[ + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getAdjustmentAlpha", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getAlphaValues", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getBondsMovingAverage", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getCommitRevealWeightsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getDifficulty", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "name": "getImmunityPeriod", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "name": "getKappa", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMaxBurn", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMaxDifficulty", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMaxWeightLimit", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMinAllowedWeights", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMinBurn", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMinDifficulty", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getNetworkRegistrationAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "name": "getRho", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getServingRateLimit", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getWeightsSetRateLimit", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getWeightsVersionKey", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "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" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "activityCutoff", + "type": "uint16" + } + ], + "name": "setActivityCutoff", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getActivityCutoff", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "adjustmentAlpha", + "type": "uint64" + } + ], + "name": "setAdjustmentAlpha", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "alphaLow", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "alphaHigh", + "type": "uint16" + } + ], + "name": "setAlphaValues", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "bondsMovingAverage", + "type": "uint64" + } + ], + "name": "setBondsMovingAverage", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "commitRevealWeightsEnabled", + "type": "bool" + } + ], + "name": "setCommitRevealWeightsEnabled", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getCommitRevealWeightsInterval", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "commitRevealWeightsInterval", + "type": "uint64" + } + ], + "name": "setCommitRevealWeightsInterval", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "difficulty", + "type": "uint64" + } + ], + "name": "setDifficulty", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "immunityPeriod", + "type": "uint64" + } + ], + "name": "setImmunityPeriod", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "kappa", + "type": "uint16" + } + ], + "name": "setKappa", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getLiquidAlphaEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "liquidAlphaEnabled", + "type": "bool" + } + ], + "name": "setLiquidAlphaEnabled", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "maxBurn", + "type": "uint64" + } + ], + "name": "setMaxBurn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "maxDifficulty", + "type": "uint64" + } + ], + "name": "setMaxDifficulty", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "maxWeightLimit", + "type": "uint64" + } + ], + "name": "setMaxWeightLimit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "minAllowedWeights", + "type": "uint16" + } + ], + "name": "setMinAllowedWeights", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "minBurn", + "type": "uint64" + } + ], + "name": "setMinBurn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "minDifficulty", + "type": "uint64" + } + ], + "name": "setMinDifficulty", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getNetworkPowRegistrationAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "networkPowRegistrationAllowed", + "type": "bool" + } + ], + "name": "setNetworkPowRegistrationAllowed", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "networkRegistrationAllowed", + "type": "bool" + } + ], + "name": "setNetworkRegistrationAllowed", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "rho", + "type": "uint16" + } + ], + "name": "setRho", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "servingRateLimit", + "type": "uint64" + } + ], + "name": "setServingRateLimit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "weightsSetRateLimit", + "type": "uint64" + } + ], + "name": "setWeightsSetRateLimit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "weightsVersionKey", + "type": "uint64" + } + ], + "name": "setWeightsVersionKey", + "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..5992c7535 --- /dev/null +++ b/runtime/src/precompiles/solidity/subnet.sol @@ -0,0 +1,98 @@ +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; + + function getServingRateLimit(uint16 netuid) external view returns (uint64); + + function setServingRateLimit(uint16 netuid, uint64 servingRateLimit) external payable; + + function getMinDifficulty(uint16 netuid) external view returns (uint64); + + function setMinDifficulty(uint16 netuid, uint64 minDifficulty) external payable; + + function getMaxDifficulty(uint16 netuid) external view returns (uint64); + + function setMaxDifficulty(uint16 netuid,uint64 maxDifficulty) external payable; + + function getWeightsVersionKey(uint16 netuid) external view returns (uint64); + + function setWeightsVersionKey(uint16 netuid, uint64 weightsVersionKey) external payable; + + function getWeightsSetRateLimit(uint16 netuid) external view returns (uint64); + + function setWeightsSetRateLimit(uint16 netuid, uint64 weightsSetRateLimit) external payable; + + function getAdjustmentAlpha(uint16 netuid) external view returns (uint64); + + function setAdjustmentAlpha(uint16 netuid, uint64 adjustmentAlpha) external payable; + + function getMaxWeightLimit(uint16 netuid) external view returns (uint64); + + function setMaxWeightLimit(uint16 netuid, uint64 maxWeightLimit) external payable; + + function getImmunityPeriod(uint16) external view returns (uint64); + + function setImmunityPeriod(uint16 netuid, uint64 immunityPeriod) external payable; + + function getMinAllowedWeights(uint16 netuid)external view returns (uint16); + + function setMinAllowedWeights(uint16 netuid, uint16 minAllowedWeights) external payable; + + function getKappa(uint16) external view returns (uint16); + + function setKappa(uint16 netuid, uint16 kappa) external payable; + + function getRho(uint16) external view returns (uint16); + + function setRho(uint16 netuid, uint16 rho) external payable; + + function getActivityCutoff(uint16 netuid) external view returns (uint16); + + function setActivityCutoff(uint16 netuid, uint16 activityCutoff) external payable; + + function getNetworkRegistrationAllowed(uint16 netuid) external view returns (bool); + + function setNetworkRegistrationAllowed(uint16 netuid, bool networkRegistrationAllowed) external payable; + + function getNetworkPowRegistrationAllowed(uint16 netuid) external view returns (bool); + + function setNetworkPowRegistrationAllowed(uint16 netuid, bool networkPowRegistrationAllowed) external payable; + + function getMinBurn(uint16 netuid) external view returns (uint64); + + function setMinBurn(uint16 netuid, uint64 minBurn) external payable; + + function getMaxBurn(uint16 netuid) external view returns (uint64); + + function setMaxBurn(uint16 netuid, uint64 maxBurn) external payable; + + function getDifficulty(uint16 netuid) external view returns (uint64); + + function setDifficulty(uint16 netuid, uint64 difficulty) external payable; + + function getBondsMovingAverage(uint16 netuid) external view returns (uint64); + + function setBondsMovingAverage(uint16 netuid, uint64 bondsMovingAverage) external payable; + + function getCommitRevealWeightsEnabled(uint16 netuid) external view returns (bool); + + function setCommitRevealWeightsEnabled(uint16 netuid, bool commitRevealWeightsEnabled) external payable; + + function getLiquidAlphaEnabled(uint16 netuid) external view returns (bool); + + function setLiquidAlphaEnabled(uint16 netuid, bool liquidAlphaEnabled) external payable; + + function getAlphaValues(uint16 netuid) external view returns (uint16, uint16); + + function setAlphaValues(uint16 netuid, uint16 alphaLow, uint16 alphaHigh) external payable; + + function getCommitRevealWeightsInterval(uint16 netuid) external view returns (uint64); + + function setCommitRevealWeightsInterval(uint16 netuid, uint64 commitRevealWeightsInterval) external payable; +} \ No newline at end of file diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index e6237dfcf..31c692cd6 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -25,23 +25,18 @@ // - 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}; pub const STAKING_PRECOMPILE_INDEX: u64 = 2049; - +// this is staking smart contract's(0x0000000000000000000000000000000000000801) sr25519 address +pub const STAKING_CONTRACT_ADDRESS: &str = "5CwnBK9Ack1mhznmCnwiibCNQc174pYQVktYW3ayRpLm4K2X"; pub struct StakingPrecompile; impl StakingPrecompile { @@ -78,7 +73,7 @@ impl StakingPrecompile { amount_staked: amount_sub.unique_saturated_into(), }); // Dispatch the add_stake call - Self::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(); @@ -98,7 +93,7 @@ impl StakingPrecompile { hotkey, amount_unstaked: amount_sub.unique_saturated_into(), }); - Self::dispatch(handle, call) + dispatch(handle, call, STAKING_CONTRACT_ADDRESS) } fn parse_hotkey(data: &[u8]) -> Result<[u8; 32], PrecompileFailure> { @@ -111,76 +106,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 = - as AddressMapping>::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 = - ::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::::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..e3a375f73 --- /dev/null +++ b/runtime/src/precompiles/subnet.rs @@ -0,0 +1,982 @@ +use crate::precompiles::{dispatch, get_method_id, get_slice}; +use crate::{Runtime, RuntimeCall}; +use pallet_evm::{ + ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, +}; +use sp_core::U256; +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; + +// this is staking smart contract's(0x0000000000000000000000000000000000000803) sr25519 address +pub const SUBNET_CONTRACT_ADDRESS: &str = "5DPSUCb5mZFfizvBDSnRoAqmxV5Bmov2CS3xV773qU6VP1w2"; + +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]) + } + + id if id == get_method_id("getServingRateLimit(uint16)") => { + Self::get_serving_rate_limit(&method_input) + } + id if id == get_method_id("setServingRateLimit(uint16,uint64)") => { + Self::set_serving_rate_limit(handle, &method_input) + } + + id if id == get_method_id("getMinDifficulty(uint16)") => { + Self::get_min_difficulty(&method_input) + } + id if id == get_method_id("setMinDifficulty(uint16,uint64)") => { + Self::set_min_difficulty(handle, &method_input) + } + + id if id == get_method_id("getMaxDifficulty(uint16)") => { + Self::get_max_difficulty(&method_input) + } + id if id == get_method_id("setMaxDifficulty(uint16,uint64)") => { + Self::set_max_difficulty(handle, &method_input) + } + + id if id == get_method_id("getWeightsVersionKey(uint16)") => { + Self::get_weights_version_key(&method_input) + } + id if id == get_method_id("setWeightsVersionKey(uint16,uint64)") => { + Self::set_weights_version_key(handle, &method_input) + } + + id if id == get_method_id("getWeightsSetRateLimit(uint16)") => { + Self::get_weights_set_rate_limit(&method_input) + } + id if id == get_method_id("setWeightsSetRateLimit(uint16,uint64)") => { + Self::set_weights_set_rate_limit(handle, &method_input) + } + + id if id == get_method_id("getAdjustmentAlpha(uint16)") => { + Self::get_adjustment_alpha(&method_input) + } + id if id == get_method_id("setAdjustmentAlpha(uint16,uint64)") => { + Self::set_adjustment_alpha(handle, &method_input) + } + + id if id == get_method_id("getMaxWeightLimit(uint16)") => { + Self::get_max_weight_limit(&method_input) + } + id if id == get_method_id("setMaxWeightLimit(uint16,uint64)") => { + Self::set_max_weight_limit(handle, &method_input) + } + + id if id == get_method_id("getImmunityPeriod(uint16)") => { + Self::get_immunity_period(&method_input) + } + id if id == get_method_id("setImmunityPeriod(uint16,uint64)") => { + Self::set_immunity_period(handle, &method_input) + } + + id if id == get_method_id("getMinAllowedWeights(uint16)") => { + Self::get_min_allowed_weights(&method_input) + } + id if id == get_method_id("setMinAllowedWeights(uint16,uint16)") => { + Self::set_min_allowed_weights(handle, &method_input) + } + + id if id == get_method_id("getKappa(uint16)") => Self::get_kappa(&method_input), + id if id == get_method_id("setKappa(uint16,uint16)") => { + Self::set_kappa(handle, &method_input) + } + + id if id == get_method_id("getRho(uint16)") => Self::get_rho(&method_input), + id if id == get_method_id("setRho(uint16,uint16)") => { + Self::set_rho(handle, &method_input) + } + + id if id == get_method_id("getActivityCutoff(uint16)") => { + Self::get_activity_cutoff(&method_input) + } + id if id == get_method_id("setActivityCutoff(uint16,uint16)") => { + Self::set_activity_cutoff(handle, &method_input) + } + + id if id == get_method_id("getNetworkRegistrationAllowed(uint16)") => { + Self::get_network_registration_allowed(&method_input) + } + id if id == get_method_id("setNetworkRegistrationAllowed(uint16,bool)") => { + Self::set_network_registration_allowed(handle, &method_input) + } + + id if id == get_method_id("getNetworkPowRegistrationAllowed(uint16)") => { + Self::get_network_pow_registration_allowed(&method_input) + } + id if id == get_method_id("setNetworkPowRegistrationAllowed(uint16,bool)") => { + Self::set_network_pow_registration_allowed(handle, &method_input) + } + + id if id == get_method_id("getMinBurn(uint16)") => Self::get_min_burn(&method_input), + id if id == get_method_id("setMinBurn(uint16,uint64)") => { + Self::set_min_burn(handle, &method_input) + } + + id if id == get_method_id("getMaxBurn(uint16)") => Self::get_max_burn(&method_input), + id if id == get_method_id("setMaxBurn(uint16,uint64)") => { + Self::set_max_burn(handle, &method_input) + } + + id if id == get_method_id("getDifficulty(uint16)") => { + Self::get_difficulty(&method_input) + } + id if id == get_method_id("setDifficulty(uint16,uint64)") => { + Self::set_difficulty(handle, &method_input) + } + + id if id == get_method_id("getBondsMovingAverage(uint16)") => { + Self::get_bonds_moving_average(&method_input) + } + id if id == get_method_id("setBondsMovingAverage(uint16,uint64)") => { + Self::set_bonds_moving_average(handle, &method_input) + } + + id if id == get_method_id("getCommitRevealWeightsEnabled(uint16)") => { + Self::get_commit_reveal_weights_enabled(&method_input) + } + id if id == get_method_id("setCommitRevealWeightsEnabled(uint16,bool)") => { + Self::set_commit_reveal_weights_enabled(handle, &method_input) + } + + id if id == get_method_id("getLiquidAlphaEnabled(uint16)") => { + Self::get_liquid_alpha_enabled(&method_input) + } + id if id == get_method_id("setLiquidAlphaEnabled(uint16,bool)") => { + Self::set_liquid_alpha_enabled(handle, &method_input) + } + + id if id == get_method_id("getAlphaValues(uint16)") => { + Self::get_alpha_values(&method_input) + } + id if id == get_method_id("setAlphaValues(uint16,uint16,uint16)") => { + Self::set_alpha_values(handle, &method_input) + } + + id if id == get_method_id("getCommitRevealWeightsInterval(uint16)") => { + Self::get_commit_reveal_weights_interval(&method_input) + } + id if id == get_method_id("setCommitRevealWeightsInterval(uint16,uint64)") => { + Self::set_commit_reveal_weights_interval(handle, &method_input) + } + _ => 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::::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::::register_network_with_identity { + identity: Some(identity), + }, + ) + }; + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_serving_rate_limit(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::ServingRateLimit::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_serving_rate_limit(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, serving_rate_limit) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_serving_rate_limit { + netuid, + serving_rate_limit, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_min_difficulty(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::MinDifficulty::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_min_difficulty(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, min_difficulty) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_min_difficulty { + netuid, + min_difficulty, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_max_difficulty(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::MaxDifficulty::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_max_difficulty(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, max_difficulty) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_max_difficulty { + netuid, + max_difficulty, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_weights_version_key(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::WeightsVersionKey::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_weights_version_key( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, weights_version_key) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_weights_version_key { + netuid, + weights_version_key, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_weights_set_rate_limit(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::WeightsSetRateLimit::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_weights_set_rate_limit( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, weights_set_rate_limit) = Self::parse_netuid_u64_parameter(data)?; + + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_weights_set_rate_limit { + netuid, + weights_set_rate_limit, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_adjustment_alpha(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::AdjustmentAlpha::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_adjustment_alpha(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, adjustment_alpha) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_adjustment_alpha { + netuid, + adjustment_alpha, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_max_weight_limit(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::MaxWeightsLimit::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_max_weight_limit(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, max_weight_limit) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_max_weight_limit { + netuid, + max_weight_limit, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_immunity_period(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::ImmunityPeriod::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_immunity_period(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, immunity_period) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_immunity_period { + netuid, + immunity_period, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_min_allowed_weights(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::MinAllowedWeights::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_min_allowed_weights( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, min_allowed_weights) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_min_allowed_weights { + netuid, + min_allowed_weights, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_kappa(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::Kappa::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_kappa(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, kappa) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_kappa { + netuid, + kappa, + }); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_rho(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::Rho::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_rho(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, rho) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_rho { + netuid, + rho, + }); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_activity_cutoff(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::ActivityCutoff::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_activity_cutoff(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, activity_cutoff) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_activity_cutoff { + netuid, + activity_cutoff, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_network_registration_allowed(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::NetworkRegistrationAllowed::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_network_registration_allowed( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, registration_allowed) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_network_registration_allowed { + netuid, + registration_allowed, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_network_pow_registration_allowed(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::NetworkPowRegistrationAllowed::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_network_pow_registration_allowed( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, registration_allowed) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_network_pow_registration_allowed { + netuid, + registration_allowed, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_min_burn(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::MinBurn::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_min_burn(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, min_burn) = Self::parse_netuid_u64_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_min_burn { + netuid, + min_burn, + }); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_max_burn(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::MaxBurn::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_max_burn(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, max_burn) = Self::parse_netuid_u64_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_max_burn { + netuid, + max_burn, + }); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_difficulty(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::Difficulty::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_difficulty(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, difficulty) = Self::parse_netuid_u64_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_difficulty { + netuid, + difficulty, + }); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_bonds_moving_average(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::BondsMovingAverage::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_bonds_moving_average( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, bonds_moving_average) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_bonds_moving_average { + netuid, + bonds_moving_average, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_commit_reveal_weights_enabled(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::CommitRevealWeightsEnabled::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_commit_reveal_weights_enabled( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, enabled) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_enabled { + netuid, + enabled, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_liquid_alpha_enabled(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::LiquidAlphaOn::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_liquid_alpha_enabled( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, enabled) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_liquid_alpha_enabled { netuid, enabled }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_alpha_values(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let (alpha_low, alpha_high) = pallet_subtensor::AlphaValues::::get(netuid); + + let mut value_u256 = U256::from(alpha_low); + let mut result = [0_u8; 64]; + U256::to_big_endian(&value_u256, &mut result[0..]); + + value_u256 = U256::from(alpha_high); + U256::to_big_endian(&value_u256, &mut result[32..]); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_alpha_values(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, alpha_low, alpha_high) = Self::parse_netuid_u16_u16_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_alpha_values { + netuid, + alpha_low, + alpha_high, + }); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn get_commit_reveal_weights_interval(data: &[u8]) -> PrecompileResult { + let netuid = Self::parse_netuid(data)?; + + let value = pallet_subtensor::RevealPeriodEpochs::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_commit_reveal_weights_interval( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, interval) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_interval { + netuid, + interval, + }, + ); + + dispatch(handle, call, SUBNET_CONTRACT_ADDRESS) + } + + fn parse_register_network_parameters( + data: &[u8], + ) -> Result<(vec::Vec, vec::Vec, vec::Vec), 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)) + } + + fn parse_netuid(data: &[u8]) -> Result { + if data.len() < 32 { + 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); + + Ok(netuid) + } + + fn parse_netuid_u64_parameter(data: &[u8]) -> Result<(u16, u64), 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_vec = [0u8; 8]; + parameter_vec.copy_from_slice(get_slice(data, 56, 64)?); + let parameter = u64::from_be_bytes(parameter_vec); + + Ok((netuid, parameter)) + } + + fn parse_netuid_u16_parameter(data: &[u8]) -> Result<(u16, u16), 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_vec = [0u8; 2]; + parameter_vec.copy_from_slice(get_slice(data, 62, 64)?); + let parameter = u16::from_be_bytes(parameter_vec); + + Ok((netuid, parameter)) + } + + fn parse_netuid_u16_u16_parameter(data: &[u8]) -> Result<(u16, u16, u16), 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_1_vec = [0u8; 2]; + parameter_1_vec.copy_from_slice(get_slice(data, 62, 64)?); + let parameter_1 = u16::from_be_bytes(parameter_1_vec); + + let mut parameter_2_vec = [0u8; 2]; + parameter_2_vec.copy_from_slice(get_slice(data, 94, 96)?); + let parameter_2 = u16::from_be_bytes(parameter_2_vec); + + Ok((netuid, parameter_1, parameter_2)) + } + + fn parse_netuid_bool_parameter(data: &[u8]) -> Result<(u16, bool), 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_vec = [0_u8]; + parameter_vec.copy_from_slice(get_slice(data, 63, 64)?); + + let parameter = parameter_vec[0] != 0; + + Ok((netuid, parameter)) + } +}