use super::*; // use frame_support::traits::{Currency as BalancesCurrency, Get, Imbalance}; use crate::coinbase::tao::CreditOf; use frame_support::traits::{Get, Imbalance}; use safe_math::*; use substrate_fixed::{transcendental::log2, types::I96F32}; impl Pallet { /// Calculates the block emission based on the total issuance and mints corresponding /// amount of TAO. /// /// This function computes the block emission by applying a logarithmic function /// to the total issuance of the network. The formula used takes into account /// the current total issuance and adjusts the emission rate accordingly to ensure /// a smooth issuance curve. The emission rate decreases as the total issuance increases, /// following a logarithmic decay. /// /// # Returns /// * `Result`: The calculated block emission rate or error. /// pub fn get_block_emission() -> CreditOf { let maybe_tao_to_mint = Self::calculate_block_emission(); if let Ok(tao_to_mint) = maybe_tao_to_mint && !tao_to_mint.is_zero() { return Self::mint_tao(tao_to_mint.into()); } CreditOf::::zero() } /// Calculates the block emission based on the total issuance only, no minting happens. pub fn calculate_block_emission() -> Result { // Convert the total issuance to a fixed-point number for calculation. Self::get_block_emission_for_issuance(Self::get_total_issuance().into()).map(Into::into) } /// Returns the block emission for an issuance value. pub fn get_block_emission_for_issuance(issuance: u64) -> Result { // Convert issuance to a float for calculations below. let total_issuance: I96F32 = I96F32::saturating_from_num(issuance); // Check to prevent division by zero when the total supply is reached // and creating an issuance greater than the total supply. if total_issuance >= I96F32::saturating_from_num(TotalSupply::::get()) { return Ok(0); } // Calculate the logarithmic residual of the issuance against half the total supply. let residual: I96F32 = log2( I96F32::saturating_from_num(1.0) .checked_div( I96F32::saturating_from_num(1.0) .checked_sub( total_issuance .checked_div(I96F32::saturating_from_num(2.0).saturating_mul( I96F32::saturating_from_num(10_500_000_000_000_000.0), )) .ok_or("Logarithm calculation failed")?, ) .ok_or("Logarithm calculation failed")?, ) .ok_or("Logarithm calculation failed")?, ) .map_err(|_| "Logarithm calculation failed")?; // Floor the residual to smooth out the emission rate. let floored_residual: I96F32 = residual.floor(); // Calculate the final emission rate using the floored residual. // Convert floored_residual to an integer let floored_residual_int: u64 = floored_residual.saturating_to_num::(); // Multiply 2.0 by itself floored_residual times to calculate the power of 2. let mut multiplier: I96F32 = I96F32::saturating_from_num(1.0); for _ in 0..floored_residual_int { multiplier = multiplier.saturating_mul(I96F32::saturating_from_num(2.0)); } let block_emission_percentage: I96F32 = I96F32::saturating_from_num(1.0).safe_div(multiplier); // Calculate the actual emission based on the emission rate let block_emission: I96F32 = block_emission_percentage .saturating_mul(I96F32::saturating_from_num(DefaultBlockEmission::::get())); // Convert to u64 let block_emission_u64: u64 = block_emission.saturating_to_num::(); Ok(block_emission_u64) } }