1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]18#![feature(is_some_with)]1920use codec::{Decode, Encode, MaxEncodedLen};21pub use pallet::*;22pub use eth::*;23use scale_info::TypeInfo;24pub mod eth;2526#[frame_support::pallet]27pub mod pallet {28 pub use super::*;29 use frame_support::pallet_prelude::*;30 use sp_core::H160;31 use pallet_evm::account::CrossAccountId;32 use frame_system::pallet_prelude::BlockNumberFor;3334 #[pallet::config]35 pub trait Config:36 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config37 {38 type ContractAddress: Get<H160>;39 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;40 }4142 #[pallet::error]43 pub enum Error<T> {44 45 NoPermission,4647 48 NoContractOwner,49 }5051 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);5253 #[pallet::pallet]54 #[pallet::storage_version(STORAGE_VERSION)]55 #[pallet::generate_store(pub(super) trait Store)]56 pub struct Pallet<T>(_);5758 59 60 61 62 #[pallet::storage]63 pub(super) type Owner<T: Config> = StorageMap<64 Hasher = Twox128,65 Key = H160,66 Value = T::CrossAccountId,67 QueryKind = OptionQuery,68 >;6970 #[pallet::storage]71 #[deprecated]72 pub(super) type SelfSponsoring<T: Config> =73 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;7475 76 77 78 79 80 81 82 #[pallet::storage]83 pub(super) type SponsoringMode<T: Config> =84 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;8586 87 88 89 90 #[pallet::storage]91 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<92 Hasher = Twox128,93 Key = H160,94 Value = T::BlockNumber,95 QueryKind = ValueQuery,96 OnEmpty = T::DefaultSponsoringRateLimit,97 >;9899 #[pallet::storage]100 #[deprecated]101 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<102 Hasher1 = Twox128,103 Key1 = H160,104 Hasher2 = Twox128,105 Key2 = H160,106 Value = T::BlockNumber,107 QueryKind = OptionQuery,108 >;109110 111 112 113 114 115 116 117 #[pallet::storage]118 pub(super) type AllowlistEnabled<T: Config> =119 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;120121 #[pallet::storage]122 #[deprecated]123 pub(super) type Allowlist<T: Config> = StorageDoubleMap<124 Hasher1 = Twox128,125 Key1 = H160,126 Hasher2 = Twox128,127 Key2 = H160,128 Value = bool,129 QueryKind = ValueQuery,130 >;131132 #[pallet::hooks]133 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {134 fn on_runtime_upgrade() -> Weight {135 let storage_version = StorageVersion::get::<Pallet<T>>();136 if storage_version < StorageVersion::new(1) {137 <Owner<T>>::translate_values::<H160, _>(|address| Some(T::CrossAccountId::from_eth(address)));138 }139140 0141 }142 }143144 impl<T: Config> Pallet<T> {145 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {146 <SponsoringMode<T>>::get(contract)147 .or_else(|| {148 <SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)149 })150 .unwrap_or_default()151 }152 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {153 if mode == SponsoringModeT::Disabled {154 <SponsoringMode<T>>::remove(contract);155 } else {156 <SponsoringMode<T>>::insert(contract, mode);157 }158 <SelfSponsoring<T>>::remove(contract)159 }160161 pub fn toggle_sponsoring(contract: H160, enabled: bool) {162 Self::set_sponsoring_mode(163 contract,164 if enabled {165 SponsoringModeT::Allowlisted166 } else {167 SponsoringModeT::Disabled168 },169 )170 }171172 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {173 <SponsoringRateLimit<T>>::insert(contract, rate_limit);174 }175176 pub fn allowed(contract: H160, user: T::CrossAccountId) -> bool {177 <Allowlist<T>>::get(&contract, user.as_eth())178 || Pallet::<T>::contract_owner(contract).is_ok_and(|owner| *owner == user)179 }180181 pub fn toggle_allowlist(contract: H160, enabled: bool) {182 <AllowlistEnabled<T>>::insert(contract, enabled)183 }184185 pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {186 <Allowlist<T>>::insert(contract, user, allowed);187 }188189 pub fn ensure_owner(contract: H160, user: H160) -> evm_coder::execution::Result<()> {190 ensure!(Pallet::<T>::contract_owner(contract).is_ok_and(|owner| *owner.as_eth() == user), "no permission");191 Ok(())192 }193 }194195 impl<T: Config> Pallet<T> {196 pub fn contract_owner(contract: H160) -> Result<T::CrossAccountId, DispatchError> {197 Ok(<Owner<T>>::get(contract).ok_or::<Error<T>>(Error::NoContractOwner)?)198 }199 }200}201202#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]203pub enum SponsoringModeT {204 Disabled,205 Allowlisted,206 Generous,207}208209impl SponsoringModeT {210 fn from_eth(v: u8) -> Option<Self> {211 Some(match v {212 0 => Self::Disabled,213 1 => Self::Allowlisted,214 2 => Self::Generous,215 _ => return None,216 })217 }218 fn to_eth(self) -> u8 {219 match self {220 SponsoringModeT::Disabled => 0,221 SponsoringModeT::Allowlisted => 1,222 SponsoringModeT::Generous => 2,223 }224 }225}226227impl Default for SponsoringModeT {228 fn default() -> Self {229 Self::Disabled230 }231}