1#![cfg_attr(not(feature = "std"), no_std)]
55#![warn(unused_crate_dependencies)]
56#![allow(clippy::too_many_arguments)]
57#![allow(clippy::useless_conversion)]
58
59extern crate alloc;
60
61#[cfg(feature = "runtime-benchmarks")]
62pub mod benchmarking;
63
64#[cfg(test)]
65mod mock;
66pub mod runner;
67#[cfg(test)]
68mod tests;
69pub mod weights;
70
71use alloc::{borrow::Cow, collections::btree_map::BTreeMap, vec::Vec};
72use core::cmp::min;
73use ethereum::AuthorizationList;
74pub use evm::{
75 Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed,
76};
77use hash_db::Hasher;
78use impl_trait_for_tuples::impl_for_tuples;
79use scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
80use scale_info::TypeInfo;
81use frame_support::{
83 dispatch::{DispatchResultWithPostInfo, Pays, PostDispatchInfo},
84 storage::KeyPrefixIterator,
85 traits::{
86 fungible::{Balanced, Credit, Debt},
87 tokens::{
88 currency::Currency,
89 fungible::Inspect,
90 imbalance::{Imbalance, OnUnbalanced, SignedImbalance},
91 ExistenceRequirement, Fortitude, Precision, Preservation, WithdrawReasons,
92 },
93 FindAuthor, Get, Time,
94 },
95 weights::Weight,
96};
97use frame_system::RawOrigin;
98use sp_core::{H160, H256, U256};
99use sp_runtime::{
100 traits::{BadOrigin, NumberFor, Saturating, UniqueSaturatedInto, Zero},
101 AccountId32, DispatchErrorWithPostInfo,
102};
103use fp_account::AccountId20;
105use fp_evm::GenesisAccount;
106pub use fp_evm::{
107 Account, AccountProvider, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo,
108 FeeCalculator, IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure,
109 PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet,
110 TransactionValidationError, Vicinity, EVM_CONFIG,
111};
112
113pub use self::{
114 pallet::*,
115 runner::{Runner, RunnerError},
116 weights::WeightInfo,
117};
118
119#[frame_support::pallet]
120pub mod pallet {
121 use super::*;
122 use frame_support::pallet_prelude::*;
123 use frame_system::pallet_prelude::*;
124
125 #[pallet::pallet]
126 #[pallet::without_storage_info]
127 pub struct Pallet<T>(PhantomData<T>);
128
129 #[pallet::config(with_default)]
130 pub trait Config: frame_system::Config {
131 #[pallet::no_default]
133 type AccountProvider: AccountProvider;
134
135 type FeeCalculator: FeeCalculator;
137
138 type GasWeightMapping: GasWeightMapping;
140
141 type WeightPerGas: Get<Weight>;
143
144 #[pallet::no_default]
146 type BlockHashMapping: BlockHashMapping;
147
148 #[pallet::no_default_bounds]
150 type CallOrigin: EnsureAddressOrigin<Self::RuntimeOrigin>;
151
152 #[pallet::no_default_bounds]
154 type CreateOriginFilter: EnsureCreateOrigin<Self>;
155
156 #[pallet::no_default_bounds]
158 type CreateInnerOriginFilter: EnsureCreateOrigin<Self>;
159
160 #[pallet::no_default_bounds]
162 type WithdrawOrigin: EnsureAddressOrigin<Self::RuntimeOrigin, Success = AccountIdOf<Self>>;
163
164 #[pallet::no_default_bounds]
166 type AddressMapping: AddressMapping<AccountIdOf<Self>>;
167
168 #[pallet::no_default]
170 type Currency: Currency<AccountIdOf<Self>> + Inspect<AccountIdOf<Self>>;
171
172 type PrecompilesType: PrecompileSet;
174 type PrecompilesValue: Get<Self::PrecompilesType>;
175
176 type ChainId: Get<u64>;
178 type BlockGasLimit: Get<U256>;
180
181 #[pallet::no_default]
183 type Runner: Runner<Self>;
184
185 #[pallet::no_default_bounds]
189 type OnChargeTransaction: OnChargeEVMTransaction<Self>;
190
191 #[pallet::no_default_bounds]
193 type OnCreate: OnCreate<Self>;
194
195 type FindAuthor: FindAuthor<H160>;
197
198 type GasLimitPovSizeRatio: Get<u64>;
200
201 type GasLimitStorageGrowthRatio: Get<u64>;
203
204 #[pallet::no_default]
206 type Timestamp: Time;
207
208 type WeightInfo: WeightInfo;
210
211 fn config() -> &'static EvmConfig {
213 &EVM_CONFIG
214 }
215 }
216
217 pub mod config_preludes {
218 use super::*;
219 use core::str::FromStr;
220 use frame_support::{derive_impl, parameter_types, ConsensusEngineId};
221 use sp_runtime::traits::BlakeTwo256;
222
223 pub struct TestDefaultConfig;
224
225 #[derive_impl(
226 frame_system::config_preludes::SolochainDefaultConfig,
227 no_aggregated_types
228 )]
229 impl frame_system::DefaultConfig for TestDefaultConfig {}
230
231 const BLOCK_GAS_LIMIT: u64 = 150_000_000;
232 const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
233 const MAX_STORAGE_GROWTH: u64 = 400 * 1024;
235
236 parameter_types! {
237 pub BlockGasLimit: U256 = U256::from(BLOCK_GAS_LIMIT);
238 pub const ChainId: u64 = 42;
239 pub const GasLimitPovSizeRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_POV_SIZE);
240 pub const GasLimitStorageGrowthRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_STORAGE_GROWTH);
241 pub WeightPerGas: Weight = Weight::from_parts(20_000, 0);
242 }
243
244 #[register_default_impl(TestDefaultConfig)]
245 impl DefaultConfig for TestDefaultConfig {
246 type CallOrigin = EnsureAddressRoot<Self::AccountId>;
247 type WithdrawOrigin = EnsureAddressNever<Self::AccountId>;
248 type AddressMapping = HashedAddressMapping<BlakeTwo256>;
249 type FeeCalculator = FixedGasPrice;
250 type GasWeightMapping = FixedGasWeightMapping<Self>;
251 type WeightPerGas = WeightPerGas;
252 type PrecompilesType = ();
253 type PrecompilesValue = ();
254 type ChainId = ChainId;
255 type BlockGasLimit = BlockGasLimit;
256 type OnChargeTransaction = ();
257 type OnCreate = ();
258 type FindAuthor = FindAuthorTruncated;
259 type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
260 type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio;
261 type CreateOriginFilter = ();
262 type CreateInnerOriginFilter = ();
263 type WeightInfo = ();
264 }
265
266 impl FixedGasWeightMappingAssociatedTypes for TestDefaultConfig {
267 type WeightPerGas = <Self as DefaultConfig>::WeightPerGas;
268 type BlockWeights = <Self as frame_system::DefaultConfig>::BlockWeights;
269 type GasLimitPovSizeRatio = <Self as DefaultConfig>::GasLimitPovSizeRatio;
270 }
271
272 pub struct FixedGasPrice;
273 impl FeeCalculator for FixedGasPrice {
274 fn min_gas_price() -> (U256, Weight) {
275 (1.into(), Weight::zero())
276 }
277 }
278
279 pub struct FindAuthorTruncated;
280 impl FindAuthor<H160> for FindAuthorTruncated {
281 fn find_author<'a, I>(_digests: I) -> Option<H160>
282 where
283 I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
284 {
285 Some(H160::from_str("1234500000000000000000000000000000000000").unwrap())
286 }
287 }
288 }
289
290 #[pallet::call]
291 impl<T: Config> Pallet<T> {
292 #[pallet::call_index(0)]
294 #[pallet::weight(<T as pallet::Config>::WeightInfo::withdraw())]
295 pub fn withdraw(
296 origin: OriginFor<T>,
297 address: H160,
298 value: BalanceOf<T>,
299 ) -> DispatchResult {
300 let destination = T::WithdrawOrigin::ensure_address_origin(&address, origin)?;
301 let address_account_id = T::AddressMapping::into_account_id(address);
302
303 T::Currency::transfer(
304 &address_account_id,
305 &destination,
306 value,
307 ExistenceRequirement::AllowDeath,
308 )?;
309
310 Ok(())
311 }
312
313 #[pallet::call_index(1)]
315 #[pallet::weight({
316 let without_base_extrinsic_weight = true;
317 T::GasWeightMapping::gas_to_weight(*gas_limit, without_base_extrinsic_weight)
318 })]
319 pub fn call(
320 origin: OriginFor<T>,
321 source: H160,
322 target: H160,
323 input: Vec<u8>,
324 value: U256,
325 gas_limit: u64,
326 max_fee_per_gas: U256,
327 max_priority_fee_per_gas: Option<U256>,
328 nonce: Option<U256>,
329 access_list: Vec<(H160, Vec<H256>)>,
330 authorization_list: AuthorizationList,
331 ) -> DispatchResultWithPostInfo {
332 T::CallOrigin::ensure_address_origin(&source, origin)?;
333
334 let is_transactional = true;
335 let validate = true;
336 let info = match T::Runner::call(
337 source,
338 target,
339 input,
340 value,
341 gas_limit,
342 Some(max_fee_per_gas),
343 max_priority_fee_per_gas,
344 nonce,
345 access_list,
346 authorization_list,
347 is_transactional,
348 validate,
349 None,
350 None,
351 T::config(),
352 ) {
353 Ok(info) => info,
354 Err(e) => {
355 return Err(DispatchErrorWithPostInfo {
356 post_info: PostDispatchInfo {
357 actual_weight: Some(e.weight),
358 pays_fee: Pays::Yes,
359 },
360 error: e.error.into(),
361 })
362 }
363 };
364
365 match info.exit_reason {
366 ExitReason::Succeed(_) => {
367 Pallet::<T>::deposit_event(Event::<T>::Executed { address: target });
368 }
369 _ => {
370 Pallet::<T>::deposit_event(Event::<T>::ExecutedFailed { address: target });
371 }
372 };
373
374 Ok(PostDispatchInfo {
375 actual_weight: {
376 let mut gas_to_weight = T::GasWeightMapping::gas_to_weight(
377 info.used_gas.standard.unique_saturated_into(),
378 true,
379 );
380 if let Some(weight_info) = info.weight_info {
381 if let Some(proof_size_usage) = weight_info.proof_size_usage {
382 *gas_to_weight.proof_size_mut() = proof_size_usage;
383 }
384 }
385 Some(gas_to_weight)
386 },
387 pays_fee: Pays::No,
388 })
389 }
390
391 #[pallet::call_index(2)]
394 #[pallet::weight({
395 let without_base_extrinsic_weight = true;
396 T::GasWeightMapping::gas_to_weight(*gas_limit, without_base_extrinsic_weight)
397 })]
398 pub fn create(
399 origin: OriginFor<T>,
400 source: H160,
401 init: Vec<u8>,
402 value: U256,
403 gas_limit: u64,
404 max_fee_per_gas: U256,
405 max_priority_fee_per_gas: Option<U256>,
406 nonce: Option<U256>,
407 access_list: Vec<(H160, Vec<H256>)>,
408 authorization_list: AuthorizationList,
409 ) -> DispatchResultWithPostInfo {
410 T::CallOrigin::ensure_address_origin(&source, origin)?;
411
412 let is_transactional = true;
413 let validate = true;
414 let info = match T::Runner::create(
415 source,
416 init,
417 value,
418 gas_limit,
419 Some(max_fee_per_gas),
420 max_priority_fee_per_gas,
421 nonce,
422 access_list,
423 authorization_list,
424 is_transactional,
425 validate,
426 None,
427 None,
428 T::config(),
429 ) {
430 Ok(info) => info,
431 Err(e) => {
432 return Err(DispatchErrorWithPostInfo {
433 post_info: PostDispatchInfo {
434 actual_weight: Some(e.weight),
435 pays_fee: Pays::Yes,
436 },
437 error: e.error.into(),
438 })
439 }
440 };
441
442 match info {
443 CreateInfo {
444 exit_reason: ExitReason::Succeed(_),
445 value: create_address,
446 ..
447 } => {
448 Pallet::<T>::deposit_event(Event::<T>::Created {
449 address: create_address,
450 });
451 }
452 CreateInfo {
453 exit_reason: _,
454 value: create_address,
455 ..
456 } => {
457 Pallet::<T>::deposit_event(Event::<T>::CreatedFailed {
458 address: create_address,
459 });
460 }
461 }
462
463 Ok(PostDispatchInfo {
464 actual_weight: {
465 let mut gas_to_weight = T::GasWeightMapping::gas_to_weight(
466 info.used_gas.standard.unique_saturated_into(),
467 true,
468 );
469 if let Some(weight_info) = info.weight_info {
470 if let Some(proof_size_usage) = weight_info.proof_size_usage {
471 *gas_to_weight.proof_size_mut() = proof_size_usage;
472 }
473 }
474 Some(gas_to_weight)
475 },
476 pays_fee: Pays::No,
477 })
478 }
479
480 #[pallet::call_index(3)]
482 #[pallet::weight({
483 let without_base_extrinsic_weight = true;
484 T::GasWeightMapping::gas_to_weight(*gas_limit, without_base_extrinsic_weight)
485 })]
486 pub fn create2(
487 origin: OriginFor<T>,
488 source: H160,
489 init: Vec<u8>,
490 salt: H256,
491 value: U256,
492 gas_limit: u64,
493 max_fee_per_gas: U256,
494 max_priority_fee_per_gas: Option<U256>,
495 nonce: Option<U256>,
496 access_list: Vec<(H160, Vec<H256>)>,
497 authorization_list: AuthorizationList,
498 ) -> DispatchResultWithPostInfo {
499 T::CallOrigin::ensure_address_origin(&source, origin)?;
500
501 let is_transactional = true;
502 let validate = true;
503 let info = match T::Runner::create2(
504 source,
505 init,
506 salt,
507 value,
508 gas_limit,
509 Some(max_fee_per_gas),
510 max_priority_fee_per_gas,
511 nonce,
512 access_list,
513 authorization_list,
514 is_transactional,
515 validate,
516 None,
517 None,
518 T::config(),
519 ) {
520 Ok(info) => info,
521 Err(e) => {
522 return Err(DispatchErrorWithPostInfo {
523 post_info: PostDispatchInfo {
524 actual_weight: Some(e.weight),
525 pays_fee: Pays::Yes,
526 },
527 error: e.error.into(),
528 })
529 }
530 };
531
532 match info {
533 CreateInfo {
534 exit_reason: ExitReason::Succeed(_),
535 value: create_address,
536 ..
537 } => {
538 Pallet::<T>::deposit_event(Event::<T>::Created {
539 address: create_address,
540 });
541 }
542 CreateInfo {
543 exit_reason: _,
544 value: create_address,
545 ..
546 } => {
547 Pallet::<T>::deposit_event(Event::<T>::CreatedFailed {
548 address: create_address,
549 });
550 }
551 }
552
553 Ok(PostDispatchInfo {
554 actual_weight: {
555 let mut gas_to_weight = T::GasWeightMapping::gas_to_weight(
556 info.used_gas.standard.unique_saturated_into(),
557 true,
558 );
559 if let Some(weight_info) = info.weight_info {
560 if let Some(proof_size_usage) = weight_info.proof_size_usage {
561 *gas_to_weight.proof_size_mut() = proof_size_usage;
562 }
563 }
564 Some(gas_to_weight)
565 },
566 pays_fee: Pays::No,
567 })
568 }
569 }
570
571 #[pallet::event]
572 #[pallet::generate_deposit(pub(super) fn deposit_event)]
573 pub enum Event<T: Config> {
574 Log { log: Log },
576 Created { address: H160 },
578 CreatedFailed { address: H160 },
580 Executed { address: H160 },
582 ExecutedFailed { address: H160 },
584 }
585
586 #[pallet::error]
587 pub enum Error<T> {
588 BalanceLow,
590 FeeOverflow,
592 PaymentOverflow,
594 WithdrawFailed,
596 GasPriceTooLow,
598 InvalidNonce,
600 GasLimitTooLow,
602 GasLimitExceedsBlockLimit,
604 InvalidChainId,
606 InvalidSignature,
608 Reentrancy,
610 TransactionMustComeFromEOA,
612 Undefined,
614 CreateOriginNotAllowed,
616 TransactionGasLimitExceedsCap,
618 }
619
620 impl<T> From<TransactionValidationError> for Error<T> {
621 fn from(validation_error: TransactionValidationError) -> Self {
622 match validation_error {
623 TransactionValidationError::GasLimitTooLow => Error::<T>::GasLimitTooLow,
624 TransactionValidationError::GasLimitExceedsBlockLimit => {
625 Error::<T>::GasLimitExceedsBlockLimit
626 }
627 TransactionValidationError::BalanceTooLow => Error::<T>::BalanceLow,
628 TransactionValidationError::TxNonceTooLow => Error::<T>::InvalidNonce,
629 TransactionValidationError::TxNonceTooHigh => Error::<T>::InvalidNonce,
630 TransactionValidationError::GasPriceTooLow => Error::<T>::GasPriceTooLow,
631 TransactionValidationError::PriorityFeeTooHigh => Error::<T>::GasPriceTooLow,
632 TransactionValidationError::InvalidFeeInput => Error::<T>::GasPriceTooLow,
633 TransactionValidationError::InvalidChainId => Error::<T>::InvalidChainId,
634 TransactionValidationError::InvalidSignature => Error::<T>::InvalidSignature,
635 TransactionValidationError::EmptyAuthorizationList => Error::<T>::Undefined,
636 TransactionValidationError::AuthorizationListTooLarge => Error::<T>::Undefined,
637 TransactionValidationError::TransactionGasLimitExceedsCap => {
638 Error::<T>::TransactionGasLimitExceedsCap
639 }
640 TransactionValidationError::UnknownError => Error::<T>::Undefined,
641 }
642 }
643 }
644
645 #[pallet::genesis_config]
646 #[derive(frame_support::DefaultNoBound)]
647 pub struct GenesisConfig<T> {
648 pub accounts: BTreeMap<H160, GenesisAccount>,
649 #[serde(skip)]
650 pub _marker: PhantomData<T>,
651 }
652
653 #[pallet::genesis_build]
654 impl<T: Config> BuildGenesisConfig for GenesisConfig<T>
655 where
656 U256: UniqueSaturatedInto<BalanceOf<T>>,
657 {
658 fn build(&self) {
659 const MAX_ACCOUNT_NONCE: usize = 100;
660
661 for (address, account) in &self.accounts {
662 let account_id = T::AddressMapping::into_account_id(*address);
663
664 for _ in 0..min(
667 MAX_ACCOUNT_NONCE,
668 UniqueSaturatedInto::<usize>::unique_saturated_into(account.nonce),
669 ) {
670 T::AccountProvider::inc_account_nonce(&account_id);
671 }
672
673 let _ = T::Currency::deposit_creating(
674 &account_id,
675 account.balance.unique_saturated_into(),
676 );
677
678 let _ = Pallet::<T>::create_account(*address, account.code.clone(), None);
679
680 for (index, value) in &account.storage {
681 <AccountStorages<T>>::insert(address, index, value);
682 }
683 }
684 }
685 }
686
687 #[pallet::storage]
688 pub type AccountCodes<T: Config> = StorageMap<_, Blake2_128Concat, H160, Vec<u8>, ValueQuery>;
689
690 #[pallet::storage]
691 pub type AccountCodesMetadata<T: Config> =
692 StorageMap<_, Blake2_128Concat, H160, CodeMetadata, OptionQuery>;
693
694 #[pallet::storage]
695 pub type AccountStorages<T: Config> =
696 StorageDoubleMap<_, Blake2_128Concat, H160, Blake2_128Concat, H256, H256, ValueQuery>;
697}
698
699pub type AccountIdOf<T> = <<T as Config>::AccountProvider as AccountProvider>::AccountId;
701
702pub type BalanceOf<T> = <<T as Config>::Currency as Currency<AccountIdOf<T>>>::Balance;
704
705type NegativeImbalanceOf<C, T> = <C as Currency<AccountIdOf<T>>>::NegativeImbalance;
707
708#[derive(
709 Debug,
710 Clone,
711 Copy,
712 Eq,
713 PartialEq,
714 Encode,
715 Decode,
716 DecodeWithMemTracking,
717 TypeInfo,
718 MaxEncodedLen
719)]
720pub struct CodeMetadata {
721 pub size: u64,
722 pub hash: H256,
723}
724
725impl CodeMetadata {
726 pub fn from_code(code: &[u8]) -> Self {
727 let size = code.len() as u64;
728 let hash = H256::from(sp_io::hashing::keccak_256(code));
729
730 Self { size, hash }
731 }
732}
733
734pub trait EnsureAddressOrigin<OuterOrigin> {
735 type Success;
737
738 fn ensure_address_origin(
740 address: &H160,
741 origin: OuterOrigin,
742 ) -> Result<Self::Success, BadOrigin> {
743 Self::try_address_origin(address, origin).map_err(|_| BadOrigin)
744 }
745
746 fn try_address_origin(
748 address: &H160,
749 origin: OuterOrigin,
750 ) -> Result<Self::Success, OuterOrigin>;
751}
752
753pub struct EnsureAddressSame;
756
757impl<OuterOrigin> EnsureAddressOrigin<OuterOrigin> for EnsureAddressSame
758where
759 OuterOrigin: Into<Result<RawOrigin<H160>, OuterOrigin>> + From<RawOrigin<H160>>,
760{
761 type Success = H160;
762
763 fn try_address_origin(address: &H160, origin: OuterOrigin) -> Result<H160, OuterOrigin> {
764 origin.into().and_then(|o| match o {
765 RawOrigin::Signed(who) if &who == address => Ok(who),
766 r => Err(OuterOrigin::from(r)),
767 })
768 }
769}
770
771pub struct EnsureAddressRoot<AccountId>(core::marker::PhantomData<AccountId>);
773
774impl<OuterOrigin, AccountId> EnsureAddressOrigin<OuterOrigin> for EnsureAddressRoot<AccountId>
775where
776 OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>> + From<RawOrigin<AccountId>>,
777{
778 type Success = ();
779
780 fn try_address_origin(_address: &H160, origin: OuterOrigin) -> Result<(), OuterOrigin> {
781 origin.into().and_then(|o| match o {
782 RawOrigin::Root => Ok(()),
783 r => Err(OuterOrigin::from(r)),
784 })
785 }
786}
787
788pub struct EnsureAddressNever<AccountId>(core::marker::PhantomData<AccountId>);
790
791impl<OuterOrigin, AccountId> EnsureAddressOrigin<OuterOrigin> for EnsureAddressNever<AccountId> {
792 type Success = AccountId;
793
794 fn try_address_origin(_address: &H160, origin: OuterOrigin) -> Result<AccountId, OuterOrigin> {
795 Err(origin)
796 }
797}
798
799pub struct EnsureAddressTruncated;
802
803impl<OuterOrigin> EnsureAddressOrigin<OuterOrigin> for EnsureAddressTruncated
804where
805 OuterOrigin: Into<Result<RawOrigin<AccountId32>, OuterOrigin>> + From<RawOrigin<AccountId32>>,
806{
807 type Success = AccountId32;
808
809 fn try_address_origin(address: &H160, origin: OuterOrigin) -> Result<AccountId32, OuterOrigin> {
810 origin.into().and_then(|o| match o {
811 RawOrigin::Signed(who) if AsRef::<[u8; 32]>::as_ref(&who)[0..20] == address[0..20] => {
812 Ok(who)
813 }
814 r => Err(OuterOrigin::from(r)),
815 })
816 }
817}
818
819pub struct EnsureAccountId20;
821
822impl<OuterOrigin> EnsureAddressOrigin<OuterOrigin> for EnsureAccountId20
823where
824 OuterOrigin: Into<Result<RawOrigin<AccountId20>, OuterOrigin>> + From<RawOrigin<AccountId20>>,
825{
826 type Success = AccountId20;
827
828 fn try_address_origin(address: &H160, origin: OuterOrigin) -> Result<AccountId20, OuterOrigin> {
829 let acc: AccountId20 = AccountId20::from(*address);
830 origin.into().and_then(|o| match o {
831 RawOrigin::Signed(who) if who == acc => Ok(who),
832 r => Err(OuterOrigin::from(r)),
833 })
834 }
835}
836
837pub trait EnsureCreateOrigin<T> {
838 fn check_create_origin(address: &H160) -> Result<(), Error<T>>;
839}
840
841pub struct EnsureAllowedCreateAddress<AddressGetter>(core::marker::PhantomData<AddressGetter>);
842
843impl<AddressGetter, T: Config> EnsureCreateOrigin<T> for EnsureAllowedCreateAddress<AddressGetter>
844where
845 AddressGetter: Get<Vec<H160>>,
846{
847 fn check_create_origin(address: &H160) -> Result<(), Error<T>> {
848 if !AddressGetter::get().contains(address) {
849 return Err(Error::<T>::CreateOriginNotAllowed);
850 }
851 Ok(())
852 }
853}
854
855impl<T> EnsureCreateOrigin<T> for () {
856 fn check_create_origin(_address: &H160) -> Result<(), Error<T>> {
857 Ok(())
858 }
859}
860
861pub trait AddressMapping<A> {
863 fn into_account_id(address: H160) -> A;
864}
865
866pub struct IdentityAddressMapping;
868
869impl<T: From<H160>> AddressMapping<T> for IdentityAddressMapping {
870 fn into_account_id(address: H160) -> T {
871 address.into()
872 }
873}
874
875pub struct HashedAddressMapping<H>(core::marker::PhantomData<H>);
877
878impl<H: Hasher<Out = H256>> AddressMapping<AccountId32> for HashedAddressMapping<H> {
879 fn into_account_id(address: H160) -> AccountId32 {
880 let mut data = [0u8; 24];
881 data[0..4].copy_from_slice(b"evm:");
882 data[4..24].copy_from_slice(&address[..]);
883 let hash = H::hash(&data);
884
885 AccountId32::from(Into::<[u8; 32]>::into(hash))
886 }
887}
888
889pub trait BlockHashMapping {
891 fn block_hash(number: u32) -> H256;
892}
893
894pub struct SubstrateBlockHashMapping<T>(core::marker::PhantomData<T>);
896impl<T: Config> BlockHashMapping for SubstrateBlockHashMapping<T> {
897 fn block_hash(number: u32) -> H256 {
898 let number = <NumberFor<T::Block>>::from(number);
899 H256::from_slice(frame_system::Pallet::<T>::block_hash(number).as_ref())
900 }
901}
902
903pub trait GasWeightMapping {
905 fn gas_to_weight(gas: u64, without_base_weight: bool) -> Weight;
906 fn weight_to_gas(weight: Weight) -> u64;
907}
908
909pub trait FixedGasWeightMappingAssociatedTypes {
910 type WeightPerGas: Get<Weight>;
911 type BlockWeights: Get<frame_system::limits::BlockWeights>;
912 type GasLimitPovSizeRatio: Get<u64>;
913}
914
915impl<T: Config> FixedGasWeightMappingAssociatedTypes for T {
916 type WeightPerGas = T::WeightPerGas;
917 type BlockWeights = T::BlockWeights;
918 type GasLimitPovSizeRatio = T::GasLimitPovSizeRatio;
919}
920
921pub struct FixedGasWeightMapping<T>(core::marker::PhantomData<T>);
922impl<T> GasWeightMapping for FixedGasWeightMapping<T>
923where
924 T: FixedGasWeightMappingAssociatedTypes,
925{
926 fn gas_to_weight(gas: u64, without_base_weight: bool) -> Weight {
927 let mut weight = T::WeightPerGas::get().saturating_mul(gas);
928 if without_base_weight {
929 weight = weight.saturating_sub(
930 T::BlockWeights::get()
931 .get(frame_support::dispatch::DispatchClass::Normal)
932 .base_extrinsic,
933 );
934 }
935 let ratio = T::GasLimitPovSizeRatio::get();
937 if ratio > 0 {
938 let proof_size = gas.saturating_div(ratio);
939 *weight.proof_size_mut() = proof_size;
940 }
941
942 weight
943 }
944 fn weight_to_gas(weight: Weight) -> u64 {
945 weight.div(T::WeightPerGas::get().ref_time()).ref_time()
946 }
947}
948
949impl<T: Config> Pallet<T> {
950 pub fn is_account_empty(address: &H160) -> bool {
952 let (account, _) = Self::account_basic(address);
953 let code_len = <AccountCodes<T>>::decode_len(address).unwrap_or(0);
954
955 account.nonce == U256::zero() && account.balance == U256::zero() && code_len == 0
956 }
957
958 pub fn iter_account_storages(address: &H160) -> KeyPrefixIterator<H256> {
959 <AccountStorages<T>>::iter_key_prefix(address)
960 }
961
962 pub fn remove_account_if_empty(address: &H160) {
964 if Self::is_account_empty(address) {
965 Self::remove_account(address);
966 }
967 }
968
969 pub fn remove_account(address: &H160) {
971 let account_id = T::AddressMapping::into_account_id(*address);
972 T::AccountProvider::remove_account(&account_id);
973
974 <AccountCodes<T>>::remove(address);
975 <AccountCodesMetadata<T>>::remove(address);
976 let _ = <AccountStorages<T>>::clear_prefix(address, u32::MAX, None);
977 }
978
979 pub fn remove_account_code(address: &H160) {
981 <AccountCodes<T>>::remove(address);
982 <AccountCodesMetadata<T>>::remove(address);
983 }
984
985 pub fn create_account(
987 address: H160,
988 code: Vec<u8>,
989 caller: Option<H160>,
990 ) -> Result<(), ExitError> {
991 if let Some(caller_address) = caller {
992 T::CreateInnerOriginFilter::check_create_origin(&caller_address).map_err(|e| {
993 let error: &'static str = e.into();
994 ExitError::Other(Cow::Borrowed(error))
995 })?;
996 }
997
998 if code.is_empty() {
999 return Ok(());
1000 }
1001
1002 if !<AccountCodes<T>>::contains_key(address) {
1003 let account_id = T::AddressMapping::into_account_id(address);
1004 T::AccountProvider::create_account(&account_id);
1005 }
1006
1007 let meta = CodeMetadata::from_code(&code);
1009 <AccountCodesMetadata<T>>::insert(address, meta);
1010
1011 <AccountCodes<T>>::insert(address, code);
1012 Ok(())
1013 }
1014
1015 pub fn account_code_metadata(address: H160) -> CodeMetadata {
1018 if let Some(meta) = <AccountCodesMetadata<T>>::get(address) {
1019 return meta;
1020 }
1021
1022 let code = <AccountCodes<T>>::get(address);
1023
1024 if code.is_empty() {
1027 const EMPTY_CODE_HASH: [u8; 32] = hex_literal::hex!(
1028 "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
1029 );
1030 return CodeMetadata {
1031 size: 0,
1032 hash: EMPTY_CODE_HASH.into(),
1033 };
1034 }
1035
1036 let meta = CodeMetadata::from_code(&code);
1037
1038 <AccountCodesMetadata<T>>::insert(address, meta);
1039 meta
1040 }
1041
1042 pub fn account_basic(address: &H160) -> (Account, frame_support::weights::Weight) {
1044 let account_id = T::AddressMapping::into_account_id(*address);
1045 let nonce = T::AccountProvider::account_nonce(&account_id);
1046 let balance =
1047 T::Currency::reducible_balance(&account_id, Preservation::Preserve, Fortitude::Polite);
1048
1049 (
1050 Account {
1051 nonce: U256::from(UniqueSaturatedInto::<u128>::unique_saturated_into(nonce)),
1052 balance: U256::from(UniqueSaturatedInto::<u128>::unique_saturated_into(balance)),
1053 },
1054 T::DbWeight::get().reads(2),
1055 )
1056 }
1057
1058 pub fn find_author() -> H160 {
1060 let digest = <frame_system::Pallet<T>>::digest();
1061 let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());
1062
1063 T::FindAuthor::find_author(pre_runtime_digests).unwrap_or_default()
1064 }
1065}
1066
1067pub trait OnChargeEVMTransaction<T: Config> {
1070 type LiquidityInfo: Default;
1071
1072 fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>>;
1075
1076 fn correct_and_deposit_fee(
1082 who: &H160,
1083 corrected_fee: U256,
1084 base_fee: U256,
1085 already_withdrawn: Self::LiquidityInfo,
1086 ) -> Self::LiquidityInfo;
1087
1088 fn pay_priority_fee(tip: Self::LiquidityInfo);
1090}
1091
1092pub struct EVMCurrencyAdapter<C, OU>(core::marker::PhantomData<(C, OU)>);
1097
1098impl<T, C, OU> OnChargeEVMTransaction<T> for EVMCurrencyAdapter<C, OU>
1099where
1100 T: Config,
1101 C: Currency<AccountIdOf<T>>,
1102 C::PositiveImbalance:
1103 Imbalance<<C as Currency<AccountIdOf<T>>>::Balance, Opposite = C::NegativeImbalance>,
1104 C::NegativeImbalance:
1105 Imbalance<<C as Currency<AccountIdOf<T>>>::Balance, Opposite = C::PositiveImbalance>,
1106 OU: OnUnbalanced<NegativeImbalanceOf<C, T>>,
1107 U256: UniqueSaturatedInto<<C as Currency<AccountIdOf<T>>>::Balance>,
1108{
1109 type LiquidityInfo = Option<NegativeImbalanceOf<C, T>>;
1111
1112 fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
1113 if fee.is_zero() {
1114 return Ok(None);
1115 }
1116 let account_id = T::AddressMapping::into_account_id(*who);
1117 let imbalance = C::withdraw(
1118 &account_id,
1119 fee.unique_saturated_into(),
1120 WithdrawReasons::FEE,
1121 ExistenceRequirement::AllowDeath,
1122 )
1123 .map_err(|_| Error::<T>::BalanceLow)?;
1124 Ok(Some(imbalance))
1125 }
1126
1127 fn correct_and_deposit_fee(
1128 who: &H160,
1129 corrected_fee: U256,
1130 base_fee: U256,
1131 already_withdrawn: Self::LiquidityInfo,
1132 ) -> Self::LiquidityInfo {
1133 if let Some(paid) = already_withdrawn {
1134 let account_id = T::AddressMapping::into_account_id(*who);
1135
1136 let refund_amount = paid
1138 .peek()
1139 .saturating_sub(corrected_fee.unique_saturated_into());
1140 let refund_imbalance = C::deposit_into_existing(&account_id, refund_amount)
1144 .unwrap_or_else(|_| C::PositiveImbalance::zero());
1145
1146 let refund_imbalance = if C::minimum_balance().is_zero()
1151 && refund_amount > C::Balance::zero()
1152 && C::total_balance(&account_id).is_zero()
1153 {
1154 match C::make_free_balance_be(&account_id, refund_amount) {
1157 SignedImbalance::Positive(p) => p,
1158 _ => C::PositiveImbalance::zero(),
1159 }
1160 } else {
1161 refund_imbalance
1162 };
1163
1164 let adjusted_paid = paid
1166 .offset(refund_imbalance)
1167 .same()
1168 .unwrap_or_else(|_| C::NegativeImbalance::zero());
1169
1170 let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
1171 OU::on_unbalanced(base_fee);
1173 return Some(tip);
1174 }
1175 None
1176 }
1177
1178 fn pay_priority_fee(tip: Self::LiquidityInfo) {
1179 if let Some(tip) = tip {
1181 let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
1182 let _ = C::deposit_into_existing(&account_id, tip.peek());
1183 }
1184 }
1185}
1186pub struct EVMFungibleAdapter<F, OU>(core::marker::PhantomData<(F, OU)>);
1193
1194impl<T, F, OU> OnChargeEVMTransaction<T> for EVMFungibleAdapter<F, OU>
1195where
1196 T: Config,
1197 F: Balanced<AccountIdOf<T>>,
1198 OU: OnUnbalanced<Credit<AccountIdOf<T>, F>>,
1199 U256: UniqueSaturatedInto<<F as Inspect<AccountIdOf<T>>>::Balance>,
1200{
1201 type LiquidityInfo = Option<Credit<AccountIdOf<T>, F>>;
1203
1204 fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
1205 if fee.is_zero() {
1206 return Ok(None);
1207 }
1208 let account_id = T::AddressMapping::into_account_id(*who);
1209 let imbalance = F::withdraw(
1210 &account_id,
1211 fee.unique_saturated_into(),
1212 Precision::Exact,
1213 Preservation::Preserve,
1214 Fortitude::Polite,
1215 )
1216 .map_err(|_| Error::<T>::BalanceLow)?;
1217 Ok(Some(imbalance))
1218 }
1219
1220 fn correct_and_deposit_fee(
1221 who: &H160,
1222 corrected_fee: U256,
1223 base_fee: U256,
1224 already_withdrawn: Self::LiquidityInfo,
1225 ) -> Self::LiquidityInfo {
1226 if let Some(paid) = already_withdrawn {
1227 let account_id = T::AddressMapping::into_account_id(*who);
1228
1229 let refund_amount = paid
1231 .peek()
1232 .saturating_sub(corrected_fee.unique_saturated_into());
1233 let refund_imbalance = F::deposit(&account_id, refund_amount, Precision::BestEffort)
1235 .unwrap_or_else(|_| Debt::<AccountIdOf<T>, F>::zero());
1236
1237 let adjusted_paid = paid
1239 .offset(refund_imbalance)
1240 .same()
1241 .unwrap_or_else(|_| Credit::<AccountIdOf<T>, F>::zero());
1242
1243 let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
1244 OU::on_unbalanced(base_fee);
1246 return Some(tip);
1247 }
1248 None
1249 }
1250
1251 fn pay_priority_fee(tip: Self::LiquidityInfo) {
1252 if let Some(tip) = tip {
1254 let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
1255 let _ = F::deposit(&account_id, tip.peek(), Precision::BestEffort);
1256 }
1257 }
1258}
1259
1260impl<T> OnChargeEVMTransaction<T> for ()
1262where
1263 T: Config,
1264 T::Currency: Balanced<AccountIdOf<T>>,
1265 U256: UniqueSaturatedInto<<<T as Config>::Currency as Inspect<AccountIdOf<T>>>::Balance>,
1266{
1267 type LiquidityInfo = Option<Credit<AccountIdOf<T>, T::Currency>>;
1269
1270 fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
1271 EVMFungibleAdapter::<T::Currency, ()>::withdraw_fee(who, fee)
1272 }
1273
1274 fn correct_and_deposit_fee(
1275 who: &H160,
1276 corrected_fee: U256,
1277 base_fee: U256,
1278 already_withdrawn: Self::LiquidityInfo,
1279 ) -> Self::LiquidityInfo {
1280 <EVMFungibleAdapter<T::Currency, ()> as OnChargeEVMTransaction<T>>::correct_and_deposit_fee(
1281 who,
1282 corrected_fee,
1283 base_fee,
1284 already_withdrawn,
1285 )
1286 }
1287
1288 fn pay_priority_fee(tip: Self::LiquidityInfo) {
1289 <EVMFungibleAdapter<T::Currency, ()> as OnChargeEVMTransaction<T>>::pay_priority_fee(tip);
1290 }
1291}
1292
1293pub trait OnCreate<T> {
1294 fn on_create(owner: H160, contract: H160);
1295}
1296
1297impl<T> OnCreate<T> for () {
1298 fn on_create(_owner: H160, _contract: H160) {}
1299}
1300
1301#[impl_for_tuples(1, 12)]
1302impl<T> OnCreate<T> for Tuple {
1303 fn on_create(owner: H160, contract: H160) {
1304 for_tuples!(#(
1305 Tuple::on_create(owner, contract);
1306 )*)
1307 }
1308}
1309
1310pub struct FrameSystemAccountProvider<T>(core::marker::PhantomData<T>);
1314
1315impl<T: frame_system::Config> AccountProvider for FrameSystemAccountProvider<T> {
1316 type AccountId = T::AccountId;
1317 type Nonce = T::Nonce;
1318
1319 fn account_nonce(who: &Self::AccountId) -> Self::Nonce {
1320 frame_system::Pallet::<T>::account_nonce(who)
1321 }
1322
1323 fn inc_account_nonce(who: &Self::AccountId) {
1324 frame_system::Pallet::<T>::inc_account_nonce(who)
1325 }
1326
1327 fn create_account(who: &Self::AccountId) {
1328 let _ = frame_system::Pallet::<T>::inc_sufficients(who);
1329 }
1330
1331 fn remove_account(who: &Self::AccountId) {
1332 let _ = frame_system::Pallet::<T>::dec_sufficients(who);
1333 }
1334}