Skip to content

Commit

Permalink
merge with subnet precompile
Browse files Browse the repository at this point in the history
  • Loading branch information
open-junius committed Dec 20, 2024
2 parents 6a0f6f9 + 2141e00 commit 2284e31
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 102 deletions.
106 changes: 102 additions & 4 deletions runtime/src/precompiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,40 @@ 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;
mod subnets;

use balance_transfer::*;
use ed25519::*;
use metagraph::*;
use staking::*;
use subnet::*;
use subnets::*;

pub struct FrontierPrecompiles<R>(PhantomData<R>);

impl<R> Default for FrontierPrecompiles<R>
where
R: pallet_evm::Config,
Expand All @@ -41,7 +53,7 @@ where
pub fn new() -> Self {
Self(Default::default())
}
pub fn used_addresses() -> [H160; 12] {
pub fn used_addresses() -> [H160; 13] {
[
hash(1),
hash(2),
Expand All @@ -53,6 +65,7 @@ where
hash(EDVERIFY_PRECOMPILE_INDEX),
hash(BALANCE_TRANSFER_INDEX),
hash(STAKING_PRECOMPILE_INDEX),
hash(SUBNET_PRECOMPILE_INDEX),
hash(METAGRAPH_PRECOMPILE_INDEX),
hash(SUBNETS_PRECOMPILE_INDEX),
]
Expand All @@ -79,6 +92,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))
}
Expand Down Expand Up @@ -129,8 +143,92 @@ 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> {
// 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()),
}),
}
}
32 changes: 32 additions & 0 deletions runtime/src/precompiles/solidity/subnet.abi
Original file line number Diff line number Diff line change
@@ -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"
}
]
10 changes: 10 additions & 0 deletions runtime/src/precompiles/solidity/subnet.sol
Original file line number Diff line number Diff line change
@@ -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 memory subnetName, bytes memory githubRepo, bytes memory subnetContact) external payable;
}
93 changes: 8 additions & 85 deletions runtime/src/precompiles/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
Expand All @@ -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> {
Expand All @@ -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 =
<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(())
}
}
Loading

0 comments on commit 2284e31

Please sign in to comment.