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