pallet_evm_tracker/
create_contract.rsuse crate::traits::{AccountIdFor, MaybeIntoEthCall, MaybeIntoEvmCall};
use codec::{Decode, Encode};
use domain_runtime_primitives::{EthereumAccountId, ERR_CONTRACT_CREATION_NOT_ALLOWED};
use frame_support::pallet_prelude::{PhantomData, TypeInfo};
use frame_system::pallet_prelude::{OriginFor, RuntimeCallFor};
use pallet_ethereum::{Transaction as EthereumTransaction, TransactionAction};
use scale_info::prelude::fmt;
use sp_core::Get;
use sp_runtime::impl_tx_ext_default;
use sp_runtime::traits::{
AsSystemOriginSigner, DispatchInfoOf, Dispatchable, TransactionExtension, ValidateResult,
};
use sp_runtime::transaction_validity::{
InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
ValidTransaction,
};
use sp_weights::Weight;
use subspace_runtime_primitives::utility::{nested_utility_call_iter, MaybeIntoUtilityCall};
pub fn is_create_contract_allowed<Runtime>(
call: &RuntimeCallFor<Runtime>,
signer: &EthereumAccountId,
) -> bool
where
Runtime: frame_system::Config<AccountId = EthereumAccountId>
+ pallet_ethereum::Config
+ pallet_evm::Config
+ pallet_utility::Config
+ crate::Config,
RuntimeCallFor<Runtime>:
MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeIntoUtilityCall<Runtime>,
for<'block> &'block RuntimeCallFor<Runtime>:
From<&'block <Runtime as pallet_utility::Config>::RuntimeCall>,
Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
{
crate::Pallet::<Runtime>::is_allowed_to_create_contracts(signer)
|| !is_create_contract::<Runtime>(call)
}
pub fn is_create_unsigned_contract_allowed<Runtime>(call: &RuntimeCallFor<Runtime>) -> bool
where
Runtime: frame_system::Config
+ pallet_ethereum::Config
+ pallet_evm::Config
+ pallet_utility::Config
+ crate::Config,
RuntimeCallFor<Runtime>:
MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeIntoUtilityCall<Runtime>,
for<'block> &'block RuntimeCallFor<Runtime>:
From<&'block <Runtime as pallet_utility::Config>::RuntimeCall>,
Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
{
crate::Pallet::<Runtime>::is_allowed_to_create_unsigned_contracts()
|| !is_create_contract::<Runtime>(call)
}
pub fn is_create_contract<Runtime>(call: &RuntimeCallFor<Runtime>) -> bool
where
Runtime: frame_system::Config
+ pallet_ethereum::Config
+ pallet_evm::Config
+ pallet_utility::Config,
RuntimeCallFor<Runtime>:
MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeIntoUtilityCall<Runtime>,
for<'block> &'block RuntimeCallFor<Runtime>:
From<&'block <Runtime as pallet_utility::Config>::RuntimeCall>,
Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
{
for call in nested_utility_call_iter::<Runtime>(call) {
if let Some(call) = call.maybe_into_eth_call() {
match call {
pallet_ethereum::Call::transact {
transaction: EthereumTransaction::Legacy(transaction),
..
} => {
if transaction.action == TransactionAction::Create {
return true;
}
}
pallet_ethereum::Call::transact {
transaction: EthereumTransaction::EIP2930(transaction),
..
} => {
if transaction.action == TransactionAction::Create {
return true;
}
}
pallet_ethereum::Call::transact {
transaction: EthereumTransaction::EIP1559(transaction),
..
} => {
if transaction.action == TransactionAction::Create {
return true;
}
}
_ => {}
}
}
if let Some(pallet_evm::Call::create { .. } | pallet_evm::Call::create2 { .. }) =
call.maybe_into_evm_call()
{
return true;
}
}
false
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub struct CheckContractCreation<Runtime>(PhantomData<Runtime>);
impl<Runtime> CheckContractCreation<Runtime> {
pub fn new() -> Self {
Self(PhantomData)
}
}
impl<Runtime> Default for CheckContractCreation<Runtime> {
fn default() -> Self {
Self::new()
}
}
impl<Runtime> CheckContractCreation<Runtime>
where
Runtime: frame_system::Config<AccountId = EthereumAccountId>
+ pallet_ethereum::Config
+ pallet_evm::Config
+ pallet_utility::Config
+ crate::Config
+ scale_info::TypeInfo
+ fmt::Debug
+ Send
+ Sync,
RuntimeCallFor<Runtime>:
MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeIntoUtilityCall<Runtime>,
for<'block> &'block RuntimeCallFor<Runtime>:
From<&'block <Runtime as pallet_utility::Config>::RuntimeCall>,
Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
<RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
AsSystemOriginSigner<AccountIdFor<Runtime>> + Clone,
{
fn do_validate_unsigned(call: &RuntimeCallFor<Runtime>) -> TransactionValidity {
if !is_create_unsigned_contract_allowed::<Runtime>(call) {
Err(InvalidTransaction::Custom(ERR_CONTRACT_CREATION_NOT_ALLOWED).into())
} else {
Ok(ValidTransaction::default())
}
}
fn do_validate(
origin: &OriginFor<Runtime>,
call: &RuntimeCallFor<Runtime>,
) -> TransactionValidity {
let Some(who) = origin.as_system_origin_signer() else {
return Self::do_validate_unsigned(call);
};
if !is_create_contract_allowed::<Runtime>(call, who) {
Err(InvalidTransaction::Custom(ERR_CONTRACT_CREATION_NOT_ALLOWED).into())
} else {
Ok(ValidTransaction::default())
}
}
}
impl<Runtime> TransactionExtension<RuntimeCallFor<Runtime>> for CheckContractCreation<Runtime>
where
Runtime: frame_system::Config<AccountId = EthereumAccountId>
+ pallet_ethereum::Config
+ pallet_evm::Config
+ pallet_utility::Config
+ crate::Config
+ scale_info::TypeInfo
+ fmt::Debug
+ Send
+ Sync,
RuntimeCallFor<Runtime>:
MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeIntoUtilityCall<Runtime>,
for<'block> &'block RuntimeCallFor<Runtime>:
From<&'block <Runtime as pallet_utility::Config>::RuntimeCall>,
Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
<RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
AsSystemOriginSigner<AccountIdFor<Runtime>> + Clone,
{
const IDENTIFIER: &'static str = "CheckContractCreation";
type Implicit = ();
type Val = ();
type Pre = ();
fn weight(&self, _: &RuntimeCallFor<Runtime>) -> Weight {
<Runtime as frame_system::Config>::DbWeight::get().reads(1)
}
fn validate(
&self,
origin: OriginFor<Runtime>,
call: &RuntimeCallFor<Runtime>,
_info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
_len: usize,
_self_implicit: Self::Implicit,
_inherited_implication: &impl Encode,
_source: TransactionSource,
) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
let validity = Self::do_validate(&origin, call)?;
Ok((validity, (), origin))
}
impl_tx_ext_default!(RuntimeCallFor<Runtime>; prepare);
fn bare_validate(
call: &RuntimeCallFor<Runtime>,
_info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
_len: usize,
) -> TransactionValidity {
Self::do_validate_unsigned(call)
}
fn bare_validate_and_prepare(
call: &RuntimeCallFor<Runtime>,
_info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
_len: usize,
) -> Result<(), TransactionValidityError> {
Self::do_validate_unsigned(call)?;
Ok(())
}
}