pallet_torus0/
burn.rs

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
41/// Adjusts registration burn for the current block.
42///
43/// The next burn is calculated by analyzing the last N
44/// (`target_registrations_interval`) blocks and increases if the target
45/// registrations per interval was reached.
46pub 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}