Coverage Report

Created: 2022-11-10 19:56

/home/runner/work/creditcoin/creditcoin/pallets/rewards/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
1
#![cfg_attr(not(feature = "std"), no_std)]#![cfg_attr(not(feature = "std"), no_std)]
2
3
use core::convert::TryFrom;
4
use frame_support::traits::Currency;
5
pub use pallet::*;
6
use sp_runtime::{traits::Saturating, FixedPointNumber};
7
8
#[cfg(test)]
9
mod mock;
10
11
#[cfg(test)]
12
mod tests;
13
14
mod benchmarking;
15
16
#[allow(clippy::unnecessary_cast)]
17
pub mod weights;
18
19
pub type BalanceOf<T> =
20
  <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
21
22
pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
23
24
pub const REWARD_HALF_LIFE: u64 = 2_500_000;
25
pub const BASE_REWARD_IN_CTC: u64 = 28;
26
pub const CREDO_PER_CTC: u64 = 1_000_000_000_000_000_000;
27
pub const SAWTOOTH_PORT_HEIGHT: u64 = 1_123_966;
28
29
19
#[frame_support::pallet
]18
30
0
pub mod pallet {
31
0
  use super::*;
32
0
  use frame_support::{pallet_prelude::*, traits::Currency};
33
0
  use frame_system::pallet_prelude::*;
34
0
  use sp_runtime::{
35
0
    traits::{UniqueSaturatedFrom, UniqueSaturatedInto},
36
0
    FixedU128,
37
0
  };
38
0
39
0
  #[pallet::config]
40
0
  pub trait Config: frame_system::Config
41
0
  where
42
0
    <Self as frame_system::Config>::BlockNumber: UniqueSaturatedInto<u64>,
43
0
    BalanceOf<Self>: UniqueSaturatedFrom<u128>,
44
0
  {
45
0
    /// Because this pallet emits events, it depends on the runtime's definition of an event.
46
0
    type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
47
0
48
0
    type Currency: Currency<AccountIdOf<Self>>;
49
0
50
0
    type WeightInfo: WeightInfo;
51
0
  }
52
0
53
0
  pub trait WeightInfo {
54
0
    fn on_finalize() -> Weight;
55
0
    fn on_initialize() -> Weight;
56
0
  }
57
0
58
4
  #[pallet::pallet]
59
0
  #[pallet::generate_store(pub(super) trait Store)]
60
0
  pub struct Pallet<T>(_);
61
0
62
38
  #[pallet::storage]
63
0
  #[pallet::getter(fn block_author)]
64
0
  pub type BlockAuthor<T> = StorageValue<_, AccountIdOf<T>>;
65
0
66
0
  // Pallets use events to inform users when important changes are made.
67
0
  // https://substrate.dev/docs/en/knowledgebase/runtime/events
68
0
  #[pallet::event]
69
17
  #[pallet::generate_deposit(pub(super) fn deposit_event)]
70
0
  pub enum Event<T: Config> {
71
0
    /// Reward was issued. [block_author, amount]
72
0
    RewardIssued(AccountIdOf<T>, BalanceOf<T>),
73
0
  }
74
0
75
0
  #[pallet::hooks]
76
0
  impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
77
18
    fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
78
18
      let block_author = frame_system::Pallet::<T>::digest().convert_first(|item| {
79
18
        item.pre_runtime_try_to::<AccountIdOf<T>>(&sp_consensus_pow::POW_ENGINE_ID)
80
18
      });
81
0
82
18
      if let Some(author) = block_author {
83
18
        BlockAuthor::<T>::put(author);
84
18
      }
0
85
0
86
18
      T::WeightInfo::on_finalize().saturating_add(T::WeightInfo::on_initialize())
87
18
    }
88
0
89
0
    fn on_finalize(block_number: BlockNumberFor<T>) {
90
18
      if let Some(
author16
) = BlockAuthor::<T>::get() {
91
16
        let reward = Self::reward_amount(block_number);
92
16
        Self::issue_reward(author, reward);
93
16
      }
2
94
18
    }
95
0
  }
96
0
97
0
  impl<T: Config> Pallet<T> {
98
22
    pub fn reward_amount(block_number: BlockNumberFor<T>) -> BalanceOf<T> {
99
22
      let block_number: u64 = Self::sawtooth_adjusted_height(block_number);
100
22
      let period = usize::try_from(block_number / REWARD_HALF_LIFE).expect("assuming a 32-bit usize, we would need to be on block number 2^32 * REWARD_HALF_LIFE for this conversion to fail.\
101
22
  given a 1s block time it would take >340 million years to reach this point; qed");
102
22
      let decay_rate_inv = FixedU128::saturating_from_rational(19, 20);
103
22
      let multiplier = decay_rate_inv.saturating_pow(period);
104
22
      let reward_in_ctc: u128 =
105
22
        multiplier.saturating_mul_int(CREDO_PER_CTC).unique_saturated_into();
106
22
      let reward_amount = reward_in_ctc.saturating_mul(BASE_REWARD_IN_CTC.into());
107
22
      <BalanceOf<T>>::unique_saturated_from(reward_amount)
108
22
    }
109
17
    pub fn issue_reward(recipient: AccountIdOf<T>, amount: BalanceOf<T>) {
110
17
      drop(T::Currency::deposit_creating(&recipient, amount));
111
17
      Self::deposit_event(Event::<T>::RewardIssued(recipient, amount));
112
17
    }
113
0
114
22
    pub fn sawtooth_adjusted_height(block_number: BlockNumberFor<T>) -> u64 {
115
22
      let block_number: u64 = block_number.unique_saturated_into();
116
22
      block_number.saturating_add(SAWTOOTH_PORT_HEIGHT)
117
22
    }
118
0
  }
119
0
}