1234567891011121314151617#![doc = include_str!("../README.md")]18#![cfg_attr(not(feature = "std"), no_std)]19#![warn(missing_docs)]2021use codec::{Decode, Encode, MaxEncodedLen};22pub use pallet::*;23pub use eth::*;24use scale_info::TypeInfo;25use frame_support::storage::bounded_btree_map::BoundedBTreeMap;26pub mod eth;272829pub const MAX_FEE_LIMITED_METHODS: u32 = 5;3031#[frame_support::pallet]32pub mod pallet {33 pub use super::*;34 use crate::eth::ContractHelpersEvents;35 use frame_support::pallet_prelude::*;36 use pallet_evm_coder_substrate::DispatchResult;37 use sp_core::{H160, U256};38 use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};39 use up_data_structs::SponsorshipState;40 use evm_coder::ToLog;4142 #[pallet::config]43 pub trait Config:44 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config45 {46 47 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;4849 50 type ContractAddress: Get<H160>;5152 53 54 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;55 }5657 #[pallet::error]58 pub enum Error<T> {59 60 NoPermission,6162 63 NoPendingSponsor,6465 66 TooManyMethodsHaveSponsoredLimit,67 }6869 #[pallet::pallet]70 #[pallet::generate_store(pub(super) trait Store)]71 pub struct Pallet<T>(_);7273 74 75 76 77 #[pallet::storage]78 pub(super) type Owner<T: Config> =79 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;8081 #[pallet::storage]82 #[deprecated]83 pub(super) type SelfSponsoring<T: Config> =84 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;8586 87 88 89 90 #[pallet::storage]91 pub(super) type Sponsoring<T: Config> = StorageMap<92 Hasher = Twox64Concat,93 Key = H160,94 Value = SponsorshipState<T::CrossAccountId>,95 QueryKind = ValueQuery,96 >;9798 99 100 101 102 103 104 105 #[pallet::storage]106 pub(super) type SponsoringMode<T: Config> =107 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;108109 110 111 112 113 #[pallet::storage]114 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<115 Hasher = Twox128,116 Key = H160,117 Value = T::BlockNumber,118 QueryKind = ValueQuery,119 OnEmpty = T::DefaultSponsoringRateLimit,120 >;121122 123 124 125 126 127 #[pallet::storage]128 pub(super) type SponsoringFeeLimit<T: Config> = StorageMap<129 Hasher = Twox128,130 Key = H160,131 Value = BoundedBTreeMap<u32, U256, ConstU32<MAX_FEE_LIMITED_METHODS>>,132 QueryKind = ValueQuery,133 >;134135 #[pallet::storage]136 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<137 Hasher1 = Twox128,138 Key1 = H160,139 Hasher2 = Twox128,140 Key2 = H160,141 Value = T::BlockNumber,142 QueryKind = OptionQuery,143 >;144145 146 147 148 149 150 151 152 #[pallet::storage]153 pub(super) type AllowlistEnabled<T: Config> =154 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;155156 157 158 159 160 161 162 163 164 #[pallet::storage]165 pub(super) type Allowlist<T: Config> = StorageDoubleMap<166 Hasher1 = Twox128,167 Key1 = H160,168 Hasher2 = Twox128,169 Key2 = H160,170 Value = bool,171 QueryKind = ValueQuery,172 >;173174 #[pallet::event]175 #[pallet::generate_deposit(pub fn deposit_event)]176 pub enum Event<T: Config> {177 178 ContractSponsorSet(179 180 H160,181 182 T::AccountId,183 ),184185 186 ContractSponsorshipConfirmed(187 188 H160,189 190 T::AccountId,191 ),192193 194 ContractSponsorRemoved(195 196 H160,197 ),198 }199200 impl<T: Config> Pallet<T> {201 202 pub fn contract_owner(contract: H160) -> H160 {203 <Owner<T>>::get(contract)204 }205206 207 208 209 pub fn set_sponsor(210 sender: &T::CrossAccountId,211 contract: H160,212 sponsor: &T::CrossAccountId,213 ) -> DispatchResult {214 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;215 Sponsoring::<T>::insert(216 contract,217 SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),218 );219220 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(221 contract,222 sponsor.as_sub().clone(),223 ));224 <PalletEvm<T>>::deposit_log(225 ContractHelpersEvents::ContractSponsorSet {226 contract_address: contract,227 sponsor: *sponsor.as_eth(),228 }229 .to_log(contract),230 );231 Ok(())232 }233234 235 236 237 pub fn force_set_sponsor(238 contract_address: H160,239 sponsor: &T::CrossAccountId,240 ) -> DispatchResult {241 Sponsoring::<T>::insert(242 contract_address,243 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor.clone()),244 );245246 let eth_sponsor = *sponsor.as_eth();247 let sub_sponsor = sponsor.as_sub().clone();248249 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(250 contract_address,251 sub_sponsor.clone(),252 ));253 <PalletEvm<T>>::deposit_log(254 ContractHelpersEvents::ContractSponsorSet {255 contract_address,256 sponsor: eth_sponsor,257 }258 .to_log(contract_address),259 );260261 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(262 contract_address,263 sub_sponsor,264 ));265 <PalletEvm<T>>::deposit_log(266 ContractHelpersEvents::ContractSponsorshipConfirmed {267 contract_address,268 sponsor: eth_sponsor,269 }270 .to_log(contract_address),271 );272273 Ok(())274 }275276 277 278 279 pub fn remove_sponsor(280 sender: &T::CrossAccountId,281 contract_address: H160,282 ) -> DispatchResult {283 Self::ensure_owner(contract_address, *sender.as_eth())?;284 Self::force_remove_sponsor(contract_address)285 }286287 288 289 290 pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {291 Sponsoring::<T>::remove(contract_address);292293 Self::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));294 <PalletEvm<T>>::deposit_log(295 ContractHelpersEvents::ContractSponsorRemoved { contract_address }296 .to_log(contract_address),297 );298299 Ok(())300 }301302 303 304 305 pub fn confirm_sponsorship(306 sender: &T::CrossAccountId,307 contract_address: H160,308 ) -> DispatchResult {309 match Sponsoring::<T>::get(contract_address) {310 SponsorshipState::Unconfirmed(sponsor) => {311 ensure!(sponsor == *sender, Error::<T>::NoPermission);312 let eth_sponsor = *sponsor.as_eth();313 let sub_sponsor = sponsor.as_sub().clone();314 Sponsoring::<T>::insert(315 contract_address,316 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),317 );318319 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(320 contract_address,321 sub_sponsor,322 ));323 <PalletEvm<T>>::deposit_log(324 ContractHelpersEvents::ContractSponsorshipConfirmed {325 contract_address,326 sponsor: eth_sponsor,327 }328 .to_log(contract_address),329 );330331 Ok(())332 }333 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {334 Err(Error::<T>::NoPendingSponsor.into())335 }336 }337 }338339 340 pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {341 match Sponsoring::<T>::get(contract) {342 SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,343 SponsorshipState::Confirmed(sponsor) => Some(sponsor),344 }345 }346347 348 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {349 <SponsoringMode<T>>::get(contract)350 .or_else(|| {351 <SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)352 })353 .unwrap_or_default()354 }355356 357 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {358 if mode == SponsoringModeT::Disabled {359 <SponsoringMode<T>>::remove(contract);360 } else {361 <SponsoringMode<T>>::insert(contract, mode);362 }363 <SelfSponsoring<T>>::remove(contract)364 }365366 367 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {368 <SponsoringRateLimit<T>>::insert(contract, rate_limit);369 }370371 372 pub fn set_sponsoring_fee_limit(contract: H160, fee_limit: U256) -> DispatchResult {373 <SponsoringFeeLimit<T>>::try_mutate(contract, |limits_map| {374 limits_map375 .try_insert(0xffffffff, fee_limit)376 .map_err(|_| <Error<T>>::TooManyMethodsHaveSponsoredLimit)377 })?;378 Ok(())379 }380381 382 pub fn allowed(contract: H160, user: H160) -> bool {383 <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user384 }385386 387 pub fn toggle_allowlist(contract: H160, enabled: bool) {388 <AllowlistEnabled<T>>::insert(contract, enabled)389 }390391 392 pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {393 <Allowlist<T>>::insert(contract, user, allowed);394 }395396 397 pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {398 ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);399 Ok(())400 }401 }402}403404405#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]406pub enum SponsoringModeT {407 408 #[default]409 Disabled,410 411 Allowlisted,412 413 Generous,414}415416impl SponsoringModeT {417 fn from_eth(v: u8) -> Option<Self> {418 Some(match v {419 0 => Self::Disabled,420 1 => Self::Allowlisted,421 2 => Self::Generous,422 _ => return None,423 })424 }425 fn to_eth(self) -> u8 {426 match self {427 SponsoringModeT::Disabled => 0,428 SponsoringModeT::Allowlisted => 1,429 SponsoringModeT::Generous => 2,430 }431 }432}