Skip to content

Commit

Permalink
Merge pull request #222 from InvArch/francisco-docs_inflation
Browse files Browse the repository at this point in the history
Checked Inflation documentation
  • Loading branch information
arrudagates authored Mar 4, 2024
2 parents fc1a774 + 833f3d5 commit 8abce80
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 4 deletions.
65 changes: 65 additions & 0 deletions pallet-checked-inflation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Checked Inflation Pallet

## Overview

The Checked Inflation Pallet is designed to facilitate the inflationary aspect of a blockchain's economy.
It automatically mints new tokens at the start of every era, with the amount determined by a configurable inflation method.
This functionality is crucial for maintaining a controlled expansion of the token supply, aligning with economic models or rewarding network participants.

### Key Features

- **Configurable Inflation**: The amount and method of inflation can be tailored to suit the blockchain's economic model.
- **Automatic Token Minting**: New tokens are minted automatically at the beginning of each era.
- **Yearly and Era-Based Inflation**: Supports fixed yearly, fixed per era, or rate-based inflation calculations.

## Functionality

The pallet's core functionality revolves around the `on_initialize` hook, which triggers at the beginning of each block.
If conditions align (start of a new era or year), the pallet calculates the amount to mint based on the configured inflation method and mints the tokens.

## Inflation Methods

Inflation can be configured in one of three ways, as defined in the `InflationMethod` enum:

- **Rate**: A percentage of the current supply.
- **FixedYearly**: A fixed amount distributed evenly across all eras in a year.
- **FixedPerEra**: A fixed amount minted at the start of each era.

The choice of method allows for flexibility in how the token supply expands over time, catering to different economic strategies.

## Dispatchable Functions

### `set_first_year_supply`

Configures the initial token supply at the year's start, preparing the system for accurate inflation calculation.

- **Access Control**: Root

### `halt_unhalt_pallet`

Toggles the inflation process, allowing it to be halted or resumed based on network needs.

- **Parameters**:
- `halt`: A boolean indicating whether to halt (`true`) or resume (`false`) the inflation process.
- **Access Control**: Root


## Events

- **NewYear**: Marks the beginning of a new year, resetting era counts and updating the starting issuance for inflation calculations.
- **NewEra**: Signifies the start of a new era, triggering token minting according to the configured inflation rate.
- **InflationMinted**: Indicates that tokens have been minted due to inflation, detailing the amounts involved.
- **OverInflationDetected**: Warns of excess token minting beyond expected amounts, prompting corrective measures.
- **HaltChanged**: Reports changes in the inflation process's halt status.

## Errors

- **NoHaltChange**: Triggered when attempting to change the halt status to its current value, indicating no action is needed.

## Conclusion

The Checked Inflation Pallet offers a flexible and automated way to manage token supply expansion through inflation.
By configuring the inflation method to match your blockchain's economic model, you can ensure a controlled and predictable increase in token supply,
this pallet is an essential tool for managing network growth and stability through controlled inflation in response to evolving economic conditions,
ensuring long-term sustainability.

15 changes: 15 additions & 0 deletions pallet-checked-inflation/src/inflation.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
//! Available inflation methods and resulting inflation amount generated per era.
//!
//! ## Overview
//!
//! This module contains the available inflation methods and the resulting inflation amount generated per era.
use crate::{BalanceOf, Config};
use codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_arithmetic::per_things::Perbill;

/// Inflation methods.
///
/// The inflation methods are used to determine the amount of inflation generated per era.
#[derive(TypeInfo, Encode, Decode)]
pub enum InflationMethod<Balance> {
/// The inflation is calculated as a percentage (`Perbill`) of the current supply.
Rate(Perbill),
/// The inflation is a fixed amount per year.
FixedYearly(Balance),
/// The inflation is a fixed amount per era.
FixedPerEra(Balance),
}

/// Getter trait for the inflation amount to be minted in each era.
pub trait GetInflation<T: Config> {
/// Returns the inflation amount to be minted per era.
fn get_inflation_args(&self, eras_per_year: u32, current_supply: BalanceOf<T>) -> BalanceOf<T>;
}

impl<T: Config> GetInflation<T> for InflationMethod<BalanceOf<T>>
where
u32: Into<BalanceOf<T>>,
{
/// Returns the inflation amount to be minted per era based on the inflation method.
fn get_inflation_args(&self, eras_per_year: u32, current_supply: BalanceOf<T>) -> BalanceOf<T> {
match self {
Self::Rate(rate) => (*rate * current_supply) / eras_per_year.into(),
Expand Down
50 changes: 46 additions & 4 deletions pallet-checked-inflation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
//! # Checked Inflation Pallet
//!
//! - [`Config`]
//! - [`Call`]
//! - [`Pallet`]
//!
//! ## Overview
//! This is a supporting pallet that provides the functionality for inflation. It is used to mint new tokens at the beginning of every era.
//!
//! The amount of tokens minted is determined by the inflation method and its amount, and is configurable in the runtime,
//! see the [`inflation`] module for the methods of inflation available and how their inflation amounts are calculated.
//!
//! Most of the logic is implemented in the `on_initialize` hook, which is called at the beginning of every block.
//!
//! ## Dispatchable Functions
//!
//! - `set_first_year_supply` - For configuring the pallet, sets the token's `YearStartIssuance` to its current total issuance.
//! - `halt_unhalt_pallet` - To start or stop the inflation process.
#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::traits::Get;
Expand Down Expand Up @@ -34,9 +53,11 @@ pub mod pallet {
};
use num_traits::CheckedSub;

/// The balance type of this pallet.
pub(crate) type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;

/// The opaque token type for an imbalance. This is returned by unbalanced operations and must be dealt with.
type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
<T as frame_system::Config>::AccountId,
>>::NegativeImbalance;
Expand All @@ -46,23 +67,30 @@ pub mod pallet {

#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// The currency (token) used in this pallet.
type Currency: LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>
+ ReservableCurrency<Self::AccountId>
+ Currency<Self::AccountId>;

/// Number of blocks per era.
#[pallet::constant]
type BlocksPerEra: Get<BlockNumberFor<Self>>;

/// Number of eras per year.
#[pallet::constant]
type ErasPerYear: Get<u32>;

/// The inflation method and its amount.
#[pallet::constant]
type Inflation: Get<InflationMethod<BalanceOf<Self>>>;

/// The `NegativeImbalanceOf` the currency, i.e. the amount of inflation to be applied.
type DealWithInflation: OnUnbalanced<NegativeImbalanceOf<Self>>;

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
}

Expand All @@ -86,44 +114,48 @@ pub mod pallet {
#[pallet::getter(fn inflation_per_era)]
pub type YearlyInflationPerEra<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;

/// Wheter or not the inflation process should be halted.
/// Whether the inflation process is halted.
#[pallet::storage]
#[pallet::getter(fn is_halted)]
pub type Halted<T: Config> = StorageValue<_, bool, ValueQuery>;

#[pallet::error]
pub enum Error<T> {
/// The pallet is already in the state that the user is trying to change it to.
NoHaltChange,
}

#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config> {
/// Beginning of a new year.
NewYear {
starting_issuance: BalanceOf<T>,
next_era_starting_block: BlockNumberFor<T>,
},

/// Beginning of a new era.
NewEra {
era: u32,
next_era_starting_block: BlockNumberFor<T>,
},

/// Tokens minted due to inflation.
InflationMinted {
year_start_issuance: BalanceOf<T>,
current_issuance: BalanceOf<T>,
expected_new_issuance: BalanceOf<T>,
minted: BalanceOf<T>,
},

/// Total supply of the token is higher than expected by Checked Inflation.
OverInflationDetected {
expected_issuance: BalanceOf<T>,
current_issuance: BalanceOf<T>,
},

HaltChanged {
is_halted: bool,
},
/// Halt status changed.
HaltChanged { is_halted: bool },
}

#[pallet::hooks]
Expand Down Expand Up @@ -257,6 +289,9 @@ pub mod pallet {

#[pallet::call]
impl<T: Config> Pallet<T> {
/// This call is used for configuring the inflation mechanism and sets the token's `YearStartIssuance` to its current total issuance.
///
/// The origin has to have `root` access.
#[pallet::call_index(0)]
#[pallet::weight(
<T as Config>::WeightInfo::set_first_year_supply()
Expand All @@ -271,6 +306,11 @@ pub mod pallet {
Ok(())
}

/// Halts or unhalts the inflation process.
///
/// The origin has to have `root` access.
///
/// - `halt`: `true` to halt the inflation process, `false` to unhalt it.
#[pallet::call_index(1)]
#[pallet::weight(
<T as Config>::WeightInfo::halt_unhalt_pallet()
Expand All @@ -291,11 +331,13 @@ pub mod pallet {
}

impl<T: Config> Pallet<T> {
/// Internal function for minting tokens to the currency due to inflation.
fn mint(amount: BalanceOf<T>) {
let inflation = T::Currency::issue(amount);
<T as Config>::DealWithInflation::on_unbalanced(inflation);
}

/// Internal function to set the halt status to storage.
pub fn internal_halt_unhalt(halt: bool) {
Halted::<T>::put(halt);
}
Expand Down

0 comments on commit 8abce80

Please sign in to comment.