pallet_block_producer_fees/
lib.rs

1//! Pallet to store Block Producer Fees settings that are relevant to rewards payments.
2//!
3//! Margin fee is percent of block rewards that will be paid to the block producer before
4//! distributing the rest of rewards to his stakers. Precision of the margin fee setting is bounded
5//! to 1/100 of a percent.
6//!
7//! The margin fees are stored together with the time at which change occurred, so this data can be
8//! exposed to rewards calculation.
9//!
10//! Log of changes per account is bounded. The oldest entries are dropped when new ones are added.
11//! Intention is to discourage users from too frequent changes and there is an assumption
12//! that rewards calculation algorithm will account for it.
13
14#![cfg_attr(not(feature = "std"), no_std)]
15#![deny(missing_docs)]
16
17pub mod benchmarking;
18
19#[cfg(test)]
20mod mock;
21#[cfg(test)]
22mod tests;
23pub mod weights;
24
25pub use pallet::*;
26pub use weights::WeightInfo;
27
28#[frame_support::pallet]
29pub mod pallet {
30	use super::*;
31	use frame_support::pallet_prelude::*;
32	use frame_system::pallet_prelude::*;
33	use sp_block_producer_fees::PerTenThousands;
34	use sp_std::collections::vec_deque::VecDeque;
35
36	/// Current version of the pallet
37	pub const PALLET_VERSION: u32 = 1;
38
39	#[pallet::pallet]
40	pub struct Pallet<T>(_);
41
42	#[pallet::config]
43	pub trait Config: frame_system::Config {
44		/// The maximum number of past changes per one block producer kept in the storage.
45		#[pallet::constant]
46		type HistoricalChangesPerProducer: Get<u16>;
47
48		/// Weight information on extrinsic in the pallet. For convenience weights in [weights] module can be used.
49		type WeightInfo: WeightInfo;
50
51		/// Moment in time when a change in fees occured
52		type Moment: Parameter + Default + MaxEncodedLen + PartialOrd;
53
54		/// Should provide the moment for the current block.
55		fn current_moment() -> Self::Moment;
56
57		#[cfg(feature = "runtime-benchmarks")]
58		/// Benchmark helper type used for running benchmarks
59		type BenchmarkHelper: benchmarking::BenchmarkHelper<Self::AccountId>;
60	}
61
62	type FeeChangeOf<T> = (<T as Config>::Moment, PerTenThousands);
63
64	/// Stores bounded amount of fee changes per account
65	#[pallet::storage]
66	#[pallet::unbounded]
67	pub type FeesChanges<T: Config> = StorageMap<
68		Hasher = Twox64Concat,
69		Key = T::AccountId,
70		Value = VecDeque<FeeChangeOf<T>>,
71		QueryKind = ValueQuery,
72	>;
73
74	#[pallet::call]
75	impl<T: Config> Pallet<T> {
76		/// Sets the margin fee of a caller. Margin fee is (fee numerator / 10000).
77		#[pallet::call_index(0)]
78		#[pallet::weight((T::WeightInfo::set_fee(), DispatchClass::Normal))]
79		pub fn set_fee(origin: OriginFor<T>, fee_numerator: PerTenThousands) -> DispatchResult {
80			let account_id = ensure_signed(origin)?;
81			if fee_numerator > 10000 {
82				return Err(DispatchError::Other("fee numerator must be in range from 0 to 10000"));
83			}
84			FeesChanges::<T>::mutate(account_id, |fees_log| {
85				if fees_log.len() > T::HistoricalChangesPerProducer::get().into() {
86					let _ = fees_log.pop_back();
87				}
88				fees_log.push_front((T::current_moment(), fee_numerator));
89			});
90			Ok(())
91		}
92	}
93
94	impl<T: Config> Pallet<T> {
95		/// Returns the current pallet version.
96		pub fn get_version() -> u32 {
97			PALLET_VERSION
98		}
99
100		/// Retrieves all stored block producer fees settings. The most recent fees are in front of vecdeque.
101		pub fn get_all() -> impl Iterator<Item = (T::AccountId, VecDeque<FeeChangeOf<T>>)> {
102			FeesChanges::<T>::iter()
103		}
104
105		/// Retrieves the latest fee settings for all accounts.
106		pub fn get_all_latest() -> impl Iterator<Item = (T::AccountId, FeeChangeOf<T>)> {
107			Self::get_all().map(|(account_id, changes)| {
108				(
109					account_id,
110					changes.front().expect("There are no empty collections in storage").clone(),
111				)
112			})
113		}
114
115		/// Retrieves fees settings for the given account id.
116		/// Empty collection is returned if there are no settings stored for given id.
117		pub fn get(id: T::AccountId) -> VecDeque<FeeChangeOf<T>> {
118			FeesChanges::<T>::get(id)
119		}
120
121		/// Gets the latest fee setting for the given account.
122		pub fn get_latest(id: T::AccountId) -> Option<FeeChangeOf<T>> {
123			FeesChanges::<T>::get(id).front().cloned()
124		}
125	}
126}