use crate::{Config, InitXp, Pallet};
use frame_system::{pallet, pallet_prelude::BlockNumberFor};
use frame_suite::xp::{XpLock, XpReserve, XpSystem};
use sp_core::{Decode, Encode, MaxEncodedLen};
use sp_runtime::{traits::Zero, RuntimeDebug};
use codec::DecodeWithMemTracking;
use scale_info::TypeInfo;
use derive_more::Constructor;
use serde::{Deserialize, Serialize};
pub type XpId<T> = <T as pallet::Config>::AccountId;
pub type ReserveReason<T, I> = <Pallet<T, I> as XpReserve>::ReserveReason;
pub type LockReason<T, I> = <Pallet<T, I> as XpLock>::LockReason;
pub type XpValue<T, I> = <Pallet<T, I> as XpSystem>::Points;
#[derive(Encode, Decode, Copy, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
#[scale_info(skip_type_params(T, I))]
pub struct Xp<T: Config<I>, I: 'static> {
pub free: T::Xp,
pub reserve: T::Xp,
pub lock: T::Xp,
pub pulse: Accumulator<T, I>,
pub timestamp: BlockNumberFor<T>,
}
#[derive(
Encode,
Decode,
Clone,
PartialEq,
Eq,
Copy,
RuntimeDebug,
MaxEncodedLen,
TypeInfo,
Constructor,
DecodeWithMemTracking,
)]
#[scale_info(skip_type_params(T, I))]
pub struct IdXp<Id, Value> {
pub id: Id,
pub points: Value,
}
#[derive(Encode, Decode, Copy, MaxEncodedLen, TypeInfo, DecodeWithMemTracking)]
#[scale_info(skip_type_params(T, I))]
pub struct Accumulator<T: Config<I>, I: 'static> {
pub value: T::Pulse,
pub step: T::Pulse,
}
#[derive(
Encode, Decode, MaxEncodedLen, TypeInfo, Serialize, Deserialize, DecodeWithMemTracking,
)]
#[scale_info(skip_type_params(T, I))]
pub struct Stepper<T: Config<I>, I: 'static> {
pub threshold: T::Pulse,
pub per_count: T::Pulse,
}
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
RuntimeDebug,
Clone,
PartialEq,
Eq,
MaxEncodedLen,
TypeInfo,
Deserialize,
Serialize,
)]
pub struct GenesisAcc<Owner, Id> {
pub owner: Owner,
pub id: Id,
}
#[derive(Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, TypeInfo)]
#[scale_info(skip_type_params(T, I))]
pub enum ForceGenesisConfig<T: Config<I>, I: 'static> {
MinPulse(T::Pulse),
InitXp(T::Xp),
PulseFactor {
threshold: T::Pulse,
per_count: T::Pulse,
},
MinTimeStamp(BlockNumberFor<T>),
}
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
RuntimeDebug,
Clone,
PartialEq,
Eq,
MaxEncodedLen,
TypeInfo,
)]
#[scale_info(skip_type_params(T, I))]
pub enum XpEligibility<T: Config<I>, I: 'static> {
Progressing(
T::Pulse,
),
Earning,
}
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
RuntimeDebug,
Clone,
PartialEq,
Eq,
MaxEncodedLen,
TypeInfo,
)]
pub struct XpProgress<T: Config<I>, I: 'static> {
pub level: T::Pulse,
pub progress: T::Pulse,
pub threshold: T::Pulse,
pub per_action: T::Pulse,
}
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
RuntimeDebug,
Clone,
PartialEq,
Eq,
MaxEncodedLen,
TypeInfo,
)]
#[scale_info(skip_type_params(T, I))]
pub struct XpState<T: Config<I>, I: 'static> {
pub liquid: T::Xp,
pub reserved: T::Xp,
pub locked: T::Xp,
pub multiplier: T::Pulse,
pub eligibility: XpEligibility<T, I>,
}
impl<T: Config<I>, I: 'static> Stepper<T, I> {
pub fn new(threshold: T::Pulse, per_count: T::Pulse) -> Option<Self> {
if per_count > threshold {
return None;
}
Some(Self {
threshold,
per_count,
})
}
}
impl<T: Config<I>, I: 'static> Clone for Xp<T, I> {
fn clone(&self) -> Self {
Self {
free: self.free,
reserve: self.reserve,
lock: self.lock,
pulse: self.pulse.clone(),
timestamp: self.timestamp,
}
}
}
impl<T: Config<I>, I: 'static> Default for Xp<T, I> {
fn default() -> Self {
Self {
free: InitXp::<T, I>::get(),
pulse: Default::default(),
reserve: T::Xp::zero(),
lock: T::Xp::zero(),
timestamp: frame_system::Pallet::<T>::block_number(),
}
}
}
impl<T: Config<I>, I: 'static> PartialEq for Xp<T, I> {
fn eq(&self, other: &Self) -> bool {
self.free == other.free
&& self.reserve == other.reserve
&& self.lock == other.lock
&& self.pulse == other.pulse
&& self.timestamp == other.timestamp
}
}
impl<T: Config<I>, I: 'static> Eq for Xp<T, I> {}
impl<T: Config<I>, I: 'static> core::fmt::Debug for Xp<T, I> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Xp")
.field("free", &self.free)
.field("reserve", &self.reserve)
.field("lock", &self.lock)
.field("pulse", &self.pulse)
.field("timestamp", &self.timestamp)
.finish()
}
}
impl<T: Config<I>, I: 'static> Clone for Accumulator<T, I> {
fn clone(&self) -> Self {
Self {
value: self.value,
step: self.step,
}
}
}
impl<T: Config<I>, I: 'static> Default for Accumulator<T, I> {
fn default() -> Self {
Self {
value: Default::default(),
step: Default::default(),
}
}
}
impl<T: Config<I>, I: 'static> PartialEq for Accumulator<T, I> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value && self.step == other.step
}
}
impl<T: Config<I>, I: 'static> Eq for Accumulator<T, I> {}
impl<T: Config<I>, I: 'static> core::fmt::Debug for Accumulator<T, I> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Accumulator")
.field("value", &self.value)
.field("step", &self.step)
.finish()
}
}
impl<T: Config<I>, I: 'static> Default for Stepper<T, I> {
fn default() -> Self {
Stepper::<T, I>::new(50u8.into(), 10u8.into()).unwrap()
}
}
impl<T, I> Clone for Stepper<T, I>
where
T: Config<I>,
T::Pulse: Clone,
{
fn clone(&self) -> Self {
Self {
threshold: self.threshold,
per_count: self.per_count,
}
}
}
impl<T, I> PartialEq for Stepper<T, I>
where
T: Config<I>,
T::Pulse: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.threshold == other.threshold && self.per_count == other.per_count
}
}
impl<T, I> Eq for Stepper<T, I>
where
T: Config<I>,
T::Pulse: Eq,
{
}
use core::fmt;
impl<T, I> fmt::Debug for Stepper<T, I>
where
T: Config<I>,
T::Pulse: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Stepper")
.field("threshold", &self.threshold)
.field("per_count", &self.per_count)
.finish()
}
}
impl<T: Config<I>, I: 'static> Clone for ForceGenesisConfig<T, I> {
fn clone(&self) -> Self {
match self {
Self::MinPulse(v) => Self::MinPulse(*v),
Self::InitXp(v) => Self::InitXp(*v),
Self::PulseFactor {
threshold,
per_count,
} => Self::PulseFactor {
threshold: *threshold,
per_count: *per_count,
},
Self::MinTimeStamp(v) => Self::MinTimeStamp(*v),
}
}
}
impl<T: Config<I>, I: 'static> core::fmt::Debug for ForceGenesisConfig<T, I> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::MinPulse(v) => f.debug_tuple("MinPulse").field(v).finish(),
Self::InitXp(v) => f.debug_tuple("InitXp").field(v).finish(),
Self::PulseFactor {
threshold,
per_count,
} => f
.debug_struct("PulseFactor")
.field("threshold", threshold)
.field("per_count", per_count)
.finish(),
Self::MinTimeStamp(v) => f.debug_tuple("MinTimeStamp").field(v).finish(),
}
}
}
impl<T: Config<I>, I: 'static> PartialEq for ForceGenesisConfig<T, I>
where
T::Pulse: PartialEq,
T::Xp: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::MinPulse(a), Self::MinPulse(b)) => a == b,
(Self::InitXp(a), Self::InitXp(b)) => a == b,
(
Self::PulseFactor {
threshold: a_t,
per_count: a_p,
},
Self::PulseFactor {
threshold: b_t,
per_count: b_p,
},
) => a_t == b_t && a_p == b_p,
(Self::MinTimeStamp(a), Self::MinTimeStamp(b)) => a == b,
_ => false,
}
}
}
impl<T: Config<I>, I: 'static> Eq for ForceGenesisConfig<T, I>
where
T::Pulse: Eq,
T::Xp: Eq,
{
}
#[cfg(test)]
mod tests {
use crate::mock::*;
#[test]
fn xp_default_check() {
xp_test_ext().execute_with(|| {
System::set_block_number(2);
let xp = MockXp::default();
assert_eq!(xp.free, 10);
assert_eq!(xp.lock, 0);
assert_eq!(xp.reserve, 0);
assert_eq!(xp.pulse.value, 0);
assert_eq!(xp.timestamp, 2);
});
}
#[test]
fn stepper_new_success() {
xp_test_ext().execute_with(|| {
let stepper = Stepper::new(100, 10).unwrap();
assert_eq!(stepper.threshold, 100);
assert_eq!(stepper.per_count, 10);
});
}
#[test]
fn stepper_new_fail_none() {
xp_test_ext().execute_with(|| {
let threshold = 150;
let per_count = 200;
assert_eq!(Stepper::new(threshold, per_count), None);
});
}
#[test]
fn accumulator_default_check() {
xp_test_ext().execute_with(|| {
let accumulator = Accumulator::default();
assert_eq!(accumulator.value, 0);
assert_eq!(accumulator.step, 0);
});
}
}