Refactoring Checkpoint: (WIP)
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
// pezkuwi/pallets/pez-treasury/src/benchmarking.rs
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use super::*;
|
||||
use crate::Pallet as PezTreasury;
|
||||
use pezframe_benchmarking::v2::*;
|
||||
use pezframe_support::traits::{
|
||||
fungibles::{Inspect, Mutate},
|
||||
Get, // HATA GİDERİLDİ: .get() fonksiyonu için bu trait eklendi
|
||||
};
|
||||
use pezframe_system::RawOrigin;
|
||||
use pezsp_runtime::traits::{Saturating, Zero};
|
||||
|
||||
#[benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
#[benchmark]
|
||||
fn initialize_treasury() {
|
||||
crate::TreasuryStartBlock::<T>::kill();
|
||||
crate::HalvingInfo::<T>::kill();
|
||||
crate::NextReleaseMonth::<T>::kill();
|
||||
|
||||
#[extrinsic_call]
|
||||
initialize_treasury(RawOrigin::Root);
|
||||
|
||||
assert!(crate::TreasuryStartBlock::<T>::get().is_some());
|
||||
let halving_info = crate::HalvingInfo::<T>::get();
|
||||
assert_eq!(halving_info.current_period, 0);
|
||||
assert!(!halving_info.monthly_amount.is_zero());
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn force_genesis_distribution() {
|
||||
// Clear the flag to allow benchmark run (tests the new storage operation)
|
||||
crate::GenesisDistributionDone::<T>::kill();
|
||||
|
||||
#[block]
|
||||
{
|
||||
PezTreasury::<T>::do_genesis_distribution().unwrap();
|
||||
}
|
||||
|
||||
let treasury_account = PezTreasury::<T>::treasury_account_id();
|
||||
let presale_account = T::PresaleAccount::get();
|
||||
let founder_account = T::FounderAccount::get();
|
||||
|
||||
assert!(!T::Assets::balance(T::PezAssetId::get(), &treasury_account).is_zero());
|
||||
assert!(!T::Assets::balance(T::PezAssetId::get(), &presale_account).is_zero());
|
||||
assert!(!T::Assets::balance(T::PezAssetId::get(), &founder_account).is_zero());
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn release_monthly_funds() {
|
||||
// Setup
|
||||
crate::TreasuryStartBlock::<T>::kill();
|
||||
crate::HalvingInfo::<T>::kill();
|
||||
crate::NextReleaseMonth::<T>::kill();
|
||||
crate::GenesisDistributionDone::<T>::kill();
|
||||
// Deprecated `remove_all` yerine `clear` kullanılıyor.
|
||||
crate::MonthlyReleases::<T>::clear(u32::MAX, None);
|
||||
|
||||
// First do genesis distribution to properly fund the treasury
|
||||
PezTreasury::<T>::do_genesis_distribution().unwrap();
|
||||
PezTreasury::<T>::do_initialize_treasury().unwrap();
|
||||
|
||||
let treasury_account = PezTreasury::<T>::treasury_account_id();
|
||||
let initial_monthly_amount = PezTreasury::<T>::halving_info().monthly_amount;
|
||||
let incentive_amount = initial_monthly_amount * 75u32.into() / 100u32.into();
|
||||
let government_amount = initial_monthly_amount.saturating_sub(incentive_amount);
|
||||
|
||||
// Ensure treasury has MORE than enough balance for the release
|
||||
// Mint additional 10x the monthly amount to ensure sufficient balance
|
||||
let _ = T::Assets::mint_into(
|
||||
T::PezAssetId::get(),
|
||||
&treasury_account,
|
||||
initial_monthly_amount * 10u32.into(),
|
||||
);
|
||||
|
||||
let current_block = pezframe_system::Pallet::<T>::block_number();
|
||||
let target_block = current_block + crate::BLOCKS_PER_MONTH.into() + 1u32.into();
|
||||
pezframe_system::Pallet::<T>::set_block_number(target_block);
|
||||
|
||||
#[extrinsic_call]
|
||||
release_monthly_funds(RawOrigin::Root);
|
||||
|
||||
assert_eq!(PezTreasury::<T>::get_incentive_pot_balance(), incentive_amount);
|
||||
assert_eq!(PezTreasury::<T>::get_government_pot_balance(), government_amount);
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(PezTreasury, crate::mock::new_test_ext(), crate::mock::Test);
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
//! # PEZ Treasury Pallet
|
||||
//!
|
||||
//! A pallet for managing the PEZ token distribution and treasury with automated halving mechanics.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! This pallet manages the complete lifecycle of PEZ token distribution including:
|
||||
//!
|
||||
//! - **Genesis Distribution**: One-time initial distribution to treasury, presale, and founder
|
||||
//! accounts
|
||||
//! - **Halving Mechanism**: Automatic reduction of monthly releases every 48 months (4 years)
|
||||
//! - **Monthly Releases**: Scheduled distribution to incentive and government pots
|
||||
//! - **Multi-Pot System**: Separate accounts for treasury, incentive rewards, and governance
|
||||
//!
|
||||
//! ## Token Economics
|
||||
//!
|
||||
//! - **Total Supply**: 5,000,000,000 PEZ (5 billion tokens)
|
||||
//! - **Treasury Allocation**: 96.25% (4,812,500,000 PEZ)
|
||||
//! - **Presale Allocation**: 1.875% (93,750,000 PEZ)
|
||||
//! - **Founder Allocation**: 1.875% (93,750,000 PEZ)
|
||||
//!
|
||||
//! ## Halving Schedule
|
||||
//!
|
||||
//! - **Halving Period**: Every 48 months (4 years)
|
||||
//! - **Period Duration**: 20,736,000 blocks (~4 years at 10 blocks/minute)
|
||||
//! - **Distribution**: 70% to Incentive Pot, 30% to Government Pot
|
||||
//! - **Automatic Halving**: Monthly release amount halves at the start of each new period
|
||||
//!
|
||||
//! ## Security Features
|
||||
//!
|
||||
//! - **One-Time Genesis**: Genesis distribution can only occur once (protected by storage flag)
|
||||
//! - **Privileged Operations**: All extrinsics require privileged origin (root or governance)
|
||||
//! - **Block-Based Scheduling**: Monthly releases based on block numbers for determinism
|
||||
//!
|
||||
//! ## Interface
|
||||
//!
|
||||
//! ### Extrinsics
|
||||
//!
|
||||
//! - `force_genesis_distribution()` - Perform initial token distribution (one-time only,
|
||||
//! privileged)
|
||||
//! - `initialize_treasury()` - Initialize the halving mechanism and start monthly releases
|
||||
//! (privileged)
|
||||
//! - `release_monthly_funds()` - Release monthly funds to incentive and government pots
|
||||
//! (privileged)
|
||||
//!
|
||||
//! ### Storage
|
||||
//!
|
||||
//! - `HalvingInfo` - Current halving period data and monthly release amount
|
||||
//! - `MonthlyReleases` - Historical record of all monthly distributions
|
||||
//! - `GenesisDistributionDone` - Flag to prevent duplicate genesis distribution
|
||||
//!
|
||||
//! ### Runtime Integration Example
|
||||
//!
|
||||
//! ```ignore
|
||||
//! impl pezpallet_pez_treasury::Config for Runtime {
|
||||
//! type RuntimeEvent = RuntimeEvent;
|
||||
//! type Assets = Assets;
|
||||
//! type WeightInfo = pezpallet_pez_treasury::weights::BizinikiwiWeight<Runtime>;
|
||||
//! type PezAssetId = ConstU32<1>; // PEZ asset ID
|
||||
//! type TreasuryPalletId = TreasuryPalletId;
|
||||
//! type IncentivePotId = IncentivePotId;
|
||||
//! type GovernmentPotId = GovernmentPotId;
|
||||
//! type PresaleAccount = PresaleAccount;
|
||||
//! type FounderAccount = FounderAccount;
|
||||
//! type ForceOrigin = EnsureRoot<AccountId>;
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
pub use pallet::*;
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
pub mod migrations;
|
||||
pub mod weights;
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benchmarking;
|
||||
|
||||
use pezframe_support::{
|
||||
traits::{
|
||||
fungibles::{Inspect, Mutate},
|
||||
tokens::Preservation,
|
||||
Get,
|
||||
},
|
||||
PalletId,
|
||||
};
|
||||
use pezframe_system::pezpallet_prelude::BlockNumberFor;
|
||||
use scale_info::TypeInfo;
|
||||
use pezsp_runtime::traits::{AccountIdConversion, Saturating, Zero};
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use pezframe_support::pezpallet_prelude::*;
|
||||
use pezframe_system::pezpallet_prelude::*;
|
||||
// use pezsp_runtime::traits::CheckedDiv;
|
||||
|
||||
pub const HALVING_PERIOD_MONTHS: u32 = 48; // 4 years = 48 months
|
||||
pub const BLOCKS_PER_MONTH: u32 = 432_000; // ~30 days * 24 hours * 60 minutes * 10 blocks/minute
|
||||
pub const HALVING_PERIOD_BLOCKS: u32 = HALVING_PERIOD_MONTHS * BLOCKS_PER_MONTH;
|
||||
|
||||
pub const TOTAL_SUPPLY: u128 = 5_000_000_000 * 1_000_000_000_000; // 5 billion PEZ (12 decimal)
|
||||
pub const TREASURY_ALLOCATION: u128 = 4_812_500_000 * 1_000_000_000_000; // %96.25
|
||||
pub const PRESALE_ALLOCATION: u128 = 93_750_000 * 1_000_000_000_000; // %1.875
|
||||
pub const FOUNDER_ALLOCATION: u128 = 93_750_000 * 1_000_000_000_000; // %1.875
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(migrations::STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: pezframe_system::Config + TypeInfo {
|
||||
type Assets: Mutate<Self::AccountId>;
|
||||
type WeightInfo: weights::WeightInfo;
|
||||
|
||||
#[pallet::constant]
|
||||
type PezAssetId: Get<<Self::Assets as Inspect<Self::AccountId>>::AssetId>;
|
||||
|
||||
#[pallet::constant]
|
||||
type TreasuryPalletId: Get<PalletId>;
|
||||
|
||||
#[pallet::constant]
|
||||
type IncentivePotId: Get<PalletId>;
|
||||
|
||||
#[pallet::constant]
|
||||
type GovernmentPotId: Get<PalletId>;
|
||||
|
||||
#[pallet::constant]
|
||||
type PresaleAccount: Get<Self::AccountId>;
|
||||
|
||||
#[pallet::constant]
|
||||
type FounderAccount: Get<Self::AccountId>;
|
||||
|
||||
type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||
}
|
||||
|
||||
pub type BalanceOf<T> =
|
||||
<<T as Config>::Assets as Inspect<<T as pezframe_system::Config>::AccountId>>::Balance;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn halving_info)]
|
||||
pub type HalvingInfo<T: Config> = StorageValue<_, HalvingData<T>, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn monthly_releases)]
|
||||
pub type MonthlyReleases<T: Config> =
|
||||
StorageMap<_, Blake2_128Concat, u32, MonthlyRelease<T>, OptionQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn next_release_month)]
|
||||
pub type NextReleaseMonth<T: Config> = StorageValue<_, u32, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn treasury_start_block)]
|
||||
pub type TreasuryStartBlock<T: Config> = StorageValue<_, BlockNumberFor<T>, OptionQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn genesis_distribution_done)]
|
||||
pub type GenesisDistributionDone<T: Config> = StorageValue<_, bool, ValueQuery>;
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct HalvingData<T: Config> {
|
||||
pub current_period: u32,
|
||||
pub period_start_block: BlockNumberFor<T>,
|
||||
pub monthly_amount: BalanceOf<T>,
|
||||
pub total_released: BalanceOf<T>,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct MonthlyRelease<T: Config> {
|
||||
pub month_index: u32,
|
||||
pub release_block: BlockNumberFor<T>,
|
||||
pub amount_released: BalanceOf<T>,
|
||||
pub incentive_amount: BalanceOf<T>,
|
||||
pub government_amount: BalanceOf<T>,
|
||||
}
|
||||
|
||||
impl<T: Config> Default for HalvingData<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current_period: 0,
|
||||
period_start_block: Zero::zero(),
|
||||
monthly_amount: Zero::zero(),
|
||||
total_released: Zero::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
TreasuryInitialized {
|
||||
start_block: BlockNumberFor<T>,
|
||||
initial_monthly_amount: BalanceOf<T>,
|
||||
},
|
||||
MonthlyFundsReleased {
|
||||
month_index: u32,
|
||||
total_amount: BalanceOf<T>,
|
||||
incentive_amount: BalanceOf<T>,
|
||||
government_amount: BalanceOf<T>,
|
||||
},
|
||||
NewHalvingPeriod {
|
||||
period: u32,
|
||||
new_monthly_amount: BalanceOf<T>,
|
||||
},
|
||||
GenesisDistributionCompleted {
|
||||
treasury_amount: BalanceOf<T>,
|
||||
presale_amount: BalanceOf<T>,
|
||||
founder_amount: BalanceOf<T>,
|
||||
},
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
TreasuryAlreadyInitialized,
|
||||
TreasuryNotInitialized,
|
||||
MonthlyReleaseAlreadyDone,
|
||||
InsufficientTreasuryBalance,
|
||||
InvalidHalvingPeriod,
|
||||
ReleaseTooEarly,
|
||||
GenesisDistributionAlreadyDone,
|
||||
}
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[derive(pezframe_support::DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub initialize_treasury: bool,
|
||||
#[serde(skip)]
|
||||
pub _phantom: core::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {
|
||||
if self.initialize_treasury {
|
||||
let _ = Pallet::<T>::do_initialize_treasury();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(T::WeightInfo::initialize_treasury())]
|
||||
pub fn initialize_treasury(origin: OriginFor<T>) -> DispatchResult {
|
||||
T::ForceOrigin::ensure_origin(origin)?;
|
||||
Self::do_initialize_treasury()
|
||||
}
|
||||
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(T::WeightInfo::release_monthly_funds())]
|
||||
pub fn release_monthly_funds(origin: OriginFor<T>) -> DispatchResult {
|
||||
T::ForceOrigin::ensure_origin(origin)?;
|
||||
Self::do_monthly_release()
|
||||
}
|
||||
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(T::WeightInfo::force_genesis_distribution())]
|
||||
pub fn force_genesis_distribution(origin: OriginFor<T>) -> DispatchResult {
|
||||
T::ForceOrigin::ensure_origin(origin)?;
|
||||
Self::do_genesis_distribution()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn treasury_account_id() -> T::AccountId {
|
||||
T::TreasuryPalletId::get().into_account_truncating()
|
||||
}
|
||||
|
||||
pub fn incentive_pot_account_id() -> T::AccountId {
|
||||
T::IncentivePotId::get().into_account_truncating()
|
||||
}
|
||||
|
||||
pub fn government_pot_account_id() -> T::AccountId {
|
||||
T::GovernmentPotId::get().into_account_truncating()
|
||||
}
|
||||
|
||||
pub fn do_genesis_distribution() -> DispatchResult {
|
||||
// SECURITY: Ensure genesis distribution can only happen once
|
||||
ensure!(
|
||||
!GenesisDistributionDone::<T>::get(),
|
||||
Error::<T>::GenesisDistributionAlreadyDone
|
||||
);
|
||||
|
||||
let treasury_account = Self::treasury_account_id();
|
||||
let presale_account = T::PresaleAccount::get();
|
||||
let founder_account = T::FounderAccount::get();
|
||||
|
||||
let treasury_amount: BalanceOf<T> = TREASURY_ALLOCATION
|
||||
.try_into()
|
||||
.map_err(|_| Error::<T>::InsufficientTreasuryBalance)?;
|
||||
let presale_amount: BalanceOf<T> = PRESALE_ALLOCATION
|
||||
.try_into()
|
||||
.map_err(|_| Error::<T>::InsufficientTreasuryBalance)?;
|
||||
let founder_amount: BalanceOf<T> = FOUNDER_ALLOCATION
|
||||
.try_into()
|
||||
.map_err(|_| Error::<T>::InsufficientTreasuryBalance)?;
|
||||
|
||||
T::Assets::mint_into(T::PezAssetId::get(), &treasury_account, treasury_amount)?;
|
||||
T::Assets::mint_into(T::PezAssetId::get(), &presale_account, presale_amount)?;
|
||||
T::Assets::mint_into(T::PezAssetId::get(), &founder_account, founder_amount)?;
|
||||
|
||||
// Mark genesis distribution as completed
|
||||
GenesisDistributionDone::<T>::put(true);
|
||||
|
||||
Self::deposit_event(Event::GenesisDistributionCompleted {
|
||||
treasury_amount,
|
||||
presale_amount,
|
||||
founder_amount,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn do_initialize_treasury() -> DispatchResult {
|
||||
ensure!(
|
||||
TreasuryStartBlock::<T>::get().is_none(),
|
||||
Error::<T>::TreasuryAlreadyInitialized
|
||||
);
|
||||
|
||||
let current_block = pezframe_system::Pallet::<T>::block_number();
|
||||
|
||||
let treasury_balance = TREASURY_ALLOCATION;
|
||||
let first_period_total =
|
||||
treasury_balance.checked_div(2).ok_or(Error::<T>::InvalidHalvingPeriod)?;
|
||||
let monthly_amount = first_period_total
|
||||
.checked_div(HALVING_PERIOD_MONTHS.into())
|
||||
.ok_or(Error::<T>::InvalidHalvingPeriod)?;
|
||||
|
||||
let monthly_amount_balance: BalanceOf<T> =
|
||||
monthly_amount.try_into().map_err(|_| Error::<T>::InsufficientTreasuryBalance)?;
|
||||
|
||||
let halving_data = HalvingData {
|
||||
current_period: 0,
|
||||
period_start_block: current_block,
|
||||
monthly_amount: monthly_amount_balance,
|
||||
total_released: Zero::zero(),
|
||||
};
|
||||
|
||||
TreasuryStartBlock::<T>::put(current_block);
|
||||
HalvingInfo::<T>::put(halving_data);
|
||||
NextReleaseMonth::<T>::put(0);
|
||||
|
||||
Self::deposit_event(Event::TreasuryInitialized {
|
||||
start_block: current_block,
|
||||
initial_monthly_amount: monthly_amount_balance,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn do_monthly_release() -> DispatchResult {
|
||||
ensure!(TreasuryStartBlock::<T>::get().is_some(), Error::<T>::TreasuryNotInitialized);
|
||||
|
||||
let current_block = pezframe_system::Pallet::<T>::block_number();
|
||||
let start_block = TreasuryStartBlock::<T>::get().unwrap();
|
||||
let next_month = NextReleaseMonth::<T>::get();
|
||||
|
||||
ensure!(
|
||||
!MonthlyReleases::<T>::contains_key(next_month),
|
||||
Error::<T>::MonthlyReleaseAlreadyDone
|
||||
);
|
||||
|
||||
let blocks_passed = current_block.saturating_sub(start_block);
|
||||
let months_passed: u32 = (blocks_passed / BLOCKS_PER_MONTH.into())
|
||||
.try_into()
|
||||
.map_err(|_| Error::<T>::InvalidHalvingPeriod)?;
|
||||
|
||||
// To release month 0, months_passed must be >= 1 (next_month + 1)
|
||||
// To release month 1, months_passed must be >= 2
|
||||
ensure!(months_passed > next_month, Error::<T>::ReleaseTooEarly);
|
||||
|
||||
let mut halving_data = HalvingInfo::<T>::get();
|
||||
|
||||
let current_period_passed_months =
|
||||
months_passed.saturating_sub(halving_data.current_period * HALVING_PERIOD_MONTHS);
|
||||
|
||||
if current_period_passed_months >= HALVING_PERIOD_MONTHS {
|
||||
halving_data.current_period = halving_data.current_period.saturating_add(1);
|
||||
halving_data.monthly_amount = halving_data
|
||||
.monthly_amount
|
||||
.checked_div(&2u32.into())
|
||||
.ok_or(Error::<T>::InvalidHalvingPeriod)?;
|
||||
halving_data.period_start_block = current_block;
|
||||
|
||||
Self::deposit_event(Event::NewHalvingPeriod {
|
||||
period: halving_data.current_period,
|
||||
new_monthly_amount: halving_data.monthly_amount,
|
||||
});
|
||||
}
|
||||
|
||||
let monthly_amount = halving_data.monthly_amount;
|
||||
let incentive_amount = monthly_amount
|
||||
.checked_mul(&75u32.into())
|
||||
.and_then(|v| v.checked_div(&100u32.into()))
|
||||
.ok_or(Error::<T>::InvalidHalvingPeriod)?;
|
||||
let government_amount = monthly_amount.saturating_sub(incentive_amount);
|
||||
|
||||
let treasury_account = Self::treasury_account_id();
|
||||
let incentive_pot = Self::incentive_pot_account_id();
|
||||
let government_pot = Self::government_pot_account_id();
|
||||
|
||||
T::Assets::transfer(
|
||||
T::PezAssetId::get(),
|
||||
&treasury_account,
|
||||
&incentive_pot,
|
||||
incentive_amount,
|
||||
Preservation::Preserve,
|
||||
)
|
||||
.map_err(|_| Error::<T>::InsufficientTreasuryBalance)?;
|
||||
|
||||
T::Assets::transfer(
|
||||
T::PezAssetId::get(),
|
||||
&treasury_account,
|
||||
&government_pot,
|
||||
government_amount,
|
||||
Preservation::Preserve,
|
||||
)
|
||||
.map_err(|_| Error::<T>::InsufficientTreasuryBalance)?;
|
||||
|
||||
halving_data.total_released =
|
||||
halving_data.total_released.saturating_add(monthly_amount);
|
||||
HalvingInfo::<T>::put(halving_data);
|
||||
|
||||
let release_info = MonthlyRelease {
|
||||
month_index: next_month,
|
||||
release_block: current_block,
|
||||
amount_released: monthly_amount,
|
||||
incentive_amount,
|
||||
government_amount,
|
||||
};
|
||||
|
||||
MonthlyReleases::<T>::insert(next_month, release_info);
|
||||
NextReleaseMonth::<T>::put(next_month + 1);
|
||||
|
||||
Self::deposit_event(Event::MonthlyFundsReleased {
|
||||
month_index: next_month,
|
||||
total_amount: monthly_amount,
|
||||
incentive_amount,
|
||||
government_amount,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_current_halving_info() -> HalvingData<T> {
|
||||
HalvingInfo::<T>::get()
|
||||
}
|
||||
|
||||
pub fn get_incentive_pot_balance() -> BalanceOf<T> {
|
||||
let pot_account = Self::incentive_pot_account_id();
|
||||
T::Assets::balance(T::PezAssetId::get(), &pot_account)
|
||||
}
|
||||
|
||||
pub fn get_government_pot_balance() -> BalanceOf<T> {
|
||||
let pot_account = Self::government_pot_account_id();
|
||||
T::Assets::balance(T::PezAssetId::get(), &pot_account)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
//! Storage migrations for pezpallet-pez-treasury
|
||||
|
||||
use super::*;
|
||||
use pezframe_support::{
|
||||
traits::{Get, GetStorageVersion, OnRuntimeUpgrade, StorageVersion},
|
||||
weights::Weight,
|
||||
};
|
||||
use pezsp_std::marker::PhantomData;
|
||||
|
||||
/// Current storage version
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
/// Migration from v0 to v1
|
||||
/// This migration handles the initial version setup for pezpallet-pez-treasury
|
||||
pub mod v1 {
|
||||
use super::*;
|
||||
|
||||
pub struct MigrateToV1<T>(PhantomData<T>);
|
||||
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log::info!(
|
||||
"🔄 Running migration for pezpallet-pez-treasury from {:?} to {:?}",
|
||||
current,
|
||||
STORAGE_VERSION
|
||||
);
|
||||
|
||||
if current == StorageVersion::new(0) {
|
||||
let mut weight = Weight::zero();
|
||||
|
||||
// Example migration logic for treasury storage
|
||||
// If storage format changes in the future, implement transformation here
|
||||
|
||||
// Count existing storage items for logging
|
||||
let monthly_releases_count = MonthlyReleases::<T>::iter().count() as u64;
|
||||
let has_halving_info = if HalvingInfo::<T>::exists() { 1u64 } else { 0u64 };
|
||||
let has_treasury_start =
|
||||
if TreasuryStartBlock::<T>::get().is_some() { 1u64 } else { 0u64 };
|
||||
let has_genesis_done =
|
||||
if GenesisDistributionDone::<T>::get() { 1u64 } else { 0u64 };
|
||||
|
||||
let migrated = monthly_releases_count +
|
||||
has_halving_info +
|
||||
has_treasury_start +
|
||||
has_genesis_done;
|
||||
|
||||
// Update storage version
|
||||
STORAGE_VERSION.put::<Pallet<T>>();
|
||||
|
||||
log::info!("✅ Migrated {} entries in pezpallet-pez-treasury", migrated);
|
||||
log::info!(" MonthlyReleases: {}, HalvingInfo: {}, TreasuryStartBlock: {}, GenesisDistributionDone: {}",
|
||||
monthly_releases_count, has_halving_info, has_treasury_start, has_genesis_done);
|
||||
|
||||
// Return weight used
|
||||
// Reads: all storage items + version read
|
||||
// Writes: version write
|
||||
weight = weight.saturating_add(T::DbWeight::get().reads_writes(migrated + 1, 1));
|
||||
|
||||
weight
|
||||
} else {
|
||||
log::info!(
|
||||
"👌 pezpallet-pez-treasury migration not needed, current version is {:?}",
|
||||
current
|
||||
);
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<pezsp_std::vec::Vec<u8>, pezsp_runtime::TryRuntimeError> {
|
||||
let current = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log::info!("🔍 Pre-upgrade check for pezpallet-pez-treasury");
|
||||
log::info!(" Current version: {:?}", current);
|
||||
|
||||
// Encode current storage counts for verification
|
||||
let monthly_releases_count = MonthlyReleases::<T>::iter().count() as u32;
|
||||
let next_release_month = NextReleaseMonth::<T>::get();
|
||||
let has_treasury_start = TreasuryStartBlock::<T>::get().is_some();
|
||||
let genesis_done = GenesisDistributionDone::<T>::get();
|
||||
|
||||
log::info!(" MonthlyReleases entries: {}", monthly_releases_count);
|
||||
log::info!(" NextReleaseMonth: {}", next_release_month);
|
||||
log::info!(" TreasuryStartBlock exists: {}", has_treasury_start);
|
||||
log::info!(" GenesisDistributionDone: {}", genesis_done);
|
||||
|
||||
Ok((monthly_releases_count, next_release_month, has_treasury_start, genesis_done)
|
||||
.encode())
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(state: pezsp_std::vec::Vec<u8>) -> Result<(), pezsp_runtime::TryRuntimeError> {
|
||||
use codec::Decode;
|
||||
|
||||
let (
|
||||
pre_monthly_releases_count,
|
||||
pre_next_release_month,
|
||||
pre_has_treasury_start,
|
||||
pre_genesis_done,
|
||||
): (u32, u32, bool, bool) = Decode::decode(&mut &state[..])
|
||||
.map_err(|_| "Failed to decode pre-upgrade state")?;
|
||||
|
||||
log::info!("🔍 Post-upgrade check for pezpallet-pez-treasury");
|
||||
|
||||
// Verify storage version was updated
|
||||
let current_version = Pallet::<T>::on_chain_storage_version();
|
||||
assert_eq!(current_version, STORAGE_VERSION, "Storage version not updated correctly");
|
||||
log::info!("✅ Storage version updated to {:?}", current_version);
|
||||
|
||||
// Verify storage counts (should be same or more, never less)
|
||||
let post_monthly_releases_count = MonthlyReleases::<T>::iter().count() as u32;
|
||||
let post_next_release_month = NextReleaseMonth::<T>::get();
|
||||
let post_has_treasury_start = TreasuryStartBlock::<T>::get().is_some();
|
||||
let post_genesis_done = GenesisDistributionDone::<T>::get();
|
||||
|
||||
log::info!(
|
||||
" MonthlyReleases entries: {} -> {}",
|
||||
pre_monthly_releases_count,
|
||||
post_monthly_releases_count
|
||||
);
|
||||
log::info!(
|
||||
" NextReleaseMonth: {} -> {}",
|
||||
pre_next_release_month,
|
||||
post_next_release_month
|
||||
);
|
||||
log::info!(
|
||||
" TreasuryStartBlock exists: {} -> {}",
|
||||
pre_has_treasury_start,
|
||||
post_has_treasury_start
|
||||
);
|
||||
log::info!(" GenesisDistributionDone: {} -> {}", pre_genesis_done, post_genesis_done);
|
||||
|
||||
// Verify no data was lost
|
||||
assert!(
|
||||
post_monthly_releases_count >= pre_monthly_releases_count,
|
||||
"MonthlyReleases entries decreased during migration"
|
||||
);
|
||||
|
||||
// NextReleaseMonth should not decrease
|
||||
assert!(
|
||||
post_next_release_month >= pre_next_release_month,
|
||||
"NextReleaseMonth decreased during migration"
|
||||
);
|
||||
|
||||
// Treasury start block should not be removed if it existed
|
||||
if pre_has_treasury_start {
|
||||
assert!(post_has_treasury_start, "TreasuryStartBlock was removed during migration");
|
||||
}
|
||||
|
||||
// Genesis done flag should not change from true to false
|
||||
if pre_genesis_done {
|
||||
assert!(post_genesis_done, "GenesisDistributionDone was reset during migration");
|
||||
}
|
||||
|
||||
log::info!("✅ Post-upgrade checks passed for pezpallet-pez-treasury");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Example migration for future version changes
|
||||
/// This demonstrates how to handle storage format changes in treasury data
|
||||
pub mod v2 {
|
||||
use super::*;
|
||||
|
||||
/// Example: Migration when halving data or release format changes
|
||||
pub struct MigrateToV2<T>(PhantomData<T>);
|
||||
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV2<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
if current < StorageVersion::new(2) {
|
||||
log::info!("🔄 Running migration for pezpallet-pez-treasury to v2");
|
||||
|
||||
// Example migration logic
|
||||
// 1. Transform halving data if format changed
|
||||
// 2. Migrate monthly release records if needed
|
||||
// 3. Update version
|
||||
|
||||
// For now, this is just a template
|
||||
StorageVersion::new(2).put::<Pallet<T>>();
|
||||
|
||||
log::info!("✅ Completed migration to pezpallet-pez-treasury v2");
|
||||
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
} else {
|
||||
log::info!("👌 pezpallet-pez-treasury v2 migration not needed");
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<pezsp_std::vec::Vec<u8>, pezsp_runtime::TryRuntimeError> {
|
||||
log::info!("🔍 Pre-upgrade check for pezpallet-pez-treasury v2");
|
||||
Ok(pezsp_std::vec::Vec::new())
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(_state: pezsp_std::vec::Vec<u8>) -> Result<(), pezsp_runtime::TryRuntimeError> {
|
||||
log::info!("✅ Post-upgrade check passed for pezpallet-pez-treasury v2");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{new_test_ext, Test};
|
||||
use pezframe_support::traits::OnRuntimeUpgrade;
|
||||
|
||||
#[test]
|
||||
fn test_migration_v1() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Set initial storage version to 0
|
||||
StorageVersion::new(0).put::<Pallet<Test>>();
|
||||
|
||||
// Run migration
|
||||
let weight = v1::MigrateToV1::<Test>::on_runtime_upgrade();
|
||||
|
||||
// Verify version was updated
|
||||
assert_eq!(Pallet::<Test>::on_chain_storage_version(), STORAGE_VERSION);
|
||||
|
||||
// Verify weight is non-zero
|
||||
assert!(weight != Weight::zero());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migration_idempotent() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Set current version
|
||||
STORAGE_VERSION.put::<Pallet<Test>>();
|
||||
|
||||
// Run migration again
|
||||
let weight = v1::MigrateToV1::<Test>::on_runtime_upgrade();
|
||||
|
||||
// Should be a no-op
|
||||
assert_eq!(weight, pezframe_support::weights::constants::RocksDbWeight::get().reads(1));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
// pezkuwi/pallets/pez-treasury/src/mock.rs
|
||||
// VERSION 3: AccountId tipi H256 yapıldı (u64 yerine)
|
||||
|
||||
use crate as pezpallet_pez_treasury;
|
||||
use pezframe_support::{
|
||||
assert_ok, construct_runtime, parameter_types,
|
||||
traits::{ConstU128, ConstU32, OnFinalize, OnInitialize},
|
||||
PalletId,
|
||||
};
|
||||
use pezsp_core::H256;
|
||||
use pezsp_runtime::{
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
BuildStorage,
|
||||
};
|
||||
|
||||
type Block = pezframe_system::mocking::MockBlock<Test>;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Test
|
||||
{
|
||||
System: pezframe_system,
|
||||
Balances: pezpallet_balances,
|
||||
Assets: pezpallet_assets,
|
||||
PezTreasury: pezpallet_pez_treasury,
|
||||
}
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
|
||||
impl pezframe_system::Config for Test {
|
||||
type BaseCallFilter = pezframe_support::traits::Everything;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = pezframe_support::weights::constants::RocksDbWeight;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type Nonce = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = H256; // V3: u64 -> H256 değişti
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Block = Block;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type Version = ();
|
||||
type PalletInfo = PalletInfo;
|
||||
type AccountData = pezpallet_balances::AccountData<u128>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
type SS58Prefix = ();
|
||||
type OnSetCode = ();
|
||||
type MaxConsumers = ConstU32<16>;
|
||||
type SingleBlockMigrations = ();
|
||||
type MultiBlockMigrator = ();
|
||||
type PreInherents = ();
|
||||
type PostInherents = ();
|
||||
type PostTransactions = ();
|
||||
type RuntimeTask = ();
|
||||
type ExtensionsWeightInfo = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ExistentialDeposit: u128 = 1;
|
||||
}
|
||||
|
||||
impl pezpallet_balances::Config for Test {
|
||||
type MaxLocks = ();
|
||||
type MaxReserves = ();
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type Balance = u128;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type FreezeIdentifier = ();
|
||||
type MaxFreezes = ();
|
||||
type RuntimeHoldReason = ();
|
||||
type RuntimeFreezeReason = ();
|
||||
type DoneSlashHandler = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const AssetDeposit: u128 = 100;
|
||||
pub const ApprovalDeposit: u128 = 1;
|
||||
pub const StringLimit: u32 = 50;
|
||||
pub const MetadataDepositBase: u128 = 10;
|
||||
pub const MetadataDepositPerByte: u128 = 1;
|
||||
}
|
||||
|
||||
impl pezpallet_assets::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Balance = u128;
|
||||
type AssetId = u32;
|
||||
type AssetIdParameter = u32;
|
||||
type Currency = Balances;
|
||||
type CreateOrigin =
|
||||
pezframe_support::traits::AsEnsureOriginWithArg<pezframe_system::EnsureSigned<Self::AccountId>>;
|
||||
type ForceOrigin = pezframe_system::EnsureRoot<Self::AccountId>;
|
||||
type AssetDeposit = AssetDeposit;
|
||||
type AssetAccountDeposit = ConstU128<0>;
|
||||
type MetadataDepositBase = MetadataDepositBase;
|
||||
type MetadataDepositPerByte = MetadataDepositPerByte;
|
||||
type ApprovalDeposit = ApprovalDeposit;
|
||||
type StringLimit = StringLimit;
|
||||
type Freezer = ();
|
||||
type Extra = ();
|
||||
type CallbackHandle = ();
|
||||
type WeightInfo = ();
|
||||
type RemoveItemsLimit = ConstU32<1000>;
|
||||
type Holder = ();
|
||||
type ReserveData = ();
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
// CRITICAL: Bu üç PalletId FARKLI olmak ZORUNDA
|
||||
parameter_types! {
|
||||
pub const PezTreasuryPalletId: PalletId = PalletId(*b"py/pztrs");
|
||||
pub const PezIncentivePotId: PalletId = PalletId(*b"py/pzinc");
|
||||
pub const PezGovernmentPotId: PalletId = PalletId(*b"py/pzgov");
|
||||
pub const PezAssetId: u32 = 1;
|
||||
}
|
||||
|
||||
// V3: Test accounts - H256 formatında
|
||||
use pezsp_runtime::traits::AccountIdConversion;
|
||||
|
||||
pub fn alice() -> H256 {
|
||||
H256::from_low_u64_be(1)
|
||||
}
|
||||
|
||||
pub fn bob() -> H256 {
|
||||
H256::from_low_u64_be(2)
|
||||
}
|
||||
|
||||
pub fn charlie() -> H256 {
|
||||
H256::from_low_u64_be(3)
|
||||
}
|
||||
|
||||
pub fn presale() -> H256 {
|
||||
H256::from_low_u64_be(10)
|
||||
}
|
||||
|
||||
pub fn founder() -> H256 {
|
||||
H256::from_low_u64_be(11)
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub PresaleAccount: H256 = presale();
|
||||
pub FounderAccount: H256 = founder();
|
||||
}
|
||||
|
||||
impl pezpallet_pez_treasury::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Assets = Assets;
|
||||
type WeightInfo = ();
|
||||
type PezAssetId = PezAssetId;
|
||||
type TreasuryPalletId = PezTreasuryPalletId;
|
||||
type IncentivePotId = PezIncentivePotId;
|
||||
type GovernmentPotId = PezGovernmentPotId;
|
||||
type PresaleAccount = PresaleAccount;
|
||||
type FounderAccount = FounderAccount;
|
||||
type ForceOrigin = pezframe_system::EnsureRoot<Self::AccountId>;
|
||||
}
|
||||
|
||||
// Build genesis storage according to the mock runtime.
|
||||
pub fn new_test_ext() -> pezsp_io::TestExternalities {
|
||||
let mut t = pezframe_system::GenesisConfig::<Test>::default().build_storage().unwrap();
|
||||
|
||||
pezpallet_balances::GenesisConfig::<Test> {
|
||||
balances: vec![
|
||||
(alice(), 1_000_000_000_000_000),
|
||||
(bob(), 1_000_000_000_000_000),
|
||||
(charlie(), 1_000_000_000_000_000),
|
||||
(presale(), 1_000_000_000_000_000),
|
||||
(founder(), 1_000_000_000_000_000),
|
||||
],
|
||||
dev_accounts: None,
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = pezsp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
|
||||
// Create PEZ asset
|
||||
assert_ok!(Assets::force_create(
|
||||
RuntimeOrigin::root(),
|
||||
PezAssetId::get(),
|
||||
alice(),
|
||||
true,
|
||||
1
|
||||
));
|
||||
});
|
||||
ext
|
||||
}
|
||||
|
||||
// Helper function to run to specific block
|
||||
pub fn run_to_block(n: u64) {
|
||||
while System::block_number() < n {
|
||||
if System::block_number() > 1 {
|
||||
AllPalletsWithSystem::on_finalize(System::block_number());
|
||||
}
|
||||
System::set_block_number(System::block_number() + 1);
|
||||
AllPalletsWithSystem::on_initialize(System::block_number());
|
||||
}
|
||||
}
|
||||
|
||||
// V3: Helper to assert balance - H256 account ile
|
||||
pub fn assert_pez_balance(account: H256, expected: u128) {
|
||||
assert_eq!(
|
||||
Assets::balance(PezAssetId::get(), account),
|
||||
expected,
|
||||
"PEZ balance mismatch for account {:?}. Expected: {}, Got: {}",
|
||||
account,
|
||||
expected,
|
||||
Assets::balance(PezAssetId::get(), account)
|
||||
);
|
||||
}
|
||||
|
||||
// V3: Helper fonksiyonlar - H256 dönüyor
|
||||
#[allow(dead_code)]
|
||||
pub fn treasury_account() -> H256 {
|
||||
PezTreasuryPalletId::get().into_account_truncating()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn incentive_pot_account() -> H256 {
|
||||
PezIncentivePotId::get().into_account_truncating()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn government_pot_account() -> H256 {
|
||||
PezGovernmentPotId::get().into_account_truncating()
|
||||
}
|
||||
|
||||
// V3: Debug helper
|
||||
#[allow(dead_code)]
|
||||
pub fn debug_pot_accounts() {
|
||||
println!("\n=== PalletId Debug ===");
|
||||
println!("Treasury bytes: {:?}", PezTreasuryPalletId::get().0);
|
||||
println!("Incentive bytes: {:?}", PezIncentivePotId::get().0);
|
||||
println!("Government bytes: {:?}", PezGovernmentPotId::get().0);
|
||||
println!("======================\n");
|
||||
}
|
||||
@@ -0,0 +1,969 @@
|
||||
// pezkuwi/pallets/pez-treasury/src/tests.rs
|
||||
|
||||
use crate::{mock::*, Error, Event};
|
||||
use pezframe_support::{assert_noop, assert_ok};
|
||||
use pezsp_runtime::traits::Zero; // FIXED: Import Zero trait for is_zero() method
|
||||
|
||||
// =============================================================================
|
||||
// 1. GENESIS DISTRIBUTION TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn genesis_distribution_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
|
||||
let treasury_amount = 4_812_500_000 * 1_000_000_000_000u128;
|
||||
let presale_amount = 93_750_000 * 1_000_000_000_000u128;
|
||||
let founder_amount = 93_750_000 * 1_000_000_000_000u128;
|
||||
|
||||
assert_pez_balance(treasury_account(), treasury_amount);
|
||||
assert_pez_balance(presale(), presale_amount);
|
||||
assert_pez_balance(founder(), founder_amount);
|
||||
|
||||
let total = treasury_amount + presale_amount + founder_amount;
|
||||
assert_eq!(total, 5_000_000_000 * 1_000_000_000_000u128);
|
||||
|
||||
System::assert_has_event(
|
||||
Event::GenesisDistributionCompleted { treasury_amount, presale_amount, founder_amount }
|
||||
.into(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn force_genesis_distribution_requires_root() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(
|
||||
PezTreasury::force_genesis_distribution(RuntimeOrigin::signed(alice())),
|
||||
pezsp_runtime::DispatchError::BadOrigin
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn force_genesis_distribution_works_with_root() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::force_genesis_distribution(RuntimeOrigin::root()));
|
||||
|
||||
assert!(Assets::balance(PezAssetId::get(), treasury_account()) > 0);
|
||||
assert!(Assets::balance(PezAssetId::get(), presale()) > 0);
|
||||
assert!(Assets::balance(PezAssetId::get(), founder()) > 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_distribution_can_only_happen_once() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// First call should succeed
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
|
||||
// Verify flag is set
|
||||
assert!(PezTreasury::genesis_distribution_done());
|
||||
|
||||
// Second call should fail
|
||||
assert_noop!(
|
||||
PezTreasury::do_genesis_distribution(),
|
||||
Error::<Test>::GenesisDistributionAlreadyDone
|
||||
);
|
||||
|
||||
// Verify balances didn't double
|
||||
let treasury_amount = 4_812_500_000 * 1_000_000_000_000u128;
|
||||
assert_pez_balance(treasury_account(), treasury_amount);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 2. TREASURY INITIALIZATION TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn initialize_treasury_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let start_block = System::block_number();
|
||||
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Verify storage
|
||||
assert_eq!(PezTreasury::treasury_start_block(), Some(start_block));
|
||||
|
||||
let halving_info = PezTreasury::halving_info();
|
||||
assert_eq!(halving_info.current_period, 0);
|
||||
assert_eq!(halving_info.period_start_block, start_block);
|
||||
assert!(!halving_info.monthly_amount.is_zero());
|
||||
|
||||
// Verify next release month
|
||||
assert_eq!(PezTreasury::next_release_month(), 0);
|
||||
|
||||
// Verify event
|
||||
System::assert_has_event(
|
||||
Event::TreasuryInitialized {
|
||||
start_block,
|
||||
initial_monthly_amount: halving_info.monthly_amount,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_treasury_fails_if_already_initialized() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Try to initialize again
|
||||
assert_noop!(
|
||||
PezTreasury::initialize_treasury(RuntimeOrigin::root()),
|
||||
Error::<Test>::TreasuryAlreadyInitialized
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_treasury_requires_root() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(
|
||||
PezTreasury::initialize_treasury(RuntimeOrigin::signed(alice())),
|
||||
pezsp_runtime::DispatchError::BadOrigin
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_treasury_calculates_correct_monthly_amount() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let halving_info = PezTreasury::halving_info();
|
||||
|
||||
// First period total = 96.25% / 2 = 48.125%
|
||||
let treasury_total = 4_812_500_000 * 1_000_000_000_000u128;
|
||||
let first_period = treasury_total / 2;
|
||||
let expected_monthly = first_period / 48; // 48 months
|
||||
|
||||
assert_eq!(halving_info.monthly_amount, expected_monthly);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 3. MONTHLY RELEASE TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn release_monthly_funds_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial_monthly = PezTreasury::halving_info().monthly_amount;
|
||||
let incentive_expected = initial_monthly * 75 / 100;
|
||||
let government_expected = initial_monthly - incentive_expected;
|
||||
|
||||
run_to_block(432_001);
|
||||
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
assert_pez_balance(PezTreasury::incentive_pot_account_id(), incentive_expected);
|
||||
assert_pez_balance(PezTreasury::government_pot_account_id(), government_expected);
|
||||
|
||||
assert_eq!(PezTreasury::next_release_month(), 1);
|
||||
|
||||
let halving_info = PezTreasury::halving_info();
|
||||
assert_eq!(halving_info.total_released, initial_monthly);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_monthly_funds_fails_if_not_initialized() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_noop!(
|
||||
PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
|
||||
Error::<Test>::TreasuryNotInitialized
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_monthly_funds_fails_if_too_early() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Try to release before time
|
||||
run_to_block(100);
|
||||
|
||||
assert_noop!(
|
||||
PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
|
||||
Error::<Test>::ReleaseTooEarly
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_monthly_funds_fails_if_already_released() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Try to release same month again
|
||||
assert_noop!(
|
||||
PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
|
||||
Error::<Test>::ReleaseTooEarly
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_monthly_funds_splits_correctly() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let monthly_amount = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
let incentive_balance =
|
||||
Assets::balance(PezAssetId::get(), PezTreasury::incentive_pot_account_id());
|
||||
let government_balance =
|
||||
Assets::balance(PezAssetId::get(), PezTreasury::government_pot_account_id());
|
||||
|
||||
// 75% to incentive, 25% to government
|
||||
assert_eq!(incentive_balance, monthly_amount * 75 / 100);
|
||||
// lib.rs'deki mantıkla aynı olmalı (saturating_sub)
|
||||
let incentive_amount_calculated = monthly_amount * 75 / 100;
|
||||
assert_eq!(government_balance, monthly_amount - incentive_amount_calculated);
|
||||
|
||||
// Total should equal monthly amount
|
||||
assert_eq!(incentive_balance + government_balance, monthly_amount);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_monthly_releases_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let monthly_amount = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// Release month 0
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
assert_eq!(PezTreasury::next_release_month(), 1);
|
||||
|
||||
// Release month 1
|
||||
run_to_block(864_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
assert_eq!(PezTreasury::next_release_month(), 2);
|
||||
|
||||
// Release month 2
|
||||
run_to_block(1_296_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
assert_eq!(PezTreasury::next_release_month(), 3);
|
||||
|
||||
// Verify total released
|
||||
let halving_info = PezTreasury::halving_info();
|
||||
assert_eq!(halving_info.total_released, monthly_amount * 3);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 4. HALVING LOGIC TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn halving_occurs_after_48_months() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial_monthly = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// Release 47 months (no halving yet)
|
||||
for month in 0..47 {
|
||||
run_to_block(1 + (month + 1) * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
}
|
||||
|
||||
// Still period 0
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 0);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly);
|
||||
|
||||
// Release 48th month - halving should occur
|
||||
run_to_block(1 + 48 * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Now in period 1 with halved amount
|
||||
let halving_info = PezTreasury::halving_info();
|
||||
assert_eq!(halving_info.current_period, 1);
|
||||
assert_eq!(halving_info.monthly_amount, initial_monthly / 2);
|
||||
|
||||
// Verify event
|
||||
System::assert_has_event(
|
||||
Event::NewHalvingPeriod { period: 1, new_monthly_amount: initial_monthly / 2 }.into(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_halvings_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial_monthly = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// First halving at month 48
|
||||
run_to_block(1 + 48 * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 1);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 2);
|
||||
|
||||
// Second halving at month 96
|
||||
run_to_block(1 + 96 * 432_000 + 1);
|
||||
for _ in 49..=96 {
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
}
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 2);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 4);
|
||||
|
||||
// Third halving at month 144
|
||||
run_to_block(1 + 144 * 432_000 + 1);
|
||||
for _ in 97..=144 {
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
}
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 3);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 8);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn halving_period_start_block_updates() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let period_0_start = PezTreasury::halving_info().period_start_block;
|
||||
|
||||
// Trigger halving
|
||||
run_to_block(1 + 48 * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
let period_1_start = PezTreasury::halving_info().period_start_block;
|
||||
assert!(period_1_start > period_0_start);
|
||||
assert_eq!(period_1_start, System::block_number());
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 5. ERROR CASES
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn insufficient_treasury_balance_error() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Initialize without genesis distribution (treasury empty)
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
run_to_block(432_001);
|
||||
|
||||
// This should fail due to insufficient balance
|
||||
assert_noop!(
|
||||
PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
|
||||
Error::<Test>::InsufficientTreasuryBalance
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_requires_root_origin() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
run_to_block(432_001);
|
||||
|
||||
assert_noop!(
|
||||
PezTreasury::release_monthly_funds(RuntimeOrigin::signed(alice())),
|
||||
pezsp_runtime::DispatchError::BadOrigin
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 6. EDGE CASES
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn release_exactly_at_boundary_block_fails() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Tam 432_000. blok (start_block=1 olduğu için) 431_999 blok geçti demektir.
|
||||
// Bu, 1 tam ay (432_000 blok) değildir.
|
||||
run_to_block(432_000);
|
||||
assert_noop!(
|
||||
PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
|
||||
Error::<Test>::ReleaseTooEarly
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_one_block_before_boundary_fails() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
run_to_block(432_000 - 1);
|
||||
assert_noop!(
|
||||
PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
|
||||
Error::<Test>::ReleaseTooEarly
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_months_and_release() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Skip directly to month 3
|
||||
run_to_block(1 + 3 * 432_000 + 1);
|
||||
|
||||
// Should release month 0
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
assert_eq!(PezTreasury::next_release_month(), 1);
|
||||
|
||||
// Can still release subsequent months
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
assert_eq!(PezTreasury::next_release_month(), 2);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn very_large_block_number() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Jump to very large block number
|
||||
System::set_block_number(u64::MAX / 2);
|
||||
|
||||
// Should still be able to release (if months passed)
|
||||
// This tests overflow protection
|
||||
let result = PezTreasury::release_monthly_funds(RuntimeOrigin::root());
|
||||
// Result depends on whether enough months passed
|
||||
// Main point: no panic/overflow
|
||||
assert!(result.is_ok() || result.is_err());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_amount_division_protection() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Initialize without any balance
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let halving_info = PezTreasury::halving_info();
|
||||
// Should not panic, should have some calculated amount
|
||||
assert!(!halving_info.monthly_amount.is_zero());
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 7. GETTER FUNCTIONS TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn get_current_halving_info_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let info = PezTreasury::get_current_halving_info();
|
||||
assert_eq!(info.current_period, 0);
|
||||
assert!(!info.monthly_amount.is_zero());
|
||||
assert_eq!(info.total_released, 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_incentive_pot_balance_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
let balance = PezTreasury::get_incentive_pot_balance();
|
||||
assert!(balance > 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_government_pot_balance_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
let balance = PezTreasury::get_government_pot_balance();
|
||||
assert!(balance > 0);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 8. ACCOUNT ID TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn treasury_account_id_is_consistent() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let account1 = PezTreasury::treasury_account_id();
|
||||
let account2 = PezTreasury::treasury_account_id();
|
||||
assert_eq!(account1, account2);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pot_accounts_are_different() {
|
||||
new_test_ext().execute_with(|| {
|
||||
debug_pot_accounts();
|
||||
|
||||
let treasury = PezTreasury::treasury_account_id();
|
||||
let incentive = PezTreasury::incentive_pot_account_id();
|
||||
let government = PezTreasury::government_pot_account_id();
|
||||
|
||||
println!("\n=== Account IDs from Pallet ===");
|
||||
println!("Treasury: {:?}", treasury);
|
||||
println!("Incentive: {:?}", incentive);
|
||||
println!("Government: {:?}", government);
|
||||
println!("================================\n");
|
||||
|
||||
// Tüm üçü farklı olmalı
|
||||
assert_ne!(treasury, incentive, "Treasury and Incentive must be different");
|
||||
assert_ne!(treasury, government, "Treasury and Government must be different");
|
||||
assert_ne!(incentive, government, "Incentive and Government must be different");
|
||||
|
||||
println!("✓ All pot accounts are different!");
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 9. MONTHLY RELEASE STORAGE TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn monthly_release_records_stored_correctly() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let monthly_amount = PezTreasury::halving_info().monthly_amount;
|
||||
let incentive_expected = monthly_amount * 75 / 100;
|
||||
let government_expected = monthly_amount - incentive_expected;
|
||||
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Verify monthly release record
|
||||
let release = PezTreasury::monthly_releases(0).unwrap();
|
||||
assert_eq!(release.month_index, 0);
|
||||
assert_eq!(release.amount_released, monthly_amount);
|
||||
assert_eq!(release.incentive_amount, incentive_expected);
|
||||
assert_eq!(release.government_amount, government_expected);
|
||||
assert_eq!(release.release_block, System::block_number());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_monthly_releases_stored_separately() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Release month 0
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Release month 1
|
||||
run_to_block(864_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Verify both records exist
|
||||
assert!(PezTreasury::monthly_releases(0).is_some());
|
||||
assert!(PezTreasury::monthly_releases(1).is_some());
|
||||
|
||||
let release_0 = PezTreasury::monthly_releases(0).unwrap();
|
||||
let release_1 = PezTreasury::monthly_releases(1).unwrap();
|
||||
|
||||
assert_eq!(release_0.month_index, 0);
|
||||
assert_eq!(release_1.month_index, 1);
|
||||
assert_ne!(release_0.release_block, release_1.release_block);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 10. INTEGRATION TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn full_lifecycle_test() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// 1. Genesis distribution
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
let treasury_initial = Assets::balance(PezAssetId::get(), treasury_account());
|
||||
assert!(treasury_initial > 0);
|
||||
|
||||
// 2. Initialize treasury
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
let monthly_amount = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// 3. Release first month
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
let treasury_after_month_0 = Assets::balance(PezAssetId::get(), treasury_account());
|
||||
assert_eq!(treasury_initial - treasury_after_month_0, monthly_amount);
|
||||
|
||||
// 4. Release multiple months
|
||||
for month in 1..10 {
|
||||
run_to_block(1 + (month + 1) * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
}
|
||||
|
||||
// 5. Verify cumulative release
|
||||
let halving_info = PezTreasury::halving_info();
|
||||
assert_eq!(halving_info.total_released, monthly_amount * 10);
|
||||
|
||||
// 6. Verify treasury balance decreased correctly
|
||||
let treasury_after_10_months = Assets::balance(PezAssetId::get(), treasury_account());
|
||||
assert_eq!(treasury_initial - treasury_after_10_months, monthly_amount * 10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_halving_cycle_test() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial_monthly = PezTreasury::halving_info().monthly_amount;
|
||||
let mut cumulative_released = 0u128;
|
||||
|
||||
// Period 0: 48 months at initial rate
|
||||
for month in 0..48 {
|
||||
run_to_block(1 + (month + 1) * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
if month < 47 {
|
||||
cumulative_released += initial_monthly;
|
||||
} else {
|
||||
// 48. sürümde (index 47) halving tetiklenir ve yarı tutar kullanılır
|
||||
cumulative_released += initial_monthly / 2;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 1);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 2);
|
||||
|
||||
// Period 1: 48 months at half rate
|
||||
for month in 48..96 {
|
||||
run_to_block(1 + (month + 1) * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
if month < 95 {
|
||||
cumulative_released += initial_monthly / 2;
|
||||
} else {
|
||||
// 96. sürümde (index 95) ikinci halving tetiklenir
|
||||
cumulative_released += initial_monthly / 4;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 2);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 4);
|
||||
|
||||
// Verify total released matches expectation
|
||||
assert_eq!(PezTreasury::halving_info().total_released, cumulative_released);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 11. PRECISION AND ROUNDING TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn division_rounding_is_consistent() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let monthly_amount = PezTreasury::halving_info().monthly_amount;
|
||||
let incentive_amount = monthly_amount * 75 / 100;
|
||||
let government_amount = monthly_amount - incentive_amount;
|
||||
|
||||
// Verify no rounding loss
|
||||
assert_eq!(incentive_amount + government_amount, monthly_amount);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn halving_precision_maintained() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// Trigger halving
|
||||
run_to_block(1 + 48 * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
let after_halving = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// Check halving is exactly half (no precision loss)
|
||||
assert_eq!(after_halving, initial / 2);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 12. EVENT EMISSION TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn all_events_emitted_correctly() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Genesis distribution event
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert!(System::events().iter().any(|e| matches!(
|
||||
e.event,
|
||||
RuntimeEvent::PezTreasury(Event::GenesisDistributionCompleted { .. })
|
||||
)));
|
||||
|
||||
// Treasury initialized event
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
assert!(System::events().iter().any(|e| matches!(
|
||||
e.event,
|
||||
RuntimeEvent::PezTreasury(Event::TreasuryInitialized { .. })
|
||||
)));
|
||||
|
||||
// Monthly funds released event
|
||||
run_to_block(432_001);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
assert!(System::events().iter().any(|e| matches!(
|
||||
e.event,
|
||||
RuntimeEvent::PezTreasury(Event::MonthlyFundsReleased { .. })
|
||||
)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn halving_event_emitted_at_correct_time() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Clear existing events
|
||||
System::reset_events();
|
||||
|
||||
// Release up to halving point
|
||||
run_to_block(1 + 48 * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Verify halving event emitted
|
||||
assert!(System::events().iter().any(|e| matches!(
|
||||
e.event,
|
||||
RuntimeEvent::PezTreasury(Event::NewHalvingPeriod { period: 1, .. })
|
||||
)));
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 13. STRESS TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn many_consecutive_releases() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
// Release 100 months consecutively
|
||||
for month in 0..100 {
|
||||
run_to_block(1 + (month + 1) * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
}
|
||||
|
||||
// Verify state is consistent
|
||||
assert_eq!(PezTreasury::next_release_month(), 100);
|
||||
|
||||
// Should be in period 2 (after 2 halvings at months 48 and 96)
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 2);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn treasury_never_goes_negative() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let _initial_balance = Assets::balance(PezAssetId::get(), treasury_account()); // FIXED: Prefixed with underscore
|
||||
|
||||
// Try to release many months
|
||||
for month in 0..200 {
|
||||
run_to_block(1 + (month + 1) * 432_000 + 1);
|
||||
|
||||
let before_balance = Assets::balance(PezAssetId::get(), treasury_account());
|
||||
|
||||
let result = PezTreasury::release_monthly_funds(RuntimeOrigin::root());
|
||||
|
||||
if result.is_ok() {
|
||||
let after_balance = Assets::balance(PezAssetId::get(), treasury_account());
|
||||
// Balance should decrease or stay the same, never increase
|
||||
assert!(after_balance <= before_balance);
|
||||
// Balance should never go below zero
|
||||
assert!(after_balance >= 0);
|
||||
} else {
|
||||
// If release fails, balance should be unchanged
|
||||
assert_eq!(before_balance, Assets::balance(PezAssetId::get(), treasury_account()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 14. BOUNDARY CONDITION TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn first_block_initialization() {
|
||||
new_test_ext().execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
assert_eq!(PezTreasury::treasury_start_block(), Some(1));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn last_month_of_period_before_halving() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial_amount = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// Release month 47 (last before halving)
|
||||
run_to_block(1 + 47 * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Should still be in period 0
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 0);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_amount);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_month_after_halving() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial_amount = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// Trigger halving at month 48
|
||||
run_to_block(1 + 48 * 432_000 + 1);
|
||||
assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
|
||||
|
||||
// Should be in period 1 with halved amount
|
||||
assert_eq!(PezTreasury::halving_info().current_period, 1);
|
||||
assert_eq!(PezTreasury::halving_info().monthly_amount, initial_amount / 2);
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 15. MATHEMATICAL CORRECTNESS TESTS
|
||||
// =============================================================================
|
||||
|
||||
#[test]
|
||||
fn total_supply_equals_sum_of_allocations() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
|
||||
let treasury = Assets::balance(PezAssetId::get(), treasury_account());
|
||||
let presale_acc = Assets::balance(PezAssetId::get(), presale());
|
||||
let founder_acc = Assets::balance(PezAssetId::get(), founder());
|
||||
|
||||
let total = treasury + presale_acc + founder_acc;
|
||||
let expected_total = 5_000_000_000 * 1_000_000_000_000u128;
|
||||
|
||||
assert_eq!(total, expected_total);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn percentage_allocations_correct() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
|
||||
let total_supply = 5_000_000_000 * 1_000_000_000_000u128;
|
||||
let treasury = Assets::balance(PezAssetId::get(), treasury_account());
|
||||
let presale_acc = Assets::balance(PezAssetId::get(), presale());
|
||||
let founder_acc = Assets::balance(PezAssetId::get(), founder());
|
||||
|
||||
assert_eq!(treasury, total_supply * 9625 / 10000);
|
||||
assert_eq!(presale_acc, total_supply * 1875 / 100000);
|
||||
assert_eq!(founder_acc, total_supply * 1875 / 100000);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_period_total_is_half_of_treasury() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::do_genesis_distribution());
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let monthly_amount = PezTreasury::halving_info().monthly_amount;
|
||||
let first_period_total = monthly_amount * 48;
|
||||
|
||||
let treasury_allocation = 4_812_500_000 * 1_000_000_000_000u128;
|
||||
let expected_first_period = treasury_allocation / 2;
|
||||
|
||||
let diff = expected_first_period.saturating_sub(first_period_total);
|
||||
// Kalanların toplamı 48'den az olmalı (her ay en fazla 1 birim kalan)
|
||||
assert!(diff < 48, "Rounding error too large: {}", diff);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn geometric_series_sum_validates() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
|
||||
|
||||
let initial_monthly = PezTreasury::halving_info().monthly_amount;
|
||||
|
||||
// Sum of geometric series: a(1 - r^n) / (1 - r)
|
||||
// For halving: first_period * (1 - 0.5^n) / 0.5
|
||||
// With infinite halvings approaches: first_period * 2
|
||||
|
||||
let first_period_total = initial_monthly * 48;
|
||||
let treasury_allocation = 4_812_500_000 * 1_000_000_000_000u128;
|
||||
|
||||
// After infinite halvings, total distributed = treasury_allocation
|
||||
// first_period_total * 2 = treasury_allocation
|
||||
let diff = treasury_allocation.saturating_sub(first_period_total * 2);
|
||||
// Kalanların toplamı (2 ile çarpılmış) 96'dan az olmalı
|
||||
assert!(diff < 96, "Rounding error too large: {}", diff);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
//! Autogenerated weights for `pezpallet_pez_treasury`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2025-12-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `MamostePC`, CPU: `11th Gen Intel(R) Core(TM) i9-11950H @ 2.60GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/release/frame-omni-bencher
|
||||
// v1
|
||||
// benchmark
|
||||
// pallet
|
||||
// --runtime
|
||||
// ./target/release/wbuild/asset-hub-pezkuwichain-runtime/asset_hub_pezkuwichain_runtime.wasm
|
||||
// --pallet
|
||||
// pezpallet_pez_treasury
|
||||
// --extrinsic
|
||||
// *
|
||||
// --steps
|
||||
// 50
|
||||
// --repeat
|
||||
// 20
|
||||
// --output
|
||||
// ./pezcumulus/teyrchains/pezpallets/pez-treasury/src/weights.rs
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use pezframe_support::{traits::Get, weights::Weight};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for `pezpallet_pez_treasury`.
|
||||
pub trait WeightInfo {
|
||||
fn initialize_treasury() -> Weight;
|
||||
fn force_genesis_distribution() -> Weight;
|
||||
fn release_monthly_funds() -> Weight;
|
||||
}
|
||||
|
||||
/// Weight functions for `pezpallet_pez_treasury`.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `PezTreasury::TreasuryStartBlock` (r:1 w:1)
|
||||
/// Proof: `PezTreasury::TreasuryStartBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `PezTreasury::NextReleaseMonth` (r:0 w:1)
|
||||
/// Proof: `PezTreasury::NextReleaseMonth` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `PezTreasury::HalvingInfo` (r:0 w:1)
|
||||
/// Proof: `PezTreasury::HalvingInfo` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`)
|
||||
fn initialize_treasury() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `3`
|
||||
// Estimated: `1489`
|
||||
// Minimum execution time: 7_724_000 picoseconds.
|
||||
Weight::from_parts(8_079_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1489))
|
||||
.saturating_add(T::DbWeight::get().reads(1))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
/// Storage: `PezTreasury::GenesisDistributionDone` (r:1 w:1)
|
||||
/// Proof: `PezTreasury::GenesisDistributionDone` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Asset` (r:1 w:1)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:3 w:3)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:3 w:3)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn force_genesis_distribution() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `489`
|
||||
// Estimated: `8817`
|
||||
// Minimum execution time: 62_294_000 picoseconds.
|
||||
Weight::from_parts(64_751_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 8817))
|
||||
.saturating_add(T::DbWeight::get().reads(8))
|
||||
.saturating_add(T::DbWeight::get().writes(8))
|
||||
}
|
||||
/// Storage: `PezTreasury::TreasuryStartBlock` (r:1 w:0)
|
||||
/// Proof: `PezTreasury::TreasuryStartBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `PezTreasury::NextReleaseMonth` (r:1 w:1)
|
||||
/// Proof: `PezTreasury::NextReleaseMonth` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
|
||||
/// Storage: `PezTreasury::MonthlyReleases` (r:1 w:1)
|
||||
/// Proof: `PezTreasury::MonthlyReleases` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`)
|
||||
/// Storage: `PezTreasury::HalvingInfo` (r:1 w:1)
|
||||
/// Proof: `PezTreasury::HalvingInfo` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Asset` (r:1 w:1)
|
||||
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Assets::Account` (r:3 w:3)
|
||||
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
|
||||
/// Storage: `AssetsFreezer::FrozenBalances` (r:1 w:0)
|
||||
/// Proof: `AssetsFreezer::FrozenBalances` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`)
|
||||
/// Storage: `System::Account` (r:2 w:2)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn release_monthly_funds() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `701`
|
||||
// Estimated: `8817`
|
||||
// Minimum execution time: 103_894_000 picoseconds.
|
||||
Weight::from_parts(109_089_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 8817))
|
||||
.saturating_add(T::DbWeight::get().reads(11))
|
||||
.saturating_add(T::DbWeight::get().writes(9))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user