pallet_evm_tracker/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
19#![expect(clippy::clone_on_copy, reason = "Comes from Substrate")]
21
22#[cfg(not(feature = "std"))]
23extern crate alloc;
24
25#[cfg(feature = "runtime-benchmarks")]
26mod benchmarking;
27
28pub mod check_nonce;
29pub mod create_contract;
30pub mod fees;
31pub mod traits;
32pub mod weights;
33
34pub use check_nonce::CheckNonce;
35use domain_runtime_primitives::EthereumAccountId;
36pub use pallet::*;
37use sp_core::U256;
38use sp_domains::PermissionedActionAllowedBy;
39use sp_weights::Weight;
40
41const MAXIMUM_NUMBER_OF_CALLS: u32 = 5_000;
43
44pub trait WeightInfo {
46 fn evm_contract_check_multiple(c: u32) -> Weight;
47 fn evm_contract_check_nested(c: u32) -> Weight;
48}
49
50#[frame_support::pallet]
51mod pallet {
52 use domain_runtime_primitives::EthereumAccountId;
53 use frame_support::pallet_prelude::*;
54 use frame_system::pallet_prelude::*;
55 use sp_core::U256;
56 use sp_domains::PermissionedActionAllowedBy;
57 use sp_evm_tracker::{INHERENT_IDENTIFIER, InherentError, InherentType};
58
59 #[pallet::config]
60 pub trait Config: frame_system::Config {}
61
62 #[pallet::storage]
66 pub(super) type AccountNonce<T: Config> =
67 StorageMap<_, Identity, T::AccountId, U256, OptionQuery>;
68
69 #[pallet::storage]
77 pub(super) type ContractCreationAllowedBy<T: Config> = StorageValue<
78 _,
79 PermissionedActionAllowedBy<EthereumAccountId>,
80 ValueQuery,
81 DefaultToAnyone,
82 >;
83
84 pub struct DefaultToAnyone;
86
87 impl Get<PermissionedActionAllowedBy<EthereumAccountId>> for DefaultToAnyone {
88 fn get() -> PermissionedActionAllowedBy<EthereumAccountId> {
89 PermissionedActionAllowedBy::Anyone
90 }
91 }
92
93 #[pallet::pallet]
95 #[pallet::without_storage_info]
96 pub struct Pallet<T>(_);
97
98 #[pallet::call]
99 impl<T: Config> Pallet<T> {
100 #[pallet::call_index(0)]
102 #[pallet::weight((T::DbWeight::get().reads_writes(0, 1), DispatchClass::Mandatory))]
103 pub fn set_contract_creation_allowed_by(
104 origin: OriginFor<T>,
105 contract_creation_allowed_by: PermissionedActionAllowedBy<EthereumAccountId>,
106 ) -> DispatchResult {
107 ensure_none(origin)?;
108
109 ContractCreationAllowedBy::<T>::put(contract_creation_allowed_by);
112
113 Ok(())
114 }
115 }
116
117 #[pallet::inherent]
118 impl<T: Config> ProvideInherent for Pallet<T> {
119 type Call = Call<T>;
120 type Error = InherentError;
121 const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
122
123 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
124 let inherent_data = data
125 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
126 .expect("EVM tracker inherent data not correctly encoded")
127 .expect("EVM tracker inherent data must be provided");
128
129 inherent_data
130 .maybe_call
131 .map(
132 |contract_creation_allowed_by| Call::set_contract_creation_allowed_by {
133 contract_creation_allowed_by,
134 },
135 )
136 }
137
138 fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
139 let inherent_data = data
140 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
141 .expect("EVM tracker inherent data not correctly encoded")
142 .expect("EVM tracker inherent data must be provided");
143
144 Ok(inherent_data
145 .maybe_call
146 .map(|_encoded_call| InherentError::MissingRuntimeCall))
147 }
148
149 fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
150 let maybe_provided_call = Self::create_inherent(data);
151
152 if let Some(provided_call) = maybe_provided_call {
153 if Self::is_inherent(call) && call != &provided_call {
154 return Err(InherentError::IncorrectRuntimeCall);
155 }
156 } else {
157 return Err(InherentError::MissingRuntimeCall);
158 }
159
160 Ok(())
161 }
162
163 fn is_inherent(call: &Self::Call) -> bool {
164 matches!(call, Call::set_contract_creation_allowed_by { .. })
165 }
166 }
167
168 #[pallet::hooks]
169 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
170 fn on_finalize(_now: BlockNumberFor<T>) {
171 let _ = AccountNonce::<T>::clear(u32::MAX, None);
174 }
175 }
176}
177
178impl<T: Config> Pallet<T> {
179 pub fn account_nonce(account: T::AccountId) -> Option<U256> {
181 AccountNonce::<T>::get(account)
182 }
183
184 pub fn set_account_nonce(account: T::AccountId, nonce: U256) {
186 AccountNonce::<T>::set(account, Some(nonce))
187 }
188
189 pub fn is_allowed_to_create_contracts(signer: &EthereumAccountId) -> bool {
191 ContractCreationAllowedBy::<T>::get().is_allowed(signer)
192 }
193
194 pub fn is_allowed_to_create_unsigned_contracts() -> bool {
196 ContractCreationAllowedBy::<T>::get().is_anyone_allowed()
197 }
198
199 pub fn contract_creation_allowed_by() -> PermissionedActionAllowedBy<EthereumAccountId> {
202 ContractCreationAllowedBy::<T>::get()
203 }
204}