1use codec::{Decode, Encode, MaxEncodedLen};
2use polkadot_sdk::{
3 frame_election_provider_support::Get,
4 frame_support::DebugNoBound,
5 polkadot_sdk_frame::prelude::BlockNumberFor,
6 sp_runtime::{traits::Saturating, FixedU128},
7};
8use scale_info::{prelude::marker::PhantomData, TypeInfo};
9
10use crate::BalanceOf;
11
12#[derive(Clone, TypeInfo, Decode, Encode, PartialEq, Eq, DebugNoBound, MaxEncodedLen)]
13#[scale_info(skip_type_params(T))]
14pub struct BurnConfiguration<T: crate::Config> {
15 pub min_burn: BalanceOf<T>,
16 pub max_burn: BalanceOf<T>,
17 pub adjustment_alpha: u64,
18 pub target_registrations_interval: BlockNumberFor<T>,
19 pub target_registrations_per_interval: u16,
20 pub max_registrations_per_interval: u16,
21 pub _pd: PhantomData<T>,
22}
23
24impl<T> Default for BurnConfiguration<T>
25where
26 T: crate::Config,
27{
28 fn default() -> Self {
29 Self {
30 min_burn: T::DefaultMinBurn::get(),
31 max_burn: T::DefaultMaxBurn::get(),
32 adjustment_alpha: T::DefaultAdjustmentAlpha::get(),
33 target_registrations_interval: T::DefaultTargetRegistrationsInterval::get(),
34 target_registrations_per_interval: T::DefaultTargetRegistrationsPerInterval::get(),
35 max_registrations_per_interval: T::DefaultMaxRegistrationsPerInterval::get(),
36 _pd: Default::default(),
37 }
38 }
39}
40
41pub fn adjust_burn<T: crate::Config>(current_block: u64) {
47 let BurnConfiguration {
48 min_burn,
49 max_burn,
50 adjustment_alpha,
51 target_registrations_interval,
52 target_registrations_per_interval,
53 ..
54 } = crate::BurnConfig::<T>::get();
55
56 let target_registrations_interval: u64 = target_registrations_interval
57 .into()
58 .try_into()
59 .expect("block number is 64 bits long");
60 let current_burn = crate::Burn::<T>::get();
61 let registrations_this_interval = crate::RegistrationsThisInterval::<T>::get();
62
63 let reached_interval = current_block
64 .checked_rem(target_registrations_interval)
65 .is_some_and(|r| r == 0);
66
67 if !reached_interval {
68 return;
69 }
70
71 let updated_burn = FixedU128::from_inner(current_burn)
72 .const_checked_mul(FixedU128::from_u32(
73 registrations_this_interval.saturating_add(target_registrations_per_interval) as u32,
74 ))
75 .unwrap_or_default()
76 .const_checked_div(FixedU128::from_u32(
77 target_registrations_per_interval.saturating_mul(2) as u32,
78 ))
79 .unwrap_or_default();
80
81 let alpha = FixedU128::from_inner(adjustment_alpha as u128)
82 .const_checked_div(FixedU128::from_inner(u64::MAX as u128))
83 .unwrap_or_else(|| FixedU128::from_inner(0));
84
85 let next_value = alpha
86 .const_checked_mul(FixedU128::from_inner(current_burn))
87 .unwrap_or_else(|| FixedU128::from_inner(0))
88 .saturating_add(
89 FixedU128::from_u32(1)
90 .saturating_sub(alpha)
91 .const_checked_mul(updated_burn)
92 .unwrap_or_else(|| FixedU128::from_inner(0)),
93 );
94
95 let new_burn = if next_value >= FixedU128::from_inner(max_burn) {
96 max_burn
97 } else if next_value <= FixedU128::from_inner(min_burn) {
98 min_burn
99 } else {
100 next_value.into_inner()
101 };
102
103 crate::Burn::<T>::set(new_burn);
104 crate::RegistrationsThisInterval::<T>::set(0);
105}