pallet_evm_tracker/
create_contract.rs1use crate::traits::{AccountIdFor, MaybeIntoEthCall, MaybeIntoEvmCall};
4use domain_runtime_primitives::{EthereumAccountId, ERR_CONTRACT_CREATION_NOT_ALLOWED};
5use frame_support::pallet_prelude::{PhantomData, TypeInfo};
6use frame_system::pallet_prelude::{OriginFor, RuntimeCallFor};
7use pallet_ethereum::{Transaction as EthereumTransaction, TransactionAction};
8use parity_scale_codec::{Decode, Encode};
9use scale_info::prelude::fmt;
10use sp_core::Get;
11use sp_runtime::impl_tx_ext_default;
12use sp_runtime::traits::{
13 AsSystemOriginSigner, DispatchInfoOf, Dispatchable, TransactionExtension, ValidateResult,
14};
15use sp_runtime::transaction_validity::{
16 InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
17 ValidTransaction,
18};
19use sp_weights::Weight;
20use subspace_runtime_primitives::utility::{nested_call_iter, MaybeNestedCall};
21
22pub fn is_create_contract_allowed<Runtime>(
26 call: &RuntimeCallFor<Runtime>,
27 signer: &EthereumAccountId,
28) -> bool
29where
30 Runtime: frame_system::Config<AccountId = EthereumAccountId>
31 + pallet_ethereum::Config
32 + pallet_evm::Config
33 + crate::Config,
34 RuntimeCallFor<Runtime>:
35 MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeNestedCall<Runtime>,
36 Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
37{
38 crate::Pallet::<Runtime>::is_allowed_to_create_contracts(signer)
41 || !is_create_contract::<Runtime>(call)
42}
43
44pub fn is_create_unsigned_contract_allowed<Runtime>(call: &RuntimeCallFor<Runtime>) -> bool
48where
49 Runtime: frame_system::Config + pallet_ethereum::Config + pallet_evm::Config + crate::Config,
50 RuntimeCallFor<Runtime>:
51 MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeNestedCall<Runtime>,
52 Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
53{
54 crate::Pallet::<Runtime>::is_allowed_to_create_unsigned_contracts()
57 || !is_create_contract::<Runtime>(call)
58}
59
60pub fn is_create_contract<Runtime>(call: &RuntimeCallFor<Runtime>) -> bool
62where
63 Runtime: frame_system::Config + pallet_ethereum::Config + pallet_evm::Config,
64 RuntimeCallFor<Runtime>:
65 MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeNestedCall<Runtime>,
66 Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
67{
68 for call in nested_call_iter::<Runtime>(call) {
69 if let Some(call) = call.maybe_into_eth_call() {
70 match call {
71 pallet_ethereum::Call::transact {
72 transaction: EthereumTransaction::Legacy(transaction),
73 ..
74 } => {
75 if transaction.action == TransactionAction::Create {
76 return true;
77 }
78 }
79 pallet_ethereum::Call::transact {
80 transaction: EthereumTransaction::EIP2930(transaction),
81 ..
82 } => {
83 if transaction.action == TransactionAction::Create {
84 return true;
85 }
86 }
87 pallet_ethereum::Call::transact {
88 transaction: EthereumTransaction::EIP1559(transaction),
89 ..
90 } => {
91 if transaction.action == TransactionAction::Create {
92 return true;
93 }
94 }
95 _ => {}
97 }
98 }
99
100 if let Some(pallet_evm::Call::create { .. } | pallet_evm::Call::create2 { .. }) =
101 call.maybe_into_evm_call()
102 {
103 return true;
104 }
105 }
106
107 false
108}
109
110#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
112pub struct CheckContractCreation<Runtime>(PhantomData<Runtime>);
113
114impl<Runtime> CheckContractCreation<Runtime> {
115 pub fn new() -> Self {
116 Self(PhantomData)
117 }
118}
119
120impl<Runtime> Default for CheckContractCreation<Runtime> {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125
126impl<Runtime> CheckContractCreation<Runtime>
127where
128 Runtime: frame_system::Config<AccountId = EthereumAccountId>
129 + pallet_ethereum::Config
130 + pallet_evm::Config
131 + crate::Config
132 + scale_info::TypeInfo
133 + fmt::Debug
134 + Send
135 + Sync,
136 RuntimeCallFor<Runtime>:
137 MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeNestedCall<Runtime>,
138 Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
139 <RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
140 AsSystemOriginSigner<AccountIdFor<Runtime>> + Clone,
141{
142 fn do_validate_unsigned(call: &RuntimeCallFor<Runtime>) -> TransactionValidity {
143 if !is_create_unsigned_contract_allowed::<Runtime>(call) {
144 Err(InvalidTransaction::Custom(ERR_CONTRACT_CREATION_NOT_ALLOWED).into())
145 } else {
146 Ok(ValidTransaction::default())
147 }
148 }
149
150 fn do_validate(
151 origin: &OriginFor<Runtime>,
152 call: &RuntimeCallFor<Runtime>,
153 ) -> TransactionValidity {
154 let Some(who) = origin.as_system_origin_signer() else {
155 return Self::do_validate_unsigned(call);
157 };
158 if !is_create_contract_allowed::<Runtime>(call, who) {
160 Err(InvalidTransaction::Custom(ERR_CONTRACT_CREATION_NOT_ALLOWED).into())
161 } else {
162 Ok(ValidTransaction::default())
163 }
164 }
165}
166
167impl<Runtime> TransactionExtension<RuntimeCallFor<Runtime>> for CheckContractCreation<Runtime>
171where
172 Runtime: frame_system::Config<AccountId = EthereumAccountId>
173 + pallet_ethereum::Config
174 + pallet_evm::Config
175 + crate::Config
176 + scale_info::TypeInfo
177 + fmt::Debug
178 + Send
179 + Sync,
180 RuntimeCallFor<Runtime>:
181 MaybeIntoEthCall<Runtime> + MaybeIntoEvmCall<Runtime> + MaybeNestedCall<Runtime>,
182 Result<pallet_ethereum::RawOrigin, OriginFor<Runtime>>: From<OriginFor<Runtime>>,
183 <RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
184 AsSystemOriginSigner<AccountIdFor<Runtime>> + Clone,
185{
186 const IDENTIFIER: &'static str = "CheckContractCreation";
187 type Implicit = ();
188 type Val = ();
189 type Pre = ();
190
191 fn weight(&self, _: &RuntimeCallFor<Runtime>) -> Weight {
194 <Runtime as frame_system::Config>::DbWeight::get().reads(1)
196 }
197
198 fn validate(
199 &self,
200 origin: OriginFor<Runtime>,
201 call: &RuntimeCallFor<Runtime>,
202 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
203 _len: usize,
204 _self_implicit: Self::Implicit,
205 _inherited_implication: &impl Encode,
206 _source: TransactionSource,
207 ) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
208 let validity = Self::do_validate(&origin, call)?;
209 Ok((validity, (), origin))
210 }
211
212 impl_tx_ext_default!(RuntimeCallFor<Runtime>; prepare);
213
214 fn bare_validate(
215 call: &RuntimeCallFor<Runtime>,
216 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
217 _len: usize,
218 ) -> TransactionValidity {
219 Self::do_validate_unsigned(call)
220 }
221
222 fn bare_validate_and_prepare(
223 call: &RuntimeCallFor<Runtime>,
224 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
225 _len: usize,
226 ) -> Result<(), TransactionValidityError> {
227 Self::do_validate_unsigned(call)?;
228 Ok(())
229 }
230}