1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]1819use core::marker::PhantomData;2021use frame_support::{22 pallet,23 weights::{WeightToFeePolynomial, WeightToFeeCoefficients, WeightToFeeCoefficient, Weight},24 traits::Get,25};26use parity_scale_codec::{Decode, Encode, MaxEncodedLen};27use scale_info::TypeInfo;28use sp_arithmetic::{29 per_things::{Perbill, PerThing},30 traits::{BaseArithmetic, Unsigned},31};32use smallvec::smallvec;3334pub use pallet::*;35use sp_core::U256;3637#[cfg(feature = "runtime-benchmarks")]38mod benchmarking;39pub mod weights;4041#[pallet]42mod pallet {43 use super::*;44 use frame_support::{45 traits::{Get, ReservableCurrency, Currency},46 pallet_prelude::{StorageValue, ValueQuery, DispatchResult, IsType, OptionQuery},47 BoundedVec, log,48 };49 use frame_system::{pallet_prelude::OriginFor, ensure_root, Config as SystemConfig};50 use xcm::v1::MultiLocation;5152 pub use crate::weights::WeightInfo;53 pub type BalanceOf<T> =54 <<T as Config>::Currency as Currency<<T as SystemConfig>::AccountId>>::Balance;5556 #[pallet::config]57 pub trait Config: frame_system::Config {58 59 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;6061 62 type Currency: ReservableCurrency<Self::AccountId>;6364 #[pallet::constant]65 type DefaultWeightToFeeCoefficient: Get<u64>;66 #[pallet::constant]67 type DefaultMinGasPrice: Get<u64>;6869 #[pallet::constant]70 type MaxXcmAllowedLocations: Get<u32>;71 #[pallet::constant]72 type AppPromotionDailyRate: Get<Perbill>;73 #[pallet::constant]74 type DayRelayBlocks: Get<Self::BlockNumber>;7576 #[pallet::constant]77 type DefaultCollatorSelectionMaxCollators: Get<u32>;78 #[pallet::constant]79 type DefaultCollatorSelectionLicenseBond: Get<BalanceOf<Self>>;80 #[pallet::constant]81 type DefaultCollatorSelectionKickThreshold: Get<Self::BlockNumber>;8283 84 type WeightInfo: WeightInfo;85 }8687 #[pallet::event]88 #[pallet::generate_deposit(pub(super) fn deposit_event)]89 pub enum Event<T: Config> {90 NewDesiredCollators {91 desired_collators: Option<u32>,92 },93 NewCollatorLicenseBond {94 bond_cost: Option<BalanceOf<T>>,95 },96 NewCollatorKickThreshold {97 length_in_blocks: Option<T::BlockNumber>,98 },99 }100101 #[pallet::error]102 pub enum Error<T> {103 InconsistentConfiguration,104 }105106 #[pallet::storage]107 pub type WeightToFeeCoefficientOverride<T: Config> = StorageValue<108 Value = u64,109 QueryKind = ValueQuery,110 OnEmpty = T::DefaultWeightToFeeCoefficient,111 >;112113 #[pallet::storage]114 pub type MinGasPriceOverride<T: Config> =115 StorageValue<Value = u64, QueryKind = ValueQuery, OnEmpty = T::DefaultMinGasPrice>;116117 #[pallet::storage]118 pub type XcmAllowedLocationsOverride<T: Config> = StorageValue<119 Value = BoundedVec<MultiLocation, T::MaxXcmAllowedLocations>,120 QueryKind = OptionQuery,121 >;122123 #[pallet::storage]124 pub type AppPromomotionConfigurationOverride<T: Config> =125 StorageValue<Value = AppPromotionConfiguration<T::BlockNumber>, QueryKind = ValueQuery>;126127 #[pallet::storage]128 pub type CollatorSelectionDesiredCollatorsOverride<T: Config> = StorageValue<129 Value = u32,130 QueryKind = ValueQuery,131 OnEmpty = T::DefaultCollatorSelectionMaxCollators,132 >;133134 #[pallet::storage]135 pub type CollatorSelectionLicenseBondOverride<T: Config> = StorageValue<136 Value = BalanceOf<T>,137 QueryKind = ValueQuery,138 OnEmpty = T::DefaultCollatorSelectionLicenseBond,139 >;140141 #[pallet::storage]142 pub type CollatorSelectionKickThresholdOverride<T: Config> = StorageValue<143 Value = T::BlockNumber,144 QueryKind = ValueQuery,145 OnEmpty = T::DefaultCollatorSelectionKickThreshold,146 >;147148 #[pallet::call]149 impl<T: Config> Pallet<T> {150 #[pallet::call_index(0)]151 #[pallet::weight(T::WeightInfo::set_weight_to_fee_coefficient_override())]152 pub fn set_weight_to_fee_coefficient_override(153 origin: OriginFor<T>,154 coeff: Option<u64>,155 ) -> DispatchResult {156 ensure_root(origin)?;157 if let Some(coeff) = coeff {158 <WeightToFeeCoefficientOverride<T>>::set(coeff);159 } else {160 <WeightToFeeCoefficientOverride<T>>::kill();161 }162 Ok(())163 }164165 #[pallet::call_index(1)]166 #[pallet::weight(T::WeightInfo::set_min_gas_price_override())]167 pub fn set_min_gas_price_override(168 origin: OriginFor<T>,169 coeff: Option<u64>,170 ) -> DispatchResult {171 ensure_root(origin)?;172 if let Some(coeff) = coeff {173 <MinGasPriceOverride<T>>::set(coeff);174 } else {175 <MinGasPriceOverride<T>>::kill();176 }177 Ok(())178 }179180 #[pallet::call_index(2)]181 #[pallet::weight(T::WeightInfo::set_xcm_allowed_locations())]182 pub fn set_xcm_allowed_locations(183 origin: OriginFor<T>,184 locations: Option<BoundedVec<MultiLocation, T::MaxXcmAllowedLocations>>,185 ) -> DispatchResult {186 ensure_root(origin)?;187 <XcmAllowedLocationsOverride<T>>::set(locations);188 Ok(())189 }190191 #[pallet::call_index(3)]192 #[pallet::weight(T::WeightInfo::set_app_promotion_configuration_override())]193 pub fn set_app_promotion_configuration_override(194 origin: OriginFor<T>,195 mut configuration: AppPromotionConfiguration<T::BlockNumber>,196 ) -> DispatchResult {197 ensure_root(origin)?;198 if configuration.interval_income.is_some() {199 return Err(<Error<T>>::InconsistentConfiguration.into());200 }201202 configuration.interval_income = configuration.recalculation_interval.map(|b| {203 Perbill::from_rational(b, T::DayRelayBlocks::get())204 * T::AppPromotionDailyRate::get()205 });206207 <AppPromomotionConfigurationOverride<T>>::set(configuration);208209 Ok(())210 }211212 #[pallet::call_index(4)]213 #[pallet::weight(T::WeightInfo::set_collator_selection_desired_collators())]214 pub fn set_collator_selection_desired_collators(215 origin: OriginFor<T>,216 max: Option<u32>,217 ) -> DispatchResult {218 ensure_root(origin)?;219 if let Some(max) = max {220 221 if max > T::DefaultCollatorSelectionMaxCollators::get() {222 log::warn!("max > T::DefaultCollatorSelectionMaxCollators; you might need to run benchmarks again");223 }224 <CollatorSelectionDesiredCollatorsOverride<T>>::set(max);225 } else {226 <CollatorSelectionDesiredCollatorsOverride<T>>::kill();227 }228 Self::deposit_event(Event::NewDesiredCollators {229 desired_collators: max,230 });231 Ok(())232 }233234 #[pallet::call_index(5)]235 #[pallet::weight(T::WeightInfo::set_collator_selection_license_bond())]236 pub fn set_collator_selection_license_bond(237 origin: OriginFor<T>,238 amount: Option<BalanceOf<T>>,239 ) -> DispatchResult {240 ensure_root(origin)?;241 if let Some(amount) = amount {242 <CollatorSelectionLicenseBondOverride<T>>::set(amount);243 } else {244 <CollatorSelectionLicenseBondOverride<T>>::kill();245 }246 Self::deposit_event(Event::NewCollatorLicenseBond { bond_cost: amount });247 Ok(())248 }249250 #[pallet::call_index(6)]251 #[pallet::weight(T::WeightInfo::set_collator_selection_kick_threshold())]252 pub fn set_collator_selection_kick_threshold(253 origin: OriginFor<T>,254 threshold: Option<T::BlockNumber>,255 ) -> DispatchResult {256 ensure_root(origin)?;257 if let Some(threshold) = threshold {258 <CollatorSelectionKickThresholdOverride<T>>::set(threshold);259 } else {260 <CollatorSelectionKickThresholdOverride<T>>::kill();261 }262 Self::deposit_event(Event::NewCollatorKickThreshold {263 length_in_blocks: threshold,264 });265 Ok(())266 }267 }268269 #[pallet::pallet]270 #[pallet::generate_store(pub(super) trait Store)]271 pub struct Pallet<T>(_);272}273274pub struct WeightToFee<T, B>(PhantomData<(T, B)>);275276impl<T, B> WeightToFeePolynomial for WeightToFee<T, B>277where278 T: Config,279 B: BaseArithmetic + From<u32> + From<u64> + Copy + Unsigned,280{281 type Balance = B;282283 fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {284 smallvec!(WeightToFeeCoefficient {285 coeff_integer: (<WeightToFeeCoefficientOverride<T>>::get() / Perbill::ACCURACY as u64)286 .into(),287 coeff_frac: Perbill::from_parts(288 (<WeightToFeeCoefficientOverride<T>>::get() % Perbill::ACCURACY as u64) as u32289 ),290 negative: false,291 degree: 1,292 })293 }294}295296pub struct FeeCalculator<T>(PhantomData<T>);297impl<T: Config> fp_evm::FeeCalculator for FeeCalculator<T> {298 fn min_gas_price() -> (U256, Weight) {299 (300 <MinGasPriceOverride<T>>::get().into(),301 T::DbWeight::get().reads(1),302 )303 }304}305306#[derive(Encode, Decode, Clone, Debug, Default, TypeInfo, MaxEncodedLen, PartialEq, PartialOrd)]307pub struct AppPromotionConfiguration<BlockNumber> {308 309 pub recalculation_interval: Option<BlockNumber>,310 311 pub pending_interval: Option<BlockNumber>,312 313 pub interval_income: Option<Perbill>,314 315 pub max_stakers_per_calculation: Option<u8>,316}