Files
pwap/scripts/tests/tests-pez-treasury.rs
T
pezkuwichain 413bcea9da fix: resolve all ESLint errors in launchpad pages
## TypeScript Fixes
- Remove unused imports (useTranslation, TrendingUp, CheckCircle2)
- Replace 'any' types with proper type annotations
- Add PresaleData interface for type safety
- Fix error handling with proper Error type casting

## React Hooks Fixes
- Move loadPresaleData function before useEffect
- Add eslint-disable comments for exhaustive-deps warnings
- Prevent function definition hoisting issues

## Code Quality
- Remove duplicate loadPresaleData function in PresaleDetail
- Proper error message handling with type assertions
- Clean imports and unused variables

All 11 ESLint errors resolved, 0 warnings remaining.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 18:40:11 +03:00

987 lines
35 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// pezkuwi/pallets/pez-treasury/src/tests.rs
use crate::{mock::*, Error, Event};
use frame_support::{assert_noop, assert_ok};
use sp_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())),
sp_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())),
sp_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())),
sp_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);
});
}